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