diff --git a/boards/native/Makefile.dep b/boards/native/Makefile.dep
index 2639777a1d2d82234ff36e87173df57079a83a13..8eec472da082e4b1542813c6f8600c7bffa1eb40 100644
--- a/boards/native/Makefile.dep
+++ b/boards/native/Makefile.dep
@@ -14,6 +14,7 @@ ifneq (,$(filter can,$(USEMODULE)))
 endif
 
 ifneq (,$(filter socket_zep,$(USEMODULE)))
+  USEMODULE += iolist
   USEMODULE += netdev_ieee802154
   USEMODULE += checksum
   USEMODULE += random
diff --git a/cpu/cc2538/radio/cc2538_rf_netdev.c b/cpu/cc2538/radio/cc2538_rf_netdev.c
index ad071120fa812f1994ddd9df160f89f4a10e65fa..71f6206c86a7b9a341e4e1f7f54fa7708dbe2dc4 100644
--- a/cpu/cc2538/radio/cc2538_rf_netdev.c
+++ b/cpu/cc2538/radio/cc2538_rf_netdev.c
@@ -33,22 +33,6 @@
 
 #define _MAX_MHR_OVERHEAD   (25)
 
-static int  _get(netdev_t *dev, netopt_t opt, void *value, size_t max_len);
-static int  _set(netdev_t *dev, netopt_t opt, const void *value, size_t value_len);
-static int  _send(netdev_t *netdev, const struct iovec *vector, unsigned count);
-static int  _recv(netdev_t *netdev, void *buf, size_t len, void *info);
-static void _isr(netdev_t *netdev);
-static int  _init(netdev_t *dev);
-
-const netdev_driver_t cc2538_rf_driver = {
-    .get  = _get,
-    .set  = _set,
-    .send = _send,
-    .recv = _recv,
-    .isr  = _isr,
-    .init = _init,
-};
-
 /* Reference pointer for the IRQ handler */
 static netdev_t *_dev;
 
@@ -253,7 +237,7 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *value, size_t value_
     return res;
 }
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
+static int _send(netdev_t *netdev, const iolist_t *iolist)
 {
     (void) netdev;
 
@@ -268,8 +252,8 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
        start of the FIFO, so we can come back and update it later */
     rfcore_write_byte(0);
 
-    for (unsigned i = 0; i < count; i++) {
-        pkt_len += vector[i].iov_len;
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        pkt_len += iol->iol_len;
 
         if (pkt_len > CC2538_RF_MAX_DATA_LEN) {
             DEBUG("cc2538_rf: packet too large (%u > %u)\n",
@@ -277,7 +261,7 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
             return -EOVERFLOW;
         }
 
-        rfcore_write_fifo(vector[i].iov_base, vector[i].iov_len);
+        rfcore_write_fifo(iol->iol_base, iol->iol_len);
     }
 
 #ifdef MODULE_NETSTATS_L2
@@ -407,3 +391,12 @@ static int _init(netdev_t *netdev)
 
     return 0;
 }
+
+const netdev_driver_t cc2538_rf_driver = {
+    .get  = _get,
+    .set  = _set,
+    .send = _send,
+    .recv = _recv,
+    .isr  = _isr,
+    .init = _init,
+};
diff --git a/cpu/native/socket_zep/socket_zep.c b/cpu/native/socket_zep/socket_zep.c
index d3e51c69ed27079c7efbf567055e11755b1fcb63..162d55ad02914fcd500a9393b110141017c30d8a 100644
--- a/cpu/native/socket_zep/socket_zep.c
+++ b/cpu/native/socket_zep/socket_zep.c
@@ -36,23 +36,6 @@
 
 #define _UNIX_NTP_ERA_OFFSET    (2208988800U)
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned n);
-static int _recv(netdev_t *netdev, void *buf, size_t n, void *info);
-static void _isr(netdev_t *netdev);
-static int _init(netdev_t *netdev);
-static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len);
-static int _set(netdev_t *netdev, netopt_t opt, const void *value,
-                size_t value_len);
-
-static const netdev_driver_t socket_zep_driver = {
-    .send = _send,
-    .recv = _recv,
-    .init = _init,
-    .isr = _isr,
-    .get = _get,
-    .set = _set,
-};
-
 static size_t _zep_hdr_fill_v2_data(socket_zep_t *dev, zep_v2_data_hdr_t *hdr,
                                     size_t payload_len)
 {
@@ -85,24 +68,23 @@ static inline size_t _zep_hdr_fill(socket_zep_t *dev, zep_hdr_t *hdr,
                                  payload_len);
 }
 
-static size_t _prep_vector(socket_zep_t *dev, const struct iovec *vector,
+static size_t _prep_vector(socket_zep_t *dev, const iolist_t *iolist,
                            unsigned n, struct iovec *out)
 {
-    size_t bytes = 0;
+    size_t bytes;
     dev->chksum_buf = 0;
 
-    for (unsigned i = 0; i < n; i++) {
-        bytes += vector[i].iov_len;
-    }
+    bytes = iolist_size(iolist);
     bytes += sizeof(uint16_t); /* FCS field */
     out[0].iov_base = &dev->snd_hdr_buf;
     out[0].iov_len = _zep_hdr_fill(dev, out[0].iov_base, bytes);
     for (unsigned i = 0; i < n; i++) {
         /* discard const qualifier, we won't change anything. Promise! */
-        out[i + 1].iov_base = vector[i].iov_base;
-        out[i + 1].iov_len = vector[i].iov_len;
+        out[i + 1].iov_base = iolist->iol_base;
+        out[i + 1].iov_len = iolist->iol_len;
         dev->chksum_buf = ucrc16_calc_le(out[i + 1].iov_base, out[i + 1].iov_len,
                                          UCRC16_CCITT_POLY_LE, dev->chksum_buf);
+        iolist = iolist->iol_next;
     }
     dev->chksum_buf = byteorder_btols(byteorder_htons(dev->chksum_buf)).u16;
     out[n + 1].iov_base = &dev->chksum_buf;
@@ -110,16 +92,17 @@ static size_t _prep_vector(socket_zep_t *dev, const struct iovec *vector,
     return bytes;
 }
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned n)
+static int _send(netdev_t *netdev, const iolist_t *iolist)
 {
     socket_zep_t *dev = (socket_zep_t *)netdev;
+    unsigned n = iolist_count(iolist);
     struct iovec v[n + 2];
     size_t bytes;
     int res;
 
     assert((dev != NULL) && (dev->sock_fd != 0));
-    bytes = _prep_vector(dev, vector, n, v);
-    DEBUG("socket_zep::send(%p, %p, %u)\n", (void *)netdev, (void *)vector, n);
+    bytes = _prep_vector(dev, iolist, n, v);
+    DEBUG("socket_zep::send(%p, %p, %u)\n", (void *)netdev, (void *)iolist, n);
     /* simulate TX_STARTED interrupt */
     if (netdev->event_callback) {
         dev->last_event = NETDEV_EVENT_TX_STARTED;
@@ -350,6 +333,14 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *value,
                                   value, value_len);
 }
 
+static const netdev_driver_t socket_zep_driver = {
+    .send = _send,
+    .recv = _recv,
+    .init = _init,
+    .isr = _isr,
+    .get = _get,
+    .set = _set,
+};
 
 void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params)
 {
diff --git a/cpu/nrf5x_common/radio/nrfmin/nrfmin.c b/cpu/nrf5x_common/radio/nrfmin/nrfmin.c
index 1d1d127869c6202e97fb10cbc993b998311a37d6..c473594572b3f66fe685a26a1ed340f0247a0266 100644
--- a/cpu/nrf5x_common/radio/nrfmin/nrfmin.c
+++ b/cpu/nrf5x_common/radio/nrfmin/nrfmin.c
@@ -325,11 +325,11 @@ void isr_radio(void)
     cortexm_isr_end();
 }
 
