diff --git a/Makefile.dep b/Makefile.dep
index d919119e4ece2f6ebc8c4a03277b48d489cbcdc2..2f668d4c6027c1d9f2f6fc3288df4f12b1a4aae1 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -76,9 +76,8 @@ ifneq (,$(filter cc2420,$(USEMODULE)))
 endif
 
 ifneq (,$(filter at86rf231,$(USEMODULE)))
-	USEMODULE += transceiver
+	USEMODULE += netdev_802154
 	USEMODULE += ieee802154
-	USEMODULE += vtimer
 endif
 
 ifneq (,$(filter vtimer,$(USEMODULE)))
@@ -95,6 +94,10 @@ ifneq (,$(filter ccn_lite,$(USEMODULE)))
 	USEMODULE += crypto
 endif
 
+ifneq (,$(filter netdev_802154,$(USEMODULE)))
+	USEMODULE += netdev_base
+endif
+
 ifneq (,$(filter rgbled,$(USEMODULE)))
 	USEMODULE += color
 endif
diff --git a/boards/iot-lab_M3/Makefile.dep b/boards/iot-lab_M3/Makefile.dep
index cbe5dc58c4b580d1eaae01cf30031eab663fcedf..ab5c150ef0981ac360a26cd1824703a4b7b32cfa 100644
--- a/boards/iot-lab_M3/Makefile.dep
+++ b/boards/iot-lab_M3/Makefile.dep
@@ -1,4 +1,6 @@
 ifneq (,$(filter defaulttransceiver,$(USEMODULE)))
     USEMODULE += at86rf231
-    USEMODULE += transceiver
+    ifeq (,$(filter netdev_base,$(USEMODULE)))
+        USEMODULE += transceiver
+    endif
 endif
diff --git a/drivers/Makefile b/drivers/Makefile
index d8d826a19022fe73edfd54118530fae15248bf43..f5c70edc184913908d625ea410c9500026887138 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -52,5 +52,8 @@ endif
 ifneq (,$(filter lps331ap,$(USEMODULE)))
     DIRS += lps331ap
 endif
+ifneq (,$(filter netdev_802154,$(USEMODULE)))
+    DIRS += netdev/802154
+endif
 
 include $(RIOTBASE)/Makefile.base
diff --git a/drivers/at86rf231/at86rf231.c b/drivers/at86rf231/at86rf231.c
index d94eed7e4105d4b042164c2576ff3808d056b067..82427c3e7b302f68b58fcffaba56cae7ccd2e61f 100644
--- a/drivers/at86rf231/at86rf231.c
+++ b/drivers/at86rf231/at86rf231.c
@@ -31,32 +31,48 @@
 #define ENABLE_DEBUG (0)
 #include "debug.h"
 
+#define _MAX_RETRIES    (100)
+
 static uint16_t radio_pan;
 static uint8_t  radio_channel;
 static uint16_t radio_address;
 static uint64_t radio_address_long;
 
+netdev_802154_raw_packet_cb_t at86rf231_raw_packet_cb;
+netdev_rcv_data_cb_t at86rf231_data_packet_cb;
+
+/* default source address length for sending in number of byte */
+static size_t _default_src_addr_len = 2;
+
 uint8_t  driver_state;
 
-uint8_t at86rf231_get_status(void);
 void at86rf231_gpio_spi_interrupts_init(void);
 void at86rf231_reset(void);
 
-
+#ifdef MODULE_TRANSCEIVER
 void at86rf231_init(kernel_pid_t tpid)
 {
     transceiver_pid = tpid;
+    at86rf231_initialize(NULL);
+}
+#endif
 
+int at86rf231_initialize(netdev_t *dev)
+{
     at86rf231_gpio_spi_interrupts_init();
 
     at86rf231_reset();
 
-    // TODO : Enable addr decode, auto ack, auto crc
-    // and configure security, power, channel, pan
+    at86rf231_on();
 
-    radio_pan = 0;
-    radio_pan = 0x00FF & (uint16_t)at86rf231_reg_read(AT86RF231_REG__PAN_ID_0);
-    radio_pan |= (uint16_t)at86rf231_reg_read(AT86RF231_REG__PAN_ID_1) << 8;
+    /* TODO :
+     * and configure security, power
+     */
+#ifdef MODULE_CONFIG
+    at86rf231_set_pan(sysconfig.radio_pan_id);
+#else
+    at86rf231_set_pan(0x0001);
+#endif
 
     radio_channel = at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA) & AT86RF231_PHY_CC_CCA_MASK__CHANNEL;
 
@@ -72,49 +88,104 @@ void at86rf231_init(kernel_pid_t tpid)
     radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 48;
     radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 56;
 
+    return 0;
+}
+
+int at86rf231_on(void)
+{
+    /* Send a FORCE TRX OFF command */
+    at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__FORCE_TRX_OFF);
+
+    /* busy wait for TRX_OFF state */
+    do {
+        int delay = _MAX_RETRIES;
+        if (!--delay) {
+            DEBUG("at86rf231 : ERROR : could not enter TRX_OFF mode\n");
+            return 0;
+        }
+    } while (at86rf231_get_status() != AT86RF231_TRX_STATUS__TRX_OFF);
+
+    at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_ON);
+
+    /* change into basic reception mode to initialise CSMA seed by RNG */
+    do {
+        int delay = _MAX_RETRIES;
+        if (!--delay) {
+            DEBUG("at86rf231 : ERROR : could not enter RX_ON mode\n");
+            return 0;
+        }
+    } while (at86rf231_get_status() != AT86RF231_TRX_STATUS__RX_ON);
+
+    /* read RNG values into CSMA_SEED_0 */
+    for (int i=0; i<7; i+=2) {
+        uint8_t tmp = at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA);
+        tmp = ((tmp&0x60)>>5);
+        at86rf231_reg_write(AT86RF231_REG__CSMA_SEED_0, tmp << i);
+    }
+    /* read CSMA_SEED_1 and write back with RNG value */
+    uint8_t tmp = at86rf231_reg_read(AT86RF231_REG__CSMA_SEED_1);
+    tmp = ((at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA)&0x60)>>5);
+    at86rf231_reg_write(AT86RF231_REG__CSMA_SEED_1, tmp);
+
+    /* change into reception mode */
     at86rf231_switch_to_rx();
+
+    return 1;
+}
+
+void at86rf231_off(void)
+{
+    /* TODO */
+}
+
+int at86rf231_is_on(void)
+{
+    return ((at86rf231_get_status() & 0x1f) != 0);
 }
 
 void at86rf231_switch_to_rx(void)
 {
     gpio_irq_disable(AT86RF231_INT);
 
-    // Send a FORCE TRX OFF command
-    at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__FORCE_TRX_OFF);
+    /* now change to PLL_ON state for extended operating mode */
+    at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__PLL_ON);
+
+    do {
+        int max_wait = _MAX_RETRIES;
+        if (!--max_wait) {
+            DEBUG("at86rf231 : ERROR : could not enter PLL_ON mode\n");
+            break;
+        }
+    } while (at86rf231_get_status() != AT86RF231_TRX_STATUS__PLL_ON);
 
-    // Reset IRQ to TRX END only
+    /* Reset IRQ to TRX END only */
     at86rf231_reg_write(AT86RF231_REG__IRQ_MASK, AT86RF231_IRQ_STATUS_MASK__TRX_END);
 
-    // Read IRQ to clear it
+    /* Read IRQ to clear it */
     at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS);
 
-    // Enable IRQ interrupt
+    /* Enable IRQ interrupt */
     gpio_irq_enable(AT86RF231_INT);
 
-    // Start RX
-    at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_ON);
-
-    // wait until it is on RX_ON state
-    uint8_t status;
-    uint8_t max_wait = 100;   // TODO : move elsewhere, this is in 10us
+    /* Enter RX_AACK_ON state */
+    at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_AACK_ON);
 
     do {
-        status = at86rf231_get_status();
-
-        hwtimer_wait(HWTIMER_TICKS(10));
-
+        int max_wait = _MAX_RETRIES;
         if (!--max_wait) {
-            printf("at86rf231 : ERROR : could not enter RX_ON mode\n");
+            DEBUG("at86rf231 : ERROR : could not enter RX_AACK_ON mode\n");
             break;
         }
-    }
-    while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) != AT86RF231_TRX_STATUS__RX_ON);
+    } while (at86rf231_get_status() != AT86RF231_TRX_STATUS__RX_AACK_ON);
 }
 
-void at86rf231_rx_irq(void *arg)
+void at86rf231_rxoverflow_irq(void)
 {
-    (void)arg;
+    /* TODO */
+}
 
+void at86rf231_rx_irq(void)
+{
     /* check if we are in sending state */
     if (driver_state == AT_DRIVER_STATE_SENDING) {
         /* Read IRQ to clear it */
@@ -123,7 +194,6 @@ void at86rf231_rx_irq(void *arg)
         at86rf231_switch_to_rx();
         /* clear internal state */
         driver_state = AT_DRIVER_STATE_DEFAULT;
-        return;
     }
     else {
         /* handle receive */
@@ -131,6 +201,51 @@ void at86rf231_rx_irq(void *arg)
     }
 }
 
+int at86rf231_add_raw_recv_callback(netdev_t *dev,
+                                    netdev_802154_raw_packet_cb_t recv_cb)
+{
+    (void)dev;
+
+    if (at86rf231_raw_packet_cb == NULL){
+        at86rf231_raw_packet_cb = recv_cb;
+        return 0;
+    }
+
+    return -ENOBUFS;
+
+}
+
+int at86rf231_rem_raw_recv_callback(netdev_t *dev,
+                                    netdev_802154_raw_packet_cb_t recv_cb)
+{
+    (void)dev;
+
+    at86rf231_raw_packet_cb = NULL;
+    return 0;
+}
+
+int at86rf231_add_data_recv_callback(netdev_t *dev,
+                                     netdev_rcv_data_cb_t recv_cb)
+{
+    (void)dev;
+
+    if (at86rf231_data_packet_cb == NULL){
+        at86rf231_data_packet_cb = recv_cb;
+        return 0;
+    }
+
+    return -ENOBUFS;
+}
+
+int at86rf231_rem_data_recv_callback(netdev_t *dev,
+                                     netdev_rcv_data_cb_t recv_cb)
+{
+    (void)dev;
+
+    at86rf231_data_packet_cb = NULL;
+    return 0;
+}
+
 radio_address_t at86rf231_set_address(radio_address_t address)
 {
     radio_address = address;
@@ -182,34 +297,44 @@ uint16_t at86rf231_get_pan(void)
     return radio_pan;
 }
 
