blob: 1e0e1f7b0aac1ede6d07488c9bdf97de124d5fbb [file] [log] [blame]
/* sicslowpan_compression.c - IPv6 header compression */
/*
* Copyright (c) 2015 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (c) 2008, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* 6lowpan implementation (RFC4944 and draft-ietf-6lowpan-hc-06)
*
* \author Adam Dunkels <adam@sics.se>
* \author Nicolas Tsiftes <nvt@sics.se>
* \author Niclas Finne <nfi@sics.se>
* \author Mathilde Durvy <mdurvy@cisco.com>
* \author Julien Abeille <jabeille@cisco.com>
* \author Joakim Eriksson <joakime@sics.se>
* \author Joel Hoglund <joel@sics.se>
*/
#include <stdio.h>
#include <string.h>
#include <net/l2_buf.h>
#include "contiki/sicslowpan/sicslowpan_compression.h"
#include "contiki/netstack.h"
#include "contiki/packetbuf.h"
#include "contiki/ip/uip.h"
#include "contiki/ip/tcpip.h"
#include "dev/watchdog.h"
#include "contiki/ipv6/uip-ds6.h"
#ifdef CONFIG_NETWORK_IP_STACK_DEBUG_6LOWPAN_COMPRESSION
#define DEBUG 1
#endif
#include "contiki/ip/uip-debug.h"
#if DEBUG
#define PRINTPACKETBUF() do { uint8_t p; PRINTF("packetbuf buffer: "); for(p = 0; p < packetbuf_datalen(); p++){PRINTF("%.2X", *(packetbuf_ptr + p));} PRINTF("\n"); } while(0)
#define PRINTUIPBUF() do { uint8_t p; PRINTF("UIP buffer: "); for(p = 0; p < uip_len; p++){PRINTF("%.2X", uip_buf[p]);}PRINTF("\n"); } while(0)
#define PRINTSICSLOWPANBUF() do { uint8_t p; PRINTF("SICSLOWPAN buffer: "); for(p = 0; p < sicslowpan_len; p++){PRINTF("%.2X", sicslowpan_buf[p]);}PRINTF("\n"); } while(0)
#else
#define PRINTPACKETBUF()
#define PRINTUIPBUF()
#define PRINTSICSLOWPANBUF()
#endif /* DEBUG == 1*/
#if UIP_LOGGING
#include <stdio.h>
void uip_log(char *msg);
#define UIP_LOG(m) uip_log(m)
#else
#define UIP_LOG(m)
#endif /* UIP_LOGGING == 1 */
#ifndef SICSLOWPAN_COMPRESSION
#ifdef SICSLOWPAN_CONF_COMPRESSION
#define SICSLOWPAN_COMPRESSION SICSLOWPAN_CONF_COMPRESSION
#else
#define SICSLOWPAN_COMPRESSION SICSLOWPAN_COMPRESSION_IPV6
#endif /* SICSLOWPAN_CONF_COMPRESSION */
#endif /* SICSLOWPAN_COMPRESSION */
#if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC1
#error 6LoWPAN HC1 compression not supported
#endif
#if (SICSLOWPAN_COMPRESSION != SICSLOWPAN_COMPRESSION_IPHC) && (SICSLOWPAN_COMPRESSION != SICSLOWPAN_COMPRESSION_IPV6)
#error Unsupported 6LoWPAN compression. Please set SICSLOWPAN_CONF_COMPRESSION.
#endif
#define GET16(ptr,index) (((uint16_t)((ptr)[index] << 8)) | ((ptr)[(index) + 1]))
#define SET16(ptr,index,value) do { \
(ptr)[index] = ((value) >> 8) & 0xff; \
(ptr)[index + 1] = (value) & 0xff; \
} while(0)
/** \name Pointers in the packetbuf buffer
* @{
*/
/* define the buffer as a byte array */
#define PACKETBUF_IPHC_BUF(buf) ((uint8_t *)(uip_packetbuf_ptr(buf) + uip_packetbuf_hdr_len(buf)))
#define PACKETBUF_HC1_PTR(buf) (uip_packetbuf_ptr(buf) + uip_packetbuf_hdr_len(buf))
#define PACKETBUF_HC1_DISPATCH 0 /* 8 bit */
/** \name Pointers in the sicslowpan and uip buffer
* @{
*/
#define SICSLOWPAN_IP_BUF(buf) ((struct uip_ip_hdr *)&buf[UIP_LLH_LEN])
#define SICSLOWPAN_UDP_BUF(buf) ((struct uip_udp_hdr *)&buf[UIP_LLIPH_LEN])
#define UIP_IP_BUF(buf) ((struct uip_ip_hdr *)&uip_buf(buf)[UIP_LLH_LEN])
#define UIP_UDP_BUF(buf) ((struct uip_udp_hdr *)&uip_buf(buf)[UIP_LLIPH_LEN])
#define UIP_TCP_BUF(buf) ((struct uip_tcp_hdr *)&uip_buf(buf)[UIP_LLIPH_LEN])
#define UIP_ICMP_BUF(buf) ((struct uip_icmp_hdr *)&uip_buf(buf)[UIP_LLIPH_LEN])
/** @} */
#define sicslowpan_buf uip_buf
#define sicslowpan_len uip_len
/** \brief Maximum available size for frame headers,
link layer security-related overhead, as well as
6LoWPAN payload. */
#ifdef SICSLOWPAN_CONF_MAC_MAX_PAYLOAD
#define MAC_MAX_PAYLOAD SICSLOWPAN_CONF_MAC_MAX_PAYLOAD
#else /* SICSLOWPAN_CONF_MAC_MAX_PAYLOAD */
#define MAC_MAX_PAYLOAD (127 - 2)
#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. */
#ifdef SICSLOWPAN_CONF_COMPRESSION_THRESHOLD
#define COMPRESSION_THRESHOLD SICSLOWPAN_CONF_COMPRESSION_THRESHOLD
#else
#define COMPRESSION_THRESHOLD 0
#endif
#if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPHC
/** \name IPHC specific variables
* @{
*/
/** Addresses contexts for IPHC. */
#if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0
static struct sicslowpan_addr_context
addr_contexts[SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS];
#endif
/** pointer to an address context. */
static struct sicslowpan_addr_context *context;
/** pointer to the byte where to write next inline field. */
static uint8_t *iphc_ptr;
/* Uncompression 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 */
/* 3 -> 2 bytes from prefix - infer 8 bytes from lladdr */
/* NOTE: => the uncompress function does change 0xf to 0x10 */
/* NOTE: 0x00 => no-autoconfig => unspecified */
const uint8_t unc_llconf[] = {0x0f,0x28,0x22,0x20};
/* Uncompression of ctx-based */
/* 0 -> 0 bits from packet [unspecified / reserved] */
/* 1 -> 8 bytes from prefix - bunch of zeroes and 8 from packet */
/* 2 -> 8 bytes from prefix - 0000::00ff:fe00:XXXX + 2 from packet */
/* 3 -> 8 bytes from prefix - infer 8 bytes from lladdr */
const uint8_t unc_ctxconf[] = {0x00,0x88,0x82,0x80};
/* Uncompression of ctx-based */
/* 0 -> 0 bits from packet */
/* 1 -> 2 bytes from prefix - bunch of zeroes 5 from packet */
/* 2 -> 2 bytes from prefix - zeroes + 3 from packet */
/* 3 -> 2 bytes from prefix - infer 1 bytes from lladdr */
const uint8_t unc_mxconf[] = {0x0f, 0x25, 0x23, 0x21};
/* Link local prefix */
const uint8_t llprefix[] = {0xfe, 0x80};
/* TTL uncompression values */
static const uint8_t ttl_values[] = {0, 1, 64, 255};
/*--------------------------------------------------------------------*/
/** \name IPHC related functions
* @{ */
/*--------------------------------------------------------------------*/
/** \brief find the context corresponding to prefix ipaddr */
static struct sicslowpan_addr_context*
addr_context_lookup_by_prefix(uip_ipaddr_t *ipaddr)
{
/* Remove code to avoid warnings and save flash if no context is used */
#if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0
int i;
for(i = 0; i < SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; i++) {
if((addr_contexts[i].used == 1) &&
uip_ipaddr_prefixcmp(&addr_contexts[i].prefix, ipaddr, 64)) {
return &addr_contexts[i];
}
}
#endif /* SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0 */
return NULL;
}
/*--------------------------------------------------------------------*/
/** \brief find the context with the given number */
static struct sicslowpan_addr_context*
addr_context_lookup_by_number(uint8_t number)
{
/* Remove code to avoid warnings and save flash if no context is used */
#if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0
int i;
for(i = 0; i < SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; i++) {
if((addr_contexts[i].used == 1) &&
addr_contexts[i].number == number) {
return &addr_contexts[i];
}
}
#endif /* SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0 */
return NULL;
}
/*--------------------------------------------------------------------*/
static uint8_t
compress_addr_64(uint8_t bitpos, uip_ipaddr_t *ipaddr, uip_lladdr_t *lladdr)
{
if(uip_is_addr_mac_addr_based(ipaddr, lladdr)) {
return 3 << bitpos; /* 0-bits */
} else if(sicslowpan_is_iid_16_bit_compressable(ipaddr)) {
/* compress IID to 16 bits xxxx::0000:00ff:fe00:XXXX */
memcpy(iphc_ptr, &ipaddr->u16[7], 2);
iphc_ptr += 2;
return 2 << bitpos; /* 16-bits */
} else {
/* do not compress IID => xxxx::IID */
memcpy(iphc_ptr, &ipaddr->u16[4], 8);
iphc_ptr += 8;
return 1 << bitpos; /* 64-bits */
}
}
/*-------------------------------------------------------------------- */
/* Uncompress addresses based on a prefix and a postfix with zeroes in
* between. If the postfix is zero in length it will use the link address
* to configure the IP address (autoconf style).
* pref_post_count takes a byte where the first nibble specify prefix count
* and the second postfix count (NOTE: 15/0xf => 16 bytes copy).
*/
static void
uncompress_addr(uip_ipaddr_t *ipaddr, uint8_t const prefix[],
uint8_t pref_post_count, uip_lladdr_t *lladdr)
{
uint8_t prefcount = pref_post_count >> 4;
uint8_t postcount = pref_post_count & 0x0f;
/* full nibble 15 => 16 */
prefcount = prefcount == 15 ? 16 : prefcount;
postcount = postcount == 15 ? 16 : postcount;
PRINTF("Uncompressing %d + %d => ", prefcount, postcount);
if(prefcount > 0) {
memcpy(ipaddr, prefix, prefcount);
}
if(prefcount + postcount < 16) {
memset(&ipaddr->u8[prefcount], 0, 16 - (prefcount + postcount));
}
if(postcount > 0) {
memcpy(&ipaddr->u8[16 - postcount], iphc_ptr, postcount);
if(postcount == 2 && prefcount < 11) {
/* 16 bits uncompression => 0000:00ff:fe00:XXXX */
ipaddr->u8[11] = 0xff;
ipaddr->u8[12] = 0xfe;
}
iphc_ptr += postcount;
} else if (prefcount > 0) {
/* no IID based configuration if no prefix and no data => unspec */
uip_ds6_set_addr_iid(ipaddr, lladdr);
}
PRINT6ADDR(ipaddr);
PRINTF("\n");
}
/*--------------------------------------------------------------------*/
/**
* \brief Compress IP/UDP header
*
* This function is called by the 6lowpan code to create a compressed
* 6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
* uip_buf buffer.
*
*
* IPHC (RFC 6282)
* http://tools.ietf.org/html/
*
* \note We do not support ISA100_UDP header compression
*
* For LOWPAN_UDP compression, we either compress both ports or none.
* General format with LOWPAN_UDP compression is
* \verbatim
* 1 2 3
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |0|1|1|TF |N|HLI|C|S|SAM|M|D|DAM| SCI | DCI | comp. IPv6 hdr|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | compressed IPv6 fields ..... |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | LOWPAN_UDP | non compressed UDP fields ... |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | L4 data ... |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* \endverbatim
* \note The context number 00 is reserved for the link local prefix.
* For unicast addresses, if we cannot compress the prefix, we neither
* compress the IID.
* \param link_destaddr L2 destination address, needed to compress IP
* dest
*/
static int
compress_hdr_iphc(struct net_buf *mbuf, struct net_buf *buf, linkaddr_t *link_destaddr)
{
uint8_t tmp, iphc0, iphc1;
iphc_ptr = uip_packetbuf_ptr(mbuf) + 2;
/*
* As we copy some bit-length fields, in the IPHC encoding bytes,
* we sometimes use |=
* If the field is 0, and the current bit value in memory is 1,
* this does not work. We therefore reset the IPHC encoding here
*/
iphc0 = SICSLOWPAN_DISPATCH_IPHC;
iphc1 = 0;
PACKETBUF_IPHC_BUF(mbuf)[2] = 0; /* might not be used - but needs to be cleared */
/*
* Address handling needs to be made first since it might
* cause an extra byte with [ SCI | DCI ]
*
*/
/* check if dest context exists (for allocating third byte) */
/* TODO: fix this so that it remembers the looked up values for
avoiding two lookups - or set the lookup values immediately */
if(addr_context_lookup_by_prefix(&UIP_IP_BUF(buf)->destipaddr) != NULL ||
addr_context_lookup_by_prefix(&UIP_IP_BUF(buf)->srcipaddr) != NULL) {
/* set context flag and increase iphc_ptr */
PRINTF("IPHC: compressing dest or src ipaddr - setting CID\n");
iphc1 |= SICSLOWPAN_IPHC_CID;
iphc_ptr++;
}
/*
* Traffic class, flow label
* If flow label is 0, compress it. If traffic class is 0, compress it
* We have to process both in the same time as the offset of traffic class
* depends on the presence of version and flow label
*/
/* IPHC format of tc is ECN | DSCP , original is DSCP | ECN */
tmp = (UIP_IP_BUF(buf)->vtc << 4) | (UIP_IP_BUF(buf)->tcflow >> 4);
tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
if(((UIP_IP_BUF(buf)->tcflow & 0x0F) == 0) &&
(UIP_IP_BUF(buf)->flow == 0)) {
/* flow label can be compressed */
iphc0 |= SICSLOWPAN_IPHC_FL_C;
if(((UIP_IP_BUF(buf)->vtc & 0x0F) == 0) &&
((UIP_IP_BUF(buf)->tcflow & 0xF0) == 0)) {
/* compress (elide) all */
iphc0 |= SICSLOWPAN_IPHC_TC_C;
} else {
/* compress only the flow label */
*iphc_ptr = tmp;
iphc_ptr += 1;
}
} else {
/* Flow label cannot be compressed */
if(((UIP_IP_BUF(buf)->vtc & 0x0F) == 0) &&
((UIP_IP_BUF(buf)->tcflow & 0xF0) == 0)) {
/* compress only traffic class */
iphc0 |= SICSLOWPAN_IPHC_TC_C;
*iphc_ptr = (tmp & 0xc0) |
(UIP_IP_BUF(buf)->tcflow & 0x0F);
memcpy(iphc_ptr + 1, &UIP_IP_BUF(buf)->flow, 2);
iphc_ptr += 3;
} else {
/* compress nothing */
memcpy(iphc_ptr, &UIP_IP_BUF(buf)->vtc, 4);
/* but replace the top byte with the new ECN | DSCP format*/
*iphc_ptr = tmp;
iphc_ptr += 4;
}
}
/* Note that the payload length is always compressed */
/* Next header. We compress it if UDP */
#if UIP_CONF_UDP || UIP_CONF_ROUTER
if(UIP_IP_BUF(buf)->proto == UIP_PROTO_UDP) {
iphc0 |= SICSLOWPAN_IPHC_NH_C;
}
#endif /*UIP_CONF_UDP*/
if ((iphc0 & SICSLOWPAN_IPHC_NH_C) == 0) {
*iphc_ptr = UIP_IP_BUF(buf)->proto;
iphc_ptr += 1;
}
/*
* Hop limit
* if 1: compress, encoding is 01
* if 64: compress, encoding is 10
* if 255: compress, encoding is 11
* else do not compress
*/
switch(UIP_IP_BUF(buf)->ttl) {
case 1:
iphc0 |= SICSLOWPAN_IPHC_TTL_1;
break;
case 64:
iphc0 |= SICSLOWPAN_IPHC_TTL_64;
break;
case 255:
iphc0 |= SICSLOWPAN_IPHC_TTL_255;
break;
default:
*iphc_ptr = UIP_IP_BUF(buf)->ttl;
iphc_ptr += 1;
break;
}
/* source address - cannot be multicast */
if(uip_is_addr_unspecified(&UIP_IP_BUF(buf)->srcipaddr)) {
PRINTF("IPHC: compressing unspecified - setting SAC\n");
iphc1 |= SICSLOWPAN_IPHC_SAC;
iphc1 |= SICSLOWPAN_IPHC_SAM_00;
} else if((context = addr_context_lookup_by_prefix(&UIP_IP_BUF(buf)->srcipaddr))
!= NULL) {
/* elide the prefix - indicate by CID and set context + SAC */
PRINTF("IPHC: compressing src with context - setting CID & SAC ctx: %d\n",
context->number);
iphc1 |= SICSLOWPAN_IPHC_CID | SICSLOWPAN_IPHC_SAC;
PACKETBUF_IPHC_BUF(mbuf)[2] |= context->number << 4;
/* compession compare with this nodes address (source) */
iphc1 |= compress_addr_64(SICSLOWPAN_IPHC_SAM_BIT,
&UIP_IP_BUF(buf)->srcipaddr, &uip_lladdr);
/* No context found for this address */
} else if(uip_is_addr_link_local(&UIP_IP_BUF(buf)->srcipaddr) &&
UIP_IP_BUF(buf)->destipaddr.u16[1] == 0 &&
UIP_IP_BUF(buf)->destipaddr.u16[2] == 0 &&
UIP_IP_BUF(buf)->destipaddr.u16[3] == 0) {
iphc1 |= compress_addr_64(SICSLOWPAN_IPHC_SAM_BIT,
&UIP_IP_BUF(buf)->srcipaddr, &uip_lladdr);
} else {
/* send the full address => SAC = 0, SAM = 00 */
iphc1 |= SICSLOWPAN_IPHC_SAM_00; /* 128-bits */
memcpy(iphc_ptr, &UIP_IP_BUF(buf)->srcipaddr.u16[0], 16);
iphc_ptr += 16;
}
/* dest address*/
if(uip_is_addr_mcast(&UIP_IP_BUF(buf)->destipaddr)) {
/* Address is multicast, try to compress */
iphc1 |= SICSLOWPAN_IPHC_M;
if(sicslowpan_is_mcast_addr_compressable8(&UIP_IP_BUF(buf)->destipaddr)) {
iphc1 |= SICSLOWPAN_IPHC_DAM_11;
/* use last byte */
*iphc_ptr = UIP_IP_BUF(buf)->destipaddr.u8[15];
iphc_ptr += 1;
} else if(sicslowpan_is_mcast_addr_compressable32(&UIP_IP_BUF(buf)->destipaddr)) {
iphc1 |= SICSLOWPAN_IPHC_DAM_10;
/* second byte + the last three */
*iphc_ptr = UIP_IP_BUF(buf)->destipaddr.u8[1];
memcpy(iphc_ptr + 1, &UIP_IP_BUF(buf)->destipaddr.u8[13], 3);
iphc_ptr += 4;
} else if(sicslowpan_is_mcast_addr_compressable48(&UIP_IP_BUF(buf)->destipaddr)) {
iphc1 |= SICSLOWPAN_IPHC_DAM_01;
/* second byte + the last five */
*iphc_ptr = UIP_IP_BUF(buf)->destipaddr.u8[1];
memcpy(iphc_ptr + 1, &UIP_IP_BUF(buf)->destipaddr.u8[11], 5);
iphc_ptr += 6;
} else {
iphc1 |= SICSLOWPAN_IPHC_DAM_00;
/* full address */
memcpy(iphc_ptr, &UIP_IP_BUF(buf)->destipaddr.u8[0], 16);
iphc_ptr += 16;
}
} else {
/* Address is unicast, try to compress */
if((context = addr_context_lookup_by_prefix(&UIP_IP_BUF(buf)->destipaddr)) != NULL) {
/* elide the prefix */
iphc1 |= SICSLOWPAN_IPHC_DAC;
PACKETBUF_IPHC_BUF(mbuf)[2] |= context->number;
/* compession compare with link adress (destination) */
iphc1 |= compress_addr_64(SICSLOWPAN_IPHC_DAM_BIT,
&UIP_IP_BUF(buf)->destipaddr, (uip_lladdr_t *)link_destaddr);
/* No context found for this address */
} else if(uip_is_addr_link_local(&UIP_IP_BUF(buf)->destipaddr) &&
UIP_IP_BUF(buf)->destipaddr.u16[1] == 0 &&
UIP_IP_BUF(buf)->destipaddr.u16[2] == 0 &&
UIP_IP_BUF(buf)->destipaddr.u16[3] == 0) {
iphc1 |= compress_addr_64(SICSLOWPAN_IPHC_DAM_BIT,
&UIP_IP_BUF(buf)->destipaddr, (uip_lladdr_t *)link_destaddr);
} else {
/* send the full address */
iphc1 |= SICSLOWPAN_IPHC_DAM_00; /* 128-bits */
memcpy(iphc_ptr, &UIP_IP_BUF(buf)->destipaddr.u16[0], 16);
iphc_ptr += 16;
}
}
uip_uncomp_hdr_len(mbuf) = UIP_IPH_LEN;
#if UIP_CONF_UDP || UIP_CONF_ROUTER
/* UDP header compression */
if(UIP_IP_BUF(buf)->proto == UIP_PROTO_UDP) {
PRINTF("IPHC: Uncompressed UDP ports on send side: %x, %x\n",
UIP_HTONS(UIP_UDP_BUF(buf)->srcport), UIP_HTONS(UIP_UDP_BUF(buf)->destport));
/* Mask out the last 4 bits can be used as a mask */
if(((UIP_HTONS(UIP_UDP_BUF(buf)->srcport) & 0xfff0) == SICSLOWPAN_UDP_4_BIT_PORT_MIN) &&
((UIP_HTONS(UIP_UDP_BUF(buf)->destport) & 0xfff0) == SICSLOWPAN_UDP_4_BIT_PORT_MIN)) {
/* we can compress 12 bits of both source and dest */
*iphc_ptr = SICSLOWPAN_NHC_UDP_CS_P_11;
PRINTF("IPHC: remove 12 b of both source & dest with prefix 0xFOB\n");
*(iphc_ptr + 1) =
(uint8_t)((UIP_HTONS(UIP_UDP_BUF(buf)->srcport) -
SICSLOWPAN_UDP_4_BIT_PORT_MIN) << 4) +
(uint8_t)((UIP_HTONS(UIP_UDP_BUF(buf)->destport) -
SICSLOWPAN_UDP_4_BIT_PORT_MIN));
iphc_ptr += 2;
} else if((UIP_HTONS(UIP_UDP_BUF(buf)->destport) & 0xff00) == SICSLOWPAN_UDP_8_BIT_PORT_MIN) {
/* we can compress 8 bits of dest, leave source. */
*iphc_ptr = SICSLOWPAN_NHC_UDP_CS_P_01;
PRINTF("IPHC: leave source, remove 8 bits of dest with prefix 0xF0\n");
memcpy(iphc_ptr + 1, &UIP_UDP_BUF(buf)->srcport, 2);
*(iphc_ptr + 3) =
(uint8_t)((UIP_HTONS(UIP_UDP_BUF(buf)->destport) -
SICSLOWPAN_UDP_8_BIT_PORT_MIN));
iphc_ptr += 4;
} else if((UIP_HTONS(UIP_UDP_BUF(buf)->srcport) & 0xff00) == SICSLOWPAN_UDP_8_BIT_PORT_MIN) {
/* we can compress 8 bits of src, leave dest. Copy compressed port */
*iphc_ptr = SICSLOWPAN_NHC_UDP_CS_P_10;
PRINTF("IPHC: remove 8 bits of source with prefix 0xF0, leave dest. hch: %i\n", *iphc_ptr);
*(iphc_ptr + 1) =
(uint8_t)((UIP_HTONS(UIP_UDP_BUF(buf)->srcport) -
SICSLOWPAN_UDP_8_BIT_PORT_MIN));
memcpy(iphc_ptr + 2, &UIP_UDP_BUF(buf)->destport, 2);
iphc_ptr += 4;
} else {
/* we cannot compress. Copy uncompressed ports, full checksum */
*iphc_ptr = SICSLOWPAN_NHC_UDP_CS_P_00;
PRINTF("IPHC: cannot compress headers\n");
memcpy(iphc_ptr + 1, &UIP_UDP_BUF(buf)->srcport, 4);
iphc_ptr += 5;
}
/* always inline the checksum */
if(1) {
memcpy(iphc_ptr, &UIP_UDP_BUF(buf)->udpchksum, 2);
iphc_ptr += 2;
}
uip_uncomp_hdr_len(mbuf) += UIP_UDPH_LEN;
}
#endif /*UIP_CONF_UDP*/
/* before the packetbuf_hdr_len operation */
PACKETBUF_IPHC_BUF(mbuf)[0] = iphc0;
PACKETBUF_IPHC_BUF(mbuf)[1] = iphc1;
uip_packetbuf_hdr_len(mbuf) = iphc_ptr - uip_packetbuf_ptr(mbuf);
return 1;
}
/*--------------------------------------------------------------------*/
/**
* \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
* 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
* are set to the appropriate values
*
* \param ip_len Equal to 0 if the packet is not a fragment (IP length
* is then inferred from the L2 length), non 0 if the packet is a 1st
* fragment.
*/
static int
uncompress_hdr_iphc(struct net_buf *mbuf, struct net_buf *ibuf)
{
uint8_t tmp, iphc0, iphc1;
uint8_t buf[UIP_IPUDPH_LEN] = {}; /* Size of (IP + UDP) header*/
int ip_len;
/* at least two byte will be used for the encoding */
iphc_ptr = uip_packetbuf_ptr(mbuf) + uip_packetbuf_hdr_len(mbuf) + 2;
iphc0 = PACKETBUF_IPHC_BUF(mbuf)[0];
iphc1 = PACKETBUF_IPHC_BUF(mbuf)[1];
/* another if the CID flag is set */
if(iphc1 & SICSLOWPAN_IPHC_CID) {
PRINTF("IPHC: CID flag set - increase header with one\n");
iphc_ptr++;
}
/* Traffic class and flow label */
if((iphc0 & SICSLOWPAN_IPHC_FL_C) == 0) {
/* Flow label are carried inline */
if((iphc0 & SICSLOWPAN_IPHC_TC_C) == 0) {
/* Traffic class is carried inline */
memcpy(&SICSLOWPAN_IP_BUF(buf)->tcflow, iphc_ptr + 1, 3);
tmp = *iphc_ptr;
iphc_ptr += 4;
/* IPHC format of tc is ECN | DSCP , original is DSCP | ECN */
/* set version, pick highest DSCP bits and set in vtc */
SICSLOWPAN_IP_BUF(buf)->vtc = 0x60 | ((tmp >> 2) & 0x0f);
/* ECN rolled down two steps + lowest DSCP bits at top two bits */
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(buf)->vtc = 0x60;
/* highest flow label bits + ECN bits */
SICSLOWPAN_IP_BUF(buf)->tcflow = (*iphc_ptr & 0x0F) |
((*iphc_ptr >> 2) & 0x30);
memcpy(&SICSLOWPAN_IP_BUF(buf)->flow, iphc_ptr + 1, 2);
iphc_ptr += 3;
}
} else {
/* Version is always 6! */
/* Version and flow label are compressed */
if((iphc0 & SICSLOWPAN_IPHC_TC_C) == 0) {
/* Traffic class is inline */
SICSLOWPAN_IP_BUF(buf)->vtc = 0x60 | ((*iphc_ptr >> 2) & 0x0f);
SICSLOWPAN_IP_BUF(buf)->tcflow = ((*iphc_ptr << 6) & 0xC0) | ((*iphc_ptr >> 2) & 0x30);
SICSLOWPAN_IP_BUF(buf)->flow = 0;
iphc_ptr += 1;
} else {
/* Traffic class is compressed */
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(buf)->proto = *iphc_ptr;
PRINTF("IPHC: next header inline: %d\n", SICSLOWPAN_IP_BUF(buf)->proto);
iphc_ptr += 1;
}
/* Hop limit */
if((iphc0 & 0x03) != SICSLOWPAN_IPHC_TTL_I) {
SICSLOWPAN_IP_BUF(buf)->ttl = ttl_values[iphc0 & 0x03];
} else {
SICSLOWPAN_IP_BUF(buf)->ttl = *iphc_ptr;
iphc_ptr += 1;
}
/* put the source address compression mode SAM in the tmp var */
tmp = ((iphc1 & SICSLOWPAN_IPHC_SAM_11) >> SICSLOWPAN_IPHC_SAM_BIT) & 0x03;
/* context based compression */
if(iphc1 & SICSLOWPAN_IPHC_SAC) {
uint8_t sci = (iphc1 & SICSLOWPAN_IPHC_CID) ?
PACKETBUF_IPHC_BUF(mbuf)[2] >> 4 : 0;
/* Source address - check context != NULL only if SAM bits are != 0*/
if (tmp != 0) {
context = addr_context_lookup_by_number(sci);
if(context == NULL) {
PRINTF("sicslowpan uncompress_hdr: error context not found\n");
return 0;
}
}
/* if tmp == 0 we do not have a context and therefore no prefix */
uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->srcipaddr,
tmp != 0 ? context->prefix : NULL, unc_ctxconf[tmp],
(uip_lladdr_t *)&ip_buf_ll_src(ibuf));
} else {
/* no compression and link local */
uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->srcipaddr, llprefix,
unc_llconf[tmp],
(uip_lladdr_t *)&ip_buf_ll_src(ibuf));
}
/* Destination address */
/* put the destination address compression mode into tmp */
tmp = ((iphc1 & SICSLOWPAN_IPHC_DAM_11) >> SICSLOWPAN_IPHC_DAM_BIT) & 0x03;
/* multicast compression */
if(iphc1 & SICSLOWPAN_IPHC_M) {
/* context based multicast compression */
if(iphc1 & SICSLOWPAN_IPHC_DAC) {
/* TODO: implement this */
} else {
/* non-context based multicast compression - */
/* DAM_00: 128 bits */
/* DAM_01: 48 bits FFXX::00XX:XXXX:XXXX */
/* DAM_10: 32 bits FFXX::00XX:XXXX */
/* DAM_11: 8 bits FF02::00XX */
uint8_t prefix[] = {0xff, 0x02};
if(tmp > 0 && tmp < 3) {
prefix[1] = *iphc_ptr;
iphc_ptr++;
}
uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->destipaddr, prefix,
unc_mxconf[tmp], NULL);
}
} else {
/* no multicast */
/* Context based */
if(iphc1 & SICSLOWPAN_IPHC_DAC) {
uint8_t dci = (iphc1 & SICSLOWPAN_IPHC_CID) ?
PACKETBUF_IPHC_BUF(mbuf)[2] & 0x0f : 0;
context = addr_context_lookup_by_number(dci);
/* all valid cases below need the context! */
if(context == NULL) {
PRINTF("sicslowpan uncompress_hdr: error context not found\n");
return 0;
}
uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->destipaddr, context->prefix,
unc_ctxconf[tmp], (uip_lladdr_t *)&ip_buf_ll_dest(ibuf));
} else {
/* not context based => link local M = 0, DAC = 0 - same as SAC */
uncompress_addr(&SICSLOWPAN_IP_BUF(buf)->destipaddr, llprefix,
unc_llconf[tmp],
(uip_lladdr_t *)&ip_buf_ll_dest(ibuf));
}
}
uip_uncomp_hdr_len(mbuf) += UIP_IPH_LEN;
/* Next header processing - continued */
if((iphc0 & SICSLOWPAN_IPHC_NH_C)) {
/* The next header is compressed, NHC is following */
if((*iphc_ptr & SICSLOWPAN_NHC_UDP_MASK) == SICSLOWPAN_NHC_UDP_ID) {
uint8_t checksum_compressed;
SICSLOWPAN_IP_BUF(buf)->proto = UIP_PROTO_UDP;
checksum_compressed = *iphc_ptr & SICSLOWPAN_NHC_UDP_CHECKSUMC;
PRINTF("IPHC: Incoming header value: %x\n", *iphc_ptr);
switch(*iphc_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(buf)->srcport, iphc_ptr + 1, 2);
memcpy(&SICSLOWPAN_UDP_BUF(buf)->destport, iphc_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));
iphc_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(buf)->srcport, iphc_ptr + 1, 2);
SICSLOWPAN_UDP_BUF(buf)->destport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN + (*(iphc_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));
iphc_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(buf)->srcport = UIP_HTONS(SICSLOWPAN_UDP_8_BIT_PORT_MIN +
(*(iphc_ptr + 1)));
memcpy(&SICSLOWPAN_UDP_BUF(buf)->destport, iphc_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));
iphc_ptr += 4;
break;
case SICSLOWPAN_NHC_UDP_CS_P_11:
/* 1 byte for NHC, 1 byte for ports */
SICSLOWPAN_UDP_BUF(buf)->srcport = UIP_HTONS(SICSLOWPAN_UDP_4_BIT_PORT_MIN +
(*(iphc_ptr + 1) >> 4));
SICSLOWPAN_UDP_BUF(buf)->destport = UIP_HTONS(SICSLOWPAN_UDP_4_BIT_PORT_MIN +
((*(iphc_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));
iphc_ptr += 2;
break;
default:
PRINTF("sicslowpan uncompress_hdr: error unsupported UDP compression\n");
return 0;
}
if(!checksum_compressed) { /* has_checksum, default */
memcpy(&SICSLOWPAN_UDP_BUF(buf)->udpchksum, iphc_ptr, 2);
iphc_ptr += 2;
PRINTF("IPHC: sicslowpan uncompress_hdr: checksum included\n");
} else {
PRINTF("IPHC: sicslowpan uncompress_hdr: checksum *NOT* included\n");
}
uip_uncomp_hdr_len(mbuf) += UIP_UDPH_LEN;
}
}
uip_packetbuf_hdr_len(mbuf) = iphc_ptr - uip_packetbuf_ptr(mbuf);
if(uip_first_frag_len(ibuf) > 0) {
ip_len = uip_len(ibuf) - UIP_IPH_LEN;
} else {
ip_len = uip_len(ibuf) + uip_uncomp_hdr_len(mbuf) -
uip_packetbuf_hdr_len(mbuf) - UIP_IPH_LEN;
}
SICSLOWPAN_IP_BUF(buf)->len[0] = ip_len >> 8;
SICSLOWPAN_IP_BUF(buf)->len[1] = ip_len & 0x00FF;
/* length field in UDP header */
if(SICSLOWPAN_IP_BUF(buf)->proto == UIP_PROTO_UDP) {
memcpy(&SICSLOWPAN_UDP_BUF(buf)->udplen, &SICSLOWPAN_IP_BUF(buf)->len[0], 2);
}
packetbuf_copyfrom(mbuf, buf, sizeof(buf));
return 1;
}
/** @} */
#endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPHC */
/*--------------------------------------------------------------------*/
/** \name IPv6 dispatch "compression" function
* @{ */
/*--------------------------------------------------------------------*/
/* \brief Packets "Compression" when only IPv6 dispatch is used
*
* There is no compression in this case, all fields are sent
* inline. We just add the IPv6 dispatch byte before the packet.
* \verbatim
* 0 1 2 3
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | IPv6 Dsp | IPv6 header and payload ...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* \endverbatim
*/
static int
compress_hdr_ipv6(struct net_buf *buf)
{
memmove(uip_buf(buf) + SICSLOWPAN_IPV6_HDR_LEN, uip_buf(buf), uip_len(buf));
*uip_buf(buf) = SICSLOWPAN_DISPATCH_IPV6;
uip_len(buf)++;
ip_buf_len(buf)++;
uip_compressed_hdr_len(buf) = UIP_IPH_LEN + SICSLOWPAN_IPV6_HDR_LEN;
uip_uncompressed_hdr_len(buf) = UIP_IPH_LEN;
return 1;
}
/** @} */
/* Just remove the IPv6 Dispatch */
static int
uncompress_hdr_ipv6(struct net_buf *buf)
{
uip_len(buf)--;
ip_buf_len(buf)--;
memmove(uip_buf(buf), uip_buf(buf) + SICSLOWPAN_IPV6_HDR_LEN, uip_len(buf));
return 1;
}
/*--------------------------------------------------------------------*/
/** \name Input/output functions common to all compression schemes
* @{ */
/*--------------------------------------------------------------------*/
static int compress(struct net_buf *buf)
{
uint8_t hdr_diff;
struct net_buf *mbuf;
int ret;
#if UIP_TCP
if(UIP_IP_BUF(buf)->proto == UIP_PROTO_TCP) {
/* Right now do not touch TCP packets. Because we modify the IPv6 header
* then the packet cannot be re-sent properly later. To be fixed later.
*/
return 1;
}
#endif
if(uip_len(buf) >= COMPRESSION_THRESHOLD) {
#if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6
return compress_hdr_ipv6(buf);
#endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6 */
} else {
return compress_hdr_ipv6(buf);
}
mbuf = l2_buf_get_reserve(0);
if (!mbuf) {
return 0;
}
/* init */
uip_uncomp_hdr_len(mbuf) = 0;
uip_packetbuf_hdr_len(mbuf) = 0;
/* reset packetbuf buffer */
packetbuf_clear(mbuf);
uip_packetbuf_ptr(mbuf) = packetbuf_dataptr(mbuf);
/* Compress the headers */
#if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPHC
ret = compress_hdr_iphc(mbuf, buf, &ip_buf_ll_dest(buf));
#endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPHC */
/* if IPHC compression fails then send uncompressed ipv6 packet */
if (!ret) {
l2_buf_unref(mbuf);
PRINTF("sending uncompressed IPv6 packet\n");
return compress_hdr_ipv6(buf);
return 0;
}
PRINTF("compress: compressed hdr len %d, uncompressed hdr len %d\n",
uip_packetbuf_hdr_len(mbuf), uip_uncomp_hdr_len(mbuf));
hdr_diff = uip_uncomp_hdr_len(mbuf) - uip_packetbuf_hdr_len(mbuf);
memcpy(uip_buf(buf), uip_packetbuf_ptr(mbuf), uip_packetbuf_hdr_len(mbuf));
memmove(uip_buf(buf) + uip_packetbuf_hdr_len(mbuf),
uip_buf(buf) + uip_uncomp_hdr_len(mbuf), uip_len(buf) - uip_uncomp_hdr_len(mbuf));
uip_len(buf) -= hdr_diff;
ip_buf_len(buf) -= hdr_diff;
uip_compressed_hdr_len(buf) = uip_packetbuf_hdr_len(mbuf);
uip_uncompressed_hdr_len(buf) = uip_uncomp_hdr_len(mbuf);
packetbuf_clear(mbuf);
l2_buf_unref(mbuf);
return 1;
}
static int uncompress(struct net_buf *buf)
{
struct net_buf *mbuf;
if (*uip_buf(buf) == SICSLOWPAN_DISPATCH_IPV6) {
return uncompress_hdr_ipv6(buf);
}
mbuf = l2_buf_get_reserve(0);
if (!mbuf) {
return 0;
}
/* init */
uip_uncomp_hdr_len(mbuf) = 0;
uip_packetbuf_hdr_len(mbuf) = 0;
packetbuf_copyfrom(mbuf, uip_buf(buf), UIP_IPUDPH_LEN); /* Size of (IP + UDP) header*/
uip_packetbuf_ptr(mbuf) = packetbuf_dataptr(mbuf);
#if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPHC
if((PACKETBUF_HC1_PTR(mbuf)[PACKETBUF_HC1_DISPATCH] & 0xe0) == SICSLOWPAN_DISPATCH_IPHC) {
PRINTF("uncompress: IPHC\n");
if(!uncompress_hdr_iphc(mbuf, buf)) {
goto fail;
}
} else
#endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPHC */
{
/* unknown header */
PRINTF("uncompress: unknown dispatch: %x--%x\n",
PACKETBUF_HC1_PTR(mbuf)[PACKETBUF_HC1_DISPATCH], *uip_buf(buf));
goto fail;
}
#if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPHC
/* Check if memmove would go past the end of the buffer */
if ((uip_uncomp_hdr_len(mbuf) - uip_packetbuf_hdr_len(mbuf)) >
net_buf_tailroom(buf)) {
PRINTF("uncompress: not enough space to store uncompressed headers\n");
goto fail;
}
/* If the packet contains some garbage, then it is possible that
* the frame checker and fragmenter might still have accepted it.
* We need to check here that the memmove() will contain sane length
* value.
*/
if (uip_len(buf) <= uip_packetbuf_hdr_len(mbuf)) {
PRINTF("uncompress: buf len (%d) <= hdr len (%d), packet discarded.\n",
uip_len(buf), uip_packetbuf_hdr_len(mbuf));
goto fail;
}
#if defined(CONFIG_NETWORKING_WITH_15_4)
if (uip_first_frag_len(buf) > 0) {
memmove(uip_buf(buf) + uip_uncomp_hdr_len(mbuf),
uip_buf(buf) + uip_packetbuf_hdr_len(mbuf),
uip_first_frag_len(buf) - uip_packetbuf_hdr_len(mbuf));
memcpy(uip_buf(buf), uip_packetbuf_ptr(mbuf), uip_uncomp_hdr_len(mbuf));
ip_buf_len(buf) = uip_len(buf);
} else {
memmove(uip_buf(buf) + uip_uncomp_hdr_len(mbuf),
uip_buf(buf) + uip_packetbuf_hdr_len(mbuf),
uip_len(buf) - uip_packetbuf_hdr_len(mbuf));
memcpy(uip_buf(buf), uip_packetbuf_ptr(mbuf), uip_uncomp_hdr_len(mbuf));
uip_len(buf) += (uip_uncomp_hdr_len(mbuf) - uip_packetbuf_hdr_len(mbuf));
ip_buf_len(buf) += (uip_uncomp_hdr_len(mbuf) - uip_packetbuf_hdr_len(mbuf));
}
#elif defined(CONFIG_NETWORKING_WITH_BT)
memmove(uip_buf(buf) + uip_uncomp_hdr_len(mbuf),
uip_buf(buf) + uip_packetbuf_hdr_len(mbuf),
uip_len(buf) - uip_packetbuf_hdr_len(mbuf));
memcpy(uip_buf(buf), uip_packetbuf_ptr(mbuf), uip_uncomp_hdr_len(mbuf));
uip_len(buf) += (uip_uncomp_hdr_len(mbuf) - uip_packetbuf_hdr_len(mbuf));
ip_buf_len(buf) += (uip_uncomp_hdr_len(mbuf) - uip_packetbuf_hdr_len(mbuf));
#endif
#endif
l2_buf_unref(mbuf);
return 1;
fail:
l2_buf_unref(mbuf);
return 0;
}
static void init(void)
{
#if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPHC
/* Preinitialize any address contexts for better header compression
* (Saves up to 13 bytes per 6lowpan packet)
* The platform contiki-conf.h file can override this using e.g.
* #define SICSLOWPAN_CONF_ADDR_CONTEXT_0 {addr_contexts[0].prefix[0]=0xbb;addr_contexts[0].prefix[1]=0xbb;}
*/
#if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0
addr_contexts[0].used = 1;
addr_contexts[0].number = 0;
#ifdef SICSLOWPAN_CONF_ADDR_CONTEXT_0
SICSLOWPAN_CONF_ADDR_CONTEXT_0;
#else
addr_contexts[0].prefix[0] = 0xaa;
addr_contexts[0].prefix[1] = 0xaa;
#endif
#endif /* SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 0 */
#if SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 1
{
int i;
for(i = 1; i < SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; i++) {
#ifdef SICSLOWPAN_CONF_ADDR_CONTEXT_1
if (i==1) {
addr_contexts[1].used = 1;
addr_contexts[1].number = 1;
SICSLOWPAN_CONF_ADDR_CONTEXT_1;
#ifdef SICSLOWPAN_CONF_ADDR_CONTEXT_2
} else if (i==2) {
addr_contexts[2].used = 1;
addr_contexts[2].number = 2;
SICSLOWPAN_CONF_ADDR_CONTEXT_2;
#endif
} else {
addr_contexts[i].used = 0;
}
#else
addr_contexts[i].used = 0;
#endif /* SICSLOWPAN_CONF_ADDR_CONTEXT_1 */
}
}
#endif /* SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS > 1 */
#endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_HC06 */
}
const struct compression sicslowpan_compression = {
.init = init,
.compress = compress,
.uncompress = uncompress
};