summaryrefslogtreecommitdiff
path: root/gweb
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2010-12-02 11:00:03 +0000
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-12-02 11:00:03 +0000
commitc969404724b19204bc1ef1634800f2b70572a297 (patch)
tree8dd14a96e9f4296a39a7ecb93b17f87c9beb82e7 /gweb
parent64533ee069c306bd9caf642fe218e9137a3b1572 (diff)
downloadconnman-c969404724b19204bc1ef1634800f2b70572a297.tar.gz
connman-c969404724b19204bc1ef1634800f2b70572a297.tar.bz2
connman-c969404724b19204bc1ef1634800f2b70572a297.zip
gresolv: Implement RFC3484 rule 9 (prefer longest matching prefix)
Diffstat (limited to 'gweb')
-rw-r--r--gweb/gresolv.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/gweb/gresolv.c b/gweb/gresolv.c
index ed1ccab3..0c7613db 100644
--- a/gweb/gresolv.c
+++ b/gweb/gresolv.c
@@ -920,6 +920,41 @@ static int rfc3484_compare(const void *__one, const void *__two)
return one->dst_scope - two->dst_scope;
/* Rule 9: Use longest matching prefix */
+ if (one->dst.sa.sa_family == AF_INET) {
+ /* Rule 9 is meaningless and counterproductive for Legacy IP
+ unless perhaps we can tell that it's actually on the local
+ subnet. But we don't (yet) have local interface config
+ information, so do nothing here for Legacy IP for now. */
+ } else {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ guint32 cmp_one, cmp_two;
+
+ cmp_one = one->src.sin6.sin6_addr.s6_addr32[i] ^
+ one->dst.sin6.sin6_addr.s6_addr32[i];
+ cmp_two = two->src.sin6.sin6_addr.s6_addr32[i] ^
+ two->dst.sin6.sin6_addr.s6_addr32[i];
+
+ if (!cmp_two && !cmp_one)
+ continue;
+
+ if (cmp_one && !cmp_two)
+ return 1;
+ if (cmp_two && !cmp_one)
+ return -1;
+
+ /* g_bit_storage() is effectively fls() */
+ cmp_one = g_bit_storage(ntohl(cmp_one));
+ cmp_two = g_bit_storage(ntohl(cmp_two));
+
+ if (cmp_one == cmp_two)
+ break;
+
+ return cmp_one - cmp_two;
+ }
+ }
+
/* Rule 10: Otherwise, leave the order unchanged */
if (one < two)