diff --git a/cpu/cc2538/radio/cc2538_rf_netdev.c b/cpu/cc2538/radio/cc2538_rf_netdev.c
index 4a163007a3d530b2d32dbb725d3b16d37427347a..08511787bef8bb9cffcc2710fdee3b3e513c5c38 100644
--- a/cpu/cc2538/radio/cc2538_rf_netdev.c
+++ b/cpu/cc2538/radio/cc2538_rf_netdev.c
@@ -283,10 +283,6 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
         rfcore_write_fifo(iol->iol_base, iol->iol_len);
     }
 
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.tx_bytes += pkt_len;
-#endif
-
     /* Set first byte of TX FIFO to the packet length */
     rfcore_poke_tx_fifo(0, pkt_len + CC2538_AUTOCRC_LEN);
 
@@ -333,10 +329,6 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
         pkt_len = len;
     }
 
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.rx_count++;
-    netdev->stats.rx_bytes += pkt_len;
-#endif
     rfcore_read_fifo(buf, pkt_len);
 
     if (info != NULL && RFCORE->XREG_RSSISTATbits.RSSI_VALID) {
@@ -397,10 +389,6 @@ static int _init(netdev_t *netdev)
 
     cc2538_set_state(dev, NETOPT_STATE_IDLE);
 
-#ifdef MODULE_NETSTATS_L2
-    memset(&netdev->stats, 0, sizeof(netstats_t));
-#endif
-
     return 0;
 }
 
diff --git a/cpu/esp32/esp-eth/esp_eth_netdev.c b/cpu/esp32/esp-eth/esp_eth_netdev.c
index bf641a77779d86e03ab4530847453a22b5b61875..2ad287a945d4f1b9bfaeb673441aa59d8b0b059f 100644
--- a/cpu/esp32/esp-eth/esp_eth_netdev.c
+++ b/cpu/esp32/esp-eth/esp_eth_netdev.c
@@ -169,10 +169,6 @@ static int _esp_eth_init(netdev_t *netdev)
         LOG_TAG_ERROR("esp_eth", "enable failed");
     }
 
-    #ifdef MODULE_NETSTATS_L2
-    memset(&netdev->stats, 0, sizeof(netstats_t));
-    #endif
-
     mutex_unlock(&dev->dev_lock);
 
     return (ret == ESP_OK) ? 0 : -1;
@@ -215,16 +211,9 @@ static int _esp_eth_send(netdev_t *netdev, const iolist_t *iolist)
 
     /* send the the packet to the peer(s) mac address */
     if (esp_eth_tx(dev->tx_buf, dev->tx_len) == ESP_OK) {
-        #ifdef MODULE_NETSTATS_L2
-        netdev->stats.tx_success++;
-        netdev->stats.tx_bytes += dev->tx_len;
-        #endif
         netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
     }
     else {
-        #ifdef MODULE_NETSTATS_L2
-        netdev->stats.tx_failed++;
-        #endif
         ret = -EIO;
     }
 
@@ -271,11 +260,6 @@ static int _esp_eth_recv(netdev_t *netdev, void *buf, size_t len, void *info)
     memcpy(buf, dev->rx_buf, dev->rx_len);
     dev->rx_len = 0;
 
-    #ifdef MODULE_NETSTATS_L2
-    netdev->stats.rx_count++;
-    netdev->stats.rx_bytes += size;
-    #endif
-
     mutex_unlock(&dev->dev_lock);
     return size;
 }
diff --git a/cpu/esp32/esp-wifi/esp_wifi_netdev.c b/cpu/esp32/esp-wifi/esp_wifi_netdev.c
index 7ae62ada7282feea18bd9616f7b4ea0b87aae2f0..afb8ee29b3c3471c21eca1532d2f619ad197e823 100644
--- a/cpu/esp32/esp-wifi/esp_wifi_netdev.c
+++ b/cpu/esp32/esp-wifi/esp_wifi_netdev.c
@@ -271,10 +271,6 @@ static int _esp_wifi_init(netdev_t *netdev)
 {
     DEBUG("%s: %p\n", __func__, netdev);
 
-    #ifdef MODULE_NETSTATS_L2
-    memset(&netdev->stats, 0x00, sizeof(netstats_t));
-    #endif
-
     return 0;
 }
 
@@ -315,17 +311,10 @@ static int _esp_wifi_send(netdev_t *netdev, const iolist_t *iolist)
 
     /* send the the packet to the peer(s) mac address */
     if (esp_wifi_internal_tx(ESP_IF_WIFI_STA, dev->tx_buf, dev->tx_len) == ESP_OK) {
-        #ifdef MODULE_NETSTATS_L2
-        netdev->stats.tx_success++;
-        netdev->stats.tx_bytes += dev->tx_len;
-        #endif
         netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
     }
     else {
         DEBUG("%s: sending WiFi packet failed\n", __func__);
-        #ifdef MODULE_NETSTATS_L2
-        netdev->stats.tx_failed++;
-        #endif
         ret = -EIO;
     }
 
