sd-ipv4ll: allow initial address to be set explicitly

This is useful in case the daemon is restarted and the state of the IPv4LL client should
be serialized/deserialized.
This commit is contained in:
Tom Gundersen 2015-10-01 21:51:49 +02:00
parent a2fae7bbb2
commit 129dc1b489
3 changed files with 47 additions and 4 deletions

View file

@ -25,6 +25,7 @@
#include <arpa/inet.h>
#include "event-util.h"
#include "in-addr-util.h"
#include "list.h"
#include "random-util.h"
#include "refcnt.h"
@ -232,6 +233,39 @@ bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
return sd_ipv4acd_is_running(ll->acd);
}
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;
}
int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) {
int r;
assert_return(ll, -EINVAL);
assert_return(address, -EINVAL);
assert_return(ipv4ll_address_is_valid(address), -EINVAL);
r = sd_ipv4acd_set_address(ll->acd, address);
if (r < 0)
return r;
ll->address = address->s_addr;
return 0;
}
static int ipv4ll_pick_address(sd_ipv4ll *ll) {
struct in_addr in_addr;
be32_t addr;
@ -247,18 +281,15 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) {
return r;
addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
} while (addr == ll->address ||
(ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
(ntohl(addr) & 0x0000FF00) == 0x0000 ||
(ntohl(addr) & 0x0000FF00) == 0xFF00);
in_addr.s_addr = addr;
r = sd_ipv4acd_set_address(ll->acd, &in_addr);
r = sd_ipv4ll_set_address(ll, &in_addr);
if (r < 0)
return r;
ll->address = addr;
return 0;
}

View file

@ -100,6 +100,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;
sd_ipv4ll *ll;
struct ether_addr mac_addr = {
@ -118,6 +119,16 @@ static void test_public_api_setters(sd_event *e) {
assert_se(sd_ipv4ll_set_callback(NULL, NULL, NULL) == -EINVAL);
assert_se(sd_ipv4ll_set_callback(ll, NULL, NULL) == 0);
assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
address.s_addr |= htobe32(169U << 24 | 254U << 16);
assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
address.s_addr |= htobe32(0x00FF);
assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
address.s_addr |= htobe32(0xF000);
assert_se(sd_ipv4ll_set_address(ll, &address) == 0);
address.s_addr |= htobe32(0x0F00);
assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
assert_se(sd_ipv4ll_set_address_seed(NULL, seed) == -EINVAL);
assert_se(sd_ipv4ll_set_address_seed(ll, seed) == 0);

View file

@ -43,6 +43,7 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_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_address(sd_ipv4ll *ll, const struct in_addr *address);
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed);
bool sd_ipv4ll_is_running(sd_ipv4ll *ll);
int sd_ipv4ll_start(sd_ipv4ll *ll);