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