diff --git a/boards/native/Makefile.dep b/boards/native/Makefile.dep
index 81853370f668ac0e3c1452c6ba25d83cb9af1eee..2639777a1d2d82234ff36e87173df57079a83a13 100644
--- a/boards/native/Makefile.dep
+++ b/boards/native/Makefile.dep
@@ -12,3 +12,9 @@ ifneq (,$(filter can,$(USEMODULE)))
     CFLAGS += -DCAN_DLL_NUMOF=2
   endif
 endif
+
+ifneq (,$(filter socket_zep,$(USEMODULE)))
+  USEMODULE += netdev_ieee802154
+  USEMODULE += checksum
+  USEMODULE += random
+endif
diff --git a/cpu/native/Makefile b/cpu/native/Makefile
index 55c4961b4eda3c688a67bf104ee912352a8110c8..343092dfab8e144008c870a58b88b3f8051a547b 100644
--- a/cpu/native/Makefile
+++ b/cpu/native/Makefile
@@ -6,6 +6,11 @@ DIRS += vfs
 ifneq (,$(filter netdev_tap,$(USEMODULE)))
   DIRS += netdev_tap
 endif
+
+ifneq (,$(filter socket_zep,$(USEMODULE)))
+  DIRS += socket_zep
+endif
+
 ifneq (,$(filter mtd_native,$(USEMODULE)))
   DIRS += mtd
 endif
diff --git a/cpu/native/include/native_internal.h b/cpu/native/include/native_internal.h
index 716c526cd54e3328b0407bafdb4aaaf2f7108b8f..e00fbaa87baf78d3f53b662217b5e6ea797d1f4d 100644
--- a/cpu/native/include/native_internal.h
+++ b/cpu/native/include/native_internal.h
@@ -94,6 +94,7 @@ extern void (*real_srandom)(unsigned int seed);
 extern int (*real_accept)(int socket, ...);
 /* The ... is a hack to save includes: */
 extern int (*real_bind)(int socket, ...);
+extern int (*real_connect)(int socket, ...);
 extern int (*real_chdir)(const char *path);
 extern int (*real_close)(int);
 extern int (*real_fcntl)(int, int, ...);
@@ -108,6 +109,7 @@ extern int (*real_fork)(void);
 extern int (*real_getaddrinfo)(const char *node, ...);
 extern int (*real_getifaddrs)(struct ifaddrs **ifap);
 extern int (*real_getpid)(void);
+extern int (*real_gettimeofday)(struct timeval *t, ...);
 extern int (*real_ioctl)(int fildes, int request, ...);
 extern int (*real_listen)(int socket, int backlog);
 extern int (*real_open)(const char *path, int oflag, ...);
