networkd-ndisc.c revision 962b0647298b601548b049893931d2477f06ab57
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen This file is part of systemd.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen Copyright (C) 2014 Intel Corporation. All rights reserved.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen systemd is free software; you can redistribute it and/or modify it
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen under the terms of the GNU Lesser General Public License as published by
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen (at your option) any later version.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen systemd is distributed in the hope that it will be useful, but
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen Lesser General Public License for more details.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen You should have received a copy of the GNU Lesser General Public License
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0 && r != -EEXIST) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen,
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen unsigned lifetime_preferred, unsigned lifetime_valid, void *userdata) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen _cleanup_address_free_ Address *address = NULL;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_error_errno(link, r, "Could not allocate address: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen memcpy(&address->in_addr.in6 + 8, &link->network->ipv6_token + 8, 8);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen /* see RFC4291 section 2.5.1 */
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->in_addr.in6.__in6_u.__u6_addr8[8] = link->mac.ether_addr_octet[0];
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->in_addr.in6.__in6_u.__u6_addr8[8] ^= 1 << 1;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->in_addr.in6.__in6_u.__u6_addr8[9] = link->mac.ether_addr_octet[1];
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->in_addr.in6.__in6_u.__u6_addr8[10] = link->mac.ether_addr_octet[2];
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->in_addr.in6.__in6_u.__u6_addr8[11] = 0xff;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->in_addr.in6.__in6_u.__u6_addr8[12] = 0xfe;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->in_addr.in6.__in6_u.__u6_addr8[13] = link->mac.ether_addr_octet[3];
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->in_addr.in6.__in6_u.__u6_addr8[14] = link->mac.ether_addr_octet[4];
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->in_addr.in6.__in6_u.__u6_addr8[15] = link->mac.ether_addr_octet[5];
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->cinfo.ifa_prefered = lifetime_preferred;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = address_configure(address, link, ndisc_netlink_handler, true);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_error_errno(link, r, "Could not allocate route: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->lifetime = time_now + lifetime * USEC_PER_SEC;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = route_configure(route, link, ndisc_netlink_handler);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_warning_errno(link, r, "Could not set prefix route: %m");
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersenstatic void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) {
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen r = sd_dhcp6_client_start(link->dhcp6_client);
f5a8c43f39937d97c9ed75e3fe8621945b42b0dbTom Gundersen if (r < 0 && r != -EALREADY)
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_error_errno(link, r, "Could not allocate route: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->lifetime = time_now + lifetime * USEC_PER_SEC;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = route_configure(route, link, ndisc_netlink_handler);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_warning_errno(link, r, "Could not set default route: %m");
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersenstatic void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen r = sd_dhcp6_client_start(link->dhcp6_client);
f5a8c43f39937d97c9ed75e3fe8621945b42b0dbTom Gundersen if (r < 0 && r != -EALREADY)
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m");
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_ndisc_new(&link->ndisc_router_discovery);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_ndisc_attach_event(link->ndisc_router_discovery, NULL, 0);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_ndisc_set_mac(link->ndisc_router_discovery, &link->mac);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_ndisc_set_index(link->ndisc_router_discovery, link->ifindex);