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