1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

ng_sixlowpan: initial import of IP header compression

This commit is contained in:
Martine Lenders 2015-04-13 12:48:53 +02:00 committed by Martine Lenders
parent 5b5ff5832c
commit 9a989264d8
9 changed files with 948 additions and 17 deletions

View File

@ -95,6 +95,11 @@ ifneq (,$(filter ng_sixlowpan_frag,$(USEMODULE)))
USEMODULE += vtimer
endif
ifneq (,$(filter ng_sixlowpan_iphc,$(USEMODULE)))
USEMODULE += ng_sixlowpan
USEMODULE += ng_sixlowpan_ctx
endif
ifneq (,$(filter ng_sixlowpan,$(USEMODULE)))
USEMODULE += ng_ipv6
USEMODULE += ng_sixlowpan_netif

View File

@ -116,6 +116,9 @@ endif
ifneq (,$(filter ng_sixlowpan_frag,$(USEMODULE)))
DIRS += net/network_layer/ng_sixlowpan/frag
endif
ifneq (,$(filter ng_sixlowpan_iphc,$(USEMODULE)))
DIRS += net/network_layer/ng_sixlowpan/iphc
endif
ifneq (,$(filter ng_sixlowpan_netif,$(USEMODULE)))
DIRS += net/network_layer/ng_sixlowpan/netif
endif

View File