-int8_t at86rf231_set_channel(uint8_t channel)
+int at86rf231_set_channel(unsigned int channel)
 {
-    uint8_t cca_state;
     radio_channel = channel;
 
-    if (channel < RF86RF231_MIN_CHANNEL ||
-        channel > RF86RF231_MAX_CHANNEL) {
+    if (channel < AT86RF231_MIN_CHANNEL ||
+        channel > AT86RF231_MAX_CHANNEL) {
 #if DEVELHELP
         puts("[at86rf231] channel out of range!");
 #endif
         return -1;
     }
 
-    cca_state = at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA) & ~AT86RF231_PHY_CC_CCA_MASK__CHANNEL;
-    at86rf231_reg_write(AT86RF231_REG__PHY_CC_CCA, cca_state | (radio_channel & AT86RF231_PHY_CC_CCA_MASK__CHANNEL));
+    at86rf231_reg_write(AT86RF231_REG__PHY_CC_CCA, (radio_channel & AT86RF231_PHY_CC_CCA_MASK__CHANNEL));
 
     return radio_channel;
 }
 
-uint8_t at86rf231_get_channel(void)
+unsigned int at86rf231_get_channel(void)
 {
     return radio_channel;
 }
 
-void at86rf231_set_monitor(uint8_t mode)
+void at86rf231_set_monitor(int mode)
 {
-    (void) mode;
-    // TODO
+    /* read register */
+    uint8_t tmp = at86rf231_reg_read(AT86RF231_REG__XAH_CTRL_1);
+    /* set promicuous mode depending on *mode* */
+    if (mode) {
+        at86rf231_reg_write(AT86RF231_REG__XAH_CTRL_1, (tmp|AT86RF231_XAH_CTRL_1__AACK_PROM_MODE));
+    }
+    else {
+        at86rf231_reg_write(AT86RF231_REG__XAH_CTRL_1, (tmp&(~AT86RF231_XAH_CTRL_1__AACK_PROM_MODE)));
+    }
+}
+
+int at86rf231_get_monitor(void)
+{
+    return (at86rf231_reg_read(AT86RF231_REG__XAH_CTRL_1) & AT86RF231_XAH_CTRL_1__AACK_PROM_MODE);
 }
 
 void at86rf231_gpio_spi_interrupts_init(void)
@@ -217,7 +342,7 @@ void at86rf231_gpio_spi_interrupts_init(void)
     /* SPI init */
     spi_init_master(AT86RF231_SPI, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ);
     /* IRQ0 */
-    gpio_init_int(AT86RF231_INT, GPIO_NOPULL, GPIO_RISING, at86rf231_rx_irq, NULL);
+    gpio_init_int(AT86RF231_INT, GPIO_NOPULL, GPIO_RISING, (gpio_cb_t)at86rf231_rx_irq, NULL);
     /* CS */
     gpio_init_out(AT86RF231_CS, GPIO_NOPULL);
     /* SLEEP */
@@ -240,21 +365,320 @@ void at86rf231_reset(void)
     while (delay--){}
 
     gpio_set(AT86RF231_RESET);
+}
 
-    /* Send a FORCE TRX OFF command */
-    at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__FORCE_TRX_OFF);
+int at86rf231_get_option(netdev_t *dev, netdev_opt_t opt, void *value,
+                         size_t *value_len)
+{
+    /* XXX: first check only for backwards compatibility with transceiver
+     *      (see at86rf231_init) remove when adapter for transceiver exists */
+    if (dev != &at86rf231_netdev) {
+        return -ENODEV;
+    }
 
-    /* busy wait for TRX_OFF state */
-    uint8_t status;
-    uint8_t max_wait = 100;
+    switch (opt) {
+        case NETDEV_OPT_CHANNEL:
+            if (*value_len < sizeof(unsigned int)) {
+                return -EOVERFLOW;
+            }
+            if (*value_len > sizeof(unsigned int)) {
+                *value_len = sizeof(unsigned int);
+            }
+            *((unsigned int *)value) = at86rf231_get_channel();
+            break;
 
-    do {
-        status = at86rf231_get_status();
+        case NETDEV_OPT_ADDRESS:
+            if (*value_len < sizeof(uint16_t)) {
+                return -EOVERFLOW;
+            }
+            if (*value_len > sizeof(uint16_t)) {
+                *value_len = sizeof(uint16_t);
+            }
+            *((uint16_t *)value) = at86rf231_get_address();
+            break;
 
-        if (!--max_wait) {
-            printf("at86rf231 : ERROR : could not enter TRX_OFF mode\n");
+        case NETDEV_OPT_NID:
+            if (*value_len < sizeof(uint16_t)) {
+                return -EOVERFLOW;
+            }
+            if (*value_len > sizeof(uint16_t)) {
+                *value_len = sizeof(uint16_t);
+            }
+            *((uint16_t *)value) = at86rf231_get_pan();
             break;
-        }
-    } while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS)
-             != AT86RF231_TRX_STATUS__TRX_OFF);
+
+        case NETDEV_OPT_ADDRESS_LONG:
+            if (*value_len < sizeof(uint64_t)) {
+                return -EOVERFLOW;
+            }
+            if (*value_len > sizeof(uint64_t)) {
+                *value_len = sizeof(uint64_t);
+            }
+            *((uint64_t *)value) = at86rf231_get_address_long();
+            break;
+
+        case NETDEV_OPT_MAX_PACKET_SIZE:
+            if (*value_len == 0) {
+                return -EOVERFLOW;
+            }
+            if (*value_len > sizeof(uint8_t)) {
+                *value_len = sizeof(uint8_t);
+            }
+            *((uint8_t *)value) = AT86RF231_MAX_PKT_LENGTH;
+            break;
+
+        case NETDEV_OPT_PROTO:
+            if (*value_len < sizeof(netdev_proto_t)) {
+                return -EOVERFLOW;
+            }
+            if (*value_len > sizeof(netdev_proto_t)) {
+                *value_len = sizeof(netdev_proto_t);
+            }
+            *((netdev_type_t *)value) = NETDEV_PROTO_802154;
+            break;
+
+        case NETDEV_OPT_SRC_LEN:
+            if (*value_len < sizeof(size_t)) {
+                return -EOVERFLOW;
+            }
+            if (*value_len > sizeof(size_t)) {
+                *value_len = sizeof(size_t);
+            }
+            *((size_t *)value) = _default_src_addr_len;
+
+        default:
+            return -ENOTSUP;
+    }
+
+    return 0;
+}
+
+static int _type_pun_up_unsigned(void *value_out, size_t desired_len,
+                                 void *value_in, size_t given_len)
+{
+    if (given_len > desired_len) {
+        return -EOVERFLOW;
+    }
+
+    /* XXX this is ugly, but bear with me */
+    switch (given_len) {
+        case 8:
+            switch (desired_len) {
+                case 8:
+                    *((uint64_t *)value_out) = (*((uint64_t *)value_in));
+                    return 0;
+                default:
+                    return -EINVAL;
+            }
+
+        case 4:
+            switch (desired_len) {
+                case 8:
+                    *((uint64_t *)value_out) = (uint64_t)(*((uint32_t *)value_in));
+                    return 0;
+                case 4:
+                    *((uint32_t *)value_out) = (*((uint32_t *)value_in));
+                    return 0;
+                default:
+                    return -EINVAL;
+            }
+
+        case 2:
+            switch (desired_len) {
+                case 8:
+                    *((uint64_t *)value_out) = (uint64_t)(*((uint16_t *)value_in));
+                    return 0;
+                case 4:
+                    *((uint32_t *)value_out) = (uint32_t)(*((uint16_t *)value_in));
+                    return 0;
+                case 2:
+                    *((uint16_t *)value_out) = (*((uint16_t *)value_in));
+                    return 0;
+                default:
+                    return -EINVAL;
+            }
+
+        case 1:
+            switch (desired_len) {
+                case 8:
+                    *((uint64_t *)value_out) = (uint64_t)(*((uint8_t *)value_in));
+                    return 0;
+                case 4:
+                    *((uint32_t *)value_out) = (uint32_t)(*((uint8_t *)value_in));
+                    return 0;
+                case 2:
+                    *((uint16_t *)value_out) = (uint16_t)(*((uint8_t *)value_in));
+                    return 0;
+                case 1:
+                    *((uint8_t *)value_out) = (*((uint8_t *)value_in));
+                    return 0;
+                default:
+                    return -EINVAL;
+            }
+
+        default:
+            return -EINVAL;
+    }
+}
+
+int at86rf231_set_option(netdev_t *dev, netdev_opt_t opt, void *value,
+                         size_t value_len)
+{
+    uint8_t set_value[sizeof(uint64_t)];
+    int res = 0;
+
+    /* XXX: first check only for backwards compatibility with transceiver
+     *      (see at86rf231_init) remove when adapter for transceiver exists */
+    if (dev != &at86rf231_netdev) {
+        return -ENODEV;
+    }
+
+    switch (opt) {
+        case NETDEV_OPT_CHANNEL:
+            if ((res = _type_pun_up_unsigned(set_value, sizeof(unsigned int),
+                                             value, value_len)) == 0) {
+                unsigned int *v = (unsigned int *)set_value;
+                if (*v > 26) {
+                    return -EINVAL;
+                }
+                at86rf231_set_channel(*v);
+            }
+            break;
+
+        case NETDEV_OPT_ADDRESS:
+            if ((res = _type_pun_up_unsigned(set_value, sizeof(uint16_t),
+                                             value, value_len)) == 0) {
+                uint16_t *v = (uint16_t *)set_value;
+                if (*v == 0xffff) {
+                    /* Do not allow setting to broadcast */
+                    return -EINVAL;
+                }
+                at86rf231_set_address(*v);
+            }
+            break;
+
+        case NETDEV_OPT_NID:
+            if ((res = _type_pun_up_unsigned(set_value, sizeof(uint16_t),
+                                             value, value_len)) == 0) {
+                uint16_t *v = (uint16_t *)set_value;
+                if (*v == 0xffff) {
+                    /* Do not allow setting to broadcast */
+                    return -EINVAL;
+                }
+                at86rf231_set_pan(*v);
+            }
+            break;
+
+        case NETDEV_OPT_ADDRESS_LONG:
+            if ((res = _type_pun_up_unsigned(set_value, sizeof(uint64_t),
+                                             value, value_len)) == 0) {
+                uint64_t *v = (uint64_t *)set_value;
+                /* TODO: error checking? */
+                at86rf231_set_address_long(*v);
+            }
+            break;
+
+        case NETDEV_OPT_SRC_LEN:
+            if ((res = _type_pun_up_unsigned(set_value, sizeof(size_t),
+                                             value, value_len)) == 0) {
+                size_t *v = (size_t *)set_value;
+
+                if (*v != 2 || *v != 8) {
+                    return -EINVAL;
+                }
+                _default_src_addr_len = *v;
+            }
+            break;
+
+        default:
+            return -ENOTSUP;
+    }
+
+    return res;
 }
