net: mgmt: Add IPv6 DAD succeed/failed event

We need a way to know when IPv6 address is successfully set
into network interface.

If IPv6 DAD (Duplicate Address Detection) succeeds or fails,
we send a management event for that. This can be used by
other components to detect when the network interface is in
usable state.

Change-Id: Ifb22415fe21f31f5dba4f55455d6e0f89b414d32
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2017-04-12 10:25:54 +03:00
commit 57e128654b
4 changed files with 38 additions and 1 deletions

View file

@ -52,6 +52,8 @@ enum net_event_ipv6_cmd {
NET_EVENT_IPV6_CMD_ROUTER_DEL, NET_EVENT_IPV6_CMD_ROUTER_DEL,
NET_EVENT_IPV6_CMD_ROUTE_ADD, NET_EVENT_IPV6_CMD_ROUTE_ADD,
NET_EVENT_IPV6_CMD_ROUTE_DEL, NET_EVENT_IPV6_CMD_ROUTE_DEL,
NET_EVENT_IPV6_CMD_DAD_SUCCEED,
NET_EVENT_IPV6_CMD_DAD_FAILED,
}; };
#define NET_EVENT_IPV6_ADDR_ADD \ #define NET_EVENT_IPV6_ADDR_ADD \
@ -90,6 +92,12 @@ enum net_event_ipv6_cmd {
#define NET_EVENT_IPV6_ROUTE_DEL \ #define NET_EVENT_IPV6_ROUTE_DEL \
(_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ROUTE_DEL) (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ROUTE_DEL)
#define NET_EVENT_IPV6_DAD_SUCCEED \
(_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_DAD_SUCCEED)
#define NET_EVENT_IPV6_DAD_FAILED \
(_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_DAD_FAILED)
/* IPv4 Events*/ /* IPv4 Events*/
#define _NET_IPV4_LAYER NET_MGMT_LAYER_L3 #define _NET_IPV4_LAYER NET_MGMT_LAYER_L3
#define _NET_IPV4_CORE_CODE 0x004 #define _NET_IPV4_CORE_CODE 0x004

View file

@ -944,6 +944,15 @@ struct in6_addr *net_if_ipv6_get_ll(struct net_if *iface,
struct in6_addr *net_if_ipv6_get_ll_addr(enum net_addr_state state, struct in6_addr *net_if_ipv6_get_ll_addr(enum net_addr_state state,
struct net_if **iface); struct net_if **iface);
/**
* @brief Stop IPv6 Duplicate Address Detection (DAD) procedure if
* we find out that our IPv6 address is already in use.
*
* @param iface Interface where the DAD was running.
* @param addr IPv6 address that failed DAD
*/
void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr);
/** /**
* @brief Return global IPv6 address from the first interface that has * @brief Return global IPv6 address from the first interface that has
* a global IPv6 address either in TENTATIVE or PREFERRED state. * a global IPv6 address either in TENTATIVE or PREFERRED state.

View file

@ -698,7 +698,7 @@ static inline bool dad_failed(struct net_if *iface, struct in6_addr *addr)
return false; return false;
} }
net_if_ipv6_addr_rm(iface, addr); net_if_ipv6_dad_failed(iface, addr);
return true; return true;
} }

View file

@ -397,6 +397,8 @@ static void dad_timeout(struct k_work *work)
*/ */
tmp = net_if_ipv6_addr_lookup(&ifaddr->address.in6_addr, &iface); tmp = net_if_ipv6_addr_lookup(&ifaddr->address.in6_addr, &iface);
if (tmp == ifaddr) { if (tmp == ifaddr) {
net_mgmt_event_notify(NET_EVENT_IPV6_DAD_SUCCEED, iface);
/* The address gets added to neighbor cache which is not needed /* The address gets added to neighbor cache which is not needed
* in this case as the address is our own one. * in this case as the address is our own one.
*/ */
@ -444,6 +446,24 @@ void net_if_start_dad(struct net_if *iface)
net_sprint_ipv6_addr(&addr), iface); net_sprint_ipv6_addr(&addr), iface);
} }
} }
void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr)
{
struct net_if_addr *ifaddr;
ifaddr = net_if_ipv6_addr_lookup(addr, &iface);
if (!ifaddr) {
NET_ERR("Cannot find %s address in interface %p",
net_sprint_ipv6_addr(addr), iface);
return;
}
k_delayed_work_cancel(&ifaddr->dad_timer);
net_mgmt_event_notify(NET_EVENT_IPV6_DAD_FAILED, iface);
net_if_ipv6_addr_rm(iface, addr);
}
#else #else
static inline void net_if_ipv6_start_dad(struct net_if *iface, static inline void net_if_ipv6_start_dad(struct net_if *iface,
struct net_if_addr *ifaddr) struct net_if_addr *ifaddr)