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