added support for multiple reassemblies

This commit is contained in:
Joakim Eriksson 2015-09-14 15:55:26 +02:00
parent 66719ef2e2
commit d0448df3b8

View file

@ -79,15 +79,9 @@ uint8_t p;
#include <stdio.h>
#define PRINTFI(...) PRINTF(__VA_ARGS__)
#define PRINTFO(...) PRINTF(__VA_ARGS__)
#define PRINTPACKETBUF() PRINTF("packetbuf buffer: "); for(p = 0; p < packetbuf_datalen(); p++){PRINTF("%.2X", *(packetbuf_ptr + p));} PRINTF("\n")
#define PRINTUIPBUF() PRINTF("UIP buffer: "); for(p = 0; p < uip_len; p++){PRINTF("%.2X", uip_buf[p]);}PRINTF("\n")
#define PRINTSICSLOWPANBUF() PRINTF("SICSLOWPAN buffer: "); for(p = 0; p < sicslowpan_len; p++){PRINTF("%.2X", sicslowpan_buf[p]);}PRINTF("\n")
#else
#define PRINTFI(...)
#define PRINTFO(...)
#define PRINTPACKETBUF()
#define PRINTUIPBUF()
#define PRINTSICSLOWPANBUF()
#endif /* DEBUG == 1*/
#if UIP_LOGGING
@ -145,8 +139,10 @@ void uip_log(char *msg);
/** \name Pointers in the sicslowpan and uip buffer
* @{
*/
#define SICSLOWPAN_IP_BUF ((struct uip_ip_hdr *)&sicslowpan_buf[UIP_LLH_LEN])
#define SICSLOWPAN_UDP_BUF ((struct uip_udp_hdr *)&sicslowpan_buf[UIP_LLIPH_LEN])
/* NOTE: In the multiple-reassembly context there is only room for the header / first fragment */
#define SICSLOWPAN_IP_BUF(buf) ((struct uip_ip_hdr *)buf)
#define SICSLOWPAN_UDP_BUF(buf) ((struct uip_udp_hdr *)&buf[UIP_IPH_LEN])
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
@ -165,9 +161,8 @@ void uip_log(char *msg);
#endif /* SICSLOWPAN_CONF_MAC_MAX_PAYLOAD */
/** \brief Some MAC layers need a minimum payload, which is
configurable through the SICSLOWPAN_CONF_MIN_MAC_PAYLOAD
option. */
/** \brief Some MAC layers need a minimum payload, which is configurable
through the SICSLOWPAN_CONF_COMPRESSION_THRESHOLD option. */
#ifdef SICSLOWPAN_CONF_COMPRESSION_THRESHOLD
#define COMPRESSION_THRESHOLD SICSLOWPAN_CONF_COMPRESSION_THRESHOLD
#else
@ -216,50 +211,232 @@ static uint8_t uncomp_hdr_len;
static int last_tx_status;
/** @} */
#if SICSLOWPAN_CONF_FRAG
/** \name Fragmentation related variables
* @{
*/
static uint16_t my_tag;
static uint16_t sicslowpan_len;
static int last_rssi;
/**
* The buffer used for the 6lowpan reassembly.
* This buffer contains only the IPv6 packet (no MAC header, 6lowpan, etc).
* It has a fix size as we do not use dynamic memory allocation.
*/
static uip_buf_t sicslowpan_aligned_buf;
#define sicslowpan_buf (sicslowpan_aligned_buf.u8)
/* ----------------------------------------------------------------- */
/* Support for reassembling multiple packets */
/* ----------------------------------------------------------------- */
/* The fragmentation buffer are also possible to use for other
* temporary memory allocation. In that case the number of available
* buffers will be lower for a short time.
**/
/** The total length of the IPv6 packet in the sicslowpan_buf. */
/**
* length of the ip packet already sent / received.
* It includes IP and transport headers.
*/
static uint16_t processed_ip_in_len;
/* This needs to be defined in NBR / Nodes depending on available RAM */
/* and expected reassembly requirements */
#ifdef SICSLOWPAN_CONF_FRAGMENT_BUFFERS
#define SICSLOWPAN_FRAGMENT_BUFFERS SICSLOWPAN_CONF_FRAGMENT_BUFFERS
#else
#define SICSLOWPAN_FRAGMENT_BUFFERS 12
#endif
/** Datagram tag to be put in the fragments I send. */
static uint16_t my_tag;
/* REASS_CONTEXTS corresponds to the number of simultaneous
* reassemblies that can be made. NOTE: the first buffer for each
* reassembly is stored in the context since it can be larger than the
* rest of the fragments due to header compression.
**/
#ifdef SICSLOWPAN_CONF_REASS_CONTEXTS
#define SICSLOWPAN_REASS_CONTEXTS SICSLOWPAN_CONF_REASS_CONTEXTS
#else
#define SICSLOWPAN_REASS_CONTEXTS 2
#endif
/** When reassembling, the tag in the fragments being merged. */
static uint16_t reass_tag;
/* The size of each fragment (IP payload) for the 6lowpan fragmentation */
#ifdef SICSLOWPAN_CONF_FRAGMENT_SIZE
#define SICSLOWPAN_FRAGMENT_SIZE SICSLOWPAN_CONF_FRAGMENT_SIZE
#else
#define SICSLOWPAN_FRAGMENT_SIZE 110
#endif
/** When reassembling, the source address of the fragments being merged */
linkaddr_t frag_sender;
/* Assuming that the worst growth for uncompression is 38 bytes */
#define SICSLOWPAN_FIRST_FRAGMENT_SIZE (SICSLOWPAN_FRAGMENT_SIZE + 38)
/** Reassembly %process %timer. */
static struct timer reass_timer;
/* all information needed for reassembly */
struct sicslowpan_frag_info {
/** When reassembling, the source address of the fragments being merged */
linkaddr_t sender;
/** The destination address of the fragments being merged */
linkaddr_t receiver;
/** When reassembling, the tag in the fragments being merged. */
uint16_t tag;
/** Total length of the fragmented packet */
uint16_t len;
/** Current length of reassembled fragments */
uint16_t reassembled_len;
/** Reassembly %process %timer. */
struct timer reass_timer;
/** @} */
#else /* SICSLOWPAN_CONF_FRAG */
/** The buffer used for the 6lowpan processing is uip_buf.
We do not use any additional buffer.*/
#define sicslowpan_buf uip_buf
#define sicslowpan_len uip_len
#endif /* SICSLOWPAN_CONF_FRAG */
/** Fragment size of first fragment */
uint16_t first_frag_len;
/** First fragment - needs a larger buffer since the size is uncompressed size
and we need to know total size to know when we have received last fragment. */
uint8_t first_frag[SICSLOWPAN_FIRST_FRAGMENT_SIZE];
};
static int last_rssi;
static struct sicslowpan_frag_info frag_info[SICSLOWPAN_REASS_CONTEXTS];
struct sicslowpan_frag_buf {
/* the index of the frag_info */
uint8_t index;
/* Fragment offset */
uint8_t offset;
/* Length of this fragment (if zero this buffer is not allocated) */
uint8_t len;
uint8_t data[SICSLOWPAN_FRAGMENT_SIZE];
};
static struct sicslowpan_frag_buf frag_buf[SICSLOWPAN_FRAGMENT_BUFFERS];
/*---------------------------------------------------------------------------*/
static int
clear_fragments(uint8_t frag_info_index)
{
int i, clear_count;
clear_count = 0;
frag_info[frag_info_index].len = 0;
for(i = 0; i < SICSLOWPAN_FRAGMENT_BUFFERS; i++) {
if(frag_buf[i].len > 0 && frag_buf[i].index == frag_info_index) {
/* deallocate the buffer */
frag_buf[i].len = 0;
clear_count++;
}
}
return clear_count;
}
/*---------------------------------------------------------------------------*/
static int
timeout_fragments(int not_context)
{
int i;
int count = 0;
for(i = 0; i < SICSLOWPAN_REASS_CONTEXTS; i++) {
if(frag_info[i].len > 0 && i != not_context &&
timer_expired(&frag_info[i].reass_timer)) {
/* This context can be freed */
count += clear_fragments(i);
}
}
return count;
}
/*---------------------------------------------------------------------------*/
static int
store_fragment(uint8_t index, uint8_t offset)
{
int i;
for(i = 0; i < SICSLOWPAN_FRAGMENT_BUFFERS; i++) {
if(frag_buf[i].len == 0) {
/* copy over the data from packetbuf into the fragment buffer and store offset and len */
frag_buf[i].offset = offset; /* frag offset */
frag_buf[i].len = packetbuf_datalen() - packetbuf_hdr_len;
frag_buf[i].index = index;
memcpy(frag_buf[i].data, packetbuf_ptr + packetbuf_hdr_len,
packetbuf_datalen() - packetbuf_hdr_len);
PRINTF("Fragsize: %d\n", frag_buf[i].len);
/* return the length of the stored fragment */
return frag_buf[i].len;
}
}
/* failed */
return -1;
}
/*---------------------------------------------------------------------------*/
/* add a new fragment to the buffer */
static int8_t
add_fragment(uint16_t tag, uint16_t frag_size, uint8_t offset)
{
int i;
int len;
int8_t found = -1;
if(offset == 0) {
/* This is a first fragment - check if we can add this */
for(i = 0; i < SICSLOWPAN_REASS_CONTEXTS; i++) {
/* clear all fragment info with expired timer to free all fragment buffers */
if(frag_info[i].len > 0 && timer_expired(&frag_info[i].reass_timer)) {
clear_fragments(i);
}
/* We use len as indication on used or not used */
if(found < 0 && frag_info[i].len == 0) {
/* We remember the first free fragment info but must continue
the loop to free any other expired fragment buffers. */
found = i;
}
}
if(found < 0) {
PRINTF("*** Failed to store new fragment session - tag: %d\n", tag);
return -1;
}
/* Found a free fragment info to store data in */
frag_info[found].len = frag_size;
frag_info[found].tag = tag;
linkaddr_copy(&frag_info[found].sender,
packetbuf_addr(PACKETBUF_ADDR_SENDER));
timer_set(&frag_info[found].reass_timer, SICSLOWPAN_REASS_MAXAGE * CLOCK_SECOND / 16);
/* first fragment can not be stored immediately but is moved into
the buffer while uncompressing */
return found;
}
/* This is a N-fragment - should find the info */
for(i = 0; i < SICSLOWPAN_REASS_CONTEXTS; i++) {
if(frag_info[i].tag == tag && frag_info[i].len > 0 &&
linkaddr_cmp(&frag_info[i].sender, packetbuf_addr(PACKETBUF_ADDR_SENDER))) {
/* Tag and Sender match - this must be the correct info to store in */
found = i;
break;
}
}
if(found < 0) {
/* no entry found for storing the new fragment */
PRINTF("*** Failed to store N-fragment - could not find session - tag: %d offset: %d\n", tag, offset);
return -1;
}
/* i is the index of the reassembly context */
len = store_fragment(i, offset);
if(len < 0 && timeout_fragments(i) > 0) {
len = store_fragment(i, offset);
}
if(len > 0) {
frag_info[i].reassembled_len += len;
return i;
} else {
/* should we also clear all fragments since we failed to store this fragment? */
PRINTF("*** Failed to store fragment - packet reassembly will fail tag:%d l\n", frag_info[i].tag);
return -1;
}
}
/*---------------------------------------------------------------------------*/
/* Copy all the fragments that are associated with a specific context into uip */
static void
copy_frags2uip(int context)
{
int i;
/* Copy from the fragment context info buffer first */
memcpy((uint8_t *)UIP_IP_BUF, (uint8_t *)frag_info[context].first_frag,
frag_info[context].first_frag_len);
for(i = 0; i < SICSLOWPAN_FRAGMENT_BUFFERS; i++) {
/* And also copy all matching fragments */
if(frag_buf[i].len > 0 && frag_buf[i].index == context) {
memcpy((uint8_t *)UIP_IP_BUF + (uint16_t)(frag_buf[i].offset << 3),
(uint8_t *)frag_buf[i].data, frag_buf[i].len);
}
}
/* deallocate all the fragments for this context */
clear_fragments(context);
}
/* -------------------------------------------------------------------------- */
/*-------------------------------------------------------------------------*/
/* Rime Sniffer support for one single listener to enable powertrace of IP */
@ -327,7 +504,7 @@ static struct sicslowpan_addr_context *context;
/** pointer to the byte where to write next inline field. */
static uint8_t *hc06_ptr;
/* Uncompression of linklocal */
/* ession of linklocal */
/* 0 -> 16 bytes from packet */
/* 1 -> 2 bytes from prefix - bunch of zeroes and 8 from packet */
/* 2 -> 2 bytes from prefix - 0000::00ff:fe00:XXXX from packet */
@ -357,7 +534,7 @@ const uint8_t llprefix[] = {0xfe, 0x80};
static const uint8_t ttl_values[] = {0, 1, 64, 255};
/*--------------------------------------------------------------------*/
/** \name HC06 related functions
/** \name IPHC related functions
* @{ */
/*--------------------------------------------------------------------*/
/** \brief find the context corresponding to prefix ipaddr */
@ -463,8 +640,8 @@ uncompress_addr(uip_ipaddr_t *ipaddr, uint8_t const prefix[],
* uip_buf buffer.
*
*
* HC-06 (draft-ietf-6lowpan-hc, version 6)\n
* http://tools.ietf.org/html/draft-ietf-6lowpan-hc-06
* IPHC (RFC 6282)\n
* http://tools.ietf.org/html/
*
* \note We do not support ISA100_UDP header compression
*
@ -490,7 +667,7 @@ uncompress_addr(uip_ipaddr_t *ipaddr, uint8_t const prefix[],
* dest
*/
static void
compress_hdr_hc06(linkaddr_t *link_destaddr)
compress_hdr_iphc(linkaddr_t *link_destaddr)
{
uint8_t tmp, iphc0, iphc1;
#if DEBUG
@ -541,7 +718,8 @@ compress_hdr_hc06(linkaddr_t *link_destaddr)
* depends on the presence of version and flow label
*/
/* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */
/* IPHC format of tc is ECN | DSCP , original is DSCP | ECN */
tmp = (UIP_IP_BUF->vtc << 4) | (UIP_IP_BUF->tcflow >> 4);
tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
@ -585,11 +763,7 @@ compress_hdr_hc06(linkaddr_t *link_destaddr)
iphc0 |= SICSLOWPAN_IPHC_NH_C;
}
#endif /*UIP_CONF_UDP*/
#ifdef SICSLOWPAN_NH_COMPRESSOR
if(SICSLOWPAN_NH_COMPRESSOR.is_compressable(UIP_IP_BUF->proto)) {
iphc0 |= SICSLOWPAN_IPHC_NH_C;
}
#endif
if ((iphc0 & SICSLOWPAN_IPHC_NH_C) == 0) {
*hc06_ptr = UIP_IP_BUF->proto;
hc06_ptr += 1;
@ -769,11 +943,11 @@ compress_hdr_hc06(linkaddr_t *link_destaddr)
/*--------------------------------------------------------------------*/
/**
* \brief Uncompress HC06 (i.e., IPHC and LOWPAN_UDP) headers and put
* \brief Uncompress IPHC (i.e., IPHC and LOWPAN_UDP) headers and put
* them in sicslowpan_buf
*
* This function is called by the input function when the dispatch is
* HC06.
* IPHC.
* We %process the packet in the packetbuf buffer, uncompress the header
* fields, and copy the result in the sicslowpan buffer.
* At the end of the decompression, packetbuf_hdr_len and uncompressed_hdr_len
@ -784,7 +958,7 @@ compress_hdr_hc06(linkaddr_t *link_destaddr)
* fragment.
*/
static void
uncompress_hdr_hc06(uint16_t ip_len)
uncompress_hdr_iphc(uint8_t *buf, uint16_t ip_len)
{
uint8_t tmp, iphc0, iphc1;
/* at least two byte will be used for the encoding */
@ -804,22 +978,22 @@ uncompress_hdr_hc06(uint16_t ip_len)
/* Flow label are carried inline */
if((iphc0 & SICSLOWPAN_IPHC_TC_C) == 0) {
/* Traffic class is carried inline */
memcpy(&SICSLOWPAN_IP_BUF->tcflow, hc06_ptr + 1, 3);
memcpy(&SICSLOWPAN_IP_BUF(buf)->tcflow, hc06_ptr + 1, 3);
tmp = *hc06_ptr;
hc06_ptr += 4;
/* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */
/* IPHC format of tc is ECN | DSCP , original is DSCP | ECN */
/* set version, pick highest DSCP bits and set in vtc */
SICSLOWPAN_IP_BUF->vtc = 0x60 | ((tmp >> 2) & 0x0f);
SICSLOWPAN_IP_BUF(buf)->vtc = 0x60 | ((tmp >> 2) & 0x0f);
/* ECN rolled down two steps + lowest DSCP bits at top two bits */
SICSLOWPAN_IP_BUF->tcflow = ((tmp >> 2) & 0x30) | (tmp << 6) |
(SICSLOWPAN_IP_BUF->tcflow & 0x0f);
SICSLOWPAN_IP_BUF(buf)->tcflow = ((tmp >> 2) & 0x30) | (tmp << 6) |
(SICSLOWPAN_IP_BUF(buf)->tcflow & 0x0f);
} else {
/* Traffic class is compressed (set version and no TC)*/
SICSLOWPAN_IP_BUF->vtc = 0x60;
SICSLOWPAN_IP_BUF(buf)->vtc = 0x60;
/* highest flow label bits + ECN bits */
SICSLOWPAN_IP_BUF->tcflow = (*hc06_ptr & 0x0F) |
SICSLOWPAN_IP_BUF(buf)->tcflow = (*hc06_ptr & 0x0F) |
((*hc06_ptr >> 2) & 0x30);
memcpy(&SICSLOWPAN_IP_BUF->flow, hc06_ptr + 1, 2);
memcpy(&SICSLOWPAN_IP_BUF(buf)->flow, hc06_ptr + 1, 2);
hc06_ptr += 3;
}
} else {
@ -827,31 +1001,31 @@ uncompress_hdr_hc06(uint16_t ip_len)
/* Version and flow label are compressed */
if((iphc0 & SICSLOWPAN_IPHC_TC_C) == 0) {
/* Traffic class is inline */
SICSLOWPAN_IP_BUF->vtc = 0x60 | ((*hc06_ptr >> 2) & 0x0f);
SICSLOWPAN_IP_BUF->tcflow = ((*hc06_ptr << 6) & 0xC0) | ((*hc06_ptr >> 2) & 0x30);
SICSLOWPAN_IP_BUF->flow = 0;
SICSLOWPAN_IP_BUF(buf)->vtc = 0x60 | ((*hc06_ptr >> 2) & 0x0f);
SICSLOWPAN_IP_BUF(buf)->tcflow = ((*hc06_ptr << 6) & 0xC0) | ((*hc06_ptr >> 2) & 0x30);
SICSLOWPAN_IP_BUF(buf)->flow = 0;
hc06_ptr += 1;
} else {
/* Traffic class is compressed */
SICSLOWPAN_IP_BUF->vtc = 0x60;
SICSLOWPAN_IP_BUF->tcflow = 0;
SICSLOWPAN_IP_BUF->flow = 0;
SICSLOWPAN_IP_BUF(buf)->vtc = 0x60;
SICSLOWPAN_IP_BUF(buf)->tcflow = 0;
SICSLOWPAN_IP_BUF(buf)->flow = 0;
}
}
/* Next Header */
if((iphc0 & SICSLOWPAN_IPHC_NH_C) == 0) {
/* Next header is carried inline */
SICSLOWPAN_IP_BUF->proto = *hc06_ptr;
PRINTF("IPHC: next header inline: %d\n", SICSLOWPAN_IP_BUF->proto);
SICSLOWPAN_IP_BUF(buf)->proto = *hc06_ptr;
PRINTF("IPHC: next header inline: %d\n", SICSLOWPAN_IP_BUF(buf)->proto);
hc06_ptr += 1;
}
/* Hop limit */
if((iphc0 & 0x03) != SICSLOWPAN_IPHC_TTL_I) {
SICSLOWPAN_IP_BUF->ttl = ttl_values[iphc0 & 0x03];
SICSLOWPAN_IP_BUF(buf)->ttl = ttl_values[iphc0 & 0x03];
} else {
SICSLOWPAN_IP_BUF->ttl = *hc06_ptr;
SICSLOWPAN_IP_BUF(buf)->ttl = *hc06_ptr;
hc06_ptr += 1;
}
@ -872,12 +1046,12 @@ uncompress_hdr_hc06(uint16_t ip_len)
}
}
/* if tmp == 0 we do not have a context and therefore no prefix */
uncompress_addr(&SICSLOWPAN_IP_BUF->srcipaddr,
uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->srcipaddr,
tmp != 0 ? context->prefix : NULL, unc_ctxconf[tmp],
(uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
} else {
/* no compression and link local */
uncompress_addr(&SICSLOWPAN_IP_BUF->srcipaddr, llprefix, unc_llconf[tmp],
uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->srcipaddr, llprefix, unc_llconf[tmp],
(uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
}
@ -902,7 +1076,7 @@ uncompress_hdr_hc06(uint16_t ip_len)
hc06_ptr++;
}
uncompress_addr(&SICSLOWPAN_IP_BUF->destipaddr, prefix,
uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->destipaddr, prefix,
unc_mxconf[tmp], NULL);
}
} else {
@ -917,12 +1091,12 @@ uncompress_hdr_hc06(uint16_t ip_len)
PRINTF("sicslowpan uncompress_hdr: error context not found\n");
return;
}
uncompress_addr(&SICSLOWPAN_IP_BUF->destipaddr, context->prefix,
uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->destipaddr, context->prefix,
unc_ctxconf[tmp],
(uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
} else {
/* not context based => link local M = 0, DAC = 0 - same as SAC */
uncompress_addr(&SICSLOWPAN_IP_BUF->destipaddr, llprefix,
uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->destipaddr, llprefix,
unc_llconf[tmp],
(uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
}
@ -934,48 +1108,49 @@ uncompress_hdr_hc06(uint16_t ip_len)
/* The next header is compressed, NHC is following */
if((*hc06_ptr & SICSLOWPAN_NHC_UDP_MASK) == SICSLOWPAN_NHC_UDP_ID) {
uint8_t checksum_compressed;
SICSLOWPAN_IP_BUF->proto = UIP_PROTO_UDP;
SICSLOWPAN_IP_BUF(buf)->proto = UIP_PROTO_UDP;
checksum_compressed = *hc06_ptr & SICSLOWPAN_NHC_UDP_CHECKSUMC;
PRINTF("IPHC: Incoming header value: %i\n", *hc06_ptr);
switch(*hc06_ptr & SICSLOWPAN_NHC_UDP_CS_P_11) {
case SICSLOWPAN_NHC_UDP_CS_P_00:
/* 1 byte for NHC, 4 byte for ports, 2 bytes chksum */
memcpy(&SICSLOWPAN_UDP_BUF->srcport, hc06_ptr + 1, 2);
memcpy(&SICSLOWPAN_UDP_BUF->destport, hc06_ptr + 3, 2);
memcpy(&SICSLOWPAN_UDP_BUF(buf)->srcport, hc06_ptr + 1, 2);
memcpy(&SICSLOWPAN_UDP_BUF(buf)->destport, hc06_ptr + 3, 2);
PRINTF("IPHC: Uncompressed UDP ports (ptr+5): %x, %x\n",
UIP_HTONS(SICSLOWPAN_UDP_BUF->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF->destport));
UIP_HTONS(SICSLOWPAN_UDP_BUF(buf)->srcport),
UIP_HTONS(SICSLOWPAN_UDP_BUF(buf)->destport));
hc06_ptr += 5;
break;
case SICSLOWPAN_NHC_UDP_CS_P_01:
/* 1 byte for NHC + source 16bit inline, dest = 0xF0 + 8 bit inline */
PRINTF("IPHC: Decompressing destination\n");
memcpy(&SICSLOWPAN_UDP_BUF->srcport, hc06_ptr + 1, 2);
SICSLOWPAN_UDP_BUF->destport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN + (*(hc06_ptr + 3)));
memcpy(&SICSLOWPAN_UDP_BUF(buf)->srcport, hc06_ptr + 1, 2);
SICSLOWPAN_UDP_BUF(buf)->destport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN + (*(hc06_ptr + 3)));
PRINTF("IPHC: Uncompressed UDP ports (ptr+4): %x, %x\n",
UIP_HTONS(SICSLOWPAN_UDP_BUF->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF->destport));
UIP_HTONS(SICSLOWPAN_UDP_BUF(buf)->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF(buf)->destport));
hc06_ptr += 4;
break;
case SICSLOWPAN_NHC_UDP_CS_P_10:
/* 1 byte for NHC + source = 0xF0 + 8bit inline, dest = 16 bit inline*/
PRINTF("IPHC: Decompressing source\n");
SICSLOWPAN_UDP_BUF->srcport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN +
SICSLOWPAN_UDP_BUF(buf)->srcport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN +
(*(hc06_ptr + 1)));
memcpy(&SICSLOWPAN_UDP_BUF->destport, hc06_ptr + 2, 2);
memcpy(&SICSLOWPAN_UDP_BUF(buf)->destport, hc06_ptr + 2, 2);
PRINTF("IPHC: Uncompressed UDP ports (ptr+4): %x, %x\n",
UIP_HTONS(SICSLOWPAN_UDP_BUF->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF->destport));
UIP_HTONS(SICSLOWPAN_UDP_BUF(buf)->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF(buf)->destport));
hc06_ptr += 4;
break;
case SICSLOWPAN_NHC_UDP_CS_P_11:
/* 1 byte for NHC, 1 byte for ports */
SICSLOWPAN_UDP_BUF->srcport = UIP_HTONS(SICSLOWPAN_UDP_4_BIT_PORT_MIN +
SICSLOWPAN_UDP_BUF(buf)->srcport = UIP_HTONS(SICSLOWPAN_UDP_4_BIT_PORT_MIN +
(*(hc06_ptr + 1) >> 4));
SICSLOWPAN_UDP_BUF->destport = UIP_HTONS(SICSLOWPAN_UDP_4_BIT_PORT_MIN +
SICSLOWPAN_UDP_BUF(buf)->destport = UIP_HTONS(SICSLOWPAN_UDP_4_BIT_PORT_MIN +
((*(hc06_ptr + 1)) & 0x0F));
PRINTF("IPHC: Uncompressed UDP ports (ptr+2): %x, %x\n",
UIP_HTONS(SICSLOWPAN_UDP_BUF->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF->destport));
UIP_HTONS(SICSLOWPAN_UDP_BUF(buf)->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF(buf)->destport));
hc06_ptr += 2;
break;
@ -984,7 +1159,7 @@ uncompress_hdr_hc06(uint16_t ip_len)
return;
}
if(!checksum_compressed) { /* has_checksum, default */
memcpy(&SICSLOWPAN_UDP_BUF->udpchksum, hc06_ptr, 2);
memcpy(&SICSLOWPAN_UDP_BUF(buf)->udpchksum, hc06_ptr, 2);
hc06_ptr += 2;
PRINTF("IPHC: sicslowpan uncompress_hdr: checksum included\n");
} else {
@ -1005,17 +1180,17 @@ uncompress_hdr_hc06(uint16_t ip_len)
if(ip_len == 0) {
int len = packetbuf_datalen() - packetbuf_hdr_len + uncomp_hdr_len - UIP_IPH_LEN;
/* This is not a fragmented packet */
SICSLOWPAN_IP_BUF->len[0] = len >> 8;
SICSLOWPAN_IP_BUF->len[1] = len & 0x00FF;
SICSLOWPAN_IP_BUF(buf)->len[0] = len >> 8;
SICSLOWPAN_IP_BUF(buf)->len[1] = len & 0x00FF;
} else {
/* This is a 1st fragment */
SICSLOWPAN_IP_BUF->len[0] = (ip_len - UIP_IPH_LEN) >> 8;
SICSLOWPAN_IP_BUF->len[1] = (ip_len - UIP_IPH_LEN) & 0x00FF;
SICSLOWPAN_IP_BUF(buf)->len[0] = (ip_len - UIP_IPH_LEN) >> 8;
SICSLOWPAN_IP_BUF(buf)->len[1] = (ip_len - UIP_IPH_LEN) & 0x00FF;
}
/* length field in UDP header */
if(SICSLOWPAN_IP_BUF->proto == UIP_PROTO_UDP) {
memcpy(&SICSLOWPAN_UDP_BUF->udplen, &SICSLOWPAN_IP_BUF->len[0], 2);
if(SICSLOWPAN_IP_BUF(buf)->proto == UIP_PROTO_UDP) {
memcpy(&SICSLOWPAN_UDP_BUF(buf)->udplen, &SICSLOWPAN_IP_BUF(buf)->len[0], 2);
}
return;
@ -1360,7 +1535,6 @@ static uint8_t
output(const uip_lladdr_t *localdest)
{
int framer_hdrlen;
int max_payload;
/* The MAC address of the destination of the packet */
linkaddr_t dest;
@ -1426,7 +1600,7 @@ output(const uip_lladdr_t *localdest)
compress_hdr_ipv6(&dest);
#endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6 */
#if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06
compress_hdr_hc06(&dest);
compress_hdr_iphc(&dest);
#endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06 */
} else {
compress_hdr_ipv6(&dest);
@ -1442,21 +1616,23 @@ output(const uip_lladdr_t *localdest)
framer_hdrlen = NETSTACK_FRAMER.length();
if(framer_hdrlen < 0) {
/* Framing failed, we assume the maximum header length */
framer_hdrlen = 21;
framer_hdrlen = 23;
}
#else /* USE_FRAMER_HDRLEN */
framer_hdrlen = 21;
framer_hdrlen = 23;
#endif /* USE_FRAMER_HDRLEN */
max_payload = MAC_MAX_PAYLOAD - framer_hdrlen;
if((int)uip_len - (int)uncomp_hdr_len > max_payload - (int)packetbuf_hdr_len) {
if((int)uip_len - (int)uncomp_hdr_len > (int)max_payload - (int)packetbuf_hdr_len) {
#if SICSLOWPAN_CONF_FRAG
struct queuebuf *q;
uint16_t frag_tag;
/*
* The outbound IPv6 packet is too large to fit into a single 15.4
* packet, so we fragment it into multiple packets and send them.
* The first fragment contains frag1 dispatch, then
* IPv6/HC1/HC06/HC_UDP dispatchs/headers.
* IPv6/IPHC/HC_UDP dispatchs/headers.
* The following fragments contain only the fragn dispatch.
*/
int estimated_fragments = ((int)uip_len) / (max_payload - SICSLOWPAN_FRAGN_HDR_LEN) + 1;
@ -1472,7 +1648,10 @@ output(const uip_lladdr_t *localdest)
/* Create 1st Fragment */
PRINTFO("sicslowpan output: 1rst fragment ");
/* move HC1/HC06/IPv6 header */
/* Reset last tx status to ok in case the fragment transmissions are deferred */
last_tx_status = MAC_TX_OK;
/* move IPHC/IPv6 header */
memmove(packetbuf_ptr + SICSLOWPAN_FRAG1_HDR_LEN, packetbuf_ptr, packetbuf_hdr_len);
/*
@ -1483,14 +1662,13 @@ output(const uip_lladdr_t *localdest)
/* uip_htons((SICSLOWPAN_DISPATCH_FRAG1 << 8) | uip_len); */
SET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_DISPATCH_SIZE,
((SICSLOWPAN_DISPATCH_FRAG1 << 8) | uip_len));
/* PACKETBUF_FRAG_BUF->tag = uip_htons(my_tag); */
SET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_TAG, my_tag);
my_tag++;
frag_tag = my_tag++;
SET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_TAG, frag_tag);
/* Copy payload and send */
packetbuf_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN;
packetbuf_payload_len = (max_payload - packetbuf_hdr_len) & 0xfffffff8;
PRINTFO("(len %d, tag %d)\n", packetbuf_payload_len, my_tag);
packetbuf_payload_len = (MAC_MAX_PAYLOAD - framer_hdrlen - packetbuf_hdr_len) & 0xfffffff8;
PRINTFO("(len %d, tag %d)\n", packetbuf_payload_len, frag_tag);
memcpy(packetbuf_ptr + packetbuf_hdr_len,
(uint8_t *)UIP_IP_BUF + uncomp_hdr_len, packetbuf_payload_len);
packetbuf_set_datalen(packetbuf_payload_len + packetbuf_hdr_len);
@ -1525,7 +1703,7 @@ output(const uip_lladdr_t *localdest)
/* uip_htons((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len); */
SET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_DISPATCH_SIZE,
((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len));
packetbuf_payload_len = (max_payload - packetbuf_hdr_len) & 0xfffffff8;
packetbuf_payload_len = (MAC_MAX_PAYLOAD - framer_hdrlen - packetbuf_hdr_len) & 0xfffffff8;
while(processed_ip_out_len < uip_len) {
PRINTFO("sicslowpan output: fragment ");
PACKETBUF_FRAG_PTR[PACKETBUF_FRAG_OFFSET] = processed_ip_out_len >> 3;
@ -1536,7 +1714,7 @@ output(const uip_lladdr_t *localdest)
packetbuf_payload_len = uip_len - processed_ip_out_len;
}
PRINTFO("(offset %d, len %d, tag %d)\n",
processed_ip_out_len >> 3, packetbuf_payload_len, my_tag);
processed_ip_out_len >> 3, packetbuf_payload_len, frag_tag);
memcpy(packetbuf_ptr + packetbuf_hdr_len,
(uint8_t *)UIP_IP_BUF + processed_ip_out_len, packetbuf_payload_len);
packetbuf_set_datalen(packetbuf_payload_len + packetbuf_hdr_len);
@ -1594,8 +1772,12 @@ input(void)
{
/* size of the IP packet (read from fragment) */
uint16_t frag_size = 0;
int8_t frag_context = 0;
/* offset of the fragment in the IP packet */
uint8_t frag_offset = 0;
uint8_t is_fragment = 0;
uint8_t *buffer;
#if SICSLOWPAN_CONF_FRAG
uint8_t is_fragment = 0;
/* tag of the fragment */
@ -1610,15 +1792,15 @@ input(void)
/* The MAC puts the 15.4 payload inside the packetbuf data buffer */
packetbuf_ptr = packetbuf_dataptr();
/* This is default uip_buf since we assume that this is not fragmented */
buffer = (uint8_t *)UIP_IP_BUF;
/* Save the RSSI of the incoming packet in case the upper layer will
want to query us for it later. */
last_rssi = (signed short)packetbuf_attr(PACKETBUF_ATTR_RSSI);
#if SICSLOWPAN_CONF_FRAG
/* if reassembly timed out, cancel it */
if(timer_expired(&reass_timer)) {
sicslowpan_len = 0;
processed_ip_in_len = 0;
}
/*
* Since we don't support the mesh and broadcast header, the first header
* we look for is the fragmentation header
@ -1637,6 +1819,14 @@ input(void)
/* printf("frag1 %d %d\n", reass_tag, frag_tag);*/
first_fragment = 1;
is_fragment = 1;
/* Add the fragment to the fragmentation context */
frag_context = add_fragment(frag_tag, frag_size, frag_offset);
if(frag_context == -1) return;
buffer = frag_info[frag_context].first_frag;
break;
case SICSLOWPAN_DISPATCH_FRAGN:
/*
@ -1656,7 +1846,16 @@ input(void)
PRINTFI("last_fragment?: processed_ip_in_len %d packetbuf_payload_len %d frag_size %d\n",
processed_ip_in_len, packetbuf_datalen() - packetbuf_hdr_len, frag_size);
if(processed_ip_in_len + packetbuf_datalen() - packetbuf_hdr_len >= frag_size) {
/* Add the fragment to the fragmentation context (this will also copy the payload) */
frag_context = add_fragment(frag_tag, frag_size, frag_offset);
if(frag_context == -1) return;
/* Ok - add_fragment will store the fragment automatically - so we should not store more */
buffer = NULL;
// if(processed_ip_in_len + packetbuf_datalen() - packetbuf_hdr_len >= frag_size) {
if(frag_info[frag_context].reassembled_len >= frag_size) {
last_fragment = 1;
}
is_fragment = 1;
@ -1665,65 +1864,7 @@ input(void)
break;
}
/* We are currently reassembling a packet, but have just received the first
* fragment of another packet. We can either ignore it and hope to receive
* the rest of the under-reassembly packet fragments, or we can discard the
* previous packet altogether, and start reassembling the new packet.
*
* We discard the previous packet, and start reassembling the new packet.
* This lessens the negative impacts of too high SICSLOWPAN_REASS_MAXAGE.
*/
#define PRIORITIZE_NEW_PACKETS 1
#if PRIORITIZE_NEW_PACKETS
if(!is_fragment) {
/* Prioritize non-fragment packets too. */
sicslowpan_len = 0;
processed_ip_in_len = 0;
} else if(processed_ip_in_len > 0 && first_fragment
&& !linkaddr_cmp(&frag_sender, packetbuf_addr(PACKETBUF_ADDR_SENDER))) {
sicslowpan_len = 0;
processed_ip_in_len = 0;
}
#endif /* PRIORITIZE_NEW_PACKETS */
if(processed_ip_in_len > 0) {
/* reassembly is ongoing */
/* printf("frag %d %d\n", reass_tag, frag_tag);*/
if((frag_size > 0 &&
(frag_size != sicslowpan_len ||
reass_tag != frag_tag ||
!linkaddr_cmp(&frag_sender, packetbuf_addr(PACKETBUF_ADDR_SENDER)))) ||
frag_size == 0) {
/*
* the packet is a fragment that does not belong to the packet
* being reassembled or the packet is not a fragment.
*/
PRINTFI("sicslowpan input: Dropping 6lowpan packet that is not a fragment of the packet currently being reassembled\n");
return;
}
} else {
/*
* reassembly is off
* start it if we received a fragment
*/
if((frag_size > 0) && (frag_size <= UIP_BUFSIZE)) {
/* We are currently not reassembling a packet, but have received a packet fragment
* that is not the first one. */
if(is_fragment && !first_fragment) {
return;
}
sicslowpan_len = frag_size;
reass_tag = frag_tag;
timer_set(&reass_timer, SICSLOWPAN_REASS_MAXAGE * CLOCK_SECOND);
PRINTFI("sicslowpan input: INIT FRAGMENTATION (len %d, tag %d)\n",
sicslowpan_len, reass_tag);
linkaddr_copy(&frag_sender, packetbuf_addr(PACKETBUF_ADDR_SENDER));
}
}
if(packetbuf_hdr_len == SICSLOWPAN_FRAGN_HDR_LEN) {
/* this is a FRAGN, skip the header compression dispatch section */
goto copypayload;
}
@ -1733,7 +1874,7 @@ input(void)
#if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06
if((PACKETBUF_HC1_PTR[PACKETBUF_HC1_DISPATCH] & 0xe0) == SICSLOWPAN_DISPATCH_IPHC) {
PRINTFI("sicslowpan input: IPHC\n");
uncompress_hdr_hc06(frag_size);
uncompress_hdr_iphc(buffer, frag_size);
} else
#endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06 */
switch(PACKETBUF_HC1_PTR[PACKETBUF_HC1_DISPATCH]) {
@ -1748,7 +1889,7 @@ input(void)
packetbuf_hdr_len += SICSLOWPAN_IPV6_HDR_LEN;
/* Put uncompressed IP header in sicslowpan_buf. */
memcpy(SICSLOWPAN_IP_BUF, packetbuf_ptr + packetbuf_hdr_len, UIP_IPH_LEN);
memcpy(buffer, packetbuf_ptr + packetbuf_hdr_len, UIP_IPH_LEN);
/* Update uncomp_hdr_len and packetbuf_hdr_len. */
packetbuf_hdr_len += UIP_IPH_LEN;
@ -1782,16 +1923,20 @@ input(void)
{
int req_size = UIP_LLH_LEN + uncomp_hdr_len + (uint16_t)(frag_offset << 3)
+ packetbuf_payload_len;
if(req_size > sizeof(sicslowpan_buf)) {
if(req_size > sizeof(uip_buf)) {
PRINTF(
"SICSLOWPAN: packet dropped, minimum required SICSLOWPAN_IP_BUF size: %d+%d+%d+%d=%d (current size: %d)\n",
"SICSLOWPAN: packet dropped, minimum required IP_BUF size: %d+%d+%d+%d=%d (current size: %u)\n",
UIP_LLH_LEN, uncomp_hdr_len, (uint16_t)(frag_offset << 3),
packetbuf_payload_len, req_size, sizeof(sicslowpan_buf));
packetbuf_payload_len, req_size, sizeof(uip_buf));
return;
}
}
memcpy((uint8_t *)SICSLOWPAN_IP_BUF + uncomp_hdr_len + (uint16_t)(frag_offset << 3), packetbuf_ptr + packetbuf_hdr_len, packetbuf_payload_len);
/* copy the payload if buffer is non-null - which is only the case with first fragment
or packets that are non fragmented */
if(buffer != NULL) {
memcpy((uint8_t *)buffer + uncomp_hdr_len, packetbuf_ptr + packetbuf_hdr_len, packetbuf_payload_len);
}
/* update processed_ip_in_len if fragment, sicslowpan_len otherwise */
@ -1799,44 +1944,40 @@ input(void)
if(frag_size > 0) {
/* Add the size of the header only for the first fragment. */
if(first_fragment != 0) {
processed_ip_in_len += uncomp_hdr_len;
frag_info[frag_context].reassembled_len = uncomp_hdr_len + packetbuf_payload_len;
frag_info[frag_context].first_frag_len = uncomp_hdr_len + packetbuf_payload_len;;
}
/* For the last fragment, we are OK if there is extrenous bytes at
the end of the packet. */
if(last_fragment != 0) {
processed_ip_in_len = frag_size;
} else {
processed_ip_in_len += packetbuf_payload_len;
frag_info[frag_context].reassembled_len = frag_size;
/* copy to uip */
copy_frags2uip(frag_context);
}
PRINTF("processed_ip_in_len %d, packetbuf_payload_len %d\n", processed_ip_in_len, packetbuf_payload_len);
} else {
#endif /* SICSLOWPAN_CONF_FRAG */
sicslowpan_len = packetbuf_payload_len + uncomp_hdr_len;
#if SICSLOWPAN_CONF_FRAG
}
/*
* If we have a full IP packet in sicslowpan_buf, deliver it to
* the IP stack
*/
PRINTF("sicslowpan_init processed_ip_in_len %d, sicslowpan_len %d\n",
processed_ip_in_len, sicslowpan_len);
if(processed_ip_in_len == 0 || (processed_ip_in_len == sicslowpan_len)) {
if(!is_fragment || last_fragment) {
/* packet is in uip already - just set length */
if(is_fragment != 0 && last_fragment != 0) {
uip_len = frag_size;
} else {
uip_len = packetbuf_payload_len + uncomp_hdr_len;
}
PRINTFI("sicslowpan input: IP packet ready (length %d)\n",
sicslowpan_len);
memcpy((uint8_t *)UIP_IP_BUF, (uint8_t *)SICSLOWPAN_IP_BUF, sicslowpan_len);
uip_len = sicslowpan_len;
sicslowpan_len = 0;
processed_ip_in_len = 0;
uip_len);
#endif /* SICSLOWPAN_CONF_FRAG */
#if DEBUG
{
uint16_t ndx;
PRINTF("after decompression %u:", SICSLOWPAN_IP_BUF->len[1]);
for (ndx = 0; ndx < SICSLOWPAN_IP_BUF->len[1] + 40; ndx++) {
uint8_t data = ((uint8_t *) (SICSLOWPAN_IP_BUF))[ndx];
PRINTF("after decompression %u:", UIP_IP_BUF->len[1]);
for (ndx = 0; ndx < UIP_IP_BUF->len[1] + 40; ndx++) {
uint8_t data = ((uint8_t *) (UIP_IP_BUF))[ndx];
PRINTF("%02x", data);
}
PRINTF("\n");
@ -1926,3 +2067,4 @@ const struct network_driver sicslowpan_driver = {
};
/*--------------------------------------------------------------------*/
/** @} */