networkd-dhcp6.c revision 85bd849f09aceb7f972a0697494ea22b2247a5d7
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering/***
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering This file is part of systemd.
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering Copyright (C) 2014 Intel Corporation. All rights reserved.
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering systemd is free software; you can redistribute it and/or modify it
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering under the terms of the GNU Lesser General Public License as published by
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering (at your option) any later version.
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering systemd is distributed in the hope that it will be useful, but
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering Lesser General Public License for more details.
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering You should have received a copy of the GNU Lesser General Public License
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering***/
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering#include <netinet/ether.h>
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering#include <linux/if.h>
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering#include "networkd-link.h"
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering#include "network-internal.h"
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering#include "sd-icmp6-nd.h"
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering#include "sd-dhcp6-client.h"
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering Link *link = userdata;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(link);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(link->network);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(link->manager);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering switch(event) {
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen case DHCP6_EVENT_STOP:
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering case DHCP6_EVENT_RESEND_EXPIRE:
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering case DHCP6_EVENT_RETRANS_MAX:
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen case DHCP6_EVENT_IP_ACQUIRE:
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering case DHCP6_EVENT_INFORMATION_REQUEST:
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering log_link_debug(link, "DHCPv6 event %d", event);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering break;
f52e61da047d7fc74e83f12dbbf87e0cbcc51c73Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering default:
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (event < 0)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering log_link_warning(link, "DHCPv6 error: %s",
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering strerror(-event));
6e0684729420912df019cc64d3f8a3c8290cc5f1Lennart Poettering else
6e0684729420912df019cc64d3f8a3c8290cc5f1Lennart Poettering log_link_warning(link, "DHCPv6 unknown event: %d",
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering event);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering}
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int dhcp6_configure(Link *link, int event) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering int r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering bool information_request;
4667e00a61c2f60922558bc5e33ac9d3073a482cLennart Poettering
4667e00a61c2f60922558bc5e33ac9d3073a482cLennart Poettering assert_return(link, -EINVAL);
d20b1667dbab8bccf69735523a0d5fc645e81b80Tom Gundersen
4667e00a61c2f60922558bc5e33ac9d3073a482cLennart Poettering if (link->dhcp6_client) {
8300ba218e3cf5049496937be8bce10f22d09bbcTom Gundersen if (event != ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED)
8300ba218e3cf5049496937be8bce10f22d09bbcTom Gundersen return 0;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = sd_dhcp6_client_get_information_request(link->dhcp6_client,
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering &information_request);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering if (r < 0) {
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering log_link_warning(link, "Could not get DHCPv6 Information request setting");
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering link->dhcp6_client =
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering sd_dhcp6_client_unref(link->dhcp6_client);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (!information_request)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering false);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering log_link_warning(link, "Could not unset DHCPv6 Information request");
f52e61da047d7fc74e83f12dbbf87e0cbcc51c73Lennart Poettering link->dhcp6_client =
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering sd_dhcp6_client_unref(link->dhcp6_client);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = sd_dhcp6_client_start(link->dhcp6_client);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering log_link_warning(link, "Could not restart DHCPv6 after enabling Information request");
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering link->dhcp6_client =
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering sd_dhcp6_client_unref(link->dhcp6_client);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
6e0684729420912df019cc64d3f8a3c8290cc5f1Lennart Poettering return r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
3b31df8301fd7dfb78bf9eaf9227d40c9bf12182Tom Gundersen r = sd_dhcp6_client_new(&link->dhcp6_client);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return r;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0) {
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
return r;
}
r = sd_dhcp6_client_set_mac(link->dhcp6_client,
(const uint8_t *) &link->mac,
sizeof (link->mac), ARPHRD_ETHER);
if (r < 0) {
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
return r;
}
r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
if (r < 0) {
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
return r;
}
r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
link);
if (r < 0) {
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
return r;
}
if (event == ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER) {
r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
true);
if (r < 0) {
link->dhcp6_client =
sd_dhcp6_client_unref(link->dhcp6_client);
return r;
}
}
r = sd_dhcp6_client_start(link->dhcp6_client);
if (r < 0)
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
return r;
}
static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
Link *link = userdata;
assert(link);
assert(link->network);
assert(link->manager);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return;
switch(event) {
case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE:
return;
case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER:
case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED:
break;
default:
if (event < 0)
log_link_warning(link, "ICMPv6 error: %s",
strerror(-event));
else
log_link_warning(link, "ICMPv6 unknown event: %d",
event);
return;
}
dhcp6_configure(link, event);
}
int icmp6_configure(Link *link) {
int r;
assert_return(link, -EINVAL);
r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
if (r < 0)
return r;
r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery, NULL, 0);
if (r < 0)
return r;
r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery, &link->mac);
if (r < 0)
return r;
r = sd_icmp6_nd_set_index(link->icmp6_router_discovery, link->ifindex);
if (r < 0)
return r;
r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery,
icmp6_router_handler, link);
return r;
}