aboutsummaryrefslogtreecommitdiffstats
path: root/ggsn
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2017-12-06 19:26:25 +0100
committerPau Espin Pedrol <pespin@sysmocom.de>2017-12-11 11:39:18 +0100
commit2d6a69e69a4b4cb2b8cc63c4810dae44e5a4d8f6 (patch)
treeb0484aa531ce9f9973f467c3720be4406d4d8518 /ggsn
parent4f0343233b83337afa1e1dfb4bcf9d076ecd4be2 (diff)
Add support for IPv4v6 End User Addresses
Before this commit, when an MS requested an ipv4v6 context osmo-ggsn returned an error stating the type was unknown, and this text was printed in the log: Processing create PDP context request for APN 'ims' Cannot decode EUA from MS/SGSN: f1 8d This patch has been tested with an MS running the 3 types of addresses: - IPv4 and IPv6: no regressions observed, the context is activated and packets are sent to the ggsn. - IPv4v6: Wireshark correctly parses request and reponse, and then ICMPv6 traffic from both sides. Finally I see the MS using the IPv4 and IPv6 DNS addresses advertised and TCP traffic over IPv4 (because probably my IPv6 network setup is not correct). I also checked I can disable/enable data (pdp ctx delete and activate) several times without any issue. Change-Id: Ic820759167fd3bdf329cb11d4b942e903fe50af5
Diffstat (limited to 'ggsn')
-rw-r--r--ggsn/ggsn.c95
-rw-r--r--ggsn/icmpv6.c7
2 files changed, 59 insertions, 43 deletions
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 1c1276f..fa3e20c 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -335,17 +335,20 @@ static bool send_trap(const struct gsn_t *gsn, const struct pdp_t *pdp, const st
static int delete_context(struct pdp_t *pdp)
{
struct gsn_t *gsn = pdp->gsn;
- struct ippoolm_t *ipp = (struct ippoolm_t *)pdp->peer;
struct apn_ctx *apn = pdp->priv;
+ struct ippoolm_t *member;
+ int i;
LOGPPDP(LOGL_INFO, pdp, "Deleting PDP context\n");
- struct ippoolm_t *member = pdp->peer;
- if (pdp->peer) {
- send_trap(gsn, pdp, member, "imsi-rem-ip"); /* TRAP with IP removal */
- ippool_freeip(ipp->pool, ipp);
- } else
- LOGPPDP(LOGL_ERROR, pdp, "Cannot find/free IP Pool member\n");
+ for (i = 0; i < 2; i++) {
+ if (pdp->peer[i]) {
+ member = pdp->peer[i];
+ send_trap(gsn, pdp, member, "imsi-rem-ip"); /* TRAP with IP removal */
+ ippool_freeip(member->pool, member);
+ } else if(i == 0)
+ LOGPPDP(LOGL_ERROR, pdp, "Cannot find/free IP Pool member\n");
+ }
if (gtp_kernel_tunnel_del(pdp, apn->tun.cfg.dev_name)) {
LOGPPDP(LOGL_ERROR, pdp, "Cannot delete tunnel from kernel:%s\n",
@@ -512,10 +515,10 @@ int create_context_ind(struct pdp_t *pdp)
static char name_buf[256];
struct gsn_t *gsn = pdp->gsn;
struct ggsn_ctx *ggsn = gsn->priv;
- struct in46_addr addr;
- struct ippoolm_t *member;
+ struct in46_addr addr[2];
+ struct ippoolm_t *member = NULL;
struct apn_ctx *apn;
- int rc;
+ int rc, num_addr, i;
osmo_apn_to_str(name_buf, pdp->apn_req.v, pdp->apn_req.l);
@@ -550,55 +553,63 @@ 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 (in46a_from_eua(&pdp->eua, &addr)) {
+ memset(addr, 0, sizeof(addr));
+ if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 0) {
LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
osmo_hexdump(pdp->eua.v, pdp->eua.l));
gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
return 0;
}
- if (addr.len == sizeof(struct in_addr)) {
- /* does this APN actually have an IPv4 pool? */
- if (!apn_supports_ipv4(apn))
- goto err_wrong_af;
+ /* Allocate dynamic addresses from the pool */
+ for (i = 0; i < num_addr; i++) {
+ if (addr[i].len == sizeof(struct in_addr)) {
+ /* does this APN actually have an IPv4 pool? */
+ if (!apn_supports_ipv4(apn))
+ goto err_wrong_af;
+
+ rc = ippool_newip(apn->v4.pool, &member, &addr[i], 0);
+ if (rc < 0)
+ goto err_pool_full;
+ /* copy back */
+ memcpy(&addr[i].v4.s_addr, &member->addr.v4, 4);
+
+ } else if (addr[i].len == sizeof(struct in6_addr)) {
+
+ /* does this APN actually have an IPv6 pool? */
+ if (!apn_supports_ipv6(apn))
+ goto err_wrong_af;
+
+ rc = ippool_newip(apn->v6.pool, &member, &addr[i], 0);
+ if (rc < 0)
+ goto err_pool_full;
+
+ /* IPv6 doesn't really send the real/allocated address at this point, but just
+ * the link-identifier which the MS shall use for router solicitation */
+ /* initialize upper 64 bits to prefix, they are discarded by MS anyway */
+ memcpy(addr[i].v6.s6_addr, &member->addr.v6, 8);
+ /* use allocated 64bit prefix as lower 64bit, used as link id by MS */
+ memcpy(addr[i].v6.s6_addr+8, &member->addr.v6, 8);
+ } else
+ OSMO_ASSERT(0);
- rc = ippool_newip(apn->v4.pool, &member, &addr, 0);
- if (rc < 0)
- goto err_pool_full;
- in46a_to_eua(&member->addr, &pdp->eua);
+ pdp->peer[i] = member;
+ member->peer = pdp;
+ }
+
+ in46a_to_eua(addr, num_addr, &pdp->eua);
+ if (apn_supports_ipv4(apn)) {
/* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
return 0;
}
- } else if (addr.len == sizeof(struct in6_addr)) {
- struct in46_addr tmp;
-
- /* does this APN actually have an IPv6 pool? */
- if (!apn_supports_ipv6(apn))
- goto err_wrong_af;
-
- rc = ippool_newip(apn->v6.pool, &member, &addr, 0);
- if (rc < 0)
- goto err_pool_full;
-
- /* IPv6 doesn't really send the real/allocated address at this point, but just
- * the link-identifier which the MS shall use for router solicitation */
- tmp.len = addr.len;
- /* initialize upper 64 bits to prefix, they are discarded by MS anyway */
- memcpy(tmp.v6.s6_addr, &member->addr.v6, 8);
- /* use allocated 64bit prefix as lower 64bit, used as link id by MS */
- memcpy(tmp.v6.s6_addr+8, &member->addr.v6, 8);
- in46a_to_eua(&tmp, &pdp->eua);
- } else
- OSMO_ASSERT(0);
+ }
- pdp->peer = member;
pdp->ipif = apn->tun.tun; /* TODO */
pdp->priv = apn;
- member->peer = pdp;
if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
diff --git a/ggsn/icmpv6.c b/ggsn/icmpv6.c
index 11ced24..6564a54 100644
--- a/ggsn/icmpv6.c
+++ b/ggsn/icmpv6.c
@@ -183,12 +183,17 @@ static bool icmpv6_validate_router_solicit(const uint8_t *pack, unsigned len)
int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, const struct in6_addr *own_ll_addr,
const uint8_t *pack, unsigned len)
{
- struct ippoolm_t *member = pdp->peer;
+ struct ippoolm_t *member;
const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h));
struct msgb *msg;
OSMO_ASSERT(pdp);
+
+ member = pdp->peer[0];
+ OSMO_ASSERT(member);
+ if (member->addr.len == sizeof(struct in_addr)) /* ipv4v6 context */
+ member = pdp->peer[1];
OSMO_ASSERT(member);
if (len < sizeof(*ip6h)) {