@@ -374,11 +363,6 @@ static int _esp_wifi_recv(netdev_t *netdev, void *buf, size_t len, void *info)
         memcpy(buf, dev->rx_buf, dev->rx_len);
         dev->rx_len = 0;
 
-        #ifdef MODULE_NETSTATS_L2
-        netdev->stats.rx_count++;
-        netdev->stats.rx_bytes += size;
-        #endif
-
         mutex_unlock(&dev->dev_lock);
         return size;
     }
diff --git a/cpu/esp_common/esp-now/esp_now_netdev.c b/cpu/esp_common/esp-now/esp_now_netdev.c
index 5e0e3b848e601cd6cb69bfab6d336903f4aa29b8..7a6fe0ce0483791603c91c1dfaece0358a4f78e0 100644
--- a/cpu/esp_common/esp-now/esp_now_netdev.c
+++ b/cpu/esp_common/esp-now/esp_now_netdev.c
@@ -466,10 +466,6 @@ static int _init(netdev_t *netdev)
 {
     DEBUG("%s: %p\n", __func__, netdev);
 
-#ifdef MODULE_NETSTATS_L2
-    memset(&netdev->stats, 0x00, sizeof(netstats_t));
-#endif
-
     return 0;
 }
 
@@ -542,9 +538,7 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
         while (_esp_now_sending > 0) {
             thread_yield_higher();
         }
-
 #ifdef MODULE_NETSTATS_L2
-        netdev->stats.tx_bytes += data_len;
         netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
 #endif
 
@@ -552,10 +546,6 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
         return data_len;
     } else {
         _esp_now_sending = 0;
-
-#ifdef MODULE_NETSTATS_L2
-        netdev->stats.tx_failed++;
-#endif
     }
 
     mutex_unlock(&dev->dev_lock);
@@ -608,12 +598,6 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
         _esp_now_add_peer(mac, esp_now_params.channel, esp_now_params.key);
     }
 #endif
-
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.rx_count++;
-    netdev->stats.rx_bytes += size;
-#endif
-
     return size;
 }
 
@@ -662,14 +646,6 @@ static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
             res = sizeof(dev->addr);
             break;
 
-#ifdef MODULE_NETSTATS_L2
-        case NETOPT_STATS:
-            CHECK_PARAM_RET(max_len == sizeof(uintptr_t), -EOVERFLOW);
-            *((netstats_t **)val) = &netdev->stats;
-            res = sizeof(uintptr_t);
-            break;
-#endif
-
         default:
             DEBUG("%s: %s not supported\n", __func__, netopt2str(opt));
             break;
diff --git a/cpu/native/netdev_tap/netdev_tap.c b/cpu/native/netdev_tap/netdev_tap.c
index 595cc200a5bf7b677dbd90bf4d685e3d5bbb0adb..dfbbcb8e79dd10b10db33b613caa4691f0aabeb2 100644
--- a/cpu/native/netdev_tap/netdev_tap.c
+++ b/cpu/native/netdev_tap/netdev_tap.c
@@ -254,10 +254,6 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
 
         _continue_reading(dev);
 
-#ifdef MODULE_NETSTATS_L2
-        netdev->stats.rx_count++;
-        netdev->stats.rx_bytes += nread;
-#endif
         return nread;
     }
     else if (nread == -1) {
@@ -284,14 +280,10 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
     struct iovec iov[iolist_count(iolist)];
 
     unsigned n;
-    size_t bytes = iolist_to_iovec(iolist, iov, &n);
+    iolist_to_iovec(iolist, iov, &n);
 
     int res = _native_writev(dev->tap_fd, iov, n);
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.tx_bytes += bytes;
-#else
-    (void)bytes;
-#endif
+
     if (netdev->event_callback) {
         netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
     }
@@ -392,9 +384,6 @@ static int _init(netdev_t *netdev)
     native_async_read_setup();
     native_async_read_add_handler(dev->tap_fd, netdev, _tap_isr);
 
-#ifdef MODULE_NETSTATS_L2
-    memset(&netdev->stats, 0, sizeof(netstats_t));
-#endif
     DEBUG("gnrc_tapnet: initialized.\n");
     return 0;
 }
