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
This commit is contained in:
parent
53165ede24
commit
a0d281db1c
11
ggsn/ggsn.c
11
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 @@ int create_context_ind(struct pdp_t *pdp)
|
|||
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 @@ int create_context_ind(struct pdp_t *pdp)
|
|||
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 @@ int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -146,3 +146,63 @@ int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net,
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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 int in46a_to_sas(struct sockaddr_storage *out, const struct in46_addr *in
|
|||
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);
|
||||
|
|
|
@ -1329,7 +1329,7 @@ int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
|||
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);
|
||||
|
|
Reference in New Issue