about summary refs log tree commit diff
path: root/src/libnm-platform/nm-linux-platform.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2026-02-22 00:40:03 +0100
committerMichael Biebl <biebl@debian.org>2026-02-22 00:40:03 +0100
commitccdb9117cca7141ee709afca8b25c966ff4fa18e (patch)
tree3b7377c95e1d4049c13dd9101ae923fee70ab91d /src/libnm-platform/nm-linux-platform.c
parentd0ea10125cc04f55c1864451198d87fb801d1457 (diff)
parent067fb576988f685e83ac8b0ae690334aff547c85 (diff)
Update upstream source from tag 'upstream/1.56.0'
Update to upstream version '1.56.0'
with Debian dir 15fab61a7abf1fd4e2ba46785f96d935e87d32bb
Diffstat (limited to 'src/libnm-platform/nm-linux-platform.c')
-rw-r--r--src/libnm-platform/nm-linux-platform.c56
1 files changed, 49 insertions, 7 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c
index 0c1097c2..cc5b99e0 100644
--- a/src/libnm-platform/nm-linux-platform.c
+++ b/src/libnm-platform/nm-linux-platform.c
@@ -59,6 +59,7 @@ G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_SUBFLOW == MPTCP_PM_ADDR_FLAG_SUBFLOW);
 G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_BACKUP == MPTCP_PM_ADDR_FLAG_BACKUP);
 G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_FULLMESH == MPTCP_PM_ADDR_FLAG_FULLMESH);
 G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_IMPLICIT == MPTCP_PM_ADDR_FLAG_IMPLICIT);
+G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_LAMINAR == MPTCP_PM_ADDR_FLAG_LAMINAR);
 
 /*****************************************************************************/
 
@@ -4014,6 +4015,7 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter
         [RTA_PREF]      = {.type = NLA_U8},
         [RTA_FLOW]      = {.type = NLA_U32},
         [RTA_CACHEINFO] = {.minlen = nm_offsetofend(struct rta_cacheinfo, rta_tsage)},
+        [RTA_VIA]       = {.minlen = nm_offsetofend(struct rtvia, rtvia_family)},
         [RTA_METRICS]   = {.type = NLA_NESTED},
         [RTA_MULTIPATH] = {.type = NLA_NESTED},
     };
@@ -4030,9 +4032,11 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter
         guint8   weight;
         int      ifindex;
         NMIPAddr gateway;
+        gboolean is_via;
     } nh = {
         .found    = FALSE,
         .has_more = FALSE,
+        .is_via   = FALSE,
     };
     guint                           v4_n_nexthops = 0;
     NMPlatformIP4RtNextHop          v4_nh_extra_nexthops_stack[10];
@@ -4201,13 +4205,26 @@ rta_multipath_done:
         return nm_assert_unreachable_val(NULL);
     }
 
-    if (tb[RTA_OIF] || tb[RTA_GATEWAY] || tb[RTA_FLOW]) {
+    if (tb[RTA_OIF] || tb[RTA_GATEWAY] || tb[RTA_FLOW] || tb[RTA_VIA]) {
         int      ifindex = 0;
         NMIPAddr gateway = {};
 
         if (tb[RTA_OIF])
             ifindex = nla_get_u32(tb[RTA_OIF]);
-        if (_check_addr_or_return_null(tb, RTA_GATEWAY, addr_len))
+
+        if (tb[RTA_VIA]) {
+            struct rtvia *rtvia;
+
+            /* Used when the gateway family doesn't match the route family */
+            rtvia = nla_data(tb[RTA_VIA]);
+            if (rtvia->rtvia_family != AF_INET6)
+                return NULL;
+            if (nla_len(tb[RTA_VIA]) < sizeof(struct rtvia) + sizeof(struct in6_addr))
+                return NULL;
+
+            nh.is_via = TRUE;
+            memcpy(&gateway, rtvia->rtvia_addr, sizeof(struct in6_addr));
+        } else if (_check_addr_or_return_null(tb, RTA_GATEWAY, addr_len))
             memcpy(&gateway, nla_data(tb[RTA_GATEWAY]), addr_len);
 
         if (!nh.found) {
@@ -4223,6 +4240,9 @@ rta_multipath_done:
         } else {
             /* Kernel supports new style nexthop configuration,
              * verify that it is a duplicate and ignore old-style nexthop. */
+            if (nh.is_via)
+                return NULL;
+
             if (nh.ifindex != ifindex || memcmp(&nh.gateway, &gateway, addr_len) != 0) {
                 /* we have a RTA_MULTIPATH attribute that does not agree.
                  * That seems not right. Error out. */
@@ -4238,7 +4258,7 @@ rta_multipath_done:
          * 1 (lo). Of course it does!! */
         if (nh.found) {
             if (IS_IPv4) {
-                if (nh.ifindex != 0 || nh.gateway.addr4 != 0) {
+                if (nh.ifindex != 0 || nh.gateway.addr4 != 0 || nh.is_via) {
                     /* we only accept kernel to notify about the ifindex/gateway, if it
                      * is zero. This is only to be a bit forgiving, but we really don't
                      * know how to handle such routes that have an ifindex. */
@@ -4337,9 +4357,14 @@ rta_multipath_done:
     if (tb[RTA_PRIORITY])
         obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]);
 
-    if (IS_IPv4)
-        obj->ip4_route.gateway = nh.gateway.addr4;
-    else
+    if (IS_IPv4) {
+        if (nh.is_via) {
+            obj->ip4_route.via.addr_family = AF_INET6;
+            obj->ip4_route.via.addr        = nh.gateway;
+        } else {
+            obj->ip4_route.gateway = nh.gateway.addr4;
+        }
+    } else
         obj->ip6_route.gateway = nh.gateway.addr6;
 
     if (IS_IPv4)
@@ -5838,7 +5863,24 @@ _nl_msg_new_route(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPObject *ob
 
     /* We currently don't have need for multi-hop routes... */
     if (IS_IPv4) {
-        NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip4_route.gateway);
+        if (obj->ip4_route.gateway == INADDR_ANY && obj->ip4_route.via.addr_family != AF_UNSPEC) {
+            struct rtvia *rtvia;
+
+            nm_assert(obj->ip4_route.via.addr_family == AF_INET6);
+
+            rtvia = nla_data(nla_reserve(
+                msg,
+                RTA_VIA,
+                sizeof(*rtvia) + nm_utils_addr_family_to_size(obj->ip4_route.via.addr_family)));
+            if (!rtvia)
+                goto nla_put_failure;
+            rtvia->rtvia_family = obj->ip4_route.via.addr_family;
+            memcpy(rtvia->rtvia_addr,
+                   obj->ip4_route.via.addr.addr_ptr,
+                   nm_utils_addr_family_to_size(obj->ip4_route.via.addr_family));
+        } else {
+            NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip4_route.gateway);
+        }
     } else {
         if (!IN6_IS_ADDR_UNSPECIFIED(&obj->ip6_route.gateway))
             NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip6_route.gateway);