- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
-
- r = sd_rtnl_message_get_errno(m);
- if (r < 0)
- log_struct_link(LOG_WARNING, link,
- "MESSAGE=%-*s: could not set MTU: %s",
- IFNAMSIZ, link->ifname, strerror(-r),
- "ERRNO=%d", -r,
- NULL);
-
- return 1;
-}
-
-static int link_set_mtu(Link *link, uint32_t mtu) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
- int r;
-
- assert(link);
- assert(link->manager);
- assert(link->manager->rtnl);
-
- log_debug_link(link, "setting MTU: %" PRIu32, mtu);
-
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
- RTM_SETLINK, link->ifindex);
- if (r < 0) {
- log_error_link(link, "Could not allocate RTM_SETLINK message");
- return r;
- }
-
- r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
- if (r < 0) {
- log_error_link(link, "Could not append MTU: %s", strerror(-r));
- return r;
- }
-
- r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
- if (r < 0) {
- log_error_link(link,
- "Could not send rtnetlink message: %s", strerror(-r));
- return r;
- }
-
- link_ref(link);
-
- return 0;
-}
-
-static int dhcp_lease_lost(Link *link) {
- _cleanup_address_free_ Address *address = NULL;
- struct in_addr addr;
- struct in_addr netmask;
- struct in_addr gateway;
- unsigned prefixlen;
- int r;
-
- assert(link);
- assert(link->dhcp_lease);
-
- log_warning_link(link, "DHCP lease lost");
-
- if (link->network->dhcp_routes) {
- struct sd_dhcp_route *routes;
- int n, i;
-
- n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
- if (n >= 0) {
- for (i = 0; i < n; i++) {
- _cleanup_route_free_ Route *route = NULL;
-
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
- if (r >= 0) {
- route->family = AF_INET;
- route->in_addr.in = routes[i].gw_addr;
- route->dst_addr.in = routes[i].dst_addr;
- route->dst_prefixlen = routes[i].dst_prefixlen;
-
- route_drop(route, link, &route_drop_handler);
- }
- }
- }
- }
-
- r = address_new_dynamic(&address);
- if (r >= 0) {
- r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
- if (r >= 0) {
- _cleanup_route_free_ Route *route_gw = NULL;
- _cleanup_route_free_ Route *route = NULL;
-
- r = route_new_dynamic(&route_gw, RTPROT_UNSPEC);
- if (r >= 0) {
- route_gw->family = AF_INET;
- route_gw->dst_addr.in = gateway;
- route_gw->dst_prefixlen = 32;
- route_gw->scope = RT_SCOPE_LINK;
-
- route_drop(route_gw, link, &route_drop_handler);
- }
-
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
- if (r >= 0) {
- route->family = AF_INET;
- route->in_addr.in = gateway;
-
- route_drop(route, link, &route_drop_handler);
- }
- }
-
- sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
- sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
- prefixlen = net_netmask_to_prefixlen(&netmask);
-
- address->family = AF_INET;
- address->in_addr.in = addr;
- address->prefixlen = prefixlen;
-
- address_drop(address, link, &address_drop_handler);
- }
-
- if (link->network->dhcp_mtu) {
- uint16_t mtu;
-
- r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
- if (r >= 0 && link->original_mtu != mtu) {
- r = link_set_mtu(link, link->original_mtu);
- if (r < 0) {
- log_warning_link(link, "DHCP error: could not reset MTU");
- link_enter_failed(link);
- return r;
- }
- }
- }
-
- if (link->network->dhcp_hostname) {
- const char *hostname = NULL;
-
- r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
- if (r >= 0 && hostname) {
- r = link_set_hostname(link, "");
- if (r < 0)
- log_error_link(link, "Failed to reset transient hostname");
- }
- }
-
- link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
-
- return 0;
-}
-
-static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
- sd_dhcp_lease *lease;
- int r;
-
- r = sd_dhcp_client_get_lease(client, &lease);
- if (r < 0) {
- log_warning_link(link, "DHCP error: no lease %s",
- strerror(-r));
- return r;
- }
-
- sd_dhcp_lease_unref(link->dhcp_lease);
- link->dhcp_lease = lease;
-
- link_enter_set_addresses(link);
-
- return 0;
-}
-
-static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
- sd_dhcp_lease *lease;
- struct in_addr address;
- struct in_addr netmask;
- struct in_addr gateway;
- unsigned prefixlen;
- int r;
-
- assert(client);
- assert(link);
-
- r = sd_dhcp_client_get_lease(client, &lease);
- if (r < 0) {
- log_warning_link(link, "DHCP error: no lease: %s",
- strerror(-r));
- return r;
- }
-
- r = sd_dhcp_lease_get_address(lease, &address);
- if (r < 0) {
- log_warning_link(link, "DHCP error: no address: %s",
- strerror(-r));
- return r;
- }
-
- r = sd_dhcp_lease_get_netmask(lease, &netmask);
- if (r < 0) {
- log_warning_link(link, "DHCP error: no netmask: %s",
- strerror(-r));
- return r;
- }
-
- prefixlen = net_netmask_to_prefixlen(&netmask);
-
- r = sd_dhcp_lease_get_router(lease, &gateway);
- if (r < 0 && r != -ENOENT) {
- log_warning_link(link, "DHCP error: could not get gateway: %s",
- strerror(-r));
- return r;
- }
-
- if (r >= 0)
- log_struct_link(LOG_INFO, link,
- "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
- IFNAMSIZ,
- link->ifname,
- ADDRESS_FMT_VAL(address),
- prefixlen,
- ADDRESS_FMT_VAL(gateway),
- "ADDRESS=%u.%u.%u.%u",
- ADDRESS_FMT_VAL(address),
- "PREFIXLEN=%u",
- prefixlen,
- "GATEWAY=%u.%u.%u.%u",
- ADDRESS_FMT_VAL(gateway),
- NULL);
- else
- log_struct_link(LOG_INFO, link,
- "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u",
- IFNAMSIZ,
- link->ifname,
- ADDRESS_FMT_VAL(address),
- prefixlen,
- "ADDRESS=%u.%u.%u.%u",
- ADDRESS_FMT_VAL(address),
- "PREFIXLEN=%u",
- prefixlen,
- NULL);
-
- link->dhcp_lease = lease;
-
- if (link->network->dhcp_mtu) {
- uint16_t mtu;
-
- r = sd_dhcp_lease_get_mtu(lease, &mtu);
- if (r >= 0) {
- r = link_set_mtu(link, mtu);
- if (r < 0)
- log_error_link(link, "Failed to set MTU "
- "to %" PRIu16, mtu);
- }
- }
-
- if (link->network->dhcp_hostname) {
- const char *hostname;
-
- r = sd_dhcp_lease_get_hostname(lease, &hostname);
- if (r >= 0) {
- r = link_set_hostname(link, hostname);
- if (r < 0)
- log_error_link(link, "Failed to set transient hostname "
- "to '%s'", hostname);
- }
- }
-
- link_enter_set_addresses(link);
-
- return 0;
-}
-
-static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
- Link *link = userdata;
- int r = 0;
-
- assert(link);
- assert(link->network);
- assert(link->manager);
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return;
-
- switch (event) {
- case DHCP_EVENT_EXPIRED:
- case DHCP_EVENT_STOP:
- case DHCP_EVENT_IP_CHANGE:
- if (link->network->dhcp_critical) {
- log_error_link(link, "DHCPv4 connection considered system critical, "
- "ignoring request to reconfigure it.");
- return;
- }
-
- if (link->dhcp_lease) {
- r = dhcp_lease_lost(link);
- if (r < 0) {
- link_enter_failed(link);
- return;
- }
- }
-
- if (event == DHCP_EVENT_IP_CHANGE) {
- r = dhcp_lease_acquired(client, link);
- if (r < 0) {
- link_enter_failed(link);
- return;
- }
- }
-
- if (event == DHCP_EVENT_EXPIRED && link->network->ipv4ll) {
- if (!sd_ipv4ll_is_running(link->ipv4ll))
- r = sd_ipv4ll_start(link->ipv4ll);
- else if (ipv4ll_is_bound(link->ipv4ll))
- r = ipv4ll_address_update(link, false);
- if (r < 0) {
- link_enter_failed(link);
- return;
- }
- }
-
- break;
- case DHCP_EVENT_RENEW:
- r = dhcp_lease_renew(client, link);
- if (r < 0) {
- link_enter_failed(link);
- return;
- }
- break;
- case DHCP_EVENT_IP_ACQUIRE:
- r = dhcp_lease_acquired(client, link);
- if (r < 0) {
- link_enter_failed(link);
- return;
- }
- if (link->ipv4ll) {
- if (ipv4ll_is_bound(link->ipv4ll))
- r = ipv4ll_address_update(link, true);
- else
- r = sd_ipv4ll_stop(link->ipv4ll);
- if (r < 0) {
- link_enter_failed(link);
- return;
- }
- }
- break;
- default:
- if (event < 0)
- log_warning_link(link, "DHCP error: client failed: %s", strerror(-event));
- else
- log_warning_link(link, "DHCP unknown event: %d", event);
- break;
- }
-
- return;
-}
-
-static int ipv4ll_address_update(Link *link, bool deprecate) {
- int r;
- struct in_addr addr;
-
- assert(link);
-
- r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
- if (r >= 0) {
- _cleanup_address_free_ Address *address = NULL;
-
- log_debug_link(link, "IPv4 link-local %s %u.%u.%u.%u",
- deprecate ? "deprecate" : "approve",
- ADDRESS_FMT_VAL(addr));
-
- r = address_new_dynamic(&address);
- if (r < 0) {
- log_error_link(link, "Could not allocate address: %s", strerror(-r));
- return r;
- }
-
- address->family = AF_INET;
- address->in_addr.in = addr;
- address->prefixlen = 16;
- address->scope = RT_SCOPE_LINK;
- address->cinfo.ifa_prefered = deprecate ? 0 : CACHE_INFO_INFINITY_LIFE_TIME;
- address->broadcast.s_addr = address->in_addr.in.s_addr | htonl(0xfffffffflu >> address->prefixlen);
-
- address_update(address, link, &address_update_handler);
- }