]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ipv4ll.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / network / networkd-ipv4ll.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
b22d8a00 2
9aa5d8ba 3#include <netinet/in.h>
b22d8a00
TG
4#include <linux/if.h>
5
b5cc5591 6#include "netif-util.h"
23f53b99 7#include "networkd-address.h"
29104ded 8#include "networkd-ipv4acd.h"
ca5ad760 9#include "networkd-ipv4ll.h"
23f53b99 10#include "networkd-link.h"
ca5ad760 11#include "networkd-manager.h"
76c5a0f2 12#include "networkd-queue.h"
ca5ad760 13#include "parse-util.h"
b22d8a00 14
29104ded
YW
15bool link_ipv4ll_enabled(Link *link) {
16 assert(link);
17
18 if (!link_ipv4acd_supported(link))
19 return false;
20
21 if (!link->network)
22 return false;
23
24 if (link->network->bond)
25 return false;
26
27 return link->network->link_local & ADDRESS_FAMILY_IPV4;
28}
29
76c5a0f2 30static int address_new_from_ipv4ll(Link *link, Address **ret) {
8e766630 31 _cleanup_(address_freep) Address *address = NULL;
b22d8a00
TG
32 struct in_addr addr;
33 int r;
34
35 assert(link);
76c5a0f2
YW
36 assert(link->ipv4ll);
37 assert(ret);
b22d8a00
TG
38
39 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
40 if (r < 0)
76c5a0f2 41 return r;
b22d8a00 42
f0213e37 43 r = address_new(&address);
fc95c359 44 if (r < 0)
76c5a0f2 45 return -ENOMEM;
b22d8a00 46
3b6a3bde 47 address->source = NETWORK_CONFIG_SOURCE_IPV4LL;
b22d8a00
TG
48 address->family = AF_INET;
49 address->in_addr.in = addr;
50 address->prefixlen = 16;
51 address->scope = RT_SCOPE_LINK;
76c5a0f2 52 address->route_metric = IPV4LL_ROUTE_METRIC;
e680486d 53 address_set_broadcast(address, link);
76c5a0f2
YW
54
55 *ret = TAKE_PTR(address);
56 return 0;
57}
58
59static int ipv4ll_address_lost(Link *link) {
60 _cleanup_(address_freep) Address *address = NULL;
3b6a3bde 61 Address *existing;
76c5a0f2
YW
62 int r;
63
64 assert(link);
b22d8a00 65
76c5a0f2
YW
66 link->ipv4ll_address_configured = false;
67
68 r = address_new_from_ipv4ll(link, &address);
69 if (r == -ENOENT)
70 return 0;
807341ec
YW
71 if (r < 0)
72 return r;
b22d8a00 73
3b6a3bde
YW
74 if (address_get(link, address, &existing) < 0)
75 return 0;
76
77 if (existing->source != NETWORK_CONFIG_SOURCE_IPV4LL)
78 return 0;
79
80 if (!address_exists(existing))
81 return 0;
82
76c5a0f2
YW
83 log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
84 IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
b22d8a00 85
3b6a3bde 86 return address_remove(existing);
b22d8a00
TG
87}
88
80d62d4f 89static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
b22d8a00
TG
90 int r;
91
92 assert(link);
1c09d84e 93 assert(!link->ipv4ll_address_configured);
b22d8a00 94
5a07fa9d
YW
95 r = address_configure_handler_internal(rtnl, m, link, "Could not set ipv4ll address");
96 if (r <= 0)
97 return r;
b22d8a00 98
1c09d84e 99 link->ipv4ll_address_configured = true;
2aa7d367 100 link_check_ready(link);
b22d8a00
TG
101
102 return 1;
103}
104
105static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
76c5a0f2 106 _cleanup_(address_freep) Address *address = NULL;
b22d8a00
TG
107 int r;
108
109 assert(ll);
110 assert(link);
111
1c09d84e 112 link->ipv4ll_address_configured = false;
79316750 113
76c5a0f2 114 r = address_new_from_ipv4ll(link, &address);
b22d8a00
TG
115 if (r == -ENOENT)
116 return 0;
b22d8a00
TG
117 if (r < 0)
118 return r;
119
76c5a0f2
YW
120 log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR,
121 IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
b22d8a00 122
76c5a0f2 123 return link_request_address(link, TAKE_PTR(address), true, NULL, ipv4ll_address_handler, NULL);
b22d8a00
TG
124}
125
9ed794a3 126static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
99534007 127 Link *link = ASSERT_PTR(userdata);
b22d8a00
TG
128 int r;
129
b22d8a00 130 assert(link->network);
b22d8a00
TG
131
132 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
133 return;
134
89346ac6 135 switch (event) {
be19c5b5 136 case SD_IPV4LL_EVENT_STOP:
0698ff41
JR
137 r = ipv4ll_address_lost(link);
138 if (r < 0) {
139 link_enter_failed(link);
140 return;
141 }
142 break;
be19c5b5 143 case SD_IPV4LL_EVENT_CONFLICT:
b22d8a00
TG
144 r = ipv4ll_address_lost(link);
145 if (r < 0) {
146 link_enter_failed(link);
147 return;
148 }
0698ff41
JR
149
150 r = sd_ipv4ll_restart(ll);
89d8ed99 151 if (r < 0) {
aa5f4c77 152 log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
89d8ed99
YW
153 link_enter_failed(link);
154 }
b22d8a00 155 break;
be19c5b5 156 case SD_IPV4LL_EVENT_BIND:
b22d8a00
TG
157 r = ipv4ll_address_claimed(ll, link);
158 if (r < 0) {
79316750 159 log_link_error(link, "Failed to configure ipv4ll address: %m");
b22d8a00
TG
160 link_enter_failed(link);
161 return;
162 }
163 break;
164 default:
b45e4eb6 165 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
b22d8a00
TG
166 break;
167 }
168}
169
d7ab6ef0 170static int ipv4ll_check_mac(sd_ipv4ll *ll, const struct ether_addr *mac, void *userdata) {
99534007 171 Manager *m = ASSERT_PTR(userdata);
d7ab6ef0
YW
172 struct hw_addr_data hw_addr;
173
d7ab6ef0
YW
174 assert(mac);
175
176 hw_addr = (struct hw_addr_data) {
177 .length = ETH_ALEN,
178 .ether = *mac,
179 };
180
181 return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
182}
183
b22d8a00 184int ipv4ll_configure(Link *link) {
dbe81cbd 185 uint64_t seed;
b22d8a00
TG
186 int r;
187
188 assert(link);
2ffd6d73 189
3ca1fab7 190 if (!link_ipv4ll_enabled(link))
2ffd6d73 191 return 0;
b22d8a00 192
bc9e40c9
YW
193 if (link->ipv4ll)
194 return -EBUSY;
ca97e7cd 195
bc9e40c9
YW
196 r = sd_ipv4ll_new(&link->ipv4ll);
197 if (r < 0)
198 return r;
199
200 r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0);
201 if (r < 0)
202 return r;
b22d8a00 203
8de56fb3
YW
204 if (link->dev &&
205 net_get_unique_predictable_data(link->dev, true, &seed) >= 0) {
51517f9e
YW
206 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
207 if (r < 0)
208 return r;
b22d8a00
TG
209 }
210
ca2b7cd8 211 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
b22d8a00
TG
212 if (r < 0)
213 return r;
214
2f8e7633 215 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
b22d8a00
TG
216 if (r < 0)
217 return r;
218
219 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
220 if (r < 0)
221 return r;
222
d7ab6ef0 223 return sd_ipv4ll_set_check_mac_callback(link->ipv4ll, ipv4ll_check_mac, link->manager);
b22d8a00 224}
ca5ad760 225
a3adb4a6 226int ipv4ll_update_mac(Link *link) {
a3adb4a6
YW
227 assert(link);
228
f8d6397a
YW
229 if (link->hw_addr.length != ETH_ALEN)
230 return 0;
231 if (ether_addr_is_null(&link->hw_addr.ether))
232 return 0;
a3adb4a6
YW
233 if (!link->ipv4ll)
234 return 0;
235
f8d6397a 236 return sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
a3adb4a6
YW
237}
238
ca5ad760
YW
239int config_parse_ipv4ll(
240 const char* unit,
241 const char *filename,
242 unsigned line,
243 const char *section,
244 unsigned section_line,
245 const char *lvalue,
246 int ltype,
247 const char *rvalue,
248 void *data,
249 void *userdata) {
250
99534007 251 AddressFamily *link_local = ASSERT_PTR(data);
ca5ad760
YW
252 int r;
253
254 assert(filename);
255 assert(lvalue);
256 assert(rvalue);
ca5ad760
YW
257
258 /* Note that this is mostly like
2d792895 259 * config_parse_address_family(), except that it
ca5ad760
YW
260 * applies only to IPv4 */
261
262 r = parse_boolean(rvalue);
263 if (r < 0) {
d96edb2c 264 log_syntax(unit, LOG_WARNING, filename, line, r,
ca5ad760
YW
265 "Failed to parse %s=%s, ignoring assignment. "
266 "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
267 lvalue, rvalue, lvalue);
268 return 0;
269 }
270
271 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
272
273 log_syntax(unit, LOG_WARNING, filename, line, 0,
274 "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
2d792895 275 lvalue, rvalue, address_family_to_string(*link_local));
ca5ad760
YW
276
277 return 0;
278}
34b63c9e
AK
279
280int config_parse_ipv4ll_address(
281 const char* unit,
282 const char *filename,
283 unsigned line,
284 const char *section,
285 unsigned section_line,
286 const char *lvalue,
287 int ltype,
288 const char *rvalue,
289 void *data,
290 void *userdata) {
291
292 union in_addr_union a;
293 struct in_addr *ipv4ll_address = ASSERT_PTR(data);
294 int r;
295
296 assert(filename);
297 assert(lvalue);
298 assert(rvalue);
299
300 if (isempty(rvalue)) {
301 *ipv4ll_address = (struct in_addr) {};
302 return 0;
303 }
304
305 r = in_addr_from_string(AF_INET, rvalue, &a);
306 if (r < 0) {
307 log_syntax(unit, LOG_WARNING, filename, line, r,
308 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
309 return 0;
310 }
d3efcd2d 311 if (!in4_addr_is_link_local_dynamic(&a.in)) {
34b63c9e 312 log_syntax(unit, LOG_WARNING, filename, line, 0,
d3efcd2d
YW
313 "Specified address cannot be used as an IPv4 link local address, ignoring assignment: %s",
314 rvalue);
34b63c9e
AK
315 return 0;
316 }
317
318 *ipv4ll_address = a.in;
319 return 0;
320}