net: ipv4: autoconf: Integrate with the ACD module
The autoconf module can now reuse generic address conflict detection, which was added for all address types. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
parent
80339ac4ee
commit
cc53826cc9
8 changed files with 103 additions and 429 deletions
|
|
@ -14,12 +14,44 @@
|
||||||
/** Current state of IPv4 Autoconfiguration */
|
/** Current state of IPv4 Autoconfiguration */
|
||||||
enum net_ipv4_autoconf_state {
|
enum net_ipv4_autoconf_state {
|
||||||
NET_IPV4_AUTOCONF_INIT, /**< Initialization state */
|
NET_IPV4_AUTOCONF_INIT, /**< Initialization state */
|
||||||
NET_IPV4_AUTOCONF_PROBE, /**< Probing state */
|
|
||||||
NET_IPV4_AUTOCONF_ANNOUNCE, /**< Announce state */
|
|
||||||
NET_IPV4_AUTOCONF_ASSIGNED, /**< Assigned state */
|
NET_IPV4_AUTOCONF_ASSIGNED, /**< Assigned state */
|
||||||
NET_IPV4_AUTOCONF_RENEW, /**< Renew state */
|
NET_IPV4_AUTOCONF_RENEW, /**< Renew state */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct net_if;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start IPv4 autoconfiguration RFC 3927: IPv4 Link Local
|
||||||
|
*
|
||||||
|
* @details Start IPv4 IP autoconfiguration
|
||||||
|
*
|
||||||
|
* @param iface A valid pointer on an interface
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_NET_IPV4_AUTO)
|
||||||
|
void net_ipv4_autoconf_start(struct net_if *iface);
|
||||||
|
#else
|
||||||
|
static inline void net_ipv4_autoconf_start(struct net_if *iface)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(iface);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset autoconf process
|
||||||
|
*
|
||||||
|
* @details Reset IPv4 IP autoconfiguration
|
||||||
|
*
|
||||||
|
* @param iface A valid pointer on an interface
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_NET_IPV4_AUTO)
|
||||||
|
void net_ipv4_autoconf_reset(struct net_if *iface);
|
||||||
|
#else
|
||||||
|
static inline void net_ipv4_autoconf_reset(struct net_if *iface)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(iface);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/** @cond INTERNAL_HIDDEN */
|
/** @cond INTERNAL_HIDDEN */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -28,7 +60,7 @@ enum net_ipv4_autoconf_state {
|
||||||
#if defined(CONFIG_NET_IPV4_AUTO)
|
#if defined(CONFIG_NET_IPV4_AUTO)
|
||||||
void net_ipv4_autoconf_init(void);
|
void net_ipv4_autoconf_init(void);
|
||||||
#else
|
#else
|
||||||
#define net_ipv4_autoconf_init(...)
|
static inline void net_ipv4_autoconf_init(void) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @endcond */
|
/** @endcond */
|
||||||
|
|
|
||||||
|
|
@ -519,36 +519,15 @@ struct net_if_dhcpv4 {
|
||||||
|
|
||||||
#if defined(CONFIG_NET_IPV4_AUTO) && defined(CONFIG_NET_NATIVE_IPV4)
|
#if defined(CONFIG_NET_IPV4_AUTO) && defined(CONFIG_NET_NATIVE_IPV4)
|
||||||
struct net_if_ipv4_autoconf {
|
struct net_if_ipv4_autoconf {
|
||||||
/** Used for timer lists */
|
|
||||||
sys_snode_t node;
|
|
||||||
|
|
||||||
/** Backpointer to correct network interface */
|
/** Backpointer to correct network interface */
|
||||||
struct net_if *iface;
|
struct net_if *iface;
|
||||||
|
|
||||||
/** Timer start */
|
|
||||||
int64_t timer_start;
|
|
||||||
|
|
||||||
/** Time for INIT, DISCOVER, REQUESTING, RENEWAL */
|
|
||||||
uint32_t timer_timeout;
|
|
||||||
|
|
||||||
/** Current IP addr */
|
|
||||||
struct in_addr current_ip;
|
|
||||||
|
|
||||||
/** Requested IP addr */
|
/** Requested IP addr */
|
||||||
struct in_addr requested_ip;
|
struct in_addr requested_ip;
|
||||||
|
|
||||||
/** IPV4 Autoconf state in the process of network address allocation.
|
/** IPV4 Autoconf state in the process of network address allocation.
|
||||||
*/
|
*/
|
||||||
enum net_ipv4_autoconf_state state;
|
enum net_ipv4_autoconf_state state;
|
||||||
|
|
||||||
/** Number of sent probe requests */
|
|
||||||
uint8_t probe_cnt;
|
|
||||||
|
|
||||||
/** Number of sent announcements */
|
|
||||||
uint8_t announce_cnt;
|
|
||||||
|
|
||||||
/** Incoming conflict count */
|
|
||||||
uint8_t conflict_cnt;
|
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_NET_IPV4_AUTO */
|
#endif /* CONFIG_NET_IPV4_AUTO */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,9 @@ config NET_IPV4_AUTO
|
||||||
depends on NET_ARP
|
depends on NET_ARP
|
||||||
select EXPERIMENTAL
|
select EXPERIMENTAL
|
||||||
select NET_IPV4_ACD
|
select NET_IPV4_ACD
|
||||||
|
select NET_MGMT
|
||||||
|
select NET_MGMT_EVENT
|
||||||
|
select NET_MGMT_EVENT_INFO
|
||||||
help
|
help
|
||||||
Enables IPv4 auto IP address configuration (see RFC 3927)
|
Enables IPv4 auto IP address configuration (see RFC 3927)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,168 +15,33 @@ LOG_MODULE_REGISTER(net_ipv4_autoconf, CONFIG_NET_IPV4_AUTO_LOG_LEVEL);
|
||||||
#include "net_private.h"
|
#include "net_private.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "../l2/ethernet/arp.h"
|
#include "../l2/ethernet/arp.h"
|
||||||
|
#include <zephyr/net/ipv4_autoconf.h>
|
||||||
#include <zephyr/net/net_pkt.h>
|
#include <zephyr/net/net_pkt.h>
|
||||||
#include <zephyr/net/net_core.h>
|
#include <zephyr/net/net_core.h>
|
||||||
#include <zephyr/net/net_if.h>
|
#include <zephyr/net/net_if.h>
|
||||||
#include <zephyr/random/random.h>
|
#include <zephyr/random/random.h>
|
||||||
|
|
||||||
#include "ipv4_autoconf_internal.h"
|
static struct net_mgmt_event_callback mgmt4_acd_cb;
|
||||||
|
|
||||||
/* Have only one timer in order to save memory */
|
|
||||||
static struct k_work_delayable ipv4auto_timer;
|
|
||||||
|
|
||||||
/* Track currently active timers */
|
|
||||||
static sys_slist_t ipv4auto_ifaces;
|
|
||||||
|
|
||||||
#define BUF_ALLOC_TIMEOUT K_MSEC(100)
|
|
||||||
|
|
||||||
static struct net_pkt *ipv4_autoconf_prepare_arp(struct net_if *iface)
|
|
||||||
{
|
|
||||||
struct net_if_config *cfg = net_if_get_config(iface);
|
|
||||||
struct net_pkt *pkt;
|
|
||||||
|
|
||||||
/* We provide AF_UNSPEC to the allocator: this packet does not
|
|
||||||
* need space for any IPv4 header.
|
|
||||||
*/
|
|
||||||
pkt = net_pkt_alloc_with_buffer(iface, sizeof(struct net_arp_hdr),
|
|
||||||
AF_UNSPEC, 0, BUF_ALLOC_TIMEOUT);
|
|
||||||
if (!pkt) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
net_pkt_set_family(pkt, AF_INET);
|
|
||||||
net_pkt_set_ipv4_acd(pkt, true);
|
|
||||||
|
|
||||||
return net_arp_prepare(pkt, &cfg->ipv4auto.requested_ip,
|
|
||||||
&cfg->ipv4auto.current_ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipv4_autoconf_send_probe(struct net_if_ipv4_autoconf *ipv4auto)
|
|
||||||
{
|
|
||||||
struct net_pkt *pkt;
|
|
||||||
|
|
||||||
pkt = ipv4_autoconf_prepare_arp(ipv4auto->iface);
|
|
||||||
if (!pkt) {
|
|
||||||
NET_DBG("Failed to prepare probe %p", ipv4auto->iface);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NET_DBG("Probing pkt %p", pkt);
|
|
||||||
|
|
||||||
if (net_if_send_data(ipv4auto->iface, pkt) == NET_DROP) {
|
|
||||||
net_pkt_unref(pkt);
|
|
||||||
} else {
|
|
||||||
ipv4auto->probe_cnt++;
|
|
||||||
ipv4auto->state = NET_IPV4_AUTOCONF_PROBE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipv4_autoconf_send_announcement(
|
|
||||||
struct net_if_ipv4_autoconf *ipv4auto)
|
|
||||||
{
|
|
||||||
struct net_pkt *pkt;
|
|
||||||
|
|
||||||
pkt = ipv4_autoconf_prepare_arp(ipv4auto->iface);
|
|
||||||
if (!pkt) {
|
|
||||||
NET_DBG("Failed to prepare announcement %p", ipv4auto->iface);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NET_DBG("Announcing pkt %p", pkt);
|
|
||||||
|
|
||||||
if (net_if_send_data(ipv4auto->iface, pkt) == NET_DROP) {
|
|
||||||
net_pkt_unref(pkt);
|
|
||||||
} else {
|
|
||||||
ipv4auto->announce_cnt++;
|
|
||||||
ipv4auto->state = NET_IPV4_AUTOCONF_ANNOUNCE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum net_verdict net_ipv4_autoconf_input(struct net_if *iface,
|
|
||||||
struct net_pkt *pkt)
|
|
||||||
{
|
|
||||||
struct net_if_config *cfg;
|
|
||||||
struct net_arp_hdr *arp_hdr;
|
|
||||||
|
|
||||||
cfg = net_if_get_config(iface);
|
|
||||||
if (!cfg) {
|
|
||||||
NET_DBG("Interface %p configuration missing!", iface);
|
|
||||||
return NET_DROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (net_pkt_get_len(pkt) < sizeof(struct net_arp_hdr)) {
|
|
||||||
NET_DBG("Invalid ARP header (len %zu, min %zu bytes)",
|
|
||||||
net_pkt_get_len(pkt), sizeof(struct net_arp_hdr));
|
|
||||||
return NET_DROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
arp_hdr = NET_ARP_HDR(pkt);
|
|
||||||
|
|
||||||
if (!net_ipv4_addr_cmp_raw(arp_hdr->dst_ipaddr,
|
|
||||||
(uint8_t *)&cfg->ipv4auto.requested_ip)) {
|
|
||||||
/* No conflict */
|
|
||||||
return NET_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!net_ipv4_addr_cmp_raw(arp_hdr->src_ipaddr,
|
|
||||||
(uint8_t *)&cfg->ipv4auto.requested_ip)) {
|
|
||||||
/* No need to defend */
|
|
||||||
return NET_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
NET_DBG("Conflict detected from %s for %s, state %d",
|
|
||||||
net_sprint_ll_addr((uint8_t *)&arp_hdr->src_hwaddr,
|
|
||||||
arp_hdr->hwlen),
|
|
||||||
net_sprint_ipv4_addr(&arp_hdr->dst_ipaddr),
|
|
||||||
cfg->ipv4auto.state);
|
|
||||||
|
|
||||||
cfg->ipv4auto.conflict_cnt++;
|
|
||||||
|
|
||||||
switch (cfg->ipv4auto.state) {
|
|
||||||
case NET_IPV4_AUTOCONF_PROBE:
|
|
||||||
/* restart probing with renewed IP */
|
|
||||||
net_ipv4_autoconf_start(iface);
|
|
||||||
break;
|
|
||||||
case NET_IPV4_AUTOCONF_ANNOUNCE:
|
|
||||||
case NET_IPV4_AUTOCONF_ASSIGNED:
|
|
||||||
if (cfg->ipv4auto.conflict_cnt == 1U) {
|
|
||||||
/* defend IP */
|
|
||||||
ipv4_autoconf_send_announcement(&cfg->ipv4auto);
|
|
||||||
} else {
|
|
||||||
/* unset host ip */
|
|
||||||
if (!net_if_ipv4_addr_rm(iface,
|
|
||||||
&cfg->ipv4auto.requested_ip)) {
|
|
||||||
NET_DBG("Failed to remove addr from iface");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* restart probing after second conflict */
|
|
||||||
net_ipv4_autoconf_start(iface);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NET_DROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ipv4_autoconf_addr_set(struct net_if_ipv4_autoconf *ipv4auto)
|
static inline void ipv4_autoconf_addr_set(struct net_if_ipv4_autoconf *ipv4auto)
|
||||||
{
|
{
|
||||||
struct in_addr netmask = { { { 255, 255, 0, 0 } } };
|
struct in_addr netmask = { { { 255, 255, 0, 0 } } };
|
||||||
|
|
||||||
if (ipv4auto->announce_cnt <=
|
if (ipv4auto->state == NET_IPV4_AUTOCONF_INIT) {
|
||||||
(IPV4_AUTOCONF_ANNOUNCE_NUM - 1)) {
|
ipv4auto->requested_ip.s4_addr[0] = 169U;
|
||||||
net_ipaddr_copy(&ipv4auto->current_ip,
|
ipv4auto->requested_ip.s4_addr[1] = 254U;
|
||||||
&ipv4auto->requested_ip);
|
ipv4auto->requested_ip.s4_addr[2] = sys_rand8_get() % 254;
|
||||||
ipv4_autoconf_send_announcement(ipv4auto);
|
ipv4auto->requested_ip.s4_addr[3] = sys_rand8_get() % 254;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Success, add new IPv4 address. */
|
NET_DBG("%s: Starting probe for 169.254.%d.%d",
|
||||||
if (!net_if_ipv4_addr_add(ipv4auto->iface,
|
ipv4auto->state == NET_IPV4_AUTOCONF_INIT ? "Init" : "Renew",
|
||||||
&ipv4auto->requested_ip,
|
ipv4auto->requested_ip.s4_addr[2],
|
||||||
NET_ADDR_AUTOCONF, 0)) {
|
ipv4auto->requested_ip.s4_addr[3]);
|
||||||
|
|
||||||
|
/* Add IPv4 address to the interface, this will trigger conflict detection. */
|
||||||
|
if (!net_if_ipv4_addr_add(ipv4auto->iface, &ipv4auto->requested_ip,
|
||||||
|
NET_ADDR_AUTOCONF, 0)) {
|
||||||
NET_DBG("Failed to add IPv4 addr to iface %p",
|
NET_DBG("Failed to add IPv4 addr to iface %p",
|
||||||
ipv4auto->iface);
|
ipv4auto->iface);
|
||||||
return;
|
return;
|
||||||
|
|
@ -189,157 +54,54 @@ static inline void ipv4_autoconf_addr_set(struct net_if_ipv4_autoconf *ipv4auto)
|
||||||
ipv4auto->state = NET_IPV4_AUTOCONF_ASSIGNED;
|
ipv4auto->state = NET_IPV4_AUTOCONF_ASSIGNED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ipv4_autoconf_send(struct net_if_ipv4_autoconf *ipv4auto)
|
static void acd_event_handler(struct net_mgmt_event_callback *cb,
|
||||||
|
uint32_t mgmt_event, struct net_if *iface)
|
||||||
{
|
{
|
||||||
switch (ipv4auto->state) {
|
struct net_if_config *cfg;
|
||||||
case NET_IPV4_AUTOCONF_INIT:
|
struct in_addr *addr;
|
||||||
ipv4auto->probe_cnt = 0U;
|
|
||||||
ipv4auto->announce_cnt = 0U;
|
|
||||||
ipv4auto->conflict_cnt = 0U;
|
|
||||||
(void)memset(&ipv4auto->current_ip, 0, sizeof(struct in_addr));
|
|
||||||
ipv4auto->requested_ip.s4_addr[0] = 169U;
|
|
||||||
ipv4auto->requested_ip.s4_addr[1] = 254U;
|
|
||||||
ipv4auto->requested_ip.s4_addr[2] = sys_rand8_get() % 254;
|
|
||||||
ipv4auto->requested_ip.s4_addr[3] = sys_rand8_get() % 254;
|
|
||||||
|
|
||||||
NET_DBG("%s: Starting probe for 169.254.%d.%d", "Init",
|
cfg = net_if_get_config(iface);
|
||||||
ipv4auto->requested_ip.s4_addr[2],
|
if (!cfg) {
|
||||||
ipv4auto->requested_ip.s4_addr[3]);
|
return;
|
||||||
ipv4_autoconf_send_probe(ipv4auto);
|
}
|
||||||
|
|
||||||
|
if (cfg->ipv4auto.iface == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mgmt_event != NET_EVENT_IPV4_ACD_SUCCEED &&
|
||||||
|
mgmt_event != NET_EVENT_IPV4_ACD_FAILED &&
|
||||||
|
mgmt_event != NET_EVENT_IPV4_ACD_CONFLICT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cb->info_length != sizeof(struct in_addr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = (struct in_addr *)cb->info;
|
||||||
|
|
||||||
|
if (!net_ipv4_addr_cmp(&cfg->ipv4auto.requested_ip, addr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mgmt_event) {
|
||||||
|
case NET_EVENT_IPV4_ACD_SUCCEED:
|
||||||
|
cfg->ipv4auto.state = NET_IPV4_AUTOCONF_ASSIGNED;
|
||||||
break;
|
break;
|
||||||
case NET_IPV4_AUTOCONF_RENEW:
|
case NET_EVENT_IPV4_ACD_CONFLICT:
|
||||||
ipv4auto->probe_cnt = 0U;
|
net_ipv4_autoconf_reset(iface);
|
||||||
ipv4auto->announce_cnt = 0U;
|
|
||||||
ipv4auto->conflict_cnt = 0U;
|
|
||||||
(void)memset(&ipv4auto->current_ip, 0, sizeof(struct in_addr));
|
|
||||||
NET_DBG("%s: Starting probe for 169.254.%d.%d", "Renew",
|
|
||||||
ipv4auto->requested_ip.s4_addr[2],
|
|
||||||
ipv4auto->requested_ip.s4_addr[3]);
|
|
||||||
ipv4_autoconf_send_probe(ipv4auto);
|
|
||||||
break;
|
|
||||||
case NET_IPV4_AUTOCONF_PROBE:
|
|
||||||
/* schedule next probe */
|
|
||||||
if (ipv4auto->probe_cnt <= (IPV4_AUTOCONF_PROBE_NUM - 1)) {
|
|
||||||
ipv4_autoconf_send_probe(ipv4auto);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
__fallthrough;
|
__fallthrough;
|
||||||
case NET_IPV4_AUTOCONF_ANNOUNCE:
|
case NET_EVENT_IPV4_ACD_FAILED:
|
||||||
ipv4_autoconf_addr_set(ipv4auto);
|
/* Try new address. */
|
||||||
|
cfg->ipv4auto.state = NET_IPV4_AUTOCONF_INIT;
|
||||||
|
ipv4_autoconf_addr_set(&cfg->ipv4auto);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t ipv4_autoconf_get_timeout(struct net_if_ipv4_autoconf *ipv4auto)
|
|
||||||
{
|
|
||||||
switch (ipv4auto->state) {
|
|
||||||
case NET_IPV4_AUTOCONF_PROBE:
|
|
||||||
if (ipv4auto->conflict_cnt >= IPV4_AUTOCONF_MAX_CONFLICTS) {
|
|
||||||
NET_DBG("Rate limiting");
|
|
||||||
return MSEC_PER_SEC * IPV4_AUTOCONF_RATE_LIMIT_INTERVAL;
|
|
||||||
|
|
||||||
} else if (ipv4auto->probe_cnt == IPV4_AUTOCONF_PROBE_NUM) {
|
|
||||||
return MSEC_PER_SEC * IPV4_AUTOCONF_ANNOUNCE_INTERVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IPV4_AUTOCONF_PROBE_WAIT * MSEC_PER_SEC +
|
|
||||||
(sys_rand32_get() % MSEC_PER_SEC);
|
|
||||||
|
|
||||||
case NET_IPV4_AUTOCONF_ANNOUNCE:
|
|
||||||
return MSEC_PER_SEC * IPV4_AUTOCONF_ANNOUNCE_INTERVAL;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipv4_autoconf_submit_work(uint32_t timeout)
|
|
||||||
{
|
|
||||||
k_work_cancel_delayable(&ipv4auto_timer);
|
|
||||||
k_work_reschedule(&ipv4auto_timer, K_MSEC(timeout));
|
|
||||||
|
|
||||||
NET_DBG("Next wakeup in %d ms",
|
|
||||||
k_ticks_to_ms_ceil32(
|
|
||||||
k_work_delayable_remaining_get(&ipv4auto_timer)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ipv4_autoconf_check_timeout(int64_t start, uint32_t time, int64_t timeout)
|
|
||||||
{
|
|
||||||
start += time;
|
|
||||||
if (start < 0) {
|
|
||||||
start = -start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start > timeout) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ipv4_autoconf_timedout(struct net_if_ipv4_autoconf *ipv4auto,
|
|
||||||
int64_t timeout)
|
|
||||||
{
|
|
||||||
return ipv4_autoconf_check_timeout(ipv4auto->timer_start,
|
|
||||||
ipv4auto->timer_timeout,
|
|
||||||
timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t ipv4_autoconf_manage_timeouts(
|
|
||||||
struct net_if_ipv4_autoconf *ipv4auto,
|
|
||||||
int64_t timeout)
|
|
||||||
{
|
|
||||||
if (ipv4_autoconf_timedout(ipv4auto, timeout)) {
|
|
||||||
ipv4_autoconf_send(ipv4auto);
|
|
||||||
}
|
|
||||||
|
|
||||||
ipv4auto->timer_timeout = ipv4_autoconf_get_timeout(ipv4auto);
|
|
||||||
|
|
||||||
return ipv4auto->timer_timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipv4_autoconf_timeout(struct k_work *work)
|
|
||||||
{
|
|
||||||
uint32_t timeout_update = UINT32_MAX - 1;
|
|
||||||
int64_t timeout = k_uptime_get();
|
|
||||||
struct net_if_ipv4_autoconf *current, *next;
|
|
||||||
|
|
||||||
ARG_UNUSED(work);
|
|
||||||
|
|
||||||
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ipv4auto_ifaces, current, next,
|
|
||||||
node) {
|
|
||||||
uint32_t next_timeout;
|
|
||||||
|
|
||||||
next_timeout = ipv4_autoconf_manage_timeouts(current, timeout);
|
|
||||||
if (next_timeout < timeout_update) {
|
|
||||||
timeout_update = next_timeout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout_update != UINT32_MAX && timeout_update > 0) {
|
|
||||||
NET_DBG("Waiting for %u ms", timeout_update);
|
|
||||||
|
|
||||||
k_work_reschedule(&ipv4auto_timer, K_MSEC(timeout_update));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipv4_autoconf_start_timer(struct net_if *iface,
|
|
||||||
struct net_if_ipv4_autoconf *ipv4auto)
|
|
||||||
{
|
|
||||||
sys_slist_append(&ipv4auto_ifaces, &ipv4auto->node);
|
|
||||||
|
|
||||||
ipv4auto->timer_start = k_uptime_get();
|
|
||||||
ipv4auto->timer_timeout = MSEC_PER_SEC * IPV4_AUTOCONF_START_DELAY;
|
|
||||||
ipv4auto->iface = iface;
|
|
||||||
|
|
||||||
ipv4_autoconf_submit_work(ipv4auto->timer_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void net_ipv4_autoconf_start(struct net_if *iface)
|
void net_ipv4_autoconf_start(struct net_if *iface)
|
||||||
{
|
{
|
||||||
/* Initialize interface and start probing */
|
/* Initialize interface and start probing */
|
||||||
|
|
@ -359,15 +121,18 @@ void net_ipv4_autoconf_start(struct net_if *iface)
|
||||||
net_ipv4_autoconf_reset(iface);
|
net_ipv4_autoconf_reset(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg->ipv4auto.iface = iface;
|
||||||
|
|
||||||
NET_DBG("Starting IPv4 autoconf for iface %p", iface);
|
NET_DBG("Starting IPv4 autoconf for iface %p", iface);
|
||||||
|
|
||||||
if (cfg->ipv4auto.state == NET_IPV4_AUTOCONF_ASSIGNED) {
|
if (cfg->ipv4auto.state == NET_IPV4_AUTOCONF_ASSIGNED) {
|
||||||
|
/* Try to reuse previously used address. */
|
||||||
cfg->ipv4auto.state = NET_IPV4_AUTOCONF_RENEW;
|
cfg->ipv4auto.state = NET_IPV4_AUTOCONF_RENEW;
|
||||||
} else {
|
} else {
|
||||||
cfg->ipv4auto.state = NET_IPV4_AUTOCONF_INIT;
|
cfg->ipv4auto.state = NET_IPV4_AUTOCONF_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
ipv4_autoconf_start_timer(iface, &cfg->ipv4auto);
|
ipv4_autoconf_addr_set(&cfg->ipv4auto);
|
||||||
}
|
}
|
||||||
|
|
||||||
void net_ipv4_autoconf_reset(struct net_if *iface)
|
void net_ipv4_autoconf_reset(struct net_if *iface)
|
||||||
|
|
@ -379,22 +144,16 @@ void net_ipv4_autoconf_reset(struct net_if *iface)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize interface and start probing */
|
net_if_ipv4_addr_rm(iface, &cfg->ipv4auto.requested_ip);
|
||||||
if (cfg->ipv4auto.state == NET_IPV4_AUTOCONF_ASSIGNED) {
|
|
||||||
net_if_ipv4_addr_rm(iface, &cfg->ipv4auto.current_ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
NET_DBG("Autoconf reset for %p", iface);
|
NET_DBG("Autoconf reset for %p", iface);
|
||||||
|
|
||||||
/* Cancel any ongoing probing/announcing attempt*/
|
|
||||||
sys_slist_find_and_remove(&ipv4auto_ifaces, &cfg->ipv4auto.node);
|
|
||||||
|
|
||||||
if (sys_slist_is_empty(&ipv4auto_ifaces)) {
|
|
||||||
k_work_cancel_delayable(&ipv4auto_timer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void net_ipv4_autoconf_init(void)
|
void net_ipv4_autoconf_init(void)
|
||||||
{
|
{
|
||||||
k_work_init_delayable(&ipv4auto_timer, ipv4_autoconf_timeout);
|
net_mgmt_init_event_callback(&mgmt4_acd_cb, acd_event_handler,
|
||||||
|
NET_EVENT_IPV4_ACD_SUCCEED |
|
||||||
|
NET_EVENT_IPV4_ACD_FAILED |
|
||||||
|
NET_EVENT_IPV4_ACD_CONFLICT);
|
||||||
|
net_mgmt_add_event_callback(&mgmt4_acd_cb);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Matthias Boesl
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @file
|
|
||||||
* @brief IPv4 Autoconfiguration
|
|
||||||
*
|
|
||||||
* This is not to be included by the application.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __IPV4_AUTOCONF_INTERNAL_H
|
|
||||||
#define __IPV4_AUTOCONF_INTERNAL_H
|
|
||||||
|
|
||||||
#include <zephyr/kernel.h>
|
|
||||||
|
|
||||||
#include <zephyr/net/ipv4_autoconf.h>
|
|
||||||
|
|
||||||
/* Initial random delay*/
|
|
||||||
#define IPV4_AUTOCONF_PROBE_WAIT 1
|
|
||||||
|
|
||||||
/* Number of probe packets */
|
|
||||||
#define IPV4_AUTOCONF_PROBE_NUM 3
|
|
||||||
|
|
||||||
/* Minimum delay till repeated probe */
|
|
||||||
#define IPV4_AUTOCONF_PROBE_MIN 1
|
|
||||||
|
|
||||||
/* Maximum delay till repeated probe */
|
|
||||||
#define IPV4_AUTOCONF_PROBE_MAX 2
|
|
||||||
|
|
||||||
/* Number of announcement packets */
|
|
||||||
#define IPV4_AUTOCONF_ANNOUNCE_NUM 2
|
|
||||||
|
|
||||||
/* Time between announcement packets */
|
|
||||||
#define IPV4_AUTOCONF_ANNOUNCE_INTERVAL 2
|
|
||||||
|
|
||||||
/* Max conflicts before rate limiting */
|
|
||||||
#define IPV4_AUTOCONF_MAX_CONFLICTS 10
|
|
||||||
|
|
||||||
/* Delay between successive attempts */
|
|
||||||
#define IPV4_AUTOCONF_RATE_LIMIT_INTERVAL 60
|
|
||||||
|
|
||||||
/* Minimum interval between defensive ARPs */
|
|
||||||
#define IPV4_AUTOCONF_DEFEND_INTERVAL 10
|
|
||||||
|
|
||||||
/* Time between carrier up and first probe */
|
|
||||||
#define IPV4_AUTOCONF_START_DELAY 3
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Start IPv4 autoconfiguration RFC 3927: IPv4 Link Local
|
|
||||||
*
|
|
||||||
* @details Start IPv4 IP autoconfiguration
|
|
||||||
*
|
|
||||||
* @param iface A valid pointer on an interface
|
|
||||||
*/
|
|
||||||
#if defined(CONFIG_NET_IPV4_AUTO)
|
|
||||||
void net_ipv4_autoconf_start(struct net_if *iface);
|
|
||||||
#else
|
|
||||||
#define net_ipv4_autoconf_start(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reset autoconf process
|
|
||||||
*
|
|
||||||
* @details Reset IPv4 IP autoconfiguration
|
|
||||||
*
|
|
||||||
* @param iface A valid pointer on an interface
|
|
||||||
*/
|
|
||||||
#if defined(CONFIG_NET_IPV4_AUTO)
|
|
||||||
void net_ipv4_autoconf_reset(struct net_if *iface);
|
|
||||||
#else
|
|
||||||
#define net_ipv4_autoconf_reset(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Autoconf ARP input message handler.
|
|
||||||
*
|
|
||||||
* @details Called when ARP message is received when auto is enabled.
|
|
||||||
*
|
|
||||||
* @param iface A valid pointer on an interface
|
|
||||||
* @param pkt Received network packet
|
|
||||||
*
|
|
||||||
* @return What should be done with packet (drop or accept)
|
|
||||||
*/
|
|
||||||
#if defined(CONFIG_NET_IPV4_AUTO)
|
|
||||||
enum net_verdict net_ipv4_autoconf_input(struct net_if *iface,
|
|
||||||
struct net_pkt *pkt);
|
|
||||||
#else
|
|
||||||
#define net_ipv4_autoconf_input(...) NET_CONTINUE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __IPV4_AUTOCONF_INTERNAL_H */
|
|
||||||
|
|
@ -21,6 +21,7 @@ LOG_MODULE_REGISTER(net_core, CONFIG_NET_CORE_LOG_LEVEL);
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <zephyr/net/ipv4_autoconf.h>
|
||||||
#include <zephyr/net/net_if.h>
|
#include <zephyr/net/net_if.h>
|
||||||
#include <zephyr/net/net_mgmt.h>
|
#include <zephyr/net/net_mgmt.h>
|
||||||
#include <zephyr/net/net_pkt.h>
|
#include <zephyr/net/net_pkt.h>
|
||||||
|
|
@ -55,7 +56,6 @@ LOG_MODULE_REGISTER(net_core, CONFIG_NET_CORE_LOG_LEVEL);
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "udp_internal.h"
|
#include "udp_internal.h"
|
||||||
#include "tcp_internal.h"
|
#include "tcp_internal.h"
|
||||||
#include "ipv4_autoconf_internal.h"
|
|
||||||
|
|
||||||
#include "net_stats.h"
|
#include "net_stats.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ LOG_MODULE_REGISTER(net_if, CONFIG_NET_IF_LOG_LEVEL);
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <zephyr/net/igmp.h>
|
#include <zephyr/net/igmp.h>
|
||||||
|
#include <zephyr/net/ipv4_autoconf.h>
|
||||||
#include <zephyr/net/net_core.h>
|
#include <zephyr/net/net_core.h>
|
||||||
#include <zephyr/net/net_event.h>
|
#include <zephyr/net/net_event.h>
|
||||||
#include <zephyr/net/net_pkt.h>
|
#include <zephyr/net/net_pkt.h>
|
||||||
|
|
@ -30,7 +31,6 @@ LOG_MODULE_REGISTER(net_if, CONFIG_NET_IF_LOG_LEVEL);
|
||||||
#include "net_private.h"
|
#include "net_private.h"
|
||||||
#include "ipv4.h"
|
#include "ipv4.h"
|
||||||
#include "ipv6.h"
|
#include "ipv6.h"
|
||||||
#include "ipv4_autoconf_internal.h"
|
|
||||||
|
|
||||||
#include "net_stats.h"
|
#include "net_stats.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ LOG_MODULE_REGISTER(net_ethernet, CONFIG_NET_L2_ETHERNET_LOG_LEVEL);
|
||||||
#include "net_private.h"
|
#include "net_private.h"
|
||||||
#include "ipv6.h"
|
#include "ipv6.h"
|
||||||
#include "ipv4.h"
|
#include "ipv4.h"
|
||||||
#include "ipv4_autoconf_internal.h"
|
|
||||||
#include "bridge.h"
|
#include "bridge.h"
|
||||||
|
|
||||||
#define NET_BUF_TIMEOUT K_MSEC(100)
|
#define NET_BUF_TIMEOUT K_MSEC(100)
|
||||||
|
|
@ -391,11 +390,6 @@ static enum net_verdict ethernet_recv(struct net_if *iface,
|
||||||
net_sprint_ll_addr((uint8_t *)hdr->src.addr,
|
net_sprint_ll_addr((uint8_t *)hdr->src.addr,
|
||||||
sizeof(struct net_eth_addr)));
|
sizeof(struct net_eth_addr)));
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_NET_IPV4_AUTO) &&
|
|
||||||
net_ipv4_autoconf_input(iface, pkt) == NET_DROP) {
|
|
||||||
return NET_DROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_NET_IPV4_ACD) &&
|
if (IS_ENABLED(CONFIG_NET_IPV4_ACD) &&
|
||||||
net_ipv4_acd_input(iface, pkt) == NET_DROP) {
|
net_ipv4_acd_input(iface, pkt) == NET_DROP) {
|
||||||
return NET_DROP;
|
return NET_DROP;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue