/* * 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 * @{ * * @file * @brief GNRC to netdev adapter for XBee devices * * @author Hauke Petersen * * @} */ #include "assert.h" #include "xbee.h" #include "net/gnrc.h" #include "net/gnrc/netdev/xbee_adpt.h" #define ENABLE_DEBUG (0) #include "debug.h" #define BCAST (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST) static gnrc_pktsnip_t *xbee_adpt_recv(gnrc_netdev_t *gnrc_netdev) { netdev_t *dev = gnrc_netdev->dev; int pktlen; int xhdr_len; gnrc_pktsnip_t *payload; gnrc_pktsnip_t *netif_snip; gnrc_pktsnip_t *xhdr_snip; gnrc_netif_hdr_t *netif; xbee_l2hdr_t l2hdr; assert(dev); /* see how much data there is to process */ pktlen = dev->driver->recv(dev, NULL, 0, NULL); if (pktlen <= 0) { DEBUG("[xbee-gnrc] recv: no data available to process\n"); return NULL; } /* allocate space for the packet in the pktbuf */ payload = gnrc_pktbuf_add(NULL, NULL, pktlen, XBEE_DEFAULT_PROTOCOL); if (payload == NULL) { DEBUG("[xbee-gnrc] recv: unable to allocate space in the pktbuf\n"); /* tell the driver to drop the packet */ dev->driver->recv(dev, NULL, 1, NULL); return NULL; } /* copy the complete including the XBee header into the packet buffer */ dev->driver->recv(dev, payload->data, pktlen, NULL); /* try to parse the L2 header data from the XBee header */ xhdr_len = xbee_parse_hdr((xbee_t *)dev, (uint8_t *)payload->data, &l2hdr); if (xhdr_len < 0) { DEBUG("[xbee-gnrc] recv: unable to parse XBee header\n"); gnrc_pktbuf_release(payload); return NULL; } /* crop the XBee header from the payload */ xhdr_snip = gnrc_pktbuf_mark(payload, xhdr_len, GNRC_NETTYPE_UNDEF); if (xhdr_snip == NULL) { DEBUG("[xbee-gnrc] recv: unable to mark XBee header snip\n"); gnrc_pktbuf_release(payload); return NULL; } gnrc_pktbuf_remove_snip(payload, xhdr_snip); /* create a netif hdr from the obtained data */ netif_snip = gnrc_netif_hdr_build(l2hdr.src_addr, l2hdr.addr_len, l2hdr.dst_addr, l2hdr.addr_len); if (netif_snip == NULL) { DEBUG("[xbee-gnrc] recv: unable to allocate netif header\n"); gnrc_pktbuf_release(payload); return NULL; } netif = (gnrc_netif_hdr_t *)netif_snip->data; netif->if_pid = gnrc_netdev->pid; netif->rssi = l2hdr.rssi; if (l2hdr.bcast) { netif->flags = GNRC_NETIF_HDR_FLAGS_BROADCAST; } DEBUG("[xbee-gnrc] recv: successfully parsed packet\n"); /* and append the netif header */ LL_APPEND(payload, netif_snip); return payload; } static int xbee_adpt_send(gnrc_netdev_t *dev, gnrc_pktsnip_t *pkt) { int res; size_t size; size_t count; gnrc_pktsnip_t *vec; gnrc_netif_hdr_t *hdr; uint8_t xhdr[XBEE_MAX_TXHDR_LENGTH]; /* check device descriptor and packet */ assert(dev && pkt); /* get the payload size and the dst address details */ size = gnrc_pkt_len(pkt->next); DEBUG("[xbee-gnrc] send: payload of packet is %i\n", (int)size); hdr = (gnrc_netif_hdr_t *)pkt->data; if (hdr->flags & BCAST) { uint16_t addr = 0xffff; res = xbee_build_hdr((xbee_t *)dev, xhdr, size, &addr, 2); DEBUG("[xbee-gnrc] send: preparing to send broadcast\n"); } else { uint8_t *addr = gnrc_netif_hdr_get_dst_addr(hdr); res = xbee_build_hdr((xbee_t *)dev, xhdr, size, addr, hdr->dst_l2addr_len); if (res < 0) { if (res == -EOVERFLOW) { DEBUG("[xbee-gnrc] send: payload length exceeds max limit\n"); } else if (res == -ENOMSG) { DEBUG("[xbee-gnrc] send: invalid destination l2 address\n"); } return res; } if (hdr->dst_l2addr_len == IEEE802154_SHORT_ADDRESS_LEN) { DEBUG("[xbee-gnrc] send: preparing to send unicast to %02x:%02x\n", (int)addr[0], (int)addr[1]); } else { DEBUG("[xbee-gnrc] send: preparing to send unicast to " "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", (int)addr[0], (int)addr[1], (int)addr[2], (int)addr[3], (int)addr[4], (int)addr[5], (int)addr[6], (int)addr[7]); } } /* now let's extract the iovector and send out the stuff */ vec = gnrc_pktbuf_get_iovec(pkt, &count); if (vec != NULL) { pkt = vec; struct iovec *vector = (struct iovec *)pkt->data; vector[0].iov_base = xhdr; vector[0].iov_len = res; #ifdef MODULE_NETSTATS_L2 if (hdr->flags & BCAST) { dev->dev->stats.tx_mcast_count++; } else { dev->dev->stats.tx_unicast_count++; } #endif DEBUG("[xbee-gnrc] send: triggering the drivers send function\n"); res = dev->dev->driver->send(dev->dev, vector, count); } else { DEBUG("[xbee-gnrc] send: unable to create iovec\n"); } gnrc_pktbuf_release(pkt); return res; } void gnrc_netdev_xbee_init(gnrc_netdev_t *gnrc_netdev, xbee_t *dev) { assert(gnrc_netdev && dev); gnrc_netdev->send = xbee_adpt_send; gnrc_netdev->recv = xbee_adpt_recv; gnrc_netdev->dev = (netdev_t *)dev; }