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