]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
TODO: update resolved
[thirdparty/systemd.git] / src / network / networkd-link.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <netinet/ether.h>
23#include <linux/if.h>
4cc7a82c 24#include <unistd.h>
f579559b
TG
25
26#include "networkd.h"
3be1d7e0 27#include "networkd-netdev.h"
f579559b 28#include "libudev-private.h"
505f8da7 29#include "udev-util.h"
f579559b 30#include "util.h"
505f8da7 31#include "virt.h"
1346b1f0 32#include "bus-util.h"
c6f7c917 33#include "network-internal.h"
ed942a9e 34#include "conf-parser.h"
f579559b 35
3a67e927 36#include "network-util.h"
fe8db0c5
TG
37#include "dhcp-lease-internal.h"
38
aba496a5
UTL
39static int ipv4ll_address_update(Link *link, bool deprecate);
40static bool ipv4ll_is_bound(sd_ipv4ll *ll);
41
505f8da7 42static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
14b746f7 43 _cleanup_link_unref_ Link *link = NULL;
505f8da7 44 uint16_t type;
ca4e095a 45 const char *ifname;
505f8da7 46 int r, ifindex;
f579559b 47
0c2f9b84 48 assert(manager);
505f8da7 49 assert(message);
f579559b
TG
50 assert(ret);
51
505f8da7
TG
52 r = sd_rtnl_message_get_type(message, &type);
53 if (r < 0)
54 return r;
55 else if (type != RTM_NEWLINK)
56 return -EINVAL;
57
58 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
59 if (r < 0)
60 return r;
61 else if (ifindex <= 0)
62 return -EINVAL;
63
64 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &ifname);
65 if (r < 0)
66 return r;
67
f579559b
TG
68 link = new0(Link, 1);
69 if (!link)
70 return -ENOMEM;
71
14b746f7 72 link->n_ref = 1;
5a3eb5a7 73 link->manager = manager;
505f8da7
TG
74 link->state = LINK_STATE_INITIALIZING;
75 link->ifindex = ifindex;
76 link->ifname = strdup(ifname);
77 if (!link->ifname)
78 return -ENOMEM;
f579559b 79
512922f8
TG
80 r = sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
81 if (r < 0)
1a941ac4 82 log_debug_link(link, "MAC address not found for new device, continuing without");
512922f8 83
ae06ab10 84 r = asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex);
fe8db0c5 85 if (r < 0)
315db1a8 86 return -ENOMEM;
fe8db0c5 87
ae06ab10 88 r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex);
68a8723c
TG
89 if (r < 0)
90 return -ENOMEM;
91
ae06ab10
TG
92 r = hashmap_ensure_allocated(&manager->links, NULL, NULL);
93 if (r < 0)
94 return r;
95
96 r = hashmap_put(manager->links, INT_TO_PTR(link->ifindex), link);
f579559b
TG
97 if (r < 0)
98 return r;
99
100 *ret = link;
101 link = NULL;
102
103 return 0;
104}
105
14b746f7 106static void link_free(Link *link) {
428fd0a7
TG
107 Address *address;
108
f579559b
TG
109 if (!link)
110 return;
111
428fd0a7
TG
112 while ((address = link->addresses)) {
113 LIST_REMOVE(addresses, link->addresses, address);
114 address_free(address);
115 }
116
11bf3cce
LP
117 while ((address = link->pool_addresses)) {
118 LIST_REMOVE(addresses, link->pool_addresses, address);
119 address_free(address);
120 }
121
e5b04c8d 122 sd_dhcp_client_unref(link->dhcp_client);
a6cc569e 123 sd_dhcp_lease_unref(link->dhcp_lease);
f5be5601 124
68a8723c
TG
125 unlink(link->lease_file);
126 free(link->lease_file);
127
56cd007a 128 sd_ipv4ll_unref(link->ipv4ll);
4138fb2c 129 sd_dhcp6_client_unref(link->dhcp6_client);
6b66097b 130 sd_icmp6_nd_unref(link->icmp6_router_discovery);
4138fb2c 131
28aeb07f 132 if (link->manager)
ae06ab10 133 hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
f579559b 134
c166a070 135 free(link->ifname);
68a8723c
TG
136
137 unlink(link->state_file);
fe8db0c5 138 free(link->state_file);
c166a070 139
b5db00e5
UTL
140 udev_device_unref(link->udev_device);
141
f579559b
TG
142 free(link);
143}
144
14b746f7
TG
145Link *link_unref(Link *link) {
146 if (link && (-- link->n_ref <= 0))
147 link_free(link);
148
149 return NULL;
150}
151
152Link *link_ref(Link *link) {
153 if (link)
154 assert_se(++ link->n_ref >= 2);
155
156 return link;
157}
158
11a7f229
TG
159int link_get(Manager *m, int ifindex, Link **ret) {
160 Link *link;
11a7f229
TG
161
162 assert(m);
11a7f229
TG
163 assert(ifindex);
164 assert(ret);
165
ae06ab10 166 link = hashmap_get(m->links, INT_TO_PTR(ifindex));
11a7f229
TG
167 if (!link)
168 return -ENODEV;
169
170 *ret = link;
171
172 return 0;
173}
174
370e9930
TG
175void link_drop(Link *link) {
176 if (!link || link->state == LINK_STATE_LINGER)
177 return;
178
179 link->state = LINK_STATE_LINGER;
180
7619683b 181 log_debug_link(link, "link removed");
370e9930
TG
182
183 link_unref(link);
184
185 return;
186}
187
57bd6899
TG
188static void link_enter_unmanaged(Link *link) {
189 assert(link);
190
df9aa406 191 log_debug_link(link, "unmanaged");
57bd6899
TG
192
193 link->state = LINK_STATE_UNMANAGED;
194
195 link_save(link);
196}
197
111bb8f9
TG
198static int link_stop_clients(Link *link) {
199 int r = 0, k;
200
201 assert(link);
202 assert(link->manager);
203 assert(link->manager->event);
204
205 if (!link->network)
206 return 0;
207
ed942a9e 208 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
111bb8f9
TG
209 assert(link->dhcp_client);
210
211 k = sd_dhcp_client_stop(link->dhcp_client);
212 if (k < 0) {
213 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
214 r = k;
215 }
216 }
217
218 if (link->network->ipv4ll) {
219 assert(link->ipv4ll);
220
221 k = sd_ipv4ll_stop(link->ipv4ll);
222 if (k < 0) {
223 log_warning_link(link, "Could not stop IPv4 link-local: %s", strerror(-r));
224 r = k;
225 }
226 }
227
dd43110f
TG
228 if (link->network->dhcp_server) {
229 assert(link->dhcp_server);
230
231 k = sd_dhcp_server_stop(link->dhcp_server);
232 if (k < 0) {
233 log_warning_link(link, "Could not stop DHCPv4 server: %s", strerror(-r));
234 r = k;
235 }
236 }
237
ed942a9e 238 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
1873a3d3
PF
239 assert(link->icmp6_router_discovery);
240
241 if (link->dhcp6_client) {
242 k = sd_dhcp6_client_stop(link->dhcp6_client);
243 if (k < 0) {
244 log_warning_link(link, "Could not stop DHCPv6 client: %s", strerror(-r));
245 r = k;
246 }
247 }
4138fb2c 248
1873a3d3 249 k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
4138fb2c 250 if (k < 0) {
1873a3d3 251 log_warning_link(link, "Could not stop ICMPv6 router discovery: %s", strerror(-r));
4138fb2c
PF
252 r = k;
253 }
254 }
255
111bb8f9
TG
256 return r;
257}
258
ef1ba606
TG
259static void link_enter_failed(Link *link) {
260 assert(link);
f882c247 261
370e9930 262 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
2139694e
TG
263 return;
264
39032b87 265 log_warning_link(link, "failed");
449f7554 266
ef1ba606 267 link->state = LINK_STATE_FAILED;
fe8db0c5 268
111bb8f9
TG
269 link_stop_clients(link);
270
fe8db0c5 271 link_save(link);
f882c247
TG
272}
273
4f434938
LP
274static Address* link_find_dhcp_server_address(Link *link) {
275 Address *address;
276
277 assert(link);
278 assert(link->network);
279
280 /* The the first statically configured address if there is any */
281 LIST_FOREACH(addresses, address, link->network->static_addresses) {
282
283 if (address->family != AF_INET)
284 continue;
285
af93291c 286 if (in_addr_is_null(address->family, &address->in_addr))
4f434938
LP
287 continue;
288
289 return address;
290 }
291
292 /* If that didn't work, find a suitable address we got from the pool */
293 LIST_FOREACH(addresses, address, link->pool_addresses) {
294 if (address->family != AF_INET)
295 continue;
296
297 return address;
298 }
299
300 return NULL;
301}
302
dd43110f
TG
303static int link_enter_configured(Link *link) {
304 int r;
305
306 assert(link);
307 assert(link->network);
308 assert(link->state == LINK_STATE_SETTING_ROUTES);
309
7c16313f
TG
310 if (link->network->dhcp_server &&
311 !sd_dhcp_server_is_running(link->dhcp_server)) {
4f434938
LP
312 struct in_addr pool_start;
313 Address *address;
314
315 address = link_find_dhcp_server_address(link);
316 if (!address) {
317 log_warning_link(link, "Failed to find suitable address for DHCPv4 server instance.");
318 link_enter_failed(link);
319 return 0;
320 }
321
dd43110f
TG
322 log_debug_link(link, "offering DHCPv4 leases");
323
4f434938
LP
324 r = sd_dhcp_server_set_address(link->dhcp_server, &address->in_addr.in);
325 if (r < 0)
326 return r;
327
328 /* offer 32 addresses starting from the address following the server address */
329 pool_start.s_addr = htobe32(be32toh(address->in_addr.in.s_addr) + 1);
330 r = sd_dhcp_server_set_lease_pool(link->dhcp_server,
331 &pool_start, 32);
332 if (r < 0)
333 return r;
334
335 /* TODO:
336 r = sd_dhcp_server_set_router(link->dhcp_server,
337 &main_address->in_addr.in);
338 if (r < 0)
339 return r;
340
341 r = sd_dhcp_server_set_prefixlen(link->dhcp_server,
342 main_address->prefixlen);
343 if (r < 0)
344 return r;
345 */
346
dd43110f
TG
347 r = sd_dhcp_server_start(link->dhcp_server);
348 if (r < 0) {
349 log_warning_link(link, "could not start DHCPv4 server "
350 "instance: %s", strerror(-r));
351
352 link_enter_failed(link);
353
354 return 0;
355 }
356 }
357
358 log_info_link(link, "link configured");
359
360 link->state = LINK_STATE_CONFIGURED;
361
362 link_save(link);
363
364 return 0;
365}
366
f882c247 367static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 368 _cleanup_link_unref_ Link *link = userdata;
f882c247
TG
369 int r;
370
f5be5601 371 assert(link->route_messages > 0);
370e9930
TG
372 assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
373 LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
374 LINK_STATE_LINGER));
f882c247 375
f5be5601 376 link->route_messages --;
f882c247 377
5da8149f 378 if (IN_SET(LINK_STATE_FAILED, LINK_STATE_LINGER))
f882c247
TG
379 return 1;
380
381 r = sd_rtnl_message_get_errno(m);
c166a070 382 if (r < 0 && r != -EEXIST)
c9ccc19f 383 log_struct_link(LOG_WARNING, link,
97578344 384 "MESSAGE=%-*s: could not set route: %s",
987efa17 385 IFNAMSIZ,
c9ccc19f
TG
386 link->ifname, strerror(-r),
387 "ERRNO=%d", -r,
388 NULL);
f882c247 389
f5be5601
TG
390 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
391 * ignore it */
392 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
39032b87 393 log_debug_link(link, "routes set");
dd3efc09
TG
394 link_enter_configured(link);
395 }
f882c247
TG
396
397 return 1;
398}
399
e1ea665e
EY
400static int link_set_dhcp_routes(Link *link) {
401 struct sd_dhcp_route *static_routes;
a2ba62c7 402 int r, n, i;
e1ea665e
EY
403
404 assert(link);
405
a2ba62c7
LP
406 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
407 if (n < 0) {
408 if (n != -ENOENT)
409 log_warning_link(link, "DHCP error: could not get routes: %s", strerror(-n));
410 return n;
e1ea665e
EY
411 }
412
a2ba62c7 413 for (i = 0; i < n; i++) {
e1ea665e
EY
414 _cleanup_route_free_ Route *route = NULL;
415
28cc555d 416 r = route_new_dynamic(&route, RTPROT_DHCP);
e1ea665e
EY
417 if (r < 0) {
418 log_error_link(link, "Could not allocate route: %s",
419 strerror(-r));
420 return r;
421 }
422
423 route->family = AF_INET;
424 route->in_addr.in = static_routes[i].gw_addr;
425 route->dst_addr.in = static_routes[i].dst_addr;
426 route->dst_prefixlen = static_routes[i].dst_prefixlen;
4faefc7f 427 route->metrics = DHCP_ROUTE_METRIC;
e1ea665e
EY
428
429 r = route_configure(route, link, &route_handler);
430 if (r < 0) {
431 log_warning_link(link,
432 "could not set host route: %s", strerror(-r));
433 return r;
434 }
435
e1ea665e
EY
436 link->route_messages ++;
437 }
438
439 return 0;
440}
441
f882c247 442static int link_enter_set_routes(Link *link) {
a6cc569e 443 Route *rt;
f882c247
TG
444 int r;
445
446 assert(link);
447 assert(link->network);
ef1ba606 448 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
f882c247 449
ef1ba606 450 link->state = LINK_STATE_SETTING_ROUTES;
f882c247 451
5c1d3fc9 452 if (!link->network->static_routes && !link->dhcp_lease &&
370e9930 453 (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
dd3efc09 454 return link_enter_configured(link);
f882c247 455
39032b87 456 log_debug_link(link, "setting routes");
449f7554 457
3d3d4255 458 LIST_FOREACH(routes, rt, link->network->static_routes) {
a6cc569e 459 r = route_configure(rt, link, &route_handler);
dd3efc09 460 if (r < 0) {
3333d748
ZJS
461 log_warning_link(link,
462 "could not set routes: %s", strerror(-r));
ef1ba606
TG
463 link_enter_failed(link);
464 return r;
dd3efc09 465 }
c166a070 466
f5be5601
TG
467 link->route_messages ++;
468 }
469
5c1d3fc9
UTL
470 if (link->ipv4ll && !link->dhcp_lease) {
471 _cleanup_route_free_ Route *route = NULL;
5c1d3fc9
UTL
472
473 if (r != -ENOENT) {
28cc555d 474 r = route_new_dynamic(&route, RTPROT_STATIC);
5c1d3fc9
UTL
475 if (r < 0) {
476 log_error_link(link, "Could not allocate route: %s",
477 strerror(-r));
478 return r;
479 }
480
481 route->family = AF_INET;
482 route->scope = RT_SCOPE_LINK;
4faefc7f 483 route->metrics = IPV4LL_ROUTE_METRIC;
5c1d3fc9
UTL
484
485 r = route_configure(route, link, &route_handler);
486 if (r < 0) {
487 log_warning_link(link,
488 "could not set routes: %s", strerror(-r));
489 link_enter_failed(link);
490 return r;
491 }
492
493 link->route_messages ++;
494 }
495 }
496
a6cc569e
TG
497 if (link->dhcp_lease) {
498 _cleanup_route_free_ Route *route = NULL;
9765ce69 499 _cleanup_route_free_ Route *route_gw = NULL;
a6cc569e
TG
500 struct in_addr gateway;
501
502 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
8ddbeaa2 503 if (r < 0 && r != -ENOENT) {
b1666580
TG
504 log_warning_link(link, "DHCP error: could not get gateway: %s",
505 strerror(-r));
a6cc569e
TG
506 return r;
507 }
508
8ddbeaa2 509 if (r >= 0) {
28cc555d 510 r = route_new_dynamic(&route, RTPROT_DHCP);
8ddbeaa2
UTL
511 if (r < 0) {
512 log_error_link(link, "Could not allocate route: %s",
513 strerror(-r));
514 return r;
515 }
a6cc569e 516
28cc555d 517 r = route_new_dynamic(&route_gw, RTPROT_DHCP);
8ddbeaa2
UTL
518 if (r < 0) {
519 log_error_link(link, "Could not allocate route: %s",
520 strerror(-r));
521 return r;
522 }
9765ce69 523
8ddbeaa2
UTL
524 /* The dhcp netmask may mask out the gateway. Add an explicit
525 * route for the gw host so that we can route no matter the
526 * netmask or existing kernel route tables. */
527 route_gw->family = AF_INET;
528 route_gw->dst_addr.in = gateway;
529 route_gw->dst_prefixlen = 32;
530 route_gw->scope = RT_SCOPE_LINK;
4faefc7f 531 route_gw->metrics = DHCP_ROUTE_METRIC;
9765ce69 532
8ddbeaa2
UTL
533 r = route_configure(route_gw, link, &route_handler);
534 if (r < 0) {
535 log_warning_link(link,
536 "could not set host route: %s", strerror(-r));
537 return r;
538 }
9765ce69 539
8ddbeaa2 540 link->route_messages ++;
9765ce69 541
8ddbeaa2
UTL
542 route->family = AF_INET;
543 route->in_addr.in = gateway;
4faefc7f 544 route->metrics = DHCP_ROUTE_METRIC;
a6cc569e 545
8ddbeaa2
UTL
546 r = route_configure(route, link, &route_handler);
547 if (r < 0) {
548 log_warning_link(link,
549 "could not set routes: %s", strerror(-r));
550 link_enter_failed(link);
551 return r;
552 }
553
554 link->route_messages ++;
f5be5601 555 }
e1ea665e
EY
556
557 if (link->network->dhcp_routes)
558 link_set_dhcp_routes(link);
8ddbeaa2 559 }
f5be5601 560
8ddbeaa2
UTL
561 if (link->route_messages == 0) {
562 link_enter_configured(link);
f882c247
TG
563 }
564
565 return 0;
566}
567
5c1d3fc9 568static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 569 _cleanup_link_unref_ Link *link = userdata;
5c1d3fc9
UTL
570 int r;
571
572 assert(m);
573 assert(link);
574 assert(link->ifname);
575
5da8149f 576 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
5c1d3fc9
UTL
577 return 1;
578
579 r = sd_rtnl_message_get_errno(m);
b90b025a 580 if (r < 0 && r != -ESRCH)
5c1d3fc9 581 log_struct_link(LOG_WARNING, link,
97578344 582 "MESSAGE=%-*s: could not drop route: %s",
987efa17 583 IFNAMSIZ,
5c1d3fc9
UTL
584 link->ifname, strerror(-r),
585 "ERRNO=%d", -r,
586 NULL);
587
5bdd314c 588 return 1;
5c1d3fc9
UTL
589}
590
4958aee4
TG
591static int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
592 _cleanup_link_unref_ Link *link = userdata;
593 int r;
594
595 assert(rtnl);
596 assert(m);
597 assert(link);
598 assert(link->manager);
599
600 for (; m; m = sd_rtnl_message_next(m)) {
601 r = sd_rtnl_message_get_errno(m);
602 if (r < 0) {
603 log_debug_link(link, "getting address failed: %s", strerror(-r));
604 continue;
605 }
606
607 r = link_rtnl_process_address(rtnl, m, link->manager);
608 if (r < 0)
609 log_warning_link(link, "could not process address: %s", strerror(-r));
610 }
611
612 return 1;
613}
614
f882c247 615static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 616 _cleanup_link_unref_ Link *link = userdata;
f882c247
TG
617 int r;
618
4958aee4 619 assert(rtnl);
f5be5601
TG
620 assert(m);
621 assert(link);
622 assert(link->ifname);
623 assert(link->addr_messages > 0);
370e9930
TG
624 assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
625 LINK_STATE_FAILED, LINK_STATE_LINGER));
f882c247 626
f5be5601 627 link->addr_messages --;
f882c247 628
5da8149f 629 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
f882c247
TG
630 return 1;
631
632 r = sd_rtnl_message_get_errno(m);
c166a070 633 if (r < 0 && r != -EEXIST)
c9ccc19f 634 log_struct_link(LOG_WARNING, link,
97578344 635 "MESSAGE=%-*s: could not set address: %s",
987efa17 636 IFNAMSIZ,
3333d748
ZJS
637 link->ifname, strerror(-r),
638 "ERRNO=%d", -r,
639 NULL);
5bdd314c 640 else if (r >= 0) {
4958aee4
TG
641 /* calling handler directly so take a ref */
642 link_ref(link);
643 link_get_address_handler(rtnl, m, link);
644 }
f882c247 645
f5be5601 646 if (link->addr_messages == 0) {
39032b87 647 log_debug_link(link, "addresses set");
ef1ba606 648 link_enter_set_routes(link);
dd3efc09 649 }
f882c247
TG
650
651 return 1;
652}
653
654static int link_enter_set_addresses(Link *link) {
a6cc569e 655 Address *ad;
f882c247 656 int r;
68ceb9df 657 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
f882c247
TG
658
659 assert(link);
660 assert(link->network);
f5be5601 661 assert(link->state != _LINK_STATE_INVALID);
f882c247 662
ef1ba606 663 link->state = LINK_STATE_SETTING_ADDRESSES;
f882c247 664
5c1d3fc9 665 if (!link->network->static_addresses && !link->dhcp_lease &&
aba496a5 666 (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
ef1ba606 667 return link_enter_set_routes(link);
f882c247 668
39032b87 669 log_debug_link(link, "setting addresses");
449f7554 670
3d3d4255 671 LIST_FOREACH(addresses, ad, link->network->static_addresses) {
a6cc569e 672 r = address_configure(ad, link, &address_handler);
dd3efc09 673 if (r < 0) {
3333d748
ZJS
674 log_warning_link(link,
675 "could not set addresses: %s", strerror(-r));
ef1ba606
TG
676 link_enter_failed(link);
677 return r;
dd3efc09 678 }
c166a070 679
f5be5601
TG
680 link->addr_messages ++;
681 }
682
5c1d3fc9
UTL
683 if (link->ipv4ll && !link->dhcp_lease) {
684 _cleanup_address_free_ Address *ll_addr = NULL;
685 struct in_addr addr;
686
687 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
688 if (r < 0 && r != -ENOENT) {
689 log_warning_link(link, "IPV4LL error: no address: %s",
690 strerror(-r));
691 return r;
692 }
693
694 if (r != -ENOENT) {
695 r = address_new_dynamic(&ll_addr);
696 if (r < 0) {
697 log_error_link(link, "Could not allocate address: %s", strerror(-r));
698 return r;
699 }
700
701 ll_addr->family = AF_INET;
702 ll_addr->in_addr.in = addr;
703 ll_addr->prefixlen = 16;
704 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
705 ll_addr->scope = RT_SCOPE_LINK;
706
707 r = address_configure(ll_addr, link, &address_handler);
708 if (r < 0) {
709 log_warning_link(link,
710 "could not set addresses: %s", strerror(-r));
711 link_enter_failed(link);
712 return r;
713 }
714
715 link->addr_messages ++;
716 }
717 }
718
a6cc569e
TG
719 if (link->dhcp_lease) {
720 _cleanup_address_free_ Address *address = NULL;
721 struct in_addr addr;
722 struct in_addr netmask;
723 unsigned prefixlen;
724
725 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
726 if (r < 0) {
727 log_warning_link(link, "DHCP error: no address: %s",
728 strerror(-r));
729 return r;
730 }
731
68ceb9df
PF
732 if (!link->network->dhcp_critical) {
733 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
734 &lifetime);
735 if (r < 0) {
736 log_warning_link(link, "DHCP error: no lifetime: %s",
737 strerror(-r));
738 return r;
739 }
740 }
741
a6cc569e
TG
742 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
743 if (r < 0) {
744 log_warning_link(link, "DHCP error: no netmask: %s",
745 strerror(-r));
746 return r;
747 }
748
749 prefixlen = net_netmask_to_prefixlen(&netmask);
750
751 r = address_new_dynamic(&address);
752 if (r < 0) {
753 log_error_link(link, "Could not allocate address: %s",
754 strerror(-r));
755 return r;
756 }
757
758 address->family = AF_INET;
759 address->in_addr.in = addr;
68ceb9df
PF
760 address->cinfo.ifa_prefered = lifetime;
761 address->cinfo.ifa_valid = lifetime;
a6cc569e
TG
762 address->prefixlen = prefixlen;
763 address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
764
46ba9fba
TG
765 /* use update rather than configure so that we will update the lifetime
766 of an existing address if it has already been configured */
767 r = address_update(address, link, &address_handler);
f5be5601 768 if (r < 0) {
3333d748
ZJS
769 log_warning_link(link,
770 "could not set addresses: %s", strerror(-r));
f5be5601
TG
771 link_enter_failed(link);
772 return r;
773 }
774
775 link->addr_messages ++;
f882c247
TG
776 }
777
778 return 0;
779}
780
aba496a5 781static int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 782 _cleanup_link_unref_ Link *link = userdata;
aba496a5
UTL
783 int r;
784
785 assert(m);
786 assert(link);
787 assert(link->ifname);
788
5da8149f 789 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
aba496a5
UTL
790 return 1;
791
792 r = sd_rtnl_message_get_errno(m);
793 if (r < 0 && r != -ENOENT)
794 log_struct_link(LOG_WARNING, link,
97578344 795 "MESSAGE=%-*s: could not update address: %s",
987efa17 796 IFNAMSIZ,
aba496a5
UTL
797 link->ifname, strerror(-r),
798 "ERRNO=%d", -r,
799 NULL);
800
5bdd314c 801 return 1;
aba496a5
UTL
802}
803
ff254138 804static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 805 _cleanup_link_unref_ Link *link = userdata;
ff254138
TG
806 int r;
807
808 assert(m);
809 assert(link);
810 assert(link->ifname);
811
5da8149f 812 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
ff254138
TG
813 return 1;
814
815 r = sd_rtnl_message_get_errno(m);
b90b025a 816 if (r < 0 && r != -EADDRNOTAVAIL)
c9ccc19f 817 log_struct_link(LOG_WARNING, link,
97578344 818 "MESSAGE=%-*s: could not drop address: %s",
987efa17 819 IFNAMSIZ,
c9ccc19f
TG
820 link->ifname, strerror(-r),
821 "ERRNO=%d", -r,
822 NULL);
ff254138 823
5bdd314c 824 return 1;
ff254138
TG
825}
826
1346b1f0 827static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
5da8149f 828 _cleanup_link_unref_ Link *link = userdata;
1346b1f0
TG
829 int r;
830
b226d99b
TG
831 assert(link);
832
5da8149f 833 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
370e9930 834 return 1;
370e9930 835
1346b1f0
TG
836 r = sd_bus_message_get_errno(m);
837 if (r < 0)
70b34f5d
MM
838 r = -r;
839 if (r > 0)
840 log_warning_link(link, "Could not set hostname: %s", strerror(r));
1346b1f0
TG
841
842 return 1;
843}
844
b226d99b 845static int link_set_hostname(Link *link, const char *hostname) {
1346b1f0
TG
846 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
847 int r = 0;
848
b226d99b
TG
849 assert(link);
850 assert(link->manager);
1346b1f0
TG
851 assert(hostname);
852
b226d99b 853 log_debug_link(link, "Setting transient hostname: '%s'", hostname);
1346b1f0 854
b226d99b
TG
855 if (!link->manager->bus) { /* TODO: replace by assert when we can rely on kdbus */
856 log_info_link(link, "Not connected to system bus, ignoring transient hostname.");
bcbca829
TG
857 return 0;
858 }
859
1346b1f0 860 r = sd_bus_message_new_method_call(
b226d99b 861 link->manager->bus,
151b9b96 862 &m,
1346b1f0
TG
863 "org.freedesktop.hostname1",
864 "/org/freedesktop/hostname1",
865 "org.freedesktop.hostname1",
151b9b96 866 "SetHostname");
1346b1f0
TG
867 if (r < 0)
868 return r;
869
870 r = sd_bus_message_append(m, "sb", hostname, false);
871 if (r < 0)
872 return r;
873
19befb2d 874 r = sd_bus_call_async(link->manager->bus, NULL, m, set_hostname_handler, link, 0);
5da8149f 875 if (r < 0) {
b226d99b 876 log_error_link(link, "Could not set transient hostname: %s", strerror(-r));
5da8149f
TG
877 return r;
878 }
b226d99b
TG
879
880 link_ref(link);
1346b1f0 881
5da8149f 882 return 0;
1346b1f0
TG
883}
884
4f882b2a 885static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 886 _cleanup_link_unref_ Link *link = userdata;
4f882b2a
TG
887 int r;
888
889 assert(m);
890 assert(link);
891 assert(link->ifname);
892
5da8149f 893 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
4f882b2a
TG
894 return 1;
895
896 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
897 if (r < 0)
898 log_struct_link(LOG_WARNING, link,
97578344
TG
899 "MESSAGE=%-*s: could not set MTU: %s",
900 IFNAMSIZ, link->ifname, strerror(-r),
c9ccc19f
TG
901 "ERRNO=%d", -r,
902 NULL);
4f882b2a
TG
903
904 return 1;
905}
906
907static int link_set_mtu(Link *link, uint32_t mtu) {
cf6a8911 908 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
4f882b2a
TG
909 int r;
910
911 assert(link);
912 assert(link->manager);
913 assert(link->manager->rtnl);
914
915 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
916
151b9b96
LP
917 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
918 RTM_SETLINK, link->ifindex);
4f882b2a
TG
919 if (r < 0) {
920 log_error_link(link, "Could not allocate RTM_SETLINK message");
921 return r;
922 }
923
924 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
925 if (r < 0) {
926 log_error_link(link, "Could not append MTU: %s", strerror(-r));
927 return r;
928 }
929
930 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
931 if (r < 0) {
932 log_error_link(link,
933 "Could not send rtnetlink message: %s", strerror(-r));
934 return r;
935 }
936
ae941762 937 link_ref(link);
b226d99b 938
4f882b2a
TG
939 return 0;
940}
941
a6cc569e
TG
942static int dhcp_lease_lost(Link *link) {
943 _cleanup_address_free_ Address *address = NULL;
944 struct in_addr addr;
945 struct in_addr netmask;
3e790eae 946 struct in_addr gateway;
a6cc569e 947 unsigned prefixlen;
ff254138
TG
948 int r;
949
950 assert(link);
a6cc569e 951 assert(link->dhcp_lease);
ff254138 952
14efd761
TG
953 log_warning_link(link, "DHCP lease lost");
954
e1ea665e
EY
955 if (link->network->dhcp_routes) {
956 struct sd_dhcp_route *routes;
a2ba62c7 957 int n, i;
e1ea665e 958
a2ba62c7
LP
959 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
960 if (n >= 0) {
961 for (i = 0; i < n; i++) {
e1ea665e
EY
962 _cleanup_route_free_ Route *route = NULL;
963
28cc555d 964 r = route_new_dynamic(&route, RTPROT_UNSPEC);
e1ea665e
EY
965 if (r >= 0) {
966 route->family = AF_INET;
967 route->in_addr.in = routes[i].gw_addr;
968 route->dst_addr.in = routes[i].dst_addr;
969 route->dst_prefixlen = routes[i].dst_prefixlen;
970
971 route_drop(route, link, &route_drop_handler);
e1ea665e
EY
972 }
973 }
974 }
975 }
976
a6cc569e
TG
977 r = address_new_dynamic(&address);
978 if (r >= 0) {
8ddbeaa2 979 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
3e790eae 980 if (r >= 0) {
e1ea665e
EY
981 _cleanup_route_free_ Route *route_gw = NULL;
982 _cleanup_route_free_ Route *route = NULL;
983
28cc555d 984 r = route_new_dynamic(&route_gw, RTPROT_UNSPEC);
8ddbeaa2
UTL
985 if (r >= 0) {
986 route_gw->family = AF_INET;
987 route_gw->dst_addr.in = gateway;
988 route_gw->dst_prefixlen = 32;
989 route_gw->scope = RT_SCOPE_LINK;
990
991 route_drop(route_gw, link, &route_drop_handler);
992 }
3e790eae 993
28cc555d 994 r = route_new_dynamic(&route, RTPROT_UNSPEC);
8ddbeaa2
UTL
995 if (r >= 0) {
996 route->family = AF_INET;
997 route->in_addr.in = gateway;
3e790eae 998
8ddbeaa2
UTL
999 route_drop(route, link, &route_drop_handler);
1000 }
3e790eae
UTL
1001 }
1002
8ddbeaa2
UTL
1003 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
1004 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
1005 prefixlen = net_netmask_to_prefixlen(&netmask);
1006
a6cc569e
TG
1007 address->family = AF_INET;
1008 address->in_addr.in = addr;
1009 address->prefixlen = prefixlen;
ff254138 1010
5c1d3fc9 1011 address_drop(address, link, &address_drop_handler);
c07aeadf 1012 }
eb27aeca 1013
c07aeadf
TG
1014 if (link->network->dhcp_mtu) {
1015 uint16_t mtu;
ff254138 1016
a6cc569e 1017 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
c07aeadf
TG
1018 if (r >= 0 && link->original_mtu != mtu) {
1019 r = link_set_mtu(link, link->original_mtu);
1020 if (r < 0) {
1021 log_warning_link(link, "DHCP error: could not reset MTU");
1022 link_enter_failed(link);
1023 return r;
1024 }
ff254138 1025 }
c07aeadf 1026 }
ff254138 1027
c07aeadf 1028 if (link->network->dhcp_hostname) {
216816c6
TG
1029 const char *hostname = NULL;
1030
1031 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
1032 if (r >= 0 && hostname) {
b226d99b 1033 r = link_set_hostname(link, "");
216816c6 1034 if (r < 0)
987efa17 1035 log_error_link(link, "Failed to reset transient hostname");
216816c6 1036 }
c07aeadf 1037 }
4f882b2a 1038
a6cc569e
TG
1039 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
1040
c07aeadf
TG
1041 return 0;
1042}
4f882b2a 1043
68ceb9df
PF
1044static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
1045 sd_dhcp_lease *lease;
1046 int r;
1047
1048 r = sd_dhcp_client_get_lease(client, &lease);
1049 if (r < 0) {
1050 log_warning_link(link, "DHCP error: no lease %s",
1051 strerror(-r));
1052 return r;
1053 }
1054
1055 sd_dhcp_lease_unref(link->dhcp_lease);
1056 link->dhcp_lease = lease;
1057
1058 link_enter_set_addresses(link);
1059
1060 return 0;
1061}
1062
c07aeadf 1063static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
a6cc569e 1064 sd_dhcp_lease *lease;
c07aeadf
TG
1065 struct in_addr address;
1066 struct in_addr netmask;
1067 struct in_addr gateway;
1068 unsigned prefixlen;
c07aeadf 1069 int r;
1346b1f0 1070
c07aeadf
TG
1071 assert(client);
1072 assert(link);
ff254138 1073
a6cc569e
TG
1074 r = sd_dhcp_client_get_lease(client, &lease);
1075 if (r < 0) {
1076 log_warning_link(link, "DHCP error: no lease: %s",
1077 strerror(-r));
1078 return r;
1079 }
1080
1081 r = sd_dhcp_lease_get_address(lease, &address);
ff254138 1082 if (r < 0) {
c07aeadf
TG
1083 log_warning_link(link, "DHCP error: no address: %s",
1084 strerror(-r));
1085 return r;
ff254138
TG
1086 }
1087
a6cc569e 1088 r = sd_dhcp_lease_get_netmask(lease, &netmask);
ff254138 1089 if (r < 0) {
c07aeadf
TG
1090 log_warning_link(link, "DHCP error: no netmask: %s",
1091 strerror(-r));
1092 return r;
ff254138
TG
1093 }
1094
377a218f 1095 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 1096
a6cc569e 1097 r = sd_dhcp_lease_get_router(lease, &gateway);
8ddbeaa2 1098 if (r < 0 && r != -ENOENT) {
b1666580
TG
1099 log_warning_link(link, "DHCP error: could not get gateway: %s",
1100 strerror(-r));
c07aeadf 1101 return r;
ff254138
TG
1102 }
1103
8ddbeaa2
UTL
1104 if (r >= 0)
1105 log_struct_link(LOG_INFO, link,
97578344 1106 "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
987efa17 1107 IFNAMSIZ,
8ddbeaa2
UTL
1108 link->ifname,
1109 ADDRESS_FMT_VAL(address),
1110 prefixlen,
1111 ADDRESS_FMT_VAL(gateway),
1112 "ADDRESS=%u.%u.%u.%u",
1113 ADDRESS_FMT_VAL(address),
1114 "PREFIXLEN=%u",
1115 prefixlen,
1116 "GATEWAY=%u.%u.%u.%u",
1117 ADDRESS_FMT_VAL(gateway),
1118 NULL);
1119 else
1120 log_struct_link(LOG_INFO, link,
97578344 1121 "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u",
987efa17 1122 IFNAMSIZ,
8ddbeaa2
UTL
1123 link->ifname,
1124 ADDRESS_FMT_VAL(address),
1125 prefixlen,
1126 "ADDRESS=%u.%u.%u.%u",
1127 ADDRESS_FMT_VAL(address),
1128 "PREFIXLEN=%u",
1129 prefixlen,
1130 NULL);
c07aeadf 1131
d50cf59b
TG
1132 link->dhcp_lease = lease;
1133
c07aeadf
TG
1134 if (link->network->dhcp_mtu) {
1135 uint16_t mtu;
1136
a6cc569e 1137 r = sd_dhcp_lease_get_mtu(lease, &mtu);
c07aeadf
TG
1138 if (r >= 0) {
1139 r = link_set_mtu(link, mtu);
1140 if (r < 0)
1141 log_error_link(link, "Failed to set MTU "
1142 "to %" PRIu16, mtu);
1143 }
1144 }
ff254138 1145
c07aeadf
TG
1146 if (link->network->dhcp_hostname) {
1147 const char *hostname;
ff254138 1148
a6cc569e 1149 r = sd_dhcp_lease_get_hostname(lease, &hostname);
c07aeadf 1150 if (r >= 0) {
b226d99b 1151 r = link_set_hostname(link, hostname);
c07aeadf 1152 if (r < 0)
987efa17 1153 log_error_link(link, "Failed to set transient hostname "
c07aeadf 1154 "to '%s'", hostname);
3bef724f 1155 }
c07aeadf 1156 }
3bef724f 1157
c07aeadf
TG
1158 link_enter_set_addresses(link);
1159
1160 return 0;
1161}
1162
1163static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
1164 Link *link = userdata;
aba496a5 1165 int r = 0;
c07aeadf
TG
1166
1167 assert(link);
1168 assert(link->network);
1169 assert(link->manager);
1170
370e9930 1171 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
c07aeadf
TG
1172 return;
1173
1174 switch (event) {
c07aeadf
TG
1175 case DHCP_EVENT_EXPIRED:
1176 case DHCP_EVENT_STOP:
1177 case DHCP_EVENT_IP_CHANGE:
1178 if (link->network->dhcp_critical) {
1179 log_error_link(link, "DHCPv4 connection considered system critical, "
1180 "ignoring request to reconfigure it.");
1181 return;
4f882b2a 1182 }
4f882b2a 1183
17256461
UTL
1184 if (link->dhcp_lease) {
1185 r = dhcp_lease_lost(link);
1186 if (r < 0) {
1187 link_enter_failed(link);
1188 return;
1189 }
c07aeadf 1190 }
1346b1f0 1191
c07aeadf
TG
1192 if (event == DHCP_EVENT_IP_CHANGE) {
1193 r = dhcp_lease_acquired(client, link);
1194 if (r < 0) {
1195 link_enter_failed(link);
1196 return;
1197 }
1346b1f0 1198 }
1346b1f0 1199
5c1d3fc9 1200 if (event == DHCP_EVENT_EXPIRED && link->network->ipv4ll) {
aba496a5
UTL
1201 if (!sd_ipv4ll_is_running(link->ipv4ll))
1202 r = sd_ipv4ll_start(link->ipv4ll);
1203 else if (ipv4ll_is_bound(link->ipv4ll))
1204 r = ipv4ll_address_update(link, false);
5c1d3fc9
UTL
1205 if (r < 0) {
1206 link_enter_failed(link);
1207 return;
1208 }
1209 }
1210
68ceb9df
PF
1211 break;
1212 case DHCP_EVENT_RENEW:
1213 r = dhcp_lease_renew(client, link);
1214 if (r < 0) {
1215 link_enter_failed(link);
1216 return;
1217 }
c07aeadf
TG
1218 break;
1219 case DHCP_EVENT_IP_ACQUIRE:
1220 r = dhcp_lease_acquired(client, link);
1221 if (r < 0) {
1222 link_enter_failed(link);
1223 return;
1224 }
5c1d3fc9 1225 if (link->ipv4ll) {
aba496a5
UTL
1226 if (ipv4ll_is_bound(link->ipv4ll))
1227 r = ipv4ll_address_update(link, true);
1228 else
1229 r = sd_ipv4ll_stop(link->ipv4ll);
5c1d3fc9
UTL
1230 if (r < 0) {
1231 link_enter_failed(link);
1232 return;
1233 }
1234 }
c07aeadf
TG
1235 break;
1236 default:
1237 if (event < 0)
b1666580 1238 log_warning_link(link, "DHCP error: client failed: %s", strerror(-event));
c07aeadf
TG
1239 else
1240 log_warning_link(link, "DHCP unknown event: %d", event);
c07aeadf 1241 break;
ff254138
TG
1242 }
1243
1244 return;
1245}
1246
aba496a5
UTL
1247static int ipv4ll_address_update(Link *link, bool deprecate) {
1248 int r;
1249 struct in_addr addr;
1250
1251 assert(link);
1252
1253 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
1254 if (r >= 0) {
1255 _cleanup_address_free_ Address *address = NULL;
1256
1257 log_debug_link(link, "IPv4 link-local %s %u.%u.%u.%u",
1258 deprecate ? "deprecate" : "approve",
1259 ADDRESS_FMT_VAL(addr));
1260
1261 r = address_new_dynamic(&address);
1262 if (r < 0) {
1263 log_error_link(link, "Could not allocate address: %s", strerror(-r));
1264 return r;
1265 }
1266
1267 address->family = AF_INET;
1268 address->in_addr.in = addr;
1269 address->prefixlen = 16;
1270 address->scope = RT_SCOPE_LINK;
1271 address->cinfo.ifa_prefered = deprecate ? 0 : CACHE_INFO_INFINITY_LIFE_TIME;
1272 address->broadcast.s_addr = address->in_addr.in.s_addr | htonl(0xfffffffflu >> address->prefixlen);
1273
1274 address_update(address, link, &address_update_handler);
1275 }
1276
1277 return 0;
1278
1279}
1280
1281static int ipv4ll_address_lost(Link *link) {
5c1d3fc9
UTL
1282 int r;
1283 struct in_addr addr;
1284
5c1d3fc9
UTL
1285 assert(link);
1286
1287 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
1288 if (r >= 0) {
1289 _cleanup_address_free_ Address *address = NULL;
1290 _cleanup_route_free_ Route *route = NULL;
1291
1292 log_debug_link(link, "IPv4 link-local release %u.%u.%u.%u",
1293 ADDRESS_FMT_VAL(addr));
1294
1295 r = address_new_dynamic(&address);
1296 if (r < 0) {
1297 log_error_link(link, "Could not allocate address: %s", strerror(-r));
1298 return r;
1299 }
1300
1301 address->family = AF_INET;
1302 address->in_addr.in = addr;
1303 address->prefixlen = 16;
1304 address->scope = RT_SCOPE_LINK;
1305
1306 address_drop(address, link, &address_drop_handler);
1307
28cc555d 1308 r = route_new_dynamic(&route, RTPROT_UNSPEC);
5c1d3fc9
UTL
1309 if (r < 0) {
1310 log_error_link(link, "Could not allocate route: %s",
1311 strerror(-r));
1312 return r;
1313 }
1314
1315 route->family = AF_INET;
1316 route->scope = RT_SCOPE_LINK;
1317 route->metrics = 99;
1318
1319 route_drop(route, link, &route_drop_handler);
1320 }
1321
1322 return 0;
1323}
1324
aba496a5
UTL
1325static bool ipv4ll_is_bound(sd_ipv4ll *ll) {
1326 int r;
1327 struct in_addr addr;
1328
1329 assert(ll);
1330
1331 r = sd_ipv4ll_get_address(ll, &addr);
1332 if (r < 0)
1333 return false;
1334 return true;
1335}
1336
5c1d3fc9
UTL
1337static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
1338 struct in_addr address;
1339 int r;
1340
1341 assert(ll);
1342 assert(link);
1343
1344 r = sd_ipv4ll_get_address(ll, &address);
1345 if (r < 0)
1346 return r;
1347
1348 log_struct_link(LOG_INFO, link,
97578344 1349 "MESSAGE=%-*s: IPv4 link-local address %u.%u.%u.%u",
987efa17 1350 IFNAMSIZ,
5c1d3fc9
UTL
1351 link->ifname,
1352 ADDRESS_FMT_VAL(address),
1353 NULL);
1354
1355 link_enter_set_addresses(link);
1356
1357 return 0;
1358}
1359
1360static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
1361 Link *link = userdata;
1362 int r;
1363
1364 assert(link);
1365 assert(link->network);
1366 assert(link->manager);
1367
370e9930
TG
1368 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1369 return;
1370
5c1d3fc9
UTL
1371 switch(event) {
1372 case IPV4LL_EVENT_STOP:
1373 case IPV4LL_EVENT_CONFLICT:
aba496a5 1374 r = ipv4ll_address_lost(link);
5c1d3fc9
UTL
1375 if (r < 0) {
1376 link_enter_failed(link);
1377 return;
1378 }
1379 break;
1380 case IPV4LL_EVENT_BIND:
1381 r = ipv4ll_address_claimed(ll, link);
1382 if (r < 0) {
1383 link_enter_failed(link);
1384 return;
1385 }
1386 break;
1387 default:
1388 if (event < 0)
1389 log_warning_link(link, "IPv4 link-local error: %s", strerror(-event));
1390 else
1391 log_warning_link(link, "IPv4 link-local unknown event: %d", event);
1392 break;
1393 }
1394}
1395
4138fb2c
PF
1396static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
1397 Link *link = userdata;
1398
1399 assert(link);
1400 assert(link->network);
1401 assert(link->manager);
1402
1403 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1404 return;
1405
1406 switch(event) {
1407 case DHCP6_EVENT_STOP:
1408 case DHCP6_EVENT_RESEND_EXPIRE:
1409 case DHCP6_EVENT_RETRANS_MAX:
1410 case DHCP6_EVENT_IP_ACQUIRE:
1411 log_debug_link(link, "DHCPv6 event %d", event);
1412
1413 break;
1414
1415 default:
1416 if (event < 0)
1417 log_warning_link(link, "DHCPv6 error: %s",
1418 strerror(-event));
1419 else
1420 log_warning_link(link, "DHCPv6 unknown event: %d",
1421 event);
1422 return;
1423 }
1424}
1425
1426static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
1427 Link *link = userdata;
1428 int r;
1429
1430 assert(link);
1431 assert(link->network);
1432 assert(link->manager);
1433
1434 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1435 return;
1436
1437 switch(event) {
1438 case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE:
1439 case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER:
1440 return;
1441
1442 case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
1443 case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED:
1444 break;
1445
1446 default:
1447 if (event < 0)
1448 log_warning_link(link, "ICMPv6 error: %s",
1449 strerror(-event));
1450 else
1451 log_warning_link(link, "ICMPv6 unknown event: %d",
1452 event);
1453
1454 return;
1455 }
1456
1457 if (link->dhcp6_client)
1458 return;
1459
1460 r = sd_dhcp6_client_new(&link->dhcp6_client);
1461 if (r < 0)
1462 return;
1463
1464 r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
1465 if (r < 0) {
1466 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
1467 return;
1468 }
1469
1470 r = sd_dhcp6_client_set_mac(link->dhcp6_client, &link->mac);
1471 if (r < 0) {
1472 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
1473 return;
1474 }
1475
1476 r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
1477 if (r < 0) {
1478 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
1479 return;
1480 }
1481
1482 r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
1483 link);
1484 if (r < 0) {
1485 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
1486 return;
1487 }
1488
1489 r = sd_dhcp6_client_start(link->dhcp6_client);
1490 if (r < 0)
1491 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
1492}
1493
ff254138
TG
1494static int link_acquire_conf(Link *link) {
1495 int r;
1496
1497 assert(link);
1498 assert(link->network);
ff254138
TG
1499 assert(link->manager);
1500 assert(link->manager->event);
1501
5c1d3fc9 1502 if (link->network->ipv4ll) {
eb34d4af 1503 assert(link->ipv4ll);
ff254138 1504
5c1d3fc9
UTL
1505 log_debug_link(link, "acquiring IPv4 link-local address");
1506
1507 r = sd_ipv4ll_start(link->ipv4ll);
124fa2c6
TG
1508 if (r < 0) {
1509 log_warning_link(link, "could not acquire IPv4 "
1510 "link-local address");
ff254138 1511 return r;
124fa2c6 1512 }
5c1d3fc9
UTL
1513 }
1514
ed942a9e 1515 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) {
eb34d4af 1516 assert(link->dhcp_client);
ff254138 1517
5c1d3fc9 1518 log_debug_link(link, "acquiring DHCPv4 lease");
ab47d620 1519
5c1d3fc9 1520 r = sd_dhcp_client_start(link->dhcp_client);
124fa2c6
TG
1521 if (r < 0) {
1522 log_warning_link(link, "could not acquire DHCPv4 "
1523 "lease");
5c1d3fc9 1524 return r;
124fa2c6 1525 }
5c1d3fc9 1526 }
ff254138 1527
ed942a9e 1528 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
4138fb2c
PF
1529 assert(link->icmp6_router_discovery);
1530
1531 log_debug_link(link, "discovering IPv6 routers");
1532
1533 r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery);
1534 if (r < 0) {
1535 log_warning_link(link, "could not start IPv6 router discovery");
1536 return r;
1537 }
1538 }
1539
ff254138
TG
1540 return 0;
1541}
1542
bbf7c048 1543bool link_has_carrier(unsigned flags, uint8_t operstate) {
deb2e523
TG
1544 /* see Documentation/networking/operstates.txt in the kernel sources */
1545
1546 if (operstate == IF_OPER_UP)
1547 return true;
1548
1549 if (operstate == IF_OPER_UNKNOWN)
1550 /* operstate may not be implemented, so fall back to flags */
1551 if ((flags & IFF_LOWER_UP) && !(flags & IFF_DORMANT))
1552 return true;
1553
1554 return false;
1555}
1556
389cc5f7
TG
1557#define FLAG_STRING(string, flag, old, new) \
1558 (((old ^ new) & flag) \
1559 ? ((old & flag) ? (" -" string) : (" +" string)) \
1560 : "")
1561
1e9be60b 1562static int link_update_flags(Link *link, sd_rtnl_message *m) {
389cc5f7 1563 unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags;
1e9be60b
TG
1564 uint8_t operstate;
1565 bool carrier_gained = false, carrier_lost = false;
ff254138
TG
1566 int r;
1567
1568 assert(link);
ff254138 1569
1e9be60b
TG
1570 r = sd_rtnl_message_link_get_flags(m, &flags);
1571 if (r < 0) {
1572 log_warning_link(link, "Could not get link flags");
1573 return r;
1574 }
1575
1576 r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate);
1577 if (r < 0)
1578 /* if we got a message without operstate, take it to mean
1579 the state was unchanged */
e375dcde 1580 operstate = link->kernel_operstate;
1e9be60b 1581
e375dcde 1582 if ((link->flags == flags) && (link->kernel_operstate == operstate))
efbc88b8 1583 return 0;
efbc88b8 1584
389cc5f7
TG
1585 if (link->flags != flags) {
1586 log_debug_link(link, "flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1587 FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags),
1588 FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags),
1589 FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags),
1590 FLAG_STRING("UP", IFF_UP, link->flags, flags),
1591 FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags),
1592 FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags),
1593 FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags),
1594 FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags),
1595 FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags),
1596 FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags),
1597 FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags),
1598 FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags),
1599 FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags),
1600 FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags),
1601 FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags),
1602 FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags),
1603 FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags),
1604 FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags),
1605 FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags));
1606
1607 unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP |
1608 IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING |
1609 IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT |
1610 IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL |
1611 IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP |
1612 IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO);
1613 unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags);
1614 unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags);
1615
1616 /* link flags are currently at most 18 bits, let's align to printing 20 */
1617 if (unknown_flags_added)
1618 log_debug_link(link, "unknown link flags gained: %#.5x (ignoring)",
1619 unknown_flags_added);
1620
1621 if (unknown_flags_removed)
1622 log_debug_link(link, "unknown link flags lost: %#.5x (ignoring)",
1623 unknown_flags_removed);
1624 }
505f8da7 1625
e375dcde 1626 carrier_gained = !link_has_carrier(link->flags, link->kernel_operstate) &&
1e9be60b 1627 link_has_carrier(flags, operstate);
e375dcde 1628 carrier_lost = link_has_carrier(link->flags, link->kernel_operstate) &&
1e9be60b
TG
1629 !link_has_carrier(flags, operstate);
1630
1631 link->flags = flags;
e375dcde 1632 link->kernel_operstate = operstate;
1e9be60b 1633
deb2e523
TG
1634 link_save(link);
1635
99b4cc3e
TG
1636 if (link->state == LINK_STATE_FAILED ||
1637 link->state == LINK_STATE_UNMANAGED)
1638 return 0;
1639
7cc832b9
TG
1640 if (carrier_gained) {
1641 log_info_link(link, "gained carrier");
ffba6166 1642
1e9be60b 1643 if (link->network) {
ffba6166
TG
1644 r = link_acquire_conf(link);
1645 if (r < 0) {
ffba6166
TG
1646 link_enter_failed(link);
1647 return r;
ff254138 1648 }
ffba6166 1649 }
7cc832b9
TG
1650 } else if (carrier_lost) {
1651 log_info_link(link, "lost carrier");
efbc88b8 1652
1e9be60b
TG
1653 r = link_stop_clients(link);
1654 if (r < 0) {
1655 link_enter_failed(link);
1656 return r;
ff254138
TG
1657 }
1658 }
1659
ff254138
TG
1660 return 0;
1661}
1662
dd3efc09 1663static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 1664 _cleanup_link_unref_ Link *link = userdata;
dd3efc09
TG
1665 int r;
1666
1746cf2a
TG
1667 assert(link);
1668
5da8149f 1669 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1746cf2a
TG
1670 return 1;
1671
dd3efc09 1672 r = sd_rtnl_message_get_errno(m);
45ad2c13 1673 if (r < 0) {
9b86b393
TG
1674 /* we warn but don't fail the link, as it may
1675 be brought up later */
76800848 1676 log_struct_link(LOG_WARNING, link,
97578344 1677 "MESSAGE=%-*s: could not bring up interface: %s",
987efa17 1678 IFNAMSIZ,
c9ccc19f
TG
1679 link->ifname, strerror(-r),
1680 "ERRNO=%d", -r,
1681 NULL);
45ad2c13
TG
1682 }
1683
f882c247
TG
1684 return 1;
1685}
1686
1687static int link_up(Link *link) {
cf6a8911 1688 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
1689 int r;
1690
f882c247
TG
1691 assert(link);
1692 assert(link->manager);
1693 assert(link->manager->rtnl);
1694
39032b87 1695 log_debug_link(link, "bringing link up");
449f7554 1696
151b9b96
LP
1697 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
1698 RTM_SETLINK, link->ifindex);
f579559b 1699 if (r < 0) {
39032b87 1700 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
1701 return r;
1702 }
1703
5d4795f3 1704 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 1705 if (r < 0) {
3333d748 1706 log_error_link(link, "Could not set link flags: %s", strerror(-r));
fc25d7f8
TG
1707 return r;
1708 }
1709
dd3efc09 1710 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 1711 if (r < 0) {
3333d748
ZJS
1712 log_error_link(link,
1713 "Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
1714 return r;
1715 }
1716
b226d99b
TG
1717 link_ref(link);
1718
f882c247
TG
1719 return 0;
1720}
1721
3f265037 1722static int link_joined(Link *link) {
f882c247
TG
1723 int r;
1724
ef1ba606 1725 assert(link);
52433f6b 1726 assert(link->state == LINK_STATE_ENSLAVING);
f5be5601 1727 assert(link->network);
dd3efc09 1728
3f265037 1729 log_debug_link(link, "joined netdev");
856f962c 1730
505f8da7
TG
1731 if (!(link->flags & IFF_UP)) {
1732 r = link_up(link);
1733 if (r < 0) {
1734 link_enter_failed(link);
1735 return r;
1736 }
ef1ba606 1737 }
f882c247 1738
fb6730c4 1739 return link_enter_set_addresses(link);
02b59d57
TG
1740}
1741
3f265037 1742static int netdev_join_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 1743 _cleanup_link_unref_ Link *link = userdata;
02b59d57
TG
1744 int r;
1745
1746cf2a 1746 assert(link);
370e9930
TG
1747 assert(IN_SET(link->state, LINK_STATE_ENSLAVING, LINK_STATE_FAILED,
1748 LINK_STATE_LINGER));
ef1ba606 1749 assert(link->network);
02b59d57 1750
52433f6b
TG
1751 link->enslaving --;
1752
5da8149f 1753 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
02b59d57
TG
1754 return 1;
1755
1756 r = sd_rtnl_message_get_errno(m);
856f962c 1757 if (r < 0 && r != -EEXIST) {
c9ccc19f 1758 log_struct_link(LOG_ERR, link,
3f265037 1759 "MESSAGE=%-*s: could not join netdev: %s",
987efa17 1760 IFNAMSIZ,
c9ccc19f
TG
1761 link->ifname, strerror(-r),
1762 "ERRNO=%d", -r,
1763 NULL);
ef1ba606
TG
1764 link_enter_failed(link);
1765 return 1;
3333d748 1766 }
02b59d57 1767
856f962c 1768 if (link->enslaving <= 0)
3f265037 1769 link_joined(link);
02b59d57
TG
1770
1771 return 1;
1772}
1773
3f265037 1774static int link_enter_join_netdev(Link *link) {
6a0a2f86 1775 NetDev *netdev;
672682a6 1776 Iterator i;
02b59d57
TG
1777 int r;
1778
1779 assert(link);
1780 assert(link->network);
505f8da7 1781 assert(link->state == LINK_STATE_INITIALIZING);
02b59d57 1782
52433f6b 1783 link->state = LINK_STATE_ENSLAVING;
02b59d57 1784
fe8db0c5
TG
1785 link_save(link);
1786
7951dea2
SS
1787 if (!link->network->bridge &&
1788 !link->network->bond &&
6a0a2f86 1789 hashmap_isempty(link->network->stacked_netdevs))
3f265037 1790 return link_joined(link);
02b59d57 1791
d9c67ea1 1792 if (link->network->bond) {
52433f6b 1793 log_struct_link(LOG_DEBUG, link,
97578344 1794 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1795 IFNAMSIZ,
af4e9e2c 1796 link->ifname, link->network->bond->ifname,
aa9f1140 1797 NETDEVIF(link->network->bond),
52433f6b 1798 NULL);
449f7554 1799
3f265037 1800 r = netdev_join(link->network->bond, link, &netdev_join_handler);
52433f6b
TG
1801 if (r < 0) {
1802 log_struct_link(LOG_WARNING, link,
3f265037 1803 "MESSAGE=%-*s: could not join netdev '%s': %s",
987efa17 1804 IFNAMSIZ,
af4e9e2c 1805 link->ifname, link->network->bond->ifname, strerror(-r),
aa9f1140 1806 NETDEVIF(link->network->bond),
52433f6b
TG
1807 NULL);
1808 link_enter_failed(link);
1809 return r;
1810 }
1811
0ad6148e
MO
1812 link->enslaving ++;
1813 }
1814
d9c67ea1 1815 if (link->network->bridge) {
0ad6148e 1816 log_struct_link(LOG_DEBUG, link,
97578344 1817 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1818 IFNAMSIZ,
af4e9e2c 1819 link->ifname, link->network->bridge->ifname,
aa9f1140 1820 NETDEVIF(link->network->bridge),
0ad6148e
MO
1821 NULL);
1822
3f265037 1823 r = netdev_join(link->network->bridge, link, &netdev_join_handler);
0ad6148e
MO
1824 if (r < 0) {
1825 log_struct_link(LOG_WARNING, link,
3f265037 1826 "MESSAGE=%-*s: could not join netdev '%s': %s",
987efa17 1827 IFNAMSIZ,
af4e9e2c 1828 link->ifname, link->network->bridge->ifname, strerror(-r),
aa9f1140 1829 NETDEVIF(link->network->bridge),
0ad6148e
MO
1830 NULL);
1831 link_enter_failed(link);
1832 return r;
1833 }
1834
52433f6b
TG
1835 link->enslaving ++;
1836 }
1837
6a0a2f86 1838 HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) {
7951dea2 1839 log_struct_link(LOG_DEBUG, link,
97578344 1840 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1841 IFNAMSIZ,
6a0a2f86 1842 link->ifname, netdev->ifname, NETDEVIF(netdev), NULL);
7951dea2 1843
6a0a2f86 1844 r = netdev_join(netdev, link, &netdev_join_handler);
7951dea2
SS
1845 if (r < 0) {
1846 log_struct_link(LOG_WARNING, link,
3f265037 1847 "MESSAGE=%-*s: could not join netdev '%s': %s",
987efa17 1848 IFNAMSIZ,
6a0a2f86
TG
1849 link->ifname, netdev->ifname, strerror(-r),
1850 NETDEVIF(netdev), NULL);
326cb406
SS
1851 link_enter_failed(link);
1852 return r;
1853 }
1854
326cb406
SS
1855 link->enslaving ++;
1856 }
1857
ef1ba606
TG
1858 return 0;
1859}
1860
a748b692 1861static int link_configure(Link *link) {
02b59d57
TG
1862 int r;
1863
ef1ba606 1864 assert(link);
505f8da7 1865 assert(link->state == LINK_STATE_INITIALIZING);
a748b692 1866
eb34d4af 1867 if (link->network->ipv4ll) {
b5db00e5 1868 uint8_t seed[8];
45ad2c13 1869
eb34d4af
TG
1870 r = sd_ipv4ll_new(&link->ipv4ll);
1871 if (r < 0)
1872 return r;
1873
505f8da7
TG
1874 if (link->udev_device) {
1875 r = net_get_unique_predictable_data(link->udev_device, seed);
1876 if (r >= 0) {
1877 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
1878 if (r < 0)
1879 return r;
1880 }
b5db00e5
UTL
1881 }
1882
eb34d4af
TG
1883 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
1884 if (r < 0)
1885 return r;
1886
4bb40e81
TG
1887 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
1888 if (r < 0)
1889 return r;
1890
eb34d4af
TG
1891 r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
1892 if (r < 0)
1893 return r;
1894
1895 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
1896 if (r < 0)
1897 return r;
1898 }
1899
ed942a9e 1900 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) {
eb34d4af
TG
1901 r = sd_dhcp_client_new(&link->dhcp_client);
1902 if (r < 0)
1903 return r;
1904
1905 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
1906 if (r < 0)
1907 return r;
1908
4bb40e81
TG
1909 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
1910 if (r < 0)
1911 return r;
1912
eb34d4af
TG
1913 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
1914 if (r < 0)
1915 return r;
1916
1917 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
1918 if (r < 0)
1919 return r;
1920
f5de5b00
TG
1921 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link->network->dhcp_broadcast);
1922 if (r < 0)
1923 return r;
1924
eb34d4af
TG
1925 if (link->network->dhcp_mtu) {
1926 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
1927 if (r < 0)
1928 return r;
1929 }
4cc7a82c 1930
e1ea665e
EY
1931 if (link->network->dhcp_routes) {
1932 r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_STATIC_ROUTE);
1933 if (r < 0)
1934 return r;
1935 r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
1936 if (r < 0)
1937 return r;
1938 }
4cc7a82c
EY
1939
1940 if (link->network->dhcp_sendhost) {
1941 _cleanup_free_ char *hostname = gethostname_malloc();
1942 if (!hostname)
1943 return -ENOMEM;
1944
1945 if (!is_localhost(hostname)) {
1946 r = sd_dhcp_client_set_hostname(link->dhcp_client, hostname);
1947 if (r < 0)
1948 return r;
1949 }
1950 }
edb85f0d
SS
1951
1952 if (link->network->dhcp_vendor_class_identifier) {
1953 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
1954 link->network->dhcp_vendor_class_identifier);
1955 if (r < 0)
1956 return r;
1957 }
eb34d4af
TG
1958 }
1959
dd43110f 1960 if (link->network->dhcp_server) {
dd43110f
TG
1961 r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
1962 if (r < 0)
1963 return r;
1964
1965 r = sd_dhcp_server_attach_event(link->dhcp_server, NULL, 0);
1966 if (r < 0)
1967 return r;
dd43110f
TG
1968 }
1969
ed942a9e 1970 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
4138fb2c
PF
1971 r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
1972 if (r < 0)
1973 return r;
1974
1975 r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery,
1976 NULL, 0);
1977 if (r < 0)
1978 return r;
1979
1980 r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery,
1981 &link->mac);
1982 if (r < 0)
1983 return r;
1984
1985 r = sd_icmp6_nd_set_index(link->icmp6_router_discovery,
1986 link->ifindex);
1987 if (r < 0)
1988 return r;
1989
1990 r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery,
1991 icmp6_router_handler, link);
1992 if (r < 0)
1993 return r;
1994 }
1995
bf0308cb 1996 if (link_has_carrier(link->flags, link->kernel_operstate)) {
1e9be60b
TG
1997 r = link_acquire_conf(link);
1998 if (r < 0)
1999 return r;
cc544d5f 2000 }
1e9be60b 2001
3f265037 2002 return link_enter_join_netdev(link);
505f8da7
TG
2003}
2004
4f561e8e 2005static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 2006 _cleanup_link_unref_ Link *link = userdata;
505f8da7 2007 Network *network;
505f8da7
TG
2008 int r;
2009
2010 assert(link);
2011 assert(link->ifname);
2012 assert(link->manager);
2013
2014 if (link->state != LINK_STATE_INITIALIZING)
5da8149f 2015 return 1;
505f8da7 2016
4f561e8e 2017 log_debug_link(link, "link state is up-to-date");
505f8da7 2018
4f561e8e 2019 r = network_get(link->manager, link->udev_device, link->ifname, &link->mac, &network);
57bd6899
TG
2020 if (r == -ENOENT) {
2021 link_enter_unmanaged(link);
5da8149f 2022 return 1;
57bd6899
TG
2023 } else if (r < 0)
2024 return r;
505f8da7
TG
2025
2026 r = network_apply(link->manager, network, link);
2027 if (r < 0)
2028 return r;
2029
a748b692
TG
2030 r = link_configure(link);
2031 if (r < 0)
2032 return r;
2033
5da8149f 2034 return 1;
505f8da7
TG
2035}
2036
4f561e8e
TG
2037int link_initialized(Link *link, struct udev_device *device) {
2038 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
2039 int r;
2040
2041 assert(link);
2042 assert(link->manager);
2043 assert(link->manager->rtnl);
2044 assert(device);
2045
2046 if (link->state != LINK_STATE_INITIALIZING)
2047 return 0;
2048
679b3605
TG
2049 if (link->udev_device)
2050 return 0;
2051
4f561e8e
TG
2052 log_debug_link(link, "udev initialized link");
2053
2054 link->udev_device = udev_device_ref(device);
2055
2056 /* udev has initialized the link, but we don't know if we have yet processed
2057 the NEWLINK messages with the latest state. Do a GETLINK, when it returns
2058 we know that the pending NEWLINKs have already been processed and that we
2059 are up-to-date */
2060
2061 r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK, link->ifindex);
2062 if (r < 0)
2063 return r;
2064
2065 r = sd_rtnl_call_async(link->manager->rtnl, req, link_initialized_and_synced, link, 0, NULL);
2066 if (r < 0)
2067 return r;
2068
5da8149f
TG
2069 link_ref(link);
2070
4f561e8e
TG
2071 return 0;
2072}
2073
fbbeb65a
TG
2074int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
2075 Manager *m = userdata;
2076 Link *link = NULL;
2077 uint16_t type;
2078 _cleanup_address_free_ Address *address = NULL;
428fd0a7 2079 Address *ad;
fbbeb65a 2080 char buf[INET6_ADDRSTRLEN];
428fd0a7 2081 bool address_dropped = false;
fbbeb65a
TG
2082 int r, ifindex;
2083
2084 assert(rtnl);
2085 assert(message);
2086 assert(m);
2087
2088 r = sd_rtnl_message_get_type(message, &type);
2089 if (r < 0) {
2090 log_warning("rtnl: could not get message type");
2091 return 0;
2092 }
2093
2094 r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
2095 if (r < 0 || ifindex <= 0) {
5ea846cc 2096 log_warning("rtnl: received address message without valid ifindex, ignoring");
fbbeb65a
TG
2097 return 0;
2098 } else {
2099 r = link_get(m, ifindex, &link);
2100 if (r < 0 || !link) {
5ea846cc 2101 log_warning("rtnl: received address for a nonexistent link, ignoring");
fbbeb65a
TG
2102 return 0;
2103 }
2104 }
2105
2106 r = address_new_dynamic(&address);
2107 if (r < 0)
393c0c5e 2108 return r;
fbbeb65a
TG
2109
2110 r = sd_rtnl_message_addr_get_family(message, &address->family);
2111 if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
987efa17 2112 log_warning_link(link, "rtnl: received address with invalid family, ignoring");
fbbeb65a
TG
2113 return 0;
2114 }
2115
2116 r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
2117 if (r < 0) {
e375dcde
TG
2118 log_warning_link(link, "rtnl: received address with invalid prefixlen, ignoring");
2119 return 0;
2120 }
2121
2122 r = sd_rtnl_message_addr_get_scope(message, &address->scope);
2123 if (r < 0) {
2124 log_warning_link(link, "rtnl: received address with invalid scope, ignoring");
fbbeb65a
TG
2125 return 0;
2126 }
2127
2128 switch (address->family) {
2129 case AF_INET:
2130 r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
2131 if (r < 0) {
987efa17 2132 log_warning_link(link, "rtnl: received address without valid address, ignoring");
fbbeb65a
TG
2133 return 0;
2134 }
2135
2136 break;
2137
2138 case AF_INET6:
2139 r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
2140 if (r < 0) {
987efa17 2141 log_warning_link(link, "rtnl: received address without valid address, ignoring");
fbbeb65a
TG
2142 return 0;
2143 }
2144
2145 break;
2146
2147 default:
2148 assert_not_reached("invalid address family");
2149 }
2150
2151 if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) {
987efa17 2152 log_warning_link(link, "could not print address");
fbbeb65a
TG
2153 return 0;
2154 }
2155
428fd0a7
TG
2156 LIST_FOREACH(addresses, ad, link->addresses) {
2157 if (address_equal(ad, address)) {
2158 LIST_REMOVE(addresses, link->addresses, ad);
2159
2160 address_free(ad);
2161
2162 address_dropped = true;
2163
2164 break;
2165 }
2166 }
2167
fbbeb65a
TG
2168 switch (type) {
2169 case RTM_NEWADDR:
428fd0a7
TG
2170 if (!address_dropped)
2171 log_debug_link(link, "added address: %s/%u", buf,
393c0c5e
TG
2172 address->prefixlen);
2173 else
2174 log_debug_link(link, "updated address: %s/%u", buf,
2175 address->prefixlen);
fbbeb65a 2176
428fd0a7
TG
2177 LIST_PREPEND(addresses, link->addresses, address);
2178 address = NULL;
2179
f5602be9
TG
2180 link_save(link);
2181
428fd0a7 2182 break;
fbbeb65a 2183 case RTM_DELADDR:
f5602be9 2184 if (address_dropped) {
428fd0a7 2185 log_debug_link(link, "removed address: %s/%u", buf,
393c0c5e 2186 address->prefixlen);
428fd0a7 2187
f5602be9 2188 link_save(link);
393c0c5e
TG
2189 } else
2190 log_warning_link(link, "removing non-existent address: %s/%u",
2191 buf, address->prefixlen);
f5602be9 2192
fbbeb65a
TG
2193 break;
2194 default:
2195 assert_not_reached("Received invalid RTNL message type");
2196 }
2197
2198 return 1;
2199}
2200
505f8da7
TG
2201int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
2202 Link *link;
fbbeb65a 2203 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
505f8da7
TG
2204 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
2205 char ifindex_str[2 + DECIMAL_STR_MAX(int)];
2206 int r;
2207
2208 assert(m);
fbbeb65a 2209 assert(m->rtnl);
505f8da7
TG
2210 assert(message);
2211 assert(ret);
2212
2213 r = link_new(m, message, ret);
2214 if (r < 0)
2215 return r;
2216
2217 link = *ret;
2218
ae06ab10 2219 log_debug_link(link, "link %d added", link->ifindex);
505f8da7 2220
fbbeb65a
TG
2221 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, link->ifindex, 0);
2222 if (r < 0)
2223 return r;
2224
2225 r = sd_rtnl_call_async(m->rtnl, req, link_get_address_handler, link, 0, NULL);
2226 if (r < 0)
2227 return r;
2228
5da8149f
TG
2229 link_ref(link);
2230
505f8da7
TG
2231 if (detect_container(NULL) <= 0) {
2232 /* not in a container, udev will be around */
ae06ab10 2233 sprintf(ifindex_str, "n%d", link->ifindex);
505f8da7
TG
2234 device = udev_device_new_from_device_id(m->udev, ifindex_str);
2235 if (!device) {
2236 log_warning_link(link, "could not find udev device");
2237 return -errno;
2238 }
2239
3c4cb064 2240 if (udev_device_get_is_initialized(device) <= 0) {
505f8da7 2241 /* not yet ready */
16cd414b 2242 log_debug_link(link, "udev initializing link...");
505f8da7 2243 return 0;
3c4cb064 2244 }
505f8da7 2245
4f561e8e
TG
2246 r = link_initialized(link, device);
2247 if (r < 0)
2248 return r;
2249 } else {
5da8149f
TG
2250 /* we are calling a callback directly, so must take a ref */
2251 link_ref(link);
2252
4f561e8e
TG
2253 r = link_initialized_and_synced(m->rtnl, NULL, link);
2254 if (r < 0)
2255 return r;
2256 }
505f8da7 2257
a748b692
TG
2258 return 0;
2259}
2260
22936833 2261int link_update(Link *link, sd_rtnl_message *m) {
c49b33ac 2262 struct ether_addr mac;
ca4e095a 2263 const char *ifname;
22936833
TG
2264 int r;
2265
dd3efc09 2266 assert(link);
b8941f74 2267 assert(link->ifname);
22936833
TG
2268 assert(m);
2269
7619683b
TG
2270 if (link->state == LINK_STATE_LINGER) {
2271 link_ref(link);
2272 log_info_link(link, "link readded");
2273 link->state = LINK_STATE_ENSLAVING;
2274 }
2275
b8941f74
TG
2276 r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
2277 if (r >= 0 && !streq(ifname, link->ifname)) {
2278 log_info_link(link, "renamed to %s", ifname);
2279
2280 free(link->ifname);
2281 link->ifname = strdup(ifname);
2282 if (!link->ifname)
2283 return -ENOMEM;
2284 }
2285
505f8da7 2286 if (!link->original_mtu) {
9842de0d
TG
2287 r = sd_rtnl_message_read_u16(m, IFLA_MTU, &link->original_mtu);
2288 if (r >= 0)
2289 log_debug_link(link, "saved original MTU: %"
2290 PRIu16, link->original_mtu);
2291 }
69629de9 2292
e9189a1f
TG
2293 /* The kernel may broadcast NEWLINK messages without the MAC address
2294 set, simply ignore them. */
c49b33ac 2295 r = sd_rtnl_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
e9189a1f 2296 if (r >= 0) {
20861203 2297 if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN)) {
c49b33ac 2298
20861203 2299 memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN);
c49b33ac 2300
20861203
TG
2301 log_debug_link(link, "MAC address: "
2302 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
2303 mac.ether_addr_octet[0],
2304 mac.ether_addr_octet[1],
2305 mac.ether_addr_octet[2],
2306 mac.ether_addr_octet[3],
2307 mac.ether_addr_octet[4],
2308 mac.ether_addr_octet[5]);
c49b33ac 2309
20861203
TG
2310 if (link->ipv4ll) {
2311 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
2312 if (r < 0) {
2313 log_warning_link(link, "Could not update MAC "
2314 "address in IPv4LL client: %s",
2315 strerror(-r));
2316 return r;
2317 }
c49b33ac 2318 }
c49b33ac 2319
20861203
TG
2320 if (link->dhcp_client) {
2321 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
2322 if (r < 0) {
2323 log_warning_link(link, "Could not update MAC "
2324 "address in DHCP client: %s",
2325 strerror(-r));
2326 return r;
2327 }
c49b33ac 2328 }
4138fb2c
PF
2329
2330 if (link->dhcp6_client) {
2331 r = sd_dhcp6_client_set_mac(link->dhcp6_client,
2332 &link->mac);
2333 if (r < 0) {
2334 log_warning_link(link, "Could not update MAC address in DHCPv6 client: %s",
2335 strerror(-r));
2336 return r;
2337 }
2338 }
c49b33ac 2339 }
4f882b2a
TG
2340 }
2341
1e9be60b 2342 return link_update_flags(link, m);
dd3efc09 2343}
fe8db0c5 2344
e375dcde
TG
2345static void link_update_operstate(Link *link) {
2346
2347 assert(link);
2348
2349 if (link->kernel_operstate == IF_OPER_DORMANT)
2350 link->operstate = LINK_OPERSTATE_DORMANT;
2351 else if (link_has_carrier(link->flags, link->kernel_operstate)) {
2352 Address *address;
2353 uint8_t scope = RT_SCOPE_NOWHERE;
2354
2355 /* if we have carrier, check what addresses we have */
2356 LIST_FOREACH(addresses, address, link->addresses) {
2357 if (address->scope < scope)
2358 scope = address->scope;
2359 }
2360
2361 if (scope < RT_SCOPE_SITE)
2362 /* universally accessible addresses found */
2363 link->operstate = LINK_OPERSTATE_ROUTABLE;
2364 else if (scope < RT_SCOPE_HOST)
2365 /* only link or site local addresses found */
2366 link->operstate = LINK_OPERSTATE_DEGRADED;
2367 else
2368 /* no useful addresses found */
2369 link->operstate = LINK_OPERSTATE_CARRIER;
2370 } else
2371 link->operstate = LINK_OPERSTATE_UNKNOWN;
2372}
2373
fe8db0c5 2374int link_save(Link *link) {
68a8723c 2375 _cleanup_free_ char *temp_path = NULL;
fe8db0c5 2376 _cleanup_fclose_ FILE *f = NULL;
e375dcde 2377 const char *admin_state, *oper_state;
fe8db0c5
TG
2378 int r;
2379
2380 assert(link);
2381 assert(link->state_file);
68a8723c 2382 assert(link->lease_file);
bbf7c048
TG
2383 assert(link->manager);
2384
e375dcde
TG
2385 link_update_operstate(link);
2386
bbf7c048
TG
2387 r = manager_save(link->manager);
2388 if (r < 0)
2389 return r;
fe8db0c5 2390
370e9930
TG
2391 if (link->state == LINK_STATE_LINGER) {
2392 unlink(link->state_file);
2393 return 0;
2394 }
2395
deb2e523
TG
2396 admin_state = link_state_to_string(link->state);
2397 assert(admin_state);
2398
e375dcde
TG
2399 oper_state = link_operstate_to_string(link->operstate);
2400 assert(oper_state);
deb2e523 2401
fe8db0c5
TG
2402 r = fopen_temporary(link->state_file, &f, &temp_path);
2403 if (r < 0)
2404 goto finish;
2405
2406 fchmod(fileno(f), 0644);
2407
2408 fprintf(f,
2409 "# This is private data. Do not parse.\n"
deb2e523 2410 "ADMIN_STATE=%s\n"
6dcaa6f5
TG
2411 "OPER_STATE=%s\n",
2412 admin_state, oper_state);
fe8db0c5 2413
bcb7a07e 2414 if (link->network) {
b0e39c82
TG
2415 char **address;
2416
2417 fputs("DNS=", f);
2418
2419 if (link->network->dhcp_dns &&
2420 link->dhcp_lease) {
2421 const struct in_addr *addresses;
2422
2423 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
2424 if (r > 0) {
2425 serialize_in_addrs(f, addresses, r);
2426 if (link->network->dns)
2427 fputs(" ", f);
2428 }
2429 }
2430
2431 STRV_FOREACH(address, link->network->dns)
2432 fprintf(f, "%s%s", *address,
2433 (address + 1 ? " " : ""));
2434
2435 fputs("\n", f);
2436
2437 fprintf(f, "NTP=");
2438
2439 if (link->network->dhcp_ntp &&
2440 link->dhcp_lease) {
2441 const struct in_addr *addresses;
2442
2443 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
2444 if (r > 0) {
2445 serialize_in_addrs(f, addresses, r);
2446 if (link->network->ntp)
2447 fputs(" ", f);
2448 }
2449 }
2450
2451 STRV_FOREACH(address, link->network->ntp)
2452 fprintf(f, "%s%s", *address,
2453 (address + 1 ? " " : ""));
2454
2455 fputs("\n", f);
bcb7a07e 2456 }
7374f9d8 2457
fe8db0c5 2458 if (link->dhcp_lease) {
d9876a52
TG
2459 assert(link->network);
2460
68a8723c 2461 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
fe8db0c5
TG
2462 if (r < 0)
2463 goto finish;
2464
7374f9d8 2465 fprintf(f,
b0e39c82
TG
2466 "DHCP_LEASE=%s\n",
2467 link->lease_file);
deb2e523 2468 } else
68a8723c 2469 unlink(link->lease_file);
fe8db0c5
TG
2470
2471 fflush(f);
2472
2473 if (ferror(f) || rename(temp_path, link->state_file) < 0) {
2474 r = -errno;
2475 unlink(link->state_file);
2476 unlink(temp_path);
2477 }
2478
2479finish:
2480 if (r < 0)
987efa17 2481 log_error_link(link, "Failed to save link data to %s: %s", link->state_file, strerror(-r));
fe8db0c5
TG
2482
2483 return r;
2484}
2485
2486static const char* const link_state_table[_LINK_STATE_MAX] = {
deb2e523 2487 [LINK_STATE_INITIALIZING] = "initializing",
fe8db0c5
TG
2488 [LINK_STATE_ENSLAVING] = "configuring",
2489 [LINK_STATE_SETTING_ADDRESSES] = "configuring",
2490 [LINK_STATE_SETTING_ROUTES] = "configuring",
2491 [LINK_STATE_CONFIGURED] = "configured",
57bd6899 2492 [LINK_STATE_UNMANAGED] = "unmanaged",
fe8db0c5 2493 [LINK_STATE_FAILED] = "failed",
370e9930 2494 [LINK_STATE_LINGER] = "linger",
fe8db0c5
TG
2495};
2496
2497DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
e375dcde
TG
2498
2499static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
2500 [LINK_OPERSTATE_UNKNOWN] = "unknown",
2501 [LINK_OPERSTATE_DORMANT] = "dormant",
2502 [LINK_OPERSTATE_CARRIER] = "carrier",
2503 [LINK_OPERSTATE_DEGRADED] = "degraded",
2504 [LINK_OPERSTATE_ROUTABLE] = "routable",
2505};
2506
2507DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);
ed942a9e
TG
2508
2509static const char* const dhcp_support_table[_DHCP_SUPPORT_MAX] = {
2510 [DHCP_SUPPORT_NONE] = "none",
2511 [DHCP_SUPPORT_BOTH] = "both",
2512 [DHCP_SUPPORT_V4] = "v4",
2513 [DHCP_SUPPORT_V6] = "v6",
2514};
2515
2516DEFINE_STRING_TABLE_LOOKUP(dhcp_support, DHCPSupport);
2517
2518int config_parse_dhcp(
2519 const char* unit,
2520 const char *filename,
2521 unsigned line,
2522 const char *section,
2523 unsigned section_line,
2524 const char *lvalue,
2525 int ltype,
2526 const char *rvalue,
2527 void *data,
2528 void *userdata) {
2529
2530 DHCPSupport *dhcp = data;
2531 int k;
2532
2533 assert(filename);
2534 assert(lvalue);
2535 assert(rvalue);
2536 assert(data);
2537
2538 /* Our enum shall be a superset of booleans, hence first try
2539 * to parse as boolean, and then as enum */
2540
2541 k = parse_boolean(rvalue);
2542 if (k > 0)
2543 *dhcp = DHCP_SUPPORT_BOTH;
2544 else if (k == 0)
2545 *dhcp = DHCP_SUPPORT_NONE;
2546 else {
2547 DHCPSupport s;
2548
2549 s = dhcp_support_from_string(rvalue);
2550 if (s < 0){
2551 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse DHCP option, ignoring: %s", rvalue);
2552 return 0;
2553 }
2554
2555 *dhcp = s;
2556 }
2557
2558 return 0;
2559}