Skip to content
Permalink
Browse files

net: Add a connection manager preliminary logic

It currently only listens to relevant events about network interface to
decide whether raising connected or disconnected event.

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
  • Loading branch information...
tbursztyka authored and jukkar committed May 9, 2019
1 parent 3ebe60a commit b2e71a2fa2565f339c4419852359f66b57d871b1
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_NET_CONN_MGR_H_
#define ZEPHYR_INCLUDE_NET_CONN_MGR_H_

#ifdef __cplusplus
extern "C" {
#endif

#if defined(CONFIG_NET_CONNECTION_MANAGER)

void net_conn_mgr_resend_status(void);

#else

#define net_conn_mgr_resend_status(...)

#endif /* CONFIG_NET_CONNECTION_MANAGER */

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_NET_CONN_MGR_H_ */
@@ -5,10 +5,11 @@ add_subdirectory_if_kconfig(coap)
add_subdirectory_if_kconfig(lwm2m)
add_subdirectory_if_kconfig(socks)
add_subdirectory_if_kconfig(sntp)
add_subdirectory_ifdef(CONFIG_MQTT_LIB mqtt)
add_subdirectory_ifdef(CONFIG_NET_CONFIG_SETTINGS config)
add_subdirectory_ifdef(CONFIG_NET_SOCKETS sockets)
add_subdirectory_ifdef(CONFIG_TLS_CREDENTIALS tls_credentials)
add_subdirectory_ifdef(CONFIG_MQTT_LIB mqtt)
add_subdirectory_ifdef(CONFIG_NET_CONFIG_SETTINGS config)
add_subdirectory_ifdef(CONFIG_NET_SOCKETS sockets)
add_subdirectory_ifdef(CONFIG_TLS_CREDENTIALS tls_credentials)
add_subdirectory_ifdef(CONFIG_NET_CONNECTION_MANAGER conn_mgr)

if (CONFIG_DNS_RESOLVER
OR CONFIG_MDNS_RESPONDER
@@ -31,3 +31,9 @@ source "subsys/net/lib/sockets/Kconfig"
source "subsys/net/lib/tls_credentials/Kconfig"

endmenu

menu "Network additional services"

source "subsys/net/lib/conn_mgr/Kconfig"

endmenu
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_include_directories(.)

zephyr_library()
zephyr_library_sources(
conn_mgr.c
events_handler.c
)
@@ -0,0 +1,40 @@
#
# Copyright (c) 2019 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#

menuconfig NET_CONNECTION_MANAGER
bool "Enable network connection manager [EXPERIMENTAL]"
depends on NET_IPV6 || NET_IPV4
select NET_MGMT
select NET_MGMT_EVENT
select NET_MGMT_EVENT_INFO
help
When enabled, this will start the connection manager that will
listen to network interface and IP events in order to verify
whether an interface is connected or not. It will then raise
L4 events "connected" or "disconnected" depending on the result.

if NET_CONNECTION_MANAGER

module = NET_CONNECTION_MANAGER
module-dep = NET_LOG
module-str = Log level for connection manager
module-help = Enables connection manager code to output debug messages.
source "subsys/net/Kconfig.template.log_config.net"

config NET_CONNECTION_MANAGER_STACK_SIZE
int "Size of the stack allocated for the connection manager"
default 512
help
Sets the stack size which will be used by the connection manager
thread.

config NET_CONNECTION_MANAGER_PRIORITY
int "Thread starting priority"
default 0
help
This sets the starting priority of the connection manager thread.

endif # NET_CONNECTION_MANAGER
@@ -0,0 +1,195 @@
/*
* Copyright (c) 2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <logging/log.h>
LOG_MODULE_REGISTER(conn_mgr, CONFIG_NET_CONNECTION_MANAGER_LOG_LEVEL);

#include <init.h>
#include <kernel.h>
#include <errno.h>
#include <net/net_core.h>
#include <net/net_if.h>
#include <net/net_mgmt.h>

#include <conn_mgr.h>

u16_t iface_states[CONN_MGR_IFACE_MAX];

K_SEM_DEFINE(conn_mgr_lock, 1, UINT_MAX);

static enum net_conn_mgr_state conn_mgr_iface_status(int index)
{
if (iface_states[index] & NET_STATE_IFACE_UP) {
return NET_CONN_MGR_STATE_CONNECTED;
}

return NET_CONN_MGR_STATE_DISCONNECTED;
}

#if defined(CONFIG_NET_IPV6)
static enum net_conn_mgr_state conn_mgr_ipv6_status(int index)
{
if ((iface_states[index] & CONN_MGR_IPV6_STATUS_MASK) ==
CONN_MGR_IPV6_STATUS_MASK) {
NET_DBG("IPv6 connected on iface index %u", index + 1);
return NET_CONN_MGR_STATE_CONNECTED;
}

return NET_CONN_MGR_STATE_DISCONNECTED;
}
#else
#define conn_mgr_ipv6_status(...) NET_CONN_MGR_STATE_CONNECTED
#endif /* CONFIG_NET_IPV6 */

#if defined(CONFIG_NET_IPV4)
static enum net_conn_mgr_state conn_mgr_ipv4_status(int index)
{
if ((iface_states[index] & CONN_MGR_IPV4_STATUS_MASK) ==
CONN_MGR_IPV4_STATUS_MASK) {
NET_DBG("IPv4 connected on iface index %u", index + 1);
return NET_CONN_MGR_STATE_CONNECTED;
}

return NET_CONN_MGR_STATE_DISCONNECTED;
}
#else
#define conn_mgr_ipv4_status(...) NET_CONN_MGR_STATE_CONNECTED
#endif /* CONFIG_NET_IPV4 */

static void conn_mgr_notify_status(int index)
{
struct net_if *iface = net_if_get_by_index(index + 1);

if (iface_states[index] & NET_STATE_CONNECTED) {
NET_DBG("Iface %p connected", iface);
net_mgmt_event_notify(NET_EVENT_L4_CONNECTED, iface);
} else {
NET_DBG("Iface %p disconnected", iface);
net_mgmt_event_notify(NET_EVENT_L4_DISCONNECTED, iface);
}
}

static void conn_mgr_act_on_changes(void)
{
int idx;

for (idx = 0; idx < ARRAY_SIZE(iface_states); idx++) {
enum net_conn_mgr_state state;

if (!(iface_states[idx] & NET_STATE_CHANGED)) {
continue;
}

state = NET_CONN_MGR_STATE_CONNECTED;

state &= conn_mgr_iface_status(idx);
if (state) {
enum net_conn_mgr_state ip_state =
NET_CONN_MGR_STATE_DISCONNECTED;

if (IS_ENABLED(CONFIG_NET_IPV6)) {
ip_state |= conn_mgr_ipv6_status(idx);
}

if (IS_ENABLED(CONFIG_NET_IPV4)) {
state |= conn_mgr_ipv4_status(idx);
}

state &= ip_state;
}

iface_states[idx] &= ~NET_STATE_CHANGED;

if (state == NET_CONN_MGR_STATE_CONNECTED &&
!(iface_states[idx] & NET_STATE_CONNECTED)) {
iface_states[idx] |= NET_STATE_CONNECTED;

conn_mgr_notify_status(idx);
} else if (state != NET_CONN_MGR_STATE_CONNECTED &&
(iface_states[idx] & NET_STATE_CONNECTED)) {
iface_states[idx] &= ~NET_STATE_CONNECTED;

conn_mgr_notify_status(idx);
}
}
}

static void conn_mgr_initial_state(struct net_if *iface)
{
int idx = net_if_get_by_iface(iface) - 1;

if (net_if_is_up(iface)) {
NET_DBG("Iface %p UP", iface);
iface_states[idx] = NET_STATE_IFACE_UP;
}

if (IS_ENABLED(CONFIG_NET_IPV6)) {
if (net_if_ipv6_get_global_addr(NET_ADDR_PREFERRED, &iface)) {
NET_DBG("IPv6 addr set");
iface_states[idx] |= NET_STATE_IPV6_ADDR_SET |
NET_STATE_IPV6_DAD_OK;
} else if (net_if_ipv6_get_global_addr(NET_ADDR_TENTATIVE,
&iface)) {
iface_states[idx] |= NET_STATE_IPV6_ADDR_SET;
}
}

if (IS_ENABLED(CONFIG_NET_IPV4)) {
if (net_if_ipv4_get_global_addr(iface, NET_ADDR_PREFERRED)) {
NET_DBG("IPv4 addr set");
iface_states[idx] |= NET_STATE_IPV4_ADDR_SET;
}

}

iface_states[idx] |= NET_STATE_CHANGED;
}

static void conn_mgr_init_cb(struct net_if *iface, void *user_data)
{
ARG_UNUSED(user_data);

conn_mgr_initial_state(iface);
}

static void conn_mgr(void)
{
conn_mgr_init_events_handler();

net_if_foreach(conn_mgr_init_cb, NULL);

NET_DBG("Connection Manager started");

while (true) {
k_sem_take(&conn_mgr_lock, K_FOREVER);

conn_mgr_act_on_changes();
}
}

K_THREAD_DEFINE(conn_mgr_thread, CONFIG_NET_CONNECTION_MANAGER_STACK_SIZE,
(k_thread_entry_t)conn_mgr, NULL, NULL, NULL,
K_PRIO_COOP(2), 0, 0);

void net_conn_mgr_resend_status(void)
{
int idx;

for (idx = 0; idx < ARRAY_SIZE(iface_states); idx++) {
conn_mgr_notify_status(idx);
}
}

static int conn_mgr_init(struct device *dev)
{
ARG_UNUSED(dev);

k_thread_start(conn_mgr_thread);

return 0;
}

SYS_INIT(conn_mgr_init, APPLICATION, CONFIG_NET_CONNECTION_MANAGER_PRIORITY);
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef __CONN_MGR_H__
#define __CONN_MGR_H__

#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
#define CONN_MGR_IFACE_MAX MAX(CONFIG_NET_IF_MAX_IPV6_COUNT, \
CONFIG_NET_IF_MAX_IPV4_COUNT)
#elif defined(CONFIG_NET_IPV6)
#define CONN_MGR_IFACE_MAX CONFIG_NET_IF_MAX_IPV6_COUNT
#else
#define CONN_MGR_IFACE_MAX CONFIG_NET_IF_MAX_IPV4_COUNT
#endif

#define NET_STATE_IFACE_UP BIT(0)
#define NET_STATE_IPV6_ADDR_SET BIT(1)
#define NET_STATE_IPV6_DAD_OK BIT(2)
#define NET_STATE_IPV4_ADDR_SET BIT(3)

#define NET_STATE_CONNECTED BIT(14)
#define NET_STATE_CHANGED BIT(15)

#define CONN_MGR_IFACE_EVENTS_MASK (NET_EVENT_IF_DOWN | \
NET_EVENT_IF_UP)

#define CONN_MGR_IPV6_EVENTS_MASK (NET_EVENT_IPV6_ADDR_ADD | \
NET_EVENT_IPV6_ADDR_DEL | \
NET_EVENT_IPV6_DAD_SUCCEED | \
NET_EVENT_IPV6_DAD_FAILED)

#define CONN_MGR_IPV4_EVENTS_MASK (NET_EVENT_IPV4_ADDR_ADD | \
NET_EVENT_IPV4_ADDR_DEL)

#define CONN_MGR_IPV6_STATUS_MASK (NET_STATE_IPV6_ADDR_SET | \
NET_STATE_IPV6_DAD_OK)

#define CONN_MGR_IPV4_STATUS_MASK (NET_STATE_IPV4_ADDR_SET)

extern struct k_sem conn_mgr_lock;

enum net_conn_mgr_state {
NET_CONN_MGR_STATE_DISCONNECTED = 0,
NET_CONN_MGR_STATE_CONNECTED = 1,
};

void conn_mgr_init_events_handler(void);

#endif /* __CONN_MGR_H__ */

0 comments on commit b2e71a2

Please sign in to comment.
You can’t perform that action at this time.