]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-ipv4ll: allow initial address to be set explicitly
authorTom Gundersen <teg@jklm.no>
Thu, 1 Oct 2015 19:51:49 +0000 (21:51 +0200)
committerTom Gundersen <teg@jklm.no>
Sun, 11 Oct 2015 13:04:16 +0000 (15:04 +0200)
This is useful in case the daemon is restarted and the state of the IPv4LL client should
be serialized/deserialized.

src/libsystemd-network/sd-ipv4ll.c
src/libsystemd-network/test-ipv4ll.c
src/systemd/sd-ipv4ll.h

index dd427ddd78467317cf564b2328b25c1f20e2cbfe..57bd337a9af20041fb389f77880928885dd1af25 100644 (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;
 }
 
index e72204d9927af0082525affb137fc68660e515e2..b67a9f17d748b6a65f93c2853f0675ce2e4fca29 100644 (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);
 
index 677505f0c6a06d38cba36f4c930725c2d8bc1b83..cc85140acdd54b1142edd41f6348383fa8e3cd3f 100644 (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);