aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Couzens <lynxis@fe80.eu>2023-04-26 19:30:04 +0200
committerlaforge <laforge@osmocom.org>2023-09-05 18:44:00 +0000
commit25d284995dbdf01af544bdec7eb0e29ac4cd31f7 (patch)
tree4b576860208ee6648898c15c5fd2a5b87a8ae483
parent4cbd207a09410163f4bdf5f52947029ab7455de4 (diff)
HLR_Tests: add testcase for multiple APNs in subscriber data
With a new HLR version there are multiple APN possible in the Subscriber Data (PDP Info). Related: SYS#6391 Change-Id: I8d0c08272bc239370e800d6014ab9c68087b8989
-rw-r--r--hlr/HLR_Tests.ttcn120
-rw-r--r--hlr/expected-results.xml3
-rw-r--r--library/GSUP_Types.ttcn44
3 files changed, 146 insertions, 21 deletions
diff --git a/hlr/HLR_Tests.ttcn b/hlr/HLR_Tests.ttcn
index e10aae48..e99011d6 100644
--- a/hlr/HLR_Tests.ttcn
+++ b/hlr/HLR_Tests.ttcn
@@ -535,12 +535,15 @@ runs on HLR_ConnHdlr return GSUP_PDU {
return ret;
}
+/* return_isd -> return the Insert Subscriber Data instead of the Update Location Result */
function f_perform_UL(hexstring imsi, template hexstring msisdn,
template (omit) integer exp_err_cause := omit,
GSUP_CnDomain dom := OSMO_GSUP_CN_DOMAIN_PS,
template (omit) octetstring source_name := omit)
-runs on HLR_ConnHdlr return GSUP_PDU {
- var GSUP_PDU ret;
+runs on HLR_ConnHdlr return GSUP_PDUs {
+ var GSUP_PDU pdu;
+ var GSUP_PDU isd;
+ var GSUP_PDUs ret;
timer T := 3.0;
var boolean exp_fail := false;
var boolean isd_done := false;
@@ -551,31 +554,31 @@ runs on HLR_ConnHdlr return GSUP_PDU {
GSUP.send(valueof(ts_GSUP_UL_REQ(imsi, dom, source_name := source_name)));
T.start;
alt {
- [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, exp_err_cause, destination_name := source_name)) -> value ret {
+ [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, exp_err_cause, destination_name := source_name)) -> value pdu {
setverdict(pass);
}
- [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?, destination_name := source_name)) -> value ret {
+ [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?, destination_name := source_name)) -> value pdu {
setverdict(fail, "Unexpected UL ERROR Cause");
mtc.stop;
}
- [exp_fail] GSUP.receive(tr_GSUP_UL_RES(imsi, destination_name := source_name)) -> value ret {
+ [exp_fail] GSUP.receive(tr_GSUP_UL_RES(imsi, destination_name := source_name)) -> value pdu {
setverdict(fail, "Unexpected UL.res for unknown IMSI");
mtc.stop;
}
- [exp_fail] GSUP.receive(tr_GSUP_ISD_REQ(imsi, destination_name := source_name)) -> value ret {
+ [exp_fail] GSUP.receive(tr_GSUP_ISD_REQ(imsi, destination_name := source_name)) -> value pdu {
setverdict(fail, "Unexpected ISD.req in error case");
mtc.stop;
}
- [not exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?, destination_name := source_name)) -> value ret {
+ [not exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?, destination_name := source_name)) -> value pdu {
setverdict(fail, "Unexpected UL ERROR");
mtc.stop;
}
- [not exp_fail and not isd_done] GSUP.receive(tr_GSUP_ISD_REQ(imsi, msisdn, destination_name := source_name)) -> value ret {
+ [not exp_fail and not isd_done] GSUP.receive(tr_GSUP_ISD_REQ(imsi, msisdn, destination_name := source_name)) -> value isd {
GSUP.send(ts_GSUP_ISD_RES(imsi, source_name := source_name));
isd_done := true;
repeat;
}
- [not exp_fail and isd_done] GSUP.receive(tr_GSUP_UL_RES(imsi, destination_name := source_name)) -> value ret {
+ [not exp_fail and isd_done] GSUP.receive(tr_GSUP_UL_RES(imsi, destination_name := source_name)) -> value pdu {
setverdict(pass);
}
[] GSUP.receive { repeat; }
@@ -584,6 +587,12 @@ runs on HLR_ConnHdlr return GSUP_PDU {
mtc.stop;
}
}
+
+ ret := { pdu };
+ if (isd_done) {
+ ret := ret & { isd };
+ }
+
return ret;
}
@@ -990,13 +999,14 @@ testcase TC_gsup_ul_unknown_imsi_via_proxy() runs on test_CT {
/* test UL for a number of different subscriber cases (algo, 2g/3g, ...) */
private function f_TC_gsup_ul() runs on HLR_ConnHdlr {
- var GSUP_PDU res;
+ var GSUP_PDUs res;
res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn, source_name := g_pars.source_name);
setverdict(pass);
}
+
testcase TC_gsup_ul() runs on test_CT {
var HlrSubscriberList sl;
- var GSUP_PDU res;
+ var GSUP_PDUs res;
f_init(false);
sl := f_gen_subs();
@@ -1015,6 +1025,72 @@ testcase TC_gsup_ul_via_proxy() runs on test_CT {
setverdict(pass);
}
+private function f_TC_gsup_ul_subscriber_data() runs on HLR_ConnHdlr {
+ var GSUP_PDUs pdus;
+ var GSUP_PDU isd;
+ log("GSUP ul subscriber_data", isd);
+ pdus := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn, source_name := g_pars.source_name);
+ isd := pdus[1];
+
+ template GSUP_IEs tr_pdp_info_internet := {
+ tr_GSUP_IE_PDP_CONTEXT_ID('01'O),
+ tr_GSUP_IE_APN(str2apn("internet"))
+ }
+ template GSUP_IEs tr_pdp_info_wildcard := {
+ tr_GSUP_IE_PDP_CONTEXT_ID('02'O),
+ tr_GSUP_IE_APN(str2apn("*"))
+ }
+
+ /* Search for PDP info 'internet', '*' */
+ var boolean found := false;
+ var GSUP_IeValue ievalue;
+ var GSUP_IEs pdp_info;
+ found := f_gsup_find_nested_ie_multiple(isd.ies, OSMO_GSUP_PDP_INFO_IE, 0, ievalue);
+ if (not found) {
+ setverdict(fail, "Multiple APNs: Coulnd't find first PDP Info IE in: ", isd);
+ return;
+ }
+ pdp_info := ievalue.pdp_info;
+ if (not match(pdp_info, tr_pdp_info_internet)) {
+ setverdict(fail, "Multiple APNs: first PDP Info doesn't match: ", pdp_info, "on Template: ", tr_pdp_info_internet);
+ return;
+ }
+
+ /* wildcard '*' */
+ found := f_gsup_find_nested_ie_multiple(isd.ies, OSMO_GSUP_PDP_INFO_IE, 1, ievalue);
+ if (not found) {
+ setverdict(fail, "Multiple APNs: Coulnd't find second PDP Info IE in: ", isd);
+ return;
+ }
+ pdp_info := ievalue.pdp_info;
+ if (not match(pdp_info, tr_pdp_info_wildcard)) {
+ setverdict(fail, "Multiple APNs: second PDP Info doesn't match: ", pdp_info, "on Template: ", tr_pdp_info_wildcard);
+ return;
+ }
+
+ setverdict(pass);
+}
+
+testcase TC_gsup_ul_subscriber_data() runs on test_CT {
+ /* Do a GSUP Update Location Request to get a Insert Subscriber Data Request (ISD).
+ * Check for multiple APN in the ISD:
+ * SGSN -> HLR: Update Location Request
+ * SGSN <- HLR: Insert Subscriber Data Request (Check the TLV)
+ * SGSN -> HLR: Insert Subscriber Data Result
+ * SGSN <- HLR: Update Location Result
+ */
+ var HlrSubscriberList sl;
+
+ f_init(false);
+ f_vty_config2(VTY, {"hlr", "ps"} , "no pdp-profiles default");
+ f_vty_config2(VTY, {"hlr", "ps", "pdp-profiles default", "profile 1"}, "apn internet");
+ f_vty_config2(VTY, {"hlr", "ps", "pdp-profiles default", "profile 2"}, "apn *");
+ sl := f_gen_subs();
+ f_start_handler_per_sub(refers(f_TC_gsup_ul_subscriber_data), sl);
+
+ setverdict(pass);
+}
+
/* Test only the VTY commands */
testcase TC_vty() runs on test_CT {
var HlrSubscriber sub;
@@ -1046,7 +1122,7 @@ testcase TC_vty() runs on test_CT {
/* VTY changes to MSISDN should result in ISD to current VLR */
private function f_TC_vty_msisdn_isd() runs on HLR_ConnHdlr {
var hexstring new_msisdn;
- var GSUP_PDU res;
+ var GSUP_PDUs res;
timer T := 5.0;
/* Create Subscriber */
@@ -1091,9 +1167,10 @@ testcase TC_vty_msisdn_isd() runs on test_CT {
/* Test PURGE MS for CS services */
private function f_TC_gsup_purge_cs() runs on HLR_ConnHdlr {
- var GSUP_PDU res;
+ var GSUP_PDUs res;
+ var GSUP_PDU pdu;
res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
- res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_CS);
+ pdu := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_CS);
}
testcase TC_gsup_purge_cs() runs on test_CT {
var HlrSubscriberList sl;
@@ -1108,9 +1185,10 @@ testcase TC_gsup_purge_cs() runs on test_CT {
/* Test PURGE MS for PS services */
private function f_TC_gsup_purge_ps() runs on HLR_ConnHdlr {
- var GSUP_PDU res;
+ var GSUP_PDUs res;
+ var GSUP_PDU pdu;
res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
- res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_PS);
+ pdu := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_PS);
}
testcase TC_gsup_purge_ps() runs on test_CT {
var HlrSubscriberList sl;
@@ -1540,7 +1618,7 @@ testcase TC_gsup_check_imei_unknown_imsi() runs on test_CT {
/* Test create-subscriber-on-demand during Check IMEI (OsmoMSC would be set to "check-imei-rqd early") */
private function f_TC_subscr_create_on_demand_check_imei_early() runs on HLR_ConnHdlr {
- var GSUP_PDU res; /* save various return values to prevent ttcn3 compiler warnings */
+ var GSUP_PDUs res; /* save various return values to prevent ttcn3 compiler warnings */
var charstring imsi_pattern := "*IMSI: " & hex2str(g_pars.sub.imsi) & "*";
/* Random MSISDN and CS+PS NAM (LU must pass) */
@@ -1613,7 +1691,7 @@ testcase TC_subscr_create_on_demand_check_imei_early() runs on test_CT {
/* Test create-subscriber-on-demand during LU (Location Update) */
private function f_TC_subscr_create_on_demand_ul() runs on HLR_ConnHdlr {
- var GSUP_PDU res;
+ var GSUP_PDUs res;
var charstring imsi_pattern := "*IMSI: " & hex2str(g_pars.sub.imsi) & "*";
/* Random MSISDN and CS+PS NAM (LU must pass) */
@@ -1680,13 +1758,14 @@ testcase TC_subscr_create_on_demand_ul() runs on test_CT {
/* Test create-subscriber-on-demand during SAI (SendAuthInfo) */
private function f_TC_subscr_create_on_demand_sai() runs on HLR_ConnHdlr {
- var GSUP_PDU res;
+ var GSUP_PDUs res;
+ var GSUP_PDU pdu;
var charstring imsi_pattern := "*IMSI: " & hex2str(g_pars.sub.imsi) & "*";
/* HLR creates the subscriber on demand. Then the IMSI is known, but there is no auth data, so the HLR returns
* the "slightly inaccurate cause 'IMSI Unknown' via GSUP". The MS is able to do a LU afterwards. */
f_vty_config(VTY, "hlr", "subscriber-create-on-demand 3 cs+ps");
- res := f_perform_SAI(g_pars.sub.imsi, 2 /* IMSI Unknown */ );
+ pdu := f_perform_SAI(g_pars.sub.imsi, 2 /* IMSI Unknown */ );
/* Verify that it was created before the LU */
f_vty_subscr_show(VTY, g_pars.sub, pattern imsi_pattern);
@@ -2000,6 +2079,7 @@ control {
execute( TC_gsup_sai_err_unknown_imsi() );
execute( TC_gsup_ul() );
execute( TC_gsup_ul_via_proxy() );
+ execute( TC_gsup_ul_subscriber_data() );
execute( TC_vty() );
execute( TC_vty_msisdn_isd() );
execute( TC_gsup_purge_cs() );
diff --git a/hlr/expected-results.xml b/hlr/expected-results.xml
index 391dcef8..2175a815 100644
--- a/hlr/expected-results.xml
+++ b/hlr/expected-results.xml
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
-<testsuite name='Titan' tests='36' failures='5' errors='0' skipped='0' inconc='0' time='MASKED'>
+<testsuite name='Titan' tests='37' failures='5' errors='0' skipped='0' inconc='0' time='MASKED'>
<testcase classname='HLR_Tests' name='TC_gsup_sai_err_invalid_imsi' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_sai' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_sai_num_auth_vectors' time='MASKED'/>
@@ -9,6 +9,7 @@
<testcase classname='HLR_Tests' name='TC_gsup_sai_err_unknown_imsi' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_ul' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_ul_via_proxy' time='MASKED'/>
+ <testcase classname='HLR_Tests' name='TC_gsup_ul_subscriber_data' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_vty' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_vty_msisdn_isd' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_purge_cs' time='MASKED'/>
diff --git a/library/GSUP_Types.ttcn b/library/GSUP_Types.ttcn
index 41181e8a..818f830c 100644
--- a/library/GSUP_Types.ttcn
+++ b/library/GSUP_Types.ttcn
@@ -216,6 +216,7 @@ type record GSUP_IE {
pdp_qos, tag = OSMO_GSUP_PDP_QOS_IE;
pdp_type, tag = OSMO_GSUP_PDP_TYPE_IE;
charg_char, tag = OSMO_GSUP_CHARG_CHAR_IE;
+ pdp_ctx_id, tag = OSMO_GSUP_PDP_CONTEXT_ID_IE;
session_state, tag = OSMO_GSUP_SESSION_STATE_IE;
session_id, tag = OSMO_GSUP_SESSION_ID_IE;
ss_info, tag = OSMO_GSUP_SS_INFO_IE;
@@ -272,6 +273,7 @@ type union GSUP_IeValue {
GSUP_CnDomain cn_domain,
/* PDP context + nested IEs */
GSUP_IEs pdp_info,
+ OCT1 pdp_ctx_id,
octetstring apn,
octetstring pdp_qos,
OCT2 pdp_type,
@@ -314,6 +316,8 @@ type record GSUP_PDU {
GSUP_IEs ies
};
+type record of GSUP_PDU GSUP_PDUs;
+
external function enc_GSUP_PDU(in GSUP_PDU msg) return octetstring
with { extension "prototype(convert) encode(RAW)" };
@@ -406,6 +410,23 @@ template GSUP_IE ts_GSUP_IE_PdpInfo(octetstring apn, octetstring pdp_type, octet
}
}
+template (value) GSUP_IE ts_GSUP_IE_PDP_CONTEXT_ID(OCT1 ctx_id) := {
+ tag := OSMO_GSUP_PDP_CONTEXT_ID_IE,
+ len := 0,
+ val := {
+ pdp_ctx_id := ctx_id
+ }
+}
+
+template GSUP_IE tr_GSUP_IE_PDP_CONTEXT_ID(template OCT1 ctx_id) := {
+ tag := OSMO_GSUP_PDP_CONTEXT_ID_IE,
+ len := ?,
+ val := {
+ pdp_ctx_id := ctx_id
+ }
+}
+
+
template (value) GSUP_IE ts_GSUP_IE_PDP_TYPE(OCT2 pdp_type) := {
tag := OSMO_GSUP_PDP_TYPE_IE,
len := 0,
@@ -764,6 +785,14 @@ template (value) GSUP_IE ts_GSUP_IE_APN(octetstring apn) := {
}
}
+template GSUP_IE tr_GSUP_IE_APN(template octetstring apn) := {
+ tag := OSMO_GSUP_ACCESS_POINT_NAME_IE,
+ len := ?,
+ val := {
+ apn := apn
+ }
+}
+
template GSUP_IE ts_GSUP_IE_CnDomain(template GSUP_CnDomain dom) := {
tag := OSMO_GSUP_CN_DOMAIN_IE,
len := 0, /* overwritten */
@@ -1689,6 +1718,21 @@ template GSUP_PDU tr_GSUP_MO_READY_FOR_SM_ERR(
}
);
+function f_gsup_find_nested_ie_multiple(GSUP_IEs ies, GSUP_IEI iei, integer nth, out GSUP_IeValue ret) return boolean {
+ var integer current := 0;
+ for (var integer i := 0; i < sizeof(ies); i := i+1) {
+ if (ies[i].tag == iei) {
+ if (current == nth) {
+ ret := ies[i].val;
+ return true;
+ } else {
+ current := current + 1;
+ }
+ }
+ }
+ return false;
+}
+
function f_gsup_find_nested_ie(GSUP_IEs ies, GSUP_IEI iei, out GSUP_IeValue ret) return boolean {
for (var integer i := 0; i < sizeof(ies); i := i+1) {
if (ies[i].tag == iei) {