1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 04:52:59 +01:00

ng_sixlowpan: Initial import of datagram fragmentation

This commit is contained in:
Martine Lenders 2015-04-08 11:56:10 +02:00
parent 1d744650cf
commit 73d9739258
9 changed files with 828 additions and 2 deletions

View File

@ -48,6 +48,11 @@ ifneq (,$(filter sixlowpan,$(USEMODULE)))
USEMODULE += vtimer
endif
ifneq (,$(filter ng_sixlowpan_frag,$(USEMODULE)))
USEMODULE += ng_sixlowpan
USEMODULE += vtimer
endif
ifneq (,$(filter ng_sixlowpan,$(USEMODULE)))
USEMODULE += ng_sixlowpan_netif
USEMODULE += ng_netbase

View File

@ -101,6 +101,9 @@ endif
ifneq (,$(filter ng_sixlowpan_ctx,$(USEMODULE)))
DIRS += net/network_layer/ng_sixlowpan/ctx
endif
ifneq (,$(filter ng_sixlowpan_frag,$(USEMODULE)))
DIRS += net/network_layer/ng_sixlowpan/frag
endif
ifneq (,$(filter ng_sixlowpan_netif,$(USEMODULE)))
DIRS += net/network_layer/ng_sixlowpan/netif
endif

View File

@ -24,6 +24,8 @@
#include "kernel_types.h"
#include "net/ng_sixlowpan/frag.h"
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -0,0 +1,127 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* 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.
*/
/**
* @defgroup net_ng_sixlowpan_frag 6LoWPAN Fragmentation
* @ingroup net_ng_sixlowpan
* @brief 6LoWPAN Fragmentation headers and functionality
* @see <a href="https://tools.ietf.org/html/rfc4944#section-5.3">
* RFC 4944, section 5.3
* </a>
* @{
*
* @file
* @brief 6LoWPAN Fragmentation definitions
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NG_SIXLOWPAN_FRAG_H_
#define NG_SIXLOWPAN_FRAG_H_
#include <inttypes.h>
#include <stdbool.h>
#include "byteorder.h"
#include "kernel_types.h"
#include "net/ng_pkt.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NG_SIXLOWPAN_FRAG_DISP_MASK (0xf8) /**< mask for fragmentation
* dispatch */
#define NG_SIXLOWPAN_FRAG_1_DISP (0xc0) /**< dispatch for 1st fragment */
#define NG_SIXLOWPAN_FRAG_N_DISP (0xe0) /**< dispatch for subsequent
* fragments */
#define NG_SIXLOWPAN_FRAG_SIZE_MASK (0x07ff) /**< mask for datagram size */
/**
* @brief General and 1st 6LoWPAN fragmentation header
*
* @see <a href="https://tools.ietf.org/html/rfc4944#section-5.1">
* RFC 4944, section 5.1
* </a>
*/
typedef struct __attribute__((packed)) {
/**
* @brief Dispatch and datagram size.
*
* @details The 5 most significant bits are the dispatch, the remaining
* bits are the size.
*/
network_uint16_t disp_size;
network_uint16_t tag; /**< datagram tag */
} ng_sixlowpan_frag_t;
/**
* @brief Subsequent 6LoWPAN fragmentation header
*
* @see <a href="https://tools.ietf.org/html/rfc4944#section-5.3">
* RFC 4944, section 5.3
* </a>
*
* @extends ng_sixlowpan_frag_t
*/
typedef struct __attribute__((packed)) {
/**
* @brief Dispatch and datagram size.
*
* @details The 5 most significant bits are the dispatch, the remaining
* bits are the size.
*/
network_uint16_t disp_size;
network_uint16_t tag; /**< datagram tag */
uint8_t offset; /**< offset */
} ng_sixlowpan_frag_n_t;
/**
* @brief Checks if a given fragment is a 6LoWPAN fragment.
*
* @param[in] hdr A 6LoWPAN fragmentation header.
*
* @return true, if given fragment is a 6LoWPAN fragment.
* @return false, if given fragment is not a 6LoWPAN fragment.
*/
static inline bool ng_sixlowpan_frag_is(ng_sixlowpan_frag_t *hdr)
{
return ((hdr->disp_size.u8[0] & NG_SIXLOWPAN_FRAG_DISP_MASK) ==
NG_SIXLOWPAN_FRAG_1_DISP) ||
((hdr->disp_size.u8[0] & NG_SIXLOWPAN_FRAG_DISP_MASK) ==
NG_SIXLOWPAN_FRAG_N_DISP);
}
/**
* @brief Sends a packet fragmented.
*
* @param[in] pid The interface to send the packet over.
* @param[in] pkt The packet to send.
* @param[in] payload_len The length of the payload to send (IPv6 packet size
* + inner 6LoWPAN dispatches).
* This value is purely given to not calculate the
* payload length using @ref ng_pkt_len() repeatedly.
* @param[in] datagram_size The length of just the IPv6 packet. It is the value
* set that the ng_sixlowpan_frag_t::disp_size will be
* set to.
*/
void ng_sixlowpan_frag_send(kernel_pid_t pid, ng_pktsnip_t *pkt,
size_t payload_len, size_t datagram_size);
/**
* @brief Handles a packet containing a fragment header.
*
* @param[in] pkt The packet to handle.
*/
void ng_sixlowpan_frag_handle_pkt(ng_pktsnip_t *pkt);
#ifdef __cplusplus
}
#endif
#endif /* NG_SIXLOWPAN_FRAG_H_ */
/** @} */

