diff --git a/Makefile.dep b/Makefile.dep
index ff30654c85017f6a47dc571414f45317e5015a30..4b23a0cf0eab54d3930e83bd327025b48fb455e3 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -419,3 +419,7 @@ endif
 ifneq (,$(filter phydat,$(USEMODULE)))
   USEMODULE += fmt
 endif
+
+ifneq (,$(filter ethos,$(USEMODULE)))
+    USEMODULE += netdev2_eth
+endif
diff --git a/drivers/ethos/Makefile b/drivers/ethos/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2
--- /dev/null
+++ b/drivers/ethos/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/drivers/ethos/ethos.c b/drivers/ethos/ethos.c
new file mode 100644
index 0000000000000000000000000000000000000000..99f158c554feabe2fc17a5629a8976c51b99bbc1
--- /dev/null
+++ b/drivers/ethos/ethos.c
@@ -0,0 +1,348 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup     driver_ethos
+ * @{
+ *
+ * @file
+ * @brief       Implementation of a simple ethernet-over-serial driver
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * @}
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include "random.h"
+#include "ethos.h"
+#include "periph/uart.h"
+#include "tsrb.h"
+
+#include "net/netdev2.h"
+#include "net/netdev2_eth.h"
+#include "net/eui64.h"
+#include "net/ethernet.h"
+
+#ifdef USE_ETHOS_FOR_STDIO
+#include "uart_stdio.h"
+#endif
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+static void _get_mac_addr(netdev2_t *dev, uint8_t* buf);
+static void ethos_isr(void *arg, char c);
+const static netdev2_driver_t netdev2_driver_ethos;
+
+static const uint8_t _esc_esc[] = {ETHOS_ESC_CHAR, (ETHOS_ESC_CHAR ^ 0x20)};
+static const uint8_t _esc_delim[] = {ETHOS_ESC_CHAR, (ETHOS_FRAME_DELIMITER ^ 0x20)};
+
+
+void ethos_setup(ethos_t *dev, uart_t uart, uint32_t baudrate, uint8_t *buf, size_t bufsize)
+{
+    dev->netdev.driver = &netdev2_driver_ethos;
+    dev->uart = uart;
+    dev->state = WAIT_FRAMESTART;
+    dev->framesize = 0;
+    dev->frametype = 0;
+    dev->last_framesize = 0;
+
+    tsrb_init(&dev->inbuf, (char*)buf, bufsize);
+    mutex_init(&dev->out_mutex);
+
+    uint32_t a = genrand_uint32();
+    memcpy(dev->mac_addr, (char*)&a, 4);
+    a = genrand_uint32();
+    memcpy(dev->mac_addr+4, (char*)&a, 2);
+
+    dev->mac_addr[0] &= (0x2);      /* unset globally unique bit */
+    dev->mac_addr[0] &= ~(0x1);     /* set unicast bit*/
+
+    uart_init(uart, baudrate, ethos_isr, (void*)dev);
+
+    uint8_t frame_delim = ETHOS_FRAME_DELIMITER;
+    uart_write(dev->uart, &frame_delim, 1);
+    ethos_send_frame(dev, dev->mac_addr, 6, ETHOS_FRAME_TYPE_HELLO);
+}
+
+static void _reset_state(ethos_t *dev)
+{
+    dev->state = WAIT_FRAMESTART;
+    dev->frametype = 0;
+    dev->framesize = 0;
+}
+
+static void _handle_char(ethos_t *dev, char c)
+{
+    switch (dev->frametype) {
+        case ETHOS_FRAME_TYPE_DATA:
+        case ETHOS_FRAME_TYPE_HELLO:
+        case ETHOS_FRAME_TYPE_HELLO_REPLY:
+             if (tsrb_add_one(&dev->inbuf, c) == 0) {
+                dev->framesize++;
+            } else {
+                //puts("lost frame");
+                dev->inbuf.reads = 0;
+                dev->inbuf.writes = 0;
+                _reset_state(dev);
+            }
+            break;
+#ifdef USE_ETHOS_FOR_STDIO
+        case ETHOS_FRAME_TYPE_TEXT:
+            dev->framesize++;
+            uart_stdio_rx_cb(NULL, c);
+#endif
+    }
+}
+
+static void _end_of_frame(ethos_t *dev)
+{
+    switch(dev->frametype) {
+        case ETHOS_FRAME_TYPE_DATA:
+            if (dev->framesize) {
+                dev->last_framesize = dev->framesize;
+                dev->netdev.event_callback((netdev2_t*) dev, NETDEV2_EVENT_ISR, NULL);
+            }
+            break;
+        case ETHOS_FRAME_TYPE_HELLO:
+            ethos_send_frame(dev, dev->mac_addr, 6, ETHOS_FRAME_TYPE_HELLO_REPLY);
+            /* fall through */
+        case ETHOS_FRAME_TYPE_HELLO_REPLY:
+            if (dev->framesize == 6) {
+                tsrb_get(&dev->inbuf, (char*)dev->remote_mac_addr, 6);
+            }
+            break;
+    }
+
+    _reset_state(dev);
+}
+
+static void ethos_isr(void *arg, char c)
+{
+    ethos_t *dev = (ethos_t *) arg;
+
+    switch (dev->state) {
+        case WAIT_FRAMESTART:
+            if (c == ETHOS_FRAME_DELIMITER) {
+                _reset_state(dev);
+                dev->state = IN_FRAME;
+            }
+            break;
+        case IN_FRAME:
+            if (c == ETHOS_ESC_CHAR) {
+                dev->state = IN_ESCAPE;
+            }
+            else if (c == ETHOS_FRAME_DELIMITER) {
+                if (dev->framesize) {
+                    _end_of_frame(dev);
+                }
+            }
+            else {
+                _handle_char(dev, c);
+            }
+            break;
+        case IN_ESCAPE:
+            switch (c) {
+                case (ETHOS_FRAME_DELIMITER ^ 0x20):
+                    _handle_char(dev, ETHOS_FRAME_DELIMITER);
+                    break;
+                case (ETHOS_ESC_CHAR ^ 0x20):
+                    _handle_char(dev, ETHOS_ESC_CHAR);
+                    break;
+                case (ETHOS_FRAME_TYPE_TEXT ^ 0x20):
+                    dev->frametype = ETHOS_FRAME_TYPE_TEXT;
+                    break;
+                case (ETHOS_FRAME_TYPE_HELLO ^ 0x20):
+                    dev->frametype = ETHOS_FRAME_TYPE_HELLO;
+                    break;
+                case (ETHOS_FRAME_TYPE_HELLO_REPLY ^ 0x20):
+                    dev->frametype = ETHOS_FRAME_TYPE_HELLO_REPLY;
+                    break;
+            }
+            dev->state = IN_FRAME;
+            break;
+    }
+}
+
+static void _isr(netdev2_t *netdev)
+{
+    ethos_t *dev = (ethos_t *) netdev;
+    dev->netdev.event_callback((netdev2_t*) dev, NETDEV2_EVENT_RX_COMPLETE, NULL);
+}
+
+static int _init(netdev2_t *encdev)
+{
+    ethos_t *dev = (ethos_t *) encdev;
+    (void)dev;
+    return 0;
+}
+
+static size_t iovec_count_total(const struct iovec *vector, int count)
+{
+    size_t result = 0;
+    while(count--) {
+        result += vector->iov_len;
+        vector++;
+    }
+    return result;
+}
+
+static void _write_escaped(uart_t uart, uint8_t c)
+{
+    uint8_t *out;
+    int n;
+
+    switch(c) {
+        case ETHOS_FRAME_DELIMITER:
+            out = (uint8_t*)_esc_delim;
+            n = 2;
+            break;
+        case ETHOS_ESC_CHAR:
+            out = (uint8_t*)_esc_esc;
+            n = 2;
+            break;
+        default:
+            out = &c;
+            n = 1;
+    }
+
+    uart_write(uart, out, n);
+}
+
+void ethos_send_frame(ethos_t *dev, const uint8_t *data, size_t len, unsigned frame_type)
+{
+    uint8_t frame_delim = ETHOS_FRAME_DELIMITER;
+
+    if (!inISR()) {
+        mutex_lock(&dev->out_mutex);
+    }
+    else {
+        /* Send frame delimiter. This cancels the current frame,
+         * but enables in-ISR writes.  */
+        uart_write(dev->uart, &frame_delim, 1);
+    }
+
+    /* send frame delimiter */
+    uart_write(dev->uart, &frame_delim, 1);
+
+    /* set frame type */
+    if (frame_type) {
+        uint8_t out[2] = { ETHOS_ESC_CHAR, (frame_type ^ 0x20) };
+        uart_write(dev->uart, out, 2);
+    }
+
+    /* send frame content */
+    while(len--) {
+        _write_escaped(dev->uart, *(uint8_t*)data++);
+    }
+
+    /* end of frame */
+    uart_write(dev->uart, &frame_delim, 1);
+
+    if (!inISR()) {
+        mutex_unlock(&dev->out_mutex);
+    }
+}
+
+static int _send(netdev2_t *netdev, const struct iovec *vector, int count)
+{
+    ethos_t * dev = (ethos_t *) netdev;
+    (void)dev;
+
+    /* count total packet length */
+    size_t pktlen = iovec_count_total(vector, count);
+
+    /* lock line in order to prevent multiple writes */
+    mutex_lock(&dev->out_mutex);
+
+    /* send start-frame-delimiter */
+    uint8_t frame_delim = ETHOS_FRAME_DELIMITER;
+    uart_write(dev->uart, &frame_delim, 1);
+
+    /* send iovec */
+    while(count--) {
+        size_t n = vector->iov_len;
+        uint8_t *ptr = vector->iov_base;
+        while(n--) {
+            _write_escaped(dev->uart, *ptr++);
+        }
+        vector++;
+    }
+
+    uart_write(dev->uart, &frame_delim, 1);
+
+    mutex_unlock(&dev->out_mutex);
+
+    return pktlen;
+}
+
+static void _get_mac_addr(netdev2_t *encdev, uint8_t* buf)
+{
+    ethos_t * dev = (ethos_t *) encdev;
+    memcpy(buf, dev->mac_addr, 6);
+}
+
+static int _recv(netdev2_t *netdev, char* buf, int len)
+{
+    ethos_t * dev = (ethos_t *) netdev;
+
+    if (buf) {
+        if (len != dev->last_framesize) {
+            DEBUG("ethos _recv(): unmatched receive buffer size.");
+            return -1;
+        }
+
+        dev->last_framesize = 0;
+
+        if ((tsrb_get(&dev->inbuf, buf, len) != len)) {
+            DEBUG("ethos _recv(): inbuf doesn't contain enough bytes.");
+            return -1;
+        }
+
+        return len;
+    }
+    else {
+        return dev->last_framesize;
+    }
+}
+
+int _get(netdev2_t *dev, netopt_t opt, void *value, size_t max_len)
+{
+    int res = 0;
+
+    switch (opt) {
+        case NETOPT_ADDRESS:
+            if (max_len < ETHERNET_ADDR_LEN) {
+                res = -EINVAL;
+            }
+            else {
+                _get_mac_addr(dev, (uint8_t*)value);
+                res = ETHERNET_ADDR_LEN;
+            }
+            break;
+        default:
+            res = netdev2_eth_get(dev, opt, value, max_len);
+            break;
+    }
+
+    return res;
+}
+
+/* netdev2 interface */
+const static netdev2_driver_t netdev2_driver_ethos = {
+    .send = _send,
+    .recv = _recv,
+    .init = _init,
+    .isr = _isr,
+    .get = _get,
+    .set = netdev2_eth_set
+};
diff --git a/drivers/include/ethos.h b/drivers/include/ethos.h
new file mode 100644
index 0000000000000000000000000000000000000000..3faa3a8caf8e4c85029c98a5c5708f026de5f5bf
--- /dev/null
+++ b/drivers/include/ethos.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+/**
+ * @defgroup    drivers_ethos ethos
+ * @ingroup     drivers_netdev
+ * @brief       Driver for the ethernet-over-serial module
+ * @{
+ *
+ * @file
+ * @brief       Interface definition for the ethernet-over-serial module
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ */
+
+#ifndef ETHOS_H
+#define ETHOS_H
+
+#include "kernel_types.h"
+#include "periph/uart.h"
+#include "net/netdev2.h"
+#include "tsrb.h"
+#include "mutex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* if using ethos + stdio, use STDIO values unless overridden */
+#ifdef USE_ETHOS_FOR_STDIO
+#include "board.h"
+#ifndef ETHOS_UART
+#define ETHOS_UART  STDIO
+#endif
+#ifndef ETHOS_BAUDRATE
+#define ETHOS_BAUDRATE STDIO_BAUDRATE
+#endif
+#endif
+
+/**
+ * @name Escape char definitions
+ * @{
+ */
+#define ETHOS_FRAME_DELIMITER           (0x7E)
+#define ETHOS_ESC_CHAR                  (0x7D)
+#define ETHOS_FRAME_TYPE_DATA           (0x0)
+#define ETHOS_FRAME_TYPE_TEXT           (0x1)
+#define ETHOS_FRAME_TYPE_HELLO          (0x2)
+#define ETHOS_FRAME_TYPE_HELLO_REPLY    (0x3)
+/** @} */
+
+/**
+ * @brief   enum describing line state
+ */
+typedef enum {
+    WAIT_FRAMESTART,
+    IN_FRAME,
+    IN_ESCAPE
+} line_state_t;
+
+/**
+ * @brief ethos netdev2 device
+ * @extends netdev2_t
+ */
+typedef struct {
+    netdev2_t netdev;       /**< extended netdev2 structure */
+    uart_t uart;            /**< UART device the to use */
+    uint8_t mac_addr[6];    /**< this device's MAC address */
+    uint8_t remote_mac_addr[6]; /**< this device's MAC address */
+    tsrb_t inbuf;           /**< ringbuffer for incoming data */
+    line_state_t state;     /**< Line status variable */
+    size_t framesize;       /**< size of currently incoming frame */
+    unsigned frametype;     /**< type of currently incoming frame */
+    size_t last_framesize;  /**< size of last completed frame */
+    mutex_t out_mutex;      /**< mutex used for locking concurrent sends */
+} ethos_t;
+
+/**
+ * @brief Setup an ethos based device state.
+ *
+ * The supplied buffer *must* have a power-of-two size, and it *must* be large
+ * enough for the largest expected packet + enough buffer space to buffer
+ * bytes that arrive while one packet is being handled.
+ *
+ * E.g., if 1536b ethernet frames are expected, 2048 is probably a good size for @p buf.
+ *
+ * @param[out]  dev         handle of the device to initialize
+ * @param[in]   uart        UART device to use
+ * @param[in]   baudrate    baudrate for UART device
+ * @param[in]   buf         buffer for incoming packets
+ * @param[in]   bufsize     size of @p buf
+ */
+void ethos_setup(ethos_t *dev, uart_t uart, uint32_t baudrate, uint8_t *buf, size_t bufsize);
+
+/**
+ * @brief send frame over serial port using ethos' framing
+ *
+ * This is used by e.g., stdio over ethos to send text frames.
+ *
+ * @param[in]   dev         handle of the device to initialize
+ * @param[in]   data        ptr to data to be sent
+ * @param[in]   len         nr of bytes to send
+ * @param[in]   frame_type  frame type to use
+ */
+void ethos_send_frame(ethos_t *dev, const uint8_t *data, size_t len, unsigned frame_type);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* ETHOS_H */
+/** @} */
diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c
index 7fa2fc35bf0b7ca72d5900c6b3d58b1e8d609857..dfbd168888cd58dcbece439773131c8f30009d62 100644
--- a/sys/auto_init/auto_init.c
+++ b/sys/auto_init/auto_init.c
@@ -158,6 +158,11 @@ void auto_init(void)
     auto_init_enc28j60();
 #endif
 
