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; +} + +/** @} */