View File

@ -0,0 +1,3 @@
MODULE = ng_sixlowpan_frag
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,264 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* 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
*/
#include "kernel_types.h"
#include "net/ng_pktbuf.h"
#include "net/ng_netapi.h"
#include "net/ng_netif/hdr.h"
#include "net/ng_sixlowpan/frag.h"
#include "net/ng_sixlowpan/netif.h"
#include "utlist.h"
#include "rbuf.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static uint16_t _tag;
static inline uint16_t _floor8(uint16_t length)
{
return length & 0xf8U;
}
static inline size_t _min(size_t a, size_t b)
{
return (a < b) ? a : b;
}
static ng_pktsnip_t *_build_frag_pkt(ng_pktsnip_t *pkt, size_t payload_len,
size_t size)
{
ng_netif_hdr_t *hdr = pkt->data, *new_hdr;
ng_pktsnip_t *netif, *frag;
netif = ng_netif_hdr_build(ng_netif_hdr_get_src_addr(hdr), hdr->src_l2addr_len,
ng_netif_hdr_get_dst_addr(hdr), hdr->dst_l2addr_len);
if (netif == NULL) {
DEBUG("6lo frag: error allocating new link-layer header\n");
return NULL;
}
new_hdr = netif->data;
new_hdr->if_pid = hdr->if_pid;
new_hdr->flags = hdr->flags;
new_hdr->rssi = hdr->rssi;
new_hdr->lqi = hdr->lqi;
frag = ng_pktbuf_add(NULL, NULL, _min(size, payload_len),
NG_NETTYPE_SIXLOWPAN);
if (frag == NULL) {
DEBUG("6lo frag: error allocating first fragment\n");
ng_pktbuf_release(netif);
return NULL;
}
LL_PREPEND(frag, netif);
return frag;
}
static uint16_t _send_1st_fragment(ng_sixlowpan_netif_t *iface, ng_pktsnip_t *pkt,
size_t payload_len, size_t datagram_size)
{
ng_pktsnip_t *frag;
uint16_t max_frag_size = _floor8(iface->max_frag_size -
(payload_len - datagram_size) -
sizeof(ng_sixlowpan_frag_t));
uint16_t local_offset = 0;
ng_sixlowpan_frag_t *hdr;
uint8_t *data;
DEBUG("6lo frag: determined max_frag_size = %" PRIu16 "\n", max_frag_size);
/* 6LoWPAN dispatches don't count into that */
max_frag_size += (payload_len - datagram_size);
frag = _build_frag_pkt(pkt, payload_len,
max_frag_size + sizeof(ng_sixlowpan_frag_t));
if (frag == NULL) {
return 0;
}
hdr = frag->next->data;
data = (uint8_t *)(hdr + 1);
hdr->disp_size = byteorder_htons((uint16_t)datagram_size);
hdr->disp_size.u8[0] |= NG_SIXLOWPAN_FRAG_1_DISP;
hdr->tag = byteorder_htons(_tag);
pkt = pkt->next; /* don't copy netif header */
while (pkt != NULL) {
size_t clen = _min(max_frag_size - local_offset, pkt->size);
memcpy(data + local_offset, pkt->data, clen);
local_offset += clen;
if (local_offset >= max_frag_size) {
break;
}
pkt = pkt->next;
}
DEBUG("6lo frag: send first fragment (datagram size: %u, "
"datagram tag: %" PRIu16 ", fragment size: %" PRIu16 ")\n",
(unsigned int)datagram_size, _tag, local_offset);
ng_netapi_send(iface->pid, frag);
return local_offset;
}
static uint16_t _send_nth_fragment(ng_sixlowpan_netif_t *iface, ng_pktsnip_t *pkt,
size_t payload_len, size_t datagram_size,
uint16_t offset)
{
ng_pktsnip_t *frag;
uint16_t max_frag_size = _floor8(iface->max_frag_size - sizeof(ng_sixlowpan_frag_n_t));
uint16_t local_offset = 0, offset_count = 0;
ng_sixlowpan_frag_n_t *hdr;
uint8_t *data;
DEBUG("6lo frag: determined max_frag_size = %" PRIu16 "\n", max_frag_size);
frag = _build_frag_pkt(pkt,
payload_len - offset + sizeof(ng_sixlowpan_frag_n_t),
max_frag_size + sizeof(ng_sixlowpan_frag_n_t));
if (frag == NULL) {
return 0;
}
hdr = frag->next->data;
data = (uint8_t *)(hdr + 1);
/* XXX: truncation of datagram_size > 4095 may happen here */
hdr->disp_size = byteorder_htons((uint16_t)datagram_size);
hdr->disp_size.u8[0] |= NG_SIXLOWPAN_FRAG_N_DISP;
hdr->tag = byteorder_htons(_tag);
hdr->offset = (uint8_t)(offset >> 3);
pkt = pkt->next; /* don't copy netif header */
while ((pkt != NULL) || (offset_count == offset)) { /* go to offset */
offset_count += (uint16_t)pkt->size;
if (offset_count > offset) { /* we overshot */
/* => copy rest of partly send packet snip */
uint16_t pkt_offset = offset - (offset_count - ((uint16_t)pkt->size));
size_t clen = _min(max_frag_size, pkt->size - pkt_offset);
memcpy(data, ((uint8_t *)pkt->data) + pkt_offset, clen);
local_offset = clen;
pkt = pkt->next;
break;
}
pkt = pkt->next;
}
if (local_offset < max_frag_size) { /* copy other packet snips */
while (pkt != NULL) {
size_t clen = _min(max_frag_size - local_offset, pkt->size);
memcpy(data + local_offset, pkt->data, clen);
local_offset += clen;
if (local_offset == max_frag_size) {
break;
}
pkt = pkt->next;
}
}
DEBUG("6lo frag: send first fragment (datagram size: %u, "
"datagram tag: %" PRIu16 ", offset: %" PRIu8 " (%u bytes), "
"fragment size: %" PRIu16 ")\n",
(unsigned int)datagram_size, _tag, hdr->offset, hdr->offset << 3,
local_offset);
ng_netapi_send(iface->pid, frag);
return local_offset;
}
void ng_sixlowpan_frag_send(kernel_pid_t pid, ng_pktsnip_t *pkt,
size_t payload_len, size_t datagram_size)
{
ng_sixlowpan_netif_t *iface = ng_sixlowpan_netif_get(pid);
uint16_t offset = 0, res;
#if defined(DEVELHELP) && defined(ENABLE_DEBUG)
if (iface == NULL) {
DEBUG("6lo frag: iface == NULL, expect segmentation fault.\n");
}
#endif
if ((res = _send_1st_fragment(iface, pkt, payload_len, datagram_size)) == 0) {
/* error sending first fragment */
ng_pktbuf_release(pkt);
return;
}
offset += res;
while (offset < datagram_size) {
if ((res = _send_nth_fragment(iface, pkt, payload_len, datagram_size,
offset)) == 0) {
/* error sending first fragment */
ng_pktbuf_release(pkt);
return;
}
offset += res;
}
/* remove original packet from packet buffer */
ng_pktbuf_release(pkt);
_tag++;
}
void ng_sixlowpan_frag_handle_pkt(ng_pktsnip_t *pkt)
{
ng_netif_hdr_t *hdr = pkt->next->data;
ng_sixlowpan_frag_t *frag = pkt->data;
uint16_t offset = 0;
size_t frag_size;
switch (frag->disp_size.u8[0] & NG_SIXLOWPAN_FRAG_DISP_MASK) {
case NG_SIXLOWPAN_FRAG_1_DISP:
frag_size = (pkt->size - sizeof(ng_sixlowpan_frag_t));
break;
case NG_SIXLOWPAN_FRAG_N_DISP:
offset = (((ng_sixlowpan_frag_n_t *)frag)->offset * 8);
frag_size = (pkt->size - sizeof(ng_sixlowpan_frag_n_t));
break;
default:
DEBUG("6lo rbuf: Not a fragment header.\n");
ng_pktbuf_release(pkt);
return;
}
rbuf_add(hdr, frag, frag_size, offset);
ng_pktbuf_release(pkt);
}
/** @} */

