mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
193 lines
6.4 KiB
C
193 lines
6.4 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/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;
|
||
|
}
|