+
+int at86rf231_get_state(netdev_t *dev, netdev_state_t *state)
+{
+    /* XXX: first check only for backwards compatibility with transceiver
+     *      (see at86rf231_init) remove when adapter for transceiver exists */
+    if (dev != &at86rf231_netdev) {
+        return -ENODEV;
+    }
+
+    if (!at86rf231_is_on()) {
+        *state = NETDEV_STATE_POWER_OFF;
+    }
+    else if (at86rf231_get_monitor()) {
+        *state = NETDEV_STATE_PROMISCUOUS_MODE;
+    }
+    else {
+        *state = NETDEV_STATE_RX_MODE;
+    }
+
+    return 0;
+}
+
+int at86rf231_set_state(netdev_t *dev, netdev_state_t state)
+{
+    /* XXX: first check only for backwards compatibility with transceiver
+     *      (see at86rf231_init) remove when adapter for transceiver exists */
+    if (dev != &at86rf231_netdev) {
+        return -ENODEV;
+    }
+
+    if (state != NETDEV_STATE_PROMISCUOUS_MODE && at86rf231_get_monitor()) {
+        at86rf231_set_monitor(0);
+    }
+
+    switch (state) {
+        case NETDEV_STATE_POWER_OFF:
+            at86rf231_off();
+            break;
+
+        case NETDEV_STATE_RX_MODE:
+            at86rf231_switch_to_rx();
+            break;
+
+        case NETDEV_STATE_PROMISCUOUS_MODE:
+            at86rf231_set_monitor(1);
+            break;
+
+        default:
+            return -ENOTSUP;
+    }
+
+    return 0;
+}
+
+int at86rf231_channel_is_clear(netdev_t *dev)
+{
+    (void)dev;
+    /* channel is checked by hardware automatically before transmission */
+    return 1;
+}
+
+void at86rf231_event(netdev_t *dev, uint32_t event_type)
+{
+    (void)dev;
+    (void)event_type;
+}
+
+const netdev_802154_driver_t at86rf231_driver = {
+    .init = at86rf231_initialize,
+    .send_data = netdev_802154_send_data,
+    .add_receive_data_callback = at86rf231_add_data_recv_callback,
+    .rem_receive_data_callback = at86rf231_rem_data_recv_callback,
+    .get_option = at86rf231_get_option,
+    .set_option = at86rf231_set_option,
+    .get_state = at86rf231_get_state,
+    .set_state = at86rf231_set_state,
+    .event = at86rf231_event,
+    .load_tx = at86rf231_load_tx_buf,
+    .transmit = at86rf231_transmit_tx_buf,
+    .send = netdev_802154_send,
+    .add_receive_raw_callback = at86rf231_add_raw_recv_callback,
+    .rem_receive_raw_callback = at86rf231_rem_raw_recv_callback,
+    .channel_is_clear = at86rf231_channel_is_clear,
+};
+
+netdev_t at86rf231_netdev = { NETDEV_TYPE_802154, (netdev_driver_t *) &at86rf231_driver, NULL };
diff --git a/drivers/at86rf231/at86rf231_rx.c b/drivers/at86rf231/at86rf231_rx.c
index 628d989069e66f77e053b93a3fec520e2f27bd38..11559cd8864ef7f134a0514dada2197ebf8656ba 100644
--- a/drivers/at86rf231/at86rf231_rx.c
+++ b/drivers/at86rf231/at86rf231_rx.c
@@ -35,28 +35,29 @@
 at86rf231_packet_t at86rf231_rx_buffer[AT86RF231_RX_BUF_SIZE];
 uint8_t buffer[AT86RF231_RX_BUF_SIZE][AT86RF231_MAX_PKT_LENGTH];
 volatile uint8_t rx_buffer_next;
+extern netdev_802154_raw_packet_cb_t at86rf231_raw_packet_cb;
 
 void at86rf231_rx_handler(void)
 {
     uint8_t lqi, fcs_rssi;
-    // read packet length
+    /* read packet length */
     at86rf231_read_fifo(&at86rf231_rx_buffer[rx_buffer_next].length, 1);
 
-    // read psdu, read packet with length as first byte and lqi as last byte.
+    /* read psdu, read packet with length as first byte and lqi as last byte. */
     uint8_t *buf = buffer[rx_buffer_next];
     at86rf231_read_fifo(buf, at86rf231_rx_buffer[rx_buffer_next].length);
 
-    // read lqi which is appended after the psdu
+    /* read lqi which is appended after the psdu */
     lqi = buf[at86rf231_rx_buffer[rx_buffer_next].length - 1];
 
-    // read fcs and rssi, from a register
+    /* read fcs and rssi, from a register */
     fcs_rssi = at86rf231_reg_read(AT86RF231_REG__PHY_RSSI);
 
-    // build package
+    /* build package */
     at86rf231_rx_buffer[rx_buffer_next].lqi = lqi;
-    // RSSI has no meaning here, it should be read during packet reception.
+    /* RSSI has no meaning here, it should be read during packet reception. */
     at86rf231_rx_buffer[rx_buffer_next].rssi = fcs_rssi & 0x0F;  // bit[4:0]
-    // bit7, boolean, 1 FCS valid, 0 FCS not valid
+    /* bit7, boolean, 1 FCS valid, 0 FCS not valid */
     at86rf231_rx_buffer[rx_buffer_next].crc = (fcs_rssi >> 7) & 0x01;
 
     if (at86rf231_rx_buffer[rx_buffer_next].crc == 0) {
@@ -64,14 +65,21 @@ void at86rf231_rx_handler(void)
         return;
     }
 
+    /* read buffer into ieee802154_frame */
     ieee802154_frame_read(&buf[1], &at86rf231_rx_buffer[rx_buffer_next].frame,
                           at86rf231_rx_buffer[rx_buffer_next].length);
 
+    /* if packet is no ACK */
     if (at86rf231_rx_buffer[rx_buffer_next].frame.fcf.frame_type != 2) {
 #ifdef DEBUG_ENABLED
         ieee802154_frame_print_fcf_frame(&at86rf231_rx_buffer[rx_buffer_next].frame);
 #endif
-
+        if (at86rf231_raw_packet_cb != NULL) {
+            at86rf231_raw_packet_cb(&at86rf231_netdev, (void*)buf,
+                                    at86rf231_rx_buffer[rx_buffer_next].length,
+                                    fcs_rssi, lqi, (fcs_rssi >> 7));
+        }
+#ifdef MODULE_TRANSCEIVER
         /* notify transceiver thread if any */
         if (transceiver_pid != KERNEL_PID_UNDEF) {
             msg_t m;
@@ -79,19 +87,21 @@ void at86rf231_rx_handler(void)
             m.content.value = rx_buffer_next;
             msg_send_int(&m, transceiver_pid);
         }
+#endif
     }
     else {
+        /* This should not happen, ACKs are consumed by hardware */
 #ifdef DEBUG_ENABLED
         DEBUG("GOT ACK for SEQ %u\n", at86rf231_rx_buffer[rx_buffer_next].frame.seq_nr);
         ieee802154_frame_print_fcf_frame(&at86rf231_rx_buffer[rx_buffer_next].frame);
 #endif
     }
 
-    // shift to next buffer element
+    /* shift to next buffer element */
     if (++rx_buffer_next == AT86RF231_RX_BUF_SIZE) {
         rx_buffer_next = 0;
     }
 
-    // Read IRQ to clear it
+    /* Read IRQ to clear it */
     at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS);
 }
diff --git a/drivers/at86rf231/at86rf231_spi.c b/drivers/at86rf231/at86rf231_spi.c
index 73c25bb0284266f61e7d7884d184def9104d68af..72fb0ff98798c0f5dc0a21ed6a04e9755d0538ae 100644
--- a/drivers/at86rf231/at86rf231_spi.c
+++ b/drivers/at86rf231/at86rf231_spi.c
@@ -72,6 +72,6 @@ void at86rf231_write_fifo(const uint8_t *data, radio_packet_length_t length)
 
 uint8_t at86rf231_get_status(void)
 {
-    return at86rf231_reg_read(AT86RF231_REG__TRX_STATUS)
-           & AT86RF231_TRX_STATUS_MASK__TRX_STATUS;
+    return (at86rf231_reg_read(AT86RF231_REG__TRX_STATUS)
+            & AT86RF231_TRX_STATUS_MASK__TRX_STATUS);
 }