@ -25,6 +25,7 @@
#include "kernel_types.h"
#include "net/ng_sixlowpan/frag.h"
#include "net/ng_sixlowpan/iphc.h"
#ifdef __cplusplus
extern "C" {

View File

@ -0,0 +1,171 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup net_ng_sixlowpan_iphc IPv6 header compression (IPHC)
* @ingroup net_ng_sixlowpan
* @brief IPv6 header compression for 6LoWPAN.
* @{
*
* @file
* @brief 6LoWPAN IPHC definitions
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NG_SIXLOWPAN_IPHC_H_
#define NG_SIXLOWPAN_IPHC_H_
#include <stdbool.h>
#include "net/ng_pkt.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Dispatch mask for LOWPAN_IPHC.
*/
#define NG_SIXLOWPAN_IPHC1_DISP_MASK (0xe0)
/**
* @brief Dispatch for LOWPAN_IPHC.
*/
#define NG_SIXLOWPAN_IPHC1_DISP (0x60)
/**
* @brief Flag for Traffic Class & Flow Label elision (part of first byte of
* LOWPAN_IPHC).
* @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
* RFC 6282, section 3.1.1
* </a>
*/
#define NG_SIXLOWPAN_IPHC1_TF (0x18)
/**
* @brief Flag for Next Header Compression (part of first byte of
* LOWPAN_IPHC).
* @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
* RFC 6282, section 3.1.1
* </a>
*/
#define NG_SIXLOWPAN_IPHC1_NH (0x04)
/**
* @brief Flag for Hop Limit elision (part of first byte of LOWPAN_IPHC).
* @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
* RFC 6282, section 3.1.1
* </a>
*/
#define NG_SIXLOWPAN_IPHC1_HL (0x03)
/**
* @brief Flag for Context Identifier Extention (part of second byte
* of LOWPAN_IPHC).
* @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
* RFC 6282, section 3.1.1
* </a>
*/
#define NG_SIXLOWPAN_IPHC2_CID_EXT (0x80)
/**
* @brief Flag for Source Address Compression (part of second byte
* of LOWPAN_IPHC).
* @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
* RFC 6282, section 3.1.1
* </a>
*/
#define NG_SIXLOWPAN_IPHC2_SAC (0x40)
/**
* @brief Bits for Source Address Mode (part of second byte of
* LOWPAN_IPHC).
* @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
* RFC 6282, section 3.1.1
* </a>
*/
#define NG_SIXLOWPAN_IPHC2_SAM (0x30)
/**
* @brief Flag for Destination Address Compression (part of second
* byte of LOWPAN_IPHC).
* @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
* RFC 6282, section 3.1.1
* </a>
*/
#define NG_SIXLOWPAN_IPHC2_DAC (0x04)
/**
* @brief Bits for Destination Address Mode (part of second byte of
* LOWPAN_IPHC).
* @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
* RFC 6282, section 3.1.1
* </a>
*/
#define NG_SIXLOWPAN_IPHC2_DAM (0x03)
/**
* @brief Flag for Multicast Compression (part of second byte of
* LOWPAN_IPHC).
* @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1.1">
* RFC 6282, section 3.1.1
* </a>
*/
#define NG_SIXLOWPAN_IPHC2_M (0x08)
/**
* @brief 6LoWPAN IPHC header length
*/
#define NG_SIXLOWPAN_IPHC_HDR_LEN (2)
/**
* @brief 6LoWPAN context idendifier extension header length
*/
#define NG_SIXLOWPAN_IPHC_CID_EXT_LEN (1)
/**
* @brief Checks if datagram is an IPHC datagram.
*
* @param[in] data Data of a datagram, may not be NULL.
*
* @return true, if datagram is an IPHC datagram.
* @return false, if datagram is not an IPHC datagram.
*/
static inline bool ng_sixlowpan_iphc_is(uint8_t *data)
{
return ((*data & NG_SIXLOWPAN_IPHC1_DISP_MASK) == NG_SIXLOWPAN_IPHC1_DISP);
}
/**
* @brief Decompresses a received 6LoWPAN IPHC frame.
*
* @param[in,out] pkt A received 6LoWPAN IPHC frame. Will be translated
* into an IPv6 packet.
*
* @return true, on success
* @return false, on error.
*/
bool ng_sixlowpan_iphc_decode(ng_pktsnip_t *pkt);
/**
* @brief Compresses a 6LoWPAN for IPHC.
*
* @param[in,out] pkt A 6LoWPAN frame with an uncompressed IPv6 header to
* send. Will be translated to an 6LoWPAN IPHC frame.
*
* @return true, on success
* @return false, on error.
*/
bool ng_sixlowpan_iphc_encode(ng_pktsnip_t *pkt);
#ifdef __cplusplus
}
#endif
#endif /* NG_SIXLOWPAN_IPHC_H_ */
/** @} */

View File

@ -20,6 +20,8 @@
#ifndef NG_SIXLOWPAN_NETIF_H_
#define NG_SIXLOWPAN_NETIF_H_
#include <stdbool.h>
#include "kernel_types.h"
#ifdef __cplusplus
@ -32,6 +34,9 @@ extern "C" {
typedef struct {
kernel_pid_t pid; /**< PID of the interface */
uint16_t max_frag_size; /**< Maximum fragment size for this interface */
#ifdef MODULE_NG_SIXLOWPAN_IPHC
bool iphc_enabled; /**< enable or disable IPHC */
#endif
} ng_sixlowpan_netif_t;
/**

View File

@ -0,0 +1,3 @@
MODULE = ng_sixlowpan_iphc
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,697 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
*/
#include <stdbool.h>
#include "byteorder.h"
#include "net/ng_ipv6/hdr.h"
#include "net/ng_netbase.h"
#include "net/ng_sixlowpan/ctx.h"
#include "utlist.h"
#include "net/ng_sixlowpan/iphc.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/* dispatch byte definitions */
#define IPHC1_IDX (0U)
#define IPHC2_IDX (1U)
#define CID_EXT_IDX (2U)
/* compression values for traffic class and flow label */
#define IPHC_TF_ECN_DSCP_FL (0x00)
#define IPHC_TF_ECN_FL (0x08)
#define IPHC_TF_ECN_DSCP (0x10)
#define IPHC_TF_ECN_ELIDE (0x18)
/* compression values for hop limit */
#define IPHC_HL_INLINE (0x00)
#define IPHC_HL_1 (0x01)
#define IPHC_HL_64 (0x02)
#define IPHC_HL_255 (0x03)
/* compression values for source address */
#define IPHC_SAC_SAM_FULL (0x00)
#define IPHC_SAC_SAM_64 (0x10)
#define IPHC_SAC_SAM_16 (0x20)
#define IPHC_SAC_SAM_L2 (0x30)
#define IPHC_SAC_SAM_UNSPEC (0x40)
#define IPHC_SAC_SAM_CTX_64 (0x50)
#define IPHC_SAC_SAM_CTX_16 (0x60)
#define IPHC_SAC_SAM_CTX_L2 (0x70)
/* compression values for destination address */
#define IPHC_M_DAC_DAM_U_FULL (0x00)
#define IPHC_M_DAC_DAM_U_64 (0x01)
#define IPHC_M_DAC_DAM_U_16 (0x02)
#define IPHC_M_DAC_DAM_U_L2 (0x03)
#define IPHC_M_DAC_DAM_U_UNSPEC (0x04)
#define IPHC_M_DAC_DAM_U_CTX_64 (0x05)
#define IPHC_M_DAC_DAM_U_CTX_16 (0x06)
#define IPHC_M_DAC_DAM_U_CTX_L2 (0x07)
#define IPHC_M_DAC_DAM_M_FULL (0x08)
#define IPHC_M_DAC_DAM_M_48 (0x09)
#define IPHC_M_DAC_DAM_M_32 (0x0a)
#define IPHC_M_DAC_DAM_M_8 (0x0b)
#define IPHC_M_DAC_DAM_M_UC_PREFIX (0x0c)
static network_uint64_t _init_iid(uint8_t *l2addr, size_t l2addr_len)
{
network_uint64_t res = { 0 };
if (l2addr_len <= 4) {
res = byteorder_htonll(0x000000fffe000000);
if (l2addr_len == 1) {
res.u8[7] = l2addr[0];
}
else if (l2addr_len == 2) {
res.u8[6] = l2addr[0];
res.u8[7] = l2addr[1];
}
else if (l2addr_len == 4) {
res.u8[0] = l2addr[0];
res.u8[1] = l2addr[1];
res.u8[6] = l2addr[2];
res.u8[7] = l2addr[3];
}
}
else if (l2addr_len == 8) {
network_uint64_t *l2addr_u64 = (network_uint64_t *)l2addr;
res = *l2addr_u64;
res.u8[0] ^= 0x02; /* swap local/universal bit */
}
return res;
}
static inline bool _context_overlaps_iid(ng_sixlowpan_ctx_t *ctx,
ng_ipv6_addr_t *addr,
network_uint64_t *iid)
{
uint8_t byte_mask[] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
if (ctx == NULL) {
return false;
}
return ((ctx->prefix_len == 128) || /* Full-length prefix overlaps IID in any case */
((ctx->prefix_len > 64) && /* otherwise, if bigger than 64-bit */
/* compare bytes until prefix length with IID */
(memcmp(&(addr->u8[(ctx->prefix_len / 8) + 1]),
&(iid->u8[(ctx->prefix_len / 8) - 7]),
sizeof(network_uint64_t) - ((ctx->prefix_len / 8) - 7)) == 0) &&
/* compare bits at prefix length with IID */
(addr->u8[(ctx->prefix_len / 8)] & byte_mask[ctx->prefix_len % 8]) ==
(iid->u8[(ctx->prefix_len / 8) - 8] & byte_mask[ctx->prefix_len % 8])));
}
bool ng_sixlowpan_iphc_decode(ng_pktsnip_t *pkt)
{
ng_netif_hdr_t *netif_hdr = pkt->next->data;
ng_ipv6_hdr_t *ipv6_hdr;
uint8_t *iphc_hdr = pkt->data;
uint16_t payload_offset = NG_SIXLOWPAN_IPHC_HDR_LEN;
ng_sixlowpan_ctx_t *ctx = NULL;
ng_pktsnip_t *payload;
ng_pktsnip_t *ipv6 = ng_pktbuf_add(NULL, NULL, sizeof(ng_ipv6_hdr_t),
NG_NETTYPE_IPV6);
if (ipv6 == NULL) {
DEBUG("6lo iphc: error allocating ipv6 header space\n");
return false;
}
ipv6_hdr = ipv6->data;
if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_CID_EXT) {
payload_offset++;
}
ng_ipv6_hdr_set_version(ipv6_hdr);
switch (iphc_hdr[IPHC1_IDX] & NG_SIXLOWPAN_IPHC1_TF) {
case IPHC_TF_ECN_DSCP_FL:
ng_ipv6_hdr_set_tc(ipv6_hdr, iphc_hdr[payload_offset++]);
ipv6_hdr->v_tc_fl.u8[1] |= iphc_hdr[payload_offset++] & 0x0f;
ipv6_hdr->v_tc_fl.u8[2] |= iphc_hdr[payload_offset++];
ipv6_hdr->v_tc_fl.u8[3] |= iphc_hdr[payload_offset++];
break;
case IPHC_TF_ECN_FL:
ng_ipv6_hdr_set_tc_ecn(ipv6_hdr, iphc_hdr[payload_offset] >> 6);
ng_ipv6_hdr_set_tc_dscp(ipv6_hdr, 0);
ipv6_hdr->v_tc_fl.u8[1] |= iphc_hdr[payload_offset++] & 0x0f;
ipv6_hdr->v_tc_fl.u8[2] |= iphc_hdr[payload_offset++];
ipv6_hdr->v_tc_fl.u8[3] |= iphc_hdr[payload_offset++];
break;
case IPHC_TF_ECN_DSCP:
ng_ipv6_hdr_set_tc(ipv6_hdr, iphc_hdr[payload_offset++]);
ng_ipv6_hdr_set_fl(ipv6_hdr, 0);
break;
case IPHC_TF_ECN_ELIDE:
ng_ipv6_hdr_set_tc(ipv6_hdr, 0);
ng_ipv6_hdr_set_fl(ipv6_hdr, 0);
break;
}
if (!(iphc_hdr[IPHC1_IDX] & NG_SIXLOWPAN_IPHC1_NH)) {
ipv6_hdr->nh = iphc_hdr[payload_offset++];
}
switch (iphc_hdr[IPHC1_IDX] & NG_SIXLOWPAN_IPHC1_HL) {
case IPHC_HL_INLINE:
ipv6_hdr->hl = iphc_hdr[payload_offset++];
break;
case IPHC_HL_1:
ipv6_hdr->hl = 1;
break;
case IPHC_HL_64:
ipv6_hdr->hl = 64;
break;
case IPHC_HL_255:
ipv6_hdr->hl = 255;
break;
}
if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_SAC) {
uint8_t sci = 0;
if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_CID_EXT) {
sci = iphc_hdr[CID_EXT_IDX] >> 4;
}
if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_SAM) {
ctx = ng_sixlowpan_ctx_lookup_id(sci);
if (ctx == NULL) {
DEBUG("6lo iphc: could not find source context\n");
return false;
}
}
}
switch (iphc_hdr[IPHC2_IDX] & (NG_SIXLOWPAN_IPHC2_SAC | NG_SIXLOWPAN_IPHC2_SAM)) {
case IPHC_SAC_SAM_FULL:
/* take full 128 from inline */
memcpy(&(ipv6_hdr->src), iphc_hdr + payload_offset, 16);
payload_offset += 16;
break;
case IPHC_SAC_SAM_64:
ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->src);
memcpy(ipv6_hdr->src.u8 + 8, iphc_hdr + payload_offset, 8);
payload_offset += 8;
break;
case IPHC_SAC_SAM_16:
ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->src);
ipv6_hdr->src.u32[2] = byteorder_htonl(0x000000ff);
ipv6_hdr->src.u16[6] = byteorder_htons(0xfe00);
memcpy(ipv6_hdr->src.u8 + 14, iphc_hdr + payload_offset, 2);
payload_offset += 2;
break;
case IPHC_SAC_SAM_L2:
ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->src);
ipv6_hdr->src.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr),
netif_hdr->src_l2addr_len);
break;
case IPHC_SAC_SAM_UNSPEC:
ng_ipv6_addr_set_unspecified(&ipv6_hdr->src);
break;
case IPHC_SAC_SAM_CTX_64:
memcpy(ipv6_hdr->src.u8 + 8, iphc_hdr + payload_offset, 8);
ng_ipv6_addr_init_prefix(&ipv6_hdr->src, &ctx->prefix,
ctx->prefix_len);
payload_offset += 8;
break;
case IPHC_SAC_SAM_CTX_16:
ipv6_hdr->src.u32[2] = byteorder_htonl(0x000000ff);
ipv6_hdr->src.u16[6] = byteorder_htons(0xfe00);
memcpy(ipv6_hdr->src.u8 + 14, iphc_hdr + payload_offset, 2);
ng_ipv6_addr_init_prefix(&ipv6_hdr->src, &ctx->prefix,
ctx->prefix_len);
payload_offset += 2;
break;
case IPHC_SAC_SAM_CTX_L2:
ipv6_hdr->src.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr),
netif_hdr->src_l2addr_len);
ng_ipv6_addr_init_prefix(&ipv6_hdr->src, &ctx->prefix,
ctx->prefix_len);
break;
}
if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_DAC) {
uint8_t dci = 0;
if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_CID_EXT) {
dci = iphc_hdr[CID_EXT_IDX] & 0x0f;
}
if (iphc_hdr[IPHC2_IDX] & NG_SIXLOWPAN_IPHC2_DAM) {
ctx = ng_sixlowpan_ctx_lookup_id(dci);
if (ctx == NULL) {
DEBUG("6lo iphc: could not find destination context\n");
return false;
}
}
}
switch (iphc_hdr[IPHC2_IDX] & (NG_SIXLOWPAN_IPHC2_M | NG_SIXLOWPAN_IPHC2_DAC |
NG_SIXLOWPAN_IPHC2_DAM)) {
case IPHC_M_DAC_DAM_U_FULL:
case IPHC_M_DAC_DAM_M_FULL:
memcpy(&(ipv6_hdr->dst.u8), iphc_hdr + payload_offset, 16);
payload_offset += 16;
break;
case IPHC_M_DAC_DAM_U_64:
ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->dst);
memcpy(ipv6_hdr->dst.u8 + 8, iphc_hdr + payload_offset, 8);
payload_offset += 8;
break;
case IPHC_M_DAC_DAM_U_16:
ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->dst);
ipv6_hdr->dst.u32[2] = byteorder_htonl(0x000000ff);
ipv6_hdr->dst.u16[6] = byteorder_htons(0xfe00);
memcpy(ipv6_hdr->dst.u8 + 14, iphc_hdr + payload_offset, 2);
payload_offset += 2;
break;
case IPHC_M_DAC_DAM_U_L2:
ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->dst);
ipv6_hdr->dst.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr),
netif_hdr->src_l2addr_len);
break;
case IPHC_M_DAC_DAM_U_CTX_64:
memcpy(ipv6_hdr->dst.u8 + 8, iphc_hdr + payload_offset, 8);
ng_ipv6_addr_init_prefix(&ipv6_hdr->dst, &ctx->prefix,
ctx->prefix_len);
payload_offset += 8;
break;
case IPHC_M_DAC_DAM_U_CTX_16:
ipv6_hdr->dst.u32[2] = byteorder_htonl(0x000000ff);
ipv6_hdr->dst.u16[6] = byteorder_htons(0xfe00);
memcpy(ipv6_hdr->dst.u8 + 14, iphc_hdr + payload_offset, 2);
ng_ipv6_addr_init_prefix(&ipv6_hdr->dst, &ctx->prefix,
ctx->prefix_len);
payload_offset += 2;
break;
case IPHC_M_DAC_DAM_U_CTX_L2:
ipv6_hdr->dst.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr),
netif_hdr->src_l2addr_len);
ng_ipv6_addr_init_prefix(&ipv6_hdr->dst, &ctx->prefix,
ctx->prefix_len);
break;
case IPHC_M_DAC_DAM_M_48:
/* ffXX::00XX:XXXX:XXXX */
ng_ipv6_addr_set_unspecified(&ipv6_hdr->dst);
ipv6_hdr->dst.u8[0] = 0xff;
ipv6_hdr->dst.u8[1] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[11] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[12] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[13] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[14] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[15] = iphc_hdr[payload_offset++];
break;
case IPHC_M_DAC_DAM_M_32:
/* ffXX::00XX:XXXX */
ng_ipv6_addr_set_unspecified(&ipv6_hdr->dst);
ipv6_hdr->dst.u8[0] = 0xff;
ipv6_hdr->dst.u8[1] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[13] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[14] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[15] = iphc_hdr[payload_offset++];
break;
case IPHC_M_DAC_DAM_M_8:
/* ffXX::XX: */
ng_ipv6_addr_set_unspecified(&ipv6_hdr->dst);
ipv6_hdr->dst.u8[0] = 0xff;
ipv6_hdr->dst.u8[1] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[15] = iphc_hdr[payload_offset++];
break;
case IPHC_M_DAC_DAM_M_UC_PREFIX:
do {
uint8_t orig_ctx_len = ctx->prefix_len;
ng_ipv6_addr_set_unspecified(&ipv6_hdr->dst);
if (ctx->prefix_len > 64) {
ctx->prefix_len = 64;
}
ipv6_hdr->dst.u8[0] = 0xff;
ipv6_hdr->dst.u8[1] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[2] = iphc_hdr[payload_offset++];
ipv6_hdr->dst.u8[3] = ctx->prefix_len;
ng_ipv6_addr_init_prefix((ng_ipv6_addr_t *)ipv6_hdr->dst.u8 + 4,
&ctx->prefix, ctx->prefix_len);
memcpy(ipv6_hdr->dst.u8 + 12, iphc_hdr + payload_offset + 2, 4);
payload_offset += 4;
ctx->prefix_len = orig_ctx_len;
} while (0); /* ANSI-C compatible block creation for orig_ctx_len allocation*/
break;
default:
DEBUG("6lo iphc: unspecified or reserved M, DAC, DAM combination\n");
return false;
}
/* TODO: add next header decoding */
/* remove 6LoWPAN dispatch */
payload = ng_pktbuf_add(pkt, pkt->data, payload_offset, NG_NETTYPE_SIXLOWPAN);
pkt = ng_pktbuf_remove_snip(pkt, payload);
/* insert IPv6 header */
ipv6->next = pkt->next;
pkt->next = ipv6;
return true;
}
bool ng_sixlowpan_iphc_encode(ng_pktsnip_t *pkt)
{
ng_netif_hdr_t *netif_hdr = pkt->data;
ng_ipv6_hdr_t *ipv6_hdr = pkt->next->data;
uint8_t *iphc_hdr;
uint16_t inline_pos = NG_SIXLOWPAN_IPHC_HDR_LEN;
bool addr_comp = false;
ng_sixlowpan_ctx_t *src_ctx = NULL, *dst_ctx = NULL;
ng_pktsnip_t *dispatch = ng_pktbuf_add(NULL, NULL, pkt->next->size,
NG_NETTYPE_SIXLOWPAN);
if (dispatch == NULL) {
DEBUG("6lo iphc: error allocating dispatch space\n");
return false;
}
iphc_hdr = dispatch->data;
/* set initial dispatch value*/
iphc_hdr[IPHC1_IDX] = NG_SIXLOWPAN_IPHC1_DISP;
iphc_hdr[2] = 0;
/* check for available contexts */
if (!ng_ipv6_addr_is_unspecified(&(ipv6_hdr->src))) {
src_ctx = ng_sixlowpan_ctx_lookup_addr(&(ipv6_hdr->src));
}
if (!ng_ipv6_addr_is_multicast(&ipv6_hdr->dst)) {
dst_ctx = ng_sixlowpan_ctx_lookup_addr(&(ipv6_hdr->dst));
}
/* if contexts available and both != 0 */
/* since this moves inline_pos we have to do this ahead*/
if (((src_ctx != NULL) && (src_ctx->id != 0)) ||
((dst_ctx != NULL) && (dst_ctx->id != 0))) {
/* add context identifier extension */
iphc_hdr[IPHC2_IDX] |= NG_SIXLOWPAN_IPHC2_CID_EXT;
iphc_hdr[CID_EXT_IDX] = 0;
/* move position to behind CID extension */
inline_pos += NG_SIXLOWPAN_IPHC_CID_EXT_LEN;
}
/* compress flow label and traffic class */
if (ng_ipv6_hdr_get_fl(ipv6_hdr) == 0) {
if (ng_ipv6_hdr_get_tc(ipv6_hdr) == 0) {
/* elide both traffic class and flow label */
iphc_hdr[IPHC1_IDX] |= IPHC_TF_ECN_ELIDE;
}
else {
/* elide flow label, traffic class (ECN + DSCP) inline (1 byte) */
iphc_hdr[IPHC1_IDX] |= IPHC_TF_ECN_DSCP;
iphc_hdr[inline_pos++] = ng_ipv6_hdr_get_tc(ipv6_hdr);
}
}
else {
if (ng_ipv6_hdr_get_tc_dscp(ipv6_hdr) == 0) {
/* elide DSCP, ECN + 2-bit pad + flow label inline (3 byte) */
iphc_hdr[IPHC1_IDX] |= IPHC_TF_ECN_FL;
iphc_hdr[inline_pos++] = (uint8_t)((ng_ipv6_hdr_get_tc_ecn(ipv6_hdr) << 6) |
((ng_ipv6_hdr_get_fl(ipv6_hdr) & 0x000f0000) >> 16));
}
else {
/* ECN + DSCP + 4-bit pad + flow label (4 bytes) */
iphc_hdr[IPHC1_IDX] |= IPHC_TF_ECN_DSCP_FL;
iphc_hdr[inline_pos++] = ng_ipv6_hdr_get_tc(ipv6_hdr);
iphc_hdr[inline_pos++] = (uint8_t)((ng_ipv6_hdr_get_fl(ipv6_hdr) & 0x000f0000) >> 16);
}
/* copy remaining byteos of flow label */
iphc_hdr[inline_pos++] = (uint8_t)((ng_ipv6_hdr_get_fl(ipv6_hdr) & 0x0000ff00) >> 8);
iphc_hdr[inline_pos++] = (uint8_t)((ng_ipv6_hdr_get_fl(ipv6_hdr) & 0x000000ff) >> 8);
}
/* compress next header */
switch (ipv6_hdr->nh) {
/* TODO: add next header compression and set NH bit */
default:
iphc_hdr[inline_pos++] = ipv6_hdr->nh;
break;
}
/* compress hop limit */
switch (ipv6_hdr->hl) {
case 1:
iphc_hdr[IPHC1_IDX] |= IPHC_HL_1;
break;
case 64:
iphc_hdr[IPHC1_IDX] |= IPHC_HL_64;
break;
case 255:
iphc_hdr[IPHC1_IDX] |= IPHC_HL_255;
break;
default:
iphc_hdr[IPHC1_IDX] |= IPHC_HL_INLINE;
iphc_hdr[inline_pos++] = ipv6_hdr->hl;
break;
}
if (ng_ipv6_addr_is_unspecified(&(ipv6_hdr->src))) {
iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_UNSPEC;
}
else {
if (src_ctx != NULL) {
/* stateful source address compression */
iphc_hdr[IPHC2_IDX] |= NG_SIXLOWPAN_IPHC2_SAC;
if (src_ctx->id != 0) { /* context id is elided */
iphc_hdr[CID_EXT_IDX] |= (src_ctx->id << 4);
}
}
if ((src_ctx != NULL) || ng_ipv6_addr_is_link_local(&(ipv6_hdr->src))) {
uint16_t l2src_len = 0;
uint8_t l2src[8];
if (netif_hdr->src_l2addr_len > 0) {
l2src_len = netif_hdr->src_l2addr_len;
memcpy(l2src, ng_netif_hdr_get_src_addr(netif_hdr), l2src_len);
}
else {
bool try_long = false;
if ((ng_netapi_get(netif_hdr->if_pid, NETCONF_OPT_ADDR_LEN, 0,
&l2src_len, sizeof(l2src_len)) >= 0) &&
(l2src_len >= 8)) {
try_long = true;
}
if ((!try_long) || (ng_netapi_get(netif_hdr->if_pid,
NETCONF_OPT_ADDRESS_LONG, 0,
&l2src, sizeof(l2src)) < 0)) {
if (ng_netapi_get(netif_hdr->if_pid, NETCONF_OPT_ADDRESS,
0, &l2src, sizeof(l2src)) < 0) {
l2src_len = 0;
}
}
}
if (l2src_len > 0) {
network_uint64_t iid = _init_iid(l2src, l2src_len);
if ((memcmp(ipv6_hdr->src.u64 + 1, &iid,
sizeof(network_uint64_t)) == 0) ||
_context_overlaps_iid(src_ctx, &ipv6_hdr->src, &iid)) {
/* 0 bits. The address is derived from link-layer address */
iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_L2;
}
else if ((byteorder_ntohl(ipv6_hdr->src.u32[2]) == 0x000000ff) &&
(byteorder_ntohs(ipv6_hdr->src.u16[6]) == 0xfe00)) {
/* 16 bits. The address is derived using 16 bits carried inline */
iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_16;
memcpy(iphc_hdr + inline_pos, ipv6_hdr->src.u16 + 7, 2);
inline_pos += 2;
}
else {
/* 64 bits. The address is derived using 64 bits carried inline */
iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_64;
memcpy(iphc_hdr + inline_pos, ipv6_hdr->src.u64 + 1, 8);
inline_pos += 8;
}
addr_comp = true;
}
}
if (!addr_comp) {
/* full address is carried inline */
iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_FULL;
memcpy(iphc_hdr + inline_pos, &ipv6_hdr->src, 16);
inline_pos += 16;
}
}
addr_comp = false;
/* M: Multicast compression */
if (ng_ipv6_addr_is_multicast(&(ipv6_hdr->dst))) {
iphc_hdr[IPHC2_IDX] |= NG_SIXLOWPAN_IPHC2_M;
/* if multicast address is of format ffXX::XXXX:XXXX:XXXX */
if ((ipv6_hdr->dst.u16[1].u16 == 0) &&
(ipv6_hdr->dst.u32[1].u32 == 0) &&
(ipv6_hdr->dst.u16[4].u16 == 0)) {
/* if multicast address is of format ff02::XX */
if ((ipv6_hdr->dst.u8[1] == 2) &&
(ipv6_hdr->dst.u32[2].u32 == 0) &&
(ipv6_hdr->dst.u16[6].u16 == 0) &&
(ipv6_hdr->dst.u8[14] == 0)) {
/* 8 bits. The address is derived using 8 bits carried inline */
iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_M_8;
iphc_hdr[inline_pos++] = ipv6_hdr->dst.u8[15];
addr_comp = true;
}
/* if multicast address is of format ffXX::XX:XXXX */
else if ((ipv6_hdr->dst.u16[5].u16 == 0) &&
(ipv6_hdr->dst.u8[12] == 0)) {
/* 32 bits. The address is derived using 32 bits carried inline */
iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_M_32;
iphc_hdr[inline_pos++] = ipv6_hdr->dst.u8[1];
memcpy(iphc_hdr + inline_pos, ipv6_hdr->dst.u8 + 13, 3);
inline_pos += 3;
addr_comp = true;
}
/* if multicast address is of format ffXX::XX:XXXX:XXXX */
else if (ipv6_hdr->dst.u8[10] == 0) {
/* 32 bits. The address is derived using 32 bits carried inline */
iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_M_32;
iphc_hdr[inline_pos++] = ipv6_hdr->dst.u8[1];
memcpy(iphc_hdr + inline_pos, ipv6_hdr->dst.u8 + 13, 3);
inline_pos += 3;
addr_comp = true;
}
}
/* try unicast prefix based compression */
else {
ng_sixlowpan_ctx_t *ctx;
ng_ipv6_addr_t unicast_prefix;
unicast_prefix.u16[0] = ipv6_hdr->dst.u16[2];
unicast_prefix.u16[1] = ipv6_hdr->dst.u16[3];
unicast_prefix.u16[2] = ipv6_hdr->dst.u16[4];
unicast_prefix.u16[3] = ipv6_hdr->dst.u16[5];
ctx = ng_sixlowpan_ctx_lookup_addr(&unicast_prefix);
if ((ctx != NULL) && (ctx->prefix_len == ipv6_hdr->dst.u8[3])) {
/* Unicast prefix based IPv6 multicast address with given
* context for unicast prefix -> context based compression */
iphc_hdr[IPHC2_IDX] |= NG_SIXLOWPAN_IPHC2_DAC;
iphc_hdr[inline_pos++] = ipv6_hdr->dst.u8[1];
iphc_hdr[inline_pos++] = ipv6_hdr->dst.u8[2];
memcpy(iphc_hdr + inline_pos, ipv6_hdr->dst.u16 + 6, 4);
inline_pos += 4;
addr_comp = true;
}
}
}
else if (((dst_ctx != NULL) || ng_ipv6_addr_is_link_local(&ipv6_hdr->dst)) &&
(netif_hdr->dst_l2addr_len > 0)) {
network_uint64_t iid = _init_iid(ng_netif_hdr_get_dst_addr(netif_hdr),
netif_hdr->dst_l2addr_len);
if ((memcmp(&(ipv6_hdr->dst.u8[8]), &iid, sizeof(uint64_t)) == 0) ||
_context_overlaps_iid(dst_ctx, &(ipv6_hdr->dst), &iid)) {
/* 0 bits. The address is derived using the link-layer address */
iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_U_L2;
addr_comp = true;
}
else if ((byteorder_ntohl(ipv6_hdr->dst.u32[2]) == 0x000000ff) &&
(byteorder_ntohs(ipv6_hdr->dst.u16[6]) == 0xfe00)) {
/* 16 bits. The address is derived using 16 bits carried inline */
iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_U_16;
memcpy(&(iphc_hdr[inline_pos]), &(ipv6_hdr->dst.u16[7]), 2);
inline_pos += 2;
addr_comp = true;
}
else {
/* 64 bits. The address is derived using 64 bits carried inline */
iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_U_64;
memcpy(&(iphc_hdr[inline_pos]), &(ipv6_hdr->dst.u8[8]), 8);
inline_pos += 8;
addr_comp = true;
}
}
if (!addr_comp) {
/* full destination address is carried inline */
iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_FULL;
memcpy(iphc_hdr + inline_pos, &ipv6_hdr->dst, 16);
inline_pos += 16;
}
/* shrink dispatch allocation to final size */
/* NOTE: Since this only shrinks the data nothing bad SHOULD happen ;-) */
ng_pktbuf_realloc_data(dispatch, (size_t)inline_pos);
/* remove IPv6 header */
pkt = ng_pktbuf_remove_snip(pkt, pkt->next);
/* insert dispatch into packet */
dispatch->next = pkt->next;
pkt->next = dispatch;
return true;
}
/** @} */

