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