diff --git a/drivers/at86rf231/at86rf231_tx.c b/drivers/at86rf231/at86rf231_tx.c
index e9666af53f111414d66acab8dc914fb7586e5060..af9a931a44e2fa62f48395cdd7f9f5c89e3d7c8b 100644
--- a/drivers/at86rf231/at86rf231_tx.c
+++ b/drivers/at86rf231/at86rf231_tx.c
@@ -11,7 +11,7 @@
  * @{
  *
  * @file
- * @brief       RX related functionality for the AT86RF231 device driver
+ * @brief       TX related functionality for the AT86RF231 device driver
  *
  * @author      Alaeddine Weslati <alaeddine.weslati@inria.fr>
  * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
@@ -26,16 +26,182 @@
 #define ENABLE_DEBUG (0)
 #include "debug.h"
 
-static void at86rf231_xmit(uint8_t *data, radio_packet_length_t length);
+#define _MAX_RETRIES   (100)
 
+static int16_t at86rf231_load(at86rf231_packet_t *packet);
 static void at86rf231_gen_pkt(uint8_t *buf, at86rf231_packet_t *packet);
 
 static uint8_t sequence_nr;
+static uint8_t wait_for_ack;
 
 int16_t at86rf231_send(at86rf231_packet_t *packet)
+{
+    int16_t result;
+    result = at86rf231_load(packet);
+    if (result < 0) {
+        return result;
+    }
+    at86rf231_transmit_tx_buf(NULL);
+    return result;
+}
+
+netdev_802154_tx_status_t at86rf231_load_tx_buf(netdev_t *dev,
+        netdev_802154_pkt_kind_t kind,
+        netdev_802154_node_addr_t *dest,
+        int use_long_addr,
+        int wants_ack,
+        netdev_hlist_t *upper_layer_hdrs,
+        void *buf,
+        unsigned int len)
+{
+    (void)dev;
+
+    uint8_t mhr[24];
+    uint8_t index = 3;
+
+    /* frame type */
+    switch (kind) {
+        case NETDEV_802154_PKT_KIND_BEACON:
+            mhr[0] = 0x00;
+            break;
+        case NETDEV_802154_PKT_KIND_DATA:
+            mhr[0] = 0x01;
+            break;
+        case NETDEV_802154_PKT_KIND_ACK:
+            mhr[0] = 0x02;
+            break;
+        default:
+            return NETDEV_802154_TX_STATUS_INVALID_PARAM;
+    }
+
+    if (wants_ack) {
+        mhr[0] |= 0x20;
+    }
+
+    wait_for_ack = wants_ack;
+
+    uint16_t src_pan = at86rf231_get_pan();
+    uint8_t compress_pan = 0;
+
+    if (use_long_addr) {
+        mhr[1] = 0xcc;
+    }
+    else {
+        mhr[1] = 0x88;
+        if (dest->pan.id == src_pan) {
+            compress_pan = 1;
+            mhr[0] |= 0x40;
+        }
+    }
+
+    mhr[2] = sequence_nr++;
+
+    /* First 3 bytes are fixed with FCS and SEQ, resume with index=3 */
+    if (use_long_addr) {
+        mhr[index++] = (uint8_t)(dest->long_addr & 0xFF);
+        mhr[index++] = (uint8_t)(dest->long_addr >> 8);
+        mhr[index++] = (uint8_t)(dest->long_addr >> 16);
+        mhr[index++] = (uint8_t)(dest->long_addr >> 24);
+        mhr[index++] = (uint8_t)(dest->long_addr >> 32);
+        mhr[index++] = (uint8_t)(dest->long_addr >> 40);
+        mhr[index++] = (uint8_t)(dest->long_addr >> 48);
+        mhr[index++] = (uint8_t)(dest->long_addr >> 56);
+
+        uint64_t src_long_addr = at86rf231_get_address_long();
+        mhr[index++] = (uint8_t)(src_long_addr & 0xFF);
+        mhr[index++] = (uint8_t)(src_long_addr >> 8);
+        mhr[index++] = (uint8_t)(src_long_addr >> 16);
+        mhr[index++] = (uint8_t)(src_long_addr >> 24);
+        mhr[index++] = (uint8_t)(src_long_addr >> 32);
+        mhr[index++] = (uint8_t)(src_long_addr >> 40);
+        mhr[index++] = (uint8_t)(src_long_addr >> 48);
+        mhr[index++] = (uint8_t)(src_long_addr >> 56);
+    }
+    else {
+        mhr[index++] = (uint8_t)(dest->pan.id & 0xFF);
+        mhr[index++] = (uint8_t)(dest->pan.id >> 8);
+
+        mhr[index++] = (uint8_t)(dest->pan.addr & 0xFF);
+        mhr[index++] = (uint8_t)(dest->pan.addr >> 8);
+
+        if (!compress_pan) {
+            mhr[index++] = (uint8_t)(src_pan & 0xFF);
+            mhr[index++] = (uint8_t)(src_pan >> 8);
+        }
+
+        uint16_t src_addr = at86rf231_get_address();
+        mhr[index++] = (uint8_t)(src_addr & 0xFF);
+        mhr[index++] = (uint8_t)(src_addr >> 8);
+    }
+
+    /* total frame size:
+     * index -> MAC header
+     * len   -> payload length
+     * 2     -> CRC bytes
+     * + lengths of upper layers' headers */
+    size_t size = index + len + 2 + netdev_get_hlist_len(upper_layer_hdrs);
+
+    if (size > AT86RF231_MAX_PKT_LENGTH) {
+        return NETDEV_802154_TX_STATUS_PACKET_TOO_LONG;
+    }
+
+    uint8_t size_byte = (uint8_t)size;
+    netdev_hlist_t *ptr = upper_layer_hdrs;
+
+    at86rf231_write_fifo(&size_byte, 1);
+    at86rf231_write_fifo(mhr, (radio_packet_length_t)index);
+    if (upper_layer_hdrs) {
+        do {
+            at86rf231_write_fifo(ptr->header,
+                                (radio_packet_length_t)(ptr->header_len));
+            netdev_hlist_advance(&ptr);
+        } while (ptr != upper_layer_hdrs);
+    }
+    at86rf231_write_fifo((uint8_t*)buf, len);
+    return NETDEV_802154_TX_STATUS_OK;
+}
+
+netdev_802154_tx_status_t at86rf231_transmit_tx_buf(netdev_t *dev)
+{
+    (void)dev;
+    /* radio driver state: sending */
+    /* will be freed in at86rf231_rx_irq when TRX_END interrupt occurs */
+    driver_state = AT_DRIVER_STATE_SENDING;
+
+    /* Start TX */
+    at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_START);
+    DEBUG("Started TX\n");
+
+    if (!wait_for_ack) {
+        return NETDEV_802154_TX_STATUS_OK;
+    }
+
+    uint8_t trac_status;
+    do {
+        trac_status = at86rf231_reg_read(AT86RF231_REG__TRX_STATE);
+        trac_status &= AT86RF231_TRX_STATE_MASK__TRAC;
+    }
+    while (trac_status == AT86RF231_TRX_STATE__TRAC_INVALID);
+
+    switch (trac_status) {
+        case AT86RF231_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE:
+            return NETDEV_802154_TX_STATUS_MEDIUM_BUSY;
+
+        case AT86RF231_TRX_STATE__TRAC_NO_ACK:
+            return NETDEV_802154_TX_STATUS_NOACK;
+
+        default:
+            return NETDEV_802154_TX_STATUS_OK;
+    }
+}
+
+int16_t at86rf231_load(at86rf231_packet_t *packet)
 {
     // Set missing frame information
     packet->frame.fcf.frame_ver = 0;
+    packet->frame.fcf.frame_type = 0x1;
+
+    packet->frame.src_pan_id = at86rf231_get_pan();
 
     if (packet->frame.src_pan_id == packet->frame.dest_pan_id) {
         packet->frame.fcf.panid_comp = 1;
@@ -59,12 +225,9 @@ int16_t at86rf231_send(at86rf231_packet_t *packet)
         packet->frame.src_addr[7] = (uint8_t)(at86rf231_get_address_long() & 0xFF);
     }
 
-    packet->frame.src_pan_id = at86rf231_get_pan();
-    packet->frame.seq_nr = sequence_nr;
+    packet->frame.seq_nr = sequence_nr++;
 
-    sequence_nr += 1;
-
-    // calculate size of the frame (payload + FCS) */
+    /* calculate size of the frame (payload + FCS) */
     packet->length = ieee802154_frame_get_hdr_len(&packet->frame) +
                      packet->frame.payload_len + 1;
 
@@ -72,54 +235,45 @@ int16_t at86rf231_send(at86rf231_packet_t *packet)
         return -1;
     }
 
-    // FCS is added in hardware
+    /* FCS is added in hardware */
     uint8_t pkt[packet->length];
 
     /* generate pkt */
     at86rf231_gen_pkt(pkt, packet);
 
-    // transmit packet
-    at86rf231_xmit(pkt, packet->length);
-    return packet->length;
-}
-
-static void at86rf231_xmit(uint8_t *data, radio_packet_length_t length)
-{
-    // Go to state PLL_ON
+    /* Go to state PLL_ON */
     at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__PLL_ON);
 
-    // wait until it is on PLL_ON state
-    uint8_t status;
-    uint8_t max_wait = 100;   // TODO : move elsewhere, this is in 10us
-
+    /* wait until it is on PLL_ON state */
     do {
-        status = at86rf231_get_status();
+        int max_wait = _MAX_RETRIES;
+        if (!--max_wait) {
+            DEBUG("at86rf231 : ERROR : could not enter PLL_ON mode\n");
+            break;
+        }
+    } while ((at86rf231_get_status() & AT86RF231_TRX_STATUS_MASK__TRX_STATUS)
+             != AT86RF231_TRX_STATUS__PLL_ON);
 
-        hwtimer_wait(HWTIMER_TICKS(10));
+    /* change into TX_ARET_ON state */
+    at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_ARET_ON);
 
+    do {
+        int max_wait = _MAX_RETRIES;
         if (!--max_wait) {
-            printf("at86rf231 : ERROR : could not enter PLL_ON mode");
+            DEBUG("at86rf231 : ERROR : could not enter TX_ARET_ON mode\n");
             break;
         }
-    }
-    while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) != AT86RF231_TRX_STATUS__PLL_ON);
-
-    /* radio driver state: sending */
-    /* will be freed in at86rf231_rx_irq when TRX_END interrupt occurs */
-    driver_state = AT_DRIVER_STATE_SENDING;
+    } while (at86rf231_get_status() != AT86RF231_TRX_STATUS__TX_ARET_ON);
 
-    // copy the packet to the radio FIFO
-    at86rf231_write_fifo(data, length);
+    /* load packet into fifo */
+    at86rf231_write_fifo(pkt, packet->length);
     DEBUG("Wrote to FIFO\n");
 
-    // Start TX
-    at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_START);
-    DEBUG("Started TX\n");
+    return packet->length;
 }
 
 /**
  * @brief Static function to generate byte array from at86rf231 packet.
- *
  */
 static void at86rf231_gen_pkt(uint8_t *buf, at86rf231_packet_t *packet)
 {
diff --git a/drivers/include/at86rf231.h b/drivers/include/at86rf231.h
index ceca8ab778228ec5d2e7a4c64f652095fc720777..80e25bced35c02430c9353e857600fdd37e56778 100644
--- a/drivers/include/at86rf231.h
+++ b/drivers/include/at86rf231.h
@@ -7,7 +7,7 @@
  */
 
 /**
- * @defgroup    drivers_at86rf231
+ * @defgroup    drivers_at86rf231 at86rf231
  * @ingroup     drivers
  * @brief       Device driver for the Atmel AT86RF231 radio
  * @{
@@ -31,34 +31,66 @@
 #include "ieee802154_frame.h"
 #include "at86rf231/at86rf231_settings.h"
 #include "periph/gpio.h"
+#include "netdev/802154.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define AT86RF231_MAX_PKT_LENGTH    127
-#define AT86RF231_MAX_DATA_LENGTH   118
+/**
+ * @brief Maximum length of a frame on at86rf231
+ */
+#define AT86RF231_MAX_PKT_LENGTH    (127)
+
+/**
+ * @brief Maximum payload length
+ * @details Assuming intra PAN short address mode
+ *          results in 2 bytes FCF
+ *          + 1 bytes SEQNr
+ *          + 2 bytes PAN Id
+ *          + 2 bytes destination address
+ *          + 2 bytes source address
+ */
+#define AT86RF231_MAX_DATA_LENGTH   (118)
+
+/**
+ * @brief Broadcast address
+ */
+#define AT86RF231_BROADCAST_ADDRESS (0xFFFF)
+
+/**
+ * @brief at86rf231's lowest supported channel
+ */
+#define AT86RF231_MIN_CHANNEL       (11)
 
 /**
- *  Structure to represent a at86rf231 packet.
+ * @brief at86rf231's highest supported channel
  */
-typedef struct __attribute__((packed))      /* TODO: do we need the packed here? it leads to an
-                                               unaligned pointer -> trouble for M0 systems... */
+#define AT86RF231_MAX_CHANNEL       (26)
+
+/**
+ *  @brief Structure to represent a at86rf231 packet.
+ */
+typedef struct __attribute__((packed))
 {
-    /* @{ */
-    uint8_t length;             /** < the length of the frame of the frame including fcs*/
-    ieee802154_frame_t frame;   /** < the ieee802154 frame */
-    int8_t rssi;                /** < the rssi value */
-    uint8_t crc;                /** < 1 if crc was successfull, 0 otherwise */
-    uint8_t lqi;                /** < the link quality indicator */
-    /* @} */
-}
-at86rf231_packet_t;
+    /** @{ */
+    uint8_t length;             /**< the length of the frame of the frame including fcs*/
+    ieee802154_frame_t frame;   /**< the ieee802154 frame */
+    int8_t rssi;                /**< the rssi value */
+    uint8_t crc;                /**< 1 if crc was successfull, 0 otherwise */
+    uint8_t lqi;                /**< the link quality indicator */
+    /** @} */
+} at86rf231_packet_t;
 
