diff --git a/Makefile.dep b/Makefile.dep
index 015db06ffb64081ec2749c04dcd12079d7925402..553b16894cd096884f779df20b992e23f4af7b70 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -12,6 +12,10 @@ ifneq (,$(filter nhdp,$(USEMODULE)))
   USEMODULE += oonf_rfc5444
 endif
 
+ifneq (,$(filter at86rf2%,$(USEMODULE)))
+  USEMODULE += netdev2_ieee802154
+endif
+
 ifneq (,$(filter netdev2_ieee802154,$(USEMODULE)))
   USEMODULE += ieee802154
 endif
diff --git a/boards/fox/Makefile.dep b/boards/fox/Makefile.dep
index cb47b51f4c62670889ebc544732edc2c59346e09..1a15e53a2e5a75fe39079c8976b2df2233b9ed0c 100644
--- a/boards/fox/Makefile.dep
+++ b/boards/fox/Makefile.dep
@@ -1,6 +1,6 @@
 ifneq (,$(filter gnrc_netif_default,$(USEMODULE)))
   USEMODULE += at86rf231
-  USEMODULE += gnrc_nomac
+  USEMODULE += gnrc_netdev2
 endif
 
 ifneq (,$(filter saul_default,$(USEMODULE)))
diff --git a/boards/iotlab-m3/Makefile.dep b/boards/iotlab-m3/Makefile.dep
index 76e00fddaec989beb9f76acd91a15192b24d362e..92db731b1c93ae87c3d733eded296b8b26d754c3 100644
--- a/boards/iotlab-m3/Makefile.dep
+++ b/boards/iotlab-m3/Makefile.dep
@@ -1,6 +1,6 @@
 ifneq (,$(filter gnrc_netif_default,$(USEMODULE)))
   USEMODULE += at86rf231
-  USEMODULE += gnrc_nomac
+  USEMODULE += gnrc_netdev2
 endif
 
 ifneq (,$(filter saul_default,$(USEMODULE)))
diff --git a/boards/mulle/Makefile.dep b/boards/mulle/Makefile.dep
index b5b923ea7633d4a78f80586088d360c9d51e8254..cc3714b7c951a8d94b02bc2200b6962411fb8b2f 100644
--- a/boards/mulle/Makefile.dep
+++ b/boards/mulle/Makefile.dep
@@ -1,6 +1,6 @@
 ifneq (,$(filter gnrc_netif_default,$(USEMODULE)))
   USEMODULE += at86rf212b
-  USEMODULE += gnrc_nomac
+  USEMODULE += gnrc_netdev2
 endif
 
 ifneq (,$(filter saul_default,$(USEMODULE)))
diff --git a/boards/samr21-xpro/Makefile.dep b/boards/samr21-xpro/Makefile.dep
index a69aeffd63ee22fdc4aa816b46356a93d76d7393..874b4f2a5e38d5c33b0b994bf2ca9b3bfa160685 100644
--- a/boards/samr21-xpro/Makefile.dep
+++ b/boards/samr21-xpro/Makefile.dep
@@ -1,6 +1,6 @@
 ifneq (,$(filter gnrc_netif_default,$(USEMODULE)))
   USEMODULE += at86rf233
-  USEMODULE += gnrc_nomac
+  USEMODULE += gnrc_netdev2
 endif
 
 ifneq (,$(filter saul_default,$(USEMODULE)))
diff --git a/drivers/at86rf2xx/at86rf2xx.c b/drivers/at86rf2xx/at86rf2xx.c
index ec7ef6f1367e54fbec57ff0e8d7f545afb44c753..4b9159228d68eddc70f5863cff9b552f3b472d78 100644
--- a/drivers/at86rf2xx/at86rf2xx.c
+++ b/drivers/at86rf2xx/at86rf2xx.c
@@ -35,22 +35,13 @@
 #include "debug.h"
 
 
-static void _irq_handler(void *arg)
+void at86rf2xx_setup(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
+                     gpio_t cs_pin, gpio_t int_pin, gpio_t sleep_pin,
+                     gpio_t reset_pin)
 {
-    msg_t msg;
-    at86rf2xx_t *dev = (at86rf2xx_t *) arg;
-
-    /* tell driver thread about the interrupt */
-    msg.type = GNRC_NETDEV_MSG_TYPE_EVENT;
-    msg_send(&msg, dev->mac_pid);
-}
-
-int at86rf2xx_init(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
-                   gpio_t cs_pin, gpio_t int_pin,
-                   gpio_t sleep_pin, gpio_t reset_pin)
-{
-    dev->driver = &at86rf2xx_driver;
+    netdev2_t *netdev = (netdev2_t *)dev;
 
+    netdev->driver = &at86rf2xx_driver;
     /* initialize device descriptor */
     dev->spi = spi;
     dev->cs_pin = cs_pin;
@@ -59,32 +50,8 @@ int at86rf2xx_init(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
     dev->reset_pin = reset_pin;
     dev->idle_state = AT86RF2XX_STATE_TRX_OFF;
     dev->state = AT86RF2XX_STATE_SLEEP;
-
     /* initialise SPI */
     spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, spi_speed);
-    /* initialise GPIOs */
-    gpio_init(dev->cs_pin, GPIO_OUT);
-    gpio_set(dev->cs_pin);
-    gpio_init(dev->sleep_pin, GPIO_OUT);
-    gpio_clear(dev->sleep_pin);
-    gpio_init(dev->reset_pin, GPIO_OUT);
-    gpio_set(dev->reset_pin);
-    gpio_init_int(dev->int_pin, GPIO_IN, GPIO_RISING, _irq_handler, dev);
-
-    /* make sure device is not sleeping, so we can query part number */
-    at86rf2xx_assert_awake(dev);
-
-    /* test if the SPI is set up correctly and the device is responding */
-    if (at86rf2xx_reg_read(dev, AT86RF2XX_REG__PART_NUM) !=
-        AT86RF2XX_PARTNUM) {
-        DEBUG("[at86rf2xx] error: unable to read correct part number\n");
-        return -1;
-    }
-
-    /* reset device to default values and put it into RX state */
-    at86rf2xx_reset(dev);
-
-    return 0;
 }
 
 void at86rf2xx_reset(at86rf2xx_t *dev)
@@ -100,8 +67,8 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
     at86rf2xx_reset_state_machine(dev);
 
     /* reset options and sequence number */
-    dev->seq_nr = 0;
-    dev->options = 0;
+    dev->netdev.seq = 0;
+    dev->netdev.flags = 0;
     /* set short and long address */
 #if CPUID_LEN
     cpuid_get(cpuid);
@@ -134,15 +101,16 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
     /* set default TX power */
     at86rf2xx_set_txpower(dev, AT86RF2XX_DEFAULT_TXPOWER);
     /* set default options */
+    at86rf2xx_set_option(dev, NETDEV2_IEEE802154_PAN_COMP, true);
     at86rf2xx_set_option(dev, AT86RF2XX_OPT_AUTOACK, true);
     at86rf2xx_set_option(dev, AT86RF2XX_OPT_CSMA, true);
     at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_START, false);
     at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_END, true);
     /* set default protocol */
 #ifdef MODULE_GNRC_SIXLOWPAN
-    dev->proto = GNRC_NETTYPE_SIXLOWPAN;
-#else
-    dev->proto = GNRC_NETTYPE_UNDEF;
+    dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN;
+#elif MODULE_GNRC
+    dev->netdev.proto = GNRC_NETTYPE_UNDEF;
 #endif
     /* enable safe mode (protect RX FIFO until reading data starts) */
     at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2,
@@ -219,39 +187,42 @@ void at86rf2xx_tx_prepare(at86rf2xx_t *dev)
     /* make sure ongoing transmissions are finished */
     do {
         state = at86rf2xx_get_status(dev);
-    }
-    while (state == AT86RF2XX_STATE_BUSY_RX_AACK ||
-           state == AT86RF2XX_STATE_BUSY_TX_ARET);
+    } while (state == AT86RF2XX_STATE_BUSY_RX_AACK ||
+             state == AT86RF2XX_STATE_BUSY_TX_ARET);
     if (state != AT86RF2XX_STATE_TX_ARET_ON) {
         dev->idle_state = state;
     }
     at86rf2xx_set_state(dev, AT86RF2XX_STATE_TX_ARET_ON);
-    dev->frame_len = IEEE802154_FCS_LEN;
+    dev->tx_frame_len = IEEE802154_FCS_LEN;
 }
 
 size_t at86rf2xx_tx_load(at86rf2xx_t *dev, uint8_t *data,
                          size_t len, size_t offset)
 {
-    dev->frame_len += (uint8_t)len;
+    dev->tx_frame_len += (uint8_t)len;
     at86rf2xx_sram_write(dev, offset + 1, data, len);
     return offset + len;
 }
 
 void at86rf2xx_tx_exec(at86rf2xx_t *dev)
 {
+    netdev2_t *netdev = (netdev2_t *)dev;
+
     /* write frame length field in FIFO */
-    at86rf2xx_sram_write(dev, 0, &(dev->frame_len), 1);
+    at86rf2xx_sram_write(dev, 0, &(dev->tx_frame_len), 1);
     /* trigger sending of pre-loaded frame */
     at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_STATE,
                         AT86RF2XX_TRX_STATE__TX_START);
-    if (dev->event_cb && (dev->options & AT86RF2XX_OPT_TELL_TX_START)) {
-        dev->event_cb(NETDEV_EVENT_TX_STARTED, NULL);
+    if (netdev->event_callback &&
+        (dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_START)) {
+        netdev->event_callback(netdev, NETDEV2_EVENT_TX_STARTED, NULL);
     }
 }
 
 size_t at86rf2xx_rx_len(at86rf2xx_t *dev)
 {
     uint8_t phr;
+
     at86rf2xx_fb_read(dev, &phr, 1);
 
     /* ignore MSB (refer p.80) and substract length of FCS field */
diff --git a/drivers/at86rf2xx/at86rf2xx_getset.c b/drivers/at86rf2xx/at86rf2xx_getset.c
index 57578eeccc1be61e55fb89a8b7552ec6d3975d0f..4fb4ae5d97d1ca977a438862be9b049c7f26bd4a 100644
--- a/drivers/at86rf2xx/at86rf2xx_getset.c
+++ b/drivers/at86rf2xx/at86rf2xx_getset.c
@@ -94,22 +94,22 @@ static const uint8_t dbm_to_tx_pow[] = {0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e,
 
 uint16_t at86rf2xx_get_addr_short(at86rf2xx_t *dev)
 {
-    return (dev->addr_short[0] << 8) | dev->addr_short[1];
+    return (dev->netdev.short_addr[0] << 8) | dev->netdev.short_addr[1];
 }
 
 void at86rf2xx_set_addr_short(at86rf2xx_t *dev, uint16_t addr)
 {
-    dev->addr_short[0] = addr >> 8;
-    dev->addr_short[1] = addr;
+    dev->netdev.short_addr[0] = (uint8_t)(addr);
+    dev->netdev.short_addr[1] = (uint8_t)(addr >> 8);
 #ifdef MODULE_SIXLOWPAN
     /* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to
      * 0 for unicast addresses */
-    dev->addr_short[1] &= 0x7F;
+    dev->netdev.short_addr[0] &= 0x7F;
 #endif
     at86rf2xx_reg_write(dev, AT86RF2XX_REG__SHORT_ADDR_0,
-                        dev->addr_short[0]);
+                        dev->netdev.short_addr[1]);
     at86rf2xx_reg_write(dev, AT86RF2XX_REG__SHORT_ADDR_1,
-                        dev->addr_short[1]);
+                        dev->netdev.short_addr[0]);
 }
 
 uint64_t at86rf2xx_get_addr_long(at86rf2xx_t *dev)
