diff --git a/Makefile.dep b/Makefile.dep
index 5e40df93ee3eaac84daca5b124523c2661782ba1..2c14046231d11bd621345f2aabcbc9aa93551cc3 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -48,6 +48,11 @@ ifneq (,$(filter sixlowpan,$(USEMODULE)))
   USEMODULE += vtimer
 endif
 
+ifneq (,$(filter ng_sixlowpan_ctx,$(USEMODULE)))
+  USEMODULE += ng_ipv6_addr
+  USEMODULE += vtimer
+endif
+
 ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE)))
   USEMODULE += ng_inet_csum
   USEMODULE += ng_pktbuf
diff --git a/sys/Makefile b/sys/Makefile
index b734317e10306e874738b41b6e8cd92b618b4931..dd4b6ba0dce01b2fbbc5e6ec7d4c3cd79f6df724 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -92,6 +92,9 @@ endif
 ifneq (,$(filter ng_pktbuf,$(USEMODULE)))
     DIRS += net/crosslayer/ng_pktbuf
 endif
+ifneq (,$(filter ng_sixlowpan_ctx,$(USEMODULE)))
+    DIRS += net/network_layer/ng_sixlowpan/ctx
+endif
 ifneq (,$(filter netapi,$(USEMODULE)))
     DIRS += net/crosslayer/netapi
 endif