-extern volatile kernel_pid_t transceiver_pid;
+extern netdev_t at86rf231_netdev;   /**< netdev representation of this driver */
 
+/**
+ * @brief States to be assigned to `driver_state`
+ * @{
+ */
 #define AT_DRIVER_STATE_DEFAULT     (0)
 #define AT_DRIVER_STATE_SENDING     (1)
+/** @} */
 
 /**
  * @brief To keep state inside of at86rf231 driver
@@ -68,38 +100,300 @@ extern volatile kernel_pid_t transceiver_pid;
  */
 extern uint8_t driver_state;
 
+/**
+ * @brief Initialize the at86rf231 transceiver
+ */
+int at86rf231_initialize(netdev_t *dev);
+
+#ifdef MODULE_TRANSCEIVER
+/**
+ * @brief Init the at86rf231 for use with RIOT's transceiver module.
+ *
+ * @param[in] tpid The PID of the transceiver thread.
+ */
+
 void at86rf231_init(kernel_pid_t tpid);
-/* void at86rf231_reset(void); */
-void at86rf231_rx(void);
-void at86rf231_rx_handler(void);
-void at86rf231_rx_irq(void *arg);
+#endif
 
-int16_t at86rf231_send(at86rf231_packet_t *packet);
+/**
+ * @brief Turn at86rf231 on.
+ *
+ * @return 1 if the radio was correctly turned on; 0 otherwise.
+ */
+int at86rf231_on(void);
+
+/**
+ * @brief Turn at86rf231 off.
+ */
+void at86rf231_off(void);
+
+/**
+ * @brief Indicate if the at86rf231 is on.
+ *
+ * @return 1 if the radio transceiver is on (active); 0 otherwise.
+ */
+int at86rf231_is_on(void);
+
+/**
+ * @brief Switches the at86rf231 into receive mode.
+ */
+void at86rf231_switch_to_rx(void);
+
+/**
+ * @brief Turns monitor (promiscuous) mode on or off.
+ *
+ * @param[in] mode The desired mode:
+ *                 1 for monitor (promiscuous) mode;
+ *                 0 for normal (auto address-decoding) mode.
+ */
+void at86rf231_set_monitor(int mode);
+
+/**
+ * @brief Indicate if the at86rf231 is in monitor (promiscuous) mode.
+ *
+ * @return 1 if the transceiver is in monitor (promiscuous) mode;
+ *         0 if it is in normal (auto address-decoding) mode.
+ */
+int at86rf231_get_monitor(void);
+
+/**
+ * @brief Set the channel of the at86rf231.
+ *
+ * @param[in] chan The desired channel, valid channels are from 11 to 26.
+ *
+ * @return The tuned channel after calling, or -1 on error.
+ */
+int at86rf231_set_channel(unsigned int chan);
+
+/**
+ * @brief Get the channel of the at86rf231.
+ *
+ * @return The tuned channel.
+ */
+unsigned int at86rf231_get_channel(void);
 
-int8_t at86rf231_set_channel(uint8_t channel);
-uint8_t at86rf231_get_channel(void);
+/**
+ * @brief Sets the short address of the at86rf231.
+ *
+ * @param[in] addr The desired address.
+ *
+ * @return The set address after calling.
+ */
+uint16_t at86rf231_set_address(uint16_t addr);
+
+/**
+ * @brief Gets the current short address of the at86rf231.
+ *
+ * @return The current short address.
+ */
+uint16_t at86rf231_get_address(void);
+
+/**
+ * @brief Sets the IEEE long address of the at86rf231.
+ *
+ * @param[in] addr The desired address.
+ *
+ * @return The set address after calling.
+ */
+uint64_t at86rf231_set_address_long(uint64_t addr);
+
+/**
+ * @brief Gets the current IEEE long address of the at86rf231.
+ *
+ * @return The current IEEE long address.
+ */
+uint64_t at86rf231_get_address_long(void);
 
+/**
+ * @brief Sets the pan ID of the at86rf231.
+ *
+ * @param[in] pan The desired pan ID.
+ *
+ * @return The set pan ID after calling.
+ */
 uint16_t at86rf231_set_pan(uint16_t pan);
+
+/**
+ * @brief Gets the current IEEE long address of the at86rf231.
+ *
+ * @return The current IEEE long address.
+ */
 uint16_t at86rf231_get_pan(void);
 
-radio_address_t at86rf231_set_address(radio_address_t address);
-radio_address_t at86rf231_get_address(void);
-uint64_t at86rf231_get_address_long(void);
-uint64_t at86rf231_set_address_long(uint64_t address);
+/**
+ * @brief Sets the output (TX) power of the at86rf231.
+ *
+ * @param[in] pow The desired TX (output) power in dBm,
+ *                 valid values are -25 to 0; other values
+ *                 will be "saturated" into this range.
+ *
+ * @return The set TX (output) power after calling.
+ */
+int at86rf231_set_tx_power(int pow);
 
-void at86rf231_switch_to_rx(void);
+/**
+ * @brief Gets the current output (TX) power of the at86rf231.
+ *
+ * @return The current TX (output) power.
+ */
+int at86rf231_get_tx_power(void);
+
+/**
+ * @brief Checks if the radio medium is available/clear to send
+ *         ("Clear Channel Assessment" a.k.a. CCA).
+ *
+ * @return a 1 value if radio medium is clear (available),
+ *         a 0 value otherwise.
+ *
+ */
+int at86rf231_channel_is_clear(netdev_t *dev);
 
-void at86rf231_set_monitor(uint8_t mode);
+/**
+ * @brief Interrupt handler, gets fired when a RX overflow happens.
+ *
+ */
+void at86rf231_rxoverflow_irq(void);
+
+/**
+ * @brief Interrupt handler, gets fired when bytes in the RX FIFO are present.
+ *
+ */
+void at86rf231_rx_irq(void);
+
+/**
+ * @brief Sets the function called back when a packet is received.
+ *        (Low-level mechanism, parallel to the `transceiver` module).
+ *
+ * @param[in] dev     The network device to operate on. (Currently not used)
+ * @param[in] recv_cb callback function for 802.15.4 packet arrival
+ *
+ * @return  0 on success
+ * @return  -ENODEV if *dev* is not recognized
+ * @return  -ENOBUFS, if maximum number of registable callbacks is exceeded
+ */
+int at86rf231_add_raw_recv_callback(netdev_t *dev,
+                                 netdev_802154_raw_packet_cb_t recv_cb);
 
-enum {
-    RF86RF231_MAX_TX_LENGTH = 125,
-    RF86RF231_MAX_RX_LENGTH = 127,
-    RF86RF231_MIN_CHANNEL = 11,
-    RF86RF231_MAX_CHANNEL = 26
-};
+/**
+ * @brief Unsets the function called back when a packet is received.
+ *        (Low-level mechanism, parallel to the `transceiver` module).
+ *
+ * @param[in] dev     The network device to operate on. (Currently not used)
+ * @param[in] recv_cb callback function to unset
+ *
+ * @return  0 on success
+ * @return  -ENODEV if *dev* is not recognized
+ * @return  -ENOBUFS, if maximum number of registable callbacks is exceeded
+ */
+int at86rf231_rem_raw_recv_callback(netdev_t *dev,
+                                 netdev_802154_raw_packet_cb_t recv_cb);
 
+/**
+ * @brief Sets a function called back when a data packet is received.
+ *
+ * @param[in] dev     The network device to operate on. (Currently not used)
+ * @param[in] recv_cb callback function for 802.15.4 data packet arrival
+ *
+ * @return  0 on success
+ * @return  -ENODEV if *dev* is not recognized
+ * @return  -ENOBUFS, if maximum number of registable callbacks is exceeded
+ */
+int at86rf231_add_data_recv_callback(netdev_t *dev,
+                                  netdev_rcv_data_cb_t recv_cb);
+
+/**
+ * @brief Unsets a function called back when a data packet is received.
+ *
+ * @param[in] dev     The network device to operate on. (Currently not used)
+ * @param[in] recv_cb callback function to unset
+ *
+ * @return  0 on success
+ * @return  -ENODEV if *dev* is not recognized
+ * @return  -ENOBUFS, if maximum number of registable callbacks is exceeded
+ */
+int at86rf231_rem_data_recv_callback(netdev_t *dev,
+                                  netdev_rcv_data_cb_t recv_cb);
+
+/**
+ * @brief RX handler, process data from the RX FIFO.
+ *
+ */
+void at86rf231_rx_handler(void);
+
+/**
+ * @brief Prepare the at86rf231 TX buffer to send with the given packet.
+ *
+ * @param[in] dev  The network device to operate on. (Currently not used)
+ * @param[in] kind Kind of packet to transmit.
+ * @param[in] dest Address of the node to which the packet is sent.
+ * @param[in] use_long_addr 1 to use the 64-bit address mode
+ *                          with *dest* param; 0 to use
+ *                          "short" PAN-centric mode.
+ * @param[in] wants_ack 1 to request an acknowledgement
+ *                      from the receiving node for this packet;
+ *                      0 otherwise.
+ * @param[in] upper_layer_hdrs  header data from higher network layers from
+ *                              highest to lowest layer. Must be prepended to
+ *                              the data stream by the network device. May be
+ *                              NULL if there are none.
+ * @param[in] buf Pointer to the buffer containing the payload
+ *                of the 802.15.4 packet to transmit.
+ *                The frame header (i.e.: FCS, sequence number,
+ *                src and dest PAN and addresses) is inserted
+ *                using values in accord with *kind* parameter
+ *                and transceiver configuration.
+ * @param[in] len Length (in bytes) of the outgoing packet payload.
+ *
+ * @return @ref netdev_802154_tx_status_t
+ */
+netdev_802154_tx_status_t at86rf231_load_tx_buf(netdev_t *dev,
+                                             netdev_802154_pkt_kind_t kind,
+                                             netdev_802154_node_addr_t *dest,
+                                             int use_long_addr,
+                                             int wants_ack,
+                                             netdev_hlist_t *upper_layer_hdrs,
+                                             void *buf,
+                                             unsigned int len);
+
+/**
+ * @brief Transmit the data loaded into the at86rf231 TX buffer.
+ *
+ * @param[in] dev The network device to operate on. (Currently not used)
+ *
+ * @return @ref netdev_802154_tx_status_t
+ */
+netdev_802154_tx_status_t at86rf231_transmit_tx_buf(netdev_t *dev);
+
+/**
+ * @brief Send function, sends a at86rf231_packet_t over the air.
+ *
+ * @param[in] *packet The Packet which will be send.
+ *
+ * @return The count of bytes which are send or -1 on error
+ *
+ */
+int16_t at86rf231_send(at86rf231_packet_t *packet);
+
+/**
+ * RX Packet Buffer, read from the transceiver, filled by the at86rf231_rx_handler.
+ */
 extern at86rf231_packet_t at86rf231_rx_buffer[AT86RF231_RX_BUF_SIZE];
 
