Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions include/zephyr/net/net_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ struct net_if_addr {
struct {
/** Duplicate address detection (DAD) timer */
sys_snode_t dad_node;

/** DAD needed list node */
sys_snode_t dad_need_node;

/** DAD start time */
uint32_t dad_start;

/** How many times we have done DAD */
Expand All @@ -102,6 +107,11 @@ struct net_if_addr {
struct {
/** Address conflict detection (ACD) timer. */
sys_snode_t acd_node;

/** ACD needed list node */
sys_snode_t acd_need_node;

/** ACD timeout value. */
k_timepoint_t acd_timeout;

/** ACD probe/announcement counter. */
Expand Down
70 changes: 62 additions & 8 deletions subsys/net/ip/net_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -1298,8 +1298,9 @@ void net_if_ipv6_start_dad(struct net_if *iface,

void net_if_start_dad(struct net_if *iface)
{
struct net_if_addr *ifaddr;
struct net_if_addr *ifaddr, *next;
struct net_if_ipv6 *ipv6;
sys_slist_t dad_needed;
struct in6_addr addr = { };
int ret;

Expand Down Expand Up @@ -1331,6 +1332,8 @@ void net_if_start_dad(struct net_if *iface)
/* Start DAD for all the addresses that were added earlier when
* the interface was down.
*/
sys_slist_init(&dad_needed);

ARRAY_FOR_EACH(ipv6->unicast, i) {
if (!ipv6->unicast[i].is_used ||
ipv6->unicast[i].address.family != AF_INET6 ||
Expand All @@ -1340,9 +1343,21 @@ void net_if_start_dad(struct net_if *iface)
continue;
}

net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
sys_slist_prepend(&dad_needed, &ipv6->unicast[i].dad_need_node);
}

net_if_unlock(iface);

/* Start DAD for all the addresses without holding the iface lock
* to avoid any possible mutex deadlock issues.
*/
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&dad_needed,
ifaddr, next, dad_need_node) {
net_if_ipv6_start_dad(iface, ifaddr);
}

return;

out:
net_if_unlock(iface);
}
Expand Down Expand Up @@ -1389,7 +1404,10 @@ void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr)
net_if_ipv6_addr_rm(iface, addr);

if (IS_ENABLED(CONFIG_NET_IPV6_PE) && iface->pe_enabled) {
net_if_unlock(iface);

net_ipv6_pe_start(iface, addr, timeout, preferred_lifetime);
return;
}

out:
Expand Down Expand Up @@ -1493,6 +1511,8 @@ void net_if_start_rs(struct net_if *iface)
goto out;
}

net_if_unlock(iface);

NET_DBG("Starting ND/RS for iface %p", iface);

if (!net_ipv6_start_rs(iface)) {
Expand All @@ -1508,6 +1528,7 @@ void net_if_start_rs(struct net_if *iface)
}
}

return;
out:
net_if_unlock(iface);
}
Expand Down Expand Up @@ -1902,6 +1923,7 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
{
struct net_if_addr *ifaddr = NULL;
struct net_if_ipv6 *ipv6;
bool do_dad = false;

net_if_lock(iface);

Expand Down Expand Up @@ -1953,8 +1975,7 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
*/
join_mcast_nodes(iface,
&ipv6->unicast[i].address.in6_addr);

net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
do_dad = true;
} else {
/* If DAD is not done for point-to-point links, then
* the address is usable immediately.
Expand All @@ -1968,9 +1989,17 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
sizeof(struct in6_addr));

ifaddr = &ipv6->unicast[i];
goto out;
break;
}

net_if_unlock(iface);

if (ifaddr != NULL && do_dad) {
net_if_ipv6_start_dad(iface, ifaddr);
}

return ifaddr;

out:
net_if_unlock(iface);

Expand Down Expand Up @@ -4215,7 +4244,9 @@ void net_if_ipv4_start_acd(struct net_if *iface, struct net_if_addr *ifaddr)

void net_if_start_acd(struct net_if *iface)
{
struct net_if_addr *ifaddr, *next;
struct net_if_ipv4 *ipv4;
sys_slist_t acd_needed;
int ret;

net_if_lock(iface);
Expand All @@ -4237,6 +4268,11 @@ void net_if_start_acd(struct net_if *iface)

ipv4->conflict_cnt = 0;

/* Start ACD for all the addresses that were added earlier when
* the interface was down.
*/
sys_slist_init(&acd_needed);

/* Start ACD for all the addresses that were added earlier when
* the interface was down.
*/
Expand All @@ -4248,9 +4284,21 @@ void net_if_start_acd(struct net_if *iface)
continue;
}

net_if_ipv4_start_acd(iface, &ipv4->unicast[i].ipv4);
sys_slist_prepend(&acd_needed, &ipv4->unicast[i].ipv4.acd_need_node);
}

net_if_unlock(iface);

/* Start ACD for all the addresses without holding the iface lock
* to avoid any possible mutex deadlock issues.
*/
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&acd_needed,
ifaddr, next, acd_need_node) {
net_if_ipv4_start_acd(iface, ifaddr);
}

return;

out:
net_if_unlock(iface);
}
Expand Down Expand Up @@ -4342,15 +4390,21 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,

if (!(l2_flags_get(iface) & NET_L2_POINT_TO_POINT) &&
!net_ipv4_is_addr_loopback(addr)) {
net_if_ipv4_start_acd(iface, ifaddr);
/* ACD is started after the lock is released. */
;
} else {
ifaddr->addr_state = NET_ADDR_PREFERRED;
}

net_mgmt_event_notify_with_info(NET_EVENT_IPV4_ADDR_ADD, iface,
&ifaddr->address.in_addr,
sizeof(struct in_addr));
goto out;

net_if_unlock(iface);

net_if_ipv4_start_acd(iface, ifaddr);

return ifaddr;
}

out:
Expand Down
Loading