1 /** @file
2 * @brief IPv4 autoconf related functions
3 */
4
5 /*
6 * Copyright (c) 2017 Matthias Boesl
7 * Copyright (c) 2018 Intel Corporation
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(net_ipv4_autoconf, CONFIG_NET_IPV4_AUTO_LOG_LEVEL);
14
15 #include "net_private.h"
16 #include <errno.h>
17 #include "../l2/ethernet/arp.h"
18 #include <zephyr/net/ipv4_autoconf.h>
19 #include <zephyr/net/net_pkt.h>
20 #include <zephyr/net/net_core.h>
21 #include <zephyr/net/net_if.h>
22 #include <zephyr/random/random.h>
23
24 static struct net_mgmt_event_callback mgmt4_acd_cb;
25
ipv4_autoconf_addr_set(struct net_if_ipv4_autoconf * ipv4auto)26 static inline void ipv4_autoconf_addr_set(struct net_if_ipv4_autoconf *ipv4auto)
27 {
28 struct in_addr netmask = { { { 255, 255, 0, 0 } } };
29
30 if (ipv4auto->state == NET_IPV4_AUTOCONF_INIT) {
31 ipv4auto->requested_ip.s4_addr[0] = 169U;
32 ipv4auto->requested_ip.s4_addr[1] = 254U;
33 ipv4auto->requested_ip.s4_addr[2] = sys_rand8_get() % 254;
34 ipv4auto->requested_ip.s4_addr[3] = sys_rand8_get() % 254;
35 }
36
37 NET_DBG("%s: Starting probe for 169.254.%d.%d",
38 ipv4auto->state == NET_IPV4_AUTOCONF_INIT ? "Init" : "Renew",
39 ipv4auto->requested_ip.s4_addr[2],
40 ipv4auto->requested_ip.s4_addr[3]);
41
42 /* Add IPv4 address to the interface, this will trigger conflict detection. */
43 if (!net_if_ipv4_addr_add(ipv4auto->iface, &ipv4auto->requested_ip,
44 NET_ADDR_AUTOCONF, 0)) {
45 NET_DBG("Failed to add IPv4 addr to iface %p",
46 ipv4auto->iface);
47 return;
48 }
49
50 net_if_ipv4_set_netmask_by_addr(ipv4auto->iface,
51 &ipv4auto->requested_ip,
52 &netmask);
53
54 ipv4auto->state = NET_IPV4_AUTOCONF_ASSIGNED;
55 }
56
acd_event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)57 static void acd_event_handler(struct net_mgmt_event_callback *cb,
58 uint32_t mgmt_event, struct net_if *iface)
59 {
60 struct net_if_config *cfg;
61 struct in_addr *addr;
62
63 cfg = net_if_get_config(iface);
64 if (!cfg) {
65 return;
66 }
67
68 if (cfg->ipv4auto.iface == NULL) {
69 return;
70 }
71
72 if (mgmt_event != NET_EVENT_IPV4_ACD_SUCCEED &&
73 mgmt_event != NET_EVENT_IPV4_ACD_FAILED &&
74 mgmt_event != NET_EVENT_IPV4_ACD_CONFLICT) {
75 return;
76 }
77
78 if (cb->info_length != sizeof(struct in_addr)) {
79 return;
80 }
81
82 addr = (struct in_addr *)cb->info;
83
84 if (!net_ipv4_addr_cmp(&cfg->ipv4auto.requested_ip, addr)) {
85 return;
86 }
87
88 switch (mgmt_event) {
89 case NET_EVENT_IPV4_ACD_SUCCEED:
90 cfg->ipv4auto.state = NET_IPV4_AUTOCONF_ASSIGNED;
91 break;
92 case NET_EVENT_IPV4_ACD_CONFLICT:
93 net_ipv4_autoconf_reset(iface);
94 __fallthrough;
95 case NET_EVENT_IPV4_ACD_FAILED:
96 /* Try new address. */
97 cfg->ipv4auto.state = NET_IPV4_AUTOCONF_INIT;
98 ipv4_autoconf_addr_set(&cfg->ipv4auto);
99 break;
100 default:
101 break;
102 }
103 }
104
net_ipv4_autoconf_start(struct net_if * iface)105 void net_ipv4_autoconf_start(struct net_if *iface)
106 {
107 /* Initialize interface and start probing */
108 struct net_if_config *cfg;
109
110 if (!net_if_flag_is_set(iface, NET_IF_IPV4)) {
111 return;
112 }
113
114 cfg = net_if_get_config(iface);
115 if (!cfg) {
116 return;
117 }
118
119 /* Remove the existing registration if found */
120 if (cfg->ipv4auto.iface == iface) {
121 net_ipv4_autoconf_reset(iface);
122 }
123
124 cfg->ipv4auto.iface = iface;
125
126 NET_DBG("Starting IPv4 autoconf for iface %p", iface);
127
128 if (cfg->ipv4auto.state == NET_IPV4_AUTOCONF_ASSIGNED) {
129 /* Try to reuse previously used address. */
130 cfg->ipv4auto.state = NET_IPV4_AUTOCONF_RENEW;
131 } else {
132 cfg->ipv4auto.state = NET_IPV4_AUTOCONF_INIT;
133 }
134
135 ipv4_autoconf_addr_set(&cfg->ipv4auto);
136 }
137
net_ipv4_autoconf_reset(struct net_if * iface)138 void net_ipv4_autoconf_reset(struct net_if *iface)
139 {
140 struct net_if_config *cfg;
141
142 cfg = net_if_get_config(iface);
143 if (!cfg) {
144 return;
145 }
146
147 net_if_ipv4_addr_rm(iface, &cfg->ipv4auto.requested_ip);
148
149 NET_DBG("Autoconf reset for %p", iface);
150 }
151
net_ipv4_autoconf_init(void)152 void net_ipv4_autoconf_init(void)
153 {
154 net_mgmt_init_event_callback(&mgmt4_acd_cb, acd_event_handler,
155 NET_EVENT_IPV4_ACD_SUCCEED |
156 NET_EVENT_IPV4_ACD_FAILED |
157 NET_EVENT_IPV4_ACD_CONFLICT);
158 net_mgmt_add_event_callback(&mgmt4_acd_cb);
159 }
160