Change in osmo-ggsn[master]: sgsnemu: Fix assumption ipv6 Interface-Identifier of public addr == a...

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

pespin gerrit-no-reply at lists.osmocom.org
Wed Apr 15 18:02:11 UTC 2020


pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ggsn/+/17828 )


Change subject: sgsnemu: Fix assumption ipv6 Interface-Identifier of public addr == announced Prefix
......................................................................

sgsnemu: Fix assumption ipv6 Interface-Identifier of public addr == announced Prefix

Until now, sgsnemu was able to identify pdp contexts of incoming packets
in the tun based on the assumption that the Interface-Identifier part of
public IPv6 addresses in incoming packets was equal to the announced
prefix path during Create Pdp Context Response (see changes in cb_tun_ind()).
This assumption works fine with osmo-ggsn due to implementation details but
breaks on other spec-conformant GGSNs.

In order to fix it, a new placeholder struct pdp_peer_sgsnemu_ctx is
introduced which will be assigned to each pdp_t "peer[0]" user-defined
pointer. This way, each pdp_t ctx upgrades from having only 1 iphash_t
item to 3 (hence being able to match against 3 different ip addresses).
This way, in IPv6 we can match against 2 different IP addresses set on
the tun iface:
* link-local: "fe80::IfId", where IfId is the Interface-Identifier
  received during Pdp Context Resp and which can be used to communicate
  with the nearest router (the GGSN).
* global: The global IPv6 addr set after SLAAC procedure, containing a
  the prefix announced by CreatePdpContextResp/RouterAdvertisement and
  an Interface-Identifier chosen by sgsnemu itself (currently ::ff).

This change is also a step forward towards supporting IPv4v6 APNs in sgsnemu.

Related: OS#4434
Change-Id: I0d36145250185e4cce699fdaedfe96bd969f5fa1
---
M sgsnemu/sgsnemu.c
1 file changed, 53 insertions(+), 41 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-ggsn refs/changes/28/17828/1

diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c
index 779c887..71af735 100644
--- a/sgsnemu/sgsnemu.c
+++ b/sgsnemu/sgsnemu.c
@@ -64,15 +64,23 @@
 #define MAXCONTEXTS 1024	/* Max number of allowed contexts */
 
 /* HASH tables for IP address allocation */
+struct pdp_peer_sgsnemu_ctx;
 struct iphash_t {
 	uint8_t inuse;		/* 0=free. 1=used by somebody */
 	struct iphash_t *ipnext;
-	struct pdp_t *pdp;
+	struct pdp_peer_sgsnemu_ctx *ctx;
 	struct in46_addr addr;
 };
-struct iphash_t iparr[MAXCONTEXTS];
 struct iphash_t *iphash[MAXCONTEXTS];
 
+struct pdp_peer_sgsnemu_ctx {
+	struct iphash_t hash_v4;
+	struct iphash_t hash_v6_ll;
+	struct iphash_t hash_v6_global;
+	struct pdp_t *pdp;
+};
+struct pdp_peer_sgsnemu_ctx ctx_arr[MAXCONTEXTS];
+
 /* State variable used for ping  */
 /* 0: Idle                       */
 /* 1: Wait_connect               */
@@ -189,6 +197,9 @@
 	int hash = ippool_hash(addr) % MAXCONTEXTS;
 	struct iphash_t *h;
 	struct iphash_t *prev = NULL;
+
+	printf("Adding IP to local pool: %s\n", in46a_ntoa(addr));
+
 	ipaddr->ipnext = NULL;
 	ipaddr->addr = *addr;
 	for (h = iphash[hash]; h; h = h->ipnext)
@@ -1552,19 +1563,8 @@
 		src.len = 4;
 		src.v4.s_addr = iph->saddr;
 	} else if (iph->version == 6) {
-		/* We only have a single entry in the hash table, and it consists of the link-local
-		 * address "fe80::prefix".  So we need to make sure to convert non-link-local source
-		 * addresses to that format before looking up the hash table via ippool_getip() */
 		src.len = 16;
-		if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
-			/* is a link-local address, we can do the hash lookup 1:1 */
-			src.v6 = ip6h->ip6_src;
-		} else {
-			/* it is not a link-local address, so we must convert from the /64 prefix
-			 * to the link-local format that's used in the hash table */
-			memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
-			memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
-		}
+		src.v6 = ip6h->ip6_src;
 	} else {
 		printf("Dropping packet with invalid IP version %u\n", iph->version);
 		return 0;
@@ -1576,8 +1576,8 @@
 		return 0;
 	}
 