+#ifdef MODULE_ETHOS
+    extern void auto_init_ethos(void);
+    auto_init_ethos();
+#endif
+
 #ifdef MODULE_GNRC_SLIP
     extern void auto_init_slip(void);
     auto_init_slip();
diff --git a/sys/auto_init/netif/auto_init_ethos.c b/sys/auto_init/netif/auto_init_ethos.c
new file mode 100644
index 0000000000000000000000000000000000000000..d8813425014874b6c4ec72f04f040dbb89faa610
--- /dev/null
+++ b/sys/auto_init/netif/auto_init_ethos.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 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.
+ *
+ */
+
+/**
+ * @ingroup auto_init_gnrc_netif
+ * @{
+ *
+ * @file
+ * @brief   Auto initialization for ethernet-over-serial module
+ *
+ * @author  Kaspar Schleiser <kaspar@schleiser.de>
+ */
+
+#ifdef MODULE_ETHOS
+
+#include "ethos.h"
+#include "periph/uart.h"
+#include "net/gnrc/netdev2/eth.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+/**
+ * @brief global ethos object, used by uart_stdio
+ */
+ethos_t ethos;
+
+/**
+ * @brief   Define stack parameters for the MAC layer thread
+ * @{
+ */
+#define MAC_STACKSIZE           (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE)
+#define MAC_PRIO                (THREAD_PRIORITY_MAIN - 4)
+
+/**
+ * @brief   Stacks for the MAC layer threads
+ */
+static char _netdev2_eth_stack[MAC_STACKSIZE];
+static gnrc_netdev2_t _gnrc_ethos;
+
+static uint8_t _inbuf[2048];
+
+void auto_init_ethos(void)
+{
+    DEBUG("auto_init_ethos(): initializing device...\n");
+
+    /* setup netdev2 device */
+    ethos_setup(&ethos, ETHOS_UART,
+            ETHOS_BAUDRATE, _inbuf, sizeof(_inbuf));
+
+    /* initialize netdev2<->gnrc adapter state */
+    gnrc_netdev2_eth_init(&_gnrc_ethos, (netdev2_t*)&ethos);
+
+    /* start gnrc netdev2 thread */
+    gnrc_netdev2_init(_netdev2_eth_stack, MAC_STACKSIZE,
+            MAC_PRIO, "gnrc_ethos", &_gnrc_ethos);
+}
+
+#else
+typedef int dont_be_pedantic;
+#endif /* MODULE_ETHOS */
+/** @} */
diff --git a/sys/uart_stdio/uart_stdio.c b/sys/uart_stdio/uart_stdio.c
index 3564e42add17636038bf3b06a088bee3fdf6ad5c..0fcbd0f4213cb8688bb13094a8cfc2f40a1373eb 100644
--- a/sys/uart_stdio/uart_stdio.c
+++ b/sys/uart_stdio/uart_stdio.c
@@ -33,6 +33,11 @@
 #include "board.h"
 #include "periph/uart.h"
 
+#ifdef USE_ETHOS_FOR_STDIO
+#include "ethos.h"
+extern ethos_t ethos;
+#endif
+
 #define ENABLE_DEBUG 0
 #include "debug.h"
 
@@ -67,7 +72,11 @@ void uart_stdio_rx_cb(void *arg, char data)
 
 void uart_stdio_init(void)
 {
+#ifndef USE_ETHOS_FOR_STDIO
     uart_init(STDIO, STDIO_BAUDRATE, uart_stdio_rx_cb, NULL);
+#else
+    uart_init(ETHOS_UART, ETHOS_BAUDRATE, uart_stdio_rx_cb, NULL);
+#endif
 }
 
 int uart_stdio_read(char* buffer, int count)
@@ -81,6 +90,10 @@ int uart_stdio_read(char* buffer, int count)
 
 int uart_stdio_write(const char* buffer, int len)
 {
+#ifndef USE_ETHOS_FOR_STDIO
     uart_write(STDIO, (uint8_t *)buffer, (size_t)len);
+#else
+    ethos_send_frame(&ethos, (uint8_t*)buffer, len, ETHOS_FRAME_TYPE_TEXT);
+#endif
     return len;
 }