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:
Patrik Flykt
2015-10-22 20:41:50 +03:00
16 changed files with 673 additions and 935 deletions
+1 -1
View File
@@ -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
View File
@@ -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 \
-3
View File
@@ -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);
-97
View File
@@ -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,
+129
View File
@@ -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;
}
+27
View File
@@ -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);
+3 -3
View File
@@ -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;
}
-357
View File
@@ -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;
}
+171
View File
@@ -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
View File
@@ -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;
}
+8 -8
View File
@@ -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;
}
+4 -3
View File
@@ -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);
+88
View File
@@ -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;
}
-79
View File
@@ -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
+71
View File
@@ -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