-static int nrfmin_send(netdev_t *dev, const struct iovec *vector, unsigned count)
+static int nrfmin_send(netdev_t *dev, const iolist_t *iolist)
 {
     (void)dev;
 
-    assert((vector != NULL) && (count > 0) && (state != STATE_OFF));
+    assert((iolist) && (state != STATE_OFF));
 
     /* wait for any ongoing transmission to finish and go into idle state */
     while (state == STATE_TX) {}
@@ -337,17 +337,17 @@ static int nrfmin_send(netdev_t *dev, const struct iovec *vector, unsigned count
 
     /* copy packet data into the transmit buffer */
     int pos = 0;
-    for (unsigned i = 0; i < count; i++) {
-        if ((pos + vector[i].iov_len) > NRFMIN_PKT_MAX) {
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        if ((pos + iol->iol_len) > NRFMIN_PKT_MAX) {
             DEBUG("[nrfmin] send: unable to do so, packet is too large!\n");
             return -EOVERFLOW;
         }
-        memcpy(&tx_buf.raw[pos], vector[i].iov_base, vector[i].iov_len);
-        pos += vector[i].iov_len;
+        memcpy(&tx_buf.raw[pos], iol->iol_base, iol->iol_len);
+        pos += iol->iol_len;
     }
 
     /* set output buffer and destination address */
-    nrfmin_hdr_t *hdr = (nrfmin_hdr_t *)vector[0].iov_base;
+    nrfmin_hdr_t *hdr = (nrfmin_hdr_t *)iolist->iol_base;
     NRF_RADIO->PACKETPTR = (uint32_t)(&tx_buf);
     NRF_RADIO->BASE0 = (CONF_ADDR_BASE | hdr->dst_addr);
 
@@ -356,7 +356,7 @@ static int nrfmin_send(netdev_t *dev, const struct iovec *vector, unsigned count
     state = STATE_TX;
     NRF_RADIO->TASKS_TXEN = 1;
 
-    return (int)count;
+    return (int)pos;
 }
 
 static int nrfmin_recv(netdev_t *dev, void *buf, size_t len, void *info)
diff --git a/cpu/nrf5x_common/radio/nrfmin/nrfmin_gnrc.c b/cpu/nrf5x_common/radio/nrfmin/nrfmin_gnrc.c
index 7bbe1424c212d8b4331b216874dba801db79b16d..5002385802ff15b3456fd9f26e29fb907a43adc7 100644
--- a/cpu/nrf5x_common/radio/nrfmin/nrfmin_gnrc.c
+++ b/cpu/nrf5x_common/radio/nrfmin/nrfmin_gnrc.c
@@ -79,9 +79,6 @@ static int hdr_netif_to_nrfmin(nrfmin_hdr_t *nrfmin, gnrc_pktsnip_t *pkt)
 static int gnrc_nrfmin_send(gnrc_netif_t *dev, gnrc_pktsnip_t *pkt)
 {
     int res;
-    struct iovec *vec;
-    size_t vec_len;
-    gnrc_pktsnip_t *vec_snip;
     nrfmin_hdr_t nrfmin_hdr;
 
     assert(pkt);
@@ -95,26 +92,21 @@ static int gnrc_nrfmin_send(gnrc_netif_t *dev, gnrc_pktsnip_t *pkt)
     res = hdr_netif_to_nrfmin(&nrfmin_hdr, pkt);
     if (res < 0) {
         DEBUG("[nrfmin_gnrc] send: failed to build nrfmin header\n");
-        gnrc_pktbuf_release(pkt);
-        return res;
+        goto out;
     }
 
-    /* create iovec of data */
-    vec_snip = gnrc_pktbuf_get_iovec(pkt, &vec_len);
-    if (vec_snip == NULL) {
-        DEBUG("[nrfmin_gnrc] send: failed to create IO vector\n");
-        gnrc_pktbuf_release(pkt);
-        return -ENOBUFS;
-    }
-
-    /* link first entry of the vector to the nrfmin header */
-    vec = (struct iovec *)vec_snip->data;
-    vec[0].iov_base = &nrfmin_hdr;
-    vec[0].iov_len = NRFMIN_HDR_LEN;
+    /* link first entry after netif hdr of the pkt to the nrfmin header */
+    iolist_t iolist = {
+        .iol_next = (iolist_t *)pkt->next,
+        .iol_base = &nrfmin_hdr,
+        .iol_len = NRFMIN_HDR_LEN
+    };
 
     /* and finally send out the data and release the packet */
-    res = dev->dev->driver->send(dev->dev, vec, vec_len);
-    gnrc_pktbuf_release(vec_snip);
+    res = dev->dev->driver->send(dev->dev, &iolist);
+
+out:
+    gnrc_pktbuf_release(pkt);
 
     return res;
 }
diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep
index 5392a1c03383784a84fdecef5a08e4a940c0bf35..de911d403b4a5e28b46aee9e605fd5fa2f4e4057 100644
--- a/drivers/Makefile.dep
+++ b/drivers/Makefile.dep
@@ -112,6 +112,7 @@ ifneq (,$(filter encx24j600,$(USEMODULE)))
 endif
 
 ifneq (,$(filter ethos,$(USEMODULE)))
+  USEMODULE += iolist
   USEMODULE += netdev_eth
   USEMODULE += random
   USEMODULE += tsrb
@@ -306,6 +307,7 @@ endif
 ifneq (,$(filter sx127%,$(USEMODULE)))
   FEATURES_REQUIRED += periph_gpio
   FEATURES_REQUIRED += periph_spi
+  USEMODULE += iolist
   USEMODULE += xtimer
   USEMODULE += sx127x
   USEMODULE += netif
diff --git a/drivers/at86rf2xx/at86rf2xx_netdev.c b/drivers/at86rf2xx/at86rf2xx_netdev.c
index 54fbd9d9bba2102317e0fdb26dca17c312e2edd3..dd697483dcc2372e2eb0eda2b9b19ca220ab70b3 100644
--- a/drivers/at86rf2xx/at86rf2xx_netdev.c
+++ b/drivers/at86rf2xx/at86rf2xx_netdev.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2015 Freie Universität Berlin
+ * Copyright (C) 2018 Kaspar Schleiser <kaspar@schleiser.de>
+ *               2015 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
@@ -17,6 +18,7 @@
  * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  * @author      Kévin Roussel <Kevin.Roussel@inria.fr>
  * @author      Martine Lenders <mlenders@inf.fu-berlin.de>
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
  *
  * @}
  */
@@ -25,6 +27,8 @@
 #include <assert.h>
 #include <errno.h>
 
+#include "iolist.h"
+
 #include "net/eui64.h"
 #include "net/ieee802154.h"
 #include "net/netdev.h"
@@ -40,7 +44,7 @@
 
 #define _MAX_MHR_OVERHEAD   (25)
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count);
+static int _send(netdev_t *netdev, const iolist_t *iolist);
 static int _recv(netdev_t *netdev, void *buf, size_t len, void *info);
 static int _init(netdev_t *netdev);
 static void _isr(netdev_t *netdev);
@@ -93,18 +97,17 @@ static int _init(netdev_t *netdev)
     return 0;
 }
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
+static int _send(netdev_t *netdev, const iolist_t *iolist)
 {
     at86rf2xx_t *dev = (at86rf2xx_t *)netdev;
-    const struct iovec *ptr = vector;
     size_t len = 0;
 
     at86rf2xx_tx_prepare(dev);
 
     /* load packet data into FIFO */
-    for (unsigned i = 0; i < count; ++i, ++ptr) {
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
         /* current packet data + FCS too long */
-        if ((len + ptr->iov_len + 2) > AT86RF2XX_MAX_PKT_LENGTH) {
+        if ((len + iol->iol_len + 2) > AT86RF2XX_MAX_PKT_LENGTH) {
             DEBUG("[at86rf2xx] error: packet too large (%u byte) to be send\n",
                   (unsigned)len + 2);
             return -EOVERFLOW;
@@ -112,7 +115,7 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
 #ifdef MODULE_NETSTATS_L2
         netdev->stats.tx_bytes += len;
 #endif
-        len = at86rf2xx_tx_load(dev, ptr->iov_base, ptr->iov_len, len);
+        len = at86rf2xx_tx_load(dev, iol->iol_base, iol->iol_len, len);
     }
 
     /* send data out directly if pre-loading id disabled */
diff --git a/drivers/cc110x/cc110x-netdev.c b/drivers/cc110x/cc110x-netdev.c
index 016c2bfba84f6ed4743ceb5cb185fba5682f5d43..a1b42c59da4817305f70d2d08b3c40703bf3954b 100644
--- a/drivers/cc110x/cc110x-netdev.c
+++ b/drivers/cc110x/cc110x-netdev.c
@@ -37,14 +37,12 @@
 #define ENABLE_DEBUG    (0)
 #include "debug.h"
 
-static int _send(netdev_t *dev, const struct iovec *vector, unsigned count)
+static int _send(netdev_t *dev, const iolist_t *iolist)
 {
     DEBUG("%s:%u\n", __func__, __LINE__);
 
-    (void)count;
-
-    netdev_cc110x_t *netdev_cc110x = (netdev_cc110x_t*) dev;
-    cc110x_pkt_t *cc110x_pkt = vector[0].iov_base;
+    netdev_cc110x_t *netdev_cc110x = (netdev_cc110x_t *)dev;
+    cc110x_pkt_t *cc110x_pkt = iolist->iol_base;
 
     return cc110x_send(&netdev_cc110x->cc110x, cc110x_pkt);
 }
diff --git a/drivers/cc110x/gnrc_cc110x/gnrc_cc110x.c b/drivers/cc110x/gnrc_cc110x/gnrc_cc110x.c
index abbad5703a12bd14a71e081c0fd2a9bbfb40c7cb..83db2cef2cc51dac1f6c3ca27a45f25ab717c7ed 100644
--- a/drivers/cc110x/gnrc_cc110x/gnrc_cc110x.c
+++ b/drivers/cc110x/gnrc_cc110x/gnrc_cc110x.c
@@ -71,9 +71,10 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
             cc110x_pkt.flags = 0;
     }
 
-    struct iovec vector;
-    vector.iov_base = (char*)&cc110x_pkt;
-    vector.iov_len = sizeof(cc110x_pkt_t);
+    iolist_t iolist = {
+        .iol_base = (char *)&cc110x_pkt,
+        .iol_len = sizeof(cc110x_pkt_t)
+    };
 
     unsigned payload_len = 0;
     uint8_t *pos = cc110x_pkt.data;
@@ -93,7 +94,7 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
         payload = payload->next;
     }
 
-    /* pkt has been copied into iovec, we're done with it. */
+    /* pkt has been copied into cc110x_pkt, we're done with it. */
     gnrc_pktbuf_release(pkt);
 
     cc110x_pkt.length = (uint8_t) payload_len + CC110X_HEADER_LENGTH;
@@ -104,7 +105,7 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
             (unsigned)cc110x_pkt.address,
             (unsigned)cc110x_pkt.length);
 
