<p>pespin <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-ggsn/+/17825">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  laforge: Looks good to me, but someone else must approve
  daniel: Looks good to me, but someone else must approve
  pespin: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">sgsnemu: Handle IPv6 SLAAC in tun iface manually<br><br>Disable IPv6 automatic SLAAC by linux kernel and handle it manually.<br>This allows us gaining control on local address acquisition and set<br>addresses and routing properly. It will also allow us to run in ping<br>mode without a tun iface.<br><br>Related: OS#4434<br><br>Change-Id: Iae59cf6ffb181357e10b3080a5c751bd454f4a1f<br>---<br>M ggsn/ggsn.c<br>M lib/icmpv6.c<br>M lib/icmpv6.h<br>M lib/netdev.c<br>M lib/netdev.h<br>M sgsnemu/sgsnemu.c<br>6 files changed, 306 insertions(+), 117 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c</span><br><span>index 3b10f70..159362f 100644</span><br><span>--- a/ggsn/ggsn.c</span><br><span>+++ b/ggsn/ggsn.c</span><br><span>@@ -636,11 +636,6 @@</span><br><span>   return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* RFC3307 link-local scope multicast address */</span><br><span style="color: hsl(0, 100%, 40%);">-static const struct in6_addr all_router_mcast_addr = {</span><br><span style="color: hsl(0, 100%, 40%);">-        .s6_addr = { 0xff,0x02,0,0,  0,0,0,0, 0,0,0,0,  0,0,0,2 }</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* MS-originated GTP1-U packet, needs to be sent via TUN device */</span><br><span> static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)</span><br><span> {</span><br><span>diff --git a/lib/icmpv6.c b/lib/icmpv6.c</span><br><span>index ae72b4c..1bddf65 100644</span><br><span>--- a/lib/icmpv6.c</span><br><span>+++ b/lib/icmpv6.c</span><br><span>@@ -27,6 +27,7 @@</span><br><span> #include "../gtp/pdp.h"</span><br><span> #include "ippool.h"</span><br><span> #include "syserr.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "icmpv6.h"</span><br><span> #include "config.h"</span><br><span> </span><br><span> /* 29.061 11.2.1.3.4 IPv6 Router Configuration Variables in GGSN */</span><br><span>@@ -35,61 +36,11 @@</span><br><span> #define GGSN_AdvValidLifetime  0xffffffff      /* infinite */</span><br><span> #define GGSN_AdvPreferredLifetime 0xffffffff  /* infinite */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct icmpv6_hdr {</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t type;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t code;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint16_t csum;</span><br><span style="color: hsl(0, 100%, 40%);">-} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+/* RFC3307 link-local scope multicast address */</span><br><span style="color: hsl(120, 100%, 40%);">+const struct in6_addr all_router_mcast_addr = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .s6_addr = { 0xff,0x02,0,0,  0,0,0,0, 0,0,0,0,  0,0,0,2 }</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* RFC4861 Section 4.2 */</span><br><span style="color: hsl(0, 100%, 40%);">-struct icmpv6_radv_hdr {</span><br><span style="color: hsl(0, 100%, 40%);">-      struct icmpv6_hdr hdr;</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t cur_ho_limit;</span><br><span style="color: hsl(0, 100%, 40%);">-#if BYTE_ORDER == LITTLE_ENDIAN</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t res:6,</span><br><span style="color: hsl(0, 100%, 40%);">-          m:1,</span><br><span style="color: hsl(0, 100%, 40%);">-            o:1;</span><br><span style="color: hsl(0, 100%, 40%);">-#elif BYTE_ORDER == BIG_ENDIAN</span><br><span style="color: hsl(0, 100%, 40%);">-      uint8_t m:1,</span><br><span style="color: hsl(0, 100%, 40%);">-            o:1,</span><br><span style="color: hsl(0, 100%, 40%);">-            res:6;</span><br><span style="color: hsl(0, 100%, 40%);">-#else</span><br><span style="color: hsl(0, 100%, 40%);">-# error      "Please fix <bits/endian.h>"</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-      uint16_t router_lifetime;</span><br><span style="color: hsl(0, 100%, 40%);">-       uint32_t reachable_time;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint32_t retrans_timer;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t options[0];</span><br><span style="color: hsl(0, 100%, 40%);">-} __attribute__ ((packed));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* RFC4861 Section 4.6 */</span><br><span style="color: hsl(0, 100%, 40%);">-struct icmpv6_opt_hdr {</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t type;</span><br><span style="color: hsl(0, 100%, 40%);">-   /* length in units of 8 octets, including type+len! */</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t len;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t data[0];</span><br><span style="color: hsl(0, 100%, 40%);">-} __attribute__ ((packed));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* RFC4861 Section 4.6.2 */</span><br><span style="color: hsl(0, 100%, 40%);">-struct icmpv6_opt_prefix {</span><br><span style="color: hsl(0, 100%, 40%);">-        struct icmpv6_opt_hdr hdr;</span><br><span style="color: hsl(0, 100%, 40%);">-      uint8_t prefix_len;</span><br><span style="color: hsl(0, 100%, 40%);">-#if BYTE_ORDER == LITTLE_ENDIAN</span><br><span style="color: hsl(0, 100%, 40%);">-      uint8_t res:6,</span><br><span style="color: hsl(0, 100%, 40%);">-          a:1,</span><br><span style="color: hsl(0, 100%, 40%);">-            l:1;</span><br><span style="color: hsl(0, 100%, 40%);">-#elif BYTE_ORDER == BIG_ENDIAN</span><br><span style="color: hsl(0, 100%, 40%);">-      uint8_t l:1,</span><br><span style="color: hsl(0, 100%, 40%);">-            a:1,</span><br><span style="color: hsl(0, 100%, 40%);">-            res:6;</span><br><span style="color: hsl(0, 100%, 40%);">-#else</span><br><span style="color: hsl(0, 100%, 40%);">-# error      "Please fix <bits/endian.h>"</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-      uint32_t valid_lifetime;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint32_t preferred_lifetime;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint32_t res2;</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t prefix[16];</span><br><span style="color: hsl(0, 100%, 40%);">-} __attribute__ ((packed));</span><br><span> /* Prepends the ipv6 header and returns checksum content */</span><br><span> static uint16_t icmpv6_prepend_ip6hdr(struct msgb *msg, const struct in6_addr *saddr,</span><br><span>                                 const struct in6_addr *daddr)</span><br><span>@@ -115,7 +66,26 @@</span><br><span>        return skb_csum;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! construct a RFC4861 compliant ICMPv6 router soliciation</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] saddr Source IPv6 address for router advertisement</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] daddr Destination IPv6 address for router advertisement IPv6 header</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] prefix The single prefix to be advertised (/64 implied!)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns callee-allocated message buffer containing router advertisement */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *icmpv6_construct_rs(const struct in6_addr *saddr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *msg = msgb_alloc_headroom(512,128, "IPv6 RS");</span><br><span style="color: hsl(120, 100%, 40%);">+ struct icmpv6_rsol_hdr *rs;</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     rs = (struct icmpv6_rsol_hdr *) msgb_put(msg, sizeof(*rs));</span><br><span style="color: hsl(120, 100%, 40%);">+   rs->hdr.type = 133;  /* see RFC4861 4.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+ rs->hdr.code = 0;    /* see RFC4861 4.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+ rs->hdr.csum = 0;    /* updated below */</span><br><span style="color: hsl(120, 100%, 40%);">+   rs->reserved = 0;    /* see RFC4861 4.1 */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     rs->hdr.csum = icmpv6_prepend_ip6hdr(msg, saddr, &all_router_mcast_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> /*! construct a 3GPP 29.061 compliant router advertisement for a given prefix</span><br><span>  *  \param[in] saddr Source IPv6 address for router advertisement</span><br><span>  *  \param[in] daddr Destination IPv6 address for router advertisement IPv6 header</span><br><span>@@ -188,6 +158,37 @@</span><br><span>    return true;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Validate an ICMPv6 router advertisement according to RFC4861 6.1.2.</span><br><span style="color: hsl(120, 100%, 40%);">+   Returns pointer packet header on success, NULL otherwise. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct icmpv6_radv_hdr *icmpv6_validate_router_adv(const uint8_t *pack, unsigned len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* ICMP length (derived from IP length) is 16 or more octets */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (len < sizeof(*ip6h) + 16)</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ic6h->type != 134) /* router advertismenet type */</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /*Routers must use their link-local address */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src))</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Hop limit field must have 255 */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_hlim != 255)</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* ICMP Code is 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ic6h->code != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* ICMP length (derived from IP length) is 16 or more octets */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_plen < 16)</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* FIXME: All included options have a length > 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+        /* FIXME: If IP source is unspecified, no source link-layer addr option */</span><br><span style="color: hsl(120, 100%, 40%);">+    return (struct icmpv6_radv_hdr *)ic6h;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* handle incoming packets to the all-routers multicast address */</span><br><span> int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp,</span><br><span>                   const struct in6_addr *pdp_prefix,</span><br><span>diff --git a/lib/icmpv6.h b/lib/icmpv6.h</span><br><span>index bf91e27..44b9b73 100644</span><br><span>--- a/lib/icmpv6.h</span><br><span>+++ b/lib/icmpv6.h</span><br><span>@@ -1,9 +1,90 @@</span><br><span> #pragma once</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/endian.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include "../gtp/gtp.h"</span><br><span> #include "../gtp/pdp.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define ICMPv6_OPT_TYPE_PREFIX_INFO 0x03</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define foreach_icmpv6_opt(icmpv6_pkt, icmpv6_len, opt_hdr) \</span><br><span style="color: hsl(120, 100%, 40%);">+         for (opt_hdr = (struct icmpv6_opt_hdr *)(icmpv6_pkt)->options; \</span><br><span style="color: hsl(120, 100%, 40%);">+                (uint8_t*)(opt_hdr) + sizeof(struct icmpv6_opt_hdr) <= (((uint8_t*)(icmpv6_pkt)) + (icmpv6_len)); \</span><br><span style="color: hsl(120, 100%, 40%);">+                opt_hdr = (struct icmpv6_opt_hdr*)((uint8_t*)(opt_hdr) + (opt_hdr)->len) \</span><br><span style="color: hsl(120, 100%, 40%);">+                )</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct icmpv6_hdr {</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t type;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t code;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t csum;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* RFC4861 Section 4.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct icmpv6_rsol_hdr {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct icmpv6_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t reserved;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t options[0];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* RFC4861 Section 4.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct icmpv6_radv_hdr {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct icmpv6_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t cur_ho_limit;</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t res:6,</span><br><span style="color: hsl(120, 100%, 40%);">+                m:1,</span><br><span style="color: hsl(120, 100%, 40%);">+          o:1;</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t m:1,</span><br><span style="color: hsl(120, 100%, 40%);">+          o:1,</span><br><span style="color: hsl(120, 100%, 40%);">+          res:6;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t router_lifetime;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t reachable_time;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t retrans_timer;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t options[0];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* RFC4861 Section 4.6 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct icmpv6_opt_hdr {</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t type;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* length in units of 8 octets, including type+len! */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t len;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t data[0];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* RFC4861 Section 4.6.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct icmpv6_opt_prefix {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct icmpv6_opt_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t prefix_len;</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t res:6,</span><br><span style="color: hsl(120, 100%, 40%);">+                a:1,</span><br><span style="color: hsl(120, 100%, 40%);">+          l:1;</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t l:1,</span><br><span style="color: hsl(120, 100%, 40%);">+          a:1,</span><br><span style="color: hsl(120, 100%, 40%);">+          res:6;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t valid_lifetime;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t preferred_lifetime;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t res2;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t prefix[16];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *icmpv6_construct_rs(const struct in6_addr *saddr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp,</span><br><span>                       const struct in6_addr *pdp_prefix,</span><br><span>                   const struct in6_addr *own_ll_addr,</span><br><span>                  const uint8_t *pack, unsigned len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct icmpv6_radv_hdr *icmpv6_validate_router_adv(const uint8_t *pack, unsigned len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* RFC3307 link-local scope multicast address */</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct in6_addr all_router_mcast_addr;</span><br><span>diff --git a/lib/netdev.c b/lib/netdev.c</span><br><span>index 4d171c9..fd3caff 100644</span><br><span>--- a/lib/netdev.c</span><br><span>+++ b/lib/netdev.c</span><br><span>@@ -643,6 +643,59 @@</span><br><span>         return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int netdev_route6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface, int delete)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int fd;</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(__linux__)</span><br><span style="color: hsl(120, 100%, 40%);">+       struct in6_rtmsg r;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ifreq ifr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   memset(&r, 0, sizeof(r));</span><br><span style="color: hsl(120, 100%, 40%);">+ r.rtmsg_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */</span><br><span style="color: hsl(120, 100%, 40%);">+  r.rtmsg_metric = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Create a channel to the NET kernel. */</span><br><span style="color: hsl(120, 100%, 40%);">+     if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (gw_iface) {</span><br><span style="color: hsl(120, 100%, 40%);">+               strncpy(ifr.ifr_name, gw_iface, IFNAMSIZ);</span><br><span style="color: hsl(120, 100%, 40%);">+            ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       SYS_ERR(DTUN, LOGL_ERROR, errno,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "ioctl(SIOCGIFINDEX) failed");</span><br><span style="color: hsl(120, 100%, 40%);">+                      close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             r.rtmsg_ifindex = ifr.ifr_ifindex;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   memcpy(&r.rtmsg_dst, dst->s6_addr, sizeof(struct in6_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+   memcpy(&r.rtmsg_gateway, gateway->s6_addr, sizeof(struct in6_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+   r.rtmsg_dst_len = prefixlen;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (delete) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (ioctl(fd, SIOCDELRT, (void *)&r) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    SYS_ERR(DTUN, LOGL_ERROR, errno,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "ioctl(SIOCDELRT) failed");</span><br><span style="color: hsl(120, 100%, 40%);">+                 close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ioctl(fd, SIOCADDRT, (void *)&r) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    SYS_ERR(DTUN, LOGL_ERROR, errno,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "ioctl(SIOCADDRT) failed");</span><br><span style="color: hsl(120, 100%, 40%);">+                 close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int netdev_addroute4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask)</span><br><span> {</span><br><span>      return netdev_route4(dst, gateway, mask, 0);</span><br><span>@@ -653,6 +706,18 @@</span><br><span>  return netdev_route4(dst, gateway, mask, 1);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int netdev_addroute6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return netdev_route6(dst, gateway, prefixlen, gw_iface, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int netdev_delroute6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return netdev_route6(dst, gateway, prefixlen, gw_iface, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include <ifaddrs.h></span><br><span> </span><br><span> /*! Obtain the local address of a network device</span><br><span>diff --git a/lib/netdev.h b/lib/netdev.h</span><br><span>index 5dab27f..1bce814 100644</span><br><span>--- a/lib/netdev.h</span><br><span>+++ b/lib/netdev.h</span><br><span>@@ -67,6 +67,8 @@</span><br><span> </span><br><span> extern int netdev_addroute4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask);</span><br><span> extern int netdev_delroute4(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask);</span><br><span style="color: hsl(120, 100%, 40%);">+extern int netdev_addroute6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface);</span><br><span style="color: hsl(120, 100%, 40%);">+extern int netdev_delroute6(struct in6_addr *dst, struct in6_addr *gateway, int prefixlen, const char *gw_iface);</span><br><span> </span><br><span> extern int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list,</span><br><span>                            size_t prefix_size, int flags);</span><br><span>diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c</span><br><span>index ea52da6..69879dd 100644</span><br><span>--- a/sgsnemu/sgsnemu.c</span><br><span>+++ b/sgsnemu/sgsnemu.c</span><br><span>@@ -58,6 +58,7 @@</span><br><span> #include "../lib/ippool.h"</span><br><span> #include "../lib/syserr.h"</span><br><span> #include "../lib/netns.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "../lib/icmpv6.h"</span><br><span> #include "../gtp/pdp.h"</span><br><span> #include "../gtp/gtp.h"</span><br><span> #include "cmdline.h"</span><br><span>@@ -966,41 +967,6 @@</span><br><span> </span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* read a single value from a /procc file, up to 255 bytes, callee-allocated */</span><br><span style="color: hsl(0, 100%, 40%);">-static char *proc_read(const char *path)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       char *ret = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-       FILE *f;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        f = fopen(path, "r");</span><br><span style="color: hsl(0, 100%, 40%);">- if (!f)</span><br><span style="color: hsl(0, 100%, 40%);">-         return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    ret = malloc(256);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!ret)</span><br><span style="color: hsl(0, 100%, 40%);">-               goto out;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!fgets(ret, 256, f)) {</span><br><span style="color: hsl(0, 100%, 40%);">-              free(ret);</span><br><span style="color: hsl(0, 100%, 40%);">-              ret = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-             goto out;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-out:</span><br><span style="color: hsl(0, 100%, 40%);">-   fclose(f);</span><br><span style="color: hsl(0, 100%, 40%);">-      return ret;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* Read value of a /proc/sys/net/ipv6/conf file for given device.</span><br><span style="color: hsl(0, 100%, 40%);">- * Memory is dynamically allocated, caller must free it later. */</span><br><span style="color: hsl(0, 100%, 40%);">-static char *proc_ipv6_conf_read(const char *dev, const char *file)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";</span><br><span style="color: hsl(0, 100%, 40%);">-    char path[strlen(fmt) + strlen(dev) + strlen(file)+1];</span><br><span style="color: hsl(0, 100%, 40%);">-  snprintf(path, sizeof(path), fmt, dev, file);</span><br><span style="color: hsl(0, 100%, 40%);">-   return proc_read(path);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* write a single value to a /proc file */</span><br><span> static int proc_write(const char *path, const char *value)</span><br><span> {</span><br><span>@@ -1522,8 +1488,10 @@</span><br><span>                           if (in46a_is_v4(&addr[i])) {</span><br><span>                                     struct in_addr rm;</span><br><span>                                   rm.s_addr = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                                  netdev_addroute4(&rm, &addr[i].v4, &rm);</span><br><span style="color: hsl(0, 100%, 40%);">-                            }</span><br><span style="color: hsl(120, 100%, 40%);">+                                     if (netdev_addroute4(&rm, &addr[i].v4, &rm) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                             SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed adding default route to %s", in46a_ntoa(&addr[i]));</span><br><span style="color: hsl(120, 100%, 40%);">+                                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                             } /* else: route will be set up once we have a global link address (Router Advertisement) */</span><br><span>                         }</span><br><span>                    if (options.ipup)</span><br><span>                            tun_runscript(tun, options.ipup);</span><br><span>@@ -1532,29 +1500,21 @@</span><br><span>          ipset(iph, &addr[i]);</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* now that ip-up has been executed, check if we are configured to</span><br><span style="color: hsl(0, 100%, 40%);">-       * accept router advertisements */</span><br><span>   if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {</span><br><span style="color: hsl(0, 100%, 40%);">-          char *accept_ra, *forwarding;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           accept_ra = proc_ipv6_conf_read(tun->devname, "accept_ra");</span><br><span style="color: hsl(0, 100%, 40%);">-                forwarding = proc_ipv6_conf_read(tun->devname, "forwarding");</span><br><span style="color: hsl(0, 100%, 40%);">-              if (!accept_ra || !forwarding)</span><br><span style="color: hsl(0, 100%, 40%);">-                  printf("Could not open proc file for %s ?!?\n", tun->devname);</span><br><span style="color: hsl(0, 100%, 40%);">-             else {</span><br><span style="color: hsl(0, 100%, 40%);">-                  if (!strcmp(accept_ra, "0")) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                printf("accept_ra=0, i.e. your tun device is not configured to accept "</span><br><span style="color: hsl(0, 100%, 40%);">-                                       "router advertisements; SLAAC will not succeed, please "</span><br><span style="color: hsl(0, 100%, 40%);">-                                      "fix your setup!\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                 }</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (!strcmp(forwarding, "1") && !strcmp(accept_ra, "1")) {</span><br><span style="color: hsl(0, 100%, 40%);">-                          printf("forwarding=1 and accept_ra=1, i.e. your tun device is not "</span><br><span style="color: hsl(0, 100%, 40%);">-                                   "configured to accept router advertisements; SLAAC will not "</span><br><span style="color: hsl(0, 100%, 40%);">-                                 "succeed, please fix your setup!\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                 }</span><br><span style="color: hsl(120, 100%, 40%);">+             struct in6_addr *saddr6;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (in46a_is_v6(&addr[0])) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      saddr6 = &addr[0].v6;</span><br><span style="color: hsl(120, 100%, 40%);">+             } else if (num_addr > 1 && in46a_is_v6(&addr[1])) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    saddr6 = &addr[1].v6;</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to find IPv6 EUA on IPv6 APN");</span><br><span style="color: hsl(120, 100%, 40%);">+                       return EOF;     /* Not a valid IP address */</span><br><span>                 }</span><br><span style="color: hsl(0, 100%, 40%);">-               free(accept_ra);</span><br><span style="color: hsl(0, 100%, 40%);">-                free(forwarding);</span><br><span style="color: hsl(120, 100%, 40%);">+             SYS_ERR(DSGSN, LOGL_INFO, 0, "Sending ICMPv6 Router Soliciation to GGSN...");</span><br><span style="color: hsl(120, 100%, 40%);">+               msg = icmpv6_construct_rs(saddr6);</span><br><span style="color: hsl(120, 100%, 40%);">+            gtp_data_req(gsn, iph->pdp, msgb_data(msg), msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_free(msg);</span><br><span>      }</span><br><span> </span><br><span> #if defined(__linux__)</span><br><span>@@ -1618,8 +1578,83 @@</span><br><span>     }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void handle_router_adv(struct ip6_hdr *ip6h, struct icmpv6_radv_hdr *ra, size_t ra_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct icmpv6_opt_hdr *opt_hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct icmpv6_opt_prefix *opt_prefix;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       sigset_t oldmask;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct in6_addr rm;</span><br><span style="color: hsl(120, 100%, 40%);">+   char ip6strbuf[200];</span><br><span style="color: hsl(120, 100%, 40%);">+  memset(&rm, 0, sizeof(rm));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     SYS_ERR(DSGSN, LOGL_INFO, 0, "Received ICMPv6 Router Advertisement");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     foreach_icmpv6_opt(ra, ra_len, opt_hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (opt_hdr->type == ICMPv6_OPT_TYPE_PREFIX_INFO) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        opt_prefix = (struct icmpv6_opt_prefix *)opt_hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+                     size_t prefix_len_bytes = (opt_prefix->prefix_len + 7)/8;</span><br><span style="color: hsl(120, 100%, 40%);">+                  SYS_ERR(DSGSN, LOGL_INFO, 0, "Parsing OPT Prefix info (prefix_len=%u): %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                         opt_prefix->prefix_len,</span><br><span style="color: hsl(120, 100%, 40%);">+                            osmo_hexdump((const unsigned char *)opt_prefix->prefix, prefix_len_bytes));</span><br><span style="color: hsl(120, 100%, 40%);">+                        if ((options.createif) && (!options.netaddr.len)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           struct in46_addr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+                                addr.len = 16;</span><br><span style="color: hsl(120, 100%, 40%);">+                                memcpy(addr.v6.s6_addr, opt_prefix->prefix, prefix_len_bytes);</span><br><span style="color: hsl(120, 100%, 40%);">+                             memset(&addr.v6.s6_addr[prefix_len_bytes], 0, 16 - prefix_len_bytes);</span><br><span style="color: hsl(120, 100%, 40%);">+                             addr.v6.s6_addr[15] = 0x02;</span><br><span style="color: hsl(120, 100%, 40%);">+                           SYS_ERR(DSGSN, LOGL_INFO, 0, "Adding addr %s to tun %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    in46a_ntoa(&addr), tun->devname);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(__linux__)</span><br><span style="color: hsl(120, 100%, 40%);">+                            if ((options.netns)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                        if ((rc = switch_ns(netns, &oldmask)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                           SYS_ERR(DSGSN, LOGL_ERROR, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 "Failed to switch to netns %s: %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 options.netns, strerror(-rc));</span><br><span style="color: hsl(120, 100%, 40%);">+                                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                             }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+                             rc = tun_addaddr(tun, &addr, NULL, opt_prefix->prefix_len);</span><br><span style="color: hsl(120, 100%, 40%);">+                            if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to add addr %s to tun %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                            in46a_ntoa(&addr), tun->devname);</span><br><span style="color: hsl(120, 100%, 40%);">+                              }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                           struct in6_addr rm;</span><br><span style="color: hsl(120, 100%, 40%);">+                           memset(&rm, 0, sizeof(rm));</span><br><span style="color: hsl(120, 100%, 40%);">+                               if (netdev_addroute6(&rm, &ip6h->ip6_src, 0, tun->devname) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                    SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed adding default route to %s", inet_ntop(AF_INET6, &ip6h->ip6_src, ip6strbuf, sizeof(ip6strbuf)));</span><br><span style="color: hsl(120, 100%, 40%);">+                               }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(__linux__)</span><br><span style="color: hsl(120, 100%, 40%);">+                           if ((options.netns)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                        if ((rc = restore_ns(&oldmask)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                         SYS_ERR(DSGSN, LOGL_ERROR, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 "Failed to switch to original netns: %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   strerror(-rc));</span><br><span style="color: hsl(120, 100%, 40%);">+                                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                             }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct iphdr *iph = (struct iphdr *)pack;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct icmpv6_radv_hdr *ra;</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (iph->version) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case 6:</span><br><span style="color: hsl(120, 100%, 40%);">+               if ((ra = icmpv6_validate_router_adv(pack, len))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   size_t ra_len = (uint8_t*)ra - (uint8_t*)pack;</span><br><span style="color: hsl(120, 100%, 40%);">+                        handle_router_adv((struct ip6_hdr *)pack, ra, ra_len);</span><br><span style="color: hsl(120, 100%, 40%);">+                        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /*  printf("encaps_tun. Packet received: forwarding to tun\n"); */</span><br><span>         return tun_encaps((struct tun_t *)pdp->ipif, pack, len);</span><br><span> }</span><br><span>@@ -1721,6 +1756,12 @@</span><br><span>            tun_set_cb_ind(tun, cb_tun_ind);</span><br><span>             if (tun->fd > maxfd)</span><br><span>                   maxfd = tun->fd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (proc_ipv6_conf_write(options.tun_dev_name, "accept_ra", "0") < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        SYS_ERR(DSGSN, LOGL_ERROR, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                         "Failed to disable IPv6 SLAAC on %s\n", options.tun_dev_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                      exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span>    }</span><br><span> </span><br><span>        if ((options.createif) && (options.netaddr.len)) {</span><br><span>@@ -1730,6 +1771,10 @@</span><br><span>                          struct in_addr rm;</span><br><span>                           rm.s_addr = 0;</span><br><span>                               netdev_addroute4(&rm, &options.netaddr.v4, &rm);</span><br><span style="color: hsl(120, 100%, 40%);">+                  } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              struct in6_addr rm;</span><br><span style="color: hsl(120, 100%, 40%);">+                           memset(&rm, 0, sizeof(rm));</span><br><span style="color: hsl(120, 100%, 40%);">+                               netdev_addroute6(&rm, &options.netaddr.v6, 0, tun->devname);</span><br><span>                      }</span><br><span>            }</span><br><span>            if (options.ipup)</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-ggsn/+/17825">change 17825</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-ggsn/+/17825"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-ggsn </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Iae59cf6ffb181357e10b3080a5c751bd454f4a1f </div>
<div style="display:none"> Gerrit-Change-Number: 17825 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>