networkd-dhcp6.c revision 6666907869fb3bc7fe6a6025540db5b887c7a78b
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt This file is part of systemd.
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt Copyright (C) 2014 Intel Corporation. All rights reserved.
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt systemd is free software; you can redistribute it and/or modify it
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt under the terms of the GNU Lesser General Public License as published by
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt the Free Software Foundation; either version 2.1 of the License, or
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt (at your option) any later version.
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt systemd is distributed in the hope that it will be useful, but
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt WITHOUT ANY WARRANTY; without even the implied warranty of
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt Lesser General Public License for more details.
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt You should have received a copy of the GNU Lesser General Public License
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt along with systemd; If not, see <http://www.gnu.org/licenses/>.
be3a09b7ffe62b52658e77ae4d6638d1b0dae654Patrik Flyktstatic int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flyktstatic int dhcp6_lease_information_acquired(sd_dhcp6_client *client,
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersenstatic int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt if (r < 0 && r != -EEXIST) {
be3a09b7ffe62b52658e77ae4d6638d1b0dae654Patrik Flykt log_link_warning(link, "Could not set extended netlink attributes, reverting to fallback mechanism");
be3a09b7ffe62b52658e77ae4d6638d1b0dae654Patrik Flykt dhcp6_lease_address_acquired(link->dhcp6_client, link);
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_link_error_errno(link, r, "Could not set DHCPv6 address: %m");
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt } else if (r >= 0)
200a0868fcdf7b95f3d8d1fda3aa2aef48d84fddTom Gundersen manager_rtnl_process_address(rtnl, m, link->manager);
36c32f6120a0c3fe19be5aeaa1926e179e8c29baTom Gundersenstatic int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr,
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt uint8_t prefixlen, uint32_t lifetime_preferred,
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann "DHCPv6 address "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
f2341e0a87cab1558c84c933956e9181d5fb6c52Lennart Poettering addr->prefixlen, lifetime_preferred, lifetime_valid);
6666907869fb3bc7fe6a6025540db5b887c7a78bTom Gundersen r = address_configure(addr, link, dhcp6_address_handler, true);
f2341e0a87cab1558c84c933956e9181d5fb6c52Lennart Poettering log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m");
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flyktstatic int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery,
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt if (r < 0 && r != -EADDRNOTAVAIL) {
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_link_warning_errno(link, r, "Could not get prefix information: %m");
36c32f6120a0c3fe19be5aeaa1926e179e8c29baTom Gundersen r = dhcp6_address_change(link, &ip6_addr, prefixlen,
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flyktstatic void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt r = dhcp6_lease_address_acquired(client, link);
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt if (r < 0) {
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt /* fall through */
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST:
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt r = dhcp6_lease_information_acquired(client, link);
c62c4628d9dbc27effd36143c75abe528f561867Patrik Flykt if (r < 0) {
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_link_warning_errno(link, event, "DHCPv6 error: %m");
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_link_warning(link, "DHCPv6 unknown event: %d", event);
85bd849f09aceb7f972a0697494ea22b2247a5d7Patrik Flyktstatic int dhcp6_configure(Link *link, int event) {
e66040417b52be98d41ba1230f25dea65147e8eePatrik Flykt assert_return(IN_SET(event, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT,
e66040417b52be98d41ba1230f25dea65147e8eePatrik Flykt SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED), -EINVAL);
85bd849f09aceb7f972a0697494ea22b2247a5d7Patrik Flykt r = sd_dhcp6_client_get_information_request(link->dhcp6_client,
85bd849f09aceb7f972a0697494ea22b2247a5d7Patrik Flykt if (r < 0) {
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_link_warning_errno(link, r, "Could not get DHCPv6 Information request setting: %m");
e66040417b52be98d41ba1230f25dea65147e8eePatrik Flykt if (information_request && event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
e66040417b52be98d41ba1230f25dea65147e8eePatrik Flykt if (r < 0) {
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_link_warning_errno(link, r, "Could not stop DHCPv6 while setting Managed mode: %m");
e66040417b52be98d41ba1230f25dea65147e8eePatrik Flykt r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
e66040417b52be98d41ba1230f25dea65147e8eePatrik Flykt if (r < 0) {
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_link_warning_errno(link, r, "Could not unset DHCPv6 Information request: %m");
e66040417b52be98d41ba1230f25dea65147e8eePatrik Flykt if (r < 0 && r != -EALREADY) {
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_link_warning_errno(link, r, "Could not restart DHCPv6: %m");
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt r = sd_dhcp6_client_set_mac(link->dhcp6_client,
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann if (event == SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
85bd849f09aceb7f972a0697494ea22b2247a5d7Patrik Flykt r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
e66040417b52be98d41ba1230f25dea65147e8eePatrik Flykt link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
be3a09b7ffe62b52658e77ae4d6638d1b0dae654Patrik Flykt r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery,
be3a09b7ffe62b52658e77ae4d6638d1b0dae654Patrik Flykt r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease);
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann log_link_info(link, "IPv6 prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d expired",
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann SD_ICMP6_ND_ADDRESS_FORMAT_VAL(*expired_prefix),
be3a09b7ffe62b52658e77ae4d6638d1b0dae654Patrik Flykt while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
be3a09b7ffe62b52658e77ae4d6638d1b0dae654Patrik Flykt r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen,
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(ip6_addr), 128);
36c32f6120a0c3fe19be5aeaa1926e179e8c29baTom Gundersen dhcp6_address_change(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid);
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flyktstatic void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE:
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER:
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED:
575ac4c62e417cb3e963f2bee627e3c10b06691dDavid Herrmann case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_link_warning_errno(link, event, "ICMPv6 error: %m");
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_link_warning(link, "ICMPv6 unknown event: %d", event);
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery, NULL, 0);
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery, &link->mac);
5c79bd79839f1e50bd3c34a0670037f7965ca5a4Patrik Flykt r = sd_icmp6_nd_set_index(link->icmp6_router_discovery, link->ifindex);