-    return dev->driver->send(dev, &vector, 1);
+    return dev->driver->send(dev, &iolist);
 }
 
 static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif)
diff --git a/drivers/cc2420/cc2420.c b/drivers/cc2420/cc2420.c
index eca7ef945e1ecc9e91fd15a4a697b1922e054d9b..a0b0600b53152835bd29fc4fa7543515b447ebe8 100644
--- a/drivers/cc2420/cc2420.c
+++ b/drivers/cc2420/cc2420.c
@@ -114,9 +114,9 @@ bool cc2420_cca(cc2420_t *dev)
     return gpio_read(dev->params.pin_cca);
 }
 
-size_t cc2420_send(cc2420_t *dev, const struct iovec *data, unsigned count)
+size_t cc2420_send(cc2420_t *dev, const iolist_t *iolist)
 {
-    size_t n = cc2420_tx_prepare(dev, data, count);
+    size_t n = cc2420_tx_prepare(dev, iolist);
 
     if ((n > 0) && !(dev->options & CC2420_OPT_PRELOADING)) {
         cc2420_tx_exec(dev);
@@ -125,7 +125,7 @@ size_t cc2420_send(cc2420_t *dev, const struct iovec *data, unsigned count)
     return n;
 }
 
-size_t cc2420_tx_prepare(cc2420_t *dev, const struct iovec *data, unsigned count)
+size_t cc2420_tx_prepare(cc2420_t *dev, const iolist_t *iolist)
 {
     size_t pkt_len = 2;     /* include the FCS (frame check sequence) */
 
@@ -134,8 +134,8 @@ size_t cc2420_tx_prepare(cc2420_t *dev, const struct iovec *data, unsigned count
     while (cc2420_get_state(dev) & NETOPT_STATE_TX) {}
 
     /* get and check the length of the packet */
-    for (unsigned i = 0; i < count; i++) {
-        pkt_len += data[i].iov_len;
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        pkt_len += iol->iol_len;
     }
     if (pkt_len >= CC2420_PKT_MAXLEN) {
         DEBUG("cc2420: tx_prep: unable to send, pkt too large\n");
@@ -147,8 +147,8 @@ size_t cc2420_tx_prepare(cc2420_t *dev, const struct iovec *data, unsigned count
     /* push packet length to TX FIFO */
     cc2420_fifo_write(dev, (uint8_t *)&pkt_len, 1);
     /* push packet to TX FIFO */
-    for (unsigned i = 0; i < count; i++) {
-        cc2420_fifo_write(dev, (uint8_t *)data[i].iov_base, data[i].iov_len);
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        cc2420_fifo_write(dev, iol->iol_base, iol->iol_len);
     }
     DEBUG("cc2420: tx_prep: loaded %i byte into the TX FIFO\n", (int)pkt_len);
 
diff --git a/drivers/cc2420/cc2420_netdev.c b/drivers/cc2420/cc2420_netdev.c
index 5514e35c88bcd48a5539cb6e74fecb9c1fa25175..fe1f42ccd300662f1445111ae7a9d577c140d985 100644
--- a/drivers/cc2420/cc2420_netdev.c
+++ b/drivers/cc2420/cc2420_netdev.c
@@ -39,7 +39,7 @@
 #include "debug.h"
 
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count);
+static int _send(netdev_t *netdev, const iolist_t *iolist);
 static int _recv(netdev_t *netdev, void *buf, size_t len, void *info);
 static int _init(netdev_t *netdev);
 static void _isr(netdev_t *netdev);
@@ -150,10 +150,10 @@ static void _isr(netdev_t *netdev)
     netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
 }
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
+static int _send(netdev_t *netdev, const iolist_t *iolist)
 {
     cc2420_t *dev = (cc2420_t *)netdev;
-    return (int)cc2420_send(dev, vector, count);
+    return (int)cc2420_send(dev, iolist);
 }
 
 static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
diff --git a/drivers/enc28j60/enc28j60.c b/drivers/enc28j60/enc28j60.c
index 2b9dd9312dd25f1fb542085d2d5131152d718327..2f55e699a0392b68a1cfac1491ab562511c98ba9 100644
--- a/drivers/enc28j60/enc28j60.c
+++ b/drivers/enc28j60/enc28j60.c
@@ -240,7 +240,7 @@ static void on_int(void *arg)
     netdev->event_callback(arg, NETDEV_EVENT_ISR);
 }
 
-static int nd_send(netdev_t *netdev, const struct iovec *data, unsigned count)
+static int nd_send(netdev_t *netdev, const iolist_t *iolist)
 {
     enc28j60_t *dev = (enc28j60_t *)netdev;
     uint8_t ctrl = 0;
@@ -256,9 +256,9 @@ static int nd_send(netdev_t *netdev, const struct iovec *data, unsigned count)
     cmd_w_addr(dev, ADDR_WRITE_PTR, BUF_TX_START);
     /* write control byte and the actual data into the buffer */
     cmd_wbm(dev, &ctrl, 1);
-    for (unsigned i = 0; i < count; i++) {
-        c += data[i].iov_len;
-        cmd_wbm(dev, (uint8_t *)data[i].iov_base, data[i].iov_len);
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        c += iol->iol_len;
+        cmd_wbm(dev, iol->iol_base, iol->iol_len);
     }
     /* set TX end pointer */
     cmd_w_addr(dev, ADDR_TX_END, cmd_r_addr(dev, ADDR_WRITE_PTR) - 1);
diff --git a/drivers/encx24j600/encx24j600.c b/drivers/encx24j600/encx24j600.c
index 491fdcbdd0ba65f7b8bd540150fa74c0ad7703d3..47c5d3d32f41416eaee10451f297a20864f214fb 100644
--- a/drivers/encx24j600/encx24j600.c
+++ b/drivers/encx24j600/encx24j600.c
@@ -64,7 +64,7 @@ static inline int _packets_available(encx24j600_t *dev);
 static void _get_mac_addr(netdev_t *dev, uint8_t* buf);
 
 /* netdev interface */
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count);
+static int _send(netdev_t *netdev, const iolist_t *iolist);
 static int _recv(netdev_t *netdev, void *buf, size_t len, void *info);
 static int _init(netdev_t *dev);
 static void _isr(netdev_t *dev);
@@ -291,7 +291,7 @@ static int _init(netdev_t *encdev)
     return 0;
 }
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count) {
+static int _send(netdev_t *netdev, const iolist_t *iolist) {
     encx24j600_t * dev = (encx24j600_t *) netdev;
     lock(dev);
 
@@ -301,9 +301,9 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count) {
     /* copy packet to SRAM */
     size_t len = 0;
 
-    for (unsigned i = 0; i < count; i++) {
-        sram_op(dev, ENC_WGPDATA, (i ? 0xFFFF : TX_BUFFER_START), vector[i].iov_base, vector[i].iov_len);
-        len += vector[i].iov_len;
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        sram_op(dev, ENC_WGPDATA, ((iol == iolist) ? TX_BUFFER_START : 0xFFFF), iol->iol_base, iol->iol_len);
+        len += iol->iol_len;
     }
 
     /* set start of TX packet and length */
diff --git a/drivers/ethos/ethos.c b/drivers/ethos/ethos.c
index 1d7c816144b534ac5e0a7b0963e0618305a39a20..511eec2865b0efe497276f4e40a1d7fc0a71b453 100644
--- a/drivers/ethos/ethos.c
+++ b/drivers/ethos/ethos.c
@@ -189,12 +189,11 @@ static int _init(netdev_t *encdev)
     return 0;
 }
 
-static size_t iovec_count_total(const struct iovec *vector, int count)
+static size_t iolist_count_total(const iolist_t *iolist)
 {
     size_t result = 0;
-    while(count--) {
-        result += vector->iov_len;
-        vector++;
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        result += iol->iol_len;
     }
     return result;
 }
@@ -256,13 +255,13 @@ void ethos_send_frame(ethos_t *dev, const uint8_t *data, size_t len, unsigned fr
     }
 }
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
+static int _send(netdev_t *netdev, const iolist_t *iolist)
 {
     ethos_t * dev = (ethos_t *) netdev;
     (void)dev;
 
     /* count total packet length */
-    size_t pktlen = iovec_count_total(vector, count);
+    size_t pktlen = iolist_count_total(iolist);
 
     /* lock line in order to prevent multiple writes */
     mutex_lock(&dev->out_mutex);
@@ -271,14 +270,13 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
     uint8_t frame_delim = ETHOS_FRAME_DELIMITER;
     uart_write(dev->uart, &frame_delim, 1);
 
-    /* send iovec */
-    while(count--) {
-        size_t n = vector->iov_len;
-        uint8_t *ptr = vector->iov_base;
+    /* send iolist */
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        size_t n = iol->iol_len;
+        uint8_t *ptr = iol->iol_base;
         while(n--) {
             _write_escaped(dev->uart, *ptr++);
         }
-        vector++;
     }
 
     uart_write(dev->uart, &frame_delim, 1);
diff --git a/drivers/include/cc2420.h b/drivers/include/cc2420.h
index a2d6f77be447b320a7930a6db29f98b6b3e20f9f..b8d21767227006a896e0cd5341f41fa627739e0e 100644
--- a/drivers/include/cc2420.h
+++ b/drivers/include/cc2420.h
@@ -263,13 +263,12 @@ netopt_state_t cc2420_get_state(cc2420_t *dev);
  * @note This function ignores the PRELOADING option
  *
  * @param[in] dev           device to use for sending
- * @param[in] data          data to send (must include IEEE802.15.4 header)
- * @param[in] count         length of @p data
+ * @param[in] iolist        data to send (must include IEEE802.15.4 header)
  *
  * @return                  number of bytes that were actually send
  * @return                  0 on error
  */
-size_t cc2420_send(cc2420_t *dev, const struct iovec *data, unsigned count);
+size_t cc2420_send(cc2420_t *dev, const iolist_t *iolist);
 
 /**
  * @brief   Prepare for sending of data
@@ -278,10 +277,9 @@ size_t cc2420_send(cc2420_t *dev, const struct iovec *data, unsigned count);
  * data is possible after it was called.
  *
  * @param[in] dev           device to prepare for sending
- * @param[in] data          data to prepare (must include IEEE802.15.4 header)
- * @param[in] count         length of @p data
+ * @param[in] iolist        data to prepare (must include IEEE802.15.4 header)
  */
-size_t cc2420_tx_prepare(cc2420_t *dev, const struct iovec *data, unsigned count);
+size_t cc2420_tx_prepare(cc2420_t *dev, const iolist_t *iolist);
 
 /**
  * @brief   Trigger sending of data previously loaded into transmit buffer
diff --git a/drivers/kw2xrf/kw2xrf_netdev.c b/drivers/kw2xrf/kw2xrf_netdev.c
index 4d8a0dd3bec3f7caf4527be8dbd9504ee0f8db6e..e22ab31fdbcc6b5492175f59f04402a890b65d0b 100644
--- a/drivers/kw2xrf/kw2xrf_netdev.c
+++ b/drivers/kw2xrf/kw2xrf_netdev.c
@@ -138,10 +138,9 @@ static void kw2xrf_wait_idle(kw2xrf_t *dev)
     }
 }
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
+static int _send(netdev_t *netdev, const iolist_t *iolist)
 {
     kw2xrf_t *dev = (kw2xrf_t *)netdev;
-    const struct iovec *ptr = vector;
     uint8_t *pkt_buf = &(dev->buf[1]);
     size_t len = 0;
 
@@ -149,14 +148,14 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
     kw2xrf_wait_idle(dev);
 
     /* load packet data into buffer */
-    for (unsigned i = 0; i < count; i++, ptr++) {
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
         /* current packet data + FCS too long */
-        if ((len + ptr->iov_len + IEEE802154_FCS_LEN) > KW2XRF_MAX_PKT_LENGTH) {
+        if ((len + iol->iol_len + IEEE802154_FCS_LEN) > KW2XRF_MAX_PKT_LENGTH) {
             LOG_ERROR("[kw2xrf] packet too large (%u byte) to be send\n",
                   (unsigned)len + IEEE802154_FCS_LEN);
             return -EOVERFLOW;
         }
-        len = kw2xrf_tx_load(pkt_buf, ptr->iov_base, ptr->iov_len, len);
+        len = kw2xrf_tx_load(pkt_buf, iol->iol_base, iol->iol_len, len);
     }
 
     kw2xrf_set_sequence(dev, XCVSEQ_IDLE);
diff --git a/drivers/mrf24j40/mrf24j40_netdev.c b/drivers/mrf24j40/mrf24j40_netdev.c
index 02598c1b4965dd2b4f4179495e7bbe69ffec500f..10f534689b771cf128a4e8ac4be617b47efc0294 100644
--- a/drivers/mrf24j40/mrf24j40_netdev.c
+++ b/drivers/mrf24j40/mrf24j40_netdev.c
@@ -39,22 +39,6 @@
 
 #define _MAX_MHR_OVERHEAD   (25)
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count);
-static int _recv(netdev_t *netdev, void *buf, size_t len, void *info);
-static int _init(netdev_t *netdev);
-static void _isr(netdev_t *netdev);
-static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len);
-static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len);
-
-const netdev_driver_t mrf24j40_driver = {
-    .send = _send,
-    .recv = _recv,
-    .init = _init,
-    .isr = _isr,
-    .get = _get,
-    .set = _set,
-};
-
 static void _irq_handler(void *arg)
 {
     netdev_t *dev = (netdev_t *) arg;
@@ -83,18 +67,17 @@ static int _init(netdev_t *netdev)
     return 0;
 }
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
+static int _send(netdev_t *netdev, const iolist_t *iolist)
 {
     mrf24j40_t *dev = (mrf24j40_t *)netdev;
-    const struct iovec *ptr = vector;
     size_t len = 0;
 
     mrf24j40_tx_prepare(dev);
 
     /* load packet data into FIFO */
-    for (unsigned i = 0; i < count; i++, ptr++) {
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
         /* current packet data + FCS too long */
-        if ((len + ptr->iov_len + 2) > IEEE802154_FRAME_LEN_MAX) {
+        if ((len + iol->iol_len + 2) > IEEE802154_FRAME_LEN_MAX) {
             DEBUG("[mrf24j40] error: packet too large (%u byte) to be send\n",
                   (unsigned)len + 2);
             return -EOVERFLOW;
@@ -103,11 +86,12 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
 #ifdef MODULE_NETSTATS_L2
         netdev->stats.tx_bytes += len;
 #endif
-        len = mrf24j40_tx_load(dev, ptr->iov_base, ptr->iov_len, len);
-        if (i == 0) {
+        len = mrf24j40_tx_load(dev, iol->iol_base, iol->iol_len, len);
+        /* only on first iteration: */
+        if (iol == iolist) {
             dev->header_len = len;
             /* Grab the FCF bits from the frame header */
-            dev->fcf_low = *(uint8_t*)(ptr->iov_base);
+            dev->fcf_low = *(uint8_t*)(iol->iol_base);
         }
 
     }
@@ -581,3 +565,12 @@ static void _isr(netdev_t *netdev)
     }
     DEBUG("[mrf24j40] END IRQ\n");
 }
+
+const netdev_driver_t mrf24j40_driver = {
+    .send = _send,
+    .recv = _recv,
+    .init = _init,
+    .isr = _isr,
+    .get = _get,
+    .set = _set,
+};
diff --git a/drivers/slipdev/slipdev.c b/drivers/slipdev/slipdev.c
index 073ab4019e9a14180154207af545e07fec4a8d30..9d0a15ac3e0c86a36e332d9ea96c91f3ff424dd6 100644
--- a/drivers/slipdev/slipdev.c
+++ b/drivers/slipdev/slipdev.c
@@ -27,31 +27,6 @@
 #define SLIP_END_ESC           (0xdcU)
 #define SLIP_ESC_ESC           (0xddU)
 
-static int _send(netdev_t *dev, const struct iovec *vector, unsigned count);
-static int _recv(netdev_t *dev, void *buf, size_t len, void *info);
-static int _init(netdev_t *dev);
-static void _isr(netdev_t *dev);
-static int _get(netdev_t *dev, netopt_t opt, void *value, size_t max_len);
-static int _set(netdev_t *dev, netopt_t opt, const void *value,
-                size_t value_len);
-
-static const netdev_driver_t slip_driver = {
-    .send = _send,
-    .recv = _recv,
-    .init = _init,
-    .isr = _isr,
-    .get = _get,
-    .set = _set,
-};
-
-void slipdev_setup(slipdev_t *dev, const slipdev_params_t *params)
-{
-    /* set device descriptor fields */
-    memcpy(&dev->config, params, sizeof(dev->config));
-    dev->inesc = 0U;
-    dev->netdev.driver = &slip_driver;
-}
-
 static void _slip_rx_cb(void *arg, uint8_t byte)
 {
     slipdev_t *dev = arg;
@@ -84,16 +59,16 @@ static inline void _write_byte(slipdev_t *dev, uint8_t byte)
     uart_write(dev->config.uart, &byte, 1);
 }
 
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
+static int _send(netdev_t *netdev, const iolist_t *iolist)
 {
     slipdev_t *dev = (slipdev_t *)netdev;
     int bytes = 0;
 
-    DEBUG("slipdev: sending vector of length %u\n", count);
-    for (unsigned i = 0; i < count; i++) {
-        uint8_t *data = vector[i].iov_base;
+    DEBUG("slipdev: sending iolist\n");
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        uint8_t *data = iol->iol_base;
 
-        for (unsigned j = 0; j < vector[i].iov_len; j++, data++) {
+        for (unsigned j = 0; j < iol->iol_len; j++, data++) {
             switch(*data) {
                 case SLIP_END:
                     /* escaping END byte*/
@@ -223,4 +198,21 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *value,
     return -ENOTSUP;
 }
 
+static const netdev_driver_t slip_driver = {
+    .send = _send,
+    .recv = _recv,
+    .init = _init,
+    .isr = _isr,
+    .get = _get,
+    .set = _set,
+};
+
+void slipdev_setup(slipdev_t *dev, const slipdev_params_t *params)
+{
+    /* set device descriptor fields */
+    memcpy(&dev->config, params, sizeof(dev->config));
+    dev->inesc = 0U;
+    dev->netdev.driver = &slip_driver;
+}
+
 /** @} */
diff --git a/drivers/sx127x/sx127x_netdev.c b/drivers/sx127x/sx127x_netdev.c
index 30c6e7ef7313c3e8ada45d9196210ad9eda74310..60723573113d7d0adc4db36df0a694b85d193a11 100644
--- a/drivers/sx127x/sx127x_netdev.c
+++ b/drivers/sx127x/sx127x_netdev.c
@@ -34,7 +34,6 @@
 #include "debug.h"
 
 /* Internal helper functions */
-static uint8_t _get_tx_len(const struct iovec *vector, unsigned count);
 static int _set_state(sx127x_t *dev, netopt_state_t state);
 static int _get_state(sx127x_t *dev, void *val);
 void _on_dio0_irq(void *arg);
@@ -42,24 +41,7 @@ void _on_dio1_irq(void *arg);
 void _on_dio2_irq(void *arg);
 void _on_dio3_irq(void *arg);
 
-/* Netdev driver api functions */
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count);
-static int _recv(netdev_t *netdev, void *buf, size_t len, void *info);
-static int _init(netdev_t *netdev);
-static void _isr(netdev_t *netdev);
-static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len);
-static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len);
-
-const netdev_driver_t sx127x_driver = {
-    .send = _send,
-    .recv = _recv,
-    .init = _init,
-    .isr = _isr,
-    .get = _get,
-    .set = _set,
-};
-
-static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
+static int _send(netdev_t *netdev, const iolist_t *iolist)
 {
     sx127x_t *dev = (sx127x_t*) netdev;
 
@@ -69,8 +51,8 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
         return -ENOTSUP;
     }
 
-    uint8_t size;
-    size = _get_tx_len(vector, count);
+    uint8_t size = iolist_size(iolist);
+
     switch (dev->settings.modem) {
         case SX127X_MODEM_FSK:
             /* todo */
@@ -91,8 +73,8 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
             }
 
             /* Write payload buffer */
-            for (size_t i = 0; i < count; i++) {
-                sx127x_write_fifo(dev, vector[i].iov_base, vector[i].iov_len);
+            for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+                sx127x_write_fifo(dev, iol->iol_base, iol->iol_len);
             }
             break;
         default:
@@ -489,17 +471,6 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len)
     return res;
 }
 
-static uint8_t _get_tx_len(const struct iovec *vector, unsigned count)
-{
-    uint8_t len = 0;
-
-    for (unsigned i = 0 ; i < count ; i++) {
-        len += vector[i].iov_len;
-    }
-
-    return len;
-}
-
 static int _set_state(sx127x_t *dev, netopt_state_t state)
 {
     switch (state) {
@@ -717,3 +688,12 @@ void _on_dio3_irq(void *arg)
             break;
     }
 }
+
+const netdev_driver_t sx127x_driver = {
+    .send = _send,
+    .recv = _recv,
+    .init = _init,
+    .isr = _isr,
+    .get = _get,
+    .set = _set,
+};
diff --git a/drivers/w5100/w5100.c b/drivers/w5100/w5100.c
index 8cc6e92b7b6e0c4fc49299335a978c659e61d194..e391752fa99692aa94b6fcb9ba56e8dfdfe5088a 100644
--- a/drivers/w5100/w5100.c
+++ b/drivers/w5100/w5100.c
@@ -194,7 +194,7 @@ static uint16_t tx_upload(w5100_t *dev, uint16_t start, void *data, size_t len)
     }
 }
 
