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 <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
d3301aae88
commit
ba026941a1
2 changed files with 81 additions and 6 deletions
|
@ -360,27 +360,36 @@ static inline bool net_is_my_ipv6_maddr(struct in6_addr *maddr)
|
||||||
* @param addr2 Second IPv6 address.
|
* @param addr2 Second IPv6 address.
|
||||||
* @param length Prefix length (max length is 128).
|
* @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,
|
static inline bool net_is_ipv6_prefix(const uint8_t *addr1,
|
||||||
const uint8_t *addr2,
|
const uint8_t *addr2,
|
||||||
uint8_t length)
|
uint8_t length)
|
||||||
{
|
{
|
||||||
uint8_t bits = 128 - length;
|
uint8_t bits = 128 - length;
|
||||||
uint8_t bytes = bits / 8;
|
uint8_t bytes = length / 8;
|
||||||
uint8_t remain = bits % 8;
|
uint8_t remain = bits % 8;
|
||||||
|
uint8_t mask;
|
||||||
|
|
||||||
if (length > 128) {
|
if (length > 128) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(addr1, addr2, 16 - bytes)) {
|
if (memcmp(addr1, addr2, bytes)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((addr1[16 - bytes] & ((8 - remain) << 8))
|
if (!remain) {
|
||||||
==
|
/* No remaining bits, the prefixes are the same as first
|
||||||
(addr2[16 - bytes] & ((8 - remain) << 8)));
|
* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -273,6 +273,71 @@ static bool test_init(void)
|
||||||
return true;
|
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)
|
static bool net_test_send_ns_mcast(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -614,6 +679,7 @@ static const struct {
|
||||||
bool (*func)(void);
|
bool (*func)(void);
|
||||||
} tests[] = {
|
} tests[] = {
|
||||||
{ "test init", test_init },
|
{ "test init", test_init },
|
||||||
|
{ "IPv6 compare prefix", net_test_cmp_prefix },
|
||||||
{ "IPv6 send NS mcast", net_test_send_ns_mcast },
|
{ "IPv6 send NS mcast", net_test_send_ns_mcast },
|
||||||
{ "IPv6 neighbor lookup fail", net_test_nbr_lookup_fail },
|
{ "IPv6 neighbor lookup fail", net_test_nbr_lookup_fail },
|
||||||
{ "IPv6 send NS", net_test_send_ns },
|
{ "IPv6 send NS", net_test_send_ns },
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue