blob: 88a82a4153190d6ad951ef2bd66438f004fb252c [file] [log] [blame]
Pau Espin Pedrolad4179b2023-10-10 19:12:26 +02001module HSS_Tests {
2
3import from General_Types all;
4import from Osmocom_Types all;
5import from Native_Functions all;
6import from Misc_Helpers all;
7
8import from DIAMETER_Types all;
9import from DIAMETER_Templates all;
10import from DIAMETER_Emulation all;
11
12type record of hexstring SubscriberConfigs;
13
14modulepar {
15 charstring mp_hss_hostname := "127.0.0.4";
16 integer mp_hss_port := 3868;
17 charstring mp_diam_local_hostname := "127.0.0.1";
18 integer mp_diam_local_port := 3868;
19 charstring mp_diam_orig_realm := "localdomain";
20 charstring mp_diam_orig_host := "mme.localdomain";
21 charstring mp_diam_dest_realm := "localdomain";
22 charstring mp_diam_dest_host := "hss.localdomain";
23 SubscriberConfigs subscribers := {
24 /* Existing subscriber, ULA returns SERVICE_GRANTED */
25 '001010000000000'H
26 };
27}
28
29/* main component, we typically have one per testcase */
30type component MTC_CT {
31
32 /* emulated MME/SGSN */
33 var DIAMETER_Emulation_CT vc_S6a;
34 port DIAMETER_PT S6a_UNIT;
35 port DIAMETEREM_PROC_PT S6a_PROC;
36 /* global test case guard timer (actual timeout value is set in f_init()) */
37 timer T_guard;
38}
39
40/* global altstep for global guard timer; */
41altstep as_Tguard() runs on MTC_CT {
42 [] T_guard.timeout {
43 setverdict(fail, "Timeout of T_guard");
44 mtc.stop;
45 }
46}
47
48type component DIAMETER_ConnHdlr_CT extends DIAMETER_ConnHdlr {
49 port DIAMETER_Conn_PT DIAMETER_CLIENT;
50 port DIAMETEREM_PROC_PT DIAMETER_PROC_CLIENT;
51}
52
53function f_diam_connhldr_ct_main(hexstring imsi) runs on DIAMETER_ConnHdlr_CT {
54 var DIAMETER_ConnHdlr vc_conn_unused;
55 var PDU_DIAMETER msg;
56 var UINT32 ete_id;
57
58 f_diameter_expect_imsi(imsi);
59
60 while (true) {
61 alt {
62 [] DIAMETER_CLIENT.receive(PDU_DIAMETER:?) -> value msg {
63 DIAMETER.send(msg);
64 }
65 [] DIAMETER.receive(PDU_DIAMETER:?) -> value msg {
66 DIAMETER_CLIENT.send(msg);
67 }
68 [] DIAMETER_PROC_CLIENT.getcall(DIAMETEREM_register_eteid:{?,?}) -> param(ete_id, vc_conn_unused) {
69 DIAMETER_PROC.call(DIAMETEREM_register_eteid:{ete_id, self}) {
70 [] DIAMETER_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
71 }
72 DIAMETER_PROC_CLIENT.reply(DIAMETEREM_register_eteid:{ete_id, vc_conn_unused});
73 }
74 }
75 }
76}
77
78/* per-session component; we typically have 1..N per testcase */
79type component Cli_Session_CT {
80 var SessionPars g_pars;
81
82 port DIAMETER_Conn_PT S6a;
83 port DIAMETEREM_PROC_PT S6a_PROC;
84}
85function f_diam_connhldr_expect_eteid(UINT32 ete_id) runs on Cli_Session_CT {
86 S6a_PROC.call(DIAMETEREM_register_eteid:{ete_id, null}) {
87 [] S6a_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
88 }
89}
90
91/* configuration data for a given Session */
92type record SessionPars {
93 hexstring imsi,
94 uint32_t s6a_next_hbh_id,
95 uint32_t s6a_next_ete_id
96}
97
98template (value) SessionPars
99t_SessionPars(hexstring imsi, uint32_t s6a_next_hbh_id := 1000, uint32_t s6a_next_ete_id := 22220) := {
100 imsi := imsi,
101 s6a_next_hbh_id := s6a_next_hbh_id,
102 s6a_next_ete_id := s6a_next_ete_id
103}
104
105type function void_fn() runs on Cli_Session_CT;
106
107friend function DiameterForwardUnitdataCallback(PDU_DIAMETER msg)
108runs on DIAMETER_Emulation_CT return template PDU_DIAMETER {
109 DIAMETER_UNIT.send(msg);
110 return omit;
111}
112
113friend function f_init_diameter(charstring id) runs on MTC_CT {
114 var DIAMETEROps ops := {
115 create_cb := refers(DIAMETER_Emulation.ExpectedCreateCallback),
116 unitdata_cb := refers(DiameterForwardUnitdataCallback),
117 raw := false /* handler mode (IMSI based routing) */
118 };
119 var DIAMETER_conn_parameters pars;
120
121 /* S6a setup: */
122 pars := {
123 remote_ip := mp_hss_hostname,
124 remote_sctp_port := mp_hss_port,
125 local_ip := mp_diam_local_hostname,
126 local_sctp_port := mp_diam_local_port,
127 origin_host := mp_diam_orig_host,
128 origin_realm := mp_diam_orig_realm,
129 auth_app_id := omit,
130 vendor_app_id := c_DIAMETER_3GPP_S6_AID
131 };
132 vc_S6a := DIAMETER_Emulation_CT.create(id);
133 map(vc_S6a:DIAMETER, system:DIAMETER_CODEC_PT);
134 connect(vc_S6a:DIAMETER_UNIT, self:S6a_UNIT);
135 connect(vc_S6a:DIAMETER_PROC, self:S6a_PROC);
136 vc_S6a.start(DIAMETER_Emulation.main(ops, pars, id));
137
138 f_diameter_wait_capability(S6a_UNIT);
139 /* Give some time for our emulation to get out of SUSPECT list of SUT (3 watchdong ping-pongs):
140 * RFC6733 sec 5.1
141 * RFC3539 sec 3.4.1 [5]
142 * https://github.com/freeDiameter/freeDiameter/blob/master/libfdcore/p_psm.c#L49
143 */
144 f_sleep(1.0);
145}
146
147private function f_init(float guard_timeout := 60.0) runs on MTC_CT {
148 T_guard.start(guard_timeout);
149 activate(as_Tguard());
150 f_init_diameter(testcasename());
151}
152
153function f_start_handler(void_fn fn, template (omit) SessionPars pars_tmpl := omit)
154runs on MTC_CT return Cli_Session_CT {
155 var charstring id := testcasename();
156 var DIAMETER_ConnHdlr_CT vc_conn_s6a;
157 var Cli_Session_CT vc_conn;
158 var SessionPars pars;
159
160 if (isvalue(pars_tmpl)) {
161 pars := valueof(pars_tmpl);
162 } else {
163 /*TODO: set default values */
164 }
165
166 vc_conn := Cli_Session_CT.create(id);
167
168 vc_conn_s6a := DIAMETER_ConnHdlr_CT.create(id);
169 connect(vc_conn_s6a:DIAMETER, vc_S6a:DIAMETER_CLIENT);
170 connect(vc_conn_s6a:DIAMETER_PROC, vc_S6a:DIAMETER_PROC);
171 connect(vc_conn:S6a, vc_conn_s6a:DIAMETER_CLIENT);
172 connect(vc_conn:S6a_PROC, vc_conn_s6a:DIAMETER_PROC_CLIENT);
173 vc_conn_s6a.start(f_diam_connhldr_ct_main(pars.imsi));
174
175 vc_conn.start(f_handler_init(fn, pars));
176 return vc_conn;
177}
178
179private function f_handler_init(void_fn fn, SessionPars pars)
180runs on Cli_Session_CT {
181 g_pars := valueof(pars);
182 fn.apply();
183}
184
185/* ULR + ULA against HSS */
186private function f_dia_ulr_ula() runs on Cli_Session_CT {
187 var octetstring sess_id := char2oct("foobar");
188 var template (present) AVP_list sub_data;
189 var PDU_DIAMETER rx_dia;
190 var UINT32 hbh_id := int2oct(g_pars.s6a_next_hbh_id, 4);
191 var UINT32 ete_id := int2oct(g_pars.s6a_next_ete_id, 4);
192
193 /* Unlike ULR, ULA contains no IMSI. Register ete_id in DIAMETER_Emulation,
194 * so AIA is forwarded back to us in DIAMETER port instead of MTC_CT.DIAMETER_UNIT.
195 */
196 f_diam_connhldr_expect_eteid(ete_id);
197
198 /* TODO: change this into a ts_DIA_ULR */
199 S6a.send(ts_DIA_ULR(g_pars.imsi, '111F11'O, sess_id,
200 mp_diam_orig_host, mp_diam_orig_realm,
201 mp_diam_dest_realm, hbh_id, ete_id));
202 g_pars.s6a_next_hbh_id := g_pars.s6a_next_hbh_id + 1;
203 g_pars.s6a_next_ete_id := g_pars.s6a_next_ete_id + 1;
204
205 sub_data := superset(
206 tr_AVP_3GPP_SubscriberStatus(SERVICE_GRANTED),
207 tr_AVP_3GPP_SubscrRauTauTmr(?),
208 tr_AVP_3GPP_AMBR(?, ?),
209 tr_AVP_3GPP_ApnConfigProfile(superset(
210 tr_AVP_3GPP_ContextId(?),
211 tr_AVP_3GPP_AllApnConfigsIncl,
212 tr_AVP_3GPP_ApnConfig(?, ?, ?)
213 ))
214 );
215
216 alt {
217 [] S6a.receive(tr_DIA_ULA(sub_data, sess_id, ?, ?, hbh_id, ete_id)) -> value rx_dia {
218 setverdict(pass);
219 }
220 [] S6a.receive(PDU_DIAMETER:?) -> value rx_dia {
221 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
222 log2str("Received unexpected DIAMETER ", rx_dia));
223 }
224 }
225}
226
227/* create a session, expect it to succeed */
228private function f_TC_ulr_ula() runs on Cli_Session_CT {
229 f_dia_ulr_ula();
230 setverdict(pass);
231}
232testcase TC_ulr_ula() runs on MTC_CT {
233 var Cli_Session_CT vc_conn;
234 var SessionPars pars := valueof(t_SessionPars(subscribers[0]));
235 f_init();
236 vc_conn := f_start_handler(refers(f_TC_ulr_ula), pars);
237 vc_conn.done;
238}
239
240
241control {
242 execute( TC_ulr_ula() );
243}
244
245
246}