diff --git a/examples/gnrc_minimal/main.c b/examples/gnrc_minimal/main.c index 16fab3323769..ea87a918a5f2 100644 --- a/examples/gnrc_minimal/main.c +++ b/examples/gnrc_minimal/main.c @@ -24,29 +24,17 @@ #include "net/ipv6/addr.h" #include "net/gnrc.h" #include "net/gnrc/netif.h" +#include "net/netif.h" int main(void) { puts("RIOT network stack example application"); - /* get interfaces and print their addresses */ - gnrc_netif_t *netif = NULL; - while ((netif = gnrc_netif_iter(netif))) { - ipv6_addr_t ipv6_addrs[CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF]; - int res = gnrc_netapi_get(netif->pid, NETOPT_IPV6_ADDR, 0, ipv6_addrs, - sizeof(ipv6_addrs)); - - if (res < 0) { - continue; - } - for (unsigned i = 0; i < (unsigned)(res / sizeof(ipv6_addr_t)); i++) { - char ipv6_addr[IPV6_ADDR_MAX_STR_LEN]; - - ipv6_addr_to_str(ipv6_addr, &ipv6_addrs[i], IPV6_ADDR_MAX_STR_LEN); - printf("My address is %s\n", ipv6_addr); - } - } + /* print all IPv6 addresses */ + printf("{\"IPv6 addresses\": [\""); + netifs_print_ipv6("\", \""); + puts("\"]}"); /* main thread exits */ return 0; diff --git a/examples/nanocoap_server/Makefile b/examples/nanocoap_server/Makefile index a7851cb46218..7f2520df74f7 100644 --- a/examples/nanocoap_server/Makefile +++ b/examples/nanocoap_server/Makefile @@ -27,9 +27,6 @@ USEMODULE += fmt # include sha256 (used by example blockwise handler) USEMODULE += hashes -# include this for printing IP addresses -USEMODULE += shell_commands - # Comment this out to enable code in RIOT that does safety checking # which is not needed in a production environment but helps in the # development process: diff --git a/examples/nanocoap_server/main.c b/examples/nanocoap_server/main.c index dca6322c0c64..739a63e3d96f 100644 --- a/examples/nanocoap_server/main.c +++ b/examples/nanocoap_server/main.c @@ -27,9 +27,6 @@ #define MAIN_QUEUE_SIZE (8) static msg_t _main_msg_queue[MAIN_QUEUE_SIZE]; -/* import "ifconfig" shell command, used for printing addresses */ -extern int _gnrc_netif_config(int argc, char **argv); - int main(void) { puts("RIOT nanocoap example application"); @@ -41,8 +38,9 @@ int main(void) xtimer_sleep(3); /* print network addresses */ - puts("Configured network interfaces:"); - _gnrc_netif_config(0, NULL); + printf("{\"IPv6 addresses\": [\""); + netifs_print_ipv6("\", \""); + puts("\"]}"); /* initialize nanocoap server instance */ uint8_t buf[COAP_INBUF_SIZE]; diff --git a/examples/telnet_server/main.c b/examples/telnet_server/main.c index 41f6b7b97a13..7cfa348591f6 100644 --- a/examples/telnet_server/main.c +++ b/examples/telnet_server/main.c @@ -30,26 +30,6 @@ #define MAIN_QUEUE_SIZE (8) static msg_t _main_msg_queue[MAIN_QUEUE_SIZE]; -static void _print_addr(void) -{ - gnrc_netif_t *netif = NULL; - while ((netif = gnrc_netif_iter(netif))) { - ipv6_addr_t ipv6_addrs[CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF]; - int res = gnrc_netapi_get(netif->pid, NETOPT_IPV6_ADDR, 0, ipv6_addrs, - sizeof(ipv6_addrs)); - - if (res < 0) { - continue; - } - for (unsigned i = 0; i < (unsigned)(res / sizeof(ipv6_addr_t)); i++) { - char ipv6_addr[IPV6_ADDR_MAX_STR_LEN]; - - ipv6_addr_to_str(ipv6_addr, &ipv6_addrs[i], IPV6_ADDR_MAX_STR_LEN); - printf("My address is %s\n", ipv6_addr); - } - } -} - static void _print_motd(void) { puts("RIOT telnet example application"); @@ -90,8 +70,10 @@ int main(void) _print_motd(); - /* print address so we can connect to it */ - _print_addr(); + /* print address(es) so we can connect to it */ + printf("{\"IPv6 addresses\": [\""); + netifs_print_ipv6("\", \""); + puts("\"]}"); /* start shell */ printf("All up, awaiting connection on port %u\n", CONFIG_TELNET_PORT); diff --git a/sys/include/net/ipv6/addr.h b/sys/include/net/ipv6/addr.h index bced25f689a2..355a04db6b7e 100644 --- a/sys/include/net/ipv6/addr.h +++ b/sys/include/net/ipv6/addr.h @@ -816,10 +816,20 @@ static inline char *ipv6_addr_split_iface(char *addr_str) /** * @brief Print IPv6 address to stdout * - * @param[in] addr Pointer to ipv6_addr_t to print + * @param[in] addr Pointer to ipv6_addr_t to print */ void ipv6_addr_print(const ipv6_addr_t *addr); +/** + * @brief Print IPv6 addresses to stdout + * + * @param[in] addrs Array of addresses to print + * @param[in] num Number of elements in @p addrs + * @param[in] separator Separator to print between addresses + */ +void ipv6_addrs_print(const ipv6_addr_t *addrs, size_t num, + const char *separator); + #ifdef __cplusplus } #endif diff --git a/sys/include/net/netif.h b/sys/include/net/netif.h index 2316695fa33f..0540c2db992f 100644 --- a/sys/include/net/netif.h +++ b/sys/include/net/netif.h @@ -35,9 +35,11 @@ #include #include +#include #include "list.h" #include "net/netopt.h" +#include "net/ipv6.h" #ifdef MODULE_NETSTATS_NEIGHBOR #include "cib.h" @@ -200,6 +202,65 @@ int netif_set_opt(netif_t *netif, netopt_t opt, uint16_t context, */ int netif_register(netif_t *netif); +/** + * @brief Get IPv6 address(es) of the given interface + * @param[in] netif Interface to get the IPv6 address(es) from + * @param[out] dest Array of IPv6 addresses to write to + * @param[in] numof Size of @p dest in array elements (not in bytes!) + * @retval -1 Failed + * @return Number of addresses written to @p dest + */ +static inline ssize_t netif_get_ipv6(netif_t *netif, ipv6_addr_t *dest, + size_t numof) +{ + int res = netif_get_opt(netif, NETOPT_IPV6_ADDR, 0, dest, sizeof(*dest) * numof); + if (res < 0) { + /* standard says at ssize_t's value range is [-1, SSIZE_MAX], so do + * not rely on smaller numbers that -1 being passed through correctly */ + return -1; + } + + return res / sizeof(*dest); +} + +/** + * @brief Get IPv6 address(es) of **all** interfaces + * @param[out] dest Array of IPv6 addresses to write to + * @param[in] numof Size of @p dest in array elements (not in bytes!) + * @retval -1 Failed + * @return Number of addresses written to @p dest + */ +ssize_t netifs_get_ipv6(ipv6_addr_t *dest, size_t numof); + +/** + * @brief Print the IPv6 address(es) of the given interface + * @param[in] netif Interface to print the IPv6 address(es) of + * @param[in] separator Separator to print between the IPv6 addresses + * + * Usage: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} + * // print IPv6 addrs of netif as JSON + * printf("{\"IPv6 addresses\": [\""); + * netif_print_ipv6(netif, "\", \""); + * puts("\"]}"); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +void netif_print_ipv6(netif_t *netif, const char *separator); + +/** + * @brief Print the IPv6 address(es) of **all** interface + * @param[in] separator Separator to print between the IPv6 addresses + * + * Usage: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} + * // print all IPv6 addrs as JSON + * printf("{\"IPv6 addresses\": [\""); + * netifs_print_ipv6("\", \""); + * puts("\"]}"); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +void netifs_print_ipv6(const char *separator); + #ifdef __cplusplus } #endif diff --git a/sys/net/netif/netif.c b/sys/net/netif/netif.c index 57064d05d7bf..79f2ce24c86f 100644 --- a/sys/net/netif/netif.c +++ b/sys/net/netif/netif.c @@ -14,10 +14,12 @@ */ #include +#include +#include #include -#include "errno.h" #include "irq.h" +#include "kernel_defines.h" #include "net/netif.h" #include "utlist.h" @@ -91,4 +93,52 @@ __attribute__((weak)) netif_t *netif_get_by_id(int16_t id) return NULL; } +ssize_t netifs_get_ipv6(ipv6_addr_t *dest, size_t numof) +{ + ssize_t result = 0; + netif_t *netif = NULL; + while (((netif = netif_iter(netif)) != NULL) && (numof > 0)) { + ssize_t addrs_numof = netif_get_ipv6(netif, dest, numof); + if (addrs_numof <= 0) { + continue; + } + result += addrs_numof; + dest += addrs_numof; + numof -= addrs_numof; + } + + return result; +} + +#ifndef NETIF_PRINT_IPV6_NUMOF +#define NETIF_PRINT_IPV6_NUMOF 4 +#endif + +void netif_print_ipv6(netif_t *netif, const char *separator) +{ + ipv6_addr_t addrs[NETIF_PRINT_IPV6_NUMOF]; + ssize_t num = netif_get_ipv6(netif, addrs, ARRAY_SIZE(addrs)); + if (num > 0) { + ipv6_addrs_print(addrs, num, separator); + } +} + +void netifs_print_ipv6(const char *separator) +{ + netif_t *netif = 0; + bool first = true; + while ((netif = netif_iter(netif)) != NULL) { + ipv6_addr_t addrs[NETIF_PRINT_IPV6_NUMOF]; + ssize_t num = netif_get_ipv6(netif, addrs, ARRAY_SIZE(addrs)); + if (num > 0) { + if (first) { + first = false; + } + else { + printf("%s", separator); + } + ipv6_addrs_print(addrs, num, separator); + } + } +} /** @} */ diff --git a/sys/net/network_layer/ipv6/addr/ipv6_addr.c b/sys/net/network_layer/ipv6/addr/ipv6_addr.c index 9b2e97f66bbe..a6a7962b0860 100644 --- a/sys/net/network_layer/ipv6/addr/ipv6_addr.c +++ b/sys/net/network_layer/ipv6/addr/ipv6_addr.c @@ -17,14 +17,11 @@ #include #include #include +#include -#include "net/ipv6/addr.h" - -#ifdef MODULE_FMT #include "fmt.h" -#else -#include -#endif +#include "kernel_defines.h" +#include "net/ipv6/addr.h" const ipv6_addr_t ipv6_addr_unspecified = IPV6_ADDR_UNSPECIFIED; const ipv6_addr_t ipv6_addr_loopback = IPV6_ADDR_LOOPBACK; @@ -147,11 +144,43 @@ void ipv6_addr_print(const ipv6_addr_t *addr) assert(addr); char addr_str[IPV6_ADDR_MAX_STR_LEN]; ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)); -#ifdef MODULE_FMT - print_str(addr_str); -#else - printf("%s", addr_str); -#endif + + if (IS_USED(MODULE_FMT)) { + print_str(addr_str); + } + else { + printf("%s", addr_str); + } +} + +void ipv6_addrs_print(const ipv6_addr_t *addrs, size_t num, + const char *separator) +{ + if (num == 0) { + return; + } + + num--; + char buf[IPV6_ADDR_MAX_STR_LEN]; + for (size_t idx = 0; idx < (size_t)num; idx++) { + ipv6_addr_to_str(buf, &addrs[idx], sizeof(buf)); + if (IS_USED(MODULE_FMT)) { + print_str(buf); + print_str(separator); + } + else { + printf("%s%s", buf, separator); + } + } + + ipv6_addr_to_str(buf, &addrs[num], sizeof(buf)); + if (IS_USED(MODULE_FMT)) { + print_str(buf); + print_str(separator); + } + else { + printf("%s%s", buf, separator); + } } /** diff --git a/tests/pkg_microcoap/Makefile b/tests/pkg_microcoap/Makefile index 40a15605276e..af6362647fa4 100644 --- a/tests/pkg_microcoap/Makefile +++ b/tests/pkg_microcoap/Makefile @@ -15,9 +15,6 @@ USEMODULE += xtimer USEPKG += microcoap -# include this for printing IP addresses -USEMODULE += shell_commands - # Use different settings when compiling for one of the following (low-memory) # boards LOW_MEMORY_BOARDS := nucleo-f334r8 diff --git a/tests/pkg_microcoap/main.c b/tests/pkg_microcoap/main.c index 25eaccaf9416..a75f00f96560 100644 --- a/tests/pkg_microcoap/main.c +++ b/tests/pkg_microcoap/main.c @@ -18,14 +18,13 @@ */ #include + #include "msg.h" +#include "net/netif.h" #include "xtimer.h" void microcoap_server_loop(void); -/* import "ifconfig" shell command, used for printing addresses */ -extern int _gnrc_netif_config(int argc, char **argv); - int main(void) { puts("RIOT microcoap test application"); @@ -34,8 +33,9 @@ int main(void) xtimer_sleep(3); /* print network addresses */ - puts("Configured network interfaces:"); - _gnrc_netif_config(0, NULL); + printf("{\"IPv6 addresses\": [\""); + netifs_print_ipv6("\", \""); + puts("\"]}"); /* start coap server loop */ microcoap_server_loop();