diff --git a/cpu/native/include/socket_zep.h b/cpu/native/include/socket_zep.h
new file mode 100644
index 0000000000000000000000000000000000000000..8797f03369b209100be0b26b5c6a873c3c932469
--- /dev/null
+++ b/cpu/native/include/socket_zep.h
@@ -0,0 +1,84 @@
+/*
+ * 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    netdev_socket_zep  Socket-based ZEP
+ * @ingroup     netdev
+ * @brief       UDP socket-based IEEE 802.15.4 device over ZEP
+ * @{
+ *
+ * @file
+ * @brief       Socket ZEP definitions
+ *
+ * @author  Martine Lenders <m.lenders@fu-berlin.de>
+ */
+#ifndef SOCKET_ZEP_H
+#define SOCKET_ZEP_H
+
+#include <netdb.h>
+#include "net/netdev.h"
+#include "net/netdev/ieee802154.h"
+#include "net/zep.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 127 - 25 as in at86rf2xx */
+#define SOCKET_ZEP_FRAME_PAYLOAD_LEN    (102)   /**< maximum possible payload size */
+
+/**
+ * @brief   ZEP device state
+ */
+typedef struct {
+    netdev_ieee802154_t netdev;     /**< netdev internal member */
+    int sock_fd;                    /**< socket fd */
+    netdev_event_t last_event;      /**< event triggered */
+    uint32_t seq;                   /**< ZEP sequence number */
+    /**
+     * @brief   Receive buffer
+     */
+    uint8_t rcv_buf[sizeof(zep_v2_data_hdr_t) + IEEE802154_FRAME_LEN_MAX];
+    /**
+     * @brief   Buffer for send header
+     */
+    uint8_t snd_hdr_buf[sizeof(zep_v2_data_hdr_t)];
+    uint16_t chksum_buf;            /**< buffer for send checksum calculation */
+} socket_zep_t;
+
+/**
+ * @brief   ZEP device initialization parameters
+ */
+typedef struct {
+    char *local_addr;   /**< local address string */
+    char *local_port;   /**< local address string */
+    char *remote_addr;  /**< remote address string */
+    char *remote_port;  /**< local address string */
+} socket_zep_params_t;
+
+/**
+ * @brief   Setup socket_zep_t structure
+ *
+ * @param[in] dev       the preallocated socket_zep_t device handle to setup
+ * @param[in] params    initialization parameters
+ */
+void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params);
+
+/**
+ * @brief Cleanup socket resources
+ *
+ * @param dev  the socket_zep device handle to cleanup
+ */
+void socket_zep_cleanup(socket_zep_t *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOCKET_ZEP_H */
+/** @} */
diff --git a/cpu/native/include/socket_zep_params.h b/cpu/native/include/socket_zep_params.h
new file mode 100644
index 0000000000000000000000000000000000000000..b8a73bfeb8be5ffbde7666b9ae216360495a1e87
--- /dev/null
+++ b/cpu/native/include/socket_zep_params.h
@@ -0,0 +1,54 @@
+/*
+ * 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 netdev_socket_zep
+ * @{
+ *
+ * @file
+ * @brief   Configuration parameters for the @ref netdev_socket_zep driver
+ *
+ * @author  Martine Lenders <m.lenders@fu-berlin.de>
+ */
+#ifndef SOCKET_ZEP_PARAMS_H
+#define SOCKET_ZEP_PARAMS_H
+
+#include "socket_zep.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Number of allocated parameters at @ref socket_zep_params
+ *
+ * @note    This was desided to only be confiruable on compile-time to be
+ *          more similar to actual boards
+ */
+#ifndef SOCKET_ZEP_MAX
+#define SOCKET_ZEP_MAX              (1)
+#endif
+
+/**
+ * @name   Default parameters for native argument parsing
+ * @{
+ */
+#define SOCKET_ZEP_PORT_DEFAULT         "17754" /**< default port */
+#define SOCKET_ZEP_LOCAL_ADDR_DEFAULT   "::"    /**< default local address */
+/**
+ * @}
+ */
+
+extern socket_zep_params_t socket_zep_params[SOCKET_ZEP_MAX];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SOCKET_ZEP_PARAMS_H */
+/** @} */
diff --git a/cpu/native/socket_zep/Makefile b/cpu/native/socket_zep/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..7d178b6174522e5864eb1770e5088aa590f02ee4
--- /dev/null
+++ b/cpu/native/socket_zep/Makefile
@@ -0,0 +1,3 @@
+include $(RIOTBASE)/Makefile.base
+
+INCLUDES = $(NATIVEINCLUDES)
diff --git a/cpu/native/socket_zep/socket_zep.c b/cpu/native/socket_zep/socket_zep.c
new file mode 100644
index 0000000000000000000000000000000000000000..d3e51c69ed27079c7efbf567055e11755b1fcb63
--- /dev/null
+++ b/cpu/native/socket_zep/socket_zep.c
@@ -0,0 +1,443 @@
+/*
+ * 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 <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include "async_read.h"
+#include "byteorder.h"
+#include "checksum/ucrc16.h"
+#include "native_internal.h"
+#include "random.h"
+
+#include "socket_zep.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+#define _UNIX_NTP_ERA_OFFSET    (2208988800U)
+
+static int _send(netdev_t *netdev, const struct iovec *vector, unsigned n);
+static int _recv(netdev_t *netdev, void *buf, size_t n, void *info);
+static void _isr(netdev_t *netdev);
+static int _init(netdev_t *netdev);
+static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len);
+static int _set(netdev_t *netdev, netopt_t opt, const void *value,
+                size_t value_len);
+
+static const netdev_driver_t socket_zep_driver = {
+    .send = _send,
+    .recv = _recv,
+    .init = _init,
+    .isr = _isr,
+    .get = _get,
+    .set = _set,
+};
+
+static size_t _zep_hdr_fill_v2_data(socket_zep_t *dev, zep_v2_data_hdr_t *hdr,
+                                    size_t payload_len)
+{
+    struct timeval tv;
+
+    real_gettimeofday(&tv, NULL);
+    hdr->hdr.version = 2;
+    hdr->type = ZEP_V2_TYPE_DATA;
+    hdr->chan = dev->netdev.chan;
+    hdr->dev = byteorder_htons((uint16_t)((((intptr_t)dev)) & 0xffff));
+    hdr->lqi_mode = 1;
+    hdr->lqi_val = 0xff;                /* TODO: set */
+    hdr->time.seconds = byteorder_htonl(tv.tv_sec + _UNIX_NTP_ERA_OFFSET);
+    hdr->time.fraction = byteorder_htonl((tv.tv_usec * 1000000) / 232);
+    hdr->seq = byteorder_htonl(dev->seq);
+    memset(hdr->resv, 0, sizeof(hdr->resv));
+    hdr->length = payload_len;
+
+    return sizeof(zep_v2_data_hdr_t);
+}
+
+static inline size_t _zep_hdr_fill(socket_zep_t *dev, zep_hdr_t *hdr,
+                                   size_t payload_len)
+{
+    hdr->preamble[0] = 'E';
+    hdr->preamble[1] = 'X';
+
+    /* keep possibility for ZEPv1 open */
+    return _zep_hdr_fill_v2_data(dev, (zep_v2_data_hdr_t *)hdr,
+                                 payload_len);
+}
+
+static size_t _prep_vector(socket_zep_t *dev, const struct iovec *vector,
+                           unsigned n, struct iovec *out)
+{
+    size_t bytes = 0;
+    dev->chksum_buf = 0;
+
+    for (unsigned i = 0; i < n; i++) {
+        bytes += vector[i].iov_len;
+    }
+    bytes += sizeof(uint16_t); /* FCS field */
+    out[0].iov_base = &dev->snd_hdr_buf;
+    out[0].iov_len = _zep_hdr_fill(dev, out[0].iov_base, bytes);
+    for (unsigned i = 0; i < n; i++) {
+        /* discard const qualifier, we won't change anything. Promise! */
+        out[i + 1].iov_base = vector[i].iov_base;
+        out[i + 1].iov_len = vector[i].iov_len;
+        dev->chksum_buf = ucrc16_calc_le(out[i + 1].iov_base, out[i + 1].iov_len,
+                                         UCRC16_CCITT_POLY_LE, dev->chksum_buf);
+    }
+    dev->chksum_buf = byteorder_btols(byteorder_htons(dev->chksum_buf)).u16;
+    out[n + 1].iov_base = &dev->chksum_buf;
+    out[n + 1].iov_len = sizeof(uint16_t);
+    return bytes;
+}
+
+static int _send(netdev_t *netdev, const struct iovec *vector, unsigned n)
+{
+    socket_zep_t *dev = (socket_zep_t *)netdev;
+    struct iovec v[n + 2];
+    size_t bytes;
+    int res;
+
+    assert((dev != NULL) && (dev->sock_fd != 0));
+    bytes = _prep_vector(dev, vector, n, v);
+    DEBUG("socket_zep::send(%p, %p, %u)\n", (void *)netdev, (void *)vector, n);
+    /* simulate TX_STARTED interrupt */
+    if (netdev->event_callback) {
+        dev->last_event = NETDEV_EVENT_TX_STARTED;
+        netdev->event_callback(netdev, NETDEV_EVENT_ISR);
+        thread_yield();
+    }
+    res = writev(dev->sock_fd, v, n + 2);
+    if (res < 0) {
+        DEBUG("socket_zep::send: error writing packet: %s\n", strerror(errno));
+        return res;
+    }
+    /* simulate TX_COMPLETE interrupt */
+    if (netdev->event_callback) {
+        dev->last_event = NETDEV_EVENT_TX_COMPLETE;
+        netdev->event_callback(netdev, NETDEV_EVENT_ISR);
+        thread_yield();
+    }
+#ifdef MODULE_NETSTATS_L2
+    netdev->stats.tx_bytes += bytes;
+#else
+    (void)bytes;
+#endif
+
+    return res - v[0].iov_len - v[n + 1].iov_len;
+}
+
+static void _continue_reading(socket_zep_t *dev)
+{
+    /* work around lost signals */
+    fd_set rfds;
+    struct timeval t;
+    memset(&t, 0, sizeof(t));
+    FD_ZERO(&rfds);
+    FD_SET(dev->sock_fd, &rfds);
+
+    _native_in_syscall++; /* no switching here */
+
+    if (real_select(dev->sock_fd + 1, &rfds, NULL, NULL, &t) == 1) {
+        int sig = SIGIO;
+        extern int _sig_pipefd[2];
+        extern ssize_t (*real_write)(int fd, const void * buf, size_t count);
+        real_write(_sig_pipefd[1], &sig, sizeof(int));
+        _native_sigpend++;
+    }
+    else {
+        native_async_read_continue(dev->sock_fd);
+    }
+
+    _native_in_syscall--;
+}
+
+static inline bool _dst_not_me(socket_zep_t *dev, const void *buf)
+{
+    uint8_t dst_addr[IEEE802154_LONG_ADDRESS_LEN] = { 0 };
+    int dst_len;
+    le_uint16_t dst_pan = { .u16 = 0 };
+
+    dst_len = ieee802154_get_dst(buf, dst_addr,
+                                 &dst_pan);
+    switch (dst_len) {
+        case IEEE802154_LONG_ADDRESS_LEN:
+            return memcmp(dst_addr, dev->netdev.long_addr, dst_len) != 0;
+        case IEEE802154_SHORT_ADDRESS_LEN:
+            return (memcmp(dst_addr, ieee802154_addr_bcast, dst_len) != 0) &&
+                   (memcmp(dst_addr, dev->netdev.short_addr, dst_len) != 0);
+        default:
+            return false;    /* better safe than sorry ;-) */
+    }
+}
+
+static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
+{
+    socket_zep_t *dev = (socket_zep_t *)netdev;
+    int size = 0;
+
+    DEBUG("socket_zep::recv(%p, %p, %u, %p)\n", (void *)netdev, buf,
+          (unsigned)len, (void *)info);
+    if ((buf == NULL) || (len == 0)) {
+        int res = real_ioctl(dev->sock_fd, FIONREAD, &size);
+#if ENABLE_DEBUG
+        if (res < 0) {
+            DEBUG("socket_zep::recv: error reading FIONREAD: %s",
+                  strerror(errno));
+        }
+#else
+        (void)res;
+#endif
+        return size;
+    }
+    else if (len > 0) {
+        size = real_read(dev->sock_fd, dev->rcv_buf, sizeof(dev->rcv_buf));
+
+        if (size > 0) {
+            zep_hdr_t *tmp = (zep_hdr_t *)&dev->rcv_buf;
+
+            if ((tmp->preamble[0] != 'E') || (tmp->preamble[1] != 'X')) {
+                DEBUG("socket_zep::recv: invalid ZEP header");
+                return -1;
+            }
+            switch (tmp->version) {
+                case 2: {
+                    zep_v2_data_hdr_t *zep = (zep_v2_data_hdr_t *)tmp;
+                    void *payload = &dev->rcv_buf[sizeof(zep_v2_data_hdr_t)];
+
+                    if (zep->type != ZEP_V2_TYPE_DATA) {
+                        DEBUG("socket_zep::recv: unexpect ZEP type\n");
+                        /* don't support ACK frames for now*/
+                        return -1;
+                    }
+                    if (((sizeof(zep_v2_data_hdr_t) + zep->length) != (unsigned)size) ||
+                        (zep->length > len) || (zep->chan != dev->netdev.chan) ||
+                        /* TODO promiscous mode */
+                        _dst_not_me(dev, payload)) {
+                        /* TODO: check checksum */
+                        return -1;
+                    }
+                    /* don't hand FCS to stack */
+                    size = zep->length - sizeof(uint16_t);
+                    if (buf != NULL) {
+                        memcpy(buf, payload, size);
+                        if (info != NULL) {
+                            struct netdev_radio_rx_info *rx_info = info;
+                            rx_info->lqi = zep->lqi_val;
+                            rx_info->rssi = UINT8_MAX;
+                        }
+                    }
+                    break;
+                }
+                default:
+                    DEBUG("socket_zep::recv: unexpected ZEP version\n");
+                    return -1;
+            }
+        }
+        else if (size == 0) {
+            DEBUG("socket_zep::recv: ignoring null-event\n");
+            return -1;
+        }
+        else if (size == -1) {
+            if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
+            }
+            else {
+                err(EXIT_FAILURE, "zep: read");
+            }
+        }
+        else {
+            errx(EXIT_FAILURE, "internal error _rx_event");
+        }
+    }
+    _continue_reading(dev);
+#ifdef MODULE_NETSTATS_L2
+    netdev->stats.rx_count++;
+    netdev->stats.rx_bytes += size;
+#endif
+    return size;
+}
+
+static void _isr(netdev_t *netdev)
+{
+    if (netdev->event_callback) {
+        socket_zep_t *dev = (socket_zep_t *)netdev;
+
+        DEBUG("socket_zep::isr: firing %u\n", (unsigned)dev->last_event);
+        netdev->event_callback(netdev, dev->last_event);
+    }
+    return;
+}
+
+static void _socket_isr(int fd, void *arg)
+{
+    (void)fd;
+    (void)arg;
+    netdev_t *netdev = (netdev_t *)arg;
+
+    DEBUG("socket_zep::_socket_isr: %d, %p (netdev == %p)\n",
+          fd, arg, (void *)netdev);
+    if (netdev == NULL) {
+        return;
+    }
+    if (netdev->event_callback) {
+        socket_zep_t *dev = (socket_zep_t *)netdev;
+
+        dev->last_event = NETDEV_EVENT_RX_COMPLETE;
+        netdev->event_callback(netdev, NETDEV_EVENT_ISR);
+    }
+}
+
+static int _init(netdev_t *netdev)
+{
+    socket_zep_t *dev = (socket_zep_t *)netdev;
+
+    assert(dev != NULL);
+    dev->netdev.chan = IEEE802154_DEFAULT_CHANNEL;
+    dev->netdev.pan = IEEE802154_DEFAULT_PANID;
+#ifdef MODULE_GNRC_SIXLOWPAN
+    dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN;
+#elif MODULE_GNRC
+    dev->netdev.proto = GNRC_NETTYPE_UNDEF;
+#endif
+    dev->seq = random_uint32();
+
+    return 0;
+}
+
+static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len)
+{
+    socket_zep_t *dev = (socket_zep_t *)netdev;
+    uint16_t *v = value;
+
+    assert((dev != NULL));
+    switch (opt) {
+        case NETOPT_MAX_PACKET_SIZE:
+            assert(value != NULL);
+            if (max_len != sizeof(uint16_t)) {
+                return -EOVERFLOW;
+            }
+            *v = SOCKET_ZEP_FRAME_PAYLOAD_LEN;
+            return sizeof(uint16_t);
+        default:
+            return netdev_ieee802154_get(&dev->netdev, opt, value, max_len);
+    }
+}
+
+static int _set(netdev_t *netdev, netopt_t opt, const void *value,
+                size_t value_len)
+{
+    assert(netdev != NULL);
+    return netdev_ieee802154_set((netdev_ieee802154_t *)netdev, opt,
+                                  value, value_len);
+}
+
+
+void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params)
+{
+    static const struct addrinfo hints = { .ai_family = AF_UNSPEC,
+                                           .ai_socktype = SOCK_DGRAM };
+    struct addrinfo *ai = NULL, *remote;
+    int res;
+
+    DEBUG("socket_zep_setup(%p, %p)\n", (void *)dev, (void *)params);
+    assert((params->local_addr != NULL) && (params->local_port != NULL) &&
+           (params->remote_addr != NULL) && (params->remote_port != NULL));
+    memset(dev, 0, sizeof(socket_zep_t));
+    dev->netdev.netdev.driver = &socket_zep_driver;
+    /* bind and connect socket */
+    if ((res = real_getaddrinfo(params->local_addr, params->local_port, &hints,
+                                &ai)) < 0) {
+        errx(EXIT_FAILURE, "ZEP: unable to get local address: %s\n",
+             gai_strerror(res));
+    }
+    for (struct addrinfo *local = ai; local != NULL; local = local->ai_next) {
+        if ((res = real_socket(local->ai_family, local->ai_socktype,
+                               local->ai_protocol)) < 0) {
+            continue;
+        }
+        if (real_bind(res, local->ai_addr, local->ai_addrlen) == 0) {
+            break;  /* successfully bound */
+        }
+    }
+    real_freeaddrinfo(ai);
+    if (res < 0) {
+        err(EXIT_FAILURE, "ZEP: Unable to bind socket");
+    }
+    dev->sock_fd = res;
+    ai = NULL;
+    if ((res = real_getaddrinfo(params->remote_addr, params->remote_port, &hints,
+                                &ai)) < 0) {
+        errx(EXIT_FAILURE, "ZEP: unable to get remote address: %s\n",
+             gai_strerror(res));
+    }
+    for (remote = ai; remote != NULL; remote = remote->ai_next) {
+        if (real_connect(dev->sock_fd, remote->ai_addr, remote->ai_addrlen) == 0) {
+            break;  /* successfully connected */
+        }
+    }
+    if (remote == NULL) {
+        err(EXIT_FAILURE, "ZEP: Unable to connect socket");
+    }
+    real_freeaddrinfo(ai);
+
+    /* generate hardware address from local address */
+    uint8_t ss_array[sizeof(struct sockaddr_storage)] = { 0 };
+    socklen_t ss_len = sizeof(struct sockaddr_storage);
+
+    if (getpeername(dev->sock_fd, (struct sockaddr *)&ss_array, &ss_len) < 0) {
+        err(EXIT_FAILURE, "ZEP: Unable to retrieve remote address");
+    }
+    assert(ss_len >= IEEE802154_LONG_ADDRESS_LEN);
+    if (getsockname(dev->sock_fd, (struct sockaddr *)&ss_array, &ss_len) < 0) {
+        err(EXIT_FAILURE, "ZEP: Unable to retrieve local address");
+    }
+    assert(ss_len >= IEEE802154_LONG_ADDRESS_LEN);
+
+    /* generate hardware address from socket address and port info */
+    dev->netdev.long_addr[1] = 'Z';     /* The "OUI" */
+    dev->netdev.long_addr[2] = 'E';
+    dev->netdev.long_addr[3] = 'P';
+    for (unsigned i = 0; i < ss_len; i++) { /* generate NIC from local source */
+        unsigned addr_idx = (i % (IEEE802154_LONG_ADDRESS_LEN / 2)) +
+                            (IEEE802154_LONG_ADDRESS_LEN / 2);
+        dev->netdev.long_addr[addr_idx] ^= ss_array[i];
+    }
+    dev->netdev.short_addr[0] = dev->netdev.long_addr[6];
+    dev->netdev.short_addr[1] = dev->netdev.long_addr[7];
+    native_async_read_setup();
+    native_async_read_add_handler(dev->sock_fd, dev, _socket_isr);
+#ifdef MODULE_NETSTATS_L2
+    memset(&dev->netdev.netdev.stats, 0, sizeof(netstats_t));
+#endif
+}
+
+void socket_zep_cleanup(socket_zep_t *dev)
+{
+    assert(dev != NULL);
+    /* cleanup signal handling */
+    native_async_read_cleanup();
+    /* close the socket */
+    close(dev->sock_fd);
+    dev->sock_fd = 0;
+}
+
+/** @} */
diff --git a/cpu/native/startup.c b/cpu/native/startup.c
index 35997b9d559b4444d72dc475be1376babb9d2a83..2f0b0173ae304c582aae826c3fab18c3be19be9b 100644
--- a/cpu/native/startup.c
+++ b/cpu/native/startup.c
@@ -75,12 +75,21 @@ netdev_tap_params_t netdev_tap_params[NETDEV_TAP_MAX];
 #include "candev_linux.h"
 #endif
 
