]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
units: local-fs.target - don't pull in default dependencies
[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
fb6730c4 1759 return link_enter_set_addresses(link);
02b59d57
TG
1760}
1761
52433f6b 1762static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
02b59d57
TG
1763 Link *link = userdata;
1764 int r;
1765
1746cf2a 1766 assert(link);
370e9930
TG
1767 assert(IN_SET(link->state, LINK_STATE_ENSLAVING, LINK_STATE_FAILED,
1768 LINK_STATE_LINGER));
ef1ba606 1769 assert(link->network);
02b59d57 1770
52433f6b
TG
1771 link->enslaving --;
1772
370e9930 1773 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
b226d99b 1774 link_unref(link);
02b59d57 1775 return 1;
b226d99b 1776 }
02b59d57
TG
1777
1778 r = sd_rtnl_message_get_errno(m);
ef1ba606 1779 if (r < 0) {
c9ccc19f 1780 log_struct_link(LOG_ERR, link,
97578344 1781 "MESSAGE=%-*s: could not enslave: %s",
987efa17 1782 IFNAMSIZ,
c9ccc19f
TG
1783 link->ifname, strerror(-r),
1784 "ERRNO=%d", -r,
1785 NULL);
ef1ba606 1786 link_enter_failed(link);
b226d99b 1787 link_unref(link);
ef1ba606 1788 return 1;
3333d748 1789 }
02b59d57 1790
52433f6b 1791 log_debug_link(link, "enslaved");
ab47d620 1792
52433f6b
TG
1793 if (link->enslaving == 0)
1794 link_enslaved(link);
02b59d57 1795
b226d99b
TG
1796 link_unref(link);
1797
02b59d57
TG
1798 return 1;
1799}
1800
52433f6b 1801static int link_enter_enslave(Link *link) {
326cb406 1802 NetDev *vlan, *macvlan, *vxlan;
672682a6 1803 Iterator i;
02b59d57
TG
1804 int r;
1805
1806 assert(link);
1807 assert(link->network);
505f8da7 1808 assert(link->state == LINK_STATE_INITIALIZING);
02b59d57 1809
52433f6b 1810 link->state = LINK_STATE_ENSLAVING;
02b59d57 1811
fe8db0c5
TG
1812 link_save(link);
1813
7951dea2
SS
1814 if (!link->network->bridge &&
1815 !link->network->bond &&
1816 !link->network->tunnel &&
fe6b2d55 1817 hashmap_isempty(link->network->vlans) &&
326cb406
SS
1818 hashmap_isempty(link->network->macvlans) &&
1819 hashmap_isempty(link->network->vxlans))
52433f6b 1820 return link_enslaved(link);
02b59d57 1821
d9c67ea1 1822 if (link->network->bond) {
52433f6b 1823 log_struct_link(LOG_DEBUG, link,
97578344 1824 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1825 IFNAMSIZ,
af4e9e2c 1826 link->ifname, link->network->bond->ifname,
d9c67ea1 1827 NETDEV(link->network->bond),
52433f6b 1828 NULL);
449f7554 1829
d9c67ea1 1830 r = netdev_enslave(link->network->bond, link, &enslave_handler);
52433f6b
TG
1831 if (r < 0) {
1832 log_struct_link(LOG_WARNING, link,
97578344 1833 "MESSAGE=%-*s: could not enslave by '%s': %s",
987efa17 1834 IFNAMSIZ,
af4e9e2c 1835 link->ifname, link->network->bond->ifname, strerror(-r),
d9c67ea1 1836 NETDEV(link->network->bond),
52433f6b
TG
1837 NULL);
1838 link_enter_failed(link);
1839 return r;
1840 }
1841
b226d99b 1842 link_ref(link);
0ad6148e
MO
1843 link->enslaving ++;
1844 }
1845
d9c67ea1 1846 if (link->network->bridge) {
0ad6148e 1847 log_struct_link(LOG_DEBUG, link,
97578344 1848 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1849 IFNAMSIZ,
af4e9e2c 1850 link->ifname, link->network->bridge->ifname,
d9c67ea1 1851 NETDEV(link->network->bridge),
0ad6148e
MO
1852 NULL);
1853
d9c67ea1 1854 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
0ad6148e
MO
1855 if (r < 0) {
1856 log_struct_link(LOG_WARNING, link,
97578344 1857 "MESSAGE=%-*s: could not enslave by '%s': %s",
987efa17 1858 IFNAMSIZ,
af4e9e2c 1859 link->ifname, link->network->bridge->ifname, strerror(-r),
d9c67ea1 1860 NETDEV(link->network->bridge),
0ad6148e
MO
1861 NULL);
1862 link_enter_failed(link);
1863 return r;
1864 }
1865
b226d99b 1866 link_ref(link);
52433f6b
TG
1867 link->enslaving ++;
1868 }
1869
7951dea2
SS
1870 if (link->network->tunnel) {
1871 log_struct_link(LOG_DEBUG, link,
97578344 1872 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1873 IFNAMSIZ,
af4e9e2c 1874 link->ifname, link->network->tunnel->ifname,
7951dea2
SS
1875 NETDEV(link->network->tunnel),
1876 NULL);
1877
1878 r = netdev_enslave(link->network->tunnel, link, &enslave_handler);
1879 if (r < 0) {
1880 log_struct_link(LOG_WARNING, link,
97578344 1881 "MESSAGE=%-*s: could not enslave by '%s': %s",
987efa17 1882 IFNAMSIZ,
af4e9e2c 1883 link->ifname, link->network->tunnel->ifname, strerror(-r),
7951dea2
SS
1884 NETDEV(link->network->tunnel),
1885 NULL);
1886 link_enter_failed(link);
1887 return r;
1888 }
1889
1890 link_ref(link);
1891 link->enslaving ++;
1892 }
1893
672682a6 1894 HASHMAP_FOREACH(vlan, link->network->vlans, i) {
52433f6b 1895 log_struct_link(LOG_DEBUG, link,
97578344 1896 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1897 IFNAMSIZ,
af4e9e2c 1898 link->ifname, vlan->ifname, NETDEV(vlan), NULL);
52433f6b 1899
672682a6 1900 r = netdev_enslave(vlan, link, &enslave_handler);
52433f6b
TG
1901 if (r < 0) {
1902 log_struct_link(LOG_WARNING, link,
97578344 1903 "MESSAGE=%-*s: could not enslave by '%s': %s",
987efa17 1904 IFNAMSIZ,
af4e9e2c 1905 link->ifname, vlan->ifname, strerror(-r),
672682a6 1906 NETDEV(vlan), NULL);
52433f6b
TG
1907 link_enter_failed(link);
1908 return r;
1909 }
1910
b226d99b 1911 link_ref(link);
52433f6b 1912 link->enslaving ++;
ef1ba606
TG
1913 }
1914
fe6b2d55
TG
1915 HASHMAP_FOREACH(macvlan, link->network->macvlans, i) {
1916 log_struct_link(LOG_DEBUG, link,
97578344 1917 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1918 IFNAMSIZ,
af4e9e2c 1919 link->ifname, macvlan->ifname, NETDEV(macvlan), NULL);
fe6b2d55
TG
1920
1921 r = netdev_enslave(macvlan, link, &enslave_handler);
1922 if (r < 0) {
1923 log_struct_link(LOG_WARNING, link,
97578344 1924 "MESSAGE=%-*s: could not enslave by '%s': %s",
987efa17 1925 IFNAMSIZ,
af4e9e2c 1926 link->ifname, macvlan->ifname, strerror(-r),
fe6b2d55
TG
1927 NETDEV(macvlan), NULL);
1928 link_enter_failed(link);
1929 return r;
1930 }
1931
b226d99b 1932 link_ref(link);
fe6b2d55
TG
1933 link->enslaving ++;
1934 }
1935
326cb406
SS
1936 HASHMAP_FOREACH(vxlan, link->network->vxlans, i) {
1937 log_struct_link(LOG_DEBUG, link,
1938 "MESSAGE=%*s: enslaving by '%s'",
1939 IFNAMSIZ,
1940 link->ifname, vxlan->ifname, NETDEV(vxlan), NULL);
1941
1942 r = netdev_enslave(vxlan, link, &enslave_handler);
1943 if (r < 0) {
1944 log_struct_link(LOG_WARNING, link,
1945 "MESSAGE=%*s: could not enslave by '%s': %s",
1946 IFNAMSIZ,
1947 link->ifname, vxlan->ifname, strerror(-r),
1948 NETDEV(vxlan), NULL);
1949 link_enter_failed(link);
1950 return r;
1951 }
1952
1953 link_ref(link);
1954 link->enslaving ++;
1955 }
1956
ef1ba606
TG
1957 return 0;
1958}
1959
a748b692 1960static int link_configure(Link *link) {
02b59d57
TG
1961 int r;
1962
ef1ba606 1963 assert(link);
505f8da7 1964 assert(link->state == LINK_STATE_INITIALIZING);
a748b692 1965
eb34d4af 1966 if (link->network->ipv4ll) {
b5db00e5 1967 uint8_t seed[8];
45ad2c13 1968
eb34d4af
TG
1969 r = sd_ipv4ll_new(&link->ipv4ll);
1970 if (r < 0)
1971 return r;
1972
505f8da7
TG
1973 if (link->udev_device) {
1974 r = net_get_unique_predictable_data(link->udev_device, seed);
1975 if (r >= 0) {
1976 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
1977 if (r < 0)
1978 return r;
1979 }
b5db00e5
UTL
1980 }
1981
eb34d4af
TG
1982 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
1983 if (r < 0)
1984 return r;
1985
4bb40e81
TG
1986 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
1987 if (r < 0)
1988 return r;
1989
eb34d4af
TG
1990 r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
1991 if (r < 0)
1992 return r;
1993
1994 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
1995 if (r < 0)
1996 return r;
1997 }
1998
ed942a9e 1999 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) {
eb34d4af
TG
2000 r = sd_dhcp_client_new(&link->dhcp_client);
2001 if (r < 0)
2002 return r;
2003
2004 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
2005 if (r < 0)
2006 return r;
2007
4bb40e81
TG
2008 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
2009 if (r < 0)
2010 return r;
2011
eb34d4af
TG
2012 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
2013 if (r < 0)
2014 return r;
2015
2016 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
2017 if (r < 0)
2018 return r;
2019
2020 if (link->network->dhcp_mtu) {
2021 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
2022 if (r < 0)
2023 return r;
2024 }
e1ea665e
EY
2025 if (link->network->dhcp_routes) {
2026 r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_STATIC_ROUTE);
2027 if (r < 0)
2028 return r;
2029 r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
2030 if (r < 0)
2031 return r;
2032 }
eb34d4af
TG
2033 }
2034
dd43110f 2035 if (link->network->dhcp_server) {
dd43110f
TG
2036 r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
2037 if (r < 0)
2038 return r;
2039
2040 r = sd_dhcp_server_attach_event(link->dhcp_server, NULL, 0);
2041 if (r < 0)
2042 return r;
dd43110f
TG
2043 }
2044
ed942a9e 2045 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
4138fb2c
PF
2046 r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
2047 if (r < 0)
2048 return r;
2049
2050 r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery,
2051 NULL, 0);
2052 if (r < 0)
2053 return r;
2054
2055 r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery,
2056 &link->mac);
2057 if (r < 0)
2058 return r;
2059
2060 r = sd_icmp6_nd_set_index(link->icmp6_router_discovery,
2061 link->ifindex);
2062 if (r < 0)
2063 return r;
2064
2065 r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery,
2066 icmp6_router_handler, link);
2067 if (r < 0)
2068 return r;
2069 }
2070
bf0308cb 2071 if (link_has_carrier(link->flags, link->kernel_operstate)) {
1e9be60b
TG
2072 r = link_acquire_conf(link);
2073 if (r < 0)
2074 return r;
cc544d5f 2075 }
1e9be60b 2076
505f8da7
TG
2077 return link_enter_enslave(link);
2078}
2079
4f561e8e
TG
2080static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
2081 Link *link = userdata;
505f8da7 2082 Network *network;
505f8da7
TG
2083 int r;
2084
2085 assert(link);
2086 assert(link->ifname);
2087 assert(link->manager);
2088
2089 if (link->state != LINK_STATE_INITIALIZING)
2090 return 0;
2091
4f561e8e 2092 log_debug_link(link, "link state is up-to-date");
505f8da7 2093
4f561e8e 2094 r = network_get(link->manager, link->udev_device, link->ifname, &link->mac, &network);
57bd6899
TG
2095 if (r == -ENOENT) {
2096 link_enter_unmanaged(link);
2097 return 0;
2098 } else if (r < 0)
2099 return r;
505f8da7
TG
2100
2101 r = network_apply(link->manager, network, link);
2102 if (r < 0)
2103 return r;
2104
a748b692
TG
2105 r = link_configure(link);
2106 if (r < 0)
2107 return r;
2108
505f8da7
TG
2109 return 0;
2110}
2111
4f561e8e
TG
2112int link_initialized(Link *link, struct udev_device *device) {
2113 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
2114 int r;
2115
2116 assert(link);
2117 assert(link->manager);
2118 assert(link->manager->rtnl);
2119 assert(device);
2120
2121 if (link->state != LINK_STATE_INITIALIZING)
2122 return 0;
2123
2124 log_debug_link(link, "udev initialized link");
2125
2126 link->udev_device = udev_device_ref(device);
2127
2128 /* udev has initialized the link, but we don't know if we have yet processed
2129 the NEWLINK messages with the latest state. Do a GETLINK, when it returns
2130 we know that the pending NEWLINKs have already been processed and that we
2131 are up-to-date */
2132
2133 r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK, link->ifindex);
2134 if (r < 0)
2135 return r;
2136
2137 r = sd_rtnl_call_async(link->manager->rtnl, req, link_initialized_and_synced, link, 0, NULL);
2138 if (r < 0)
2139 return r;
2140
2141 return 0;
2142}
2143
fbbeb65a
TG
2144int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
2145 Manager *m = userdata;
2146 Link *link = NULL;
2147 uint16_t type;
2148 _cleanup_address_free_ Address *address = NULL;
428fd0a7 2149 Address *ad;
fbbeb65a 2150 char buf[INET6_ADDRSTRLEN];
428fd0a7 2151 bool address_dropped = false;
fbbeb65a
TG
2152 int r, ifindex;
2153
2154 assert(rtnl);
2155 assert(message);
2156 assert(m);
2157
2158 r = sd_rtnl_message_get_type(message, &type);
2159 if (r < 0) {
2160 log_warning("rtnl: could not get message type");
2161 return 0;
2162 }
2163
2164 r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
2165 if (r < 0 || ifindex <= 0) {
5ea846cc 2166 log_warning("rtnl: received address message without valid ifindex, ignoring");
fbbeb65a
TG
2167 return 0;
2168 } else {
2169 r = link_get(m, ifindex, &link);
2170 if (r < 0 || !link) {
5ea846cc 2171 log_warning("rtnl: received address for a nonexistent link, ignoring");
fbbeb65a
TG
2172 return 0;
2173 }
2174 }
2175
2176 r = address_new_dynamic(&address);
2177 if (r < 0)
2178 return 0;
2179
2180 r = sd_rtnl_message_addr_get_family(message, &address->family);
2181 if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
987efa17 2182 log_warning_link(link, "rtnl: received address with invalid family, ignoring");
fbbeb65a
TG
2183 return 0;
2184 }
2185
2186 r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
2187 if (r < 0) {
e375dcde
TG
2188 log_warning_link(link, "rtnl: received address with invalid prefixlen, ignoring");
2189 return 0;
2190 }
2191
2192 r = sd_rtnl_message_addr_get_scope(message, &address->scope);
2193 if (r < 0) {
2194 log_warning_link(link, "rtnl: received address with invalid scope, ignoring");
fbbeb65a
TG
2195 return 0;
2196 }
2197
2198 switch (address->family) {
2199 case AF_INET:
2200 r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
2201 if (r < 0) {
987efa17 2202 log_warning_link(link, "rtnl: received address without valid address, ignoring");
fbbeb65a
TG
2203 return 0;
2204 }
2205
2206 break;
2207
2208 case AF_INET6:
2209 r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
2210 if (r < 0) {
987efa17 2211 log_warning_link(link, "rtnl: received address without valid address, ignoring");
fbbeb65a
TG
2212 return 0;
2213 }
2214
2215 break;
2216
2217 default:
2218 assert_not_reached("invalid address family");
2219 }
2220
2221 if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) {
987efa17 2222 log_warning_link(link, "could not print address");
fbbeb65a
TG
2223 return 0;
2224 }
2225
428fd0a7
TG
2226 LIST_FOREACH(addresses, ad, link->addresses) {
2227 if (address_equal(ad, address)) {
2228 LIST_REMOVE(addresses, link->addresses, ad);
2229
2230 address_free(ad);
2231
2232 address_dropped = true;
2233
2234 break;
2235 }
2236 }
2237
fbbeb65a
TG
2238 switch (type) {
2239 case RTM_NEWADDR:
428fd0a7
TG
2240 if (!address_dropped)
2241 log_debug_link(link, "added address: %s/%u", buf,
2242 address->prefixlen);
fbbeb65a 2243
428fd0a7
TG
2244 LIST_PREPEND(addresses, link->addresses, address);
2245 address = NULL;
2246
f5602be9
TG
2247 link_save(link);
2248
428fd0a7 2249 break;
fbbeb65a 2250 case RTM_DELADDR:
f5602be9 2251 if (address_dropped) {
428fd0a7
TG
2252 log_debug_link(link, "removed address: %s/%u", buf,
2253 address->prefixlen);
2254
f5602be9
TG
2255 link_save(link);
2256 }
2257
fbbeb65a
TG
2258 break;
2259 default:
2260 assert_not_reached("Received invalid RTNL message type");
2261 }
2262
2263 return 1;
2264}
2265
2266static int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
2267 Link *link = userdata;
2268 int r;
2269
2270 assert(rtnl);
2271 assert(m);
2272 assert(link);
2273
2274 for (; m; m = sd_rtnl_message_next(m)) {
2275 r = sd_rtnl_message_get_errno(m);
2276 if (r < 0) {
2277 log_debug_link(link, "getting address failed: %s", strerror(-r));
2278 continue;
2279 }
2280
2281 r = link_rtnl_process_address(rtnl, m, link->manager);
2282 if (r < 0)
2283 log_warning_link(link, "could not process address: %s", strerror(-r));
2284 }
2285
2286 return 1;
2287}
2288
505f8da7
TG
2289int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
2290 Link *link;
fbbeb65a 2291 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
505f8da7
TG
2292 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
2293 char ifindex_str[2 + DECIMAL_STR_MAX(int)];
2294 int r;
2295
2296 assert(m);
fbbeb65a 2297 assert(m->rtnl);
505f8da7
TG
2298 assert(message);
2299 assert(ret);
2300
2301 r = link_new(m, message, ret);
2302 if (r < 0)
2303 return r;
2304
2305 link = *ret;
2306
5261692f 2307 log_debug_link(link, "link %"PRIu64" added", link->ifindex);
505f8da7 2308
fbbeb65a
TG
2309 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, link->ifindex, 0);
2310 if (r < 0)
2311 return r;
2312
2313 r = sd_rtnl_call_async(m->rtnl, req, link_get_address_handler, link, 0, NULL);
2314 if (r < 0)
2315 return r;
2316
505f8da7
TG
2317 if (detect_container(NULL) <= 0) {
2318 /* not in a container, udev will be around */
2319 sprintf(ifindex_str, "n%"PRIu64, link->ifindex);
2320 device = udev_device_new_from_device_id(m->udev, ifindex_str);
2321 if (!device) {
2322 log_warning_link(link, "could not find udev device");
2323 return -errno;
2324 }
2325
3c4cb064 2326 if (udev_device_get_is_initialized(device) <= 0) {
505f8da7 2327 /* not yet ready */
16cd414b 2328 log_debug_link(link, "udev initializing link...");
505f8da7 2329 return 0;
3c4cb064 2330 }
505f8da7 2331
4f561e8e
TG
2332 r = link_initialized(link, device);
2333 if (r < 0)
2334 return r;
2335 } else {
2336 r = link_initialized_and_synced(m->rtnl, NULL, link);
2337 if (r < 0)
2338 return r;
2339 }
505f8da7 2340
a748b692
TG
2341 return 0;
2342}
2343
22936833 2344int link_update(Link *link, sd_rtnl_message *m) {
c49b33ac 2345 struct ether_addr mac;
b8941f74 2346 char *ifname;
22936833
TG
2347 int r;
2348
dd3efc09 2349 assert(link);
b8941f74 2350 assert(link->ifname);
22936833
TG
2351 assert(m);
2352
7619683b
TG
2353 if (link->state == LINK_STATE_LINGER) {
2354 link_ref(link);
2355 log_info_link(link, "link readded");
2356 link->state = LINK_STATE_ENSLAVING;
2357 }
2358
b8941f74
TG
2359 r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
2360 if (r >= 0 && !streq(ifname, link->ifname)) {
2361 log_info_link(link, "renamed to %s", ifname);
2362
2363 free(link->ifname);
2364 link->ifname = strdup(ifname);
2365 if (!link->ifname)
2366 return -ENOMEM;
2367 }
2368
505f8da7 2369 if (!link->original_mtu) {
9842de0d
TG
2370 r = sd_rtnl_message_read_u16(m, IFLA_MTU, &link->original_mtu);
2371 if (r >= 0)
2372 log_debug_link(link, "saved original MTU: %"
2373 PRIu16, link->original_mtu);
2374 }
69629de9 2375
e9189a1f
TG
2376 /* The kernel may broadcast NEWLINK messages without the MAC address
2377 set, simply ignore them. */
c49b33ac 2378 r = sd_rtnl_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
e9189a1f 2379 if (r >= 0) {
20861203 2380 if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN)) {
c49b33ac 2381
20861203 2382 memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN);
c49b33ac 2383
20861203
TG
2384 log_debug_link(link, "MAC address: "
2385 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
2386 mac.ether_addr_octet[0],
2387 mac.ether_addr_octet[1],
2388 mac.ether_addr_octet[2],
2389 mac.ether_addr_octet[3],
2390 mac.ether_addr_octet[4],
2391 mac.ether_addr_octet[5]);
c49b33ac 2392
20861203
TG
2393 if (link->ipv4ll) {
2394 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
2395 if (r < 0) {
2396 log_warning_link(link, "Could not update MAC "
2397 "address in IPv4LL client: %s",
2398 strerror(-r));
2399 return r;
2400 }
c49b33ac 2401 }
c49b33ac 2402
20861203
TG
2403 if (link->dhcp_client) {
2404 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
2405 if (r < 0) {
2406 log_warning_link(link, "Could not update MAC "
2407 "address in DHCP client: %s",
2408 strerror(-r));
2409 return r;
2410 }
c49b33ac 2411 }
4138fb2c
PF
2412
2413 if (link->dhcp6_client) {
2414 r = sd_dhcp6_client_set_mac(link->dhcp6_client,
2415 &link->mac);
2416 if (r < 0) {
2417 log_warning_link(link, "Could not update MAC address in DHCPv6 client: %s",
2418 strerror(-r));
2419 return r;
2420 }
2421 }
c49b33ac 2422 }
4f882b2a
TG
2423 }
2424
1e9be60b 2425 return link_update_flags(link, m);
dd3efc09 2426}
fe8db0c5 2427
7374f9d8
TG
2428static void serialize_addresses(FILE *f, const char *key, Address *address) {
2429 Address *ad;
2430
2431 assert(f);
2432 assert(key);
2433
2434 if (!address)
2435 return;
2436
2437 fprintf(f, "%s=", key);
2438
2439 LIST_FOREACH(addresses, ad, address) {
2440 char buf[INET6_ADDRSTRLEN];
2441
d408b506 2442 if (inet_ntop(ad->family, &ad->in_addr, buf, INET6_ADDRSTRLEN))
7374f9d8
TG
2443 fprintf(f, "%s%s", buf, (ad->addresses_next) ? " ": "");
2444 }
2445
2446 fputs("\n", f);
2447}
2448
e375dcde
TG
2449static void link_update_operstate(Link *link) {
2450
2451 assert(link);
2452
2453 if (link->kernel_operstate == IF_OPER_DORMANT)
2454 link->operstate = LINK_OPERSTATE_DORMANT;
2455 else if (link_has_carrier(link->flags, link->kernel_operstate)) {
2456 Address *address;
2457 uint8_t scope = RT_SCOPE_NOWHERE;
2458
2459 /* if we have carrier, check what addresses we have */
2460 LIST_FOREACH(addresses, address, link->addresses) {
2461 if (address->scope < scope)
2462 scope = address->scope;
2463 }
2464
2465 if (scope < RT_SCOPE_SITE)
2466 /* universally accessible addresses found */
2467 link->operstate = LINK_OPERSTATE_ROUTABLE;
2468 else if (scope < RT_SCOPE_HOST)
2469 /* only link or site local addresses found */
2470 link->operstate = LINK_OPERSTATE_DEGRADED;
2471 else
2472 /* no useful addresses found */
2473 link->operstate = LINK_OPERSTATE_CARRIER;
2474 } else
2475 link->operstate = LINK_OPERSTATE_UNKNOWN;
2476}
2477
fe8db0c5 2478int link_save(Link *link) {
68a8723c 2479 _cleanup_free_ char *temp_path = NULL;
fe8db0c5 2480 _cleanup_fclose_ FILE *f = NULL;
e375dcde 2481 const char *admin_state, *oper_state;
fe8db0c5
TG
2482 int r;
2483
2484 assert(link);
2485 assert(link->state_file);
68a8723c 2486 assert(link->lease_file);
bbf7c048
TG
2487 assert(link->manager);
2488
e375dcde
TG
2489 link_update_operstate(link);
2490
bbf7c048
TG
2491 r = manager_save(link->manager);
2492 if (r < 0)
2493 return r;
fe8db0c5 2494
370e9930
TG
2495 if (link->state == LINK_STATE_LINGER) {
2496 unlink(link->state_file);
2497 return 0;
2498 }
2499
deb2e523
TG
2500 admin_state = link_state_to_string(link->state);
2501 assert(admin_state);
2502
e375dcde
TG
2503 oper_state = link_operstate_to_string(link->operstate);
2504 assert(oper_state);
deb2e523 2505
fe8db0c5
TG
2506 r = fopen_temporary(link->state_file, &f, &temp_path);
2507 if (r < 0)
2508 goto finish;
2509
2510 fchmod(fileno(f), 0644);
2511
2512 fprintf(f,
2513 "# This is private data. Do not parse.\n"
deb2e523
TG
2514 "ADMIN_STATE=%s\n"
2515 "OPER_STATE=%s\n"
2516 "FLAGS=%u\n",
2517 admin_state, oper_state, link->flags);
fe8db0c5 2518
bcb7a07e 2519 if (link->network) {
7374f9d8 2520 serialize_addresses(f, "DNS", link->network->dns);
bcb7a07e
TG
2521 serialize_addresses(f, "NTP", link->network->ntp);
2522 }
7374f9d8 2523
fe8db0c5 2524 if (link->dhcp_lease) {
d9876a52
TG
2525 assert(link->network);
2526
68a8723c 2527 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
fe8db0c5
TG
2528 if (r < 0)
2529 goto finish;
2530
7374f9d8
TG
2531 fprintf(f,
2532 "DHCP_LEASE=%s\n"
bcb7a07e
TG
2533 "DHCP_USE_DNS=%s\n"
2534 "DHCP_USE_NTP=%s\n",
2535 link->lease_file,
2536 yes_no(link->network->dhcp_dns),
2537 yes_no(link->network->dhcp_ntp));
deb2e523 2538 } else
68a8723c 2539 unlink(link->lease_file);
fe8db0c5
TG
2540
2541 fflush(f);
2542
2543 if (ferror(f) || rename(temp_path, link->state_file) < 0) {
2544 r = -errno;
2545 unlink(link->state_file);
2546 unlink(temp_path);
2547 }
2548
2549finish:
2550 if (r < 0)
987efa17 2551 log_error_link(link, "Failed to save link data to %s: %s", link->state_file, strerror(-r));
fe8db0c5
TG
2552
2553 return r;
2554}
2555
2556static const char* const link_state_table[_LINK_STATE_MAX] = {
deb2e523 2557 [LINK_STATE_INITIALIZING] = "initializing",
fe8db0c5
TG
2558 [LINK_STATE_ENSLAVING] = "configuring",
2559 [LINK_STATE_SETTING_ADDRESSES] = "configuring",
2560 [LINK_STATE_SETTING_ROUTES] = "configuring",
2561 [LINK_STATE_CONFIGURED] = "configured",
57bd6899 2562 [LINK_STATE_UNMANAGED] = "unmanaged",
fe8db0c5 2563 [LINK_STATE_FAILED] = "failed",
370e9930 2564 [LINK_STATE_LINGER] = "linger",
fe8db0c5
TG
2565};
2566
2567DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
e375dcde
TG
2568
2569static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
2570 [LINK_OPERSTATE_UNKNOWN] = "unknown",
2571 [LINK_OPERSTATE_DORMANT] = "dormant",
2572 [LINK_OPERSTATE_CARRIER] = "carrier",
2573 [LINK_OPERSTATE_DEGRADED] = "degraded",
2574 [LINK_OPERSTATE_ROUTABLE] = "routable",
2575};
2576
2577DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);
ed942a9e
TG
2578
2579static const char* const dhcp_support_table[_DHCP_SUPPORT_MAX] = {
2580 [DHCP_SUPPORT_NONE] = "none",
2581 [DHCP_SUPPORT_BOTH] = "both",
2582 [DHCP_SUPPORT_V4] = "v4",
2583 [DHCP_SUPPORT_V6] = "v6",
2584};
2585
2586DEFINE_STRING_TABLE_LOOKUP(dhcp_support, DHCPSupport);
2587
2588int config_parse_dhcp(
2589 const char* unit,
2590 const char *filename,
2591 unsigned line,
2592 const char *section,
2593 unsigned section_line,
2594 const char *lvalue,
2595 int ltype,
2596 const char *rvalue,
2597 void *data,
2598 void *userdata) {
2599
2600 DHCPSupport *dhcp = data;
2601 int k;
2602
2603 assert(filename);
2604 assert(lvalue);
2605 assert(rvalue);
2606 assert(data);
2607
2608 /* Our enum shall be a superset of booleans, hence first try
2609 * to parse as boolean, and then as enum */
2610
2611 k = parse_boolean(rvalue);
2612 if (k > 0)
2613 *dhcp = DHCP_SUPPORT_BOTH;
2614 else if (k == 0)
2615 *dhcp = DHCP_SUPPORT_NONE;
2616 else {
2617 DHCPSupport s;
2618
2619 s = dhcp_support_from_string(rvalue);
2620 if (s < 0){
2621 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse DHCP option, ignoring: %s", rvalue);
2622 return 0;
2623 }
2624
2625 *dhcp = s;
2626 }
2627
2628 return 0;
2629}