Added support for the FTP standalone client to the c64 target.
[contiki-2.x.git] / core / net / sicslowpan.c
blobc7227cbf448e9b53625fafe1fbe3eac5057a9e06
1 /**
2 * \addtogroup sicslowpan
3 * @{
4 */
5 /*
6 * Copyright (c) 2008, Swedish Institute of Computer Science.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
33 * This file is part of the Contiki operating system.
35 * $Id: sicslowpan.c,v 1.46 2010/10/19 18:29:04 adamdunkels Exp $
37 /**
38 * \file
39 * 6lowpan implementation (RFC4944 and draft-ietf-6lowpan-hc-06)
41 * \author Adam Dunkels <adam@sics.se>
42 * \author Nicolas Tsiftes <nvt@sics.se>
43 * \author Niclas Finne <nfi@sics.se>
44 * \author Mathilde Durvy <mdurvy@cisco.com>
45 * \author Julien Abeille <jabeille@cisco.com>
46 * \author Joakim Eriksson <joakime@sics.se>
47 * \author Joel Hoglund <joel@sics.se>
50 /**
51 * FOR HC-06 COMPLIANCE TODO:
52 * -Add compression options to UDP, currently only supports
53 * both ports compressed or both ports elided
55 * -Verify TC/FL compression works
57 * -Add stateless multicast option
60 #include <string.h>
62 #include "contiki.h"
63 #include "dev/watchdog.h"
64 #include "net/tcpip.h"
65 #include "net/uip.h"
66 #include "net/uip-ds6.h"
67 #include "net/rime.h"
68 #include "net/sicslowpan.h"
69 #include "net/neighbor-info.h"
70 #include "net/netstack.h"
72 #define DEBUG 0
73 #if DEBUG
74 /* PRINTFI and PRINTFO are defined for input and output to debug one without changing the timing of the other */
75 u8_t p;
76 #include <stdio.h>
77 #define PRINTF(...) printf(__VA_ARGS__)
78 #define PRINTFI(...) printf(__VA_ARGS__)
79 #define PRINTFO(...) printf(__VA_ARGS__)
80 #define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_t *)addr)[15])
81 #define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ",lladdr->addr[0], lladdr->addr[1], lladdr->addr[2], lladdr->addr[3],lladdr->addr[4], lladdr->addr[5],lladdr->addr[6], lladdr->addr[7])
82 #define PRINTPACKETBUF() PRINTF("RIME buffer: "); for(p = 0; p < packetbuf_datalen(); p++){PRINTF("%.2X", *(rime_ptr + p));} PRINTF("\n")
83 #define PRINTUIPBUF() PRINTF("UIP buffer: "); for(p = 0; p < uip_len; p++){PRINTF("%.2X", uip_buf[p]);}PRINTF("\n")
84 #define PRINTSICSLOWPANBUF() PRINTF("SICSLOWPAN buffer: "); for(p = 0; p < sicslowpan_len; p++){PRINTF("%.2X", sicslowpan_buf[p]);}PRINTF("\n")
85 #else
86 #define PRINTF(...)
87 #define PRINTFI(...)
88 #define PRINTFO(...)
89 #define PRINT6ADDR(addr)
90 #define PRINTLLADDR(lladdr)
91 #define PRINTPACKETBUF()
92 #define PRINTUIPBUF()
93 #define PRINTSICSLOWPANBUF()
94 #endif /* DEBUG == 1*/
96 #if UIP_LOGGING
97 #include <stdio.h>
98 void uip_log(char *msg);
99 #define UIP_LOG(m) uip_log(m)
100 #else
101 #define UIP_LOG(m)
102 #endif /* UIP_LOGGING == 1 */
104 #ifndef SICSLOWPAN_COMPRESSION
105 #ifdef SICSLOWPAN_CONF_COMPRESSION
106 #define SICSLOWPAN_COMPRESSION SICSLOWPAN_CONF_COMPRESSION
107 #else
108 #define SICSLOWPAN_COMPRESSION SICSLOWPAN_COMPRESSION_IPV6
109 #endif /* SICSLOWPAN_CONF_COMPRESSION */
110 #endif /* SICSLOWPAN_COMPRESSION */
112 #ifndef SICSLOWPAN_CONF_NEIGHBOR_INFO
113 /* Default is to use neighbor info updates if using RPL */
114 #define SICSLOWPAN_CONF_NEIGHBOR_INFO UIP_CONF_IPV6_RPL
115 #endif /* SICSLOWPAN_CONF_NEIGHBOR_INFO */
117 #define GET16(ptr,index) (((uint16_t)((ptr)[index] << 8)) | ((ptr)[(index) + 1]))
118 #define SET16(ptr,index,value) do { \
119 (ptr)[index] = ((value) >> 8) & 0xff; \
120 (ptr)[index + 1] = (value) & 0xff; \
121 } while(0)
123 /** \name Pointers in the rime buffer
124 * @{
126 #define RIME_FRAG_PTR (rime_ptr)
127 #define RIME_FRAG_DISPATCH_SIZE 0 /* 16 bit */
128 #define RIME_FRAG_TAG 2 /* 16 bit */
129 #define RIME_FRAG_OFFSET 4 /* 8 bit */
131 /* define the buffer as a byte array */
132 #define RIME_IPHC_BUF ((uint8_t *)(rime_ptr + rime_hdr_len))
134 #define RIME_HC1_PTR (rime_ptr + rime_hdr_len)
135 #define RIME_HC1_DISPATCH 0 /* 8 bit */
136 #define RIME_HC1_ENCODING 1 /* 8 bit */
137 #define RIME_HC1_TTL 2 /* 8 bit */
139 #define RIME_HC1_HC_UDP_PTR (rime_ptr + rime_hdr_len)
140 #define RIME_HC1_HC_UDP_DISPATCH 0 /* 8 bit */
141 #define RIME_HC1_HC_UDP_HC1_ENCODING 1 /* 8 bit */
142 #define RIME_HC1_HC_UDP_UDP_ENCODING 2 /* 8 bit */
143 #define RIME_HC1_HC_UDP_TTL 3 /* 8 bit */
144 #define RIME_HC1_HC_UDP_PORTS 4 /* 8 bit */
145 #define RIME_HC1_HC_UDP_CHKSUM 5 /* 16 bit */
147 /** \name Pointers in the sicslowpan and uip buffer
148 * @{
150 #define SICSLOWPAN_IP_BUF ((struct uip_ip_hdr *)&sicslowpan_buf[UIP_LLH_LEN])
151 #define SICSLOWPAN_UDP_BUF ((struct uip_udp_hdr *)&sicslowpan_buf[UIP_LLIPH_LEN])
153 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
154 #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
155 #define UIP_TCP_BUF ((struct uip_tcp_hdr *)&uip_buf[UIP_LLIPH_LEN])
156 /** @} */
159 /** \brief Size of the 802.15.4 payload (127byte - 25 for MAC header) */
160 #define MAC_MAX_PAYLOAD 102
162 /** \name General variables
163 * @{
165 /** A pointer to the mac driver */
166 const struct mac_driver *sicslowpan_mac;
168 #ifdef SICSLOWPAN_NH_COMPRESSOR
169 /** A pointer to the additional compressor */
170 extern struct sicslowpan_nh_compressor SICSLOWPAN_NH_COMPRESSOR;
171 #endif
174 * A pointer to the rime buffer.
175 * We initialize it to the beginning of the rime buffer, then
176 * access different fields by updating the offset rime_hdr_len.
178 static u8_t *rime_ptr;
181 * rime_hdr_len is the total length of (the processed) 6lowpan headers
182 * (fragment headers, IPV6 or HC1, HC2, and HC1 and HC2 non compressed
183 * fields).
185 static u8_t rime_hdr_len;
188 * The length of the payload in the Rime buffer.
189 * The payload is what comes after the compressed or uncompressed
190 * headers (can be the IP payload if the IP header only is compressed
191 * or the UDP payload if the UDP header is also compressed)
193 static u8_t rime_payload_len;
196 * uncomp_hdr_len is the length of the headers before compression (if HC2
197 * is used this includes the UDP header in addition to the IP header).
199 static u8_t uncomp_hdr_len;
200 /** @} */
202 #if SICSLOWPAN_CONF_FRAG
203 /** \name Fragmentation related variables
204 * @{
207 static u16_t sicslowpan_len;
210 * The buffer used for the 6lowpan reassembly.
211 * This buffer contains only the IPv6 packet (no MAC header, 6lowpan, etc).
212 * It has a fix size as we do not use dynamic memory allocation.
214 static uip_buf_t sicslowpan_aligned_buf;
215 #define sicslowpan_buf (sicslowpan_aligned_buf.u8)
217 /** The total length of the IPv6 packet in the sicslowpan_buf. */
220 * length of the ip packet already sent / received.
221 * It includes IP and transport headers.
223 static u16_t processed_ip_len;
225 /** Datagram tag to be put in the fragments I send. */
226 static u16_t my_tag;
228 /** When reassembling, the tag in the fragments being merged. */
229 static u16_t reass_tag;
231 /** When reassembling, the source address of the fragments being merged */
232 rimeaddr_t frag_sender;
234 /** Reassembly %process %timer. */
235 static struct timer reass_timer;
237 /** @} */
238 #else /* SICSLOWPAN_CONF_FRAG */
239 /** The buffer used for the 6lowpan processing is uip_buf.
240 We do not use any additional buffer.*/
241 #define sicslowpan_buf uip_buf
242 #define sicslowpan_len uip_len
243 #endif /* SICSLOWPAN_CONF_FRAG */
245 #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06
246 /** \name HC06 specific variables
247 * @{
250 /** Addresses contexts for IPHC. */
251 #if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0
252 static struct sicslowpan_addr_context
253 addr_contexts[SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS];
254 #endif
256 /** pointer to an address context. */
257 static struct sicslowpan_addr_context *context;
259 /** pointer to the byte where to write next inline field. */
260 static uint8_t *hc06_ptr;
262 /* Uncompression of linklocal */
263 /* 0 -> 16 bytes from packet */
264 /* 1 -> 2 bytes from prefix - bunch of zeroes and 8 from packet */
265 /* 2 -> 2 bytes from prefix - zeroes + 2 from packet */
266 /* 3 -> 2 bytes from prefix - infer 8 bytes from lladdr */
267 /* NOTE: => the uncompress function does change 0xf to 0x10 */
268 /* NOTE: 0x00 => no-autoconfig => unspecified */
269 const uint8_t unc_llconf[] = {0x0f,0x28,0x22,0x20};
271 /* Uncompression of ctx-based */
272 /* 0 -> 0 bits from packet [unspecified / reserved] */
273 /* 1 -> 8 bytes from prefix - bunch of zeroes and 8 from packet */
274 /* 2 -> 8 bytes from prefix - zeroes + 2 from packet */
275 /* 3 -> 8 bytes from prefix - infer 8 bytes from lladdr */
276 const uint8_t unc_ctxconf[] = {0x00,0x88,0x82,0x80};
278 /* Uncompression of ctx-based */
279 /* 0 -> 0 bits from packet */
280 /* 1 -> 2 bytes from prefix - bunch of zeroes 5 from packet */
281 /* 2 -> 2 bytes from prefix - zeroes + 3 from packet */
282 /* 3 -> 2 bytes from prefix - infer 1 bytes from lladdr */
283 const uint8_t unc_mxconf[] = {0x0f, 0x25, 0x23, 0x21};
285 /* Link local prefix */
286 const uint8_t llprefix[] = {0xfe, 0x80};
288 /* TTL uncompression values */
289 static const uint8_t ttl_values[] = {0, 1, 64, 255};
291 /*--------------------------------------------------------------------*/
292 /** \name HC06 related functions
293 * @{ */
294 /*--------------------------------------------------------------------*/
295 /** \brief find the context corresponding to prefix ipaddr */
296 static struct sicslowpan_addr_context*
297 addr_context_lookup_by_prefix(uip_ipaddr_t *ipaddr) {
298 /* Remove code to avoid warnings and save flash if no context is used */
299 #if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0
300 int i;
301 for(i = 0; i < SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; i++) {
302 if((addr_contexts[i].used == 1) &&
303 uip_ipaddr_prefixcmp(&addr_contexts[i].prefix, ipaddr, 64)) {
304 return &addr_contexts[i];
307 #endif /* SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0 */
308 return NULL;
310 /*--------------------------------------------------------------------*/
311 /** \brief find the context with the given number */
312 static struct sicslowpan_addr_context*
313 addr_context_lookup_by_number(u8_t number) {
314 /* Remove code to avoid warnings and save flash if no context is used */
315 #if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0
316 int i;
317 for(i = 0; i < SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; i++) {
318 if((addr_contexts[i].used == 1) &&
319 addr_contexts[i].number == number) {
320 return &addr_contexts[i];
323 #endif /* SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0 */
324 return NULL;
326 /*--------------------------------------------------------------------*/
327 static uint8_t
328 compress_addr_64(uint8_t bitpos, uip_ipaddr_t *ipaddr, uip_lladdr_t *lladdr) {
329 if(uip_is_addr_mac_addr_based(ipaddr, lladdr)){
330 return 3 << bitpos; /* 0-bits */
331 } else if(sicslowpan_is_iid_16_bit_compressable(ipaddr)){
332 /* compress IID to 16 bits xxxx::XXXX */
333 memcpy(hc06_ptr, &ipaddr->u16[7], 2);
334 hc06_ptr += 2;
335 return 2 << bitpos; /* 16-bits */
336 } else {
337 /* do not compress IID => xxxx::IID */
338 memcpy(hc06_ptr, &ipaddr->u16[4], 8);
339 hc06_ptr += 8;
340 return 1 << bitpos; /* 64-bits */
344 /*-------------------------------------------------------------------- */
345 /* Uncompress addresses based on a prefix and a postfix with zeroes in
346 * between. If the postfix is zero in length it will use the link address
347 * to configure the IP address (autoconf style).
348 * pref_post_count takes a byte where the first nibble specify prefix count
349 * and the second postfix count (NOTE: 15/0xf => 16 bytes copy).
351 static void
352 uncompress_addr(uip_ipaddr_t *ipaddr, uint8_t const prefix[],
353 uint8_t pref_post_count, uip_lladdr_t *lladdr) {
354 uint8_t prefcount = pref_post_count >> 4;
355 uint8_t postcount = pref_post_count & 0x0f;
356 /* full nibble 15 => 16 */
357 prefcount = prefcount == 15 ? 16 : prefcount;
358 postcount = postcount == 15 ? 16 : postcount;
360 PRINTF("Uncompressing %d + %d => ", prefcount, postcount);
362 if(prefcount > 0) {
363 memcpy(ipaddr, prefix, prefcount);
365 if(prefcount + postcount < 16) {
366 memset(&ipaddr->u8[prefcount], 0, 16 - (prefcount + postcount));
368 if(postcount > 0) {
369 memcpy(&ipaddr->u8[16 - postcount], hc06_ptr, postcount);
370 hc06_ptr += postcount;
371 } else if (prefcount > 0){
372 /* no IID based configuration if no prefix and no data => unspec */
373 uip_ds6_set_addr_iid(ipaddr, lladdr);
376 PRINT6ADDR(ipaddr);
377 PRINTF("\n");
380 /*--------------------------------------------------------------------*/
382 * \brief Compress IP/UDP header
384 * This function is called by the 6lowpan code to create a compressed
385 * 6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
386 * uip_buf buffer.
389 * HC-06 (draft-ietf-6lowpan-hc, version 6)\n
390 * http://tools.ietf.org/html/draft-ietf-6lowpan-hc-06
392 * \note We do not support ISA100_UDP header compression
394 * For LOWPAN_UDP compression, we either compress both ports or none.
395 * General format with LOWPAN_UDP compression is
396 * \verbatim
397 * 1 2 3
398 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
399 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
400 * |0|1|1|TF |N|HLI|C|S|SAM|M|D|DAM| SCI | DCI | comp. IPv6 hdr|
401 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
402 * | compressed IPv6 fields ..... |
403 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
404 * | LOWPAN_UDP | non compressed UDP fields ... |
405 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
406 * | L4 data ... |
407 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
408 * \endverbatim
409 * \note The context number 00 is reserved for the link local prefix.
410 * For unicast addresses, if we cannot compress the prefix, we neither
411 * compress the IID.
412 * \param rime_destaddr L2 destination address, needed to compress IP
413 * dest
415 static void
416 compress_hdr_hc06(rimeaddr_t *rime_destaddr)
418 uint8_t tmp, iphc0, iphc1;
419 #if DEBUG
420 PRINTF("before compression: ");
421 for (tmp = 0; tmp < UIP_IP_BUF->len[1] + 40; tmp++) {
422 uint8_t data = ((uint8_t *) (UIP_IP_BUF))[tmp];
423 PRINTF("%02x", data);
425 PRINTF("\n");
426 #endif
428 hc06_ptr = rime_ptr + 2;
430 * As we copy some bit-length fields, in the IPHC encoding bytes,
431 * we sometimes use |=
432 * If the field is 0, and the current bit value in memory is 1,
433 * this does not work. We therefore reset the IPHC encoding here
436 iphc0 = SICSLOWPAN_DISPATCH_IPHC;
437 iphc1 = 0;
438 RIME_IPHC_BUF[2] = 0; /* might not be used - but needs to be cleared */
441 * Address handling needs to be made first since it might
442 * cause an extra byte with [ SCI | DCI ]
447 /* check if dest context exists (for allocating third byte) */
448 /* TODO: fix this so that it remembers the looked up values for
449 avoiding two lookups - or set the lookup values immediately */
450 if(addr_context_lookup_by_prefix(&UIP_IP_BUF->destipaddr) != NULL ||
451 addr_context_lookup_by_prefix(&UIP_IP_BUF->srcipaddr) != NULL) {
452 /* set context flag and increase hc06_ptr */
453 PRINTF("IPHC: compressing dest or src ipaddr - setting CID\n");
454 iphc1 |= SICSLOWPAN_IPHC_CID;
455 hc06_ptr++;
459 * Traffic class, flow label
460 * If flow label is 0, compress it. If traffic class is 0, compress it
461 * We have to process both in the same time as the offset of traffic class
462 * depends on the presence of version and flow label
465 /* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */
466 tmp = (UIP_IP_BUF->vtc << 4) | (UIP_IP_BUF->tcflow >> 4);
467 tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
469 if(((UIP_IP_BUF->tcflow & 0x0F) == 0) &&
470 (UIP_IP_BUF->flow == 0)) {
471 /* flow label can be compressed */
472 iphc0 |= SICSLOWPAN_IPHC_FL_C;
473 if(((UIP_IP_BUF->vtc & 0x0F) == 0) &&
474 ((UIP_IP_BUF->tcflow & 0xF0) == 0)) {
475 /* compress (elide) all */
476 iphc0 |= SICSLOWPAN_IPHC_TC_C;
477 } else {
478 /* compress only the flow label */
479 *hc06_ptr = tmp;
480 hc06_ptr += 1;
482 } else {
483 /* Flow label cannot be compressed */
484 if(((UIP_IP_BUF->vtc & 0x0F) == 0) &&
485 ((UIP_IP_BUF->tcflow & 0xF0) == 0)) {
486 /* compress only traffic class */
487 iphc0 |= SICSLOWPAN_IPHC_TC_C;
488 *hc06_ptr = (tmp & 0xc0) |
489 (UIP_IP_BUF->tcflow & 0x0F);
490 memcpy(hc06_ptr + 1, &UIP_IP_BUF->flow, 2);
491 hc06_ptr += 3;
492 } else {
493 /* compress nothing */
494 memcpy(hc06_ptr, &UIP_IP_BUF->vtc, 4);
495 /* but replace the top byte with the new ECN | DSCP format*/
496 *hc06_ptr = tmp;
497 hc06_ptr += 4;
501 /* Note that the payload length is always compressed */
503 /* Next header. We compress it if UDP */
504 #if UIP_CONF_UDP
505 if(UIP_IP_BUF->proto == UIP_PROTO_UDP) {
506 iphc0 |= SICSLOWPAN_IPHC_NH_C;
508 #endif /*UIP_CONF_UDP*/
509 #ifdef SICSLOWPAN_NH_COMPRESSOR
510 if(SICSLOWPAN_NH_COMPRESSOR.is_compressable(UIP_IP_BUF->proto)) {
511 iphc0 |= SICSLOWPAN_IPHC_NH_C;
513 #endif
514 if ((iphc0 & SICSLOWPAN_IPHC_NH_C) == 0) {
515 *hc06_ptr = UIP_IP_BUF->proto;
516 hc06_ptr += 1;
520 * Hop limit
521 * if 1: compress, encoding is 01
522 * if 64: compress, encoding is 10
523 * if 255: compress, encoding is 11
524 * else do not compress
526 switch(UIP_IP_BUF->ttl) {
527 case 1:
528 iphc0 |= SICSLOWPAN_IPHC_TTL_1;
529 break;
530 case 64:
531 iphc0 |= SICSLOWPAN_IPHC_TTL_64;
532 break;
533 case 255:
534 iphc0 |= SICSLOWPAN_IPHC_TTL_255;
535 break;
536 default:
537 *hc06_ptr = UIP_IP_BUF->ttl;
538 hc06_ptr += 1;
539 break;
542 /* source address - cannot be multicast */
543 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
544 PRINTF("IPHC: compressing unspecified - setting SAC\n");
545 iphc1 |= SICSLOWPAN_IPHC_SAC;
546 iphc1 |= SICSLOWPAN_IPHC_SAM_00;
547 } else if((context = addr_context_lookup_by_prefix(&UIP_IP_BUF->srcipaddr))
548 != NULL) {
549 /* elide the prefix - indicate by CID and set context + SAC */
550 PRINTF("IPHC: compressing src with context - setting CID & SAC ctx: %d\n",
551 context->number);
552 iphc1 |= SICSLOWPAN_IPHC_CID | SICSLOWPAN_IPHC_SAC;
553 RIME_IPHC_BUF[2] |= context->number << 4;
554 /* compession compare with this nodes address (source) */
556 iphc1 |= compress_addr_64(SICSLOWPAN_IPHC_SAM_BIT,
557 &UIP_IP_BUF->srcipaddr, &uip_lladdr);
558 /* No context found for this address */
559 } else if(uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr)) {
560 iphc1 |= compress_addr_64(SICSLOWPAN_IPHC_SAM_BIT,
561 &UIP_IP_BUF->srcipaddr, &uip_lladdr);
562 } else {
563 /* send the full address => SAC = 0, SAM = 00 */
564 iphc1 |= SICSLOWPAN_IPHC_SAM_00; /* 128-bits */
565 memcpy(hc06_ptr, &UIP_IP_BUF->srcipaddr.u16[0], 16);
566 hc06_ptr += 16;
569 /* dest address*/
570 if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
571 /* Address is multicast, try to compress */
572 iphc1 |= SICSLOWPAN_IPHC_M;
573 if(sicslowpan_is_mcast_addr_compressable8(&UIP_IP_BUF->destipaddr)) {
574 iphc1 |= SICSLOWPAN_IPHC_DAM_11;
575 /* use last byte */
576 *hc06_ptr = UIP_IP_BUF->destipaddr.u8[15];
577 hc06_ptr += 1;
578 } else if(sicslowpan_is_mcast_addr_compressable32(&UIP_IP_BUF->destipaddr)){
579 iphc1 |= SICSLOWPAN_IPHC_DAM_10;
580 /* second byte + the last three */
581 *hc06_ptr = UIP_IP_BUF->destipaddr.u8[1];
582 memcpy(hc06_ptr + 1, &UIP_IP_BUF->destipaddr.u8[13], 3);
583 hc06_ptr += 4;
584 } else if(sicslowpan_is_mcast_addr_compressable48(&UIP_IP_BUF->destipaddr)){
585 iphc1 |= SICSLOWPAN_IPHC_DAM_01;
586 /* second byte + the last five */
587 *hc06_ptr = UIP_IP_BUF->destipaddr.u8[1];
588 memcpy(hc06_ptr + 1, &UIP_IP_BUF->destipaddr.u8[11], 5);
589 hc06_ptr += 6;
590 } else {
591 iphc1 |= SICSLOWPAN_IPHC_DAM_00;
592 /* full address */
593 memcpy(hc06_ptr, &UIP_IP_BUF->destipaddr.u8[0], 16);
594 hc06_ptr += 16;
596 } else {
597 /* Address is unicast, try to compress */
598 if((context = addr_context_lookup_by_prefix(&UIP_IP_BUF->destipaddr)) != NULL) {
599 /* elide the prefix */
600 iphc1 |= SICSLOWPAN_IPHC_DAC;
601 RIME_IPHC_BUF[2] |= context->number;
602 /* compession compare with link adress (destination) */
604 iphc1 |= compress_addr_64(SICSLOWPAN_IPHC_DAM_BIT,
605 &UIP_IP_BUF->destipaddr, (uip_lladdr_t *)rime_destaddr);
606 /* No context found for this address */
607 } else if(uip_is_addr_link_local(&UIP_IP_BUF->destipaddr)) {
608 iphc1 |= compress_addr_64(SICSLOWPAN_IPHC_DAM_BIT,
609 &UIP_IP_BUF->destipaddr, (uip_lladdr_t *)rime_destaddr);
610 } else {
611 /* send the full address */
612 iphc1 |= SICSLOWPAN_IPHC_DAM_00; /* 128-bits */
613 memcpy(hc06_ptr, &UIP_IP_BUF->destipaddr.u16[0], 16);
614 hc06_ptr += 16;
618 uncomp_hdr_len = UIP_IPH_LEN;
620 #if UIP_CONF_UDP
621 /* UDP header compression */
622 if(UIP_IP_BUF->proto == UIP_PROTO_UDP) {
623 PRINTF("IPHC: Uncompressed UDP ports on send side: %x, %x\n",
624 UIP_HTONS(UIP_UDP_BUF->srcport), UIP_HTONS(UIP_UDP_BUF->destport));
625 /* Mask out the last 4 bits can be used as a mask */
626 if(((UIP_HTONS(UIP_UDP_BUF->srcport) & 0xfff0) == SICSLOWPAN_UDP_4_BIT_PORT_MIN) &&
627 ((UIP_HTONS(UIP_UDP_BUF->destport) & 0xfff0) == SICSLOWPAN_UDP_4_BIT_PORT_MIN)) {
628 /* we can compress 12 bits of both source and dest */
629 *hc06_ptr = SICSLOWPAN_NHC_UDP_CS_P_11;
630 PRINTF("IPHC: remove 12 b of both source & dest with prefix 0xFOB\n");
631 *(hc06_ptr + 1) =
632 (u8_t)((UIP_HTONS(UIP_UDP_BUF->srcport) -
633 SICSLOWPAN_UDP_4_BIT_PORT_MIN) << 4) +
634 (u8_t)((UIP_HTONS(UIP_UDP_BUF->destport) -
635 SICSLOWPAN_UDP_4_BIT_PORT_MIN));
636 hc06_ptr += 2;
637 } else if((UIP_HTONS(UIP_UDP_BUF->destport) & 0xff00) == SICSLOWPAN_UDP_8_BIT_PORT_MIN) {
638 /* we can compress 8 bits of dest, leave source. */
639 *hc06_ptr = SICSLOWPAN_NHC_UDP_CS_P_01;
640 PRINTF("IPHC: leave source, remove 8 bits of dest with prefix 0xF0\n");
641 memcpy(hc06_ptr + 1, &UIP_UDP_BUF->srcport, 2);
642 *(hc06_ptr + 3) =
643 (u8_t)((UIP_HTONS(UIP_UDP_BUF->destport) -
644 SICSLOWPAN_UDP_8_BIT_PORT_MIN));
645 hc06_ptr += 4;
646 } else if((UIP_HTONS(UIP_UDP_BUF->srcport) & 0xff00) == SICSLOWPAN_UDP_8_BIT_PORT_MIN) {
647 /* we can compress 8 bits of src, leave dest. Copy compressed port */
648 *hc06_ptr = SICSLOWPAN_NHC_UDP_CS_P_10;
649 PRINTF("IPHC: remove 8 bits of source with prefix 0xF0, leave dest. hch: %i\n", *hc06_ptr);
650 *(hc06_ptr + 1) =
651 (u8_t)((UIP_HTONS(UIP_UDP_BUF->srcport) -
652 SICSLOWPAN_UDP_8_BIT_PORT_MIN));
653 memcpy(hc06_ptr + 2, &UIP_UDP_BUF->destport, 2);
654 hc06_ptr += 4;
655 } else {
656 /* we cannot compress. Copy uncompressed ports, full checksum */
657 *hc06_ptr = SICSLOWPAN_NHC_UDP_CS_P_00;
658 PRINTF("IPHC: cannot compress headers\n");
659 memcpy(hc06_ptr + 1, &UIP_UDP_BUF->srcport, 4);
660 hc06_ptr += 5;
662 /* always inline the checksum */
663 if(1) {
664 memcpy(hc06_ptr, &UIP_UDP_BUF->udpchksum, 2);
665 hc06_ptr += 2;
667 uncomp_hdr_len += UIP_UDPH_LEN;
669 #endif /*UIP_CONF_UDP*/
671 #ifdef SICSLOWPAN_NH_COMPRESSOR
672 /* if nothing to compress just return zero */
673 hc06_ptr += SICSLOWPAN_NH_COMPRESSOR.compress(hc06_ptr, &uncomp_hdr_len);
674 #endif
676 /* before the rime_hdr_len operation */
677 RIME_IPHC_BUF[0] = iphc0;
678 RIME_IPHC_BUF[1] = iphc1;
680 rime_hdr_len = hc06_ptr - rime_ptr;
681 return;
684 /*--------------------------------------------------------------------*/
686 * \brief Uncompress HC06 (i.e., IPHC and LOWPAN_UDP) headers and put
687 * them in sicslowpan_buf
689 * This function is called by the input function when the dispatch is
690 * HC06.
691 * We %process the packet in the rime buffer, uncompress the header
692 * fields, and copy the result in the sicslowpan buffer.
693 * At the end of the decompression, rime_hdr_len and uncompressed_hdr_len
694 * are set to the appropriate values
696 * \param ip_len Equal to 0 if the packet is not a fragment (IP length
697 * is then inferred from the L2 length), non 0 if the packet is a 1st
698 * fragment.
701 static void
702 uncompress_hdr_hc06(u16_t ip_len) {
703 uint8_t tmp, iphc0, iphc1;
704 /* at least two byte will be used for the encoding */
705 hc06_ptr = rime_ptr + rime_hdr_len + 2;
707 iphc0 = RIME_IPHC_BUF[0];
708 iphc1 = RIME_IPHC_BUF[1];
710 /* another if the CID flag is set */
711 if(iphc1 & SICSLOWPAN_IPHC_CID) {
712 PRINTF("IPHC: CID flag set - increase header with one\n");
713 hc06_ptr++;
716 /* Traffic class and flow label */
717 if((iphc0 & SICSLOWPAN_IPHC_FL_C) == 0) {
718 /* Flow label are carried inline */
719 if((iphc0 & SICSLOWPAN_IPHC_TC_C) == 0) {
720 /* Traffic class is carried inline */
721 memcpy(&SICSLOWPAN_IP_BUF->tcflow, hc06_ptr + 1, 3);
722 tmp = *hc06_ptr;
723 hc06_ptr += 4;
724 /* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */
725 /* set version, pick highest DSCP bits and set in vtc */
726 SICSLOWPAN_IP_BUF->vtc = 0x60 | ((tmp >> 2) & 0x0f);
727 /* ECN rolled down two steps + lowest DSCP bits at top two bits */
728 SICSLOWPAN_IP_BUF->tcflow = ((tmp >> 2) & 0x30) | (tmp << 6) |
729 (SICSLOWPAN_IP_BUF->tcflow & 0x0f);
730 } else {
731 /* Traffic class is compressed (set version and no TC)*/
732 SICSLOWPAN_IP_BUF->vtc = 0x60;
733 /* highest flow label bits + ECN bits */
734 SICSLOWPAN_IP_BUF->tcflow = (*hc06_ptr & 0x0F) |
735 ((*hc06_ptr >> 2) & 0x30);
736 memcpy(&SICSLOWPAN_IP_BUF->flow, hc06_ptr + 1, 2);
737 hc06_ptr += 3;
739 } else {
740 /* Version is always 6! */
741 /* Version and flow label are compressed */
742 if((iphc0 & SICSLOWPAN_IPHC_TC_C) == 0) {
743 /* Traffic class is inline */
744 SICSLOWPAN_IP_BUF->vtc = 0x60 | ((*hc06_ptr >> 2) & 0x0f);
745 SICSLOWPAN_IP_BUF->tcflow = ((*hc06_ptr << 6) & 0xC0) | ((*hc06_ptr >> 2) & 0x30);
746 SICSLOWPAN_IP_BUF->flow = 0;
747 hc06_ptr += 3;
748 } else {
749 /* Traffic class is compressed */
750 SICSLOWPAN_IP_BUF->vtc = 0x60;
751 SICSLOWPAN_IP_BUF->tcflow = 0;
752 SICSLOWPAN_IP_BUF->flow = 0;
756 /* Next Header */
757 if((iphc0 & SICSLOWPAN_IPHC_NH_C) == 0) {
758 /* Next header is carried inline */
759 SICSLOWPAN_IP_BUF->proto = *hc06_ptr;
760 PRINTF("IPHC: next header inline: %d\n", SICSLOWPAN_IP_BUF->proto);
761 hc06_ptr += 1;
764 /* Hop limit */
765 if((iphc0 & 0x03) != SICSLOWPAN_IPHC_TTL_I) {
766 SICSLOWPAN_IP_BUF->ttl = ttl_values[iphc0 & 0x03];
767 } else {
768 SICSLOWPAN_IP_BUF->ttl = *hc06_ptr;
769 hc06_ptr += 1;
772 /* put the source address compression mode SAM in the tmp var */
773 tmp = ((iphc1 & SICSLOWPAN_IPHC_SAM_11) >> SICSLOWPAN_IPHC_SAM_BIT) & 0x03;
775 /* context based compression */
776 if(iphc1 & SICSLOWPAN_IPHC_SAC) {
777 uint8_t sci = (iphc1 & SICSLOWPAN_IPHC_CID) ?
778 RIME_IPHC_BUF[2] >> 4 : 0;
780 /* Source address - check context != NULL only if SAM bits are != 0*/
781 if (tmp != 0) {
782 context = addr_context_lookup_by_number(sci);
783 if(context == NULL) {
784 PRINTF("sicslowpan uncompress_hdr: error context not found\n");
785 return;
788 /* if tmp == 0 we do not have a context and therefore no prefix */
789 uncompress_addr(&SICSLOWPAN_IP_BUF->srcipaddr,
790 tmp != 0 ? context->prefix : NULL, unc_ctxconf[tmp],
791 (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
792 } else {
793 /* no compression and link local */
794 uncompress_addr(&SICSLOWPAN_IP_BUF->srcipaddr, llprefix, unc_llconf[tmp],
795 (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
798 /* Destination address */
799 /* put the destination address compression mode into tmp */
800 tmp = ((iphc1 & SICSLOWPAN_IPHC_DAM_11) >> SICSLOWPAN_IPHC_DAM_BIT) & 0x03;
802 /* multicast compression */
803 if(iphc1 & SICSLOWPAN_IPHC_M) {
804 /* context based multicast compression */
805 if(iphc1 & SICSLOWPAN_IPHC_DAC) {
806 /* TODO: implement this */
807 } else {
808 /* non-context based multicast compression - */
809 /* DAM_00: 128 bits */
810 /* DAM_01: 48 bits FFXX::00XX:XXXX:XXXX */
811 /* DAM_10: 32 bits FFXX::00XX:XXXX */
812 /* DAM_11: 8 bits FF02::00XX */
813 uint8_t prefix[] = {0xff, 0x02};
814 if(tmp > 0 && tmp < 3) {
815 prefix[1] = *hc06_ptr;
816 hc06_ptr++;
819 uncompress_addr(&SICSLOWPAN_IP_BUF->destipaddr, prefix,
820 unc_mxconf[tmp], NULL);
822 } else {
823 /* no multicast */
824 /* Context based */
825 if(iphc1 & SICSLOWPAN_IPHC_DAC) {
826 uint8_t dci = (iphc1 & SICSLOWPAN_IPHC_CID) ?
827 RIME_IPHC_BUF[2] & 0x0f : 0;
828 context = addr_context_lookup_by_number(dci);
830 /* all valid cases below need the context! */
831 if(context == NULL) {
832 PRINTF("sicslowpan uncompress_hdr: error context not found\n");
833 return;
835 uncompress_addr(&SICSLOWPAN_IP_BUF->destipaddr, context->prefix,
836 unc_ctxconf[tmp],
837 (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
838 } else {
839 /* not context based => link local M = 0, DAC = 0 - same as SAC */
840 uncompress_addr(&SICSLOWPAN_IP_BUF->destipaddr, llprefix,
841 unc_llconf[tmp],
842 (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
845 uncomp_hdr_len += UIP_IPH_LEN;
847 /* Next header processing - continued */
848 if((iphc0 & SICSLOWPAN_IPHC_NH_C)) {
849 /* The next header is compressed, NHC is following */
850 if((*hc06_ptr & SICSLOWPAN_NHC_UDP_MASK) == SICSLOWPAN_NHC_UDP_ID) {
851 uint8_t checksum_compressed;
852 SICSLOWPAN_IP_BUF->proto = UIP_PROTO_UDP;
853 checksum_compressed = *hc06_ptr & SICSLOWPAN_NHC_UDP_CHECKSUMC;
854 PRINTF("IPHC: Incoming header value: %i\n", *hc06_ptr);
855 switch(*hc06_ptr & SICSLOWPAN_NHC_UDP_CS_P_11) {
856 case SICSLOWPAN_NHC_UDP_CS_P_00:
857 /* 1 byte for NHC, 4 byte for ports, 2 bytes chksum */
858 memcpy(&SICSLOWPAN_UDP_BUF->srcport, hc06_ptr + 1, 2);
859 memcpy(&SICSLOWPAN_UDP_BUF->destport, hc06_ptr + 3, 2);
860 PRINTF("IPHC: Uncompressed UDP ports (ptr+5): %x, %x\n",
861 UIP_HTONS(SICSLOWPAN_UDP_BUF->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF->destport));
862 hc06_ptr += 5;
863 break;
865 case SICSLOWPAN_NHC_UDP_CS_P_01:
866 /* 1 byte for NHC + source 16bit inline, dest = 0xF0 + 8 bit inline */
867 PRINTF("IPHC: Decompressing destination\n");
868 memcpy(&SICSLOWPAN_UDP_BUF->srcport, hc06_ptr + 1, 2);
869 SICSLOWPAN_UDP_BUF->destport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN + (*(hc06_ptr + 3)));
870 PRINTF("IPHC: Uncompressed UDP ports (ptr+4): %x, %x\n",
871 UIP_HTONS(SICSLOWPAN_UDP_BUF->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF->destport));
872 hc06_ptr += 4;
873 break;
875 case SICSLOWPAN_NHC_UDP_CS_P_10:
876 /* 1 byte for NHC + source = 0xF0 + 8bit inline, dest = 16 bit inline*/
877 PRINTF("IPHC: Decompressing source\n");
878 SICSLOWPAN_UDP_BUF->srcport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN +
879 (*(hc06_ptr + 1)));
880 memcpy(&SICSLOWPAN_UDP_BUF->destport, hc06_ptr + 2, 2);
881 PRINTF("IPHC: Uncompressed UDP ports (ptr+4): %x, %x\n",
882 UIP_HTONS(SICSLOWPAN_UDP_BUF->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF->destport));
883 hc06_ptr += 4;
884 break;
886 case SICSLOWPAN_NHC_UDP_CS_P_11:
887 /* 1 byte for NHC, 1 byte for ports */
888 SICSLOWPAN_UDP_BUF->srcport = UIP_HTONS(SICSLOWPAN_UDP_4_BIT_PORT_MIN +
889 (*(hc06_ptr + 1) >> 4));
890 SICSLOWPAN_UDP_BUF->destport = UIP_HTONS(SICSLOWPAN_UDP_4_BIT_PORT_MIN +
891 ((*(hc06_ptr + 1)) & 0x0F));
892 PRINTF("IPHC: Uncompressed UDP ports (ptr+2): %x, %x\n",
893 UIP_HTONS(SICSLOWPAN_UDP_BUF->srcport), UIP_HTONS(SICSLOWPAN_UDP_BUF->destport));
894 hc06_ptr += 2;
895 break;
897 default:
898 PRINTF("sicslowpan uncompress_hdr: error unsupported UDP compression\n");
899 return;
901 if(!checksum_compressed) { /* has_checksum, default */
902 memcpy(&SICSLOWPAN_UDP_BUF->udpchksum, hc06_ptr, 2);
903 hc06_ptr += 2;
904 PRINTF("IPHC: sicslowpan uncompress_hdr: checksum included\n");
905 } else {
906 PRINTF("IPHC: sicslowpan uncompress_hdr: checksum *NOT* included\n");
908 uncomp_hdr_len += UIP_UDPH_LEN;
910 #ifdef SICSLOWPAN_NH_COMPRESSOR
911 else {
912 hc06_ptr += SICSLOWPAN_NH_COMPRESSOR.uncompress(hc06_ptr, sicslowpan_buf, &uncomp_hdr_len);
914 #endif
917 rime_hdr_len = hc06_ptr - rime_ptr;
919 /* IP length field. */
920 if(ip_len == 0) {
921 /* This is not a fragmented packet */
922 SICSLOWPAN_IP_BUF->len[0] = 0;
923 SICSLOWPAN_IP_BUF->len[1] = packetbuf_datalen() - rime_hdr_len + uncomp_hdr_len - UIP_IPH_LEN;
924 } else {
925 /* This is a 1st fragment */
926 SICSLOWPAN_IP_BUF->len[0] = (ip_len - UIP_IPH_LEN) >> 8;
927 SICSLOWPAN_IP_BUF->len[1] = (ip_len - UIP_IPH_LEN) & 0x00FF;
930 /* length field in UDP header */
931 if(SICSLOWPAN_IP_BUF->proto == UIP_PROTO_UDP) {
932 memcpy(&SICSLOWPAN_UDP_BUF->udplen, &SICSLOWPAN_IP_BUF->len[0], 2);
935 return;
937 /** @} */
938 #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06 */
941 #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC1
942 /*--------------------------------------------------------------------*/
943 /** \name HC1 compression and uncompression functions
944 * @{ */
945 /*--------------------------------------------------------------------*/
947 * \brief Compress IP/UDP header using HC1 and HC_UDP
949 * This function is called by the 6lowpan code to create a compressed
950 * 6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
951 * uip_buf buffer.
954 * If we can compress everything, we use HC1 dispatch, if not we use
955 * IPv6 dispatch.\n
956 * We can compress everything if:
957 * - IP version is
958 * - Flow label and traffic class are 0
959 * - Both src and dest ip addresses are link local
960 * - Both src and dest interface ID are recoverable from lower layer
961 * header
962 * - Next header is either ICMP, UDP or TCP
963 * Moreover, if next header is UDP, we try to compress it using HC_UDP.
964 * This is feasible is both ports are between F0B0 and F0B0 + 15\n\n
966 * Resulting header structure:
967 * - For ICMP, TCP, non compressed UDP\n
968 * HC1 encoding = 11111010 (UDP) 11111110 (TCP) 11111100 (ICMP)\n
969 * \verbatim
970 * 1 2 3
971 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
972 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
973 * | LoWPAN HC1 Dsp | HC1 encoding | IPv6 Hop limit| L4 hdr + data|
974 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
975 * | ...
976 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
977 * \endverbatim
979 * - For compressed UDP
980 * HC1 encoding = 11111011, HC_UDP encoding = 11100000\n
981 * \verbatim
982 * 1 2 3
983 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
984 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
985 * | LoWPAN HC1 Dsp| HC1 encoding | HC_UDP encod.| IPv6 Hop limit|
986 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
987 * | src p.| dst p.| UDP checksum | L4 data...
988 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
989 * \endverbatim
991 * \param rime_destaddr L2 destination address, needed to compress the
992 * IP destination field
994 static void
995 compress_hdr_hc1(rimeaddr_t *rime_destaddr)
998 * Check if all the assumptions for full compression
999 * are valid :
1001 if(UIP_IP_BUF->vtc != 0x60 ||
1002 UIP_IP_BUF->tcflow != 0 ||
1003 UIP_IP_BUF->flow != 0 ||
1004 !uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr) ||
1005 !uip_is_addr_mac_addr_based(&UIP_IP_BUF->srcipaddr, &uip_lladdr) ||
1006 !uip_is_addr_link_local(&UIP_IP_BUF->destipaddr) ||
1007 !uip_is_addr_mac_addr_based(&UIP_IP_BUF->destipaddr,
1008 (uip_lladdr_t *)rime_destaddr) ||
1009 (UIP_IP_BUF->proto != UIP_PROTO_ICMP6 &&
1010 UIP_IP_BUF->proto != UIP_PROTO_UDP &&
1011 UIP_IP_BUF->proto != UIP_PROTO_TCP))
1014 * IPV6 DISPATCH
1015 * Something cannot be compressed, use IPV6 DISPATCH,
1016 * compress nothing, copy IPv6 header in rime buffer
1018 *rime_ptr = SICSLOWPAN_DISPATCH_IPV6;
1019 rime_hdr_len += SICSLOWPAN_IPV6_HDR_LEN;
1020 memcpy(rime_ptr + rime_hdr_len, UIP_IP_BUF, UIP_IPH_LEN);
1021 rime_hdr_len += UIP_IPH_LEN;
1022 uncomp_hdr_len += UIP_IPH_LEN;
1023 } else {
1025 * HC1 DISPATCH
1026 * maximum compresssion:
1027 * All fields in the IP header but Hop Limit are elided
1028 * If next header is UDP, we compress UDP header using HC2
1030 RIME_HC1_PTR[RIME_HC1_DISPATCH] = SICSLOWPAN_DISPATCH_HC1;
1031 uncomp_hdr_len += UIP_IPH_LEN;
1032 switch(UIP_IP_BUF->proto) {
1033 case UIP_PROTO_ICMP6:
1034 /* HC1 encoding and ttl */
1035 RIME_HC1_PTR[RIME_HC1_ENCODING] = 0xFC;
1036 RIME_HC1_PTR[RIME_HC1_TTL] = UIP_IP_BUF->ttl;
1037 rime_hdr_len += SICSLOWPAN_HC1_HDR_LEN;
1038 break;
1039 #if UIP_CONF_TCP
1040 case UIP_PROTO_TCP:
1041 /* HC1 encoding and ttl */
1042 RIME_HC1_PTR[RIME_HC1_ENCODING] = 0xFE;
1043 RIME_HC1_PTR[RIME_HC1_TTL] = UIP_IP_BUF->ttl;
1044 rime_hdr_len += SICSLOWPAN_HC1_HDR_LEN;
1045 break;
1046 #endif /* UIP_CONF_TCP */
1047 #if UIP_CONF_UDP
1048 case UIP_PROTO_UDP:
1050 * try to compress UDP header (we do only full compression).
1051 * This is feasible if both src and dest ports are between
1052 * SICSLOWPAN_UDP_PORT_MIN and SICSLOWPAN_UDP_PORT_MIN + 15
1054 PRINTF("local/remote port %u/%u\n",UIP_UDP_BUF->srcport,UIP_UDP_BUF->destport);
1055 if(UIP_HTONS(UIP_UDP_BUF->srcport) >= SICSLOWPAN_UDP_PORT_MIN &&
1056 UIP_HTONS(UIP_UDP_BUF->srcport) < SICSLOWPAN_UDP_PORT_MAX &&
1057 UIP_HTONS(UIP_UDP_BUF->destport) >= SICSLOWPAN_UDP_PORT_MIN &&
1058 UIP_HTONS(UIP_UDP_BUF->destport) < SICSLOWPAN_UDP_PORT_MAX) {
1059 /* HC1 encoding */
1060 RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_HC1_ENCODING] = 0xFB;
1062 /* HC_UDP encoding, ttl, src and dest ports, checksum */
1063 RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_UDP_ENCODING] = 0xE0;
1064 RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_TTL] = UIP_IP_BUF->ttl;
1066 RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_PORTS] =
1067 (u8_t)((UIP_HTONS(UIP_UDP_BUF->srcport) -
1068 SICSLOWPAN_UDP_PORT_MIN) << 4) +
1069 (u8_t)((UIP_HTONS(UIP_UDP_BUF->destport) - SICSLOWPAN_UDP_PORT_MIN));
1070 memcpy(&RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_CHKSUM], &UIP_UDP_BUF->udpchksum, 2);
1071 rime_hdr_len += SICSLOWPAN_HC1_HC_UDP_HDR_LEN;
1072 uncomp_hdr_len += UIP_UDPH_LEN;
1073 } else {
1074 /* HC1 encoding and ttl */
1075 RIME_HC1_PTR[RIME_HC1_ENCODING] = 0xFA;
1076 RIME_HC1_PTR[RIME_HC1_TTL] = UIP_IP_BUF->ttl;
1077 rime_hdr_len += SICSLOWPAN_HC1_HDR_LEN;
1079 break;
1080 #endif /*UIP_CONF_UDP*/
1083 return;
1086 /*--------------------------------------------------------------------*/
1088 * \brief Uncompress HC1 (and HC_UDP) headers and put them in
1089 * sicslowpan_buf
1091 * This function is called by the input function when the dispatch is
1092 * HC1.
1093 * We %process the packet in the rime buffer, uncompress the header
1094 * fields, and copy the result in the sicslowpan buffer.
1095 * At the end of the decompression, rime_hdr_len and uncompressed_hdr_len
1096 * are set to the appropriate values
1098 * \param ip_len Equal to 0 if the packet is not a fragment (IP length
1099 * is then inferred from the L2 length), non 0 if the packet is a 1st
1100 * fragment.
1102 static void
1103 uncompress_hdr_hc1(u16_t ip_len) {
1104 /* version, traffic class, flow label */
1105 SICSLOWPAN_IP_BUF->vtc = 0x60;
1106 SICSLOWPAN_IP_BUF->tcflow = 0;
1107 SICSLOWPAN_IP_BUF->flow = 0;
1109 /* src and dest ip addresses */
1110 uip_ip6addr(&SICSLOWPAN_IP_BUF->srcipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0);
1111 uip_sd6_set_addr_iid(&SICSLOWPAN_IP_BUF->srcipaddr,
1112 (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
1113 uip_ip6addr(&SICSLOWPAN_IP_BUF->destipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0);
1114 uip_sd6_set_addr_iid(&SICSLOWPAN_IP_BUF->destipaddr,
1115 (uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
1117 uncomp_hdr_len += UIP_IPH_LEN;
1119 /* Next header field */
1120 switch(RIME_HC1_PTR[RIME_HC1_ENCODING] & 0x06) {
1121 case SICSLOWPAN_HC1_NH_ICMP6:
1122 SICSLOWPAN_IP_BUF->proto = UIP_PROTO_ICMP6;
1123 SICSLOWPAN_IP_BUF->ttl = RIME_HC1_PTR[RIME_HC1_TTL];
1124 rime_hdr_len += SICSLOWPAN_HC1_HDR_LEN;
1125 break;
1126 #if UIP_CONF_TCP
1127 case SICSLOWPAN_HC1_NH_TCP:
1128 SICSLOWPAN_IP_BUF->proto = UIP_PROTO_TCP;
1129 SICSLOWPAN_IP_BUF->ttl = RIME_HC1_PTR[RIME_HC1_TTL];
1130 rime_hdr_len += SICSLOWPAN_HC1_HDR_LEN;
1131 break;
1132 #endif/* UIP_CONF_TCP */
1133 #if UIP_CONF_UDP
1134 case SICSLOWPAN_HC1_NH_UDP:
1135 SICSLOWPAN_IP_BUF->proto = UIP_PROTO_UDP;
1136 if(RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_HC1_ENCODING] & 0x01) {
1137 /* UDP header is compressed with HC_UDP */
1138 if(RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_UDP_ENCODING] !=
1139 SICSLOWPAN_HC_UDP_ALL_C) {
1140 PRINTF("sicslowpan (uncompress_hdr), packet not supported");
1141 return;
1143 /* IP TTL */
1144 SICSLOWPAN_IP_BUF->ttl = RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_TTL];
1145 /* UDP ports, len, checksum */
1146 SICSLOWPAN_UDP_BUF->srcport =
1147 UIP_HTONS(SICSLOWPAN_UDP_PORT_MIN +
1148 (RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_PORTS] >> 4));
1149 SICSLOWPAN_UDP_BUF->destport =
1150 UIP_HTONS(SICSLOWPAN_UDP_PORT_MIN +
1151 (RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_PORTS] & 0x0F));
1152 memcpy(&SICSLOWPAN_UDP_BUF->udpchksum, &RIME_HC1_HC_UDP_PTR[RIME_HC1_HC_UDP_CHKSUM], 2);
1153 uncomp_hdr_len += UIP_UDPH_LEN;
1154 rime_hdr_len += SICSLOWPAN_HC1_HC_UDP_HDR_LEN;
1155 } else {
1156 rime_hdr_len += SICSLOWPAN_HC1_HDR_LEN;
1158 break;
1159 #endif/* UIP_CONF_UDP */
1160 default:
1161 /* this shouldn't happen, drop */
1162 return;
1165 /* IP length field. */
1166 if(ip_len == 0) {
1167 /* This is not a fragmented packet */
1168 SICSLOWPAN_IP_BUF->len[0] = 0;
1169 SICSLOWPAN_IP_BUF->len[1] = packetbuf_datalen() - rime_hdr_len + uncomp_hdr_len - UIP_IPH_LEN;
1170 } else {
1171 /* This is a 1st fragment */
1172 SICSLOWPAN_IP_BUF->len[0] = (ip_len - UIP_IPH_LEN) >> 8;
1173 SICSLOWPAN_IP_BUF->len[1] = (ip_len - UIP_IPH_LEN) & 0x00FF;
1175 /* length field in UDP header */
1176 if(SICSLOWPAN_IP_BUF->proto == UIP_PROTO_UDP) {
1177 memcpy(&SICSLOWPAN_UDP_BUF->udplen, &SICSLOWPAN_IP_BUF->len[0], 2);
1179 return;
1181 /** @} */
1182 #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC1 */
1185 #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6
1186 /*--------------------------------------------------------------------*/
1187 /** \name IPv6 dispatch "compression" function
1188 * @{ */
1189 /*--------------------------------------------------------------------*/
1190 /* \brief Packets "Compression" when only IPv6 dispatch is used
1192 * There is no compression in this case, all fields are sent
1193 * inline. We just add the IPv6 dispatch byte before the packet.
1194 * \verbatim
1195 * 0 1 2 3
1196 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1197 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1198 * | IPv6 Dsp | IPv6 header and payload ...
1199 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1200 * \endverbatim
1202 static void
1203 compress_hdr_ipv6(rimeaddr_t *rime_destaddr) {
1204 *rime_ptr = SICSLOWPAN_DISPATCH_IPV6;
1205 rime_hdr_len += SICSLOWPAN_IPV6_HDR_LEN;
1206 memcpy(rime_ptr + rime_hdr_len, UIP_IP_BUF, UIP_IPH_LEN);
1207 rime_hdr_len += UIP_IPH_LEN;
1208 uncomp_hdr_len += UIP_IPH_LEN;
1209 return;
1211 /** @} */
1212 #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6 */
1216 /*--------------------------------------------------------------------*/
1217 /** \name Input/output functions common to all compression schemes
1218 * @{ */
1219 /*--------------------------------------------------------------------*/
1221 * Callback function for the MAC packet sent callback
1223 static void
1224 packet_sent(void *ptr, int status, int transmissions)
1226 #if SICSLOWPAN_CONF_NEIGHBOR_INFO
1227 neighbor_info_packet_sent(status, transmissions);
1228 #endif /* SICSLOWPAN_CONF_NEIGHBOR_INFO */
1230 /*--------------------------------------------------------------------*/
1232 * \brief This function is called by the 6lowpan code to send out a
1233 * packet.
1234 * \param dest the link layer destination address of the packet
1236 static void
1237 send_packet(rimeaddr_t *dest)
1240 /* Set the link layer destination address for the packet as a
1241 * packetbuf attribute. The MAC layer can access the destination
1242 * address with the function packetbuf_addr(PACKETBUF_ADDR_RECEIVER).
1244 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, dest);
1246 /* Provide a callback function to receive the result of
1247 a packet transmission. */
1248 NETSTACK_MAC.send(&packet_sent, NULL);
1250 /* If we are sending multiple packets in a row, we need to let the
1251 watchdog know that we are still alive. */
1252 watchdog_periodic();
1255 /** \brief Take an IP packet and format it to be sent on an 802.15.4
1256 * network using 6lowpan.
1257 * \param localdest The MAC address of the destination
1259 * The IP packet is initially in uip_buf. Its header is compressed
1260 * and if necessary it is fragmented. The resulting
1261 * packet/fragments are put in packetbuf and delivered to the 802.15.4
1262 * MAC.
1264 static u8_t
1265 output(uip_lladdr_t *localdest)
1267 /* The MAC address of the destination of the packet */
1268 rimeaddr_t dest;
1271 /* init */
1272 uncomp_hdr_len = 0;
1273 rime_hdr_len = 0;
1275 /* reset rime buffer */
1276 packetbuf_clear();
1277 rime_ptr = packetbuf_dataptr();
1279 packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, 3);
1281 #define TCP_FIN 0x01
1282 /* Set stream mode for all TCP packets, except FIN packets. */
1283 if(UIP_IP_BUF->proto == UIP_PROTO_TCP &&
1284 (UIP_TCP_BUF->flags & TCP_FIN) == 0) {
1285 packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
1286 PACKETBUF_ATTR_PACKET_TYPE_STREAM);
1290 * The destination address will be tagged to each outbound
1291 * packet. If the argument localdest is NULL, we are sending a
1292 * broadcast packet.
1294 if(localdest == NULL) {
1295 rimeaddr_copy(&dest, &rimeaddr_null);
1296 } else {
1297 rimeaddr_copy(&dest, (const rimeaddr_t *)localdest);
1300 PRINTFO("sicslowpan output: sending packet len %d\n", uip_len);
1302 /* Try to compress the headers */
1303 #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC1
1304 compress_hdr_hc1(&dest);
1305 #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC1 */
1306 #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6
1307 compress_hdr_ipv6(&dest);
1308 #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6 */
1309 #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06
1310 compress_hdr_hc06(&dest);
1311 #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06 */
1312 PRINTFO("sicslowpan output: header of len %d\n", rime_hdr_len);
1314 if(uip_len - uncomp_hdr_len > MAC_MAX_PAYLOAD - rime_hdr_len) {
1315 #if SICSLOWPAN_CONF_FRAG
1316 struct queuebuf *q;
1318 * The outbound IPv6 packet is too large to fit into a single 15.4
1319 * packet, so we fragment it into multiple packets and send them.
1320 * The first fragment contains frag1 dispatch, then
1321 * IPv6/HC1/HC06/HC_UDP dispatchs/headers.
1322 * The following fragments contain only the fragn dispatch.
1325 /* Create 1st Fragment */
1326 PRINTFO("sicslowpan output: 1rst fragment ");
1328 /* move HC1/HC06/IPv6 header */
1329 memmove(rime_ptr + SICSLOWPAN_FRAG1_HDR_LEN, rime_ptr, rime_hdr_len);
1332 * FRAG1 dispatch + header
1333 * Note that the length is in units of 8 bytes
1335 /* RIME_FRAG_BUF->dispatch_size = */
1336 /* uip_htons((SICSLOWPAN_DISPATCH_FRAG1 << 8) | uip_len); */
1337 SET16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE,
1338 ((SICSLOWPAN_DISPATCH_FRAG1 << 8) | uip_len));
1339 /* RIME_FRAG_BUF->tag = uip_htons(my_tag); */
1340 SET16(RIME_FRAG_PTR, RIME_FRAG_TAG, my_tag);
1342 /* Copy payload and send */
1343 rime_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN;
1344 rime_payload_len = (MAC_MAX_PAYLOAD - rime_hdr_len) & 0xf8;
1345 PRINTFO("(len %d, tag %d)\n", rime_payload_len, my_tag);
1346 memcpy(rime_ptr + rime_hdr_len,
1347 (void *)UIP_IP_BUF + uncomp_hdr_len, rime_payload_len);
1348 packetbuf_set_datalen(rime_payload_len + rime_hdr_len);
1349 q = queuebuf_new_from_packetbuf();
1350 if(q == NULL) {
1351 PRINTFO("could not allocate queuebuf for first fragment, dropping packet\n");
1352 return 0;
1354 send_packet(&dest);
1355 queuebuf_to_packetbuf(q);
1356 queuebuf_free(q);
1357 q = NULL;
1359 /* set processed_ip_len to what we already sent from the IP payload*/
1360 processed_ip_len = rime_payload_len + uncomp_hdr_len;
1363 * Create following fragments
1364 * Datagram tag is already in the buffer, we need to set the
1365 * FRAGN dispatch and for each fragment, the offset
1367 rime_hdr_len = SICSLOWPAN_FRAGN_HDR_LEN;
1368 /* RIME_FRAG_BUF->dispatch_size = */
1369 /* uip_htons((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len); */
1370 SET16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE,
1371 ((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len));
1372 rime_payload_len = (MAC_MAX_PAYLOAD - rime_hdr_len) & 0xf8;
1373 while(processed_ip_len < uip_len){
1374 PRINTFO("sicslowpan output: fragment ");
1375 RIME_FRAG_PTR[RIME_FRAG_OFFSET] = processed_ip_len >> 3;
1377 /* Copy payload and send */
1378 if(uip_len - processed_ip_len < rime_payload_len){
1379 /* last fragment */
1380 rime_payload_len = uip_len - processed_ip_len;
1382 PRINTFO("(offset %d, len %d, tag %d)\n",
1383 processed_ip_len >> 3, rime_payload_len, my_tag);
1384 memcpy(rime_ptr + rime_hdr_len,
1385 (void *)UIP_IP_BUF + processed_ip_len, rime_payload_len);
1386 packetbuf_set_datalen(rime_payload_len + rime_hdr_len);
1387 q = queuebuf_new_from_packetbuf();
1388 if(q == NULL) {
1389 PRINTFO("could not allocate queuebuf, dropping fragment\n");
1390 return 0;
1392 send_packet(&dest);
1393 queuebuf_to_packetbuf(q);
1394 queuebuf_free(q);
1395 q = NULL;
1396 processed_ip_len += rime_payload_len;
1399 /* end: reset global variables */
1400 my_tag++;
1401 processed_ip_len = 0;
1402 #else /* SICSLOWPAN_CONF_FRAG */
1403 PRINTFO("sicslowpan output: Packet too large to be sent without fragmentation support; dropping packet\n");
1404 return 0;
1405 #endif /* SICSLOWPAN_CONF_FRAG */
1406 } else {
1408 * The packet does not need to be fragmented
1409 * copy "payload" and send
1411 memcpy(rime_ptr + rime_hdr_len, (void *)UIP_IP_BUF + uncomp_hdr_len,
1412 uip_len - uncomp_hdr_len);
1413 packetbuf_set_datalen(uip_len - uncomp_hdr_len + rime_hdr_len);
1414 send_packet(&dest);
1416 return 1;
1419 /*--------------------------------------------------------------------*/
1420 /** \brief Process a received 6lowpan packet.
1421 * \param r The MAC layer
1423 * The 6lowpan packet is put in packetbuf by the MAC. If its a frag1 or
1424 * a non-fragmented packet we first uncompress the IP header. The
1425 * 6lowpan payload and possibly the uncompressed IP header are then
1426 * copied in siclowpan_buf. If the IP packet is complete it is copied
1427 * to uip_buf and the IP layer is called.
1429 * \note We do not check for overlapping sicslowpan fragments
1430 * (it is a SHALL in the RFC 4944 and should never happen)
1432 static void
1433 input(void)
1435 /* size of the IP packet (read from fragment) */
1436 u16_t frag_size = 0;
1437 /* offset of the fragment in the IP packet */
1438 u8_t frag_offset = 0;
1439 #if SICSLOWPAN_CONF_FRAG
1440 /* tag of the fragment */
1441 u16_t frag_tag = 0;
1442 #endif /*SICSLOWPAN_CONF_FRAG*/
1444 /* init */
1445 uncomp_hdr_len = 0;
1446 rime_hdr_len = 0;
1448 /* The MAC puts the 15.4 payload inside the RIME data buffer */
1449 rime_ptr = packetbuf_dataptr();
1451 #if SICSLOWPAN_CONF_FRAG
1452 /* if reassembly timed out, cancel it */
1453 if(timer_expired(&reass_timer)){
1454 sicslowpan_len = 0;
1455 processed_ip_len = 0;
1458 * Since we don't support the mesh and broadcast header, the first header
1459 * we look for is the fragmentation header
1461 switch((GET16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE) & 0xf800) >> 8) {
1462 case SICSLOWPAN_DISPATCH_FRAG1:
1463 PRINTFI("sicslowpan input: FRAG1 ");
1464 frag_offset = 0;
1465 /* frag_size = (uip_ntohs(RIME_FRAG_BUF->dispatch_size) & 0x07ff); */
1466 frag_size = GET16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE) & 0x07ff;
1467 /* frag_tag = uip_ntohs(RIME_FRAG_BUF->tag); */
1468 frag_tag = GET16(RIME_FRAG_PTR, RIME_FRAG_TAG);
1469 PRINTFI("size %d, tag %d, offset %d)\n",
1470 frag_size, frag_tag, frag_offset);
1471 rime_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN;
1472 /* printf("frag1 %d %d\n", reass_tag, frag_tag);*/
1473 break;
1474 case SICSLOWPAN_DISPATCH_FRAGN:
1476 * set offset, tag, size
1477 * Offset is in units of 8 bytes
1479 PRINTFI("sicslowpan input: FRAGN ");
1480 frag_offset = RIME_FRAG_PTR[RIME_FRAG_OFFSET];
1481 frag_tag = GET16(RIME_FRAG_PTR, RIME_FRAG_TAG);
1482 frag_size = GET16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE) & 0x07ff;
1483 PRINTFI("size %d, tag %d, offset %d)\n",
1484 frag_size, frag_tag, frag_offset);
1485 rime_hdr_len += SICSLOWPAN_FRAGN_HDR_LEN;
1486 break;
1487 default:
1488 break;
1491 if(processed_ip_len > 0) {
1492 /* reassembly is ongoing */
1493 /* printf("frag %d %d\n", reass_tag, frag_tag);*/
1494 if((frag_size > 0 &&
1495 (frag_size != sicslowpan_len ||
1496 reass_tag != frag_tag ||
1497 !rimeaddr_cmp(&frag_sender, packetbuf_addr(PACKETBUF_ADDR_SENDER)))) ||
1498 frag_size == 0) {
1500 * the packet is a fragment that does not belong to the packet
1501 * being reassembled or the packet is not a fragment.
1503 PRINTFI("sicslowpan input: Dropping 6lowpan packet that is not a fragment of the packet currently being reassembled\n");
1504 return;
1506 } else {
1508 * reassembly is off
1509 * start it if we received a fragment
1511 if(frag_size > 0){
1512 sicslowpan_len = frag_size;
1513 reass_tag = frag_tag;
1514 timer_set(&reass_timer, SICSLOWPAN_REASS_MAXAGE*CLOCK_SECOND);
1515 PRINTFI("sicslowpan input: INIT FRAGMENTATION (len %d, tag %d)\n",
1516 sicslowpan_len, reass_tag);
1517 rimeaddr_copy(&frag_sender, packetbuf_addr(PACKETBUF_ADDR_SENDER));
1521 if(rime_hdr_len == SICSLOWPAN_FRAGN_HDR_LEN) {
1522 /* this is a FRAGN, skip the header compression dispatch section */
1523 goto copypayload;
1525 #endif /* SICSLOWPAN_CONF_FRAG */
1527 /* Process next dispatch and headers */
1528 #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06
1529 if((RIME_HC1_PTR[RIME_HC1_DISPATCH] & 0xe0) == SICSLOWPAN_DISPATCH_IPHC) {
1530 PRINTFI("sicslowpan input: IPHC\n");
1531 uncompress_hdr_hc06(frag_size);
1532 } else
1533 #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06 */
1534 switch(RIME_HC1_PTR[RIME_HC1_DISPATCH]) {
1535 #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC1
1536 case SICSLOWPAN_DISPATCH_HC1:
1537 PRINTFI("sicslowpan input: HC1\n");
1538 uncompress_hdr_hc1(frag_size);
1539 break;
1540 #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC1 */
1541 case SICSLOWPAN_DISPATCH_IPV6:
1542 PRINTFI("sicslowpan input: IPV6\n");
1543 rime_hdr_len += SICSLOWPAN_IPV6_HDR_LEN;
1545 /* Put uncompressed IP header in sicslowpan_buf. */
1546 memcpy(SICSLOWPAN_IP_BUF, rime_ptr + rime_hdr_len, UIP_IPH_LEN);
1548 /* Update uncomp_hdr_len and rime_hdr_len. */
1549 rime_hdr_len += UIP_IPH_LEN;
1550 uncomp_hdr_len += UIP_IPH_LEN;
1551 break;
1552 default:
1553 /* unknown header */
1554 PRINTFI("sicslowpan input: unknown dispatch: %u\n",
1555 RIME_HC1_PTR[RIME_HC1_DISPATCH]);
1556 return;
1560 #if SICSLOWPAN_CONF_FRAG
1561 copypayload:
1562 #endif /*SICSLOWPAN_CONF_FRAG*/
1564 * copy "payload" from the rime buffer to the sicslowpan_buf
1565 * if this is a first fragment or not fragmented packet,
1566 * we have already copied the compressed headers, uncomp_hdr_len
1567 * and rime_hdr_len are non 0, frag_offset is.
1568 * If this is a subsequent fragment, this is the contrary.
1570 if(packetbuf_datalen() < rime_hdr_len) {
1571 PRINTF("SICSLOWPAN: packet dropped due to header > total packet\n");
1572 return;
1574 rime_payload_len = packetbuf_datalen() - rime_hdr_len;
1575 memcpy((void *)SICSLOWPAN_IP_BUF + uncomp_hdr_len + (u16_t)(frag_offset << 3), rime_ptr + rime_hdr_len, rime_payload_len);
1577 /* update processed_ip_len if fragment, sicslowpan_len otherwise */
1579 #if SICSLOWPAN_CONF_FRAG
1580 if(frag_size > 0){
1581 if(processed_ip_len == 0) {
1582 processed_ip_len += uncomp_hdr_len;
1584 processed_ip_len += rime_payload_len;
1585 } else {
1586 #endif /* SICSLOWPAN_CONF_FRAG */
1587 sicslowpan_len = rime_payload_len + uncomp_hdr_len;
1588 #if SICSLOWPAN_CONF_FRAG
1592 * If we have a full IP packet in sicslowpan_buf, deliver it to
1593 * the IP stack
1595 if(processed_ip_len == 0 || (processed_ip_len == sicslowpan_len)){
1596 PRINTFI("sicslowpan input: IP packet ready (length %d)\n",
1597 sicslowpan_len);
1598 memcpy((void *)UIP_IP_BUF, (void *)SICSLOWPAN_IP_BUF, sicslowpan_len);
1599 uip_len = sicslowpan_len;
1600 sicslowpan_len = 0;
1601 processed_ip_len = 0;
1602 #endif /* SICSLOWPAN_CONF_FRAG */
1604 #if DEBUG
1606 uint8_t tmp;
1607 PRINTF("after decompression: ");
1608 for (tmp = 0; tmp < SICSLOWPAN_IP_BUF->len[1] + 40; tmp++) {
1609 uint8_t data = ((uint8_t *) (SICSLOWPAN_IP_BUF))[tmp];
1610 PRINTF("%02x", data);
1612 PRINTF("\n");
1614 #endif
1616 #if SICSLOWPAN_CONF_NEIGHBOR_INFO
1617 neighbor_info_packet_received();
1618 #endif /* SICSLOWPAN_CONF_NEIGHBOR_INFO */
1620 tcpip_input();
1621 #if SICSLOWPAN_CONF_FRAG
1623 #endif /* SICSLOWPAN_CONF_FRAG */
1625 /** @} */
1627 /*--------------------------------------------------------------------*/
1628 /* \brief 6lowpan init function (called by the MAC layer) */
1629 /*--------------------------------------------------------------------*/
1630 void
1631 sicslowpan_init(void)
1633 /* remember the mac driver */
1634 sicslowpan_mac = &NETSTACK_MAC;
1637 * Set out output function as the function to be called from uIP to
1638 * send a packet.
1640 tcpip_set_outputfunc(output);
1642 #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06
1643 #if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0
1644 addr_contexts[0].used = 1;
1645 addr_contexts[0].number = 0;
1646 addr_contexts[0].prefix[0] = 0xaa;
1647 addr_contexts[0].prefix[1] = 0xaa;
1648 #endif /* SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0 */
1649 #if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 1
1651 int i;
1652 for(i = 1; i < SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; i++) {
1653 addr_contexts[i].used = 0;
1656 #endif /* SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 1 */
1658 #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06 */
1660 /*--------------------------------------------------------------------*/
1661 const struct network_driver sicslowpan_driver = {
1662 "sicslowpan",
1663 sicslowpan_init,
1664 input
1666 /*--------------------------------------------------------------------*/
1667 /** @} */