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