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