-static int send(netdev_t *netdev, const struct iovec *vector, unsigned count)
+static int send(netdev_t *netdev, const iolist_t *iolist)
 {
     w5100_t *dev = (w5100_t *)netdev;
     int sum = 0;
@@ -210,9 +210,10 @@ static int send(netdev_t *netdev, const struct iovec *vector, unsigned count)
         pos = S0_TX_BASE;
     }
 
-    for (unsigned i = 0; i < count; i++) {
-        pos = tx_upload(dev, pos, vector[i].iov_base, vector[i].iov_len);
-        sum += vector[i].iov_len;
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        size_t len = iol->iol_len;
+        pos = tx_upload(dev, pos, iol->iol_base, len);
+        sum += len;
     }
 
     waddr(dev, S0_TX_WR0, S0_TX_WR1, pos);
diff --git a/drivers/xbee/gnrc_xbee.c b/drivers/xbee/gnrc_xbee.c
index be78de2aee81acf9abf4847cc0d91c74fd356e3b..8d66233c64d6551f45d648eb70a0e6f730cececa 100644
--- a/drivers/xbee/gnrc_xbee.c
+++ b/drivers/xbee/gnrc_xbee.c
@@ -104,8 +104,6 @@ static int xbee_adpt_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
 {
     int res;
     size_t size;
-    size_t count;
-    gnrc_pktsnip_t *vec;
     gnrc_netif_hdr_t *hdr;
     uint8_t xhdr[XBEE_MAX_TXHDR_LENGTH];
 
@@ -146,27 +144,23 @@ static int xbee_adpt_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
         }
     }
 
