From 1d8dcae6867bcff4339affbecaaf49afba128122 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Tue, 25 Jul 2017 19:53:53 +0200 Subject: [PATCH] gnrc_netif2: add IEEE 802.15.4 support --- sys/include/net/gnrc/netif2/ieee802154.h | 50 ++++ sys/net/gnrc/netif2/gnrc_netif2_ieee802154.c | 246 +++++++++++++++++++ 2 files changed, 296 insertions(+) create mode 100644 sys/include/net/gnrc/netif2/ieee802154.h create mode 100644 sys/net/gnrc/netif2/gnrc_netif2_ieee802154.c diff --git a/sys/include/net/gnrc/netif2/ieee802154.h b/sys/include/net/gnrc/netif2/ieee802154.h new file mode 100644 index 0000000000..80b73ae3a1 --- /dev/null +++ b/sys/include/net/gnrc/netif2/ieee802154.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2017 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_netif2 + * @{ + * + * @file + * @brief IEEE 802.15.4 adaption for @ref net_gnrc_netif2 + * + * @author Martine Lenders + */ +#ifndef NET_GNRC_NETIF2_IEEE802154_H +#define NET_GNRC_NETIF2_IEEE802154_H + +#include "net/gnrc/netif2.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Creates an IEEE 802.15.4 network interface + * + * @param[in] stack The stack for the network interface's thread. + * @param[in] stacksize Size of @p stack. + * @param[in] priority Priority for the network interface's thread. + * @param[in] name Name for the network interface. May be NULL. + * @param[in] dev Device for the interface + * + * @see @ref gnrc_netif2_create() + * + * @return The network interface on success. + * @return NULL, on error. + */ +gnrc_netif2_t *gnrc_netif2_ieee802154_create(char *stack, int stacksize, + char priority, char *name, + netdev_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* NET_GNRC_NETIF2_IEEE802154_H */ +/** @} */ diff --git a/sys/net/gnrc/netif2/gnrc_netif2_ieee802154.c b/sys/net/gnrc/netif2/gnrc_netif2_ieee802154.c new file mode 100644 index 0000000000..ffad686c39 --- /dev/null +++ b/sys/net/gnrc/netif2/gnrc_netif2_ieee802154.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2017 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 "net/gnrc.h" +#include "net/gnrc/netif2/ieee802154.h" +#include "net/netdev/ieee802154.h" + +#ifdef MODULE_GNRC_IPV6 +#include "net/ipv6/hdr.h" +#endif + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#ifdef MODULE_NETDEV_IEEE802154 +static int _send(gnrc_netif2_t *netif, gnrc_pktsnip_t *pkt); +static gnrc_pktsnip_t *_recv(gnrc_netif2_t *netif); + +static const gnrc_netif2_ops_t ieee802154_ops = { + .send = _send, + .recv = _recv, + .get = gnrc_netif2_get_from_netdev, + .set = gnrc_netif2_set_from_netdev, +}; + +gnrc_netif2_t *gnrc_netif2_ieee802154_create(char *stack, int stacksize, + char priority, char *name, + netdev_t *dev) +{ + return gnrc_netif2_create(stack, stacksize, priority, name, dev, + &ieee802154_ops); +} + +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_netif2_t *netif) +{ + netdev_t *dev = netif->dev; + netdev_ieee802154_rx_info_t rx_info; + netdev_ieee802154_t *state = (netdev_ieee802154_t *)netif->dev; + gnrc_pktsnip_t *pkt = NULL; + int bytes_expected = dev->driver->recv(dev, 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 = dev->driver->recv(dev, pkt->data, bytes_expected, &rx_info); + if (nread <= 0) { + gnrc_pktbuf_release(pkt); + return NULL; + } + if (!(state->flags & NETDEV_IEEE802154_RAW)) { + gnrc_pktsnip_t *ieee802154_hdr, *netif_hdr; + gnrc_netif_hdr_t *hdr; +#if ENABLE_DEBUG + char src_str[GNRC_NETIF_HDR_L2ADDR_PRINT_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; + +#ifdef MODULE_L2FILTER + if (!l2filter_pass(dev->filter, gnrc_netif_hdr_get_src_addr(hdr), + hdr->src_l2addr_len)) { + gnrc_pktbuf_release(pkt); + gnrc_pktbuf_release(netif_hdr); + DEBUG("_recv_ieee802154: packet dropped by l2filter\n"); + return NULL; + } +#endif + + 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_netif2_t *netif, gnrc_pktsnip_t *pkt) +{ + netdev_t *dev = netif->dev; + netdev_ieee802154_t *state = (netdev_ieee802154_t *)netif->dev; + gnrc_netif_hdr_t *netif_hdr; + gnrc_pktsnip_t *vec_snip; + const uint8_t *src, *dst = NULL; + int res = 0; + size_t n, src_len, dst_len; + uint8_t mhr[IEEE802154_MAX_HDR_LEN]; + uint8_t flags = (uint8_t)(state->flags & NETDEV_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 assume broadcast */ + (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) { + dst = ieee802154_addr_bcast; + dst_len = IEEE802154_ADDR_BCAST_LEN; + } + else { + dst = gnrc_netif_hdr_get_dst_addr(netif_hdr); + dst_len = netif_hdr->dst_l2addr_len; + } + src_len = netif_hdr->src_l2addr_len; + if (src_len > 0) { + src = gnrc_netif_hdr_get_src_addr(netif_hdr); + } + else { + src_len = netif->l2addr_len; + src = netif->l2addr; + } + /* fill MAC header, seq should be set by device */ + if ((res = ieee802154_set_frame_hdr(mhr, src, src_len, + dst, dst_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); + 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; +#ifdef MODULE_NETSTATS_L2 + if (netif_hdr->flags & + (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) { + netif->dev->stats.tx_mcast_count++; + } + else { + netif->dev->stats.tx_unicast_count++; + } +#endif +#ifdef MODULE_GNRC_MAC + if (netif->mac_info & GNRC_NETDEV_MAC_INFO_CSMA_ENABLED) { + res = csma_sender_csma_ca_send(dev, vector, n, &netif->csma_conf); + } + else { + res = dev->driver->send(dev, vector, n); + } +#else + res = dev->driver->send(dev, vector, n); +#endif + } + else { + return -ENOBUFS; + } + /* release old data */ + gnrc_pktbuf_release(pkt); + return res; +} +#else /* MODULE_NETDEV_IEEE802154 */ +typedef int dont_be_pedantic; +#endif /* MODULE_NETDEV_IEEE802154 */ +/** @} */