
9 changed files with 828 additions and 2 deletions
@ -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_ */ |
||||
/** @} */ |
@ -0,0 +1,3 @@
|
||||
MODULE = ng_sixlowpan_frag
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -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); |
||||
} |
||||
|
||||
/** @} */ |
@ -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; |
||||
} |
||||
|
||||
/** @} */ |
@ -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_ */ |
||||
/** @} */ |
Loading…
Reference in new issue