samples: net: echo-client: Check IPv6 address deprecation

If the IPv6 address that our socket is bound to deprecates, then
re-create the socket so that we avoid using deprecated IPv6 address.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
This commit is contained in:
Jukka Rissanen 2024-04-25 13:02:07 +03:00 committed by Fabio Baltieri
parent e2792c6509
commit 3046e95d85
3 changed files with 164 additions and 14 deletions

View file

@ -24,6 +24,8 @@ LOG_MODULE_REGISTER(net_echo_client_sample, LOG_LEVEL_DBG);
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <zephyr/posix/sys/eventfd.h>
#include <zephyr/net/socket.h> #include <zephyr/net/socket.h>
#include <zephyr/net/tls_credentials.h> #include <zephyr/net/tls_credentials.h>
@ -46,6 +48,8 @@ struct k_mem_domain app_domain;
#define EVENT_MASK (NET_EVENT_L4_CONNECTED | \ #define EVENT_MASK (NET_EVENT_L4_CONNECTED | \
NET_EVENT_L4_DISCONNECTED) NET_EVENT_L4_DISCONNECTED)
#define IPV6_EVENT_MASK (NET_EVENT_IPV6_ADDR_ADD | \
NET_EVENT_IPV6_ADDR_DEPRECATED)
/* Generated by http://www.lipsum.com/ /* Generated by http://www.lipsum.com/
* 2 paragraphs, 179 words, 1160 bytes of Lorem Ipsum * 2 paragraphs, 179 words, 1160 bytes of Lorem Ipsum
@ -87,16 +91,26 @@ APP_DMEM struct configs conf = {
}, },
}; };
static APP_BMEM struct pollfd fds[4]; static APP_BMEM struct pollfd fds[1 + 4];
static APP_BMEM int nfds; static APP_BMEM int nfds;
static APP_BMEM bool connected; static APP_BMEM bool connected;
static APP_BMEM bool need_restart;
K_SEM_DEFINE(run_app, 0, 1); K_SEM_DEFINE(run_app, 0, 1);
static struct net_mgmt_event_callback mgmt_cb; static struct net_mgmt_event_callback mgmt_cb;
static struct net_mgmt_event_callback ipv6_mgmt_cb;
static void prepare_fds(void) static void prepare_fds(void)
{ {
nfds = 0;
/* eventfd is used to trigger restart */
fds[nfds].fd = eventfd(0, 0);
fds[nfds].events = POLLIN;
nfds++;
if (conf.ipv4.udp.sock >= 0) { if (conf.ipv4.udp.sock >= 0) {
fds[nfds].fd = conf.ipv4.udp.sock; fds[nfds].fd = conf.ipv4.udp.sock;
fds[nfds].events = POLLIN; fds[nfds].events = POLLIN;
@ -124,11 +138,29 @@ static void prepare_fds(void)
static void wait(void) static void wait(void)
{ {
int ret;
/* Wait for event on any socket used. Once event occurs, /* Wait for event on any socket used. Once event occurs,
* we'll check them all. * we'll check them all.
*/ */
if (poll(fds, nfds, -1) < 0) { ret = poll(fds, nfds, -1);
LOG_ERR("Error in poll:%d", errno); if (ret < 0) {
static bool once;
if (!once) {
once = true;
LOG_ERR("Error in poll:%d", errno);
}
return;
}
if (ret > 0 && fds[0].revents) {
eventfd_t value;
eventfd_read(fds[0].fd, &value);
LOG_DBG("Received restart event.");
return;
} }
} }
@ -193,6 +225,99 @@ static void stop_udp_and_tcp(void)
} }
} }
static int check_our_ipv6_sockets(int sock,
struct in6_addr *deprecated_addr)
{
struct sockaddr_in6 addr = { 0 };
socklen_t addrlen = sizeof(addr);
int ret;
if (sock < 0) {
return -EINVAL;
}
ret = getsockname(sock, (struct sockaddr *)&addr, &addrlen);
if (ret != 0) {
return -errno;
}
if (!net_ipv6_addr_cmp(deprecated_addr, &addr.sin6_addr)) {
return -ENOENT;
}
need_restart = true;
return 0;
}
static void ipv6_event_handler(struct net_mgmt_event_callback *cb,
uint32_t mgmt_event, struct net_if *iface)
{
static char addr_str[INET6_ADDRSTRLEN];
if (!IS_ENABLED(CONFIG_NET_IPV6_PE)) {
return;
}
if ((mgmt_event & IPV6_EVENT_MASK) != mgmt_event) {
return;
}
if (cb->info == NULL ||
cb->info_length != sizeof(struct in6_addr)) {
return;
}
if (mgmt_event == NET_EVENT_IPV6_ADDR_ADD) {
struct net_if_addr *ifaddr;
struct in6_addr added_addr;
memcpy(&added_addr, cb->info, sizeof(struct in6_addr));
ifaddr = net_if_ipv6_addr_lookup(&added_addr, &iface);
if (ifaddr == NULL) {
return;
}
/* Wait until we get a temporary address before continuing after
* boot.
*/
if (ifaddr->is_temporary) {
static bool once;
LOG_INF("Temporary IPv6 address %s added",
inet_ntop(AF_INET6, &added_addr, addr_str,
sizeof(addr_str) - 1));
if (!once) {
k_sem_give(&run_app);
once = true;
}
}
}
if (mgmt_event == NET_EVENT_IPV6_ADDR_DEPRECATED) {
struct in6_addr deprecated_addr;
memcpy(&deprecated_addr, cb->info, sizeof(struct in6_addr));
LOG_INF("IPv6 address %s deprecated",
inet_ntop(AF_INET6, &deprecated_addr, addr_str,
sizeof(addr_str) - 1));
(void)check_our_ipv6_sockets(conf.ipv6.tcp.sock,
&deprecated_addr);
(void)check_our_ipv6_sockets(conf.ipv6.udp.sock,
&deprecated_addr);
if (need_restart) {
eventfd_write(fds[0].fd, 1);
}
return;
}
}
static void event_handler(struct net_mgmt_event_callback *cb, static void event_handler(struct net_mgmt_event_callback *cb,
uint32_t mgmt_event, struct net_if *iface) uint32_t mgmt_event, struct net_if *iface)
{ {
@ -206,7 +331,10 @@ static void event_handler(struct net_mgmt_event_callback *cb,
connected = true; connected = true;
conf.ipv4.udp.mtu = net_if_get_mtu(iface); conf.ipv4.udp.mtu = net_if_get_mtu(iface);
conf.ipv6.udp.mtu = conf.ipv4.udp.mtu; conf.ipv6.udp.mtu = conf.ipv4.udp.mtu;
k_sem_give(&run_app);
if (!IS_ENABLED(CONFIG_NET_IPV6_PE)) {
k_sem_give(&run_app);
}
return; return;
} }
@ -275,6 +403,10 @@ static void init_app(void)
conn_mgr_mon_resend_status(); conn_mgr_mon_resend_status();
} }
net_mgmt_init_event_callback(&ipv6_mgmt_cb,
ipv6_event_handler, IPV6_EVENT_MASK);
net_mgmt_add_event_callback(&ipv6_mgmt_cb);
init_vlan(); init_vlan();
init_udp(); init_udp();
} }
@ -293,19 +425,35 @@ static void start_client(void *p1, void *p2, void *p3)
/* Wait for the connection. */ /* Wait for the connection. */
k_sem_take(&run_app, K_FOREVER); k_sem_take(&run_app, K_FOREVER);
ret = start_udp_and_tcp(); if (IS_ENABLED(CONFIG_NET_IPV6_PE)) {
/* Make sure that we have a temporary address */
k_sleep(K_SECONDS(1));
}
while (connected && (ret == 0)) { do {
ret = run_udp_and_tcp(); if (need_restart) {
/* Close all sockets and get a fresh restart */
stop_udp_and_tcp();
need_restart = false;
}
if (iterations > 0) { ret = start_udp_and_tcp();
i++;
if (i >= iterations) { while (connected && (ret == 0)) {
ret = run_udp_and_tcp();
if (iterations > 0) {
i++;
if (i >= iterations) {
break;
}
}
if (need_restart) {
break; break;
} }
} }
} } while (need_restart);
stop_udp_and_tcp(); stop_udp_and_tcp();
} }

