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