+#ifdef MODULE_SOCKET_ZEP
+#include "socket_zep_params.h"
+
+socket_zep_params_t socket_zep_params[SOCKET_ZEP_MAX];
+#endif
+
 static const char short_opts[] = ":hi:s:deEoc:"
 #ifdef MODULE_MTD_NATIVE
     "m:"
 #endif
 #ifdef MODULE_CAN_LINUX
     "n:"
+#endif
+#ifdef MODULE_SOCKET_ZEP
+    "z:"
 #endif
     "";
 
@@ -98,6 +107,9 @@ static const struct option long_opts[] = {
 #endif
 #ifdef MODULE_CAN_LINUX
     { "can", required_argument, NULL, 'n' },
+#endif
+#ifdef MODULE_SOCKET_ZEP
+    { "zep", required_argument, NULL, 'z' },
 #endif
     { NULL, 0, NULL, '\0' },
 };
@@ -228,8 +240,15 @@ void usage_exit(int status)
         real_printf(" <tap interface %d>", i + 1);
     }
 #endif
-
     real_printf(" [-i <id>] [-d] [-e|-E] [-o] [-c <tty>]\n");
+#if defined(MODULE_SOCKET_ZEP) && (SOCKET_ZEP_MAX > 0)
+    real_printf(" -z [[<laddr>:<lport>,]<raddr>:<rport>]\n");
+    for (int i = 0; i < SOCKET_ZEP_MAX - 1; i++) {
+        /* for further interfaces the local address must be different so we omit
+         * the braces (marking them as optional) to be 100% clear on that */
+        real_printf(" -z <laddr>:<lport>,<raddr>:<rport>\n");
+    }
+#endif
 
     real_printf(" help: %s -h\n\n", _progname);
 