+/**
+ * Get at86rf231's status byte
+ */
+uint8_t at86rf231_get_status(void);
+
+/**
+ * Get at86rf231's TRAC status byte
+ */
+uint8_t at86rf231_get_trac_status(void);
+
+/**
+ * at86rf231 low-level radio driver definition.
+ */
+extern const netdev_802154_driver_t at86rf231_driver;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/drivers/include/at86rf231/at86rf231_settings.h b/drivers/include/at86rf231/at86rf231_settings.h
index c1bf82e043dfcf841cea7d75cdbfccedb7c55b4e..274202e82a2e86a811efc6c9df153030e4812910 100644
--- a/drivers/include/at86rf231/at86rf231_settings.h
+++ b/drivers/include/at86rf231/at86rf231_settings.h
@@ -158,6 +158,8 @@ enum at86rf231_trx_status {
 };
 
 enum at86rf231_trx_state {
+    AT86RF231_TRX_STATE_MASK__TRAC = 0xe0,
+
     AT86RF231_TRX_STATE__NOP = 0x00,
     AT86RF231_TRX_STATE__TX_START = 0x02,
     AT86RF231_TRX_STATE__FORCE_TRX_OFF = 0x03,
@@ -167,6 +169,13 @@ enum at86rf231_trx_state {
     AT86RF231_TRX_STATE__PLL_ON = 0x09,
     AT86RF231_TRX_STATE__RX_AACK_ON = 0x16,
     AT86RF231_TRX_STATE__TX_ARET_ON = 0x19,
+
+    AT86RF231_TRX_STATE__TRAC_SUCCESS = 0x00,
+    AT86RF231_TRX_STATE__TRAC_SUCCESS_DATA_PENDING = 0x20,
+    AT86RF231_TRX_STATE__TRAC_SUCCESS_WAIT_FOR_ACK = 0x40,
+    AT86RF231_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE = 0x60,
+    AT86RF231_TRX_STATE__TRAC_NO_ACK = 0xa0,
+    AT86RF231_TRX_STATE__TRAC_INVALID = 0xe0,
 };
 
 enum at86rf231_phy_cc_cca {
@@ -216,7 +225,7 @@ enum at86rf231_xosc_ctrl {
     AT86RF231_XOSC_CTRL__XTAL_MODE_EXTERNAL = 0xF0,
 };
 
-enum {
+enum at86rf231_timing {
     AT86RF231_TIMING__VCC_TO_P_ON = 330,
     AT86RF231_TIMING__SLEEP_TO_TRX_OFF = 380,
     AT86RF231_TIMING__TRX_OFF_TO_PLL_ON = 110,
@@ -227,8 +236,20 @@ enum {
     AT86RF231_TIMING__RESET_TO_TRX_OFF = 37,
 };
 
+enum at86rf231_xah_ctrl_1 {
+    AT86RF231_XAH_CTRL_1__AACK_FLTR_RES_FT = 0x20,
+    AT86RF231_XAH_CTRL_1__AACK_UPLD_RES_FT = 0x10,
+    AT86RF231_XAH_CTRL_1__AACK_ACK_TIME = 0x04,
+    AT86RF231_XAH_CTRL_1__AACK_PROM_MODE = 0x02,
+};
+
+enum at86rf231_csma_seed_1 {
+    AT86RF231_CSMA_SEED_1__AACK_SET_PD = 0x20,
+    AT86RF231_CSMA_SEED_1__AACK_DIS_ACK = 0x10,
+    AT86RF231_CSMA_SEED_1__AACK_I_AM_COORD = 0x08,
+};
+
 #ifdef __cplusplus
 }
 #endif
-
-#endif
+#endif /* AT86AT86RF231_SETTINGS_H */
diff --git a/drivers/include/netdev/802154.h b/drivers/include/netdev/802154.h
new file mode 100644
index 0000000000000000000000000000000000000000..e949fe60693c50bc2ab4abf1c76b136437378d83
--- /dev/null
+++ b/drivers/include/netdev/802154.h
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2014 INRIA
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup    netdev_802154  IEEE 802.15.4 interface
+ * @addtogroup  netdev
+ * @{
+ * @file  netdev/802154.h
+ * @brief API definitions for 802.15.4 radio transceivers' drivers
+ * @author Kévin Roussel <Kevin.Roussel@inria.fr>
+ * @author Martine Lenders <mlenders@inf.fu-berlin.de>
+ *
+ */
+
+#ifndef __NETDEV_802154_H_
+#define __NETDEV_802154_H_
+
+#include <stdint.h>
+
+#include "netdev/base.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Callback function type for receiving incoming packets
+ *        from 802.15.4 radio transceiver.
+ *
+ * @param[in] buf  Pointer to the buffer containing the incoming
+ *                 802.15.4 packet's raw data.
+ * @param[in] len  Length (in bytes) of the incoming packet's raw data.
+ * @param[in] rssi Value of the Receive Signal Strength Indicator (RSSI)
+ *                 for the incoming packet.
+ * @param[in] lqi  Value of the Link Quality Indicator (LQI)
+ *                 for the incoming packet.
+ * @param[in] crc_ok 1 if incoming packet's checksum (CRC) is valid;
+ *                   0 otherwise (corrupted packet).
+ */
+typedef void (* netdev_802154_raw_packet_cb_t)(netdev_t *dev,
+        void *buf,
+        size_t len,
+        int8_t rssi,
+        uint8_t lqi,
+        int crc_ok);
+
+/**
+ * @brief Kind of packet to prepare/configure for transmission.
+ *
+ */
+typedef enum {
+    /** Beacon packet */
+    NETDEV_802154_PKT_KIND_BEACON,
+
+    /** Standard data packet */
+    NETDEV_802154_PKT_KIND_DATA,
+
+    /** Acknowledgement packet */
+    NETDEV_802154_PKT_KIND_ACK,
+
+    /** MAC command */
+    NETDEV_802154_PKT_KIND_MAC_CMD,
+
+    /** invalid packet kind */
+    NETDEV_802154_PKT_KIND_INVALID = -1
+
+} netdev_802154_pkt_kind_t;
+
+/**
+ * @brief Return values for packet emission function of 802.15.4 radio driver.
+ *
+ */
+typedef enum {
+    /** Transmission completed successfully */
+    NETDEV_802154_TX_STATUS_OK,
+
+    /** Device not found or not an IEEE 802.15.4 device */
+    NETDEV_802154_TX_STATUS_NO_DEV,
+
+    /** Transmission buffer underflow (forgot to call netdev_802154_driver_t::load_tx()
+        before netdev_802154_driver_t::transmit() ) */
+    NETDEV_802154_TX_STATUS_UNDERFLOW,
+
+    /** Transmission cannot start because radio medium is already busy */
+    NETDEV_802154_TX_STATUS_MEDIUM_BUSY,
+
+    /** Transmission failed because of collision on radio medium */
+    NETDEV_802154_TX_STATUS_COLLISION,
+
+    /** Wrong parameter given to TX-related functions */
+    NETDEV_802154_TX_STATUS_INVALID_PARAM,
+
+    /** Too much given data to be included in a single packet */
+    NETDEV_802154_TX_STATUS_PACKET_TOO_LONG,
+
+    /** Transmission supposedly failed since no ACK packet
+        has been received as response */
+    NETDEV_802154_TX_STATUS_NOACK,
+
+    /** Transmission failed because of an unexpected (fatal?) error */
+    NETDEV_802154_TX_STATUS_ERROR,
+
+} netdev_802154_tx_status_t;
+
+/**
+ * @brief Definition of an IEEE 802.15.4 node address.
+ *
+ * @details The `union` allows to choose between PAN-centric addressing
+ *           ("volatile" 16-bit address and 16-bit PAN ID), or canonical
+ *           IEEE 64-bit ("long") addressing.
+ *
+ */
+typedef union {
+    /** @brief PAN-centric ("short") addressing mode */
+    struct {
+        /** @brief Address assigned to the node within its current PAN */
+        uint16_t addr;
+        /** @brief ID of the PAN to which the node is currently associated */
+        uint16_t id;
+    } pan;
+    /** @brief 64-bit ("long") addressing mode */
+    uint64_t long_addr;
+} netdev_802154_node_addr_t;
+
+/**
+ * @brief IEEE 802.15.4 radio driver API definition.
+ *
+ * @details This is the set of functions that must be implemented
+ *          by any driver for a 802.15.4 radio transceiver.
+ *
+ * @extends netdev_driver_t
+ */
+typedef struct {
+    /**
+     * @see netdev_driver_t::init
+     */
+    int (*init)(netdev_t *dev);
+
+    /**
+     * @details  wraps netdev_802154_driver_t::send with
+     *
+     * @see netdev_driver_t::send_data
+     */
+    int (*send_data)(netdev_t *dev, void *dest, size_t dest_len,
+                     netdev_hlist_t *upper_layer_hdrs, void *data,
+                     size_t data_len);
+
+    /**
+     * @see netdev_driver_t::add_receive_data_callback
+     */
+    int (*add_receive_data_callback)(netdev_t *dev, netdev_rcv_data_cb_t cb);
+
+    /**
+     * @see netdev_driver_t::rem_receive_data_callback
+     */
+    int (*rem_receive_data_callback)(netdev_t *dev, netdev_rcv_data_cb_t cb);
+
+    /**
+     * @see netdev_driver_t::get_option
+     *
+     * @details The options are constrained as follows:
+     *
+     *         *opt*                       | type        | *value_len*
+     *         --------------------------- | ----------- | -----------
+     *         NETDEV_OPT_CHANNEL          | uint8_t     | >= 1
+     *         NETDEV_OPT_ADDRESS          | uint16_t    | >= 2
+     *         NETDEV_OPT_NID              | uint16_t    | >= 2
+     *         NETDEV_OPT_ADDRESS_LONG     | uint64_t    | >= 8
+     *         NETDEV_OPT_TX_POWER         | int         | >= 4
+     *         NETDEV_OPT_MAX_PACKET_SIZE  | uint8_t     | >= 1
+     */
+    int (*get_option)(netdev_t *dev, netdev_opt_t opt, void *value,
+                      size_t *value_len);
+
+    /**
+     * @see netdev_driver_t::set_option
+     *
+     * @details The options are constrained as follows:
+     *
+     *         *opt*                       | type        | *value_len* | *value*
+     *         --------------------------- | ----------- | ----------- | --------
+     *         NETDEV_OPT_CHANNEL          | uint8_t     | >= 1        | <= 26
+     *         NETDEV_OPT_ADDRESS          | uint16_t    | >= 2        |
+     *         NETDEV_OPT_NID              | uint16_t    | >= 2        |
+     *         NETDEV_OPT_ADDRESS_LONG     | uint64_t    | >= 8        |
+     *         NETDEV_OPT_TX_POWER         | int         | >= 4        |
+     *
+     *         NETDEV_OPT_MAX_PACKET_SIZE can not be set.
+     */
+    int (*set_option)(netdev_t *dev, netdev_opt_t opt, void *value,
+                      size_t value_len);
+
+    /**
+     * @see netdev_driver_t::get_state
+     */
+    int (*get_state)(netdev_t *dev, netdev_state_t *state);
+
+    /**
+     * @see netdev_driver_t::set_state
+     */
+    int (*set_state)(netdev_t *dev, netdev_state_t state);
+
+    /**
+     * @see netdev_driver_t::event
+     */
+    void (*event)(netdev_t *dev, uint32_t event_type);
+
+    /**
+     * @brief Load the transceiver TX buffer with the given
+     *        IEEE 802.15.4 packet.
+     *
+     * @param[in] dev  the network device
+     * @param[in] kind Kind of packet to transmit.
+     * @param[in] dest Address of the node to which the packet is sent.
+     * @param[in] use_long_addr 1 to use the 64-bit address mode
+     *                          with *dest* param; 0 to use
+     *                          "short" PAN-centric mode.
+     * @param[in] wants_ack 1 to request an acknowledgement
+     *                      from the receiving node for this packet;
+     *                      0 otherwise.
+     * @param[in] upper_layer_hdrs  header data from higher network layers from
+     *                              highest to lowest layer. Must be prepended to
+     *                              the data stream by the network device. May be
+     *                              NULL if there are none.
+     * @param[in] buf Pointer to the buffer containing the payload
+     *                of the 802.15.4 packet to transmit.
+     *                The frame header (i.e.: FCS, sequence number,
+     *                src and dest PAN and addresses) is inserted
+     *                using values in accord with *kind* parameter
+     *                and transceiver configuration.
+     * @param[in] len Length (in bytes) of the outgoing packet payload.
+     *
+     * @return The outcome of this packet's transmission.
+     *         @see netdev_802154_tx_status_t
+     */
+    netdev_802154_tx_status_t (* load_tx)(netdev_t *dev,
+                                          netdev_802154_pkt_kind_t kind,
+                                          netdev_802154_node_addr_t *dest,
+                                          int use_long_addr,
+                                          int wants_ack,
+                                          netdev_hlist_t *upper_layer_hdrs,
+                                          void *buf,
+                                          unsigned int len);
+
+    /**
+     * @brief Transmit the data loaded into the transceiver TX buffer.
+     *
+     * @param[in] dev the network device
+     *
+     * @return The outcome of this packet's transmission.
+     *         @see netdev_802154_tx_status_t
+     */
+    netdev_802154_tx_status_t (* transmit)(netdev_t *dev);
+
+    /**
+     * @brief Transmit the given IEEE 802.15.4 packet,
+     *        by calling successively functions netdev_802154_driver_t::load_tx()
+     *        and netdev_802154_driver_t::transmit().
+     *
+     * @param[in] dev  the network device
+     * @param[in] kind Kind of packet to transmit.
+     * @param[in] dest Address of the node to which the packet is sent.
+     * @param[in] use_long_addr 1 to use the 64-bit address mode
+     *                          with *dest* param; 0 to use
+     *                          "short" PAN-centric mode.
+     * @param[in] wants_ack 1 to request an acknowledgement
+     *                      from the receiving node for this packet;
+     *                      0 otherwise.
+     * @param[in] upper_layer_hdrs  header data from higher network layers from
+     *                              highest to lowest layer. Must be prepended to
+     *                              the data stream by the network device. May be
+     *                              NULL if there are none.
+     * @param[in] buf Pointer to the buffer containing the payload
+     *                of the 802.15.4 packet to transmit.
+     *                The frame header (i.e.: FCS, sequence number,
+     *                src and dest PAN and addresses) is inserted
+     *                using values in accord with *kind* parameter
+     *                and transceiver configuration.
+     * @param[in] len Length (in bytes) of the outgoing packet payload.
+     *
+     * @return The outcome of this packet's transmission.
+     *         @see netdev_802154_tx_status_t
+     */
+    netdev_802154_tx_status_t (* send)(netdev_t *dev,
+                                       netdev_802154_pkt_kind_t kind,
+                                       netdev_802154_node_addr_t *dest,
+                                       int use_long_addr,
+                                       int wants_ack,
+                                       netdev_hlist_t *upper_layer_hdrs,
+                                       void *buf,
+                                       unsigned int len);
+
+    /**
+     * @brief Add a function to be called back when the radio transceiver
+     *        has received a incoming packet.
+     *
+     * @details  This function differentiates from
+     *          netdev_driver_t::add_receive_data_callback() as it expects
+     *          a callback that excepts the raw frame format of IEEE 802.15.4,
+     *          rather than just the source and destination addresses and the
+     *          payload.
+     *
+     * @param[in] dev       the network device
+     * @param[in] recv_func the callback function to invoke for each
+     *                      packet received by the radio transceiver.
+     * @see netdev_802153_raw_packet_cb_t
+     *
+     * @return  0, on success
+     * @return  -ENOBUFS, if maximum number of registrable callbacks is exceeded
+     * @return  -ENODEV, if *dev* is not recognized
+     */
+    int (* add_receive_raw_callback)(netdev_t *dev, netdev_802154_raw_packet_cb_t recv_func);
+
+    /**
+     * @brief Remove a callback set by netdev_802154_driver_t::add_receive_raw_callback()
+     *
+     * @param[in] dev       the network device
+     * @param[in] recv_func the callback function to invoke for each
+     *                      packet received by the radio transceiver.
+     * @see netdev_802153_raw_packet_cb_t
+     *
+     * @return  0, on success
+     * @return  -ENODEV, if *dev* is not recognized
+     */
+    int (* rem_receive_raw_callback)(netdev_t *dev, netdev_802154_raw_packet_cb_t recv_func);
+
+    /**
+     * @brief Indicates if the radio medium is available for transmission
+     *        ("Clear Channel Assessment").
+     *
+     * @param[in] dev the network device
+     *
+     * @return 1 if radio medium is "clear" (available);
+     * @return 0 if another transmission is already running.
+     * @return  -ENODEV, if *dev* is not recognized
+     */
+    int (* channel_is_clear)(netdev_t *dev);
+} netdev_802154_driver_t;
+
+/* define to implement yourself and omit compilation of this function */
+#ifndef NETDEV_802154_SEND_DATA_OVERLOAD
+/**
+ * @brief  wraps netdev_802154_driver_t::send(), default value for
+ *         netdev_802154_driver_t::send_data().
+ *
+ * @param[in] dev               the network device
+ * @param[in] dest              the (hardware) destination address for the data
+ *                              in host byte order.
+ * @param[in] dest_len          the length of *dest* in byte
+ * @param[in] upper_layer_hdrs  header data from higher network layers from
+ *                              highest to lowest layer. Must be prepended to
+ *                              the data stream by the network device. May be
+ *                              NULL if there are none.
+ * @param[in] data              the data to send
+ * @param[in] data_len          the length of *data* in byte
+ *
+ * @return  the number of byte actually (data_len + total length of upper layer
+ *          headers) send on success
+ * @return  -EAFNOSUPPORT if address of length dest_len is not supported
+ *          by the device *dev*
+ * @return  -EBUSY if transmission cannot start because radio medium is already
+ *          busy or collision on radio medium occured.
+ * @return  -EINVAL if wrong parameter was given
+ * @return  -ENODEV if *dev* is not recognized as IEEE 802.15.4 device
+ * @return  -EMSGSIZE if the total frame size is too long to fit in a frame
+ *          of the device *dev*
+ * @return  -EIO if any other occured (netdev_802154_driver_t::send() returned
+ *          NETDEV_802154_TX_STATUS_ERROR)
+ */
+int netdev_802154_send_data(netdev_t *dev, void *dest, size_t dest_len,
+                            netdev_hlist_t *upper_layer_hdrs, void *data,
+                            size_t data_len);
+#endif /* NETDEV_802154_SEND_DATA_OVERLOAD */
+
+/* define to implement yourself and omit compilation of this function */
+#ifndef NETDEV_802154_SEND_OVERLOAD
+/**
+ * @brief Transmit the given IEEE 802.15.4 packet, by calling
+ *        functions netdev_802154_driver_t::load_tx() and
+ *        netdev_802154_driver_t::transmit() successfully. Default value for
+ *        netdev_802154_driver_t::send()
+ *
+ * @param[in] dev  the network device
+ * @param[in] kind Kind of packet to transmit.
+ * @param[in] dest Address of the node to which the packet is sent.
+ * @param[in] use_long_addr 1 to use the 64-bit address mode
+ *                          with *dest* param; 0 to use
+ *                          "short" PAN-centric mode.
+ * @param[in] wants_ack 1 to request an acknowledgement
+ *                      from the receiving node for this packet;
+ *                      0 otherwise.
+ * @param[in] upper_layer_hdrs  header data from higher network layers from
+ *                              highest to lowest layer. Must be prepended to
+ *                              the data stream by the network device. May be
+ *                              NULL if there are none.
+ * @param[in] buf Pointer to the buffer containing the payload
+ *                of the 802.15.4 packet to transmit.
+ *                The frame header (i.e.: FCS, sequence number,
+ *                src and dest PAN and addresses) is inserted
+ *                using values in accord with *kind* parameter
+ *                and transceiver configuration.
+ * @param[in] len Length (in bytes) of the outgoing packet payload.
+ *
+ * @return @ref netdev_802154_tx_status_t
+ */
+netdev_802154_tx_status_t netdev_802154_send(netdev_t *dev,
+        netdev_802154_pkt_kind_t kind,
+        netdev_802154_node_addr_t *dest,
+        int use_long_addr,
+        int wants_ack,
+        netdev_hlist_t *upper_layer_hdrs,
+        void *buf,
+        unsigned int len);
+#endif /* NETDEV_802154_SEND_OVERLOAD */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NETDEV_802154_H_ */
+
+/**
+ * @}
+ */
diff --git a/drivers/include/netdev/base.h b/drivers/include/netdev/base.h
index 94fa1947fb457c00321fd6c5d91f0ba0835e26e8..f8fde140a9cc5e19d8ff8f61c6f7314ad6411575 100644
--- a/drivers/include/netdev/base.h
+++ b/drivers/include/netdev/base.h
@@ -41,6 +41,8 @@ typedef enum {
     NETDEV_TYPE_UNKNOWN = 0,    /**< Type was not specified and may not
                                      understand this API */
     NETDEV_TYPE_BASE,           /**< Device understands this API */
+    NETDEV_TYPE_802154,         /**< Device understands this API and the API
+                                     defined in @ref netdev_802154 */
 } netdev_type_t;
 
 /**
@@ -105,6 +107,10 @@ typedef enum {
                                          signed value in host byte order */
     NETDEV_OPT_MAX_PACKET_SIZE,     /**< Maximum packet size the device supports
                                          unsigned value in host byte order */
+    NETDEV_OPT_SRC_LEN,             /**< Default mode the source address is
+                                         set to as value of `size_t`. (e.g.
+                                         either PAN-centric 16-bit address or
+                                         EUI-64 in IEEE 802.15.4) */
 
     /**
      * @brief   Last value for @netdev_opt_t defined here
diff --git a/drivers/include/netdev/default.h b/drivers/include/netdev/default.h
index 4446bb62ceb882587bd28e1e24fc1f02e3ff9a7a..0d525af9ba3c99a11b091f42d08a0021386f5597 100644
--- a/drivers/include/netdev/default.h
+++ b/drivers/include/netdev/default.h
@@ -27,6 +27,13 @@
  *
  * @brief   Default device as a pointer of netdev_t.
  */
+#ifdef MODULE_AT86RF231
+#include "at86rf231.h"
+
+#ifndef NETDEV_DEFAULT
+#define NETDEV_DEFAULT  ((netdev_t *)(&at86rf231_netdev))
+#endif /* NETDEV_DEFAULT */
+#endif /* MODULE_AT86RF231 */
 
 #ifdef MODULE_NATIVENET
 
diff --git a/drivers/netdev/802154/802154.c b/drivers/netdev/802154/802154.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2cf538aabbee5afa977b5e314a10dda8eebcbaa
--- /dev/null
+++ b/drivers/netdev/802154/802154.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 Martin 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.
+ */
+
+/**
+ * @addtogroup  netdev
+ * @{
+ *
+ * @file        802154.c
+ * @brief       Provides wrappers of @ref netdev/base.h functions to
+ *              netdev/802154.h functions.
+ *
+ * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "netdev/802154.h"
+
+static inline netdev_802154_driver_t *_get_driver(netdev_t *dev)
+{
+    return (netdev_802154_driver_t *)dev->driver;
+}
+
+/* define to implement yourself and omit compilation of this function */
+#ifndef NETDEV_802154_SEND_DATA_OVERLOAD
+static size_t _get_src_len(netdev_t *dev)
+{
+    size_t src_len, src_len_len = sizeof(size_t);
+
+    if (_get_driver(dev)->get_option(dev, NETDEV_OPT_SRC_LEN, &src_len, &src_len_len) < 0) {
+        return 2;
+    }
+
+    return src_len;
+}
+
+int netdev_802154_send_data(netdev_t *dev, void *dest, size_t dest_len,
+                            netdev_hlist_t *upper_layer_hdrs, void *data,
+                            size_t data_len)
+{
+    int use_long_addr;
+
+    if (dev == NULL || dev->type != NETDEV_TYPE_802154) {
+        return -ENODEV;
+    }
+
+    use_long_addr = _get_src_len(dev) == 8;
+
+    if (dest_len != 8 && dest_len != 4) { /* 8 for EUI-64, 4 for short address + PAN ID*/
+        return -EAFNOSUPPORT;
+    }
+
+    switch (_get_driver(dev)->send(dev, NETDEV_802154_PKT_KIND_DATA,
+                                   (netdev_802154_node_addr_t *)dest,
+                                   use_long_addr, 0, upper_layer_hdrs,
+                                   data, data_len)) {
+        case NETDEV_802154_TX_STATUS_OK:
+            return (int)(data_len + netdev_get_hlist_len(upper_layer_hdrs));
+
+        case NETDEV_802154_TX_STATUS_MEDIUM_BUSY:
+        case NETDEV_802154_TX_STATUS_COLLISION:
+            return -EBUSY;
+
+        case NETDEV_802154_TX_STATUS_INVALID_PARAM:
+            return -EINVAL;
+
+        case NETDEV_802154_TX_STATUS_PACKET_TOO_LONG:
+            return -EMSGSIZE;
+
+        case NETDEV_802154_TX_STATUS_ERROR:
+        default:
+            return -EIO;
+            /* NETDEV_802154_TX_STATUS_UNDERFLOW can not happen since
+             * netdev_802154_driver_t::send always calls
+             * netdev_802154_driver_t::load_tx */
+            /* NETDEV_802154_TX_STATUS_NOACK can not happen since
+             * wants_ack == 0 */
+    }
+}
+#endif /* NETDEV_802154_SEND_DATA_OVERLOAD */
+
+/* define to implement yourself and omit compilation of this function */
+#ifndef NETDEV_802154_SEND_OVERLOAD
+netdev_802154_tx_status_t netdev_802154_send(netdev_t *dev,
+        netdev_802154_pkt_kind_t kind,
+        netdev_802154_node_addr_t *dest,
+        int use_long_addr,
+        int wants_ack,
+        netdev_hlist_t *upper_layer_hdrs,
+        void *buf,
+        unsigned int len)
+{
+    netdev_802154_tx_status_t status;
+
+    if (dev == NULL || dev->type != NETDEV_TYPE_802154) {
+        return NETDEV_802154_TX_STATUS_NO_DEV;
+    }
+
+    status = _get_driver(dev)->load_tx(dev, kind, dest, use_long_addr, wants_ack,
+                                       upper_layer_hdrs, buf, len);
+
+    if (status != NETDEV_802154_TX_STATUS_OK) {
+        return status;
+    }
+
+    return _get_driver(dev)->transmit(dev);
+}
+#endif /* NETDEV_802154_SEND_OVERLOAD */
+
+/**
+ * @}
+ */
diff --git a/drivers/netdev/802154/Makefile b/drivers/netdev/802154/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..18db41909ad13949f4fa950640e92ddc9b2e4f78
--- /dev/null
+++ b/drivers/netdev/802154/Makefile
@@ -0,0 +1,5 @@
+MODULE := netdev_802154
+
+INCLUDES += -I$(RIOTBASE)/drivers/include
+
+include $(RIOTBASE)/Makefile.base
diff --git a/drivers/netdev/base/base.c b/drivers/netdev/base/base.c
index ff22b679e8a7b96afb9b0df157dc7125e118809b..abfd8316b4f9ed333d55bcf63d9664876aae7431 100644
--- a/drivers/netdev/base/base.c
+++ b/drivers/netdev/base/base.c
@@ -31,7 +31,7 @@ size_t netdev_get_hlist_len(const netdev_hlist_t *hlist)
 
     do {
         length += ptr->header_len;
-        clist_advance((clist_node_t **)&ptr);
+        netdev_hlist_advance(&ptr);
     } while (ptr != hlist);
 
     return length;
diff --git a/sys/config/config.c b/sys/config/config.c
index 12251d509431b718ba3124aaef2ca5b2fa5b9303..b6b595674b98b9028d21d0e9512ac0954063c04a 100644
--- a/sys/config/config.c
+++ b/sys/config/config.c
@@ -23,6 +23,7 @@ config_t sysconfig  = {
 #ifdef HAS_RADIO
     0,      /**< default radio address */
     0,      /**< default radio channel */
+    1,      /**< default radio PAN id   */
 #endif
-    "foobar", /**< default name */
+    "foobar",   /**< default name */
 };
diff --git a/sys/include/config.h b/sys/include/config.h
index c2162419a0448bb88890a247296f1ba691d31947..fef77ebded20c2a3c8c9b0b76fccd71e83d05b6c 100644
--- a/sys/include/config.h
+++ b/sys/include/config.h
@@ -45,6 +45,7 @@ typedef struct {
 #ifdef HAS_RADIO
     radio_address_t radio_address;  /**< address for radio communication */
     uint8_t radio_channel;          /**< current frequency               */
+    uint16_t radio_pan_id;          /**< PAN id for radio communication  */
 #endif
     /* cppcheck-suppress unusedStructMember : useful for debug purposes */
     char name[CONFIG_NAME_LEN];     /**< name of the node                */
diff --git a/sys/shell/commands/sc_transceiver.c b/sys/shell/commands/sc_transceiver.c
index f4b8a7fe464278f66a9d2372b55356a286a6a5c4..16b1b264ebd71c7a76fa14ca9de697de75344c9d 100644
--- a/sys/shell/commands/sc_transceiver.c
+++ b/sys/shell/commands/sc_transceiver.c
@@ -218,8 +218,8 @@ void _transceiver_send_handler(int argc, char **argv)
         puts("Transceiver not initialized");
         return;
     }
-    if (argc != 3) {
-        printf("Usage:\t%s <ADDR> <MSG>\n", argv[0]);
+    if (argc < 3) {
+        printf("Usage:\t%s <ADDR> <MSG> [PAN]\n", argv[0]);
         return;
     }
 
@@ -243,8 +243,13 @@ void _transceiver_send_handler(int argc, char **argv)
     p.frame.payload_len = strlen(text_msg) + 1;
     p.frame.fcf.dest_addr_m = IEEE_802154_SHORT_ADDR_M;
     p.frame.fcf.src_addr_m = IEEE_802154_SHORT_ADDR_M;
-    p.frame.dest_pan_id = 1;
     p.frame.dest_addr[1] = atoi(argv[1]);
+    if (argc == 4) {
+        p.frame.dest_pan_id = atoi(argv[3]);
+    }
+    else {
+        p.frame.dest_pan_id = 1;
+    }
 #else
     p.data = (uint8_t *) text_msg;
     p.length = strlen(text_msg) + 1;