diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index f7f2b986f8..956a6062d6 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -75,6 +75,50 @@ nm_ethernet_address_is_valid (const struct ether_addr *test_addr) } +/* nm_utils_ip4_address_clear_host_address: + * @addr: source ip6 address + * @plen: prefix length of network + * + * returns: the input address, with the host address set to 0. + */ +in_addr_t +nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen) +{ + return addr & nm_utils_ip4_prefix_to_netmask (plen); +} + + /* nm_utils_ip6_address_clear_host_address: + * @dst: destination output buffer, will contain the network part of the @src address + * @src: source ip6 address + * @plen: prefix length of network + * + * Note: this function is self assignment save, to update @src inplace, set both + * @dst and @src to the same destination. + */ +void +nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen) +{ + g_return_if_fail (plen <= 128); + g_return_if_fail (src); + g_return_if_fail (dst); + + if (plen < 128) { + guint nbytes = plen / 8; + guint nbits = plen % 8; + + if (nbytes && dst != src) + memcpy (dst, src, nbytes); + if (nbits) { + dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits))); + nbytes++; + } + if (nbytes <= 15) + memset (&dst->s6_addr[nbytes], 0, 16 - nbytes); + } else if (src != dst) + *dst = *src; +} + + int nm_spawn_process (const char *args) { diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index d33ceda507..ee234dda80 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -35,6 +35,9 @@ gboolean nm_ethernet_address_is_valid (const struct ether_addr *test_addr); +in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen); +void nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen); + int nm_spawn_process (const char *args); gboolean nm_match_spec_string (const GSList *specs, const char *string); diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c index 5fb28778fc..3b0b0365b4 100644 --- a/src/rdisc/nm-lndp-rdisc.c +++ b/src/rdisc/nm-lndp-rdisc.c @@ -428,29 +428,6 @@ fill_address_from_mac (struct in6_addr *address, const char *mac) memcpy (identifier + 5, mac + 3, 3); } -/* Ensure the given address is masked with its prefix and that all host - * bits are set to zero. Some IPv6 router advertisement daemons (eg, radvd) - * don't enforce this in their configuration. - */ -static void -set_address_masked (struct in6_addr *dst, struct in6_addr *src, guint8 plen) -{ - guint nbytes = plen / 8; - guint nbits = plen % 8; - - g_return_if_fail (plen <= 128); - g_assert (src); - g_assert (dst); - - if (plen >= 128) - *dst = *src; - else { - memset (dst, 0, sizeof (*dst)); - memcpy (dst, src, nbytes); - dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits))); - } -} - static int receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) { @@ -529,7 +506,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) /* Device route */ memset (&route, 0, sizeof (route)); route.plen = ndp_msg_opt_prefix_len (msg, offset); - set_address_masked (&route.network, ndp_msg_opt_prefix (msg, offset), route.plen); + nm_utils_ip6_address_clear_host_address (&route.network, ndp_msg_opt_prefix (msg, offset), route.plen); route.timestamp = now; if (ndp_msg_opt_prefix_flag_on_link (msg, offset)) { route.lifetime = ndp_msg_opt_prefix_valid_time (msg, offset); @@ -560,7 +537,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) memset (&route, 0, sizeof (route)); route.gateway = gateway.address; route.plen = ndp_msg_opt_route_prefix_len (msg, offset); - set_address_masked (&route.network, ndp_msg_opt_route_prefix (msg, offset), route.plen); + nm_utils_ip6_address_clear_host_address (&route.network, ndp_msg_opt_route_prefix (msg, offset), route.plen); route.timestamp = now; route.lifetime = ndp_msg_opt_route_lifetime (msg, offset); route.preference = translate_preference (ndp_msg_opt_route_preference (msg, offset)); diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 649653c75e..3fd7115cb0 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -60,6 +60,76 @@ test_nm_utils_ascii_str_to_int64 (void) test_nm_utils_ascii_str_to_int64_do ("\r\n\t10000\t\n\t\n", 10, 0, 10000, -1, 0, 10000); } +/* Reference implementation for nm_utils_ip6_address_clear_host_address. + * Taken originally from set_address_masked(), src/rdisc/nm-lndp-rdisc.c + **/ +static void +ip6_address_clear_host_address_reference (struct in6_addr *dst, struct in6_addr *src, guint8 plen) +{ + guint nbytes = plen / 8; + guint nbits = plen % 8; + + g_return_if_fail (plen <= 128); + g_assert (src); + g_assert (dst); + + if (plen >= 128) + *dst = *src; + else { + memset (dst, 0, sizeof (*dst)); + memcpy (dst, src, nbytes); + dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits))); + } +} + +static void +_randomize_in6_addr (struct in6_addr *addr, GRand *rand) +{ + int i; + + for (i=0; i < 4; i++) + ((guint32 *)addr)[i] = g_rand_int (rand); +} + +static void +test_nm_utils_ip6_address_clear_host_address (void) +{ + GRand *rand = g_rand_new (); + int plen, i; + + g_rand_set_seed (rand, 0); + + for (plen = 0; plen <= 128; plen++) { + for (i =0; i<50; i++) { + struct in6_addr addr_src, addr_ref; + struct in6_addr addr1, addr2; + + _randomize_in6_addr (&addr_src, rand); + _randomize_in6_addr (&addr_ref, rand); + _randomize_in6_addr (&addr1, rand); + _randomize_in6_addr (&addr2, rand); + + addr1 = addr_src; + ip6_address_clear_host_address_reference (&addr_ref, &addr1, plen); + + _randomize_in6_addr (&addr1, rand); + _randomize_in6_addr (&addr2, rand); + addr1 = addr_src; + nm_utils_ip6_address_clear_host_address (&addr2, &addr1, plen); + g_assert_cmpint (memcmp (&addr1, &addr_src, sizeof (struct in6_addr)), ==, 0); + g_assert_cmpint (memcmp (&addr2, &addr_ref, sizeof (struct in6_addr)), ==, 0); + + /* test for self assignment/inplace update. */ + _randomize_in6_addr (&addr1, rand); + addr1 = addr_src; + nm_utils_ip6_address_clear_host_address (&addr1, &addr1, plen); + g_assert_cmpint (memcmp (&addr1, &addr_ref, sizeof (struct in6_addr)), ==, 0); + } + } + + g_rand_free (rand); +} + /*******************************************/ int @@ -70,6 +140,7 @@ main (int argc, char **argv) g_type_init (); g_test_add_func ("/general/nm_utils_ascii_str_to_int64", test_nm_utils_ascii_str_to_int64); + g_test_add_func ("/general/nm_utils_ip6_address_clear_host_address", test_nm_utils_ip6_address_clear_host_address); return g_test_run (); }