net: config: rely on type rather than number of services configured

So far net config initialization code relied on number of services
needed by application. This was fine as long as all enabled
services (e.g. CONFIG_NET_IPV4=y, CONFIG_NET_IPV6=y) were selected by
project configuration as "needed" (e.g. CONFIG_NET_CONFIG_NEED_IPV4=y,
CONFIG_NET_CONFIG_NEED_IPV6=y). Problem appeared for example when both
IPv4 and IPv6 were enabled (CONFIG_NET_IPV4=y, CONFIG_NET_IPV6=y), but
only IPv6 was marked as "needed" (CONFIG_NET_CONFIG_NEED_IPV6=y). In
such situation number of required services was equal to 1. When IPv4
setup was completed, this resulted in returning from net_config_init()
function. Application code failed, because IPv6 was still not
functional.

Do not rely on number of services anymore, as it is error prone. Use
flags instead to mark which services are ready. Compare those flags with
the flags passed to net_config_init() (selected in project configuration
in most cases) to decide whether network configuration has completed
already or not.

Also introduce services_notify_ready() and services_are_ready() helper
functions to isolate implementation details from the logic.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
This commit is contained in:
Marcin Niestroj 2020-05-20 22:19:41 +02:00 committed by Jukka Rissanen
commit e548c6c5b2

View file

@ -33,11 +33,23 @@ extern int net_init_clock_via_sntp(void);
static K_SEM_DEFINE(waiter, 0, 1);
static struct k_sem counter;
static atomic_t services_flags;
#if defined(CONFIG_NET_NATIVE)
static struct net_mgmt_event_callback mgmt_iface_cb;
#endif
static inline void services_notify_ready(int flags)
{
atomic_or(&services_flags, flags);
k_sem_give(&waiter);
}
static inline bool services_are_ready(int flags)
{
return (atomic_get(&services_flags) & flags) == flags;
}
#if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_NATIVE_IPV4)
static struct net_mgmt_event_callback mgmt4_cb;
@ -81,8 +93,7 @@ static void ipv4_addr_add_handler(struct net_mgmt_event_callback *cb,
break;
}
k_sem_take(&counter, K_NO_WAIT);
k_sem_give(&waiter);
services_notify_ready(NET_CONFIG_NEED_IPV4);
}
static void setup_dhcpv4(struct net_if *iface)
@ -168,8 +179,7 @@ static void setup_ipv4(struct net_if *iface)
}
}
k_sem_take(&counter, K_NO_WAIT);
k_sem_give(&waiter);
services_notify_ready(NET_CONFIG_NEED_IPV4);
}
#else
@ -225,13 +235,11 @@ static void ipv6_event_handler(struct net_mgmt_event_callback *cb,
NET_IPV6_ADDR_LEN)));
#endif
k_sem_take(&counter, K_NO_WAIT);
k_sem_give(&waiter);
services_notify_ready(NET_CONFIG_NEED_IPV6);
}
if (mgmt_event == NET_EVENT_IPV6_ROUTER_ADD) {
k_sem_take(&counter, K_NO_WAIT);
k_sem_give(&waiter);
services_notify_ready(NET_CONFIG_NEED_ROUTER);
}
}
@ -275,8 +283,7 @@ static void setup_ipv6(struct net_if *iface, uint32_t flags)
}
#if !defined(CONFIG_NET_IPV6_DAD)
k_sem_take(&counter, K_NO_WAIT);
k_sem_give(&waiter);
services_notify_ready(NET_CONFIG_NEED_IPV6);
#endif
return;
@ -329,7 +336,7 @@ int net_config_init(const char *app_info, uint32_t flags, int32_t timeout)
#define LOOP_DIVIDER 10
struct net_if *iface = net_if_get_default();
int loop = timeout / LOOP_DIVIDER;
int count, need = 0;
int count;
if (app_info) {
NET_INFO("%s", log_strdup(app_info));
@ -384,16 +391,6 @@ int net_config_init(const char *app_info, uint32_t flags, int32_t timeout)
return -ENETDOWN;
}
if (flags & NET_CONFIG_NEED_IPV6) {
need++;
}
if (flags & NET_CONFIG_NEED_IPV4) {
need++;
}
k_sem_init(&counter, need, UINT_MAX);
setup_ipv4(iface);
setup_dhcpv4(iface);
setup_ipv6(iface, flags);
@ -401,12 +398,8 @@ int net_config_init(const char *app_info, uint32_t flags, int32_t timeout)
/* Loop here until we are ready to continue. As we might need
* to wait multiple events, sleep smaller amounts of data.
*/
while (count--) {
while (!services_are_ready(flags) && count--) {
k_sem_take(&waiter, K_MSEC(loop));
if (!k_sem_count_get(&counter)) {
break;
}
}
if (!count && timeout) {