diff --git a/cpu/native/socket_zep/socket_zep.c b/cpu/native/socket_zep/socket_zep.c
index 82ec572838c4ee70ef67e15a12750ae96ce69fa3..c0e229a3db6a5a5397467748fe03a7541ef04dd4 100644
--- a/cpu/native/socket_zep/socket_zep.c
+++ b/cpu/native/socket_zep/socket_zep.c
@@ -103,11 +103,10 @@ 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, iolist, n, v);
+    _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) {
@@ -126,11 +125,6 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
         netdev->event_callback(netdev, NETDEV_EVENT_ISR);
         thread_yield();
     }
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.tx_bytes += bytes;
-#else
-    (void)bytes;
-#endif
 
     return res - v[0].iov_len - v[n + 1].iov_len;
 }
@@ -258,10 +252,7 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
         }
     }
     _continue_reading(dev);
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.rx_count++;
-    netdev->stats.rx_bytes += size;
-#endif
+
     return size;
 }
 
@@ -404,9 +395,6 @@ void socket_zep_setup(socket_zep_t *dev, const socket_zep_params_t *params)
     dev->netdev.short_addr[1] = dev->netdev.long_addr[7];
     native_async_read_setup();
     native_async_read_add_handler(dev->sock_fd, dev, _socket_isr);
-#ifdef MODULE_NETSTATS_L2
-    memset(&dev->netdev.netdev.stats, 0, sizeof(netstats_t));
-#endif
 }
 
 void socket_zep_cleanup(socket_zep_t *dev)
diff --git a/cpu/nrf5x_common/radio/nrfble/nrfble.c b/cpu/nrf5x_common/radio/nrfble/nrfble.c
index dd500cbde3972e536bb3627bb2ce361821ca61e5..bd0f4c8e907e95b19250eb941599434b33662c62 100644
--- a/cpu/nrf5x_common/radio/nrfble/nrfble.c
+++ b/cpu/nrf5x_common/radio/nrfble/nrfble.c
@@ -230,9 +230,6 @@ netdev_t *nrfble_setup(void)
     _nrfble_dev.driver = &netdev_driver;
     _nrfble_dev.event_callback = NULL;
     _nrfble_dev.context = NULL;
-#ifdef MODULE_NETSTATS_L2
-    memset(&_nrfble_dev.stats, 0, sizeof(netstats_t));;
-#endif
     return &_nrfble_dev;
 }
 
diff --git a/cpu/nrf5x_common/radio/nrfmin/nrfmin.c b/cpu/nrf5x_common/radio/nrfmin/nrfmin.c
index db2c10a139de767751970bba9e432572815fae22..ad1dabf44352aec47e1292bbb46cc0b8514fef0e 100644
--- a/cpu/nrf5x_common/radio/nrfmin/nrfmin.c
+++ b/cpu/nrf5x_common/radio/nrfmin/nrfmin.c
@@ -178,9 +178,6 @@ void nrfmin_setup(void)
     nrfmin_dev.driver = &nrfmin_netdev;
     nrfmin_dev.event_callback = NULL;
     nrfmin_dev.context = NULL;
-#ifdef MODULE_NETSTATS_L2
-    memset(&nrfmin_dev.stats, 0, sizeof(netstats_t));;
-#endif
 }
 
 uint16_t nrfmin_get_addr(void)
diff --git a/drivers/at86rf2xx/at86rf2xx_netdev.c b/drivers/at86rf2xx/at86rf2xx_netdev.c
index 2c35186dd83f3ce6b7cf9b284300f6581db060b6..4e55a2804387c926c8a871d02c7e46d50363e029 100644
--- a/drivers/at86rf2xx/at86rf2xx_netdev.c
+++ b/drivers/at86rf2xx/at86rf2xx_netdev.c
@@ -88,10 +88,6 @@ static int _init(netdev_t *netdev)
         return -1;
     }
 
-#ifdef MODULE_NETSTATS_L2
-    memset(&netdev->stats, 0, sizeof(netstats_t));
-#endif
-
     return 0;
 }
 
@@ -110,9 +106,6 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
                   (unsigned)len + 2);
             return -EOVERFLOW;
         }
-#ifdef MODULE_NETSTATS_L2
-        netdev->stats.tx_bytes += len;
-#endif
         len = at86rf2xx_tx_load(dev, iol->iol_base, iol->iol_len, len);
     }
 
@@ -167,10 +160,6 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
         at86rf2xx_set_state(dev, dev->idle_state);
         return -ENOBUFS;
     }
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.rx_count++;
-    netdev->stats.rx_bytes += pkt_len;
-#endif
     /* copy payload */
     at86rf2xx_fb_read(dev, (uint8_t *)buf, pkt_len);
 
