From ba026941a10325f4ac7fff93e4ad579b0b349e05 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 18 Jan 2017 09:38:20 +0200 Subject: [PATCH] net: ipv6: Fix IPv6 prefix comparision If the prefix length % 8 is not 0, then the remaining bit length was calculated incorrectly and the prefixes were claimed to match even though they might not be the same. Adding a test cases for testing this properly. Coverity-CID: 157591 Change-Id: I9cb5a73d5cc211ec183176400fa5e2dfd209e2da Signed-off-by: Jukka Rissanen --- include/net/net_ip.h | 21 +++++++++---- tests/net/ipv6/src/main.c | 66 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/include/net/net_ip.h b/include/net/net_ip.h index f058bc552c2..e055d71c95a 100644 --- a/include/net/net_ip.h +++ b/include/net/net_ip.h @@ -360,27 +360,36 @@ static inline bool net_is_my_ipv6_maddr(struct in6_addr *maddr) * @param addr2 Second IPv6 address. * @param length Prefix length (max length is 128). * - * @return True if addresses are the same, False otherwise. + * @return True if IPv6 prefixes are the same, False otherwise. */ static inline bool net_is_ipv6_prefix(const uint8_t *addr1, const uint8_t *addr2, uint8_t length) { uint8_t bits = 128 - length; - uint8_t bytes = bits / 8; + uint8_t bytes = length / 8; uint8_t remain = bits % 8; + uint8_t mask; if (length > 128) { return false; } - if (memcmp(addr1, addr2, 16 - bytes)) { + if (memcmp(addr1, addr2, bytes)) { return false; } - return ((addr1[16 - bytes] & ((8 - remain) << 8)) - == - (addr2[16 - bytes] & ((8 - remain) << 8))); + if (!remain) { + /* No remaining bits, the prefixes are the same as first + * bytes are the same. + */ + return true; + } + + /* Create a mask that has remaining most significant bits set */ + mask = ((0xff << (8 - remain)) ^ 0xff) << remain; + + return (addr1[bytes] & mask) == (addr2[bytes] & mask); } /** diff --git a/tests/net/ipv6/src/main.c b/tests/net/ipv6/src/main.c index db8f64d7fff..5fb277f44f6 100644 --- a/tests/net/ipv6/src/main.c +++ b/tests/net/ipv6/src/main.c @@ -273,6 +273,71 @@ static bool test_init(void) return true; } +static bool net_test_cmp_prefix(void) +{ + bool st; + + struct in6_addr prefix1 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + struct in6_addr prefix2 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x2 } } }; + + st = net_is_ipv6_prefix((uint8_t *)&prefix1, (uint8_t *)&prefix2, 64); + if (!st) { + TC_ERROR("Prefix /64 compare failed\n"); + return false; + } + + st = net_is_ipv6_prefix((uint8_t *)&prefix1, (uint8_t *)&prefix2, 65); + if (!st) { + TC_ERROR("Prefix /65 compare failed\n"); + return false; + } + + /* Set one extra bit in the other prefix for testing /65 */ + prefix1.s6_addr[8] = 0x80; + + st = net_is_ipv6_prefix((uint8_t *)&prefix1, (uint8_t *)&prefix2, 65); + if (st) { + TC_ERROR("Prefix /65 compare should have failed\n"); + return false; + } + + /* Set two bits in prefix2, it is now /66 */ + prefix2.s6_addr[8] = 0xc0; + + st = net_is_ipv6_prefix((uint8_t *)&prefix1, (uint8_t *)&prefix2, 65); + if (!st) { + TC_ERROR("Prefix /65 compare failed\n"); + return false; + } + + /* Set all remaining bits in prefix2, it is now /128 */ + memset(&prefix2.s6_addr[8], 0xff, 8); + + st = net_is_ipv6_prefix((uint8_t *)&prefix1, (uint8_t *)&prefix2, 65); + if (!st) { + TC_ERROR("Prefix /65 compare failed\n"); + return false; + } + + /* Comparing /64 should be still ok */ + st = net_is_ipv6_prefix((uint8_t *)&prefix1, (uint8_t *)&prefix2, 64); + if (!st) { + TC_ERROR("Prefix /64 compare failed\n"); + return false; + } + + /* But comparing /66 should should fail */ + st = net_is_ipv6_prefix((uint8_t *)&prefix1, (uint8_t *)&prefix2, 66); + if (st) { + TC_ERROR("Prefix /66 compare should have failed\n"); + return false; + } + + return true; +} + static bool net_test_send_ns_mcast(void) { int ret; @@ -614,6 +679,7 @@ static const struct { bool (*func)(void); } tests[] = { { "test init", test_init }, + { "IPv6 compare prefix", net_test_cmp_prefix }, { "IPv6 send NS mcast", net_test_send_ns_mcast }, { "IPv6 neighbor lookup fail", net_test_nbr_lookup_fail }, { "IPv6 send NS", net_test_send_ns },