]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-dhcp4.c
Merge pull request #5624 from glaubitz/x32
[thirdparty/systemd.git] / src / network / networkd-dhcp4.c
CommitLineData
3c9b8860
TG
1/***
2 This file is part of systemd.
3
4 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <netinet/ether.h>
21#include <linux/if.h>
22
b5efdb8a
LP
23#include "alloc-util.h"
24#include "dhcp-lease-internal.h"
958b66ea 25#include "hostname-util.h"
3c9b8860 26#include "network-internal.h"
23f53b99
TG
27#include "networkd-link.h"
28#include "networkd-manager.h"
29#include "networkd-network.h"
3c9b8860 30
1c4baffc 31static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
3c9b8860
TG
32 void *userdata) {
33 _cleanup_link_unref_ Link *link = userdata;
34 int r;
35
36 assert(link);
6cf4a01c 37 assert(link->dhcp4_messages > 0);
3c9b8860 38
313cefa1 39 link->dhcp4_messages--;
3c9b8860 40
1c4baffc 41 r = sd_netlink_message_get_errno(m);
3c9b8860 42 if (r < 0 && r != -EEXIST) {
f6b8196f 43 log_link_error_errno(link, r, "Could not set DHCPv4 route: %m");
3c9b8860
TG
44 link_enter_failed(link);
45 }
46
6cf4a01c 47 if (link->dhcp4_messages == 0) {
3c9b8860 48 link->dhcp4_configured = true;
8012cd39 49 link_check_ready(link);
3c9b8860
TG
50 }
51
52 return 1;
53}
54
55static int link_set_dhcp_routes(Link *link) {
56 struct in_addr gateway;
f8693fc7 57 _cleanup_free_ sd_dhcp_route **static_routes = NULL;
3c9b8860
TG
58 int r, n, i;
59
60 assert(link);
61 assert(link->dhcp_lease);
964b26fe
SS
62 assert(link->network);
63
64 if (!link->network->dhcp_use_routes)
65 return 0;
3c9b8860
TG
66
67 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
397d15fd 68 if (r < 0 && r != -ENODATA)
f6b8196f
LP
69 return log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
70
3c9b8860 71 if (r >= 0) {
46b0c76e 72 struct in_addr address;
3c9b8860
TG
73 _cleanup_route_free_ Route *route = NULL;
74 _cleanup_route_free_ Route *route_gw = NULL;
75
46b0c76e 76 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
f6b8196f
LP
77 if (r < 0)
78 return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
46b0c76e 79
ed9e361a 80 r = route_new(&route);
f6b8196f
LP
81 if (r < 0)
82 return log_link_error_errno(link, r, "Could not allocate route: %m");
3c9b8860 83
ed9e361a
TG
84 route->protocol = RTPROT_DHCP;
85
86 r = route_new(&route_gw);
f6b8196f
LP
87 if (r < 0)
88 return log_link_error_errno(link, r, "Could not allocate route: %m");
3c9b8860
TG
89
90 /* The dhcp netmask may mask out the gateway. Add an explicit
91 * route for the gw host so that we can route no matter the
92 * netmask or existing kernel route tables. */
93 route_gw->family = AF_INET;
2ce40956 94 route_gw->dst.in = gateway;
3c9b8860 95 route_gw->dst_prefixlen = 32;
2ce40956 96 route_gw->prefsrc.in = address;
3c9b8860 97 route_gw->scope = RT_SCOPE_LINK;
ed9e361a 98 route_gw->protocol = RTPROT_DHCP;
86655331 99 route_gw->priority = link->network->dhcp_route_metric;
f594276b 100 route_gw->table = link->network->dhcp_route_table;
3c9b8860 101
483d099e 102 r = route_configure(route_gw, link, dhcp4_route_handler);
f6b8196f
LP
103 if (r < 0)
104 return log_link_warning_errno(link, r, "Could not set host route: %m");
3c9b8860 105
313cefa1 106 link->dhcp4_messages++;
3c9b8860
TG
107
108 route->family = AF_INET;
2ce40956
TG
109 route->gw.in = gateway;
110 route->prefsrc.in = address;
86655331 111 route->priority = link->network->dhcp_route_metric;
f594276b 112 route->table = link->network->dhcp_route_table;
3c9b8860 113
483d099e 114 r = route_configure(route, link, dhcp4_route_handler);
3c9b8860 115 if (r < 0) {
f6b8196f 116 log_link_warning_errno(link, r, "Could not set routes: %m");
3c9b8860
TG
117 link_enter_failed(link);
118 return r;
119 }
120
313cefa1 121 link->dhcp4_messages++;
3c9b8860
TG
122 }
123
124 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
397d15fd 125 if (n == -ENODATA)
3c9b8860 126 return 0;
f6b8196f
LP
127 if (n < 0)
128 return log_link_warning_errno(link, n, "DHCP error: could not get routes: %m");
3c9b8860
TG
129
130 for (i = 0; i < n; i++) {
131 _cleanup_route_free_ Route *route = NULL;
132
ed9e361a 133 r = route_new(&route);
f6b8196f
LP
134 if (r < 0)
135 return log_link_error_errno(link, r, "Could not allocate route: %m");
3c9b8860
TG
136
137 route->family = AF_INET;
ed9e361a 138 route->protocol = RTPROT_DHCP;
f8693fc7
BG
139 assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
140 assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
141 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
86655331 142 route->priority = link->network->dhcp_route_metric;
f594276b 143 route->table = link->network->dhcp_route_table;
3c9b8860 144
483d099e 145 r = route_configure(route, link, dhcp4_route_handler);
f6b8196f
LP
146 if (r < 0)
147 return log_link_warning_errno(link, r, "Could not set host route: %m");
3c9b8860 148
313cefa1 149 link->dhcp4_messages++;
3c9b8860
TG
150 }
151
152 return 0;
153}
154
155static int dhcp_lease_lost(Link *link) {
156 _cleanup_address_free_ Address *address = NULL;
157 struct in_addr addr;
158 struct in_addr netmask;
159 struct in_addr gateway;
f414a269 160 unsigned prefixlen = 0;
3c9b8860
TG
161 int r;
162
163 assert(link);
164 assert(link->dhcp_lease);
165
79008bdd 166 log_link_warning(link, "DHCP lease lost");
3c9b8860 167
27cb34f5 168 if (link->network->dhcp_use_routes) {
f8693fc7 169 _cleanup_free_ sd_dhcp_route **routes = NULL;
3c9b8860
TG
170 int n, i;
171
172 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
173 if (n >= 0) {
174 for (i = 0; i < n; i++) {
175 _cleanup_route_free_ Route *route = NULL;
176
ed9e361a 177 r = route_new(&route);
3c9b8860
TG
178 if (r >= 0) {
179 route->family = AF_INET;
f8693fc7
BG
180 assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
181 assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
182 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
3c9b8860 183
91b5f997 184 route_remove(route, link,
483d099e 185 link_route_remove_handler);
3c9b8860
TG
186 }
187 }
188 }
189 }
190
f0213e37 191 r = address_new(&address);
3c9b8860
TG
192 if (r >= 0) {
193 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
194 if (r >= 0) {
195 _cleanup_route_free_ Route *route_gw = NULL;
196 _cleanup_route_free_ Route *route = NULL;
197
ed9e361a 198 r = route_new(&route_gw);
3c9b8860
TG
199 if (r >= 0) {
200 route_gw->family = AF_INET;
2ce40956 201 route_gw->dst.in = gateway;
3c9b8860
TG
202 route_gw->dst_prefixlen = 32;
203 route_gw->scope = RT_SCOPE_LINK;
204
91b5f997 205 route_remove(route_gw, link,
483d099e 206 link_route_remove_handler);
3c9b8860
TG
207 }
208
ed9e361a 209 r = route_new(&route);
3c9b8860
TG
210 if (r >= 0) {
211 route->family = AF_INET;
2ce40956 212 route->gw.in = gateway;
3c9b8860 213
91b5f997 214 route_remove(route, link,
483d099e 215 link_route_remove_handler);
3c9b8860
TG
216 }
217 }
218
f414a269
TG
219 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
220 if (r >= 0) {
221 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
222 if (r >= 0)
223 prefixlen = in_addr_netmask_to_prefixlen(&netmask);
3c9b8860 224
f414a269
TG
225 address->family = AF_INET;
226 address->in_addr.in = addr;
227 address->prefixlen = prefixlen;
3c9b8860 228
483d099e 229 address_remove(address, link, link_address_remove_handler);
f414a269 230 }
3c9b8860
TG
231 }
232
27cb34f5 233 if (link->network->dhcp_use_mtu) {
3c9b8860
TG
234 uint16_t mtu;
235
236 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
237 if (r >= 0 && link->original_mtu != mtu) {
238 r = link_set_mtu(link, link->original_mtu);
239 if (r < 0) {
79008bdd 240 log_link_warning(link,
3c9b8860
TG
241 "DHCP error: could not reset MTU");
242 link_enter_failed(link);
243 return r;
244 }
245 }
246 }
247
27cb34f5 248 if (link->network->dhcp_use_hostname) {
3c9b8860
TG
249 const char *hostname = NULL;
250
27cb34f5
LP
251 if (link->network->dhcp_hostname)
252 hostname = link->network->dhcp_hostname;
dce391e7
LP
253 else
254 (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
a7d0ef44 255
dce391e7
LP
256 if (hostname) {
257 /* If a hostname was set due to the lease, then unset it now. */
59eb33e0 258 r = manager_set_hostname(link->manager, NULL);
3c9b8860 259 if (r < 0)
dce391e7 260 log_link_warning_errno(link, r, "Failed to reset transient hostname: %m");
3c9b8860
TG
261 }
262 }
263
264 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
6a3e5f6a 265 link_dirty(link);
3c9b8860
TG
266 link->dhcp4_configured = false;
267
268 return 0;
269}
270
1c4baffc 271static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
3c9b8860
TG
272 void *userdata) {
273 _cleanup_link_unref_ Link *link = userdata;
274 int r;
275
276 assert(link);
277
1c4baffc 278 r = sd_netlink_message_get_errno(m);
3c9b8860 279 if (r < 0 && r != -EEXIST) {
f6b8196f 280 log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
3c9b8860 281 link_enter_failed(link);
45af44d4 282 } else if (r >= 0)
200a0868 283 manager_rtnl_process_address(rtnl, m, link->manager);
3c9b8860
TG
284
285 link_set_dhcp_routes(link);
286
287 return 1;
288}
289
290static int dhcp4_update_address(Link *link,
291 struct in_addr *address,
292 struct in_addr *netmask,
293 uint32_t lifetime) {
294 _cleanup_address_free_ Address *addr = NULL;
295 unsigned prefixlen;
296 int r;
297
298 assert(address);
299 assert(netmask);
300 assert(lifetime);
301
302 prefixlen = in_addr_netmask_to_prefixlen(netmask);
303
f0213e37 304 r = address_new(&addr);
3c9b8860
TG
305 if (r < 0)
306 return r;
307
308 addr->family = AF_INET;
309 addr->in_addr.in.s_addr = address->s_addr;
310 addr->cinfo.ifa_prefered = lifetime;
311 addr->cinfo.ifa_valid = lifetime;
312 addr->prefixlen = prefixlen;
313 addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
314
66669078
TG
315 /* allow reusing an existing address and simply update its lifetime
316 * in case it already exists */
483d099e 317 r = address_configure(addr, link, dhcp4_address_handler, true);
3c9b8860
TG
318 if (r < 0)
319 return r;
320
321 return 0;
322}
323
324static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
325 sd_dhcp_lease *lease;
326 struct in_addr address;
327 struct in_addr netmask;
328 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
329 int r;
330
331 assert(link);
332 assert(client);
333 assert(link->network);
334
335 r = sd_dhcp_client_get_lease(client, &lease);
f6b8196f
LP
336 if (r < 0)
337 return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
3c9b8860
TG
338
339 sd_dhcp_lease_unref(link->dhcp_lease);
340 link->dhcp4_configured = false;
e6b18ffa 341 link->dhcp_lease = sd_dhcp_lease_ref(lease);
6a3e5f6a 342 link_dirty(link);
3c9b8860
TG
343
344 r = sd_dhcp_lease_get_address(lease, &address);
f6b8196f
LP
345 if (r < 0)
346 return log_link_warning_errno(link, r, "DHCP error: no address: %m");
3c9b8860
TG
347
348 r = sd_dhcp_lease_get_netmask(lease, &netmask);
f6b8196f
LP
349 if (r < 0)
350 return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
3c9b8860
TG
351
352 if (!link->network->dhcp_critical) {
f6b8196f
LP
353 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
354 if (r < 0)
355 return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
3c9b8860
TG
356 }
357
358 r = dhcp4_update_address(link, &address, &netmask, lifetime);
359 if (r < 0) {
f6b8196f 360 log_link_warning_errno(link, r, "Could not update IP address: %m");
3c9b8860
TG
361 link_enter_failed(link);
362 return r;
363 }
364
365 return 0;
366}
367
368static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
369 sd_dhcp_lease *lease;
370 struct in_addr address;
371 struct in_addr netmask;
372 struct in_addr gateway;
373 unsigned prefixlen;
374 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
375 int r;
376
377 assert(client);
378 assert(link);
379
380 r = sd_dhcp_client_get_lease(client, &lease);
f2341e0a 381 if (r < 0)
f6b8196f 382 return log_link_error_errno(link, r, "DHCP error: No lease: %m");
3c9b8860
TG
383
384 r = sd_dhcp_lease_get_address(lease, &address);
f2341e0a 385 if (r < 0)
f6b8196f 386 return log_link_error_errno(link, r, "DHCP error: No address: %m");
3c9b8860
TG
387
388 r = sd_dhcp_lease_get_netmask(lease, &netmask);
f2341e0a 389 if (r < 0)
f6b8196f 390 return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
3c9b8860
TG
391
392 prefixlen = in_addr_netmask_to_prefixlen(&netmask);
393
394 r = sd_dhcp_lease_get_router(lease, &gateway);
397d15fd 395 if (r < 0 && r != -ENODATA)
f6b8196f 396 return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
3c9b8860
TG
397
398 if (r >= 0)
f2341e0a
LP
399 log_struct(LOG_INFO,
400 LOG_LINK_INTERFACE(link),
401 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
402 ADDRESS_FMT_VAL(address),
403 prefixlen,
404 ADDRESS_FMT_VAL(gateway)),
405 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
406 "PREFIXLEN=%u", prefixlen,
407 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway),
408 NULL);
3c9b8860 409 else
f2341e0a
LP
410 log_struct(LOG_INFO,
411 LOG_LINK_INTERFACE(link),
412 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
413 ADDRESS_FMT_VAL(address),
414 prefixlen),
415 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
416 "PREFIXLEN=%u", prefixlen,
417 NULL);
3c9b8860 418
e6b18ffa 419 link->dhcp_lease = sd_dhcp_lease_ref(lease);
6a3e5f6a 420 link_dirty(link);
3c9b8860 421
27cb34f5 422 if (link->network->dhcp_use_mtu) {
3c9b8860
TG
423 uint16_t mtu;
424
425 r = sd_dhcp_lease_get_mtu(lease, &mtu);
426 if (r >= 0) {
427 r = link_set_mtu(link, mtu);
428 if (r < 0)
f2341e0a 429 log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
3c9b8860
TG
430 }
431 }
432
27cb34f5 433 if (link->network->dhcp_use_hostname) {
49f6e11e 434 const char *hostname = NULL;
3c9b8860 435
27cb34f5
LP
436 if (link->network->dhcp_hostname)
437 hostname = link->network->dhcp_hostname;
dce391e7
LP
438 else
439 (void) sd_dhcp_lease_get_hostname(lease, &hostname);
a7d0ef44 440
dce391e7 441 if (hostname) {
59eb33e0 442 r = manager_set_hostname(link->manager, hostname);
3c9b8860 443 if (r < 0)
f2341e0a 444 log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
3c9b8860
TG
445 }
446 }
447
27cb34f5 448 if (link->network->dhcp_use_timezone) {
21b80ad1
LP
449 const char *tz = NULL;
450
451 (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
452
453 if (tz) {
59eb33e0 454 r = manager_set_timezone(link->manager, tz);
21b80ad1
LP
455 if (r < 0)
456 log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
457 }
458 }
459
3c9b8860 460 if (!link->network->dhcp_critical) {
f2341e0a 461 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
3c9b8860 462 if (r < 0) {
f2341e0a 463 log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
3c9b8860
TG
464 return r;
465 }
466 }
467
468 r = dhcp4_update_address(link, &address, &netmask, lifetime);
469 if (r < 0) {
f2341e0a 470 log_link_warning_errno(link, r, "Could not update IP address: %m");
3c9b8860
TG
471 link_enter_failed(link);
472 return r;
473 }
474
475 return 0;
476}
477static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
478 Link *link = userdata;
479 int r = 0;
480
481 assert(link);
482 assert(link->network);
483 assert(link->manager);
484
485 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
486 return;
487
488 switch (event) {
03748142
DH
489 case SD_DHCP_CLIENT_EVENT_EXPIRED:
490 case SD_DHCP_CLIENT_EVENT_STOP:
491 case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
3c9b8860 492 if (link->network->dhcp_critical) {
f6b8196f 493 log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
3c9b8860
TG
494 return;
495 }
496
497 if (link->dhcp_lease) {
498 r = dhcp_lease_lost(link);
499 if (r < 0) {
500 link_enter_failed(link);
501 return;
502 }
503 }
504
03748142 505 if (event == SD_DHCP_CLIENT_EVENT_IP_CHANGE) {
3c9b8860
TG
506 r = dhcp_lease_acquired(client, link);
507 if (r < 0) {
508 link_enter_failed(link);
509 return;
510 }
511 }
512
513 break;
03748142 514 case SD_DHCP_CLIENT_EVENT_RENEW:
3c9b8860
TG
515 r = dhcp_lease_renew(client, link);
516 if (r < 0) {
517 link_enter_failed(link);
518 return;
519 }
520 break;
03748142 521 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
3c9b8860
TG
522 r = dhcp_lease_acquired(client, link);
523 if (r < 0) {
524 link_enter_failed(link);
525 return;
526 }
527 break;
528 default:
529 if (event < 0)
f6b8196f 530 log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
3c9b8860 531 else
f6b8196f 532 log_link_warning(link, "DHCP unknown event: %i", event);
3c9b8860
TG
533 break;
534 }
535
536 return;
537}
538
7192bb81
LP
539static int dhcp4_set_hostname(Link *link) {
540 _cleanup_free_ char *hostname = NULL;
541 const char *hn;
542 int r;
543
544 assert(link);
545
546 if (!link->network->dhcp_send_hostname)
547 hn = NULL;
548 else if (link->network->dhcp_hostname)
549 hn = link->network->dhcp_hostname;
550 else {
551 r = gethostname_strict(&hostname);
552 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
553 return r;
554
555 hn = hostname;
556 }
557
558 return sd_dhcp_client_set_hostname(link->dhcp_client, hn);
559}
560
3c9b8860
TG
561int dhcp4_configure(Link *link) {
562 int r;
563
564 assert(link);
565 assert(link->network);
e0ee46f2 566 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
3c9b8860 567
0bc70f1d
TG
568 if (!link->dhcp_client) {
569 r = sd_dhcp_client_new(&link->dhcp_client);
570 if (r < 0)
571 return r;
572 }
3c9b8860
TG
573
574 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
575 if (r < 0)
576 return r;
577
76253e73
DW
578 r = sd_dhcp_client_set_mac(link->dhcp_client,
579 (const uint8_t *) &link->mac,
580 sizeof (link->mac), ARPHRD_ETHER);
3c9b8860
TG
581 if (r < 0)
582 return r;
583
2f8e7633 584 r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
3c9b8860
TG
585 if (r < 0)
586 return r;
587
588 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
589 if (r < 0)
590 return r;
591
592 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
593 link->network->dhcp_broadcast);
594 if (r < 0)
595 return r;
596
597 if (link->mtu) {
598 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
599 if (r < 0)
600 return r;
601 }
602
27cb34f5 603 if (link->network->dhcp_use_mtu) {
39745a5a 604 r = sd_dhcp_client_set_request_option(link->dhcp_client,
22805d92 605 SD_DHCP_OPTION_INTERFACE_MTU);
39745a5a
LP
606 if (r < 0)
607 return r;
3c9b8860
TG
608 }
609
27cb34f5 610 if (link->network->dhcp_use_routes) {
3c9b8860 611 r = sd_dhcp_client_set_request_option(link->dhcp_client,
22805d92 612 SD_DHCP_OPTION_STATIC_ROUTE);
3c9b8860
TG
613 if (r < 0)
614 return r;
615 r = sd_dhcp_client_set_request_option(link->dhcp_client,
22805d92 616 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
7d6884b6
TA
617 if (r < 0)
618 return r;
3c9b8860
TG
619 }
620
27cb34f5 621 /* Always acquire the timezone and NTP */
22805d92 622 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
4b7b5abb
LP
623 if (r < 0)
624 return r;
625
22805d92 626 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
8eb9058d
LP
627 if (r < 0)
628 return r;
629
7192bb81
LP
630 r = dhcp4_set_hostname(link);
631 if (r < 0)
632 return r;
3c9b8860
TG
633
634 if (link->network->dhcp_vendor_class_identifier) {
635 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
636 link->network->dhcp_vendor_class_identifier);
637 if (r < 0)
638 return r;
639 }
640
9faed222
SS
641 if (link->network->dhcp_client_port) {
642 r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
643 if (r < 0)
644 return r;
645 }
646
3e43b2cd 647 switch (link->network->dhcp_client_identifier) {
8341a5c3 648 case DHCP_CLIENT_ID_DUID: {
413708d1 649 /* If configured, apply user specified DUID and/or IAID */
8341a5c3
ZJS
650 const DUID *duid = link_duid(link);
651
652 r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
653 link->network->iaid,
654 duid->type,
655 duid->raw_data_len > 0 ? duid->raw_data : NULL,
656 duid->raw_data_len);
413708d1
VK
657 if (r < 0)
658 return r;
3e43b2cd 659 break;
8341a5c3 660 }
3e43b2cd
JJ
661 case DHCP_CLIENT_ID_MAC:
662 r = sd_dhcp_client_set_client_id(link->dhcp_client,
663 ARPHRD_ETHER,
664 (const uint8_t *) &link->mac,
8341a5c3 665 sizeof(link->mac));
3e43b2cd
JJ
666 if (r < 0)
667 return r;
668 break;
669 default:
670 assert_not_reached("Unknown client identifier type.");
671 }
672
3c9b8860
TG
673 return 0;
674}