]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libsystemd-network/sd-ipv4ll.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / libsystemd-network / sd-ipv4ll.c
index dd427ddd78467317cf564b2328b25c1f20e2cbfe..0d025768a91095705421d78d5ad4a68c2920d58f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
+#include <arpa/inet.h>
 #include <errno.h>
-#include <string.h>
 #include <stdio.h>
-#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sd-ipv4acd.h"
+#include "sd-ipv4ll.h"
 
 #include "event-util.h"
+#include "in-addr-util.h"
 #include "list.h"
 #include "random-util.h"
 #include "refcnt.h"
@@ -32,9 +36,6 @@
 #include "sparse-endian.h"
 #include "util.h"
 
-#include "sd-ipv4acd.h"
-#include "sd-ipv4ll.h"
-
 #define IPV4LL_NETWORK 0xA9FE0000L
 #define IPV4LL_NETMASK 0xFFFF0000L
 
@@ -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;
 }