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
diff --git a/tests/lib/in46a_test.c b/tests/lib/in46a_test.c
index c0bb670..b22da16 100644
--- a/tests/lib/in46a_test.c
+++ b/tests/lib/in46a_test.c
@@ -137,7 +137,7 @@
#endif
/* IPv4 address */
- OSMO_ASSERT(in46a_to_eua(&g_ia4, &eua) == 0);
+ OSMO_ASSERT(in46a_to_eua(&g_ia4, 1, &eua) == 0);
OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v4);
OSMO_ASSERT(osmo_load32le(&eua.v[2]) == g_ia4.v4.s_addr);
@@ -154,7 +154,7 @@
printf("Testing in46a_from_eua() with IPv4 addresses\n");
/* default: v4 unspec */
- OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0);
+ OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
OSMO_ASSERT(ia.len == 4);
OSMO_ASSERT(ia.v4.s_addr == 0);
@@ -173,14 +173,14 @@
/* unspecified V4 */
memcpy(eua.v, v4_unspec, sizeof(v4_unspec));
eua.l = sizeof(v4_unspec);
- OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0);
+ OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
OSMO_ASSERT(ia.len == 4);
OSMO_ASSERT(ia.v4.s_addr == 0);
/* specified V4 */
memcpy(eua.v, v4_spec, sizeof(v4_spec));
eua.l = sizeof(v4_spec);
- OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0);
+ OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
OSMO_ASSERT(ia.len == 4);
OSMO_ASSERT(ia.v4.s_addr == htonl(0x01020304));
}
@@ -278,21 +278,43 @@
};
struct ul66_t eua;
- printf("testing in46a_to_eua() with IPv6 addresses\n");
+ printf("Testing in46a_to_eua() with IPv6 addresses\n");
/* IPv6 address */
- OSMO_ASSERT(in46a_to_eua(&g_ia6, &eua) == 0);
+ OSMO_ASSERT(in46a_to_eua(&g_ia6, 1, &eua) == 0);
OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6);
OSMO_ASSERT(!memcmp(&eua.v[2], &g_ia6.v6, 16));
/* IPv6 address with prefix / length 8 */
- OSMO_ASSERT(in46a_to_eua(&ia_v6_8, &eua) == 0);
+ OSMO_ASSERT(in46a_to_eua(&ia_v6_8, 1, &eua) == 0);
OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6);
OSMO_ASSERT(!memcmp(&eua.v[2], &ia_v6_8.v6, 16));
}
+static void test_in46a_to_eua_v4v6() {
+ const struct in46_addr ia_v4v6[2] = {
+ {
+ .len = 16,
+ .v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
+ },
+ {
+ .len = 4,
+ .v4.s_addr = 0x0d0c0b0a,
+ }
+ };
+ struct ul66_t eua;
+ printf("Testing in46a_to_eua() with IPv4v6 addresses\n");
+
+ /* IPv4 address */
+ OSMO_ASSERT(in46a_to_eua(ia_v4v6, 2, &eua) == 0);
+ OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
+ OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v4v6);
+ OSMO_ASSERT(osmo_load32le(&eua.v[2]) == g_ia4.v4.s_addr);
+ OSMO_ASSERT(!memcmp(&eua.v[6], &g_ia6.v6, 16));
+}
+
static void test_in46a_from_eua_v6(void)
{
struct in46_addr ia;
@@ -308,18 +330,67 @@
/* unspecified V6 */
memcpy(eua.v, v6_unspec, sizeof(v6_unspec));
eua.l = sizeof(v6_unspec);
- OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0);
+ OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
OSMO_ASSERT(ia.len == 16);
OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia.v6));
/* specified V6 */
memcpy(eua.v, v6_spec, sizeof(v6_spec));
eua.l = sizeof(v6_spec);
- OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0);
+ OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
OSMO_ASSERT(ia.len == 16);
OSMO_ASSERT(!memcmp(&ia.v6, v6_spec+2, ia.len));
}
+static void test_in46a_from_eua_v4v6(void) {
+ struct in46_addr ia[2];
+ struct ul66_t eua;
+ const uint8_t v4_unspec_v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6 };
+ const uint8_t v4_spec_v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4 };
+ const uint8_t v4_unspec_v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
+ const uint8_t v4_spec_v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4, 1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
+
+ memset(&eua, 0, sizeof(eua));
+
+ printf("Testing in46a_from_eua() with IPv4v6 addresses\n");
+
+ /* unspecified V4 & V6 */
+ memcpy(eua.v, v4_unspec_v6_unspec, sizeof(v4_unspec_v6_unspec));
+ eua.l = sizeof(v4_unspec_v6_unspec);
+ OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
+ OSMO_ASSERT(ia[0].len == 4);
+ OSMO_ASSERT(ia[1].len == 16);
+ OSMO_ASSERT(ia[0].v4.s_addr == 0);
+ OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia[1].v6));
+
+ /* specified V4, unspecified V6 */
+ memcpy(eua.v, v4_spec_v6_unspec, sizeof(v4_spec_v6_unspec));
+ eua.l = sizeof(v4_spec_v6_unspec);
+ OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
+ OSMO_ASSERT(ia[0].len == 4);
+ OSMO_ASSERT(ia[1].len == 16);
+ OSMO_ASSERT(ia[0].v4.s_addr == htonl(0x01020304));
+ OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia[1].v6));
+
+ /* unspecified V4, specified V6 */
+ memcpy(eua.v, v4_unspec_v6_spec, sizeof(v4_unspec_v6_spec));
+ eua.l = sizeof(v4_unspec_v6_spec);
+ OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
+ OSMO_ASSERT(ia[0].len == 4);
+ OSMO_ASSERT(ia[1].len == 16);
+ OSMO_ASSERT(ia[0].v4.s_addr == 0);
+ OSMO_ASSERT(!memcmp(&ia[1].v6, v4_unspec_v6_spec+2, ia[1].len));
+
+ /* specified V4, specified V6 */
+ memcpy(eua.v, v4_spec_v6_spec, sizeof(v4_spec_v6_spec));
+ eua.l = sizeof(v4_spec_v6_spec);
+ OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
+ OSMO_ASSERT(ia[0].len == 4);
+ OSMO_ASSERT(ia[1].len == 16);
+ OSMO_ASSERT(ia[0].v4.s_addr == htonl(0x01020304));
+ OSMO_ASSERT(!memcmp(&ia[1].v6, v4_spec_v6_spec+6, ia[1].len));
+}
+
static void test_in46a_netmasklen_v6(void)
{
unsigned int len;
@@ -378,6 +449,8 @@
test_in46a_equal_v6();
test_in46a_to_eua_v6();
test_in46a_from_eua_v6();
+ test_in46a_to_eua_v4v6();
+ test_in46a_from_eua_v4v6();
test_in46a_netmasklen_v6();
}
return 0;