1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/net/gnrc/link_layer/lwmac/lwmac_internal.c
smlng 6d0384f068 netstats: collect layer 2 netstats in gnrc_netif
This the first step in moving the collection of layer 2 netstats from
the low level driver to a central location, ie. gnrc_netif, to avoid
code duplication.
2019-02-01 10:35:03 +02:00

274 lines
8.9 KiB
C

/*
* Copyright (C) 2015 Daniel Krebs
* 2016 INRIA
*
* 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_lwmac
* @{
*
* @file
* @brief Implementation of internal functions of LWMAC
*
* @author Daniel Krebs <github@daniel-krebs.net>
* @author Shuguo Zhuo <shuguo.zhuo@inria.fr>
* @}
*/
#include <stdbool.h>
#include "periph/rtt.h"
#include "net/gnrc.h"
#include "net/gnrc/mac/mac.h"
#include "net/gnrc/lwmac/lwmac.h"
#include "include/lwmac_internal.h"
#include "net/gnrc/netif/ieee802154.h"
#include "net/netdev/ieee802154.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
int _gnrc_lwmac_transmit(gnrc_netif_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;
const uint8_t *src, *dst = NULL;
int res = 0;
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;
/* 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 */
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)) {
netif->stats.tx_mcast_count++;
}
else {
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);
}
else {
res = dev->driver->send(dev, &iolist);
}
#else
res = dev->driver->send(dev, &iolist);
#endif
/* release old data */
gnrc_pktbuf_release(pkt);
return res;
}
int _gnrc_lwmac_parse_packet(gnrc_pktsnip_t *pkt, gnrc_lwmac_packet_info_t *info)
{
gnrc_netif_hdr_t *netif_hdr;
gnrc_pktsnip_t *lwmac_snip;
gnrc_lwmac_hdr_t *lwmac_hdr;
assert(info != NULL);
assert(pkt != NULL);
netif_hdr = (gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF))->data;
if (netif_hdr == NULL) {
return -1;
}
/* Dissect LWMAC header, Every frame has header as first member */
lwmac_hdr = (gnrc_lwmac_hdr_t *) pkt->data;
switch (lwmac_hdr->type) {
case GNRC_LWMAC_FRAMETYPE_WR: {
lwmac_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_lwmac_frame_wr_t),
GNRC_NETTYPE_LWMAC);
break;
}
case GNRC_LWMAC_FRAMETYPE_WA: {
lwmac_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_lwmac_frame_wa_t),
GNRC_NETTYPE_LWMAC);
break;
}
case GNRC_LWMAC_FRAMETYPE_DATA_PENDING:
case GNRC_LWMAC_FRAMETYPE_DATA: {
lwmac_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_lwmac_frame_data_t),
GNRC_NETTYPE_LWMAC);
break;
}
case GNRC_LWMAC_FRAMETYPE_BROADCAST: {
lwmac_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_lwmac_frame_broadcast_t),
GNRC_NETTYPE_LWMAC);
break;
}
default: {
return -2;
}
}
/* Memory location may have changed while marking */
lwmac_hdr = lwmac_snip->data;
if (lwmac_hdr->type == GNRC_LWMAC_FRAMETYPE_WA) {
/* WA is broadcast, so get dst address out of header instead of netif */
info->dst_addr = ((gnrc_lwmac_frame_wa_t *)lwmac_hdr)->dst_addr;
}
else if (lwmac_hdr->type == GNRC_LWMAC_FRAMETYPE_WR) {
/* WR is broadcast, so get dst address out of header instead of netif */
info->dst_addr = ((gnrc_lwmac_frame_wr_t *)lwmac_hdr)->dst_addr;
}
else if (netif_hdr->dst_l2addr_len) {
info->dst_addr.len = netif_hdr->dst_l2addr_len;
memcpy(info->dst_addr.addr,
gnrc_netif_hdr_get_dst_addr(netif_hdr),
netif_hdr->dst_l2addr_len);
}
if (netif_hdr->src_l2addr_len) {
info->src_addr.len = netif_hdr->src_l2addr_len;
memcpy(info->src_addr.addr,
gnrc_netif_hdr_get_src_addr(netif_hdr),
netif_hdr->src_l2addr_len);
}
info->header = lwmac_hdr;
return 0;
}
void _gnrc_lwmac_set_netdev_state(gnrc_netif_t *netif, netopt_state_t devstate)
{
netif->dev->driver->set(netif->dev,
NETOPT_STATE,
&devstate,
sizeof(devstate));
#if (GNRC_MAC_ENABLE_DUTYCYCLE_RECORD == 1)
if (devstate == NETOPT_STATE_IDLE) {
if (!(netif->mac.prot.lwmac.lwmac_info & GNRC_LWMAC_RADIO_IS_ON)) {
netif->mac.prot.lwmac.last_radio_on_time_ticks = rtt_get_counter();
netif->mac.prot.lwmac.lwmac_info |= GNRC_LWMAC_RADIO_IS_ON;
}
return;
}
else if ((devstate == NETOPT_STATE_SLEEP) &&
(netif->mac.prot.lwmac.lwmac_info & GNRC_LWMAC_RADIO_IS_ON)) {
netif->mac.prot.lwmac.radio_off_time_ticks = rtt_get_counter();
netif->mac.prot.lwmac.awake_duration_sum_ticks +=
(netif->mac.prot.lwmac.radio_off_time_ticks -
netif->mac.prot.lwmac.last_radio_on_time_ticks);
netif->mac.prot.lwmac.lwmac_info &= ~GNRC_LWMAC_RADIO_IS_ON;
}
#endif
}
netopt_state_t _gnrc_lwmac_get_netdev_state(gnrc_netif_t *netif)
{
netopt_state_t state;
if (0 < netif->dev->driver->get(netif->dev,
NETOPT_STATE,
&state,
sizeof(state))) {
return state;
}
return -1;
}
int _gnrc_lwmac_dispatch_defer(gnrc_pktsnip_t *buffer[], gnrc_pktsnip_t *pkt)
{
assert(buffer != NULL);
assert(pkt != NULL);
/* We care about speed here, so assume packet structure */
assert(pkt->next->type == GNRC_NETTYPE_LWMAC);
assert(pkt->next->next->type == GNRC_NETTYPE_NETIF);
gnrc_lwmac_frame_broadcast_t *bcast = NULL;
if (((gnrc_lwmac_hdr_t *)pkt->next->data)->type == GNRC_LWMAC_FRAMETYPE_BROADCAST) {
bcast = pkt->next->data;
}
for (unsigned i = 0; i < GNRC_MAC_DISPATCH_BUFFER_SIZE; i++) {
/* Buffer will be filled bottom-up and emptied completely so no holes */
if (buffer[i] == NULL) {
buffer[i] = pkt;
return 0;
}
else if (bcast &&
(((gnrc_lwmac_hdr_t *)buffer[i]->next->data)->type == GNRC_LWMAC_FRAMETYPE_BROADCAST) &&
(bcast->seq_nr == ((gnrc_lwmac_frame_broadcast_t *)buffer[i]->next->data)->seq_nr)) {
/* Filter same broadcasts, compare sequence number */
gnrc_netif_hdr_t *hdr_queued, *hdr_new;
hdr_new = pkt->next->next->data;
hdr_queued = buffer[i]->next->next->data;
/* Sequence numbers match, compare source addresses */
if ((hdr_new->src_l2addr_len == hdr_queued->src_l2addr_len) &&
(memcmp(gnrc_netif_hdr_get_src_addr(hdr_new),
gnrc_netif_hdr_get_src_addr(hdr_queued),
hdr_new->src_l2addr_len) == 0)) {
/* Source addresses match, same packet */
DEBUG("[LWMAC] Found duplicate broadcast packet, dropping\n");
gnrc_pktbuf_release(pkt);
return -2;
}
}
}
DEBUG("[LWMAC] Dispatch buffer full, dropping packet\n");
gnrc_pktbuf_release(pkt);
return -1;
}