]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-dhcp4.c
Merge pull request #7469 from kinvolk/dongsu/nspawn-netns
[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 *dhcpname = NULL;
466 _cleanup_free_ char *hostname = NULL;
467
468 if (link->network->dhcp_hostname)
469 dhcpname = link->network->dhcp_hostname;
470 else
471 (void) sd_dhcp_lease_get_hostname(lease, &dhcpname);
472
473 if (dhcpname) {
474 r = shorten_overlong(dhcpname, &hostname);
475 if (r < 0)
476 log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname);
477 if (r == 1)
478 log_link_notice(link, "Overlong DCHP hostname received, shortened from '%s' to '%s'", dhcpname, hostname);
479 }
480
481 if (hostname) {
482 r = manager_set_hostname(link->manager, hostname);
483 if (r < 0)
484 log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
485 }
486 }
487
488 if (link->network->dhcp_use_timezone) {
489 const char *tz = NULL;
490
491 (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
492
493 if (tz) {
494 r = manager_set_timezone(link->manager, tz);
495 if (r < 0)
496 log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
497 }
498 }
499
500 if (!link->network->dhcp_critical) {
501 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
502 if (r < 0) {
503 log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
504 return r;
505 }
506 }
507
508 r = dhcp4_update_address(link, &address, &netmask, lifetime);
509 if (r < 0) {
510 log_link_warning_errno(link, r, "Could not update IP address: %m");
511 link_enter_failed(link);
512 return r;
513 }
514
515 return 0;
516 }
517 static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
518 Link *link = userdata;
519 int r = 0;
520
521 assert(link);
522 assert(link->network);
523 assert(link->manager);
524
525 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
526 return;
527
528 switch (event) {
529 case SD_DHCP_CLIENT_EVENT_EXPIRED:
530 case SD_DHCP_CLIENT_EVENT_STOP:
531 case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
532 if (link->network->dhcp_critical) {
533 log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
534 return;
535 }
536
537 if (link->dhcp_lease) {
538 r = dhcp_lease_lost(link);
539 if (r < 0) {
540 link_enter_failed(link);
541 return;
542 }
543 }
544
545 if (event == SD_DHCP_CLIENT_EVENT_IP_CHANGE) {
546 r = dhcp_lease_acquired(client, link);
547 if (r < 0) {
548 link_enter_failed(link);
549 return;
550 }
551 }
552
553 break;
554 case SD_DHCP_CLIENT_EVENT_RENEW:
555 r = dhcp_lease_renew(client, link);
556 if (r < 0) {
557 link_enter_failed(link);
558 return;
559 }
560 break;
561 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
562 r = dhcp_lease_acquired(client, link);
563 if (r < 0) {
564 link_enter_failed(link);
565 return;
566 }
567 break;
568 default:
569 if (event < 0)
570 log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
571 else
572 log_link_warning(link, "DHCP unknown event: %i", event);
573 break;
574 }
575
576 return;
577 }
578
579 static int dhcp4_set_hostname(Link *link) {
580 _cleanup_free_ char *hostname = NULL;
581 const char *hn;
582 int r;
583
584 assert(link);
585
586 if (!link->network->dhcp_send_hostname)
587 hn = NULL;
588 else if (link->network->dhcp_hostname)
589 hn = link->network->dhcp_hostname;
590 else {
591 r = gethostname_strict(&hostname);
592 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
593 return r;
594
595 hn = hostname;
596 }
597
598 return sd_dhcp_client_set_hostname(link->dhcp_client, hn);
599 }
600
601 static bool promote_secondaries_enabled(const char *ifname) {
602 _cleanup_free_ char *promote_secondaries_sysctl = NULL;
603 char *promote_secondaries_path;
604 int r;
605
606 promote_secondaries_path = strjoina("net/ipv4/conf/", ifname, "/promote_secondaries");
607 r = sysctl_read(promote_secondaries_path, &promote_secondaries_sysctl);
608 if (r < 0) {
609 log_debug_errno(r, "Cannot read sysctl %s", promote_secondaries_path);
610 return false;
611 }
612
613 truncate_nl(promote_secondaries_sysctl);
614 r = parse_boolean(promote_secondaries_sysctl);
615 if (r < 0)
616 log_warning_errno(r, "Cannot parse sysctl %s with content %s as boolean", promote_secondaries_path, promote_secondaries_sysctl);
617 return r > 0;
618 }
619
620 /* dhcp4_set_promote_secondaries will ensure this interface has
621 * the "promote_secondaries" option in the kernel set. If this sysctl
622 * is not set DHCP will work only as long as the IP address does not
623 * changes between leases. The kernel will remove all secondary IP
624 * addresses of an interface otherwise. The way systemd-network works
625 * is that the new IP of a lease is added as a secondary IP and when
626 * the primary one expires it relies on the kernel to promote the
627 * secondary IP. See also https://github.com/systemd/systemd/issues/7163
628 */
629 int dhcp4_set_promote_secondaries(Link *link) {
630 int r;
631
632 assert(link);
633 assert(link->network);
634 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
635
636 /* check if the kernel has promote_secondaries enabled for our
637 * interface. If it is not globally enabled or enabled for the
638 * specific interface we must either enable it.
639 */
640 if (!(promote_secondaries_enabled("all") || promote_secondaries_enabled(link->ifname))) {
641 char *promote_secondaries_path = NULL;
642
643 log_link_debug(link, "promote_secondaries is unset, setting it");
644 promote_secondaries_path = strjoina("net/ipv4/conf/", link->ifname, "/promote_secondaries");
645 r = sysctl_write(promote_secondaries_path, "1");
646 if (r < 0)
647 log_link_warning_errno(link, r, "cannot set sysctl %s to 1", promote_secondaries_path);
648 return r > 0;
649 }
650
651 return 0;
652 }
653
654 int dhcp4_configure(Link *link) {
655 int r;
656
657 assert(link);
658 assert(link->network);
659 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
660
661 if (!link->dhcp_client) {
662 r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
663 if (r < 0)
664 return r;
665 }
666
667 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
668 if (r < 0)
669 return r;
670
671 r = sd_dhcp_client_set_mac(link->dhcp_client,
672 (const uint8_t *) &link->mac,
673 sizeof (link->mac), ARPHRD_ETHER);
674 if (r < 0)
675 return r;
676
677 r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
678 if (r < 0)
679 return r;
680
681 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
682 if (r < 0)
683 return r;
684
685 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
686 link->network->dhcp_broadcast);
687 if (r < 0)
688 return r;
689
690 if (link->mtu) {
691 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
692 if (r < 0)
693 return r;
694 }
695
696 if (link->network->dhcp_use_mtu) {
697 r = sd_dhcp_client_set_request_option(link->dhcp_client,
698 SD_DHCP_OPTION_INTERFACE_MTU);
699 if (r < 0)
700 return r;
701 }
702
703 /* NOTE: even if this variable is called "use", it also "sends" PRL
704 * options, maybe there should be a different configuration variable
705 * to send or not route options?. */
706 /* NOTE: when using Anonymize=yes, routes PRL options are sent
707 * by default, so they don't need to be added here. */
708 if (link->network->dhcp_use_routes && !link->network->dhcp_anonymize) {
709 r = sd_dhcp_client_set_request_option(link->dhcp_client,
710 SD_DHCP_OPTION_STATIC_ROUTE);
711 if (r < 0)
712 return r;
713 r = sd_dhcp_client_set_request_option(link->dhcp_client,
714 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
715 if (r < 0)
716 return r;
717 }
718
719 if (link->network->dhcp_use_ntp) {
720 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
721 if (r < 0)
722 return r;
723 }
724
725 if (link->network->dhcp_use_timezone) {
726 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
727 if (r < 0)
728 return r;
729 }
730
731 r = dhcp4_set_hostname(link);
732 if (r < 0)
733 return r;
734
735 if (link->network->dhcp_vendor_class_identifier) {
736 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
737 link->network->dhcp_vendor_class_identifier);
738 if (r < 0)
739 return r;
740 }
741
742 if (link->network->dhcp_client_port) {
743 r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
744 if (r < 0)
745 return r;
746 }
747
748 switch (link->network->dhcp_client_identifier) {
749 case DHCP_CLIENT_ID_DUID: {
750 /* If configured, apply user specified DUID and/or IAID */
751 const DUID *duid = link_duid(link);
752
753 r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
754 link->network->iaid,
755 duid->type,
756 duid->raw_data_len > 0 ? duid->raw_data : NULL,
757 duid->raw_data_len);
758 if (r < 0)
759 return r;
760 break;
761 }
762 case DHCP_CLIENT_ID_MAC:
763 r = sd_dhcp_client_set_client_id(link->dhcp_client,
764 ARPHRD_ETHER,
765 (const uint8_t *) &link->mac,
766 sizeof(link->mac));
767 if (r < 0)
768 return r;
769 break;
770 default:
771 assert_not_reached("Unknown client identifier type.");
772 }
773
774 return 0;
775 }