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:
parent
e2792c6509
commit
3046e95d85
3 changed files with 164 additions and 14 deletions
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue