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
|
|
|
*/
|
|
|
|
|
2016-08-24 11:58:29 +02:00
|
|
|
#if defined(CONFIG_NET_DEBUG_IF)
|
2016-05-09 15:43:06 +03:00
|
|
|
#define SYS_LOG_DOMAIN "net/if"
|
2016-12-15 13:55:01 +01:00
|
|
|
#define NET_LOG_ENABLED 1
|
2016-05-09 15:43:06 +03:00
|
|
|
#endif
|
|
|
|
|
2016-05-02 09:02:04 +02:00
|
|
|
#include <init.h>
|
2016-11-09 17:44:21 +01:00
|
|
|
#include <kernel.h>
|
2016-05-03 09:34:45 +03:00
|
|
|
#include <sections.h>
|
2016-05-09 15:43:06 +03:00
|
|
|
#include <string.h>
|
|
|
|
#include <net/net_core.h>
|
2016-05-19 12:15:06 +03:00
|
|
|
#include <net/nbuf.h>
|
|
|
|
#include <net/net_if.h>
|
2016-05-23 17:36:55 +03:00
|
|
|
#include <net/arp.h>
|
2016-09-29 18:33:03 +02:00
|
|
|
#include <net/net_mgmt.h>
|
2016-05-19 12:15:06 +03:00
|
|
|
|
|
|
|
#include "net_private.h"
|
2016-06-07 16:34:49 +03:00
|
|
|
#include "ipv6.h"
|
2016-10-26 13:57:30 +03:00
|
|
|
#include "rpl.h"
|
2016-05-02 09:02:04 +02:00
|
|
|
|
2016-12-13 14:50:31 +01:00
|
|
|
#include "net_stats.h"
|
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
#define REACHABLE_TIME (30 * MSEC_PER_SEC) /* in ms */
|
2016-06-07 10:16:58 +03:00
|
|
|
#define MIN_RANDOM_FACTOR (1/2)
|
|
|
|
#define MAX_RANDOM_FACTOR (3/2)
|
|
|
|
|
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[];
|
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
static struct net_if_router routers[CONFIG_NET_MAX_ROUTERS];
|
|
|
|
|
2016-09-28 14:18:55 +03:00
|
|
|
/* We keep track of the link callbacks in this list.
|
|
|
|
*/
|
|
|
|
static sys_slist_t link_callbacks;
|
|
|
|
|
2016-12-15 13:55:01 +01:00
|
|
|
#if defined(CONFIG_NET_DEBUG_IF)
|
2016-12-06 19:20:03 +02:00
|
|
|
#define debug_check_packet(buf) \
|
|
|
|
{ \
|
|
|
|
size_t len = net_buf_frags_len(buf->frags); \
|
|
|
|
\
|
|
|
|
NET_DBG("Processing (buf %p, data len %zu) network packet", \
|
|
|
|
buf, len); \
|
|
|
|
\
|
|
|
|
NET_ASSERT(buf->frags && len); \
|
2016-06-08 14:35:07 +03:00
|
|
|
} while (0)
|
|
|
|
#else
|
|
|
|
#define debug_check_packet(...)
|
2016-12-15 13:55:01 +01:00
|
|
|
#endif /* CONFIG_NET_DEBUG_IF */
|
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)
|
|
|
|
{
|
|
|
|
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) {
|
|
|
|
net_stats_update_udp_sent();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
static void net_if_tx_thread(struct net_if *iface)
|
2016-05-03 09:34:45 +03:00
|
|
|
{
|
2016-12-20 10:25:40 +00:00
|
|
|
const struct net_if_api *api = iface->dev->driver_api;
|
2016-05-19 12:15:06 +03:00
|
|
|
|
2016-06-01 10:35:00 +03:00
|
|
|
NET_ASSERT(api && api->init && api->send);
|
|
|
|
|
2016-12-06 19:20:03 +02:00
|
|
|
NET_DBG("Starting TX thread (stack %zu bytes) for driver %p queue %p",
|
2016-11-09 17:44:21 +01:00
|
|
|
sizeof(iface->tx_stack), api, &iface->tx_queue);
|
2016-06-01 10:35:00 +03:00
|
|
|
|
|
|
|
api->init(iface);
|
2016-12-19 14:18:10 +02:00
|
|
|
/* Attempt to bring the interface up */
|
|
|
|
net_if_up(iface);
|
2016-05-03 09:34:45 +03:00
|
|
|
|
|
|
|
while (1) {
|
2016-09-28 14:18:55 +03:00
|
|
|
struct net_linkaddr *dst;
|
2016-09-28 14:26:27 +03:00
|
|
|
struct net_context *context;
|
|
|
|
void *context_token;
|
2016-05-03 09:34:45 +03:00
|
|
|
struct net_buf *buf;
|
2016-09-28 14:18:55 +03:00
|
|
|
int status;
|
2017-02-03 12:36:16 +02:00
|
|
|
#if defined(CONFIG_NET_STATISTICS)
|
|
|
|
size_t pkt_len;
|
|
|
|
#endif
|
2016-05-03 09:34:45 +03:00
|
|
|
/* Get next packet from application - wait if necessary */
|
2016-10-18 23:24:51 +03:00
|
|
|
buf = net_buf_get(&iface->tx_queue, K_FOREVER);
|
2016-05-03 09:34:45 +03:00
|
|
|
|
2016-06-08 14:35:07 +03:00
|
|
|
debug_check_packet(buf);
|
2016-05-19 12:15:06 +03:00
|
|
|
|
2016-09-28 14:18:55 +03:00
|
|
|
dst = net_nbuf_ll_dst(buf);
|
2016-09-28 14:26:27 +03:00
|
|
|
context = net_nbuf_context(buf);
|
|
|
|
context_token = net_nbuf_token(buf);
|
2016-09-28 14:18:55 +03:00
|
|
|
|
2016-12-19 14:18:10 +02:00
|
|
|
if (atomic_test_bit(iface->flags, NET_IF_UP)) {
|
2017-02-03 12:36:16 +02:00
|
|
|
#if defined(CONFIG_NET_STATISTICS)
|
|
|
|
pkt_len = net_buf_frags_len(buf);
|
|
|
|
#endif
|
2016-12-19 14:18:10 +02:00
|
|
|
status = api->send(iface, buf);
|
|
|
|
} else {
|
|
|
|
/* Drop packet if interface is not up */
|
|
|
|
NET_WARN("iface %p is down", iface);
|
|
|
|
status = -ENETDOWN;
|
|
|
|
}
|
|
|
|
|
2016-09-28 14:18:55 +03:00
|
|
|
if (status < 0) {
|
2016-05-19 12:15:06 +03:00
|
|
|
net_nbuf_unref(buf);
|
2017-02-03 12:36:16 +02:00
|
|
|
} else {
|
|
|
|
net_stats_update_bytes_sent(pkt_len);
|
2016-05-19 12:15:06 +03:00
|
|
|
}
|
2016-05-03 09:34:45 +03:00
|
|
|
|
2016-09-28 14:26:27 +03: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);
|
|
|
|
}
|
|
|
|
|
2016-09-28 14:18:55 +03:00
|
|
|
net_if_call_link_cb(iface, dst, status);
|
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
net_analyze_stack("TX thread", iface->tx_stack,
|
|
|
|
sizeof(iface->tx_stack));
|
2016-07-06 16:12:02 +03:00
|
|
|
net_nbuf_print();
|
2016-06-08 14:16:17 +03:00
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
k_yield();
|
2016-05-03 09:34:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void init_tx_queue(struct net_if *iface)
|
|
|
|
{
|
2016-06-21 12:10:13 +02:00
|
|
|
NET_DBG("On iface %p", iface);
|
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
k_fifo_init(&iface->tx_queue);
|
2016-05-03 09:34:45 +03:00
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
k_thread_spawn(iface->tx_stack, sizeof(iface->tx_stack),
|
|
|
|
(k_thread_entry_t)net_if_tx_thread,
|
|
|
|
iface, NULL, NULL, K_PRIO_COOP(7), 0, 0);
|
2016-05-03 09:34:45 +03:00
|
|
|
}
|
|
|
|
|
2016-06-29 16:39:06 +03:00
|
|
|
enum net_verdict net_if_send_data(struct net_if *iface, struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct net_context *context = net_nbuf_context(buf);
|
2016-09-28 14:18:55 +03:00
|
|
|
struct net_linkaddr *dst = net_nbuf_ll_dst(buf);
|
2016-06-29 16:39:06 +03:00
|
|
|
void *token = net_nbuf_token(buf);
|
|
|
|
enum net_verdict verdict;
|
2016-12-19 14:18:10 +02:00
|
|
|
int status = -EIO;
|
2016-06-29 16:39:06 +03:00
|
|
|
|
2017-01-31 16:43:43 +02:00
|
|
|
if (!atomic_test_bit(iface->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:
|
|
|
|
* https://jira.zephyrproject.org/browse/ZEP-1656
|
2017-01-31 16:43:43 +02:00
|
|
|
*/
|
2017-02-02 11:58:15 +02:00
|
|
|
if (!atomic_test_bit(iface->flags, NET_IF_POINTOPOINT) &&
|
|
|
|
!net_nbuf_ll_src(buf)->addr) {
|
2017-01-31 16:43:43 +02:00
|
|
|
net_nbuf_ll_src(buf)->addr = net_nbuf_ll_if(buf)->addr;
|
|
|
|
net_nbuf_ll_src(buf)->len = net_nbuf_ll_if(buf)->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV6)
|
|
|
|
/* If the ll dst address is not set check if it is present in the nbr
|
|
|
|
* cache.
|
|
|
|
*/
|
|
|
|
if (net_nbuf_family(buf) == AF_INET6) {
|
|
|
|
buf = net_ipv6_prepare_for_send(buf);
|
|
|
|
if (!buf) {
|
|
|
|
verdict = NET_CONTINUE;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
verdict = iface->l2->send(iface, buf);
|
|
|
|
|
|
|
|
done:
|
2016-06-29 16:39:06 +03:00
|
|
|
/* The L2 send() function can return
|
2017-02-27 16:33:34 +02:00
|
|
|
* NET_OK in which case packet was sent successfully. In this case
|
|
|
|
* 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.
|
|
|
|
*/
|
2016-09-28 14:26:27 +03:00
|
|
|
if (context && verdict == NET_DROP) {
|
2016-06-29 16:39:06 +03:00
|
|
|
NET_DBG("Calling context send cb %p token %p verdict %d",
|
|
|
|
context, token, verdict);
|
|
|
|
|
2016-12-19 14:18:10 +02:00
|
|
|
net_context_send_cb(context, token, status);
|
2016-06-29 16:39:06 +03:00
|
|
|
}
|
|
|
|
|
2016-09-28 14:18:55 +03:00
|
|
|
if (verdict == NET_DROP) {
|
2016-12-19 14:18:10 +02:00
|
|
|
net_if_call_link_cb(iface, dst, status);
|
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++) {
|
|
|
|
if (!memcmp(iface->link_addr.addr, ll_addr->addr,
|
|
|
|
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++) {
|
|
|
|
if (iface->dev == dev) {
|
|
|
|
return iface;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-24 17:34:30 +02:00
|
|
|
struct net_if *net_if_get_default(void)
|
|
|
|
{
|
|
|
|
return __net_if_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV6)
|
|
|
|
|
2016-06-16 11:01:40 +03:00
|
|
|
#if defined(CONFIG_NET_IPV6_DAD)
|
2016-11-09 17:44:21 +01:00
|
|
|
#define DAD_TIMEOUT (MSEC_PER_SEC / 10)
|
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",
|
|
|
|
net_sprint_ipv6_addr(&ifaddr->address.in6_addr));
|
|
|
|
|
|
|
|
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) {
|
|
|
|
/* 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;
|
|
|
|
ifaddr->dad_count = 1;
|
|
|
|
|
|
|
|
NET_DBG("Interface %p ll addr %s tentative IPv6 addr %s", iface,
|
|
|
|
net_sprint_ll_addr(iface->link_addr.addr,
|
|
|
|
iface->link_addr.len),
|
|
|
|
net_sprint_ipv6_addr(&ifaddr->address.in6_addr));
|
|
|
|
|
|
|
|
if (!net_ipv6_start_dad(iface, ifaddr)) {
|
2016-11-09 17:44:21 +01:00
|
|
|
k_delayed_work_init(&ifaddr->dad_timer, dad_timeout);
|
|
|
|
k_delayed_work_submit(&ifaddr->dad_timer, DAD_TIMEOUT);
|
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;
|
2016-11-11 20:14:20 +02:00
|
|
|
struct in6_addr addr = { };
|
2016-11-11 10:34:51 +02:00
|
|
|
|
|
|
|
net_ipv6_addr_create_iid(&addr, &iface->link_addr);
|
|
|
|
|
|
|
|
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",
|
|
|
|
net_sprint_ipv6_addr(&addr), iface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define net_if_ipv6_start_dad(...)
|
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)
|
2016-11-09 17:44:21 +01:00
|
|
|
#define RS_TIMEOUT MSEC_PER_SEC
|
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. */
|
|
|
|
struct net_if *iface = CONTAINER_OF(work, struct net_if, rs_timer);
|
|
|
|
|
|
|
|
iface->rs_count++;
|
|
|
|
|
|
|
|
NET_DBG("RS no respond iface %p count %d", iface, iface->rs_count);
|
|
|
|
|
|
|
|
if (iface->rs_count < RS_COUNT) {
|
|
|
|
net_if_start_rs(iface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_start_rs(struct net_if *iface)
|
|
|
|
{
|
|
|
|
NET_DBG("Interface %p", iface);
|
|
|
|
|
|
|
|
if (!net_ipv6_start_rs(iface)) {
|
2016-11-09 17:44:21 +01:00
|
|
|
k_delayed_work_init(&iface->rs_timer, rs_timeout);
|
|
|
|
k_delayed_work_submit(&iface->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
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
|
|
|
if (!iface->ipv6.unicast[i].is_used ||
|
|
|
|
iface->ipv6.unicast[i].address.family != AF_INET6) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_is_ipv6_prefix(addr->s6_addr,
|
|
|
|
iface->ipv6.unicast[i].address.in6_addr.s6_addr,
|
|
|
|
128)) {
|
2016-06-22 15:34:47 +03:00
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
*ret = iface;
|
|
|
|
}
|
|
|
|
|
2016-05-17 12:33:45 +03:00
|
|
|
return &iface->ipv6.unicast[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-11 10:34:51 +02:00
|
|
|
static void ipv6_addr_expired(struct k_work *work)
|
|
|
|
{
|
|
|
|
struct net_if_addr *ifaddr = CONTAINER_OF(work,
|
|
|
|
struct net_if_addr,
|
|
|
|
lifetime);
|
|
|
|
|
|
|
|
NET_DBG("IPv6 address %s is deprecated",
|
|
|
|
net_sprint_ipv6_addr(&ifaddr->address.in6_addr));
|
|
|
|
|
|
|
|
ifaddr->addr_state = NET_ADDR_DEPRECATED;
|
|
|
|
}
|
|
|
|
|
2016-11-11 10:26:17 +02:00
|
|
|
void net_if_ipv6_addr_update_lifetime(struct net_if_addr *ifaddr,
|
|
|
|
uint32_t vlifetime)
|
|
|
|
{
|
2016-12-06 19:20:03 +02:00
|
|
|
NET_DBG("Updating expire time of %s by %u secs",
|
2016-11-11 10:26:17 +02:00
|
|
|
net_sprint_ipv6_addr(&ifaddr->address.in6_addr),
|
|
|
|
vlifetime);
|
|
|
|
|
|
|
|
k_delayed_work_submit(&ifaddr->lifetime,
|
|
|
|
vlifetime * MSEC_PER_SEC);
|
|
|
|
}
|
|
|
|
|
2016-11-25 20:10:58 +02:00
|
|
|
static struct net_if_addr *ipv6_addr_find(struct net_if *iface,
|
|
|
|
struct in6_addr *addr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
|
|
|
if (!iface->ipv6.unicast[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_ipv6_addr_cmp(addr,
|
|
|
|
&iface->ipv6.unicast[i].address.in6_addr)) {
|
|
|
|
return &iface->ipv6.unicast[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
uint32_t vlifetime)
|
|
|
|
{
|
2016-11-25 20:10:58 +02:00
|
|
|
struct net_if_addr *ifaddr;
|
2016-05-17 12:33:45 +03:00
|
|
|
int i;
|
|
|
|
|
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++) {
|
|
|
|
if (iface->ipv6.unicast[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->ipv6.unicast[i].is_used = true;
|
|
|
|
iface->ipv6.unicast[i].address.family = AF_INET6;
|
|
|
|
iface->ipv6.unicast[i].addr_type = addr_type;
|
|
|
|
memcpy(&iface->ipv6.unicast[i].address.in6_addr, addr, 16);
|
|
|
|
|
|
|
|
/* FIXME - set the mcast addr for this node */
|
|
|
|
|
|
|
|
if (vlifetime) {
|
|
|
|
iface->ipv6.unicast[i].is_infinite = false;
|
|
|
|
|
2016-11-11 10:34:51 +02:00
|
|
|
k_delayed_work_init(
|
|
|
|
&iface->ipv6.unicast[i].lifetime,
|
|
|
|
ipv6_addr_expired);
|
|
|
|
|
2016-12-06 19:20:03 +02:00
|
|
|
NET_DBG("Expiring %s in %u secs",
|
2016-11-11 10:34:51 +02:00
|
|
|
net_sprint_ipv6_addr(addr), vlifetime);
|
|
|
|
|
|
|
|
net_if_ipv6_addr_update_lifetime(
|
|
|
|
&iface->ipv6.unicast[i], vlifetime);
|
2016-05-17 12:33:45 +03:00
|
|
|
} else {
|
|
|
|
iface->ipv6.unicast[i].is_infinite = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p address %s type %s added", i, iface,
|
|
|
|
net_sprint_ipv6_addr(addr),
|
|
|
|
net_addr_type2str(addr_type));
|
|
|
|
|
2016-11-11 10:34:51 +02:00
|
|
|
net_if_ipv6_start_dad(iface, &iface->ipv6.unicast[i]);
|
|
|
|
|
2016-09-29 18:33:03 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_ADDR_ADD, iface);
|
|
|
|
|
2016-05-17 12:33:45 +03:00
|
|
|
return &iface->ipv6.unicast[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-01 10:54:10 +03:00
|
|
|
bool net_if_ipv6_addr_rm(struct net_if *iface, struct in6_addr *addr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
NET_ASSERT(addr);
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
|
|
|
struct in6_addr maddr;
|
|
|
|
|
|
|
|
if (!iface->ipv6.unicast[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!net_ipv6_addr_cmp(
|
|
|
|
&iface->ipv6.unicast[i].address.in6_addr,
|
|
|
|
addr)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-11-11 10:34:51 +02:00
|
|
|
k_delayed_work_cancel(&iface->ipv6.unicast[i].lifetime);
|
|
|
|
|
2016-06-01 10:54:10 +03:00
|
|
|
iface->ipv6.unicast[i].is_used = false;
|
|
|
|
|
|
|
|
net_ipv6_addr_create_solicited_node(addr, &maddr);
|
|
|
|
net_if_ipv6_maddr_rm(iface, &maddr);
|
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p address %s type %s removed",
|
|
|
|
i, iface, net_sprint_ipv6_addr(addr),
|
|
|
|
net_addr_type2str(iface->ipv6.unicast[i].addr_type));
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!net_is_ipv6_addr_mcast(addr)) {
|
|
|
|
NET_DBG("Address %s is not a multicast address.",
|
|
|
|
net_sprint_ipv6_addr(addr));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
|
|
|
|
if (iface->ipv6.mcast[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->ipv6.mcast[i].is_used = true;
|
2016-06-22 15:49:50 +03:00
|
|
|
iface->ipv6.mcast[i].address.family = AF_INET6;
|
2016-05-17 12:33:45 +03:00
|
|
|
memcpy(&iface->ipv6.mcast[i].address.in6_addr, addr, 16);
|
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p address %s added", i, iface,
|
|
|
|
net_sprint_ipv6_addr(addr));
|
|
|
|
|
2016-09-29 18:33:03 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_MADDR_ADD, iface);
|
|
|
|
|
2016-05-17 12:33:45 +03:00
|
|
|
return &iface->ipv6.mcast[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
|
|
|
|
if (!iface->ipv6.mcast[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!net_ipv6_addr_cmp(
|
|
|
|
&iface->ipv6.mcast[i].address.in6_addr,
|
|
|
|
addr)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->ipv6.mcast[i].is_used = false;
|
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p address %s removed",
|
|
|
|
i, iface, net_sprint_ipv6_addr(addr));
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
|
|
|
int i;
|
|
|
|
|
2017-02-09 09:50:50 +02:00
|
|
|
if (ret && *ret && iface != *ret) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-05-17 12:33:45 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
|
|
|
|
if (!iface->ipv6.mcast[i].is_used ||
|
|
|
|
iface->ipv6.mcast[i].address.family != AF_INET6) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_is_ipv6_prefix(maddr->s6_addr,
|
|
|
|
iface->ipv6.mcast[i].address.in6_addr.s6_addr,
|
|
|
|
128)) {
|
2016-06-22 15:34:47 +03:00
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
*ret = iface;
|
|
|
|
}
|
|
|
|
|
2016-05-17 12:33:45 +03:00
|
|
|
return &iface->ipv6.mcast[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-25 20:12:37 +02:00
|
|
|
static struct net_if_ipv6_prefix *ipv6_prefix_find(struct net_if *iface,
|
|
|
|
struct in6_addr *prefix,
|
|
|
|
uint8_t prefix_len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
|
|
|
if (!iface->ipv6.unicast[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_ipv6_addr_cmp(prefix, &iface->ipv6.prefix[i].prefix) &&
|
|
|
|
prefix_len == iface->ipv6.prefix[i].len) {
|
|
|
|
return &iface->ipv6.prefix[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
uint8_t len,
|
|
|
|
uint32_t lifetime)
|
|
|
|
{
|
2016-11-25 20:12:37 +02:00
|
|
|
struct net_if_ipv6_prefix *if_prefix;
|
2016-06-07 10:16:58 +03:00
|
|
|
int i;
|
|
|
|
|
2016-11-25 20:12:37 +02:00
|
|
|
if_prefix = ipv6_prefix_find(iface, prefix, len);
|
|
|
|
if (if_prefix) {
|
|
|
|
return if_prefix;
|
|
|
|
}
|
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
|
|
|
if (iface->ipv6.prefix[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->ipv6.prefix[i].is_used = true;
|
|
|
|
iface->ipv6.prefix[i].len = len;
|
|
|
|
|
|
|
|
if (lifetime == NET_IPV6_ND_INFINITE_LIFETIME) {
|
|
|
|
iface->ipv6.prefix[i].is_infinite = true;
|
|
|
|
} else {
|
|
|
|
iface->ipv6.prefix[i].is_infinite = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&iface->ipv6.prefix[i].prefix, prefix,
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p prefix %s/%d added", i, iface,
|
|
|
|
net_sprint_ipv6_addr(prefix), len);
|
|
|
|
|
2016-09-29 18:33:03 +02:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV6_PREFIX_ADD, iface);
|
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
return &iface->ipv6.prefix[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool net_if_ipv6_prefix_rm(struct net_if *iface, struct in6_addr *addr,
|
|
|
|
uint8_t len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
|
|
|
if (!iface->ipv6.prefix[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!net_ipv6_addr_cmp(&iface->ipv6.prefix[i].prefix, addr) ||
|
|
|
|
iface->ipv6.prefix[i].len != len) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-07 10:54:34 +03:00
|
|
|
net_if_ipv6_prefix_unset_timer(&iface->ipv6.prefix[i]);
|
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
iface->ipv6.prefix[i].is_used = false;
|
2016-07-07 10:54:34 +03:00
|
|
|
|
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;
|
|
|
|
}
|
2016-06-24 17:34:30 +02:00
|
|
|
|
2016-06-07 10:16:58 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct net_if_ipv6_prefix *net_if_ipv6_prefix_lookup(struct net_if *iface,
|
|
|
|
struct in6_addr *addr,
|
|
|
|
uint8_t len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
|
|
|
if (!iface->ipv6.prefix[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_is_ipv6_prefix(iface->ipv6.prefix[i].prefix.s6_addr,
|
|
|
|
addr->s6_addr, len)) {
|
|
|
|
return &iface->ipv6.prefix[i];
|
|
|
|
}
|
|
|
|
}
|
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)
|
|
|
|
{
|
|
|
|
struct net_if *tmp;
|
|
|
|
|
|
|
|
for (tmp = __net_if_start; tmp != __net_if_end; tmp++) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (iface && *iface && *iface != tmp) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
|
|
|
|
if (tmp->ipv6.prefix[i].is_used &&
|
|
|
|
net_is_ipv6_prefix(tmp->ipv6.prefix[i].prefix.
|
|
|
|
s6_addr,
|
|
|
|
addr->s6_addr,
|
|
|
|
tmp->ipv6.prefix[i].len)) {
|
|
|
|
if (iface) {
|
|
|
|
*iface = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
static inline void prefix_lf_timeout(struct k_work *work)
|
2016-07-07 10:54:34 +03:00
|
|
|
{
|
|
|
|
struct net_if_ipv6_prefix *prefix =
|
|
|
|
CONTAINER_OF(work, struct net_if_ipv6_prefix, lifetime);
|
|
|
|
|
|
|
|
NET_DBG("Prefix %s/%d expired",
|
|
|
|
net_sprint_ipv6_addr(&prefix->prefix), prefix->len);
|
|
|
|
|
|
|
|
prefix->is_used = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_ipv6_prefix_set_timer(struct net_if_ipv6_prefix *prefix,
|
|
|
|
uint32_t lifetime)
|
|
|
|
{
|
|
|
|
/* The maximum lifetime might be shorter than expected
|
|
|
|
* because we have only 32-bit int to store the value and
|
2016-11-09 17:44:21 +01:00
|
|
|
* the timer API uses ms value. The lifetime value with
|
2016-07-07 10:54:34 +03:00
|
|
|
* all bits set means infinite and that value is never set
|
|
|
|
* to timer.
|
|
|
|
*/
|
2016-11-09 17:44:21 +01:00
|
|
|
uint32_t timeout = lifetime * MSEC_PER_SEC;
|
2016-07-07 10:54:34 +03:00
|
|
|
|
|
|
|
NET_ASSERT(lifetime != 0xffffffff);
|
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
if (lifetime > (0xfffffffe / MSEC_PER_SEC)) {
|
2016-07-07 10:54:34 +03:00
|
|
|
timeout = 0xfffffffe;
|
|
|
|
|
|
|
|
NET_ERR("Prefix %s/%d lifetime %u overflow, "
|
|
|
|
"setting it to %u secs",
|
|
|
|
net_sprint_ipv6_addr(&prefix->prefix),
|
|
|
|
prefix->len,
|
2016-11-09 17:44:21 +01:00
|
|
|
lifetime, timeout / MSEC_PER_SEC);
|
2016-07-07 10:54:34 +03:00
|
|
|
}
|
|
|
|
|
2016-11-29 15:18:02 +02:00
|
|
|
NET_DBG("Prefix lifetime %u ms", timeout);
|
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
k_delayed_work_init(&prefix->lifetime, prefix_lf_timeout);
|
|
|
|
k_delayed_work_submit(&prefix->lifetime, timeout);
|
2016-07-07 10:54:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void net_if_ipv6_prefix_unset_timer(struct net_if_ipv6_prefix *prefix)
|
|
|
|
{
|
|
|
|
if (!prefix->is_used) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-09 17:44:21 +01:00
|
|
|
k_delayed_work_cancel(&prefix->lifetime);
|
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)
|
|
|
|
{
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
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)
|
|
|
|
{
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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",
|
|
|
|
net_sprint_ipv6_addr(&router->address.in6_addr));
|
|
|
|
|
|
|
|
router->is_used = false;
|
|
|
|
}
|
|
|
|
|
2016-11-11 11:20:28 +02:00
|
|
|
void net_if_ipv6_router_update_lifetime(struct net_if_router *router,
|
|
|
|
uint32_t lifetime)
|
|
|
|
{
|
2016-12-06 19:20:03 +02:00
|
|
|
NET_DBG("Updating expire time of %s by %u secs",
|
2016-11-11 11:20:28 +02:00
|
|
|
net_sprint_ipv6_addr(&router->address.in6_addr),
|
|
|
|
lifetime);
|
|
|
|
|
|
|
|
k_delayed_work_submit(&router->lifetime,
|
|
|
|
lifetime * MSEC_PER_SEC);
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
uint16_t lifetime)
|
|
|
|
{
|
|
|
|
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_INET6;
|
|
|
|
|
|
|
|
if (lifetime) {
|
|
|
|
/* This is a default router. RFC 4861 page 43
|
|
|
|
* AdvDefaultLifetime variable
|
|
|
|
*/
|
|
|
|
routers[i].is_default = true;
|
|
|
|
routers[i].is_infinite = false;
|
|
|
|
|
2016-11-11 11:22:35 +02:00
|
|
|
k_delayed_work_init(&routers[i].lifetime,
|
|
|
|
ipv6_router_expired);
|
|
|
|
|
2016-12-06 19:20:03 +02:00
|
|
|
NET_DBG("Expiring %s in %u secs",
|
2016-11-11 11:22:35 +02:00
|
|
|
net_sprint_ipv6_addr(addr), lifetime);
|
2016-06-07 10:16:58 +03:00
|
|
|
} else {
|
|
|
|
routers[i].is_default = false;
|
|
|
|
routers[i].is_infinite = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_ipaddr_copy(&routers[i].address.in6_addr, addr);
|
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p router %s lifetime %u default %d "
|
|
|
|
"added",
|
|
|
|
i, iface, net_sprint_ipv6_addr(addr), lifetime,
|
|
|
|
routers[i].is_default);
|
|
|
|
|
|
|
|
return &routers[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-11 11:21:34 +02:00
|
|
|
bool net_if_ipv6_router_rm(struct net_if_router *router)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
NET_DBG("[%d] router %s removed",
|
|
|
|
i, net_sprint_ipv6_addr(&routers[i].address.in6_addr));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
|
|
|
if (!iface->ipv6.unicast[i].is_used ||
|
|
|
|
(addr_state != NET_ADDR_ANY_STATE &&
|
|
|
|
iface->ipv6.unicast[i].addr_state != addr_state) ||
|
|
|
|
iface->ipv6.unicast[i].address.family != AF_INET6) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (net_is_ipv6_ll_addr(&iface->ipv6.unicast[i].address.in6_addr)) {
|
|
|
|
return &iface->ipv6.unicast[i].address.in6_addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct in6_addr *check_global_addr(struct net_if *iface)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
|
|
|
if (!iface->ipv6.unicast[i].is_used ||
|
|
|
|
(iface->ipv6.unicast[i].addr_state != NET_ADDR_TENTATIVE &&
|
|
|
|
iface->ipv6.unicast[i].addr_state != NET_ADDR_PREFERRED) ||
|
|
|
|
iface->ipv6.unicast[i].address.family != AF_INET6) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!net_is_ipv6_ll_addr(
|
|
|
|
&iface->ipv6.unicast[i].address.in6_addr)) {
|
|
|
|
return &iface->ipv6.unicast[i].address.in6_addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct in6_addr *net_if_ipv6_get_global_addr(struct net_if **iface)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-18 11:15:41 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint8_t get_length(struct in6_addr *src, struct in6_addr *dst)
|
|
|
|
{
|
|
|
|
uint8_t j, k, xor;
|
|
|
|
uint8_t len = 0;
|
|
|
|
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
if (src->s6_addr[j] == dst->s6_addr[j]) {
|
|
|
|
len += 8;
|
|
|
|
} else {
|
|
|
|
xor = src->s6_addr[j] ^ dst->s6_addr[j];
|
|
|
|
for (k = 0; k < 8; k++) {
|
|
|
|
if (!(xor & 0x80)) {
|
|
|
|
len++;
|
|
|
|
xor <<= 1;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 &&
|
|
|
|
!net_is_ipv6_ll_addr(&addr->address.in6_addr)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct in6_addr *net_if_ipv6_get_best_match(struct net_if *iface,
|
|
|
|
struct in6_addr *dst,
|
|
|
|
uint8_t *best_so_far)
|
|
|
|
{
|
|
|
|
struct in6_addr *src = NULL;
|
|
|
|
uint8_t i, len;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
|
|
|
|
if (!is_proper_ipv6_address(&iface->ipv6.unicast[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = get_length(dst,
|
|
|
|
&iface->ipv6.unicast[i].address.in6_addr);
|
|
|
|
if (len >= *best_so_far) {
|
|
|
|
*best_so_far = len;
|
|
|
|
src = &iface->ipv6.unicast[i].address.in6_addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
2016-06-02 16:57:03 +03:00
|
|
|
const struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *dst_iface,
|
|
|
|
struct in6_addr *dst)
|
2016-05-18 11:15:41 +03:00
|
|
|
{
|
|
|
|
struct in6_addr *src = NULL;
|
|
|
|
uint8_t best_match = 0;
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
if (!net_is_ipv6_ll_addr(dst) && !net_is_ipv6_addr_mcast(dst)) {
|
|
|
|
|
|
|
|
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;
|
2016-06-24 17:34:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t net_if_ipv6_calc_reachable_time(struct net_if *iface)
|
|
|
|
{
|
|
|
|
return MIN_RANDOM_FACTOR * iface->base_reachable_time +
|
|
|
|
sys_rand32_get() %
|
|
|
|
(MAX_RANDOM_FACTOR * iface->base_reachable_time -
|
|
|
|
MIN_RANDOM_FACTOR * iface->base_reachable_time);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_IPV6 */
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV4)
|
|
|
|
struct net_if_router *net_if_ipv4_router_lookup(struct net_if *iface,
|
|
|
|
struct in_addr *addr)
|
|
|
|
{
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
uint16_t lifetime)
|
|
|
|
{
|
|
|
|
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",
|
|
|
|
i, iface, net_sprint_ipv4_addr(addr), lifetime,
|
|
|
|
is_default);
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool net_if_ipv4_addr_mask_cmp(struct net_if *iface,
|
|
|
|
struct in_addr *addr)
|
|
|
|
{
|
|
|
|
uint32_t subnet = ntohl(addr->s_addr[0]) &
|
|
|
|
ntohl(iface->ipv4.netmask.s_addr[0]);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
|
|
|
if (!iface->ipv4.unicast[i].is_used ||
|
|
|
|
iface->ipv4.unicast[i].address.family != AF_INET) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((ntohl(iface->ipv4.unicast[i].address.in_addr.s_addr[0]) &
|
|
|
|
ntohl(iface->ipv4.netmask.s_addr[0])) == subnet) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2016-05-18 11:15:41 +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
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
|
|
|
if (!iface->ipv4.unicast[i].is_used ||
|
|
|
|
iface->ipv4.unicast[i].address.family != AF_INET) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr->s4_addr32[0] ==
|
|
|
|
iface->ipv4.unicast[i].address.in_addr.s_addr[0]) {
|
2016-06-22 15:34:47 +03:00
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
*ret = iface;
|
|
|
|
}
|
|
|
|
|
2016-05-17 14:13:17 +03:00
|
|
|
return &iface->ipv4.unicast[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-25 20:25:34 +02:00
|
|
|
static struct net_if_addr *ipv4_addr_find(struct net_if *iface,
|
|
|
|
struct in_addr *addr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
|
|
|
if (!iface->ipv4.unicast[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_ipv4_addr_cmp(addr,
|
|
|
|
&iface->ipv4.unicast[i].address.in_addr)) {
|
|
|
|
return &iface->ipv4.unicast[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
uint32_t vlifetime)
|
|
|
|
{
|
2016-11-25 20:25:34 +02:00
|
|
|
struct net_if_addr *ifaddr;
|
2016-05-17 14:13:17 +03:00
|
|
|
int i;
|
|
|
|
|
2016-11-25 20:25:34 +02:00
|
|
|
ifaddr = ipv4_addr_find(iface, addr);
|
|
|
|
if (ifaddr) {
|
|
|
|
return ifaddr;
|
|
|
|
}
|
|
|
|
|
2016-05-17 14:13:17 +03:00
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
|
|
|
if (iface->ipv4.unicast[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->ipv4.unicast[i].is_used = true;
|
|
|
|
iface->ipv4.unicast[i].address.family = AF_INET;
|
|
|
|
iface->ipv4.unicast[i].address.in_addr.s4_addr32[0] =
|
|
|
|
addr->s4_addr32[0];
|
|
|
|
iface->ipv4.unicast[i].addr_type = addr_type;
|
|
|
|
|
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) {
|
|
|
|
iface->ipv4.unicast[i].is_infinite = false;
|
|
|
|
} else {
|
|
|
|
iface->ipv4.unicast[i].is_infinite = true;
|
|
|
|
}
|
|
|
|
|
2016-09-12 16:37:36 +03:00
|
|
|
/**
|
|
|
|
* TODO: Handle properly PREFERRED/DEPRECATED state when
|
|
|
|
* address in use, expired and renewal state.
|
|
|
|
*/
|
|
|
|
iface->ipv4.unicast[i].addr_state = NET_ADDR_PREFERRED;
|
|
|
|
|
2016-05-17 14:13:17 +03:00
|
|
|
NET_DBG("[%d] interface %p address %s type %s added", i, iface,
|
|
|
|
net_sprint_ipv4_addr(addr),
|
|
|
|
net_addr_type2str(addr_type));
|
|
|
|
|
2016-10-26 10:52:36 +03:00
|
|
|
net_mgmt_event_notify(NET_EVENT_IPV4_ADDR_ADD, iface);
|
|
|
|
|
2016-05-17 14:13:17 +03:00
|
|
|
return &iface->ipv4.unicast[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-06 11:51:30 +03:00
|
|
|
bool net_if_ipv4_addr_rm(struct net_if *iface, struct in_addr *addr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
|
|
|
if (!iface->ipv4.unicast[i].is_used) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!net_ipv4_addr_cmp(
|
|
|
|
&iface->ipv4.unicast[i].address.in_addr,
|
|
|
|
addr)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->ipv4.unicast[i].is_used = false;
|
|
|
|
|
|
|
|
NET_DBG("[%d] interface %p address %s removed",
|
|
|
|
i, iface, net_sprint_ipv4_addr(addr));
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-24 17:34:30 +02:00
|
|
|
#endif /* CONFIG_NET_IPV4 */
|
2016-06-07 10:16:58 +03:00
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-22 15:42:55 +03:00
|
|
|
struct net_if *net_if_get_by_index(uint8_t index)
|
|
|
|
{
|
2017-01-31 14:50:21 +00:00
|
|
|
if (&__net_if_start[index] >= __net_if_end) {
|
2016-06-22 15:42:55 +03:00
|
|
|
NET_DBG("Index %d is too large", index);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &__net_if_start[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t net_if_get_by_iface(struct net_if *iface)
|
|
|
|
{
|
2017-01-31 14:50:21 +00:00
|
|
|
NET_ASSERT(iface >= __net_if_start && iface < __net_if_end);
|
2016-06-22 15:42:55 +03:00
|
|
|
|
|
|
|
return iface - __net_if_start;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (atomic_test_bit(iface->flags, NET_IF_UP)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-21 13:33:09 +02:00
|
|
|
/* If the L2 does not support enable just set the flag */
|
|
|
|
if (!iface->l2->enable) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Notify L2 to enable the interface */
|
|
|
|
status = iface->l2->enable(iface, true);
|
|
|
|
if (status < 0) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2016-12-19 14:18:10 +02:00
|
|
|
atomic_set_bit(iface->flags, NET_IF_UP);
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV6_DAD)
|
|
|
|
NET_DBG("Starting DAD for iface %p", iface);
|
|
|
|
net_if_start_dad(iface);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_IPV6_ND)
|
|
|
|
NET_DBG("Starting ND/RS for iface %p", iface);
|
|
|
|
net_if_start_rs(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-01-24 15:25:37 +00:00
|
|
|
/* If the L2 does not support enable just clear the flag */
|
2016-12-21 13:33:09 +02:00
|
|
|
if (!iface->l2->enable) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Notify L2 to disable the interface */
|
|
|
|
status = iface->l2->enable(iface, false);
|
|
|
|
if (status < 0) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2016-12-19 14:18:10 +02:00
|
|
|
atomic_clear_bit(iface->flags, NET_IF_UP);
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-06-03 12:29:58 +02:00
|
|
|
void net_if_init(void)
|
2016-05-02 09:02:04 +02:00
|
|
|
{
|
|
|
|
struct net_if *iface;
|
|
|
|
|
2016-06-21 12:10:13 +02:00
|
|
|
NET_DBG("");
|
|
|
|
|
2016-05-02 09:02:04 +02:00
|
|
|
for (iface = __net_if_start; iface != __net_if_end; iface++) {
|
2016-06-03 12:29:58 +02:00
|
|
|
init_tx_queue(iface);
|
2016-05-19 11:26:06 +03:00
|
|
|
|
2016-06-14 09:31:34 +03:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
|
|
|
iface->ttl = CONFIG_NET_INITIAL_TTL;
|
|
|
|
#endif
|
|
|
|
|
2016-05-19 11:26:06 +03:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
|
|
|
iface->hop_limit = CONFIG_NET_INITIAL_HOP_LIMIT;
|
2016-06-07 10:16:58 +03:00
|
|
|
iface->base_reachable_time = REACHABLE_TIME;
|
|
|
|
|
2016-09-23 10:52:24 +03:00
|
|
|
net_if_ipv6_set_reachable_time(iface);
|
2016-05-19 11:26:06 +03:00
|
|
|
#endif
|
2016-05-02 09:02:04 +02:00
|
|
|
}
|
2016-10-26 13:57:30 +03:00
|
|
|
|
|
|
|
/* RPL init must be done after the network interface is up
|
|
|
|
* as the RPL code wants to add multicast address to interface.
|
|
|
|
*/
|
|
|
|
net_rpl_init();
|
2016-05-02 09:02:04 +02:00
|
|
|
}
|