networkd-dhcp4.c revision 6666907869fb3bc7fe6a6025540db5b887c7a78b
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/***
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering This file is part of systemd.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is free software; you can redistribute it and/or modify it
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering under the terms of the GNU Lesser General Public License as published by
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering (at your option) any later version.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is distributed in the hope that it will be useful, but
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Lesser General Public License for more details.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering You should have received a copy of the GNU Lesser General Public License
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering***/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <netinet/ether.h>
4871690d9e32608bbd9b18505b5326c2079c9690Allin Cottrell#include <linux/if.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "hostname-util.h"
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include "networkd-link.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "network-internal.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "dhcp-lease-internal.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering void *userdata) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_link_unref_ Link *link = userdata;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering int r;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering assert(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(link->dhcp4_messages);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link->dhcp4_messages --;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_netlink_message_get_errno(m);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0 && r != -EEXIST) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_link_error_errno(link, r, "Could not set DHCPv4 route: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link_enter_failed(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!link->dhcp4_messages) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link->dhcp4_configured = true;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link_check_ready(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int link_set_dhcp_routes(Link *link) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct in_addr gateway;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct sd_dhcp_route *static_routes;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r, n, i;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(link->dhcp_lease);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0 && r != -ENODATA)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct in_addr address;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_route_free_ Route *route = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_route_free_ Route *route_gw = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = route_new(&route, RTPROT_DHCP);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_error_errno(link, r, "Could not allocate route: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = route_new(&route_gw, RTPROT_DHCP);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return log_link_error_errno(link, r, "Could not allocate route: %m");
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* The dhcp netmask may mask out the gateway. Add an explicit
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering * route for the gw host so that we can route no matter the
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering * netmask or existing kernel route tables. */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_gw->family = AF_INET;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_gw->dst_addr.in = gateway;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_gw->dst_prefixlen = 32;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_gw->prefsrc_addr.in = address;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_gw->scope = RT_SCOPE_LINK;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_gw->metrics = link->network->dhcp_route_metric;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = route_configure(route_gw, link, &dhcp4_route_handler);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_warning_errno(link, r, "Could not set host route: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link->dhcp4_messages ++;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->family = AF_INET;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering route->in_addr.in = gateway;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering route->prefsrc_addr.in = address;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->metrics = link->network->dhcp_route_metric;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = route_configure(route, link, &dhcp4_route_handler);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_link_warning_errno(link, r, "Could not set routes: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link_enter_failed(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link->dhcp4_messages ++;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (n == -ENODATA)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (n < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_warning_errno(link, n, "DHCP error: could not get routes: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (i = 0; i < n; i++) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_route_free_ Route *route = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = route_new(&route, RTPROT_DHCP);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_error_errno(link, r, "Could not allocate route: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->family = AF_INET;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->in_addr.in = static_routes[i].gw_addr;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->dst_addr.in = static_routes[i].dst_addr;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->dst_prefixlen = static_routes[i].dst_prefixlen;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->metrics = link->network->dhcp_route_metric;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = route_configure(route, link, &dhcp4_route_handler);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_warning_errno(link, r, "Could not set host route: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link->dhcp4_messages ++;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int dhcp_lease_lost(Link *link) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_address_free_ Address *address = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct in_addr addr;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct in_addr netmask;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct in_addr gateway;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned prefixlen = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(link->dhcp_lease);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_link_warning(link, "DHCP lease lost");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (link->network->dhcp_routes) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct sd_dhcp_route *routes;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int n, i;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (n >= 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (i = 0; i < n; i++) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_route_free_ Route *route = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = route_new(&route, RTPROT_UNSPEC);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->family = AF_INET;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->in_addr.in = routes[i].gw_addr;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->dst_addr.in = routes[i].dst_addr;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->dst_prefixlen = routes[i].dst_prefixlen;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_remove(route, link,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering &link_route_remove_handler);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = address_new(&address);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_route_free_ Route *route_gw = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_route_free_ Route *route = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = route_new(&route_gw, RTPROT_UNSPEC);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0) {
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek route_gw->family = AF_INET;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_gw->dst_addr.in = gateway;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_gw->dst_prefixlen = 32;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_gw->scope = RT_SCOPE_LINK;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_remove(route_gw, link,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering &link_route_remove_handler);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = route_new(&route, RTPROT_UNSPEC);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->family = AF_INET;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route->in_addr.in = gateway;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering route_remove(route, link,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering &link_route_remove_handler);
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering prefixlen = in_addr_netmask_to_prefixlen(&netmask);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering address->family = AF_INET;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering address->in_addr.in = addr;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering address->prefixlen = prefixlen;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering address_remove(address, link, &link_address_remove_handler);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (link->network->dhcp_mtu) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering uint16_t mtu;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0 && link->original_mtu != mtu) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = link_set_mtu(link, link->original_mtu);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_link_warning(link,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "DHCP error: could not reset MTU");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link_enter_failed(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek if (link->network->dhcp_hostname) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *hostname = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (link->network->hostname)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering hostname = link->network->hostname;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering else
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (hostname) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering /* If a hostname was set due to the lease, then unset it now. */
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = link_set_hostname(link, NULL);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering log_link_warning_errno(link, r, "Failed to reset transient hostname: %m");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering link->dhcp4_configured = false;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering void *userdata) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering _cleanup_link_unref_ Link *link = userdata;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering assert(link);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_netlink_message_get_errno(m);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0 && r != -EEXIST) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering link_enter_failed(link);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering } else if (r >= 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering manager_rtnl_process_address(rtnl, m, link->manager);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering link_set_dhcp_routes(link);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 1;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic int dhcp4_update_address(Link *link,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering struct in_addr *address,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering struct in_addr *netmask,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering uint32_t lifetime) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering _cleanup_address_free_ Address *addr = NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering unsigned prefixlen;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering assert(address);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering assert(netmask);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering assert(lifetime);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering prefixlen = in_addr_netmask_to_prefixlen(netmask);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = address_new(&addr);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering addr->family = AF_INET;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering addr->in_addr.in.s_addr = address->s_addr;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering addr->cinfo.ifa_prefered = lifetime;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering addr->cinfo.ifa_valid = lifetime;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering addr->prefixlen = prefixlen;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering /* allow reusing an existing address and simply update its lifetime
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering * in case it already exists */
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = address_configure(addr, link, &dhcp4_address_handler, true);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return 0;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering sd_dhcp_lease *lease;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering struct in_addr address;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering struct in_addr netmask;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int r;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering assert(link);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering assert(client);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering assert(link->network);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_dhcp_client_get_lease(client, &lease);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering sd_dhcp_lease_unref(link->dhcp_lease);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering link->dhcp4_configured = false;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering link->dhcp_lease = sd_dhcp_lease_ref(lease);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_dhcp_lease_get_address(lease, &address);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return log_link_warning_errno(link, r, "DHCP error: no address: %m");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_dhcp_lease_get_netmask(lease, &netmask);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!link->network->dhcp_critical) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (r < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = dhcp4_update_address(link, &address, &netmask, lifetime);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_link_warning_errno(link, r, "Could not update IP address: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link_enter_failed(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering sd_dhcp_lease *lease;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct in_addr address;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct in_addr netmask;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct in_addr gateway;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering unsigned prefixlen;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(client);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_client_get_lease(client, &lease);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_error_errno(link, r, "DHCP error: No lease: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_dhcp_lease_get_address(lease, &address);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_error_errno(link, r, "DHCP error: No address: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_lease_get_netmask(lease, &netmask);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering prefixlen = in_addr_netmask_to_prefixlen(&netmask);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_lease_get_router(lease, &gateway);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0 && r != -ENODATA)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_struct(LOG_INFO,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LOG_LINK_INTERFACE(link),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ADDRESS_FMT_VAL(address),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering prefixlen,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ADDRESS_FMT_VAL(gateway)),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "PREFIXLEN=%u", prefixlen,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering else
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_struct(LOG_INFO,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LOG_LINK_INTERFACE(link),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ADDRESS_FMT_VAL(address),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering prefixlen),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "PREFIXLEN=%u", prefixlen,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link->dhcp_lease = sd_dhcp_lease_ref(lease);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (link->network->dhcp_mtu) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering uint16_t mtu;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_lease_get_mtu(lease, &mtu);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r >= 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = link_set_mtu(link, mtu);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (link->network->dhcp_hostname) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *hostname = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (link->network->hostname)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering hostname = link->network->hostname;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering else
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering (void) sd_dhcp_lease_get_hostname(lease, &hostname);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (hostname) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = link_set_hostname(link, hostname);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (link->network->dhcp_timezone) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *tz = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (tz) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = link_set_timezone(link, tz);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!link->network->dhcp_critical) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = dhcp4_update_address(link, &address, &netmask, lifetime);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (r < 0) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering log_link_warning_errno(link, r, "Could not update IP address: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering link_enter_failed(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return r;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Link *link = userdata;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int r = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(link);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(link->network);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering assert(link->manager);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering switch (event) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering case SD_DHCP_CLIENT_EVENT_EXPIRED:
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering case SD_DHCP_CLIENT_EVENT_STOP:
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (link->network->dhcp_critical) {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering }
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (link->dhcp_lease) {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering r = dhcp_lease_lost(link);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (r < 0) {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering link_enter_failed(link);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering return;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering }
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering }
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (event == SD_DHCP_CLIENT_EVENT_IP_CHANGE) {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering r = dhcp_lease_acquired(client, link);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (r < 0) {
link_enter_failed(link);
return;
}
}
break;
case SD_DHCP_CLIENT_EVENT_RENEW:
r = dhcp_lease_renew(client, link);
if (r < 0) {
link_enter_failed(link);
return;
}
break;
case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
r = dhcp_lease_acquired(client, link);
if (r < 0) {
link_enter_failed(link);
return;
}
break;
default:
if (event < 0)
log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
else
log_link_warning(link, "DHCP unknown event: %i", event);
break;
}
return;
}
int dhcp4_configure(Link *link) {
int r;
assert(link);
assert(link->network);
assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
r = sd_dhcp_client_new(&link->dhcp_client);
if (r < 0)
return r;
r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
if (r < 0)
return r;
r = sd_dhcp_client_set_mac(link->dhcp_client,
(const uint8_t *) &link->mac,
sizeof (link->mac), ARPHRD_ETHER);
if (r < 0)
return r;
r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
if (r < 0)
return r;
r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
if (r < 0)
return r;
r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
link->network->dhcp_broadcast);
if (r < 0)
return r;
if (link->mtu) {
r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
if (r < 0)
return r;
}
if (link->network->dhcp_mtu) {
r = sd_dhcp_client_set_request_option(link->dhcp_client,
DHCP_OPTION_INTERFACE_MTU);
if (r < 0)
return r;
}
if (link->network->dhcp_routes) {
r = sd_dhcp_client_set_request_option(link->dhcp_client,
DHCP_OPTION_STATIC_ROUTE);
if (r < 0)
return r;
r = sd_dhcp_client_set_request_option(link->dhcp_client,
DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
if (r < 0)
return r;
}
/* Always acquire the timezone and NTP*/
r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NTP_SERVER);
if (r < 0)
return r;
r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NEW_TZDB_TIMEZONE);
if (r < 0)
return r;
if (link->network->dhcp_sendhost) {
_cleanup_free_ char *hostname = NULL;
const char *hn = NULL;
if (!link->network->hostname) {
hostname = gethostname_malloc();
if (!hostname)
return -ENOMEM;
hn = hostname;
} else
hn = link->network->hostname;
if (!is_localhost(hn)) {
r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
if (r < 0)
return r;
}
}
if (link->network->dhcp_vendor_class_identifier) {
r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
link->network->dhcp_vendor_class_identifier);
if (r < 0)
return r;
}
switch (link->network->dhcp_client_identifier) {
case DHCP_CLIENT_ID_DUID:
/* Library defaults to this. */
break;
case DHCP_CLIENT_ID_MAC:
r = sd_dhcp_client_set_client_id(link->dhcp_client,
ARPHRD_ETHER,
(const uint8_t *) &link->mac,
sizeof (link->mac));
if (r < 0)
return r;
break;
default:
assert_not_reached("Unknown client identifier type.");
}
return 0;
}