diff --git a/Makefile.dep b/Makefile.dep
index e6f70295b468d2d80fb0fce36526fffb9d0233c5..2eb1d993dab40183a5d21f90261bbb2208fca0f4 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -58,6 +58,19 @@ ifneq (,$(filter gnrc_conn_udp,$(USEMODULE)))
   USEMODULE += gnrc_udp
 endif
 
+ifneq (,$(filter gnrc_sock_%,$(USEMODULE)))
+  USEMODULE += gnrc_sock
+endif
+
+ifneq (,$(filter gnrc_sock_udp,$(USEMODULE)))
+  USEMODULE += gnrc_udp
+  USEMODULE += random     # to generate random ports
+endif
+
+ifneq (,$(filter gnrc_sock,$(USEMODULE)))
+  USEMODULE += gnrc_netapi_mbox
+endif
+
 ifneq (,$(filter gnrc_netapi_mbox,$(USEMODULE)))
   USEMODULE += core_mbox
 endif
diff --git a/Makefile.pseudomodules b/Makefile.pseudomodules
index 27976a1dab9b386be6ad4d44c15d65990712c214..cf0349561dd08fdf37de37e5f5cbbdd0c57941fa 100644
--- a/Makefile.pseudomodules
+++ b/Makefile.pseudomodules
@@ -21,6 +21,7 @@ PSEUDOMODULES += gnrc_sixlowpan_iphc_nhc
 PSEUDOMODULES += gnrc_sixlowpan_nd_border_router
 PSEUDOMODULES += gnrc_sixlowpan_router
 PSEUDOMODULES += gnrc_sixlowpan_router_default
+PSEUDOMODULES += gnrc_sock_check_reuse
 PSEUDOMODULES += log
 PSEUDOMODULES += log_printfnoformat
 PSEUDOMODULES += lwip_arp
@@ -51,6 +52,10 @@ PSEUDOMODULES += saul_adc
 PSEUDOMODULES += saul_default
 PSEUDOMODULES += saul_gpio
 PSEUDOMODULES += schedstatistics
+PSEUDOMODULES += sock
+PSEUDOMODULES += sock_ip
+PSEUDOMODULES += sock_tcp
+PSEUDOMODULES += sock_udp
 
 # include variants of the AT86RF2xx drivers as pseudo modules
 PSEUDOMODULES += at86rf23%
diff --git a/sys/Makefile.include b/sys/Makefile.include
index 51790bc3ec01fcc405f2172f8febc1ebd687011a..7a460af0f8c21e7515eaa6564036af002847741f 100644
--- a/sys/Makefile.include
+++ b/sys/Makefile.include
@@ -9,6 +9,12 @@ endif
 ifneq (,$(filter fib,$(USEMODULE)))
     USEMODULE_INCLUDES += $(RIOTBASE)/sys/posix/include
 endif
+ifneq (,$(filter gnrc_sock,$(USEMODULE)))
+  USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/gnrc/sock/include
+  ifneq (,$(filter gnrc_ipv6,$(USEMODULE)))
+    CFLAGS += -DSOCK_HAS_IPV6
+  endif
+endif
 ifneq (,$(filter posix,$(USEMODULE)))
     USEMODULE_INCLUDES += $(RIOTBASE)/sys/posix/include
 endif
diff --git a/sys/net/gnrc/Makefile b/sys/net/gnrc/Makefile
index a4b69955ff01a060914103bb24ed56087544e2ad..0eb7f61ef74003719343baabd25c2623448e58f8 100644
--- a/sys/net/gnrc/Makefile
+++ b/sys/net/gnrc/Makefile
@@ -112,6 +112,15 @@ endif
 ifneq (,$(filter gnrc_slip,$(USEMODULE)))
     DIRS += link_layer/slip
 endif
+ifneq (,$(filter gnrc_sock,$(USEMODULE)))
+    DIRS += sock
+endif
+ifneq (,$(filter gnrc_sock_ip,$(USEMODULE)))
+    DIRS += sock/ip
+endif
+ifneq (,$(filter gnrc_sock_udp,$(USEMODULE)))
+    DIRS += sock/udp
+endif
 ifneq (,$(filter gnrc_udp,$(USEMODULE)))
     DIRS += transport_layer/udp
 endif
