Skip to content

Commit

Permalink
sixlowpan.iphc_cbuf: Initial import of an IPHC context buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
miri64 committed Dec 3, 2014
1 parent 3403bca commit 38b5464
Show file tree
Hide file tree
Showing 13 changed files with 789 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ ifneq (,$(filter sixlowpan_legacy,$(USEMODULE)))
USEMODULE += vtimer
endif

ifneq (,$(filter sixlowpan_iphc_cbuf,$(USEMODULE)))
USEMODULE += vtimer
endif

ifneq (,$(filter sixlowpan,$(USEMODULE)))
USEMODULE += netapi
USEMODULE += netdev_base
Expand Down
3 changes: 3 additions & 0 deletions sys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ endif
ifneq (,$(filter sixlowpan,$(USEMODULE)))
DIRS += net/link_layer/sixlowpan
endif
ifneq (,$(filter sixlowpan_iphc_cbuf,$(USEMODULE)))
DIRS += net/link_layer/sixlowpan/iphc_cbuf
endif
ifneq (,$(filter ipv6,$(USEMODULE)))
# TODO
endif
Expand Down
3 changes: 3 additions & 0 deletions sys/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ endif
ifneq (,$(filter sixlowpan_legacy,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include
endif
ifneq (,$(filter sixlowpan_iphc_cbuf,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include
endif
ifneq (,$(filter rpl,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/routing/rpl
Expand Down
128 changes: 128 additions & 0 deletions sys/net/include/sixlowpan/iphc_cbuf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* Copyright (C) 2014 Martin 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_sixlowpan_iphc_cbuf Context buffer for 6LoWPAN IP header compression
* @addtogroup net_sixlowpan
* @{
*
* @file iphc_cbuf.h
* @brief Context buffer for 6LoWPAN IP header compression
*
* @see <a href="https://tools.ietf.org/html/rfc6282#section-3.1.2">
* RFC 6282, section 3.1.2
* </a>
* @see <a href="http://tools.ietf.org/html/rfc6775#section-4.2">
* RFC 6775, section 4.2
* </a>
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/


#ifndef __SIXLOWPAN_IPHC_CBUF_H_
#define __SIXLOWPAN_IPHC_CBUF_H_

#include "ipv6.h"

#define SIXLOWPAN_IPHC_CBUF_SIZE (16)

/**
* @brief Data type to configure 6LoWPAN contexts
* @see <a href="http://tools.ietf.org/html/rfc6282#section-3.1">
* RFC 6282, section 3.1
* </a>
*/
typedef struct {
uint8_t cid; /**< Context ID */
uint8_t prefix_len; /**< Length of the prefix in bits, if 0 on
NETAPI_CMD_SET the context will be removed. */
ipv6_addr_t prefix; /**< The prefix associated to this context */

/**
* @brief Lifetime in minutes this context is valid.
*
* @see <a href="http://tools.ietf.org/html/rfc6775#section-4.2">
* 6LoWPAN Context Option
* </a>
*/
uint32_t lifetime;
} sixlowpan_iphc_cbuf_t;

/**
* @brief Lookup best context for an IPv6 address.
*
* @param[in] addr An IPv6 address.
*
* @return best fitting context for given IPv6 address.
* @return NULL, if no fitting context can be found.
*/
sixlowpan_iphc_cbuf_t *sixlowpan_iphc_cbuf_lookup_addr(const ipv6_addr_t *addr);

/**
* @brief Lookup best context for a context ID.
*
* @param[in] cid A context ID, must be < 16.
*
* @return best fitting context for given context ID.
* @return NULL, if no fitting context can be found.
*/
sixlowpan_iphc_cbuf_t *sixlowpan_iphc_cbuf_lookup_cid(uint8_t cid);

/**
* @brief Returns number of currently saved contexts.
*
* @return Number of currently saved contexts.
*/
uint8_t sixlowpan_iphc_cbuf_num(void);

/**
* @brief Remove context by context ID.
* @param[in] cid A context ID, must be < 16.
*/
void sixlowpan_iphc_cbuf_remove_by_cid(uint8_t cid);

/**
* @brief Remove context by best address match.
*
* @param[in] addr An IPv6 address.
*/
static inline void sixlowpan_iphc_cbuf_remove_by_addr(const ipv6_addr_t *addr)
{
sixlowpan_iphc_cbuf_t *context = sixlowpan_iphc_cbuf_lookup_addr(addr);

if (context) {
sixlowpan_iphc_cbuf_remove_by_cid(context->cid);
}
}

/**
* @brief Removes all context with expired lifetime
*/
void sixlowpan_iphc_cbuf_remove_invalid(void);

/**
* @brief Update a context
*
* @param[in] cid A context ID, must be < 16.
* @param[in] prefix An IPv6 prefix to associate with *cid*.
* @param[in] prefix_len Length of prefix in bits. If *prefix_len* is longer
* then 128, it will be set to 128. Must be > 0.
* @param[in] lifetime Lifetime the context is valid in minutes. Must be > 0.
*
* @return The updated context on success.
* @return NULL, if cid is >= 16, prefix_len is 0, or lifetime is 0.
*/
sixlowpan_iphc_cbuf_t *sixlowpan_iphc_cbuf_update(uint8_t cid, const ipv6_addr_t *prefix,
uint8_t prefix_len, uint16_t lifetime);

#endif /* __SIXLOWPAN_IPHC_CBUF_H_ */
/**
* @}
*/
3 changes: 3 additions & 0 deletions sys/net/link_layer/sixlowpan/iphc_cbuf/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE = sixlowpan_iphc_cbuf

include $(RIOTBASE)/Makefile.base
227 changes: 227 additions & 0 deletions sys/net/link_layer/sixlowpan/iphc_cbuf/iphc_cbuf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/*
* Copyright (C) 2014 Martin 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.
*/

/**
* @addtogroup net_sixlowpan_iphc_cbuf
* @{
*
* @file iphc_cbuf.c
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/

#include <string.h>

#include "mutex.h"
#include "vtimer.h"

#include "ipv6.h"
#include "sixlowpan/iphc_cbuf.h"

static sixlowpan_iphc_cbuf_t _cbuf[SIXLOWPAN_IPHC_CBUF_SIZE];
static uint32_t _cbuf_invalid_time[SIXLOWPAN_IPHC_CBUF_SIZE];
static mutex_t _cbuf_mutex = MUTEX_INIT;

#ifndef MODULE_IPV6
void ipv6_addr_init_prefix(ipv6_addr_t *out, const ipv6_addr_t *prefix,
uint8_t bits)
{
if (bits > 128) {
bits = 128;
}

uint8_t bytes = bits / 8, mask;

if (bits % 8) {
mask = 0xff << (8 - (bits - (bytes * 8)));
}
else {
mask = 0x00;
}

memcpy(out, prefix, bytes);
out->u8[bytes] = prefix->u8[bytes] & mask;
memset(&(out[bytes + 1]), 0, 15 - bytes);
}
#endif /* MODULE_IPV6 */

static uint32_t _now_in_minutes(void)
{
timex_t now;

vtimer_now(&now);

return now.seconds / 60;
}

static void _cid_update_lifetime(uint8_t cid)
{
uint32_t now = _now_in_minutes();
#ifdef DEVELHELP

if (cid >= SIXLOWPAN_IPHC_CBUF_SIZE) {
return;
}

#endif

if (now >= _cbuf_invalid_time[cid]) {
_cbuf[cid].lifetime = 0;
}
else {
_cbuf[cid].lifetime = _cbuf_invalid_time[cid] - now;
}
}

static int _cid_still_valid(uint8_t cid)
{
#ifdef DEVELHELP

if (cid >= SIXLOWPAN_IPHC_CBUF_SIZE) {
return 0;
}

#endif
_cid_update_lifetime(cid);

return (_cbuf[cid].lifetime > 0);
}

void _iphc_cbuf_internal_remove(uint8_t cid)
{
if (cid < SIXLOWPAN_IPHC_CBUF_SIZE) {
_cbuf[cid].cid = 0;
_cbuf[cid].prefix_len = 0;
memset(&(_cbuf[cid].prefix), 0, sizeof(ipv6_addr_t));
_cbuf[cid].lifetime = 0;
_cbuf_invalid_time[cid] = 0;
}
}

sixlowpan_iphc_cbuf_t *sixlowpan_iphc_cbuf_lookup_addr(const ipv6_addr_t *addr)
{
sixlowpan_iphc_cbuf_t *c = NULL;
uint8_t bytes;

mutex_lock(&_cbuf_mutex);

for (int i = 0; i < SIXLOWPAN_IPHC_CBUF_SIZE; i++) {
bytes = _cbuf[i].prefix_len / 8;

if (_cbuf[i].prefix_len > 0 && memcmp(addr, &(_cbuf[i].prefix), bytes) == 0) {
if (_cbuf[i].prefix_len % 8) {
uint8_t mask = 0xff << (8 - (_cbuf[i].prefix_len - (bytes * 8)));

if ((addr->u8[bytes] & mask) != (_cbuf[i].prefix.u8[bytes] & mask)) {
continue;
}
}

if (_cid_still_valid(i)) {
if (c == NULL || c->prefix_len < _cbuf[i].prefix_len) {
c = &_cbuf[i];
}
}
else {
_iphc_cbuf_internal_remove(i);
}
}
}

mutex_unlock(&_cbuf_mutex);

return c;
}

sixlowpan_iphc_cbuf_t *sixlowpan_iphc_cbuf_lookup_cid(uint8_t cid)
{
sixlowpan_iphc_cbuf_t *c = NULL;

if (cid >= SIXLOWPAN_IPHC_CBUF_SIZE) {
return NULL;
}

mutex_lock(&_cbuf_mutex);

if (_cid_still_valid(cid)) {
c = &(_cbuf[cid]);
}
else {
_iphc_cbuf_internal_remove(cid);
}

mutex_unlock(&_cbuf_mutex);

return c;
}

uint8_t sixlowpan_iphc_cbuf_num(void)
{
uint8_t num = 0;

mutex_lock(&_cbuf_mutex);

for (int i = 0; i < SIXLOWPAN_IPHC_CBUF_SIZE; i++) {
if (_cid_still_valid(i) && _cbuf[i].prefix_len > 0) {
num++;
}
else {
_iphc_cbuf_internal_remove(i);
}
}

mutex_unlock(&_cbuf_mutex);

return num;
}

void sixlowpan_iphc_cbuf_remove_by_cid(uint8_t cid)
{
mutex_lock(&_cbuf_mutex);
_iphc_cbuf_internal_remove(cid);
mutex_unlock(&_cbuf_mutex);
}

void sixlowpan_iphc_cbuf_remove_invalid(void)
{
mutex_lock(&_cbuf_mutex);

for (int i = 0; i < SIXLOWPAN_IPHC_CBUF_SIZE; i++) {
if (!_cid_still_valid(i)) {
_iphc_cbuf_internal_remove(i);
}
}

mutex_unlock(&_cbuf_mutex);
}

sixlowpan_iphc_cbuf_t *sixlowpan_iphc_cbuf_update(uint8_t cid, const ipv6_addr_t *prefix,
uint8_t prefix_len, uint16_t lifetime)
{
sixlowpan_iphc_cbuf_t *c = NULL;

mutex_lock(&_cbuf_mutex);

if (cid < SIXLOWPAN_IPHC_CBUF_SIZE && prefix_len > 0 && lifetime > 0) {
_cbuf[cid].cid = cid;
_cbuf[cid].prefix_len = (prefix_len < IPV6_ADDR_BIT_LEN) ? prefix_len : IPV6_ADDR_BIT_LEN;
_cbuf[cid].lifetime = lifetime;
ipv6_addr_init_prefix(&(_cbuf[cid].prefix), prefix, prefix_len);
_cbuf_invalid_time[cid] = _now_in_minutes() + lifetime;

c = &(_cbuf[cid]);
}

mutex_unlock(&_cbuf_mutex);

return c;
}

/**
* @}
*/
Loading

0 comments on commit 38b5464

Please # to comment.