View File

@ -0,0 +1,307 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* 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
*/
#include <inttypes.h>
#include <stdbool.h>
#include "rbuf.h"
#include "net/ng_netapi.h"
#include "net/ng_netif.h"
#include "net/ng_netif/hdr.h"
#include "net/ng_pktbuf.h"
#include "net/ng_ipv6/netif.h"
#include "net/ng_sixlowpan.h"
#include "net/ng_sixlowpan/frag.h"
#include "thread.h"
#include "timex.h"
#include "vtimer.h"
#include "utlist.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#ifndef RBUF_INT_SIZE
#define RBUF_INT_SIZE (NG_IPV6_NETIF_DEFAULT_MTU * RBUF_SIZE / 127)
#endif
static rbuf_int_t rbuf_int[RBUF_INT_SIZE];
static rbuf_t rbuf[RBUF_SIZE];
#if ENABLE_DEBUG
static char l2addr_str[3 * RBUF_L2ADDR_MAX_LEN];
#endif
/* ------------------------------------
* internal function definitions
* ------------------------------------*/
/* checks whether start and end are in given interval i */
static inline bool _rbuf_int_in(rbuf_int_t *i, uint16_t start, uint16_t end);
/* gets a free entry from interval buffer */
static rbuf_int_t *_rbuf_int_get_free(void);
/* remove entry from reassembly buffer */
static void _rbuf_rem(rbuf_t *entry);
/* update interval buffer of entry */
static bool _rbuf_update_ints(rbuf_t *entry, uint16_t offset, size_t frag_size);
/* checks timeouts and removes entries if necessary (oldest if full) */
static void _rbuf_gc(void);
/* gets an entry identified by its tupel */
static rbuf_t *_rbuf_get(const void *src, size_t src_len,
const void *dst, size_t dst_len,
size_t size, uint16_t tag);
void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_sixlowpan_frag_t *frag,
size_t frag_size, size_t offset)
{
rbuf_t *entry;
rbuf_int_t *ptr;
uint8_t *data = ((uint8_t *)frag) + sizeof(ng_sixlowpan_frag_t);
_rbuf_gc();
entry = _rbuf_get(ng_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len,
ng_netif_hdr_get_dst_addr(netif_hdr), netif_hdr->dst_l2addr_len,
byteorder_ntohs(frag->disp_size) & NG_SIXLOWPAN_FRAG_SIZE_MASK,
byteorder_ntohs(frag->tag));
if (entry == NULL) {
DEBUG("6lo rbuf: reassembly buffer full.\n");
return;
}
ptr = entry->ints;
while (ptr != NULL) {
if (_rbuf_int_in(ptr, offset, offset + frag_size - 1)) {
DEBUG("6lo rfrag: overlapping or same intervals, discarding datagram\n");
ng_pktbuf_release(entry->pkt);
_rbuf_rem(entry);
return;
}
ptr = ptr->next;
}
if (_rbuf_update_ints(entry, offset, frag_size)) {
if (offset == 0) {
/* some dispatches do not count to datagram size and we need
* more space because of that */
switch (data[0]) {
case NG_SIXLOWPAN_UNCOMPRESSED:
if (ng_pktbuf_realloc_data(entry->pkt, entry->pkt->size + 1) < 0) {
DEBUG("6lo rbuf: could not reallocate packet data.\n");
return;
}
/* move already inserted fragments 1 to the right */
for (int i = entry->pkt->size - 1; i > 0; i--) {
uint8_t *d = ((uint8_t *)(entry->pkt->data)) + i;
*d = *(d - 1);
}
default:
break;
}
}
else {
data += 1; /* skip offset field in fragmentation header */
}
/* also adapt offset according to stored dispatch */
/* above case only applies for first fragment incoming, this for all */
switch (*((uint8_t *)entry->pkt->data)) {
case NG_SIXLOWPAN_UNCOMPRESSED:
offset++;
break;
default:
break;
}
DEBUG("6lo rbuf: add fragment data\n");
memcpy(((uint8_t *)entry->pkt->data) + offset, data, frag_size);
entry->cur_size += (uint16_t)frag_size;
}
if (entry->cur_size == entry->pkt->size) {
kernel_pid_t iface = netif_hdr->if_pid;
ng_pktsnip_t *netif = ng_netif_hdr_build(entry->src, entry->src_len,
entry->dst, entry->dst_len);
if (netif == NULL) {
DEBUG("6lo rbuf: error allocating netif header\n");
ng_pktbuf_release(entry->pkt);
return;
}
netif_hdr = netif->data;
netif_hdr->if_pid = iface;
entry->pkt->next = netif;
DEBUG("6lo rbuf: datagram complete, send to self\n");
ng_netapi_receive(thread_getpid(), entry->pkt);
_rbuf_rem(entry);
}
}
static inline bool _rbuf_int_in(rbuf_int_t *i, uint16_t start, uint16_t end)
{
return (((i->start < start) && (start <= i->end)) ||
((start < i->start) && (i->start <= end)) ||
((i->start == start) && (i->end == end)));
}
static rbuf_int_t *_rbuf_int_get_free(void)
{
for (int i = 0; i < RBUF_INT_SIZE; i++) {
if (rbuf_int[i].end == 0) { /* start must be smaller than end anyways*/
return rbuf_int + i;
}
}
return NULL;
}
static void _rbuf_rem(rbuf_t *entry)
{
while (entry->ints != NULL) {
rbuf_int_t *next = entry->ints->next;
entry->ints->start = 0;
entry->ints->end = 0;
entry->ints->next = NULL;
entry->ints = next;
}
entry->pkt = NULL;
}
static bool _rbuf_update_ints(rbuf_t *entry, uint16_t offset, size_t frag_size)
{
rbuf_int_t *new;
uint16_t end = (uint16_t)(offset + frag_size - 1);
new = _rbuf_int_get_free();
if (new == NULL) {
DEBUG("6lo rfrag: no space left in rbuf interval buffer.\n");
return false;
}
new->start = offset;
new->end = end;
DEBUG("6lo rfrag: add interval (%" PRIu16 ", %" PRIu16 ") to entry (%s, ",
new->start, new->end, ng_netif_addr_to_str(l2addr_str,
sizeof(l2addr_str), entry->src, entry->src_len));
DEBUG("%s, %zu, %" PRIu16 ")\n", ng_netif_addr_to_str(l2addr_str,
sizeof(l2addr_str), entry->dst, entry->dst_len), entry->pkt->size,
entry->tag);
LL_PREPEND(entry->ints, new);
return true;
}
static void _rbuf_gc(void)
{
rbuf_t *oldest = NULL;
timex_t now;
int i;
vtimer_now(&now);
for (i = 0; i < RBUF_SIZE; i++) {
if ((rbuf[i].pkt != NULL) &&
((now.seconds - rbuf[i].arrival) > RBUF_TIMEOUT)) {
DEBUG("6lo rfrag: entry (%s, ", ng_netif_addr_to_str(l2addr_str,
sizeof(l2addr_str), rbuf[i].src, rbuf[i].src_len));
DEBUG("%s, %zu, %" PRIu16 ") timed out\n",
ng_netif_addr_to_str(l2addr_str, sizeof(l2addr_str), rbuf[i].dst,
rbuf[i].dst_len),
rbuf[i].pkt->size, rbuf[i].tag);
ng_pktbuf_release(rbuf[i].pkt);
_rbuf_rem(&(rbuf[i]));
}
else if ((oldest == NULL) || (rbuf[i].arrival < oldest->arrival)) {
oldest = &(rbuf[i]);
}
}
if (((i >= RBUF_SIZE) && (oldest != NULL))) {
DEBUG("6lo rfrag: reassembly buffer full, remove oldest entry");
ng_pktbuf_release(oldest->pkt);
_rbuf_rem(oldest);
}
}
static rbuf_t *_rbuf_get(const void *src, size_t src_len,
const void *dst, size_t dst_len,
size_t size, uint16_t tag)
{
rbuf_t *res = NULL;
timex_t now;
vtimer_now(&now);
for (int i = 0; i < RBUF_SIZE; i++) {
/* check first if entry already available */
if ((rbuf[i].pkt != NULL) && (rbuf[i].pkt->size == size) &&
(rbuf[i].tag == tag) && (rbuf[i].src_len == src_len) &&
(rbuf[i].dst_len == dst_len) &&
(memcmp(rbuf[i].src, src, src_len) == 0) &&
(memcmp(rbuf[i].dst, dst, dst_len) == 0)) {
DEBUG("6lo rfrag: entry (%s, ", ng_netif_addr_to_str(l2addr_str,
sizeof(l2addr_str), rbuf[i].src, rbuf[i].src_len));
DEBUG("%s, %zu, %" PRIu16 ") found\n",
ng_netif_addr_to_str(l2addr_str, sizeof(l2addr_str),
rbuf[i].dst, rbuf[i].dst_len),
rbuf[i].pkt->size, rbuf[i].tag);
res->arrival = now.seconds;
return &(rbuf[i]);
}
/* if there is a free spot: remember it */
if ((res == NULL) && (rbuf[i].cur_size == 0)) {
res = &(rbuf[i]);
}
}
if (res != NULL) { /* entry not in buffer but found empty spot */
res->pkt = ng_pktbuf_add(NULL, NULL, size, NG_NETTYPE_SIXLOWPAN);
if (res->pkt == NULL) {
DEBUG("6lo rfrag: can not allocate reassembly buffer space.\n");
return NULL;
}
res->arrival = now.seconds;
memcpy(res->src, src, src_len);
memcpy(res->dst, dst, dst_len);
res->src_len = src_len;
res->dst_len = dst_len;
res->tag = tag;
res->cur_size = 0;
DEBUG("6lo rfrag: entry (%s, ", ng_netif_addr_to_str(l2addr_str,
sizeof(l2addr_str), res->src, res->src_len));
DEBUG("%s, %zu, %" PRIu16 ") created\n",
ng_netif_addr_to_str(l2addr_str, sizeof(l2addr_str), res->dst,
res->dst_len), res->pkt->size, res->tag);
}
return res;
}
/** @} */

