Merge pull request #3328 from poettering/ipv4ll-ipv4acd-fixes
various sd-Ipv4ll/sd-ipv4acd fixes
This commit is contained in:
+1
-1
@@ -1610,9 +1610,9 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const
|
||||
}
|
||||
|
||||
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
||||
|
||||
_cleanup_fdset_free_ FDSet *fds = NULL;
|
||||
Manager *m = userdata;
|
||||
|
||||
char buf[NOTIFY_BUFFER_MAX+1];
|
||||
struct iovec iovec = {
|
||||
.iov_base = buf,
|
||||
|
||||
@@ -65,4 +65,5 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum);
|
||||
#define DHCP_CLIENT_DONT_DESTROY(client) \
|
||||
_cleanup_(sd_dhcp_client_unrefp) _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client)
|
||||
|
||||
#define log_dhcp_client(client, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
|
||||
#define log_dhcp_client_errno(client, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
|
||||
#define log_dhcp_client(client, fmt, ...) log_dhcp_client_errno(client, 0, fmt, ##__VA_ARGS__)
|
||||
|
||||
@@ -59,7 +59,7 @@ typedef struct DHCPPacket DHCPPacket;
|
||||
#define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE)
|
||||
#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage))
|
||||
#define DHCP_DEFAULT_MIN_SIZE 576 /* the minimum internet hosts must be able to receive */
|
||||
#define DHCP_MIN_OPTIONS_SIZE DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE
|
||||
#define DHCP_MIN_OPTIONS_SIZE (DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE)
|
||||
#define DHCP_MAGIC_COOKIE (uint32_t)(0x63825363)
|
||||
|
||||
enum {
|
||||
|
||||
@@ -53,7 +53,7 @@ struct sd_dhcp_client {
|
||||
sd_event *event;
|
||||
int event_priority;
|
||||
sd_event_source *timeout_resend;
|
||||
int index;
|
||||
int ifindex;
|
||||
int fd;
|
||||
union sockaddr_union link;
|
||||
sd_event_source *receive_message;
|
||||
@@ -101,7 +101,7 @@ struct sd_dhcp_client {
|
||||
sd_event_source *timeout_t1;
|
||||
sd_event_source *timeout_t2;
|
||||
sd_event_source *timeout_expire;
|
||||
sd_dhcp_client_callback_t cb;
|
||||
sd_dhcp_client_callback_t callback;
|
||||
void *userdata;
|
||||
sd_dhcp_lease *lease;
|
||||
usec_t start_delay;
|
||||
@@ -131,9 +131,10 @@ int sd_dhcp_client_set_callback(
|
||||
sd_dhcp_client *client,
|
||||
sd_dhcp_client_callback_t cb,
|
||||
void *userdata) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
client->cb = cb;
|
||||
client->callback = cb;
|
||||
client->userdata = userdata;
|
||||
|
||||
return 0;
|
||||
@@ -151,10 +152,10 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
|
||||
size_t i;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return (IN_SET(client->state, DHCP_STATE_INIT,
|
||||
DHCP_STATE_STOPPED), -EBUSY);
|
||||
assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
|
||||
|
||||
switch(option) {
|
||||
|
||||
case SD_DHCP_OPTION_PAD:
|
||||
case SD_DHCP_OPTION_OVERLOAD:
|
||||
case SD_DHCP_OPTION_MESSAGE_TYPE:
|
||||
@@ -182,9 +183,9 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
|
||||
int sd_dhcp_client_set_request_address(
|
||||
sd_dhcp_client *client,
|
||||
const struct in_addr *last_addr) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return (IN_SET(client->state, DHCP_STATE_INIT,
|
||||
DHCP_STATE_STOPPED), -EBUSY);
|
||||
assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
|
||||
|
||||
if (last_addr)
|
||||
client->last_addr = last_addr->s_addr;
|
||||
@@ -194,14 +195,13 @@ int sd_dhcp_client_set_request_address(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
|
||||
int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return (IN_SET(client->state, DHCP_STATE_INIT,
|
||||
DHCP_STATE_STOPPED), -EBUSY);
|
||||
assert_return(interface_index > 0, -EINVAL);
|
||||
|
||||
client->index = interface_index;
|
||||
assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
|
||||
client->ifindex = ifindex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -231,8 +231,7 @@ int sd_dhcp_client_set_mac(
|
||||
return 0;
|
||||
|
||||
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
|
||||
log_dhcp_client(client, "Changing MAC address on running DHCP "
|
||||
"client, restarting");
|
||||
log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting");
|
||||
need_restart = true;
|
||||
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
|
||||
}
|
||||
@@ -284,14 +283,17 @@ int sd_dhcp_client_set_client_id(
|
||||
assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case ARPHRD_ETHER:
|
||||
if (data_len != ETH_ALEN)
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
case ARPHRD_INFINIBAND:
|
||||
if (data_len != INFINIBAND_ALEN)
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -348,7 +350,7 @@ int sd_dhcp_client_set_iaid_duid(
|
||||
|
||||
/* If IAID is not configured, generate it. */
|
||||
if (iaid == 0) {
|
||||
r = dhcp_identifier_set_iaid(client->index, client->mac_addr,
|
||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
|
||||
client->mac_addr_len,
|
||||
&client->client_id.ns.iaid);
|
||||
if (r < 0)
|
||||
@@ -435,28 +437,29 @@ int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
|
||||
|
||||
int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (client->state != DHCP_STATE_BOUND &&
|
||||
client->state != DHCP_STATE_RENEWING &&
|
||||
client->state != DHCP_STATE_REBINDING)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
*ret = client->lease;
|
||||
if (ret)
|
||||
*ret = client->lease;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void client_notify(sd_dhcp_client *client, int event) {
|
||||
if (client->cb)
|
||||
client->cb(client, event, client->userdata);
|
||||
assert(client);
|
||||
|
||||
if (client->callback)
|
||||
client->callback(client, event, client->userdata);
|
||||
}
|
||||
|
||||
static int client_initialize(sd_dhcp_client *client) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
client->receive_message =
|
||||
sd_event_source_unref(client->receive_message);
|
||||
client->receive_message = sd_event_source_unref(client->receive_message);
|
||||
|
||||
client->fd = asynchronous_close(client->fd);
|
||||
|
||||
@@ -565,7 +568,7 @@ static int client_message_init(
|
||||
|
||||
client->client_id.type = 255;
|
||||
|
||||
r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid);
|
||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -751,8 +754,9 @@ static int client_send_request(sd_dhcp_client *client) {
|
||||
size_t optoffset, optlen;
|
||||
int r;
|
||||
|
||||
r = client_message_init(client, &request, DHCP_REQUEST,
|
||||
&optlen, &optoffset);
|
||||
assert(client);
|
||||
|
||||
r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -849,18 +853,23 @@ static int client_send_request(sd_dhcp_client *client) {
|
||||
return r;
|
||||
|
||||
switch (client->state) {
|
||||
|
||||
case DHCP_STATE_REQUESTING:
|
||||
log_dhcp_client(client, "REQUEST (requesting)");
|
||||
break;
|
||||
|
||||
case DHCP_STATE_INIT_REBOOT:
|
||||
log_dhcp_client(client, "REQUEST (init-reboot)");
|
||||
break;
|
||||
|
||||
case DHCP_STATE_RENEWING:
|
||||
log_dhcp_client(client, "REQUEST (renewing)");
|
||||
break;
|
||||
|
||||
case DHCP_STATE_REBINDING:
|
||||
log_dhcp_client(client, "REQUEST (rebinding)");
|
||||
break;
|
||||
|
||||
default:
|
||||
log_dhcp_client(client, "REQUEST (invalid)");
|
||||
break;
|
||||
@@ -892,6 +901,7 @@ static int client_timeout_resend(
|
||||
goto error;
|
||||
|
||||
switch (client->state) {
|
||||
|
||||
case DHCP_STATE_RENEWING:
|
||||
|
||||
time_left = (client->lease->t2 - client->lease->t1) / 2;
|
||||
@@ -1101,15 +1111,14 @@ static int client_start_delayed(sd_dhcp_client *client) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->event, -EINVAL);
|
||||
assert_return(client->index > 0, -EINVAL);
|
||||
assert_return(client->ifindex > 0, -EINVAL);
|
||||
assert_return(client->fd < 0, -EBUSY);
|
||||
assert_return(client->xid == 0, -EINVAL);
|
||||
assert_return(client->state == DHCP_STATE_INIT ||
|
||||
client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
|
||||
assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY);
|
||||
|
||||
client->xid = random_u32();
|
||||
|
||||
r = dhcp_network_bind_raw_socket(client->index, &client->link,
|
||||
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
|
||||
client->xid, client->mac_addr,
|
||||
client->mac_addr_len, client->arp_type);
|
||||
if (r < 0) {
|
||||
@@ -1151,13 +1160,15 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
|
||||
DHCP_CLIENT_DONT_DESTROY(client);
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
|
||||
client->receive_message = sd_event_source_unref(client->receive_message);
|
||||
client->fd = asynchronous_close(client->fd);
|
||||
|
||||
client->state = DHCP_STATE_REBINDING;
|
||||
client->attempt = 1;
|
||||
|
||||
r = dhcp_network_bind_raw_socket(client->index, &client->link,
|
||||
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
|
||||
client->xid, client->mac_addr,
|
||||
client->mac_addr_len, client->arp_type);
|
||||
if (r < 0) {
|
||||
@@ -1624,7 +1635,7 @@ static int client_receive_message_udp(
|
||||
|
||||
sd_dhcp_client *client = userdata;
|
||||
_cleanup_free_ DHCPMessage *message = NULL;
|
||||
const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
|
||||
const struct ether_addr zero_mac = {};
|
||||
const struct ether_addr *expected_chaddr = NULL;
|
||||
uint8_t expected_hlen = 0;
|
||||
ssize_t len, buflen;
|
||||
@@ -1645,9 +1656,9 @@ static int client_receive_message_udp(
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
return 0;
|
||||
|
||||
log_dhcp_client(client, "Could not receive message from UDP socket: %m");
|
||||
return -errno;
|
||||
} else if ((size_t)len < sizeof(DHCPMessage)) {
|
||||
return log_dhcp_client_errno(client, errno, "Could not receive message from UDP socket: %m");
|
||||
}
|
||||
if ((size_t) len < sizeof(DHCPMessage)) {
|
||||
log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
|
||||
return 0;
|
||||
}
|
||||
@@ -1778,7 +1789,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
|
||||
|
||||
r = client_start(client);
|
||||
if (r >= 0)
|
||||
log_dhcp_client(client, "STARTED on ifindex %i", client->index);
|
||||
log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1822,8 +1833,7 @@ int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
|
||||
}
|
||||
|
||||
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
|
||||
if (!client)
|
||||
return NULL;
|
||||
assert_return(client, NULL);
|
||||
|
||||
return client->event;
|
||||
}
|
||||
@@ -1879,13 +1889,12 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) {
|
||||
|
||||
client->n_ref = 1;
|
||||
client->state = DHCP_STATE_INIT;
|
||||
client->index = -1;
|
||||
client->ifindex = -1;
|
||||
client->fd = -1;
|
||||
client->attempt = 1;
|
||||
client->mtu = DHCP_DEFAULT_MIN_SIZE;
|
||||
|
||||
client->req_opts_size = ELEMENTSOF(default_req_opts);
|
||||
|
||||
client->req_opts = memdup(default_req_opts, client->req_opts_size);
|
||||
if (!client->req_opts)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -45,7 +45,7 @@ struct sd_dhcp6_client {
|
||||
enum DHCP6State state;
|
||||
sd_event *event;
|
||||
int event_priority;
|
||||
int index;
|
||||
int ifindex;
|
||||
struct in6_addr local_address;
|
||||
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
|
||||
size_t mac_addr_len;
|
||||
@@ -64,7 +64,7 @@ struct sd_dhcp6_client {
|
||||
uint8_t retransmit_count;
|
||||
sd_event_source *timeout_resend;
|
||||
sd_event_source *timeout_resend_expire;
|
||||
sd_dhcp6_client_callback_t cb;
|
||||
sd_dhcp6_client_callback_t callback;
|
||||
void *userdata;
|
||||
struct duid duid;
|
||||
size_t duid_len;
|
||||
@@ -115,22 +115,22 @@ int sd_dhcp6_client_set_callback(
|
||||
sd_dhcp6_client *client,
|
||||
sd_dhcp6_client_callback_t cb,
|
||||
void *userdata) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
client->cb = cb;
|
||||
client->callback = cb;
|
||||
client->userdata = userdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(interface_index >= -1, -EINVAL);
|
||||
int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(ifindex >= -1, -EINVAL);
|
||||
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
|
||||
|
||||
client->index = interface_index;
|
||||
|
||||
client->ifindex = ifindex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -256,6 +256,7 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
|
||||
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
|
||||
|
||||
switch(option) {
|
||||
|
||||
case SD_DHCP6_OPTION_DNS_SERVERS:
|
||||
case SD_DHCP6_OPTION_DOMAIN_LIST:
|
||||
case SD_DHCP6_OPTION_SNTP_SERVERS:
|
||||
@@ -292,20 +293,25 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
|
||||
}
|
||||
|
||||
static void client_notify(sd_dhcp6_client *client, int event) {
|
||||
if (client->cb)
|
||||
client->cb(client, event, client->userdata);
|
||||
assert(client);
|
||||
|
||||
if (client->callback)
|
||||
client->callback(client, event, client->userdata);
|
||||
}
|
||||
|
||||
static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
|
||||
assert(client);
|
||||
|
||||
if (client->lease) {
|
||||
dhcp6_lease_clear_timers(&client->lease->ia);
|
||||
sd_dhcp6_lease_unref(client->lease);
|
||||
}
|
||||
|
||||
client->lease = lease;
|
||||
}
|
||||
|
||||
static int client_reset(sd_dhcp6_client *client) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert(client);
|
||||
|
||||
client_set_lease(client, NULL);
|
||||
|
||||
@@ -353,6 +359,8 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
usec_t elapsed_usec;
|
||||
be16_t elapsed_time;
|
||||
|
||||
assert(client);
|
||||
|
||||
len = sizeof(DHCP6Message) + optlen;
|
||||
|
||||
message = malloc0(len);
|
||||
@@ -454,9 +462,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
sd_dhcp6_client *client = userdata;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->lease, -EINVAL);
|
||||
assert(s);
|
||||
assert(client);
|
||||
assert(client->lease);
|
||||
|
||||
client->lease->ia.timeout_t2 =
|
||||
sd_event_source_unref(client->lease->ia.timeout_t2);
|
||||
@@ -471,9 +479,9 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
|
||||
static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
sd_dhcp6_client *client = userdata;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->lease, -EINVAL);
|
||||
assert(s);
|
||||
assert(client);
|
||||
assert(client->lease);
|
||||
|
||||
client->lease->ia.timeout_t1 =
|
||||
sd_event_source_unref(client->lease->ia.timeout_t1);
|
||||
@@ -671,7 +679,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
|
||||
if (client->ia_na.id)
|
||||
return 0;
|
||||
|
||||
r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->ia_na.id);
|
||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &client->ia_na.id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -690,6 +698,11 @@ static int client_parse_message(
|
||||
bool clientid = false;
|
||||
be32_t iaid_lease;
|
||||
|
||||
assert(client);
|
||||
assert(message);
|
||||
assert(len >= sizeof(DHCP6Message));
|
||||
assert(lease);
|
||||
|
||||
option = (uint8_t *)message + sizeof(DHCP6Message);
|
||||
len -= sizeof(DHCP6Message);
|
||||
|
||||
@@ -834,9 +847,12 @@ static int client_parse_message(
|
||||
}
|
||||
|
||||
static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) {
|
||||
int r;
|
||||
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
|
||||
bool rapid_commit;
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
assert(reply);
|
||||
|
||||
if (reply->type != DHCP6_REPLY)
|
||||
return 0;
|
||||
@@ -865,9 +881,9 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si
|
||||
}
|
||||
|
||||
static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) {
|
||||
int r;
|
||||
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
|
||||
uint8_t pref_advertise = 0, pref_lease = 0;
|
||||
int r;
|
||||
|
||||
if (advertise->type != DHCP6_ADVERTISE)
|
||||
return 0;
|
||||
@@ -898,7 +914,12 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver
|
||||
return r;
|
||||
}
|
||||
|
||||
static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
static int client_receive_message(
|
||||
sd_event_source *s,
|
||||
int fd, uint32_t
|
||||
revents,
|
||||
void *userdata) {
|
||||
|
||||
sd_dhcp6_client *client = userdata;
|
||||
DHCP6_CLIENT_DONT_DESTROY(client);
|
||||
_cleanup_free_ DHCP6Message *message = NULL;
|
||||
@@ -924,8 +945,11 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
|
||||
|
||||
return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
|
||||
|
||||
} else if ((size_t)len < sizeof(DHCP6Message))
|
||||
}
|
||||
if ((size_t) len < sizeof(DHCP6Message)) {
|
||||
log_dhcp6_client(client, "Too small to be DHCP6 message: ignoring");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(message->type) {
|
||||
case DHCP6_SOLICIT:
|
||||
@@ -1019,7 +1043,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->event, -EINVAL);
|
||||
assert_return(client->index > 0, -EINVAL);
|
||||
assert_return(client->ifindex > 0, -EINVAL);
|
||||
assert_return(client->state != state, -EINVAL);
|
||||
|
||||
client->timeout_resend_expire =
|
||||
@@ -1152,12 +1176,12 @@ int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
||||
int r = 0;
|
||||
enum DHCP6State state = DHCP6_STATE_SOLICITATION;
|
||||
int r = 0;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->event, -EINVAL);
|
||||
assert_return(client->index > 0, -EINVAL);
|
||||
assert_return(client->ifindex > 0, -EINVAL);
|
||||
assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL);
|
||||
|
||||
if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
|
||||
@@ -1175,7 +1199,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp6_network_bind_udp_socket(client->index, &client->local_address);
|
||||
r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address);
|
||||
if (r < 0) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
@@ -1244,8 +1268,7 @@ int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) {
|
||||
}
|
||||
|
||||
sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
|
||||
if (!client)
|
||||
return NULL;
|
||||
assert_return(client, NULL);
|
||||
|
||||
return client->event;
|
||||
}
|
||||
@@ -1293,15 +1316,11 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
||||
return -ENOMEM;
|
||||
|
||||
client->n_ref = 1;
|
||||
|
||||
client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
|
||||
|
||||
client->index = -1;
|
||||
|
||||
client->ifindex = -1;
|
||||
client->fd = -1;
|
||||
|
||||
client->req_opts_len = ELEMENTSOF(default_req_opts);
|
||||
|
||||
client->req_opts = new0(be16_t, client->req_opts_len);
|
||||
if (!client->req_opts)
|
||||
return -ENOMEM;
|
||||
|
||||
+239
-247
@@ -33,41 +33,25 @@
|
||||
#include "in-addr-util.h"
|
||||
#include "list.h"
|
||||
#include "random-util.h"
|
||||
#include "refcnt.h"
|
||||
#include "siphash24.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Constants from the RFC */
|
||||
#define PROBE_WAIT 1
|
||||
#define PROBE_NUM 3
|
||||
#define PROBE_MIN 1
|
||||
#define PROBE_MAX 2
|
||||
#define ANNOUNCE_WAIT 2
|
||||
#define ANNOUNCE_NUM 2
|
||||
#define ANNOUNCE_INTERVAL 2
|
||||
#define MAX_CONFLICTS 10
|
||||
#define RATE_LIMIT_INTERVAL 60
|
||||
#define DEFEND_INTERVAL 10
|
||||
|
||||
#define IPV4ACD_NETWORK 0xA9FE0000L
|
||||
#define IPV4ACD_NETMASK 0xFFFF0000L
|
||||
|
||||
#define log_ipv4acd_full(ll, level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__)
|
||||
|
||||
#define log_ipv4acd_debug(ll, ...) log_ipv4acd_full(ll, LOG_DEBUG, 0, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_info(ll, ...) log_ipv4acd_full(ll, LOG_INFO, 0, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_notice(ll, ...) log_ipv4acd_full(ll, LOG_NOTICE, 0, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_warning(ll, ...) log_ipv4acd_full(ll, LOG_WARNING, 0, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_error(ll, ...) log_ipv4acd_full(ll, LOG_ERR, 0, ##__VA_ARGS__)
|
||||
|
||||
#define log_ipv4acd_debug_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_DEBUG, error, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_info_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_INFO, error, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_notice_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_NOTICE, error, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_warning_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_WARNING, error, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_error_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_ERR, error, ##__VA_ARGS__)
|
||||
#define PROBE_WAIT_USEC (1U * USEC_PER_SEC)
|
||||
#define PROBE_NUM 3U
|
||||
#define PROBE_MIN_USEC (1U * USEC_PER_SEC)
|
||||
#define PROBE_MAX_USEC (2U * USEC_PER_SEC)
|
||||
#define ANNOUNCE_WAIT_USEC (2U * USEC_PER_SEC)
|
||||
#define ANNOUNCE_NUM 2U
|
||||
#define ANNOUNCE_INTERVAL_USEC (2U * USEC_PER_SEC)
|
||||
#define MAX_CONFLICTS 10U
|
||||
#define RATE_LIMIT_INTERVAL_USEC (60U * USEC_PER_SEC)
|
||||
#define DEFEND_INTERVAL_USEC (10U * USEC_PER_SEC)
|
||||
|
||||
typedef enum IPv4ACDState {
|
||||
IPV4ACD_STATE_INIT,
|
||||
IPV4ACD_STATE_STARTED,
|
||||
IPV4ACD_STATE_WAITING_PROBE,
|
||||
IPV4ACD_STATE_PROBING,
|
||||
IPV4ACD_STATE_WAITING_ANNOUNCE,
|
||||
@@ -78,158 +62,164 @@ typedef enum IPv4ACDState {
|
||||
} IPv4ACDState;
|
||||
|
||||
struct sd_ipv4acd {
|
||||
RefCount n_ref;
|
||||
unsigned n_ref;
|
||||
|
||||
IPv4ACDState state;
|
||||
int index;
|
||||
int ifindex;
|
||||
int fd;
|
||||
int iteration;
|
||||
int conflict;
|
||||
sd_event_source *receive_message;
|
||||
sd_event_source *timer;
|
||||
|
||||
unsigned n_iteration;
|
||||
unsigned n_conflict;
|
||||
|
||||
sd_event_source *receive_message_event_source;
|
||||
sd_event_source *timer_event_source;
|
||||
|
||||
usec_t defend_window;
|
||||
be32_t address;
|
||||
|
||||
/* External */
|
||||
struct ether_addr mac_addr;
|
||||
|
||||
sd_event *event;
|
||||
int event_priority;
|
||||
sd_ipv4acd_callback_t cb;
|
||||
sd_ipv4acd_callback_t callback;
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll) {
|
||||
if (ll)
|
||||
assert_se(REFCNT_INC(ll->n_ref) >= 2);
|
||||
#define log_ipv4acd_errno(acd, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__)
|
||||
#define log_ipv4acd(acd, fmt, ...) log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__)
|
||||
|
||||
return ll;
|
||||
static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_counter) {
|
||||
assert(acd);
|
||||
assert(st < _IPV4ACD_STATE_MAX);
|
||||
|
||||
if (st == acd->state && !reset_counter)
|
||||
acd->n_iteration++;
|
||||
else {
|
||||
acd->state = st;
|
||||
acd->n_iteration = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) {
|
||||
if (!ll || REFCNT_DEC(ll->n_ref) > 0)
|
||||
static void ipv4acd_reset(sd_ipv4acd *acd) {
|
||||
assert(acd);
|
||||
|
||||
acd->timer_event_source = sd_event_source_unref(acd->timer_event_source);
|
||||
acd->receive_message_event_source = sd_event_source_unref(acd->receive_message_event_source);
|
||||
|
||||
acd->fd = safe_close(acd->fd);
|
||||
|
||||
ipv4acd_set_state(acd, IPV4ACD_STATE_INIT, true);
|
||||
}
|
||||
|
||||
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd) {
|
||||
if (!acd)
|
||||
return NULL;
|
||||
|
||||
ll->receive_message = sd_event_source_unref(ll->receive_message);
|
||||
ll->fd = safe_close(ll->fd);
|
||||
assert_se(acd->n_ref >= 1);
|
||||
acd->n_ref++;
|
||||
|
||||
ll->timer = sd_event_source_unref(ll->timer);
|
||||
return acd;
|
||||
}
|
||||
|
||||
sd_ipv4acd_detach_event(ll);
|
||||
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd) {
|
||||
if (!acd)
|
||||
return NULL;
|
||||
|
||||
free(ll);
|
||||
assert_se(acd->n_ref >= 1);
|
||||
acd->n_ref--;
|
||||
|
||||
if (acd->n_ref > 0)
|
||||
return NULL;
|
||||
|
||||
ipv4acd_reset(acd);
|
||||
sd_ipv4acd_detach_event(acd);
|
||||
|
||||
free(acd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_new(sd_ipv4acd **ret) {
|
||||
_cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *ll = NULL;
|
||||
_cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
ll = new0(sd_ipv4acd, 1);
|
||||
if (!ll)
|
||||
acd = new0(sd_ipv4acd, 1);
|
||||
if (!acd)
|
||||
return -ENOMEM;
|
||||
|
||||
ll->n_ref = REFCNT_INIT;
|
||||
ll->state = IPV4ACD_STATE_INIT;
|
||||
ll->index = -1;
|
||||
ll->fd = -1;
|
||||
acd->n_ref = 1;
|
||||
acd->state = IPV4ACD_STATE_INIT;
|
||||
acd->ifindex = -1;
|
||||
acd->fd = -1;
|
||||
|
||||
*ret = ll;
|
||||
ll = NULL;
|
||||
*ret = acd;
|
||||
acd = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) {
|
||||
static void ipv4acd_client_notify(sd_ipv4acd *acd, int event) {
|
||||
assert(acd);
|
||||
|
||||
assert(ll);
|
||||
assert(st < _IPV4ACD_STATE_MAX);
|
||||
|
||||
if (st == ll->state && !reset_counter)
|
||||
ll->iteration++;
|
||||
else {
|
||||
ll->state = st;
|
||||
ll->iteration = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) {
|
||||
assert(ll);
|
||||
|
||||
if (!ll->cb)
|
||||
if (!acd->callback)
|
||||
return;
|
||||
|
||||
ll->cb(ll, event, ll->userdata);
|
||||
acd->callback(acd, event, acd->userdata);
|
||||
}
|
||||
|
||||
static void ipv4acd_stop(sd_ipv4acd *ll) {
|
||||
assert(ll);
|
||||
int sd_ipv4acd_stop(sd_ipv4acd *acd) {
|
||||
assert_return(acd, -EINVAL);
|
||||
|
||||
ll->receive_message = sd_event_source_unref(ll->receive_message);
|
||||
ll->fd = safe_close(ll->fd);
|
||||
ipv4acd_reset(acd);
|
||||
|
||||
ll->timer = sd_event_source_unref(ll->timer);
|
||||
log_ipv4acd(acd, "STOPPED");
|
||||
|
||||
log_ipv4acd_debug(ll, "STOPPED");
|
||||
|
||||
ipv4acd_set_state (ll, IPV4ACD_STATE_INIT, true);
|
||||
}
|
||||
|
||||
int sd_ipv4acd_stop(sd_ipv4acd *ll) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
ipv4acd_stop(ll);
|
||||
|
||||
ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_STOP);
|
||||
ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata);
|
||||
|
||||
static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, int sec, int random_sec) {
|
||||
static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_usec) {
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL;
|
||||
usec_t next_timeout;
|
||||
usec_t time_now;
|
||||
usec_t next_timeout, time_now;
|
||||
int r;
|
||||
|
||||
assert(sec >= 0);
|
||||
assert(random_sec >= 0);
|
||||
assert(ll);
|
||||
assert(acd);
|
||||
|
||||
next_timeout = sec * USEC_PER_SEC;
|
||||
next_timeout = usec;
|
||||
|
||||
if (random_sec)
|
||||
next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
|
||||
if (random_usec > 0)
|
||||
next_timeout += (usec_t) random_u64() % random_usec;
|
||||
|
||||
assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);
|
||||
assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
|
||||
|
||||
r = sd_event_add_time(ll->event, &timer, clock_boottime_or_monotonic(),
|
||||
time_now + next_timeout, 0, ipv4acd_on_timeout, ll);
|
||||
r = sd_event_add_time(acd->event, &timer, clock_boottime_or_monotonic(), time_now + next_timeout, 0, ipv4acd_on_timeout, acd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_source_set_priority(timer, ll->event_priority);
|
||||
r = sd_event_source_set_priority(timer, acd->event_priority);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_source_set_description(timer, "ipv4acd-timer");
|
||||
if (r < 0)
|
||||
return r;
|
||||
(void) sd_event_source_set_description(timer, "ipv4acd-timer");
|
||||
|
||||
ll->timer = sd_event_source_unref(ll->timer);
|
||||
ll->timer = timer;
|
||||
sd_event_source_unref(acd->timer_event_source);
|
||||
acd->timer_event_source = timer;
|
||||
timer = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ipv4acd_arp_conflict(sd_ipv4acd *ll, struct ether_arp *arp) {
|
||||
assert(ll);
|
||||
static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) {
|
||||
assert(acd);
|
||||
assert(arp);
|
||||
|
||||
/* see the BPF */
|
||||
if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0)
|
||||
if (memcmp(arp->arp_spa, &acd->address, sizeof(acd->address)) == 0)
|
||||
return true;
|
||||
|
||||
/* the TPA matched instead of the SPA, this is not a conflict */
|
||||
@@ -237,116 +227,118 @@ static bool ipv4acd_arp_conflict(sd_ipv4acd *ll, struct ether_arp *arp) {
|
||||
}
|
||||
|
||||
static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
sd_ipv4acd *ll = userdata;
|
||||
sd_ipv4acd *acd = userdata;
|
||||
int r = 0;
|
||||
|
||||
assert(ll);
|
||||
assert(acd);
|
||||
|
||||
switch (ll->state) {
|
||||
case IPV4ACD_STATE_INIT:
|
||||
switch (acd->state) {
|
||||
|
||||
ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true);
|
||||
case IPV4ACD_STATE_STARTED:
|
||||
ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true);
|
||||
|
||||
if (ll->conflict >= MAX_CONFLICTS) {
|
||||
log_ipv4acd_notice(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL);
|
||||
r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
|
||||
if (acd->n_conflict >= MAX_CONFLICTS) {
|
||||
char ts[FORMAT_TIMESPAN_MAX];
|
||||
log_ipv4acd(acd, "Max conflicts reached, delaying by %s", format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0));
|
||||
|
||||
r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
goto fail;
|
||||
|
||||
ll->conflict = 0;
|
||||
acd->n_conflict = 0;
|
||||
} else {
|
||||
r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT);
|
||||
r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IPV4ACD_STATE_WAITING_PROBE:
|
||||
case IPV4ACD_STATE_PROBING:
|
||||
/* Send a probe */
|
||||
r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr);
|
||||
r = arp_send_probe(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
|
||||
if (r < 0) {
|
||||
log_ipv4acd_error_errno(ll, r, "Failed to send ARP probe: %m");
|
||||
goto out;
|
||||
log_ipv4acd_errno(acd, r, "Failed to send ARP probe: %m");
|
||||
goto fail;
|
||||
} else {
|
||||
_cleanup_free_ char *address = NULL;
|
||||
union in_addr_union addr = { .in.s_addr = ll->address };
|
||||
union in_addr_union addr = { .in.s_addr = acd->address };
|
||||
|
||||
r = in_addr_to_string(AF_INET, &addr, &address);
|
||||
if (r >= 0)
|
||||
log_ipv4acd_debug(ll, "Probing %s", address);
|
||||
(void) in_addr_to_string(AF_INET, &addr, &address);
|
||||
log_ipv4acd(acd, "Probing %s", strna(address));
|
||||
}
|
||||
|
||||
if (ll->iteration < PROBE_NUM - 2) {
|
||||
ipv4acd_set_state(ll, IPV4ACD_STATE_PROBING, false);
|
||||
if (acd->n_iteration < PROBE_NUM - 2) {
|
||||
ipv4acd_set_state(acd, IPV4ACD_STATE_PROBING, false);
|
||||
|
||||
r = ipv4acd_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));
|
||||
r = ipv4acd_set_next_wakeup(acd, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC));
|
||||
if (r < 0)
|
||||
goto out;
|
||||
goto fail;
|
||||
} else {
|
||||
ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_ANNOUNCE, true);
|
||||
ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_ANNOUNCE, true);
|
||||
|
||||
r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);
|
||||
r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_WAIT_USEC, 0);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IPV4ACD_STATE_ANNOUNCING:
|
||||
if (ll->iteration >= ANNOUNCE_NUM - 1) {
|
||||
ipv4acd_set_state(ll, IPV4ACD_STATE_RUNNING, false);
|
||||
|
||||
if (acd->n_iteration >= ANNOUNCE_NUM - 1) {
|
||||
ipv4acd_set_state(acd, IPV4ACD_STATE_RUNNING, false);
|
||||
break;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
|
||||
case IPV4ACD_STATE_WAITING_ANNOUNCE:
|
||||
/* Send announcement packet */
|
||||
r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
|
||||
r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
|
||||
if (r < 0) {
|
||||
log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m");
|
||||
goto out;
|
||||
log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
|
||||
goto fail;
|
||||
} else
|
||||
log_ipv4acd_debug(ll, "ANNOUNCE");
|
||||
log_ipv4acd(acd, "ANNOUNCE");
|
||||
|
||||
ipv4acd_set_state(ll, IPV4ACD_STATE_ANNOUNCING, false);
|
||||
ipv4acd_set_state(acd, IPV4ACD_STATE_ANNOUNCING, false);
|
||||
|
||||
r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);
|
||||
r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_INTERVAL_USEC, 0);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
goto fail;
|
||||
|
||||
if (ll->iteration == 0) {
|
||||
ll->conflict = 0;
|
||||
ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_BIND);
|
||||
if (acd->n_iteration == 0) {
|
||||
acd->n_conflict = 0;
|
||||
ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_BIND);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Invalid state.");
|
||||
}
|
||||
|
||||
out:
|
||||
if (r < 0)
|
||||
sd_ipv4acd_stop(ll);
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
sd_ipv4acd_stop(acd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipv4acd_on_conflict(sd_ipv4acd *ll) {
|
||||
static void ipv4acd_on_conflict(sd_ipv4acd *acd) {
|
||||
_cleanup_free_ char *address = NULL;
|
||||
union in_addr_union addr = { .in.s_addr = ll->address };
|
||||
int r;
|
||||
union in_addr_union addr = { .in.s_addr = acd->address };
|
||||
|
||||
assert(ll);
|
||||
assert(acd);
|
||||
|
||||
ll->conflict++;
|
||||
acd->n_conflict++;
|
||||
|
||||
r = in_addr_to_string(AF_INET, &addr, &address);
|
||||
if (r >= 0)
|
||||
log_ipv4acd_debug(ll, "Conflict on %s (%u)", address, ll->conflict);
|
||||
(void) in_addr_to_string(AF_INET, &addr, &address);
|
||||
log_ipv4acd(acd, "Conflict on %s (%u)", strna(address), acd->n_conflict);
|
||||
|
||||
ipv4acd_stop(ll);
|
||||
|
||||
ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_CONFLICT);
|
||||
ipv4acd_reset(acd);
|
||||
ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_CONFLICT);
|
||||
}
|
||||
|
||||
static int ipv4acd_on_packet(
|
||||
@@ -355,47 +347,50 @@ static int ipv4acd_on_packet(
|
||||
uint32_t revents,
|
||||
void *userdata) {
|
||||
|
||||
sd_ipv4acd *ll = userdata;
|
||||
sd_ipv4acd *acd = userdata;
|
||||
struct ether_arp packet;
|
||||
ssize_t n;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(ll);
|
||||
assert(acd);
|
||||
assert(fd >= 0);
|
||||
|
||||
n = recv(fd, &packet, sizeof(struct ether_arp), 0);
|
||||
if (n < 0) {
|
||||
r = log_ipv4acd_debug_errno(ll, errno, "Failed to read ARP packet: %m");
|
||||
goto out;
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
return 0;
|
||||
|
||||
log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m");
|
||||
goto fail;
|
||||
}
|
||||
if ((size_t) n != sizeof(struct ether_arp)) {
|
||||
log_ipv4acd_debug(ll, "Ignoring too short ARP packet.");
|
||||
log_ipv4acd(acd, "Ignoring too short ARP packet.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (ll->state) {
|
||||
switch (acd->state) {
|
||||
|
||||
case IPV4ACD_STATE_ANNOUNCING:
|
||||
case IPV4ACD_STATE_RUNNING:
|
||||
|
||||
if (ipv4acd_arp_conflict(ll, &packet)) {
|
||||
if (ipv4acd_arp_conflict(acd, &packet)) {
|
||||
usec_t ts;
|
||||
|
||||
assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &ts) >= 0);
|
||||
assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &ts) >= 0);
|
||||
|
||||
/* Defend address */
|
||||
if (ts > ll->defend_window) {
|
||||
ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC;
|
||||
r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
|
||||
if (ts > acd->defend_window) {
|
||||
acd->defend_window = ts + DEFEND_INTERVAL_USEC;
|
||||
r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
|
||||
if (r < 0) {
|
||||
log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m");
|
||||
goto out;
|
||||
log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
|
||||
goto fail;
|
||||
} else
|
||||
log_ipv4acd_debug(ll, "DEFEND");
|
||||
log_ipv4acd(acd, "DEFEND");
|
||||
|
||||
} else
|
||||
ipv4acd_on_conflict(ll);
|
||||
ipv4acd_on_conflict(acd);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -403,132 +398,129 @@ static int ipv4acd_on_packet(
|
||||
case IPV4ACD_STATE_PROBING:
|
||||
case IPV4ACD_STATE_WAITING_ANNOUNCE:
|
||||
/* BPF ensures this packet indicates a conflict */
|
||||
ipv4acd_on_conflict(ll);
|
||||
ipv4acd_on_conflict(acd);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Invalid state.");
|
||||
}
|
||||
|
||||
out:
|
||||
if (r < 0)
|
||||
sd_ipv4acd_stop(ll);
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
sd_ipv4acd_stop(acd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(interface_index > 0, -EINVAL);
|
||||
assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) {
|
||||
assert_return(acd, -EINVAL);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
|
||||
ll->index = interface_index;
|
||||
acd->ifindex = ifindex;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr) {
|
||||
assert_return(ll, -EINVAL);
|
||||
int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) {
|
||||
assert_return(acd, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
|
||||
memcpy(&ll->mac_addr, addr, ETH_ALEN);
|
||||
acd->mac_addr = *addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_detach_event(sd_ipv4acd *ll) {
|
||||
assert_return(ll, -EINVAL);
|
||||
int sd_ipv4acd_detach_event(sd_ipv4acd *acd) {
|
||||
assert_return(acd, -EINVAL);
|
||||
|
||||
ll->event = sd_event_unref(ll->event);
|
||||
acd->event = sd_event_unref(acd->event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority) {
|
||||
int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(!ll->event, -EBUSY);
|
||||
assert_return(acd, -EINVAL);
|
||||
assert_return(!acd->event, -EBUSY);
|
||||
|
||||
if (event)
|
||||
ll->event = sd_event_ref(event);
|
||||
acd->event = sd_event_ref(event);
|
||||
else {
|
||||
r = sd_event_default(&ll->event);
|
||||
r = sd_event_default(&acd->event);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ll->event_priority = priority;
|
||||
acd->event_priority = priority;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata) {
|
||||
assert_return(ll, -EINVAL);
|
||||
int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata) {
|
||||
assert_return(acd, -EINVAL);
|
||||
|
||||
ll->cb = cb;
|
||||
ll->userdata = userdata;
|
||||
acd->callback = cb;
|
||||
acd->userdata = userdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address) {
|
||||
assert_return(ll, -EINVAL);
|
||||
int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address) {
|
||||
assert_return(acd, -EINVAL);
|
||||
assert_return(address, -EINVAL);
|
||||
assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
|
||||
ll->address = address->s_addr;
|
||||
acd->address = address->s_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_is_running(sd_ipv4acd *ll) {
|
||||
assert_return(ll, false);
|
||||
int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
|
||||
assert_return(acd, false);
|
||||
|
||||
return ll->state != IPV4ACD_STATE_INIT;
|
||||
return acd->state != IPV4ACD_STATE_INIT;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_start(sd_ipv4acd *ll) {
|
||||
int sd_ipv4acd_start(sd_ipv4acd *acd) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(ll->event, -EINVAL);
|
||||
assert_return(ll->index > 0, -EINVAL);
|
||||
assert_return(ll->address != 0, -EINVAL);
|
||||
assert_return(!ether_addr_is_null(&ll->mac_addr), -EINVAL);
|
||||
assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
assert_return(acd, -EINVAL);
|
||||
assert_return(acd->event, -EINVAL);
|
||||
assert_return(acd->ifindex > 0, -EINVAL);
|
||||
assert_return(acd->address != 0, -EINVAL);
|
||||
assert_return(!ether_addr_is_null(&acd->mac_addr), -EINVAL);
|
||||
assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
|
||||
ll->defend_window = 0;
|
||||
|
||||
r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr);
|
||||
r = arp_network_bind_raw_socket(acd->ifindex, acd->address, &acd->mac_addr);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
ll->fd = safe_close(ll->fd);
|
||||
ll->fd = r;
|
||||
|
||||
r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
|
||||
EPOLLIN, ipv4acd_on_packet, ll);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_source_set_description(ll->receive_message, "ipv4acd-receive-message");
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = ipv4acd_set_next_wakeup(ll, 0, 0);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
out:
|
||||
if (r < 0) {
|
||||
ipv4acd_stop(ll);
|
||||
return r;
|
||||
}
|
||||
|
||||
safe_close(acd->fd);
|
||||
acd->fd = r;
|
||||
acd->defend_window = 0;
|
||||
acd->n_conflict = 0;
|
||||
|
||||
r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_event_source_set_priority(acd->receive_message_event_source, acd->event_priority);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
(void) sd_event_source_set_description(acd->receive_message_event_source, "ipv4acd-receive-message");
|
||||
|
||||
r = ipv4acd_set_next_wakeup(acd, 0, 0);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
ipv4acd_set_state(acd, IPV4ACD_STATE_STARTED, true);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ipv4acd_reset(acd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -28,16 +28,17 @@
|
||||
#include "sd-ipv4ll.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "list.h"
|
||||
#include "random-util.h"
|
||||
#include "refcnt.h"
|
||||
#include "siphash24.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
#define IPV4LL_NETWORK 0xA9FE0000L
|
||||
#define IPV4LL_NETMASK 0xFFFF0000L
|
||||
#define IPV4LL_NETWORK UINT32_C(0xA9FE0000)
|
||||
#define IPV4LL_NETMASK UINT32_C(0xFFFF0000)
|
||||
|
||||
#define IPV4LL_DONT_DESTROY(ll) \
|
||||
_cleanup_(sd_ipv4ll_unrefp) _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll)
|
||||
@@ -46,16 +47,28 @@ struct sd_ipv4ll {
|
||||
unsigned n_ref;
|
||||
|
||||
sd_ipv4acd *acd;
|
||||
|
||||
be32_t address; /* the address pushed to ACD */
|
||||
struct random_data *random_data;
|
||||
char *random_data_state;
|
||||
struct ether_addr mac;
|
||||
|
||||
struct {
|
||||
le64_t value;
|
||||
le64_t generation;
|
||||
} seed;
|
||||
bool seed_set;
|
||||
|
||||
/* External */
|
||||
be32_t claimed_address;
|
||||
sd_ipv4ll_callback_t cb;
|
||||
|
||||
sd_ipv4ll_callback_t callback;
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
#define log_ipv4ll_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "IPV4LL: " fmt, ##__VA_ARGS__)
|
||||
#define log_ipv4ll(ll, fmt, ...) log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__)
|
||||
|
||||
static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata);
|
||||
|
||||
sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) {
|
||||
if (!ll)
|
||||
return NULL;
|
||||
@@ -77,16 +90,11 @@ sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) {
|
||||
return NULL;
|
||||
|
||||
sd_ipv4acd_unref(ll->acd);
|
||||
|
||||
free(ll->random_data);
|
||||
free(ll->random_data_state);
|
||||
free(ll);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata);
|
||||
|
||||
int sd_ipv4ll_new(sd_ipv4ll **ret) {
|
||||
_cleanup_(sd_ipv4ll_unrefp) sd_ipv4ll *ll = NULL;
|
||||
int r;
|
||||
@@ -114,44 +122,32 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) {
|
||||
}
|
||||
|
||||
int sd_ipv4ll_stop(sd_ipv4ll *ll) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
r = sd_ipv4acd_stop(ll->acd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
return sd_ipv4acd_stop(ll->acd);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) {
|
||||
int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int ifindex) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
|
||||
|
||||
return sd_ipv4acd_set_index(ll->acd, interface_index);
|
||||
return sd_ipv4acd_set_ifindex(ll->acd, ifindex);
|
||||
}
|
||||
|
||||
#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
|
||||
|
||||
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
|
||||
|
||||
if (!ll->random_data) {
|
||||
uint64_t seed;
|
||||
r = sd_ipv4acd_set_mac(ll->acd, addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* If no random data is set, generate some from the MAC */
|
||||
seed = siphash24(&addr->ether_addr_octet, ETH_ALEN, HASH_KEY.bytes);
|
||||
|
||||
assert_cc(sizeof(unsigned) <= 8);
|
||||
|
||||
r = sd_ipv4ll_set_address_seed(ll, (unsigned) htole64(seed));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_ipv4acd_set_mac(ll->acd, addr);
|
||||
ll->mac = *addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
|
||||
@@ -161,21 +157,15 @@ int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
|
||||
}
|
||||
|
||||
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
r = sd_ipv4acd_attach_event(ll->acd, event, priority);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
return sd_ipv4acd_attach_event(ll->acd, event, priority);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
ll->cb = cb;
|
||||
ll->callback = cb;
|
||||
ll->userdata = userdata;
|
||||
|
||||
return 0;
|
||||
@@ -193,32 +183,12 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
|
||||
_cleanup_free_ struct random_data *random_data = NULL;
|
||||
_cleanup_free_ char *random_data_state = NULL;
|
||||
int r;
|
||||
|
||||
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
|
||||
|
||||
random_data = new0(struct random_data, 1);
|
||||
if (!random_data)
|
||||
return -ENOMEM;
|
||||
|
||||
random_data_state = new0(char, 128);
|
||||
if (!random_data_state)
|
||||
return -ENOMEM;
|
||||
|
||||
r = initstate_r(seed, random_data_state, 128, random_data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
free(ll->random_data);
|
||||
ll->random_data = random_data;
|
||||
random_data = NULL;
|
||||
|
||||
free(ll->random_data_state);
|
||||
ll->random_data_state = random_data_state;
|
||||
random_data_state = NULL;
|
||||
ll->seed.value = htole64(seed);
|
||||
ll->seed_set = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -230,20 +200,12 @@ int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
|
||||
}
|
||||
|
||||
static bool ipv4ll_address_is_valid(const struct in_addr *address) {
|
||||
uint32_t addr;
|
||||
|
||||
assert(address);
|
||||
|
||||
if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address))
|
||||
return false;
|
||||
|
||||
addr = be32toh(address->s_addr);
|
||||
|
||||
if ((addr & 0x0000FF00) == 0x0000 ||
|
||||
(addr & 0x0000FF00) == 0xFF00)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return !IN_SET(be32toh(address->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) {
|
||||
@@ -262,48 +224,67 @@ int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PICK_HASH_KEY SD_ID128_MAKE(15,ac,82,a6,d6,3f,49,78,98,77,5d,0c,69,02,94,0b)
|
||||
|
||||
static int ipv4ll_pick_address(sd_ipv4ll *ll) {
|
||||
struct in_addr in_addr;
|
||||
_cleanup_free_ char *address = NULL;
|
||||
be32_t addr;
|
||||
int r;
|
||||
int32_t random;
|
||||
|
||||
assert(ll);
|
||||
assert(ll->random_data);
|
||||
|
||||
do {
|
||||
r = random_r(ll->random_data, &random);
|
||||
if (r < 0)
|
||||
return r;
|
||||
addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
|
||||
uint64_t h;
|
||||
|
||||
h = siphash24(&ll->seed, sizeof(ll->seed), PICK_HASH_KEY.bytes);
|
||||
|
||||
/* Increase the generation counter by one */
|
||||
ll->seed.generation = htole64(le64toh(ll->seed.generation) + 1);
|
||||
|
||||
addr = htobe32((h & UINT32_C(0x0000FFFF)) | IPV4LL_NETWORK);
|
||||
} while (addr == ll->address ||
|
||||
(ntohl(addr) & 0x0000FF00) == 0x0000 ||
|
||||
(ntohl(addr) & 0x0000FF00) == 0xFF00);
|
||||
IN_SET(be32toh(addr) & 0x0000FF00U, 0x0000U, 0xFF00U));
|
||||
|
||||
in_addr.s_addr = addr;
|
||||
(void) in_addr_to_string(AF_INET, &(union in_addr_union) { .in.s_addr = addr }, &address);
|
||||
log_ipv4ll(ll, "Picked new IP address %s.", strna(address));
|
||||
|
||||
r = sd_ipv4ll_set_address(ll, &in_addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr });
|
||||
}
|
||||
|
||||
#define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
|
||||
|
||||
int sd_ipv4ll_start(sd_ipv4ll *ll) {
|
||||
int r;
|
||||
bool picked_address = false;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(ll->random_data, -EINVAL);
|
||||
assert_return(!ether_addr_is_null(&ll->mac), -EINVAL);
|
||||
assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
|
||||
|
||||
/* If no random seed is set, generate some from the MAC address */
|
||||
if (!ll->seed_set)
|
||||
ll->seed.value = htole64(siphash24(ll->mac.ether_addr_octet, ETH_ALEN, MAC_HASH_KEY.bytes));
|
||||
|
||||
/* Restart the generation counter. */
|
||||
ll->seed.generation = 0;
|
||||
|
||||
if (ll->address == 0) {
|
||||
r = ipv4ll_pick_address(ll);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
picked_address = true;
|
||||
}
|
||||
|
||||
r = sd_ipv4acd_start(ll->acd);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
|
||||
/* We couldn't start? If so, let's forget the picked address again, the user might make a change and
|
||||
* retry, and we want the new data to take effect when picking an address. */
|
||||
if (picked_address)
|
||||
ll->address = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -311,8 +292,8 @@ int sd_ipv4ll_start(sd_ipv4ll *ll) {
|
||||
static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
|
||||
assert(ll);
|
||||
|
||||
if (ll->cb)
|
||||
ll->cb(ll, event, ll->userdata);
|
||||
if (ll->callback)
|
||||
ll->callback(ll, event, ll->userdata);
|
||||
}
|
||||
|
||||
void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
@@ -324,17 +305,17 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
assert(ll);
|
||||
|
||||
switch (event) {
|
||||
|
||||
case SD_IPV4ACD_EVENT_STOP:
|
||||
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP);
|
||||
|
||||
ll->claimed_address = 0;
|
||||
|
||||
break;
|
||||
|
||||
case SD_IPV4ACD_EVENT_BIND:
|
||||
ll->claimed_address = ll->address;
|
||||
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_BIND);
|
||||
|
||||
break;
|
||||
|
||||
case SD_IPV4ACD_EVENT_CONFLICT:
|
||||
/* if an address was already bound we must call up to the
|
||||
user to handle this, otherwise we just try again */
|
||||
@@ -353,6 +334,7 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Invalid IPv4ACD event.");
|
||||
}
|
||||
|
||||
+112
-118
@@ -34,20 +34,20 @@
|
||||
#include "socket-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
#define NDISC_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC
|
||||
#define NDISC_MAX_ROUTER_SOLICITATIONS 3
|
||||
#define NDISC_ROUTER_SOLICITATION_INTERVAL (4U * USEC_PER_SEC)
|
||||
#define NDISC_MAX_ROUTER_SOLICITATIONS 3U
|
||||
|
||||
enum NDiscState {
|
||||
NDISC_STATE_IDLE,
|
||||
NDISC_STATE_SOLICITATION_SENT,
|
||||
NDISC_STATE_ADVERTISMENT_LISTEN,
|
||||
NDISC_STATE_ADVERTISEMENT_LISTEN,
|
||||
_NDISC_STATE_MAX,
|
||||
_NDISC_STATE_INVALID = -1,
|
||||
};
|
||||
|
||||
#define IP6_MIN_MTU (unsigned)1280
|
||||
#define IP6_MIN_MTU 1280U
|
||||
#define ICMP6_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr))
|
||||
#define NDISC_OPT_LEN_UNITS 8
|
||||
#define NDISC_OPT_LEN_UNITS 8U
|
||||
|
||||
#define ND_RA_FLAG_PREF 0x18
|
||||
#define ND_RA_FLAG_PREF_LOW 0x03
|
||||
@@ -73,16 +73,22 @@ struct sd_ndisc {
|
||||
unsigned n_ref;
|
||||
|
||||
enum NDiscState state;
|
||||
int ifindex;
|
||||
int fd;
|
||||
|
||||
sd_event *event;
|
||||
int event_priority;
|
||||
int index;
|
||||
|
||||
struct ether_addr mac_addr;
|
||||
uint32_t mtu;
|
||||
|
||||
LIST_HEAD(NDiscPrefix, prefixes);
|
||||
int fd;
|
||||
sd_event_source *recv;
|
||||
sd_event_source *timeout;
|
||||
int nd_sent;
|
||||
|
||||
sd_event_source *recv_event_source;
|
||||
sd_event_source *timeout_event_source;
|
||||
|
||||
unsigned nd_sent;
|
||||
|
||||
sd_ndisc_router_callback_t router_callback;
|
||||
sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback;
|
||||
sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback;
|
||||
@@ -90,7 +96,8 @@ struct sd_ndisc {
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
#define log_ndisc(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__)
|
||||
#define log_ndisc_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__)
|
||||
#define log_ndisc(p, fmt, ...) log_ndisc_errno(p, 0, fmt, ##__VA_ARGS__)
|
||||
|
||||
static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) {
|
||||
|
||||
@@ -128,13 +135,15 @@ static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ndisc_set_callback(sd_ndisc *nd,
|
||||
sd_ndisc_router_callback_t router_callback,
|
||||
sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback,
|
||||
sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback,
|
||||
sd_ndisc_callback_t callback,
|
||||
void *userdata) {
|
||||
assert(nd);
|
||||
int sd_ndisc_set_callback(
|
||||
sd_ndisc *nd,
|
||||
sd_ndisc_router_callback_t router_callback,
|
||||
sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback,
|
||||
sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback,
|
||||
sd_ndisc_callback_t callback,
|
||||
void *userdata) {
|
||||
|
||||
assert_return(nd, -EINVAL);
|
||||
|
||||
nd->router_callback = router_callback;
|
||||
nd->prefix_onlink_callback = prefix_onlink_callback;
|
||||
@@ -145,17 +154,16 @@ int sd_ndisc_set_callback(sd_ndisc *nd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ndisc_set_index(sd_ndisc *nd, int interface_index) {
|
||||
assert(nd);
|
||||
assert(interface_index >= -1);
|
||||
|
||||
nd->index = interface_index;
|
||||
int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) {
|
||||
assert_return(nd, -EINVAL);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
|
||||
nd->ifindex = ifindex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) {
|
||||
assert(nd);
|
||||
assert_return(nd, -EINVAL);
|
||||
|
||||
if (mac_addr)
|
||||
memcpy(&nd->mac_addr, mac_addr, sizeof(nd->mac_addr));
|
||||
@@ -194,7 +202,7 @@ int sd_ndisc_detach_event(sd_ndisc *nd) {
|
||||
}
|
||||
|
||||
sd_event *sd_ndisc_get_event(sd_ndisc *nd) {
|
||||
assert(nd);
|
||||
assert_return(nd, NULL);
|
||||
|
||||
return nd->event;
|
||||
}
|
||||
@@ -210,12 +218,12 @@ sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) {
|
||||
return nd;
|
||||
}
|
||||
|
||||
static int ndisc_init(sd_ndisc *nd) {
|
||||
static int ndisc_reset(sd_ndisc *nd) {
|
||||
assert(nd);
|
||||
|
||||
nd->recv = sd_event_source_unref(nd->recv);
|
||||
nd->recv_event_source = sd_event_source_unref(nd->recv_event_source);
|
||||
nd->fd = asynchronous_close(nd->fd);
|
||||
nd->timeout = sd_event_source_unref(nd->timeout);
|
||||
nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -232,7 +240,7 @@ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) {
|
||||
if (nd->n_ref > 0)
|
||||
return NULL;
|
||||
|
||||
ndisc_init(nd);
|
||||
ndisc_reset(nd);
|
||||
sd_ndisc_detach_event(nd);
|
||||
|
||||
LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes)
|
||||
@@ -246,15 +254,14 @@ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) {
|
||||
int sd_ndisc_new(sd_ndisc **ret) {
|
||||
_cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
|
||||
|
||||
assert(ret);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
nd = new0(sd_ndisc, 1);
|
||||
if (!nd)
|
||||
return -ENOMEM;
|
||||
|
||||
nd->n_ref = 1;
|
||||
|
||||
nd->index = -1;
|
||||
nd->ifindex = -1;
|
||||
nd->fd = -1;
|
||||
|
||||
LIST_HEAD_INIT(nd->prefixes);
|
||||
@@ -273,7 +280,6 @@ int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) {
|
||||
return -ENOMSG;
|
||||
|
||||
*mtu = nd->mtu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -282,8 +288,8 @@ static int prefix_match(const struct in6_addr *prefix, uint8_t prefixlen,
|
||||
uint8_t addr_prefixlen) {
|
||||
uint8_t bytes, mask, len;
|
||||
|
||||
assert_return(prefix, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert(prefix);
|
||||
assert(addr);
|
||||
|
||||
len = MIN(prefixlen, addr_prefixlen);
|
||||
|
||||
@@ -336,7 +342,7 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len,
|
||||
assert(prefix_opt);
|
||||
|
||||
if (len < prefix_opt->nd_opt_pi_len)
|
||||
return -ENOMSG;
|
||||
return -EBADMSG;
|
||||
|
||||
if (!(prefix_opt->nd_opt_pi_flags_reserved & (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO)))
|
||||
return 0;
|
||||
@@ -356,7 +362,7 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len,
|
||||
if (r != -EADDRNOTAVAIL)
|
||||
return r;
|
||||
|
||||
/* if router advertisment prefix valid timeout is zero, the timeout
|
||||
/* if router advertisement prefix valid timeout is zero, the timeout
|
||||
callback will be called immediately to clean up the prefix */
|
||||
|
||||
r = ndisc_prefix_new(nd, &prefix);
|
||||
@@ -411,32 +417,32 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len) {
|
||||
void *opt;
|
||||
static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, size_t len) {
|
||||
struct nd_opt_hdr *opt_hdr;
|
||||
void *opt;
|
||||
|
||||
assert_return(nd, -EINVAL);
|
||||
assert_return(ra, -EINVAL);
|
||||
assert(nd);
|
||||
assert(ra);
|
||||
|
||||
len -= sizeof(*ra);
|
||||
if (len < NDISC_OPT_LEN_UNITS) {
|
||||
if (len < sizeof(struct nd_router_advert) + NDISC_OPT_LEN_UNITS) {
|
||||
log_ndisc(nd, "Router Advertisement below minimum length");
|
||||
|
||||
return -ENOMSG;
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
len -= sizeof(struct nd_router_advert);
|
||||
opt = ra + 1;
|
||||
opt_hdr = opt;
|
||||
|
||||
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;
|
||||
uint32_t mtu;
|
||||
|
||||
if (opt_hdr->nd_opt_len == 0)
|
||||
return -ENOMSG;
|
||||
return -EBADMSG;
|
||||
|
||||
switch (opt_hdr->nd_opt_type) {
|
||||
|
||||
case ND_OPT_MTU:
|
||||
opt_mtu = opt;
|
||||
|
||||
@@ -444,24 +450,19 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len
|
||||
|
||||
if (mtu != nd->mtu) {
|
||||
nd->mtu = MAX(mtu, IP6_MIN_MTU);
|
||||
|
||||
log_ndisc(nd, "Router Advertisement link MTU %d using %d",
|
||||
mtu, nd->mtu);
|
||||
log_ndisc(nd, "Router Advertisement link MTU %d using %d", mtu, nd->mtu);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ND_OPT_PREFIX_INFORMATION:
|
||||
opt_prefix = opt;
|
||||
|
||||
ndisc_prefix_update(nd, len, opt_prefix);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
len -= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS;
|
||||
opt = (void *)((char *)opt +
|
||||
opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS);
|
||||
opt = (void*) ((uint8_t*) opt + opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS);
|
||||
opt_hdr = opt;
|
||||
}
|
||||
|
||||
@@ -471,7 +472,7 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
_cleanup_free_ struct nd_router_advert *ra = NULL;
|
||||
sd_ndisc *nd = userdata;
|
||||
union {
|
||||
@@ -515,11 +516,14 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
return 0;
|
||||
|
||||
log_ndisc(nd, "Could not receive message from ICMPv6 socket: %m");
|
||||
return -errno;
|
||||
} else if ((size_t)len < sizeof(struct nd_router_advert)) {
|
||||
return log_ndisc_errno(nd, errno, "Could not receive message from ICMPv6 socket: %m");
|
||||
}
|
||||
if ((size_t) len < sizeof(struct nd_router_advert)) {
|
||||
log_ndisc(nd, "Too small to be a router advertisement: ignoring");
|
||||
return 0;
|
||||
} else if (msg.msg_namelen == 0)
|
||||
}
|
||||
|
||||
if (msg.msg_namelen == 0)
|
||||
gw = NULL; /* only happens when running the test-suite over a socketpair */
|
||||
else if (msg.msg_namelen != sizeof(sa.in6)) {
|
||||
log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)msg.msg_namelen);
|
||||
@@ -560,21 +564,14 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
|
||||
if (ra->nd_ra_code != 0)
|
||||
return 0;
|
||||
|
||||
nd->timeout = sd_event_source_unref(nd->timeout);
|
||||
|
||||
nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
|
||||
nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source);
|
||||
nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN;
|
||||
|
||||
stateful = ra->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER);
|
||||
pref = (ra->nd_ra_flags_reserved & ND_RA_FLAG_PREF) >> 3;
|
||||
|
||||
switch (pref) {
|
||||
case ND_RA_FLAG_PREF_LOW:
|
||||
case ND_RA_FLAG_PREF_HIGH:
|
||||
break;
|
||||
default:
|
||||
if (!IN_SET(pref, ND_RA_FLAG_PREF_LOW, ND_RA_FLAG_PREF_HIGH))
|
||||
pref = ND_RA_FLAG_PREF_MEDIUM;
|
||||
break;
|
||||
}
|
||||
|
||||
lifetime = be16toh(ra->nd_ra_router_lifetime);
|
||||
|
||||
@@ -583,9 +580,9 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
|
||||
pref == ND_RA_FLAG_PREF_HIGH ? "high" : pref == ND_RA_FLAG_PREF_LOW ? "low" : "medium",
|
||||
lifetime);
|
||||
|
||||
r = ndisc_ra_parse(nd, ra, len);
|
||||
r = ndisc_ra_parse(nd, ra, (size_t) len);
|
||||
if (r < 0) {
|
||||
log_ndisc(nd, "Could not parse Router Advertisement: %s", strerror(-r));
|
||||
log_ndisc_errno(nd, r, "Could not parse Router Advertisement: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -597,24 +594,25 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
|
||||
|
||||
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;
|
||||
usec_t time_now, next_timeout;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(nd);
|
||||
assert(nd->event);
|
||||
|
||||
nd->timeout = sd_event_source_unref(nd->timeout);
|
||||
nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source);
|
||||
|
||||
if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) {
|
||||
if (nd->callback)
|
||||
nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata);
|
||||
nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
|
||||
nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN;
|
||||
} else {
|
||||
r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr);
|
||||
if (r < 0)
|
||||
log_ndisc(nd, "Error sending Router Solicitation");
|
||||
else {
|
||||
if (r < 0) {
|
||||
log_ndisc_errno(nd, r, "Error sending Router Solicitation: %m");
|
||||
goto fail;
|
||||
} else {
|
||||
nd->state = NDISC_STATE_SOLICITATION_SENT;
|
||||
log_ndisc(nd, "Sent Router Solicitation");
|
||||
}
|
||||
@@ -625,35 +623,39 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
|
||||
|
||||
next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL;
|
||||
|
||||
r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
|
||||
r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(),
|
||||
next_timeout, 0,
|
||||
ndisc_router_solicitation_timeout, nd);
|
||||
if (r < 0) {
|
||||
/* we cannot continue if we are unable to rearm the timer */
|
||||
sd_ndisc_stop(nd);
|
||||
return 0;
|
||||
log_ndisc_errno(nd, r, "Failed to allocate timer event: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_event_source_set_priority(nd->timeout, nd->event_priority);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
r = sd_event_source_set_priority(nd->timeout_event_source, nd->event_priority);
|
||||
if (r < 0) {
|
||||
log_ndisc_errno(nd, r, "Cannot set timer priority: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_event_source_set_description(nd->timeout, "ndisc-timeout");
|
||||
if (r < 0)
|
||||
return 0;
|
||||
(void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
sd_ndisc_stop(nd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ndisc_stop(sd_ndisc *nd) {
|
||||
assert_return(nd, -EINVAL);
|
||||
assert_return(nd->event, -EINVAL);
|
||||
|
||||
log_ndisc(client, "Stop NDisc");
|
||||
if (nd->state == NDISC_STATE_IDLE)
|
||||
return 0;
|
||||
|
||||
ndisc_init(nd);
|
||||
log_ndisc(nd, "Stopping IPv6 Router Solicitation client");
|
||||
|
||||
ndisc_reset(nd);
|
||||
nd->state = NDISC_STATE_IDLE;
|
||||
|
||||
if (nd->callback)
|
||||
@@ -665,49 +667,41 @@ int sd_ndisc_stop(sd_ndisc *nd) {
|
||||
int sd_ndisc_router_discovery_start(sd_ndisc *nd) {
|
||||
int r;
|
||||
|
||||
assert(nd);
|
||||
assert(nd->event);
|
||||
assert_return(nd, -EINVAL);
|
||||
assert_return(nd->event, -EINVAL);
|
||||
assert_return(nd->ifindex > 0, -EINVAL);
|
||||
assert_return(nd->state == NDISC_STATE_IDLE, -EBUSY);
|
||||
|
||||
if (nd->state != NDISC_STATE_IDLE)
|
||||
return -EBUSY;
|
||||
|
||||
if (nd->index < 1)
|
||||
return -EINVAL;
|
||||
|
||||
r = icmp6_bind_router_solicitation(nd->index);
|
||||
r = icmp6_bind_router_solicitation(nd->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
nd->fd = r;
|
||||
|
||||
r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN,
|
||||
ndisc_router_advertisment_recv, nd);
|
||||
r = sd_event_add_io(nd->event, &nd->recv_event_source, nd->fd, EPOLLIN, ndisc_router_advertisement_recv, nd);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
goto fail;
|
||||
|
||||
r = sd_event_source_set_priority(nd->recv, nd->event_priority);
|
||||
r = sd_event_source_set_priority(nd->recv_event_source, nd->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
goto fail;
|
||||
|
||||
r = sd_event_source_set_description(nd->recv, "ndisc-receive-message");
|
||||
(void) sd_event_source_set_description(nd->recv_event_source, "ndisc-receive-message");
|
||||
|
||||
r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), 0, 0, ndisc_router_solicitation_timeout, nd);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
goto fail;
|
||||
|
||||
r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
|
||||
0, 0, ndisc_router_solicitation_timeout, nd);
|
||||
r = sd_event_source_set_priority(nd->timeout_event_source, nd->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
goto fail;
|
||||
|
||||
r = sd_event_source_set_priority(nd->timeout, nd->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
(void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout");
|
||||
|
||||
r = sd_event_source_set_description(nd->timeout, "ndisc-timeout");
|
||||
error:
|
||||
if (r < 0)
|
||||
ndisc_init(nd);
|
||||
else
|
||||
log_ndisc(client, "Start Router Solicitation");
|
||||
log_ndisc(ns, "Started IPv6 Router Solicitation client");
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ndisc_reset(nd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ static int client_run(int ifindex, const struct in_addr *pa, const struct ether_
|
||||
assert_se(sd_ipv4acd_new(&acd) >= 0);
|
||||
assert_se(sd_ipv4acd_attach_event(acd, e, 0) >= 0);
|
||||
|
||||
assert_se(sd_ipv4acd_set_index(acd, ifindex) >= 0);
|
||||
assert_se(sd_ipv4acd_set_ifindex(acd, ifindex) >= 0);
|
||||
assert_se(sd_ipv4acd_set_mac(acd, ha) >= 0);
|
||||
assert_se(sd_ipv4acd_set_address(acd, pa) >= 0);
|
||||
assert_se(sd_ipv4acd_set_callback(acd, acd_handler, NULL) >= 0);
|
||||
|
||||
@@ -66,13 +66,13 @@ static void test_request_basic(sd_event *e) {
|
||||
|
||||
assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
|
||||
assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
|
||||
assert_se(sd_dhcp_client_set_index(NULL, 0) == -EINVAL);
|
||||
assert_se(sd_dhcp_client_set_ifindex(NULL, 0) == -EINVAL);
|
||||
|
||||
assert_se(sd_dhcp_client_set_index(client, 15) == 0);
|
||||
assert_se(sd_dhcp_client_set_index(client, -42) == -EINVAL);
|
||||
assert_se(sd_dhcp_client_set_index(client, -1) == -EINVAL);
|
||||
assert_se(sd_dhcp_client_set_index(client, 0) == -EINVAL);
|
||||
assert_se(sd_dhcp_client_set_index(client, 1) == 0);
|
||||
assert_se(sd_dhcp_client_set_ifindex(client, 15) == 0);
|
||||
assert_se(sd_dhcp_client_set_ifindex(client, -42) == -EINVAL);
|
||||
assert_se(sd_dhcp_client_set_ifindex(client, -1) == -EINVAL);
|
||||
assert_se(sd_dhcp_client_set_ifindex(client, 0) == -EINVAL);
|
||||
assert_se(sd_dhcp_client_set_ifindex(client, 1) == 0);
|
||||
|
||||
assert_se(sd_dhcp_client_set_request_option(client,
|
||||
SD_DHCP_OPTION_SUBNET_MASK) == -EEXIST);
|
||||
@@ -243,7 +243,7 @@ static void test_discover_message(sd_event *e) {
|
||||
r = sd_dhcp_client_attach_event(client, e, 0);
|
||||
assert_se(r >= 0);
|
||||
|
||||
assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
|
||||
assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
|
||||
assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
|
||||
|
||||
assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
|
||||
@@ -458,7 +458,7 @@ static void test_addr_acq(sd_event *e) {
|
||||
r = sd_dhcp_client_attach_event(client, e, 0);
|
||||
assert_se(r >= 0);
|
||||
|
||||
assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
|
||||
assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
|
||||
assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
|
||||
|
||||
assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
|
||||
|
||||
@@ -59,10 +59,10 @@ static int test_client_basic(sd_event *e) {
|
||||
|
||||
assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
|
||||
|
||||
assert_se(sd_dhcp6_client_set_index(client, 15) == 0);
|
||||
assert_se(sd_dhcp6_client_set_index(client, -42) == -EINVAL);
|
||||
assert_se(sd_dhcp6_client_set_index(client, -1) == 0);
|
||||
assert_se(sd_dhcp6_client_set_index(client, 42) >= 0);
|
||||
assert_se(sd_dhcp6_client_set_ifindex(client, 15) == 0);
|
||||
assert_se(sd_dhcp6_client_set_ifindex(client, -42) == -EINVAL);
|
||||
assert_se(sd_dhcp6_client_set_ifindex(client, -1) == 0);
|
||||
assert_se(sd_dhcp6_client_set_ifindex(client, 42) >= 0);
|
||||
|
||||
assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
|
||||
sizeof (mac_addr),
|
||||
@@ -712,7 +712,7 @@ static int test_client_solicit(sd_event *e) {
|
||||
|
||||
assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
|
||||
|
||||
assert_se(sd_dhcp6_client_set_index(client, test_index) == 0);
|
||||
assert_se(sd_dhcp6_client_set_ifindex(client, test_index) == 0);
|
||||
assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
|
||||
sizeof (mac_addr),
|
||||
ARPHRD_ETHER) >= 0);
|
||||
|
||||
@@ -64,7 +64,7 @@ static int client_run(int ifindex, const char *seed_str, const struct ether_addr
|
||||
assert_se(sd_ipv4ll_new(&ll) >= 0);
|
||||
assert_se(sd_ipv4ll_attach_event(ll, e, 0) >= 0);
|
||||
|
||||
assert_se(sd_ipv4ll_set_index(ll, ifindex) >= 0);
|
||||
assert_se(sd_ipv4ll_set_ifindex(ll, ifindex) >= 0);
|
||||
assert_se(sd_ipv4ll_set_mac(ll, ha) >= 0);
|
||||
assert_se(sd_ipv4ll_set_callback(ll, ll_handler, NULL) >= 0);
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_ad
|
||||
|
||||
static void test_public_api_setters(sd_event *e) {
|
||||
struct in_addr address = {};
|
||||
unsigned seed = 0;
|
||||
uint64_t seed = 0;
|
||||
sd_ipv4ll *ll;
|
||||
struct ether_addr mac_addr = {
|
||||
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}};
|
||||
@@ -136,11 +136,11 @@ static void test_public_api_setters(sd_event *e) {
|
||||
assert_se(sd_ipv4ll_set_mac(ll, NULL) == -EINVAL);
|
||||
assert_se(sd_ipv4ll_set_mac(ll, &mac_addr) == 0);
|
||||
|
||||
assert_se(sd_ipv4ll_set_index(NULL, -1) == -EINVAL);
|
||||
assert_se(sd_ipv4ll_set_index(ll, -1) == -EINVAL);
|
||||
assert_se(sd_ipv4ll_set_index(ll, -99) == -EINVAL);
|
||||
assert_se(sd_ipv4ll_set_index(ll, 1) == 0);
|
||||
assert_se(sd_ipv4ll_set_index(ll, 99) == 0);
|
||||
assert_se(sd_ipv4ll_set_ifindex(NULL, -1) == -EINVAL);
|
||||
assert_se(sd_ipv4ll_set_ifindex(ll, -1) == -EINVAL);
|
||||
assert_se(sd_ipv4ll_set_ifindex(ll, -99) == -EINVAL);
|
||||
assert_se(sd_ipv4ll_set_ifindex(ll, 1) == 0);
|
||||
assert_se(sd_ipv4ll_set_ifindex(ll, 99) == 0);
|
||||
|
||||
assert_se(sd_ipv4ll_ref(ll) == ll);
|
||||
assert_se(sd_ipv4ll_unref(ll) == NULL);
|
||||
@@ -172,7 +172,7 @@ static void test_basic_request(sd_event *e) {
|
||||
basic_request_handler_userdata) == 0);
|
||||
assert_se(sd_ipv4ll_start(ll) == -EINVAL);
|
||||
|
||||
assert_se(sd_ipv4ll_set_index(ll, 1) == 0);
|
||||
assert_se(sd_ipv4ll_set_ifindex(ll, 1) == 0);
|
||||
assert_se(sd_ipv4ll_start(ll) == 0);
|
||||
|
||||
sd_event_run(e, (uint64_t) -1);
|
||||
|
||||
@@ -130,7 +130,7 @@ static void test_rs(void) {
|
||||
|
||||
assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
|
||||
|
||||
assert_se(sd_ndisc_set_index(nd, 42) >= 0);
|
||||
assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
|
||||
assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
|
||||
assert_se(sd_ndisc_set_callback(nd, test_rs_done, NULL, NULL, NULL, e) >= 0);
|
||||
|
||||
|
||||
@@ -554,7 +554,7 @@ int dhcp4_configure(Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
|
||||
r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ int dhcp6_configure(Link *link) {
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_dhcp6_client_set_index(client, link->ifindex);
|
||||
r = sd_dhcp6_client_set_ifindex(client, link->ifindex);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
|
||||
@@ -215,9 +215,7 @@ int ipv4ll_configure(Link *link) {
|
||||
if (link->udev_device) {
|
||||
r = net_get_unique_predictable_data(link->udev_device, &seed);
|
||||
if (r >= 0) {
|
||||
assert_cc(sizeof(unsigned) <= 8);
|
||||
|
||||
r = sd_ipv4ll_set_address_seed(link->ipv4ll, (unsigned)seed);
|
||||
r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -231,7 +229,7 @@ int ipv4ll_configure(Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
|
||||
r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ int ndisc_configure(Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ndisc_set_index(link->ndisc_router_discovery, link->ifindex);
|
||||
r = sd_ndisc_set_ifindex(link->ndisc_router_discovery, link->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ int sd_dhcp_client_set_request_address(
|
||||
int sd_dhcp_client_set_request_broadcast(
|
||||
sd_dhcp_client *client,
|
||||
int broadcast);
|
||||
int sd_dhcp_client_set_index(
|
||||
int sd_dhcp_client_set_ifindex(
|
||||
sd_dhcp_client *client,
|
||||
int interface_index);
|
||||
int sd_dhcp_client_set_mac(
|
||||
|
||||
@@ -82,7 +82,7 @@ int sd_dhcp6_client_set_callback(
|
||||
sd_dhcp6_client_callback_t cb,
|
||||
void *userdata);
|
||||
|
||||
int sd_dhcp6_client_set_index(
|
||||
int sd_dhcp6_client_set_ifindex(
|
||||
sd_dhcp6_client *client,
|
||||
int interface_index);
|
||||
int sd_dhcp6_client_set_local_address(
|
||||
|
||||
+13
-13
@@ -37,20 +37,20 @@ enum {
|
||||
};
|
||||
|
||||
typedef struct sd_ipv4acd sd_ipv4acd;
|
||||
typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *ll, int event, void *userdata);
|
||||
typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *acd, int event, void *userdata);
|
||||
|
||||
int sd_ipv4acd_detach_event(sd_ipv4acd *ll);
|
||||
int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority);
|
||||
int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address);
|
||||
int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata);
|
||||
int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr);
|
||||
int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index);
|
||||
int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address);
|
||||
int sd_ipv4acd_is_running(sd_ipv4acd *ll);
|
||||
int sd_ipv4acd_start(sd_ipv4acd *ll);
|
||||
int sd_ipv4acd_stop(sd_ipv4acd *ll);
|
||||
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll);
|
||||
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll);
|
||||
int sd_ipv4acd_detach_event(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority);
|
||||
int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address);
|
||||
int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata);
|
||||
int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr);
|
||||
int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index);
|
||||
int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address);
|
||||
int sd_ipv4acd_is_running(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_start(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_stop(sd_ipv4acd *acd);
|
||||
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd);
|
||||
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_new(sd_ipv4acd **ret);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4acd, sd_ipv4acd_unref);
|
||||
|
||||
@@ -43,15 +43,15 @@ int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority);
|
||||
int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
|
||||
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata);
|
||||
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
|
||||
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
|
||||
int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index);
|
||||
int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address);
|
||||
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed);
|
||||
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed);
|
||||
int sd_ipv4ll_is_running(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_start(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_stop(sd_ipv4ll *ll);
|
||||
sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll);
|
||||
sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_new (sd_ipv4ll **ret);
|
||||
int sd_ipv4ll_new(sd_ipv4ll **ret);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4ll, sd_ipv4ll_unref);
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ int sd_ndisc_set_callback(sd_ndisc *nd,
|
||||
sd_ndisc_prefix_autonomous_callback_t pacb,
|
||||
sd_ndisc_callback_t cb,
|
||||
void *userdata);
|
||||
int sd_ndisc_set_index(sd_ndisc *nd, int interface_index);
|
||||
int sd_ndisc_set_ifindex(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, int64_t priority);
|
||||
|
||||
Reference in New Issue
Block a user