]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
sd-dhcp-client: do not reset 'secs' when entering INIT-REBOOT
[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"
27#include "util.h"
1346b1f0 28#include "bus-util.h"
377a218f 29#include "net-util.h"
f579559b 30
fe8db0c5
TG
31#include "dhcp-lease-internal.h"
32
f579559b
TG
33int link_new(Manager *manager, struct udev_device *device, Link **ret) {
34 _cleanup_link_free_ Link *link = NULL;
8cd11a0f 35 const char *mac;
602cc437 36 struct ether_addr *mac_addr;
c166a070 37 const char *ifname;
f579559b
TG
38 int r;
39
0c2f9b84
TG
40 assert(manager);
41 assert(manager->links);
f579559b
TG
42 assert(device);
43 assert(ret);
44
45 link = new0(Link, 1);
46 if (!link)
47 return -ENOMEM;
48
5a3eb5a7
TG
49 link->manager = manager;
50 link->state = _LINK_STATE_INVALID;
51
0617ffab
TG
52 link->ifindex = udev_device_get_ifindex(device);
53 if (link->ifindex <= 0)
f579559b
TG
54 return -EINVAL;
55
315db1a8
ZJS
56 r = asprintf(&link->state_file, "/run/systemd/network/links/%"PRIu64,
57 link->ifindex);
fe8db0c5 58 if (r < 0)
315db1a8 59 return -ENOMEM;
fe8db0c5 60
8cd11a0f 61 mac = udev_device_get_sysattr_value(device, "address");
5a3eb5a7
TG
62 if (mac) {
63 mac_addr = ether_aton(mac);
64 if (mac_addr)
65 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
66 }
f579559b 67
c166a070
TG
68 ifname = udev_device_get_sysname(device);
69 link->ifname = strdup(ifname);
70
0617ffab 71 r = hashmap_put(manager->links, &link->ifindex, link);
f579559b
TG
72 if (r < 0)
73 return r;
74
75 *ret = link;
76 link = NULL;
77
78 return 0;
79}
80
81void link_free(Link *link) {
82 if (!link)
83 return;
84
0617ffab 85 assert(link->manager);
f579559b 86
a6cc569e
TG
87 sd_dhcp_client_free(link->dhcp_client);
88 sd_dhcp_lease_unref(link->dhcp_lease);
f5be5601 89
5c1d3fc9
UTL
90 sd_ipv4ll_free(link->ipv4ll);
91
0617ffab 92 hashmap_remove(link->manager->links, &link->ifindex);
f579559b 93
c166a070 94 free(link->ifname);
fe8db0c5 95 free(link->state_file);
c166a070 96
f579559b
TG
97 free(link);
98}
99
11a7f229
TG
100int link_get(Manager *m, int ifindex, Link **ret) {
101 Link *link;
102 uint64_t ifindex_64;
103
104 assert(m);
105 assert(m->links);
106 assert(ifindex);
107 assert(ret);
108
109 ifindex_64 = ifindex;
110 link = hashmap_get(m->links, &ifindex_64);
111 if (!link)
112 return -ENODEV;
113
114 *ret = link;
115
116 return 0;
117}
118
f882c247 119static int link_enter_configured(Link *link) {
ef1ba606
TG
120 assert(link);
121 assert(link->state == LINK_STATE_SETTING_ROUTES);
122
39032b87 123 log_info_link(link, "link configured");
f882c247
TG
124
125 link->state = LINK_STATE_CONFIGURED;
126
fe8db0c5
TG
127 link_save(link);
128
f882c247
TG
129 return 0;
130}
131
ef1ba606
TG
132static void link_enter_failed(Link *link) {
133 assert(link);
f882c247 134
39032b87 135 log_warning_link(link, "failed");
449f7554 136
ef1ba606 137 link->state = LINK_STATE_FAILED;
fe8db0c5
TG
138
139 link_save(link);
f882c247
TG
140}
141
f882c247
TG
142static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
143 Link *link = userdata;
144 int r;
145
f5be5601
TG
146 assert(link->route_messages > 0);
147 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
148 link->state == LINK_STATE_SETTING_ROUTES ||
149 link->state == LINK_STATE_FAILED);
f882c247 150
f5be5601 151 link->route_messages --;
f882c247
TG
152
153 if (link->state == LINK_STATE_FAILED)
154 return 1;
155
156 r = sd_rtnl_message_get_errno(m);
c166a070 157 if (r < 0 && r != -EEXIST)
c9ccc19f
TG
158 log_struct_link(LOG_WARNING, link,
159 "MESSAGE=%s: could not set route: %s",
160 link->ifname, strerror(-r),
161 "ERRNO=%d", -r,
162 NULL);
f882c247 163
f5be5601
TG
164 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
165 * ignore it */
166 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
39032b87 167 log_debug_link(link, "routes set");
dd3efc09
TG
168 link_enter_configured(link);
169 }
f882c247
TG
170
171 return 1;
172}
173
174static int link_enter_set_routes(Link *link) {
a6cc569e 175 Route *rt;
5c1d3fc9 176 struct in_addr a;
f882c247
TG
177 int r;
178
179 assert(link);
180 assert(link->network);
ef1ba606 181 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
f882c247 182
ef1ba606 183 link->state = LINK_STATE_SETTING_ROUTES;
f882c247 184
5c1d3fc9
UTL
185 if (!link->network->static_routes && !link->dhcp_lease &&
186 (!link->ipv4ll || sd_ipv4ll_get_address(link->ipv4ll, &a) < 0))
dd3efc09 187 return link_enter_configured(link);
f882c247 188
39032b87 189 log_debug_link(link, "setting routes");
449f7554 190
a6cc569e
TG
191 LIST_FOREACH(static_routes, rt, link->network->static_routes) {
192 r = route_configure(rt, link, &route_handler);
dd3efc09 193 if (r < 0) {
3333d748
ZJS
194 log_warning_link(link,
195 "could not set routes: %s", strerror(-r));
ef1ba606
TG
196 link_enter_failed(link);
197 return r;
dd3efc09 198 }
c166a070 199
f5be5601
TG
200 link->route_messages ++;
201 }
202
5c1d3fc9
UTL
203 if (link->ipv4ll && !link->dhcp_lease) {
204 _cleanup_route_free_ Route *route = NULL;
205 struct in_addr addr;
206
207 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
208 if (r < 0 && r != -ENOENT) {
209 log_warning_link(link, "IPV4LL error: no address: %s",
210 strerror(-r));
211 return r;
212 }
213
214 if (r != -ENOENT) {
215 r = route_new_dynamic(&route);
216 if (r < 0) {
217 log_error_link(link, "Could not allocate route: %s",
218 strerror(-r));
219 return r;
220 }
221
222 route->family = AF_INET;
223 route->scope = RT_SCOPE_LINK;
224 route->metrics = 99;
225
226 r = route_configure(route, link, &route_handler);
227 if (r < 0) {
228 log_warning_link(link,
229 "could not set routes: %s", strerror(-r));
230 link_enter_failed(link);
231 return r;
232 }
233
234 link->route_messages ++;
235 }
236 }
237
a6cc569e
TG
238 if (link->dhcp_lease) {
239 _cleanup_route_free_ Route *route = NULL;
240 struct in_addr gateway;
241
242 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
243 if (r < 0) {
244 log_warning_link(link, "DHCP error: no router: %s",
245 strerror(-r));
246 return r;
247 }
248
249 r = route_new_dynamic(&route);
250 if (r < 0) {
251 log_error_link(link, "Could not allocate route: %s",
252 strerror(-r));
253 return r;
254 }
255
256 route->family = AF_INET;
257 route->in_addr.in = gateway;
258
259 r = route_configure(route, link, &route_handler);
f5be5601 260 if (r < 0) {
3333d748
ZJS
261 log_warning_link(link,
262 "could not set routes: %s", strerror(-r));
f5be5601
TG
263 link_enter_failed(link);
264 return r;
265 }
266
267 link->route_messages ++;
f882c247
TG
268 }
269
270 return 0;
271}
272
5c1d3fc9
UTL
273static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
274 Link *link = userdata;
275 int r;
276
277 assert(m);
278 assert(link);
279 assert(link->ifname);
280
281 if (link->state == LINK_STATE_FAILED)
282 return 1;
283
284 r = sd_rtnl_message_get_errno(m);
285 if (r < 0 && r != -ENOENT)
286 log_struct_link(LOG_WARNING, link,
287 "MESSAGE=%s: could not drop route: %s",
288 link->ifname, strerror(-r),
289 "ERRNO=%d", -r,
290 NULL);
291
292 return 0;
293}
294
f882c247
TG
295static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
296 Link *link = userdata;
297 int r;
298
f5be5601
TG
299 assert(m);
300 assert(link);
301 assert(link->ifname);
302 assert(link->addr_messages > 0);
ef1ba606 303 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
f882c247 304
f5be5601 305 link->addr_messages --;
f882c247
TG
306
307 if (link->state == LINK_STATE_FAILED)
308 return 1;
309
310 r = sd_rtnl_message_get_errno(m);
c166a070 311 if (r < 0 && r != -EEXIST)
c9ccc19f 312 log_struct_link(LOG_WARNING, link,
3333d748
ZJS
313 "MESSAGE=%s: could not set address: %s",
314 link->ifname, strerror(-r),
315 "ERRNO=%d", -r,
316 NULL);
f882c247 317
f5be5601 318 if (link->addr_messages == 0) {
39032b87 319 log_debug_link(link, "addresses set");
ef1ba606 320 link_enter_set_routes(link);
dd3efc09 321 }
f882c247
TG
322
323 return 1;
324}
325
326static int link_enter_set_addresses(Link *link) {
a6cc569e 327 Address *ad;
5c1d3fc9 328 struct in_addr a;
f882c247
TG
329 int r;
330
331 assert(link);
332 assert(link->network);
f5be5601 333 assert(link->state != _LINK_STATE_INVALID);
f882c247 334
ef1ba606 335 link->state = LINK_STATE_SETTING_ADDRESSES;
f882c247 336
5c1d3fc9
UTL
337 if (!link->network->static_addresses && !link->dhcp_lease &&
338 (!link->ipv4ll || sd_ipv4ll_get_address(link->ipv4ll, &a) < 0))
ef1ba606 339 return link_enter_set_routes(link);
f882c247 340
39032b87 341 log_debug_link(link, "setting addresses");
449f7554 342
a6cc569e
TG
343 LIST_FOREACH(static_addresses, ad, link->network->static_addresses) {
344 r = address_configure(ad, link, &address_handler);
dd3efc09 345 if (r < 0) {
3333d748
ZJS
346 log_warning_link(link,
347 "could not set addresses: %s", strerror(-r));
ef1ba606
TG
348 link_enter_failed(link);
349 return r;
dd3efc09 350 }
c166a070 351
f5be5601
TG
352 link->addr_messages ++;
353 }
354
5c1d3fc9
UTL
355 if (link->ipv4ll && !link->dhcp_lease) {
356 _cleanup_address_free_ Address *ll_addr = NULL;
357 struct in_addr addr;
358
359 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
360 if (r < 0 && r != -ENOENT) {
361 log_warning_link(link, "IPV4LL error: no address: %s",
362 strerror(-r));
363 return r;
364 }
365
366 if (r != -ENOENT) {
367 r = address_new_dynamic(&ll_addr);
368 if (r < 0) {
369 log_error_link(link, "Could not allocate address: %s", strerror(-r));
370 return r;
371 }
372
373 ll_addr->family = AF_INET;
374 ll_addr->in_addr.in = addr;
375 ll_addr->prefixlen = 16;
376 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
377 ll_addr->scope = RT_SCOPE_LINK;
378
379 r = address_configure(ll_addr, link, &address_handler);
380 if (r < 0) {
381 log_warning_link(link,
382 "could not set addresses: %s", strerror(-r));
383 link_enter_failed(link);
384 return r;
385 }
386
387 link->addr_messages ++;
388 }
389 }
390
a6cc569e
TG
391 if (link->dhcp_lease) {
392 _cleanup_address_free_ Address *address = NULL;
393 struct in_addr addr;
394 struct in_addr netmask;
395 unsigned prefixlen;
396
397 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
398 if (r < 0) {
399 log_warning_link(link, "DHCP error: no address: %s",
400 strerror(-r));
401 return r;
402 }
403
404 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
405 if (r < 0) {
406 log_warning_link(link, "DHCP error: no netmask: %s",
407 strerror(-r));
408 return r;
409 }
410
411 prefixlen = net_netmask_to_prefixlen(&netmask);
412
413 r = address_new_dynamic(&address);
414 if (r < 0) {
415 log_error_link(link, "Could not allocate address: %s",
416 strerror(-r));
417 return r;
418 }
419
420 address->family = AF_INET;
421 address->in_addr.in = addr;
422 address->prefixlen = prefixlen;
423 address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
424
425 r = address_configure(address, link, &address_handler);
f5be5601 426 if (r < 0) {
3333d748
ZJS
427 log_warning_link(link,
428 "could not set addresses: %s", strerror(-r));
f5be5601
TG
429 link_enter_failed(link);
430 return r;
431 }
432
433 link->addr_messages ++;
f882c247
TG
434 }
435
436 return 0;
437}
438
ff254138
TG
439static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
440 Link *link = userdata;
441 int r;
442
443 assert(m);
444 assert(link);
445 assert(link->ifname);
446
447 if (link->state == LINK_STATE_FAILED)
448 return 1;
449
450 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
451 if (r < 0 && r != -ENOENT)
452 log_struct_link(LOG_WARNING, link,
453 "MESSAGE=%s: could not drop address: %s",
454 link->ifname, strerror(-r),
455 "ERRNO=%d", -r,
456 NULL);
ff254138 457
5c1d3fc9 458 return 0;
ff254138
TG
459}
460
1346b1f0
TG
461static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
462 int r;
463
464 r = sd_bus_message_get_errno(m);
465 if (r < 0)
466 log_warning("Could not set hostname: %s", strerror(-r));
467
468 return 1;
469}
470
471static int set_hostname(sd_bus *bus, const char *hostname) {
472 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
473 int r = 0;
474
1346b1f0
TG
475 assert(hostname);
476
477 log_debug("Setting transient hostname: '%s'", hostname);
478
bcbca829
TG
479 if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
480 log_info("Not connected to system bus, ignoring transient hostname.");
481 return 0;
482 }
483
1346b1f0
TG
484 r = sd_bus_message_new_method_call(
485 bus,
151b9b96 486 &m,
1346b1f0
TG
487 "org.freedesktop.hostname1",
488 "/org/freedesktop/hostname1",
489 "org.freedesktop.hostname1",
151b9b96 490 "SetHostname");
1346b1f0
TG
491 if (r < 0)
492 return r;
493
494 r = sd_bus_message_append(m, "sb", hostname, false);
495 if (r < 0)
496 return r;
497
498 r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
499 if (r < 0)
500 log_error("Could not set transient hostname: %s", strerror(-r));
501
502 return r;
503}
504
4f882b2a
TG
505static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
506 Link *link = userdata;
507 int r;
508
509 assert(m);
510 assert(link);
511 assert(link->ifname);
512
513 if (link->state == LINK_STATE_FAILED)
514 return 1;
515
516 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
517 if (r < 0)
518 log_struct_link(LOG_WARNING, link,
519 "MESSAGE=%s: could not set MTU: %s",
520 link->ifname, strerror(-r),
521 "ERRNO=%d", -r,
522 NULL);
4f882b2a
TG
523
524 return 1;
525}
526
527static int link_set_mtu(Link *link, uint32_t mtu) {
cf6a8911 528 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
4f882b2a
TG
529 int r;
530
531 assert(link);
532 assert(link->manager);
533 assert(link->manager->rtnl);
534
535 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
536
151b9b96
LP
537 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
538 RTM_SETLINK, link->ifindex);
4f882b2a
TG
539 if (r < 0) {
540 log_error_link(link, "Could not allocate RTM_SETLINK message");
541 return r;
542 }
543
544 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
545 if (r < 0) {
546 log_error_link(link, "Could not append MTU: %s", strerror(-r));
547 return r;
548 }
549
550 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
551 if (r < 0) {
552 log_error_link(link,
553 "Could not send rtnetlink message: %s", strerror(-r));
554 return r;
555 }
556
557 return 0;
558}
559
a6cc569e
TG
560static int dhcp_lease_lost(Link *link) {
561 _cleanup_address_free_ Address *address = NULL;
562 struct in_addr addr;
563 struct in_addr netmask;
564 unsigned prefixlen;
ff254138
TG
565 int r;
566
567 assert(link);
a6cc569e 568 assert(link->dhcp_lease);
ff254138 569
14efd761
TG
570 log_warning_link(link, "DHCP lease lost");
571
a6cc569e
TG
572 r = address_new_dynamic(&address);
573 if (r >= 0) {
574 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
575 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
576 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 577
a6cc569e
TG
578 address->family = AF_INET;
579 address->in_addr.in = addr;
580 address->prefixlen = prefixlen;
ff254138 581
5c1d3fc9 582 address_drop(address, link, &address_drop_handler);
c07aeadf 583 }
eb27aeca 584
c07aeadf
TG
585 if (link->network->dhcp_mtu) {
586 uint16_t mtu;
ff254138 587
a6cc569e 588 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
c07aeadf
TG
589 if (r >= 0 && link->original_mtu != mtu) {
590 r = link_set_mtu(link, link->original_mtu);
591 if (r < 0) {
592 log_warning_link(link, "DHCP error: could not reset MTU");
593 link_enter_failed(link);
594 return r;
595 }
ff254138 596 }
c07aeadf 597 }
ff254138 598
c07aeadf 599 if (link->network->dhcp_hostname) {
216816c6
TG
600 const char *hostname = NULL;
601
602 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
603 if (r >= 0 && hostname) {
604 r = set_hostname(link->manager->bus, "");
605 if (r < 0)
606 log_error("Failed to reset transient hostname");
607 }
c07aeadf 608 }
4f882b2a 609
a6cc569e
TG
610 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
611
c07aeadf
TG
612 return 0;
613}
4f882b2a 614
c07aeadf 615static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
a6cc569e 616 sd_dhcp_lease *lease;
c07aeadf
TG
617 struct in_addr address;
618 struct in_addr netmask;
619 struct in_addr gateway;
620 unsigned prefixlen;
c07aeadf
TG
621 struct in_addr *nameservers;
622 size_t nameservers_size;
623 int r;
1346b1f0 624
c07aeadf
TG
625 assert(client);
626 assert(link);
ff254138 627
a6cc569e
TG
628 r = sd_dhcp_client_get_lease(client, &lease);
629 if (r < 0) {
630 log_warning_link(link, "DHCP error: no lease: %s",
631 strerror(-r));
632 return r;
633 }
634
635 r = sd_dhcp_lease_get_address(lease, &address);
ff254138 636 if (r < 0) {
c07aeadf
TG
637 log_warning_link(link, "DHCP error: no address: %s",
638 strerror(-r));
639 return r;
ff254138
TG
640 }
641
a6cc569e 642 r = sd_dhcp_lease_get_netmask(lease, &netmask);
ff254138 643 if (r < 0) {
c07aeadf
TG
644 log_warning_link(link, "DHCP error: no netmask: %s",
645 strerror(-r));
646 return r;
ff254138
TG
647 }
648
377a218f 649 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 650
a6cc569e 651 r = sd_dhcp_lease_get_router(lease, &gateway);
ff254138 652 if (r < 0) {
c07aeadf
TG
653 log_warning_link(link, "DHCP error: no router: %s",
654 strerror(-r));
655 return r;
ff254138
TG
656 }
657
c07aeadf
TG
658 log_struct_link(LOG_INFO, link,
659 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
660 link->ifname,
661 ADDRESS_FMT_VAL(address),
662 prefixlen,
663 ADDRESS_FMT_VAL(gateway),
664 "ADDRESS=%u.%u.%u.%u",
665 ADDRESS_FMT_VAL(address),
666 "PREFIXLEN=%u",
667 prefixlen,
668 "GATEWAY=%u.%u.%u.%u",
669 ADDRESS_FMT_VAL(gateway),
670 NULL);
671
d50cf59b
TG
672 link->dhcp_lease = lease;
673
c07aeadf 674 if (link->network->dhcp_dns) {
a6cc569e 675 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
c07aeadf
TG
676 if (r >= 0) {
677 r = manager_update_resolv_conf(link->manager);
678 if (r < 0)
679 log_error("Failed to update resolv.conf");
ff254138 680 }
c07aeadf 681 }
ff254138 682
c07aeadf
TG
683 if (link->network->dhcp_mtu) {
684 uint16_t mtu;
685
a6cc569e 686 r = sd_dhcp_lease_get_mtu(lease, &mtu);
c07aeadf
TG
687 if (r >= 0) {
688 r = link_set_mtu(link, mtu);
689 if (r < 0)
690 log_error_link(link, "Failed to set MTU "
691 "to %" PRIu16, mtu);
692 }
693 }
ff254138 694
c07aeadf
TG
695 if (link->network->dhcp_hostname) {
696 const char *hostname;
ff254138 697
a6cc569e 698 r = sd_dhcp_lease_get_hostname(lease, &hostname);
c07aeadf
TG
699 if (r >= 0) {
700 r = set_hostname(link->manager->bus, hostname);
701 if (r < 0)
702 log_error("Failed to set transient hostname "
703 "to '%s'", hostname);
3bef724f 704 }
c07aeadf 705 }
3bef724f 706
c07aeadf
TG
707 link_enter_set_addresses(link);
708
709 return 0;
710}
711
712static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
713 Link *link = userdata;
714 int r;
715
716 assert(link);
717 assert(link->network);
718 assert(link->manager);
719
720 if (link->state == LINK_STATE_FAILED)
721 return;
722
723 switch (event) {
724 case DHCP_EVENT_NO_LEASE:
725 log_debug_link(link, "IP address in use.");
726 break;
727 case DHCP_EVENT_EXPIRED:
728 case DHCP_EVENT_STOP:
729 case DHCP_EVENT_IP_CHANGE:
730 if (link->network->dhcp_critical) {
731 log_error_link(link, "DHCPv4 connection considered system critical, "
732 "ignoring request to reconfigure it.");
733 return;
4f882b2a 734 }
4f882b2a 735
17256461
UTL
736 if (link->dhcp_lease) {
737 r = dhcp_lease_lost(link);
738 if (r < 0) {
739 link_enter_failed(link);
740 return;
741 }
c07aeadf 742 }
1346b1f0 743
c07aeadf
TG
744 if (event == DHCP_EVENT_IP_CHANGE) {
745 r = dhcp_lease_acquired(client, link);
746 if (r < 0) {
747 link_enter_failed(link);
748 return;
749 }
1346b1f0 750 }
1346b1f0 751
5c1d3fc9
UTL
752 if (event == DHCP_EVENT_EXPIRED && link->network->ipv4ll) {
753 r = sd_ipv4ll_start (link->ipv4ll);
754 if (r < 0) {
755 link_enter_failed(link);
756 return;
757 }
758 }
759
c07aeadf
TG
760 break;
761 case DHCP_EVENT_IP_ACQUIRE:
762 r = dhcp_lease_acquired(client, link);
763 if (r < 0) {
764 link_enter_failed(link);
765 return;
766 }
5c1d3fc9
UTL
767 if (link->ipv4ll) {
768 r = sd_ipv4ll_stop(link->ipv4ll);
769 if (r < 0) {
770 link_enter_failed(link);
771 return;
772 }
773 }
c07aeadf
TG
774 break;
775 default:
776 if (event < 0)
777 log_warning_link(link, "DHCP error: %s", strerror(-event));
778 else
779 log_warning_link(link, "DHCP unknown event: %d", event);
c07aeadf 780 break;
ff254138
TG
781 }
782
783 return;
784}
785
5c1d3fc9
UTL
786static int ipv4ll_address_lost(sd_ipv4ll *ll, Link *link) {
787 int r;
788 struct in_addr addr;
789
790 assert(ll);
791 assert(link);
792
793 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
794 if (r >= 0) {
795 _cleanup_address_free_ Address *address = NULL;
796 _cleanup_route_free_ Route *route = NULL;
797
798 log_debug_link(link, "IPv4 link-local release %u.%u.%u.%u",
799 ADDRESS_FMT_VAL(addr));
800
801 r = address_new_dynamic(&address);
802 if (r < 0) {
803 log_error_link(link, "Could not allocate address: %s", strerror(-r));
804 return r;
805 }
806
807 address->family = AF_INET;
808 address->in_addr.in = addr;
809 address->prefixlen = 16;
810 address->scope = RT_SCOPE_LINK;
811
812 address_drop(address, link, &address_drop_handler);
813
814 r = route_new_dynamic(&route);
815 if (r < 0) {
816 log_error_link(link, "Could not allocate route: %s",
817 strerror(-r));
818 return r;
819 }
820
821 route->family = AF_INET;
822 route->scope = RT_SCOPE_LINK;
823 route->metrics = 99;
824
825 route_drop(route, link, &route_drop_handler);
826 }
827
828 return 0;
829}
830
831static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
832 struct in_addr address;
833 int r;
834
835 assert(ll);
836 assert(link);
837
838 r = sd_ipv4ll_get_address(ll, &address);
839 if (r < 0)
840 return r;
841
842 log_struct_link(LOG_INFO, link,
843 "MESSAGE=%s: IPv4 link-local address %u.%u.%u.%u",
844 link->ifname,
845 ADDRESS_FMT_VAL(address),
846 NULL);
847
848 link_enter_set_addresses(link);
849
850 return 0;
851}
852
853static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
854 Link *link = userdata;
855 int r;
856
857 assert(link);
858 assert(link->network);
859 assert(link->manager);
860
861 switch(event) {
862 case IPV4LL_EVENT_STOP:
863 case IPV4LL_EVENT_CONFLICT:
864 r = ipv4ll_address_lost(ll, link);
865 if (r < 0) {
866 link_enter_failed(link);
867 return;
868 }
869 break;
870 case IPV4LL_EVENT_BIND:
871 r = ipv4ll_address_claimed(ll, link);
872 if (r < 0) {
873 link_enter_failed(link);
874 return;
875 }
876 break;
877 default:
878 if (event < 0)
879 log_warning_link(link, "IPv4 link-local error: %s", strerror(-event));
880 else
881 log_warning_link(link, "IPv4 link-local unknown event: %d", event);
882 break;
883 }
884}
885
ff254138
TG
886static int link_acquire_conf(Link *link) {
887 int r;
888
889 assert(link);
890 assert(link->network);
ff254138
TG
891 assert(link->manager);
892 assert(link->manager->event);
893
5c1d3fc9
UTL
894 if (link->network->ipv4ll) {
895 if (!link->ipv4ll) {
896 r = sd_ipv4ll_new(&link->ipv4ll);
897 if (r < 0)
898 return r;
b25ef18b 899
5c1d3fc9
UTL
900 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
901 if (r < 0)
902 return r;
ff254138 903
5c1d3fc9
UTL
904 r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
905 if (r < 0)
906 return r;
ff254138 907
5c1d3fc9
UTL
908 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
909 if (r < 0)
910 return r;
911
912 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
913 if (r < 0)
914 return r;
915 }
ff254138 916
5c1d3fc9
UTL
917 log_debug_link(link, "acquiring IPv4 link-local address");
918
919 r = sd_ipv4ll_start(link->ipv4ll);
ff254138
TG
920 if (r < 0)
921 return r;
5c1d3fc9
UTL
922 }
923
924 if (link->network->dhcp) {
925 if (!link->dhcp_client) {
926 r = sd_dhcp_client_new(&link->dhcp_client);
927 if (r < 0)
928 return r;
929
930 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
931 if (r < 0)
932 return r;
933
934 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
935 if (r < 0)
936 return r;
937
938 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
939 if (r < 0)
940 return r;
6fc73498 941
5c1d3fc9 942 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
6fc73498
TG
943 if (r < 0)
944 return r;
5c1d3fc9
UTL
945
946 if (link->network->dhcp_mtu) {
947 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
948 if (r < 0)
949 return r;
950 }
6fc73498 951 }
ff254138 952
5c1d3fc9 953 log_debug_link(link, "acquiring DHCPv4 lease");
ab47d620 954
5c1d3fc9
UTL
955 r = sd_dhcp_client_start(link->dhcp_client);
956 if (r < 0)
957 return r;
958 }
ff254138
TG
959
960 return 0;
961}
962
963static int link_update_flags(Link *link, unsigned flags) {
964 int r;
965
966 assert(link);
967 assert(link->network);
968
969 if (link->state == LINK_STATE_FAILED)
970 return 0;
971
a748b692 972 if (link->flags == flags)
efbc88b8 973 return 0;
efbc88b8 974
3333d748
ZJS
975 if ((link->flags & IFF_UP) != (flags & IFF_UP))
976 log_info_link(link,
e6674986 977 "link is %s", flags & IFF_UP ? "up": "down");
efbc88b8
TG
978
979 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
980 if (flags & IFF_LOWER_UP) {
39032b87 981 log_info_link(link, "carrier on");
efbc88b8 982
5c1d3fc9 983 if (link->network->dhcp || link->network->ipv4ll) {
efbc88b8
TG
984 r = link_acquire_conf(link);
985 if (r < 0) {
5c1d3fc9 986 log_warning_link(link, "Could not acquire configuration: %s", strerror(-r));
efbc88b8
TG
987 link_enter_failed(link);
988 return r;
989 }
ff254138 990 }
efbc88b8 991 } else {
39032b87 992 log_info_link(link, "carrier off");
efbc88b8
TG
993
994 if (link->network->dhcp) {
a6cc569e 995 r = sd_dhcp_client_stop(link->dhcp_client);
efbc88b8 996 if (r < 0) {
1f6d9bc9 997 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
efbc88b8
TG
998 link_enter_failed(link);
999 return r;
1000 }
ff254138 1001 }
5c1d3fc9
UTL
1002
1003 if (link->network->ipv4ll) {
1004 r = sd_ipv4ll_stop(link->ipv4ll);
1005 if (r < 0) {
1006 log_warning_link(link, "Could not stop IPv4 link-local: %s", strerror(-r));
1007 link_enter_failed(link);
1008 return r;
1009 }
1010 }
ff254138
TG
1011 }
1012 }
1013
a748b692
TG
1014 log_debug_link(link, "link status updated: %#.8x -> %#.8x",
1015 link->flags, flags);
efbc88b8 1016
ff254138
TG
1017 link->flags = flags;
1018
1019 return 0;
1020}
1021
dd3efc09
TG
1022static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
1023 Link *link = userdata;
1024 int r;
1025
1746cf2a
TG
1026 assert(link);
1027
1028 if (link->state == LINK_STATE_FAILED)
1029 return 1;
1030
dd3efc09 1031 r = sd_rtnl_message_get_errno(m);
58b12917
ZJS
1032 if (r >= 0)
1033 link_update_flags(link, link->flags | IFF_UP);
1034 else
76800848 1035 log_struct_link(LOG_WARNING, link,
c9ccc19f
TG
1036 "MESSAGE=%s: could not bring up interface: %s",
1037 link->ifname, strerror(-r),
1038 "ERRNO=%d", -r,
1039 NULL);
f882c247
TG
1040 return 1;
1041}
1042
1043static int link_up(Link *link) {
cf6a8911 1044 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
1045 int r;
1046
f882c247
TG
1047 assert(link);
1048 assert(link->manager);
1049 assert(link->manager->rtnl);
1050
39032b87 1051 log_debug_link(link, "bringing link up");
449f7554 1052
151b9b96
LP
1053 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
1054 RTM_SETLINK, link->ifindex);
f579559b 1055 if (r < 0) {
39032b87 1056 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
1057 return r;
1058 }
1059
5d4795f3 1060 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 1061 if (r < 0) {
3333d748 1062 log_error_link(link, "Could not set link flags: %s", strerror(-r));
fc25d7f8
TG
1063 return r;
1064 }
1065
dd3efc09 1066 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 1067 if (r < 0) {
3333d748
ZJS
1068 log_error_link(link,
1069 "Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
1070 return r;
1071 }
1072
f882c247
TG
1073 return 0;
1074}
1075
52433f6b 1076static int link_enslaved(Link *link) {
f882c247
TG
1077 int r;
1078
ef1ba606 1079 assert(link);
52433f6b 1080 assert(link->state == LINK_STATE_ENSLAVING);
f5be5601 1081 assert(link->network);
dd3efc09 1082
f882c247 1083 r = link_up(link);
ef1ba606
TG
1084 if (r < 0) {
1085 link_enter_failed(link);
1086 return r;
1087 }
f882c247 1088
5c1d3fc9 1089 if (!link->network->dhcp && !link->network->ipv4ll)
1746cf2a 1090 return link_enter_set_addresses(link);
ef1ba606
TG
1091
1092 return 0;
02b59d57
TG
1093}
1094
52433f6b 1095static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
02b59d57
TG
1096 Link *link = userdata;
1097 int r;
1098
1746cf2a 1099 assert(link);
52433f6b 1100 assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
ef1ba606 1101 assert(link->network);
02b59d57 1102
52433f6b
TG
1103 link->enslaving --;
1104
02b59d57
TG
1105 if (link->state == LINK_STATE_FAILED)
1106 return 1;
1107
1108 r = sd_rtnl_message_get_errno(m);
ef1ba606 1109 if (r < 0) {
c9ccc19f
TG
1110 log_struct_link(LOG_ERR, link,
1111 "MESSAGE=%s: could not enslave: %s",
1112 link->ifname, strerror(-r),
1113 "ERRNO=%d", -r,
1114 NULL);
ef1ba606
TG
1115 link_enter_failed(link);
1116 return 1;
3333d748 1117 }
02b59d57 1118
52433f6b 1119 log_debug_link(link, "enslaved");
ab47d620 1120
52433f6b
TG
1121 if (link->enslaving == 0)
1122 link_enslaved(link);
02b59d57
TG
1123
1124 return 1;
1125}
1126
52433f6b 1127static int link_enter_enslave(Link *link) {
fe6b2d55 1128 NetDev *vlan, *macvlan;
672682a6 1129 Iterator i;
02b59d57
TG
1130 int r;
1131
1132 assert(link);
1133 assert(link->network);
ef1ba606 1134 assert(link->state == _LINK_STATE_INVALID);
02b59d57 1135
52433f6b 1136 link->state = LINK_STATE_ENSLAVING;
02b59d57 1137
fe8db0c5
TG
1138 link_save(link);
1139
63ffa720 1140 if (!link->network->bridge && !link->network->bond &&
fe6b2d55
TG
1141 hashmap_isempty(link->network->vlans) &&
1142 hashmap_isempty(link->network->macvlans))
52433f6b 1143 return link_enslaved(link);
02b59d57 1144
52433f6b
TG
1145 if (link->network->bridge) {
1146 log_struct_link(LOG_DEBUG, link,
1147 "MESSAGE=%s: enslaving by '%s'",
c9ccc19f 1148 link->ifname, link->network->bridge->name,
52433f6b
TG
1149 NETDEV(link->network->bridge),
1150 NULL);
449f7554 1151
52433f6b
TG
1152 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
1153 if (r < 0) {
1154 log_struct_link(LOG_WARNING, link,
1155 "MESSAGE=%s: could not enslave by '%s': %s",
c9ccc19f 1156 link->ifname, link->network->bridge->name, strerror(-r),
52433f6b
TG
1157 NETDEV(link->network->bridge),
1158 NULL);
1159 link_enter_failed(link);
1160 return r;
1161 }
1162
0ad6148e
MO
1163 link->enslaving ++;
1164 }
1165
1166 if (link->network->bond) {
1167 log_struct_link(LOG_DEBUG, link,
1168 "MESSAGE=%s: enslaving by '%s'",
1169 link->ifname, link->network->bond->name,
1170 NETDEV(link->network->bond),
1171 NULL);
1172
1173 r = netdev_enslave(link->network->bond, link, &enslave_handler);
1174 if (r < 0) {
1175 log_struct_link(LOG_WARNING, link,
1176 "MESSAGE=%s: could not enslave by '%s': %s",
1177 link->ifname, link->network->bond->name, strerror(-r),
1178 NETDEV(link->network->bond),
1179 NULL);
1180 link_enter_failed(link);
1181 return r;
1182 }
1183
52433f6b
TG
1184 link->enslaving ++;
1185 }
1186
672682a6 1187 HASHMAP_FOREACH(vlan, link->network->vlans, i) {
52433f6b
TG
1188 log_struct_link(LOG_DEBUG, link,
1189 "MESSAGE=%s: enslaving by '%s'",
672682a6 1190 link->ifname, vlan->name, NETDEV(vlan), NULL);
52433f6b 1191
672682a6 1192 r = netdev_enslave(vlan, link, &enslave_handler);
52433f6b
TG
1193 if (r < 0) {
1194 log_struct_link(LOG_WARNING, link,
1195 "MESSAGE=%s: could not enslave by '%s': %s",
672682a6
TG
1196 link->ifname, vlan->name, strerror(-r),
1197 NETDEV(vlan), NULL);
52433f6b
TG
1198 link_enter_failed(link);
1199 return r;
1200 }
1201
1202 link->enslaving ++;
ef1ba606
TG
1203 }
1204
fe6b2d55
TG
1205 HASHMAP_FOREACH(macvlan, link->network->macvlans, i) {
1206 log_struct_link(LOG_DEBUG, link,
1207 "MESSAGE=%s: enslaving by '%s'",
1208 link->ifname, macvlan->name, NETDEV(macvlan), NULL);
1209
1210 r = netdev_enslave(macvlan, link, &enslave_handler);
1211 if (r < 0) {
1212 log_struct_link(LOG_WARNING, link,
1213 "MESSAGE=%s: could not enslave by '%s': %s",
1214 link->ifname, macvlan->name, strerror(-r),
1215 NETDEV(macvlan), NULL);
1216 link_enter_failed(link);
1217 return r;
1218 }
1219
1220 link->enslaving ++;
1221 }
1222
ef1ba606
TG
1223 return 0;
1224}
1225
11a7f229
TG
1226static int link_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
1227 void *userdata) {
ef1ba606
TG
1228 Link *link = userdata;
1229 int r;
1230
1746cf2a
TG
1231 assert(link);
1232
1233 if (link->state == LINK_STATE_FAILED)
1234 return 1;
1235
ef1ba606
TG
1236 r = sd_rtnl_message_get_errno(m);
1237 if (r < 0) {
c9ccc19f
TG
1238 log_struct_link(LOG_ERR, link,
1239 "MESSAGE=%s: could not get state: %s",
1240 link->ifname, strerror(-r),
1241 "ERRNO=%d", -r,
1242 NULL);
ef1ba606 1243 link_enter_failed(link);
c9ccc19f 1244 return 1;
ef1ba606
TG
1245 }
1246
5eb036ca
TG
1247 link_update(link, m);
1248
ef1ba606
TG
1249 return 1;
1250}
1251
11a7f229 1252static int link_getlink(Link *link) {
cf6a8911 1253 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
ef1ba606
TG
1254 int r;
1255
1256 assert(link);
1257 assert(link->manager);
1258 assert(link->manager->rtnl);
1259
39032b87 1260 log_debug_link(link, "requesting link status");
449f7554 1261
151b9b96
LP
1262 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
1263 RTM_GETLINK, link->ifindex);
ef1ba606 1264 if (r < 0) {
39032b87 1265 log_error_link(link, "Could not allocate RTM_GETLINK message");
ef1ba606
TG
1266 return r;
1267 }
1268
11a7f229
TG
1269 r = sd_rtnl_call_async(link->manager->rtnl, req, link_getlink_handler,
1270 link, 0, NULL);
ef1ba606 1271 if (r < 0) {
3333d748
ZJS
1272 log_error_link(link,
1273 "Could not send rtnetlink message: %s", strerror(-r));
ef1ba606 1274 return r;
dd3efc09 1275 }
02b59d57
TG
1276
1277 return 0;
1278}
1279
a748b692 1280static int link_configure(Link *link) {
02b59d57
TG
1281 int r;
1282
ef1ba606 1283 assert(link);
ef1ba606
TG
1284 assert(link->state == _LINK_STATE_INVALID);
1285
11a7f229 1286 r = link_getlink(link);
a748b692 1287 if (r < 0)
ef1ba606 1288 return r;
dd3efc09 1289
52433f6b 1290 return link_enter_enslave(link);
f579559b 1291}
dd3efc09 1292
a748b692
TG
1293int link_add(Manager *m, struct udev_device *device, Link **ret) {
1294 Link *link = NULL;
1295 Network *network;
1296 int r;
1297
1298 assert(m);
1299 assert(device);
1300
1301 r = link_new(m, device, &link);
1302 if (r < 0)
1303 return r;
1304
1305 *ret = link;
1306
1307 r = network_get(m, device, &network);
1308 if (r < 0)
1309 return r == -ENOENT ? 0 : r;
1310
1311 r = network_apply(m, network, link);
1312 if (r < 0)
1313 return r;
1314
1315 r = link_configure(link);
1316 if (r < 0)
1317 return r;
1318
1319 return 0;
1320}
1321
22936833
TG
1322int link_update(Link *link, sd_rtnl_message *m) {
1323 unsigned flags;
1324 int r;
1325
dd3efc09 1326 assert(link);
a748b692 1327 assert(link->network);
22936833
TG
1328 assert(m);
1329
1746cf2a
TG
1330 if (link->state == LINK_STATE_FAILED)
1331 return 0;
1332
9842de0d
TG
1333 if (link->network->dhcp && link->network->dhcp_mtu &&
1334 !link->original_mtu) {
1335 r = sd_rtnl_message_read_u16(m, IFLA_MTU, &link->original_mtu);
1336 if (r >= 0)
1337 log_debug_link(link, "saved original MTU: %"
1338 PRIu16, link->original_mtu);
1339 }
69629de9 1340
9842de0d
TG
1341 r = sd_rtnl_message_read_ether_addr(m, IFLA_ADDRESS, &link->mac);
1342 if (r >= 0) {
1343 log_debug_link(link, "MAC address: "
1344 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
1345 link->mac.ether_addr_octet[0],
1346 link->mac.ether_addr_octet[1],
1347 link->mac.ether_addr_octet[2],
1348 link->mac.ether_addr_octet[3],
1349 link->mac.ether_addr_octet[4],
1350 link->mac.ether_addr_octet[5]);
4f882b2a
TG
1351 }
1352
a748b692
TG
1353 r = sd_rtnl_message_link_get_flags(m, &flags);
1354 if (r < 0) {
1355 log_warning_link(link, "Could not get link flags");
1356 return r;
1357 }
1358
ff254138 1359 return link_update_flags(link, flags);
dd3efc09 1360}
fe8db0c5
TG
1361
1362int link_save(Link *link) {
1363 _cleanup_free_ char *temp_path = NULL;
1364 _cleanup_fclose_ FILE *f = NULL;
1365 int r;
1366
1367 assert(link);
1368 assert(link->state_file);
1369
fe8db0c5
TG
1370 r = fopen_temporary(link->state_file, &f, &temp_path);
1371 if (r < 0)
1372 goto finish;
1373
1374 fchmod(fileno(f), 0644);
1375
1376 fprintf(f,
1377 "# This is private data. Do not parse.\n"
1378 "STATE=%s\n",
1379 link_state_to_string(link->state));
1380
1381 if (link->dhcp_lease) {
2a1763ed
TG
1382 char *lease_file;
1383
315db1a8
ZJS
1384 r = asprintf(&lease_file, "/run/systemd/network/leases/%"PRIu64,
1385 link->ifindex);
2a1763ed 1386 if (r < 0)
315db1a8 1387 return -ENOMEM;
fe8db0c5
TG
1388
1389 r = dhcp_lease_save(link->dhcp_lease, lease_file);
1390 if (r < 0)
1391 goto finish;
1392
1393 fprintf(f, "DHCP_LEASE=%s\n", lease_file);
1394 }
1395
1396 fflush(f);
1397
1398 if (ferror(f) || rename(temp_path, link->state_file) < 0) {
1399 r = -errno;
1400 unlink(link->state_file);
1401 unlink(temp_path);
1402 }
1403
1404finish:
1405 if (r < 0)
1406 log_error("Failed to save link data %s: %s", link->state_file, strerror(-r));
1407
1408 return r;
1409}
1410
1411static const char* const link_state_table[_LINK_STATE_MAX] = {
1412 [LINK_STATE_ENSLAVING] = "configuring",
1413 [LINK_STATE_SETTING_ADDRESSES] = "configuring",
1414 [LINK_STATE_SETTING_ROUTES] = "configuring",
1415 [LINK_STATE_CONFIGURED] = "configured",
1416 [LINK_STATE_FAILED] = "failed",
1417};
1418
1419DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);