From 16e7fc83360a58c2093b65eae9f24f6e043b84ad Mon Sep 17 00:00:00 2001
From: Martine Lenders <m.lenders@fu-berlin.de>
Date: Fri, 18 Jan 2019 15:28:51 +0100
Subject: [PATCH] gnrc_netif: introduce L2 address to EUI-64 conversion

---
 sys/include/net/gnrc/netif/internal.h       | 59 ++++++++++++++
 sys/net/gnrc/netif/gnrc_netif_device_type.c | 88 ++++++++++++++++++---
 2 files changed, 134 insertions(+), 13 deletions(-)

diff --git a/sys/include/net/gnrc/netif/internal.h b/sys/include/net/gnrc/netif/internal.h
index 4a055343aa..2b07074613 100644
--- a/sys/include/net/gnrc/netif/internal.h
+++ b/sys/include/net/gnrc/netif/internal.h
@@ -426,6 +426,59 @@ static inline bool gnrc_netif_is_6lbr(const gnrc_netif_t *netif)
  */
 netopt_t gnrc_netif_get_l2addr_opt(const gnrc_netif_t *netif);
 
+/**
+ * @brief   Converts a given hardware address to an EUI-64.
+ *
+ * @attention When the link-layer of the interface has link-layer addresses, and
+ *            `NDEBUG` is not defined, the node fails with an assertion instead
+ *            returning `-ENOTSUP`.
+ *
+ * @param[in] netif     The network interface @p addr came from (either as
+ *                      gnrc_netif_t::l2addr or from a packet that came over
+ *                      it).
+ * @param[in] addr      A hardware address.
+ * @param[in] addr_len  Number of bytes in @p addr.
+ * @param[out] eui64    The EUI-64 based on gnrc_netif_t::device_type
+ *
+ * @return  `sizeof(eui64_t)` on success.
+ * @return  `-ENOTSUP`, when gnrc_netif_t::device_type of @p netif does not
+ *          support IID conversion.
+ * @return  `-EINVAL`, when @p addr_len is invalid for the
+ *          gnrc_netif_t::device_type of @p netif.
+ */
+int gnrc_netif_eui64_from_addr(const gnrc_netif_t *netif,
+                               const uint8_t *addr, size_t addr_len,
+                               eui64_t *eui64);
+
+/**
+ * @brief   Converts an interface EUI-64 from an interface's hardware address
+ *
+ * @param[in] netif     The network interface @p eui64 came from
+ * @param[out] eui64    The EUI-64 based on gnrc_netif_t::device_type
+ *
+ * @note    This wraps around @ref gnrc_netif_eui64_from_addr by using by using
+ *          gnrc_netif_t::l2addr and gnrc_netif_t::l2addr_len of @p netif.
+ *
+ * @return  `sizeof(eui64_t)` on success.
+ * @return  `-ENOTSUP`, if interface has no link-layer address or if
+ *          gnrc_netif_t::device_type is not supported.
+ * @return  `-EINVAL`, when gnrc_netif_t::l2addr_len of @p netif is invalid for
+ *          the gnrc_netif_t::device_type of @p netif.
+ */
+static inline int gnrc_netif_get_eui64(gnrc_netif_t *netif, eui64_t *eui64)
+{
+#if GNRC_NETIF_L2ADDR_MAXLEN > 0
+    if (netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR) {
+        return gnrc_netif_eui64_from_addr(netif,
+                                          netif->l2addr, netif->l2addr_len,
+                                          eui64);
+    }
+#endif /* GNRC_NETIF_L2ADDR_MAXLEN > 0 */
+    (void)netif;
+    (void)eui64;
+    return -ENOTSUP;
+}
+
 #if defined(MODULE_GNRC_IPV6) || defined(DOXYGEN)
 /**
  * @brief   Initialize IPv6 MTU and other packet length related members of
@@ -438,6 +491,9 @@ void gnrc_netif_ipv6_init_mtu(gnrc_netif_t *netif);
 /**
  * @brief   Converts a given hardware address to an IPv6 IID.
  *
+ * @note      The IPv6 IID is derived from the EUI-64 for most link-layers by
+ *            flipping the U/L bit.
+ * @see       [RFC 2464, section 4](https://tools.ietf.org/html/rfc2464#section-4)
  * @attention When the link-layer of the interface has link-layer addresses, and
  *            `NDEBUG` is not defined, the node fails with an assertion instead
  *            returning `-ENOTSUP`.
@@ -492,6 +548,9 @@ int gnrc_netif_ipv6_iid_to_addr(const gnrc_netif_t *netif, const eui64_t *iid,
  * @param[in] netif     The network interface @p iid came from
  * @param[out] iid      The IID based on gnrc_netif_t::device_type
  *
+ * @note    The IPv6 IID is derived from the EUI-64 for most link-layers by
+ *          flipping the U/L bit.
+ * @see     [RFC 2464, section 4](https://tools.ietf.org/html/rfc2464#section-4)
  * @note    This wraps around @ref gnrc_netif_ipv6_iid_from_addr by using
  *          by using gnrc_netif_t::l2addr and gnrc_netif_t::l2addr_len of
  *          @p netif.
diff --git a/sys/net/gnrc/netif/gnrc_netif_device_type.c b/sys/net/gnrc/netif/gnrc_netif_device_type.c
index 4321706fed..838d43de48 100644
--- a/sys/net/gnrc/netif/gnrc_netif_device_type.c
+++ b/sys/net/gnrc/netif/gnrc_netif_device_type.c
@@ -54,6 +54,81 @@ netopt_t gnrc_netif_get_l2addr_opt(const gnrc_netif_t *netif)
     return res;
 }
 
+#if defined(MODULE_CC110X) || defined(MODULE_NRFMIN)
+static void _create_eui64_from_short(const uint8_t *addr, size_t addr_len,
+                                     eui64_t *eui64)
+{
+    const unsigned offset = sizeof(eui64_t) - addr_len;
+
+    memset(eui64->uint8, 0, sizeof(eui64->uint8));
+    eui64->uint8[3] = 0xff;
+    eui64->uint8[4] = 0xfe;
+    memcpy(&eui64->uint8[offset], addr, addr_len);
+}
+#endif /* defined(MODULE_CC110X) || defined(MODULE_NRFMIN) */
+
+int gnrc_netif_eui64_from_addr(const gnrc_netif_t *netif,
+                               const uint8_t *addr, size_t addr_len,
+                               eui64_t *eui64)
+{
+#if GNRC_NETIF_L2ADDR_MAXLEN > 0
+    if (netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR) {
+        switch (netif->device_type) {
+#if defined(MODULE_NETDEV_ETH) || defined(MODULE_ESP_NOW) || \
+    defined(MODULE_NORDIC_SOFTDEVICE_BLE)
+            case NETDEV_TYPE_ETHERNET:
+            case NETDEV_TYPE_ESP_NOW:
+            case NETDEV_TYPE_BLE:
+                if (addr_len == sizeof(eui48_t)) {
+                    eui48_to_eui64(eui64, (const eui48_t *)addr);
+                    return sizeof(eui64_t);
+                }
+                else {
+                    return -EINVAL;
+                }
+#endif  /* defined(MODULE_NETDEV_ETH) || defined(MODULE_ESP_NOW) */
+#if defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE)
+            case NETDEV_TYPE_IEEE802154:
+                switch (addr_len) {
+                    case IEEE802154_SHORT_ADDRESS_LEN: {
+                        netdev_t *dev = netif->dev;
+                        return dev->driver->get(dev, NETOPT_ADDRESS_LONG, eui64,
+                                                sizeof(eui64_t));
+                    }
+                    case IEEE802154_LONG_ADDRESS_LEN:
+                        memcpy(eui64, addr, addr_len);
+                        return sizeof(eui64_t);
+                    default:
+                        return -EINVAL;
+                }
+#endif  /* defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) */
+#if defined(MODULE_CC110X) || defined(MODULE_NRFMIN)
+            case NETDEV_TYPE_CC110X:
+            case NETDEV_TYPE_NRFMIN:
+                if (addr_len <= 3) {
+                    _create_eui64_from_short(addr, addr_len, eui64);
+                    return sizeof(eui64_t);
+                }
+                else {
+                    return -EINVAL;
+                }
+#endif  /* defined(MODULE_CC110X) || defined(MODULE_NRFMIN) */
+            default:
+                (void)addr;
+                (void)addr_len;
+                (void)eui64;
+#ifdef DEVELHELP
+                LOG_ERROR("gnrc_netif: can't convert hardware address to EUI-64"
+                          " on interface %u\n", netif->pid);
+#endif  /* DEVELHELP */
+                assert(false);
+                break;
+        }
+    }
+#endif /* GNRC_NETIF_L2ADDR_MAXLEN > 0 */
+    return -ENOTSUP;
+}
+
 #ifdef MODULE_GNRC_IPV6
 void gnrc_netif_ipv6_init_mtu(gnrc_netif_t *netif)
 {
@@ -122,19 +197,6 @@ void gnrc_netif_ipv6_init_mtu(gnrc_netif_t *netif)
 #endif
 }
 
-#if defined(MODULE_CC110X) || defined(MODULE_NRFMIN)
-static void _create_eui64_from_short(const uint8_t *addr, size_t addr_len,
-                                     eui64_t *eui64)
-{
-    const unsigned offset = sizeof(eui64_t) - addr_len;
-
-    memset(eui64->uint8, 0, sizeof(eui64->uint8));
-    eui64->uint8[3] = 0xff;
-    eui64->uint8[4] = 0xfe;
-    memcpy(&eui64->uint8[offset], addr, addr_len);
-}
-#endif /* defined(MODULE_CC110X) || defined(MODULE_NRFMIN) */
-
 int gnrc_netif_ipv6_iid_from_addr(const gnrc_netif_t *netif,
                                   const uint8_t *addr, size_t addr_len,
                                   eui64_t *iid)
-- 
GitLab