]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-dhcp4.c
Merge pull request #7934 from keszybz/man-improvements
[thirdparty/systemd.git] / src / network / networkd-dhcp4.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <netinet/ether.h>
22 #include <linux/if.h>
23
24 #include "alloc-util.h"
25 #include "dhcp-lease-internal.h"
26 #include "hostname-util.h"
27 #include "parse-util.h"
28 #include "netdev/vrf.h"
29 #include "network-internal.h"
30 #include "networkd-link.h"
31 #include "networkd-manager.h"
32 #include "networkd-network.h"
33 #include "string-util.h"
34 #include "sysctl-util.h"
35
36 static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
37 void *userdata) {
38 _cleanup_link_unref_ Link *link = userdata;
39 int r;
40
41 assert(link);
42 assert(link->dhcp4_messages > 0);
43
44 link->dhcp4_messages--;
45
46 r = sd_netlink_message_get_errno(m);
47 if (r < 0 && r != -EEXIST) {
48 log_link_error_errno(link, r, "Could not set DHCPv4 route: %m");
49 link_enter_failed(link);
50 }
51
52 if (link->dhcp4_messages == 0) {
53 link->dhcp4_configured = true;
54 link_check_ready(link);
55 }
56
57 return 1;
58 }
59
60 static int route_scope_from_address(const Route *route, const struct in_addr *self_addr) {
61 assert(route);
62 assert(self_addr);
63
64 if (in_addr_is_localhost(AF_INET, &route->dst) ||
65 (self_addr->s_addr && route->dst.in.s_addr == self_addr->s_addr))
66 return RT_SCOPE_HOST;
67 else if (in4_addr_is_null(&route->gw.in))
68 return RT_SCOPE_LINK;
69 else
70 return RT_SCOPE_UNIVERSE;
71 }
72
73 static int link_set_dhcp_routes(Link *link) {
74 _cleanup_free_ sd_dhcp_route **static_routes = NULL;
75 bool classless_route = false, static_route = false;
76 struct in_addr gateway, address;
77 int r, n, i;
78 uint32_t table;
79
80 assert(link);
81
82 if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
83 return 0;
84
85 if (!link->network) /* link went down while we configured the IP addresses? */
86 return 0;
87
88 if (!link->network->dhcp_use_routes)
89 return 0;
90
91 /* When the interface is part of an VRF use the VRFs routing table, unless
92 * there is a another table specified. */
93 table = link->network->dhcp_route_table;
94 if (!link->network->dhcp_route_table_set && link->network->vrf != NULL)
95 table = VRF(link->network->vrf)->table;
96
97 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
98 if (r < 0)
99 return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
100
101 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
102 if (n < 0)
103 log_link_debug_errno(link, n, "DHCP error: could not get routes: %m");
104
105 for (i = 0; i < n; i++) {
106 if (static_routes[i]->option == SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
107 classless_route = true;
108
109 if (static_routes[i]->option == SD_DHCP_OPTION_STATIC_ROUTE)
110 static_route = true;
111 }
112
113 for (i = 0; i < n; i++) {
114 _cleanup_route_free_ Route *route = NULL;
115
116 /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
117 the DHCP client MUST ignore the Static Routes option. */
118 if (classless_route && static_routes[i]->option == SD_DHCP_OPTION_STATIC_ROUTE)
119 continue;
120
121 r = route_new(&route);
122 if (r < 0)
123 return log_link_error_errno(link, r, "Could not allocate route: %m");
124
125 route->family = AF_INET;
126 route->protocol = RTPROT_DHCP;
127 assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
128 assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
129 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
130 route->priority = link->network->dhcp_route_metric;
131 route->table = table;
132 route->scope = route_scope_from_address(route, &address);
133
134 r = route_configure(route, link, dhcp4_route_handler);
135 if (r < 0)
136 return log_link_warning_errno(link, r, "Could not set host route: %m");
137
138 link->dhcp4_messages++;
139 }
140
141 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
142 if (r == -ENODATA)
143 log_link_info_errno(link, r, "DHCP: No routes received from DHCP server: %m");
144 else if (r < 0)
145 log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
146
147 /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
148 a Router option, the DHCP client MUST ignore the Router option. */
149 if (classless_route && static_route)
150 log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option");
151
152 if (r >= 0 && !classless_route) {
153 _cleanup_route_free_ Route *route = NULL;
154 _cleanup_route_free_ Route *route_gw = NULL;
155
156 r = route_new(&route);
157 if (r < 0)
158 return log_link_error_errno(link, r, "Could not allocate route: %m");
159
160 route->protocol = RTPROT_DHCP;
161
162 r = route_new(&route_gw);
163 if (r < 0)
164 return log_link_error_errno(link, r, "Could not allocate route: %m");
165
166 /* The dhcp netmask may mask out the gateway. Add an explicit
167 * route for the gw host so that we can route no matter the
168 * netmask or existing kernel route tables. */
169 route_gw->family = AF_INET;
170 route_gw->dst.in = gateway;
171 route_gw->dst_prefixlen = 32;
172 route_gw->prefsrc.in = address;
173 route_gw->scope = RT_SCOPE_LINK;
174 route_gw->protocol = RTPROT_DHCP;
175 route_gw->priority = link->network->dhcp_route_metric;
176 route_gw->table = table;
177
178 r = route_configure(route_gw, link, dhcp4_route_handler);
179 if (r < 0)
180 return log_link_warning_errno(link, r, "Could not set host route: %m");
181
182 link->dhcp4_messages++;
183
184 route->family = AF_INET;
185 route->gw.in = gateway;
186 route->prefsrc.in = address;
187 route->priority = link->network->dhcp_route_metric;
188 route->table = table;
189
190 r = route_configure(route, link, dhcp4_route_handler);
191 if (r < 0) {
192 log_link_warning_errno(link, r, "Could not set routes: %m");
193 link_enter_failed(link);
194 return r;
195 }
196
197 link->dhcp4_messages++;
198 }
199
200 return 0;
201 }
202
203 static int dhcp_lease_lost(Link *link) {
204 _cleanup_address_free_ Address *address = NULL;
205 struct in_addr addr;
206 struct in_addr netmask;
207 struct in_addr gateway;
208 unsigned prefixlen = 0;
209 int r;
210
211 assert(link);
212 assert(link->dhcp_lease);
213
214 log_link_warning(link, "DHCP lease lost");
215
216 if (link->network->dhcp_use_routes) {
217 _cleanup_free_ sd_dhcp_route **routes = NULL;
218 int n, i;
219
220 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
221 if (n >= 0) {
222 for (i = 0; i < n; i++) {
223 _cleanup_route_free_ Route *route = NULL;
224
225 r = route_new(&route);
226 if (r >= 0) {
227 route->family = AF_INET;
228 assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
229 assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
230 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
231
232 route_remove(route, link,
233 link_route_remove_handler);
234 }
235 }
236 }
237 }
238
239 r = address_new(&address);
240 if (r >= 0) {
241 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
242 if (r >= 0) {
243 _cleanup_route_free_ Route *route_gw = NULL;
244 _cleanup_route_free_ Route *route = NULL;
245
246 r = route_new(&route_gw);
247 if (r >= 0) {
248 route_gw->family = AF_INET;
249 route_gw->dst.in = gateway;
250 route_gw->dst_prefixlen = 32;
251 route_gw->scope = RT_SCOPE_LINK;
252
253 route_remove(route_gw, link,
254 link_route_remove_handler);
255 }
256
257 r = route_new(&route);
258 if (r >= 0) {
259 route->family = AF_INET;
260 route->gw.in = gateway;
261
262 route_remove(route, link,
263 link_route_remove_handler);
264 }
265 }
266
267 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
268 if (r >= 0) {
269 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
270 if (r >= 0)
271 prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
272
273 address->family = AF_INET;
274 address->in_addr.in = addr;
275 address->prefixlen = prefixlen;
276
277 address_remove(address, link, link_address_remove_handler);
278 }
279 }
280
281 if (link->network->dhcp_use_mtu) {
282 uint16_t mtu;
283
284 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
285 if (r >= 0 && link->original_mtu != mtu) {
286 r = link_set_mtu(link, link->original_mtu);
287 if (r < 0) {
288 log_link_warning(link,
289 "DHCP error: could not reset MTU");
290 link_enter_failed(link);
291 return r;
292 }
293 }
294 }
295
296 if (link->network->dhcp_use_hostname) {
297 const char *hostname = NULL;
298
299 if (link->network->dhcp_hostname)
300 hostname = link->network->dhcp_hostname;
301 else
302 (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
303
304 if (hostname) {
305 /* If a hostname was set due to the lease, then unset it now. */
306 r = manager_set_hostname(link->manager, NULL);
307 if (r < 0)
308 log_link_warning_errno(link, r, "Failed to reset transient hostname: %m");
309 }
310 }
311
312 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
313 link_dirty(link);
314 link->dhcp4_configured = false;
315
316 return 0;
317 }
318
319 static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
320 void *userdata) {
321 _cleanup_link_unref_ Link *link = userdata;
322 int r;
323
324 assert(link);
325
326 r = sd_netlink_message_get_errno(m);
327 if (r < 0 && r != -EEXIST) {
328 log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
329 link_enter_failed(link);
330 } else if (r >= 0)
331 manager_rtnl_process_address(rtnl, m, link->manager);
332
333 link_set_dhcp_routes(link);
334
335 return 1;
336 }
337
338 static int dhcp4_update_address(Link *link,
339 struct in_addr *address,
340 struct in_addr *netmask,
341 uint32_t lifetime) {
342 _cleanup_address_free_ Address *addr = NULL;
343 unsigned prefixlen;
344 int r;
345
346 assert(address);
347 assert(netmask);
348 assert(lifetime);
349
350 prefixlen = in4_addr_netmask_to_prefixlen(netmask);
351
352 r = address_new(&addr);
353 if (r < 0)
354 return r;
355
356 addr->family = AF_INET;
357 addr->in_addr.in.s_addr = address->s_addr;
358 addr->cinfo.ifa_prefered = lifetime;
359 addr->cinfo.ifa_valid = lifetime;
360 addr->prefixlen = prefixlen;
361 addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
362
363 /* allow reusing an existing address and simply update its lifetime
364 * in case it already exists */
365 r = address_configure(addr, link, dhcp4_address_handler, true);
366 if (r < 0)
367 return r;
368
369 return 0;
370 }
371
372 static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
373 sd_dhcp_lease *lease;
374 struct in_addr address;
375 struct in_addr netmask;
376 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
377 int r;
378
379 assert(link);
380 assert(client);
381 assert(link->network);
382
383 r = sd_dhcp_client_get_lease(client, &lease);
384 if (r < 0)
385 return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
386
387 sd_dhcp_lease_unref(link->dhcp_lease);
388 link->dhcp4_configured = false;
389 link->dhcp_lease = sd_dhcp_lease_ref(lease);
390 link_dirty(link);
391
392 r = sd_dhcp_lease_get_address(lease, &address);
393 if (r < 0)
394 return log_link_warning_errno(link, r, "DHCP error: no address: %m");
395
396 r = sd_dhcp_lease_get_netmask(lease, &netmask);
397 if (r < 0)
398 return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
399
400 if (!link->network->dhcp_critical) {
401 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
402 if (r < 0)
403 return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
404 }
405
406 r = dhcp4_update_address(link, &address, &netmask, lifetime);
407 if (r < 0) {
408 log_link_warning_errno(link, r, "Could not update IP address: %m");
409 link_enter_failed(link);
410 return r;
411 }
412
413 return 0;
414 }
415
416 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
417 sd_dhcp_lease *lease;
418 struct in_addr address;
419 struct in_addr netmask;
420 struct in_addr gateway;
421 unsigned prefixlen;
422 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
423 int r;
424
425 assert(client);
426 assert(link);
427
428 r = sd_dhcp_client_get_lease(client, &lease);
429 if (r < 0)
430 return log_link_error_errno(link, r, "DHCP error: No lease: %m");
431
432 r = sd_dhcp_lease_get_address(lease, &address);
433 if (r < 0)
434 return log_link_error_errno(link, r, "DHCP error: No address: %m");
435
436 r = sd_dhcp_lease_get_netmask(lease, &netmask);
437 if (r < 0)
438 return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
439
440 prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
441
442 r = sd_dhcp_lease_get_router(lease, &gateway);
443 if (r < 0 && r != -ENODATA)
444 return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
445
446 if (r >= 0)
447 log_struct(LOG_INFO,
448 LOG_LINK_INTERFACE(link),
449 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
450 ADDRESS_FMT_VAL(address),
451 prefixlen,
452 ADDRESS_FMT_VAL(gateway)),
453 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
454 "PREFIXLEN=%u", prefixlen,
455 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway),
456 NULL);
457 else
458 log_struct(LOG_INFO,
459 LOG_LINK_INTERFACE(link),
460 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
461 ADDRESS_FMT_VAL(address),
462 prefixlen),
463 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
464 "PREFIXLEN=%u", prefixlen,
465 NULL);
466
467 link->dhcp_lease = sd_dhcp_lease_ref(lease);
468 link_dirty(link);
469
470 if (link->network->dhcp_use_mtu) {
471 uint16_t mtu;
472
473 r = sd_dhcp_lease_get_mtu(lease, &mtu);
474 if (r >= 0) {
475 r = link_set_mtu(link, mtu);
476 if (r < 0)
477 log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
478 }
479 }
480
481 if (link->network->dhcp_use_hostname) {
482 const char *dhcpname = NULL;
483 _cleanup_free_ char *hostname = NULL;
484
485 if (link->network->dhcp_hostname)
486 dhcpname = link->network->dhcp_hostname;
487 else
488 (void) sd_dhcp_lease_get_hostname(lease, &dhcpname);
489
490 if (dhcpname) {
491 r = shorten_overlong(dhcpname, &hostname);
492 if (r < 0)
493 log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname);
494 if (r == 1)
495 log_link_notice(link, "Overlong DCHP hostname received, shortened from '%s' to '%s'", dhcpname, hostname);
496 }
497
498 if (hostname) {
499 r = manager_set_hostname(link->manager, hostname);
500 if (r < 0)
501 log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
502 }
503 }
504
505 if (link->network->dhcp_use_timezone) {
506 const char *tz = NULL;
507
508 (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
509
510 if (tz) {
511 r = manager_set_timezone(link->manager, tz);
512 if (r < 0)
513 log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
514 }
515 }
516
517 if (!link->network->dhcp_critical) {
518 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
519 if (r < 0) {
520 log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
521 return r;
522 }
523 }
524
525 r = dhcp4_update_address(link, &address, &netmask, lifetime);
526 if (r < 0) {
527 log_link_warning_errno(link, r, "Could not update IP address: %m");
528 link_enter_failed(link);
529 return r;
530 }
531
532 return 0;
533 }
534 static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
535 Link *link = userdata;
536 int r = 0;
537
538 assert(link);
539 assert(link->network);
540 assert(link->manager);
541
542 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
543 return;
544
545 switch (event) {
546 case SD_DHCP_CLIENT_EVENT_EXPIRED:
547 case SD_DHCP_CLIENT_EVENT_STOP:
548 case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
549 if (link->network->dhcp_critical) {
550 log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
551 return;
552 }
553
554 if (link->dhcp_lease) {
555 r = dhcp_lease_lost(link);
556 if (r < 0) {
557 link_enter_failed(link);
558 return;
559 }
560 }
561
562 if (event == SD_DHCP_CLIENT_EVENT_IP_CHANGE) {
563 r = dhcp_lease_acquired(client, link);
564 if (r < 0) {
565 link_enter_failed(link);
566 return;
567 }
568 }
569
570 break;
571 case SD_DHCP_CLIENT_EVENT_RENEW:
572 r = dhcp_lease_renew(client, link);
573 if (r < 0) {
574 link_enter_failed(link);
575 return;
576 }
577 break;
578 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
579 r = dhcp_lease_acquired(client, link);
580 if (r < 0) {
581 link_enter_failed(link);
582 return;
583 }
584 break;
585 default:
586 if (event < 0)
587 log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
588 else
589 log_link_warning(link, "DHCP unknown event: %i", event);
590 break;
591 }
592
593 return;
594 }
595
596 static int dhcp4_set_hostname(Link *link) {
597 _cleanup_free_ char *hostname = NULL;
598 const char *hn;
599 int r;
600
601 assert(link);
602
603 if (!link->network->dhcp_send_hostname)
604 hn = NULL;
605 else if (link->network->dhcp_hostname)
606 hn = link->network->dhcp_hostname;
607 else {
608 r = gethostname_strict(&hostname);
609 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
610 return r;
611
612 hn = hostname;
613 }
614
615 return sd_dhcp_client_set_hostname(link->dhcp_client, hn);
616 }
617
618 static bool promote_secondaries_enabled(const char *ifname) {
619 _cleanup_free_ char *promote_secondaries_sysctl = NULL;
620 char *promote_secondaries_path;
621 int r;
622
623 promote_secondaries_path = strjoina("net/ipv4/conf/", ifname, "/promote_secondaries");
624 r = sysctl_read(promote_secondaries_path, &promote_secondaries_sysctl);
625 if (r < 0) {
626 log_debug_errno(r, "Cannot read sysctl %s", promote_secondaries_path);
627 return false;
628 }
629
630 truncate_nl(promote_secondaries_sysctl);
631 r = parse_boolean(promote_secondaries_sysctl);
632 if (r < 0)
633 log_warning_errno(r, "Cannot parse sysctl %s with content %s as boolean", promote_secondaries_path, promote_secondaries_sysctl);
634 return r > 0;
635 }
636
637 /* dhcp4_set_promote_secondaries will ensure this interface has
638 * the "promote_secondaries" option in the kernel set. If this sysctl
639 * is not set DHCP will work only as long as the IP address does not
640 * changes between leases. The kernel will remove all secondary IP
641 * addresses of an interface otherwise. The way systemd-network works
642 * is that the new IP of a lease is added as a secondary IP and when
643 * the primary one expires it relies on the kernel to promote the
644 * secondary IP. See also https://github.com/systemd/systemd/issues/7163
645 */
646 int dhcp4_set_promote_secondaries(Link *link) {
647 int r;
648
649 assert(link);
650 assert(link->network);
651 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
652
653 /* check if the kernel has promote_secondaries enabled for our
654 * interface. If it is not globally enabled or enabled for the
655 * specific interface we must either enable it.
656 */
657 if (!(promote_secondaries_enabled("all") || promote_secondaries_enabled(link->ifname))) {
658 char *promote_secondaries_path = NULL;
659
660 log_link_debug(link, "promote_secondaries is unset, setting it");
661 promote_secondaries_path = strjoina("net/ipv4/conf/", link->ifname, "/promote_secondaries");
662 r = sysctl_write(promote_secondaries_path, "1");
663 if (r < 0)
664 log_link_warning_errno(link, r, "cannot set sysctl %s to 1", promote_secondaries_path);
665 return r > 0;
666 }
667
668 return 0;
669 }
670
671 int dhcp4_configure(Link *link) {
672 int r;
673
674 assert(link);
675 assert(link->network);
676 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
677
678 if (!link->dhcp_client) {
679 r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
680 if (r < 0)
681 return r;
682 }
683
684 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
685 if (r < 0)
686 return r;
687
688 r = sd_dhcp_client_set_mac(link->dhcp_client,
689 (const uint8_t *) &link->mac,
690 sizeof (link->mac), ARPHRD_ETHER);
691 if (r < 0)
692 return r;
693
694 r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
695 if (r < 0)
696 return r;
697
698 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
699 if (r < 0)
700 return r;
701
702 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
703 link->network->dhcp_broadcast);
704 if (r < 0)
705 return r;
706
707 if (link->mtu) {
708 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
709 if (r < 0)
710 return r;
711 }
712
713 if (link->network->dhcp_use_mtu) {
714 r = sd_dhcp_client_set_request_option(link->dhcp_client,
715 SD_DHCP_OPTION_INTERFACE_MTU);
716 if (r < 0)
717 return r;
718 }
719
720 /* NOTE: even if this variable is called "use", it also "sends" PRL
721 * options, maybe there should be a different configuration variable
722 * to send or not route options?. */
723 /* NOTE: when using Anonymize=yes, routes PRL options are sent
724 * by default, so they don't need to be added here. */
725 if (link->network->dhcp_use_routes && !link->network->dhcp_anonymize) {
726 r = sd_dhcp_client_set_request_option(link->dhcp_client,
727 SD_DHCP_OPTION_STATIC_ROUTE);
728 if (r < 0)
729 return r;
730 r = sd_dhcp_client_set_request_option(link->dhcp_client,
731 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
732 if (r < 0)
733 return r;
734 }
735
736 if (link->network->dhcp_use_ntp) {
737 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
738 if (r < 0)
739 return r;
740 }
741
742 if (link->network->dhcp_use_timezone) {
743 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
744 if (r < 0)
745 return r;
746 }
747
748 r = dhcp4_set_hostname(link);
749 if (r < 0)
750 return r;
751
752 if (link->network->dhcp_vendor_class_identifier) {
753 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
754 link->network->dhcp_vendor_class_identifier);
755 if (r < 0)
756 return r;
757 }
758
759 if (link->network->dhcp_client_port) {
760 r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
761 if (r < 0)
762 return r;
763 }
764
765 switch (link->network->dhcp_client_identifier) {
766 case DHCP_CLIENT_ID_DUID: {
767 /* If configured, apply user specified DUID and/or IAID */
768 const DUID *duid = link_duid(link);
769
770 r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
771 link->network->iaid,
772 duid->type,
773 duid->raw_data_len > 0 ? duid->raw_data : NULL,
774 duid->raw_data_len);
775 if (r < 0)
776 return r;
777 break;
778 }
779 case DHCP_CLIENT_ID_MAC:
780 r = sd_dhcp_client_set_client_id(link->dhcp_client,
781 ARPHRD_ETHER,
782 (const uint8_t *) &link->mac,
783 sizeof(link->mac));
784 if (r < 0)
785 return r;
786 break;
787 default:
788 assert_not_reached("Unknown client identifier type.");
789 }
790
791 return 0;
792 }