diff --git a/sys/net/gnrc/sock/Makefile b/sys/net/gnrc/sock/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..667aec4086c3e67d7f5fd3c4ad8af137725f3dce
--- /dev/null
+++ b/sys/net/gnrc/sock/Makefile
@@ -0,0 +1,3 @@
+MODULE = gnrc_sock
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/gnrc/sock/gnrc_sock.c b/sys/net/gnrc/sock/gnrc_sock.c
new file mode 100644
index 0000000000000000000000000000000000000000..8b81758c0740eb70df7addca3c61b578af81028e
--- /dev/null
+++ b/sys/net/gnrc/sock/gnrc_sock.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2016 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
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+#include <errno.h>
+
+#include "net/af.h"
+#include "net/ipv6/hdr.h"
+#include "net/gnrc/ipv6/hdr.h"
+#include "net/gnrc/ipv6/netif.h"
+#include "net/gnrc/netreg.h"
+#include "net/udp.h"
+#include "utlist.h"
+#include "xtimer.h"
+
+#include "sock_types.h"
+#include "gnrc_sock_internal.h"
+
+#ifdef MODULE_XTIMER
+#define _TIMEOUT_MAGIC      (0xF38A0B63U)
+#define _TIMEOUT_MSG_TYPE   (0x8474)
+
+static void _callback_put(void *arg)
+{
+    msg_t timeout_msg = { .sender_pid = KERNEL_PID_UNDEF,
+                          .type = _TIMEOUT_MSG_TYPE,
+                          .content = { .value = _TIMEOUT_MAGIC } };
+    gnrc_sock_reg_t *reg = arg;
+
+    /* should be safe, because otherwise if mbox were filled this callback is
+     * senseless */
+    mbox_try_put(&reg->mbox, &timeout_msg);
+}
+#endif
+
+void gnrc_sock_create(gnrc_sock_reg_t *reg, gnrc_nettype_t type, uint32_t demux_ctx)
+{
+    mbox_init(&reg->mbox, reg->mbox_queue, SOCK_MBOX_SIZE);
+    gnrc_netreg_entry_init_mbox(&reg->entry, demux_ctx, &reg->mbox);
+    gnrc_netreg_register(type, &reg->entry);
+}
+
+ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
+                       uint32_t timeout, sock_ip_ep_t *remote)
+{
+    gnrc_pktsnip_t *pkt, *ip, *netif;
+    msg_t msg;
+
+#ifdef MODULE_XTIMER
+    xtimer_t timeout_timer;
+
+    if ((timeout != SOCK_NO_TIMEOUT) && (timeout != 0)) {
+        timeout_timer.callback = _callback_put;
+        timeout_timer.arg = reg;
+        xtimer_set(&timeout_timer, timeout);
+    }
+#endif
+    if (timeout != 0) {
+        mbox_get(&reg->mbox, &msg);
+    }
+    else {
+        if (!mbox_try_get(&reg->mbox, &msg)) {
+            return -EAGAIN;
+        }
+    }
+#ifdef MODULE_XTIMER
+    xtimer_remove(&timeout_timer);
+#endif
+    switch (msg.type) {
+        case GNRC_NETAPI_MSG_TYPE_RCV:
+            pkt = msg.content.ptr;
+            break;
+#ifdef MODULE_XTIMER
+        case _TIMEOUT_MSG_TYPE:
+            if (msg.content.value == _TIMEOUT_MAGIC) {
+                return -ETIMEDOUT;
+            }
+#endif
+        default:
+            return -EINTR;
+    }
+    /* TODO: discern NETTYPE from remote->family (set in caller), when IPv4
+     * was implemented */
+    ipv6_hdr_t *ipv6_hdr;
+    ip = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
+    assert((ip != NULL) && (ip->size >= 40));
+    ipv6_hdr = ip->data;
+    memcpy(&remote->addr, &ipv6_hdr->src, sizeof(ipv6_addr_t));
+    remote->family = AF_INET6;
+    netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);
+    if (netif == NULL) {
+        remote->netif = SOCK_ADDR_ANY_NETIF;
+    }
+    else {
+        gnrc_netif_hdr_t *netif_hdr = netif->data;
+        /* TODO: use API in #5511 */
+        remote->netif = (uint16_t)netif_hdr->if_pid;
+    }
+    *pkt_out = pkt; /* set out parameter */
+    return 0;
+}
+
+ssize_t gnrc_sock_send(gnrc_pktsnip_t *payload, sock_ip_ep_t *local,
+                       const sock_ip_ep_t *remote, uint8_t nh)
+{
+    gnrc_pktsnip_t *pkt;
+    kernel_pid_t iface = KERNEL_PID_UNDEF;
+    gnrc_nettype_t type;
+    size_t payload_len = gnrc_pkt_len(payload);
+
+    if (local->family != remote->family) {
+        gnrc_pktbuf_release(payload);
+        return -EAFNOSUPPORT;
+    }
+    switch (local->family) {
+#ifdef SOCK_HAS_IPV6
+        case AF_INET6: {
+            ipv6_hdr_t *hdr;
+            pkt = gnrc_ipv6_hdr_build(payload, (ipv6_addr_t *)&local->addr.ipv6,
+                                      (ipv6_addr_t *)&remote->addr.ipv6);
+            if (pkt == NULL) {
+                return -ENOMEM;
+            }
+            if (payload->type == GNRC_NETTYPE_UNDEF) {
+                payload->type = GNRC_NETTYPE_IPV6;
+                type = GNRC_NETTYPE_IPV6;
+            }
+            else {
+                type = payload->type;
+            }
+            hdr = pkt->data;
+            hdr->nh = nh;
+            break;
+        }
+#endif
+        default:
+            (void)nh;
+            gnrc_pktbuf_release(payload);
+            return -EAFNOSUPPORT;
+    }
+    if (local->netif != SOCK_ADDR_ANY_NETIF) {
+        /* TODO: use API in #5511 */
+        iface = (kernel_pid_t)local->netif;
+    }
+    else if (remote->netif != SOCK_ADDR_ANY_NETIF) {
+        /* TODO: use API in #5511 */
+        iface = (kernel_pid_t)remote->netif;
+    }
+    if (iface != KERNEL_PID_UNDEF) {
+        gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
+        gnrc_netif_hdr_t *netif_hdr;
+
+        if (netif == NULL) {
+            gnrc_pktbuf_release(pkt);
+            return -ENOMEM;
+        }
+        netif_hdr = netif->data;
+        netif_hdr->if_pid = iface;
+        LL_PREPEND(pkt, netif);
+    }
+#ifdef MODULE_GNRC_NETERR
+    gnrc_neterr_reg(pkt);   /* no error should occur since pkt was created here */
+#endif
+    if (!gnrc_netapi_dispatch_send(type, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) {
+        /* this should not happen, but just in case */
+        gnrc_pktbuf_release(pkt);
+        return -EBADMSG;
+    }
+#ifdef MODULE_GNRC_NETERR
+    msg_t err_report;
+    err_report.type = 0;
+
+    while (err_report.type != GNRC_NETERR_MSG_TYPE) {
+        msg_try_receive(err_report);
+        if (err_report.type != GNRC_NETERR_MSG_TYPE) {
+            msg_try_send(err_report, sched_active_pid);
+        }
+    }
+    if (err_report.content.value != GNRC_NETERR_SUCCESS) {
+        return (int)(-err_report.content.value);
+    }
+#endif
+    return payload_len;
+}
+
+/** @} */
diff --git a/sys/net/gnrc/sock/include/gnrc_sock_internal.h b/sys/net/gnrc/sock/include/gnrc_sock_internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..49cb4763855299a19e282b65178900cb509f5f27
--- /dev/null
+++ b/sys/net/gnrc/sock/include/gnrc_sock_internal.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 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_gnrc_sock   GNRC-specific implementation of the sock API
+ * @ingroup     net_gnrc
+ * @brief       Provides an implementation of the @ref net_sock by the
+ *              @ref net_gnrc
+ *
+ * @{
+ *
+ * @file
+ * @brief   GNRC-specific types and function definitions
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef GNRC_SOCK_INTERNAL_H_
+#define GNRC_SOCK_INTERNAL_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "mbox.h"
+#include "net/af.h"
+#include "net/gnrc.h"
+#include "net/gnrc/netreg.h"
+#include "net/sock/ip.h"
+
+#include "sock_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Internal helper functions for GNRC
+ * @internal
+ * @{
+ */
+/**
+ * @brief   Checks if address family is not supported
+ * @internal
+ */
+static inline bool gnrc_af_not_supported(int af)
+{
+    /* TODO: add AF_INET support */
+    return (af != AF_INET6);
+}
+
+/**
+ * @brief   Check if end point points to any address
+ * @internal
+ */
+static inline bool gnrc_ep_addr_any(const sock_ip_ep_t *ep)
+{
+    assert(ep != NULL);
+    const uint8_t *p = (uint8_t *)&ep->addr;
+    for (uint8_t i = 0; i < sizeof(ep->addr); i++) {
+        if (p[i] != 0) {
+            return false;
+        }
+    }
+    return true;
+}
+
+/**
+ * @brief   Create a sock internally
+ * @internal
+ */
+void gnrc_sock_create(gnrc_sock_reg_t *reg, gnrc_nettype_t type, uint32_t demux_ctx);
+
+/**
+ * @brief   Receive a packet internally
+ * @internal
+ */
+ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt, uint32_t timeout,
+                       sock_ip_ep_t *remote);
+
+/**
+ * @brief   Send a packet internally
+ * @internal
+ */
+ssize_t gnrc_sock_send(gnrc_pktsnip_t *payload, sock_ip_ep_t *local,
+                       const sock_ip_ep_t *remote, uint8_t nh);
+/**
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GNRC_SOCK_INTERNAL_H_ */
+/** @} */
diff --git a/sys/net/gnrc/sock/include/sock_types.h b/sys/net/gnrc/sock/include/sock_types.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e86b0c37526f93610000c1a85cd992a9e38ab31
--- /dev/null
+++ b/sys/net/gnrc/sock/include/sock_types.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 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_gnrc_sock   GNRC-specific implementation of the sock API
+ * @ingroup     net_gnrc
+ * @brief       Provides an implementation of the @ref net_sock by the
+ *              @ref net_gnrc
+ *
+ * @{
+ *
+ * @file
+ * @brief   GNRC-specific types and function definitions
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef SOCK_TYPES_H_
+#define SOCK_TYPES_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "mbox.h"
+#include "net/gnrc.h"
+#include "net/gnrc/netreg.h"
+#include "net/sock/ip.h"
+#include "net/sock/udp.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SOCK_MBOX_SIZE
+#define SOCK_MBOX_SIZE      (8)         /**< Size for gnrc_sock_reg_t::mbox_queue */
+#endif
+
+/**
+ * @brief   sock @ref net_gnrc_netreg info
+ * @internal
+ */
+typedef struct gnrc_sock_reg {
+#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
+    struct gnrc_sock_reg *next;         /**< list-like for internal storage */
+#endif
+    gnrc_netreg_entry_t entry;          /**< @ref net_gnrc_netreg entry for mbox */
+    mbox_t mbox;                        /**< @ref core_mbox target for the sock */
+    msg_t mbox_queue[SOCK_MBOX_SIZE];   /**< queue for gnrc_sock_reg_t::mbox */
+} gnrc_sock_reg_t;
+
+/**
+ * @brief   Raw IP sock type
+ * @internal
+ */
+struct sock_ip {
+    gnrc_sock_reg_t reg;                /**< netreg info */
+    sock_ip_ep_t local;                 /**< local end-point */
+    sock_ip_ep_t remote;                /**< remote end-point */
+    uint16_t flags;                     /**< option flags */
+};
+
+/**
+ * @brief   UDP sock type
+ * @internal
+ */
+struct sock_udp {
+    gnrc_sock_reg_t reg;                /**< netreg info */
+    sock_udp_ep_t local;                /**< local end-point */
+    sock_udp_ep_t remote;               /**< remote end-point */
+    uint16_t flags;                     /**< option flags */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOCK_TYPES_H_ */
+/** @} */
diff --git a/sys/net/gnrc/sock/ip/Makefile b/sys/net/gnrc/sock/ip/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..5004d566c83f449e9730a7817c953f2ae7d73f00
--- /dev/null
+++ b/sys/net/gnrc/sock/ip/Makefile
@@ -0,0 +1,3 @@
+MODULE = gnrc_sock_ip
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/gnrc/sock/ip/gnrc_sock_ip.c b/sys/net/gnrc/sock/ip/gnrc_sock_ip.c
new file mode 100644
index 0000000000000000000000000000000000000000..a72716e2fcf676a2bed428914b0c6d221690e146
--- /dev/null
+++ b/sys/net/gnrc/sock/ip/gnrc_sock_ip.c
@@ -0,0 +1,199 @@
+/*
+ * 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
+ * @brief       GNRC implementation of @ref net_sock_ip
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+#include <errno.h>
+
+#include "byteorder.h"
+#include "net/af.h"
+#include "net/protnum.h"
+#include "net/gnrc/ipv6.h"
+#include "net/sock/ip.h"
+#include "random.h"
+
+#include "gnrc_sock_internal.h"
+
+int sock_ip_create(sock_ip_t *sock, const sock_ip_ep_t *local,
+                    const sock_ip_ep_t *remote, uint8_t proto, uint16_t flags)
+{
+    assert(sock);
+    if ((local != NULL) && (remote != NULL) &&
+        (local->netif != SOCK_ADDR_ANY_NETIF) &&
+        (remote->netif != SOCK_ADDR_ANY_NETIF) &&
+        (local->netif != remote->netif)) {
+        return -EINVAL;
+    }
+    memset(&sock->local, 0, sizeof(sock_ip_t));
+    if (local != NULL) {
+        if (gnrc_af_not_supported(local->family)) {
+            return -EAFNOSUPPORT;
+        }
+        memcpy(&sock->local, local, sizeof(sock_ip_t));
+    }
+    memset(&sock->remote, 0, sizeof(sock_ip_t));
+    if (remote != NULL) {
+        if (gnrc_af_not_supported(remote->family)) {
+            return -EAFNOSUPPORT;
+        }
+        if (gnrc_ep_addr_any(remote)) {
+            return -EINVAL;
+        }
+        memcpy(&sock->remote, remote, sizeof(sock_ip_t));
+    }
+    gnrc_sock_create(&sock->reg, GNRC_NETTYPE_IPV6,
+                     proto);
+    sock->flags = flags;
+    return 0;
+}
+
+void sock_ip_close(sock_ip_t *sock)
+{
+    assert(sock != NULL);
+    gnrc_netreg_unregister(GNRC_NETTYPE_IPV6, &sock->reg.entry);
+}
+
+int sock_ip_get_local(sock_ip_t *sock, sock_ip_ep_t *local)
+{
+    assert(sock && local);
+    if (sock->local.family == AF_UNSPEC) {
+        return -EADDRNOTAVAIL;
+    }
+    memcpy(local, &sock->local, sizeof(sock_ip_ep_t));
+    return 0;
+}
+
+int sock_ip_get_remote(sock_ip_t *sock, sock_ip_ep_t *remote)
+{
+    assert(sock && remote);
+    if (sock->remote.family == AF_UNSPEC) {
+        return -ENOTCONN;
+    }
+    memcpy(remote, &sock->remote, sizeof(sock_ip_ep_t));
+    return 0;
+}
+
+ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
+                     uint32_t timeout, sock_ip_ep_t *remote)
+{
+    gnrc_pktsnip_t *pkt;
+    sock_ip_ep_t tmp;
+    int res;
+
+    assert((sock != NULL) && (data != NULL) && (max_len > 0));
+    if (sock->local.family == 0) {
+        return -EADDRNOTAVAIL;
+    }
+    tmp.family = sock->local.family;
+    res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp);
+    if (res < 0) {
+        return res;
+    }
+    if (pkt->size > max_len) {
+        gnrc_pktbuf_release(pkt);
+        return -ENOBUFS;
+    }
+    if (remote != NULL) {
+        /* return remote to possibly block if wrong remote */
+        memcpy(remote, &tmp, sizeof(tmp));
+    }
+    if ((sock->remote.family != AF_UNSPEC) &&   /* check remote end-point if set */
+        /* We only have IPv6 for now, so just comparing the whole end point
+         * should suffice */
+        ((memcmp(&sock->remote.addr, &ipv6_addr_unspecified,
+                 sizeof(ipv6_addr_t)) != 0) &&
+         (memcmp(&sock->remote.addr, &tmp.addr, sizeof(ipv6_addr_t)) != 0))) {
+        gnrc_pktbuf_release(pkt);
+        return -EPROTO;
+    }
+    memcpy(data, pkt->data, pkt->size);
+    gnrc_pktbuf_release(pkt);
+    return (int)pkt->size;
+}
+
+ssize_t sock_ip_send(sock_ip_t *sock, const void *data, size_t len,
+                     uint8_t proto, const sock_ip_ep_t *remote)
+{
+    int res;
+    gnrc_pktsnip_t *pkt;
+    sock_ip_ep_t local;
+    sock_ip_ep_t rem;
+
+    assert((sock != NULL) || (remote != NULL));
+    assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */
+    if ((remote != NULL) && (sock != NULL) &&
+        (sock->local.netif != SOCK_ADDR_ANY_NETIF) &&
+        (remote->netif != SOCK_ADDR_ANY_NETIF) &&
+        (sock->local.netif != remote->netif)) {
+        return -EINVAL;
+    }
+    if ((remote == NULL) &&
+        /* sock can't be NULL as per assertion above */
+        (sock->remote.family == AF_UNSPEC)) {
+        return -ENOTCONN;
+    }
+    else if ((remote != NULL) && (gnrc_ep_addr_any(remote))) {
+        return -EINVAL;
+    }
+    /* compiler evaluates lazily so this isn't a redundundant check and cppcheck
+     * is being weird here anyways */
+    /* cppcheck-suppress nullPointerRedundantCheck */
+    /* cppcheck-suppress nullPointer */
+    if ((sock == NULL) || (sock->local.family == AF_UNSPEC)) {
+        /* no sock or sock currently unbound */
+        memset(&local, 0, sizeof(local));
+    }
+    else {
+        if (sock != NULL) {
+            proto = (uint8_t)sock->reg.entry.demux_ctx;
+        }
+        memcpy(&local, &sock->local, sizeof(local));
+    }
+    if (remote == NULL) {
+        /* sock can't be NULL at this point */
+        memcpy(&rem, &sock->remote, sizeof(rem));
+    }
+    else {
+        memcpy(&rem, remote, sizeof(rem));
+    }
+    if ((remote != NULL) && (remote->family == AF_UNSPEC) &&
+        (sock->remote.family != AF_UNSPEC)) {
+        /* remote was set on create so take its family */
+        rem.family = sock->remote.family;
+    }
+    else if ((remote != NULL) && gnrc_af_not_supported(remote->family)) {
+        return -EAFNOSUPPORT;
+    }
+    else if ((local.family == AF_UNSPEC) && (rem.family != AF_UNSPEC)) {
+        /* local was set to 0 above */
+        local.family = rem.family;
+    }
+    else if ((local.family != AF_UNSPEC) && (rem.family == AF_UNSPEC)) {
+        /* local was given on create, but remote family wasn't given by user and
+         * there was no remote given on create, take from local */
+        rem.family = local.family;
+    }
+    pkt = gnrc_pktbuf_add(NULL, (void *)data, len, GNRC_NETTYPE_UNDEF);
+    if (pkt == NULL) {
+        return -ENOMEM;
+    }
+    res = gnrc_sock_send(pkt, &local, &rem, proto);
+    if (res <= 0) {
+        return res;
+    }
+    return res;
+}
+
+/** @} */
diff --git a/sys/net/gnrc/sock/udp/Makefile b/sys/net/gnrc/sock/udp/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..257f780a5c2cf37539cc710f84d5a16a592a2a51
--- /dev/null
+++ b/sys/net/gnrc/sock/udp/Makefile
@@ -0,0 +1,3 @@
+MODULE = gnrc_sock_udp
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/net/gnrc/sock/udp/gnrc_sock_udp.c b/sys/net/gnrc/sock/udp/gnrc_sock_udp.c
new file mode 100644
index 0000000000000000000000000000000000000000..31bb5897b8fbc26a8fd0901a2a8fba613607f354
--- /dev/null
+++ b/sys/net/gnrc/sock/udp/gnrc_sock_udp.c
@@ -0,0 +1,277 @@
+/*
+ * 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
+ * @brief       GNRC implementation of @ref net_sock_udp
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+#include <errno.h>
+
+#include "byteorder.h"
+#include "net/af.h"
+#include "net/protnum.h"
+#include "net/gnrc/ipv6.h"
+#include "net/gnrc/udp.h"
+#include "net/sock/udp.h"
+#include "net/udp.h"
+#include "random.h"
+
+#include "gnrc_sock_internal.h"
+
+#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
+static sock_udp_t *_udp_socks = NULL;
+#endif
+
+int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local,
+                    const sock_udp_ep_t *remote, uint16_t flags)
+{
+    assert(sock);
+    assert(local == NULL || local->port != 0);
+    assert(remote == NULL || remote->port != 0);
+    if ((local != NULL) && (remote != NULL) &&
+        (local->netif != SOCK_ADDR_ANY_NETIF) &&
+        (remote->netif != SOCK_ADDR_ANY_NETIF) &&
+        (local->netif != remote->netif)) {
+        return -EINVAL;
+    }
+    memset(&sock->local, 0, sizeof(sock_udp_ep_t));
+    if (local != NULL) {
+#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
+        if (!(flags & SOCK_FLAGS_REUSE_EP)) {
+            for (sock_udp_t *ptr = _udp_socks; ptr != NULL;
+                 ptr = (sock_udp_t *)ptr->reg.next) {
+                if (memcmp(&ptr->local, local, sizeof(sock_udp_ep_t)) == 0) {
+                    return -EADDRINUSE;
+                }
+            }
+        }
+        /* prepend to current socks */
+        sock->reg.next = (gnrc_sock_reg_t *)_udp_socks;
+        _udp_socks = sock;
+#endif
+        if (gnrc_af_not_supported(local->family)) {
+            return -EAFNOSUPPORT;
+        }
+        memcpy(&sock->local, local, sizeof(sock_udp_ep_t));
+    }
+    memset(&sock->remote, 0, sizeof(sock_udp_ep_t));
+    if (remote != NULL) {
+        if (gnrc_af_not_supported(remote->family)) {
+            return -EAFNOSUPPORT;
+        }
+        if (gnrc_ep_addr_any((const sock_ip_ep_t *)remote)) {
+            return -EINVAL;
+        }
+        memcpy(&sock->remote, remote, sizeof(sock_udp_ep_t));
+    }
+    if (local != NULL) {
+        /* listen only with local given */
+        gnrc_sock_create(&sock->reg, GNRC_NETTYPE_UDP,
+                         local->port);
+    }
+    sock->flags = flags;
+    return 0;
+}
+
+void sock_udp_close(sock_udp_t *sock)
+{
+    assert(sock != NULL);
+    gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &sock->reg.entry);
+#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
+    if (_udp_socks != NULL) {
+        gnrc_sock_reg_t *head = (gnrc_sock_reg_t *)_udp_socks;
+        LL_DELETE(head, (gnrc_sock_reg_t *)sock);
+    }
+#endif
+}
+
+int sock_udp_get_local(sock_udp_t *sock, sock_udp_ep_t *local)
+{
+    assert(sock && local);
+    if (sock->local.family == AF_UNSPEC) {
+        return -EADDRNOTAVAIL;
+    }
+    memcpy(local, &sock->local, sizeof(sock_udp_ep_t));
+    return 0;
+}
+
+int sock_udp_get_remote(sock_udp_t *sock, sock_udp_ep_t *remote)
+{
+    assert(sock && remote);
+    if (sock->remote.family == AF_UNSPEC) {
+        return -ENOTCONN;
+    }
+    memcpy(remote, &sock->remote, sizeof(sock_udp_ep_t));
+    return 0;
+}
+
+ssize_t sock_udp_recv(sock_udp_t *sock, void *data, size_t max_len,
+                      uint32_t timeout, sock_udp_ep_t *remote)
+{
+    gnrc_pktsnip_t *pkt, *udp;
+    udp_hdr_t *hdr;
+    sock_ip_ep_t tmp;
+    int res;
+
+    assert((sock != NULL) && (data != NULL) && (max_len > 0));
+    if (sock->local.family == AF_UNSPEC) {
+        return -EADDRNOTAVAIL;
+    }
+    tmp.family = sock->local.family;
+    res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp);
+    if (res < 0) {
+        return res;
+    }
+    if (pkt->size > max_len) {
+        gnrc_pktbuf_release(pkt);
+        return -ENOBUFS;
+    }
+    udp = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_UDP);
+    assert(udp);
+    hdr = udp->data;
+    if (remote != NULL) {
+        /* return remote to possibly block if wrong remote */
+        memcpy(remote, &tmp, sizeof(tmp));
+        remote->port = byteorder_ntohs(hdr->src_port);
+    }
+    if ((sock->remote.family != AF_UNSPEC) &&  /* check remote end-point if set */
+        ((sock->remote.port != byteorder_ntohs(hdr->src_port)) ||
+        /* We only have IPv6 for now, so just comparing the whole end point
+         * should suffice */
+        ((memcmp(&sock->remote.addr, &ipv6_addr_unspecified,
+                 sizeof(ipv6_addr_t)) != 0) &&
+         (memcmp(&sock->remote.addr, &tmp.addr, sizeof(ipv6_addr_t)) != 0)))) {
+        gnrc_pktbuf_release(pkt);
+        return -EPROTO;
+    }
+    memcpy(data, pkt->data, pkt->size);
+    gnrc_pktbuf_release(pkt);
+    return (int)pkt->size;
+}
+
+ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len,
+                      const sock_udp_ep_t *remote)
+{
+    int res;
+    gnrc_pktsnip_t *payload, *pkt;
+    uint16_t src_port = 0, dst_port;
+    sock_ip_ep_t local;
+    sock_ip_ep_t rem;
+
+    assert((sock != NULL) || (remote != NULL));
+    assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */
+    if ((remote != NULL) && (sock != NULL) &&
+        (sock->local.netif != SOCK_ADDR_ANY_NETIF) &&
+        (remote->netif != SOCK_ADDR_ANY_NETIF) &&
+        (sock->local.netif != remote->netif)) {
+        return -EINVAL;
+    }
+    if ((remote != NULL) && ((remote->port == 0) ||
+                             gnrc_ep_addr_any((const sock_ip_ep_t *)remote))) {
+        return -EINVAL;
+    }
+    if ((remote == NULL) &&
+        /* sock can't be NULL as per assertion above */
+        (sock->remote.port == AF_UNSPEC)) {
+        return -ENOTCONN;
+    }
+    /* compiler evaluates lazily so this isn't a redundundant check and cppcheck
+     * is being weird here anyways */
+    /* cppcheck-suppress nullPointerRedundantCheck */
+    /* cppcheck-suppress nullPointer */
+    if ((sock == NULL) || (sock->local.family == AF_UNSPEC)) {
+        /* no sock or sock currently unbound */
+        while (src_port == 0) {
+            src_port = (uint16_t)(random_uint32() & UINT16_MAX);
+#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
+            if ((sock == NULL) || !(sock->flags & SOCK_FLAGS_REUSE_EP)) {
+                /* check if port already registered somewhere */
+                for (sock_udp_t *ptr = _udp_socks; ptr != NULL;
+                     ptr = (sock_udp_t *)ptr->reg.next) {
+                    bool spec_addr = false;
+                    for (unsigned i = 0; i < sizeof(ptr->local.addr); i++) {
+                        const uint8_t *const p = (uint8_t *)&ptr->local.addr;
+                        if (p[i] != 0) {
+                            spec_addr = true;
+                        }
+                    }
+                    if (spec_addr) {
+                        continue;
+                    }
+                    if (ptr->local.port == src_port) {
+                        /* we already have one of this port registered
+                         * => generate a new one */
+                        src_port = 0;
+                    }
+                }
+            }
+#endif
+        }
+        memset(&local, 0, sizeof(local));
+        if (sock != NULL) {
+            /* bind sock object implicitly */
+            sock->local.port = src_port;
+#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
+            /* prepend to current socks */
+            sock->reg.next = (gnrc_sock_reg_t *)_udp_socks;
+            _udp_socks = sock;
+#endif
+        }
+    }
+    else {
+        src_port = sock->local.port;
+        memcpy(&local, &sock->local, sizeof(local));
+    }
+    if (remote == NULL) {
+        /* sock can't be NULL at this point */
+        memcpy(&rem, &sock->remote, sizeof(rem));
+        dst_port = sock->remote.port;
+    }
+    else {
+        memcpy(&rem, remote, sizeof(rem));
+        dst_port = remote->port;
+    }
+    if ((remote != NULL) && (remote->family == AF_UNSPEC) &&
+        (sock->remote.family != AF_UNSPEC)) {
+        /* remote was set on create so take its family */
+        rem.family = sock->remote.family;
+    }
+    else if ((remote != NULL) && gnrc_af_not_supported(remote->family)) {
+        return -EAFNOSUPPORT;
+    }
+    else if ((local.family == AF_UNSPEC) && (rem.family != AF_UNSPEC)) {
+        /* local was set to 0 above */
+        local.family = rem.family;
+    }
+    else if ((local.family != AF_UNSPEC) && (rem.family == AF_UNSPEC)) {
+        /* local was given on create, but remote family wasn't given by user and
+         * there was no remote given on create, take from local */
+        rem.family = local.family;
+    }
+    payload = gnrc_pktbuf_add(NULL, (void *)data, len, GNRC_NETTYPE_UNDEF);
+    if (payload == NULL) {
+        return -ENOMEM;
+    }
+    pkt = gnrc_udp_hdr_build(payload, src_port, dst_port);
+    if (pkt == NULL) {
+        gnrc_pktbuf_release(payload);
+        return -ENOMEM;
+    }
+    res = gnrc_sock_send(pkt, &local, &rem, PROTNUM_UDP);
+    if (res <= 0) {
+        return res;
+    }
+    return res - sizeof(udp_hdr_t);
+}
+
+/** @} */
diff --git a/tests/gnrc_sock_ip/Makefile b/tests/gnrc_sock_ip/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..8c06d87bbe1755eaa53ae14d3e3d62b76e30e7a2
--- /dev/null
+++ b/tests/gnrc_sock_ip/Makefile
@@ -0,0 +1,20 @@
+APPLICATION = gnrc_sock_ip
+
+BOARD ?= native
+
+RIOTBASE ?= $(CURDIR)/../..
+
+USEMODULE += gnrc_sock_ip
+USEMODULE += gnrc_ipv6
+USEMODULE += ps
+
+CFLAGS += -DDEVELHELP
+CFLAGS += -DGNRC_PKTBUF_SIZE=200
+CFLAGS += -DTEST_SUITES
+
+QUIET ?= 1
+
+include $(RIOTBASE)/Makefile.include
+
+test:
+	./tests/01-run.py
diff --git a/tests/gnrc_sock_ip/constants.h b/tests/gnrc_sock_ip/constants.h
new file mode 100644
index 0000000000000000000000000000000000000000..88776e4ee242ec889a916271de391f9d5e0e3e4c
--- /dev/null
+++ b/tests/gnrc_sock_ip/constants.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 Freie Universität Berlin
+ *
+ * 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
+ * @ingroup
+ * @brief
+ * @{
+ *
+ * @file
+ * @brief
+ *
+ * @author  Martine Lenders <m.lenders@fu-berlin.de>
+ */
+#ifndef CONSTANTS_H_
+#define CONSTANTS_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _TEST_PROTO         (254) /* https://tools.ietf.org/html/rfc3692#section-2.1 */
+#define _TEST_NETIF         (31)
+#define _TEST_TIMEOUT       (1000000U)
+#define _TEST_ADDR_LOCAL    { 0x7f, 0xc4, 0x11, 0x5a, 0xe6, 0x91, 0x8d, 0x5d, \
+                              0x8c, 0xd1, 0x47, 0x07, 0xb7, 0x6f, 0x9b, 0x48 }
+#define _TEST_ADDR_REMOTE   { 0xe8, 0xb3, 0xb2, 0xe6, 0x70, 0xd4, 0x55, 0xba, \
+                              0x93, 0xcf, 0x11, 0xe1, 0x72, 0x44, 0xc5, 0x9d }
+#define _TEST_ADDR_WRONG    { 0x2a, 0xce, 0x5d, 0x4e, 0xc8, 0xbf, 0x86, 0xf7, \
+                              0x85, 0x49, 0xb4, 0x19, 0xf2, 0x28, 0xde, 0x9b }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONSTANTS_H_ */
+/** @} */
diff --git a/tests/gnrc_sock_ip/main.c b/tests/gnrc_sock_ip/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..f4c6c0774b757c35b2d27e6114dab7aff432a87f
--- /dev/null
+++ b/tests/gnrc_sock_ip/main.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) 2016 Freie Universität Berlin
+ *
+ * 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.
+ */
+
+/**
+ * @ingroup     examples
+ * @{
+ *
+ * @file
+ * @brief       Test for raw IP socks
+ *
+ * @author      Martine Lenders <m.lenders@fu-berlin.de>
+ * @}
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "net/af.h"
+#include "net/sock/ip.h"
+#include "xtimer.h"
+
+#include "constants.h"
+#include "stack.h"
+
+#define _TEST_BUFFER_SIZE   (128)
+
+#define CALL(fn)            puts("Calling " # fn); fn; tear_down()
+
+static sock_ip_t _sock, _sock2;
+static uint8_t _test_buffer[_TEST_BUFFER_SIZE];
+
+static void tear_down(void)
+{
+    sock_ip_close(&_sock);
+    memset(&_sock, 0, sizeof(_sock));
+}
+
+static void test_sock_ip_create__EAFNOSUPPORT(void)
+{
+    static const sock_ip_ep_t local = { .family = AF_UNSPEC };
+    static const sock_ip_ep_t remote = { .family = AF_UNSPEC };
+
+    assert(-EAFNOSUPPORT == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                                           SOCK_FLAGS_REUSE_EP));
+    assert(-EAFNOSUPPORT == sock_ip_create(&_sock, NULL, &remote, _TEST_PROTO,
+                                           SOCK_FLAGS_REUSE_EP));
+}
+
+static void test_sock_ip_create__EINVAL_addr(void)
+{
+    static const sock_ip_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF };
+    static const sock_ip_ep_t remote = { .family = AF_INET6,
+                                         .netif = _TEST_NETIF };
+
+    assert(-EINVAL == sock_ip_create(&_sock, &local, &remote, _TEST_PROTO,
+                                     SOCK_FLAGS_REUSE_EP));
+}
+
+static void test_sock_ip_create__EINVAL_netif(void)
+{
+    static const sock_ip_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF };
+    static const sock_ip_ep_t remote = { .family = AF_INET6,
+                                         .netif = (_TEST_NETIF + 1),
+                                         .addr = { .ipv6 = _TEST_ADDR_REMOTE } };
+
+    assert(-EINVAL == sock_ip_create(&_sock, &local, &remote, _TEST_PROTO,
+                                     SOCK_FLAGS_REUSE_EP));
+}
+
+static void test_sock_ip_create__no_endpoints(void)
+{
+    sock_ip_ep_t ep;
+
+    assert(0 == sock_ip_create(&_sock, NULL, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(-EADDRNOTAVAIL == sock_ip_get_local(&_sock, &ep));
+    assert(-ENOTCONN == sock_ip_get_remote(&_sock, &ep));
+}
+
+static void test_sock_ip_create__only_local(void)
+{
+    static const sock_ip_ep_t local = { .family = AF_INET6 };
+    sock_ip_ep_t ep;
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(0 == sock_ip_get_local(&_sock, &ep));
+    assert(AF_INET6 == ep.family);
+    assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6,
+                  sizeof(ipv6_addr_t)) == 0);
+    assert(SOCK_ADDR_ANY_NETIF == ep.netif);
+    assert(-ENOTCONN == sock_ip_get_remote(&_sock, &ep));
+}
+
+static void test_sock_ip_create__only_local_reuse_ep(void)
+{
+    static const sock_ip_ep_t local = { .family = AF_INET6 };
+    sock_ip_ep_t ep, ep2;
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(0 == sock_ip_create(&_sock2, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(0 == sock_ip_get_local(&_sock, &ep));
+    assert(0 == sock_ip_get_local(&_sock2, &ep2));
+    assert(AF_INET6 == ep.family);
+    assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6,
+                  sizeof(ipv6_addr_t)) == 0);
+    assert(SOCK_ADDR_ANY_NETIF == ep.netif);
+    assert(-ENOTCONN == sock_ip_get_remote(&_sock, &ep));
+    assert(AF_INET6 == ep2.family);
+    assert(memcmp(&ipv6_addr_unspecified, &ep2.addr.ipv6,
+                  sizeof(ipv6_addr_t)) == 0);
+    assert(SOCK_ADDR_ANY_NETIF == ep2.netif);
+    assert(-ENOTCONN == sock_ip_get_remote(&_sock, &ep2));
+    sock_ip_close(&_sock2);
+}
+
+static void test_sock_ip_create__only_remote(void)
+{
+    static const ipv6_addr_t remote_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t remote = { .family = AF_INET6,
+                                         .addr = { .ipv6 = _TEST_ADDR_REMOTE } };
+    sock_ip_ep_t ep;
+
+    assert(0 == sock_ip_create(&_sock, NULL, &remote, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(-EADDRNOTAVAIL == sock_ip_get_local(&_sock, &ep));
+    assert(0 == sock_ip_get_remote(&_sock, &ep));
+    assert(AF_INET6 == ep.family);
+    assert(memcmp(&remote_addr, &ep.addr.ipv6, sizeof(ipv6_addr_t)) == 0);
+    assert(SOCK_ADDR_ANY_NETIF == ep.netif);
+}
+
+static void test_sock_ip_create__full(void)
+{
+    static const ipv6_addr_t remote_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF };
+    static const sock_ip_ep_t remote = { .family = AF_INET6,
+                                         .addr = { .ipv6 = _TEST_ADDR_REMOTE } };
+    sock_ip_ep_t ep;
+
+    assert(0 == sock_ip_create(&_sock, &local, &remote, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(0 == sock_ip_get_local(&_sock, &ep));
+    assert(AF_INET6 == ep.family);
+    assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6,
+                  sizeof(ipv6_addr_t)) == 0);
+    assert(_TEST_NETIF == ep.netif);
+    assert(0 == sock_ip_get_remote(&_sock, &ep));
+    assert(AF_INET6 == ep.family);
+    assert(memcmp(&remote_addr, &ep.addr.ipv6, sizeof(ipv6_addr_t)) == 0);
+    assert(SOCK_ADDR_ANY_NETIF == ep.netif);
+}
+
+static void test_sock_ip_recv__EADDRNOTAVAIL(void)
+{
+    assert(0 == sock_ip_create(&_sock, NULL, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+
+    assert(-EADDRNOTAVAIL == sock_ip_recv(&_sock, _test_buffer,
+                                          sizeof(_test_buffer), SOCK_NO_TIMEOUT,
+                                          NULL));
+}
+
+static void test_sock_ip_recv__EAGAIN(void)
+{
+    static const sock_ip_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF };
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+
+    assert(-EAGAIN == sock_ip_recv(&_sock, _test_buffer, sizeof(_test_buffer),
+                                   0, NULL));
+}
+
+static void test_sock_ip_recv__ENOBUFS(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_ip_ep_t local = { .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                          sizeof("ABCD"), _TEST_NETIF));
+    assert(-ENOBUFS == sock_ip_recv(&_sock, _test_buffer, 2, SOCK_NO_TIMEOUT,
+                                    NULL));
+    assert(_check_net());
+}
+
+static void test_sock_ip_recv__EPROTO(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_WRONG };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_ip_ep_t local = { .family = AF_INET6 };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, &local, &remote, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                          sizeof("ABCD"), _TEST_NETIF));
+    assert(-EPROTO == sock_ip_recv(&_sock, _test_buffer, sizeof(_test_buffer),
+                                   SOCK_NO_TIMEOUT, NULL));
+    assert(_check_net());
+}
+
+static void test_sock_ip_recv__ETIMEDOUT(void)
+{
+    static const sock_ip_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF };
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+
+    puts(" * Calling sock_ip_recv()");
+    assert(-ETIMEDOUT == sock_ip_recv(&_sock, _test_buffer,
+                                      sizeof(_test_buffer), _TEST_TIMEOUT,
+                                      NULL));
+    printf(" * (timed out with timeout %lu)\n", (long unsigned)_TEST_TIMEOUT);
+}
+
+static void test_sock_ip_recv__socketed(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_ip_ep_t local = { .family = AF_INET6 };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, &local, &remote, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                          sizeof("ABCD"), _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_ip_recv(&_sock, _test_buffer,
+                                          sizeof(_test_buffer), SOCK_NO_TIMEOUT,
+                                          NULL));
+    assert(_check_net());
+}
+
+static void test_sock_ip_recv__socketed_with_remote(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_ip_ep_t local = { .family = AF_INET6 };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+    sock_ip_ep_t result;
+
+    assert(0 == sock_ip_create(&_sock, &local, &remote, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                          sizeof("ABCD"), _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_ip_recv(&_sock, _test_buffer,
+                                          sizeof(_test_buffer), SOCK_NO_TIMEOUT,
+                                          &result));
+    assert(AF_INET6 == result.family);
+    assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0);
+    assert(_TEST_NETIF == result.netif);
+    assert(_check_net());
+}
+
+static void test_sock_ip_recv__unsocketed(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_ip_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                        .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                          sizeof("ABCD"), _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_ip_recv(&_sock, _test_buffer,
+                                          sizeof(_test_buffer), SOCK_NO_TIMEOUT,
+                                          NULL));
+    assert(_check_net());
+}
+
+static void test_sock_ip_recv__unsocketed_with_remote(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_ip_ep_t local = { .family = AF_INET6 };
+    sock_ip_ep_t result;
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                          sizeof("ABCD"), _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_ip_recv(&_sock, _test_buffer,
+                                          sizeof(_test_buffer), SOCK_NO_TIMEOUT,
+                                          &result));
+    assert(AF_INET6 == result.family);
+    assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0);
+    assert(_TEST_NETIF == result.netif);
+    assert(_check_net());
+}
+
+static void test_sock_ip_recv__with_timeout(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_ip_ep_t local = { .family = AF_INET6 };
+    sock_ip_ep_t result;
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                          sizeof("ABCD"), _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_ip_recv(&_sock, _test_buffer,
+                                          sizeof(_test_buffer), _TEST_TIMEOUT,
+                                          &result));
+    assert(AF_INET6 == result.family);
+    assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0);
+    assert(_TEST_NETIF == result.netif);
+    assert(_check_net());
+}
+
+static void test_sock_ip_recv__non_blocking(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_ip_ep_t local = { .family = AF_INET6 };
+    sock_ip_ep_t result;
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                          sizeof("ABCD"), _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_ip_recv(&_sock, _test_buffer,
+                                          sizeof(_test_buffer), 0, &result));
+    assert(AF_INET6 == result.family);
+    assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0);
+    assert(_TEST_NETIF == result.netif);
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__EAFNOSUPPORT(void)
+{
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET };
+
+    assert(-EAFNOSUPPORT == sock_ip_send(NULL, "ABCD", sizeof("ABCD"),
+                                         _TEST_PROTO, &remote));
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__EINVAL_addr(void)
+{
+    static const sock_ip_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                        .family = AF_INET6,
+                                        .netif = _TEST_NETIF };
+    static const sock_ip_ep_t remote = { .family = AF_INET6,
+                                         .netif = _TEST_NETIF };
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(-EINVAL == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"), _TEST_PROTO,
+                                   &remote));
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__EINVAL_netif(void)
+{
+    static const sock_ip_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                        .family = AF_INET6,
+                                        .netif = _TEST_NETIF };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6,
+                                         .netif = _TEST_NETIF + 1 };
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(-EINVAL == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"), _TEST_PROTO,
+                                   &remote));
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__ENOTCONN(void)
+{
+    assert(0 == sock_ip_create(&_sock, NULL, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(-ENOTCONN == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"),
+                                     _TEST_PROTO, NULL));
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__socketed_no_local_no_netif(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, NULL, &remote, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, NULL));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), SOCK_ADDR_ANY_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__socketed_no_netif(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                        .family = AF_INET6 };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, &local, &remote, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, NULL));
+    assert(_check_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), SOCK_ADDR_ANY_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__socketed_no_local(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6,
+                                         .netif = _TEST_NETIF };
+
+    assert(0 == sock_ip_create(&_sock, NULL, &remote, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, NULL));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), _TEST_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__socketed(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                        .family = AF_INET6,
+                                        .netif = _TEST_NETIF };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, &local, &remote, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, NULL));
+    assert(_check_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), _TEST_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__socketed_other_remote(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                        .family = AF_INET6,
+                                        .netif = _TEST_NETIF };
+    static const sock_ip_ep_t sock_remote = { .addr = { .ipv6 = _TEST_ADDR_WRONG },
+                                              .family = AF_INET6 };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, &local, &sock_remote, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, &remote));
+    assert(_check_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), _TEST_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__unsocketed_no_local_no_netif(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, NULL, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, &remote));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), SOCK_ADDR_ANY_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__unsocketed_no_netif(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                        .family = AF_INET6 };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, &remote));
+    assert(_check_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), SOCK_ADDR_ANY_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__unsocketed_no_local(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6,
+                                         .netif = _TEST_NETIF };
+
+    assert(0 == sock_ip_create(&_sock, NULL, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, &remote));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), _TEST_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__unsocketed(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                        .family = AF_INET6,
+                                        .netif = _TEST_NETIF };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+
+    assert(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
+                               SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_ip_send(&_sock, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, &remote));
+    assert(_check_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), _TEST_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__no_sock_no_netif(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6 };
+
+    assert(sizeof("ABCD") == sock_ip_send(NULL, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, &remote));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), SOCK_ADDR_ANY_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_ip_send__no_sock(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                         .family = AF_INET6,
+                                         .netif = _TEST_NETIF };
+
+    assert(sizeof("ABCD") == sock_ip_send(NULL, "ABCD", sizeof("ABCD"),
+                                          _TEST_PROTO, &remote));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, _TEST_PROTO, "ABCD",
+                         sizeof("ABCD"), _TEST_NETIF));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+int main(void)
+{
+    _net_init();
+    tear_down();
+    /* EADDRINUSE does not apply for GNRC */
+    CALL(test_sock_ip_create__EAFNOSUPPORT());
+    CALL(test_sock_ip_create__EINVAL_addr());
+    CALL(test_sock_ip_create__EINVAL_netif());
+    /* EPROTONOSUPPORT does not apply for gnrc_ipv6 */
+    CALL(test_sock_ip_create__no_endpoints());
+    CALL(test_sock_ip_create__only_local());
+    CALL(test_sock_ip_create__only_local_reuse_ep());
+    CALL(test_sock_ip_create__only_remote());
+    CALL(test_sock_ip_create__full());
+    /* sock_ip_close() is tested in tear_down() */
+    /* sock_ip_get_local() is tested in sock_ip_create() tests */
+    /* sock_ip_get_remote() is tested in sock_ip_create() tests */
+    CALL(test_sock_ip_recv__EADDRNOTAVAIL());
+    CALL(test_sock_ip_recv__EAGAIN());
+    CALL(test_sock_ip_recv__ENOBUFS());
+    CALL(test_sock_ip_recv__EPROTO());
+    CALL(test_sock_ip_recv__ETIMEDOUT());
+    CALL(test_sock_ip_recv__socketed());
+    CALL(test_sock_ip_recv__socketed_with_remote());
+    CALL(test_sock_ip_recv__unsocketed());
+    CALL(test_sock_ip_recv__unsocketed_with_remote());
+    CALL(test_sock_ip_recv__with_timeout());
+    CALL(test_sock_ip_recv__non_blocking());
+    _prepare_send_checks();
+    CALL(test_sock_ip_send__EAFNOSUPPORT());
+    CALL(test_sock_ip_send__EINVAL_addr());
+    CALL(test_sock_ip_send__EINVAL_netif());
+    CALL(test_sock_ip_send__ENOTCONN());
+    /* EPROTOTYPE does not apply for gnrc_ipv6 */
+    CALL(test_sock_ip_send__socketed_no_local_no_netif());
+    CALL(test_sock_ip_send__socketed_no_netif());
+    CALL(test_sock_ip_send__socketed_no_local());
+    CALL(test_sock_ip_send__socketed());
+    CALL(test_sock_ip_send__socketed_other_remote());
+    CALL(test_sock_ip_send__unsocketed_no_local_no_netif());
+    CALL(test_sock_ip_send__unsocketed_no_netif());
+    CALL(test_sock_ip_send__unsocketed_no_local());
+    CALL(test_sock_ip_send__unsocketed());
+    CALL(test_sock_ip_send__no_sock_no_netif());
+    CALL(test_sock_ip_send__no_sock());
+
+    puts("ALL TESTS SUCCESSFUL");
+
+    return 0;
+}
diff --git a/tests/gnrc_sock_ip/stack.c b/tests/gnrc_sock_ip/stack.c
new file mode 100644
index 0000000000000000000000000000000000000000..62196798290f01b32d06c929e8fc9be90b050705
--- /dev/null
+++ b/tests/gnrc_sock_ip/stack.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 Freie Universität Berlin
+ *
+ * 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
+ * @author  Martine Lenders <m.lenders@fu-berlin.de>
+ */
+
+#include "stack.h"
+
+#include "net/gnrc/ipv6.h"
+#include "net/gnrc/netif/hdr.h"
+#include "net/gnrc/netreg.h"
+#include "net/sock.h"
+#include "sched.h"
+
+#define _MSG_QUEUE_SIZE     (4)
+
+static msg_t _msg_queue[_MSG_QUEUE_SIZE];
+static gnrc_netreg_entry_t _ip_handler;
+
+void _net_init(void)
+{
+    msg_init_queue(_msg_queue, _MSG_QUEUE_SIZE);
+    gnrc_netreg_entry_init_pid(&_ip_handler, GNRC_NETREG_DEMUX_CTX_ALL,
+                               sched_active_pid);
+}
+
+void _prepare_send_checks(void)
+{
+    gnrc_netreg_register(GNRC_NETTYPE_IPV6, &_ip_handler);
+}
+
+static gnrc_pktsnip_t *_build_ipv6_packet(const ipv6_addr_t *src,
+                                          const ipv6_addr_t *dst, uint8_t nh,
+                                          void *data, size_t data_len,
+                                          uint16_t netif)
+{
+    gnrc_pktsnip_t *netif_hdr, *ipv6, *payload;
+    ipv6_hdr_t *ipv6_hdr;
+
+    if ((netif > INT16_MAX) || (data_len > UINT16_MAX)) {
+        return NULL;
+    }
+
+    payload = gnrc_pktbuf_add(NULL, data, data_len, GNRC_NETTYPE_UNDEF);
+    if (payload == NULL) {
+        return NULL;
+    }
+    ipv6 = gnrc_ipv6_hdr_build(NULL, src, dst);
+    if (ipv6 == NULL) {
+        return NULL;
+    }
+    ipv6_hdr = ipv6->data;
+    ipv6_hdr->len = byteorder_htons((uint16_t)payload->size);
+    ipv6_hdr->nh = nh;
+    ipv6_hdr->hl = 64;
+    LL_APPEND(payload, ipv6);
+    netif_hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
+    if (netif_hdr == NULL) {
+        return NULL;
+    }
+    ((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = (kernel_pid_t)netif;
+    LL_APPEND(payload, netif_hdr);
+    return payload;
+}
+
+
+bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
+                    uint8_t proto, void *data, size_t data_len,
+                    uint16_t netif)
+{
+    gnrc_pktsnip_t *pkt = _build_ipv6_packet(src, dst, proto, data, data_len,
+                                             netif);
+
+    if (pkt == NULL) {
+        return false;
+    }
+    /* put directly in mbox, dispatching to IPv6 would result in the packet
+     * being dropped, since dst is not on any interface */
+    return (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, proto, pkt) > 0);
+}
+
+bool _check_net(void)
+{
+    return (gnrc_pktbuf_is_sane() && gnrc_pktbuf_is_empty());
+}
+
+static inline bool _res(gnrc_pktsnip_t *pkt, bool res)
+{
+    gnrc_pktbuf_release(pkt);
+    return res;
+}
+
+bool _check_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
+                   uint8_t proto, void *data, size_t data_len,
+                   uint16_t netif)
+{
+    gnrc_pktsnip_t *pkt, *ipv6;
+    ipv6_hdr_t *ipv6_hdr;
+    msg_t msg;
+
+    msg_receive(&msg);
+    if (msg.type != GNRC_NETAPI_MSG_TYPE_SND) {
+        return false;
+    }
+    pkt = msg.content.ptr;
+    if (netif != SOCK_ADDR_ANY_NETIF) {
+        gnrc_netif_hdr_t *netif_hdr;
+
+        if (pkt->type != GNRC_NETTYPE_NETIF) {
+            return _res(pkt, false);
+        }
+        netif_hdr = pkt->data;
+        if (netif_hdr->if_pid != netif) {
+            return _res(pkt, false);
+        }
+        ipv6 = pkt->next;
+    }
+    else {
+        ipv6 = pkt;
+    }
+    if (ipv6->type != GNRC_NETTYPE_IPV6) {
+        return _res(pkt, false);
+    }
+    ipv6_hdr = ipv6->data;
+    return _res(pkt, (memcmp(src, &ipv6_hdr->src, sizeof(ipv6_addr_t)) == 0) &&
+                (memcmp(dst, &ipv6_hdr->dst, sizeof(ipv6_addr_t)) == 0) &&
+                (ipv6_hdr->nh == proto) &&
+                (ipv6->next != NULL) &&
+                (data_len == ipv6->next->size) &&
+                (memcmp(data, ipv6->next->data, data_len) == 0));
+}
+
+/** @} */
diff --git a/tests/gnrc_sock_ip/stack.h b/tests/gnrc_sock_ip/stack.h
new file mode 100644
index 0000000000000000000000000000000000000000..637ef466f5ec2dc994b2ef05709bd834c2618208
--- /dev/null
+++ b/tests/gnrc_sock_ip/stack.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 Freie Universität Berlin
+ *
+ * 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
+ * @ingroup
+ * @brief
+ * @{
+ *
+ * @file
+ * @brief
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef STACK_H_
+#define STACK_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "net/ipv6/addr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Initializes networking for tests
+ */
+void _net_init(void);
+
+/**
+ * @brief   Does what ever preparations are needed to check the packets sent
+ */
+void _prepare_send_checks(void);
+
+/**
+ * @brief   Injects a received IPv6 packet into the stack
+ *
+ * @param[in] src       The source address of the IPv6 packet
+ * @param[in] dst       The destination address of the IPv6 packet
+ * @param[in] proto     The next header field of the IPv6 packet
+ * @param[in] data      The payload of the IPv6 packet
+ * @param[in] data_len  The payload length of the IPv6 packet
+ * @param[in] netif     The interface the packet came over
+ *
+ * @return  true, if packet was successfully injected
+ * @return  false, if an error occured during injection
+ */
+bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
+                    uint8_t proto, void *data, size_t data_len,
+                    uint16_t netif);
+
+/**
+ * @brief   Checks networking state (e.g. packet buffer state)
+ *
+ * @return  true, if networking component is still in valid state
+ * @return  false, if networking component is in an invalid state
+ */
+bool _check_net(void);
+
+/**
+ * @brief   Checks if a IPv6 packet was sent by the networking component
+ *
+ * @param[in] src               Expected source address of the IPv6 packet
+ * @param[in] dst               Expected destination address of the IPv6 packet
+ * @param[in] proto             Expected next header field of the IPv6 packet
+ * @param[in] data              Expected payload of the IPv6 packet
+ * @param[in] data_len          Expected payload length of the IPv6 packet
+ * @param[in] netif             Expected interface the packet is supposed to
+ *                              be send over
+ *
+ * @return  true, if all parameters match as expected
+ * @return  false, if not.
+ */
+bool _check_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
+                   uint8_t proto, void *data, size_t data_len, uint16_t netif);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STACK_H_ */
+/** @} */
diff --git a/tests/gnrc_sock_ip/tests/01-run.py b/tests/gnrc_sock_ip/tests/01-run.py
new file mode 100755
index 0000000000000000000000000000000000000000..a42c3f5c660e8fea1c924c4a8d290448542f19fb
--- /dev/null
+++ b/tests/gnrc_sock_ip/tests/01-run.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.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.
+
+import os
+import sys
+
+from datetime import datetime
+
+sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner'))
+import testrunner
+
+class InvalidTimeout(Exception):
+    pass
+
+def testfunc(child):
+    child.expect_exact(u"Calling test_sock_ip_create__EAFNOSUPPORT()")
+    child.expect_exact(u"Calling test_sock_ip_create__EINVAL_addr()")
+    child.expect_exact(u"Calling test_sock_ip_create__EINVAL_netif()")
+    child.expect_exact(u"Calling test_sock_ip_create__no_endpoints()")
+    child.expect_exact(u"Calling test_sock_ip_create__only_local()")
+    child.expect_exact(u"Calling test_sock_ip_create__only_local_reuse_ep()")
+    child.expect_exact(u"Calling test_sock_ip_create__only_remote()")
+    child.expect_exact(u"Calling test_sock_ip_create__full()")
+    child.expect_exact(u"Calling test_sock_ip_recv__EADDRNOTAVAIL()")
+    child.expect_exact(u"Calling test_sock_ip_recv__ENOBUFS()")
+    child.expect_exact(u"Calling test_sock_ip_recv__EPROTO()")
+    child.expect_exact(u"Calling test_sock_ip_recv__ETIMEDOUT()")
+    child.match         # get to ensure program reached that point
+    start = datetime.now()
+    child.expect_exact(u" * Calling sock_ip_recv()")
+    child.expect(u" \\* \\(timed out with timeout (\\d+)\\)")
+    exp_diff = int(child.match.group(1))
+    stop = datetime.now()
+    diff = (stop - start)
+    diff = (diff.seconds * 1000000) + diff.microseconds
+    # fail within 5% of expected
+    if diff > (exp_diff + (exp_diff * 0.05)) or \
+       diff < (exp_diff - (exp_diff * 0.05)):
+        raise InvalidTimeout("Invalid timeout %d (expected %d)" % (diff, exp_diff));
+    else:
+        print("Timed out correctly: %d (expected %d)" % (diff, exp_diff))
+    child.expect_exact(u"Calling test_sock_ip_recv__socketed()")
+    child.expect_exact(u"Calling test_sock_ip_recv__socketed_with_remote()")
+    child.expect_exact(u"Calling test_sock_ip_recv__unsocketed()")
+    child.expect_exact(u"Calling test_sock_ip_recv__unsocketed_with_remote()")
+    child.expect_exact(u"Calling test_sock_ip_recv__with_timeout()")
+    child.expect_exact(u"Calling test_sock_ip_send__EAFNOSUPPORT()")
+    child.expect_exact(u"Calling test_sock_ip_send__EINVAL_addr()")
+    child.expect_exact(u"Calling test_sock_ip_send__EINVAL_netif()")
+    child.expect_exact(u"Calling test_sock_ip_send__ENOTCONN()")
+    child.expect_exact(u"Calling test_sock_ip_send__socketed_no_local_no_netif()")
+    child.expect_exact(u"Calling test_sock_ip_send__socketed_no_netif()")
+    child.expect_exact(u"Calling test_sock_ip_send__socketed_no_local()")
+    child.expect_exact(u"Calling test_sock_ip_send__socketed()")
+    child.expect_exact(u"Calling test_sock_ip_send__socketed_other_remote()")
+    child.expect_exact(u"Calling test_sock_ip_send__unsocketed_no_local_no_netif()")
+    child.expect_exact(u"Calling test_sock_ip_send__unsocketed_no_netif()")
+    child.expect_exact(u"Calling test_sock_ip_send__unsocketed_no_local()")
+    child.expect_exact(u"Calling test_sock_ip_send__unsocketed()")
+    child.expect_exact(u"Calling test_sock_ip_send__no_sock_no_netif()")
+    child.expect_exact(u"Calling test_sock_ip_send__no_sock()")
+    child.expect_exact(u"ALL TESTS SUCCESSFUL")
+
+if __name__ == "__main__":
+    sys.exit(testrunner.run(testfunc))
diff --git a/tests/gnrc_sock_udp/Makefile b/tests/gnrc_sock_udp/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..bbfdfc3a7eb8e42f39b3bc3dcc5b53932ee02e18
--- /dev/null
+++ b/tests/gnrc_sock_udp/Makefile
@@ -0,0 +1,21 @@
+APPLICATION = gnrc_sock_udp
+
+BOARD ?= native
+
+RIOTBASE ?= $(CURDIR)/../..
+
+USEMODULE += gnrc_sock_check_reuse
+USEMODULE += gnrc_sock_udp
+USEMODULE += gnrc_ipv6
+USEMODULE += ps
+
+CFLAGS += -DDEVELHELP
+CFLAGS += -DGNRC_PKTBUF_SIZE=200
+CFLAGS += -DTEST_SUITES
+
+QUIET ?= 1
+
+include $(RIOTBASE)/Makefile.include
+
+test:
+	./tests/01-run.py
diff --git a/tests/gnrc_sock_udp/constants.h b/tests/gnrc_sock_udp/constants.h
new file mode 100644
index 0000000000000000000000000000000000000000..fefe41663889cf44e7590569a183e3bd139f542d
--- /dev/null
+++ b/tests/gnrc_sock_udp/constants.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 Freie Universität Berlin
+ *
+ * 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
+ * @ingroup
+ * @brief
+ * @{
+ *
+ * @file
+ * @brief
+ *
+ * @author  Martine Lenders <m.lenders@fu-berlin.de>
+ */
+#ifndef CONSTANTS_H_
+#define CONSTANTS_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _TEST_PORT_LOCAL    (0x2c94)
+#define _TEST_PORT_REMOTE   (0xa615)
+#define _TEST_NETIF         (31)
+#define _TEST_TIMEOUT       (1000000U)
+#define _TEST_ADDR_LOCAL    { 0x7f, 0xc4, 0x11, 0x5a, 0xe6, 0x91, 0x8d, 0x5d, \
+                              0x8c, 0xd1, 0x47, 0x07, 0xb7, 0x6f, 0x9b, 0x48 }
+#define _TEST_ADDR_REMOTE   { 0xe8, 0xb3, 0xb2, 0xe6, 0x70, 0xd4, 0x55, 0xba, \
+                              0x93, 0xcf, 0x11, 0xe1, 0x72, 0x44, 0xc5, 0x9d }
+#define _TEST_ADDR_WRONG    { 0x2a, 0xce, 0x5d, 0x4e, 0xc8, 0xbf, 0x86, 0xf7, \
+                              0x85, 0x49, 0xb4, 0x19, 0xf2, 0x28, 0xde, 0x9b }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONSTANTS_H_ */
+/** @} */
diff --git a/tests/gnrc_sock_udp/main.c b/tests/gnrc_sock_udp/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..043eae3e26e02db5f5b7fc0cbd09927b7fe2edfc
--- /dev/null
+++ b/tests/gnrc_sock_udp/main.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (C) 2016 Freie Universität Berlin
+ *
+ * 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.
+ */
+
+/**
+ * @ingroup     tests
+ * @{
+ *
+ * @file
+ * @brief       Test for UDP socks
+ *
+ * @author      Martine Lenders <m.lenders@fu-berlin.de>
+ * @}
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "net/af.h"
+#include "net/sock/udp.h"
+#include "xtimer.h"
+
+#include "constants.h"
+#include "stack.h"
+
+#define _TEST_BUFFER_SIZE   (128)
+
+static uint8_t _test_buffer[_TEST_BUFFER_SIZE];
+static sock_udp_t _sock, _sock2;
+
+#define CALL(fn)            puts("Calling " # fn); fn; tear_down()
+
+static void tear_down(void)
+{
+    sock_udp_close(&_sock);
+    memset(&_sock, 0, sizeof(_sock));
+}
+
+#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
+static void test_sock_udp_create__EADDRINUSE(void)
+{
+    static const sock_udp_ep_t local = { .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, 0));
+    assert(-EADDRINUSE == sock_udp_create(&_sock2, &local, NULL, 0));
+}
+#endif
+
+static void test_sock_udp_create__EAFNOSUPPORT(void)
+{
+    /* port may not be NULL according to doc */
+    static const sock_udp_ep_t local = { .family = AF_UNSPEC,
+                                         .port = _TEST_PORT_LOCAL };
+    /* port may not be NULL according to doc */
+    static const sock_udp_ep_t remote = { .family = AF_UNSPEC,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(-EAFNOSUPPORT == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(-EAFNOSUPPORT == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP));
+}
+
+static void test_sock_udp_create__EINVAL_addr(void)
+{
+    /* port may not be NULL according to doc */
+    static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF,
+                                         .port = _TEST_PORT_LOCAL };
+    /* port may not be NULL according to doc */
+    static const sock_udp_ep_t remote = { .family = AF_INET6,
+                                          .netif = _TEST_NETIF,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(-EINVAL == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
+}
+
+static void test_sock_udp_create__EINVAL_netif(void)
+{
+    /* port may not be NULL according to doc */
+    static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF,
+                                         .port = _TEST_PORT_LOCAL };
+    /* port may not be NULL according to doc */
+    static const sock_udp_ep_t remote = { .family = AF_INET6,
+                                          .netif = (_TEST_NETIF + 1),
+                                          .port = _TEST_PORT_REMOTE,
+                                          .addr = { .ipv6 = _TEST_ADDR_REMOTE } };
+
+    assert(-EINVAL == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
+}
+
+static void test_sock_udp_create__no_endpoints(void)
+{
+    sock_udp_ep_t ep;
+
+    assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(-EADDRNOTAVAIL == sock_udp_get_local(&_sock, &ep));
+    assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep));
+}
+
+static void test_sock_udp_create__only_local(void)
+{
+    static const sock_udp_ep_t local = { .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+    sock_udp_ep_t ep;
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(0 == sock_udp_get_local(&_sock, &ep));
+    assert(AF_INET6 == ep.family);
+    assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6,
+                  sizeof(ipv6_addr_t)) == 0);
+    assert(SOCK_ADDR_ANY_NETIF == ep.netif);
+    assert(_TEST_PORT_LOCAL == ep.port);
+    assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep));
+}
+
+static void test_sock_udp_create__only_local_reuse_ep(void)
+{
+    static const sock_udp_ep_t local = { .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+    sock_udp_ep_t ep, ep2;
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(0 == sock_udp_create(&_sock2, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(0 == sock_udp_get_local(&_sock, &ep));
+    assert(0 == sock_udp_get_local(&_sock2, &ep2));
+    assert(AF_INET6 == ep.family);
+    assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6,
+                  sizeof(ipv6_addr_t)) == 0);
+    assert(SOCK_ADDR_ANY_NETIF == ep.netif);
+    assert(_TEST_PORT_LOCAL == ep.port);
+    assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep));
+    assert(AF_INET6 == ep2.family);
+    assert(memcmp(&ipv6_addr_unspecified, &ep2.addr.ipv6,
+                  sizeof(ipv6_addr_t)) == 0);
+    assert(SOCK_ADDR_ANY_NETIF == ep2.netif);
+    assert(_TEST_PORT_LOCAL == ep2.port);
+    assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep2));
+    sock_udp_close(&_sock2);
+}
+
+static void test_sock_udp_create__only_remote(void)
+{
+    static const ipv6_addr_t remote_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t remote = { .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE,
+                                          .addr = { .ipv6 = _TEST_ADDR_REMOTE } };
+    sock_udp_ep_t ep;
+
+    assert(0 == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP));
+    assert(-EADDRNOTAVAIL == sock_udp_get_local(&_sock, &ep));
+    assert(0 == sock_udp_get_remote(&_sock, &ep));
+    assert(AF_INET6 == ep.family);
+    assert(memcmp(&remote_addr, &ep.addr.ipv6, sizeof(ipv6_addr_t)) == 0);
+    assert(SOCK_ADDR_ANY_NETIF == ep.netif);
+    assert(_TEST_PORT_REMOTE == ep.port);
+}
+
+static void test_sock_udp_create__full(void)
+{
+    static const ipv6_addr_t remote_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF,
+                                         .port = _TEST_PORT_LOCAL };
+    static const sock_udp_ep_t remote = { .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE,
+                                          .addr = { .ipv6 = _TEST_ADDR_REMOTE } };
+    sock_udp_ep_t ep;
+
+    assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
+    assert(0 == sock_udp_get_local(&_sock, &ep));
+    assert(AF_INET6 == ep.family);
+    assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6,
+                  sizeof(ipv6_addr_t)) == 0);
+    assert(_TEST_NETIF == ep.netif);
+    assert(_TEST_PORT_LOCAL == ep.port);
+    assert(0 == sock_udp_get_remote(&_sock, &ep));
+    assert(AF_INET6 == ep.family);
+    assert(memcmp(&remote_addr, &ep.addr.ipv6, sizeof(ipv6_addr_t)) == 0);
+    assert(SOCK_ADDR_ANY_NETIF == ep.netif);
+    assert(_TEST_PORT_REMOTE == ep.port);
+}
+
+static void test_sock_udp_recv__EADDRNOTAVAIL(void)
+{
+    assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP));
+
+    assert(-EADDRNOTAVAIL == sock_udp_recv(&_sock, _test_buffer,
+                                           sizeof(_test_buffer),
+                                           SOCK_NO_TIMEOUT, NULL));
+}
+
+static void test_sock_udp_recv__EAGAIN(void)
+{
+    static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF,
+                                         .port = _TEST_PORT_LOCAL };
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+
+    assert(-EAGAIN == sock_udp_recv(&_sock, _test_buffer, sizeof(_test_buffer),
+                                    0, NULL));
+}
+
+static void test_sock_udp_recv__ENOBUFS(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_udp_ep_t local = { .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
+                          _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"), _TEST_NETIF));
+    assert(-ENOBUFS == sock_udp_recv(&_sock, _test_buffer, 2, SOCK_NO_TIMEOUT,
+                                     NULL));
+    assert(_check_net());
+}
+
+static void test_sock_udp_recv__EPROTO(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_WRONG };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_udp_ep_t local = { .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
+                          _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
+                          _TEST_NETIF));
+    assert(-EPROTO == sock_udp_recv(&_sock, _test_buffer, sizeof(_test_buffer),
+                                    SOCK_NO_TIMEOUT, NULL));
+    assert(_check_net());
+}
+
+static void test_sock_udp_recv__ETIMEDOUT(void)
+{
+    static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF,
+                                         .port = _TEST_PORT_LOCAL };
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+
+    puts(" * Calling sock_udp_recv()");
+    assert(-ETIMEDOUT == sock_udp_recv(&_sock, _test_buffer,
+                                       sizeof(_test_buffer), _TEST_TIMEOUT,
+                                       NULL));
+    printf(" * (timed out with timeout %lu)\n", (long unsigned)_TEST_TIMEOUT);
+}
+
+static void test_sock_udp_recv__socketed(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_udp_ep_t local = { .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
+                          _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
+                          _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer,
+                                           sizeof(_test_buffer),
+                                           SOCK_NO_TIMEOUT, NULL));
+    assert(_check_net());
+}
+
+static void test_sock_udp_recv__socketed_with_remote(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_udp_ep_t local = { .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+    sock_udp_ep_t result;
+
+    assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
+                          _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
+                          _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer,
+                                           sizeof(_test_buffer),
+                                           SOCK_NO_TIMEOUT, &result));
+    assert(AF_INET6 == result.family);
+    assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0);
+    assert(_TEST_PORT_REMOTE == result.port);
+    assert(_TEST_NETIF == result.netif);
+    assert(_check_net());
+}
+
+static void test_sock_udp_recv__unsocketed(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                         .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
+                          _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
+                          _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer,
+                                           sizeof(_test_buffer),
+                                           SOCK_NO_TIMEOUT, NULL));
+    assert(_check_net());
+}
+
+static void test_sock_udp_recv__unsocketed_with_remote(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_udp_ep_t local = { .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+    sock_udp_ep_t result;
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
+                          _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
+                          _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer,
+                                           sizeof(_test_buffer),
+                                           SOCK_NO_TIMEOUT, &result));
+    assert(AF_INET6 == result.family);
+    assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0);
+    assert(_TEST_PORT_REMOTE == result.port);
+    assert(_TEST_NETIF == result.netif);
+    assert(_check_net());
+}
+
+static void test_sock_udp_recv__with_timeout(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_udp_ep_t local = { .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+    sock_udp_ep_t result;
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
+                          _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
+                          _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer,
+                                           sizeof(_test_buffer), _TEST_TIMEOUT,
+                                           &result));
+    assert(AF_INET6 == result.family);
+    assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0);
+    assert(_TEST_PORT_REMOTE == result.port);
+    assert(_TEST_NETIF == result.netif);
+    assert(_check_net());
+}
+
+static void test_sock_udp_recv__non_blocking(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const sock_udp_ep_t local = { .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+    sock_udp_ep_t result;
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
+                          _TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
+                          _TEST_NETIF));
+    assert(sizeof("ABCD") == sock_udp_recv(&_sock, _test_buffer,
+                                           sizeof(_test_buffer), 0, &result));
+    assert(AF_INET6 == result.family);
+    assert(memcmp(&result.addr, &src_addr, sizeof(result.addr)) == 0);
+    assert(_TEST_PORT_REMOTE == result.port);
+    assert(_TEST_NETIF == result.netif);
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__EAFNOSUPPORT(void)
+{
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(-EAFNOSUPPORT == sock_udp_send(NULL, "ABCD", sizeof("ABCD"),
+                                          &remote));
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__EINVAL_addr(void)
+{
+    static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                         .family = AF_INET6,
+                                         .port = _TEST_PORT_REMOTE,
+                                         .netif = _TEST_NETIF };
+    static const sock_udp_ep_t remote = { .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE,
+                                          .netif = _TEST_NETIF };
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(-EINVAL == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), &remote));
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__EINVAL_netif(void)
+{
+    static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                         .family = AF_INET6,
+                                         .port = _TEST_PORT_REMOTE,
+                                         .netif = _TEST_NETIF };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE,
+                                          .netif = _TEST_NETIF + 1 };
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(-EINVAL == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), &remote));
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__EINVAL_port(void)
+{
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6 };
+
+    assert(-EINVAL == sock_udp_send(NULL, "ABCD", sizeof("ABCD"), &remote));
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__ENOTCONN(void)
+{
+    assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(-ENOTCONN == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"), NULL));
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__socketed_no_local_no_netif(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"),
+                                           NULL));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, 0,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"),
+                         SOCK_ADDR_ANY_NETIF, true));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__socketed_no_netif(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                         .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"),
+                                           NULL));
+    assert(_check_packet(&src_addr, &dst_addr, _TEST_PORT_LOCAL,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"),
+                         SOCK_ADDR_ANY_NETIF, false));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__socketed_no_local(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .netif = _TEST_NETIF,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, NULL, &remote, SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"),
+                                           NULL));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, 0,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), _TEST_NETIF,
+                         true));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__socketed(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                         .family = AF_INET6,
+                                         .netif = _TEST_NETIF,
+                                         .port = _TEST_PORT_LOCAL };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"),
+                                           NULL));
+    assert(_check_packet(&src_addr, &dst_addr, _TEST_PORT_LOCAL,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"),
+                         _TEST_NETIF, false));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__socketed_other_remote(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                         .family = AF_INET6,
+                                         .netif = _TEST_NETIF,
+                                         .port = _TEST_PORT_LOCAL };
+    static const sock_udp_ep_t sock_remote = { .addr = { .ipv6 = _TEST_ADDR_WRONG },
+                                               .family = AF_INET6,
+                                               .port = _TEST_PORT_REMOTE + _TEST_PORT_LOCAL };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, &local, &sock_remote, SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"),
+                                           &remote));
+    assert(_check_packet(&src_addr, &dst_addr, _TEST_PORT_LOCAL,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"),
+                         _TEST_NETIF, false));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__unsocketed_no_local_no_netif(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"),
+                                           &remote));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, 0,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"),
+                         SOCK_ADDR_ANY_NETIF, true));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__unsocketed_no_netif(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                         .family = AF_INET6,
+                                         .port = _TEST_PORT_LOCAL };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"),
+                                           &remote));
+    assert(_check_packet(&src_addr, &dst_addr, _TEST_PORT_LOCAL,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"),
+                         SOCK_ADDR_ANY_NETIF, false));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__unsocketed_no_local(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .netif = _TEST_NETIF,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, NULL, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"),
+                                           &remote));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, 0,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"), _TEST_NETIF,
+                         true));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__unsocketed(void)
+{
+    static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_LOCAL };
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t local = { .addr = { .ipv6 = _TEST_ADDR_LOCAL },
+                                         .family = AF_INET6,
+                                         .netif = _TEST_NETIF,
+                                         .port = _TEST_PORT_LOCAL };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
+    assert(sizeof("ABCD") == sock_udp_send(&_sock, "ABCD", sizeof("ABCD"),
+                                           &remote));
+    assert(_check_packet(&src_addr, &dst_addr, _TEST_PORT_LOCAL,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"),
+                         _TEST_NETIF, false));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__no_sock_no_netif(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(sizeof("ABCD") == sock_udp_send(NULL, "ABCD", sizeof("ABCD"),
+                                           &remote));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, 0,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"),
+                         SOCK_ADDR_ANY_NETIF, true));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+static void test_sock_udp_send__no_sock(void)
+{
+    static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_REMOTE };
+    static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR_REMOTE },
+                                          .family = AF_INET6,
+                                          .netif = _TEST_NETIF,
+                                          .port = _TEST_PORT_REMOTE };
+
+    assert(sizeof("ABCD") == sock_udp_send(NULL, "ABCD", sizeof("ABCD"),
+                                           &remote));
+    assert(_check_packet(&ipv6_addr_unspecified, &dst_addr, 0,
+                         _TEST_PORT_REMOTE, "ABCD", sizeof("ABCD"),
+                         _TEST_NETIF, true));
+    xtimer_usleep(1000);    /* let GNRC stack finish */
+    assert(_check_net());
+}
+
+int main(void)
+{
+    _net_init();
+    tear_down();
+#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
+    CALL(test_sock_udp_create__EADDRINUSE());
+#endif
+    CALL(test_sock_udp_create__EAFNOSUPPORT());
+    CALL(test_sock_udp_create__EINVAL_addr());
+    CALL(test_sock_udp_create__EINVAL_netif());
+    CALL(test_sock_udp_create__no_endpoints());
+    CALL(test_sock_udp_create__only_local());
+    CALL(test_sock_udp_create__only_local_reuse_ep());
+    CALL(test_sock_udp_create__only_remote());
+    CALL(test_sock_udp_create__full());
+    /* sock_udp_close() is tested in tear_down() */
+    /* sock_udp_get_local() is tested in sock_udp_create() tests */
+    /* sock_udp_get_remote() is tested in sock_udp_create() tests */
+    CALL(test_sock_udp_recv__EADDRNOTAVAIL());
+    CALL(test_sock_udp_recv__EAGAIN());
+    CALL(test_sock_udp_recv__ENOBUFS());
+    CALL(test_sock_udp_recv__EPROTO());
+    CALL(test_sock_udp_recv__ETIMEDOUT());
+    CALL(test_sock_udp_recv__socketed());
+    CALL(test_sock_udp_recv__socketed_with_remote());
+    CALL(test_sock_udp_recv__unsocketed());
+    CALL(test_sock_udp_recv__unsocketed_with_remote());
+    CALL(test_sock_udp_recv__with_timeout());
+    CALL(test_sock_udp_recv__non_blocking());
+    _prepare_send_checks();
+    CALL(test_sock_udp_send__EAFNOSUPPORT());
+    CALL(test_sock_udp_send__EINVAL_addr());
+    CALL(test_sock_udp_send__EINVAL_netif());
+    CALL(test_sock_udp_send__EINVAL_port());
+    CALL(test_sock_udp_send__ENOTCONN());
+    CALL(test_sock_udp_send__socketed_no_local_no_netif());
+    CALL(test_sock_udp_send__socketed_no_netif());
+    CALL(test_sock_udp_send__socketed_no_local());
+    CALL(test_sock_udp_send__socketed());
+    CALL(test_sock_udp_send__socketed_other_remote());
+    CALL(test_sock_udp_send__unsocketed_no_local_no_netif());
+    CALL(test_sock_udp_send__unsocketed_no_netif());
+    CALL(test_sock_udp_send__unsocketed_no_local());
+    CALL(test_sock_udp_send__unsocketed());
+    CALL(test_sock_udp_send__no_sock_no_netif());
+    CALL(test_sock_udp_send__no_sock());
+
+    puts("ALL TESTS SUCCESSFUL");
+
+    return 0;
+}
diff --git a/tests/gnrc_sock_udp/stack.c b/tests/gnrc_sock_udp/stack.c
new file mode 100644
index 0000000000000000000000000000000000000000..f9a556abcc5024c5eae628ddc9e2bc69b70f9ddc
--- /dev/null
+++ b/tests/gnrc_sock_udp/stack.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2016 Freie Universität Berlin
+ *
+ * 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
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+
+#include "msg.h"
+#include "net/gnrc/ipv6.h"
+#include "net/gnrc/netif/hdr.h"
+#include "net/gnrc/netreg.h"
+#include "net/gnrc/udp.h"
+#include "net/sock.h"
+#include "sched.h"
+
+#include "stack.h"
+
+#define _MSG_QUEUE_SIZE     (4)
+
+static msg_t _msg_queue[_MSG_QUEUE_SIZE];
+static gnrc_netreg_entry_t _udp_handler;
+
+void _net_init(void)
+{
+    msg_init_queue(_msg_queue, _MSG_QUEUE_SIZE);
+    gnrc_netreg_entry_init_pid(&_udp_handler, GNRC_NETREG_DEMUX_CTX_ALL,
+                               sched_active_pid);
+}
+
+void _prepare_send_checks(void)
+{
+    gnrc_netreg_register(GNRC_NETTYPE_UDP, &_udp_handler);
+}
+
+static gnrc_pktsnip_t *_build_udp_packet(const ipv6_addr_t *src,
+                                         const ipv6_addr_t *dst,
+                                         uint16_t src_port, uint16_t dst_port,
+                                         void *data, size_t data_len,
+                                         uint16_t netif)
+{
+    gnrc_pktsnip_t *netif_hdr, *ipv6, *udp;
+    udp_hdr_t *udp_hdr;
+    ipv6_hdr_t *ipv6_hdr;
+    uint16_t csum = 0;
+
+    if ((netif > INT16_MAX) || ((sizeof(udp_hdr_t) + data_len) > UINT16_MAX)) {
+        return NULL;
+    }
+
+    udp = gnrc_pktbuf_add(NULL, NULL, sizeof(udp_hdr_t) + data_len,
+                          GNRC_NETTYPE_UNDEF);
+    if (udp == NULL) {
+        return NULL;
+    }
+    udp_hdr = udp->data;
+    udp_hdr->src_port = byteorder_htons(src_port);
+    udp_hdr->dst_port = byteorder_htons(dst_port);
+    udp_hdr->length = byteorder_htons((uint16_t)udp->size);
+    udp_hdr->checksum.u16 = 0;
+    memcpy(udp_hdr + 1, data, data_len);
+    csum = inet_csum(csum, (uint8_t *)udp->data, udp->size);
+    ipv6 = gnrc_ipv6_hdr_build(NULL, src, dst);
+    if (ipv6 == NULL) {
+        return NULL;
+    }
+    ipv6_hdr = ipv6->data;
+    ipv6_hdr->len = byteorder_htons((uint16_t)udp->size);
+    ipv6_hdr->nh = PROTNUM_UDP;
+    ipv6_hdr->hl = 64;
+    csum = ipv6_hdr_inet_csum(csum, ipv6_hdr, PROTNUM_UDP, (uint16_t)udp->size);
+    if (csum == 0xffff) {
+        udp_hdr->checksum = byteorder_htons(csum);
+    }
+    else {
+        udp_hdr->checksum = byteorder_htons(~csum);
+    }
+    LL_APPEND(udp, ipv6);
+    netif_hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
+    if (netif_hdr == NULL) {
+        return NULL;
+    }
+    ((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = (kernel_pid_t)netif;
+    LL_APPEND(udp, netif_hdr);
+    return udp;
+}
+
+
+bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
+                    uint16_t src_port, uint16_t dst_port,
+                    void *data, size_t data_len, uint16_t netif)
+{
+    gnrc_pktsnip_t *pkt = _build_udp_packet(src, dst, src_port, dst_port,
+                                            data, data_len, netif);
+
+    if (pkt == NULL) {
+        return false;
+    }
+    return (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_UDP,
+                                         GNRC_NETREG_DEMUX_CTX_ALL, pkt) > 0);
+}
+
+bool _check_net(void)
+{
+    return (gnrc_pktbuf_is_sane() && gnrc_pktbuf_is_empty());
+}
+
+static inline bool _res(gnrc_pktsnip_t *pkt, bool res)
+{
+    gnrc_pktbuf_release(pkt);
+    return res;
+}
+
+bool _check_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
+                   uint16_t src_port, uint16_t dst_port,
+                   void *data, size_t data_len, uint16_t iface,
+                   bool random_src_port)
+{
+    gnrc_pktsnip_t *pkt, *ipv6, *udp;
+    ipv6_hdr_t *ipv6_hdr;
+    udp_hdr_t *udp_hdr;
+    msg_t msg;
+
+    msg_receive(&msg);
+    if (msg.type != GNRC_NETAPI_MSG_TYPE_SND) {
+        return false;
+    }
+    pkt = msg.content.ptr;
+    if (iface != SOCK_ADDR_ANY_NETIF) {
+        gnrc_netif_hdr_t *netif_hdr;
+
+        if (pkt->type != GNRC_NETTYPE_NETIF) {
+            return _res(pkt, false);
+        }
+        netif_hdr = pkt->data;
+        if (netif_hdr->if_pid != iface) {
+            return _res(pkt, false);
+        }
+        ipv6 = pkt->next;
+    }
+    else {
+        ipv6 = pkt;
+    }
+    if (ipv6->type != GNRC_NETTYPE_IPV6) {
+        return _res(pkt, false);
+    }
+    ipv6_hdr = ipv6->data;
+    udp = gnrc_pktsnip_search_type(ipv6, GNRC_NETTYPE_UDP);
+    if (udp == NULL) {
+        return _res(pkt, false);
+    }
+    udp_hdr = udp->data;
+    return _res(pkt, (memcmp(src, &ipv6_hdr->src, sizeof(ipv6_addr_t)) == 0) &&
+                (memcmp(dst, &ipv6_hdr->dst, sizeof(ipv6_addr_t)) == 0) &&
+                (ipv6_hdr->nh == PROTNUM_UDP) &&
+                (random_src_port || (src_port == byteorder_ntohs(udp_hdr->src_port))) &&
+                (dst_port == byteorder_ntohs(udp_hdr->dst_port)) &&
+                (udp->next != NULL) &&
+                (data_len == udp->next->size) &&
+                (memcmp(data, udp->next->data, data_len) == 0));
+}
+
+
+/** @} */
diff --git a/tests/gnrc_sock_udp/stack.h b/tests/gnrc_sock_udp/stack.h
new file mode 100644
index 0000000000000000000000000000000000000000..415057a3a9128edc91f504a117408d5b183dd750
--- /dev/null
+++ b/tests/gnrc_sock_udp/stack.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 Freie Universität Berlin
+ *
+ * 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
+ * @ingroup
+ * @brief
+ * @{
+ *
+ * @file
+ * @brief
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef STACK_H_
+#define STACK_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "net/ipv6/addr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Initializes networking for tests
+ */
+void _net_init(void);
+
+/**
+ * @brief   Does what ever preparations are needed to check the packets sent
+ */
+void _prepare_send_checks(void);
+
+/**
+ * @brief   Injects a received UDP packet into the stack
+ *
+ * @param[in] src       The source address of the UDP packet
+ * @param[in] dst       The destination address of the UDP packet
+ * @param[in] src_port  The source port of the UDP packet
+ * @param[in] dst_port  The destination port of the UDP packet
+ * @param[in] data      The payload of the UDP packet
+ * @param[in] data_len  The payload length of the UDP packet
+ * @param[in] netif     The interface the packet came over
+ *
+ * @return  true, if packet was successfully injected
+ * @return  false, if an error occured during injection
+ */
+bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
+                    uint16_t src_port, uint16_t dst_port,
+                    void *data, size_t data_len, uint16_t netif);
+
+/**
+ * @brief   Checks networking state (e.g. packet buffer state)
+ *
+ * @return  true, if networking component is still in valid state
+ * @return  false, if networking component is in an invalid state
+ */
+bool _check_net(void);
+
+/**
+ * @brief   Checks if a UDP packet was sent by the networking component
+ *
+ * @param[in] src               Expected source address of the UDP packet
+ * @param[in] dst               Expected destination address of the UDP packet
+ * @param[in] src_port          Expected source port of the UDP packet
+ * @param[in] dst_port          Expected destination port of the UDP packet
+ * @param[in] data              Expected payload of the UDP packet
+ * @param[in] data_len          Expected payload length of the UDP packet
+ * @param[in] netif             Expected interface the packet is supposed to
+ *                              be send over
+ * @param[in] random_src_port   Do not check source port, it might be random
+ *
+ * @return  true, if all parameters match as expected
+ * @return  false, if not.
+ */
+bool _check_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
+                   uint16_t src_port, uint16_t dst_port,
+                   void *data, size_t data_len, uint16_t netif,
+                   bool random_src_port);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STACK_H_ */
+/** @} */
diff --git a/tests/gnrc_sock_udp/tests/01-run.py b/tests/gnrc_sock_udp/tests/01-run.py
new file mode 100755
index 0000000000000000000000000000000000000000..8d0df09d63275364386b1e84e47c4dd97b164015
--- /dev/null
+++ b/tests/gnrc_sock_udp/tests/01-run.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.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.
+
+import os
+import sys
+
+from datetime import datetime
+
+sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner'))
+import testrunner
+
+class InvalidTimeout(Exception):
+    pass
+
+def testfunc(child):
+    child.expect_exact(u"Calling test_sock_udp_create__EADDRINUSE()")
+    child.expect_exact(u"Calling test_sock_udp_create__EAFNOSUPPORT()")
+    child.expect_exact(u"Calling test_sock_udp_create__EINVAL_addr()")
+    child.expect_exact(u"Calling test_sock_udp_create__EINVAL_netif()")
+    child.expect_exact(u"Calling test_sock_udp_create__no_endpoints()")
+    child.expect_exact(u"Calling test_sock_udp_create__only_local()")
+    child.expect_exact(u"Calling test_sock_udp_create__only_local_reuse_ep()")
+    child.expect_exact(u"Calling test_sock_udp_create__only_remote()")
+    child.expect_exact(u"Calling test_sock_udp_create__full()")
+    child.expect_exact(u"Calling test_sock_udp_recv__EADDRNOTAVAIL()")
+    child.expect_exact(u"Calling test_sock_udp_recv__EAGAIN()")
+    child.expect_exact(u"Calling test_sock_udp_recv__ENOBUFS()")
+    child.expect_exact(u"Calling test_sock_udp_recv__EPROTO()")
+    child.expect_exact(u"Calling test_sock_udp_recv__ETIMEDOUT()")
+    child.match         # get to ensure program reached that point
+    start = datetime.now()
+    child.expect_exact(u" * Calling sock_udp_recv()")
+    child.expect(u" \\* \\(timed out with timeout (\\d+)\\)")
+    exp_diff = int(child.match.group(1))
+    stop = datetime.now()
+    diff = (stop - start)
+    diff = (diff.seconds * 1000000) + diff.microseconds
+    # fail within 5% of expected
+    if diff > (exp_diff + (exp_diff * 0.05)) or \
+       diff < (exp_diff - (exp_diff * 0.05)):
+        raise InvalidTimeout("Invalid timeout %d (expected %d)" % (diff, exp_diff));
+    else:
+        print("Timed out correctly: %d (expected %d)" % (diff, exp_diff))
+    child.expect_exact(u"Calling test_sock_udp_recv__socketed()")
+    child.expect_exact(u"Calling test_sock_udp_recv__socketed_with_remote()")
+    child.expect_exact(u"Calling test_sock_udp_recv__unsocketed()")
+    child.expect_exact(u"Calling test_sock_udp_recv__unsocketed_with_remote()")
+    child.expect_exact(u"Calling test_sock_udp_recv__with_timeout()")
+    child.expect_exact(u"Calling test_sock_udp_recv__non_blocking()")
+    child.expect_exact(u"Calling test_sock_udp_send__EAFNOSUPPORT()")
+    child.expect_exact(u"Calling test_sock_udp_send__EINVAL_addr()")
+    child.expect_exact(u"Calling test_sock_udp_send__EINVAL_netif()")
+    child.expect_exact(u"Calling test_sock_udp_send__EINVAL_port()")
+    child.expect_exact(u"Calling test_sock_udp_send__ENOTCONN()")
+    child.expect_exact(u"Calling test_sock_udp_send__socketed_no_local_no_netif()")
+    child.expect_exact(u"Calling test_sock_udp_send__socketed_no_netif()")
+    child.expect_exact(u"Calling test_sock_udp_send__socketed_no_local()")
+    child.expect_exact(u"Calling test_sock_udp_send__socketed()")
+    child.expect_exact(u"Calling test_sock_udp_send__socketed_other_remote()")
+    child.expect_exact(u"Calling test_sock_udp_send__unsocketed_no_local_no_netif()")
+    child.expect_exact(u"Calling test_sock_udp_send__unsocketed_no_netif()")
+    child.expect_exact(u"Calling test_sock_udp_send__unsocketed_no_local()")
+    child.expect_exact(u"Calling test_sock_udp_send__unsocketed()")
+    child.expect_exact(u"Calling test_sock_udp_send__no_sock_no_netif()")
+    child.expect_exact(u"Calling test_sock_udp_send__no_sock()")
+    child.expect_exact(u"ALL TESTS SUCCESSFUL")
+
+if __name__ == "__main__":
+    sys.exit(testrunner.run(testfunc))