a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen/***
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen This file is part of systemd.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen Copyright (C) 2014 Intel Corporation. All rights reserved.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
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
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
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/>.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen***/
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen#include <netinet/ether.h>
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen#include <netinet/icmp6.h>
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen#include <linux/if.h>
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen#include "sd-ndisc.h"
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "networkd-link.h"
fe30727643a7c53faa29f1caa8dcabcb2b6f6fcbTom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen _cleanup_link_unref_ Link *link = userdata;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen int r;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert(link);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert(link->ndisc_messages > 0);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen link->ndisc_messages --;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_netlink_message_get_errno(m);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0 && r != -EEXIST) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen link_enter_failed(link);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (link->ndisc_messages == 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen link->ndisc_configured = true;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen link_check_ready(link);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return 1;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen}
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
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 Link *link = userdata;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen usec_t time_now;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen int r;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert(nd);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert(link);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert(link->network);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = address_new(&address);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_error_errno(link, r, "Could not allocate address: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->family = AF_INET6;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->in_addr.in6 = *prefix;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
fb84d8966e5ce49b0c705768bb4da4956c4e529aTom Gundersen memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen else {
fe30727643a7c53faa29f1caa8dcabcb2b6f6fcbTom 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 }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->prefixlen = prefixlen;
f217be196ef831df7226bfd5ee6f10149d5b5787Dominik Hannen address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->cinfo.ifa_prefered = lifetime_preferred;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen address->cinfo.ifa_valid = lifetime_valid;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = address_configure(address, link, ndisc_netlink_handler, true);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen link_enter_failed(link);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen link->ndisc_messages ++;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen}
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen _cleanup_route_free_ Route *route = NULL;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen Link *link = userdata;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen usec_t time_now;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen int r;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert(nd);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert(link);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = route_new(&route);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_error_errno(link, r, "Could not allocate route: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->family = AF_INET6;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->table = RT_TABLE_MAIN;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->protocol = RTPROT_RA;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->flags = RTM_F_PREFIX;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->dst.in6 = *prefix;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->dst_prefixlen = prefixlen;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->lifetime = time_now + lifetime * USEC_PER_SEC;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = route_configure(route, link, ndisc_netlink_handler);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_warning_errno(link, r, "Could not set prefix route: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen link_enter_failed(link);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen link->ndisc_messages ++;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen}
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersenstatic void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen _cleanup_route_free_ Route *route = NULL;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen Link *link = userdata;
fe30727643a7c53faa29f1caa8dcabcb2b6f6fcbTom Gundersen usec_t time_now;
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen int r;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen assert(link);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen assert(link->network);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert(link->manager);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen if (flags & ND_RA_FLAG_MANAGED)
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen dhcp6_request_address(link);
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen r = sd_dhcp6_client_start(link->dhcp6_client);
63348d13fae61fefcb29133bfae8371b33cf4b6dTom Gundersen if (r < 0 && r != -EBUSY)
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m");
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (!gateway)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = route_new(&route);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_error_errno(link, r, "Could not allocate route: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->family = AF_INET6;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->table = RT_TABLE_MAIN;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->protocol = RTPROT_RA;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->pref = pref;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->gw.in6 = *gateway;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen route->lifetime = time_now + lifetime * USEC_PER_SEC;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = route_configure(route, link, ndisc_netlink_handler);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_link_warning_errno(link, r, "Could not set default route: %m");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen link_enter_failed(link);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen link->ndisc_messages ++;
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen}
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersenstatic void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen Link *link = userdata;
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen int r;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen assert(link);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen return;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen switch (event) {
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen case SD_NDISC_EVENT_TIMEOUT:
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen dhcp6_request_address(link);
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen r = sd_dhcp6_client_start(link->dhcp6_client);
63348d13fae61fefcb29133bfae8371b33cf4b6dTom Gundersen if (r < 0 && r != -EBUSY)
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m");
962b0647298b601548b049893931d2477f06ab57Tom Gundersen
962b0647298b601548b049893931d2477f06ab57Tom Gundersen link->ndisc_configured = true;
962b0647298b601548b049893931d2477f06ab57Tom Gundersen link_check_ready(link);
962b0647298b601548b049893931d2477f06ab57Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen break;
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen case SD_NDISC_EVENT_STOP:
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen break;
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen default:
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen }
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen}
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersenint ndisc_configure(Link *link) {
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen int r;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen assert_return(link, -EINVAL);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_ndisc_new(&link->ndisc_router_discovery);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (r < 0)
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return r;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_ndisc_attach_event(link->ndisc_router_discovery, NULL, 0);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (r < 0)
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return r;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_ndisc_set_mac(link->ndisc_router_discovery, &link->mac);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (r < 0)
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return r;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_ndisc_set_index(link->ndisc_router_discovery, link->ifindex);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (r < 0)
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return r;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_ndisc_set_callback(link->ndisc_router_discovery,
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen ndisc_router_handler,
fe30727643a7c53faa29f1caa8dcabcb2b6f6fcbTom Gundersen ndisc_prefix_onlink_handler,
fe30727643a7c53faa29f1caa8dcabcb2b6f6fcbTom Gundersen ndisc_prefix_autonomous_handler,
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen ndisc_handler,
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen link);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return r;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen}