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