From bca68ff4841982ab6484aa34c679d6ee8b20cb15 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 9 Jul 2020 01:44:11 +0200 Subject: [PATCH] net/link_layer: implement EUI provider This adds the possibility to define EUI sources and assign them to a network device. --- Makefile.dep | 4 + sys/Makefile | 3 + sys/Makefile.include | 4 + sys/include/net/eui_provider.h | 209 ++++++++++++++++++ sys/net/link_layer/eui_provider/Makefile | 1 + .../link_layer/eui_provider/eui_provider.c | 71 ++++++ .../include/eui48_provider_params.h | 94 ++++++++ .../include/eui64_provider_params.h | 94 ++++++++ 8 files changed, 480 insertions(+) create mode 100644 sys/include/net/eui_provider.h create mode 100644 sys/net/link_layer/eui_provider/Makefile create mode 100644 sys/net/link_layer/eui_provider/eui_provider.c create mode 100644 sys/net/link_layer/eui_provider/include/eui48_provider_params.h create mode 100644 sys/net/link_layer/eui_provider/include/eui64_provider_params.h diff --git a/Makefile.dep b/Makefile.dep index 7b73c2e2c8..6e0737c55a 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -189,6 +189,10 @@ ifneq (,$(filter trickle,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter eui_provider,$(USEMODULE))) + USEMODULE += luid +endif + ifneq (,$(filter gnrc_netif,$(USEMODULE))) USEMODULE += netif USEMODULE += l2util diff --git a/sys/Makefile b/sys/Makefile index b91a9b3cbf..9abc50975f 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -47,6 +47,9 @@ endif ifneq (,$(filter emcute,$(USEMODULE))) DIRS += net/application_layer/emcute endif +ifneq (,$(filter eui_provider,$(USEMODULE))) + DIRS += net/link_layer/eui_provider +endif ifneq (,$(filter fib,$(USEMODULE))) DIRS += net/network_layer/fib endif diff --git a/sys/Makefile.include b/sys/Makefile.include index a449b90e99..a5f336d6ff 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -29,6 +29,10 @@ ifneq (,$(filter oneway_malloc,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/sys/oneway-malloc/include endif +ifneq (,$(filter eui_provider,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/link_layer/eui_provider/include +endif + ifneq (,$(filter app_metadata,$(USEMODULE))) # Overwrite the application shell formats. # This is an optional macro that can be used to coordinate diff --git a/sys/include/net/eui_provider.h b/sys/include/net/eui_provider.h new file mode 100644 index 0000000000..cccd03c19d --- /dev/null +++ b/sys/include/net/eui_provider.h @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * 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 net_eui_provider IEEE EUI-48/64 provider + * @ingroup net + * @brief MAC address management + * + * About + * ===== + * + * An EUI provider provides an Extended Unique Identifier, that is + * a hardware address for a network device. + * + * A board may have an EEPROM with a unique ID (e.g. @ref drivers_at24mac) that is used + * to store an address, a unique address is stored in a config + * area of the board's flash during production, etc. + * + * The EUI provider is connected to a network device that will then use + * this address. + * + * How it works + * ============ + * + * If there is only one EUI provider on the board, the configuration + * is done through three defines: + * + * - `EUIxx_PROVIDER_TYPE` to specify which device the EUI should be used for. + * That is to prevent it from matching to 'virtual' devices like ethos or SLIP. + * It is of course also possible to provide a fixed address for 'virtual' devices + * this way. + + * - `EUIxx_PROVIDER_INDEX` to specify which interface the EUI should be used for if + * there are multiple interfaces. + * + * - `EUIxx_PROVIDER_FUNC` the function that provides the EUI. It can use an optional + * `EUIxx_PROVIDER_ARG` argument that is passed unmodified. + * + * If more than one EUI provider is present on the board, an array of `euiXX_conf_t` + * has to be provided to `EUI64_PROVIDER_PARAMS`: + * + * ```C + * #define EUI64_PROVIDER_PARAMS { \ + * .provider = _board_get_eui, \ + * .arg = BOARD_ADDR_SUBGHZ, \ + * .type = NETDEV_AT86RF215, \ + * .index = 0, }, \ + * { \ + * .provider = _board_get_eui, \ + * .arg = BOARD_ADDR_24GHZ, \ + * .type = NETDEV_AT86RF215, \ + * .index = 1, } + * ``` + * + * This also assumes a `_board_get_eui()` function to provide the EUI. + * For example, it could read an EUI from a config region on the flash + * that is provided with the memory-mapped addresses `BOARD_ADDR_SUBGHZ` and + * `BOARD_ADDR_24GHZ`. + * The function would then do + * + * ```C + * static inline int _board_get_eui(const void *src, eui64_t *addr) + * { + * memcpy(addr, src, sizeof(*addr)); + * return 0; + * } + * + * ``` + * + * Recommendations + * =============== + * + * While it is possible to match EUIs with any netdev in a first come, first serve + * fashion (`NETDEV_ANY`, `NETDEV_INDEX_ANY`) it is recommended to fix the EUI + * providers to a device and interface to avoid them being used for 'virtual' + * interfaces. + * + * Fixed addresses are only guaranteed if the network devices are also fixed. + * E.g. if you usually have two netdevs and disable the first one at compile-time + * the second interface will now use the first slot / index and therefore also + * use the EUI provider that was previously used by interface in the first slot. + * + * @{ + * + * @file + * @brief EUI-48 and EUI-64 address provider + * + * @author Benjamin Valentin + */ +#ifndef NET_EUI_PROVIDER_H +#define NET_EUI_PROVIDER_H + +#include "net/eui48.h" +#include "net/eui64.h" +#include "net/netdev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Will match any device index + */ +#define NETDEV_INDEX_ANY (0xFF) + +/** + * @brief Function for providing a EUI-48 to a device + * + * @param[in] arg Optional argument provided by eui48_conf_t + * @param[out] addr Destination pointer for the EUI-48 address + * + * @return 0 on success, next provider in eui48_conf_t will be + * used otherwise. + * Will fall back to @see luid_get_eui48 eventually. + */ +typedef int (*netdev_get_eui48_cb_t)(const void *arg, eui48_t *addr); + +/** + * @brief Function for providing a EUI-64 to a device + * + * @param[in] arg Optional argument provided by eui64_conf_t + * @param[out] addr Destination pointer for the EUI-64 address + * + * @return 0 on success, next provider in eui64_conf_t will be + * used otherwise. + * Will fall back to @see luid_get_eui64 eventually. + */ +typedef int (*netdev_get_eui64_cb_t)(const void *arg, eui64_t *addr); + +/** + * @brief Structure to hold providers for EUI-48 addresses + */ +typedef struct { + netdev_get_eui48_cb_t provider; /**< function to provide an EUI-48 */ + const void *arg; /**< argument to the provider function */ + netdev_type_t type; /**< device type to match or `NETDEV_ANY` */ + uint8_t index; /**< device index to match or `NETDEV_INDEX_ANY` */ +} eui48_conf_t; + +/** + * @brief Structure to hold providers for EUI-64 addresses + */ +typedef struct { + netdev_get_eui64_cb_t provider; /**< function to provide an EUI-64 */ + const void *arg; /**< argument to the provider function */ + netdev_type_t type; /**< device type to match or `NETDEV_ANY` */ + uint8_t index; /**< device index to match or `NETDEV_INDEX_ANY` */ +} eui64_conf_t; + +/** + * @brief Generates an EUI-48 address for the netdev interface. + * + * @note It is possible to supply a board-specific, constant address + * by implementing a EUI-48 provider function. + * If no such function is available, this will fall back to + * @ref luid_get_eui48. + * + * @param[in] netdev The network device for which the address is + * generated. + * @param[out] addr The generated EUI-48 address + * + */ +void netdev_eui48_get(netdev_t *netdev, eui48_t *addr); + +/** + * @brief Generates an EUI-64 address for the netdev interface. + * + * @note It is possible to supply a board-specific, constant address + * by implementing a EUI-64 provider function. + * If no such function is available, this will fall back to + * @ref luid_get_eui64. + * + * @param[in] netdev The network device for which the address is + * generated. + * @param[out] addr The generated EUI-64 address + * + */ +void netdev_eui64_get(netdev_t *netdev, eui64_t *addr); + +/** + * @brief Get a short unicast address from an EUI-64 + * + * The resulting address is built from the provided long address. + * The last two bytes of the long address will be used as the short + * address with the first bit cleared. + * + * @param[in] addr_long the address to base the short address on + * @param[out] addr_short memory location to copy the address into. + */ +static inline void eui_short_from_eui64(eui64_t *addr_long, + network_uint16_t *addr_short) +{ + /* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to + * 0 for unicast addresses */ + addr_short->u8[0] = addr_long->uint8[6] & 0x7F; + addr_short->u8[1] = addr_long->uint8[7]; +} + +#ifdef __cplusplus +} +#endif + +#endif /* NET_EUI_PROVIDER_H */ +/** @} */ diff --git a/sys/net/link_layer/eui_provider/Makefile b/sys/net/link_layer/eui_provider/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/net/link_layer/eui_provider/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/link_layer/eui_provider/eui_provider.c b/sys/net/link_layer/eui_provider/eui_provider.c new file mode 100644 index 0000000000..558b5b4e35 --- /dev/null +++ b/sys/net/link_layer/eui_provider/eui_provider.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * 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. + */ + +/** + * @{ + * + * @file + * @author Benjamin Valentin + */ + +#include "eui48_provider_params.h" +#include "eui64_provider_params.h" +#include "luid.h" +#include "net/eui_provider.h" + +void netdev_eui48_get(netdev_t *netdev, eui48_t *addr) +{ + unsigned i = EUI48_PROVIDER_NUMOF; + while (i--) { +#ifdef MODULE_NETDEV_REGISTER + if (eui48_conf[i].type != netdev->type && + eui48_conf[i].type != NETDEV_ANY) { + continue; + } + + if (eui48_conf[i].index != netdev->index && + eui48_conf[i].index != NETDEV_INDEX_ANY) { + continue; + } +#else + (void) netdev; +#endif + if (eui48_conf[i].provider(eui48_conf[i].arg, addr) == 0) { + return; + } + } + + luid_netdev_get_eui48(netdev, addr); +} + +void netdev_eui64_get(netdev_t *netdev, eui64_t *addr) +{ + unsigned i = EUI64_PROVIDER_NUMOF; + while (i--) { +#ifdef MODULE_NETDEV_REGISTER + if (eui64_conf[i].type != netdev->type && + eui64_conf[i].type != NETDEV_ANY) { + continue; + } + + if (eui64_conf[i].index != netdev->index && + eui64_conf[i].index != NETDEV_INDEX_ANY) { + continue; + } +#else + (void) netdev; +#endif + if (eui64_conf[i].provider(eui64_conf[i].arg, addr) == 0) { + return; + } + } + + luid_netdev_get_eui64(netdev, addr); +} + +/** @} */ diff --git a/sys/net/link_layer/eui_provider/include/eui48_provider_params.h b/sys/net/link_layer/eui_provider/include/eui48_provider_params.h new file mode 100644 index 0000000000..26cda3fbd0 --- /dev/null +++ b/sys/net/link_layer/eui_provider/include/eui48_provider_params.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * 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. + */ + +/** + * @ingroup net_eui_provider + * + * @file + * @brief EUI-48 address provider default values + * + * @author Benjamin Valentin + */ +#ifndef EUI48_PROVIDER_PARAMS_H +#define EUI48_PROVIDER_PARAMS_H + +#include "board.h" +#include "net/eui_provider.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief A `netdev_get_eui48_cb_t` function + */ +#ifndef EUI48_PROVIDER_FUNC +#define EUI48_PROVIDER_FUNC NULL + +/** + * @brief Number of EUI-48 providers, determined automatically + */ +#ifndef EUI48_PROVIDER_PARAMS +#define EUI48_PROVIDER_NUMOF 0U +#endif +#endif + +/** + * @brief Optional function argument to `netdev_get_eui48_cb_t` + */ +#ifndef EUI48_PROVIDER_ARG +#define EUI48_PROVIDER_ARG NULL +#endif + +/** + * @brief Driver type to match with EUI-48 provider + */ +#ifndef EUI48_PROVIDER_TYPE +#define EUI48_PROVIDER_TYPE NETDEV_ANY +#endif + +/** + * @brief If multiple instances of a device exist, which one should + * be assigned the EUI-48 + */ +#ifndef EUI48_PROVIDER_INDEX +#define EUI48_PROVIDER_INDEX NETDEV_INDEX_ANY +#endif + +/** + * @brief Array of available EUI-48 providers + */ +#ifndef EUI48_PROVIDER_PARAMS +#define EUI48_PROVIDER_PARAMS { \ + .provider = EUI48_PROVIDER_FUNC, \ + .arg = EUI48_PROVIDER_ARG, \ + .type = EUI48_PROVIDER_TYPE, \ + .index = EUI48_PROVIDER_INDEX, \ + }, +#endif + + +/** + * @name EUI-48 sources on the board + * + * @{ + */ +static const eui48_conf_t eui48_conf[] = { + EUI48_PROVIDER_PARAMS +}; + +#ifndef EUI48_PROVIDER_NUMOF +#define EUI48_PROVIDER_NUMOF ARRAY_SIZE(eui48_conf) +#endif +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* EUI48_PROVIDER_PARAMS_H */ diff --git a/sys/net/link_layer/eui_provider/include/eui64_provider_params.h b/sys/net/link_layer/eui_provider/include/eui64_provider_params.h new file mode 100644 index 0000000000..802cfaec23 --- /dev/null +++ b/sys/net/link_layer/eui_provider/include/eui64_provider_params.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * 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. + */ + +/** + * @ingroup net_eui_provider + * + * @file + * @brief EUI-64 address provider default values + * + * @author Benjamin Valentin + */ +#ifndef EUI64_PROVIDER_PARAMS_H +#define EUI64_PROVIDER_PARAMS_H + +#include "board.h" +#include "net/eui_provider.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief A `netdev_get_eui64_cb_t` function + */ +#ifndef EUI64_PROVIDER_FUNC +#define EUI64_PROVIDER_FUNC NULL + +/** + * @brief Number of EUI-64 providers, determined automatically + */ +#ifndef EUI64_PROVIDER_PARAMS +#define EUI64_PROVIDER_NUMOF 0U +#endif +#endif + +/** + * @brief Optional function argument to `netdev_get_eui64_cb_t` + */ +#ifndef EUI64_PROVIDER_ARG +#define EUI64_PROVIDER_ARG NULL +#endif + +/** + * @brief Driver type to match with EUI-64 provider + */ +#ifndef EUI64_PROVIDER_TYPE +#define EUI64_PROVIDER_TYPE NETDEV_ANY +#endif + +/** + * @brief If multiple instances of a device exist, which one should + * be assigned the EUI-64 + */ +#ifndef EUI64_PROVIDER_INDEX +#define EUI64_PROVIDER_INDEX NETDEV_INDEX_ANY +#endif + +/** + * @brief Array of available EUI-64 providers + */ +#ifndef EUI64_PROVIDER_PARAMS +#define EUI64_PROVIDER_PARAMS { \ + .provider = EUI64_PROVIDER_FUNC, \ + .arg = EUI64_PROVIDER_ARG, \ + .type = EUI64_PROVIDER_TYPE, \ + .index = EUI64_PROVIDER_INDEX, \ + }, +#endif + + +/** + * @name EUI-64 sources on the board + * + * @{ + */ +static const eui64_conf_t eui64_conf[] = { + EUI64_PROVIDER_PARAMS +}; + +#ifndef EUI64_PROVIDER_NUMOF +#define EUI64_PROVIDER_NUMOF ARRAY_SIZE(eui64_conf) +#endif +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* EUI64_PROVIDER_PARAMS_H */