@@ -117,7 +117,7 @@ uint64_t at86rf2xx_get_addr_long(at86rf2xx_t *dev)
     uint64_t addr;
     uint8_t *ap = (uint8_t *)(&addr);
     for (int i = 0; i < 8; i++) {
-        ap[i] = dev->addr_long[7 - i];
+        ap[i] = dev->netdev.long_addr[i];
     }
     return addr;
 }
@@ -125,26 +125,26 @@ uint64_t at86rf2xx_get_addr_long(at86rf2xx_t *dev)
 void at86rf2xx_set_addr_long(at86rf2xx_t *dev, uint64_t addr)
 {
     for (int i = 0; i < 8; i++) {
-        dev->addr_long[i] = (addr >> ((7 - i) * 8));
+        dev->netdev.long_addr[i] = (uint8_t)(addr >> (i * 8));
         at86rf2xx_reg_write(dev, (AT86RF2XX_REG__IEEE_ADDR_0 + i),
-                            dev->addr_long[i]);
+                            (addr >> ((7 - i) * 8)));
     }
 }
 
 uint8_t at86rf2xx_get_chan(at86rf2xx_t *dev)
 {
-    return dev->chan;
+    return dev->netdev.chan;
 }
 
 void at86rf2xx_set_chan(at86rf2xx_t *dev, uint8_t channel)
 {
     if ((channel < AT86RF2XX_MIN_CHANNEL) ||
         (channel > AT86RF2XX_MAX_CHANNEL) ||
-        (dev->chan == channel)) {
+        (dev->netdev.chan == channel)) {
         return;
     }
 
-    dev->chan = channel;
+    dev->netdev.chan = channel;
 
     at86rf2xx_configure_phy(dev);
 }
@@ -172,15 +172,16 @@ void at86rf2xx_set_page(at86rf2xx_t *dev, uint8_t page)
 
 uint16_t at86rf2xx_get_pan(at86rf2xx_t *dev)
 {
-    return dev->pan;
+    return dev->netdev.pan;
 }
 
 void at86rf2xx_set_pan(at86rf2xx_t *dev, uint16_t pan)
 {
-    dev->pan = pan;
-    DEBUG("pan0: %u, pan1: %u\n", (uint8_t)pan, pan >> 8);
-    at86rf2xx_reg_write(dev, AT86RF2XX_REG__PAN_ID_0, (uint8_t)pan);
-    at86rf2xx_reg_write(dev, AT86RF2XX_REG__PAN_ID_1, (pan >> 8));
+    le_uint16_t le_pan = byteorder_btols(byteorder_htons(pan));
+    dev->netdev.pan = pan;
+    DEBUG("pan0: %u, pan1: %u\n", le_pan.u8[0], le_pan.u8[1]);
+    at86rf2xx_reg_write(dev, AT86RF2XX_REG__PAN_ID_0, le_pan.u8[0]);
+    at86rf2xx_reg_write(dev, AT86RF2XX_REG__PAN_ID_1, le_pan.u8[1]);
 }
 
 int16_t at86rf2xx_get_txpower(at86rf2xx_t *dev)
@@ -188,7 +189,7 @@ int16_t at86rf2xx_get_txpower(at86rf2xx_t *dev)
 #ifdef MODULE_AT86RF212B
     uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR);
     DEBUG("txpower value: %x\n", txpower);
-    return _tx_pow_to_dbm_212b(dev->chan, dev->page, txpower);
+    return _tx_pow_to_dbm_212b(dev->netdev.chan, dev->page, txpower);
 #else
     uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR)
                 & AT86RF2XX_PHY_TX_PWR_MASK__TX_PWR;
@@ -220,11 +221,11 @@ void at86rf2xx_set_txpower(at86rf2xx_t *dev, int16_t txpower)
 #endif
     }
 #ifdef MODULE_AT86RF212B
-    if (dev->chan == 0) {
+    if (dev->netdev.chan == 0) {
         at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
                             dbm_to_tx_pow_868[txpower]);
     }
-    else if (dev->chan < 11) {
+    else if (dev->netdev.chan < 11) {
         at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
                             dbm_to_tx_pow_915[txpower]);
     }
