aboutsummaryrefslogtreecommitdiffstats
path: root/lib/in46_addr.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-08-02 21:48:16 +0200
committerHarald Welte <laforge@gnumonks.org>2017-08-09 22:09:34 +0200
commita0d281db1cd2f122fb8f0adfd9e4a82e60efbd2f (patch)
tree613095b3ce11731d6cf757df5cee0c36ec3c0f2b /lib/in46_addr.c
parent53165ede24b106326d3762232435e0a28c10e1bb (diff)
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
Diffstat (limited to 'lib/in46_addr.c')
-rw-r--r--lib/in46_addr.c60
1 files changed, 60 insertions, 0 deletions
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 @@ 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;
+}