1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #4645 from authmillenon/netdev2/enh/ieee802154

netdev2: add basic IEEE 802.15.4 support
This commit is contained in:
Martine Lenders 2016-03-15 18:28:29 +01:00
commit 1caf0bcc8a
7 changed files with 669 additions and 10 deletions

View File

@ -12,6 +12,10 @@ ifneq (,$(filter nhdp,$(USEMODULE)))
USEMODULE += oonf_rfc5444
endif
ifneq (,$(filter netdev2_ieee802154,$(USEMODULE)))
USEMODULE += ieee802154
endif
ifneq (,$(filter gnrc_%,$(filter-out gnrc_netapi gnrc_netreg gnrc_netif% gnrc_pktbuf,$(USEMODULE))))
USEMODULE += gnrc
endif

View File

@ -52,7 +52,7 @@ enum {
NETDEV2_TYPE_UNKNOWN,
NETDEV2_TYPE_RAW,
NETDEV2_TYPE_ETHERNET,
NETDEV2_TYPE_802154,
NETDEV2_TYPE_IEEE802154,
NETDEV2_TYPE_CC110X,
};
@ -61,13 +61,15 @@ enum {
* upper layer
*/
typedef enum {
NETDEV2_EVENT_ISR, /**< driver needs it's ISR handled */
NETDEV2_EVENT_RX_STARTED, /**< started to receive a packet */
NETDEV2_EVENT_RX_COMPLETE, /**< finished receiving a packet */
NETDEV2_EVENT_TX_STARTED, /**< started to transfer a packet */
NETDEV2_EVENT_TX_COMPLETE, /**< finished transferring packet */
NETDEV2_EVENT_LINK_UP, /**< link established */
NETDEV2_EVENT_LINK_DOWN, /**< link gone */
NETDEV2_EVENT_ISR, /**< driver needs it's ISR handled */
NETDEV2_EVENT_RX_STARTED, /**< started to receive a packet */
NETDEV2_EVENT_RX_COMPLETE, /**< finished receiving a packet */
NETDEV2_EVENT_TX_STARTED, /**< started to transfer a packet */
NETDEV2_EVENT_TX_COMPLETE, /**< finished transferring packet */
NETDEV2_EVENT_TX_NOACK, /**< ACK requested but not received */
NETDEV2_EVENT_TX_MEDIUM_BUSY, /**< couldn't transfer packet */
NETDEV2_EVENT_LINK_UP, /**< link established */
NETDEV2_EVENT_LINK_DOWN, /**< link gone */
/* expand this list if needed */
} netdev2_event_t;
@ -92,7 +94,7 @@ typedef struct netdev2 netdev2_t;
* @param[in] type type of the event
* @param[in] arg event argument
*/
typedef void (*netdev2_event_cb_t)(netdev2_t *dev, netdev2_event_t event, void* arg);
typedef void (*netdev2_event_cb_t)(netdev2_t *dev, netdev2_event_t event, void *arg);
/**
* @brief Structure to hold driver state
@ -103,7 +105,7 @@ typedef void (*netdev2_event_cb_t)(netdev2_t *dev, netdev2_event_t event, void*
struct netdev2 {
const struct netdev2_driver *driver; /**< ptr to that driver's interface. */
netdev2_event_cb_t event_callback; /**< callback for device events */
void* isr_arg; /**< argument to pass on isr event */
void *isr_arg; /**< argument to pass on isr event */
};
/**

View File

@ -0,0 +1,154 @@
/*
* Copyright (C) 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_netdev_netdev2
* @brief
* @{
*
* @file
* @brief Definitions for netdev2 common IEEE 802.15.4 code
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NETDEV2_IEEE802154_H_
#define NETDEV2_IEEE802154_H_
#include "net/ieee802154.h"
#include "net/gnrc/nettype.h"
#include "net/netopt.h"
#include "net/netdev2.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name IEEE 802.15.4 netdev2 flags
* @brief Flags for netdev_ieee802154_t::flags
*
* The flag-space `0xff00` is available for device-specific flags.
* The flag-space `0x00ff` was chosen for global flags to be in accordance to
* the IEEE 802.15.4 MAC header flags.
* @{
*/
#define NETDEV2_IEEE802154_SEND_MASK (0x0068) /**< flags to take for send packets */
#define NETDEV2_IEEE802154_RESV1 (0x0001) /**< reserved flag */
#define NETDEV2_IEEE802154_RAW (0x0002) /**< pass raw frame to upper layer */
/**
* @brief use long source addres (set) or short source address (unset)
*/
#define NETDEV2_IEEE802154_SRC_MODE_LONG (0x0004)
#define NETDEV2_IEEE802154_SECURITY_EN (0x0008) /**< enable security */
#define NETDEV2_IEEE802154_RESV2 (0x0010) /**< reserved flag */
/**
* @brief request ACK from receiver
*/
#define NETDEV2_IEEE802154_ACK_REQ (0x0020)
#define NETDEV2_IEEE802154_PAN_COMP (0x0040) /**< compress source PAN ID */
#define NETDEV2_IEEE802154_RESV3 (0x0080) /**< reserved flag */
/**
* @}
*/
/**
* @brief Extended structure to hold IEEE 802.15.4 driver state
*
* @extends netdev2_t
*
* Supposed to be extended by driver implementations.
* The extended structure should contain all variable driver state.
*/
typedef struct {
netdev2_t netdev; /**< @ref netdev2_t base class */
/**
* @brief IEEE 802.15.4 specific fields
* @{
*/
#ifdef MODULE_GNRC
gnrc_nettype_t proto; /**< Protocol for upper layer */
#endif
/**
* @brief PAN ID in network byte order
*/
uint16_t pan;
/**
* @brief Short address in network byte order
*/
uint8_t short_addr[IEEE802154_SHORT_ADDRESS_LEN];
/**
* @brief Long address in network byte order
*/
uint8_t long_addr[IEEE802154_LONG_ADDRESS_LEN];
uint8_t seq; /**< sequence number */
uint8_t chan; /**< channel */
uint16_t flags; /**< flags as defined above */
/** @} */
} netdev2_ieee802154_t;
/**
* @brief Received packet status information for IEEE 802.15.4 radios
*/
typedef struct netdev2_radio_rx_info netdev2_ieee802154_rx_info_t;
/**
* @brief Fallback function for netdev2 IEEE 802.15.4 devices' _get function
*
* Supposed to be used by netdev2 drivers as default case.
*
* @param[in] dev network device descriptor
* @param[in] opt option type
* @param[out] value pointer to store the option's value in
* @param[in] max_len maximal amount of byte that fit into @p value
*
* @return number of bytes written to @p value
* @return <0 on error
*/
int netdev2_ieee802154_get(netdev2_ieee802154_t *dev, netopt_t opt, void *value,
size_t max_len);
/**
* @brief Fallback function for netdev2 IEEE 802.15.4 devices' _set function
*
* Sets netdev2_ieee802154_t::pan, netdev2_ieee802154_t::short_addr, and
* netdev2_ieee802154_t::long_addr in device struct.
* Additionally @ref NETDEV2_IEEE802154_SRC_MODE_LONG,
* @ref NETDEV2_IEEE802154_RAW and, @ref NETDEV2_IEEE802154_ACK_REQ in
* netdev2_ieee802154_t::flags can be set or unset.
*
* The setting of netdev2_ieee802154_t::chan is omitted since the legality of
* its value can be very device specific and can't be checked in this function.
* Please set it in the netdev2_driver_t::set function of your driver.
*
* Be aware that this only manipulates the netdev2_ieee802154_t struct.
* Configuration to the device needs to be done in the netdev2_driver_t::set
* function of the device driver (which should call this function as a fallback
* afterwards).
*
* @param[in] dev network device descriptor
* @param[in] opt option type
* @param[in] value value to set
* @param[in] value_len the length of @p value
*
* @return number of bytes used from @p value
* @return <0 on error
*/
int netdev2_ieee802154_set(netdev2_ieee802154_t *dev, netopt_t opt, void *value,
size_t value_len);
#ifdef __cplusplus
}
#endif
#endif /* NETDEV2_IEEE802154_H_ */
/** @} */

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,243 @@
/*
* Copyright (C) 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <stdbool.h>
#include "net/eui64.h"
#include "net/ieee802154.h"
#include "net/netdev2.h"
#include "net/netdev2/ieee802154.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static int _get_iid(netdev2_ieee802154_t *dev, eui64_t *value, size_t max_len)
{
uint8_t *addr;
uint16_t addr_len;
if (max_len < sizeof(eui64_t)) {
return -EOVERFLOW;
}
if (dev->flags & NETDEV2_IEEE802154_SRC_MODE_LONG) {
addr_len = IEEE802154_LONG_ADDRESS_LEN;
addr = dev->long_addr;
}
else {
addr_len = IEEE802154_SHORT_ADDRESS_LEN;
addr = dev->short_addr;
}
ieee802154_get_iid(value, addr, addr_len);
return sizeof(eui64_t);
}
int netdev2_ieee802154_get(netdev2_ieee802154_t *dev, netopt_t opt, void *value,
size_t max_len)
{
int res = -ENOTSUP;
switch (opt) {
case NETOPT_ADDRESS:
if (max_len < sizeof(dev->short_addr)) {
res = -EOVERFLOW;
break;
}
memcpy(value, dev->short_addr, sizeof(dev->short_addr));
res = sizeof(dev->short_addr);
break;
case NETOPT_ADDRESS_LONG:
if (max_len < sizeof(dev->long_addr)) {
res = -EOVERFLOW;
break;
}
memcpy(value, dev->long_addr, sizeof(dev->long_addr));
res = sizeof(dev->long_addr);
break;
case NETOPT_ADDR_LEN:
case NETOPT_SRC_LEN:
if (max_len < sizeof(uint16_t)) {
res = -EOVERFLOW;
break;
}
if (dev->flags & NETDEV2_IEEE802154_SRC_MODE_LONG) {
*((uint16_t *)value) = IEEE802154_LONG_ADDRESS_LEN;
}
else {
*((uint16_t *)value) = IEEE802154_SHORT_ADDRESS_LEN;
}
res = sizeof(uint16_t);
break;
case NETOPT_NID:
if (max_len < sizeof(dev->pan)) {
res = -EOVERFLOW;
break;
}
*((uint16_t *)value) = dev->pan;
res = sizeof(dev->pan);
break;
case NETOPT_CHANNEL:
if (max_len < sizeof(uint16_t)) {
res = -EOVERFLOW;
break;
}
*((uint16_t *)value) = (uint16_t)dev->chan;
res = sizeof(dev->chan);
break;
case NETOPT_AUTOACK:
if (max_len < sizeof(netopt_enable_t)) {
res = -EOVERFLOW;
break;
}
if (dev->flags & NETDEV2_IEEE802154_ACK_REQ) {
*((netopt_enable_t *)value) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)value) = NETOPT_DISABLE;
}
res = sizeof(netopt_enable_t);
break;
case NETOPT_RAWMODE:
if (max_len < sizeof(netopt_enable_t)) {
res = -EOVERFLOW;
break;
}
if (dev->flags & NETDEV2_IEEE802154_RAW) {
*((netopt_enable_t *)value) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)value) = NETOPT_DISABLE;
}
res = sizeof(netopt_enable_t);
break;
#ifdef MODULE_GNRC
case NETOPT_PROTO:
if (max_len < sizeof(gnrc_nettype_t)) {
res = -EOVERFLOW;
break;
}
*((gnrc_nettype_t *)value) = dev->proto;
res = sizeof(gnrc_nettype_t);
break;
#endif
case NETOPT_DEVICE_TYPE:
if (max_len < sizeof(uint16_t)) {
res = -EOVERFLOW;
break;
}
*((uint16_t *)value) = NETDEV2_TYPE_IEEE802154;
res = sizeof(uint16_t);
break;
case NETOPT_IPV6_IID:
res = _get_iid(dev, value, max_len);
break;
default:
break;
}
return res;
}
int netdev2_ieee802154_set(netdev2_ieee802154_t *dev, netopt_t opt, void *value,
size_t len)
{
int res = -ENOTSUP;
switch (opt) {
case NETOPT_ADDRESS:
if (len > sizeof(dev->short_addr)) {
res = -EOVERFLOW;
break;
}
memset(dev->short_addr, 0, sizeof(dev->short_addr));
memcpy(dev->short_addr, value, len);
res = sizeof(dev->short_addr);
break;
case NETOPT_ADDRESS_LONG:
if (len > sizeof(dev->long_addr)) {
res = -EOVERFLOW;
break;
}
memset(dev->long_addr, 0, sizeof(dev->long_addr));
memcpy(dev->long_addr, value, len);
res = sizeof(dev->long_addr);
break;
case NETOPT_ADDR_LEN:
case NETOPT_SRC_LEN:
if (len > sizeof(uint16_t)) {
res = -EOVERFLOW;
break;
}
switch ((*(uint16_t *)value)) {
case IEEE802154_SHORT_ADDRESS_LEN:
dev->flags &= ~NETDEV2_IEEE802154_SRC_MODE_LONG;
break;
case IEEE802154_LONG_ADDRESS_LEN:
dev->flags |= NETDEV2_IEEE802154_SRC_MODE_LONG;
break;
default:
res = -EAFNOSUPPORT;
break;
}
res = sizeof(uint16_t);
break;
case NETOPT_NID:
if (len > sizeof(dev->pan)) {
res = -EOVERFLOW;
break;
}
dev->pan = *((uint16_t *)value);
res = sizeof(dev->pan);
break;
/* channel can be very device specific */
case NETOPT_AUTOACK:
if ((*(bool *)value)) {
dev->flags |= NETDEV2_IEEE802154_ACK_REQ;
}
else {
dev->flags &= ~NETDEV2_IEEE802154_ACK_REQ;
}
res = sizeof(uint16_t);
break;
case NETOPT_RAWMODE:
if ((*(bool *)value)) {
dev->flags |= NETDEV2_IEEE802154_RAW;
}
else {
dev->flags &= ~NETDEV2_IEEE802154_RAW;
}
res = sizeof(uint16_t);
break;
#ifdef MODULE_GNRC
case NETOPT_PROTO:
if (len > sizeof(gnrc_nettype_t)) {
res = -EOVERFLOW;
break;
}
dev->proto = *((gnrc_nettype_t *)value);
res = sizeof(gnrc_nettype_t);
break;
#endif
default:
break;
}
return res;
}
/** @} */

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup net_gnrc
* @brief
* @{
*
* @file
* @brief netdev2 gnrc IEEE 802.15.4 glue code interface
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef GNRC_NETDEV2_IEEE802154_H_
#define GNRC_NETDEV2_IEEE802154_H_
#include "net/netdev2/ieee802154.h"
#include "net/gnrc/netdev2.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize gnrc handler for netdev2 IEEE 802.15.4 device
*
* @param[in] gnrc_netdev2 gnrc_netdev2 struct to initialize
* @param[in] dev netdev2 device to handle
*
* @return 1 on success
* @return <=0 on error
*/
int gnrc_netdev2_ieee802154_init(gnrc_netdev2_t *gnrc_netdev2,
netdev2_ieee802154_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* GNRC_IEEE802154_H_ */
/** @} */

View File

@ -0,0 +1,209 @@
/*
* Copyright (C) 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <stddef.h>
#include "od.h"
#include "net/gnrc.h"
#include "net/ieee802154.h"
#include "net/gnrc/netdev2/ieee802154.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static gnrc_pktsnip_t *_recv(gnrc_netdev2_t *gnrc_netdev2);
static int _send(gnrc_netdev2_t *gnrc_netdev2, gnrc_pktsnip_t *pkt);
int gnrc_netdev2_ieee802154_init(gnrc_netdev2_t *gnrc_netdev2,
netdev2_ieee802154_t *dev)
{
gnrc_netdev2->send = _send;
gnrc_netdev2->recv = _recv;
gnrc_netdev2->dev = (netdev2_t *)dev;
return 0;
}
static gnrc_pktsnip_t *_make_netif_hdr(uint8_t *mhr)
{
gnrc_pktsnip_t *snip;
uint8_t src[IEEE802154_LONG_ADDRESS_LEN], dst[IEEE802154_LONG_ADDRESS_LEN];
int src_len, dst_len;
le_uint16_t _pan_tmp; /* TODO: hand-up PAN IDs to GNRC? */
dst_len = ieee802154_get_dst(mhr, dst, &_pan_tmp);
src_len = ieee802154_get_src(mhr, src, &_pan_tmp);
if ((dst_len < 0) || (src_len < 0)) {
DEBUG("_make_netif_hdr: unable to get addresses\n");
return NULL;
}
/* allocate space for header */
snip = gnrc_netif_hdr_build(src, (size_t)src_len, dst, (size_t)dst_len);
if (snip == NULL) {
DEBUG("_make_netif_hdr: no space left in packet buffer\n");
return NULL;
}
/* set broadcast flag for broadcast destination */
if ((dst_len == 2) && (dst[0] == 0xff) && (dst[1] == 0xff)) {
gnrc_netif_hdr_t *hdr = snip->data;
hdr->flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST;
}
return snip;
}
static gnrc_pktsnip_t *_recv(gnrc_netdev2_t *gnrc_netdev2)
{
netdev2_t *netdev = gnrc_netdev2->dev;
netdev2_ieee802154_rx_info_t rx_info;
netdev2_ieee802154_t *state = (netdev2_ieee802154_t *)gnrc_netdev2->dev;
gnrc_pktsnip_t *pkt = NULL;
int bytes_expected = netdev->driver->recv(netdev, NULL, 0, NULL);
if (bytes_expected > 0) {
int nread;
pkt = gnrc_pktbuf_add(NULL, NULL, bytes_expected, GNRC_NETTYPE_UNDEF);
if (pkt == NULL) {
DEBUG("_recv_ieee802154: cannot allocate pktsnip.\n");
return NULL;
}
nread = netdev->driver->recv(netdev, pkt->data, bytes_expected, &rx_info);
if (nread <= 0) {
gnrc_pktbuf_release(pkt);
return NULL;
}
if (!(state->flags & NETDEV2_IEEE802154_RAW)) {
gnrc_pktsnip_t *ieee802154_hdr, *netif_hdr;
gnrc_netif_hdr_t *hdr;
#if ENABLE_DEBUG
char src_str[GNRC_NETIF_HDR_L2ADDR_MAX_LEN];
#endif
size_t mhr_len = ieee802154_get_frame_hdr_len(pkt->data);
if (mhr_len == 0) {
DEBUG("_recv_ieee802154: illegally formatted frame received\n");
gnrc_pktbuf_release(pkt);
return NULL;
}
nread -= mhr_len;
/* mark IEEE 802.15.4 header */
ieee802154_hdr = gnrc_pktbuf_mark(pkt, mhr_len, GNRC_NETTYPE_UNDEF);
if (ieee802154_hdr == NULL) {
DEBUG("_recv_ieee802154: no space left in packet buffer\n");
gnrc_pktbuf_release(pkt);
return NULL;
}
netif_hdr = _make_netif_hdr(ieee802154_hdr->data);
if (netif_hdr == NULL) {
DEBUG("_recv_ieee802154: no space left in packet buffer\n");
gnrc_pktbuf_release(pkt);
return NULL;
}
hdr = netif_hdr->data;
hdr->lqi = rx_info.lqi;
hdr->rssi = rx_info.rssi;
hdr->if_pid = thread_getpid();
pkt->type = state->proto;
#if ENABLE_DEBUG
DEBUG("_recv_ieee802154: received packet from %s of length %u\n",
gnrc_netif_addr_to_str(src_str, sizeof(src_str),
gnrc_netif_hdr_get_src_addr(hdr),
hdr->src_l2addr_len),
nread);
#if defined(MODULE_OD)
od_hex_dump(pkt->data, nread, OD_WIDTH_DEFAULT);
#endif
#endif
gnrc_pktbuf_remove_snip(pkt, ieee802154_hdr);
LL_APPEND(pkt, netif_hdr);
}
DEBUG("_recv_ieee802154: reallocating.\n");
gnrc_pktbuf_realloc_data(pkt, nread);
}
return pkt;
}
static int _send(gnrc_netdev2_t *gnrc_netdev2, gnrc_pktsnip_t *pkt)
{
netdev2_t *netdev = gnrc_netdev2->dev;
netdev2_ieee802154_t *state = (netdev2_ieee802154_t *)gnrc_netdev2->dev;
gnrc_netif_hdr_t *netif_hdr;
gnrc_pktsnip_t *vec_snip;
uint8_t *src, *dst = NULL;
int res = 0;
size_t n, src_len;
uint8_t mhr[IEEE802154_MAX_HDR_LEN];
uint8_t flags = (uint8_t)(state->flags & NETDEV2_IEEE802154_SEND_MASK);
le_uint16_t dev_pan = byteorder_btols(byteorder_htons(state->pan));
flags |= IEEE802154_FCF_TYPE_DATA;
if (pkt == NULL) {
DEBUG("_send_ieee802154: pkt was NULL\n");
return -EINVAL;
}
if (pkt->type != GNRC_NETTYPE_NETIF) {
DEBUG("_send_ieee802154: first header is not generic netif header\n");
return -EBADMSG;
}
netif_hdr = pkt->data;
/* prepare destination address */
if (netif_hdr->flags & /* If any of these flags is set so this is correct */
(GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
flags |= IEEE802154_BCAST;
}
else {
dst = gnrc_netif_hdr_get_dst_addr(netif_hdr);
}
src_len = netif_hdr->src_l2addr_len;
if (src_len > 0) {
src = gnrc_netif_hdr_get_src_addr(netif_hdr);
}
else if (state->flags & NETDEV2_IEEE802154_SRC_MODE_LONG) {
src_len = IEEE802154_LONG_ADDRESS_LEN;
src = state->long_addr;
}
else {
src_len = IEEE802154_SHORT_ADDRESS_LEN;
src = state->short_addr;
}
/* fill MAC header, seq should be set by device */
if ((res = ieee802154_set_frame_hdr(mhr, src, src_len,
dst, netif_hdr->dst_l2addr_len,
dev_pan, dev_pan, flags,
state->seq++)) == 0) {
DEBUG("_send_ieee802154: Error preperaring frame\n");
return -EINVAL;
}
/* prepare packet for sending */
vec_snip = gnrc_pktbuf_get_iovec(pkt, &n);
res = -ENOBUFS;
if (vec_snip != NULL) {
struct iovec *vector;
pkt = vec_snip; /* reassign for later release; vec_snip is prepended to pkt */
vector = (struct iovec *)pkt->data;
vector[0].iov_base = mhr;
vector[0].iov_len = (size_t)res;
res = netdev->driver->send(netdev, vector, n);
}
/* release old data */
gnrc_pktbuf_release(pkt);
return res;
}
/** @} */