diff --git a/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c b/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c
index c25e4aadc67c82a3f97220745ca1b78d96c21655..2c55bc11b6438c04843c8a31977cf28b18606895 100644
--- a/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c
+++ b/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c
@@ -139,14 +139,6 @@ static int cc1xxx_adpt_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
         .iol_len = sizeof(l2hdr),
     };
 
-#ifdef MODULE_NETSTATS_L2
-    if (netif_hdr->flags & BCAST) {
-        netif->dev->stats.tx_mcast_count++;
-    }
-    else {
-        netif->dev->stats.tx_unicast_count++;
-    }
-#endif
     DEBUG("[cc1xxx-gnrc] send: triggering the drivers send function\n");
     res = netif->dev->driver->send(netif->dev, &iolist);
 
diff --git a/drivers/cc2420/cc2420_netdev.c b/drivers/cc2420/cc2420_netdev.c
index 58cbe50e6a763c9328ca267efc72f30edbf6add2..66612b8c24cbd859cf4718d796929ef19806fdc3 100644
--- a/drivers/cc2420/cc2420_netdev.c
+++ b/drivers/cc2420/cc2420_netdev.c
@@ -137,10 +137,6 @@ static int _init(netdev_t *netdev)
         return -1;
     }
 
-#ifdef MODULE_NETSTATS_L2
-    memset(&netdev->stats, 0, sizeof(netstats_t));
-#endif
-
     return cc2420_init((cc2420_t *)dev);
 }
 
diff --git a/drivers/enc28j60/enc28j60.c b/drivers/enc28j60/enc28j60.c
index efba924a3a95aa0446f6a606461338a870a048ac..a4586d8057443968bd2792587ece0fa26a579f60 100644
--- a/drivers/enc28j60/enc28j60.c
+++ b/drivers/enc28j60/enc28j60.c
@@ -299,10 +299,6 @@ static int nd_send(netdev_t *netdev, const iolist_t *iolist)
     /* set last transmission time for timeout handling */
     dev->tx_time = xtimer_now_usec();
 
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.tx_bytes += c;
-#endif
-
     mutex_unlock(&dev->lock);
     return c;
 }
@@ -340,10 +336,6 @@ static int nd_recv(netdev_t *netdev, void *buf, size_t max_len, void *info)
           (int)size, (int)next, buf, max_len);
 
     if (buf != NULL) {
-#ifdef MODULE_NETSTATS_L2
-        netdev->stats.rx_count++;
-        netdev->stats.rx_bytes += size;
-#endif
         /* read packet content into the supplied buffer */
         if (size <= max_len) {
             cmd_rbm(dev, (uint8_t *)buf, size);
@@ -454,9 +446,6 @@ static int nd_init(netdev_t *netdev)
     /* allow receiving bytes from now on */
     cmd_bfs(dev, REG_ECON1, -1, ECON1_RXEN);
 
-#ifdef MODULE_NETSTATS_L2
-    memset(&netdev->stats, 0, sizeof(netstats_t));
-#endif
     mutex_unlock(&dev->lock);
     return 0;
 }
diff --git a/drivers/encx24j600/encx24j600.c b/drivers/encx24j600/encx24j600.c
index 4f8cd3818c3acb714ad63b9ddbe5efe6686d7bc9..301fa8087c6392b78d1f3791afe445937ef29c6c 100644
--- a/drivers/encx24j600/encx24j600.c
+++ b/drivers/encx24j600/encx24j600.c
@@ -33,11 +33,6 @@
 #include "net/eui64.h"
 #include "net/ethernet.h"
 
-#ifdef MODULE_NETSTATS_L2
-#include <string.h>
-#include "net/netstats.h"
-#endif
-
 #define ENABLE_DEBUG (0)
 #include "debug.h"
 
@@ -285,9 +280,6 @@ static int _init(netdev_t *encdev)
 
     unlock(dev);
 
-#ifdef MODULE_NETSTATS_L2
-    memset(&encdev->stats, 0, sizeof(netstats_t));
-#endif
     return 0;
 }
 
@@ -317,10 +309,6 @@ static int _send(netdev_t *netdev, const iolist_t *iolist) {
     /* (not sure if it is needed, keeping the line uncommented) */
     /*while ((reg_get(dev, ENC_ECON1) & ENC_TXRTS)) {}*/
 
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.tx_bytes += len;
-#endif
-
     unlock(dev);
 
     return len;
@@ -367,10 +355,6 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
             unlock(dev);
             return -ENOBUFS;
         }
-#ifdef MODULE_NETSTATS_L2
-        netdev->stats.rx_count++;
-        netdev->stats.rx_bytes += payload_len;
-#endif
         /* read packet (without 4 bytes checksum) */
         sram_op(dev, ENC_RRXDATA, 0xFFFF, buf, payload_len);
 
