Hello Jenkins Builder,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/3406

to look at the new patch set (#6).

IPv6 support for user IP

This patch enables the use of IPv6 PDP contexts.  The phone will
have to request an IPv6 End-user-Address, and the GGSN will have
to be configured for an IPv6 pool.

The outer transport-layer IP between SGSN and GGSN must still be
IPv4, it is not modified by this patch

Change-Id: I22c3bf32a98e5daf99d6eaeac8c9f95cc7574774
---
M ggsn/ggsn.c
M lib/in46_addr.c
M lib/in46_addr.h
M sgsnemu/sgsnemu.c
4 files changed, 74 insertions(+), 4 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/openggsn refs/changes/06/3406/6

diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 4fb2066..8e7d1e3 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -35,6 +35,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <arpa/inet.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
@@ -190,7 +191,7 @@
        memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
        pdp->qos_neg.l = pdp->qos_req.l;
 
-       if (pdp_euaton(&pdp->eua, &addr.v4)) {
+       if (in46a_from_eua(&pdp->eua, &addr)) {
                addr.v4.s_addr = 0;     /* Request dynamic */
        }
 
@@ -199,7 +200,7 @@
                return 0;       /* Allready in use, or no more available */
        }
 
-       pdp_ntoeua(&member->addr.v4, &pdp->eua);
+       in46a_to_eua(&member->addr, &pdp->eua);
        pdp->peer = member;
        pdp->ipif = tun;        /* TODO */
        member->peer = pdp;
@@ -224,14 +225,18 @@
        struct ippoolm_t *ipm;
        struct in46_addr dst;
        struct iphdr *iph = (struct iphdr *)pack;
+       struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 
        if (iph->version == 4) {
                if (len < sizeof(*iph) || len < 4*iph->ihl)
                        return -1;
                dst.len = 4;
                dst.v4.s_addr = iph->daddr;
+       } else if (iph->version == 6) {
+               dst.len = 16;
+               dst.v6 = ip6h->ip6_dst;
        } else {
-               LOGP(DGGSN, LOGL_NOTICE, "non-IPv4 packet received from tun\n");
+               LOGP(DGGSN, LOGL_NOTICE, "non-IPv packet received from tun\n");
                return -1;
        }
 
diff --git a/lib/in46_addr.c b/lib/in46_addr.c
index 903ceec..844e318 100644
--- a/lib/in46_addr.c
+++ b/lib/in46_addr.c
@@ -146,3 +146,63 @@
                return 0;
        }
 }
+
+/*! Convert given PDP End User Address to in46_addr
+ *  \returns 0 on success; negative on error */
+int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua)
+{
+       switch (src->len) {
+       case 4:
+               eua->l = 6;
+               eua->v[0] = 0xf1;       /* IETF */
+               eua->v[1] = 0x21;       /* IPv4 */
+               memcpy(&eua->v[2], &src->v4, 4);        /* Copy a 4 byte 
address */
+               break;
+       case 16:
+               eua->l = 18;
+               eua->v[0] = 0xf1;       /* IETF */
+               eua->v[1] = 0x57;       /* IPv6 */
+               memcpy(&eua->v[2], &src->v6, 16);       /* Copy a 16 byte 
address */
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+/*! Convert given in46_addr to PDP End User Address
+ *  \returns 0 on success; negative on error */
+int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst)
+{
+       if (eua->l < 2)
+               goto default_to_dyn_v4;
+
+       if (eua->v[0] != 0xf1)
+               return -1;
+
+       switch (eua->v[1]) {
+       case 0x21:
+               dst->len = 4;
+               if (eua->l >= 6)
+                       memcpy(&dst->v4, &eua->v[2], 4);        /* Copy a 4 
byte address */
+               else
+                       dst->v4.s_addr = 0;
+               break;
+       case 0x57:
+               dst->len = 16;
+               if (eua->l >= 18)
+                       memcpy(&dst->v6, &eua->v[2], 16);       /* Copy a 16 
byte address */
+               else
+                       memset(&dst->v6, 0, 16);
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+
+default_to_dyn_v4:
+       /* assume dynamic IPv4 by default */
+       dst->len = 4;
+       dst->v4.s_addr = 0;
+       return 0;
+}
diff --git a/lib/in46_addr.h b/lib/in46_addr.h
index f28fd8e..a0ad6e1 100644
--- a/lib/in46_addr.h
+++ b/lib/in46_addr.h
@@ -2,6 +2,8 @@
 #include <stdint.h>
 #include <netinet/in.h>
 
+#include "../gtp/pdp.h"
+
 /* a simple wrapper around an in6_addr to also contain the length of the 
address,
  * thereby implicitly indicating the address family of the address */
 struct in46_addr {
@@ -17,3 +19,6 @@
 extern const char *in46a_ntop(const struct in46_addr *in, char *dst, socklen_t 
dst_size);
 extern int in46a_equal(const struct in46_addr *a, const struct in46_addr *b);
 extern int in46a_within_mask(const struct in46_addr *addr, const struct 
in46_addr *net, size_t prefixlen);
+
+int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua);
+int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst);
diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c
index af8f9fa..8c9cfd3 100644
--- a/sgsnemu/sgsnemu.c
+++ b/sgsnemu/sgsnemu.c
@@ -1329,7 +1329,7 @@
                return EOF;     /* Not what we expected */
        }
 
-       if (pdp_euaton(&pdp->eua, &addr.v4)) {
+       if (in46a_from_eua(&pdp->eua, &addr)) {
                printf
                    ("Received create PDP context response. Cause value: %d\n",
                     cause);

-- 
To view, visit https://gerrit.osmocom.org/3406
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I22c3bf32a98e5daf99d6eaeac8c9f95cc7574774
Gerrit-PatchSet: 6
Gerrit-Project: openggsn
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <lafo...@gnumonks.org>
Gerrit-Reviewer: Jenkins Builder

Reply via email to