]> git.ipfire.org Git - people/ms/libloc.git/commitdiff
addresses: Implement subtraction for IPv4
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 7 Mar 2022 11:07:55 +0000 (11:07 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 7 Mar 2022 11:07:55 +0000 (11:07 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libloc/private.h
src/network-list.c

index 7b008d57f1cf2103ea6a8ae39561967b31f21ff2..301672d87c826c0c8505a399a173d50ab6016f02 100644 (file)
@@ -19,6 +19,7 @@
 
 #ifdef LIBLOC_PRIVATE
 
+#include <errno.h>
 #include <netinet/in.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -151,10 +152,8 @@ static inline struct in6_addr loc_address_or(
        return a;
 }
 
-static inline struct in6_addr loc_address_sub(
+static inline int __loc_address6_sub(struct in6_addr* result,
                const struct in6_addr* address1, const struct in6_addr* address2) {
-       struct in6_addr a;
-
        int remainder = 0;
 
        for (int octet = 15; octet >= 0; octet--) {
@@ -163,10 +162,56 @@ static inline struct in6_addr loc_address_sub(
                // Store remainder for the next iteration
                remainder = (x >> 8);
 
-               a.s6_addr[octet] = x & 0xff;
+               result->s6_addr[octet] = x & 0xff;
        }
 
-       return a;
+       return 0;
+}
+
+static inline int __loc_address4_sub(struct in6_addr* result,
+               const struct in6_addr* address1, const struct in6_addr* address2) {
+       int remainder = 0;
+
+       for (int octet = 4; octet >= 0; octet--) {
+               int x = address1->s6_addr[octet] - address2->s6_addr[octet] + remainder;
+
+               // Store remainder for the next iteration
+               remainder = (x >> 8);
+
+               result->s6_addr[octet] = x & 0xff;
+       }
+
+       return 0;
+}
+
+static inline int loc_address_sub(struct in6_addr* result,
+               const struct in6_addr* address1, const struct in6_addr* address2) {
+       // XXX should be using loc_address_family
+       int family1 = IN6_IS_ADDR_V4MAPPED(address1) ? AF_INET : AF_INET6;
+       int family2 = IN6_IS_ADDR_V4MAPPED(address2) ? AF_INET : AF_INET6;
+
+       // Address family must match
+       if (family1 != family2) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       // Clear result
+       int r = loc_address_reset(result, family1);
+       if (r)
+               return r;
+
+       switch (family1) {
+               case AF_INET6:
+                       return __loc_address6_sub(result, address1, address2);
+
+               case AF_INET:
+                       return __loc_address4_sub(result, address1, address2);
+
+               default:
+                       errno = ENOTSUP;
+                       return 1;
+       }
 }
 
 static inline void hexdump(struct loc_ctx* ctx, const void* addr, size_t len) {
index 61b36de84d29eaf601c157e08a8b2b9cd0a6e19e..b8a485db873c45b821a667237559c4e9ab31873c 100644 (file)
@@ -327,12 +327,17 @@ int loc_network_list_summarize(struct loc_ctx* ctx,
        struct in6_addr start = *first;
 
        while (in6_addr_cmp(&start, last) <= 0) {
+               struct in6_addr num;
+
                // Find the number of trailing zeroes of the start address
                int bits1 = loc_address_count_trailing_zero_bits(&start);
 
                // Subtract the start address from the last address and add one
                // (i.e. how many addresses are in this network?)
-               struct in6_addr num = loc_address_sub(last, &start);
+               r = loc_address_sub(&num, last, &start);
+               if (r)
+                       return r;
+
                num = address_increment(&num);
 
                // How many bits do we need to represent this address?