diff --git a/Makefile.dep b/Makefile.dep index 9b9dcd53ab..356746da10 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -143,6 +143,10 @@ ifneq (,$(filter trickle,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter gnrc_netif,$(USEMODULE))) + USEMODULE += netif +endif + ifneq (,$(filter ieee802154 nrfmin,$(USEMODULE))) ifneq (,$(filter gnrc_ipv6, $(USEMODULE))) USEMODULE += gnrc_sixlowpan diff --git a/sys/Makefile.include b/sys/Makefile.include index dfbb94067b..baa5e0b298 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -13,6 +13,9 @@ endif ifneq (,$(filter fib,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/sys/posix/include endif +ifneq (,$(filter gnrc_netif,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/gnrc/netif/include +endif ifneq (,$(filter gnrc_sock,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/gnrc/sock/include ifneq (,$(filter gnrc_ipv6,$(USEMODULE))) diff --git a/sys/include/net/netif.h b/sys/include/net/netif.h new file mode 100644 index 0000000000..e0fedf0a65 --- /dev/null +++ b/sys/include/net/netif.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2016 Kaspar Schleiser + * Copyright (C) 2017 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 + * directory for more details. + */ + +/** + * @defgroup net_netif Network interfaces + * @ingroup net + * @brief Common network interface API + * + * This allows access to network interfaces regardless of the network stack + * implementation. @anchor NETIF_INVALID The network stack must provide + * + * - Both a definition for the type `netif_t` and the + * value `NETIF_INVALID` of type `netif_t` in a file `netif_types.h` and + * - implementation of all the functions defined in @ref net/netif.h + * + * @{ + * + * @file + * @brief Common network interface API definitions + * + * @author Martine Lenders + * @author Kaspar Schleiser + */ +#ifndef NET_NETIF_H +#define NET_NETIF_H + +#include "net/netopt.h" + +#include "netif_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Maximum length for an interface name + */ +#ifndef NETIF_NAMELENMAX +#define NETIF_NAMELENMAX (8U) +#endif + +/** + * @brief Iterator for the interfaces + * + * Returns interface after @p last. To start use `last == NETIF_INVALID`. + * + * @param[in] last The previous interface. Usen `NETIF_INVALID` to start + * iteration. + * + * @note Supposed to be implemented by the networking module + * + * @return next network interface. + * @return @ref NETIF_INVALID, if there is no interface after @p last + */ +netif_t netif_iter(netif_t last); + +/** + * @brief Gets name of an interface + * + * @pre `name != NULL` + * @pre name holds at least @ref NETIF_NAMELENMAX characters + * + * @note Supposed to be implemented by the networking module. `name` must be + * zero-terminated in the result! + * + * @param[in] netif A network interface. + * @param[out] name The name of the interface. Must not be `NULL`. Must at least + * hold @ref NETIF_NAMELENMAX bytes. + * + * @return length of @p name on success + * @return 0, if @p netif was not a valid interface. + */ +int netif_get_name(netif_t netif, char *name); + +/** + * @brief Gets interface by name + * + * @pre `name != NULL` + * + * @note Supposed to be implemented by the networking module. + + * + * @param[in] name The name of an interface as a zero-terminated. Must not be + * `NULL`. + * + * @return The identifier of the interface on success. + * @return @ref NETIF_INVALID if no interface is named @p name. + */ +netif_t netif_get_by_name(const char *name); + +/** + * @brief Gets option from an interface + * + * @note Supposed to be implemented by the networking module + * + * @param[in] netif A network interface. + * @param[in] opt Option type. + * @param[in] context (Optional) context to the given option + * @param[out] value Pointer to store the option's value in. + * @param[in] max_len Maximal amount of byte that fit into @p value. + * + * @return Number of bytes written to @p value. + * @return `< 0` on error, 0 on success. + */ +int netif_get_opt(netif_t netif, netopt_t opt, uint16_t context, + void *value, size_t max_len); + +/** + * @brief Sets option to an interface + * + * @note Supposed to be implemented by the networking module + * + * @param[in] netif A network interface. + * @param[in] opt Option type. + * @param[in] context (Optional) context to the given option + * @param[in] value Pointer to store the option's value in. + * @param[in] value_len The length of @p value. + * + * @return Number of bytes used from @p value. + * @return `< 0` on error, 0 on success. + */ +int netif_set_opt(netif_t netif, netopt_t opt, uint16_t context, + void *value, size_t value_len); + +#ifdef __cplusplus +} +#endif + +#endif /* NET_NETIF_H */ +/** @} */ diff --git a/sys/net/gnrc/netif/_netif.c b/sys/net/gnrc/netif/_netif.c new file mode 100644 index 0000000000..4c534b797c --- /dev/null +++ b/sys/net/gnrc/netif/_netif.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 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 + * directory for more details. + */ + +/** + * @{ + * + * Implements @ref net_netif for @ref net_gnrc + * + * @file + * @author Martine Lenders + */ + +#include + +#include "fmt.h" +#include "net/gnrc/netapi.h" +#include "net/gnrc/netif/internal.h" + +#include "net/netif.h" + +netif_t netif_iter(netif_t last) +{ + gnrc_netif_t *netif; + + if (last == NETIF_INVALID) { + netif = gnrc_netif_iter(NULL); + } + else if ((netif = gnrc_netif_get_by_pid((kernel_pid_t)last)) != NULL) { + netif = gnrc_netif_iter(netif); + } + if (netif != NULL) { + return netif->pid; + } + else { + return NETIF_INVALID; + } +} + +int netif_get_name(netif_t iface, char *name) +{ + gnrc_netif_t *netif = gnrc_netif_get_by_pid((kernel_pid_t)iface); + int res = 0; + + if (netif != NULL) { + res += fmt_str(name, "if"); + res += fmt_u16_dec(&name[res], netif->pid); + name[res] = '\0'; + } + return res; +} + +netif_t netif_get_by_name(const char *name) +{ + if ((strncmp(name, "if", 2) == 0)) { + kernel_pid_t _name_pid = (kernel_pid_t)scn_u32_dec(&name[2], 2); + if (_name_pid > 0) { + gnrc_netif_t *netif = NULL; + + while ((netif = gnrc_netif_iter(netif)) != NULL) { + if (netif->pid == _name_pid) { + return netif->pid; + } + } + } + } + return NETIF_INVALID; +} + +int netif_get_opt(netif_t netif, netopt_t opt, uint16_t context, + void *value, size_t max_len) +{ + return gnrc_netapi_get(netif, opt, context, value, max_len); +} + +int netif_set_opt(netif_t netif, netopt_t opt, uint16_t context, + void *value, size_t value_len) +{ + return gnrc_netapi_set(netif, opt, context, value, value_len); +} + +/** @} */ diff --git a/sys/net/gnrc/netif/include/netif_types.h b/sys/net/gnrc/netif/include/netif_types.h new file mode 100644 index 0000000000..96101e1d10 --- /dev/null +++ b/sys/net/gnrc/netif/include/netif_types.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 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 + * directory for more details. + */ + +/** + * @ingroup net_netif + * @{ + * + * @file + * @brief GNRC-specfic type definitions for @ref net_netif + * + * @author Martine Lenders + */ +#ifndef NETIF_TYPES_H +#define NETIF_TYPES_H + +#include "kernel_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NETIF_INVALID (KERNEL_PID_UNDEF) /**< Invalid interface */ + +typedef kernel_pid_t netif_t; /**< GNRC-representation of a network interface */ + +#ifdef __cplusplus +} +#endif + +#endif /* NETIF_TYPES_H */ +/** @} */ diff --git a/tests/gnrc_netif/main.c b/tests/gnrc_netif/main.c index 04899c3eb7..ef84b12592 100644 --- a/tests/gnrc_netif/main.c +++ b/tests/gnrc_netif/main.c @@ -34,6 +34,7 @@ #include "net/gnrc/netif/ieee802154.h" #include "net/gnrc/netif/internal.h" #include "net/netdev_test.h" +#include "net/netif.h" #include "utlist.h" #include "xtimer.h" @@ -1029,6 +1030,82 @@ static void test_netapi_set__SRC_LEN(void) sizeof(orig_ieee802154))); } +static void test_netif_iter(void) +{ + netif_t netif = NETIF_INVALID; + int netif_count = 0; + + while ((netif = netif_iter(netif)) != NETIF_INVALID) { + netif_count++; + } + TEST_ASSERT_EQUAL_INT(gnrc_netif_numof(), netif_count); +} + +static void test_netif_get_name(void) +{ + char exp_name[NETIF_NAMELENMAX]; + char name[NETIF_NAMELENMAX]; + int res; + netif_t netif = netif_iter(NETIF_INVALID); + /* there must be at least one interface */ + TEST_ASSERT(NETIF_INVALID != netif); + + res = netif_get_name(netif, name); + sprintf(exp_name, "if%d", (int)netif); + TEST_ASSERT_EQUAL_INT(strlen(exp_name), res); + TEST_ASSERT_EQUAL_STRING(&exp_name[0], &name[0]); + TEST_ASSERT_EQUAL_INT(0, netif_get_name(INT16_MAX, name)); +} + +static void test_netif_get_by_name(void) +{ + char name[NETIF_NAMELENMAX] = "6nPRK28"; + netif_t netif = netif_iter(NETIF_INVALID); + + TEST_ASSERT_EQUAL_INT(NETIF_INVALID, netif_get_by_name(name)); + /* there must be at least one interface */ + TEST_ASSERT(NETIF_INVALID != netif); + TEST_ASSERT(netif_get_name(netif, name) > 0); + TEST_ASSERT_EQUAL_INT(netif, netif_get_by_name(name)); +} + +static void test_netif_get_opt(void) +{ + /* just repeat one of the gnrc_netapi_get tests, just with netif_get_opt */ + static const uint8_t exp_ethernet[] = ETHERNET_SRC; + uint8_t value[GNRC_NETIF_L2ADDR_MAXLEN]; + + TEST_ASSERT_EQUAL_INT(sizeof(exp_ethernet), + netif_get_opt((netif_t)ethernet_netif->pid, + NETOPT_ADDRESS, 0, + &value, sizeof(value))); + TEST_ASSERT_EQUAL_INT(0, memcmp(exp_ethernet, value, sizeof(exp_ethernet))); +} + +static void test_netif_set_opt(void) +{ + /* just repeat one of the gnrc_netapi_set tests, just with netif_set_opt */ + static const uint8_t exp_ethernet[] = ETHERNET_SRC; + uint8_t value[] = { LA1 + 1, LA2 + 2, LA3 + 3, LA4 + 4, LA5 + 5, LA6 + 6 }; + + TEST_ASSERT_EQUAL_INT(sizeof(exp_ethernet), + netif_set_opt((netif_t)ethernet_netif->pid, + NETOPT_ADDRESS, 0, + &value, sizeof(value))); + TEST_ASSERT_EQUAL_INT(sizeof(value), ethernet_netif->l2addr_len); + TEST_ASSERT_EQUAL_INT(0, memcmp(value, ethernet_netif->l2addr, + ETHERNET_ADDR_LEN)); + /* return addresses to previous state for further testing */ + memcpy(value, exp_ethernet, sizeof(exp_ethernet)); + TEST_ASSERT_EQUAL_INT(sizeof(exp_ethernet), + netif_set_opt(ethernet_netif->pid, + NETOPT_ADDRESS, 0, + &value, sizeof(value))); + TEST_ASSERT_EQUAL_INT(sizeof(value), ethernet_netif->l2addr_len); + TEST_ASSERT_EQUAL_INT(0, memcmp(value, ethernet_netif->l2addr, + sizeof(value))); +} + static void test_netapi_send__raw_unicast_ethernet_packet(void) { uint8_t dst[] = { LA1, LA2, LA3, LA4, LA5, LA6 + 1 }; @@ -1431,6 +1508,11 @@ static Test *embunit_tests_gnrc_netif(void) new_TestFixture(test_netapi_set__ADDRESS), new_TestFixture(test_netapi_set__ADDRESS_LONG), new_TestFixture(test_netapi_set__SRC_LEN), + new_TestFixture(test_netif_iter), + new_TestFixture(test_netif_get_name), + new_TestFixture(test_netif_get_by_name), + new_TestFixture(test_netif_get_opt), + new_TestFixture(test_netif_set_opt), /* only add tests not involving output here */ }; EMB_UNIT_TESTCALLER(tests, _set_up, NULL, fixtures);