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