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