-	if (ipm->pdp)		/* Check if a peer protocol is defined */
-		gtp_data_req(gsn, ipm->pdp, pack, len);
+	if (ipm->ctx->pdp)		/* Check if a peer protocol is defined */
+		gtp_data_req(gsn, ipm->ctx->pdp, pack, len);
 	return 0;
 }
 
@@ -1589,19 +1589,19 @@
 	sigset_t oldmask;
 #endif
 
-	struct iphash_t *iph = (struct iphash_t *)cbp;
+	struct pdp_peer_sgsnemu_ctx *ctx = (struct pdp_peer_sgsnemu_ctx *) cbp;
 
 	if (cause < 0) {
 		printf("Create PDP Context Request timed out\n");
-		if (iph->pdp->version == 1) {
+		if (ctx->pdp->version == 1) {
 			printf("Retrying with version 0\n");
-			iph->pdp->version = 0;
-			gtp_create_context_req(gsn, iph->pdp, iph);
+			ctx->pdp->version = 0;
+			gtp_create_context_req(gsn, ctx->pdp, ctx);
 			return 0;
 		} else {
 			state = 0;
-			pdp_freepdp(iph->pdp);
-			iph->pdp = NULL;
+			pdp_freepdp(ctx->pdp);
+			ctx->pdp = NULL;
 			return EOF;
 		}
 	}
@@ -1611,8 +1611,8 @@
 		    ("Received create PDP context response. Cause value: %d\n",
 		     cause);
 		state = 0;
-		pdp_freepdp(iph->pdp);
-		iph->pdp = NULL;
+		pdp_freepdp(ctx->pdp);
+		ctx->pdp = NULL;
 		return EOF;	/* Not what we expected */
 	}
 
@@ -1620,8 +1620,8 @@
 		printf
 		    ("Received create PDP context response. Cause value: %d\n",
 		     cause);
-		pdp_freepdp(iph->pdp);
-		iph->pdp = NULL;
+		pdp_freepdp(ctx->pdp);
+		ctx->pdp = NULL;
 		state = 0;
 		return EOF;	/* Not a valid IP address */
 	}
@@ -1643,13 +1643,18 @@
 
 		switch (addr[i].len) {
 		case 16: /* IPv6 */
-			/* we have to enable the kernel to perform stateless autoconfiguration,
-			 * i.e. send a router solicitation using the lover 64bits of the allocated
-			 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
+			/* Convert address to link local using the lower 64bits
+			   of the allocated EUA as Interface-Identifier to
+			   send router solicitation, as per 3GPP TS 29.061
+			   Section 11.2.1.3.2 */
 			memcpy(addr[i].v6.s6_addr, ll_prefix, sizeof(ll_prefix));
 			printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr[i]));
+			ctx->hash_v6_ll.inuse = 1;
+			ipset(&ctx->hash_v6_ll, &addr[i]);
 			break;
 		case 4: /* IPv4 */
+			ctx->hash_v4.inuse = 1;
+			ipset(&ctx->hash_v4, &addr[i]);
 			break;
 		}
 
@@ -1671,8 +1676,6 @@
 			if (options.ipup)
 				tun_runscript(tun, options.ipup);
 		}
-
-		ipset(iph, &addr[i]);
 	}
 
 	if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
@@ -1688,7 +1691,7 @@
 		}
 		SYS_ERR(DSGSN, LOGL_INFO, 0, "Sending ICMPv6 Router Soliciation to GGSN...");
 		msg = icmpv6_construct_rs(saddr6);
-		gtp_data_req(gsn, iph->pdp, msgb_data(msg), msgb_length(msg));
+		gtp_data_req(gsn, ctx->pdp, msgb_data(msg), msgb_length(msg));
 		msgb_free(msg);
 	}
 
@@ -1753,8 +1756,9 @@
 	}
 }
 
