| /* |
| * Copyright (c) 2019 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_DECLARE(conn_mgr, CONFIG_NET_CONNECTION_MANAGER_LOG_LEVEL); |
| |
| #include <errno.h> |
| #include <zephyr/net/net_if.h> |
| #include <zephyr/net/net_mgmt.h> |
| |
| #include "conn_mgr_private.h" |
| |
| extern uint16_t iface_states[CONN_MGR_IFACE_MAX]; |
| |
| static struct net_mgmt_event_callback iface_events_cb; |
| static struct net_mgmt_event_callback ipv6_events_cb; |
| static struct net_mgmt_event_callback ipv4_events_cb; |
| |
| static void conn_mgr_iface_events_handler(struct net_mgmt_event_callback *cb, |
| uint32_t mgmt_event, |
| struct net_if *iface) |
| { |
| int idx; |
| |
| NET_DBG("Iface event %u received on iface %d (%p)", mgmt_event, |
| net_if_get_by_iface(iface), iface); |
| |
| if ((mgmt_event & CONN_MGR_IFACE_EVENTS_MASK) != mgmt_event) { |
| return; |
| } |
| |
| idx = net_if_get_by_iface(iface) - 1; |
| |
| NET_DBG("Iface index %u", idx); |
| |
| k_mutex_lock(&conn_mgr_lock, K_FOREVER); |
| |
| switch (NET_MGMT_GET_COMMAND(mgmt_event)) { |
| case NET_EVENT_IF_CMD_DOWN: |
| iface_states[idx] &= ~CONN_MGR_IF_UP; |
| break; |
| case NET_EVENT_IF_CMD_UP: |
| iface_states[idx] |= CONN_MGR_IF_UP; |
| break; |
| default: |
| goto done; |
| } |
| |
| iface_states[idx] |= CONN_MGR_IF_CHANGED; |
| k_sem_give(&conn_mgr_event_signal); |
| |
| done: |
| k_mutex_unlock(&conn_mgr_lock); |
| } |
| |
| #if defined(CONFIG_NET_IPV6) |
| static void conn_mgr_ipv6_events_handler(struct net_mgmt_event_callback *cb, |
| uint32_t mgmt_event, |
| struct net_if *iface) |
| { |
| int idx; |
| |
| NET_DBG("IPv6 event %u received on iface %d (%p)", mgmt_event, |
| net_if_get_by_iface(iface), iface); |
| |
| if ((mgmt_event & CONN_MGR_IPV6_EVENTS_MASK) != mgmt_event) { |
| return; |
| } |
| |
| idx = net_if_get_by_iface(iface) - 1; |
| |
| NET_DBG("Iface index %u", idx); |
| |
| k_mutex_lock(&conn_mgr_lock, K_FOREVER); |
| |
| switch (NET_MGMT_GET_COMMAND(mgmt_event)) { |
| case NET_EVENT_IPV6_CMD_DAD_SUCCEED: |
| __fallthrough; |
| case NET_EVENT_IPV6_CMD_ADDR_ADD: |
| if (net_if_ipv6_get_global_addr(NET_ADDR_PREFERRED, &iface)) { |
| iface_states[idx] |= CONN_MGR_IF_IPV6_SET; |
| } |
| break; |
| case NET_EVENT_IPV6_CMD_DAD_FAILED: |
| __fallthrough; |
| case NET_EVENT_IPV6_CMD_ADDR_DEL: |
| if (!net_if_ipv6_get_global_addr(NET_ADDR_PREFERRED, &iface)) { |
| iface_states[idx] &= ~CONN_MGR_IF_IPV6_SET; |
| } |
| |
| break; |
| default: |
| goto done; |
| } |
| |
| iface_states[idx] |= CONN_MGR_IF_CHANGED; |
| k_sem_give(&conn_mgr_event_signal); |
| |
| done: |
| k_mutex_unlock(&conn_mgr_lock); |
| } |
| #else |
| static inline |
| void conn_mgr_ipv6_events_handler(struct net_mgmt_event_callback *cb, |
| uint32_t mgmt_event, |
| struct net_if *iface) |
| { |
| ARG_UNUSED(cb); |
| ARG_UNUSED(mgmt_event); |
| ARG_UNUSED(iface); |
| } |
| #endif /* CONFIG_NET_IPV6 */ |
| |
| #if defined(CONFIG_NET_IPV4) |
| static void conn_mgr_ipv4_events_handler(struct net_mgmt_event_callback *cb, |
| uint32_t mgmt_event, |
| struct net_if *iface) |
| { |
| int idx; |
| |
| NET_DBG("IPv4 event %u received on iface %d (%p)", mgmt_event, |
| net_if_get_by_iface(iface), iface); |
| |
| if ((mgmt_event & CONN_MGR_IPV4_EVENTS_MASK) != mgmt_event) { |
| return; |
| } |
| |
| idx = net_if_get_by_iface(iface) - 1; |
| |
| NET_DBG("Iface index %u", idx); |
| |
| k_mutex_lock(&conn_mgr_lock, K_FOREVER); |
| |
| switch (NET_MGMT_GET_COMMAND(mgmt_event)) { |
| case NET_EVENT_IPV4_CMD_ADDR_ADD: |
| iface_states[idx] |= CONN_MGR_IF_IPV4_SET; |
| break; |
| case NET_EVENT_IPV4_CMD_ADDR_DEL: |
| if (net_if_ipv4_get_global_addr(iface, NET_ADDR_PREFERRED)) { |
| break; |
| } |
| |
| iface_states[idx] &= ~CONN_MGR_IF_IPV4_SET; |
| break; |
| default: |
| goto done; |
| } |
| |
| iface_states[idx] |= CONN_MGR_IF_CHANGED; |
| k_sem_give(&conn_mgr_event_signal); |
| |
| done: |
| k_mutex_unlock(&conn_mgr_lock); |
| } |
| #else |
| static inline |
| void conn_mgr_ipv4_events_handler(struct net_mgmt_event_callback *cb, |
| uint32_t mgmt_event, |
| struct net_if *iface) |
| { |
| ARG_UNUSED(cb); |
| ARG_UNUSED(mgmt_event); |
| ARG_UNUSED(iface); |
| } |
| #endif /* CONFIG_NET_IPV4 */ |
| |
| void conn_mgr_init_events_handler(void) |
| { |
| net_mgmt_init_event_callback(&iface_events_cb, |
| conn_mgr_iface_events_handler, |
| CONN_MGR_IFACE_EVENTS_MASK); |
| net_mgmt_add_event_callback(&iface_events_cb); |
| |
| if (IS_ENABLED(CONFIG_NET_IPV6)) { |
| net_mgmt_init_event_callback(&ipv6_events_cb, |
| conn_mgr_ipv6_events_handler, |
| CONN_MGR_IPV6_EVENTS_MASK); |
| net_mgmt_add_event_callback(&ipv6_events_cb); |
| } |
| |
| if (IS_ENABLED(CONFIG_NET_IPV4)) { |
| net_mgmt_init_event_callback(&ipv4_events_cb, |
| conn_mgr_ipv4_events_handler, |
| CONN_MGR_IPV4_EVENTS_MASK); |
| net_mgmt_add_event_callback(&ipv4_events_cb); |
| } |
| } |