diff --git a/drivers/include/net/netdev/ieee802154.h b/drivers/include/net/netdev/ieee802154.h index e47483213fed..0bec28e23924 100644 --- a/drivers/include/net/netdev/ieee802154.h +++ b/drivers/include/net/netdev/ieee802154.h @@ -194,6 +194,31 @@ int netdev_ieee802154_set(netdev_ieee802154_t *dev, netopt_t opt, const void *va */ int netdev_ieee802154_dst_filter(netdev_ieee802154_t *dev, const uint8_t *mhr); +typedef struct { + uint8_t *psdu; + size_t psdu_len; + uint8_t lqi; + int16_t rssi; + void *ctx; +} ieee802154_phy_ind_t; + +typedef struct { + iolist_t msdu; + uint8_t *src; + size_t src_len; + uint8_t *dst; + size_t dst_len; + uint8_t frame_pending; +} ieee802154_mac_ind_t; + +void ieee802154_rf_rx_done(netdev_t *netdev); +void ieee802154_mac_recv(netdev_ieee802154_t *dev, ieee802154_phy_ind_t *ind); +void ieee802154_mac_ind(netdev_ieee802154_t *netdev, ieee802154_mac_ind_t *ind, ieee802154_phy_ind_t *phy_ind); +void ieee802154_phy_ind(netdev_t *netdev, ieee802154_phy_ind_t *ind); +int ieee802154_mac_send(netdev_ieee802154_t *netdev, iolist_t *msdu, int frame_pending, + uint8_t *src, size_t src_len, uint8_t *dst, size_t dst_len); + + #ifdef __cplusplus } #endif diff --git a/sys/include/net/netbuf.h b/sys/include/net/netbuf.h new file mode 100644 index 000000000000..4fe14add2a65 --- /dev/null +++ b/sys/include/net/netbuf.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 HAW Hamburg + * + * 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. + */ + +/** + * @defgroup net_netbuf Network buffer abstraction + * @ingroup net + * @brief Provides an abstraction for network stack buffers + * @{ + * + * @file + * @brief Network buffer abstraction definition + * + * @author Jose I. Alamos + */ +#ifndef NET_NETBUF_H +#define NET_NETBUF_H + +#include +#include "iolist.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Get a network buffer with a given size. + * + * @note Supposed to be implemented by the networking module. + * + * @param[in] size size of the buffer to be allocated. + * @param[out] ctx allocation context. + * + * @return pointer to the buffer. + * @return packet context in @p ctx. + * @return NULL on failure (e.g there's not enough memory for allocation) + */ +void *netbuf_get(size_t size, void **ctx); + +/** + * @brief Free the resources of a network buffer + * + * @note Supposed to be implemented by the networking module. + * + * @param[in] ctx pointer to the allocation context. + */ +void netbuf_free(void *ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* NET_NETBUF_H */ +/** @} */ diff --git a/sys/include/net/netif.h b/sys/include/net/netif.h index f4593548dff8..c571b8ca16f0 100644 --- a/sys/include/net/netif.h +++ b/sys/include/net/netif.h @@ -37,6 +37,7 @@ #include "list.h" #include "net/netopt.h" +#include "net/netbuf.h" #ifdef __cplusplus extern "C" { @@ -58,6 +59,21 @@ typedef struct { list_node_t node; /**< Pointer to the next interface */ } netif_t; +typedef struct { + iolist_t msdu; + void *ctx; + uint8_t *src_l2addr; + uint8_t *dst_l2addr; + int16_t rssi; + uint8_t lqi; + uint8_t src_l2addr_len; + uint8_t dst_l2addr_len; + uint8_t flags; +} netif_pkt_t; + + +int netif_recv(netif_t *netif, netif_pkt_t *pkt); + /** * @brief Iterator for the interfaces * diff --git a/sys/net/gnrc/netif/_netif.c b/sys/net/gnrc/netif/_netif.c index 2cc064158742..5c09e110471c 100644 --- a/sys/net/gnrc/netif/_netif.c +++ b/sys/net/gnrc/netif/_netif.c @@ -18,11 +18,78 @@ #include #include "fmt.h" +#include "net/gnrc.h" #include "net/gnrc/netapi.h" #include "net/gnrc/netif/internal.h" #include "net/netif.h" +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* GNRC implementation of netif_recv. + * + * This function converts the `netif_pkt` representation + * into a `gnrc_pkt` representation. Note that the + * netbuf implementation of GNRC uses the gnrc_pktsnip_t + * pointer as netbuf context, so we can get fetch the packet + * from there. + * + * Also, we need to create the gnrc_netif_hdr to pass the + * L2 metadata to the upper layers. And also remove the + * L2 header. + * + * Note that if a PHY layer didn't call the netbuf allocation + * function (e.g the PHY layer had a static framebuffer like + * the ESP-WIFI implementation), it's possible to set the + * allocation context (netif_pkt->ctx) to NULL. + * So, it's possible to only allocate the MSDU + * and not the full packet!! This would reduce the number + * of memcpy in those cases. + */ +int netif_recv(netif_t *netif, netif_pkt_t *pkt) +{ + gnrc_pktsnip_t *gnrc_pkt = pkt->ctx; + gnrc_netif_t *gnrc_netif = (gnrc_netif_t*) netif; + netdev_t *dev = gnrc_netif->dev; + + gnrc_pktsnip_t *netif_snip = gnrc_netif_hdr_build(pkt->src_l2addr, pkt->src_l2addr_len, pkt->dst_l2addr, pkt->dst_l2addr_len); + + if (netif_snip == NULL) { + DEBUG("_recv_ieee802154: no space left in packet buffer\n"); + gnrc_pktbuf_release(gnrc_pkt); + return 0; + } + + /* We can avoid the following logic if we know the PHY layer + * didn't allocate the packet (see the description of this function). + * + * In that case, we would need to call + * `gnrc_pktbuf_add(pkt->msdu.iol_base, pkt->msdu.iol_len, GNRC_NETTYPE_UNDEF)` + * instead of removing the snip and reallocating data. + */ + gnrc_pktsnip_t *ieee802154_hdr = gnrc_pktbuf_mark(gnrc_pkt, ((uint8_t*) pkt->msdu.iol_base) - ((uint8_t*) gnrc_pkt->data), GNRC_NETTYPE_UNDEF); + + gnrc_pktbuf_remove_snip(gnrc_pkt, ieee802154_hdr); + gnrc_pktbuf_realloc_data(gnrc_pkt, pkt->msdu.iol_len); + gnrc_netif_hdr_t *hdr = netif_snip->data; + hdr->lqi = pkt->lqi; + hdr->rssi = pkt->rssi; + gnrc_netif_hdr_set_netif(hdr, (gnrc_netif_t*) netif); + dev->driver->get(dev, NETOPT_PROTO, &gnrc_pkt->type, sizeof(gnrc_pkt->type)); + + hdr->flags |= pkt->flags; + + LL_APPEND(gnrc_pkt, netif_snip); + + if (!gnrc_netapi_dispatch_receive(gnrc_pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, gnrc_pkt)) + { + return 0; + } + + return 1; +} + int netif_get_name(netif_t *iface, char *name) { gnrc_netif_t *netif = (gnrc_netif_t*) iface; diff --git a/sys/net/gnrc/netif/gnrc_netif.c b/sys/net/gnrc/netif/gnrc_netif.c index a6053073e5a7..690f8c677f0c 100644 --- a/sys/net/gnrc/netif/gnrc_netif.c +++ b/sys/net/gnrc/netif/gnrc_netif.c @@ -33,6 +33,7 @@ #include "sched.h" #include "xtimer.h" +#include "net/netbuf.h" #include "net/gnrc/netif.h" #include "net/gnrc/netif/internal.h" @@ -46,6 +47,25 @@ static void _configure_netdev(netdev_t *dev); static void *_gnrc_netif_thread(void *args); static void _event_cb(netdev_t *dev, netdev_event_t event); +/* GNRC implementation of the netbuf_get function */ +void *netbuf_get(size_t size, void **ctx) +{ + gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, NULL, size, GNRC_NETTYPE_UNDEF); + + if(pkt) { + *ctx = pkt; + return pkt->data; + } + + return NULL; +} + +/* GNRC implementation of the netbuf_free function */ +void netbuf_free(void *netbuf) +{ + gnrc_pktbuf_release(netbuf); +} + gnrc_netif_t *gnrc_netif_create(char *stack, int stacksize, char priority, const char *name, netdev_t *netdev, const gnrc_netif_ops_t *ops) @@ -1332,6 +1352,7 @@ void gnrc_netif_default_init(gnrc_netif_t *netif) #endif } +extern int gnrc_netif_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt); static void *_gnrc_netif_thread(void *args) { gnrc_netapi_opt_t *opt; @@ -1388,7 +1409,7 @@ static void *_gnrc_netif_thread(void *args) break; case GNRC_NETAPI_MSG_TYPE_SND: DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_SND received\n"); - res = netif->ops->send(netif, msg.content.ptr); + res = gnrc_netif_send(netif, msg.content.ptr); if (res < 0) { DEBUG("gnrc_netif: error sending packet %p (code: %i)\n", msg.content.ptr, res); diff --git a/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c b/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c index ad15ec080ab0..a104775f392f 100644 --- a/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c +++ b/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c @@ -17,6 +17,8 @@ #include "net/gnrc/netif/ieee802154.h" #include "net/netdev/ieee802154.h" +#include "net/netbuf.h" + #ifdef MODULE_GNRC_IPV6 #include "net/ipv6/hdr.h" #endif @@ -28,12 +30,11 @@ #include "od.h" #endif -static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt); static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif); static const gnrc_netif_ops_t ieee802154_ops = { .init = gnrc_netif_default_init, - .send = _send, + .send = NULL, /* to be migrated to netif->ops */ .recv = _recv, .get = gnrc_netif_get_from_netdev, .set = gnrc_netif_set_from_netdev, @@ -47,236 +48,40 @@ gnrc_netif_t *gnrc_netif_ieee802154_create(char *stack, int stacksize, &ieee802154_ops); } -static gnrc_pktsnip_t *_make_netif_hdr(uint8_t *mhr) -{ - gnrc_netif_hdr_t *hdr; - 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; - } - hdr = snip->data; - /* set broadcast flag for broadcast destination */ - if ((dst_len == 2) && (dst[0] == 0xff) && (dst[1] == 0xff)) { - hdr->flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST; - } - /* set flags for pending frames */ - if (mhr[0] & IEEE802154_FCF_FRAME_PEND) { - hdr->flags |= GNRC_NETIF_HDR_FLAGS_MORE_DATA; - } - return snip; -} - -#if MODULE_GNRC_NETIF_DEDUP -static inline bool _already_received(gnrc_netif_t *netif, - gnrc_netif_hdr_t *netif_hdr, - uint8_t *mhr) -{ - const uint8_t seq = ieee802154_get_seq(mhr); - - return (netif->last_pkt.seq == seq) && - (netif->last_pkt.src_len == netif_hdr->src_l2addr_len) && - (memcmp(netif->last_pkt.src, gnrc_netif_hdr_get_src_addr(netif_hdr), - netif_hdr->src_l2addr_len) == 0); -} -#endif /* MODULE_GNRC_NETIF_DEDUP */ - static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif) { - netdev_t *dev = netif->dev; - netdev_ieee802154_rx_info_t rx_info; - gnrc_pktsnip_t *pkt = NULL; - int bytes_expected = dev->driver->recv(dev, NULL, 0, NULL); - - if (bytes_expected >= (int)IEEE802154_MIN_FRAME_LEN) { - int nread; - - pkt = gnrc_pktbuf_add(NULL, NULL, bytes_expected, GNRC_NETTYPE_UNDEF); - if (pkt == NULL) { - DEBUG("_recv_ieee802154: cannot allocate pktsnip.\n"); - /* Discard packet on netdev device */ - dev->driver->recv(dev, NULL, bytes_expected, NULL); - return NULL; - } - nread = dev->driver->recv(dev, pkt->data, bytes_expected, &rx_info); - if (nread <= 0) { - gnrc_pktbuf_release(pkt); - return NULL; - } -#ifdef MODULE_NETSTATS_L2 - netif->stats.rx_count++; - netif->stats.rx_bytes += nread; -#endif - - if (netif->flags & GNRC_NETIF_FLAGS_RAWMODE) { - /* Raw mode, skip packet processing, but provide rx_info via - * GNRC_NETTYPE_NETIF */ - gnrc_pktsnip_t *netif_snip = gnrc_netif_hdr_build(NULL, 0, NULL, 0); - if (netif_snip == NULL) { - DEBUG("_recv_ieee802154: no space left in packet buffer\n"); - gnrc_pktbuf_release(pkt); - return NULL; - } - gnrc_netif_hdr_t *hdr = netif_snip->data; - hdr->lqi = rx_info.lqi; - hdr->rssi = rx_info.rssi; - gnrc_netif_hdr_set_netif(hdr, netif); - LL_APPEND(pkt, netif_snip); - } - else { - /* Normal mode, try to parse the frame according to IEEE 802.15.4 */ - 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); - - /* nread was checked for <= 0 before so we can safely cast it to - * unsigned */ - if ((mhr_len == 0) || ((size_t)nread < mhr_len)) { - 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 -#ifdef MODULE_GNRC_NETIF_DEDUP - if (_already_received(netif, hdr, ieee802154_hdr->data)) { - gnrc_pktbuf_release(pkt); - gnrc_pktbuf_release(netif_hdr); - DEBUG("_recv_ieee802154: packet dropped by deduplication\n"); - return NULL; - } - memcpy(netif->last_pkt.src, gnrc_netif_hdr_get_src_addr(hdr), - hdr->src_l2addr_len); - netif->last_pkt.src_len = hdr->src_l2addr_len; - netif->last_pkt.seq = ieee802154_get_seq(ieee802154_hdr->data); -#endif /* MODULE_GNRC_NETIF_DEDUP */ - - hdr->lqi = rx_info.lqi; - hdr->rssi = rx_info.rssi; - gnrc_netif_hdr_set_netif(hdr, netif); - dev->driver->get(dev, NETOPT_PROTO, &pkt->type, sizeof(pkt->type)); -#if ENABLE_DEBUG - DEBUG("_recv_ieee802154: received packet from %s of length %u\n", - gnrc_netif_addr_to_str(gnrc_netif_hdr_get_src_addr(hdr), - hdr->src_l2addr_len, - src_str), - 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); - } else if (bytes_expected > 0) { - DEBUG("_recv_ieee802154: received frame is too short\n"); - dev->driver->recv(dev, NULL, bytes_expected, NULL); - } - - return pkt; + ieee802154_rf_rx_done(netif->dev); + return NULL; } -static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) +/* Implementation of netif_ieee802144 send function. + * This function sits on top of the IEEE802154 MAC layer. + * Note this functions is intended to be GNRC agnostic! */ +void netif_ieee802154_send(netif_t *netif, netif_pkt_t *pkt) { - netdev_t *dev = netif->dev; - netdev_ieee802154_t *state = (netdev_ieee802154_t *)netif->dev; - gnrc_netif_hdr_t *netif_hdr; - const uint8_t *src, *dst = NULL; - int res = 0; + //const uint8_t *src, *dst = NULL; + uint8_t *src, *dst = NULL; size_t 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; - if (netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_MORE_DATA) { - /* Set frame pending field */ - flags |= IEEE802154_FCF_FRAME_PEND; - } /* prepare destination address */ - if (netif_hdr->flags & /* If any of these flags is set assume broadcast */ + if (pkt->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 = (uint8_t*) 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; + dst = pkt->dst_l2addr; + dst_len = pkt->dst_l2addr_len; } - src_len = netif_hdr->src_l2addr_len; + src_len = pkt->src_l2addr_len; if (src_len > 0) { - src = gnrc_netif_hdr_get_src_addr(netif_hdr); + src = pkt->src_l2addr; } 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; + src_len = ((gnrc_netif_t*) netif)->l2addr_len; + src = ((gnrc_netif_t*) netif)->l2addr; } - /* prepare iolist for netdev / mac layer */ - iolist_t iolist = { - .iol_next = (iolist_t *)pkt->next, - .iol_base = mhr, - .iol_len = (size_t)res - }; - #ifdef MODULE_NETSTATS_L2 if (netif_hdr->flags & (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) { @@ -286,19 +91,65 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) netif->stats.tx_unicast_count++; } #endif -#ifdef MODULE_GNRC_MAC - if (netif->mac.mac_info & GNRC_NETIF_MAC_INFO_CSMA_ENABLED) { - res = csma_sender_csma_ca_send(dev, &iolist, &netif->mac.csma_conf); + + + gnrc_netif_t *gnrc_netif = (gnrc_netif_t*) netif; + /* We don't need any MAC interface here since we know gnrc_netif_ieee802154 + * talks to a IEEE802.15.4 MAC layer... */ + ieee802154_mac_send((netdev_ieee802154_t*) gnrc_netif->dev, &pkt->msdu, pkt->flags & GNRC_NETIF_HDR_FLAGS_MORE_DATA, + src, src_len, dst, dst_len); + + /* This is usually handled by the MAC layer. + * But anyway, we release the old data */ + netbuf_free(pkt->ctx); +} + +/* Send a `netif_pkt` via the given interface- + * + * Note this function is GNRC independent! + */ +void netif_send(netif_t *netif, netif_pkt_t *pkt) +{ + /* Of course, this will be: + * netif->ops->send(netif, pkt); */ + netif_ieee802154_send(netif, pkt); /* We use this one, since there's no netif->ops yet :( */ +} + +/* Function to be called when GNRC needs to send a + * pkt snip that contains the netif hdr. + * + * This function should build the `netif_pkt` and + * call the `netif_send` function. From there, all + * functions are GNRC independent. + */ +int gnrc_netif_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) +{ + /* ========== BEGIN GNRC_NETIF_GLUE_CODE ========== */ + gnrc_netif_hdr_t *netif_hdr; + netif_pkt_t netif_pkt = {0}; + + if (pkt->type != GNRC_NETTYPE_NETIF) { + DEBUG("_send_ieee802154: first header is not generic netif header\n"); + return -EBADMSG; } - else { - res = dev->driver->send(dev, &iolist); + if (pkt == NULL) { + DEBUG("_send_ieee802154: pkt was NULL\n"); + return -EINVAL; } -#else - res = dev->driver->send(dev, &iolist); -#endif - /* release old data */ - gnrc_pktbuf_release(pkt); - return res; + netif_hdr = pkt->data; + + netif_pkt.flags = netif_hdr->flags; + netif_pkt.src_l2addr = gnrc_netif_hdr_get_src_addr(netif_hdr); + netif_pkt.src_l2addr_len = netif_hdr->src_l2addr_len; + netif_pkt.dst_l2addr = gnrc_netif_hdr_get_dst_addr(netif_hdr); + netif_pkt.dst_l2addr_len = netif_hdr->dst_l2addr_len; + memcpy(&netif_pkt.msdu, pkt->next, sizeof(iolist_t)); + netif_pkt.ctx = pkt; + + /* We call this function to send the packet via the interface */ + netif_send((netif_t*) netif, &netif_pkt); + /* ========== END GNRC_NETIF_GLUE_CODE ========== */ + return 0; } /** @} */ diff --git a/sys/net/link_layer/ieee802154/ieee802154.c b/sys/net/link_layer/ieee802154/ieee802154.c index ae687703d683..79a2a2002df9 100644 --- a/sys/net/link_layer/ieee802154/ieee802154.c +++ b/sys/net/link_layer/ieee802154/ieee802154.c @@ -17,7 +17,12 @@ #include #include +#include "net/netbuf.h" + #include "net/ieee802154.h" +#include "net/netdev/ieee802154.h" + +#include "net/gnrc/netif.h" const uint8_t ieee802154_addr_bcast[IEEE802154_ADDR_BCAST_LEN] = IEEE802154_ADDR_BCAST; diff --git a/sys/net/link_layer/ieee802154/ieee802154_mac.c b/sys/net/link_layer/ieee802154/ieee802154_mac.c new file mode 100644 index 000000000000..696b0475b275 --- /dev/null +++ b/sys/net/link_layer/ieee802154/ieee802154_mac.c @@ -0,0 +1,186 @@ +#include "net/netdev/ieee802154.h" +#include "net/netbuf.h" +#include "net/netif.h" +#include "net/gnrc/netif.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Receive function of the IEEE802.15.4 MAC. + * This function parses the packet and does handles MAC duties + * (packet filtering, handle ACK, security, etc). + * + * This function interacts with the IEEE802.15.4 PHY (represented by + * the `netdev_ieee802154_t` structure). + * + * It will generate a MAC indication with the MSDU (MAC Service Data Unit, + * L2 payload) and L2 information (source and destination addresses, + * frame pending, etc). + */ +void ieee802154_mac_recv(netdev_ieee802154_t *dev, ieee802154_phy_ind_t *ind) +{ + ieee802154_mac_ind_t mac_ind; + if (ind->psdu_len < (int)IEEE802154_MIN_FRAME_LEN) { + DEBUG("_recv_ieee802154: received frame is too short\n"); + netbuf_free(ind->ctx); + return; + } + + /* Normal mode, try to parse the frame according to IEEE 802.15.4 */ +#if ENABLE_DEBUG + char src_str[GNRC_NETIF_HDR_L2ADDR_PRINT_LEN]; +#endif + uint8_t *mhr = ind->psdu; + size_t mhr_len = ieee802154_get_frame_hdr_len(mhr); + + /* nread was checked for <= 0 before so we can safely cast it to + * unsigned */ + if ((mhr_len == 0) || ((size_t)ind->psdu_len < mhr_len)) { + DEBUG("_recv_ieee802154: illegally formatted frame received\n"); + netbuf_free(ind->ctx); + return; + } + /* mark IEEE 802.15.4 header */ + mac_ind.msdu.iol_base = mhr + mhr_len; + mac_ind.msdu.iol_len = ind->psdu_len-mhr_len; + + 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"); + netbuf_free(ind->ctx); + return; + } + mac_ind.src = src; + mac_ind.src_len = src_len; + mac_ind.dst = dst; + mac_ind.dst_len = dst_len; + +#ifdef MODULE_L2FILTER + if (!l2filter_pass(dev->filter, src, + src_len)) { + netbuf_free(ind->ctx); + DEBUG("_recv_ieee802154: packet dropped by l2filter\n"); + return NULL; + } +#endif +#ifdef MODULE_GNRC_NETIF_DEDUP + /* NOTE!!: This should be implemented by the IEEE802.15.4 layer! */ + const uint8_t seq = ieee802154_get_seq(mhr); + + int received = (netif->last_pkt.seq == seq) && + (netif->last_pkt.src_len == src_len) && + (memcmp(netif->last_pkt.src, src, + src_len) == 0); + + if (received) { + netbuf_free(ind->ctx); + DEBUG("_recv_ieee802154: packet dropped by deduplication\n"); + return NULL; + } + + memcpy(netif->last_pkt.src, src, + src_len); + netif->last_pkt.src_len = src_len; + netif->last_pkt.seq = ieee802154_get_seq(mhr); +#endif /* MODULE_GNRC_NETIF_DEDUP */ + + /* IEEE802.15.4 indication with L1 + L2 data */ + /* We could think of having an interface here + * E.g ieee802154_mac->ind(dev, &mac_ind, ind) + */ + ieee802154_mac_ind(dev, &mac_ind, ind); +} + +/* Implementation of the PHY indication. + * This PHY indication implementation checks if the packet has to be processed + * by the IEEE802.15.4 MAC layer. If so, it calls the receive function + * of the IEEE802.15.4 MAC. Otherwise, it calls `netif_recv` directly + * with the `netif_pkt`. + * + * Note the PHY indication contains all the data required by the MAC layer + * (PSDU, RSSI, LQI, etc). + */ +void ieee802154_phy_ind(netdev_t *netdev, ieee802154_phy_ind_t *ind) +{ +#ifdef MODULE_NETSTATS_L2 + netif->stats.rx_count++; + netif->stats.rx_bytes += nread; +#endif + + if (((gnrc_netif_t*) netdev->context)->flags & GNRC_NETIF_FLAGS_RAWMODE) { + /* Raw mode, skip packet processing, but provide rx_info via + * GNRC_NETTYPE_NETIF */ + netif_pkt_t pkt = {0}; + pkt.lqi = ind->lqi; + pkt.rssi = ind->rssi; + pkt.ctx = ind->ctx; + pkt.msdu.iol_base = ind->psdu; + pkt.msdu.iol_len = ind->psdu_len; + if(!netif_recv((netif_t*) netdev->context, &pkt)) { + netbuf_free(ind->ctx); + } + } + else { + ieee802154_mac_recv((netdev_ieee802154_t*) netdev, ind); + } +} + +/* IEEE802.15.4 send function. + * Note this functions is GNRC independent! + * + * This function interacts with the PHY layer (represented by + * `netdev_ieee802154_t`) in order to send a IEEE802.15.4 packet + */ +int ieee802154_mac_send(netdev_ieee802154_t *netdev, iolist_t *msdu, int frame_pending, + uint8_t *src, size_t src_len, uint8_t *dst, size_t dst_len) +{ + netdev_ieee802154_t *state = netdev; + netdev_t *dev = &netdev->netdev; + + int res = 0; + uint8_t mhr[IEEE802154_MAX_HDR_LEN]; + le_uint16_t dev_pan = byteorder_btols(byteorder_htons(state->pan)); + uint8_t flags = (uint8_t)(state->flags & NETDEV_IEEE802154_SEND_MASK); + + flags |= IEEE802154_FCF_TYPE_DATA; + + if (frame_pending) { + /* Set frame pending field */ + flags |= IEEE802154_FCF_FRAME_PEND; + } + /* 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 iolist for netdev / mac layer */ + iolist_t iolist = { + .iol_next = msdu, + .iol_base = mhr, + .iol_len = (size_t)res + }; + +#ifdef MODULE_GNRC_MAC + if (netif->mac.mac_info & GNRC_NETIF_MAC_INFO_CSMA_ENABLED) { + res = csma_sender_csma_ca_send(dev, &iolist, &netif->mac.csma_conf); + } + else { + res = dev->driver->send(dev, &iolist); + } +#else + /* We call our PHY layer send function */ + res = dev->driver->send(dev, &iolist); +#endif + + return res; +} + diff --git a/sys/net/link_layer/ieee802154/ieee802154_netif.c b/sys/net/link_layer/ieee802154/ieee802154_netif.c new file mode 100644 index 000000000000..de7169894d79 --- /dev/null +++ b/sys/net/link_layer/ieee802154/ieee802154_netif.c @@ -0,0 +1,56 @@ +#include "net/netdev.h" +#include "net/netdev/ieee802154.h" +#include "net/netif.h" +#include "net/gnrc/netif.h" +#include "net/gnrc/netif/hdr.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Implementation of the MAC indication. + * This function generates the `netif_pkt` from the MAC layer output, + * and calls the `netif_recv` function. + */ +void ieee802154_mac_ind(netdev_ieee802154_t *netdev, ieee802154_mac_ind_t *ind, ieee802154_phy_ind_t *phy_ind) +{ + netif_pkt_t pkt = {0}; + + /* set broadcast flag for broadcast destination */ + if ((ind->dst_len == 2) && (ind->dst[0] == 0xff) && (ind->dst[1] == 0xff)) { + pkt.flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST; + } + + /* set flags for pending frames */ + if (ind->frame_pending & IEEE802154_FCF_FRAME_PEND) { + pkt.flags |= GNRC_NETIF_HDR_FLAGS_MORE_DATA; + } + + pkt.lqi = phy_ind->lqi; + pkt.rssi = phy_ind->rssi; + pkt.ctx = phy_ind->ctx; + pkt.msdu = ind->msdu; + pkt.src_l2addr = ind->src; + pkt.src_l2addr_len = ind->src_len; + pkt.dst_l2addr = ind->dst; + pkt.dst_l2addr_len = ind->dst_len; + +#if ENABLE_DEBUG + DEBUG("_recv_ieee802154: received packet from %s of length %u\n", + gnrc_netif_addr_to_str(src, + src_len, + src_str), + pkt.msdu.iol_len); +#if defined(MODULE_OD) + od_hex_dump(mhr, pkt.msdu.iol_len, OD_WIDTH_DEFAULT); +#endif +#endif + + netif_t *netif = ((netdev_t*) netdev)->context; + + /* We call the `netif_recv` function to pass the packet + * to the stack. If the stack doesn't want the packet, + * we release it via the netbuf API. */ + if(!netif_recv(netif, &pkt)) { + netbuf_free(phy_ind->ctx); + } +} diff --git a/sys/net/link_layer/ieee802154/ieee802154_phy.c b/sys/net/link_layer/ieee802154/ieee802154_phy.c new file mode 100644 index 000000000000..800a4a261bb0 --- /dev/null +++ b/sys/net/link_layer/ieee802154/ieee802154_phy.c @@ -0,0 +1,57 @@ +#include "net/netdev.h" +#include "net/netdev/ieee802154.h" + +#include "net/netbuf.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* The transceiver HAL will call this function when there's a packet + * in the framebuffer of the transceiver. The role of the PHY layer + * is to use the transceiver HAL and the netbuf API to: + * - Allocate a buffer from the network stack + * - Read L1 data (LQI, RSSI, etc). + * - Generate a PHY indication with the packet + L1 data. + * + * Here we use some components of `netdev` as our transceiver + * HAL. + * Note this function is the same for all IEEE802154 devices, + * as seen, we reuse the PHY layer for those :) + */ +void ieee802154_rf_rx_done(netdev_t *dev) +{ + netdev_ieee802154_rx_info_t rx_info; + int bytes_expected = dev->driver->recv(dev, NULL, 0, NULL); + ieee802154_phy_ind_t ind = {0}; + + void *psdu = netbuf_get(bytes_expected, &ind.ctx); + + if (psdu == NULL) { + DEBUG("_recv_ieee802154: cannot allocate netbuf.\n"); + + /* Discard packet on netdev device */ + dev->driver->recv(dev, NULL, bytes_expected, NULL); + return; + } + + int nread = dev->driver->recv(dev, psdu, bytes_expected, &rx_info); + + if (nread <= 0) { + netbuf_free(ind.ctx); + return; + } + + /* Here we populate the indication with the Physical Service + * Data Unit (PSDU, full L2 frame), allocation context and + * L1 info + */ + ind.lqi = rx_info.lqi; + ind.rssi = rx_info.rssi; + ind.psdu = psdu; + ind.psdu_len = nread; + + /* We have to decide if we need an interface here + * E.g ieee802154_phy->ind(dev, &ind); */ + ieee802154_phy_ind(dev, &ind); +} +