View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* 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_ng_sixlowpan_frag
* @{
*
* @file
* @internal
* @brief 6LoWPAN reassembly buffer
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NG_SIXLOWPAN_FRAG_RBUF_H_
#define NG_SIXLOWPAN_FRAG_RBUF_H_
#include <inttypes.h>
#include "net/ng_netif/hdr.h"
#include "net/ng_pkt.h"
#include "timex.h"
#include "net/ng_sixlowpan/frag.h"
#ifdef __cplusplus
extern "C" {
#endif
#define RBUF_L2ADDR_MAX_LEN (8U) /**< maximum length for link-layer addresses */
#define RBUF_SIZE (4U) /**< size of the reassembly buffer */
#define RBUF_TIMEOUT (3U) /**< timeout for reassembly in seconds */
/**
* @brief Fragment intervals to identify limits of fragments.
*
* @note Fragments MUST NOT overlap and overlapping fragments are to be
* discarded
*
* @see <a href="https://tools.ietf.org/html/rfc4944#section-5.3">
* RFC 4944, section 5.3
* </a>
*/
typedef struct rbuf_int {
struct rbuf_int *next; /**< next element in interval list */
uint16_t start; /**< start byte of interval */
uint16_t end; /**< end byte of interval */
} rbuf_int_t;
/**
* @brief An entry in the 6LoWPAN reassembly buffer.
*
* @details A receipient of a fragment SHALL use
*
* 1. the source address,
* 2. the destination address,
* 3. the datagram size (ng_pktsnip_t::size of rbuf_t::pkt), and
* 4. the datagram tag
*
* to identify all fragments that belong to the given datagram.
*
* @see <a href="https://tools.ietf.org/html/rfc4944#section-5.3">
* RFC 4944, section 5.3
* </a>
*/
typedef struct {
rbuf_int_t *ints; /**< intervals of the fragment */
ng_pktsnip_t *pkt; /**< the reassembled packet in packet buffer */
uint32_t arrival; /**< time in seconds of arrival of last
* received fragment */
uint8_t src[RBUF_L2ADDR_MAX_LEN]; /**< source address */
uint8_t dst[RBUF_L2ADDR_MAX_LEN]; /**< destination address */
uint8_t src_len; /**< length of source address */
uint8_t dst_len; /**< length of destination address */
uint16_t tag; /**< the datagram's tag */
uint16_t cur_size; /**< the datagram's current size */
} rbuf_t;
/**
* @brief Adds a new fragment to the reassembly buffer.
*
* @param[in] netif_hdr The interface header of the fragment, with
* ng_netif_hdr_t::if_pid and its source and
* destination address set.
* @param[in] frag The fragment to add.
* @param[in] frag_size The fragment's size.
* @param[in] offset The fragment's offset.
*/
void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_sixlowpan_frag_t *frag,
size_t frag_size, size_t offset);
#ifdef __cplusplus
}
#endif
#endif /* NG_SIXLOWPAN_FRAG_RBUF_H_ */
/** @} */