@@ -331,14 +332,14 @@ void at86rf2xx_set_option(at86rf2xx_t *dev, uint16_t option, bool state)
 
     /* set option field */
     if (state) {
-        dev->options |= option;
+        dev->netdev.flags |= option;
         /* trigger option specific actions */
         switch (option) {
             case AT86RF2XX_OPT_CSMA:
                 DEBUG("[at86rf2xx] opt: enabling CSMA mode" \
                       "(4 retries, min BE: 3 max BE: 5)\n");
                 /* Initialize CSMA seed with hardware address */
-                at86rf2xx_set_csma_seed(dev, dev->addr_long);
+                at86rf2xx_set_csma_seed(dev, dev->netdev.long_addr);
                 at86rf2xx_set_csma_max_retries(dev, 4);
                 at86rf2xx_set_csma_backoff_exp(dev, 3, 5);
                 break;
@@ -371,7 +372,7 @@ void at86rf2xx_set_option(at86rf2xx_t *dev, uint16_t option, bool state)
         }
     }
     else {
-        dev->options &= ~(option);
+        dev->netdev.flags &= ~(option);
         /* trigger option specific actions */
         switch (option) {
             case AT86RF2XX_OPT_CSMA:
@@ -386,7 +387,7 @@ void at86rf2xx_set_option(at86rf2xx_t *dev, uint16_t option, bool state)
                 tmp &= ~(AT86RF2XX_XAH_CTRL_1__AACK_PROM_MODE);
                 at86rf2xx_reg_write(dev, AT86RF2XX_REG__XAH_CTRL_1, tmp);
                 /* re-enable AUTOACK only if the option is set */
-                if (dev->options & AT86RF2XX_OPT_AUTOACK) {
+                if (dev->netdev.flags & AT86RF2XX_OPT_AUTOACK) {
                     tmp = at86rf2xx_reg_read(dev,
                                              AT86RF2XX_REG__CSMA_SEED_1);
                     tmp &= ~(AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK);
diff --git a/drivers/at86rf2xx/at86rf2xx_internal.c b/drivers/at86rf2xx/at86rf2xx_internal.c
index 3a640ea04b74bf39ecb043e4c1c196aab18ea693..11c78bd51135ea6e631704706e49a06f98564b30 100644
--- a/drivers/at86rf2xx/at86rf2xx_internal.c
+++ b/drivers/at86rf2xx/at86rf2xx_internal.c
@@ -173,7 +173,7 @@ void at86rf2xx_configure_phy(at86rf2xx_t *dev)
     /* Clear previous configuration for GC_TX_OFFS */
     rf_ctrl0 &= ~AT86RF2XX_RF_CTRL_0_MASK__GC_TX_OFFS;
 
-    if (dev->chan != 0) {
+    if (dev->netdev.chan != 0) {
         /* Set sub mode bit on 915 MHz as recommended by the data sheet */
         trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__SUB_MODE;
     }
@@ -199,7 +199,7 @@ void at86rf2xx_configure_phy(at86rf2xx_t *dev)
     phy_cc_cca &= ~(AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
 
     /* Update the channel register */
-    phy_cc_cca |= (dev->chan & AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
+    phy_cc_cca |= (dev->netdev.chan & AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
     at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, phy_cc_cca);
 
 #ifdef MODULE_AT86RF212B
diff --git a/drivers/at86rf2xx/at86rf2xx_netdev.c b/drivers/at86rf2xx/at86rf2xx_netdev.c
index 6909a2f3da1c00aa317db6412d2834bce8ea3a2d..488ed33d25d8c43da8ecc1aadf64ea00dc32636b 100644
--- a/drivers/at86rf2xx/at86rf2xx_netdev.c
+++ b/drivers/at86rf2xx/at86rf2xx_netdev.c
@@ -16,13 +16,19 @@
  * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
  * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  * @author      Kévin Roussel <Kevin.Roussel@inria.fr>
+ * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
  *
  * @}
  */
 
+#include <assert.h>
+#include <errno.h>
+
 #include "net/eui64.h"
 #include "net/ieee802154.h"
-#include "net/gnrc.h"
+#include "net/netdev2.h"
+#include "net/netdev2/ieee802154.h"
+
 #include "at86rf2xx.h"
 #include "at86rf2xx_netdev.h"
 #include "at86rf2xx_internal.h"
@@ -33,243 +39,92 @@
 
 #define _MAX_MHR_OVERHEAD   (25)
 
-/* TODO: generalize and move to (gnrc_)ieee802154 */
-static size_t _make_data_frame_hdr(at86rf2xx_t *dev, uint8_t *buf,
-                                   gnrc_netif_hdr_t *hdr)
-{
-    int pos = 0;
+static int _send(netdev2_t *netdev, const struct iovec *vector, int count);
+static int _recv(netdev2_t *netdev, char *buf, int len, void *info);
+static int _init(netdev2_t *netdev);
+static void _isr(netdev2_t *netdev);
+static int _get(netdev2_t *netdev, netopt_t opt, void *val, size_t max_len);
+static int _set(netdev2_t *netdev, netopt_t opt, void *val, size_t len);
+
+const netdev2_driver_t at86rf2xx_driver = {
+    .send = _send,
+    .recv = _recv,
+    .init = _init,
+    .isr = _isr,
+    .get = _get,
+    .set = _set,
+};
 
-    /* we are building a data frame here */
-    buf[0] = IEEE802154_FCF_TYPE_DATA;
-    buf[1] = IEEE802154_FCF_VERS_V1;
+static void _irq_handler(void *arg)
+{
+    netdev2_t *dev = (netdev2_t *) arg;
 
-    /* if AUTOACK is enabled, then we also expect ACKs for this packet */
-    if (!(hdr->flags & GNRC_NETIF_HDR_FLAGS_BROADCAST) &&
-        !(hdr->flags & GNRC_NETIF_HDR_FLAGS_MULTICAST) &&
-        (dev->options & AT86RF2XX_OPT_AUTOACK)) {
-        buf[0] |= IEEE802154_FCF_ACK_REQ;
+    if (dev->event_callback) {
+        dev->event_callback(dev, NETDEV2_EVENT_ISR, NULL);
     }
+}
 
-    /* fill in destination PAN ID */
-    pos = 3;
-    buf[pos++] = (uint8_t)((dev->pan) & 0xff);
-    buf[pos++] = (uint8_t)((dev->pan) >> 8);
-
-    /* fill in destination address */
-    if (hdr->flags &
-        (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
-        buf[1] |= IEEE802154_FCF_DST_ADDR_SHORT;
-        buf[pos++] = 0xff;
-        buf[pos++] = 0xff;
-    }
-    else if (hdr->dst_l2addr_len == 2) {
-        uint8_t *dst_addr = gnrc_netif_hdr_get_dst_addr(hdr);
-        buf[1] |= IEEE802154_FCF_DST_ADDR_SHORT;
-        buf[pos++] = dst_addr[1];
-        buf[pos++] = dst_addr[0];
-    }
-    else if (hdr->dst_l2addr_len == 8) {
-        buf[1] |= IEEE802154_FCF_DST_ADDR_LONG;
-        uint8_t *dst_addr = gnrc_netif_hdr_get_dst_addr(hdr);
-        for (int i = 7;  i >= 0; i--) {
-            buf[pos++] = dst_addr[i];
-        }
-    }
-    else {
-        /* unsupported address length */
-        return 0;
-    }
+static int _init(netdev2_t *netdev)
+{
+    at86rf2xx_t *dev = (at86rf2xx_t *)netdev;
 
-    /* fill in source PAN ID (if applicable */
-    if (dev->options & AT86RF2XX_OPT_USE_SRC_PAN) {
-        buf[pos++] = (uint8_t)((dev->pan) & 0xff);
-        buf[pos++] = (uint8_t)((dev->pan) >> 8);
-    } else {
-        buf[0] |= IEEE802154_FCF_PAN_COMP;
-    }
+    /* initialise GPIOs */
+    gpio_init(dev->cs_pin, GPIO_OUT);
+    gpio_set(dev->cs_pin);
+    gpio_init(dev->sleep_pin, GPIO_OUT);
+    gpio_clear(dev->sleep_pin);
+    gpio_init(dev->reset_pin, GPIO_OUT);
+    gpio_set(dev->reset_pin);
+    gpio_init_int(dev->int_pin, GPIO_IN, GPIO_RISING, _irq_handler, dev);
 
-    /* fill in source address */
-    if (dev->options & AT86RF2XX_OPT_SRC_ADDR_LONG) {
-        buf[1] |= IEEE802154_FCF_SRC_ADDR_LONG;
-        memcpy(&(buf[pos]), dev->addr_long, 8);
-        pos += 8;
-    }
-    else {
-        buf[1] |= IEEE802154_FCF_SRC_ADDR_SHORT;
-        buf[pos++] = dev->addr_short[0];
-        buf[pos++] = dev->addr_short[1];
-    }
+    /* make sure device is not sleeping, so we can query part number */
+    at86rf2xx_assert_awake(dev);
 
-    /* set sequence number */
-    buf[2] = dev->seq_nr++;
-    /* return actual header length */
-    return pos;
-}
+    /* test if the SPI is set up correctly and the device is responding */
+    if (at86rf2xx_reg_read(dev, AT86RF2XX_REG__PART_NUM) !=
+        AT86RF2XX_PARTNUM) {
+        DEBUG("[at86rf2xx] error: unable to read correct part number\n");
+        return -1;
+    }
 
-/* TODO: generalize and move to ieee802154 */
-/* TODO: include security header implications */
-static size_t _get_frame_hdr_len(uint8_t *mhr)
-{
-    uint8_t tmp;
-    size_t len = 3;
+    /* reset device to default values and put it into RX state */
+    at86rf2xx_reset(dev);
 
-    /* figure out address sizes */
-    tmp = (mhr[1] & IEEE802154_FCF_DST_ADDR_MASK);
-    if (tmp == IEEE802154_FCF_DST_ADDR_SHORT) {
-        len += 4;
-    }
-    else if (tmp == IEEE802154_FCF_DST_ADDR_LONG) {
-        len += 10;
-    }
-    else if (tmp != IEEE802154_FCF_DST_ADDR_VOID) {
-        return 0;
-    }
-    tmp = (mhr[1] & IEEE802154_FCF_SRC_ADDR_MASK);
-    if (tmp == IEEE802154_FCF_SRC_ADDR_VOID) {
-        return len;
-    }
-    else {
-        if (!(mhr[0] & IEEE802154_FCF_PAN_COMP)) {
-            len += 2;
-        }
-        if (tmp == IEEE802154_FCF_SRC_ADDR_SHORT) {
-            return (len + 2);
-        }
-        else if (tmp == IEEE802154_FCF_SRC_ADDR_LONG) {
-            return (len + 8);
-        }
-    }
     return 0;
 }
 
-/* TODO: generalize and move to (gnrc_)ieee802154 */
-static gnrc_pktsnip_t *_make_netif_hdr(uint8_t *mhr)
-{
-    uint8_t tmp;
-    uint8_t *addr;
-    uint8_t src_len, dst_len;
-    gnrc_pktsnip_t *snip;
-    gnrc_netif_hdr_t *hdr;
-
-    /* figure out address sizes */
-    tmp = mhr[1] & IEEE802154_FCF_SRC_ADDR_MASK;
-    if (tmp == IEEE802154_FCF_SRC_ADDR_SHORT) {
-        src_len = 2;
-    }
-    else if (tmp == IEEE802154_FCF_SRC_ADDR_LONG) {
-        src_len = 8;
-    }
-    else if (tmp == IEEE802154_FCF_SRC_ADDR_VOID) {
-        src_len = 0;
-    }
-    else {
-        return NULL;
-    }
-    tmp = mhr[1] & IEEE802154_FCF_DST_ADDR_MASK;
-    if (tmp == IEEE802154_FCF_DST_ADDR_SHORT) {
-        dst_len = 2;
-    }
-    else if (tmp == IEEE802154_FCF_DST_ADDR_LONG) {
-        dst_len = 8;
-    }
-    else if (tmp == IEEE802154_FCF_DST_ADDR_VOID) {
-        dst_len = 0;
-    }
-    else {
-        return NULL;
-    }
-    /* allocate space for header */
-    snip = gnrc_pktbuf_add(NULL, NULL, sizeof(gnrc_netif_hdr_t) + src_len + dst_len,
-                           GNRC_NETTYPE_NETIF);
-    if (snip == NULL) {
-        return NULL;
-    }
-    /* fill header */
-    hdr = (gnrc_netif_hdr_t *)snip->data;
-    gnrc_netif_hdr_init(hdr, src_len, dst_len);
-    if (dst_len > 0) {
-        hdr->flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST;
-        tmp = 5 + dst_len;
-        addr = gnrc_netif_hdr_get_dst_addr(hdr);
-        for (int i = 0; i < dst_len; i++) {
-            addr[i] = mhr[5 + (dst_len - i) - 1];
-            if(addr[i] != 0xff) {
-                hdr->flags &= ~(GNRC_NETIF_HDR_FLAGS_BROADCAST);
-            }
-        }
-    }
-    else {
-        tmp = 3;
-    }
-    if (!(mhr[0] & IEEE802154_FCF_PAN_COMP)) {
-        tmp += 2;
-    }
-    if (src_len > 0) {
-        addr = gnrc_netif_hdr_get_src_addr(hdr);
-        for (int i = 0; i < src_len; i++) {
-            addr[i] = mhr[tmp + (src_len - i) - 1];
-        }
-    }
-    return snip;
-}
-
-
-static int _send(gnrc_netdev_t *netdev, gnrc_pktsnip_t *pkt)
+static int _send(netdev2_t *netdev, const struct iovec *vector, int count)
 {
     at86rf2xx_t *dev = (at86rf2xx_t *)netdev;
-    gnrc_pktsnip_t *snip;
-    uint8_t mhr[IEEE802154_MAX_HDR_LEN];
-    size_t len;
-
-    if (pkt == NULL) {
-        return -ENOMSG;
-    }
-    if (dev == NULL) {
-        gnrc_pktbuf_release(pkt);
-        return -ENODEV;
-    }
-
-    /* create 802.15.4 header */
-    len = _make_data_frame_hdr(dev, mhr, (gnrc_netif_hdr_t *)pkt->data);
-    if (len == 0) {
-        DEBUG("[at86rf2xx] error: unable to create 802.15.4 header\n");
-        gnrc_pktbuf_release(pkt);
-        return -ENOMSG;
-    }
-    /* check if packet (header + payload + FCS) fits into FIFO */
-    snip = pkt->next;
-    if ((gnrc_pkt_len(snip) + len + 2) > AT86RF2XX_MAX_PKT_LENGTH) {
-        printf("[at86rf2xx] error: packet too large (%u byte) to be send\n",
-               gnrc_pkt_len(snip) + len + 2);
-        gnrc_pktbuf_release(pkt);
-        return -EOVERFLOW;
-    }
+    const struct iovec *ptr = vector;
+    size_t len = 0;
 
     at86rf2xx_tx_prepare(dev);
-    /* put header into FIFO */
-    len = at86rf2xx_tx_load(dev, mhr, len, 0);
+
     /* load packet data into FIFO */
-    while (snip) {
-        len = at86rf2xx_tx_load(dev, snip->data, snip->size, len);
-        snip = snip->next;
+    for (int i = 0; i < count; i++, ptr++) {
+        /* current packet data + FCS too long */
+        if ((len + ptr->iov_len + 2) > AT86RF2XX_MAX_PKT_LENGTH) {
+            printf("[at86rf2xx] error: packet too large (%u byte) to be send\n",
+                   (unsigned)len + 2);
+            return -EOVERFLOW;
+        }
+        len = at86rf2xx_tx_load(dev, ptr->iov_base, ptr->iov_len, len);
     }
+
     /* send data out directly if pre-loading id disabled */
-    if (!(dev->options & AT86RF2XX_OPT_PRELOADING)) {
+    if (!(dev->netdev.flags & AT86RF2XX_OPT_PRELOADING)) {
         at86rf2xx_tx_exec(dev);
     }
-    /* release packet */
-    gnrc_pktbuf_release(pkt);
     /* return the number of bytes that were actually send out */
     return (int)len;
 }
 
-static void _receive_data(at86rf2xx_t *dev)
+static int _recv(netdev2_t *netdev, char *buf, int len, void *info)
 {
-    uint8_t mhr[IEEE802154_MAX_HDR_LEN];
+    at86rf2xx_t *dev = (at86rf2xx_t *)netdev;
     uint8_t phr;
-    size_t pkt_len, hdr_len;
-    gnrc_pktsnip_t *hdr, *payload = NULL;
-    gnrc_netif_hdr_t *netif;
+    size_t pkt_len;
 
     /* frame buffer protection will be unlocked as soon as at86rf2xx_fb_stop()
      * is called*/
@@ -281,75 +136,38 @@ static void _receive_data(at86rf2xx_t *dev)
     /* Ignore FCS for packet length */
     pkt_len = phr - 2;
 
-    /* abort here already if no event callback is registered */
-    if (!dev->event_cb) {
-        at86rf2xx_fb_stop(dev);
-        return;
-    }
-
-    /* in raw mode, just read the binary dump into the packet buffer */
-    if (dev->options & AT86RF2XX_OPT_RAWDUMP) {
-        payload = gnrc_pktbuf_add(NULL, NULL, pkt_len, GNRC_NETTYPE_UNDEF);
-        if (payload == NULL ) {
-            at86rf2xx_fb_stop(dev);
-            DEBUG("[at86rf2xx] error: unable to allocate RAW data\n");
-            return;
-        }
-        at86rf2xx_fb_read(dev, payload->data, pkt_len);
-        at86rf2xx_fb_stop(dev);
-        dev->event_cb(NETDEV_EVENT_RX_COMPLETE, payload);
-        return;
-    }
-
-    /* get FCF field and compute 802.15.4 header length */
-    at86rf2xx_fb_read(dev, mhr, 2);
-
-    hdr_len = _get_frame_hdr_len(mhr);
-    if (hdr_len == 0) {
+    /* just return length when buf == NULL */
+    if (buf == NULL) {
         at86rf2xx_fb_stop(dev);
-        DEBUG("[at86rf2xx] error: unable parse incoming frame header\n");
-        return;
+        return pkt_len;
     }
-
-    /* read the rest of the header and parse the netif header from it */
-    at86rf2xx_fb_read(dev, &(mhr[2]), hdr_len - 2);
-    hdr = _make_netif_hdr(mhr);
-    if (hdr == NULL) {
+    /* not enough space in buf */
+    if (pkt_len > len) {
         at86rf2xx_fb_stop(dev);
-        DEBUG("[at86rf2xx] error: unable to allocate netif header\n");
-        return;
-    }
-
-    /* fill missing fields in netif header */
-    netif = (gnrc_netif_hdr_t *)hdr->data;
-    netif->if_pid = dev->mac_pid;
-
-    /* allocate payload */
-    payload = gnrc_pktbuf_add(hdr, NULL, (pkt_len - hdr_len), dev->proto);
-    if (payload == NULL) {
-        at86rf2xx_fb_stop(dev);
-        DEBUG("[at86rf2xx] error: unable to allocate incoming payload\n");
-        gnrc_pktbuf_release(hdr);
-        return;
+        return -ENOBUFS;
     }
     /* copy payload */
-    at86rf2xx_fb_read(dev, payload->data, payload->size);
+    at86rf2xx_fb_read(dev, (uint8_t *)buf, pkt_len);
 
     /* Ignore FCS but advance fb read */
     at86rf2xx_fb_read(dev, NULL, 2);
 
-    at86rf2xx_fb_read(dev, &(netif->lqi), 1);
-
+    if (info != NULL) {
+        netdev2_ieee802154_rx_info_t *radio_info = info;
+        at86rf2xx_fb_read(dev, &(radio_info->lqi), 1);
 #ifndef MODULE_AT86RF231
-    at86rf2xx_fb_read(dev, &(netif->rssi), 1);
-    at86rf2xx_fb_stop(dev);
+        at86rf2xx_fb_read(dev, &(radio_info->rssi), 1);
+        at86rf2xx_fb_stop(dev);
 #else
-    at86rf2xx_fb_stop(dev);
-    netif->rssi = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_ED_LEVEL);
+        at86rf2xx_fb_stop(dev);
+        radio_info->rssi = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_ED_LEVEL);
 #endif
+    }
+    else {
+        at86rf2xx_fb_stop(dev);
+    }
 
-    /* finish up and send data to upper layers */
-    dev->event_cb(NETDEV_EVENT_RX_COMPLETE, payload);
+    return pkt_len;
 }
 
 static int _set_state(at86rf2xx_t *dev, netopt_state_t state)
@@ -362,7 +180,7 @@ static int _set_state(at86rf2xx_t *dev, netopt_state_t state)
             at86rf2xx_set_state(dev, AT86RF2XX_STATE_RX_AACK_ON);
             break;
         case NETOPT_STATE_TX:
-            if (dev->options & AT86RF2XX_OPT_PRELOADING) {
+            if (dev->netdev.flags & AT86RF2XX_OPT_PRELOADING) {
                 at86rf2xx_tx_exec(dev);
             }
             break;
@@ -391,86 +209,16 @@ netopt_state_t _get_state(at86rf2xx_t *dev)
     }
 }
 
-static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
+static int _get(netdev2_t *netdev, netopt_t opt, void *val, size_t max_len)
 {
-    at86rf2xx_t *dev = (at86rf2xx_t *) device;
+    at86rf2xx_t *dev = (at86rf2xx_t *) netdev;
 
-    if (device == NULL) {
+    if (netdev == NULL) {
         return -ENODEV;
     }
 
     /* getting these options doesn't require the transceiver to be responsive */
     switch (opt) {
-
-        case NETOPT_ADDRESS:
-            if (max_len < sizeof(uint16_t)) {
-                return -EOVERFLOW;
-            }
-            *((uint16_t *)val) = at86rf2xx_get_addr_short(dev);
-            return sizeof(uint16_t);
-
-        case NETOPT_ADDRESS_LONG:
-            if (max_len < sizeof(uint64_t)) {
-                return -EOVERFLOW;
-            }
-            *((uint64_t *)val) = at86rf2xx_get_addr_long(dev);
-            return sizeof(uint64_t);
-
-        case NETOPT_ADDR_LEN:
-            if (max_len < sizeof(uint16_t)) {
-                return -EOVERFLOW;
-            }
-            *((uint16_t *)val) = 2;
-            return sizeof(uint16_t);
-
-        case NETOPT_SRC_LEN:
-            if (max_len < sizeof(uint16_t)) {
-                return -EOVERFLOW;
-            }
-            if (dev->options & AT86RF2XX_OPT_SRC_ADDR_LONG) {
-                *((uint16_t *)val) = 8;
-            }
-            else {
-                *((uint16_t *)val) = 2;
-            }
-            return sizeof(uint16_t);
-
-        case NETOPT_NID:
-            if (max_len < sizeof(uint16_t)) {
-                return -EOVERFLOW;
-            }
-            *((uint16_t *)val) = dev->pan;
-            return sizeof(uint16_t);
-
-        case NETOPT_IPV6_IID:
-            if (max_len < sizeof(eui64_t)) {
-                return -EOVERFLOW;
-            }
-            if (dev->options & AT86RF2XX_OPT_SRC_ADDR_LONG) {
-                uint64_t addr = at86rf2xx_get_addr_long(dev);
-                ieee802154_get_iid(val, (uint8_t *)&addr, 8);
-            }
-            else {
-                uint16_t addr = at86rf2xx_get_addr_short(dev);
-                ieee802154_get_iid(val, (uint8_t *)&addr, 2);
-            }
-            return sizeof(eui64_t);
-
-        case NETOPT_PROTO:
-            if (max_len < sizeof(gnrc_nettype_t)) {
-                return -EOVERFLOW;
-            }
-            *((gnrc_nettype_t *)val) = dev->proto;
-            return sizeof(gnrc_nettype_t);
-
-        case NETOPT_CHANNEL:
-            if (max_len < sizeof(uint16_t)) {
-                return -EOVERFLOW;
-            }
-            ((uint8_t *)val)[1] = 0;
-            ((uint8_t *)val)[0] = at86rf2xx_get_chan(dev);
-            return sizeof(uint16_t);
-
         case NETOPT_CHANNEL_PAGE:
             if (max_len < sizeof(uint16_t)) {
                 return -EOVERFLOW;
@@ -490,20 +238,11 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
             if (max_len < sizeof(netopt_state_t)) {
                 return -EOVERFLOW;
             }
-            *((netopt_state_t*)val) = _get_state(dev);
+            *((netopt_state_t *)val) = _get_state(dev);
             return sizeof(netopt_state_t);
 
         case NETOPT_PRELOADING:
-            if (dev->options & AT86RF2XX_OPT_PRELOADING) {
-                *((netopt_enable_t *)val) = NETOPT_ENABLE;
-            }
-            else {
-                *((netopt_enable_t *)val) = NETOPT_DISABLE;
-            }
-            return sizeof(netopt_enable_t);
-
-        case NETOPT_AUTOACK:
-            if (dev->options & AT86RF2XX_OPT_AUTOACK) {
+            if (dev->netdev.flags & AT86RF2XX_OPT_PRELOADING) {
                 *((netopt_enable_t *)val) = NETOPT_ENABLE;
             }
             else {
@@ -512,16 +251,7 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
             return sizeof(netopt_enable_t);
 
         case NETOPT_PROMISCUOUSMODE:
-            if (dev->options & AT86RF2XX_OPT_PROMISCUOUS) {
-                *((netopt_enable_t *)val) = NETOPT_ENABLE;
-            }
-            else {
-                *((netopt_enable_t *)val) = NETOPT_DISABLE;
-            }
-            return sizeof(netopt_enable_t);
-
-        case NETOPT_RAWMODE:
-            if (dev->options & AT86RF2XX_OPT_RAWDUMP) {
+            if (dev->netdev.flags & AT86RF2XX_OPT_PROMISCUOUS) {
                 *((netopt_enable_t *)val) = NETOPT_ENABLE;
             }
             else {
@@ -531,27 +261,27 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
 
         case NETOPT_RX_START_IRQ:
             *((netopt_enable_t *)val) =
-                !!(dev->options & AT86RF2XX_OPT_TELL_RX_START);
+                !!(dev->netdev.flags & AT86RF2XX_OPT_TELL_RX_START);
             return sizeof(netopt_enable_t);
 
         case NETOPT_RX_END_IRQ:
             *((netopt_enable_t *)val) =
-                !!(dev->options & AT86RF2XX_OPT_TELL_RX_END);
+                !!(dev->netdev.flags & AT86RF2XX_OPT_TELL_RX_END);
             return sizeof(netopt_enable_t);
 
         case NETOPT_TX_START_IRQ:
             *((netopt_enable_t *)val) =
-                !!(dev->options & AT86RF2XX_OPT_TELL_TX_START);
+                !!(dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_START);
             return sizeof(netopt_enable_t);
 
         case NETOPT_TX_END_IRQ:
             *((netopt_enable_t *)val) =
-                !!(dev->options & AT86RF2XX_OPT_TELL_TX_END);
+                !!(dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_END);
             return sizeof(netopt_enable_t);
 
         case NETOPT_CSMA:
             *((netopt_enable_t *)val) =
-                !!(dev->options & AT86RF2XX_OPT_CSMA);
+                !!(dev->netdev.flags & AT86RF2XX_OPT_CSMA);
             return sizeof(netopt_enable_t);
 
         default:
@@ -559,12 +289,18 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
             break;
     }
 
+    int res;
+
+    if (((res = netdev2_ieee802154_get((netdev2_ieee802154_t *)netdev, opt, val,
+                                       max_len)) >= 0) || (res != -ENOTSUP)) {
+        return res;
+    }
 
     uint8_t old_state = at86rf2xx_get_status(dev);
-    int res = 0;
+    res = 0;
 
     /* temporarily wake up if sleeping */
-    if(old_state == AT86RF2XX_STATE_SLEEP) {
+    if (old_state == AT86RF2XX_STATE_SLEEP) {
         at86rf2xx_assert_awake(dev);
     }
 
@@ -573,7 +309,8 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
         case NETOPT_TX_POWER:
             if (max_len < sizeof(int16_t)) {
                 res = -EOVERFLOW;
-            } else {
+            }
+            else {
                 *((uint16_t *)val) = at86rf2xx_get_txpower(dev);
                 res = sizeof(uint16_t);
             }
@@ -582,7 +319,8 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
         case NETOPT_RETRANS:
             if (max_len < sizeof(uint8_t)) {
                 res = -EOVERFLOW;
-            } else {
+            }
+            else {
                 *((uint8_t *)val) = at86rf2xx_get_max_retries(dev);
                 res = sizeof(uint8_t);
             }
@@ -601,7 +339,8 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
         case NETOPT_CSMA_RETRIES:
             if (max_len < sizeof(uint8_t)) {
                 res = -EOVERFLOW;
-            } else {
+            }
+            else {
                 *((uint8_t *)val) = at86rf2xx_get_csma_max_retries(dev);
                 res = sizeof(uint8_t);
             }
@@ -610,7 +349,8 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
         case NETOPT_CCA_THRESHOLD:
             if (max_len < sizeof(int8_t)) {
                 res = -EOVERFLOW;
-            } else {
+            }
+            else {
                 *((int8_t *)val) = at86rf2xx_get_cca_threshold(dev);
                 res = sizeof(int8_t);
             }
@@ -621,16 +361,16 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
     }
 
     /* go back to sleep if were sleeping */
-    if(old_state == AT86RF2XX_STATE_SLEEP) {
+    if (old_state == AT86RF2XX_STATE_SLEEP) {
         at86rf2xx_set_state(dev, AT86RF2XX_STATE_SLEEP);
     }
 
     return res;
 }
 
-static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
+static int _set(netdev2_t *netdev, netopt_t opt, void *val, size_t len)
 {
-    at86rf2xx_t *dev = (at86rf2xx_t *) device;
+    at86rf2xx_t *dev = (at86rf2xx_t *) netdev;
     uint8_t old_state = at86rf2xx_get_status(dev);
     int res = 0;
 
@@ -639,7 +379,7 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
     }
 
     /* temporarily wake up if sleeping */
-    if(old_state == AT86RF2XX_STATE_SLEEP) {
+    if (old_state == AT86RF2XX_STATE_SLEEP) {
         at86rf2xx_assert_awake(dev);
     }
 
@@ -647,64 +387,38 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
         case NETOPT_ADDRESS:
             if (len > sizeof(uint16_t)) {
                 res = -EOVERFLOW;
-            } else {
-                at86rf2xx_set_addr_short(dev, *((uint16_t*)val));
-                res = sizeof(uint16_t);
+            }
+            else {
+                at86rf2xx_set_addr_short(dev, *((uint16_t *)val));
+                /* don't set res to set netdev2_ieee802154_t::short_addr */
             }
             break;
 
         case NETOPT_ADDRESS_LONG:
             if (len > sizeof(uint64_t)) {
                 res = -EOVERFLOW;
-            } else {
-                at86rf2xx_set_addr_long(dev, *((uint64_t*)val));
-                res = sizeof(uint64_t);
             }
-            break;
-
-        case NETOPT_SRC_LEN:
-            if (len > sizeof(uint16_t)) {
-                res = -EOVERFLOW;
-            } else {
-                if (*((uint16_t *)val) == 2) {
-                    at86rf2xx_set_option(dev, AT86RF2XX_OPT_SRC_ADDR_LONG,
-                                         false);
-                }
-                else if (*((uint16_t *)val) == 8) {
-                    at86rf2xx_set_option(dev, AT86RF2XX_OPT_SRC_ADDR_LONG,
-                                         true);
-                }
-                else {
-                    res = -ENOTSUP;
-                    break;
-                }
-                res = sizeof(uint16_t);
+            else {
+                at86rf2xx_set_addr_long(dev, *((uint64_t *)val));
+                /* don't set res to set netdev2_ieee802154_t::long_addr */
             }
             break;
 
         case NETOPT_NID:
             if (len > sizeof(uint16_t)) {
                 res = -EOVERFLOW;
-            } else {
-                at86rf2xx_set_pan(dev, *((uint16_t *)val));
-                res = sizeof(uint16_t);
-            }
-            break;
-
-        case NETOPT_PROTO:
-            if (len != sizeof(gnrc_nettype_t)) {
-                res = -EINVAL;
             }
             else {
-                dev->proto = *((gnrc_nettype_t*) val);
-                res = sizeof(gnrc_nettype_t);
+                at86rf2xx_set_pan(dev, *((uint16_t *)val));
+                /* don't set res to set netdev2_ieee802154_t::pan */
             }
             break;
 
         case NETOPT_CHANNEL:
             if (len != sizeof(uint16_t)) {
                 res = -EINVAL;
-            } else {
+            }
+            else {
                 uint8_t chan = ((uint8_t *)val)[0];
                 if (chan < AT86RF2XX_MIN_CHANNEL ||
                     chan > AT86RF2XX_MAX_CHANNEL) {
@@ -712,19 +426,21 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
                     break;
                 }
                 at86rf2xx_set_chan(dev, chan);
-                res = sizeof(uint16_t);
+                /* don't set res to set netdev2_ieee802154_t::chan */
             }
             break;
 
         case NETOPT_CHANNEL_PAGE:
             if (len != sizeof(uint16_t)) {
                 res = -EINVAL;
-            } else {
+            }
+            else {
                 uint8_t page = ((uint8_t *)val)[0];
 #ifdef MODULE_AT86RF212B
                 if ((page != 0) && (page != 2)) {
                     res = -ENOTSUP;
-                } else {
+                }
+                else {
                     at86rf2xx_set_page(dev, page);
                     res = sizeof(uint16_t);
                 }
@@ -732,7 +448,8 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
                 /* rf23x only supports page 0, no need to configure anything in the driver. */
                 if (page != 0) {
                     res = -ENOTSUP;
-                } else {
+                }
+                else {
                     res = sizeof(uint16_t);
                 }
 #endif
@@ -742,7 +459,8 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
         case NETOPT_TX_POWER:
             if (len > sizeof(int16_t)) {
                 res = -EOVERFLOW;
-            } else {
+            }
+            else {
                 at86rf2xx_set_txpower(dev, *((int16_t *)val));
                 res = sizeof(uint16_t);
             }
@@ -751,7 +469,8 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
         case NETOPT_STATE:
             if (len > sizeof(netopt_state_t)) {
                 res = -EOVERFLOW;
-            } else {
+            }
+            else {
                 res = _set_state(dev, *((netopt_state_t *)val));
             }
             break;
@@ -759,13 +478,14 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
         case NETOPT_AUTOACK:
             at86rf2xx_set_option(dev, AT86RF2XX_OPT_AUTOACK,
                                  ((bool *)val)[0]);
-            res = sizeof(netopt_enable_t);
+            /* don't set res to set netdev2_ieee802154_t::flags */
             break;
 
         case NETOPT_RETRANS:
             if (len > sizeof(uint8_t)) {
                 res = -EOVERFLOW;
-            } else {
+            }
+            else {
                 at86rf2xx_set_max_retries(dev, *((uint8_t *)val));
                 res = sizeof(uint8_t);
             }
@@ -783,12 +503,6 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
             res = sizeof(netopt_enable_t);
             break;
 
-        case NETOPT_RAWMODE:
-            at86rf2xx_set_option(dev, AT86RF2XX_OPT_RAWDUMP,
-                                 ((bool *)val)[0]);
-            res = sizeof(netopt_enable_t);
-            break;
-
         case NETOPT_RX_START_IRQ:
             at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_START,
                                  ((bool *)val)[0]);
@@ -815,18 +529,20 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
 
         case NETOPT_CSMA:
             at86rf2xx_set_option(dev, AT86RF2XX_OPT_CSMA,
-                                    ((bool *)val)[0]);
+                                 ((bool *)val)[0]);
             res = sizeof(netopt_enable_t);
             break;
 
         case NETOPT_CSMA_RETRIES:
-            if( (len > sizeof(uint8_t)) ||
-                (*((uint8_t *)val) > 5) ) {
+            if ((len > sizeof(uint8_t)) ||
+                (*((uint8_t *)val) > 5)) {
                 res = -EOVERFLOW;
-            } else if( !(dev->options & AT86RF2XX_OPT_CSMA) ) {
+            }
+            else if (!(dev->netdev.flags & AT86RF2XX_OPT_CSMA)) {
                 /* If CSMA is disabled, don't allow setting retries */
                 res = -ENOTSUP;
-            } else {
+            }
+            else {
                 at86rf2xx_set_csma_max_retries(dev, *((uint8_t *)val));
                 res = sizeof(uint8_t);
             }
@@ -835,7 +551,8 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
         case NETOPT_CCA_THRESHOLD:
             if (len > sizeof(int8_t)) {
                 res = -EOVERFLOW;
-            } else {
+            }
+            else {
                 at86rf2xx_set_cca_threshold(dev, *((int8_t *)val));
                 res = sizeof(int8_t);
             }
@@ -846,44 +563,22 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
     }
 
     /* go back to sleep if were sleeping and state hasn't been changed */
-    if( (old_state == AT86RF2XX_STATE_SLEEP) &&
-        (opt != NETOPT_STATE) ) {
+    if ((old_state == AT86RF2XX_STATE_SLEEP) &&
+        (opt != NETOPT_STATE)) {
         at86rf2xx_set_state(dev, AT86RF2XX_STATE_SLEEP);
     }
 
-    return res;
-}
-
-static int _add_event_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb)
-{
-    if (dev == NULL) {
-        return -ENODEV;
-    }
-    if (dev->event_cb) {
-        return -ENOBUFS;
-    }
-
-    dev->event_cb = cb;
-    return 0;
-}
-
-static int _rem_event_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb)
-{
-    if (dev == NULL) {
-        return -ENODEV;
-    }
-    if (dev->event_cb != cb) {
-        return -ENOENT;
+    if (res == -ENOTSUP) {
+        res = netdev2_ieee802154_set((netdev2_ieee802154_t *)netdev, opt,
+                                     val, len);
     }
 
-    dev->event_cb = NULL;
-    return 0;
+    return res;
 }
 
-static void _isr_event(gnrc_netdev_t *device, uint32_t event_type)
+static void _isr(netdev2_t *netdev)
 {
-    (void) event_type;
-    at86rf2xx_t *dev = (at86rf2xx_t *) device;
+    at86rf2xx_t *dev = (at86rf2xx_t *) netdev;
     uint8_t irq_mask;
     uint8_t state;
     uint8_t trac_status;
@@ -892,28 +587,29 @@ static void _isr_event(gnrc_netdev_t *device, uint32_t event_type)
      * lost anyway, so return immediately.
      */
     state = at86rf2xx_get_status(dev);
-    if(state == AT86RF2XX_STATE_SLEEP)
+    if (state == AT86RF2XX_STATE_SLEEP) {
         return;
+    }
 
     /* read (consume) device status */
     irq_mask = at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
 
     trac_status = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATE) &
-                    AT86RF2XX_TRX_STATE_MASK__TRAC;
+                  AT86RF2XX_TRX_STATE_MASK__TRAC;
 
     if (irq_mask & AT86RF2XX_IRQ_STATUS_MASK__RX_START) {
-        dev->event_cb(NETDEV_EVENT_RX_STARTED, NULL);
+        netdev->event_callback(netdev, NETDEV2_EVENT_RX_STARTED, NULL);
         DEBUG("[at86rf2xx] EVT - RX_START\n");
     }
 
     if (irq_mask & AT86RF2XX_IRQ_STATUS_MASK__TRX_END) {
-        if(state == AT86RF2XX_STATE_RX_AACK_ON ||
-           state == AT86RF2XX_STATE_BUSY_RX_AACK) {
+        if (state == AT86RF2XX_STATE_RX_AACK_ON ||
+            state == AT86RF2XX_STATE_BUSY_RX_AACK) {
             DEBUG("[at86rf2xx] EVT - RX_END\n");
-            if (!(dev->options & AT86RF2XX_OPT_TELL_RX_END)) {
+            if (!(dev->netdev.flags & AT86RF2XX_OPT_TELL_RX_END)) {
                 return;
             }
-            _receive_data(dev);
+            netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE, NULL);
         }
         else if (state == AT86RF2XX_STATE_TX_ARET_ON ||
                  state == AT86RF2XX_STATE_BUSY_TX_ARET) {
@@ -921,35 +617,26 @@ static void _isr_event(gnrc_netdev_t *device, uint32_t event_type)
             DEBUG("[at86rf2xx] EVT - TX_END\n");
             DEBUG("[at86rf2xx] return to state 0x%x\n", dev->idle_state);
 
-            if (dev->event_cb && (dev->options & AT86RF2XX_OPT_TELL_TX_END)) {
-                switch(trac_status) {
-                case AT86RF2XX_TRX_STATE__TRAC_SUCCESS:
-                case AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING:
-                    dev->event_cb(NETDEV_EVENT_TX_COMPLETE, NULL);
-                    DEBUG("[at86rf2xx] TX SUCCESS\n");
-                    break;
-                case AT86RF2XX_TRX_STATE__TRAC_NO_ACK:
-                    dev->event_cb(NETDEV_EVENT_TX_NOACK, NULL);
-                    DEBUG("[at86rf2xx] TX NO_ACK\n");
-                    break;
-                case AT86RF2XX_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE:
-                    dev->event_cb(NETDEV_EVENT_TX_MEDIUM_BUSY, NULL);
-                    DEBUG("[at86rf2xx] TX_CHANNEL_ACCESS_FAILURE\n");
-                    break;
-                default:
-                    DEBUG("[at86rf2xx] Unhandled TRAC_STATUS: %d\n",
-                          trac_status >> 5);
+            if (netdev->event_callback && (dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_END)) {
+                switch (trac_status) {
+                    case AT86RF2XX_TRX_STATE__TRAC_SUCCESS:
+                    case AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING:
+                        netdev->event_callback(netdev, NETDEV2_EVENT_TX_COMPLETE, NULL);
+                        DEBUG("[at86rf2xx] TX SUCCESS\n");
+                        break;
+                    case AT86RF2XX_TRX_STATE__TRAC_NO_ACK:
+                        netdev->event_callback(netdev, NETDEV2_EVENT_TX_NOACK, NULL);
+                        DEBUG("[at86rf2xx] TX NO_ACK\n");
+                        break;
+                    case AT86RF2XX_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE:
+                        netdev->event_callback(netdev, NETDEV2_EVENT_TX_MEDIUM_BUSY, NULL);
+                        DEBUG("[at86rf2xx] TX_CHANNEL_ACCESS_FAILURE\n");
+                        break;
+                    default:
+                        DEBUG("[at86rf2xx] Unhandled TRAC_STATUS: %d\n",
+                              trac_status >> 5);
                 }
             }
         }
     }
 }
-
-const gnrc_netdev_driver_t at86rf2xx_driver = {
-    .send_data = _send,
-    .add_event_callback = _add_event_cb,
-    .rem_event_callback = _rem_event_cb,
-    .get = _get,
-    .set = _set,
-    .isr_event = _isr_event,
-};
diff --git a/drivers/at86rf2xx/include/at86rf2xx_netdev.h b/drivers/at86rf2xx/include/at86rf2xx_netdev.h
index 92a1fdc9953b333a73aea61fa2bef5fcf6fb49c6..7b6e1f18a38af6a929f63002424229fa5c8d7322 100644
--- a/drivers/at86rf2xx/include/at86rf2xx_netdev.h
+++ b/drivers/at86rf2xx/include/at86rf2xx_netdev.h
@@ -19,7 +19,7 @@
 #ifndef AT86RF2XX_NETDEV_H_
 #define AT86RF2XX_NETDEV_H_
 
-#include "net/gnrc/netdev.h"
+#include "net/netdev2.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -28,7 +28,7 @@ extern "C" {
 /**
  * @brief   Reference to the netdev device driver struct
  */
-extern const gnrc_netdev_driver_t at86rf2xx_driver;
+extern const netdev2_driver_t at86rf2xx_driver;
 
 #ifdef __cplusplus
 }
diff --git a/drivers/include/at86rf2xx.h b/drivers/include/at86rf2xx.h
index f2e63d7cb1df0582d6d4055baa14f629ee2b93ec..ede06f710f0567f6b4f40ca3880f3fadcc278118 100644
--- a/drivers/include/at86rf2xx.h
+++ b/drivers/include/at86rf2xx.h
@@ -8,7 +8,7 @@
 
 /**
  * @defgroup    drivers_at86rf2xx AT86RF2xx based drivers
- * @ingroup     drivers_netdev
+ * @ingroup     drivers_netdev_netdev2
  *
  * This module contains drivers for radio devices in Atmel's AT86RF2xx series.
  * The driver is aimed to work with all devices of this series.
@@ -34,7 +34,9 @@
 #include "board.h"
 #include "periph/spi.h"
 #include "periph/gpio.h"
-#include "net/gnrc/netdev.h"
+#include "net/netdev2.h"
+#include "net/netdev2/ieee802154.h"
+#include "net/gnrc/nettype.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -54,9 +56,9 @@ extern "C" {
 /** @} */
 
 /**
-  * @brief   Channel configuration
-  * @{
-  */
+ * @brief   Channel configuration
+ * @{
+ */
 #ifdef MODULE_AT86RF212B
 /* the AT86RF212B has a sub-1GHz radio */
 #define AT86RF2XX_MIN_CHANNEL           (0)
@@ -106,57 +108,54 @@ extern "C" {
 
 /**
  * @brief   Internal device option flags
+ *
+ * `0x00ff` is reserved for general IEEE 802.15.4 flags
+ * (see @ref netdev2_ieee802154_t)
+ *
  * @{
  */
-#define AT86RF2XX_OPT_AUTOACK        (0x0001)       /**< auto ACKs active */
-#define AT86RF2XX_OPT_CSMA           (0x0002)       /**< CSMA active */
-#define AT86RF2XX_OPT_PROMISCUOUS    (0x0004)       /**< promiscuous mode
+#define AT86RF2XX_OPT_SRC_ADDR_LONG  (NETDEV2_IEEE802154_SRC_MODE_LONG) /**< legacy define */
+#define AT86RF2XX_OPT_RAWDUMP        (NETDEV2_IEEE802154_RAW)           /**< legacy define */
+#define AT86RF2XX_OPT_AUTOACK        (NETDEV2_IEEE802154_ACK_REQ)       /**< legacy define */
+
+#define AT86RF2XX_OPT_CSMA           (0x0100)       /**< CSMA active */
+#define AT86RF2XX_OPT_PROMISCUOUS    (0x0200)       /**< promiscuous mode
                                                      *   active */
-#define AT86RF2XX_OPT_PRELOADING     (0x0008)       /**< preloading enabled */
-#define AT86RF2XX_OPT_TELL_TX_START  (0x0010)       /**< notify MAC layer on TX
+#define AT86RF2XX_OPT_PRELOADING     (0x0400)       /**< preloading enabled */
+#define AT86RF2XX_OPT_TELL_TX_START  (0x0800)       /**< notify MAC layer on TX
                                                      *   start */
-#define AT86RF2XX_OPT_TELL_TX_END    (0x0020)       /**< notify MAC layer on TX
+#define AT86RF2XX_OPT_TELL_TX_END    (0x1000)       /**< notify MAC layer on TX
                                                      *   finished */
-#define AT86RF2XX_OPT_TELL_RX_START  (0x0040)       /**< notify MAC layer on RX
+#define AT86RF2XX_OPT_TELL_RX_START  (0x2000)       /**< notify MAC layer on RX
                                                      *   start */
-#define AT86RF2XX_OPT_TELL_RX_END    (0x0080)       /**< notify MAC layer on RX
+#define AT86RF2XX_OPT_TELL_RX_END    (0x4000)       /**< notify MAC layer on RX
                                                      *   finished */
-#define AT86RF2XX_OPT_RAWDUMP        (0x0100)       /**< pass RAW frame data to
-                                                     *   upper layer */
-#define AT86RF2XX_OPT_SRC_ADDR_LONG  (0x0200)       /**< send data using long
-                                                     *   source address */
-#define AT86RF2XX_OPT_USE_SRC_PAN    (0x0400)       /**< do not compress source
-                                                     *   PAN ID */
 /** @} */
 
 /**
  * @brief   Device descriptor for AT86RF2XX radio devices
+ *
+ * @extends netdev2_ieee802154_t
  */
 typedef struct {
-    /* netdev fields */
-    const gnrc_netdev_driver_t *driver; /**< pointer to the devices interface */
-    gnrc_netdev_event_cb_t event_cb;    /**< netdev event callback */
-    kernel_pid_t mac_pid;               /**< the driver's thread's PID */
-    /* device specific fields */
-    spi_t spi;                          /**< used SPI device */
-    gpio_t cs_pin;                      /**< chip select pin */
-    gpio_t sleep_pin;                   /**< sleep pin */
-    gpio_t reset_pin;                   /**< reset pin */
-    gpio_t int_pin;                     /**< external interrupt pin */
-    gnrc_nettype_t proto;               /**< protocol the radio expects */
-    uint8_t state;                      /**< current state of the radio */
-    uint8_t seq_nr;                     /**< sequence number to use next */
-    uint8_t frame_len;                  /**< length of the current TX frame */
-    uint16_t pan;                       /**< currently used PAN ID */
-    uint8_t chan;                       /**< currently used channel number */
+    netdev2_ieee802154_t netdev;            /**< netdev2 parent struct */
+    /**
+     * @brief   device specific fields
+     * @{
+     */
+    spi_t spi;                              /**< used SPI device */
+    gpio_t cs_pin;                          /**< chip select pin */
+    gpio_t sleep_pin;                       /**< sleep pin */
+    gpio_t reset_pin;                       /**< reset pin */
+    gpio_t int_pin;                         /**< external interrupt pin */
+    uint8_t state;                          /**< current state of the radio */
+    uint8_t tx_frame_len;                   /**< length of the current TX frame */
 #ifdef MODULE_AT86RF212B
     /* Only AT86RF212B supports multiple pages (PHY modes) */
     uint8_t page;                       /**< currently used channel page */
 #endif
-    uint8_t addr_short[2];              /**< the radio's short address */
-    uint8_t addr_long[8];               /**< the radio's long address */
-    uint16_t options;                   /**< state of used options */
     uint8_t idle_state;                 /**< state to return to after sending */
+    /** @} */
 } at86rf2xx_t;
 
 /**
@@ -172,7 +171,7 @@ typedef struct at86rf2xx_params {
 } at86rf2xx_params_t;
 
 /**
- * @brief   Initialize a given AT86RF2xx device
+ * @brief   Setup an AT86RF2xx based device state
  *
  * @param[out] dev          device descriptor
  * @param[in] spi           SPI bus the device is connected to
@@ -181,13 +180,10 @@ typedef struct at86rf2xx_params {
  * @param[in] int_pin       GPIO pin connected to the interrupt pin
  * @param[in] sleep_pin     GPIO pin connected to the sleep pin
  * @param[in] reset_pin     GPIO pin connected to the reset pin
- *
- * @return                  0 on success
- * @return                  <0 on error
  */
-int at86rf2xx_init(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
-                   gpio_t cs_pin, gpio_t int_pin,
-                   gpio_t sleep_pin, gpio_t reset_pin);
+void at86rf2xx_setup(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
+                     gpio_t cs_pin, gpio_t int_pin, gpio_t sleep_pin,
+                     gpio_t reset_pin);
 
 /**
  * @brief   Trigger a hardware reset and configure radio with default values
diff --git a/sys/auto_init/netif/auto_init_at86rf2xx.c b/sys/auto_init/netif/auto_init_at86rf2xx.c
index a80ffe3b8a354f640aea5ca84f464f5643a093e8..775d9f9b0651268e293810d7945b474ebbf23f05 100644
--- a/sys/auto_init/netif/auto_init_at86rf2xx.c
+++ b/sys/auto_init/netif/auto_init_at86rf2xx.c
@@ -20,7 +20,8 @@
 #ifdef MODULE_AT86RF2XX
 
 #include "board.h"
-#include "net/gnrc/nomac.h"
+#include "net/gnrc/netdev2.h"
+#include "net/gnrc/netdev2/ieee802154.h"
 #include "net/gnrc.h"
 
 #include "at86rf2xx.h"
@@ -36,32 +37,38 @@
 #define AT86RF2XX_MAC_STACKSIZE     (THREAD_STACKSIZE_DEFAULT)
 #define AT86RF2XX_MAC_PRIO          (THREAD_PRIORITY_MAIN - 4)
 
-#define AT86RF2XX_NUM (sizeof(at86rf2xx_params)/sizeof(at86rf2xx_params[0]))
+#define AT86RF2XX_NUM (sizeof(at86rf2xx_params) / sizeof(at86rf2xx_params[0]))
 
 static at86rf2xx_t at86rf2xx_devs[AT86RF2XX_NUM];
-static char _nomac_stacks[AT86RF2XX_MAC_STACKSIZE][AT86RF2XX_NUM];
+static gnrc_netdev2_t gnrc_adpt[AT86RF2XX_NUM];
+static char _at86rf2xx_stacks[AT86RF2XX_MAC_STACKSIZE][AT86RF2XX_NUM];
 
 void auto_init_at86rf2xx(void)
 {
     for (unsigned i = 0; i < AT86RF2XX_NUM; i++) {
         const at86rf2xx_params_t *p = &at86rf2xx_params[i];
+        int res;
 
         DEBUG("Initializing AT86RF2xx radio at SPI_%i\n", p->spi);
-        int res = at86rf2xx_init(&at86rf2xx_devs[i],
-                                 p->spi,
-                                 p->spi_speed,
-                                 p->cs_pin,
-                                 p->int_pin,
-                                 p->sleep_pin,
-                                 p->reset_pin);
+        at86rf2xx_setup(&at86rf2xx_devs[i],
+                        p->spi,
+                        p->spi_speed,
+                        p->cs_pin,
+                        p->int_pin,
+                        p->sleep_pin,
+                        p->reset_pin);
+        res = gnrc_netdev2_ieee802154_init(&gnrc_adpt[i],
+                                           (netdev2_ieee802154_t *)&at86rf2xx_devs[i]);
 
         if (res < 0) {
             DEBUG("Error initializing AT86RF2xx radio device!\n");
         }
         else {
-            gnrc_nomac_init(_nomac_stacks[i],
-                            AT86RF2XX_MAC_STACKSIZE, AT86RF2XX_MAC_PRIO,
-                            "at86rfxx", (gnrc_netdev_t *)&at86rf2xx_devs[i]);
+            gnrc_netdev2_init(_at86rf2xx_stacks[i],
+                              AT86RF2XX_MAC_STACKSIZE,
+                              AT86RF2XX_MAC_PRIO,
+                              "at86rf2xx",
+                              &gnrc_adpt[i]);
         }
     }
 }
diff --git a/tests/driver_at86rf2xx/Makefile b/tests/driver_at86rf2xx/Makefile
index 03f6c10e65ab98d5a7338024521b2f5688f04b7e..02dc1afe96f43c12db2dca5ad5427e4e7cf3b9f3 100644
--- a/tests/driver_at86rf2xx/Makefile
+++ b/tests/driver_at86rf2xx/Makefile
@@ -3,12 +3,9 @@ include ../Makefile.tests_common
 
 FEATURES_REQUIRED = periph_spi periph_gpio
 
-BOARD_INSUFFICIENT_MEMORY := nucleo-f334 stm32f0discovery weio
+DISABLE_MODULE += auto_init
 
-USEMODULE += auto_init_gnrc_netif
-USEMODULE += gnrc_netif
-USEMODULE += gnrc_nomac
-USEMODULE += gnrc_pktdump
+USEMODULE += od
 USEMODULE += shell
 USEMODULE += shell_commands
 USEMODULE += ps
diff --git a/tests/driver_at86rf2xx/addr.c b/tests/driver_at86rf2xx/addr.c
new file mode 100644
index 0000000000000000000000000000000000000000..af6b0c22611ac887a825385874b99d7331fa2d90
--- /dev/null
+++ b/tests/driver_at86rf2xx/addr.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 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 <stdio.h>
+#include <stdint.h>
+
+#include "common.h"
+
+void print_addr(uint8_t *addr, size_t addr_len)
+{
+    for (int i = 0; i < addr_len; i++) {
+        if (i != 0) {
+            printf(":");
+        }
+        printf("%02x", (unsigned)addr[i]);
+    }
+}
+
+/** @} */
diff --git a/tests/driver_at86rf2xx/cmd.c b/tests/driver_at86rf2xx/cmd.c
new file mode 100644
index 0000000000000000000000000000000000000000..10d44df3f942c54cb08373c4a1c9de20128b41ad
--- /dev/null
+++ b/tests/driver_at86rf2xx/cmd.c
@@ -0,0 +1,306 @@
+/*
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "net/netdev2/ieee802154.h"
+#include "net/ieee802154.h"
+
+#include "common.h"
+
+#include "od.h"
+
+#define _MAX_ADDR_LEN   (8)
+
+static int _parse_addr(uint8_t *out, size_t out_len, const char *in);
+static int send(int iface, le_uint16_t dst_pan, uint8_t *dst_addr,
+                size_t dst_len, char *data);
+
+int ifconfig_list(int idx)
+{
+    int res;
+    uint8_t array_val[_MAX_ADDR_LEN];
+    netdev2_ieee802154_t *dev = (netdev2_ieee802154_t *)(&devs[idx]);
+
+    int (*get)(netdev2_t *, netopt_t, void *, size_t) = dev->netdev.driver->get;
+    netopt_enable_t enable_val;
+    uint16_t u16_val;
+
+    printf("Iface %3d  HWaddr: ", idx);
+    print_addr(dev->short_addr, IEEE802154_SHORT_ADDRESS_LEN);
+    printf(", Long HWaddr: ");
+    print_addr(dev->long_addr, IEEE802154_LONG_ADDRESS_LEN);
+    printf(", PAN: 0x%04x", dev->pan);
+
+    res = get((netdev2_t *)dev, NETOPT_ADDR_LEN, &u16_val, sizeof(u16_val));
+    if (res < 0) {
+        puts("(err)");
+        return 1;
+    }
+    printf("\n           Address length: %u", (unsigned)u16_val);
+
+    res = get((netdev2_t *)dev, NETOPT_SRC_LEN, &u16_val, sizeof(u16_val));
+    if (res < 0) {
+        puts("(err)");
+        return 1;
+    }
+    printf(", Source address length: %u", (unsigned)u16_val);
+
+    res = get((netdev2_t *)dev, NETOPT_MAX_PACKET_SIZE, &u16_val,
+              sizeof(u16_val));
+    if (res < 0) {
+        puts("(err)");
+        return 1;
+    }
+    printf(", Max.Payload: %u", (unsigned)u16_val);
+
+    res = get((netdev2_t *)dev, NETOPT_IPV6_IID, array_val, sizeof(array_val));
+    if (res > 0) {
+        printf("\n           IPv6 IID: ");
+        print_addr(array_val, res);
+    }
+
+    printf("\n           Channel: %u", dev->chan);
+
+    res = get((netdev2_t *)dev, NETOPT_CHANNEL_PAGE, &u16_val, sizeof(u16_val));
+    if (res < 0) {
+        puts("(err)");
+        return 1;
+    }
+    printf(", Ch.page: %u", (unsigned)u16_val);
+
+    res = get((netdev2_t *)dev, NETOPT_TX_POWER, &u16_val, sizeof(u16_val));
+    if (res < 0) {
+        puts("(err)");
+        return 1;
+    }
+    printf(", TXPower: %d dBm", (int)u16_val);
+    res = get((netdev2_t *)dev, NETOPT_IS_WIRED, &u16_val, sizeof(u16_val));
+    if (res < 0) {
+        puts(", wireless");
+    }
+    else {
+        puts(", wired");
+    }
+
+    printf("         ");
+    res = get((netdev2_t *)dev, NETOPT_PRELOADING, &enable_val,
+              sizeof(netopt_enable_t));
+    if ((res > 0) && (enable_val == NETOPT_ENABLE)) {
+        printf("  PRELOAD");
+    }
+    res = get((netdev2_t *)dev, NETOPT_AUTOACK, &enable_val,
+              sizeof(netopt_enable_t));
+    if ((res > 0) && (enable_val == NETOPT_ENABLE)) {
+        printf("  AUTOACK");
+    }
+    res = get((netdev2_t *)dev, NETOPT_RAWMODE, &enable_val,
+              sizeof(netopt_enable_t));
+    if ((res > 0) && (enable_val == NETOPT_ENABLE)) {
+        printf("  RAW");
+    }
+    res = get((netdev2_t *)dev, NETOPT_AUTOCCA, &enable_val,
+              sizeof(netopt_enable_t));
+    if ((res > 0) && (enable_val == NETOPT_ENABLE)) {
+        printf("  AUTOCCA");
+    }
+    res = get((netdev2_t *)dev, NETOPT_CSMA, &enable_val,
+              sizeof(netopt_enable_t));
+    if ((res > 0) && (enable_val == NETOPT_ENABLE)) {
+        printf("  CSMA");
+    }
+    puts("");
+
+    return 0;
+}
+
+int ifconfig(int argc, char **argv)
+{
+    (void)argc;
+    (void)argv;
+    for (int i = 0; i < AT86RF2XX_NUM; i++) {
+        ifconfig_list(i);
+    }
+    return 0;
+}
+
+static void txtsnd_usage(char *cmd_name)
+{
+    printf("usage: %s <iface> [<pan>] <addr> <text>\n", cmd_name);
+}
+
+int txtsnd(int argc, char **argv)
+{
+    char *text;
+    uint8_t addr[_MAX_ADDR_LEN];
+    int iface, idx = 2, res;
+    le_uint16_t pan = { 0 };
+
+    switch (argc) {
+        case 4:
+            break;
+        case 5:
+            res = _parse_addr((uint8_t *)&pan, sizeof(pan), argv[idx++]);
+            if ((res <= 0) || (res > sizeof(pan))) {
+                txtsnd_usage(argv[0]);
+                return 1;
+            }
+            pan.u16 = byteorder_swaps(pan.u16);
+            break;
+        default:
+            txtsnd_usage(argv[0]);
+            return 1;
+    }
+
+    iface = atoi(argv[1]);
+    res = _parse_addr(addr, sizeof(addr), argv[idx++]);
+    if (res <= 0) {
+        txtsnd_usage(argv[0]);
+        return 1;
+    }
+    text = argv[idx++];
+    return send(iface, pan, addr, (size_t)res, text);
+}
+
+static inline int _dehex(char c, int default_)
+{
+    if ('0' <= c && c <= '9') {
+        return c - '0';
+    }
+    else if ('A' <= c && c <= 'F') {
+        return c - 'A' + 10;
+    }
+    else if ('a' <= c && c <= 'f') {
+        return c - 'a' + 10;
+    }
+    else {
+        return default_;
+    }
+}
+
+static int _parse_addr(uint8_t *out, size_t out_len, const char *in)
+{
+    const char *end_str = in;
+    uint8_t *out_end = out;
+    size_t count = 0;
+    int assert_cell = 1;
+
+    if (!in || !*in) {
+        return 0;
+    }
+    while (end_str[1]) {
+        ++end_str;
+    }
+
+    while (end_str >= in) {
+        int a = 0, b = _dehex(*end_str--, -1);
+        if (b < 0) {
+            if (assert_cell) {
+                return 0;
+            }
+            else {
+                assert_cell = 1;
+                continue;
+            }
+        }
+        assert_cell = 0;
+
+        if (end_str >= in) {
+            a = _dehex(*end_str--, 0);
+        }
+
+        if (++count > out_len) {
+            return 0;
+        }
+        *out_end++ = (a << 4) | b;
+    }
+    if (assert_cell) {
+        return 0;
+    }
+    /* out is reversed */
+
+    while (out < --out_end) {
+        uint8_t tmp = *out_end;
+        *out_end = *out;
+        *out++ = tmp;
+    }
+
+    return count;
+}
+
+static int send(int iface, le_uint16_t dst_pan, uint8_t *dst, size_t dst_len,
+                char *data)
+{
+    int res;
+    netdev2_ieee802154_t *dev;
+    const size_t count = 2;         /* mhr + payload */
+    struct iovec vector[count];
+    uint8_t *src;
+    size_t src_len;
+    uint8_t mhr[IEEE802154_MAX_HDR_LEN];
+    uint8_t flags;
+    le_uint16_t src_pan;
+
+    if (((unsigned)iface) > (AT86RF2XX_NUM - 1)) {
+        printf("txtsnd: %d is not an interface\n", iface);
+        return 1;
+    }
+
+    dev = (netdev2_ieee802154_t *)&devs[iface];
+    flags = (uint8_t)(dev->flags & NETDEV2_IEEE802154_SEND_MASK);
+    flags |= IEEE802154_FCF_TYPE_DATA;
+    vector[1].iov_base = data;
+    vector[1].iov_len = strlen(data);
+    src_pan = byteorder_btols(byteorder_htons(dev->pan));
+    if (dst_pan.u16 == 0) {
+        dst_pan = src_pan;
+    }
+    if (dev->flags & NETDEV2_IEEE802154_SRC_MODE_LONG) {
+        src_len = 8;
+        src = dev->long_addr;
+    }
+    else {
+        src_len = 2;
+        src = dev->short_addr;
+    }
+    /* fill MAC header, seq should be set by device */
+    if ((res = ieee802154_set_frame_hdr(mhr, src, src_len,
+                                        dst, dst_len,
+                                        src_pan, dst_pan,
+                                        flags, dev->seq++)) < 0) {
+        puts("txtsnd: Error preperaring frame");
+        return 1;
+    }
+    vector[0].iov_base = mhr;
+    vector[0].iov_len = (size_t)res;
+    res = dev->netdev.driver->send((netdev2_t *)dev, vector, count);
+    if (res < 0) {
+        puts("txtsnd: Error on sending");
+        return 1;
+    }
+    else {
+        printf("txtsnd: send %u bytes to ", (unsigned)vector[1].iov_len);
+        print_addr(dst, dst_len);
+        printf(" (PAN: ");
+        print_addr((uint8_t *)&dst_pan, sizeof(dst_pan));
+        puts(")");
+    }
+    return 0;
+}
+
+/** @} */
diff --git a/tests/driver_at86rf2xx/common.h b/tests/driver_at86rf2xx/common.h
new file mode 100644
index 0000000000000000000000000000000000000000..8829b6e54d5b05d2247bf76306d12497adb38f4a
--- /dev/null
+++ b/tests/driver_at86rf2xx/common.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup     tests
+ * @{
+ *
+ * @file
+ * @brief   Common header for at86rf2xx tests
+ *
+ * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#include <stdint.h>
+
+#include "at86rf2xx.h"
+#include "at86rf2xx_params.h"
+#include "net/netdev2.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Application-internal functions and variables for at86rf2xx tests
+ * @internal
+ * @{
+ */
+#define AT86RF2XX_NUM   (sizeof(at86rf2xx_params) / sizeof(at86rf2xx_params[0]))
+
+extern at86rf2xx_t devs[AT86RF2XX_NUM];
+
+void recv(netdev2_t *dev);
+int ifconfig(int argc, char **argv);
+int txtsnd(int argc, char **argv);
+void print_addr(uint8_t *addr, size_t addr_len);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COMMON_H_ */
+/** @} */
diff --git a/tests/driver_at86rf2xx/main.c b/tests/driver_at86rf2xx/main.c
index 1a5f12f9a7f605ac869a94159f1358e71ce9c525..1be7bfb5bbc0a9ea6763ef254bff4a242f8f2d3a 100644
--- a/tests/driver_at86rf2xx/main.c
+++ b/tests/driver_at86rf2xx/main.c
@@ -20,31 +20,102 @@
 
 #include <stdio.h>
 
+#include "net/netdev2.h"
 #include "shell.h"
 #include "shell_commands.h"
-#include "net/gnrc/pktdump.h"
-#include "net/gnrc.h"
+#include "thread.h"
+#include "xtimer.h"
 
-/**
- * @brief   Maybe you are a golfer?!
- */
-int main(void)
+#include "common.h"
+
+#define _STACKSIZE      (THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF)
+#define MSG_TYPE_ISR    (0x3456)
+
+static char stack[_STACKSIZE];
+static kernel_pid_t _recv_pid;
+
+at86rf2xx_t devs[AT86RF2XX_NUM];
+
+static const shell_command_t shell_commands[] = {
+    { "ifconfig", "Configure netdev2", ifconfig },
+    { "txtsnd", "Send IEEE 802.15.4 packet", txtsnd },
+    { NULL, NULL, NULL }
+};
+
+static void _event_cb(netdev2_t *dev, netdev2_event_t event, void *data)
 {
-    gnrc_netreg_entry_t dump;
+    (void) data;
+
+    if (event == NETDEV2_EVENT_ISR) {
+        msg_t msg;
+
+        msg.type = MSG_TYPE_ISR;
+        msg.content.ptr = (void *) dev;
+
+        if (msg_send(&msg, _recv_pid) <= 0) {
+            puts("gnrc_netdev2: possibly lost interrupt.");
+        }
+    }
+    else {
+        switch (event) {
+            case NETDEV2_EVENT_RX_COMPLETE:
+            {
+                recv(dev);
 
+                break;
+            }
+            default:
+                puts("Unexpected event received");
+                break;
+        }
+    }
+}
+
+void *_recv_thread(void *arg)
+{
+    while (1) {
+        msg_t msg;
+        msg_receive(&msg);
+        if (msg.type == MSG_TYPE_ISR) {
+            netdev2_t *dev = (netdev2_t *)msg.content.ptr;
+            dev->driver->isr(dev);
+        }
+        else {
+            puts("unexpected message type");
+        }
+    }
+}
+
+int main(void)
+{
     puts("AT86RF2xx device driver test");
+    xtimer_init();
+
+    for (unsigned i = 0; i < AT86RF2XX_NUM; i++) {
+        const at86rf2xx_params_t *p = &at86rf2xx_params[i];
+        netdev2_t *dev = (netdev2_t *)(&devs[i]);
+
+        printf("Initializing AT86RF2xx radio at SPI_%d\n", p->spi);
+        at86rf2xx_setup(&devs[i], p->spi, p->spi_speed, p->cs_pin,
+                        p->int_pin, p->sleep_pin, p->reset_pin);
+        dev->event_callback = _event_cb;
+        dev->driver->init(dev);
+    }
+
+    _recv_pid = thread_create(stack, sizeof(stack), THREAD_PRIORITY_MAIN - 1,
+                              THREAD_CREATE_STACKTEST, _recv_thread, NULL,
+                              "recv_thread");
 
-    /* register the pktdump thread */
-    puts("Register the packet dump thread for GNRC_NETTYPE_UNDEF packets");
-    dump.pid = gnrc_pktdump_pid;
-    dump.demux_ctx = GNRC_NETREG_DEMUX_CTX_ALL;
-    gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &dump);
+    if (_recv_pid <= KERNEL_PID_UNDEF) {
+        puts("Creation of receiver thread failed");
+        return 1;
+    }
 
     /* start the shell */
     puts("Initialization successful - starting the shell now");
 
     char line_buf[SHELL_DEFAULT_BUFSIZE];
-    shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
+    shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
 
     return 0;
 }
diff --git a/tests/driver_at86rf2xx/recv.c b/tests/driver_at86rf2xx/recv.c
new file mode 100644
index 0000000000000000000000000000000000000000..d351eb2574a4db0db3ad2d8633dad130b130adf9
--- /dev/null
+++ b/tests/driver_at86rf2xx/recv.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 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 <stdio.h>
+
+#include "at86rf2xx.h"
+#include "od.h"
+#include "net/ieee802154.h"
+#include "net/netdev2.h"
+
+#include "common.h"
+
+#define MAX_LINE    (80)
+
+static uint8_t buffer[AT86RF2XX_MAX_PKT_LENGTH];
+
+void recv(netdev2_t *dev)
+{
+    uint8_t src[IEEE802154_LONG_ADDRESS_LEN], dst[IEEE802154_LONG_ADDRESS_LEN];
+    size_t mhr_len, data_len, src_len, dst_len;
+    netdev2_ieee802154_rx_info_t rx_info;
+    le_uint16_t src_pan, dst_pan;
+
+    putchar('\n');
+    data_len = dev->driver->recv(dev, (char *)buffer, sizeof(buffer), &rx_info);
+    mhr_len = ieee802154_get_frame_hdr_len(buffer);
+    if (mhr_len == 0) {
+        puts("Unexpected MHR for incoming packet");
+        return;
+    }
+    dst_len = ieee802154_get_dst(buffer, dst, &dst_pan);
+    src_len = ieee802154_get_src(buffer, src, &src_pan);
+    switch (buffer[0] & IEEE802154_FCF_TYPE_MASK) {
+        case IEEE802154_FCF_TYPE_BEACON:
+            puts("BEACON");
+            break;
+        case IEEE802154_FCF_TYPE_DATA:
+            puts("DATA");
+            break;
+        case IEEE802154_FCF_TYPE_ACK:
+            puts("ACK");
+            break;
+        case IEEE802154_FCF_TYPE_MACCMD:
+            puts("MACCMD");
+            break;
+        default:
+            puts("UNKNOWN");
+            break;
+    }
+    printf("Dest. PAN: 0x%04x, Dest. addr.: ",
+           byteorder_ntohs(byteorder_ltobs(dst_pan)));
+    print_addr(dst, dst_len);
+    printf("\nSrc. PAN: 0x%04x, Src. addr.: ",
+           byteorder_ntohs(byteorder_ltobs(src_pan)));
+    print_addr(src, src_len);
+    printf("\nSecurity: ");
+    if (buffer[0] & IEEE802154_FCF_SECURITY_EN) {
+        printf("1, ");
+    }
+    else {
+        printf("0, ");
+    }
+    printf("Frame pend.: ");
+    if (buffer[0] & IEEE802154_FCF_FRAME_PEND) {
+        printf("1, ");
+    }
+    else {
+        printf("0, ");
+    }
+    printf("ACK req.: ");
+    if (buffer[0] & IEEE802154_FCF_ACK_REQ) {
+        printf("1, ");
+    }
+    else {
+        printf("0, ");
+    }
+    printf("PAN comp.: ");
+    if (buffer[0] & IEEE802154_FCF_ACK_REQ) {
+        puts("1");
+    }
+    else {
+        puts("0");
+    }
+    printf("Version: ");
+    printf("%u, ", (unsigned)((buffer[1] & IEEE802154_FCF_VERS_MASK) >> 4));
+    printf("Seq.: %u\n", (unsigned)ieee802154_get_seq(buffer));
+    od_hex_dump(buffer + mhr_len, data_len - mhr_len, 0);
+    printf("txt: ");
+    for (int i = mhr_len; i < data_len; i++) {
+        if ((buffer[i] > 0x1F) && (buffer[i] < 0x80)) {
+            putchar((char)buffer[i]);
+        }
+        else {
+            putchar('?');
+        }
+        if (((((i - mhr_len) + 1) % (MAX_LINE - sizeof("txt: "))) == 1) &&
+            (i - mhr_len) != 0) {
+            printf("\n     ");
+        }
+    }
+    printf("\n");
+    printf("RSSI: %u, LQI: %u\n\n", rx_info.rssi, rx_info.lqi);
+}
+
+/** @} */