/* * 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 * @author Shuguo Zhuo * @} */ #include #include "periph/rtt.h" #include "net/gnrc.h" #include "net/gnrc/mac/mac.h" #include "net/gnrc/netdev.h" #include "net/gnrc/lwmac/lwmac.h" #include "include/lwmac_internal.h" #define ENABLE_DEBUG (0) #include "debug.h" 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_netdev_t *gnrc_netdev, netopt_state_t devstate) { gnrc_netdev->dev->driver->set(gnrc_netdev->dev, NETOPT_STATE, &devstate, sizeof(devstate)); #if (GNRC_LWMAC_ENABLE_DUTYCYLE_RECORD == 1) if (devstate == NETOPT_STATE_IDLE) { if (!(gnrc_netdev->lwmac.lwmac_info & GNRC_LWMAC_RADIO_IS_ON)) { gnrc_netdev->lwmac.last_radio_on_time_ticks = rtt_get_counter(); gnrc_netdev->lwmac.lwmac_info |= GNRC_LWMAC_RADIO_IS_ON; } return; } else if ((devstate == NETOPT_STATE_SLEEP) && (gnrc_netdev->lwmac.lwmac_info & GNRC_LWMAC_RADIO_IS_ON)) { gnrc_netdev->lwmac.radio_off_time_ticks = rtt_get_counter(); gnrc_netdev->lwmac.awake_duration_sum_ticks += (gnrc_netdev->lwmac.radio_off_time_ticks - gnrc_netdev->lwmac.last_radio_on_time_ticks); gnrc_netdev->lwmac.lwmac_info &= ~GNRC_LWMAC_RADIO_IS_ON; } #endif } netopt_state_t _gnrc_lwmac_get_netdev_state(gnrc_netdev_t *gnrc_netdev) { netopt_state_t state; if (0 < gnrc_netdev->dev->driver->get(gnrc_netdev->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; }