diff --git a/sys/include/net/ng_sixlowpan/ctx.h b/sys/include/net/ng_sixlowpan/ctx.h
new file mode 100644
index 0000000000000000000000000000000000000000..40e1544ebf92e3b3705839eebb6ba3c731fd2d16
--- /dev/null
+++ b/sys/include/net/ng_sixlowpan/ctx.h
@@ -0,0 +1,103 @@
+/*
+ * 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_ctx    Contexts for 6LoWPAN address compression
+ * @ingroup     net_ng_sixlowpan
+ * @brief       Context buffer for stateful 6LoWPAN address 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>
+ * @{
+ *
+ * @file
+ * @brief   Context buffer definitions
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef NG_SIXLOWPAN_CTX_H_
+#define NG_SIXLOWPAN_CTX_H_
+
+#include <inttypes.h>
+
+#include "net/ng_ipv6/addr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NG_SIXLOWPAN_CTX_SIZE   (16)    /**< maximum number of entries in
+                                         *   context buffer */
+
+typedef struct {
+    ng_ipv6_addr_t prefix;  /**< The prefix associated to this context. */
+    uint8_t prefix_len;     /**< Length of ng_sixlowpan_ctx_t::prefix in bit. */
+    /**
+     * @brief   4-bit Context ID.
+     *
+     * @note    This needs to be here to easily translate prefixes to
+     *          ID.
+     */
+    uint8_t id;
+    /**
+     * @brief   Lifetime in minutes this context is valid.
+     *
+     * @see     <a href="http://tools.ietf.org/html/rfc6775#section-4.2">
+     *              6LoWPAN Context Option
+     *          </a>
+     */
+    uint16_t ltime;
+} ng_sixlowpan_ctx_t;
+
+/**
+ * @brief   Gets a context matching the given IPv6 address best with its prefix.
+ *
+ * @param[in] addr  An IPv6 address.
+ *
+ * @return  The context associated with the best prefix for @p addr.
+ * @return  NULL if there is no such context.
+ */
+ng_sixlowpan_ctx_t *ng_sixlowpan_ctx_lookup_addr(const ng_ipv6_addr_t *addr);
+
+/**
+ * @brief   Gets context by ID.
+ *
+ * @param[in] id    A context ID.
+ *
+ * @return  The context associated with @p id.
+ * @return  NULL if there is no such context.
+ */
+ng_sixlowpan_ctx_t *ng_sixlowpan_ctx_lookup_id(uint8_t id);
+
+/**
+ * @brief   Updates (or adds if currently not registered) a context
+ *
+ * @param[in] id            The ID for the context.
+ *                          Must be < @ref NG_SIXLOWPAN_CTX_SIZE.
+ * @param[in] prefix        The prefix for the context.
+ * @param[in] prefix_len    Length of @p prefix in bits. Must be > 0, when
+ *                          @p ltime > 0.
+ * @param[in] ltime         New lifetime of the context. The context will
+ *                          be removed if 0.
+ *
+ * @return  The new context on success.
+ * @return  NULL, on error or on removal.
+ */
+ng_sixlowpan_ctx_t *ng_sixlowpan_ctx_update(uint8_t id, const ng_ipv6_addr_t *prefix,
+                                            uint8_t prefix_len, uint16_t ltime);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NG_SIXLOWPAN_CTX_H_ */
+/** @} */
diff --git a/sys/net/network_layer/ng_sixlowpan/ctx/Makefile b/sys/net/network_layer/ng_sixlowpan/ctx/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..afa4a1ee6dc5de5ecbd8a79cff16d8818618fd33
--- /dev/null
+++ b/sys/net/network_layer/ng_sixlowpan/ctx/Makefile
@@ -0,0 +1,3 @@
+MODULE = ng_sixlowpan_ctx
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/network_layer/ng_sixlowpan/ctx/ng_sixlowpan_ctx.c b/sys/net/network_layer/ng_sixlowpan/ctx/ng_sixlowpan_ctx.c
new file mode 100644
index 0000000000000000000000000000000000000000..3bd57f68ef9820534608d369cad7eba6573944d8
--- /dev/null
+++ b/sys/net/network_layer/ng_sixlowpan/ctx/ng_sixlowpan_ctx.c
@@ -0,0 +1,172 @@
+/*
+ * 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 <inttypes.h>
+
+#include "mutex.h"
+#include "net/ng_sixlowpan/ctx.h"
+#include "vtimer.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+static ng_sixlowpan_ctx_t _ctxs[NG_SIXLOWPAN_CTX_SIZE];
+static uint32_t _ctx_inval_times[NG_SIXLOWPAN_CTX_SIZE];
+static mutex_t _ctx_mutex = MUTEX_INIT;
+
+static uint32_t _current_minute(void);
+static void _update_lifetime(unsigned int id);
+
+#if ENABLE_DEBUG
+static char ipv6str[NG_IPV6_ADDR_MAX_STR_LEN];
+#endif
+
+static inline bool _still_valid(unsigned int id)
+{
+    _update_lifetime(id);
+    return (_ctxs[id].ltime > 0);
+}
+
+ng_sixlowpan_ctx_t *ng_sixlowpan_ctx_lookup_addr(const ng_ipv6_addr_t *addr)
+{
+    uint8_t best = 0;
+    ng_sixlowpan_ctx_t *res = NULL;
+
+    mutex_lock(&_ctx_mutex);
+
+    for (unsigned int id = 0; id < NG_SIXLOWPAN_CTX_SIZE; id++) {
+        if (_still_valid(id)) {
+            uint8_t match = ng_ipv6_addr_match_prefix(&_ctxs[id].prefix, addr);
+
+            if ((_ctxs[id].prefix_len <= match) && (match > best)) {
+                best = match;
+                res = _ctxs + id;
+            }
+        }
+    }
+
+    mutex_unlock(&_ctx_mutex);
+
+#if ENABLE_DEBUG
+    if (res != NULL) {
+        DEBUG("6lo ctx: found context (%u, %s/%" PRIu8 ") ", res->id,
+              ng_ipv6_addr_to_str(ipv6str, &res->prefix, sizeof(ipv6str)),
+              res->prefix_len);
+        DEBUG("for address %s\n", ng_ipv6_addr_to_str(ipv6str, addr, sizeof(ipv6str)));
+    }
+#endif
+
+    return res;
+}
+
+ng_sixlowpan_ctx_t *ng_sixlowpan_ctx_lookup_id(uint8_t id)
+{
+    if (id >= NG_SIXLOWPAN_CTX_SIZE) {
+        return NULL;
+    }
+
+    mutex_lock(&_ctx_mutex);
+
+    if (_still_valid((unsigned int)id)) {
+        DEBUG("6lo ctx: found context (%u, %s/%" PRIu8 ")\n", id,
+              ng_ipv6_addr_to_str(ipv6str, &_ctxs[id].prefix, sizeof(ipv6str)),
+              _ctxs[id].prefix_len);
+        mutex_unlock(&_ctx_mutex);
+        return _ctxs + id;
+    }
+
+    mutex_unlock(&_ctx_mutex);
+
+    return NULL;
+}
+
+ng_sixlowpan_ctx_t *ng_sixlowpan_ctx_update(uint8_t id, const ng_ipv6_addr_t *prefix,
+                                            uint8_t prefix_len, uint16_t ltime)
+{
+    if ((id >= NG_SIXLOWPAN_CTX_SIZE)) {
+        return NULL;
+    }
+
+    mutex_lock(&_ctx_mutex);
+
+    _ctxs[id].ltime = ltime;
+
+    if (ltime == 0) {
+        mutex_unlock(&_ctx_mutex);
+        DEBUG("6lo ctx: remove context (%u, %s/%" PRIu8 ")\n", id,
+              ng_ipv6_addr_to_str(ipv6str, &_ctxs[id].prefix, sizeof(ipv6str)),
+              _ctxs[id].prefix_len);
+        return NULL;
+    }
+
+    /* test prefix_len now so that invalidation is possible regardless of the
+     * value. */
+    if (prefix_len == 0) {
+        mutex_unlock(&_ctx_mutex);
+        _ctxs[id].ltime = 0;
+        return NULL;
+    }
+
+    if (prefix_len > NG_IPV6_ADDR_BIT_LEN) {
+        _ctxs[id].prefix_len = NG_IPV6_ADDR_BIT_LEN;
+    }
+    else {
+        _ctxs[id].prefix_len = prefix_len;
+    }
+
+    _ctxs[id].id = id;
+
+    if (!ng_ipv6_addr_equal(&(_ctxs[id].prefix), prefix)) {
+        ng_ipv6_addr_set_unspecified(&(_ctxs[id].prefix));
+        ng_ipv6_addr_init_prefix(&(_ctxs[id].prefix), prefix,
+                                 _ctxs[id].prefix_len);
+    }
+    DEBUG("6lo ctx: update context (%u, %s/%" PRIu8 "), lifetime: %" PRIu16 " min\n",
+          id, ng_ipv6_addr_to_str(ipv6str, &_ctxs[id].prefix, sizeof(ipv6str)),
+          _ctxs[id].prefix_len, _ctxs[id].ltime);
+    _ctx_inval_times[id] = ltime + _current_minute();
+
+    mutex_unlock(&_ctx_mutex);
+
+    return _ctxs + id;
+}
+
+static uint32_t _current_minute(void)
+{
+    timex_t now;
+    vtimer_now(&now);
+    return now.seconds / 60;
+}
+
+static void _update_lifetime(unsigned int id)
+{
+    uint32_t now;
+
+    if (_ctxs[id].ltime == 0) {
+        return;
+    }
+
+    now = _current_minute();
+
+    if (now >= _ctx_inval_times[id]) {
+        DEBUG("6lo ctx: context %u was invalidated\n", id);
+        _ctxs[id].ltime = 0;
+    }
+    else {
+        _ctxs[id].ltime = (uint16_t)(_ctx_inval_times[id] - now);
+    }
+}
+
+/** @} */