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