]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libsystemd-network/sd-ipv4ll.c
Merge pull request #1668 from ssahani/net1
[thirdparty/systemd.git] / src / libsystemd-network / sd-ipv4ll.c
index f0230b919c431b0d43c810a5a75cf35c8cc4d26b..68ec58da901a274cc925efb61fcc79f4e4e316d4 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
 
@@ -202,7 +203,6 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
         int r;
 
         assert_return(ll, -EINVAL);
-        assert_return(seed, -EINVAL);
 
         random_data = new0(struct random_data, 1);
         if (!random_data)
@@ -227,12 +227,45 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
         return 0;
 }
 
-bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
+int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
         assert_return(ll, false);
 
         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;
@@ -248,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;
 }
 
@@ -298,22 +328,22 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
         assert(ll);
 
         switch (event) {
-        case IPV4ACD_EVENT_STOP:
-                ipv4ll_client_notify(ll, IPV4LL_EVENT_STOP);
+        case SD_IPV4ACD_EVENT_STOP:
+                ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP);
 
                 ll->claimed_address = 0;
 
                 break;
-        case IPV4ACD_EVENT_BIND:
+        case SD_IPV4ACD_EVENT_BIND:
                 ll->claimed_address = ll->address;
-                ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND);
+                ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_BIND);
 
                 break;
-        case IPV4ACD_EVENT_CONFLICT:
+        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 */
                 if (ll->claimed_address != 0) {
-                        ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
+                        ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_CONFLICT);
 
                         ll->claimed_address = 0;
                 } else {
@@ -334,5 +364,5 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
         return;
 
 error:
-        ipv4ll_client_notify(ll, IPV4LL_EVENT_STOP);
+        ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP);
 }