From 7d8f6abd45b23cc74e9f1ca5746853e9c7484f4a Mon Sep 17 00:00:00 2001
From: Martine Lenders <mail@martine-lenders.eu>
Date: Fri, 30 Nov 2018 20:00:02 +0100
Subject: [PATCH] gnrc_netif: check all required options on initialization

With `DEVELHELP` activated all required options required by GNRC are
now checked at interface initialization, so that developers of new
link-layer protocols or device drivers notice as soon as possible that
something is missing.
---
 sys/net/gnrc/netif/gnrc_netif.c | 107 ++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/sys/net/gnrc/netif/gnrc_netif.c b/sys/net/gnrc/netif/gnrc_netif.c
index e226b26e99..33e6b90f90 100644
--- a/sys/net/gnrc/netif/gnrc_netif.c
+++ b/sys/net/gnrc/netif/gnrc_netif.c
@@ -1161,6 +1161,110 @@ static void _configure_netdev(netdev_t *dev)
 #endif
 }
 
+#ifdef DEVELHELP
+/* checks if a device supports all required options and functions */
+static void _test_options(gnrc_netif_t *netif)
+{
+    uint8_t dummy_addr[GNRC_NETIF_L2ADDR_MAXLEN] = { 0 };
+    ndp_opt_t dummy_opt = { .len = 1U };
+    uint64_t tmp64 = 0ULL;
+
+    (void)dummy_addr;
+    (void)dummy_opt;
+    (void)tmp64;
+#if (GNRC_NETIF_L2ADDR_MAXLEN > 0)
+    /* check if address was set in _update_l2addr_from_dev()
+     * (NETOPT_DEVICE_TYPE already tested in _configure_netdev()) and
+     * if MTU and max. fragment size was set properly by
+     * gnrc_netif_ipv6_init_mtu()
+     * all checked types below have link-layer addresses so we don't need to
+     * check `GNRC_NETIF_FLAGS_HAS_L2ADDR` */
+    switch (netif->device_type) {
+#ifdef TEST_SUITES
+        case NETDEV_TYPE_TEST:
+            /* make no assumptions about test devices */
+            break;
+#endif
+        case NETDEV_TYPE_BLE:
+        case NETDEV_TYPE_ETHERNET:
+        case NETDEV_TYPE_ESP_NOW:
+            assert(netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR);
+            assert(ETHERNET_ADDR_LEN == netif->l2addr_len);
+#ifdef MODULE_GNRC_IPV6
+            switch (netif->device_type) {
+                case NETDEV_TYPE_BLE:
+                    assert(netif->ipv6.mtu == IPV6_MIN_MTU);
+                    break;
+                case NETDEV_TYPE_ETHERNET:
+                    assert(netif->ipv6.mtu == ETHERNET_DATA_LEN);
+                    break;
+                case NETDEV_TYPE_ESP_NOW:
+                    assert(netif->ipv6.mtu <= ETHERNET_DATA_LEN);
+            }
+#endif  /* MODULE GNRC_IPV6 */
+            break;
+        case NETDEV_TYPE_IEEE802154:
+        case NETDEV_TYPE_NRFMIN: {
+            gnrc_nettype_t tmp;
+
+            /* in case assert() evaluates to NOP */
+            (void)tmp;
+            assert(netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR);
+            assert((IEEE802154_SHORT_ADDRESS_LEN == netif->l2addr_len) ||
+                   (IEEE802154_LONG_ADDRESS_LEN == netif->l2addr_len));
+            assert(-ENOTSUP != netif->dev->driver->get(netif->dev, NETOPT_PROTO,
+                                                       &tmp, sizeof(tmp)));
+#ifdef MODULE_GNRC_IPV6
+#ifdef MODULE_GNRC_SIXLOWPAN
+            assert(netif->ipv6.mtu == IPV6_MIN_MTU);
+            assert(netif->sixlo.max_frag_size > 0);
+#else   /* MODULE_GNRC_SIXLOWPAN */
+            assert(netif->ipv6.mtu < UINT16_MAX);
+#endif  /* MODULE_GNRC_SIXLOWPAN */
+#endif  /* MODULE_GNRC_IPV6 */
+#ifdef MODULE_GNRC_SIXLOWPAN_ND
+            assert((netif->device_type != NETDEV_TYPE_IEEE802154) ||
+                   (-ENOTSUP != netif->dev->driver->get(netif->dev,
+                                                        NETOPT_ADDRESS_LONG,
+                                                        &dummy_addr,
+                                                        sizeof(dummy_addr))));
+#endif  /* MODULE_GNRC_SIXLOWPAN_ND */
+            break;
+        }
+        case NETDEV_TYPE_CC110X:
+            assert(netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR);
+            assert(1U == netif->l2addr_len);
+#ifdef MODULE_GNRC_IPV6
+            assert(netif->ipv6.mtu < UINT16_MAX);
+#endif  /* MODULE_GNRC_IPV6 */
+            break;
+        case NETDEV_TYPE_SLIP:
+            assert(!(netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR));
+            assert(0U == netif->l2addr_len);
+            /* don't check MTU here for now since I'm not sure the current
+             * one is correct ^^" "*/
+            break;
+        default:
+            /* device type not supported yet, please amend case above when
+             * porting new device type */
+            assert(false);
+    }
+    /* These functions only apply to network devices having link-layers */
+    if (netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR) {
+#ifdef MODULE_GNRC_IPV6
+        assert(-ENOTSUP != gnrc_netif_ipv6_get_iid(netif, (eui64_t *)&tmp64));
+        assert(-ENOTSUP != gnrc_netif_ndp_addr_len_from_l2ao(netif,
+                                                             &dummy_opt));
+#endif  /* MODULE_GNRC_IPV6 */
+#if GNRC_IPV6_NIB_CONF_6LN
+        assert(-ENOTSUP != gnrc_netif_ipv6_iid_to_addr(netif, (eui64_t *)&tmp64,
+                                                       dummy_addr));
+#endif  /* GNRC_IPV6_NIB_CONF_6LN */
+    }
+#endif /* (GNRC_NETIF_L2ADDR_MAXLEN > 0) */
+}
+#endif /* DEVELHELP */
+
 static void *_gnrc_netif_thread(void *args)
 {
     gnrc_netapi_opt_t *opt;
@@ -1194,6 +1298,9 @@ static void *_gnrc_netif_thread(void *args)
     }
     _configure_netdev(dev);
     _init_from_device(netif);
+#ifdef DEVELHELP
+    _test_options(netif);
+#endif
     netif->cur_hl = GNRC_NETIF_DEFAULT_HL;
 #ifdef MODULE_GNRC_IPV6_NIB
     gnrc_ipv6_nib_init_iface(netif);
-- 
GitLab