diff options
author | Tom Gundersen <teg@jklm.no> | 2015-10-01 21:51:49 +0200 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2015-10-11 15:04:16 +0200 |
commit | 129dc1b489d924d28956b09a06f03d7607beb8ad (patch) | |
tree | 9ff47f802047fa6c2d92c437d0881f8e2a64a1b7 /src/libsystemd-network | |
parent | a2fae7bbb21bdcc9d0a2094b7fd6b364ffbaae86 (diff) |
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.
Diffstat (limited to 'src/libsystemd-network')
-rw-r--r-- | src/libsystemd-network/sd-ipv4ll.c | 39 | ||||
-rw-r--r-- | src/libsystemd-network/test-ipv4ll.c | 11 |
2 files changed, 46 insertions, 4 deletions
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index dd427ddd78..57bd337a9a 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -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; } diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c index e72204d992..b67a9f17d7 100644 --- a/src/libsystemd-network/test-ipv4ll.c +++ b/src/libsystemd-network/test-ipv4ll.c @@ -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); |