-    /* now let's extract the iovector and send out the stuff */
-    vec = gnrc_pktbuf_get_iovec(pkt, &count);
-    if (vec != NULL) {
-        pkt = vec;
-        struct iovec *vector = (struct iovec *)pkt->data;
-        vector[0].iov_base = xhdr;
-        vector[0].iov_len = res;
+    /* now let's send out the stuff */
+    iolist_t iolist = {
+        .iol_next = (iolist_t *)pkt->next,
+        .iol_base = xhdr,
+        .iol_len = res
+    };
+
 #ifdef MODULE_NETSTATS_L2
-        if (hdr->flags & BCAST) {
-            netif->dev->stats.tx_mcast_count++;
-        }
-        else {
-            netif->dev->stats.tx_unicast_count++;
-        }
-#endif
-        DEBUG("[xbee-gnrc] send: triggering the drivers send function\n");
-        res = netif->dev->driver->send(netif->dev, vector, count);
+    if (hdr->flags & BCAST) {
+        netif->dev->stats.tx_mcast_count++;
     }
     else {
-        DEBUG("[xbee-gnrc] send: unable to create iovec\n");
+        netif->dev->stats.tx_unicast_count++;
     }
+#endif
+    DEBUG("[xbee-gnrc] send: triggering the drivers send function\n");
+    res = netif->dev->driver->send(netif->dev, &iolist);
 
     gnrc_pktbuf_release(pkt);
 
diff --git a/drivers/xbee/xbee.c b/drivers/xbee/xbee.c
index 93df3ab782a459070d8e296b2e5c8000fc4c542a..fb9985896d0739c1e177a9922a2612f7b9c80291 100644
--- a/drivers/xbee/xbee.c
+++ b/drivers/xbee/xbee.c
@@ -634,21 +634,23 @@ int xbee_init(netdev_t *dev)
     return 0;
 }
 
