2016-05-02 09:02:04 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016 Intel Corporation.
|
|
|
|
*
|
2017-01-18 17:01:01 -08:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2016-05-02 09:02:04 +02:00
|
|
|
*/
|
|
|
|
|
2018-11-30 12:54:56 +02:00
|
|
|
#include <logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(net_if, CONFIG_NET_IF_LOG_LEVEL);
|
2016-05-09 15:43:06 +03:00
|
|
|
|
2016-05-02 09:02:04 +02:00
|
|
|
#include <init.h>
|
2016-11-09 17:44:21 +01:00
|
|
|
#include <kernel.h>
|
2017-06-17 11:30:47 -04:00
|
|
|
#include <linker/sections.h>
|
2018-08-17 10:20:05 +03:00
|
|
|
#include <stdlib.h>
|
2016-05-09 15:43:06 +03:00
|
|
|
#include <string.h>
|
|
|
|
#include <net/net_core.h>
|
2017-04-03 17:14:35 +02:00
|
|
|
#include <net/net_pkt.h>
|
2016-05-19 12:15:06 +03:00
|
|
|
#include <net/net_if.h>
|
2016-09-29 18:33:03 +02:00
|
|
|
#include <net/net_mgmt.h>
|
2018-03-14 10:55:19 +02:00
|
|
|
#include <net/ethernet.h>
|
2016-05-19 12:15:06 +03:00
|
|
|
|
|
|
|
#include "net_private.h"
|
2016-06-07 16:34:49 +03:00
|
|
|
#include "ipv6.h"
|
2018-07-30 18:28:35 +03:00
|
|
|
#include "ipv4_autoconf_internal.h"
|
2016-05-02 09:02:04 +02:00
|
|
|
|
2016-12-13 14:50:31 +01:00
|
|
|
#include "net_stats.h"
|
|
|
|
|
2018-05-24 12:41:58 +03:00
|
|
|
#define REACHABLE_TIME K_SECONDS(30) /* in ms */
|
2017-12-02 21:18:50 -08:00
|
|
|
/*
|
|
|
|
* split the min/max random reachable factors into numerator/denominator
|
|
|
|
* so that integer-based math works better
|
|
|
|
*/
|
|
|
|
#define MIN_RANDOM_NUMER (1)
|
|
|
|
#define MIN_RANDOM_DENOM (2)
|
|
|
|
#define MAX_RANDOM_NUMER (3)
|
|
|
|
#define MAX_RANDOM_DENOM (2)
|
2016-06-07 10:16:58 +03:00
|
|
|
|
2016-05-02 09:02:04 +02:00
|
|
|
/* net_if dedicated section limiters */
|
|
|
|
extern struct net_if __net_if_start[];
|
|
|
|
extern struct net_if __net_if_end[];
|
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
extern struct net_if_dev __net_if_dev_start[];
|
|
|
|
extern struct net_if_dev __net_if_dev_end[];
|
2017-03-08 09:30:03 +01:00
|
|
|
|
2019-02-07 15:00:44 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4) || defined(CONFIG_NET_IPV6)
|
2016-06-07 10:16:58 +03:00
|
|
|
static struct net_if_router routers[CONFIG_NET_MAX_ROUTERS];
|
2019-02-07 15:00:44 +02:00
|
|
|
#endif
|
2016-06-07 10:16:58 +03:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-08-17 10:20:05 +03:00
|
|
|
/* Timer that triggers network address renewal */
|
|
|
|
static struct k_delayed_work address_lifetime_timer;
|
|
|
|
|
|
|
|
/* Track currently active address lifetime timers */
|
|
|
|
static sys_slist_t active_address_lifetime_timers;
|
|
|
|
|
2018-08-27 14:02:09 +03:00
|
|
|
/* Timer that triggers IPv6 prefix lifetime */
|
|
|
|
static struct k_delayed_work prefix_lifetime_timer;
|
|
|
|
|
|
|
|
/* Track currently active IPv6 prefix lifetime timers */
|
|
|
|
static sys_slist_t active_prefix_lifetime_timers;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
static struct {
|
|
|
|
struct net_if_ipv6 ipv6;
|
|
|
|
struct net_if *iface;
|
|
|
|
} ipv6_addresses[CONFIG_NET_IF_MAX_IPV6_COUNT];
|
|
|
|
#endif /* CONFIG_NET_IPV6 */
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV4)
|
|
|
|
static struct {
|
|
|
|
struct net_if_ipv4 ipv4;
|
|
|
|
struct net_if *iface;
|
|
|
|
} ipv4_addresses[CONFIG_NET_IF_MAX_IPV4_COUNT];
|
|
|
|
#endif /* CONFIG_NET_IPV4 */
|
|
|
|
|
2016-09-28 14:18:55 +03:00
|
|
|
/* We keep track of the link callbacks in this list.
|
|
|
|
*/
|
|
|
|
static sys_slist_t link_callbacks;
|
|
|
|
|
2017-08-29 09:57:27 +03:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
|
|
|
/* Multicast join/leave tracking.
|
|
|
|
*/
|
|
|
|
static sys_slist_t mcast_monitor_callbacks;
|
|
|
|
#endif
|
|
|
|
|
2018-01-24 15:20:21 +02:00
|
|
|
#if defined(CONFIG_NET_PKT_TIMESTAMP)
|
|
|
|
#if !defined(CONFIG_NET_PKT_TIMESTAMP_STACK_SIZE)
|
|
|
|
#define CONFIG_NET_PKT_TIMESTAMP_STACK_SIZE 1024
|
|
|
|
#endif
|
|
|
|
|
|
|
|
NET_STACK_DEFINE(TIMESTAMP, tx_ts_stack,
|
|
|
|
CONFIG_NET_PKT_TIMESTAMP_STACK_SIZE,
|
|
|
|
CONFIG_NET_PKT_TIMESTAMP_STACK_SIZE);
|
|
|
|
K_FIFO_DEFINE(tx_ts_queue);
|
|
|
|
|
|
|
|
static struct k_thread tx_thread_ts;
|
|
|
|
|
|
|
|
/* We keep track of the timestamp callbacks in this list.
|
|
|
|
*/
|
|
|
|
static sys_slist_t timestamp_callbacks;
|
|
|
|
#endif /* CONFIG_NET_PKT_TIMESTAMP */
|
|
|
|
|
2018-11-30 12:54:56 +02:00
|
|
|
#if CONFIG_NET_IF_LOG_LEVEL >= LOG_LEVEL_DBG
|
2018-02-07 15:09:36 +02:00
|
|
|
#if defined(CONFIG_NET_STATISTICS)
|
2018-02-07 15:00:08 +02:00
|
|
|
#define debug_check_packet(pkt) \
|
2018-02-07 15:09:36 +02:00
|
|
|
do { \
|
|
|
|
NET_DBG("Processing (pkt %p, data len %d, " \
|
2018-02-07 15:00:08 +02:00
|
|
|
"prio %d) network packet", \
|
2018-02-07 15:09:36 +02:00
|
|
|
pkt, pkt->total_pkt_len, \
|
2018-02-07 15:00:08 +02:00
|
|
|
net_pkt_priority(pkt)); \
|
|
|
|
\
|
2018-02-07 15:09:36 +02:00
|
|
|
NET_ASSERT(pkt->frags && pkt->total_pkt_len); \
|
2016-06-08 14:35:07 +03:00
|
|
|
} while (0)
|
2018-02-07 15:09:36 +02:00
|
|
|
#else /* CONFIG_NET_STATISTICS */
|
|
|
|
#define debug_check_packet(pkt) \
|
|
|
|
do { \
|
|
|
|
NET_DBG("Processing (pkt %p, prio %d) network packet", \
|
|
|
|
pkt, net_pkt_priority(pkt)); \
|
|
|
|
\
|
|
|
|
NET_ASSERT(pkt->frags); \
|
|
|
|
} while (0)
|
|
|
|
#endif /* CONFIG_NET_STATISTICS */
|
2016-06-08 14:35:07 +03:00
|
|
|
#else
|
|
|
|
#define debug_check_packet(...)
|
2018-11-30 12:54:56 +02:00
|
|
|
#endif /* CONFIG_NET_IF_LOG_LEVEL >= LOG_LEVEL_DBG */
|
2016-06-08 14:35:07 +03:00
|
|
|
|
2016-12-13 14:50:31 +01:00
|
|
|
static inline void net_context_send_cb(struct net_context *context,
|
|
|
|
void *token, int status)
|
|
|
|
{
|
2017-08-25 23:28:02 +03:00
|
|
|
if (!context) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-12-13 14:50:31 +01:00
|
|
|
if (context->send_cb) {
|
|
|
|
context->send_cb(context, status, token, context->user_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_UDP)
|
|
|
|
if (net_context_get_ip_proto(context) == IPPROTO_UDP) {
|
2018-03-27 11:31:31 +03:00
|
|
|
net_stats_update_udp_sent(net_context_get_iface(context));
|
2017-05-16 15:27:27 +03:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_TCP)
|
|
|
|
if (net_context_get_ip_proto(context) == IPPROTO_TCP) {
|
2018-03-27 11:31:31 +03:00
|
|
|
net_stats_update_tcp_seg_sent(net_context_get_iface(context));
|
2017-05-16 15:27:27 +03:00
|
|
|
} else
|
2016-12-13 14:50:31 +01:00
|
|
|
#endif
|
2017-05-16 15:27:27 +03:00
|
|
|
{
|
|
|
|
}
|
2016-12-13 14:50:31 +01:00
|
|
|
}
|
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt)
|
2017-02-10 10:38:15 +02:00
|
|
|
{
|
|
|
|
struct net_linkaddr *dst;
|
|
|
|
struct net_context *context;
|
|
|
|
void *context_token;
|
|
|
|
int status;
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
if (!pkt) {
|
2017-03-08 09:30:03 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
debug_check_packet(pkt);
|
2017-02-10 10:38:15 +02:00
|
|
|
|
2018-09-11 09:16:03 +02:00
|
|
|
dst = net_pkt_lladdr_dst(pkt);
|
2017-04-05 08:37:44 +02:00
|
|
|
context = net_pkt_context(pkt);
|
|
|
|
context_token = net_pkt_token(pkt);
|
2017-02-10 10:38:15 +02:00
|
|
|
|
2018-01-11 16:06:53 +02:00
|
|
|
if (atomic_test_bit(iface->if_dev->flags, NET_IF_UP)) {
|
2018-11-13 16:22:52 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_TCP) &&
|
|
|
|
net_pkt_family(pkt) != AF_UNSPEC) {
|
2017-08-15 16:13:30 +03:00
|
|
|
net_pkt_set_sent(pkt, true);
|
2017-08-16 14:39:59 +03:00
|
|
|
net_pkt_set_queued(pkt, false);
|
2017-08-15 16:13:30 +03:00
|
|
|
}
|
|
|
|
|
2018-06-26 14:51:05 +02:00
|
|
|
status = net_if_l2(iface)->send(iface, pkt);
|
2017-02-10 10:38:15 +02:00
|
|
|
} else {
|
|
|
|
/* Drop packet if interface is not up */
|
|
|
|
NET_WARN("iface %p is down", iface);
|
|
|
|
status = -ENETDOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status < 0) {
|
2018-11-13 16:22:52 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_TCP)
|
|
|
|
&& net_pkt_family(pkt) != AF_UNSPEC) {
|
2017-08-15 16:13:30 +03:00
|
|
|
net_pkt_set_sent(pkt, false);
|
|
|
|
}
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
net_pkt_unref(pkt);
|
2017-02-10 10:38:15 +02:00
|
|
|
} else {
|
2018-06-26 14:51:05 +02:00
|
|
|
net_stats_update_bytes_sent(iface, status);
|
2017-02-10 10:38:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (context) {
|
|
|
|
NET_DBG("Calling context send cb %p token %p status %d",
|
|
|
|
context, context_token, status);
|
|
|
|
|
|
|
|
net_context_send_cb(context, context_token, status);
|
|
|
|
}
|
|
|
|
|
2017-03-24 12:47:11 +02:00
|
|
|
if (dst->addr) {
|
|
|
|
net_if_call_link_cb(iface, dst, status);
|
|
|
|
}
|
2017-03-08 09:30:03 +01:00
|
|
|
|
|
|
|
return true;
|
2017-02-10 10:38:15 +02:00
|
|
|
}
|
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
static void process_tx_packet(struct k_work *work)
|
2017-02-10 10:38:15 +02:00
|
|
|
{
|
2018-02-07 15:00:08 +02:00
|
|
|
struct net_pkt *pkt;
|
2016-05-19 12:15:06 +03:00
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
pkt = CONTAINER_OF(work, struct net_pkt, work);
|
2016-06-01 10:35:00 +03:00
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
net_if_tx(net_pkt_iface(pkt), pkt);
|
2017-03-08 09:30:03 +01:00
|
|
|
}
|
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
void net_if_queue_tx(struct net_if *iface, struct net_pkt *pkt)
|
2017-03-08 09:30:03 +01:00
|
|
|
{
|
2018-02-07 15:00:08 +02:00
|
|
|
u8_t prio = net_pkt_priority(pkt);
|
|
|
|
u8_t tc = net_tx_priority2tc(prio);
|
2017-02-10 10:38:15 +02:00
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
k_work_init(net_pkt_work(pkt), process_tx_packet);
|
2016-05-03 09:34:45 +03:00
|
|
|
|
2018-02-07 15:09:36 +02:00
|
|
|
#if defined(CONFIG_NET_STATISTICS)
|
|
|
|
pkt->total_pkt_len = net_pkt_get_len(pkt);
|
|
|
|
|
2018-03-27 11:31:31 +03:00
|
|
|
net_stats_update_tc_sent_pkt(iface, tc);
|
|
|
|
net_stats_update_tc_sent_bytes(iface, tc, pkt->total_pkt_len);
|
|
|
|
net_stats_update_tc_sent_priority(iface, tc, prio);
|
2018-02-07 15:09:36 +02:00
|
|
|
#endif
|
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
#if NET_TC_TX_COUNT > 1
|
|
|
|
NET_DBG("TC %d with prio %d pkt %p", tc, prio, pkt);
|
|
|
|
#endif
|
2016-06-08 14:16:17 +03:00
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
net_tc_submit_to_tx_queue(tc, pkt);
|
2016-05-03 09:34:45 +03:00
|
|
|
}
|
|
|
|
|
2017-03-08 09:30:03 +01:00
|
|
|
static inline void init_iface(struct net_if *iface)
|
2016-05-03 09:34:45 +03:00
|
|
|
{
|
2018-01-11 16:06:53 +02:00
|
|
|
const struct net_if_api *api = net_if_get_device(iface)->driver_api;
|
2017-03-08 09:30:03 +01:00
|
|
|
|
2018-10-08 15:11:27 -07:00
|
|
|
NET_ASSERT(api && api->init);
|
2017-03-08 09:30:03 +01:00
|
|
|
|
2016-06-21 12:10:13 +02:00
|
|
|
NET_DBG("On iface %p", iface);
|
|
|
|
|
2017-03-08 09:30:03 +01:00
|
|
|
api->init(iface);
|
2016-05-03 09:34:45 +03:00
|
|
|
}
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt)
|
2016-06-29 16:39:06 +03:00
|
|
|
{
|
2017-04-05 08:37:44 +02:00
|
|
|
struct net_context *context = net_pkt_context(pkt);
|
2018-09-11 09:16:03 +02:00
|
|
|
struct net_linkaddr *dst = net_pkt_lladdr_dst(pkt);
|
2018-06-26 14:51:05 +02:00
|
|
|
enum net_verdict verdict = NET_OK;
|
2017-04-05 08:37:44 +02:00
|
|
|
void *token = net_pkt_token(pkt);
|
2016-12-19 14:18:10 +02:00
|
|
|
int status = -EIO;
|
2016-06-29 16:39:06 +03:00
|
|
|
|
2018-01-11 16:06:53 +02:00
|
|
|
if (!atomic_test_bit(iface->if_dev->flags, NET_IF_UP)) {
|
2016-12-19 14:18:10 +02:00
|
|
|
/* Drop packet if interface is not up */
|
|
|
|
NET_WARN("iface %p is down", iface);
|
|
|
|
verdict = NET_DROP;
|
|
|
|
status = -ENETDOWN;
|
2017-01-31 16:43:43 +02:00
|
|
|
goto done;
|
2016-12-19 14:18:10 +02:00
|
|
|
}
|
2016-06-29 16:39:06 +03:00
|
|
|
|
2017-01-31 16:43:43 +02:00
|
|
|
/* If the ll address is not set at all, then we must set
|
|
|
|
* it here.
|
2017-02-02 11:58:15 +02:00
|
|
|
* Workaround Linux bug, see:
|
2018-03-26 10:11:00 -05:00
|
|
|
* https://github.com/zephyrproject-rtos/zephyr/issues/3111
|
2017-01-31 16:43:43 +02:00
|
|
|
*/
|
2018-01-11 16:06:53 +02:00
|
|
|
if (!atomic_test_bit(iface->if_dev->flags, NET_IF_POINTOPOINT) &&
|
2018-09-11 09:16:03 +02:00
|
|
|
!net_pkt_lladdr_src(pkt)->addr) {
|
|
|
|
net_pkt_lladdr_src(pkt)->addr = net_pkt_lladdr_if(pkt)->addr;
|
|
|
|
net_pkt_lladdr_src(pkt)->len = net_pkt_lladdr_if(pkt)->len;
|
2017-01-31 16:43:43 +02:00
|
|
|
}
|
|
|
|
|
2017-11-14 17:06:28 +02:00
|
|
|
#if defined(CONFIG_NET_LOOPBACK)
|
|
|
|
/* If the packet is destined back to us, then there is no need to do
|
|
|
|
* additional checks, so let the packet through.
|
|
|
|
*/
|
2018-01-11 16:06:53 +02:00
|
|
|
if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) {
|
2018-06-26 14:51:05 +02:00
|
|
|
goto done;
|
2017-11-14 17:06:28 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-01-31 16:43:43 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
|
|
|
/* If the ll dst address is not set check if it is present in the nbr
|
|
|
|
* cache.
|
|
|
|
*/
|
2017-04-05 08:37:44 +02:00
|
|
|
if (net_pkt_family(pkt) == AF_INET6) {
|
2018-12-21 09:08:19 +01:00
|
|
|
verdict = net_ipv6_prepare_for_send(pkt);
|
2017-01-31 16:43:43 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
done:
|
2018-06-26 14:51:05 +02:00
|
|
|
/* NET_OK in which case packet has checked successfully. In this case
|
2017-02-27 16:33:34 +02:00
|
|
|
* the net_context callback is called after successful delivery in
|
|
|
|
* net_if_tx_thread().
|
|
|
|
*
|
|
|
|
* NET_DROP in which case we call net_context callback that will
|
|
|
|
* give the status to user application.
|
2016-06-29 16:39:06 +03:00
|
|
|
*
|
|
|
|
* NET_CONTINUE in which case the sending of the packet is delayed.
|
|
|
|
* This can happen for example if we need to do IPv6 ND to figure
|
|
|
|
* out link layer address.
|
|
|
|
*/
|
2018-06-26 14:51:05 +02:00
|
|
|
if (verdict == NET_DROP) {
|
|
|
|
if (context) {
|
|
|
|
NET_DBG("Calling ctx send cb %p token %p verdict %d",
|
|
|
|
context, token, verdict);
|
|
|
|
net_context_send_cb(context, token, status);
|
|
|
|
}
|
2016-06-29 16:39:06 +03:00
|
|
|
|
2018-06-26 14:51:05 +02:00
|
|
|
if (dst->addr) {
|
|
|
|
net_if_call_link_cb(iface, dst, status);
|
|
|
|
}
|
|
|
|
} else if (verdict == NET_OK) {
|
|
|
|
/* Packet is ready to be sent by L2, let's queue */
|
|
|
|
net_if_queue_tx(iface, pkt);
|
2016-09-28 14:18:55 +03:00
|
|
|
}
|
|
|
|
|
2016-06-29 16:39:06 +03:00
|
|
|
return verdict;
|
|
|
|
}
|
|
|
|
|
2016-05-09 15:00:30 +03:00
|
|
|
struct net_if *net_if_get_by_link_addr(struct net_linkaddr *ll_addr)
|
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
2018-01-11 16:06:53 +02:00
|
|
|
if (!memcmp(net_if_get_link_addr(iface)->addr, ll_addr->addr,
|
2016-05-09 15:00:30 +03:00
|
|
|
ll_addr->len)) {
|
|
|
|
return iface;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-15 13:15:40 +02:00
|
|
|
struct net_if *net_if_lookup_by_dev(struct device *dev)
|
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
2018-01-11 16:06:53 +02:00
|
|
|
if (net_if_get_device(iface) == dev) {
|
2016-06-15 13:15:40 +02:00
|
|
|
return iface;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-24 17:34:30 +02:00
|
|
|
struct net_if *net_if_get_default(void)
|
|
|
|
{
|
2018-01-23 13:47:03 +02:00
|
|
|
struct net_if *iface = NULL;
|
|
|
|
|
2017-05-16 00:54:27 +03:00
|
|
|
if (__net_if_start == __net_if_end) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-01-23 13:47:03 +02:00
|
|
|
#if defined(CONFIG_NET_DEFAULT_IF_ETHERNET)
|
|
|
|
iface = net_if_get_first_by_type(&NET_L2_GET_NAME(ETHERNET));
|
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_DEFAULT_IF_IEEE802154)
|
|
|
|
iface = net_if_get_first_by_type(&NET_L2_GET_NAME(IEEE802154));
|
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_DEFAULT_IF_BLUETOOTH)
|
|
|
|
iface = net_if_get_first_by_type(&NET_L2_GET_NAME(BLUETOOTH));
|
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_DEFAULT_IF_DUMMY)
|
|
|
|
iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
|
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_DEFAULT_IF_OFFLOAD)
|
2017-05-03 10:32:24 +02:00
|
|
|
iface = net_if_get_first_by_type(NULL);
|
2018-01-23 13:47:03 +02:00
|
|
|
#endif
|
2019-01-23 13:58:11 +02:00
|
|
|
#if defined(CONFIG_NET_DEFAULT_IF_CANBUS)
|
|
|
|
iface = net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS));
|
|
|
|
#endif
|
2018-01-23 13:47:03 +02:00
|
|
|
|
|
|
|
return iface ? iface : __net_if_start;
|
2016-06-24 17:34:30 +02:00
|
|
|
}
|
|
|
|
|
2017-08-08 08:38:47 +03:00
|
|
|
struct net_if *net_if_get_first_by_type(const struct net_l2 *l2)
|
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
2017-05-03 10:32:24 +02:00
|
|
|
#if defined(CONFIG_NET_OFFLOAD)
|
|
|
|
if (!l2 && iface->if_dev->offload) {
|
|
|
|
return iface;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-01-11 16:06:53 +02:00
|
|
|
if (net_if_l2(iface) == l2) {
|
2017-08-08 08:38:47 +03:00
|
|
|
return iface;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-02-07 15:00:44 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4) || defined(CONFIG_NET_IPV6)
|
2018-04-27 13:01:33 +03:00
|
|
|
/* Return how many bits are shared between two IP addresses */
|
|
|
|
static u8_t get_ipaddr_diff(const u8_t *src, const u8_t *dst, int addr_len)
|
|
|
|
{
|
|
|
|
u8_t j, k, xor;
|
2018-11-29 11:23:03 -08:00
|
|
|
u8_t len = 0U;
|
2018-04-27 13:01:33 +03:00
|
|
|
|
2018-11-29 11:23:03 -08:00
|
|
|
for (j = 0U; j < addr_len; j++) {
|
2018-04-27 13:01:33 +03:00
|
|
|
if (src[j] == dst[j]) {
|
|
|
|
len += 8;
|
|
|
|
} else {
|
|
|
|
xor = src[j] ^ dst[j];
|
2018-11-29 11:23:03 -08:00
|
|
|
for (k = 0U; k < 8; k++) {
|
2018-04-27 13:01:33 +03:00
|
|
|
if (!(xor & 0x80)) {
|
|
|
|
len++;
|
|
|
|
xor <<= 1;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
2019-02-07 15:00:44 +02:00
|
|
|
#endif
|
2018-04-27 13:01:33 +03:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
int net_if_config_ipv6_get(struct net_if *iface, struct net_if_ipv6 **ipv6)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-01-19 19:01:23 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (iface->config.ip.ipv6) {
|
|
|
|
if (ipv6) {
|
|
|
|
*ipv6 = iface->config.ip.ipv6;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ipv6_addresses); i++) {
|
|
|
|
if (ipv6_addresses[i].iface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->config.ip.ipv6 = &ipv6_addresses[i].ipv6;
|
|
|
|
ipv6_addresses[i].iface = iface;
|
|
|
|
|
|
|
|
if (ipv6) {
|
|
|
|
*ipv6 = &ipv6_addresses[i].ipv6;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2018-01-19 19:01:23 +02:00
|
|
|
|
|
|
|
return -ESRCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
int net_if_config_ipv6_put(struct net_if *iface)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-01-19 19:01:23 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!iface->config.ip.ipv6) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ipv6_addresses); i++) {
|
|
|
|
if (ipv6_addresses[i].iface != iface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->config.ip.ipv6 = NULL;
|
|
|
|
ipv6_addresses[i].iface = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2018-01-19 19:01:23 +02:00
|
|
|
|
|
|
|
return -ESRCH;
|
|
|
|
}
|
2016-06-24 17:34:30 +02:00
|
|
|
|
2017-02-09 09:57:06 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6_MLD)
|
|
|
|
static void join_mcast_allnodes(struct net_if *iface)
|
|
|
|
{
|
|
|
|
struct in6_addr addr;
|
2017-03-06 11:03:26 +02:00
|
|
|
int ret;
|
2017-02-09 09:57:06 +02:00
|
|
|
|
|
|
|
net_ipv6_addr_create_ll_allnodes_mcast(&addr);
|
2017-03-06 11:03:26 +02:00
|
|
|
|
|
|
|
ret = net_ipv6_mld_join(iface, &addr);
|
2017-03-09 15:45:34 +02:00
|
|
|
if (ret < 0 && ret != -EALREADY) {
|
2017-03-06 11:03:26 +02:00
|
|
|
NET_ERR("Cannot join all nodes address %s (%d)",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(&addr)), ret);
|
2017-03-06 11:03:26 +02:00
|
|
|
}
|
2017-02-09 09:57:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void join_mcast_solicit_node(struct net_if *iface,
|
|
|
|
struct in6_addr *my_addr)
|
|
|
|
{
|
|
|
|
struct in6_addr addr;
|
2017-03-06 11:03:26 +02:00
|
|
|
int ret;
|
2017-02-09 09:57:06 +02:00
|
|
|
|
|
|
|
/* Join to needed multicast groups, RFC 4291 ch 2.8 */
|
|
|
|
net_ipv6_addr_create_solicited_node(my_addr, &addr);
|
2017-03-06 11:03:26 +02:00
|
|
|
|
|
|
|
ret = net_ipv6_mld_join(iface, &addr);
|
2017-03-09 15:45:34 +02:00
|
|
|
if (ret < 0 && ret != -EALREADY) {
|
2017-03-06 11:03:26 +02:00
|
|
|
NET_ERR("Cannot join solicit node address %s (%d)",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(&addr)), ret);
|
2017-03-06 11:03:26 +02:00
|
|
|
}
|
2017-02-09 09:57:06 +02:00
|
|
|
}
|
|
|
|
|
2017-02-10 09:36:09 +02:00
|
|
|
static void leave_mcast_all(struct net_if *iface)
|
2017-02-09 09:57:06 +02:00
|
|
|
{
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2017-02-09 09:57:06 +02:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
return;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2017-02-09 09:57:06 +02:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->mcast[i].is_used ||
|
|
|
|
!ipv6->mcast[i].is_joined) {
|
2017-02-09 09:57:06 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
net_ipv6_mld_leave(iface, &ipv6->mcast[i].address.in6_addr);
|
2017-02-09 09:57:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define join_mcast_allnodes(...)
|
|
|
|
#define join_mcast_solicit_node(...)
|
2017-02-10 09:36:09 +02:00
|
|
|
#define leave_mcast_all(...)
|
2017-02-09 09:57:06 +02:00
|
|
|
#endif /* CONFIG_NET_IPV6_MLD */
|
|
|
|
|
2016-06-16 11:01:40 +03:00
|
|
|
#if defined(CONFIG_NET_IPV6_DAD)
|
2018-05-24 12:41:58 +03:00
|
|
|
#define DAD_TIMEOUT K_MSEC(100)
|
2016-06-07 16:34:49 +03:00
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
static void dad_timeout(struct k_work *work)
|
2016-06-07 16:34:49 +03:00
|
|
|
{
|
|
|
|
/* This means that the DAD succeed. */
|
2017-02-21 17:16:19 +02:00
|
|
|
struct net_if_addr *tmp, *ifaddr = CONTAINER_OF(work,
|
|
|
|
struct net_if_addr,
|
|
|
|
dad_timer);
|
|
|
|
struct net_if *iface = NULL;
|
2016-06-07 16:34:49 +03:00
|
|
|
|
|
|
|
NET_DBG("DAD succeeded for %s",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(&ifaddr->address.in6_addr)));
|
2016-06-07 16:34:49 +03:00
|
|
|
|
|
|
|
ifaddr->addr_state = NET_ADDR_PREFERRED;
|
2017-02-21 17:16:19 +02:00
|
|
|
|
|
|
|
/* Because we do not know the interface at this point, we need to
|
|
|
|
* lookup for it.
|
|
|
|
*/
|
|
|
|
tmp = net_if_ipv6_addr_lookup(&ifaddr->address.in6_addr, &iface);
|
|
|
|
if (tmp == ifaddr) {
|
2017-04-12 10:25:54 +03:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_DAD_SUCCEED, iface);
|
|
|
|
|
2017-02-21 17:16:19 +02:00
|
|
|
/* The address gets added to neighbor cache which is not needed
|
|
|
|
* in this case as the address is our own one.
|
|
|
|
*/
|
|
|
|
net_ipv6_nbr_rm(iface, &ifaddr->address.in6_addr);
|
|
|
|
}
|
2016-06-07 16:34:49 +03:00
|
|
|
}
|
|
|
|
|
2016-11-11 10:34:51 +02:00
|
|
|
static void net_if_ipv6_start_dad(struct net_if *iface,
|
|
|
|
struct net_if_addr *ifaddr)
|
2016-06-07 16:34:49 +03:00
|
|
|
{
|
|
|
|
ifaddr->addr_state = NET_ADDR_TENTATIVE;
|
|
|
|
|
2017-07-27 15:20:35 +03:00
|
|
|
if (net_if_is_up(iface)) {
|
|
|
|
NET_DBG("Interface %p ll addr %s tentative IPv6 addr %s",
|
|
|
|
iface,
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ll_addr(
|
|
|
|
net_if_get_link_addr(iface)->addr,
|
|
|
|
net_if_get_link_addr(iface)->len)),
|
|
|
|
log_strdup(net_sprint_ipv6_addr(
|
|
|
|
&ifaddr->address.in6_addr)));
|
2017-07-27 15:20:35 +03:00
|
|
|
|
|
|
|
ifaddr->dad_count = 1;
|
2016-06-07 16:34:49 +03:00
|
|
|
|
2017-07-27 15:20:35 +03:00
|
|
|
if (!net_ipv6_start_dad(iface, ifaddr)) {
|
|
|
|
k_delayed_work_submit(&ifaddr->dad_timer, DAD_TIMEOUT);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
NET_DBG("Interface %p is down, starting DAD for %s later.",
|
|
|
|
iface,
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(
|
|
|
|
&ifaddr->address.in6_addr)));
|
2016-06-07 16:34:49 +03:00
|
|
|
}
|
|
|
|
}
|
2016-11-11 10:34:51 +02:00
|
|
|
|
|
|
|
void net_if_start_dad(struct net_if *iface)
|
|
|
|
{
|
|
|
|
struct net_if_addr *ifaddr;
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6;
|
2016-11-11 20:14:20 +02:00
|
|
|
struct in6_addr addr = { };
|
2017-07-27 15:20:35 +03:00
|
|
|
int i;
|
2016-11-11 10:34:51 +02:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
|
|
|
|
NET_WARN("Cannot do DAD IPv6 config is not valid.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ipv6) {
|
|
|
|
return;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
|
|
|
net_ipv6_addr_create_iid(&addr, net_if_get_link_addr(iface));
|
2016-11-11 10:34:51 +02:00
|
|
|
|
|
|
|
ifaddr = net_if_ipv6_addr_add(iface, &addr, NET_ADDR_AUTOCONF, 0);
|
|
|
|
if (!ifaddr) {
|
|
|
|
NET_ERR("Cannot add %s address to interface %p, DAD fails",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(&addr)), iface);
|
2016-11-11 10:34:51 +02:00
|
|
|
}
|
2017-07-27 15:20:35 +03:00
|
|
|
|
|
|
|
/* Start DAD for all the addresses that were added earlier when
|
|
|
|
* the interface was down.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->unicast[i].is_used ||
|
|
|
|
ipv6->unicast[i].address.family != AF_INET6 ||
|
|
|
|
&ipv6->unicast[i] == ifaddr) {
|
2017-07-27 15:20:35 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
|
2017-07-27 15:20:35 +03:00
|
|
|
}
|
2016-11-11 10:34:51 +02:00
|
|
|
}
|
2017-04-12 10:25:54 +03:00
|
|
|
|
|
|
|
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",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(addr)), iface);
|
2017-04-12 10:25:54 +03:00
|
|
|
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);
|
|
|
|
}
|
2016-11-11 10:34:51 +02:00
|
|
|
#else
|
2017-03-24 14:33:34 +01:00
|
|
|
static inline void net_if_ipv6_start_dad(struct net_if *iface,
|
|
|
|
struct net_if_addr *ifaddr)
|
|
|
|
{
|
|
|
|
ifaddr->addr_state = NET_ADDR_PREFERRED;
|
|
|
|
}
|
2016-06-16 11:01:40 +03:00
|
|
|
#endif /* CONFIG_NET_IPV6_DAD */
|
2016-06-07 16:34:49 +03:00
|
|
|
|
2016-06-16 11:01:40 +03:00
|
|
|
#if defined(CONFIG_NET_IPV6_ND)
|
2018-05-24 12:41:58 +03:00
|
|
|
#define RS_TIMEOUT K_SECONDS(1)
|
2016-06-10 10:31:21 +03:00
|
|
|
#define RS_COUNT 3
|
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
static void rs_timeout(struct k_work *work)
|
2016-06-10 10:31:21 +03:00
|
|
|
{
|
|
|
|
/* Did not receive RA yet. */
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = CONTAINER_OF(work,
|
|
|
|
struct net_if_ipv6,
|
|
|
|
rs_timer);
|
2018-01-11 16:06:53 +02:00
|
|
|
struct net_if *iface;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
ipv6->rs_count++;
|
2018-01-11 16:06:53 +02:00
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (iface->config.ip.ipv6 == ipv6) {
|
2018-01-11 16:06:53 +02:00
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
2016-06-10 10:31:21 +03:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
NET_DBG("Interface IPv6 config %p not found", ipv6);
|
2018-01-11 16:06:53 +02:00
|
|
|
return;
|
2016-06-10 10:31:21 +03:00
|
|
|
|
2018-01-11 16:06:53 +02:00
|
|
|
found:
|
|
|
|
NET_DBG("RS no respond iface %p count %d", iface,
|
2018-01-19 19:01:23 +02:00
|
|
|
ipv6->rs_count);
|
2016-06-10 10:31:21 +03:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (ipv6->rs_count < RS_COUNT) {
|
2016-06-10 10:31:21 +03:00
|
|
|
net_if_start_rs(iface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_start_rs(struct net_if *iface)
|
|
|
|
{
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
return;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-06-10 10:31:21 +03:00
|
|
|
NET_DBG("Interface %p", iface);
|
|
|
|
|
|
|
|
if (!net_ipv6_start_rs(iface)) {
|
2018-01-19 19:01:23 +02:00
|
|
|
k_delayed_work_submit(&ipv6->rs_timer, RS_TIMEOUT);
|
2016-06-10 10:31:21 +03:00
|
|
|
}
|
|
|
|
}
|
2016-06-16 11:01:40 +03:00
|
|
|
#endif /* CONFIG_NET_IPV6_ND */
|
2016-06-10 10:31:21 +03:00
|
|
|
|
2016-06-22 15:34:47 +03:00
|
|
|
struct net_if_addr *net_if_ipv6_addr_lookup(const struct in6_addr *addr,
|
|
|
|
struct net_if **ret)
|
2016-05-17 12:33:45 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-05-17 12:33:45 +03:00
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2016-05-17 12:33:45 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-05-17 12:33:45 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->unicast[i].is_used ||
|
|
|
|
ipv6->unicast[i].address.family != AF_INET6) {
|
2016-05-17 12:33:45 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (net_ipv6_is_prefix(
|
2018-01-19 19:01:23 +02:00
|
|
|
addr->s6_addr,
|
|
|
|
ipv6->unicast[i].address.in6_addr.s6_addr,
|
|
|
|
128)) {
|
2016-06-22 15:34:47 +03:00
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
*ret = iface;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
return &ipv6->unicast[i];
|
2016-05-17 12:33:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-05-17 12:33:45 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-08-07 12:57:21 +03:00
|
|
|
struct net_if_addr *net_if_ipv6_addr_lookup_by_iface(struct net_if *iface,
|
|
|
|
struct in6_addr *addr)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-08-07 12:57:21 +03:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!ipv6) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
|
|
|
if (!ipv6->unicast[i].is_used ||
|
|
|
|
ipv6->unicast[i].address.family != AF_INET6) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (net_ipv6_is_prefix(
|
2018-08-07 12:57:21 +03:00
|
|
|
addr->s6_addr,
|
|
|
|
ipv6->unicast[i].address.in6_addr.s6_addr,
|
|
|
|
128)) {
|
|
|
|
return &ipv6->unicast[i];
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2018-08-07 12:57:21 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-08-17 17:04:10 +03:00
|
|
|
static bool check_timeout(u32_t start, s32_t timeout, u32_t counter,
|
|
|
|
u32_t current_time)
|
2018-08-17 10:20:05 +03:00
|
|
|
{
|
2018-08-17 17:04:10 +03:00
|
|
|
if (counter > 0) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-08-17 10:20:05 +03:00
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
if ((s32_t)((start + (u32_t)timeout) - current_time) > 0) {
|
2018-08-17 10:20:05 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-27 14:02:09 +03:00
|
|
|
static void address_expired(struct net_if_addr *ifaddr)
|
|
|
|
{
|
|
|
|
NET_DBG("IPv6 address %s is deprecated",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(&ifaddr->address.in6_addr)));
|
2018-08-27 14:02:09 +03:00
|
|
|
|
|
|
|
ifaddr->addr_state = NET_ADDR_DEPRECATED;
|
|
|
|
ifaddr->lifetime.timer_timeout = 0;
|
|
|
|
ifaddr->lifetime.wrap_counter = 0;
|
|
|
|
|
|
|
|
sys_slist_find_and_remove(&active_address_lifetime_timers,
|
|
|
|
&ifaddr->lifetime.node);
|
|
|
|
}
|
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
static bool address_manage_timeout(struct net_if_addr *ifaddr,
|
|
|
|
u32_t current_time, u32_t *next_wakeup)
|
2018-08-17 10:20:05 +03:00
|
|
|
{
|
2018-08-17 17:04:10 +03:00
|
|
|
if (check_timeout(ifaddr->lifetime.timer_start,
|
|
|
|
ifaddr->lifetime.timer_timeout,
|
|
|
|
ifaddr->lifetime.wrap_counter,
|
|
|
|
current_time)) {
|
|
|
|
address_expired(ifaddr);
|
|
|
|
return true;
|
|
|
|
}
|
2018-08-17 10:20:05 +03:00
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
if (current_time == NET_TIMEOUT_MAX_VALUE) {
|
|
|
|
ifaddr->lifetime.timer_start = k_uptime_get_32();
|
|
|
|
ifaddr->lifetime.wrap_counter--;
|
|
|
|
}
|
2018-08-17 10:20:05 +03:00
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
if (ifaddr->lifetime.wrap_counter > 0) {
|
|
|
|
*next_wakeup = NET_TIMEOUT_MAX_VALUE;
|
|
|
|
} else {
|
|
|
|
*next_wakeup = ifaddr->lifetime.timer_timeout;
|
2018-08-17 10:20:05 +03:00
|
|
|
}
|
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-08-17 10:20:05 +03:00
|
|
|
static void address_lifetime_timeout(struct k_work *work)
|
|
|
|
{
|
2018-08-17 17:04:10 +03:00
|
|
|
u64_t timeout_update = UINT64_MAX;
|
|
|
|
u32_t current_time = k_uptime_get_32();
|
|
|
|
bool found = false;
|
2018-08-17 10:20:05 +03:00
|
|
|
struct net_if_addr *current, *next;
|
|
|
|
|
|
|
|
ARG_UNUSED(work);
|
|
|
|
|
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&active_address_lifetime_timers,
|
2018-08-17 17:04:10 +03:00
|
|
|
current, next, lifetime.node) {
|
2018-08-17 10:20:05 +03:00
|
|
|
u32_t next_timeout;
|
2018-08-17 17:04:10 +03:00
|
|
|
bool is_timeout;
|
|
|
|
|
|
|
|
is_timeout = address_manage_timeout(current, current_time,
|
|
|
|
&next_timeout);
|
|
|
|
if (!is_timeout) {
|
|
|
|
if (next_timeout < timeout_update) {
|
|
|
|
timeout_update = next_timeout;
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
2018-08-17 10:20:05 +03:00
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
if (current == next) {
|
|
|
|
break;
|
2018-08-17 10:20:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
if (found) {
|
|
|
|
/* If we are near upper limit of s32_t timeout, then lower it
|
|
|
|
* a bit so that kernel timeout variable will not overflow.
|
|
|
|
*/
|
|
|
|
if (timeout_update >= NET_TIMEOUT_MAX_VALUE) {
|
|
|
|
timeout_update = NET_TIMEOUT_MAX_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NET_DBG("Waiting for %d ms", (s32_t)timeout_update);
|
2018-08-17 10:20:05 +03:00
|
|
|
|
|
|
|
k_delayed_work_submit(&address_lifetime_timer, timeout_update);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-27 10:05:17 +03:00
|
|
|
#if defined(CONFIG_NET_TEST)
|
|
|
|
void net_address_lifetime_timeout(void)
|
|
|
|
{
|
|
|
|
address_lifetime_timeout(NULL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
static void address_submit_work(struct net_if_addr *ifaddr)
|
2018-08-17 10:20:05 +03:00
|
|
|
{
|
2018-08-17 17:04:10 +03:00
|
|
|
s32_t remaining;
|
|
|
|
|
|
|
|
remaining = k_delayed_work_remaining_get(&address_lifetime_timer);
|
|
|
|
if (!remaining || (ifaddr->lifetime.wrap_counter == 0 &&
|
|
|
|
ifaddr->lifetime.timer_timeout < remaining)) {
|
2018-08-17 10:20:05 +03:00
|
|
|
k_delayed_work_cancel(&address_lifetime_timer);
|
2018-08-17 17:04:10 +03:00
|
|
|
|
|
|
|
if (ifaddr->lifetime.wrap_counter > 0 && remaining == 0) {
|
|
|
|
k_delayed_work_submit(&address_lifetime_timer,
|
|
|
|
NET_TIMEOUT_MAX_VALUE);
|
|
|
|
} else {
|
|
|
|
k_delayed_work_submit(&address_lifetime_timer,
|
|
|
|
ifaddr->lifetime.timer_timeout);
|
|
|
|
}
|
2018-08-17 10:20:05 +03:00
|
|
|
|
|
|
|
NET_DBG("Next wakeup in %d ms",
|
|
|
|
k_delayed_work_remaining_get(&address_lifetime_timer));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void address_start_timer(struct net_if_addr *ifaddr, u32_t vlifetime)
|
|
|
|
{
|
2018-08-17 17:04:10 +03:00
|
|
|
u64_t expire_timeout = K_SECONDS((u64_t)vlifetime);
|
|
|
|
|
|
|
|
sys_slist_append(&active_address_lifetime_timers,
|
|
|
|
&ifaddr->lifetime.node);
|
2018-08-17 10:20:05 +03:00
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
ifaddr->lifetime.timer_start = k_uptime_get_32();
|
|
|
|
ifaddr->lifetime.wrap_counter = expire_timeout /
|
|
|
|
(u64_t)NET_TIMEOUT_MAX_VALUE;
|
|
|
|
ifaddr->lifetime.timer_timeout = expire_timeout -
|
|
|
|
(u64_t)NET_TIMEOUT_MAX_VALUE *
|
|
|
|
(u64_t)ifaddr->lifetime.wrap_counter;
|
2018-08-17 10:20:05 +03:00
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
address_submit_work(ifaddr);
|
2016-11-11 10:34:51 +02:00
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-11-11 10:34:51 +02:00
|
|
|
|
2016-11-11 10:26:17 +02:00
|
|
|
void net_if_ipv6_addr_update_lifetime(struct net_if_addr *ifaddr,
|
2017-04-21 09:27:50 -05:00
|
|
|
u32_t vlifetime)
|
2016-11-11 10:26:17 +02:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-12-06 19:20:03 +02:00
|
|
|
NET_DBG("Updating expire time of %s by %u secs",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(&ifaddr->address.in6_addr)),
|
2016-11-11 10:26:17 +02:00
|
|
|
vlifetime);
|
|
|
|
|
2018-08-17 13:05:28 +03:00
|
|
|
ifaddr->addr_state = NET_ADDR_PREFERRED;
|
|
|
|
|
2018-08-17 10:20:05 +03:00
|
|
|
address_start_timer(ifaddr, vlifetime);
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-11-11 10:26:17 +02:00
|
|
|
}
|
|
|
|
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-11-25 20:10:58 +02:00
|
|
|
static struct net_if_addr *ipv6_addr_find(struct net_if *iface,
|
|
|
|
struct in6_addr *addr)
|
|
|
|
{
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2016-11-25 20:10:58 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->unicast[i].is_used) {
|
2016-11-25 20:10:58 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (net_ipv6_addr_cmp(
|
|
|
|
addr, &ipv6->unicast[i].address.in6_addr)) {
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
return &ipv6->unicast[i];
|
2016-11-25 20:10:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-03-15 11:25:27 +02:00
|
|
|
static inline void net_if_addr_init(struct net_if_addr *ifaddr,
|
|
|
|
struct in6_addr *addr,
|
|
|
|
enum net_addr_type addr_type,
|
2017-04-21 09:27:50 -05:00
|
|
|
u32_t vlifetime)
|
2017-03-15 11:25:27 +02:00
|
|
|
{
|
|
|
|
ifaddr->is_used = true;
|
|
|
|
ifaddr->address.family = AF_INET6;
|
|
|
|
ifaddr->addr_type = addr_type;
|
|
|
|
net_ipaddr_copy(&ifaddr->address.in6_addr, addr);
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV6_DAD)
|
|
|
|
k_delayed_work_init(&ifaddr->dad_timer, dad_timeout);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* FIXME - set the mcast addr for this node */
|
|
|
|
|
|
|
|
if (vlifetime) {
|
|
|
|
ifaddr->is_infinite = false;
|
|
|
|
|
2018-10-02 14:57:55 +03:00
|
|
|
NET_DBG("Expiring %s in %u secs",
|
|
|
|
log_strdup(net_sprint_ipv6_addr(addr)),
|
2017-03-15 11:25:27 +02:00
|
|
|
vlifetime);
|
|
|
|
|
|
|
|
net_if_ipv6_addr_update_lifetime(ifaddr, vlifetime);
|
|
|
|
} else {
|
|
|
|
ifaddr->is_infinite = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-08 13:30:52 +02:00
|
|
|
static inline struct in6_addr *check_global_addr(struct net_if *iface)
|
|
|
|
{
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2018-01-08 13:30:52 +02:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2018-01-08 13:30:52 +02:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->unicast[i].is_used ||
|
|
|
|
(ipv6->unicast[i].addr_state != NET_ADDR_TENTATIVE &&
|
|
|
|
ipv6->unicast[i].addr_state != NET_ADDR_PREFERRED) ||
|
|
|
|
ipv6->unicast[i].address.family != AF_INET6) {
|
2018-01-08 13:30:52 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (!net_ipv6_is_ll_addr(&ipv6->unicast[i].address.in6_addr)) {
|
2018-01-19 19:01:23 +02:00
|
|
|
return &ipv6->unicast[i].address.in6_addr;
|
2018-01-08 13:30:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-08-06 16:59:33 +03:00
|
|
|
static void join_mcast_nodes(struct net_if *iface, struct in6_addr *addr)
|
|
|
|
{
|
|
|
|
enum net_l2_flags flags = 0;
|
|
|
|
|
|
|
|
if (net_if_l2(iface)->get_flags) {
|
|
|
|
flags = net_if_l2(iface)->get_flags(iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & NET_L2_MULTICAST) {
|
|
|
|
join_mcast_allnodes(iface);
|
|
|
|
|
2018-08-06 17:02:14 +03:00
|
|
|
if (!(flags & NET_L2_MULTICAST_SKIP_JOIN_SOLICIT_NODE)) {
|
|
|
|
join_mcast_solicit_node(iface, addr);
|
|
|
|
}
|
2018-08-06 16:59:33 +03:00
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#else /* CONFIG_NET_IPV6 */
|
|
|
|
#define join_mcast_allnodes(...)
|
|
|
|
#define join_mcast_solicit_node(...)
|
|
|
|
#define leave_mcast_all(...)
|
|
|
|
#define join_mcast_nodes(...)
|
|
|
|
#endif /* CONFIG_NET_IPV6 */
|
2018-08-06 16:59:33 +03:00
|
|
|
|
2016-05-17 12:33:45 +03:00
|
|
|
struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
|
|
|
|
struct in6_addr *addr,
|
|
|
|
enum net_addr_type addr_type,
|
2017-04-21 09:27:50 -05:00
|
|
|
u32_t vlifetime)
|
2016-05-17 12:33:45 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-11-25 20:10:58 +02:00
|
|
|
struct net_if_addr *ifaddr;
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6;
|
2016-05-17 12:33:45 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-25 20:10:58 +02:00
|
|
|
ifaddr = ipv6_addr_find(iface, addr);
|
|
|
|
if (ifaddr) {
|
|
|
|
return ifaddr;
|
|
|
|
}
|
|
|
|
|
2016-05-17 12:33:45 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (ipv6->unicast[i].is_used) {
|
2016-05-17 12:33:45 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
net_if_addr_init(&ipv6->unicast[i], addr, addr_type,
|
2017-03-15 11:25:27 +02:00
|
|
|
vlifetime);
|
2016-05-17 12:33:45 +03:00
|
|
|
|
2018-01-11 16:06:53 +02:00
|
|
|
NET_DBG("[%d] interface %p address %s type %s added", i,
|
2018-10-02 14:57:55 +03:00
|
|
|
iface, log_strdup(net_sprint_ipv6_addr(addr)),
|
2016-05-17 12:33:45 +03:00
|
|
|
net_addr_type2str(addr_type));
|
|
|
|
|
2017-12-05 17:24:58 +02:00
|
|
|
/* RFC 4862 5.4.2
|
|
|
|
* "Before sending a Neighbor Solicitation, an interface
|
|
|
|
* MUST join the all-nodes multicast address and the
|
|
|
|
* solicited-node multicast address of the tentative address."
|
|
|
|
*/
|
|
|
|
/* The allnodes multicast group is only joined once as
|
|
|
|
* net_ipv6_mcast_join() checks if we have already joined.
|
|
|
|
*/
|
2018-08-06 16:59:33 +03:00
|
|
|
join_mcast_nodes(iface, &ipv6->unicast[i].address.in6_addr);
|
2018-01-08 13:30:52 +02:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
|
2016-11-11 10:34:51 +02:00
|
|
|
|
2016-09-29 18:33:03 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_ADDR_ADD, iface);
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
return &ipv6->unicast[i];
|
2016-05-17 12:33:45 +03:00
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-05-17 12:33:45 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-04-12 10:34:59 +03:00
|
|
|
bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr)
|
2016-06-01 10:54:10 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2016-06-01 10:54:10 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
NET_ASSERT(addr);
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-06-01 10:54:10 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
|
|
|
struct in6_addr maddr;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->unicast[i].is_used) {
|
2016-06-01 10:54:10 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!net_ipv6_addr_cmp(&ipv6->unicast[i].address.in6_addr,
|
|
|
|
addr)) {
|
2016-06-01 10:54:10 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->unicast[i].is_infinite) {
|
2018-08-17 10:20:05 +03:00
|
|
|
sys_slist_find_and_remove(
|
|
|
|
&active_address_lifetime_timers,
|
2018-08-17 17:04:10 +03:00
|
|
|
&ipv6->unicast[i].lifetime.node);
|
2018-08-17 10:20:05 +03:00
|
|
|
|
|
|
|
if (sys_slist_is_empty(
|
|
|
|
&active_address_lifetime_timers)) {
|
|
|
|
k_delayed_work_cancel(&address_lifetime_timer);
|
|
|
|
}
|
2017-07-19 19:48:01 +03:00
|
|
|
}
|
2016-11-11 10:34:51 +02:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
ipv6->unicast[i].is_used = false;
|
2016-06-01 10:54:10 +03:00
|
|
|
|
|
|
|
net_ipv6_addr_create_solicited_node(addr, &maddr);
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-06-01 10:54:10 +03:00
|
|
|
net_if_ipv6_maddr_rm(iface, &maddr);
|
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p address %s type %s removed",
|
2018-10-02 14:57:55 +03:00
|
|
|
i, iface, log_strdup(net_sprint_ipv6_addr(addr)),
|
2018-01-19 19:01:23 +02:00
|
|
|
net_addr_type2str(ipv6->unicast[i].addr_type));
|
2016-06-01 10:54:10 +03:00
|
|
|
|
2016-09-29 18:33:03 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_ADDR_DEL, iface);
|
|
|
|
|
2016-06-01 10:54:10 +03:00
|
|
|
return true;
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-06-01 10:54:10 +03:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-17 12:33:45 +03:00
|
|
|
struct net_if_mcast_addr *net_if_ipv6_maddr_add(struct net_if *iface,
|
2017-02-09 09:48:31 +02:00
|
|
|
const struct in6_addr *addr)
|
2016-05-17 12:33:45 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6;
|
2016-05-17 12:33:45 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (!net_ipv6_is_addr_mcast(addr)) {
|
2016-05-17 12:33:45 +03:00
|
|
|
NET_DBG("Address %s is not a multicast address.",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(addr)));
|
2016-05-17 12:33:45 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (ipv6->mcast[i].is_used) {
|
2016-05-17 12:33:45 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
ipv6->mcast[i].is_used = true;
|
|
|
|
ipv6->mcast[i].address.family = AF_INET6;
|
|
|
|
memcpy(&ipv6->mcast[i].address.in6_addr, addr, 16);
|
2016-05-17 12:33:45 +03:00
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p address %s added", i, iface,
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(addr)));
|
2016-05-17 12:33:45 +03:00
|
|
|
|
2016-09-29 18:33:03 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_MADDR_ADD, iface);
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
return &ipv6->mcast[i];
|
2016-05-17 12:33:45 +03:00
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-05-17 12:33:45 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-02-09 09:48:31 +02:00
|
|
|
bool net_if_ipv6_maddr_rm(struct net_if *iface, const struct in6_addr *addr)
|
2016-06-01 10:54:10 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2016-06-01 10:54:10 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-06-01 10:54:10 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->mcast[i].is_used) {
|
2016-06-01 10:54:10 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!net_ipv6_addr_cmp(&ipv6->mcast[i].address.in6_addr,
|
|
|
|
addr)) {
|
2016-06-01 10:54:10 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
ipv6->mcast[i].is_used = false;
|
2016-06-01 10:54:10 +03:00
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p address %s removed",
|
2018-10-02 14:57:55 +03:00
|
|
|
i, iface, log_strdup(net_sprint_ipv6_addr(addr)));
|
2016-06-01 10:54:10 +03:00
|
|
|
|
2016-09-29 18:33:03 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_MADDR_DEL, iface);
|
|
|
|
|
2016-06-01 10:54:10 +03:00
|
|
|
return true;
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-06-01 10:54:10 +03:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-22 15:34:47 +03:00
|
|
|
struct net_if_mcast_addr *net_if_ipv6_maddr_lookup(const struct in6_addr *maddr,
|
|
|
|
struct net_if **ret)
|
2016-05-17 12:33:45 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-05-17 12:33:45 +03:00
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2016-05-17 12:33:45 +03:00
|
|
|
int i;
|
|
|
|
|
2017-02-09 09:50:50 +02:00
|
|
|
if (ret && *ret && iface != *ret) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-05-17 12:33:45 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->mcast[i].is_used ||
|
|
|
|
ipv6->mcast[i].address.family != AF_INET6) {
|
2016-05-17 12:33:45 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (net_ipv6_is_prefix(
|
2018-01-19 19:01:23 +02:00
|
|
|
maddr->s6_addr,
|
|
|
|
ipv6->mcast[i].address.in6_addr.s6_addr,
|
|
|
|
128)) {
|
2016-06-22 15:34:47 +03:00
|
|
|
if (ret) {
|
|
|
|
*ret = iface;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
return &ipv6->mcast[i];
|
2016-05-17 12:33:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-05-17 12:33:45 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-08-29 09:57:27 +03:00
|
|
|
void net_if_mcast_mon_register(struct net_if_mcast_monitor *mon,
|
|
|
|
struct net_if *iface,
|
|
|
|
net_if_mcast_callback_t cb)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2017-08-29 09:57:27 +03:00
|
|
|
sys_slist_find_and_remove(&mcast_monitor_callbacks, &mon->node);
|
|
|
|
sys_slist_prepend(&mcast_monitor_callbacks, &mon->node);
|
|
|
|
|
|
|
|
mon->iface = iface;
|
|
|
|
mon->cb = cb;
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2017-08-29 09:57:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_mcast_mon_unregister(struct net_if_mcast_monitor *mon)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2017-08-29 09:57:27 +03:00
|
|
|
sys_slist_find_and_remove(&mcast_monitor_callbacks, &mon->node);
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2017-08-29 09:57:27 +03:00
|
|
|
}
|
|
|
|
|
2018-01-11 16:06:53 +02:00
|
|
|
void net_if_mcast_monitor(struct net_if *iface,
|
|
|
|
const struct in6_addr *addr,
|
2017-08-29 09:57:27 +03:00
|
|
|
bool is_joined)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2017-08-29 09:57:27 +03:00
|
|
|
struct net_if_mcast_monitor *mon, *tmp;
|
|
|
|
|
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&mcast_monitor_callbacks,
|
|
|
|
mon, tmp, node) {
|
|
|
|
if (iface == mon->iface) {
|
|
|
|
mon->cb(iface, addr, is_joined);
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2017-08-29 09:57:27 +03:00
|
|
|
}
|
|
|
|
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-08-17 13:33:20 +03:00
|
|
|
static void remove_prefix_addresses(struct net_if *iface,
|
|
|
|
struct net_if_ipv6 *ipv6,
|
|
|
|
struct in6_addr *addr,
|
|
|
|
u8_t len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
|
|
|
if (!ipv6->unicast[i].is_used ||
|
|
|
|
ipv6->unicast[i].address.family != AF_INET6 ||
|
|
|
|
ipv6->unicast[i].addr_type != NET_ADDR_AUTOCONF) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (net_ipv6_is_prefix(
|
2018-08-17 13:33:20 +03:00
|
|
|
addr->s6_addr,
|
|
|
|
ipv6->unicast[i].address.in6_addr.s6_addr,
|
|
|
|
len)) {
|
|
|
|
net_if_ipv6_addr_rm(iface,
|
|
|
|
&ipv6->unicast[i].address.in6_addr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-27 14:02:09 +03:00
|
|
|
static void prefix_lifetime_expired(struct net_if_ipv6_prefix *ifprefix)
|
2017-03-15 11:25:27 +02:00
|
|
|
{
|
2018-08-17 13:33:20 +03:00
|
|
|
struct net_if_ipv6 *ipv6;
|
2017-03-15 11:25:27 +02:00
|
|
|
|
|
|
|
NET_DBG("Prefix %s/%d expired",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(&ifprefix->prefix)),
|
|
|
|
ifprefix->len);
|
2017-03-15 11:25:27 +02:00
|
|
|
|
2018-08-27 14:02:09 +03:00
|
|
|
ifprefix->is_used = false;
|
2018-08-17 13:33:20 +03:00
|
|
|
|
2018-08-27 14:02:09 +03:00
|
|
|
if (net_if_config_ipv6_get(ifprefix->iface, &ipv6) < 0) {
|
2018-08-17 13:33:20 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove also all auto addresses if the they have the same prefix.
|
|
|
|
*/
|
2018-08-27 14:02:09 +03:00
|
|
|
remove_prefix_addresses(ifprefix->iface, ipv6, &ifprefix->prefix,
|
|
|
|
ifprefix->len);
|
|
|
|
|
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_PREFIX_DEL, ifprefix->iface);
|
|
|
|
}
|
2018-08-17 13:33:20 +03:00
|
|
|
|
2018-08-27 14:02:09 +03:00
|
|
|
static void prefix_timer_remove(struct net_if_ipv6_prefix *ifprefix)
|
|
|
|
{
|
|
|
|
NET_DBG("IPv6 prefix %s/%d removed",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(&ifprefix->prefix)),
|
2018-08-27 14:02:09 +03:00
|
|
|
ifprefix->len);
|
|
|
|
|
|
|
|
ifprefix->lifetime.timer_timeout = 0;
|
|
|
|
ifprefix->lifetime.wrap_counter = 0;
|
|
|
|
|
|
|
|
sys_slist_find_and_remove(&active_prefix_lifetime_timers,
|
|
|
|
&ifprefix->lifetime.node);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool prefix_manage_timeout(struct net_if_ipv6_prefix *ifprefix,
|
|
|
|
u32_t current_time, u32_t *next_wakeup)
|
|
|
|
{
|
|
|
|
if (check_timeout(ifprefix->lifetime.timer_start,
|
|
|
|
ifprefix->lifetime.timer_timeout,
|
|
|
|
ifprefix->lifetime.wrap_counter,
|
|
|
|
current_time)) {
|
|
|
|
prefix_lifetime_expired(ifprefix);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (current_time == NET_TIMEOUT_MAX_VALUE) {
|
|
|
|
ifprefix->lifetime.wrap_counter--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ifprefix->lifetime.wrap_counter > 0) {
|
|
|
|
*next_wakeup = NET_TIMEOUT_MAX_VALUE;
|
|
|
|
} else {
|
|
|
|
*next_wakeup = ifprefix->lifetime.timer_timeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void prefix_lifetime_timeout(struct k_work *work)
|
|
|
|
{
|
|
|
|
u64_t timeout_update = UINT64_MAX;
|
|
|
|
u32_t current_time = k_uptime_get_32();
|
|
|
|
bool found = false;
|
|
|
|
struct net_if_ipv6_prefix *current, *next;
|
|
|
|
|
|
|
|
ARG_UNUSED(work);
|
|
|
|
|
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&active_prefix_lifetime_timers,
|
|
|
|
current, next, lifetime.node) {
|
|
|
|
u32_t next_timeout;
|
|
|
|
bool is_timeout;
|
|
|
|
|
|
|
|
is_timeout = prefix_manage_timeout(current, current_time,
|
|
|
|
&next_timeout);
|
|
|
|
if (!is_timeout) {
|
|
|
|
if (next_timeout < timeout_update) {
|
|
|
|
timeout_update = next_timeout;
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (current == next) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found) {
|
|
|
|
/* If we are near upper limit of s32_t timeout, then lower it
|
|
|
|
* a bit so that kernel timeout will not overflow.
|
|
|
|
*/
|
|
|
|
if (timeout_update >= NET_TIMEOUT_MAX_VALUE) {
|
|
|
|
timeout_update = NET_TIMEOUT_MAX_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NET_DBG("Waiting for %d ms", (u32_t)timeout_update);
|
|
|
|
|
|
|
|
k_delayed_work_submit(&prefix_lifetime_timer, timeout_update);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void prefix_submit_work(struct net_if_ipv6_prefix *ifprefix)
|
|
|
|
{
|
|
|
|
s32_t remaining;
|
|
|
|
|
|
|
|
remaining = k_delayed_work_remaining_get(&prefix_lifetime_timer);
|
|
|
|
if (!remaining || (ifprefix->lifetime.wrap_counter == 0 &&
|
|
|
|
ifprefix->lifetime.timer_timeout < remaining)) {
|
|
|
|
k_delayed_work_cancel(&prefix_lifetime_timer);
|
|
|
|
|
|
|
|
if (ifprefix->lifetime.wrap_counter > 0 && remaining == 0) {
|
|
|
|
k_delayed_work_submit(&prefix_lifetime_timer,
|
|
|
|
NET_TIMEOUT_MAX_VALUE);
|
|
|
|
} else {
|
|
|
|
k_delayed_work_submit(&prefix_lifetime_timer,
|
|
|
|
ifprefix->lifetime.timer_timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
NET_DBG("Next wakeup in %d ms",
|
|
|
|
k_delayed_work_remaining_get(&prefix_lifetime_timer));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void prefix_start_timer(struct net_if_ipv6_prefix *ifprefix,
|
|
|
|
u32_t lifetime)
|
|
|
|
{
|
|
|
|
u64_t expire_timeout = K_SECONDS((u64_t)lifetime);
|
|
|
|
|
|
|
|
sys_slist_append(&active_prefix_lifetime_timers,
|
|
|
|
&ifprefix->lifetime.node);
|
|
|
|
|
|
|
|
ifprefix->lifetime.timer_start = k_uptime_get_32();
|
|
|
|
ifprefix->lifetime.wrap_counter = expire_timeout /
|
|
|
|
(u64_t)NET_TIMEOUT_MAX_VALUE;
|
|
|
|
ifprefix->lifetime.timer_timeout = expire_timeout -
|
|
|
|
(u64_t)NET_TIMEOUT_MAX_VALUE *
|
|
|
|
(u64_t)ifprefix->lifetime.wrap_counter;
|
|
|
|
|
|
|
|
prefix_submit_work(ifprefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct net_if_ipv6_prefix *ipv6_prefix_find(struct net_if *iface,
|
|
|
|
struct in6_addr *prefix,
|
|
|
|
u8_t prefix_len)
|
|
|
|
{
|
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!ipv6) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
|
|
|
if (!ipv6->unicast[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_ipv6_addr_cmp(prefix, &ipv6->prefix[i].prefix) &&
|
|
|
|
prefix_len == ipv6->prefix[i].len) {
|
|
|
|
return &ipv6->prefix[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2017-03-15 11:25:27 +02:00
|
|
|
}
|
|
|
|
|
2018-08-17 13:33:20 +03:00
|
|
|
static void net_if_ipv6_prefix_init(struct net_if *iface,
|
2018-08-27 14:02:09 +03:00
|
|
|
struct net_if_ipv6_prefix *ifprefix,
|
2017-04-21 09:27:50 -05:00
|
|
|
struct in6_addr *addr, u8_t len,
|
|
|
|
u32_t lifetime)
|
2017-03-15 11:25:27 +02:00
|
|
|
{
|
2018-08-27 14:02:09 +03:00
|
|
|
ifprefix->is_used = true;
|
|
|
|
ifprefix->len = len;
|
|
|
|
ifprefix->iface = iface;
|
|
|
|
net_ipaddr_copy(&ifprefix->prefix, addr);
|
2017-03-15 11:25:27 +02:00
|
|
|
|
|
|
|
if (lifetime == NET_IPV6_ND_INFINITE_LIFETIME) {
|
2018-08-27 14:02:09 +03:00
|
|
|
ifprefix->is_infinite = true;
|
2017-03-15 11:25:27 +02:00
|
|
|
} else {
|
2018-08-27 14:02:09 +03:00
|
|
|
ifprefix->is_infinite = false;
|
2017-03-15 11:25:27 +02:00
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif /* CONFIG_NET_IPV6 */
|
2017-03-15 11:25:27 +02:00
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
struct net_if_ipv6_prefix *net_if_ipv6_prefix_add(struct net_if *iface,
|
|
|
|
struct in6_addr *prefix,
|
2017-04-21 09:27:50 -05:00
|
|
|
u8_t len,
|
|
|
|
u32_t lifetime)
|
2016-06-07 10:16:58 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-08-27 14:02:09 +03:00
|
|
|
struct net_if_ipv6_prefix *ifprefix;
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6;
|
2016-06-07 10:16:58 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-08-27 14:02:09 +03:00
|
|
|
ifprefix = ipv6_prefix_find(iface, prefix, len);
|
|
|
|
if (ifprefix) {
|
|
|
|
return ifprefix;
|
2016-11-25 20:12:37 +02:00
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (ipv6->prefix[i].is_used) {
|
2016-06-07 10:16:58 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:33:20 +03:00
|
|
|
net_if_ipv6_prefix_init(iface, &ipv6->prefix[i], prefix,
|
2018-01-11 16:06:53 +02:00
|
|
|
len, lifetime);
|
2016-06-07 10:16:58 +03:00
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p prefix %s/%d added", i, iface,
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(prefix)), len);
|
2016-06-07 10:16:58 +03:00
|
|
|
|
2016-09-29 18:33:03 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_PREFIX_ADD, iface);
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
return &ipv6->prefix[i];
|
2016-06-07 10:16:58 +03:00
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-06-07 10:16:58 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool net_if_ipv6_prefix_rm(struct net_if *iface, struct in6_addr *addr,
|
2017-04-21 09:27:50 -05:00
|
|
|
u8_t len)
|
2016-06-07 10:16:58 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2016-06-07 10:16:58 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->prefix[i].is_used) {
|
2016-06-07 10:16:58 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!net_ipv6_addr_cmp(&ipv6->prefix[i].prefix, addr) ||
|
|
|
|
ipv6->prefix[i].len != len) {
|
2016-06-07 10:16:58 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
net_if_ipv6_prefix_unset_timer(&ipv6->prefix[i]);
|
2016-07-07 10:54:34 +03:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
ipv6->prefix[i].is_used = false;
|
2016-07-07 10:54:34 +03:00
|
|
|
|
2018-08-17 13:33:20 +03:00
|
|
|
/* Remove also all auto addresses if the they have the same
|
|
|
|
* prefix.
|
|
|
|
*/
|
|
|
|
remove_prefix_addresses(iface, ipv6, addr, len);
|
|
|
|
|
2016-09-29 18:33:03 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_PREFIX_DEL, iface);
|
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
return true;
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-06-24 17:34:30 +02:00
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-08-22 12:41:30 +03:00
|
|
|
struct net_if_ipv6_prefix *net_if_ipv6_prefix_get(struct net_if *iface,
|
|
|
|
struct in6_addr *addr)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-08-22 12:41:30 +03:00
|
|
|
struct net_if_ipv6_prefix *prefix = NULL;
|
|
|
|
struct net_if_ipv6 *ipv6;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!iface) {
|
|
|
|
iface = net_if_get_default();
|
|
|
|
}
|
|
|
|
|
|
|
|
ipv6 = iface->config.ip.ipv6;
|
|
|
|
if (!ipv6) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
|
|
|
if (!ipv6->prefix[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (net_ipv6_is_prefix(ipv6->prefix[i].prefix.s6_addr,
|
2018-08-22 12:41:30 +03:00
|
|
|
addr->s6_addr,
|
|
|
|
ipv6->prefix[i].len)) {
|
|
|
|
if (!prefix || prefix->len > ipv6->prefix[i].len) {
|
|
|
|
prefix = &ipv6->prefix[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return prefix;
|
2018-11-05 13:22:14 +02:00
|
|
|
#else
|
|
|
|
return NULL;
|
|
|
|
#endif
|
2018-08-22 12:41:30 +03:00
|
|
|
}
|
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
struct net_if_ipv6_prefix *net_if_ipv6_prefix_lookup(struct net_if *iface,
|
|
|
|
struct in6_addr *addr,
|
2017-04-21 09:27:50 -05:00
|
|
|
u8_t len)
|
2016-06-07 10:16:58 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2016-06-07 10:16:58 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->prefix[i].is_used) {
|
2016-06-07 10:16:58 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (net_ipv6_is_prefix(ipv6->prefix[i].prefix.s6_addr,
|
2018-01-19 19:01:23 +02:00
|
|
|
addr->s6_addr, len)) {
|
|
|
|
return &ipv6->prefix[i];
|
2016-06-07 10:16:58 +03:00
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-06-24 17:34:30 +02:00
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-10-17 13:00:45 +03:00
|
|
|
bool net_if_ipv6_addr_onlink(struct net_if **iface, struct in6_addr *addr)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-10-17 13:00:45 +03:00
|
|
|
struct net_if *tmp;
|
|
|
|
|
|
|
|
for (tmp = __net_if_start; tmp != __net_if_end; tmp++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = tmp->config.ip.ipv6;
|
2016-10-17 13:00:45 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (iface && *iface && *iface != tmp) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-10-17 13:00:45 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (ipv6->prefix[i].is_used &&
|
2018-11-02 16:05:58 +02:00
|
|
|
net_ipv6_is_prefix(ipv6->prefix[i].prefix.s6_addr,
|
2018-01-19 19:01:23 +02:00
|
|
|
addr->s6_addr,
|
|
|
|
ipv6->prefix[i].len)) {
|
2016-10-17 13:00:45 +03:00
|
|
|
if (iface) {
|
|
|
|
*iface = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-10-17 13:00:45 +03:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-07 10:54:34 +03:00
|
|
|
void net_if_ipv6_prefix_set_timer(struct net_if_ipv6_prefix *prefix,
|
2017-04-21 09:27:50 -05:00
|
|
|
u32_t lifetime)
|
2016-07-07 10:54:34 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-08-27 14:02:09 +03:00
|
|
|
/* No need to set a timer for infinite timeout */
|
|
|
|
if (lifetime == 0xffffffff) {
|
|
|
|
return;
|
2016-07-07 10:54:34 +03:00
|
|
|
}
|
|
|
|
|
2018-08-27 14:02:09 +03:00
|
|
|
NET_DBG("Prefix lifetime %u sec", lifetime);
|
2016-11-29 15:18:02 +02:00
|
|
|
|
2018-08-27 14:02:09 +03:00
|
|
|
prefix_start_timer(prefix, lifetime);
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-07-07 10:54:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_ipv6_prefix_unset_timer(struct net_if_ipv6_prefix *prefix)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-07-07 10:54:34 +03:00
|
|
|
if (!prefix->is_used) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-27 14:02:09 +03:00
|
|
|
prefix_timer_remove(prefix);
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-07-07 10:54:34 +03:00
|
|
|
}
|
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
struct net_if_router *net_if_ipv6_router_lookup(struct net_if *iface,
|
|
|
|
struct in6_addr *addr)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-06-07 10:16:58 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_MAX_ROUTERS; i++) {
|
|
|
|
if (!routers[i].is_used ||
|
|
|
|
routers[i].address.family != AF_INET6 ||
|
|
|
|
routers[i].iface != iface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_ipv6_addr_cmp(&routers[i].address.in6_addr, addr)) {
|
|
|
|
return &routers[i];
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-06-24 17:34:30 +02:00
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-10-17 13:23:36 +03:00
|
|
|
struct net_if_router *net_if_ipv6_router_find_default(struct net_if *iface,
|
|
|
|
struct in6_addr *addr)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-10-17 13:23:36 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_MAX_ROUTERS; i++) {
|
|
|
|
if (!routers[i].is_used ||
|
|
|
|
!routers[i].is_default ||
|
|
|
|
routers[i].address.family != AF_INET6) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iface && iface != routers[i].iface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &routers[i];
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-10-17 13:23:36 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-11-11 11:22:35 +02:00
|
|
|
static void ipv6_router_expired(struct k_work *work)
|
|
|
|
{
|
|
|
|
struct net_if_router *router = CONTAINER_OF(work,
|
|
|
|
struct net_if_router,
|
|
|
|
lifetime);
|
|
|
|
|
|
|
|
NET_DBG("IPv6 router %s is expired",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(&router->address.in6_addr)));
|
2016-11-11 11:22:35 +02:00
|
|
|
|
|
|
|
router->is_used = false;
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif /* CONFIG_NET_IPV6 */
|
2016-11-11 11:22:35 +02:00
|
|
|
|
2016-11-11 11:20:28 +02:00
|
|
|
void net_if_ipv6_router_update_lifetime(struct net_if_router *router,
|
2017-04-21 09:27:50 -05:00
|
|
|
u32_t lifetime)
|
2016-11-11 11:20:28 +02:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-12-06 19:20:03 +02:00
|
|
|
NET_DBG("Updating expire time of %s by %u secs",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv6_addr(&router->address.in6_addr)),
|
2016-11-11 11:20:28 +02:00
|
|
|
lifetime);
|
|
|
|
|
2018-05-24 12:41:58 +03:00
|
|
|
k_delayed_work_submit(&router->lifetime, K_SECONDS(lifetime));
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-11-11 11:20:28 +02:00
|
|
|
}
|
|
|
|
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2017-03-15 11:25:27 +02:00
|
|
|
static inline void net_if_router_init(struct net_if_router *router,
|
|
|
|
struct net_if *iface,
|
2017-04-21 09:27:50 -05:00
|
|
|
struct in6_addr *addr, u16_t lifetime)
|
2017-03-15 11:25:27 +02:00
|
|
|
{
|
|
|
|
router->is_used = true;
|
|
|
|
router->iface = iface;
|
|
|
|
router->address.family = AF_INET6;
|
|
|
|
net_ipaddr_copy(&router->address.in6_addr, addr);
|
|
|
|
|
|
|
|
if (lifetime) {
|
|
|
|
/* This is a default router. RFC 4861 page 43
|
|
|
|
* AdvDefaultLifetime variable
|
|
|
|
*/
|
|
|
|
router->is_default = true;
|
|
|
|
router->is_infinite = false;
|
|
|
|
|
|
|
|
k_delayed_work_init(&router->lifetime, ipv6_router_expired);
|
2018-05-24 12:41:58 +03:00
|
|
|
k_delayed_work_submit(&router->lifetime, K_SECONDS(lifetime));
|
2017-03-15 11:25:27 +02:00
|
|
|
|
2018-10-02 14:57:55 +03:00
|
|
|
NET_DBG("Expiring %s in %u secs",
|
|
|
|
log_strdup(net_sprint_ipv6_addr(addr)),
|
2017-03-15 11:25:27 +02:00
|
|
|
lifetime);
|
|
|
|
} else {
|
|
|
|
router->is_default = false;
|
|
|
|
router->is_infinite = true;
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif /* CONFIG_NET_IPV6 */
|
2017-03-15 11:25:27 +02:00
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
struct net_if_router *net_if_ipv6_router_add(struct net_if *iface,
|
|
|
|
struct in6_addr *addr,
|
2017-04-21 09:27:50 -05:00
|
|
|
u16_t lifetime)
|
2016-06-07 10:16:58 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-06-07 10:16:58 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_MAX_ROUTERS; i++) {
|
|
|
|
if (routers[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-03-15 11:25:27 +02:00
|
|
|
net_if_router_init(&routers[i], iface, addr, lifetime);
|
2016-06-07 10:16:58 +03:00
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p router %s lifetime %u default %d "
|
|
|
|
"added",
|
2018-10-02 14:57:55 +03:00
|
|
|
i, iface, log_strdup(net_sprint_ipv6_addr(addr)),
|
|
|
|
lifetime, routers[i].is_default);
|
2016-06-07 10:16:58 +03:00
|
|
|
|
2017-03-21 10:47:15 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_ROUTER_ADD, iface);
|
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
return &routers[i];
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-06-07 10:16:58 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-11 11:21:34 +02:00
|
|
|
bool net_if_ipv6_router_rm(struct net_if_router *router)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-11-11 11:21:34 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_MAX_ROUTERS; i++) {
|
|
|
|
if (!routers[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (&routers[i] != router) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
k_delayed_work_cancel(&routers[i].lifetime);
|
|
|
|
|
|
|
|
routers[i].is_used = false;
|
|
|
|
|
2017-03-21 10:47:15 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_ROUTER_DEL,
|
|
|
|
routers[i].iface);
|
|
|
|
|
2016-11-11 11:21:34 +02:00
|
|
|
NET_DBG("[%d] router %s removed",
|
2018-10-02 14:57:55 +03:00
|
|
|
i, log_strdup(net_sprint_ipv6_addr(
|
|
|
|
&routers[i].address.in6_addr)));
|
2016-11-11 11:21:34 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-11-11 11:21:34 +02:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-18 11:15:41 +03:00
|
|
|
struct in6_addr *net_if_ipv6_get_ll(struct net_if *iface,
|
|
|
|
enum net_addr_state addr_state)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2016-05-18 11:15:41 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-05-18 11:15:41 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6->unicast[i].is_used ||
|
2016-05-18 11:15:41 +03:00
|
|
|
(addr_state != NET_ADDR_ANY_STATE &&
|
2018-01-19 19:01:23 +02:00
|
|
|
ipv6->unicast[i].addr_state != addr_state) ||
|
|
|
|
ipv6->unicast[i].address.family != AF_INET6) {
|
2016-05-18 11:15:41 +03:00
|
|
|
continue;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (net_ipv6_is_ll_addr(&ipv6->unicast[i].address.in6_addr)) {
|
2018-01-19 19:01:23 +02:00
|
|
|
return &ipv6->unicast[i].address.in6_addr;
|
2016-05-18 11:15:41 +03:00
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-05-18 11:15:41 +03:00
|
|
|
|
2016-10-26 13:55:44 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct in6_addr *net_if_ipv6_get_ll_addr(enum net_addr_state state,
|
|
|
|
struct net_if **iface)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-10-26 13:55:44 +03:00
|
|
|
struct net_if *tmp;
|
|
|
|
|
|
|
|
for (tmp = __net_if_start; tmp != __net_if_end; tmp++) {
|
|
|
|
struct in6_addr *addr;
|
|
|
|
|
|
|
|
addr = net_if_ipv6_get_ll(tmp, state);
|
|
|
|
if (addr) {
|
|
|
|
if (iface) {
|
|
|
|
*iface = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-10-26 13:55:44 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct in6_addr *net_if_ipv6_get_global_addr(struct net_if **iface)
|
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-10-26 13:55:44 +03:00
|
|
|
struct net_if *tmp;
|
|
|
|
|
|
|
|
for (tmp = __net_if_start; tmp != __net_if_end; tmp++) {
|
|
|
|
struct in6_addr *addr;
|
|
|
|
|
|
|
|
if (iface && *iface && tmp != *iface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr = check_global_addr(tmp);
|
|
|
|
if (addr) {
|
|
|
|
if (iface) {
|
|
|
|
*iface = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif
|
2016-10-26 13:55:44 +03:00
|
|
|
|
2016-05-18 11:15:41 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-04-27 13:01:33 +03:00
|
|
|
static u8_t get_diff_ipv6(const struct in6_addr *src,
|
|
|
|
const struct in6_addr *dst)
|
2016-05-18 11:15:41 +03:00
|
|
|
{
|
2018-04-27 13:01:33 +03:00
|
|
|
return get_ipaddr_diff((const u8_t *)src, (const u8_t *)dst, 16);
|
2016-05-18 11:15:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool is_proper_ipv6_address(struct net_if_addr *addr)
|
|
|
|
{
|
|
|
|
if (addr->is_used && addr->addr_state == NET_ADDR_PREFERRED &&
|
|
|
|
addr->address.family == AF_INET6 &&
|
2018-11-02 16:05:58 +02:00
|
|
|
!net_ipv6_is_ll_addr(&addr->address.in6_addr)) {
|
2016-05-18 11:15:41 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-12-07 15:15:31 +02:00
|
|
|
static struct in6_addr *net_if_ipv6_get_best_match(struct net_if *iface,
|
|
|
|
const struct in6_addr *dst,
|
|
|
|
u8_t *best_so_far)
|
2016-05-18 11:15:41 +03:00
|
|
|
{
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
|
2016-05-18 11:15:41 +03:00
|
|
|
struct in6_addr *src = NULL;
|
2018-01-11 16:06:53 +02:00
|
|
|
u8_t len;
|
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv6) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-05-18 11:15:41 +03:00
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!is_proper_ipv6_address(&ipv6->unicast[i])) {
|
2016-05-18 11:15:41 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-04-27 13:01:33 +03:00
|
|
|
len = get_diff_ipv6(dst, &ipv6->unicast[i].address.in6_addr);
|
2016-05-18 11:15:41 +03:00
|
|
|
if (len >= *best_so_far) {
|
2019-01-24 15:56:10 +01:00
|
|
|
/* Mesh local address can only be selected for the same
|
|
|
|
* subnet.
|
|
|
|
*/
|
|
|
|
if (ipv6->unicast[i].is_mesh_local && len < 64) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-05-18 11:15:41 +03:00
|
|
|
*best_so_far = len;
|
2018-01-19 19:01:23 +02:00
|
|
|
src = &ipv6->unicast[i].address.in6_addr;
|
2016-05-18 11:15:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return src;
|
|
|
|
}
|
2018-11-05 13:22:14 +02:00
|
|
|
#endif /* CONFIG_NET_IPV6 */
|
2016-05-18 11:15:41 +03:00
|
|
|
|
2016-06-02 16:57:03 +03:00
|
|
|
const struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *dst_iface,
|
2018-12-07 15:15:31 +02:00
|
|
|
const struct in6_addr *dst)
|
2016-05-18 11:15:41 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2016-05-18 11:15:41 +03:00
|
|
|
struct in6_addr *src = NULL;
|
2018-11-29 11:23:03 -08:00
|
|
|
u8_t best_match = 0U;
|
2016-05-18 11:15:41 +03:00
|
|
|
struct net_if *iface;
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (!net_ipv6_is_ll_addr(dst) && !net_ipv6_is_addr_mcast(dst)) {
|
2016-05-18 11:15:41 +03:00
|
|
|
|
|
|
|
for (iface = __net_if_start;
|
|
|
|
!dst_iface && iface != __net_if_end;
|
|
|
|
iface++) {
|
|
|
|
struct in6_addr *addr;
|
|
|
|
|
|
|
|
addr = net_if_ipv6_get_best_match(iface, dst,
|
|
|
|
&best_match);
|
|
|
|
if (addr) {
|
|
|
|
src = addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If caller has supplied interface, then use that */
|
|
|
|
if (dst_iface) {
|
|
|
|
src = net_if_ipv6_get_best_match(dst_iface, dst,
|
|
|
|
&best_match);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
for (iface = __net_if_start;
|
|
|
|
!dst_iface && iface != __net_if_end;
|
|
|
|
iface++) {
|
|
|
|
struct in6_addr *addr;
|
|
|
|
|
|
|
|
addr = net_if_ipv6_get_ll(iface, NET_ADDR_PREFERRED);
|
|
|
|
if (addr) {
|
|
|
|
src = addr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dst_iface) {
|
|
|
|
src = net_if_ipv6_get_ll(dst_iface, NET_ADDR_PREFERRED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!src) {
|
2016-11-08 21:12:21 +02:00
|
|
|
return net_ipv6_unspecified_address();
|
2016-05-18 11:15:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return src;
|
2018-11-05 13:22:14 +02:00
|
|
|
#else
|
|
|
|
return NULL;
|
|
|
|
#endif
|
2016-06-24 17:34:30 +02:00
|
|
|
}
|
|
|
|
|
2018-12-07 15:15:31 +02:00
|
|
|
struct net_if *net_if_ipv6_select_src_iface(const struct in6_addr *dst)
|
2018-08-07 11:28:49 +03:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-08-07 11:28:49 +03:00
|
|
|
const struct in6_addr *src;
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
src = net_if_ipv6_select_src_addr(NULL, dst);
|
|
|
|
if (src == net_ipv6_unspecified_address()) {
|
|
|
|
return net_if_get_default();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!net_if_ipv6_addr_lookup(src, &iface)) {
|
|
|
|
return net_if_get_default();
|
|
|
|
}
|
|
|
|
|
|
|
|
return iface;
|
2018-11-05 13:22:14 +02:00
|
|
|
#else
|
|
|
|
return NULL;
|
|
|
|
#endif
|
2018-08-07 11:28:49 +03:00
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
u32_t net_if_ipv6_calc_reachable_time(struct net_if_ipv6 *ipv6)
|
2016-06-24 17:34:30 +02:00
|
|
|
{
|
2018-11-05 13:22:14 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2017-12-02 21:18:50 -08:00
|
|
|
u32_t min_reachable, max_reachable;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
min_reachable = (MIN_RANDOM_NUMER * ipv6->base_reachable_time)
|
2017-12-02 21:18:50 -08:00
|
|
|
/ MIN_RANDOM_DENOM;
|
2018-01-19 19:01:23 +02:00
|
|
|
max_reachable = (MAX_RANDOM_NUMER * ipv6->base_reachable_time)
|
2017-12-02 21:18:50 -08:00
|
|
|
/ MAX_RANDOM_DENOM;
|
|
|
|
|
|
|
|
NET_DBG("min_reachable:%u max_reachable:%u", min_reachable,
|
|
|
|
max_reachable);
|
|
|
|
|
|
|
|
return min_reachable +
|
|
|
|
sys_rand32_get() % (max_reachable - min_reachable);
|
2018-11-05 13:22:14 +02:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
2016-06-24 17:34:30 +02:00
|
|
|
}
|
2017-02-09 09:57:06 +02:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
int net_if_config_ipv4_get(struct net_if *iface, struct net_if_ipv4 **ipv4)
|
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-01-19 19:01:23 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (iface->config.ip.ipv4) {
|
|
|
|
if (ipv4) {
|
|
|
|
*ipv4 = iface->config.ip.ipv4;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ipv4_addresses); i++) {
|
|
|
|
if (ipv4_addresses[i].iface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->config.ip.ipv4 = &ipv4_addresses[i].ipv4;
|
|
|
|
ipv4_addresses[i].iface = iface;
|
|
|
|
|
|
|
|
if (ipv4) {
|
|
|
|
*ipv4 = &ipv4_addresses[i].ipv4;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ESRCH;
|
2018-11-05 16:07:48 +02:00
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
2018-01-19 19:01:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int net_if_config_ipv4_put(struct net_if *iface)
|
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-01-19 19:01:23 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!iface->config.ip.ipv4) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ipv4_addresses); i++) {
|
|
|
|
if (ipv4_addresses[i].iface != iface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->config.ip.ipv4 = NULL;
|
|
|
|
ipv4_addresses[i].iface = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2018-11-05 16:07:48 +02:00
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
2018-01-19 19:01:23 +02:00
|
|
|
}
|
|
|
|
|
2016-06-24 17:34:30 +02:00
|
|
|
struct net_if_router *net_if_ipv4_router_lookup(struct net_if *iface,
|
|
|
|
struct in_addr *addr)
|
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2016-06-24 17:34:30 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_MAX_ROUTERS; i++) {
|
|
|
|
if (!routers[i].is_used ||
|
|
|
|
routers[i].address.family != AF_INET) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_ipv4_addr_cmp(&routers[i].address.in_addr, addr)) {
|
|
|
|
return &routers[i];
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2016-06-24 17:34:30 +02:00
|
|
|
|
2016-05-18 11:15:41 +03:00
|
|
|
return NULL;
|
2016-06-24 17:34:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct net_if_router *net_if_ipv4_router_add(struct net_if *iface,
|
|
|
|
struct in_addr *addr,
|
|
|
|
bool is_default,
|
2017-04-21 09:27:50 -05:00
|
|
|
u16_t lifetime)
|
2016-06-24 17:34:30 +02:00
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2016-06-24 17:34:30 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_NET_MAX_ROUTERS; i++) {
|
|
|
|
if (routers[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
routers[i].is_used = true;
|
|
|
|
routers[i].iface = iface;
|
|
|
|
routers[i].address.family = AF_INET;
|
|
|
|
routers[i].is_default = is_default;
|
|
|
|
|
|
|
|
if (lifetime) {
|
|
|
|
routers[i].is_infinite = false;
|
|
|
|
|
|
|
|
/* FIXME - add timer */
|
|
|
|
} else {
|
|
|
|
routers[i].is_infinite = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_ipaddr_copy(&routers[i].address.in_addr, addr);
|
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p router %s lifetime %u default %d "
|
|
|
|
"added",
|
2018-10-02 14:57:55 +03:00
|
|
|
i, iface, log_strdup(net_sprint_ipv4_addr(addr)),
|
|
|
|
lifetime, is_default);
|
2016-06-24 17:34:30 +02:00
|
|
|
|
2016-10-26 10:52:36 +03:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV4_ROUTER_ADD, iface);
|
|
|
|
|
2016-06-24 17:34:30 +02:00
|
|
|
return &routers[i];
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2016-06-24 17:34:30 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool net_if_ipv4_addr_mask_cmp(struct net_if *iface,
|
2018-10-23 17:43:22 +03:00
|
|
|
const struct in_addr *addr)
|
2016-06-24 17:34:30 +02:00
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
|
2018-01-11 16:06:53 +02:00
|
|
|
u32_t subnet;
|
2016-06-24 17:34:30 +02:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv4) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2018-10-23 17:43:22 +03:00
|
|
|
subnet = UNALIGNED_GET(&addr->s_addr) & ipv4->netmask.s_addr;
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-06-24 17:34:30 +02:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv4->unicast[i].is_used ||
|
|
|
|
ipv4->unicast[i].address.family != AF_INET) {
|
2018-01-11 16:06:53 +02:00
|
|
|
continue;
|
2016-06-24 17:34:30 +02:00
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2018-10-23 17:43:22 +03:00
|
|
|
if ((ipv4->unicast[i].address.in_addr.s_addr &
|
|
|
|
ipv4->netmask.s_addr) == subnet) {
|
2016-06-24 17:34:30 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2016-06-24 17:34:30 +02:00
|
|
|
|
|
|
|
return false;
|
2016-05-18 11:15:41 +03:00
|
|
|
}
|
|
|
|
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-10-23 17:49:32 +03:00
|
|
|
static bool ipv4_is_broadcast_address(struct net_if *iface,
|
|
|
|
const struct in_addr *addr)
|
|
|
|
{
|
|
|
|
struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
|
|
|
|
|
|
|
|
if (!ipv4) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!net_if_ipv4_addr_mask_cmp(iface, addr)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((UNALIGNED_GET(&addr->s_addr) & ~ipv4->netmask.s_addr) ==
|
|
|
|
~ipv4->netmask.s_addr) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2018-10-23 17:49:32 +03:00
|
|
|
|
|
|
|
bool net_if_ipv4_is_addr_bcast(struct net_if *iface,
|
|
|
|
const struct in_addr *addr)
|
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-10-23 17:49:32 +03:00
|
|
|
if (iface) {
|
|
|
|
return ipv4_is_broadcast_address(iface, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
ret = ipv4_is_broadcast_address(iface, addr);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2018-10-23 17:49:32 +03:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-12-07 15:15:31 +02:00
|
|
|
struct net_if *net_if_ipv4_select_src_iface(const struct in_addr *dst)
|
2018-01-31 16:09:38 +02:00
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-01-31 16:09:38 +02:00
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
ret = net_if_ipv4_addr_mask_cmp(iface, dst);
|
|
|
|
if (ret) {
|
|
|
|
return iface;
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2018-01-31 16:09:38 +02:00
|
|
|
|
|
|
|
return net_if_get_default();
|
|
|
|
}
|
|
|
|
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-04-27 13:01:33 +03:00
|
|
|
static u8_t get_diff_ipv4(const struct in_addr *src,
|
|
|
|
const struct in_addr *dst)
|
|
|
|
{
|
|
|
|
return get_ipaddr_diff((const u8_t *)src, (const u8_t *)dst, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool is_proper_ipv4_address(struct net_if_addr *addr)
|
|
|
|
{
|
|
|
|
if (addr->is_used && addr->addr_state == NET_ADDR_PREFERRED &&
|
|
|
|
addr->address.family == AF_INET &&
|
2018-11-02 16:05:58 +02:00
|
|
|
!net_ipv4_is_ll_addr(&addr->address.in_addr)) {
|
2018-04-27 13:01:33 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct in_addr *net_if_ipv4_get_best_match(struct net_if *iface,
|
2018-12-07 15:15:31 +02:00
|
|
|
const struct in_addr *dst,
|
2018-04-27 13:01:33 +03:00
|
|
|
u8_t *best_so_far)
|
|
|
|
{
|
|
|
|
struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
|
|
|
|
struct in_addr *src = NULL;
|
|
|
|
u8_t len;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!ipv4) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
|
|
|
if (!is_proper_ipv4_address(&ipv4->unicast[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = get_diff_ipv4(dst, &ipv4->unicast[i].address.in_addr);
|
|
|
|
if (len >= *best_so_far) {
|
|
|
|
*best_so_far = len;
|
|
|
|
src = &ipv4->unicast[i].address.in_addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return src;
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif /* CONFIG_NET_IPV4 */
|
2018-04-27 13:01:33 +03:00
|
|
|
|
|
|
|
struct in_addr *net_if_ipv4_get_ll(struct net_if *iface,
|
|
|
|
enum net_addr_state addr_state)
|
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-04-27 13:01:33 +03:00
|
|
|
struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!ipv4) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
|
|
|
if (!ipv4->unicast[i].is_used ||
|
|
|
|
(addr_state != NET_ADDR_ANY_STATE &&
|
|
|
|
ipv4->unicast[i].addr_state != addr_state) ||
|
|
|
|
ipv4->unicast[i].address.family != AF_INET) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (net_ipv4_is_ll_addr(&ipv4->unicast[i].address.in_addr)) {
|
2018-04-27 13:01:33 +03:00
|
|
|
return &ipv4->unicast[i].address.in_addr;
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2018-04-27 13:01:33 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct in_addr *net_if_ipv4_select_src_addr(struct net_if *dst_iface,
|
2018-12-07 15:15:31 +02:00
|
|
|
const struct in_addr *dst)
|
2018-04-27 13:01:33 +03:00
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-04-27 13:01:33 +03:00
|
|
|
struct in_addr *src = NULL;
|
2018-11-29 11:23:03 -08:00
|
|
|
u8_t best_match = 0U;
|
2018-04-27 13:01:33 +03:00
|
|
|
struct net_if *iface;
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (!net_ipv4_is_ll_addr(dst) && !net_ipv4_is_addr_mcast(dst)) {
|
2018-04-27 13:01:33 +03:00
|
|
|
|
|
|
|
for (iface = __net_if_start;
|
|
|
|
!dst_iface && iface != __net_if_end;
|
|
|
|
iface++) {
|
|
|
|
struct in_addr *addr;
|
|
|
|
|
|
|
|
addr = net_if_ipv4_get_best_match(iface, dst,
|
|
|
|
&best_match);
|
|
|
|
if (addr) {
|
|
|
|
src = addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If caller has supplied interface, then use that */
|
|
|
|
if (dst_iface) {
|
|
|
|
src = net_if_ipv4_get_best_match(dst_iface, dst,
|
|
|
|
&best_match);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
for (iface = __net_if_start;
|
|
|
|
!dst_iface && iface != __net_if_end;
|
|
|
|
iface++) {
|
|
|
|
struct in_addr *addr;
|
|
|
|
|
|
|
|
addr = net_if_ipv4_get_ll(iface, NET_ADDR_PREFERRED);
|
|
|
|
if (addr) {
|
|
|
|
src = addr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dst_iface) {
|
|
|
|
src = net_if_ipv4_get_ll(dst_iface, NET_ADDR_PREFERRED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!src) {
|
|
|
|
return net_ipv4_unspecified_address();
|
|
|
|
}
|
|
|
|
|
|
|
|
return src;
|
2018-11-05 16:07:48 +02:00
|
|
|
#else
|
|
|
|
return NULL;
|
|
|
|
#endif
|
2018-04-27 13:01:33 +03:00
|
|
|
}
|
|
|
|
|
2016-06-22 15:34:47 +03:00
|
|
|
struct net_if_addr *net_if_ipv4_addr_lookup(const struct in_addr *addr,
|
|
|
|
struct net_if **ret)
|
2016-05-17 14:13:17 +03:00
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2016-05-17 14:13:17 +03:00
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
|
2016-05-17 14:13:17 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv4) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-05-17 14:13:17 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv4->unicast[i].is_used ||
|
|
|
|
ipv4->unicast[i].address.family != AF_INET) {
|
2016-05-17 14:13:17 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-04-10 17:13:35 +03:00
|
|
|
if (UNALIGNED_GET(&addr->s4_addr32[0]) ==
|
2018-01-19 19:01:23 +02:00
|
|
|
ipv4->unicast[i].address.in_addr.s_addr) {
|
2016-06-22 15:34:47 +03:00
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
*ret = iface;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
return &ipv4->unicast[i];
|
2016-05-17 14:13:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2016-05-17 14:13:17 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2016-11-25 20:25:34 +02:00
|
|
|
static struct net_if_addr *ipv4_addr_find(struct net_if *iface,
|
|
|
|
struct in_addr *addr)
|
|
|
|
{
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
|
2016-11-25 20:25:34 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv4->unicast[i].is_used) {
|
2016-11-25 20:25:34 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (net_ipv4_addr_cmp(addr,
|
|
|
|
&ipv4->unicast[i].address.in_addr)) {
|
|
|
|
return &ipv4->unicast[i];
|
2016-11-25 20:25:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif /* CONFIG_NET_IPV4 */
|
2016-11-25 20:25:34 +02:00
|
|
|
|
2016-05-17 14:13:17 +03:00
|
|
|
struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
|
|
|
|
struct in_addr *addr,
|
|
|
|
enum net_addr_type addr_type,
|
2017-04-21 09:27:50 -05:00
|
|
|
u32_t vlifetime)
|
2016-05-17 14:13:17 +03:00
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2016-11-25 20:25:34 +02:00
|
|
|
struct net_if_addr *ifaddr;
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv4 *ipv4;
|
2016-05-17 14:13:17 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (net_if_config_ipv4_get(iface, &ipv4) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-25 20:25:34 +02:00
|
|
|
ifaddr = ipv4_addr_find(iface, addr);
|
|
|
|
if (ifaddr) {
|
2018-01-19 15:44:22 +02:00
|
|
|
/* TODO: should set addr_type/vlifetime */
|
2016-11-25 20:25:34 +02:00
|
|
|
return ifaddr;
|
|
|
|
}
|
|
|
|
|
2016-05-17 14:13:17 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_addr *cur = &ipv4->unicast[i];
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2018-01-19 15:44:22 +02:00
|
|
|
if (addr_type == NET_ADDR_DHCP
|
|
|
|
&& cur->addr_type == NET_ADDR_OVERRIDABLE) {
|
|
|
|
ifaddr = cur;
|
|
|
|
break;
|
2016-05-17 14:13:17 +03:00
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv4->unicast[i].is_used) {
|
2018-01-19 15:44:22 +02:00
|
|
|
ifaddr = cur;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ifaddr) {
|
|
|
|
ifaddr->is_used = true;
|
|
|
|
ifaddr->address.family = AF_INET;
|
|
|
|
ifaddr->address.in_addr.s4_addr32[0] =
|
2016-05-17 14:13:17 +03:00
|
|
|
addr->s4_addr32[0];
|
2018-01-19 15:44:22 +02:00
|
|
|
ifaddr->addr_type = addr_type;
|
2016-05-17 14:13:17 +03:00
|
|
|
|
2016-09-12 16:37:36 +03:00
|
|
|
/* Caller has to take care of timers and their expiry */
|
2016-05-17 14:13:17 +03:00
|
|
|
if (vlifetime) {
|
2018-01-19 15:44:22 +02:00
|
|
|
ifaddr->is_infinite = false;
|
2016-05-17 14:13:17 +03:00
|
|
|
} else {
|
2018-01-19 15:44:22 +02:00
|
|
|
ifaddr->is_infinite = true;
|
2016-05-17 14:13:17 +03:00
|
|
|
}
|
|
|
|
|
2016-09-12 16:37:36 +03:00
|
|
|
/**
|
|
|
|
* TODO: Handle properly PREFERRED/DEPRECATED state when
|
|
|
|
* address in use, expired and renewal state.
|
|
|
|
*/
|
2018-01-19 15:44:22 +02:00
|
|
|
ifaddr->addr_state = NET_ADDR_PREFERRED;
|
2016-09-12 16:37:36 +03:00
|
|
|
|
2016-05-17 14:13:17 +03:00
|
|
|
NET_DBG("[%d] interface %p address %s type %s added", i, iface,
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv4_addr(addr)),
|
2016-05-17 14:13:17 +03:00
|
|
|
net_addr_type2str(addr_type));
|
|
|
|
|
2016-10-26 10:52:36 +03:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV4_ADDR_ADD, iface);
|
|
|
|
|
2018-01-19 15:44:22 +02:00
|
|
|
return ifaddr;
|
2016-05-17 14:13:17 +03:00
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2016-05-17 14:13:17 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-06 11:51:30 +03:00
|
|
|
bool net_if_ipv4_addr_rm(struct net_if *iface, struct in_addr *addr)
|
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
|
2016-06-06 11:51:30 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv4) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2016-06-06 11:51:30 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv4->unicast[i].is_used) {
|
2016-06-06 11:51:30 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!net_ipv4_addr_cmp(&ipv4->unicast[i].address.in_addr,
|
|
|
|
addr)) {
|
2016-06-06 11:51:30 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
ipv4->unicast[i].is_used = false;
|
2016-06-06 11:51:30 +03:00
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p address %s removed",
|
2018-10-02 14:57:55 +03:00
|
|
|
i, iface, log_strdup(net_sprint_ipv4_addr(addr)));
|
2016-06-06 11:51:30 +03:00
|
|
|
|
2016-10-26 10:52:36 +03:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV4_ADDR_DEL, iface);
|
|
|
|
|
2016-06-06 11:51:30 +03:00
|
|
|
return true;
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2016-06-06 11:51:30 +03:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2017-09-21 23:06:59 +03:00
|
|
|
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2017-09-21 23:06:59 +03:00
|
|
|
static struct net_if_mcast_addr *ipv4_maddr_find(struct net_if *iface,
|
|
|
|
bool is_used,
|
|
|
|
const struct in_addr *addr)
|
|
|
|
{
|
2018-01-19 19:01:23 +02:00
|
|
|
struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
|
2017-09-21 23:06:59 +03:00
|
|
|
int i;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!ipv4) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-01-11 16:06:53 +02:00
|
|
|
|
2017-09-21 23:06:59 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if ((is_used && !ipv4->mcast[i].is_used) ||
|
|
|
|
(!is_used && ipv4->mcast[i].is_used)) {
|
2017-09-21 23:06:59 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr) {
|
2018-01-19 19:01:23 +02:00
|
|
|
if (!net_ipv4_addr_cmp(&ipv4->mcast[i].address.in_addr,
|
|
|
|
addr)) {
|
2017-09-21 23:06:59 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
return &ipv4->mcast[i];
|
2017-09-21 23:06:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2017-09-21 23:06:59 +03:00
|
|
|
|
|
|
|
struct net_if_mcast_addr *net_if_ipv4_maddr_add(struct net_if *iface,
|
|
|
|
const struct in_addr *addr)
|
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2017-09-21 23:06:59 +03:00
|
|
|
struct net_if_mcast_addr *maddr;
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
if (net_if_config_ipv4_get(iface, NULL) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-11-02 16:05:58 +02:00
|
|
|
if (!net_ipv4_is_addr_mcast(addr)) {
|
2017-09-21 23:06:59 +03:00
|
|
|
NET_DBG("Address %s is not a multicast address.",
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv4_addr(addr)));
|
2017-09-21 23:06:59 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
maddr = ipv4_maddr_find(iface, false, NULL);
|
|
|
|
if (maddr) {
|
|
|
|
maddr->is_used = true;
|
|
|
|
maddr->address.family = AF_INET;
|
|
|
|
maddr->address.in_addr.s4_addr32[0] = addr->s4_addr32[0];
|
|
|
|
|
|
|
|
NET_DBG("interface %p address %s added", iface,
|
2018-10-02 14:57:55 +03:00
|
|
|
log_strdup(net_sprint_ipv4_addr(addr)));
|
2017-09-21 23:06:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return maddr;
|
2018-11-05 16:07:48 +02:00
|
|
|
#else
|
|
|
|
return NULL;
|
|
|
|
#endif
|
2017-09-21 23:06:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool net_if_ipv4_maddr_rm(struct net_if *iface, const struct in_addr *addr)
|
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2017-09-21 23:06:59 +03:00
|
|
|
struct net_if_mcast_addr *maddr;
|
|
|
|
|
|
|
|
maddr = ipv4_maddr_find(iface, true, addr);
|
|
|
|
if (maddr) {
|
|
|
|
maddr->is_used = false;
|
|
|
|
|
|
|
|
NET_DBG("interface %p address %s removed",
|
2018-10-02 14:57:55 +03:00
|
|
|
iface, log_strdup(net_sprint_ipv4_addr(addr)));
|
2017-09-21 23:06:59 +03:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2017-09-21 23:06:59 +03:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct net_if_mcast_addr *net_if_ipv4_maddr_lookup(const struct in_addr *maddr,
|
|
|
|
struct net_if **ret)
|
|
|
|
{
|
2018-11-05 16:07:48 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2017-09-21 23:06:59 +03:00
|
|
|
struct net_if_mcast_addr *addr;
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
|
|
|
if (ret && *ret && iface != *ret) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr = ipv4_maddr_find(iface, true, maddr);
|
|
|
|
if (addr) {
|
|
|
|
if (ret) {
|
|
|
|
*ret = iface;
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
}
|
2018-11-05 16:07:48 +02:00
|
|
|
#endif
|
2017-09-21 23:06:59 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-06-07 10:16:58 +03:00
|
|
|
|
2018-08-07 13:05:55 +03:00
|
|
|
struct net_if *net_if_select_src_iface(const struct sockaddr *dst)
|
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
if (!dst) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) && dst->sa_family == AF_INET6) {
|
|
|
|
iface = net_if_ipv6_select_src_iface(&net_sin6(dst)->sin6_addr);
|
|
|
|
if (!iface) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
return iface;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV4) && dst->sa_family == AF_INET) {
|
|
|
|
iface = net_if_ipv4_select_src_iface(&net_sin(dst)->sin_addr);
|
|
|
|
if (!iface) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
return iface;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return net_if_get_default();
|
|
|
|
}
|
|
|
|
|
2018-07-23 14:03:11 +03:00
|
|
|
enum net_verdict net_if_recv_data(struct net_if *iface, struct net_pkt *pkt)
|
|
|
|
{
|
|
|
|
if (IS_ENABLED(CONFIG_NET_PROMISCUOUS_MODE) &&
|
|
|
|
net_if_is_promisc(iface)) {
|
|
|
|
/* If the packet is not for us and the promiscuous
|
|
|
|
* mode is enabled, then increase the ref count so
|
|
|
|
* that net_core.c:processing_data() will not free it.
|
|
|
|
* The promiscuous mode handler must free the packet
|
|
|
|
* after it has finished working with it.
|
|
|
|
*
|
|
|
|
* If packet is for us, then NET_CONTINUE is returned.
|
|
|
|
* In this case we must clone the packet, as the packet
|
|
|
|
* could be manipulated by other part of the stack.
|
|
|
|
*/
|
|
|
|
enum net_verdict verdict;
|
|
|
|
struct net_pkt *new_pkt;
|
|
|
|
|
|
|
|
/* This protects pkt so that it will not be freed by L2 recv()
|
|
|
|
*/
|
|
|
|
net_pkt_ref(pkt);
|
|
|
|
|
|
|
|
verdict = net_if_l2(iface)->recv(iface, pkt);
|
|
|
|
if (verdict == NET_CONTINUE) {
|
2019-02-08 09:26:29 +01:00
|
|
|
new_pkt = net_pkt_clone(pkt, K_NO_WAIT);
|
2018-07-23 14:03:11 +03:00
|
|
|
} else {
|
|
|
|
new_pkt = net_pkt_ref(pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_promisc_mode_input(new_pkt) == NET_DROP) {
|
|
|
|
net_pkt_unref(new_pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
net_pkt_unref(pkt);
|
|
|
|
|
|
|
|
return verdict;
|
|
|
|
}
|
|
|
|
|
|
|
|
return net_if_l2(iface)->recv(iface, pkt);
|
|
|
|
}
|
|
|
|
|
2016-09-28 14:18:55 +03:00
|
|
|
void net_if_register_link_cb(struct net_if_link_cb *link,
|
|
|
|
net_if_link_callback_t cb)
|
|
|
|
{
|
|
|
|
sys_slist_find_and_remove(&link_callbacks, &link->node);
|
|
|
|
sys_slist_prepend(&link_callbacks, &link->node);
|
|
|
|
|
|
|
|
link->cb = cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_unregister_link_cb(struct net_if_link_cb *link)
|
|
|
|
{
|
|
|
|
sys_slist_find_and_remove(&link_callbacks, &link->node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_call_link_cb(struct net_if *iface, struct net_linkaddr *lladdr,
|
|
|
|
int status)
|
|
|
|
{
|
2017-02-08 16:08:23 +02:00
|
|
|
struct net_if_link_cb *link, *tmp;
|
2016-09-28 14:18:55 +03:00
|
|
|
|
2017-02-08 16:08:23 +02:00
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&link_callbacks, link, tmp, node) {
|
2016-09-28 14:18:55 +03:00
|
|
|
link->cb(iface, lladdr, status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-06 10:57:13 +02:00
|
|
|
static bool need_calc_checksum(struct net_if *iface, enum ethernet_hw_caps caps)
|
2018-03-14 10:55:19 +02:00
|
|
|
{
|
|
|
|
#if defined(CONFIG_NET_L2_ETHERNET)
|
2018-01-11 16:06:53 +02:00
|
|
|
if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
|
2018-03-14 10:55:19 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return !(net_eth_get_hw_capabilities(iface) & caps);
|
|
|
|
#else
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool net_if_need_calc_tx_checksum(struct net_if *iface)
|
|
|
|
{
|
2018-04-06 10:57:13 +02:00
|
|
|
return need_calc_checksum(iface, ETHERNET_HW_TX_CHKSUM_OFFLOAD);
|
2018-03-14 10:55:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool net_if_need_calc_rx_checksum(struct net_if *iface)
|
|
|
|
{
|
2018-04-06 10:57:13 +02:00
|
|
|
return need_calc_checksum(iface, ETHERNET_HW_RX_CHKSUM_OFFLOAD);
|
2018-03-14 10:55:19 +02:00
|
|
|
}
|
|
|
|
|
2019-02-14 11:37:23 +02:00
|
|
|
struct net_if *net_if_get_by_index(int index)
|
2016-06-22 15:42:55 +03:00
|
|
|
{
|
2019-02-14 11:37:23 +02:00
|
|
|
if (index <= 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (&__net_if_start[index - 1] >= __net_if_end) {
|
2016-06-22 15:42:55 +03:00
|
|
|
NET_DBG("Index %d is too large", index);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-02-14 11:37:23 +02:00
|
|
|
return &__net_if_start[index - 1];
|
2016-06-22 15:42:55 +03:00
|
|
|
}
|
|
|
|
|
2019-02-14 11:37:23 +02:00
|
|
|
int net_if_get_by_iface(struct net_if *iface)
|
2016-06-22 15:42:55 +03:00
|
|
|
{
|
2019-02-14 11:37:23 +02:00
|
|
|
if (!(iface >= __net_if_start && iface < __net_if_end)) {
|
|
|
|
return -1;
|
|
|
|
}
|
2016-06-22 15:42:55 +03:00
|
|
|
|
2019-02-14 11:37:23 +02:00
|
|
|
return (iface - __net_if_start) + 1;
|
2016-06-22 15:42:55 +03:00
|
|
|
}
|
|
|
|
|
2016-10-11 18:28:09 +03:00
|
|
|
void net_if_foreach(net_if_cb_t cb, void *user_data)
|
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
|
|
|
cb(iface, user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-19 14:18:10 +02:00
|
|
|
int net_if_up(struct net_if *iface)
|
|
|
|
{
|
2016-12-21 13:33:09 +02:00
|
|
|
int status;
|
|
|
|
|
2016-12-19 14:18:10 +02:00
|
|
|
NET_DBG("iface %p", iface);
|
|
|
|
|
2018-01-11 16:06:53 +02:00
|
|
|
if (atomic_test_bit(iface->if_dev->flags, NET_IF_UP)) {
|
2016-12-19 14:18:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-02-21 15:24:07 -08:00
|
|
|
#if defined(CONFIG_NET_OFFLOAD)
|
|
|
|
if (net_if_is_ip_offloaded(iface)) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-12-21 13:33:09 +02:00
|
|
|
/* If the L2 does not support enable just set the flag */
|
2018-01-11 16:06:53 +02:00
|
|
|
if (!net_if_l2(iface)->enable) {
|
2016-12-21 13:33:09 +02:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Notify L2 to enable the interface */
|
2018-01-11 16:06:53 +02:00
|
|
|
status = net_if_l2(iface)->enable(iface, true);
|
2016-12-21 13:33:09 +02:00
|
|
|
if (status < 0) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2018-11-02 12:51:14 +02:00
|
|
|
/* In many places it's assumed that link address was set with
|
|
|
|
* net_if_set_link_addr(). Better check that now.
|
|
|
|
*/
|
|
|
|
NET_ASSERT(net_if_get_link_addr(iface)->addr != NULL);
|
|
|
|
|
2018-01-11 16:06:53 +02:00
|
|
|
atomic_set_bit(iface->if_dev->flags, NET_IF_UP);
|
2016-12-19 14:18:10 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV6_DAD)
|
|
|
|
NET_DBG("Starting DAD for iface %p", iface);
|
|
|
|
net_if_start_dad(iface);
|
2017-02-09 09:57:06 +02:00
|
|
|
#else
|
2018-08-06 16:59:33 +03:00
|
|
|
join_mcast_nodes(iface,
|
|
|
|
&iface->config.ip.ipv6->mcast[0].address.in6_addr);
|
2018-01-11 16:06:53 +02:00
|
|
|
#endif /* CONFIG_NET_IPV6_DAD */
|
2016-12-19 14:18:10 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV6_ND)
|
|
|
|
NET_DBG("Starting ND/RS for iface %p", iface);
|
|
|
|
net_if_start_rs(iface);
|
|
|
|
#endif
|
|
|
|
|
2018-07-30 18:28:35 +03:00
|
|
|
#if defined(CONFIG_NET_IPV4_AUTO)
|
|
|
|
net_ipv4_autoconf_start(iface);
|
|
|
|
#endif
|
|
|
|
|
2017-01-04 15:54:20 +01:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IF_UP, iface);
|
|
|
|
|
2016-12-19 14:18:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-02-19 10:36:06 +02:00
|
|
|
void net_if_carrier_down(struct net_if *iface)
|
|
|
|
{
|
|
|
|
NET_DBG("iface %p", iface);
|
|
|
|
|
2018-01-11 16:06:53 +02:00
|
|
|
atomic_clear_bit(iface->if_dev->flags, NET_IF_UP);
|
2018-02-19 10:36:06 +02:00
|
|
|
|
2018-07-30 18:28:35 +03:00
|
|
|
#if defined(CONFIG_NET_IPV4_AUTO)
|
|
|
|
net_ipv4_autoconf_reset(iface);
|
|
|
|
#endif
|
|
|
|
|
2018-02-19 10:36:06 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IF_DOWN, iface);
|
|
|
|
}
|
|
|
|
|
2016-12-19 14:18:10 +02:00
|
|
|
int net_if_down(struct net_if *iface)
|
|
|
|
{
|
2016-12-21 13:33:09 +02:00
|
|
|
int status;
|
|
|
|
|
2016-12-19 14:18:10 +02:00
|
|
|
NET_DBG("iface %p", iface);
|
|
|
|
|
2017-02-10 09:36:09 +02:00
|
|
|
leave_mcast_all(iface);
|
2017-02-09 09:57:06 +02:00
|
|
|
|
2018-02-21 15:24:07 -08:00
|
|
|
#if defined(CONFIG_NET_OFFLOAD)
|
|
|
|
if (net_if_is_ip_offloaded(iface)) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-01-24 15:25:37 +00:00
|
|
|
/* If the L2 does not support enable just clear the flag */
|
2018-01-11 16:06:53 +02:00
|
|
|
if (!net_if_l2(iface)->enable) {
|
2016-12-21 13:33:09 +02:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Notify L2 to disable the interface */
|
2018-01-11 16:06:53 +02:00
|
|
|
status = net_if_l2(iface)->enable(iface, false);
|
2016-12-21 13:33:09 +02:00
|
|
|
if (status < 0) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2018-01-11 16:06:53 +02:00
|
|
|
atomic_clear_bit(iface->if_dev->flags, NET_IF_UP);
|
2016-12-19 14:18:10 +02:00
|
|
|
|
2017-01-04 15:54:20 +01:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IF_DOWN, iface);
|
|
|
|
|
2016-12-19 14:18:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-12 16:30:51 +02:00
|
|
|
static int promisc_mode_set(struct net_if *iface, bool enable)
|
2018-07-20 16:42:54 +03:00
|
|
|
{
|
2018-08-06 17:46:37 +03:00
|
|
|
enum net_l2_flags l2_flags = 0;
|
2018-07-20 16:42:54 +03:00
|
|
|
|
|
|
|
NET_ASSERT(iface);
|
|
|
|
|
2018-08-06 17:46:37 +03:00
|
|
|
if (net_if_l2(iface)->get_flags) {
|
|
|
|
l2_flags = net_if_l2(iface)->get_flags(iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(l2_flags & NET_L2_PROMISC_MODE)) {
|
2018-07-20 16:42:54 +03:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2018-08-06 17:46:37 +03:00
|
|
|
#if defined(CONFIG_NET_L2_ETHERNET)
|
|
|
|
if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
|
2018-11-12 16:30:51 +02:00
|
|
|
int ret = net_eth_promisc_mode(iface, enable);
|
|
|
|
|
2018-08-06 17:46:37 +03:00
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2018-07-20 16:42:54 +03:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
|
2018-11-12 16:30:51 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int net_if_set_promisc(struct net_if *iface)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = promisc_mode_set(iface, true);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-07-20 16:42:54 +03:00
|
|
|
ret = atomic_test_and_set_bit(iface->if_dev->flags, NET_IF_PROMISC);
|
|
|
|
if (ret) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_unset_promisc(struct net_if *iface)
|
|
|
|
{
|
2018-11-12 16:30:51 +02:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = promisc_mode_set(iface, false);
|
|
|
|
if (ret < 0) {
|
|
|
|
return;
|
|
|
|
}
|
2018-07-20 16:42:54 +03:00
|
|
|
|
|
|
|
atomic_clear_bit(iface->if_dev->flags, NET_IF_PROMISC);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool net_if_is_promisc(struct net_if *iface)
|
|
|
|
{
|
|
|
|
NET_ASSERT(iface);
|
|
|
|
|
|
|
|
return atomic_test_bit(iface->if_dev->flags, NET_IF_PROMISC);
|
|
|
|
}
|
|
|
|
|
2018-01-24 15:20:21 +02:00
|
|
|
#if defined(CONFIG_NET_PKT_TIMESTAMP)
|
|
|
|
static void net_tx_ts_thread(void)
|
|
|
|
{
|
|
|
|
struct net_pkt *pkt;
|
|
|
|
|
|
|
|
NET_DBG("Starting TX timestamp callback thread");
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
pkt = k_fifo_get(&tx_ts_queue, K_FOREVER);
|
|
|
|
if (pkt) {
|
|
|
|
net_if_call_timestamp_cb(pkt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_register_timestamp_cb(struct net_if_timestamp_cb *handle,
|
2018-06-04 14:23:12 +02:00
|
|
|
struct net_pkt *pkt,
|
2018-01-24 15:20:21 +02:00
|
|
|
struct net_if *iface,
|
|
|
|
net_if_timestamp_callback_t cb)
|
|
|
|
{
|
|
|
|
sys_slist_find_and_remove(×tamp_callbacks, &handle->node);
|
|
|
|
sys_slist_prepend(×tamp_callbacks, &handle->node);
|
|
|
|
|
|
|
|
handle->iface = iface;
|
|
|
|
handle->cb = cb;
|
2018-06-04 14:23:12 +02:00
|
|
|
handle->pkt = pkt;
|
2018-01-24 15:20:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_unregister_timestamp_cb(struct net_if_timestamp_cb *handle)
|
|
|
|
{
|
|
|
|
sys_slist_find_and_remove(×tamp_callbacks, &handle->node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_call_timestamp_cb(struct net_pkt *pkt)
|
|
|
|
{
|
|
|
|
sys_snode_t *sn, *sns;
|
|
|
|
|
|
|
|
SYS_SLIST_FOR_EACH_NODE_SAFE(×tamp_callbacks, sn, sns) {
|
|
|
|
struct net_if_timestamp_cb *handle =
|
|
|
|
CONTAINER_OF(sn, struct net_if_timestamp_cb, node);
|
|
|
|
|
2018-06-04 14:23:12 +02:00
|
|
|
if (((handle->iface == NULL) ||
|
|
|
|
(handle->iface == net_pkt_iface(pkt))) &&
|
|
|
|
(handle->pkt == NULL || handle->pkt == pkt)) {
|
2018-01-24 15:20:21 +02:00
|
|
|
handle->cb(pkt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_add_tx_timestamp(struct net_pkt *pkt)
|
|
|
|
{
|
|
|
|
k_fifo_put(&tx_ts_queue, pkt);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_PKT_TIMESTAMP */
|
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
void net_if_init(void)
|
2016-05-02 09:02:04 +02:00
|
|
|
{
|
|
|
|
struct net_if *iface;
|
2019-02-07 15:00:44 +02:00
|
|
|
int if_count;
|
|
|
|
#if defined(CONFIG_NET_IPV4) || defined(CONFIG_NET_IPV6)
|
|
|
|
int i;
|
|
|
|
#endif
|
2016-05-02 09:02:04 +02:00
|
|
|
|
2016-06-21 12:10:13 +02:00
|
|
|
NET_DBG("");
|
|
|
|
|
2018-02-07 15:00:08 +02:00
|
|
|
net_tc_tx_init();
|
|
|
|
|
2018-08-17 17:04:10 +03:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
|
|
|
k_delayed_work_init(&address_lifetime_timer, address_lifetime_timeout);
|
2018-08-27 14:02:09 +03:00
|
|
|
k_delayed_work_init(&prefix_lifetime_timer, prefix_lifetime_timeout);
|
2018-08-17 17:04:10 +03:00
|
|
|
#endif
|
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
for (iface = __net_if_start, if_count = 0; iface != __net_if_end;
|
|
|
|
iface++, if_count++) {
|
2017-03-08 09:30:03 +01:00
|
|
|
init_iface(iface);
|
2018-01-19 19:01:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (iface == __net_if_start) {
|
|
|
|
NET_ERR("There is no network interface to work with!");
|
|
|
|
return;
|
|
|
|
}
|
2016-05-19 11:26:06 +03:00
|
|
|
|
2016-06-14 09:31:34 +03:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2018-01-19 19:01:23 +02:00
|
|
|
if (if_count > ARRAY_SIZE(ipv4_addresses)) {
|
|
|
|
NET_WARN("You have %lu IPv4 net_if addresses but %d "
|
|
|
|
"network interfaces", ARRAY_SIZE(ipv4_addresses),
|
|
|
|
if_count);
|
|
|
|
NET_WARN("Consider increasing CONFIG_NET_IF_MAX_IPV4_COUNT "
|
|
|
|
"value.");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ipv4_addresses); i++) {
|
|
|
|
ipv4_addresses[i].ipv4.ttl = CONFIG_NET_INITIAL_TTL;
|
|
|
|
}
|
2016-06-14 09:31:34 +03:00
|
|
|
#endif
|
|
|
|
|
2016-05-19 11:26:06 +03:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2018-01-19 19:01:23 +02:00
|
|
|
if (if_count > ARRAY_SIZE(ipv6_addresses)) {
|
|
|
|
NET_WARN("You have %lu IPv6 net_if addresses but %d "
|
|
|
|
"network interfaces", ARRAY_SIZE(ipv6_addresses),
|
|
|
|
if_count);
|
|
|
|
NET_WARN("Consider increasing CONFIG_NET_IF_MAX_IPV6_COUNT "
|
|
|
|
"value.");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ipv6_addresses); i++) {
|
|
|
|
ipv6_addresses[i].ipv6.hop_limit = CONFIG_NET_INITIAL_HOP_LIMIT;
|
|
|
|
ipv6_addresses[i].ipv6.base_reachable_time = REACHABLE_TIME;
|
2016-06-07 10:16:58 +03:00
|
|
|
|
2018-01-19 19:01:23 +02:00
|
|
|
net_if_ipv6_set_reachable_time(&ipv6_addresses[i].ipv6);
|
2017-03-15 11:25:27 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV6_ND)
|
2018-01-19 19:01:23 +02:00
|
|
|
k_delayed_work_init(&ipv6_addresses[i].ipv6.rs_timer,
|
2018-01-11 16:06:53 +02:00
|
|
|
rs_timeout);
|
2016-05-19 11:26:06 +03:00
|
|
|
#endif
|
2017-05-03 10:14:42 +02:00
|
|
|
}
|
2018-01-19 19:01:23 +02:00
|
|
|
#endif /* CONFIG_NET_IPV6 */
|
2018-01-19 12:24:33 +02:00
|
|
|
|
2018-01-24 15:20:21 +02:00
|
|
|
#if defined(CONFIG_NET_PKT_TIMESTAMP)
|
|
|
|
k_thread_create(&tx_thread_ts, tx_ts_stack,
|
|
|
|
K_THREAD_STACK_SIZEOF(tx_ts_stack),
|
|
|
|
(k_thread_entry_t)net_tx_ts_thread,
|
|
|
|
NULL, NULL, NULL, K_PRIO_COOP(1), 0, 0);
|
2018-10-12 21:17:19 +03:00
|
|
|
k_thread_name_set(&tx_thread_ts, "tx_tstamp");
|
2018-01-24 15:20:21 +02:00
|
|
|
#endif /* CONFIG_NET_PKT_TIMESTAMP */
|
|
|
|
|
2018-01-19 12:24:33 +02:00
|
|
|
#if defined(CONFIG_NET_VLAN)
|
|
|
|
/* Make sure that we do not have too many network interfaces
|
|
|
|
* compared to the number of VLAN interfaces.
|
|
|
|
*/
|
|
|
|
for (iface = __net_if_start, if_count = 0;
|
|
|
|
iface != __net_if_end; iface++) {
|
|
|
|
if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
|
|
|
|
if_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (if_count > CONFIG_NET_VLAN_COUNT) {
|
|
|
|
NET_WARN("You have configured only %d VLAN interfaces"
|
|
|
|
" but you have %d network interfaces.",
|
|
|
|
CONFIG_NET_VLAN_COUNT, if_count);
|
|
|
|
}
|
|
|
|
#endif
|
2017-03-13 15:50:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_post_init(void)
|
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
NET_DBG("");
|
|
|
|
|
|
|
|
/* After TX is running, attempt to bring the interface up */
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
|
|
|
net_if_up(iface);
|
|
|
|
}
|
2016-05-02 09:02:04 +02:00
|
|
|
}
|