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 19:41:51 +0400
commit17e52061bacec93e84324b23382e5ec61e1f16d0 (patch)
treebae9f3f8f8e89b531e5df167d33427627ea709fc /lib
parent681b84e8f50a09ff871d9e6536e8d8afb115ce13 (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 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 *);