View File

@ -18,6 +18,7 @@
#include "utlist.h"
#include "net/ng_sixlowpan.h"
#include "net/ng_sixlowpan/frag.h"
#include "net/ng_sixlowpan/netif.h"
#define ENABLE_DEBUG (0)
@ -80,6 +81,12 @@ void _receive(ng_pktsnip_t *pkt)
LL_DELETE(pkt, sixlowpan);
ng_pktbuf_release(sixlowpan);
}
#ifdef MODULE_NG_SIXLOWPAN_FRAG
else if (ng_sixlowpan_frag_is((ng_sixlowpan_frag_t *)dispatch)) {
DEBUG("6lo: received 6LoWPAN fragment\n");
ng_sixlowpan_frag_handle_pkt(pkt);
}
#endif
else {
DEBUG("6lo: dispatch %02x ... is not supported\n",
dispatch[0]);
@ -137,8 +144,6 @@ void _send(ng_pktsnip_t *pkt)
* length is the length of the IPv6 datagram + 6LoWPAN dispatches,
* while the datagram size is the size of only the IPv6 datagram */
payload_len = ng_pkt_len(ipv6);
/* cppcheck: datagram_size will be read by ng_sixlowpan_frag implementation */
/* cppcheck-suppress unreadVariable */
datagram_size = (uint16_t)payload_len;
/* use sixlowpan packet snip as temporary one */
@ -197,8 +202,17 @@ void _send(ng_pktsnip_t *pkt)
return;
}
#ifdef MODULE_NG_SIXLOWPAN_FRAG
else {
DEBUG("6lo: Send fragmented (%u > %" PRIu16 ")\n",
(unsigned int)payload_len, max_frag_size);
ng_sixlowpan_frag_send(hdr->if_pid, pkt, payload_len, datagram_size);
}
#else
(void)datagram_size;
DEBUG("6lo: packet too big (%u> %" PRIu16 ")\n",
(unsigned int)payload_len, max_frag_size);
#endif
}
static void *_event_loop(void *args)