@@ -253,7 +272,14 @@ void usage_exit(int status)
 "        to socket\n"
 "    -c <tty>, --uart-tty=<tty>\n"
 "        specify TTY device for UART. This argument can be used multiple\n"
-"        times (up to UART_NUMOF)\n");
+"        times (up to UART_NUMOF)\n"
+#if defined(MODULE_SOCKET_ZEP) && (SOCKET_ZEP_MAX > 0)
+"    -z [<laddr>:<lport>,]<raddr>:<rport> --zep=[<laddr>:<lport>,]<raddr>:<rport>\n"
+"        provide a ZEP interface with local address and port (<laddr>, <lport>)\n"
+"        and remote address and port (default local: [::]:17754).\n"
+"        Required to be provided SOCKET_ZEP_MAX times\n"
+#endif
+    );
 #ifdef MODULE_MTD_NATIVE
     real_printf(
 "    -m <mtd>, --mtd=<mtd>\n"
@@ -268,6 +294,65 @@ void usage_exit(int status)
     real_exit(status);
 }
 
+#ifdef MODULE_SOCKET_ZEP
+static void _parse_ep_str(char *ep_str, char **addr, char **port)
+{
+    /* read endpoint string in reverse, the last chars are the port and decimal
+     * numbers, then a colon, then the address (potentially containing colons,
+     * that's why we read in reverse) */
+    for (int i = strlen(ep_str) - 1; (i >= 0) && (*port == NULL); i--) {
+        if (((ep_str[i] < '0') || (ep_str[i] > '9')) && (ep_str[i] != ':')) {
+            usage_exit(EXIT_FAILURE);
+        }
+        if ((ep_str[i] == ':') && (i >= (int)sizeof("[]"))) {
+            /* found port delimiter, but we need to make sure it isn't delivered
+             * like :<port>. Two characters for either hostname or IP address
+             * seems reasonable especially considering, that we need to
+             * remove the [] around IPv6 addresses */
+            *port = &ep_str[i + 1];
+            if ((ep_str[0] == '[') && (ep_str[i - 1] == ']')) {
+                /* addr is in the format [<addr>], strip [] */
+                *addr = &ep_str[1];
+                ep_str[i - 1] = '\0';
+            }
+            else if ((ep_str[0] == '[') || (ep_str[i - 1] == ']')) {
+                /* unbalanced brackets */
+                usage_exit(EXIT_FAILURE);
+            }
+            else {
+                *addr = ep_str;
+            }
+            ep_str[i] = '\0';
+        }
+    }
+    if (*port == NULL) {
+        usage_exit(EXIT_FAILURE);
+    }
+}
+
+static void _zep_params_setup(char *zep_str, int zep)
+{
+    char *save_ptr, *first_ep, *second_ep;
+
+    if ((first_ep = strtok_r(zep_str, ",", &save_ptr)) == NULL) {
+        usage_exit(EXIT_FAILURE);
+    }
+    second_ep = strtok_r(NULL, ",", &save_ptr);
+    if (second_ep == NULL) {
+        socket_zep_params[zep].local_addr = SOCKET_ZEP_LOCAL_ADDR_DEFAULT;
+        socket_zep_params[zep].local_port = SOCKET_ZEP_PORT_DEFAULT;
+        _parse_ep_str(first_ep, &socket_zep_params[zep].remote_addr,
+                      &socket_zep_params[zep].remote_port);
+    }
+    else {
+        _parse_ep_str(first_ep, &socket_zep_params[zep].local_addr,
+                      &socket_zep_params[zep].local_port);
+        _parse_ep_str(second_ep, &socket_zep_params[zep].remote_addr,
+                      &socket_zep_params[zep].remote_port);
+    }
+}
+#endif
+
 /** @brief Initialization function pointer type */
 typedef void (*init_func_t)(int argc, char **argv, char **envp);
 #ifdef __APPLE__