diff --git a/drivers/include/net/netdev.h b/drivers/include/net/netdev.h
index cdaeba365dc59771ccf7e17090588573c2e06119..3f9d6d68fea2f44dda7de0f507d0d88eac63fd9b 100644
--- a/drivers/include/net/netdev.h
+++ b/drivers/include/net/netdev.h
@@ -200,9 +200,6 @@ extern "C" {
 #include "iolist.h"
 #include "net/netopt.h"
 
-#ifdef MODULE_NETSTATS_L2
-#include "net/netstats.h"
-#endif
 #ifdef MODULE_L2FILTER
 #include "net/l2filter.h"
 #endif
@@ -281,9 +278,6 @@ struct netdev {
 #ifdef MODULE_NETDEV_LAYER
     netdev_t *lower;                        /**< ptr to the lower netdev layer */
 #endif
-#ifdef MODULE_NETSTATS_L2
-    netstats_t stats;                       /**< transceiver's statistics */
-#endif
 #ifdef MODULE_L2FILTER
     l2filter_t filter[L2FILTER_LISTSIZE];   /**< link layer address filters */
 #endif
diff --git a/drivers/include/xbee.h b/drivers/include/xbee.h
index 1cbdb4335a98f4db72a079e44e2c299489d5d5a6..ce77a6635e187394029b6e1fa52e88d3e11ec098 100644
--- a/drivers/include/xbee.h
+++ b/drivers/include/xbee.h
@@ -131,9 +131,6 @@ typedef struct {
     const struct netdev_driver *driver;     /**< ptr to that driver's interface. */
     netdev_event_cb_t event_callback;       /**< callback for device events */
     void* context;                          /**< ptr to network stack context */
-#ifdef MODULE_NETSTATS_L2
-    netstats_t stats;                       /**< transceiver's statistics */
-#endif
     /* device driver specific fields */
     xbee_params_t p;                    /**< configuration parameters */
     uint8_t options;                    /**< options field */
diff --git a/drivers/kw2xrf/kw2xrf_netdev.c b/drivers/kw2xrf/kw2xrf_netdev.c
index baaaf2a8b196d0efdfb8feee4bb008c6e0348941..9e66836c56911e6b7bde3e5161a8be424b848c6a 100644
--- a/drivers/kw2xrf/kw2xrf_netdev.c
+++ b/drivers/kw2xrf/kw2xrf_netdev.c
@@ -81,10 +81,6 @@ static int _init(netdev_t *netdev)
         return -1;
     }
 
-#ifdef MODULE_NETSTATS_L2
-    memset(&netdev->stats, 0, sizeof(netstats_t));
-#endif
-
     /* reset device to default values and put it into RX state */
     kw2xrf_reset_phy(dev);
 
@@ -169,9 +165,6 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
     _send_last_fcf = dev->buf[1];
 
     kw2xrf_write_fifo(dev, dev->buf, dev->buf[0]);
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.tx_bytes += len;
-#endif
 
     /* send data out directly if pre-loading id disabled */
     if (!(dev->netdev.flags & KW2XRF_OPT_PRELOADING)) {
@@ -194,11 +187,6 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
         return pkt_len + 1;
     }
 
-#ifdef MODULE_NETSTATS_L2
-    netdev->stats.rx_count++;
-    netdev->stats.rx_bytes += pkt_len;
-#endif
-
     if (pkt_len > len) {
         /* not enough space in buf */
         return -ENOBUFS;
diff --git a/drivers/mrf24j40/mrf24j40_netdev.c b/drivers/mrf24j40/mrf24j40_netdev.c
index be1d89226d9e2d81958f5fb3ba427276ab855ada..289bd6a5bd9a0a72f0df5a21ba8681e6182f9ffb 100644
--- a/drivers/mrf24j40/mrf24j40_netdev.c
+++ b/drivers/mrf24j40/mrf24j40_netdev.c
@@ -57,9 +57,6 @@ static int _init(netdev_t *netdev)
     gpio_set(dev->params.reset_pin);
     gpio_init_int(dev->params.int_pin, GPIO_IN, GPIO_RISING, _irq_handler, dev);
 
-#ifdef MODULE_NETSTATS_L2
-    memset(&netdev->stats, 0, sizeof(netstats_t));
-#endif
     /* reset device to default values and put it into RX state */
     mrf24j40_reset(dev);
     return 0;
@@ -80,10 +77,6 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
                   (unsigned)len + 2);
             return -EOVERFLOW;
         }
-
-#ifdef MODULE_NETSTATS_L2
-        netdev->stats.tx_bytes += len;
-#endif
         len = mrf24j40_tx_load(dev, iol->iol_base, iol->iol_len, len);
         /* only on first iteration: */
         if (iol == iolist) {
@@ -136,10 +129,6 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
             mrf24j40_rx_fifo_read(dev, phr + 2, &(rssi_scalar), 1);
             radio_info->rssi = mrf24j40_dbm_from_reg(rssi_scalar);
         }
-#ifdef MODULE_NETSTATS_L2
-        netdev->stats.rx_count++;
-        netdev->stats.rx_bytes += pkt_len;
-#endif
         res = pkt_len;
     }
     /* Turn on reception of packets off the air */
