From f39c751d55cc52a3651d45c94a41c61708dc928f Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Mon, 7 Mar 2022 11:07:55 +0000 Subject: [PATCH] addresses: Implement subtraction for IPv4 Signed-off-by: Michael Tremer --- src/libloc/private.h | 55 ++++++++++++++++++++++++++++++++++++++++---- src/network-list.c | 7 +++++- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/libloc/private.h b/src/libloc/private.h index 7b008d5..301672d 100644 --- a/src/libloc/private.h +++ b/src/libloc/private.h @@ -19,6 +19,7 @@ #ifdef LIBLOC_PRIVATE +#include #include #include #include @@ -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) { diff --git a/src/network-list.c b/src/network-list.c index 61b36de..b8a485d 100644 --- a/src/network-list.c +++ b/src/network-list.c @@ -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? -- 2.47.3