View File

@ -49,6 +49,9 @@ void ng_sixlowpan_netif_add(kernel_pid_t pid, uint16_t max_frag_size)
free_entry->pid = pid;
free_entry->max_frag_size = max_frag_size;
#ifdef MODULE_NG_SIXLOWPAN_IPHC
free_entry->iphc_enabled = true;
#endif
return;
}

View File

@ -19,6 +19,7 @@
#include "net/ng_sixlowpan.h"
#include "net/ng_sixlowpan/frag.h"
#include "net/ng_sixlowpan/iphc.h"
#include "net/ng_sixlowpan/netif.h"
#define ENABLE_DEBUG (0)
@ -101,6 +102,18 @@ void _receive(ng_pktsnip_t *pkt)
return;
}
#ifdef MODULE_NG_SIXLOWPAN_IPHC
if (ng_sixlowpan_iphc_is(payload->data)) {
if (!ng_sixlowpan_iphc_decode(pkt)) {
DEBUG("6lo: error on IPHC decoding\n");
ng_pktbuf_release(pkt);
return;
}
LL_SEARCH_SCALAR(pkt, payload, type, NG_NETTYPE_IPV6);
}
#endif
payload->type = NG_NETTYPE_IPV6;
entry = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL);
@ -151,6 +164,8 @@ void _send(ng_pktsnip_t *pkt)
* length is the length of the IPv6 datagram + 6LoWPAN dispatches,
* while the datagram size is the size of only the IPv6 datagram */
payload_len = ng_pkt_len(ipv6);
/* cppcheck: datagram_size will be read by ng_sixlowpan_frag implementation */
/* cppcheck-suppress unreadVariable */
datagram_size = (uint16_t)payload_len;
/* use sixlowpan packet snip as temporary one */
@ -163,7 +178,51 @@ void _send(ng_pktsnip_t *pkt)
}
pkt = sixlowpan;
iface = ng_sixlowpan_netif_get(hdr->if_pid);
if (iface == NULL) {
if (ng_netapi_get(hdr->if_pid, NETCONF_OPT_MAX_PACKET_SIZE,
0, &max_frag_size, sizeof(max_frag_size)) < 0) {
/* if error we assume it works */
DEBUG("6lo: can not get max packet size from interface %"
PRIkernel_pid "\n", hdr->if_pid);
max_frag_size = UINT16_MAX;
}
ng_sixlowpan_netif_add(hdr->if_pid, max_frag_size);
iface = ng_sixlowpan_netif_get(hdr->if_pid);
}
else {
max_frag_size = iface->max_frag_size;
}
#ifdef MODULE_NG_SIXLOWPAN_IPHC
if (iface->iphc_enabled) {
if (!ng_sixlowpan_iphc_encode(pkt)) {
DEBUG("6lo: error on IPHC encoding\n");
ng_pktbuf_release(pkt);
return;
}
}
else {
DEBUG("6lo: Send uncompressed\n");
sixlowpan = ng_pktbuf_add(NULL, NULL, sizeof(uint8_t),
NG_NETTYPE_SIXLOWPAN);
if (sixlowpan == NULL) {
DEBUG("6lo: no space left in packet buffer\n");
ng_pktbuf_release(pkt);
return;
}
sixlowpan->next = ipv6;
pkt->next = sixlowpan;
disp = sixlowpan->data;
disp[0] = NG_SIXLOWPAN_UNCOMPRESSED;
payload_len++;
}
#else
DEBUG("6lo: Send uncompressed\n");
sixlowpan = ng_pktbuf_add(NULL, NULL, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN);
@ -179,23 +238,7 @@ void _send(ng_pktsnip_t *pkt)
disp = sixlowpan->data;
disp[0] = NG_SIXLOWPAN_UNCOMPRESSED;
payload_len++;
iface = ng_sixlowpan_netif_get(hdr->if_pid);
if (iface == NULL) {
if (ng_netapi_get(hdr->if_pid, NETCONF_OPT_MAX_PACKET_SIZE,
0, &max_frag_size, sizeof(max_frag_size)) < 0) {
/* if error we assume it works */
DEBUG("6lo: can not get max packet size from interface %"
PRIkernel_pid "\n", hdr->if_pid);
max_frag_size = UINT16_MAX;
}
ng_sixlowpan_netif_add(hdr->if_pid, max_frag_size);
}
else {
max_frag_size = iface->max_frag_size;
}
#endif
DEBUG("6lo: max_frag_size = %" PRIu16 " for interface %"
PRIkernel_pid "\n", max_frag_size, hdr->if_pid);