1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <netinet/ether.h>
25 #include "networkd-link.h"
26 #include "network-internal.h"
27 #include "dhcp-lease-internal.h"
29 static int dhcp4_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
31 _cleanup_link_unref_ Link *link = userdata;
35 assert(link->dhcp4_messages);
37 link->dhcp4_messages --;
39 r = sd_rtnl_message_get_errno(m);
40 if (r < 0 && r != -EEXIST) {
41 log_error_link(link, "could not set DHCPv4 route: %s",
43 link_enter_failed(link);
46 if (!link->dhcp4_messages) {
47 link->dhcp4_configured = true;
48 link_client_handler(link);
54 static int link_set_dhcp_routes(Link *link) {
55 struct in_addr gateway;
56 struct sd_dhcp_route *static_routes;
60 assert(link->dhcp_lease);
62 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
63 if (r < 0 && r != -ENOENT) {
64 log_warning_link(link,
65 "DHCP error: could not get gateway: %s",
70 _cleanup_route_free_ Route *route = NULL;
71 _cleanup_route_free_ Route *route_gw = NULL;
73 r = route_new_dynamic(&route, RTPROT_DHCP);
76 "Could not allocate route: %s",
81 r = route_new_dynamic(&route_gw, RTPROT_DHCP);
84 "Could not allocate route: %s",
89 /* The dhcp netmask may mask out the gateway. Add an explicit
90 * route for the gw host so that we can route no matter the
91 * netmask or existing kernel route tables. */
92 route_gw->family = AF_INET;
93 route_gw->dst_addr.in = gateway;
94 route_gw->dst_prefixlen = 32;
95 route_gw->scope = RT_SCOPE_LINK;
96 route_gw->metrics = DHCP_ROUTE_METRIC;
98 r = route_configure(route_gw, link, &dhcp4_route_handler);
100 log_warning_link(link,
101 "could not set host route: %s",
106 link->dhcp4_messages ++;
108 route->family = AF_INET;
109 route->in_addr.in = gateway;
110 route->metrics = DHCP_ROUTE_METRIC;
112 r = route_configure(route, link, &dhcp4_route_handler);
114 log_warning_link(link,
115 "could not set routes: %s",
117 link_enter_failed(link);
121 link->dhcp4_messages ++;
124 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
128 log_warning_link(link,
129 "DHCP error: could not get routes: %s",
135 for (i = 0; i < n; i++) {
136 _cleanup_route_free_ Route *route = NULL;
138 r = route_new_dynamic(&route, RTPROT_DHCP);
140 log_error_link(link, "Could not allocate route: %s",
145 route->family = AF_INET;
146 route->in_addr.in = static_routes[i].gw_addr;
147 route->dst_addr.in = static_routes[i].dst_addr;
148 route->dst_prefixlen = static_routes[i].dst_prefixlen;
149 route->metrics = DHCP_ROUTE_METRIC;
151 r = route_configure(route, link, &dhcp4_route_handler);
153 log_warning_link(link,
154 "could not set host route: %s",
159 link->dhcp4_messages ++;
165 static int dhcp_lease_lost(Link *link) {
166 _cleanup_address_free_ Address *address = NULL;
168 struct in_addr netmask;
169 struct in_addr gateway;
174 assert(link->dhcp_lease);
176 log_warning_link(link, "DHCP lease lost");
178 if (link->network->dhcp_routes) {
179 struct sd_dhcp_route *routes;
182 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
184 for (i = 0; i < n; i++) {
185 _cleanup_route_free_ Route *route = NULL;
187 r = route_new_dynamic(&route, RTPROT_UNSPEC);
189 route->family = AF_INET;
190 route->in_addr.in = routes[i].gw_addr;
191 route->dst_addr.in = routes[i].dst_addr;
192 route->dst_prefixlen = routes[i].dst_prefixlen;
194 route_drop(route, link,
195 &link_route_drop_handler);
201 r = address_new_dynamic(&address);
203 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
205 _cleanup_route_free_ Route *route_gw = NULL;
206 _cleanup_route_free_ Route *route = NULL;
208 r = route_new_dynamic(&route_gw, RTPROT_UNSPEC);
210 route_gw->family = AF_INET;
211 route_gw->dst_addr.in = gateway;
212 route_gw->dst_prefixlen = 32;
213 route_gw->scope = RT_SCOPE_LINK;
215 route_drop(route_gw, link,
216 &link_route_drop_handler);
219 r = route_new_dynamic(&route, RTPROT_UNSPEC);
221 route->family = AF_INET;
222 route->in_addr.in = gateway;
224 route_drop(route, link,
225 &link_route_drop_handler);
229 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
230 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
231 prefixlen = in_addr_netmask_to_prefixlen(&netmask);
233 address->family = AF_INET;
234 address->in_addr.in = addr;
235 address->prefixlen = prefixlen;
237 address_drop(address, link, &link_address_drop_handler);
240 if (link->network->dhcp_mtu) {
243 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
244 if (r >= 0 && link->original_mtu != mtu) {
245 r = link_set_mtu(link, link->original_mtu);
247 log_warning_link(link,
248 "DHCP error: could not reset MTU");
249 link_enter_failed(link);
255 if (link->network->dhcp_hostname) {
256 const char *hostname = NULL;
258 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
259 if (r >= 0 && hostname) {
260 r = link_set_hostname(link, "");
263 "Failed to reset transient hostname");
267 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
268 link->dhcp4_configured = false;
273 static int dhcp4_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
275 _cleanup_link_unref_ Link *link = userdata;
280 r = sd_rtnl_message_get_errno(m);
281 if (r < 0 && r != -EEXIST) {
282 log_error_link(link, "could not set DHCPv4 address: %s",
284 link_enter_failed(link);
286 /* calling handler directly so take a ref */
288 link_get_address_handler(rtnl, m, link);
291 link_set_dhcp_routes(link);
296 static int dhcp4_update_address(Link *link,
297 struct in_addr *address,
298 struct in_addr *netmask,
300 _cleanup_address_free_ Address *addr = NULL;
308 prefixlen = in_addr_netmask_to_prefixlen(netmask);
310 r = address_new_dynamic(&addr);
314 addr->family = AF_INET;
315 addr->in_addr.in.s_addr = address->s_addr;
316 addr->cinfo.ifa_prefered = lifetime;
317 addr->cinfo.ifa_valid = lifetime;
318 addr->prefixlen = prefixlen;
319 addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
321 /* use update rather than configure so that we will update the
322 * lifetime of an existing address if it has already been configured */
323 r = address_update(addr, link, &dhcp4_address_handler);
330 static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
331 sd_dhcp_lease *lease;
332 struct in_addr address;
333 struct in_addr netmask;
334 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
339 assert(link->network);
341 r = sd_dhcp_client_get_lease(client, &lease);
343 log_warning_link(link, "DHCP error: no lease %s",
348 sd_dhcp_lease_unref(link->dhcp_lease);
349 link->dhcp4_configured = false;
350 link->dhcp_lease = lease;
352 r = sd_dhcp_lease_get_address(lease, &address);
354 log_warning_link(link, "DHCP error: no address: %s",
359 r = sd_dhcp_lease_get_netmask(lease, &netmask);
361 log_warning_link(link, "DHCP error: no netmask: %s",
366 if (!link->network->dhcp_critical) {
367 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
370 log_warning_link(link,
371 "DHCP error: no lifetime: %s",
377 r = dhcp4_update_address(link, &address, &netmask, lifetime);
379 log_warning_link(link, "could not update IP address: %s",
381 link_enter_failed(link);
388 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
389 sd_dhcp_lease *lease;
390 struct in_addr address;
391 struct in_addr netmask;
392 struct in_addr gateway;
394 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
400 r = sd_dhcp_client_get_lease(client, &lease);
402 log_warning_link(link, "DHCP error: no lease: %s",
407 r = sd_dhcp_lease_get_address(lease, &address);
409 log_warning_link(link, "DHCP error: no address: %s",
414 r = sd_dhcp_lease_get_netmask(lease, &netmask);
416 log_warning_link(link, "DHCP error: no netmask: %s",
421 prefixlen = in_addr_netmask_to_prefixlen(&netmask);
423 r = sd_dhcp_lease_get_router(lease, &gateway);
424 if (r < 0 && r != -ENOENT) {
425 log_warning_link(link, "DHCP error: could not get gateway: %s",
431 log_struct_link(LOG_INFO, link,
432 "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
435 ADDRESS_FMT_VAL(address),
437 ADDRESS_FMT_VAL(gateway),
438 "ADDRESS=%u.%u.%u.%u",
439 ADDRESS_FMT_VAL(address),
442 "GATEWAY=%u.%u.%u.%u",
443 ADDRESS_FMT_VAL(gateway),
446 log_struct_link(LOG_INFO, link,
447 "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u",
450 ADDRESS_FMT_VAL(address),
452 "ADDRESS=%u.%u.%u.%u",
453 ADDRESS_FMT_VAL(address),
458 link->dhcp_lease = lease;
460 if (link->network->dhcp_mtu) {
463 r = sd_dhcp_lease_get_mtu(lease, &mtu);
465 r = link_set_mtu(link, mtu);
467 log_error_link(link, "Failed to set MTU "
472 if (link->network->dhcp_hostname) {
473 const char *hostname;
475 r = sd_dhcp_lease_get_hostname(lease, &hostname);
477 r = link_set_hostname(link, hostname);
480 "Failed to set transient hostname to '%s'",
485 if (!link->network->dhcp_critical) {
486 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
489 log_warning_link(link,
490 "DHCP error: no lifetime: %s",
496 r = dhcp4_update_address(link, &address, &netmask, lifetime);
498 log_warning_link(link, "could not update IP address: %s",
500 link_enter_failed(link);
506 static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
507 Link *link = userdata;
511 assert(link->network);
512 assert(link->manager);
514 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
518 case DHCP_EVENT_EXPIRED:
519 case DHCP_EVENT_STOP:
520 case DHCP_EVENT_IP_CHANGE:
521 if (link->network->dhcp_critical) {
523 "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
527 if (link->dhcp_lease) {
528 r = dhcp_lease_lost(link);
530 link_enter_failed(link);
535 if (event == DHCP_EVENT_IP_CHANGE) {
536 r = dhcp_lease_acquired(client, link);
538 link_enter_failed(link);
544 case DHCP_EVENT_RENEW:
545 r = dhcp_lease_renew(client, link);
547 link_enter_failed(link);
551 case DHCP_EVENT_IP_ACQUIRE:
552 r = dhcp_lease_acquired(client, link);
554 link_enter_failed(link);
560 log_warning_link(link,
561 "DHCP error: client failed: %s",
564 log_warning_link(link,
565 "DHCP unknown event: %d",
573 int dhcp4_configure(Link *link) {
577 assert(link->network);
578 assert(IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4));
580 r = sd_dhcp_client_new(&link->dhcp_client);
584 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
588 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
592 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
596 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
600 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
601 link->network->dhcp_broadcast);
606 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
611 if (link->network->dhcp_mtu) {
612 r = sd_dhcp_client_set_request_option(link->dhcp_client,
613 DHCP_OPTION_INTERFACE_MTU);
618 if (link->network->dhcp_routes) {
619 r = sd_dhcp_client_set_request_option(link->dhcp_client,
620 DHCP_OPTION_STATIC_ROUTE);
623 r = sd_dhcp_client_set_request_option(link->dhcp_client,
624 DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
629 if (link->network->dhcp_sendhost) {
630 _cleanup_free_ char *hostname = NULL;
632 hostname = gethostname_malloc();
636 if (!is_localhost(hostname)) {
637 r = sd_dhcp_client_set_hostname(link->dhcp_client,
644 if (link->network->dhcp_vendor_class_identifier) {
645 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
646 link->network->dhcp_vendor_class_identifier);