1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/net/gnrc/netif/gnrc_netif_ieee802154.c

255 lines
8.1 KiB
C
Raw Normal View History

2017-07-25 19:53:53 +02:00
/*
* 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 <m.lenders@fu-berlin.de>
*/
#include "net/gnrc.h"
2017-11-16 18:06:46 +01:00
#include "net/gnrc/netif/ieee802154.h"
2017-07-25 19:53:53 +02:00
#include "net/netdev/ieee802154.h"
#ifdef MODULE_GNRC_IPV6
#include "net/ipv6/hdr.h"
#endif
#define ENABLE_DEBUG (0)
#include "debug.h"
2017-12-05 14:41:35 +01:00
#if defined(MODULE_OD) && ENABLE_DEBUG
#include "od.h"
#endif
2017-07-25 19:53:53 +02:00
#ifdef MODULE_NETDEV_IEEE802154
2017-11-16 18:06:46 +01:00
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt);
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif);
2017-07-25 19:53:53 +02:00
2017-11-16 18:06:46 +01:00
static const gnrc_netif_ops_t ieee802154_ops = {
2017-07-25 19:53:53 +02:00
.send = _send,
.recv = _recv,
2017-11-16 18:06:46 +01:00
.get = gnrc_netif_get_from_netdev,
.set = gnrc_netif_set_from_netdev,
2017-07-25 19:53:53 +02:00
};
2017-11-16 18:06:46 +01:00
gnrc_netif_t *gnrc_netif_ieee802154_create(char *stack, int stacksize,
char priority, char *name,
netdev_t *dev)
2017-07-25 19:53:53 +02:00
{
2017-11-16 18:06:46 +01:00
return gnrc_netif_create(stack, stacksize, priority, name, dev,
&ieee802154_ops);
2017-07-25 19:53:53 +02:00
}
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;
}
2017-11-16 18:06:46 +01:00
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif)
2017-07-25 19:53:53 +02:00
{
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 >= (int)IEEE802154_MIN_FRAME_LEN) {
2017-07-25 19:53:53 +02:00
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);
2017-07-25 19:53:53 +02:00
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(gnrc_netif_hdr_get_src_addr(hdr),
hdr->src_l2addr_len,
src_str),
2017-07-25 19:53:53 +02:00
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);
2017-07-25 19:53:53 +02:00
}
return pkt;
}
2017-11-16 18:06:46 +01:00
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
2017-07-25 19:53:53 +02:00
{
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;
size_t src_len, dst_len;
2017-07-25 19:53:53 +02:00
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;
}
2017-07-25 19:53:53 +02:00
/* 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 iolist for netdev / mac layer */
iolist_t iolist = {
.iol_next = (iolist_t *)pkt->next,
.iol_base = mhr,
.iol_len = (size_t)res
};
2017-07-25 19:53:53 +02:00
#ifdef MODULE_NETSTATS_L2
2017-11-17 10:25:17 +01:00
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++;
}
2017-07-25 19:53:53 +02:00
#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);
2017-07-25 19:53:53 +02:00
}
else {
res = dev->driver->send(dev, &iolist);
2017-07-25 19:53:53 +02:00
}
#else
res = dev->driver->send(dev, &iolist);
#endif
2017-07-25 19:53:53 +02:00
/* release old data */
gnrc_pktbuf_release(pkt);
return res;
}
#else /* MODULE_NETDEV_IEEE802154 */
typedef int dont_be_pedantic;
#endif /* MODULE_NETDEV_IEEE802154 */
/** @} */