diff --git a/core/net/ipv6/sicslowpan.c b/core/net/ipv6/sicslowpan.c index 3cec1a534..f6af5d46f 100644 --- a/core/net/ipv6/sicslowpan.c +++ b/core/net/ipv6/sicslowpan.c @@ -79,15 +79,9 @@ uint8_t p; #include #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) | - ((*hc06_ptr >> 2) & 0x30); - memcpy(&SICSLOWPAN_IP_BUF->flow, hc06_ptr + 1, 2); + SICSLOWPAN_IP_BUF(buf)->tcflow = (*hc06_ptr & 0x0F) | + ((*hc06_ptr >> 2) & 0x30); + 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,59 +1108,60 @@ 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); - PRINTF("IPHC: Uncompressed UDP ports (ptr+5): %x, %x\n", - UIP_HTONS(SICSLOWPAN_UDP_BUF->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF->destport)); - hc06_ptr += 5; - break; + /* 1 byte for NHC, 4 byte for ports, 2 bytes chksum */ + 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(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))); - PRINTF("IPHC: Uncompressed UDP ports (ptr+4): %x, %x\n", - UIP_HTONS(SICSLOWPAN_UDP_BUF->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF->destport)); - hc06_ptr += 4; - break; + PRINTF("IPHC: Decompressing destination\n"); + 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(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 + - (*(hc06_ptr + 1))); - memcpy(&SICSLOWPAN_UDP_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)); - hc06_ptr += 4; - break; + PRINTF("IPHC: Decompressing source\n"); + SICSLOWPAN_UDP_BUF(buf)->srcport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN + + (*(hc06_ptr + 1))); + 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(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 + - (*(hc06_ptr + 1) >> 4)); - SICSLOWPAN_UDP_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)); - hc06_ptr += 2; - break; + /* 1 byte for NHC, 1 byte for ports */ + SICSLOWPAN_UDP_BUF(buf)->srcport = UIP_HTONS(SICSLOWPAN_UDP_4_BIT_PORT_MIN + + (*(hc06_ptr + 1) >> 4)); + 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(buf)->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF(buf)->destport)); + hc06_ptr += 2; + break; default: PRINTF("sicslowpan uncompress_hdr: error unsupported UDP compression\n"); return; } if(!checksum_compressed) { /* has_checksum, default */ - memcpy(&SICSLOWPAN_UDP_BUF->udpchksum, hc06_ptr, 2); - hc06_ptr += 2; - PRINTF("IPHC: sicslowpan uncompress_hdr: checksum included\n"); + memcpy(&SICSLOWPAN_UDP_BUF(buf)->udpchksum, hc06_ptr, 2); + hc06_ptr += 2; + PRINTF("IPHC: sicslowpan uncompress_hdr: checksum included\n"); } else { PRINTF("IPHC: sicslowpan uncompress_hdr: checksum *NOT* included\n"); } @@ -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) { + if(is_fragment && !first_fragment) { /* 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 = { }; /*--------------------------------------------------------------------*/ /** @} */ +