diff options
author | Pau Espin Pedrol <pespin@sysmocom.de> | 2017-10-16 14:27:32 +0200 |
---|---|---|
committer | Pau Espin Pedrol <pespin@sysmocom.de> | 2017-10-16 17:45:40 +0200 |
commit | 2e7b9ff891a0d4c84a4be3fffbac1b9502fe267c (patch) | |
tree | 0ee3abe0431822780117efbf9994dee62adabec3 | |
parent | 361cb9e910e77f657ad39e0be4684b8028711a0c (diff) |
lib/in46a: Introduce in46a_netmasklen API
Change-Id: I06e3e038afd8f7afaec2a3fa67b1616500c8db80
-rw-r--r-- | lib/in46_addr.c | 58 | ||||
-rw-r--r-- | lib/in46_addr.h | 1 | ||||
-rw-r--r-- | tests/lib/in46a_test.c | 59 | ||||
-rw-r--r-- | tests/lib/in46a_test.ok | 2 |
4 files changed, 120 insertions, 0 deletions
diff --git a/lib/in46_addr.c b/lib/in46_addr.c index 32e0f8d..36ad6af 100644 --- a/lib/in46_addr.c +++ b/lib/in46_addr.c @@ -195,6 +195,64 @@ int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net, } } +static unsigned int ipv4_netmasklen(const struct in_addr *netmask) +{ + uint32_t bits = netmask->s_addr; + uint8_t *b = (uint8_t*) &bits; + unsigned int i, prefix = 0; + + for (i = 0; i < 4; i++) { + while (b[i] & 0x80) { + prefix++; + b[i] = b[i] << 1; + } + } + return prefix; +} + +static unsigned int ipv6_netmasklen(const struct in6_addr *netmask) +{ + #if defined(__linux__) + #define ADDRFIELD(i) s6_addr32[i] + #else + #define ADDRFIELD(i) __u6_addr.__u6_addr32[i] + #endif + + unsigned int i, j, prefix = 0; + + for (j = 0; j < 4; j++) { + uint32_t bits = netmask->ADDRFIELD(j); + uint8_t *b = (uint8_t*) &bits; + for (i = 0; i < 4; i++) { + while (b[i] & 0x80) { + prefix++; + b[i] = b[i] << 1; + } + } + } + + #undef ADDRFIELD + + return prefix; +} + +/*! Convert netmask to prefix length representation + * \param[in] netmask in46_addr containing a netmask (consecutive list of 1-bit followed by consecutive list of 0-bit) + * \returns prefix length representation of the netmask (count of 1-bit from the start of the netmask) + */ +unsigned int in46a_netmasklen(const struct in46_addr *netmask) +{ + switch (netmask->len) { + case 4: + return ipv4_netmasklen(&netmask->v4); + case 16: + return ipv6_netmasklen(&netmask->v6); + default: + OSMO_ASSERT(0); + return 0; + } +} + /*! Convert given PDP End User Address to in46_addr * \returns 0 on success; negative on error */ int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua) diff --git a/lib/in46_addr.h b/lib/in46_addr.h index ce2df14..ff26521 100644 --- a/lib/in46_addr.h +++ b/lib/in46_addr.h @@ -27,6 +27,7 @@ extern const char *in46p_ntoa(const struct in46_prefix *in46p); extern int in46a_equal(const struct in46_addr *a, const struct in46_addr *b); extern int in46a_prefix_equal(const struct in46_addr *a, const struct in46_addr *b); extern int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net, size_t prefixlen); +unsigned int in46a_netmasklen(const struct in46_addr *netmask); int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua); int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst); diff --git a/tests/lib/in46a_test.c b/tests/lib/in46a_test.c index d6215e7..42a1768 100644 --- a/tests/lib/in46a_test.c +++ b/tests/lib/in46a_test.c @@ -246,6 +246,64 @@ static void test_in46a_from_eua(void) OSMO_ASSERT(!memcmp(&ia.v6, v6_spec+2, ia.len)); } +static void test_in46a_netmasklen(void) +{ + struct in46_addr netmask; + unsigned int len; + + printf("Testing in46a_netmasklen() with IPv4 addresses\n"); + netmask.len = 4; + + netmask.v4.s_addr = 0xffffffff; + len = in46a_netmasklen(&netmask); + OSMO_ASSERT(len == 32); + + netmask.v4.s_addr = 0x00ffffff; + len = in46a_netmasklen(&netmask); + OSMO_ASSERT(len == 24); + + netmask.v4.s_addr = 0x00f0ffff; + len = in46a_netmasklen(&netmask); + OSMO_ASSERT(len == 20); + + netmask.v4.s_addr = 0x000000fe; + len = in46a_netmasklen(&netmask); + OSMO_ASSERT(len == 7); + + netmask.v4.s_addr = 0x00000000; + len = in46a_netmasklen(&netmask); + OSMO_ASSERT(len == 0); + + printf("Testing in46a_netmasklen() with IPv6 addresses\n"); + const struct in46_addr netmaskA = { + .len = 16, + .v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, + }; + len = in46a_netmasklen(&netmaskA); + OSMO_ASSERT(len == 128); + + const struct in46_addr netmaskB = { + .len = 16, + .v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00}, + }; + len = in46a_netmasklen(&netmaskB); + OSMO_ASSERT(len == 104); + + const struct in46_addr netmaskC = { + .len = 16, + .v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00}, + }; + len = in46a_netmasklen(&netmaskC); + OSMO_ASSERT(len == 103); + + const struct in46_addr netmaskD = { + .len = 16, + .v6.s6_addr = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + }; + len = in46a_netmasklen(&netmaskD); + OSMO_ASSERT(len == 0); +} + int main(int argc, char **argv) { osmo_init_logging(&log_info); @@ -262,4 +320,5 @@ int main(int argc, char **argv) test_in46a_within_mask(); test_in46a_to_eua(); test_in46a_from_eua(); + test_in46a_netmasklen(); } diff --git a/tests/lib/in46a_test.ok b/tests/lib/in46a_test.ok index b115444..9a0ff7a 100644 --- a/tests/lib/in46a_test.ok +++ b/tests/lib/in46a_test.ok @@ -15,3 +15,5 @@ in46a_within_mask(10.11.12.14, 10.11.12.13, 32) = 0 in46a_within_mask(10.11.12.14, 10.11.12.12, 30) = 1 testing in46a_to_eua() Testing in46a_from_eua() +Testing in46a_netmasklen() with IPv4 addresses +Testing in46a_netmasklen() with IPv6 addresses |