Merge pull request #1625 from teg/ndisc
sd-ndisc: Rename (from sd-icmp6-nd) and prepare for handling SLAAC and router discovery
This commit is contained in:
+1
-1
@@ -195,7 +195,7 @@
|
||||
/test-hashmap
|
||||
/test-hostname
|
||||
/test-hostname-util
|
||||
/test-icmp6-rs
|
||||
/test-ndisc-rs
|
||||
/test-id128
|
||||
/test-inhibit
|
||||
/test-install
|
||||
|
||||
+11
-8
@@ -3214,7 +3214,7 @@ libsystemd_network_la_SOURCES = \
|
||||
src/systemd/sd-dhcp-lease.h \
|
||||
src/systemd/sd-ipv4ll.h \
|
||||
src/systemd/sd-ipv4acd.h \
|
||||
src/systemd/sd-icmp6-nd.h \
|
||||
src/systemd/sd-ndisc.h \
|
||||
src/systemd/sd-dhcp6-client.h \
|
||||
src/systemd/sd-dhcp6-lease.h \
|
||||
src/systemd/sd-pppoe.h \
|
||||
@@ -3236,7 +3236,9 @@ libsystemd_network_la_SOURCES = \
|
||||
src/libsystemd-network/sd-pppoe.c \
|
||||
src/libsystemd-network/network-internal.c \
|
||||
src/libsystemd-network/network-internal.h \
|
||||
src/libsystemd-network/sd-icmp6-nd.c \
|
||||
src/libsystemd-network/sd-ndisc.c \
|
||||
src/libsystemd-network/icmp6-util.h \
|
||||
src/libsystemd-network/icmp6-util.c \
|
||||
src/libsystemd-network/sd-dhcp6-client.c \
|
||||
src/libsystemd-network/dhcp6-internal.h \
|
||||
src/libsystemd-network/dhcp6-protocol.h \
|
||||
@@ -3320,15 +3322,15 @@ test_pppoe_LDADD = \
|
||||
libsystemd-network.la \
|
||||
libshared.la
|
||||
|
||||
test_icmp6_rs_SOURCES = \
|
||||
test_ndisc_rs_SOURCES = \
|
||||
src/systemd/sd-dhcp6-client.h \
|
||||
src/systemd/sd-icmp6-nd.h \
|
||||
src/libsystemd-network/dhcp6-internal.h \
|
||||
src/libsystemd-network/test-icmp6-rs.c \
|
||||
src/systemd/sd-ndisc.h \
|
||||
src/libsystemd-network/icmp6-util.h \
|
||||
src/libsystemd-network/test-ndisc-rs.c \
|
||||
src/libsystemd-network/dhcp-identifier.h \
|
||||
src/libsystemd-network/dhcp-identifier.c
|
||||
|
||||
test_icmp6_rs_LDADD = \
|
||||
test_ndisc_rs_LDADD = \
|
||||
libsystemd-network.la \
|
||||
libudev.la \
|
||||
libshared.la
|
||||
@@ -3360,7 +3362,7 @@ tests += \
|
||||
test-dhcp-client \
|
||||
test-dhcp-server \
|
||||
test-ipv4ll \
|
||||
test-icmp6-rs \
|
||||
test-ndisc-rs \
|
||||
test-dhcp6-client \
|
||||
test-lldp
|
||||
|
||||
@@ -5230,6 +5232,7 @@ libnetworkd_core_la_SOURCES = \
|
||||
src/network/networkd-ipv4ll.c \
|
||||
src/network/networkd-dhcp4.c \
|
||||
src/network/networkd-dhcp6.c \
|
||||
src/network/networkd-ndisc.c \
|
||||
src/network/networkd-network.h \
|
||||
src/network/networkd-network.c \
|
||||
src/network/networkd-network-bus.c \
|
||||
|
||||
@@ -58,9 +58,6 @@ typedef struct DHCP6IA DHCP6IA;
|
||||
|
||||
#define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
|
||||
|
||||
int dhcp_network_icmp6_bind_router_solicitation(int index);
|
||||
int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
|
||||
|
||||
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
|
||||
size_t optlen, const void *optval);
|
||||
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia);
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
@@ -33,102 +32,6 @@
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
|
||||
#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
|
||||
{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
|
||||
|
||||
#define IN6ADDR_ALL_NODES_MULTICAST_INIT \
|
||||
{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
|
||||
|
||||
int dhcp_network_icmp6_bind_router_solicitation(int index) {
|
||||
struct icmp6_filter filter = { };
|
||||
struct ipv6_mreq mreq = {
|
||||
.ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
|
||||
.ipv6mr_interface = index,
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r, zero = 0, hops = 255;
|
||||
|
||||
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
IPPROTO_ICMPV6);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
|
||||
r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
|
||||
sizeof(filter));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
/* RFC 3315, section 6.7, bullet point 2 may indicate that an
|
||||
IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
|
||||
Empirical experiments indicates otherwise and therefore an
|
||||
IPV6_MULTICAST_IF socket option is used here instead */
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
|
||||
sizeof(index));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
|
||||
sizeof(zero));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
|
||||
sizeof(hops));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
|
||||
sizeof(mreq));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = s;
|
||||
s = -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
|
||||
struct sockaddr_in6 dst = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
|
||||
};
|
||||
struct {
|
||||
struct nd_router_solicit rs;
|
||||
struct nd_opt_hdr rs_opt;
|
||||
struct ether_addr rs_opt_mac;
|
||||
} _packed_ rs = {
|
||||
.rs.nd_rs_type = ND_ROUTER_SOLICIT,
|
||||
};
|
||||
struct iovec iov[1] = {
|
||||
{ &rs, },
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_name = &dst,
|
||||
.msg_namelen = sizeof(dst),
|
||||
.msg_iov = iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
int r;
|
||||
|
||||
if (ether_addr) {
|
||||
memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
|
||||
rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
|
||||
rs.rs_opt.nd_opt_len = 1;
|
||||
iov[0].iov_len = sizeof(rs);
|
||||
} else
|
||||
iov[0].iov_len = sizeof(rs.rs);
|
||||
|
||||
r = sendmsg(s, &msg, 0);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
|
||||
struct in6_pktinfo pktinfo = {
|
||||
.ipi6_ifindex = index,
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
|
||||
#include "icmp6-util.h"
|
||||
|
||||
#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
|
||||
{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
|
||||
|
||||
#define IN6ADDR_ALL_NODES_MULTICAST_INIT \
|
||||
{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
|
||||
|
||||
int icmp6_bind_router_solicitation(int index) {
|
||||
struct icmp6_filter filter = { };
|
||||
struct ipv6_mreq mreq = {
|
||||
.ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
|
||||
.ipv6mr_interface = index,
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r, zero = 0, hops = 255;
|
||||
|
||||
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
IPPROTO_ICMPV6);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
|
||||
r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
|
||||
sizeof(filter));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
/* RFC 3315, section 6.7, bullet point 2 may indicate that an
|
||||
IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
|
||||
Empirical experiments indicates otherwise and therefore an
|
||||
IPV6_MULTICAST_IF socket option is used here instead */
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
|
||||
sizeof(index));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
|
||||
sizeof(zero));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
|
||||
sizeof(hops));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
|
||||
sizeof(mreq));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = s;
|
||||
s = -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
|
||||
struct sockaddr_in6 dst = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
|
||||
};
|
||||
struct {
|
||||
struct nd_router_solicit rs;
|
||||
struct nd_opt_hdr rs_opt;
|
||||
struct ether_addr rs_opt_mac;
|
||||
} _packed_ rs = {
|
||||
.rs.nd_rs_type = ND_ROUTER_SOLICIT,
|
||||
};
|
||||
struct iovec iov[1] = {
|
||||
{ &rs, },
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_name = &dst,
|
||||
.msg_namelen = sizeof(dst),
|
||||
.msg_iov = iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
int r;
|
||||
|
||||
if (ether_addr) {
|
||||
memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
|
||||
rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
|
||||
rs.rs_opt.nd_opt_len = 1;
|
||||
iov[0].iov_len = sizeof(rs);
|
||||
} else
|
||||
iov[0].iov_len = sizeof(rs.rs);
|
||||
|
||||
r = sendmsg(s, &msg, 0);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/ethernet.h>
|
||||
|
||||
int icmp6_bind_router_solicitation(int index);
|
||||
int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "conf-parser.h"
|
||||
#include "condition.h"
|
||||
#include "network-internal.h"
|
||||
#include "sd-icmp6-nd.h"
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
const char *net_get_name(struct udev_device *device) {
|
||||
const char *name, *field;
|
||||
@@ -390,8 +390,8 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
|
||||
assert(size);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
fprintf(f, SD_ICMP6_ND_ADDRESS_FORMAT_STR"%s",
|
||||
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addresses[i]),
|
||||
fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s",
|
||||
SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]),
|
||||
(i < (size - 1)) ? " ": "");
|
||||
}
|
||||
|
||||
|
||||
@@ -24,59 +24,63 @@
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
#include "async.h"
|
||||
#include "list.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
#include "dhcp6-internal.h"
|
||||
#include "sd-icmp6-nd.h"
|
||||
#include "icmp6-util.h"
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
#define ICMP6_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC
|
||||
#define ICMP6_MAX_ROUTER_SOLICITATIONS 3
|
||||
#define NDISC_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC
|
||||
#define NDISC_MAX_ROUTER_SOLICITATIONS 3
|
||||
|
||||
enum icmp6_nd_state {
|
||||
ICMP6_NEIGHBOR_DISCOVERY_IDLE = 0,
|
||||
ICMP6_ROUTER_SOLICITATION_SENT = 10,
|
||||
ICMP6_ROUTER_ADVERTISMENT_LISTEN = 11,
|
||||
enum NDiscState {
|
||||
NDISC_STATE_IDLE,
|
||||
NDISC_STATE_SOLICITATION_SENT,
|
||||
NDISC_STATE_ADVERTISMENT_LISTEN,
|
||||
_NDISC_STATE_MAX,
|
||||
_NDISC_STATE_INVALID = -1,
|
||||
};
|
||||
|
||||
#define IP6_MIN_MTU (unsigned)1280
|
||||
#define ICMP6_ND_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr))
|
||||
#define ICMP6_OPT_LEN_UNITS 8
|
||||
#define ICMP6_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr))
|
||||
#define NDISC_OPT_LEN_UNITS 8
|
||||
|
||||
typedef struct ICMP6Prefix ICMP6Prefix;
|
||||
typedef struct NDiscPrefix NDiscPrefix;
|
||||
|
||||
struct ICMP6Prefix {
|
||||
struct NDiscPrefix {
|
||||
unsigned n_ref;
|
||||
|
||||
LIST_FIELDS(ICMP6Prefix, prefixes);
|
||||
sd_ndisc *nd;
|
||||
|
||||
LIST_FIELDS(NDiscPrefix, prefixes);
|
||||
|
||||
uint8_t len;
|
||||
sd_event_source *timeout_valid;
|
||||
usec_t valid_until;
|
||||
struct in6_addr addr;
|
||||
};
|
||||
|
||||
struct sd_icmp6_nd {
|
||||
struct sd_ndisc {
|
||||
unsigned n_ref;
|
||||
|
||||
enum icmp6_nd_state state;
|
||||
enum NDiscState state;
|
||||
sd_event *event;
|
||||
int event_priority;
|
||||
int index;
|
||||
struct ether_addr mac_addr;
|
||||
uint32_t mtu;
|
||||
ICMP6Prefix *expired_prefix;
|
||||
LIST_HEAD(ICMP6Prefix, prefixes);
|
||||
LIST_HEAD(NDiscPrefix, prefixes);
|
||||
int fd;
|
||||
sd_event_source *recv;
|
||||
sd_event_source *timeout;
|
||||
int nd_sent;
|
||||
sd_icmp6_nd_callback_t callback;
|
||||
sd_ndisc_callback_t callback;
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
#define log_icmp6_nd(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "ICMPv6 CLIENT: " fmt, ##__VA_ARGS__)
|
||||
#define log_ndisc(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__)
|
||||
|
||||
static ICMP6Prefix *icmp6_prefix_unref(ICMP6Prefix *prefix) {
|
||||
static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) {
|
||||
|
||||
if (!prefix)
|
||||
return NULL;
|
||||
@@ -87,22 +91,26 @@ static ICMP6Prefix *icmp6_prefix_unref(ICMP6Prefix *prefix) {
|
||||
if (prefix->n_ref > 0)
|
||||
return NULL;
|
||||
|
||||
prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid);
|
||||
if (prefix->nd)
|
||||
LIST_REMOVE(prefixes, prefix->nd->prefixes, prefix);
|
||||
|
||||
free(prefix);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int icmp6_prefix_new(ICMP6Prefix **ret) {
|
||||
_cleanup_free_ ICMP6Prefix *prefix = NULL;
|
||||
static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) {
|
||||
_cleanup_free_ NDiscPrefix *prefix = NULL;
|
||||
|
||||
assert(ret);
|
||||
|
||||
prefix = new0(ICMP6Prefix, 1);
|
||||
prefix = new0(NDiscPrefix, 1);
|
||||
if (!prefix)
|
||||
return -ENOMEM;
|
||||
|
||||
prefix->n_ref = 1;
|
||||
LIST_INIT(prefixes, prefix);
|
||||
prefix->nd = nd;
|
||||
|
||||
*ret = prefix;
|
||||
prefix = NULL;
|
||||
@@ -110,12 +118,12 @@ static int icmp6_prefix_new(ICMP6Prefix **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void icmp6_nd_notify(sd_icmp6_nd *nd, int event) {
|
||||
static void ndisc_notify(sd_ndisc *nd, int event) {
|
||||
if (nd->callback)
|
||||
nd->callback(nd, event, nd->userdata);
|
||||
}
|
||||
|
||||
int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t callback,
|
||||
int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t callback,
|
||||
void *userdata) {
|
||||
assert(nd);
|
||||
|
||||
@@ -125,7 +133,7 @@ int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t callback,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index) {
|
||||
int sd_ndisc_set_index(sd_ndisc *nd, int interface_index) {
|
||||
assert(nd);
|
||||
assert(interface_index >= -1);
|
||||
|
||||
@@ -134,7 +142,7 @@ int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr) {
|
||||
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) {
|
||||
assert(nd);
|
||||
|
||||
if (mac_addr)
|
||||
@@ -146,7 +154,7 @@ int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr) {
|
||||
|
||||
}
|
||||
|
||||
int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority) {
|
||||
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority) {
|
||||
int r;
|
||||
|
||||
assert_return(nd, -EINVAL);
|
||||
@@ -165,7 +173,7 @@ int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd) {
|
||||
int sd_ndisc_detach_event(sd_ndisc *nd) {
|
||||
assert_return(nd, -EINVAL);
|
||||
|
||||
nd->event = sd_event_unref(nd->event);
|
||||
@@ -173,13 +181,13 @@ int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd) {
|
||||
sd_event *sd_ndisc_get_event(sd_ndisc *nd) {
|
||||
assert(nd);
|
||||
|
||||
return nd->event;
|
||||
}
|
||||
|
||||
sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd) {
|
||||
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) {
|
||||
|
||||
if (!nd)
|
||||
return NULL;
|
||||
@@ -190,7 +198,7 @@ sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd) {
|
||||
return nd;
|
||||
}
|
||||
|
||||
static int icmp6_nd_init(sd_icmp6_nd *nd) {
|
||||
static int ndisc_init(sd_ndisc *nd) {
|
||||
assert(nd);
|
||||
|
||||
nd->recv = sd_event_source_unref(nd->recv);
|
||||
@@ -200,8 +208,8 @@ static int icmp6_nd_init(sd_icmp6_nd *nd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd) {
|
||||
ICMP6Prefix *prefix, *p;
|
||||
sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) {
|
||||
NDiscPrefix *prefix, *p;
|
||||
|
||||
if (!nd)
|
||||
return NULL;
|
||||
@@ -212,29 +220,26 @@ sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd) {
|
||||
if (nd->n_ref > 0)
|
||||
return NULL;
|
||||
|
||||
icmp6_nd_init(nd);
|
||||
sd_icmp6_nd_detach_event(nd);
|
||||
ndisc_init(nd);
|
||||
sd_ndisc_detach_event(nd);
|
||||
|
||||
LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) {
|
||||
LIST_REMOVE(prefixes, nd->prefixes, prefix);
|
||||
|
||||
prefix = icmp6_prefix_unref(prefix);
|
||||
}
|
||||
LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes)
|
||||
prefix = ndisc_prefix_unref(prefix);
|
||||
|
||||
free(nd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_icmp6_nd*, sd_icmp6_nd_unref);
|
||||
#define _cleanup_sd_icmp6_nd_free_ _cleanup_(sd_icmp6_nd_unrefp)
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ndisc*, sd_ndisc_unref);
|
||||
#define _cleanup_sd_ndisc_free_ _cleanup_(sd_ndisc_unrefp)
|
||||
|
||||
int sd_icmp6_nd_new(sd_icmp6_nd **ret) {
|
||||
_cleanup_sd_icmp6_nd_free_ sd_icmp6_nd *nd = NULL;
|
||||
int sd_ndisc_new(sd_ndisc **ret) {
|
||||
_cleanup_sd_ndisc_free_ sd_ndisc *nd = NULL;
|
||||
|
||||
assert(ret);
|
||||
|
||||
nd = new0(sd_icmp6_nd, 1);
|
||||
nd = new0(sd_ndisc, 1);
|
||||
if (!nd)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -251,7 +256,7 @@ int sd_icmp6_nd_new(sd_icmp6_nd **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu) {
|
||||
int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) {
|
||||
assert_return(nd, -EINVAL);
|
||||
assert_return(mtu, -EINVAL);
|
||||
|
||||
@@ -263,75 +268,9 @@ int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icmp6_ra_prefix_timeout(sd_event_source *s, uint64_t usec,
|
||||
void *userdata) {
|
||||
sd_icmp6_nd *nd = userdata;
|
||||
ICMP6Prefix *prefix, *p;
|
||||
|
||||
assert(nd);
|
||||
|
||||
LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) {
|
||||
if (prefix->timeout_valid != s)
|
||||
continue;
|
||||
|
||||
log_icmp6_nd(nd, "Prefix expired "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d",
|
||||
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
|
||||
prefix->len);
|
||||
|
||||
LIST_REMOVE(prefixes, nd->prefixes, prefix);
|
||||
|
||||
nd->expired_prefix = prefix;
|
||||
icmp6_nd_notify(nd,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED);
|
||||
nd->expired_prefix = NULL;
|
||||
|
||||
prefix = icmp6_prefix_unref(prefix);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icmp6_ra_prefix_set_timeout(sd_icmp6_nd *nd,
|
||||
ICMP6Prefix *prefix,
|
||||
usec_t valid) {
|
||||
usec_t time_now;
|
||||
int r;
|
||||
|
||||
assert_return(prefix, -EINVAL);
|
||||
|
||||
r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid);
|
||||
|
||||
r = sd_event_add_time(nd->event, &prefix->timeout_valid,
|
||||
clock_boottime_or_monotonic(), time_now + valid,
|
||||
USEC_PER_SEC, icmp6_ra_prefix_timeout, nd);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_priority(prefix->timeout_valid,
|
||||
nd->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_description(prefix->timeout_valid,
|
||||
"icmp6-prefix-timeout");
|
||||
|
||||
error:
|
||||
if (r < 0)
|
||||
prefix->timeout_valid =
|
||||
sd_event_source_unref(prefix->timeout_valid);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int icmp6_prefix_match(const struct in6_addr *prefix, uint8_t prefixlen,
|
||||
const struct in6_addr *addr,
|
||||
uint8_t addr_prefixlen) {
|
||||
static int prefix_match(const struct in6_addr *prefix, uint8_t prefixlen,
|
||||
const struct in6_addr *addr,
|
||||
uint8_t addr_prefixlen) {
|
||||
uint8_t bytes, mask, len;
|
||||
|
||||
assert_return(prefix, -EINVAL);
|
||||
@@ -349,13 +288,26 @@ static int icmp6_prefix_match(const struct in6_addr *prefix, uint8_t prefixlen,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icmp6_ra_prefix_match(ICMP6Prefix *head, const struct in6_addr *addr,
|
||||
uint8_t addr_len, ICMP6Prefix **result) {
|
||||
ICMP6Prefix *prefix;
|
||||
static int ndisc_prefix_match(sd_ndisc *nd, const struct in6_addr *addr,
|
||||
uint8_t addr_len, NDiscPrefix **result) {
|
||||
NDiscPrefix *prefix, *p;
|
||||
usec_t time_now;
|
||||
int r;
|
||||
|
||||
LIST_FOREACH(prefixes, prefix, head) {
|
||||
if (icmp6_prefix_match(&prefix->addr, prefix->len, addr,
|
||||
addr_len) >= 0) {
|
||||
assert(nd);
|
||||
|
||||
r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) {
|
||||
if (prefix->valid_until < time_now) {
|
||||
prefix = ndisc_prefix_unref(prefix);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prefix_match(&prefix->addr, prefix->len, addr, addr_len) >= 0) {
|
||||
*result = prefix;
|
||||
return 0;
|
||||
}
|
||||
@@ -364,54 +316,16 @@ static int icmp6_ra_prefix_match(ICMP6Prefix *head, const struct in6_addr *addr,
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen,
|
||||
struct in6_addr *addr) {
|
||||
return icmp6_prefix_match(prefix, prefixlen, addr,
|
||||
sizeof(addr->s6_addr) * 8);
|
||||
}
|
||||
|
||||
int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr,
|
||||
uint8_t *prefixlen) {
|
||||
int r;
|
||||
ICMP6Prefix *prefix;
|
||||
|
||||
assert_return(nd, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert_return(prefixlen, -EINVAL);
|
||||
|
||||
r = icmp6_ra_prefix_match(nd->prefixes, addr,
|
||||
sizeof(addr->s6_addr) * 8, &prefix);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*prefixlen = prefix->len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr, uint8_t *prefixlen) {
|
||||
assert_return(nd, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert_return(prefixlen, -EINVAL);
|
||||
|
||||
if (!nd->expired_prefix)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
*addr = &nd->expired_prefix->addr;
|
||||
*prefixlen = nd->expired_prefix->len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
|
||||
const struct nd_opt_prefix_info *prefix_opt) {
|
||||
int r;
|
||||
ICMP6Prefix *prefix;
|
||||
static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len,
|
||||
const struct nd_opt_prefix_info *prefix_opt) {
|
||||
NDiscPrefix *prefix;
|
||||
uint32_t lifetime;
|
||||
usec_t time_now;
|
||||
char time_string[FORMAT_TIMESPAN_MAX];
|
||||
int r;
|
||||
|
||||
assert_return(nd, -EINVAL);
|
||||
assert_return(prefix_opt, -EINVAL);
|
||||
assert(nd);
|
||||
assert(prefix_opt);
|
||||
|
||||
if (len < prefix_opt->nd_opt_pi_len)
|
||||
return -ENOMSG;
|
||||
@@ -421,9 +335,8 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
|
||||
|
||||
lifetime = be32toh(prefix_opt->nd_opt_pi_valid_time);
|
||||
|
||||
r = icmp6_ra_prefix_match(nd->prefixes,
|
||||
&prefix_opt->nd_opt_pi_prefix,
|
||||
prefix_opt->nd_opt_pi_prefix_len, &prefix);
|
||||
r = ndisc_prefix_match(nd, &prefix_opt->nd_opt_pi_prefix,
|
||||
prefix_opt->nd_opt_pi_prefix_len, &prefix);
|
||||
|
||||
if (r < 0 && r != -EADDRNOTAVAIL)
|
||||
return r;
|
||||
@@ -432,7 +345,7 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
|
||||
callback will be called immediately to clean up the prefix */
|
||||
|
||||
if (r == -EADDRNOTAVAIL) {
|
||||
r = icmp6_prefix_new(&prefix);
|
||||
r = ndisc_prefix_new(nd, &prefix);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -441,8 +354,8 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
|
||||
memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix,
|
||||
sizeof(prefix->addr));
|
||||
|
||||
log_icmp6_nd(nd, "New prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
|
||||
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
|
||||
log_ndisc(nd, "New prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
|
||||
SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr),
|
||||
prefix->len, lifetime,
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime * USEC_PER_SEC, USEC_PER_SEC));
|
||||
|
||||
@@ -454,7 +367,7 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
|
||||
|
||||
prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len);
|
||||
|
||||
log_icmp6_nd(nd, "Prefix length mismatch %d/%d using %d",
|
||||
log_ndisc(nd, "Prefix length mismatch %d/%d using %d",
|
||||
prefix->len,
|
||||
prefix_opt->nd_opt_pi_prefix_len,
|
||||
prefixlen);
|
||||
@@ -462,18 +375,22 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
|
||||
prefix->len = prefixlen;
|
||||
}
|
||||
|
||||
log_icmp6_nd(nd, "Update prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
|
||||
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
|
||||
log_ndisc(nd, "Update prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
|
||||
SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr),
|
||||
prefix->len, lifetime,
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime * USEC_PER_SEC, USEC_PER_SEC));
|
||||
}
|
||||
|
||||
r = icmp6_ra_prefix_set_timeout(nd, prefix, lifetime * USEC_PER_SEC);
|
||||
r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
prefix->valid_until = time_now + lifetime * USEC_PER_SEC;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
|
||||
static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra,
|
||||
ssize_t len) {
|
||||
void *opt;
|
||||
struct nd_opt_hdr *opt_hdr;
|
||||
@@ -482,8 +399,8 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
|
||||
assert_return(ra, -EINVAL);
|
||||
|
||||
len -= sizeof(*ra);
|
||||
if (len < ICMP6_OPT_LEN_UNITS) {
|
||||
log_icmp6_nd(nd, "Router Advertisement below minimum length");
|
||||
if (len < NDISC_OPT_LEN_UNITS) {
|
||||
log_ndisc(nd, "Router Advertisement below minimum length");
|
||||
|
||||
return -ENOMSG;
|
||||
}
|
||||
@@ -491,7 +408,7 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
|
||||
opt = ra + 1;
|
||||
opt_hdr = opt;
|
||||
|
||||
while (len != 0 && len >= opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS) {
|
||||
while (len != 0 && len >= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS) {
|
||||
struct nd_opt_mtu *opt_mtu;
|
||||
uint32_t mtu;
|
||||
struct nd_opt_prefix_info *opt_prefix;
|
||||
@@ -508,7 +425,7 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
|
||||
if (mtu != nd->mtu) {
|
||||
nd->mtu = MAX(mtu, IP6_MIN_MTU);
|
||||
|
||||
log_icmp6_nd(nd, "Router Advertisement link MTU %d using %d",
|
||||
log_ndisc(nd, "Router Advertisement link MTU %d using %d",
|
||||
mtu, nd->mtu);
|
||||
}
|
||||
|
||||
@@ -517,29 +434,29 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
|
||||
case ND_OPT_PREFIX_INFORMATION:
|
||||
opt_prefix = opt;
|
||||
|
||||
icmp6_ra_prefix_update(nd, len, opt_prefix);
|
||||
ndisc_prefix_update(nd, len, opt_prefix);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
len -= opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS;
|
||||
len -= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS;
|
||||
opt = (void *)((char *)opt +
|
||||
opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS);
|
||||
opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS);
|
||||
opt_hdr = opt;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
log_icmp6_nd(nd, "Router Advertisement contains %zd bytes of trailing garbage", len);
|
||||
log_ndisc(nd, "Router Advertisement contains %zd bytes of trailing garbage", len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
sd_icmp6_nd *nd = userdata;
|
||||
static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
sd_ndisc *nd = userdata;
|
||||
int r, buflen = 0;
|
||||
ssize_t len;
|
||||
_cleanup_free_ struct nd_router_advert *ra = NULL;
|
||||
int event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE;
|
||||
int event = SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE;
|
||||
|
||||
assert(s);
|
||||
assert(nd);
|
||||
@@ -547,7 +464,7 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
|
||||
|
||||
r = ioctl(fd, FIONREAD, &buflen);
|
||||
if (r < 0 || buflen <= 0)
|
||||
buflen = ICMP6_ND_RECV_SIZE;
|
||||
buflen = ICMP6_RECV_SIZE;
|
||||
|
||||
ra = malloc(buflen);
|
||||
if (!ra)
|
||||
@@ -555,7 +472,7 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
|
||||
|
||||
len = read(fd, ra, buflen);
|
||||
if (len < 0) {
|
||||
log_icmp6_nd(nd, "Could not receive message from UDP socket: %m");
|
||||
log_ndisc(nd, "Could not receive message from UDP socket: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -567,34 +484,34 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
|
||||
|
||||
nd->timeout = sd_event_source_unref(nd->timeout);
|
||||
|
||||
nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN;
|
||||
nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
|
||||
|
||||
if (ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER )
|
||||
event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER;
|
||||
event = SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER;
|
||||
|
||||
if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
|
||||
event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED;
|
||||
event = SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED;
|
||||
|
||||
log_icmp6_nd(nd, "Received Router Advertisement flags %s/%s",
|
||||
log_ndisc(nd, "Received Router Advertisement flags %s/%s",
|
||||
ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED? "MANAGED": "none",
|
||||
ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER? "OTHER": "none");
|
||||
|
||||
if (event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE) {
|
||||
r = icmp6_ra_parse(nd, ra, len);
|
||||
if (event != SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE) {
|
||||
r = ndisc_ra_parse(nd, ra, len);
|
||||
if (r < 0) {
|
||||
log_icmp6_nd(nd, "Could not parse Router Advertisement: %s",
|
||||
log_ndisc(nd, "Could not parse Router Advertisement: %s",
|
||||
strerror(-r));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
icmp6_nd_notify(nd, event);
|
||||
ndisc_notify(nd, event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
sd_icmp6_nd *nd = userdata;
|
||||
static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
sd_ndisc *nd = userdata;
|
||||
uint64_t time_now, next_timeout;
|
||||
struct ether_addr unset = { };
|
||||
struct ether_addr *addr = NULL;
|
||||
@@ -606,89 +523,80 @@ static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
|
||||
|
||||
nd->timeout = sd_event_source_unref(nd->timeout);
|
||||
|
||||
if (nd->nd_sent >= ICMP6_MAX_ROUTER_SOLICITATIONS) {
|
||||
icmp6_nd_notify(nd, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT);
|
||||
nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN;
|
||||
if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) {
|
||||
ndisc_notify(nd, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT);
|
||||
nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
|
||||
} else {
|
||||
if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr)))
|
||||
addr = &nd->mac_addr;
|
||||
|
||||
r = dhcp_network_icmp6_send_router_solicitation(nd->fd, addr);
|
||||
r = icmp6_send_router_solicitation(nd->fd, addr);
|
||||
if (r < 0)
|
||||
log_icmp6_nd(nd, "Error sending Router Solicitation");
|
||||
log_ndisc(nd, "Error sending Router Solicitation");
|
||||
else {
|
||||
nd->state = ICMP6_ROUTER_SOLICITATION_SENT;
|
||||
log_icmp6_nd(nd, "Sent Router Solicitation");
|
||||
nd->state = NDISC_STATE_SOLICITATION_SENT;
|
||||
log_ndisc(nd, "Sent Router Solicitation");
|
||||
}
|
||||
|
||||
nd->nd_sent++;
|
||||
|
||||
r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
|
||||
if (r < 0) {
|
||||
icmp6_nd_notify(nd, r);
|
||||
return 0;
|
||||
}
|
||||
assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
|
||||
|
||||
next_timeout = time_now + ICMP6_ROUTER_SOLICITATION_INTERVAL;
|
||||
next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL;
|
||||
|
||||
r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
|
||||
next_timeout, 0,
|
||||
icmp6_router_solicitation_timeout, nd);
|
||||
ndisc_router_solicitation_timeout, nd);
|
||||
if (r < 0) {
|
||||
icmp6_nd_notify(nd, r);
|
||||
ndisc_notify(nd, r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_event_source_set_priority(nd->timeout,
|
||||
nd->event_priority);
|
||||
if (r < 0) {
|
||||
icmp6_nd_notify(nd, r);
|
||||
r = sd_event_source_set_priority(nd->timeout, nd->event_priority);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_event_source_set_description(nd->timeout, "icmp6-timeout");
|
||||
if (r < 0) {
|
||||
icmp6_nd_notify(nd, r);
|
||||
r = sd_event_source_set_description(nd->timeout, "ndisc-timeout");
|
||||
if (r < 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_icmp6_nd_stop(sd_icmp6_nd *nd) {
|
||||
int sd_ndisc_stop(sd_ndisc *nd) {
|
||||
assert_return(nd, -EINVAL);
|
||||
assert_return(nd->event, -EINVAL);
|
||||
|
||||
log_icmp6_nd(client, "Stop ICMPv6");
|
||||
log_ndisc(client, "Stop NDisc");
|
||||
|
||||
icmp6_nd_init(nd);
|
||||
ndisc_init(nd);
|
||||
|
||||
nd->state = ICMP6_NEIGHBOR_DISCOVERY_IDLE;
|
||||
nd->state = NDISC_STATE_IDLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
|
||||
int sd_ndisc_router_discovery_start(sd_ndisc *nd) {
|
||||
int r;
|
||||
|
||||
assert(nd);
|
||||
assert(nd->event);
|
||||
|
||||
if (nd->state != ICMP6_NEIGHBOR_DISCOVERY_IDLE)
|
||||
if (nd->state != NDISC_STATE_IDLE)
|
||||
return -EINVAL;
|
||||
|
||||
if (nd->index < 1)
|
||||
return -EINVAL;
|
||||
|
||||
r = dhcp_network_icmp6_bind_router_solicitation(nd->index);
|
||||
r = icmp6_bind_router_solicitation(nd->index);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
nd->fd = r;
|
||||
|
||||
r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN,
|
||||
icmp6_router_advertisment_recv, nd);
|
||||
ndisc_router_advertisment_recv, nd);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
@@ -696,12 +604,12 @@ int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_description(nd->recv, "icmp6-receive-message");
|
||||
r = sd_event_source_set_description(nd->recv, "ndisc-receive-message");
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
|
||||
0, 0, icmp6_router_solicitation_timeout, nd);
|
||||
0, 0, ndisc_router_solicitation_timeout, nd);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
@@ -709,12 +617,12 @@ int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_description(nd->timeout, "icmp6-timeout");
|
||||
r = sd_event_source_set_description(nd->timeout, "ndisc-timeout");
|
||||
error:
|
||||
if (r < 0)
|
||||
icmp6_nd_init(nd);
|
||||
ndisc_init(nd);
|
||||
else
|
||||
log_icmp6_nd(client, "Start Router Solicitation");
|
||||
log_ndisc(client, "Start Router Solicitation");
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1,357 +0,0 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
|
||||
#include "dhcp6-internal.h"
|
||||
#include "sd-icmp6-nd.h"
|
||||
|
||||
static struct ether_addr mac_addr = {
|
||||
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
|
||||
};
|
||||
|
||||
static bool verbose = false;
|
||||
static sd_event_source *test_hangcheck;
|
||||
static int test_fd[2];
|
||||
|
||||
typedef int (*send_ra_t)(uint8_t flags);
|
||||
static send_ra_t send_ra_function;
|
||||
|
||||
static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
|
||||
void *userdata) {
|
||||
assert_se(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_network_icmp6_bind_router_solicitation(int index) {
|
||||
assert_se(index == 42);
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
|
||||
return -errno;
|
||||
|
||||
return test_fd[0];
|
||||
}
|
||||
|
||||
static int send_ra_short_prefix(uint8_t flags) {
|
||||
uint8_t advertisement[] = {
|
||||
0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x03, 0x04, 0x34, 0xc0, 0x00, 0x00, 0x01, 0xf4,
|
||||
0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
|
||||
sizeof(advertisement));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_short_prefix_cb(sd_icmp6_nd *nd, int event, void *userdata) {
|
||||
sd_event *e = userdata;
|
||||
struct {
|
||||
struct in6_addr addr;
|
||||
uint8_t prefixlen;
|
||||
bool success;
|
||||
} addrs[] = {
|
||||
{ { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
|
||||
52, true },
|
||||
{ { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
|
||||
64, false },
|
||||
{ { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
|
||||
60, true },
|
||||
{ { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
|
||||
64, true },
|
||||
{ { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
|
||||
52, true },
|
||||
};
|
||||
uint8_t prefixlen;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(addrs); i++) {
|
||||
printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
__FUNCTION__,
|
||||
addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1],
|
||||
addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3],
|
||||
addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5],
|
||||
addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]);
|
||||
|
||||
if (addrs[i].success) {
|
||||
assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
|
||||
&prefixlen) >= 0);
|
||||
assert_se(addrs[i].prefixlen == prefixlen);
|
||||
printf("/%d onlink\n", prefixlen);
|
||||
} else {
|
||||
assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
|
||||
&prefixlen) == -EADDRNOTAVAIL);
|
||||
printf("/128 offlink\n");
|
||||
}
|
||||
}
|
||||
|
||||
sd_event_exit(e, 0);
|
||||
}
|
||||
|
||||
static int send_ra_prefixes(uint8_t flags) {
|
||||
uint8_t advertisement[] = {
|
||||
0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x04, 0x3f, 0xc0, 0x00, 0x00, 0x01, 0xf4,
|
||||
0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x04, 0x40, 0x00, 0x00, 0x00, 0x02, 0x58,
|
||||
0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x04, 0x3c, 0x80, 0x00, 0x00, 0x03, 0x84,
|
||||
0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x03, 0x84,
|
||||
0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
|
||||
0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53
|
||||
};
|
||||
|
||||
assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
|
||||
sizeof(advertisement));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_prefixes_cb(sd_icmp6_nd *nd, int event, void *userdata) {
|
||||
sd_event *e = userdata;
|
||||
struct {
|
||||
struct in6_addr addr;
|
||||
uint8_t prefixlen;
|
||||
bool success;
|
||||
} addrs[] = {
|
||||
{ { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
|
||||
63, true },
|
||||
{ { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
|
||||
64, false },
|
||||
{ { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
|
||||
60, true },
|
||||
{ { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
|
||||
64, true },
|
||||
{ { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
|
||||
63, false },
|
||||
};
|
||||
uint8_t prefixlen;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(addrs); i++) {
|
||||
printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
__FUNCTION__,
|
||||
addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1],
|
||||
addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3],
|
||||
addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5],
|
||||
addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]);
|
||||
|
||||
if (addrs[i].success) {
|
||||
assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
|
||||
&prefixlen) >= 0);
|
||||
assert_se(addrs[i].prefixlen == prefixlen);
|
||||
printf("/%d onlink\n", prefixlen);
|
||||
} else {
|
||||
assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
|
||||
&prefixlen) == -EADDRNOTAVAIL);
|
||||
printf("/128 offlink\n");
|
||||
}
|
||||
}
|
||||
|
||||
send_ra_function = send_ra_short_prefix;
|
||||
assert_se(sd_icmp6_nd_set_callback(nd, test_short_prefix_cb, e) >= 0);
|
||||
assert_se(sd_icmp6_nd_stop(nd) >= 0);
|
||||
assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
|
||||
}
|
||||
|
||||
static void test_prefixes(void) {
|
||||
sd_event *e;
|
||||
sd_icmp6_nd *nd;
|
||||
|
||||
if (verbose)
|
||||
printf("* %s\n", __FUNCTION__);
|
||||
|
||||
send_ra_function = send_ra_prefixes;
|
||||
|
||||
assert_se(sd_event_new(&e) >= 0);
|
||||
|
||||
assert_se(sd_icmp6_nd_new(&nd) >= 0);
|
||||
assert_se(nd);
|
||||
|
||||
assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
|
||||
|
||||
assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
|
||||
assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
|
||||
assert_se(sd_icmp6_nd_set_callback(nd, test_prefixes_cb, e) >= 0);
|
||||
|
||||
assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
|
||||
|
||||
sd_event_loop(e);
|
||||
|
||||
nd = sd_icmp6_nd_unref(nd);
|
||||
assert_se(!nd);
|
||||
|
||||
close(test_fd[1]);
|
||||
|
||||
sd_event_unref(e);
|
||||
}
|
||||
|
||||
static int send_ra(uint8_t flags) {
|
||||
uint8_t advertisement[] = {
|
||||
0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
|
||||
0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
|
||||
0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
|
||||
};
|
||||
|
||||
advertisement[5] = flags;
|
||||
|
||||
assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
|
||||
sizeof(advertisement));
|
||||
|
||||
if (verbose)
|
||||
printf(" sent RA with flag 0x%02x\n", flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
|
||||
return send_ra_function(0);
|
||||
}
|
||||
|
||||
static void test_rs_done(sd_icmp6_nd *nd, int event, void *userdata) {
|
||||
sd_event *e = userdata;
|
||||
static int idx = 0;
|
||||
struct {
|
||||
uint8_t flag;
|
||||
int event;
|
||||
} flag_event[] = {
|
||||
{ 0, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE },
|
||||
{ ND_RA_FLAG_OTHER, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER },
|
||||
{ ND_RA_FLAG_MANAGED, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED }
|
||||
};
|
||||
uint32_t mtu;
|
||||
|
||||
assert_se(nd);
|
||||
|
||||
assert_se(event == flag_event[idx].event);
|
||||
idx++;
|
||||
|
||||
if (verbose)
|
||||
printf(" got event %d\n", event);
|
||||
|
||||
if (idx < 3) {
|
||||
send_ra(flag_event[idx].flag);
|
||||
return;
|
||||
}
|
||||
|
||||
assert_se(sd_icmp6_ra_get_mtu(nd, &mtu) == -ENOMSG);
|
||||
|
||||
sd_event_exit(e, 0);
|
||||
}
|
||||
|
||||
static void test_rs(void) {
|
||||
sd_event *e;
|
||||
sd_icmp6_nd *nd;
|
||||
usec_t time_now = now(clock_boottime_or_monotonic());
|
||||
|
||||
if (verbose)
|
||||
printf("* %s\n", __FUNCTION__);
|
||||
|
||||
send_ra_function = send_ra;
|
||||
|
||||
assert_se(sd_event_new(&e) >= 0);
|
||||
|
||||
assert_se(sd_icmp6_nd_new(&nd) >= 0);
|
||||
assert_se(nd);
|
||||
|
||||
assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
|
||||
|
||||
assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
|
||||
assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
|
||||
assert_se(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 0);
|
||||
|
||||
assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
|
||||
time_now + 2 *USEC_PER_SEC, 0,
|
||||
test_rs_hangcheck, NULL) >= 0);
|
||||
|
||||
assert_se(sd_icmp6_nd_stop(nd) >= 0);
|
||||
assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
|
||||
assert_se(sd_icmp6_nd_stop(nd) >= 0);
|
||||
|
||||
assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
|
||||
|
||||
sd_event_loop(e);
|
||||
|
||||
test_hangcheck = sd_event_source_unref(test_hangcheck);
|
||||
|
||||
nd = sd_icmp6_nd_unref(nd);
|
||||
assert_se(!nd);
|
||||
|
||||
close(test_fd[1]);
|
||||
|
||||
sd_event_unref(e);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
log_set_max_level(LOG_DEBUG);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
test_rs();
|
||||
test_prefixes();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
|
||||
#include "icmp6-util.h"
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
static struct ether_addr mac_addr = {
|
||||
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
|
||||
};
|
||||
|
||||
static bool verbose = false;
|
||||
static sd_event_source *test_hangcheck;
|
||||
static int test_fd[2];
|
||||
|
||||
typedef int (*send_ra_t)(uint8_t flags);
|
||||
static send_ra_t send_ra_function;
|
||||
|
||||
static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
|
||||
void *userdata) {
|
||||
assert_se(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int icmp6_bind_router_solicitation(int index) {
|
||||
assert_se(index == 42);
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
|
||||
return -errno;
|
||||
|
||||
return test_fd[0];
|
||||
}
|
||||
|
||||
static int send_ra(uint8_t flags) {
|
||||
uint8_t advertisement[] = {
|
||||
0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
|
||||
0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
|
||||
0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
|
||||
};
|
||||
|
||||
advertisement[5] = flags;
|
||||
|
||||
assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
|
||||
sizeof(advertisement));
|
||||
|
||||
if (verbose)
|
||||
printf(" sent RA with flag 0x%02x\n", flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
|
||||
return send_ra_function(0);
|
||||
}
|
||||
|
||||
static void test_rs_done(sd_ndisc *nd, int event, void *userdata) {
|
||||
sd_event *e = userdata;
|
||||
static int idx = 0;
|
||||
struct {
|
||||
uint8_t flag;
|
||||
int event;
|
||||
} flag_event[] = {
|
||||
{ 0, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE },
|
||||
{ ND_RA_FLAG_OTHER, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER },
|
||||
{ ND_RA_FLAG_MANAGED, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED }
|
||||
};
|
||||
uint32_t mtu;
|
||||
|
||||
assert_se(nd);
|
||||
|
||||
assert_se(event == flag_event[idx].event);
|
||||
idx++;
|
||||
|
||||
if (verbose)
|
||||
printf(" got event %d\n", event);
|
||||
|
||||
if (idx < 3) {
|
||||
send_ra(flag_event[idx].flag);
|
||||
return;
|
||||
}
|
||||
|
||||
assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENOMSG);
|
||||
|
||||
sd_event_exit(e, 0);
|
||||
}
|
||||
|
||||
static void test_rs(void) {
|
||||
sd_event *e;
|
||||
sd_ndisc *nd;
|
||||
usec_t time_now = now(clock_boottime_or_monotonic());
|
||||
|
||||
if (verbose)
|
||||
printf("* %s\n", __FUNCTION__);
|
||||
|
||||
send_ra_function = send_ra;
|
||||
|
||||
assert_se(sd_event_new(&e) >= 0);
|
||||
|
||||
assert_se(sd_ndisc_new(&nd) >= 0);
|
||||
assert_se(nd);
|
||||
|
||||
assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
|
||||
|
||||
assert_se(sd_ndisc_set_index(nd, 42) >= 0);
|
||||
assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
|
||||
assert_se(sd_ndisc_set_callback(nd, test_rs_done, e) >= 0);
|
||||
|
||||
assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
|
||||
time_now + 2 *USEC_PER_SEC, 0,
|
||||
test_rs_hangcheck, NULL) >= 0);
|
||||
|
||||
assert_se(sd_ndisc_stop(nd) >= 0);
|
||||
assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
|
||||
assert_se(sd_ndisc_stop(nd) >= 0);
|
||||
|
||||
assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
|
||||
|
||||
sd_event_loop(e);
|
||||
|
||||
test_hangcheck = sd_event_source_unref(test_hangcheck);
|
||||
|
||||
nd = sd_ndisc_unref(nd);
|
||||
assert_se(!nd);
|
||||
|
||||
close(test_fd[1]);
|
||||
|
||||
sd_event_unref(e);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
log_set_max_level(LOG_DEBUG);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
test_rs();
|
||||
|
||||
return 0;
|
||||
}
|
||||
+11
-135
@@ -25,7 +25,6 @@
|
||||
#include "networkd-link.h"
|
||||
#include "network-internal.h"
|
||||
|
||||
#include "sd-icmp6-nd.h"
|
||||
#include "sd-dhcp6-client.h"
|
||||
|
||||
static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
|
||||
@@ -64,8 +63,7 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
|
||||
}
|
||||
|
||||
static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr,
|
||||
uint8_t prefixlen, uint32_t lifetime_preferred,
|
||||
uint32_t lifetime_valid) {
|
||||
uint32_t lifetime_preferred, uint32_t lifetime_valid) {
|
||||
int r;
|
||||
_cleanup_address_free_ Address *addr = NULL;
|
||||
|
||||
@@ -77,14 +75,14 @@ static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr,
|
||||
memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));
|
||||
|
||||
addr->flags = IFA_F_NOPREFIXROUTE;
|
||||
addr->prefixlen = prefixlen;
|
||||
addr->prefixlen = 128;
|
||||
|
||||
addr->cinfo.ifa_prefered = lifetime_preferred;
|
||||
addr->cinfo.ifa_valid = lifetime_valid;
|
||||
|
||||
log_link_info(link,
|
||||
"DHCPv6 address "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
|
||||
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
|
||||
"DHCPv6 address "SD_NDISC_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
|
||||
SD_NDISC_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
|
||||
addr->prefixlen, lifetime_preferred, lifetime_valid);
|
||||
|
||||
r = address_configure(addr, link, dhcp6_address_handler, true);
|
||||
@@ -99,7 +97,6 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
|
||||
sd_dhcp6_lease *lease;
|
||||
struct in6_addr ip6_addr;
|
||||
uint32_t lifetime_preferred, lifetime_valid;
|
||||
uint8_t prefixlen;
|
||||
|
||||
r = sd_dhcp6_client_get_lease(client, &lease);
|
||||
if (r < 0)
|
||||
@@ -111,18 +108,7 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
|
||||
&lifetime_preferred,
|
||||
&lifetime_valid) >= 0) {
|
||||
|
||||
r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery,
|
||||
&ip6_addr, &prefixlen);
|
||||
if (r < 0 && r != -EADDRNOTAVAIL) {
|
||||
log_link_warning_errno(link, r, "Could not get prefix information: %m");
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r == -EADDRNOTAVAIL)
|
||||
prefixlen = 128;
|
||||
|
||||
r = dhcp6_address_change(link, &ip6_addr, prefixlen,
|
||||
lifetime_preferred, lifetime_valid);
|
||||
r = dhcp6_address_change(link, &ip6_addr, lifetime_preferred, lifetime_valid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -179,34 +165,29 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
static int dhcp6_configure(Link *link, int event) {
|
||||
int dhcp6_configure(Link *link, bool inf_req) {
|
||||
int r;
|
||||
bool information_request;
|
||||
|
||||
assert_return(link, -EINVAL);
|
||||
assert_return(IN_SET(event, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED), -EINVAL);
|
||||
|
||||
link->dhcp6_configured = false;
|
||||
|
||||
if (link->dhcp6_client) {
|
||||
r = sd_dhcp6_client_get_information_request(link->dhcp6_client,
|
||||
&information_request);
|
||||
r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &information_request);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not get DHCPv6 Information request setting: %m");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (information_request && event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
|
||||
if (information_request && !inf_req) {
|
||||
r = sd_dhcp6_client_stop(link->dhcp6_client);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not stop DHCPv6 while setting Managed mode: %m");
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
|
||||
false);
|
||||
r = sd_dhcp6_client_set_information_request(link->dhcp6_client, false);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not unset DHCPv6 Information request: %m");
|
||||
goto error;
|
||||
@@ -249,9 +230,8 @@ static int dhcp6_configure(Link *link, int event) {
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (event == SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
|
||||
r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
|
||||
true);
|
||||
if (inf_req) {
|
||||
r = sd_dhcp6_client_set_information_request(link->dhcp6_client, true);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
}
|
||||
@@ -266,107 +246,3 @@ static int dhcp6_configure(Link *link, int event) {
|
||||
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int dhcp6_prefix_expired(Link *link) {
|
||||
int r;
|
||||
sd_dhcp6_lease *lease;
|
||||
struct in6_addr *expired_prefix, ip6_addr;
|
||||
uint8_t expired_prefixlen;
|
||||
uint32_t lifetime_preferred, lifetime_valid;
|
||||
|
||||
r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery,
|
||||
&expired_prefix, &expired_prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_link_info(link, "IPv6 prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d expired",
|
||||
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(*expired_prefix),
|
||||
expired_prefixlen);
|
||||
|
||||
sd_dhcp6_lease_reset_address_iter(lease);
|
||||
|
||||
while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
|
||||
&lifetime_preferred,
|
||||
&lifetime_valid) >= 0) {
|
||||
|
||||
r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen,
|
||||
&ip6_addr);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(ip6_addr), 128);
|
||||
|
||||
dhcp6_address_change(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE:
|
||||
return;
|
||||
|
||||
case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
|
||||
case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER:
|
||||
case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED:
|
||||
dhcp6_configure(link, event);
|
||||
|
||||
break;
|
||||
|
||||
case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
|
||||
if (!link->rtnl_extended_attrs)
|
||||
dhcp6_prefix_expired(link);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (event < 0)
|
||||
log_link_warning_errno(link, event, "ICMPv6 error: %m");
|
||||
else
|
||||
log_link_warning(link, "ICMPv6 unknown event: %d", event);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -370,7 +370,7 @@ static void link_free(Link *link) {
|
||||
|
||||
sd_ipv4ll_unref(link->ipv4ll);
|
||||
sd_dhcp6_client_unref(link->dhcp6_client);
|
||||
sd_icmp6_nd_unref(link->icmp6_router_discovery);
|
||||
sd_ndisc_unref(link->ndisc_router_discovery);
|
||||
|
||||
if (link->manager)
|
||||
hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
|
||||
@@ -481,16 +481,16 @@ static int link_stop_clients(Link *link) {
|
||||
r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m");
|
||||
}
|
||||
|
||||
if(link->icmp6_router_discovery) {
|
||||
if(link->ndisc_router_discovery) {
|
||||
if (link->dhcp6_client) {
|
||||
k = sd_dhcp6_client_stop(link->dhcp6_client);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
|
||||
}
|
||||
|
||||
k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
|
||||
k = sd_ndisc_stop(link->ndisc_router_discovery);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, r, "Could not stop ICMPv6 router discovery: %m");
|
||||
r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m");
|
||||
}
|
||||
|
||||
if (link->lldp) {
|
||||
@@ -1238,13 +1238,13 @@ static int link_acquire_conf(Link *link) {
|
||||
}
|
||||
|
||||
if (link_dhcp6_enabled(link)) {
|
||||
assert(link->icmp6_router_discovery);
|
||||
assert(link->ndisc_router_discovery);
|
||||
|
||||
log_link_debug(link, "Discovering IPv6 routers");
|
||||
|
||||
r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery);
|
||||
r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not start IPv6 router discovery: %m");
|
||||
return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
|
||||
}
|
||||
|
||||
if (link_lldp_enabled(link)) {
|
||||
@@ -2002,7 +2002,7 @@ static int link_configure(Link *link) {
|
||||
}
|
||||
|
||||
if (link_dhcp6_enabled(link)) {
|
||||
r = icmp6_configure(link);
|
||||
r = ndisc_configure(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "sd-dhcp-client.h"
|
||||
#include "sd-dhcp-server.h"
|
||||
#include "sd-ipv4ll.h"
|
||||
#include "sd-icmp6-nd.h"
|
||||
#include "sd-ndisc.h"
|
||||
#include "sd-dhcp6-client.h"
|
||||
#include "sd-lldp.h"
|
||||
|
||||
@@ -104,7 +104,7 @@ struct Link {
|
||||
|
||||
sd_dhcp_server *dhcp_server;
|
||||
|
||||
sd_icmp6_nd *icmp6_router_discovery;
|
||||
sd_ndisc *ndisc_router_discovery;
|
||||
sd_dhcp6_client *dhcp6_client;
|
||||
bool rtnl_extended_attrs;
|
||||
|
||||
@@ -145,7 +145,8 @@ int link_set_timezone(Link *link, const char *timezone);
|
||||
|
||||
int ipv4ll_configure(Link *link);
|
||||
int dhcp4_configure(Link *link);
|
||||
int icmp6_configure(Link *link);
|
||||
int dhcp6_configure(Link *link, bool information_request);
|
||||
int ndisc_configure(Link *link);
|
||||
|
||||
bool link_lldp_enabled(Link *link);
|
||||
bool link_ipv4ll_enabled(Link *link);
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <netinet/ether.h>
|
||||
#include <linux/if.h>
|
||||
|
||||
#include "networkd-link.h"
|
||||
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
static void ndisc_router_handler(sd_ndisc *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 SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE:
|
||||
return;
|
||||
|
||||
case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER:
|
||||
dhcp6_configure(link, true);
|
||||
|
||||
break;
|
||||
case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
|
||||
case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED:
|
||||
dhcp6_configure(link, false);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (event < 0)
|
||||
log_link_warning_errno(link, event, "IPv6 Neighbor Discover error: %m");
|
||||
else
|
||||
log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int ndisc_configure(Link *link) {
|
||||
int r;
|
||||
|
||||
assert_return(link, -EINVAL);
|
||||
|
||||
r = sd_ndisc_new(&link->ndisc_router_discovery);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ndisc_attach_event(link->ndisc_router_discovery, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ndisc_set_mac(link->ndisc_router_discovery, &link->mac);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ndisc_set_index(link->ndisc_router_discovery, link->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ndisc_set_callback(link->ndisc_router_discovery,
|
||||
ndisc_router_handler, link);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosdicmp6ndfoo
|
||||
#define foosdicmp6ndfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
enum {
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE = 0,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER = 2,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED = 4,
|
||||
};
|
||||
|
||||
typedef struct sd_icmp6_nd sd_icmp6_nd;
|
||||
|
||||
typedef void(*sd_icmp6_nd_callback_t)(sd_icmp6_nd *nd, int event,
|
||||
void *userdata);
|
||||
|
||||
int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t cb,
|
||||
void *userdata);
|
||||
int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index);
|
||||
int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr);
|
||||
|
||||
int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority);
|
||||
int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd);
|
||||
sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd);
|
||||
|
||||
sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd);
|
||||
sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd);
|
||||
int sd_icmp6_nd_new(sd_icmp6_nd **ret);
|
||||
|
||||
int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen,
|
||||
struct in6_addr *addr);
|
||||
|
||||
int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu);
|
||||
int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr,
|
||||
uint8_t *prefixlen);
|
||||
int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr,
|
||||
uint8_t *prefixlen);
|
||||
|
||||
int sd_icmp6_nd_stop(sd_icmp6_nd *nd);
|
||||
int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd);
|
||||
|
||||
#define SD_ICMP6_ND_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
|
||||
|
||||
#define SD_ICMP6_ND_ADDRESS_FORMAT_VAL(address) \
|
||||
be16toh((address).s6_addr16[0]), \
|
||||
be16toh((address).s6_addr16[1]), \
|
||||
be16toh((address).s6_addr16[2]), \
|
||||
be16toh((address).s6_addr16[3]), \
|
||||
be16toh((address).s6_addr16[4]), \
|
||||
be16toh((address).s6_addr16[5]), \
|
||||
be16toh((address).s6_addr16[6]), \
|
||||
be16toh((address).s6_addr16[7])
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosdndiscfoo
|
||||
#define foosdndiscfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
enum {
|
||||
SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE = 0,
|
||||
SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1,
|
||||
SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER = 2,
|
||||
SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3,
|
||||
};
|
||||
|
||||
typedef struct sd_ndisc sd_ndisc;
|
||||
|
||||
typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event,
|
||||
void *userdata);
|
||||
|
||||
int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb,
|
||||
void *userdata);
|
||||
int sd_ndisc_set_index(sd_ndisc *nd, int interface_index);
|
||||
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
|
||||
|
||||
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority);
|
||||
int sd_ndisc_detach_event(sd_ndisc *nd);
|
||||
sd_event *sd_ndisc_get_event(sd_ndisc *nd);
|
||||
|
||||
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
|
||||
sd_ndisc *sd_ndisc_unref(sd_ndisc *nd);
|
||||
int sd_ndisc_new(sd_ndisc **ret);
|
||||
|
||||
int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu);
|
||||
|
||||
int sd_ndisc_stop(sd_ndisc *nd);
|
||||
int sd_ndisc_router_discovery_start(sd_ndisc *nd);
|
||||
|
||||
#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
|
||||
|
||||
#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \
|
||||
be16toh((address).s6_addr16[0]), \
|
||||
be16toh((address).s6_addr16[1]), \
|
||||
be16toh((address).s6_addr16[2]), \
|
||||
be16toh((address).s6_addr16[3]), \
|
||||
be16toh((address).s6_addr16[4]), \
|
||||
be16toh((address).s6_addr16[5]), \
|
||||
be16toh((address).s6_addr16[6]), \
|
||||
be16toh((address).s6_addr16[7])
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user