about summary refs log tree commit diff
path: root/src/libnm-glib-aux/nm-inet-utils.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2026-07-03 19:53:23 +0200
committerMichael Biebl <biebl@debian.org>2026-07-03 19:53:23 +0200
commitaa308069bebf2d5a3200728caa69a76137c03d8b (patch)
treec0ba2281e801c4720a0d8a5e5ee943688234f088 /src/libnm-glib-aux/nm-inet-utils.c
parent0a4b2c29da4ccf259bbcea3298d15abebb94348f (diff)
parent537bfce2bda471c92caabd388589230200891509 (diff)
Update upstream source from tag 'upstream/1.58_rc1'
Update to upstream version '1.58~rc1'
with Debian dir 451489c9234e2b6b7c2f41ca6670287ea3ac3efd
Diffstat (limited to 'src/libnm-glib-aux/nm-inet-utils.c')
-rw-r--r--src/libnm-glib-aux/nm-inet-utils.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/libnm-glib-aux/nm-inet-utils.c b/src/libnm-glib-aux/nm-inet-utils.c
index f4f418cf..ead060bc 100644
--- a/src/libnm-glib-aux/nm-inet-utils.c
+++ b/src/libnm-glib-aux/nm-inet-utils.c
@@ -167,6 +167,92 @@ nm_ip6_addr_is_ula(const struct in6_addr *address)
     return (address->s6_addr32[0] & htonl(0xfe000000u)) == htonl(0xfc000000u);
 }
 
+/**
+ * nm_ip6_addr_common_prefix_len:
+ * @a: first IPv6 address
+ * @b: second IPv6 address
+ *
+ * Returns: the number of leading bits that @a and @b have in common,
+ * from 0 to 128.
+ */
+guint
+nm_ip6_addr_common_prefix_len(const struct in6_addr *a, const struct in6_addr *b)
+{
+    guint i;
+
+    for (i = 0; i < 16; i++) {
+        guint8 diff = a->s6_addr[i] ^ b->s6_addr[i];
+
+        if (diff != 0)
+            return i * 8u + __builtin_clz((guint) diff) - 24u;
+    }
+    return 128;
+}
+
+/**
+ * nm_ip6_addr_rfc6724_label:
+ * @addr: an IPv6 address
+ *
+ * Returns the label for @addr from the default policy table defined
+ * in RFC 6724, Section 2.1:
+ *
+ *   Prefix        Precedence Label
+ *   ::1/128               50     0
+ *   ::/0                  40     1
+ *   ::ffff:0:0/96         35     4
+ *   2002::/16             30     2
+ *   2001::/32              5     5
+ *   fc00::/7               3    13
+ *   ::/96                  1     3
+ *   fec0::/10              1    11
+ *   3ffe::/16              1    12
+ *
+ * Returns: the label value (0-13). It can be used in the Source
+ *   Address Selection algorithm to prefer a source whose label
+ *   matches with the label of the destination.
+ */
+guint
+nm_ip6_addr_rfc6724_label(const struct in6_addr *addr)
+{
+    /* Checked from most-specific to least-specific prefix length. */
+
+    /* ::1/128 (loopback) */
+    if (IN6_IS_ADDR_LOOPBACK(addr))
+        return 0;
+
+    /* ::ffff:0:0/96 (IPv4-mapped) */
+    if (IN6_IS_ADDR_V4MAPPED(addr))
+        return 4;
+
+    /* ::/96 (IPv4-compatible, deprecated) */
+    if (addr->s6_addr32[0] == 0 && addr->s6_addr32[1] == 0 && addr->s6_addr32[2] == 0
+        && !IN6_IS_ADDR_UNSPECIFIED(addr))
+        return 3;
+
+    /* 2001::/32 (Teredo) */
+    if (addr->s6_addr32[0] == htonl(0x20010000u))
+        return 5;
+
+    /* 2002::/16 (6to4) */
+    if ((addr->s6_addr32[0] & htonl(0xFFFF0000u)) == htonl(0x20020000u))
+        return 2;
+
+    /* 3ffe::/16 (deprecated 6bone) */
+    if ((addr->s6_addr32[0] & htonl(0xFFFF0000u)) == htonl(0x3FFE0000u))
+        return 12;
+
+    /* fec0::/10 (deprecated site-local) */
+    if ((addr->s6_addr32[0] & htonl(0xFFC00000u)) == htonl(0xFEC00000u))
+        return 11;
+
+    /* fc00::/7 (ULA) */
+    if (nm_ip6_addr_is_ula(addr))
+        return 13;
+
+    /* ::/0 (default) */
+    return 1;
+}
+
 /*****************************************************************************/
 
 gconstpointer