Harald Welte has submitted this change and it was merged.

Change subject: ippool: Extend pool to work with /64 prefixes
......................................................................


ippool: Extend pool to work with /64 prefixes

In IPv6 GPRS, we actually don't want to allocate an individual v6
address (like in IPv4), but we want to allocate a prefix.  The
standard prefix lengh is 8 bytes, i.e. a /64 prefix.  This patch
extends the pool to be able to work with such v6 prefixes.

Change-Id: I0cf700b6baf195a2e5fbea000531f801acaaa443
---
M ggsn/ggsn.c
M lib/in46_addr.c
M lib/ippool.c
3 files changed, 17 insertions(+), 8 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 0629f9e..9b11884 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -241,7 +241,11 @@
                dst.len = 4;
                dst.v4.s_addr = iph->daddr;
        } else if (iph->version == 6) {
-               dst.len = 16;
+               /* Due to the fact that 3GPP requires an allocation of a
+                * /64 prefix to each MS, we must instruct
+                * ippool_getip() below to match only the leading /64
+                * prefix, i.e. the first 8 bytes of the address */
+               dst.len = 8;
                dst.v6 = ip6h->ip6_dst;
        } else {
                LOGP(DGGSN, LOGL_NOTICE, "non-IPv packet received from tun\n");
diff --git a/lib/in46_addr.c b/lib/in46_addr.c
index a220583..1785377 100644
--- a/lib/in46_addr.c
+++ b/lib/in46_addr.c
@@ -25,6 +25,7 @@
        switch (in->len) {
        case 4:
                return AF_INET;
+       case 8:
        case 16:
                return AF_INET6;
        default:
@@ -175,6 +176,7 @@
                eua->v[1] = 0x21;       /* IPv4 */
                memcpy(&eua->v[2], &src->v4, 4);        /* Copy a 4 byte 
address */
                break;
+       case 8:
        case 16:
                eua->l = 18;
                eua->v[0] = 0xf1;       /* IETF */
diff --git a/lib/ippool.c b/lib/ippool.c
index 007dc50..1729ec7 100644
--- a/lib/ippool.c
+++ b/lib/ippool.c
@@ -96,11 +96,10 @@
        return lookup((unsigned char *)&addr->s_addr, sizeof(addr->s_addr), 0);
 }
 
-static unsigned long int ippool_hash6(struct in6_addr *addr)
+static unsigned long int ippool_hash6(struct in6_addr *addr, unsigned int len)
 {
        /* TODO: Review hash spread for IPv6 */
-       return lookup((unsigned char *)addr->s6_addr, sizeof(addr->s6_addr),
-                     0);
+       return lookup((unsigned char *)addr->s6_addr, len, 0);
 }
 
 unsigned long int ippool_hash(struct in46_addr *addr)
@@ -108,7 +107,7 @@
        if (addr->len == 4)
                return ippool_hash4(&addr->v4);
        else
-               return ippool_hash6(&addr->v6);
+               return ippool_hash6(&addr->v6, addr->len);
 }
 
 /* Get IP address and mask */
@@ -209,6 +208,10 @@
                                "Failed to parse dynamic pool");
                        return -1;
                }
+               /* we want to work with /64 prefixes, i.e. allocate /64 
prefixes rather
+                * than /128 (single IPv6 addresses) */
+               if (addr.len == sizeof(struct in6_addr))
+                       addr.len = 64/8;
 
                /* Set IPPOOL_NONETWORK if IPPOOL_NOGATEWAY is set */
                if (flags & IPPOOL_NOGATEWAY) {
@@ -348,7 +351,7 @@
        /* Find in hash table */
        hash = ippool_hash(addr) & this->hashmask;
        for (p = this->hash[hash]; p; p = p->nexthash) {
-               if (in46a_equal(&p->addr, addr)) {
+               if (in46a_prefix_equal(&p->addr, addr)) {
                        if (member)
                                *member = p;
                        return 0;
@@ -421,7 +424,7 @@
                /* Find in hash table */
                hash = ippool_hash(addr) & this->hashmask;
                for (p = this->hash[hash]; p; p = p->nexthash) {
-                       if (in46a_equal(&p->addr, addr)) {
+                       if (in46a_prefix_equal(&p->addr, addr)) {
                                p2 = p;
                                break;
                        }
@@ -450,7 +453,7 @@
                        return -GTPCAUSE_SYS_FAIL;      /* Allready in use / 
Should not happen */
                }
 
-               if (p2->addr.len != addr->len) {
+               if (p2->addr.len != addr->len && !(addr->len == 16 && 
p2->addr.len == 8)) {
                        SYS_ERR(DIP, LOGL_ERROR, 0, "MS requested unsupported 
PDP context type");
                        return -GTPCAUSE_UNKNOWN_PDP;
                }

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

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

Reply via email to