-static int xbee_send(netdev_t *dev, const struct iovec *vector, unsigned count)
+static int xbee_send(netdev_t *dev, const iolist_t *iolist)
 {
     xbee_t *xbee = (xbee_t *)dev;
     size_t size;
     uint8_t csum;
 
-    assert(xbee && vector && (count > 0));
+    assert(xbee && iolist);
 
     /* calculate the checksum and the packet size */
-    size = vector[0].iov_len;
-    csum = _cksum(3, (uint8_t *)vector[0].iov_base, size);
-    for (unsigned i = 1; i < count; i++) {
-        size += vector[i].iov_len;
-        for (size_t p = 0; p < vector[i].iov_len; p++) {
-            csum -= ((uint8_t *)vector[i].iov_base)[p];
+    size = iolist->iol_len;
+    csum = _cksum(3, (uint8_t *)iolist->iol_base, size);
+    for (const iolist_t *iol = iolist->iol_next; iol; iol = iol->iol_next) {
+        size_t len = iol->iol_len;
+
+        size += len;
+        for (size_t p = 0; p < len; p++) {
+            csum -= ((uint8_t *)iol->iol_base)[p];
         }
     }
 
@@ -661,13 +663,13 @@ static int xbee_send(netdev_t *dev, const struct iovec *vector, unsigned count)
     /* send the actual data packet */
     DEBUG("[xbee] send: now sending out %i byte\n", (int)size);
     mutex_lock(&(xbee->tx_lock));
-    for (unsigned i = 0; i < count; i++) {
-        uart_write(xbee->p.uart, vector[i].iov_base, vector[i].iov_len);
+    for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
+        uart_write(xbee->p.uart, iol->iol_base, iol->iol_len);
     }
     uart_write(xbee->p.uart, &csum, 1);
     mutex_unlock(&(xbee->tx_lock));
 
-    /* return number of payload byte */
+    /* return number of payload bytes */
     return (int)size;
 }
 
diff --git a/tests/driver_at86rf2xx/cmd.c b/tests/driver_at86rf2xx/cmd.c
index 58c34630804d3674675fc94a1bc6db113517a12f..6105cfe95cbe13deed0c7d89f0f5f82c9d281a9b 100644
--- a/tests/driver_at86rf2xx/cmd.c
+++ b/tests/driver_at86rf2xx/cmd.c
@@ -250,7 +250,6 @@ static int send(int iface, le_uint16_t dst_pan, uint8_t *dst, size_t dst_len,
 {
     int res;
     netdev_ieee802154_t *dev;
-    struct iovec vector[MAC_VECTOR_SIZE];
     uint8_t *src;
     size_t src_len;
     uint8_t mhr[IEEE802154_MAX_HDR_LEN];
@@ -262,11 +261,14 @@ static int send(int iface, le_uint16_t dst_pan, uint8_t *dst, size_t dst_len,
         return 1;
     }
 
+    iolist_t iol_data = {
+        .iol_base = data,
+        .iol_len = strlen(data)
+    };
+
     dev = (netdev_ieee802154_t *)&devs[iface];
     flags = (uint8_t)(dev->flags & NETDEV_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;
@@ -287,15 +289,20 @@ static int send(int iface, le_uint16_t dst_pan, uint8_t *dst, size_t dst_len,
         puts("txtsnd: Error preperaring frame");
         return 1;
     }
-    vector[0].iov_base = mhr;
-    vector[0].iov_len = (size_t)res;
-    res = dev->netdev.driver->send((netdev_t *)dev, vector, MAC_VECTOR_SIZE);
+
+    iolist_t iol_hdr = {
+        .iol_next = &iol_data,
+        .iol_base = mhr,
+        .iol_len = (size_t)res
+    };
+
+    res = dev->netdev.driver->send((netdev_t *)dev, &iol_hdr);
     if (res < 0) {
         puts("txtsnd: Error on sending");
         return 1;
     }
     else {
-        printf("txtsnd: send %u bytes to ", (unsigned)vector[1].iov_len);
+        printf("txtsnd: send %u bytes to ", (unsigned)iol_data.iol_len);
         print_addr(dst, dst_len);
         printf(" (PAN: ");
         print_addr((uint8_t *)&dst_pan, sizeof(dst_pan));
diff --git a/tests/driver_sx127x/main.c b/tests/driver_sx127x/main.c
index e978cf4e1f26e0d071244ef5968f3a0b83df3fa6..961c145edf2eaa4df72b11a1f57ad54b3d23ef9e 100644
--- a/tests/driver_sx127x/main.c
+++ b/tests/driver_sx127x/main.c
@@ -224,10 +224,12 @@ int send_cmd(int argc, char **argv)
     printf("sending \"%s\" payload (%d bytes)\n",
            argv[1], strlen(argv[1]) + 1);
 
-    struct iovec vec[1];
-    vec[0].iov_base = argv[1];
-    vec[0].iov_len = strlen(argv[1]) + 1;
-    if (netdev->driver->send(netdev, vec, 1) == -ENOTSUP) {
+    iolist_t iolist = {
+        .iol_base = argv[1],
+        .iol_len = (strlen(argv[1]) + 1)
+    };
+
+    if (netdev->driver->send(netdev, &iolist) == -ENOTSUP) {
         puts("Cannot send: radio is still transmitting");
     }
 
diff --git a/tests/socket_zep/main.c b/tests/socket_zep/main.c
index faac4e172ee8ba04a4c1feb5bd1be8f5f6298a16..d5e9ee382303635de505d14cd1cba4fb9abd7d25 100644
--- a/tests/socket_zep/main.c
+++ b/tests/socket_zep/main.c
@@ -56,29 +56,29 @@ static void test_init(void)
     _print_info(netdev);
 }
 
-static void test_send__vector_NULL__count_0(void)
+static void test_send__iolist_NULL(void)
 {
     netdev_t *netdev = (netdev_t *)(&_dev);
-    int res;
 
     puts("Send zero-length packet");
-    res = netdev->driver->send(netdev, NULL, 0);
+    int res = netdev->driver->send(netdev, NULL);
     assert((res < 0) || (res == 0));
     if ((res < 0) && (errno == ECONNREFUSED)) {
         puts("No remote socket exists (use scripts in `tests/` to have proper tests)");
     }
 }
 
-static void test_send__vector_not_NULL__count_2(void)
+static void test_send__iolist_not_NULL(void)
 {
-    struct iovec vector[] = { { .iov_base = "Hello", .iov_len = sizeof("Hello") },
-                              { .iov_base = "World", .iov_len = sizeof("World") } };
+    iolist_t iolist[] = { { .iol_base = "Hello", .iol_len = sizeof("Hello") },
+                          { .iol_base = "World", .iol_len = sizeof("World") } };
+
+    iolist[0].iol_next = &iolist[1];
+
     netdev_t *netdev = (netdev_t *)(&_dev);
-    int res;
 
     puts("Send 'Hello\\0World\\0'");
-    res =  netdev->driver->send(netdev, vector,
-                                sizeof(vector) / sizeof(struct iovec));
+    int res =  netdev->driver->send(netdev, iolist);
     assert((res < 0) || (res == (sizeof("Hello")) + sizeof("World")));
     if ((res < 0) && (errno == ECONNREFUSED)) {
         puts("No remote socket exists (use scripts in `tests/` to have proper tests)");
@@ -109,8 +109,8 @@ int main(void)
     _main_pid = sched_active_pid;
 
     test_init();
-    test_send__vector_NULL__count_0();
-    test_send__vector_not_NULL__count_2();
+    test_send__iolist_NULL();
+    test_send__iolist_not_NULL();
     test_recv();    /* does not return */
     puts("ALL TESTS SUCCESSFUL");
     return 0;