diff --git a/drivers/netdev_eth/netdev_eth.c b/drivers/netdev_eth/netdev_eth.c
index 1b94991b5c5e68ed3504212517ee0733f309baa2..df420461e8257457bc6b7e5f272a49195ab33cae 100644
--- a/drivers/netdev_eth/netdev_eth.c
+++ b/drivers/netdev_eth/netdev_eth.c
@@ -80,15 +80,6 @@ int netdev_eth_get(netdev_t *dev, netopt_t opt, void *value, size_t max_len)
             {
                 return _get_iid(dev, value, max_len);
             }
-#ifdef MODULE_NETSTATS_L2
-        case NETOPT_STATS:
-            {
-                assert(max_len >= sizeof(uintptr_t));
-                *((netstats_t**)value) = &dev->stats;
-                res = sizeof(uintptr_t);
-                break;
-            }
-#endif
 #ifdef MODULE_L2FILTER
         case NETOPT_L2FILTER:
             {
diff --git a/drivers/netdev_ieee802154/netdev_ieee802154.c b/drivers/netdev_ieee802154/netdev_ieee802154.c
index 9c04a19be2b8cefe4272af2ca378c84593eb336b..9318ac21abd4c9a6cf28cd0c7f1aaa68b13af8bc 100644
--- a/drivers/netdev_ieee802154/netdev_ieee802154.c
+++ b/drivers/netdev_ieee802154/netdev_ieee802154.c
@@ -143,13 +143,6 @@ int netdev_ieee802154_get(netdev_ieee802154_t *dev, netopt_t opt, void *value,
         case NETOPT_IPV6_IID:
             res = _get_iid(dev, value, max_len);
             break;
-#ifdef MODULE_NETSTATS_L2
-        case NETOPT_STATS:
-            assert(max_len == sizeof(uintptr_t));
-            *((netstats_t **)value) = &dev->netdev.stats;
-            res = sizeof(uintptr_t);
-            break;
-#endif
 #ifdef MODULE_L2FILTER
         case NETOPT_L2FILTER:
             assert(max_len >= sizeof(l2filter_t **));
diff --git a/drivers/xbee/gnrc_xbee.c b/drivers/xbee/gnrc_xbee.c
index 8d66233c64d6551f45d648eb70a0e6f730cececa..ad514256a8885b1505e003796c3ee1a6d56eec75 100644
--- a/drivers/xbee/gnrc_xbee.c
+++ b/drivers/xbee/gnrc_xbee.c
@@ -151,14 +151,6 @@ static int xbee_adpt_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
         .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, &iolist);
 
diff --git a/sys/include/net/gnrc/netif.h b/sys/include/net/gnrc/netif.h
index 37eb8413e63bda44f06930c356b608b6b16797a1..a69948d68388bcc63afd3be7d763f9b4784ba7f2 100644
--- a/sys/include/net/gnrc/netif.h
+++ b/sys/include/net/gnrc/netif.h
@@ -47,6 +47,9 @@
 #include "net/ndp.h"
 #include "net/netdev.h"
 #include "net/netopt.h"
+#ifdef MODULE_NETSTATS_L2
+#include "net/netstats.h"
+#endif
 #include "rmutex.h"
 
 #ifdef __cplusplus
@@ -65,6 +68,9 @@ typedef struct {
     const gnrc_netif_ops_t *ops;            /**< Operations of the network interface */
     netdev_t *dev;                          /**< Network device of the network interface */
     rmutex_t mutex;                         /**< Mutex of the interface */
+#ifdef MODULE_NETSTATS_L2
+    netstats_t stats;                       /**< transceiver's statistics */
+#endif
 #if defined(MODULE_GNRC_IPV6) || DOXYGEN
     gnrc_netif_ipv6_t ipv6;                 /**< IPv6 component */
 #endif
diff --git a/sys/net/gnrc/link_layer/gomach/gomach_internal.c b/sys/net/gnrc/link_layer/gomach/gomach_internal.c
index 3b6618324509a85ea2f1338a81a8744494fce8bb..85b3ee54de0f49a0afaf7625367e3a3c60cfb3ec 100644
--- a/sys/net/gnrc/link_layer/gomach/gomach_internal.c
+++ b/sys/net/gnrc/link_layer/gomach/gomach_internal.c
@@ -103,10 +103,10 @@ int _gnrc_gomach_transmit(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
 #ifdef MODULE_NETSTATS_L2
     if (netif_hdr->flags &
             (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
-        netif->dev->stats.tx_mcast_count++;
+        netif->stats.tx_mcast_count++;
     }
     else {
-        netif->dev->stats.tx_unicast_count++;
+        netif->stats.tx_unicast_count++;
     }
 #endif
 #ifdef MODULE_GNRC_MAC
@@ -343,8 +343,8 @@ int gnrc_gomach_send_preamble_ack(gnrc_netif_t *netif, gnrc_gomach_packet_info_t
     assert(netif != NULL);
     assert(info != NULL);
 
+    gnrc_pktsnip_t *pkt;
     gnrc_pktsnip_t *gomach_pkt = NULL;
-    gnrc_pktsnip_t *pkt = NULL;
     gnrc_netif_hdr_t *nethdr_preamble_ack = NULL;
 
     /* Start assemble the preamble-ACK packet according to preamble packet info. */
diff --git a/sys/net/gnrc/link_layer/lwmac/lwmac_internal.c b/sys/net/gnrc/link_layer/lwmac/lwmac_internal.c
index f28ec6468997ed70081f23061c683977bc377287..371c9430ada792771d041ea6ca975e248d8cd9d4 100644
--- a/sys/net/gnrc/link_layer/lwmac/lwmac_internal.c
+++ b/sys/net/gnrc/link_layer/lwmac/lwmac_internal.c
@@ -90,10 +90,10 @@ int _gnrc_lwmac_transmit(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
 #ifdef MODULE_NETSTATS_L2
     if (netif_hdr->flags &
             (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
-        netif->dev->stats.tx_mcast_count++;
+        netif->stats.tx_mcast_count++;
     }
     else {
-        netif->dev->stats.tx_unicast_count++;
+        netif->stats.tx_unicast_count++;
     }
 #endif
 #ifdef MODULE_GNRC_MAC
diff --git a/sys/net/gnrc/netif/ethernet/gnrc_netif_ethernet.c b/sys/net/gnrc/netif/ethernet/gnrc_netif_ethernet.c
index 703550a2d59204ca5b06ffbbaa88c957f868e8a6..a12c6f9fbb7e2928e4395d2fe7d9aef31e59f1f5 100644
--- a/sys/net/gnrc/netif/ethernet/gnrc_netif_ethernet.c
+++ b/sys/net/gnrc/netif/ethernet/gnrc_netif_ethernet.c
@@ -145,10 +145,10 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
 #ifdef MODULE_NETSTATS_L2
     if ((netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_BROADCAST) ||
         (netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
-        dev->stats.tx_mcast_count++;
+        netif->stats.tx_mcast_count++;
     }
     else {
-        dev->stats.tx_unicast_count++;
+        netif->stats.tx_unicast_count++;
     }
 #endif
     res = dev->driver->send(dev, &iolist);
@@ -183,6 +183,10 @@ static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif)
             DEBUG("gnrc_netif_ethernet: read error.\n");
             goto safe_out;
         }
+#ifdef MODULE_NETSTATS_L2
+        netif->stats.rx_count++;
+        netif->stats.rx_bytes += nread;
+#endif
 
         if (nread < bytes_expected) {
             /* we've got less than the expected packet size,
diff --git a/sys/net/gnrc/netif/gnrc_netif.c b/sys/net/gnrc/netif/gnrc_netif.c
index df0085d371ddc7abaae2ca9a14abdf8b39049096..09da4038cd243c9363624f7bee72d35d75dd67f0 100644
--- a/sys/net/gnrc/netif/gnrc_netif.c
+++ b/sys/net/gnrc/netif/gnrc_netif.c
@@ -25,7 +25,7 @@
 #include "net/gnrc/ipv6/nib.h"
 #include "net/gnrc/ipv6.h"
 #endif /* MODULE_GNRC_IPV6_NIB */
-#ifdef MODULE_NETSTATS_IPV6
+#ifdef MODULE_NETSTATS
 #include "net/netstats.h"
 #endif
 #include "fmt.h"
@@ -126,6 +126,13 @@ int gnrc_netif_get_from_netdev(gnrc_netif_t *netif, gnrc_netapi_opt_t *opt)
                     *((netstats_t **)opt->data) = &netif->ipv6.stats;
                     res = sizeof(&netif->ipv6.stats);
                     break;
+#endif
+#ifdef MODULE_NETSTATS_L2
+                case NETSTATS_LAYER2:
+                    assert(opt->data_len == sizeof(netstats_t *));
+                    *((netstats_t **)opt->data) = &netif->stats;
+                    res = sizeof(&netif->stats);
+                    break;
 #endif
                 default:
                     /* take from device */
@@ -1196,6 +1203,9 @@ static void *_gnrc_netif_thread(void *args)
     if (netif->ops->init) {
         netif->ops->init(netif);
     }
+#ifdef MODULE_NETSTATS_L2
+    memset(&netif->stats, 0, sizeof(netstats_t));
+#endif
     /* now let rest of GNRC use the interface */
     gnrc_netif_release(netif);
 
@@ -1215,6 +1225,11 @@ static void *_gnrc_netif_thread(void *args)
                     DEBUG("gnrc_netif: error sending packet %p (code: %u)\n",
                           msg.content.ptr, res);
                 }
+#ifdef MODULE_NETSTATS_L2
+                else {
+                    netif->stats.tx_bytes += res;
+                }
+#endif
                 break;
             case GNRC_NETAPI_MSG_TYPE_SET:
                 opt = msg.content.ptr;
@@ -1287,25 +1302,24 @@ static void _event_cb(netdev_t *dev, netdev_event_t event)
     }
     else {
         DEBUG("gnrc_netif: event triggered -> %i\n", event);
+        gnrc_pktsnip_t *pkt = NULL;
         switch (event) {
-            case NETDEV_EVENT_RX_COMPLETE: {
-                    gnrc_pktsnip_t *pkt = netif->ops->recv(netif);
-
-                    if (pkt) {
-                        _pass_on_packet(pkt);
-                    }
+            case NETDEV_EVENT_RX_COMPLETE:
+                pkt = netif->ops->recv(netif);
+                if (pkt) {
+                    _pass_on_packet(pkt);
                 }
                 break;
 #ifdef MODULE_NETSTATS_L2
             case NETDEV_EVENT_TX_MEDIUM_BUSY:
                 /* we are the only ones supposed to touch this variable,
                  * so no acquire necessary */
-                dev->stats.tx_failed++;
+                netif->stats.tx_failed++;
                 break;
             case NETDEV_EVENT_TX_COMPLETE:
                 /* we are the only ones supposed to touch this variable,
                  * so no acquire necessary */
-                dev->stats.tx_success++;
+                netif->stats.tx_success++;
                 break;
 #endif
             default:
diff --git a/sys/net/gnrc/netif/gnrc_netif_raw.c b/sys/net/gnrc/netif/gnrc_netif_raw.c
index cc8760b4ce7cef2c5cdb23af59b03526c0f3ac30..886c00731e2bc25c939251a97fc26f0b7dccf2a4 100644
--- a/sys/net/gnrc/netif/gnrc_netif_raw.c
+++ b/sys/net/gnrc/netif/gnrc_netif_raw.c
@@ -70,6 +70,11 @@ static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif)
             gnrc_pktbuf_release(pkt);
             return NULL;
         }
+#ifdef MODULE_NETSTATS_L2
+        netif->stats.rx_count++;
+        netif->stats.rx_bytes += nread;
+#endif
+
         if (nread < bytes_expected) {
             /* we've got less then the expected packet size,
              * so free the unused space.*/
@@ -102,7 +107,7 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
     netdev_t *dev = netif->dev;
 
 #ifdef MODULE_NETSTATS_L2
-    dev->stats.tx_unicast_count++;
+    netif->stats.tx_unicast_count++;
 #endif
 
     res = dev->driver->send(dev, (iolist_t *)pkt);
diff --git a/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c b/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c
index d99653a8bf0af36a35fdece687b14845dd65a760..fc2bbddeb5b8f6d2497f6ec3ac6dc0d7b73a04de 100644
--- a/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c
+++ b/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c
@@ -95,6 +95,11 @@ static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif)
             gnrc_pktbuf_release(pkt);
             return NULL;
         }
+#ifdef MODULE_NETSTATS_L2
+        netif->stats.rx_count++;
+        netif->stats.rx_bytes += nread;
+#endif
+
         if (netif->flags & GNRC_NETIF_FLAGS_RAWMODE) {
             /* Raw mode, skip packet processing, but provide rx_info via
              * GNRC_NETTYPE_NETIF */
@@ -241,10 +246,10 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
 #ifdef MODULE_NETSTATS_L2
     if (netif_hdr->flags &
             (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
-        netif->dev->stats.tx_mcast_count++;
+        netif->stats.tx_mcast_count++;
     }
     else {
-        netif->dev->stats.tx_unicast_count++;
+        netif->stats.tx_unicast_count++;
     }
 #endif
 #ifdef MODULE_GNRC_MAC