@@ -295,6 +380,9 @@ __attribute__((constructor)) static void startup(int argc, char **argv, char **e
     _native_id = _native_pid;
 
     int c, opt_idx = 0, uart = 0;
+#ifdef MODULE_SOCKET_ZEP
+    unsigned zeps = 0;
+#endif
     bool dmn = false, force_stderr = false;
     _stdiotype_t stderrtype = _STDIOTYPE_STDIO;
     _stdiotype_t stdouttype = _STDIOTYPE_STDIO;
@@ -360,6 +448,11 @@ __attribute__((constructor)) static void startup(int argc, char **argv, char **e
                         CAN_MAX_SIZE_INTERFACE_NAME);
                 }
                 break;
+#endif
+#ifdef MODULE_SOCKET_ZEP
+            case 'z':
+                _zep_params_setup(optarg, zeps++);
+                break;
 #endif
             default:
                 usage_exit(EXIT_FAILURE);
@@ -374,6 +467,12 @@ __attribute__((constructor)) static void startup(int argc, char **argv, char **e
         }
     }
 #endif
+#ifdef MODULE_SOCKET_ZEP
+    if (zeps != SOCKET_ZEP_MAX) {
+        /* not enough ZEPs given */
+        usage_exit(EXIT_FAILURE);
+    }
+#endif
 
     if (dmn) {
         filter_daemonize_argv(_native_argv);
diff --git a/cpu/native/syscalls.c b/cpu/native/syscalls.c
index c4417153c10fe4fa4a5f9c50f803834f93da9d35..765044d9f19aca06054bf042c4f49e69dd61a0e4 100644
--- a/cpu/native/syscalls.c
+++ b/cpu/native/syscalls.c
@@ -62,9 +62,11 @@ void (*real_freeifaddrs)(struct ifaddrs *ifa);
 void (*real_srandom)(unsigned int seed);
 int (*real_accept)(int socket, ...);
 int (*real_bind)(int socket, ...);
+int (*real_connect)(int socket, ...);
 int (*real_printf)(const char *format, ...);
 int (*real_getaddrinfo)(const char *node, ...);
 int (*real_getifaddrs)(struct ifaddrs **ifap);
+int (*real_gettimeofday)(struct timeval *t, ...);
 int (*real_getpid)(void);
 int (*real_chdir)(const char *path);
 int (*real_close)(int);
@@ -447,11 +449,13 @@ void _native_init_syscalls(void)
     *(void **)(&real_srandom) = dlsym(RTLD_NEXT, "srandom");
     *(void **)(&real_accept) = dlsym(RTLD_NEXT, "accept");
     *(void **)(&real_bind) = dlsym(RTLD_NEXT, "bind");
+    *(void **)(&real_connect) = dlsym(RTLD_NEXT, "connect");
     *(void **)(&real_printf) = dlsym(RTLD_NEXT, "printf");
     *(void **)(&real_gai_strerror) = dlsym(RTLD_NEXT, "gai_strerror");
     *(void **)(&real_getaddrinfo) = dlsym(RTLD_NEXT, "getaddrinfo");
     *(void **)(&real_getifaddrs) = dlsym(RTLD_NEXT, "getifaddrs");
     *(void **)(&real_getpid) = dlsym(RTLD_NEXT, "getpid");
+    *(void **)(&real_gettimeofday) = dlsym(RTLD_NEXT, "gettimeofday");
     *(void **)(&real_pipe) = dlsym(RTLD_NEXT, "pipe");
     *(void **)(&real_chdir) = dlsym(RTLD_NEXT, "chdir");
     *(void **)(&real_close) = dlsym(RTLD_NEXT, "close");
diff --git a/examples/gnrc_border_router/Makefile b/examples/gnrc_border_router/Makefile
index 40e9576cf61d496415238ad9947a42e63403611b..7c6e479f4fe5eb34ffc69c58b1b49fa2841ed83d 100644
--- a/examples/gnrc_border_router/Makefile
+++ b/examples/gnrc_border_router/Makefile
@@ -29,6 +29,10 @@ ifeq (,$(filter native,$(BOARD)))
   ETHOS_BAUDRATE ?= 115200
   CFLAGS += -DETHOS_BAUDRATE=$(ETHOS_BAUDRATE) -DUSE_ETHOS_FOR_STDIO
   FEATURES_REQUIRED += periph_uart
+else
+  GNRC_NETIF_NUMOF := 2
+  TERMFLAGS += -z [::1]:17754
+  USEMODULE += socket_zep
 endif
 
 # SLIP legacy compatibility
@@ -82,6 +86,14 @@ QUIET ?= 1
 TAP ?= tap0
 IPV6_PREFIX ?= 2001:db8::/64
 
+ifeq (native,$(BOARD))
+TERMDEPS += uhcpd-daemon
+
+.PHONY: uhcpd-daemon
+
+uhcpd-daemon: host-tools
+	$(RIOTBASE)/dist/tools/uhcpd/bin/uhcpd $(TAP) $(IPV6_PREFIX) &
+else
 # We override the `make term` command to use ethos
 TERMPROG ?= sudo sh $(RIOTBASE)/dist/tools/ethos/start_network.sh
 TERMFLAGS ?= $(PORT) $(TAP) $(IPV6_PREFIX)
@@ -89,6 +101,7 @@ TERMFLAGS ?= $(PORT) $(TAP) $(IPV6_PREFIX)
 # We depend on the ethos host tools to run the border router, we build them
 # if necessary
 TERMDEPS += host-tools
+endif
 
 include $(RIOTBASE)/Makefile.include
 
diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c
index aa3768f04ff41ce7609a5820b842a801f6163e17..76248d0e40ee048c31ebbcee566208919a49040b 100644
--- a/sys/auto_init/auto_init.c
+++ b/sys/auto_init/auto_init.c
@@ -215,6 +215,11 @@ void auto_init(void)
     auto_init_netdev_tap();
 #endif
 
+#ifdef MODULE_SOCKET_ZEP
+    extern void auto_init_socket_zep(void);
+    auto_init_socket_zep();
+#endif
+
 #ifdef MODULE_NORDIC_SOFTDEVICE_BLE
     extern void gnrc_nordic_ble_6lowpan_init(void);
     gnrc_nordic_ble_6lowpan_init();
diff --git a/sys/auto_init/netif/auto_init_socket_zep.c b/sys/auto_init/netif/auto_init_socket_zep.c
new file mode 100644
index 0000000000000000000000000000000000000000..b80457798cda422d6fc9d1effdb6a72ae46b5a66
--- /dev/null
+++ b/sys/auto_init/netif/auto_init_socket_zep.c
@@ -0,0 +1,60 @@
+/*
+ * 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 auto_init_gnrc_netif
+ * @{
+ *
+ * @file
+ * @brief   Auto initialization for @ref netdev_socket_zep devices
+ *
+ * @author  Martine Lenders <m.lenders@fu-berlin.de>
+ */
+
+#ifdef MODULE_SOCKET_ZEP
+
+#include "log.h"
+#include "socket_zep.h"
+#include "socket_zep_params.h"
+#include "net/gnrc/netif/ieee802154.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+/**
+ * @brief   Define stack parameters for the MAC layer thread
+ */
+#define SOCKET_ZEP_MAC_STACKSIZE    (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE)
+#ifndef SOCKET_ZEP_MAC_PRIO
+#define SOCKET_ZEP_MAC_PRIO         (GNRC_NETIF_PRIO)
+#endif
+
+/**
+ * @brief   Stacks for the MAC layer threads
+ */
+static char _socket_zep_stacks[SOCKET_ZEP_MAX][SOCKET_ZEP_MAC_STACKSIZE];
+static socket_zep_t _socket_zeps[SOCKET_ZEP_MAX];
+
+void auto_init_socket_zep(void)
+{
+    for (int i = 0; i < SOCKET_ZEP_MAX; i++) {
+        LOG_DEBUG("[auto_init_netif: initializing socket ZEP device #%u\n", i);
+        /* setup netdev device */
+        socket_zep_setup(&_socket_zeps[i], &socket_zep_params[i]);
+        gnrc_netif_ieee802154_create(_socket_zep_stacks[i],
+                                     SOCKET_ZEP_MAC_STACKSIZE,
+                                     SOCKET_ZEP_MAC_PRIO, "socket_zep",
+                                     (netdev_t *)&_socket_zeps[i]);
+    }
+}
+
+#else
+typedef int dont_be_pedantic;
+#endif /* MODULE_SOCKET_ZEP */
+/** @} */
diff --git a/sys/include/net/zep.h b/sys/include/net/zep.h
new file mode 100644
index 0000000000000000000000000000000000000000..80a317a40e1d58a8c81b99c92b7d4441052f2c68
--- /dev/null
+++ b/sys/include/net/zep.h
@@ -0,0 +1,102 @@
+/*
+ * 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    net_zep  ZEP header definitions
+ * @ingroup     net
+ * @{
+ *
+ * @file
+ * @brief
+ *
+ * @author  Martine Lenders <m.lenders@fu-berlin.de>
+ */
+#ifndef NET_ZEP_H
+#define NET_ZEP_H
+
+#include <stdint.h>
+
+#include "byteorder.h"
+#include "net/ntp_packet.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZEP_PORT_DEFAULT        (17754) /**< default ZEP port */
+
+/**
+ * @brief   Type == Data for ZEPv2 header
+ */
+#define ZEP_V2_TYPE_DATA        (1)
+
+/**
+ * @brief   Type == Ack for ZEPv2 header
+ */
+#define ZEP_V2_TYPE_ACK         (2)
+
+/**
+ * @brief   Mask for length field
+ */
+#define ZEP_LENGTH_MASK         (0x7f)
+
+/**
+ * @brief   ZEP header definition
+ */
+typedef struct __attribute__((packed)) {
+    char preamble[2];       /**< Preamble code (must be "EX") */
+    uint8_t version;        /**< Protocol Version (must be 1 or 2) */
+} zep_hdr_t;
+
+/**
+ * @brief   ZEPv1 header definition
+ * @extends zep_hdr_t
+ */
+typedef struct __attribute__((packed)) {
+    zep_hdr_t hdr;          /**< common header fields */
+    uint8_t chan;           /**< channel ID */
+    network_uint16_t dev;   /**< device ID */
+    uint8_t lqi_mode;       /**< CRC/LQI Mode (0: append LQI to frame, 1: append FCS) */
+    uint8_t lqi_val;        /**< LQI value */
+    uint8_t resv[7];        /**< reserved field, must always be 0 */
+    uint8_t length;         /**< length of the frame */
+} zep_v1_hdr_t;
+
+/**
+ * @brief   ZEPv2 header definition (type == Data)
+ * @extends zep_hdr_t
+ */
+typedef struct __attribute__((packed)) {
+    zep_hdr_t hdr;          /**< common header fields */
+    uint8_t type;           /**< type (must be @ref ZEP_V2_TYPE_DATA) */
+    uint8_t chan;           /**< channel ID */
+    network_uint16_t dev;   /**< device ID */
+    uint8_t lqi_mode;       /**< CRC/LQI Mode */
+    uint8_t lqi_val;        /**< LQI value */
+    ntp_timestamp_t time;   /**< NTP timestamp */
+    network_uint32_t seq;   /**< Sequence number */
+    uint8_t resv[10];       /**< reserved field, must always be 0 */
+    uint8_t length;         /**< length of the frame */
+} zep_v2_data_hdr_t;
+
+/**
+ * @brief   ZEPv2 header definition (type == Ack)
+ * @extends zep_hdr_t
+ */
+typedef struct __attribute__((packed)) {
+    zep_hdr_t hdr;          /**< common header fields */
+    uint8_t type;           /**< type (must be @ref ZEP_V2_TYPE_ACK) */
+    network_uint32_t seq;   /**< Sequence number */
+} zep_v2_ack_hdr_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NET_ZEP_H */
+/** @} */
diff --git a/tests/socket_zep/Makefile b/tests/socket_zep/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..db55c1d71ec0bdae3ab9d58b4b52a743735d0d2d
--- /dev/null
+++ b/tests/socket_zep/Makefile
@@ -0,0 +1,18 @@
+APPLICATION = socket_zep
+include ../Makefile.tests_common
+
+BOARD_WHITELIST = native    # socket_zep is only available on native
+
+DISABLE_MODULE += auto_init
+
+USEMODULE += od
+USEMODULE += socket_zep
+
+CFLAGS += -DDEVELHELP
+
+TERMFLAGS ?= -z [::1]:17754
+
+include $(RIOTBASE)/Makefile.include
+
+test:
+	./tests/01-run.py
diff --git a/tests/socket_zep/main.c b/tests/socket_zep/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..faac4e172ee8ba04a4c1feb5bd1be8f5f6298a16
--- /dev/null
+++ b/tests/socket_zep/main.c
@@ -0,0 +1,179 @@
+/*
+ * 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 application for socket_zep network device driver
+ *
+ * @author      Martine Lenders <m.lenders@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+
+#include "byteorder.h"
+#include "net/ieee802154.h"
+#include "sched.h"
+#include "socket_zep.h"
+#include "socket_zep_params.h"
+#include "msg.h"
+#include "od.h"
+
+#define MSG_QUEUE_SIZE  (8)
+#define MSG_TYPE_ISR    (0x3456)
+#define RECVBUF_SIZE    (IEEE802154_FRAME_LEN_MAX)
+
+static uint8_t _recvbuf[RECVBUF_SIZE];
+static msg_t _msg_queue[MSG_QUEUE_SIZE];
+static socket_zep_t _dev;
+static kernel_pid_t _main_pid;
+
+static void _event_cb(netdev_t *dev, netdev_event_t event);
+static void _print_info(netdev_t *netdev);
+
+static void test_init(void)
+{
+    const socket_zep_params_t *p = &socket_zep_params[0];
+    netdev_t *netdev = (netdev_t *)(&_dev);
+
+    printf("Initializing socket ZEP with (local: [%s]:%s, remote: [%s]:%s)\n",
+           p->local_addr, p->local_port, p->remote_addr, p->remote_port);
+    socket_zep_setup(&_dev, p);
+    netdev->event_callback = _event_cb;
+    assert(netdev->driver->init(netdev) >= 0);
+    _print_info(netdev);
+}
+
+static void test_send__vector_NULL__count_0(void)
+{
+    netdev_t *netdev = (netdev_t *)(&_dev);
+    int res;
+
+    puts("Send zero-length packet");
+    res = netdev->driver->send(netdev, NULL, 0);
+    assert((res < 0) || (res == 0));
+    if ((res < 0) && (errno == ECONNREFUSED)) {
+        puts("No remote socket exists (use scripts in `tests/` to have proper tests)");
+    }
+}
+
+static void test_send__vector_not_NULL__count_2(void)
+{
+    struct iovec vector[] = { { .iov_base = "Hello", .iov_len = sizeof("Hello") },
+                              { .iov_base = "World", .iov_len = sizeof("World") } };
+    netdev_t *netdev = (netdev_t *)(&_dev);
+    int res;
+
+    puts("Send 'Hello\\0World\\0'");
+    res =  netdev->driver->send(netdev, vector,
+                                sizeof(vector) / sizeof(struct iovec));
+    assert((res < 0) || (res == (sizeof("Hello")) + sizeof("World")));
+    if ((res < 0) && (errno == ECONNREFUSED)) {
+        puts("No remote socket exists (use scripts in `tests/` to have proper tests)");
+    }
+}
+
+static void test_recv(void)
+{
+    puts("Waiting for an incoming message (use `make test`)");
+    while (1) {
+        netdev_t *netdev = (netdev_t *)(&_dev);
+        msg_t msg;
+
+        msg_receive(&msg);
+        if (msg.type == MSG_TYPE_ISR) {
+            netdev->driver->isr(netdev);
+        }
+        else {
+            puts("unexpected message type");
+        }
+    }
+}
+
+int main(void)
+{
+    puts("Socket ZEP device driver test");
+    msg_init_queue(_msg_queue, MSG_QUEUE_SIZE);
+    _main_pid = sched_active_pid;
+
+    test_init();
+    test_send__vector_NULL__count_0();
+    test_send__vector_not_NULL__count_2();
+    test_recv();    /* does not return */
+    puts("ALL TESTS SUCCESSFUL");
+    return 0;
+}
+
+static void _recv(netdev_t *dev)
+{
+    netdev_ieee802154_rx_info_t rx_info;
+    const int exp_len = dev->driver->recv(dev, NULL, 0, NULL);
+    int data_len;
+
+    assert(exp_len >= 0);
+    assert(((unsigned)exp_len) <= sizeof(_recvbuf));
+    data_len = dev->driver->recv(dev, _recvbuf, sizeof(_recvbuf), &rx_info);
+    if (data_len < 0) {
+        puts("Received invalid packet");
+    }
+    else {
+        assert(data_len <= exp_len);
+        printf("RSSI: %u, LQI: %u, Data:\n", rx_info.rssi, rx_info.lqi);
+        if (data_len > 0) {
+            od_hex_dump(_recvbuf, data_len, OD_WIDTH_DEFAULT);
+        }
+    }
+}
+
+static void _event_cb(netdev_t *dev, netdev_event_t event)
+{
+    if (event == NETDEV_EVENT_ISR) {
+        msg_t msg;
+
+        msg.type = MSG_TYPE_ISR;
+        msg.content.ptr = dev;
+
+        if (msg_send(&msg, _main_pid) <= 0) {
+            puts("possibly lost interrupt.");
+        }
+    }
+    else {
+        switch (event) {
+            case NETDEV_EVENT_RX_COMPLETE:
+            {
+                _recv(dev);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}
+
+static void _print_info(netdev_t *netdev)
+{
+    uint64_t long_addr;
+    uint16_t short_addr;
+
+    assert(netdev->driver->get(netdev, NETOPT_ADDRESS, &short_addr,
+                               sizeof(short_addr)) == sizeof(uint16_t));
+    assert(netdev->driver->get(netdev, NETOPT_ADDRESS_LONG, &long_addr,
+                               sizeof(long_addr)) == sizeof(uint64_t));
+
+    /* we are on native, so using PRIu* is okay */
+    printf("(Hwaddrs: %04" PRIx16 ", %016" PRIx64 ")\n",
+           byteorder_htons(short_addr).u16,
+           byteorder_htonll(long_addr).u64);
+}
diff --git a/tests/socket_zep/tests/01-run.py b/tests/socket_zep/tests/01-run.py
new file mode 100755
index 0000000000000000000000000000000000000000..bcbfedd1bfab701601666635e6aa8b4536808e9d
--- /dev/null
+++ b/tests/socket_zep/tests/01-run.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+
+# 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.
+
+import os
+import sys
+
+import socket
+
+IEEE802154_FRAME_LEN_MAX = 127
+ZEP_DATA_HEADER_SIZE = 32
+FCS_LEN = 2
+RCVBUF_LEN = IEEE802154_FRAME_LEN_MAX + ZEP_DATA_HEADER_SIZE + FCS_LEN
+zep_params = {
+        "local_addr": "::",
+        "local_port": 12345,
+        "remote_addr": "::1",
+        "remote_port": 17754,
+    }
+s = None
+
+
+def testfunc(child):
+    child.expect_exact("Socket ZEP device driver test")
+    child.expect(r"Initializing socket ZEP with " +
+                 r"\(local: \[(?P<local_addr>[:0-9a-f]+)\]:(?P<local_port>\d+), " +
+                 r"remote: \[(?P<remote_addr>[:0-9a-f]+)\]:(?P<remote_port>\d+)\)")
+    assert(child.match.group('local_addr') == zep_params['local_addr'])
+    assert(int(child.match.group('local_port')) == zep_params['local_port'])
+    assert(child.match.group('remote_addr') == zep_params['remote_addr'])
+    assert(int(child.match.group('remote_port')) == zep_params['remote_port'])
+    child.expect(r"\(Hwaddrs: (?P<short_addr>[0-9a-f]{4}), (?P<long_addr>[0-9a-f]{16})\)")
+    child.expect_exact("Send zero-length packet")
+    data, addr = s.recvfrom(RCVBUF_LEN)
+    assert(len(data) == (ZEP_DATA_HEADER_SIZE + FCS_LEN))
+    child.expect_exact("Send 'Hello\\0World\\0'")
+    data, addr = s.recvfrom(RCVBUF_LEN)
+    assert(len(data) == (ZEP_DATA_HEADER_SIZE + len("Hello\0World\0") + FCS_LEN))
+    assert(b"Hello\0World\0" == data[ZEP_DATA_HEADER_SIZE:-2])
+    child.expect_exact("Waiting for an incoming message (use `make test`)")
+    s.sendto(b"\x45\x58\x02\x01\x1a\x44\xe0\x01\xff\xdb\xde\xa6\x1a\x00\x8b" +
+             b"\xfd\xae\x60\xd3\x21\xf1\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
+             b"\x00\x22\x41\xdc\x02\x23\x00\x38\x30\x00\x0a\x50\x45\x5a\x00" +
+             b"\x5b\x45\x00\x0a\x50\x45\x5a\x00Hello World\x3a\xf2",
+             ("::1", zep_params['local_port']))
+    child.expect(r"RSSI: \d+, LQI: \d+, Data:")
+    child.expect_exact(r"00000000  41  DC  02  23  00  38  30  00  0A  50  45  5A  00  5B  45  00")
+    child.expect_exact(r"00000010  0A  50  45  5A  00  48  65  6C  6C  6F  20  57  6F  72  6C  64")
+
+
+if __name__ == "__main__":
+    sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner'))
+    import testrunner
+
+    os.environ['TERMFLAGS'] = "-z [%s]:%d,[%s]:%d" % (
+            zep_params['local_addr'], zep_params['local_port'],
+            zep_params['remote_addr'], zep_params['remote_port'])
+    s = socket.socket(family=socket.AF_INET6, type=socket.SOCK_DGRAM)
+    s.bind(("::", zep_params['remote_port']))
+    res = testrunner.run(testfunc, timeout=1, echo=True, traceback=True)
+    s.close()
+    if (res == 0):
+        print("Run tests successful")
+    else:
+        print("Run tests failed")
+    sys.exit(res)