summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2010-02-02 20:16:35 +0100
committerDenis Ovsienko <infrastation@yandex.ru>2011-11-21 18:23:10 +0400
commit188506f4c618626e3da2c1e657100315f49664ee (patch)
treefaf3e43e2b941b21105760d8fd6a84f179f95810 /lib
parent8b1eb59bb954af49455a97dbabf65321001d0225 (diff)
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/prefix.c54
-rw-r--r--lib/prefix.h2
2 files changed, 56 insertions, 0 deletions
diff --git a/lib/prefix.c b/lib/prefix.c
index 9633a894..4be3ba20 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -253,6 +253,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)
@@ -629,6 +669,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 42334649..675f94d4 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 *);