From 17e52061bacec93e84324b23382e5ec61e1f16d0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 2 Feb 2010 20:16:35 +0100 Subject: lib: prefix2sockunion, prefix_common_bits helper functions prefix2sockunion converts a struct prefix* to a union sockunion *; prefix_common_bits counts the number of common bits in the prefix's address part. --- lib/prefix.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/prefix.h | 2 ++ 2 files changed, 56 insertions(+) (limited to 'lib') diff --git a/lib/prefix.c b/lib/prefix.c index 61a278ca..fff09326 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -181,6 +181,46 @@ prefix_cmp (const struct prefix *p1, const struct prefix *p2) return 0; } +/* + * Count the number of common bits in 2 prefixes. The prefix length is + * ignored for this function; the whole prefix is compared. If the prefix + * address families don't match, return -1; otherwise the return value is + * in range 0 ... maximum prefix length for the address family. + */ +int +prefix_common_bits (const struct prefix *p1, const struct prefix *p2) +{ + int pos, bit; + int length = 0; + u_char xor; + + /* Set both prefix's head pointer. */ + const u_char *pp1 = (const u_char *)&p1->u.prefix; + const u_char *pp2 = (const u_char *)&p2->u.prefix; + + if (p1->family == AF_INET) + length = IPV4_MAX_BYTELEN; +#ifdef HAVE_IPV6 + if (p1->family == AF_INET6) + length = IPV6_MAX_BYTELEN; +#endif + if (p1->family != p2->family || !length) + return -1; + + for (pos = 0; pos < length; pos++) + if (pp1[pos] != pp2[pos]) + break; + if (pos == length) + return pos * 8; + + xor = pp1[pos] ^ pp2[pos]; + for (bit = 0; bit < 8; bit++) + if (xor & (1 << (7 - bit))) + break; + + return pos * 8 + bit; +} + /* Return prefix family type string. */ const char * prefix_family_str (const struct prefix *p) @@ -570,6 +610,20 @@ sockunion2hostprefix (const union sockunion *su) return NULL; } +void +prefix2sockunion (const struct prefix *p, union sockunion *su) +{ + memset (su, 0, sizeof (*su)); + + su->sa.sa_family = p->family; + if (p->family == AF_INET) + su->sin.sin_addr = p->u.prefix4; +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + memcpy (&su->sin6.sin6_addr, &p->u.prefix6, sizeof (struct in6_addr)); +#endif /* HAVE_IPV6 */ +} + int prefix_blen (const struct prefix *p) { diff --git a/lib/prefix.h b/lib/prefix.h index 1cb91b2a..54f47c71 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -157,12 +157,14 @@ extern int prefix2str (const struct prefix *, char *, int); extern int prefix_match (const struct prefix *, const struct prefix *); extern int prefix_same (const struct prefix *, const struct prefix *); extern int prefix_cmp (const struct prefix *, const struct prefix *); +extern int prefix_common_bits (const struct prefix *, const struct prefix *); extern void prefix_copy (struct prefix *dest, const struct prefix *src); extern void apply_mask (struct prefix *); extern struct prefix *sockunion2prefix (const union sockunion *dest, const union sockunion *mask); extern struct prefix *sockunion2hostprefix (const union sockunion *); +extern void prefix2sockunion (const struct prefix *, union sockunion *); extern struct prefix_ipv4 *prefix_ipv4_new (void); extern void prefix_ipv4_free (struct prefix_ipv4 *); -- cgit v1.2.1