-static void handle_router_adv(struct ip6_hdr *ip6h, struct icmpv6_radv_hdr *ra, size_t ra_len)
+static void handle_router_adv(struct pdp_t *pdp, struct ip6_hdr *ip6h, struct icmpv6_radv_hdr *ra, size_t ra_len)
 {
+	struct pdp_peer_sgsnemu_ctx* ctx = (struct pdp_peer_sgsnemu_ctx*)pdp->peer[0];
 	struct icmpv6_opt_hdr *opt_hdr;
 	struct icmpv6_opt_prefix *opt_prefix;
 	int rc;
@@ -1780,6 +1784,12 @@
 				addr.v6.s6_addr[15] = 0x02;
 				SYS_ERR(DSGSN, LOGL_INFO, 0, "Adding addr %s to tun %s",
 					in46a_ntoa(&addr), tun->devname);
+				if (!ctx->hash_v6_global.inuse) {
+					ctx->hash_v6_global.inuse = 1;
+					ipset(&ctx->hash_v6_global, &addr);
+				} else {
+					SYS_ERR(DSGSN, LOGL_ERROR, 0, "First v6 global address in hash already in use!");
+				}
 
 #if defined(__linux__)
 				if ((options.netns)) {
@@ -1824,7 +1834,7 @@
 	case 6:
 		if ((ra = icmpv6_validate_router_adv(pack, len))) {
 			size_t ra_len = (uint8_t*)ra - (uint8_t*)pack;
-			handle_router_adv((struct ip6_hdr *)pack, ra, ra_len);
+			handle_router_adv(pdp, (struct ip6_hdr *)pack, ra, ra_len);
 			return 0;
 		}
 	break;
@@ -1965,7 +1975,7 @@
 
 	/* Initialise hash tables */
 	memset(&iphash, 0, sizeof(iphash));
-	memset(&iparr, 0, sizeof(iparr));
+	memset(&ctx_arr, 0, sizeof(ctx_arr));
 
 	printf("Done initialising GTP library\n\n");
 
@@ -1977,7 +1987,6 @@
 	for (n = 0; n < options.contexts; n++) {
 		uint64_t myimsi;
 		printf("Setting up PDP context #%d\n", n);
-		iparr[n].inuse = 1;	/* TODO */
 
 		imsi_add(options.imsi, &myimsi, n);
 
@@ -1986,9 +1995,12 @@
 		/* Otherwise it is deallocated by gtplib */
 		gtp_pdp_newpdp(gsn, &pdp, myimsi, options.nsapi, NULL);
 
-		pdp->peer[0] = &iparr[n]; /* FIXME: support v4v6, have 2 peers */
+		pdp->peer[0] = &ctx_arr[n];
 		pdp->ipif = tun;	/* TODO */
-		iparr[n].pdp = pdp;
+		ctx_arr[n].pdp = pdp;
+		ctx_arr[n].hash_v4.ctx = &ctx_arr[n];
+		ctx_arr[n].hash_v6_ll.ctx = &ctx_arr[n];
+		ctx_arr[n].hash_v6_global.ctx = &ctx_arr[n];
 
 		if (options.gtpversion == 0) {
 			if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
@@ -2076,7 +2088,7 @@
 
 		/* Create context */
 		/* We send this of once. Retransmissions are handled by gtplib */
-		gtp_create_context_req(gsn, pdp, &iparr[n]);
+		gtp_create_context_req(gsn, pdp, &ctx_arr[n]);
 	}
 
 	state = 1;		/* Enter wait_connection state */
@@ -2126,7 +2138,7 @@
 			for (n = 0; n < options.contexts; n++) {
 				/* Delete context */
 				printf("Disconnecting PDP context #%d\n", n);
-				gtp_delete_context_req2(gsn, iparr[n].pdp, NULL, 1);
+				gtp_delete_context_req2(gsn, ctx_arr[n].pdp, NULL, 1);
 				if ((options.pinghost.len)
 				    && ntransmitted)
 					ping_finish();
@@ -2148,7 +2160,7 @@
 				if (options.debug)
 					printf("Create_ping %d\n", diff);
 				create_ping(gsn,
-					    iparr[pingseq %
+					    ctx_arr[pingseq %
 						  options.contexts].pdp,
 					    &options.pinghost, pingseq,
 					    options.pingsize);

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-ggsn/+/17828
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-ggsn
Gerrit-Branch: master
Gerrit-Change-Id: I0d36145250185e4cce699fdaedfe96bd969f5fa1
Gerrit-Change-Number: 17828
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200415/6b66fb94/attachment.htm>


More information about the gerrit-log mailing list