View file

@ -239,7 +239,8 @@ int start_tcp(void)
inet_pton(AF_INET6, CONFIG_NET_CONFIG_PEER_IPV6_ADDR, inet_pton(AF_INET6, CONFIG_NET_CONFIG_PEER_IPV6_ADDR,
&addr6.sin6_addr); &addr6.sin6_addr);
ret = start_tcp_proto(&conf.ipv6, (struct sockaddr *)&addr6, ret = start_tcp_proto(&conf.ipv6,
(struct sockaddr *)&addr6,
sizeof(addr6)); sizeof(addr6));
if (ret < 0) { if (ret < 0) {
return ret; return ret;

View file

@ -308,7 +308,8 @@ int start_udp(void)
inet_pton(AF_INET6, CONFIG_NET_CONFIG_PEER_IPV6_ADDR, inet_pton(AF_INET6, CONFIG_NET_CONFIG_PEER_IPV6_ADDR,
&addr6.sin6_addr); &addr6.sin6_addr);
ret = start_udp_proto(&conf.ipv6, (struct sockaddr *)&addr6, ret = start_udp_proto(&conf.ipv6,
(struct sockaddr *)&addr6,
sizeof(addr6)); sizeof(addr6));
if (ret < 0) { if (ret < 0) {
return ret; return ret;