From b1a9dfe3848339267ee3c0bb4bf886cc5ae49754 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sat, 16 Jan 2016 19:42:10 +0100 Subject: [PATCH 1/2] netdev2_ieee802154: import of common IEEE802.15.4 netdev2 module --- Makefile.dep | 4 + drivers/include/net/netdev2.h | 22 +- drivers/include/net/netdev2/ieee802154.h | 145 ++++++++++++ drivers/netdev2_ieee802154/Makefile | 1 + .../netdev2_ieee802154/netdev2_ieee802154.c | 223 ++++++++++++++++++ 5 files changed, 385 insertions(+), 10 deletions(-) create mode 100644 drivers/include/net/netdev2/ieee802154.h create mode 100644 drivers/netdev2_ieee802154/Makefile create mode 100644 drivers/netdev2_ieee802154/netdev2_ieee802154.c diff --git a/Makefile.dep b/Makefile.dep index 650fff2e43..8aea56dee5 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -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 diff --git a/drivers/include/net/netdev2.h b/drivers/include/net/netdev2.h index c268dce2e7..8fdd971635 100644 --- a/drivers/include/net/netdev2.h +++ b/drivers/include/net/netdev2.h @@ -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 */ }; /** diff --git a/drivers/include/net/netdev2/ieee802154.h b/drivers/include/net/netdev2/ieee802154.h new file mode 100644 index 0000000000..b61907813a --- /dev/null +++ b/drivers/include/net/netdev2/ieee802154.h @@ -0,0 +1,145 @@ +/* + * 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 + */ +#ifndef NETDEV2_IEEE802154_H_ +#define NETDEV2_IEEE802154_H_ + +#include "net/ieee802154.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 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_ */ +/** @} */ diff --git a/drivers/netdev2_ieee802154/Makefile b/drivers/netdev2_ieee802154/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/netdev2_ieee802154/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/netdev2_ieee802154/netdev2_ieee802154.c b/drivers/netdev2_ieee802154/netdev2_ieee802154.c new file mode 100644 index 0000000000..139c37a559 --- /dev/null +++ b/drivers/netdev2_ieee802154/netdev2_ieee802154.c @@ -0,0 +1,223 @@ +/* + * 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 + */ + +#include +#include +#include +#include + +#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_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; + 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_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; + default: + break; + } + return res; +} + +/** @} */ From b0b76ba3a63caf86ffe49d125b90be0dd2cf3917 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sat, 16 Jan 2016 19:43:38 +0100 Subject: [PATCH 2/2] gnrc: initial import of GNRC<->netdev2 glue code for 802.15.4 --- drivers/include/net/netdev2/ieee802154.h | 9 + .../netdev2_ieee802154/netdev2_ieee802154.c | 46 ++-- sys/include/net/gnrc/netdev2/ieee802154.h | 46 ++++ .../netdev2/gnrc_netdev2_ieee802154.c | 209 ++++++++++++++++++ 4 files changed, 297 insertions(+), 13 deletions(-) create mode 100644 sys/include/net/gnrc/netdev2/ieee802154.h create mode 100644 sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_ieee802154.c diff --git a/drivers/include/net/netdev2/ieee802154.h b/drivers/include/net/netdev2/ieee802154.h index b61907813a..d491d5b43d 100644 --- a/drivers/include/net/netdev2/ieee802154.h +++ b/drivers/include/net/netdev2/ieee802154.h @@ -20,6 +20,7 @@ #define NETDEV2_IEEE802154_H_ #include "net/ieee802154.h" +#include "net/gnrc/nettype.h" #include "net/netopt.h" #include "net/netdev2.h" @@ -67,6 +68,13 @@ extern "C" { */ 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 @@ -85,6 +93,7 @@ typedef struct { uint8_t seq; /**< sequence number */ uint8_t chan; /**< channel */ uint16_t flags; /**< flags as defined above */ + /** @} */ } netdev2_ieee802154_t; /** diff --git a/drivers/netdev2_ieee802154/netdev2_ieee802154.c b/drivers/netdev2_ieee802154/netdev2_ieee802154.c index 139c37a559..0b7a3b6e57 100644 --- a/drivers/netdev2_ieee802154/netdev2_ieee802154.c +++ b/drivers/netdev2_ieee802154/netdev2_ieee802154.c @@ -101,19 +101,6 @@ int netdev2_ieee802154_get(netdev2_ieee802154_t *dev, netopt_t opt, void *value, *((uint16_t *)value) = (uint16_t)dev->chan; res = sizeof(dev->chan); 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; case NETOPT_AUTOACK: if (max_len < sizeof(netopt_enable_t)) { res = -EOVERFLOW; @@ -127,6 +114,29 @@ int netdev2_ieee802154_get(netdev2_ieee802154_t *dev, netopt_t opt, void *value, } 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; @@ -214,6 +224,16 @@ int netdev2_ieee802154_set(netdev2_ieee802154_t *dev, netopt_t opt, void *value, } 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; } diff --git a/sys/include/net/gnrc/netdev2/ieee802154.h b/sys/include/net/gnrc/netdev2/ieee802154.h new file mode 100644 index 0000000000..c9acf9405b --- /dev/null +++ b/sys/include/net/gnrc/netdev2/ieee802154.h @@ -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 + */ +#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_ */ +/** @} */ diff --git a/sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_ieee802154.c b/sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_ieee802154.c new file mode 100644 index 0000000000..dc44156511 --- /dev/null +++ b/sys/net/gnrc/link_layer/netdev2/gnrc_netdev2_ieee802154.c @@ -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 + */ + +#include + +#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; +} + +/** @} */