blob: 45d7a1d53fd7d1afae6f268f667433074d8d9b95 [file] [log] [blame]
Pau Espin Pedrol965ac642023-10-16 18:12:45 +02001module EPDG_Tests {
2
3import from Misc_Helpers all;
4import from General_Types all;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +02005import from Native_Functions all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +02006import from Osmocom_Types all;
7import from L3_Common all;
Pau Espin Pedrolc2cfd552024-02-07 17:51:55 +01008import from DNS_Helpers all;
Pau Espin Pedrolbf03d772024-03-01 16:15:21 +01009import from IP_Types all;
10import from ICMP_Types all;
11import from ICMP_Templates all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020012
13import from IPA_Emulation all;
Pau Espin Pedrolce1d3cb2024-02-21 17:40:59 +010014import from PCO_Types all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020015import from GSUP_Types all;
Pau Espin Pedrol8f1403a2024-01-18 20:08:43 +010016import from GSUP_Templates all;
17import from GSUP_Emulation all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020018
19import from DIAMETER_Types all;
20import from DIAMETER_Templates all;
Pau Espin Pedrol009ab6f2024-03-05 13:25:19 +010021import from DIAMETER_rfc4004_Templates all;
Pau Espin Pedrol6601f222024-03-05 18:51:09 +010022import from DIAMETER_ts29_272_Templates all;
Pau Espin Pedrol4669b612023-10-23 17:43:14 +020023import from DIAMETER_ts29_273_Templates all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020024import from DIAMETER_Emulation all;
25
Pau Espin Pedrol65a7f762024-02-29 21:07:58 +010026import from GTPv1U_CodecPort all;
27import from GTPU_Types all;
28import from GTPv1U_Templates all;
29
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +020030import from GTPv2_Types all;
31import from GTPv2_Templates all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020032import from GTPv2_Emulation all;
33
34modulepar {
35 /* our emulated GSUP strongswan (CEAI iface) */
36 charstring mp_gsup_local_ip := "127.0.0.100";
37 integer mp_gsup_local_port := 0;
38 charstring mp_gsup_remote_ip := "127.0.0.1";
39 integer mp_gsup_remote_port := 4222;
40
41 /* our emulated HSS */
42 charstring mp_swx_local_ip := "127.0.0.100";
43 integer mp_swx_local_port := 3868;
44
45 /* our emulated PGW (Diameter S6b) */
46 charstring mp_s6b_local_ip := "127.0.0.100";
47 integer mp_s6b_local_port := 3869;
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +020048 charstring mp_s6b_remote_ip := "127.0.0.1";
49 integer mp_s6b_remote_port := 3869;
Pau Espin Pedrol8586b262024-02-09 18:12:21 +010050 /* 3GPP TS 23.003 clause 19: "nai.epc.mnc<MNC>.mcc<MCC>.3gppnetwork.org" */
51 charstring mp_s6b_nai_realm := "nai.epc.mnc001.mcc01.3gppnetwork.org";
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020052
53 /* our emulated PGW (GTPv2C S2b) */
54 charstring mp_s2b_local_ip := "127.0.0.100";
55 integer mp_s2b_local_port := GTP2C_PORT;
56 charstring mp_s2b_remote_ip := "127.0.0.1";
57 integer mp_s2b_remote_port := GTP2C_PORT;
Pau Espin Pedrolf2925862024-02-22 20:12:30 +010058 charstring mp_s2b_dns_ipv4 := "1.2.3.4";
59 charstring mp_s2b_dns_ipv6 := "::1";
60 charstring mp_s2b_pcscf_ipv4 := "5.6.7.8";
61 charstring mp_s2b_pcscf_ipv6 := "::2";
Pau Espin Pedrol65a7f762024-02-29 21:07:58 +010062 /* our emulated PGW /* GTP1U */
63 charstring mp_upf_gtpu_local_ip := "127.0.0.100";
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020064
65 charstring mp_diam_realm := "localdomain";
Pau Espin Pedrolc13a4cd2024-01-16 17:28:25 +010066 integer mp_diam_watchdog_initial_wait_sec := 6*3;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020067}
68
Pau Espin Pedrol285a2b62024-02-27 18:25:45 +010069type port Coord_PT message
70{
71 inout charstring;
72} with { extension "internal" };
73private const charstring COORD_CMD_READY := "COORD_CMD_READY";
74private const charstring COORD_CMD_START := "COORD_CMD_START";
75private const charstring COORD_CMD_ATTACHED := "COORD_CMD_ATTACHED";
76private const charstring COORD_CMD_STOP := "COORD_CMD_STOP";
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020077
78type component MTC_CT {
79 var DIAMETER_Emulation_CT vc_SWx;
80 port DIAMETER_PT SWx_UNIT;
81 port DIAMETEREM_PROC_PT SWx_PROC;
82
83 var DIAMETER_Emulation_CT vc_S6b;
84 port DIAMETER_PT S6b_UNIT;
85 port DIAMETEREM_PROC_PT S6b_PROC;
86
87 var GSUP_Emulation_CT vc_GSUP;
88 var IPA_Emulation_CT vc_GSUP_IPA;
89 port IPA_CTRL_PT GSUP_IPA_EVENT;
90
91 var GTPv2_Emulation_CT vc_GTP2;
92 port GTP2EM_PT TEID0;
93
Pau Espin Pedrol285a2b62024-02-27 18:25:45 +010094 port Coord_PT COORD;
95
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020096 timer g_Tguard;
97};
98
99private altstep as_Tguard() runs on MTC_CT {
100 [] g_Tguard.timeout {
101 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
102 }
103}
104
105type component DIAMETER_ConnHdlr_CT extends DIAMETER_ConnHdlr {
106 port DIAMETER_Conn_PT DIAMETER_CLIENT;
107 port DIAMETEREM_PROC_PT DIAMETER_PROC_CLIENT;
108}
109
110function f_diam_connhldr_ct_main(hexstring imsi) runs on DIAMETER_ConnHdlr_CT {
111 var DIAMETER_ConnHdlr vc_conn_unused;
112 var PDU_DIAMETER msg;
113 var UINT32 ete_id;
114
115 f_diameter_expect_imsi(imsi);
116
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200117 while (true) {
118 alt {
119 [] DIAMETER_CLIENT.receive(PDU_DIAMETER:?) -> value msg {
120 DIAMETER.send(msg);
121 }
122 [] DIAMETER.receive(PDU_DIAMETER:?) -> value msg {
123 DIAMETER_CLIENT.send(msg);
124 }
125 [] DIAMETER_PROC_CLIENT.getcall(DIAMETEREM_register_eteid:{?,?}) -> param(ete_id, vc_conn_unused) {
126 DIAMETER_PROC.call(DIAMETEREM_register_eteid:{ete_id, self}) {
127 [] DIAMETER_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
128 }
129 DIAMETER_PROC_CLIENT.reply(DIAMETEREM_register_eteid:{ete_id, vc_conn_unused});
130 }
131 }
132 }
133}
134
135type component EPDG_ConnHdlr extends DIAMETER_ConnHdlr, GSUP_ConnHdlr, GTP2_ConnHdlr {
136 var EPDG_ConnHdlrPars g_pars;
137
138 port DIAMETER_Conn_PT SWx;
139 port DIAMETEREM_PROC_PT SWx_PROC;
140 port DIAMETER_Conn_PT S6b;
141 port DIAMETEREM_PROC_PT S6b_PROC;
Pau Espin Pedrol285a2b62024-02-27 18:25:45 +0100142 port Coord_PT COORD;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200143};
Pau Espin Pedrol285a2b62024-02-27 18:25:45 +0100144type record of EPDG_ConnHdlr EPDG_ConnHdlrList;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200145
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200146type record BearerConfig {
147 /* EPS Bearer ID */
148 uint4_t ebi optional,
149 /* TEI (Data) local side */
150 OCT4 teid_local optional,
151 /* TEI (Data) remote side */
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +0100152 OCT4 teid_remote optional,
153 /* GTP-U address of the peer (ePDG) */
154 charstring gtpu_addr_remote optional
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200155};
156
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200157type record EPDG_ConnHdlrPars {
158 hexstring imsi,
Pau Espin Pedrol2c2e1872023-10-23 18:31:03 +0200159 charstring apn,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200160 charstring ue_ip,
161
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200162 /* TEI (Control) local side */
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200163 OCT4 teic_local,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200164 /* TEI (Control) remote side */
165 OCT4 teic_remote optional,
166
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200167 BearerConfig bearer optional,
168
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200169 AuthVector vec optional
170};
171
172private function f_epdg_connhldr_SWx_expect_eteid(UINT32 ete_id) runs on EPDG_ConnHdlr {
173 SWx_PROC.call(DIAMETEREM_register_eteid:{ete_id, null}) {
174 [] SWx_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
175 }
176}
177private function f_epdg_connhldr_S6b_expect_eteid(UINT32 ete_id) runs on EPDG_ConnHdlr {
178 S6b_PROC.call(DIAMETEREM_register_eteid:{ete_id, null}) {
179 [] S6b_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
180 }
181}
182
Pau Espin Pedrol285a2b62024-02-27 18:25:45 +0100183private function f_gen_addr_in_pool(integer idx := 0) return charstring
184{
185 /* Skip first 2 addresses reserved for TUN */
186 var integer internal_idx := idx + 2;
187 var integer suffix := internal_idx rem (256*256);
188 var integer C := suffix / 256;
189 var integer D := suffix rem 256;
190 return "192.168." & int2str(C) & "." & int2str(D);
191}
192
193private function f_init_pars(integer idx := 0)
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200194runs on MTC_CT return EPDG_ConnHdlrPars {
195 var EPDG_ConnHdlrPars pars := {
Pau Espin Pedrol285a2b62024-02-27 18:25:45 +0100196 imsi := f_rnd_imsi('26242'H),
Pau Espin Pedrol2c2e1872023-10-23 18:31:03 +0200197 apn := "internet",
Pau Espin Pedrol285a2b62024-02-27 18:25:45 +0100198 ue_ip := f_gen_addr_in_pool(idx),
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200199 teic_local := '00000000'O,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200200 teic_remote := omit,
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200201 bearer := {
202 ebi := omit,
203 teid_local := omit,
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +0100204 teid_remote := omit,
205 gtpu_addr_remote := omit
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200206 },
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200207 vec := f_gen_auth_vec_3g()
208 };
209 return pars;
210}
211
212private function f_init_gsup(charstring id) runs on MTC_CT {
213 id := id & "-GSUP";
214 var GsupOps ops := {
215 create_cb := refers(GSUP_Emulation.ExpectedCreateCallback)
216 };
217
218 vc_GSUP_IPA := IPA_Emulation_CT.create(id & "-IPA");
219 vc_GSUP := GSUP_Emulation_CT.create(id);
220
221 map(vc_GSUP_IPA:IPA_PORT, system:IPA_CODEC_PT);
222 connect(vc_GSUP:GSUP, vc_GSUP_IPA:IPA_GSUP_PORT);
223 /* we use this hack to get events like ASP_IPA_EVENT_UP */
224 connect(vc_GSUP_IPA:IPA_CTRL_PORT, self:GSUP_IPA_EVENT);
225
226 vc_GSUP.start(GSUP_Emulation.main(ops, id));
227 vc_GSUP_IPA.start(IPA_Emulation.main_client(mp_gsup_remote_ip, mp_gsup_remote_port,
228 mp_gsup_local_ip, mp_gsup_local_port));
229
230 /* wait for incoming connection to GSUP port before proceeding */
231 timer T := 10.0;
232 T.start;
233 alt {
234 [] GSUP_IPA_EVENT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) { }
235 [] T.timeout {
236 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "No connection to GSUP Port");
237 }
238 }
239}
240
241private function DiameterForwardUnitdataCallback(PDU_DIAMETER msg)
242runs on DIAMETER_Emulation_CT return template PDU_DIAMETER {
243 DIAMETER_UNIT.send(msg);
244 return omit;
245}
246
247private function f_init_diameter(charstring id) runs on MTC_CT {
248 var DIAMETEROps ops := {
249 create_cb := refers(DIAMETER_Emulation.ExpectedCreateCallback),
250 unitdata_cb := refers(DiameterForwardUnitdataCallback),
251 raw := false /* handler mode (IMSI based routing) */
252 };
253 var DIAMETER_conn_parameters pars;
254
255 /* SWx setup: */
256 pars := {
257 remote_ip := "",
258 remote_sctp_port := -1, /* server mode */
259 local_ip := mp_swx_local_ip,
260 local_sctp_port := mp_swx_local_port,
261 origin_host := "hss." & mp_diam_realm,
262 origin_realm := mp_diam_realm,
263 auth_app_id := omit,
264 vendor_app_id := c_DIAMETER_3GPP_SWx_AID
265 };
266 vc_SWx := DIAMETER_Emulation_CT.create(id);
267 map(vc_SWx:DIAMETER, system:DIAMETER_CODEC_PT);
268 connect(vc_SWx:DIAMETER_UNIT, self:SWx_UNIT);
269 connect(vc_SWx:DIAMETER_PROC, self:SWx_PROC);
270 vc_SWx.start(DIAMETER_Emulation.main(ops, pars, id));
271
272 /* S6b setup: */
273 pars := {
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200274 remote_ip := mp_s6b_remote_ip,
275 remote_sctp_port := mp_s6b_remote_port, /* client mode */
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200276 local_ip := mp_s6b_local_ip,
277 local_sctp_port := mp_s6b_local_port,
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200278 origin_host := "pgw." & mp_diam_realm,
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200279 origin_realm := mp_diam_realm,
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200280 auth_app_id := c_DIAMETER_3GPP_S6b_AID,
281 vendor_app_id := c_DIAMETER_3GPP_S6b_AID
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200282 };
283 vc_S6b := DIAMETER_Emulation_CT.create(id);
284 map(vc_S6b:DIAMETER, system:DIAMETER_CODEC_PT);
285 connect(vc_S6b:DIAMETER_UNIT, self:S6b_UNIT);
286 connect(vc_S6b:DIAMETER_PROC, self:S6b_PROC);
287 vc_S6b.start(DIAMETER_Emulation.main(ops, pars, id));
288
289 f_diameter_wait_capability(SWx_UNIT);
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200290 f_diameter_wait_capability(S6b_UNIT);
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200291
292 /* Give some time for our emulation to get out of SUSPECT list of SUT (3 watchdog ping-pongs):
293 * RFC6733 sec 5.1
294 * RFC3539 sec 3.4.1 [5]
295 * https://github.com/freeDiameter/freeDiameter/blob/master/libfdcore/p_psm.c#L49
296 */
Pau Espin Pedrolc13a4cd2024-01-16 17:28:25 +0100297 f_sleep(int2float(mp_diam_watchdog_initial_wait_sec));
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200298}
299
300private function f_init_gtp(charstring id) runs on MTC_CT {
301 var Gtp2EmulationCfg cfg := {
302 gtpc_bind_ip := mp_s2b_local_ip,
303 gtpc_bind_port := mp_s2b_local_port,
304 gtpc_remote_ip := mp_s2b_remote_ip,
305 gtpc_remote_port := mp_s2b_remote_port,
Pau Espin Pedrol65a7f762024-02-29 21:07:58 +0100306 gtpu_bind_ip := mp_upf_gtpu_local_ip,
307 gtpu_bind_port := GTP1U_PORT,
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200308 sgw_role := false,
309 use_gtpu_daemon := false /* TODO: maybe use, set to true */
310 };
311
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200312 vc_GTP2 := GTPv2_Emulation_CT.create(id & "-GTPV2");
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200313 map(vc_GTP2:GTP2C, system:GTP2C);
314 connect(vc_GTP2:TEID0, self:TEID0);
315 vc_GTP2.start(GTPv2_Emulation.main(cfg));
316}
317
318private function f_init(float t_guard := 40.0) runs on MTC_CT {
319
320 g_Tguard.start(t_guard);
321 activate(as_Tguard());
322
323 f_init_gsup(testcasename());
324 f_init_diameter(testcasename());
325 f_init_gtp(testcasename());
326}
327
328private type function void_fn(charstring id) runs on EPDG_ConnHdlr;
329
330private function f_init_handler(void_fn fn, charstring id, EPDG_ConnHdlrPars pars) runs on EPDG_ConnHdlr {
331 g_pars := pars;
332
333 /* tell GSUP dispatcher to send this IMSI to us */
334 f_create_gsup_expect(hex2str(g_pars.imsi));
335
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200336 /* tell GTPv2 dispatcher to send this IMSI to us */
337 f_gtp2_register_imsi(g_pars.imsi);
338
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200339 fn.apply(id);
340}
341
342private function f_start_handler(void_fn fn, EPDG_ConnHdlrPars pars)
343runs on MTC_CT return EPDG_ConnHdlr {
344 var EPDG_ConnHdlr vc_conn;
345 var charstring id := testcasename();
346 var DIAMETER_ConnHdlr_CT vc_conn_swx, vc_conn_s6b;
347
348 vc_conn := EPDG_ConnHdlr.create(id);
349
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200350 /* GSUP */
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200351 connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT);
352 connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC);
353
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200354 /* GTP2 */
355 connect(vc_conn:GTP2, vc_GTP2:CLIENT);
356 connect(vc_conn:GTP2_PROC, vc_GTP2:CLIENT_PROC);
357
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200358 /* SWx */
359 vc_conn_swx := DIAMETER_ConnHdlr_CT.create(id);
360 connect(vc_conn_swx:DIAMETER, vc_SWx:DIAMETER_CLIENT);
361 connect(vc_conn_swx:DIAMETER_PROC, vc_SWx:DIAMETER_PROC);
362 connect(vc_conn:SWx, vc_conn_swx:DIAMETER_CLIENT);
363 connect(vc_conn:SWx_PROC, vc_conn_swx:DIAMETER_PROC_CLIENT);
364 vc_conn_swx.start(f_diam_connhldr_ct_main(pars.imsi));
365
366 /* S6b */
367 vc_conn_s6b := DIAMETER_ConnHdlr_CT.create(id);
368 connect(vc_conn_s6b:DIAMETER, vc_S6b:DIAMETER_CLIENT);
369 connect(vc_conn_s6b:DIAMETER_PROC, vc_S6b:DIAMETER_PROC);
370 connect(vc_conn:S6b, vc_conn_s6b:DIAMETER_CLIENT);
371 connect(vc_conn:S6b_PROC, vc_conn_s6b:DIAMETER_PROC_CLIENT);
372 vc_conn_s6b.start(f_diam_connhldr_ct_main(pars.imsi));
373
Pau Espin Pedrol285a2b62024-02-27 18:25:45 +0100374 /* COORD */
375 connect(vc_conn:COORD, self:COORD);
376
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200377 vc_conn.start(f_init_handler(fn, id, pars));
378 return vc_conn;
379}
380
Pau Espin Pedrol8586b262024-02-09 18:12:21 +0100381private function f_nai() runs on EPDG_ConnHdlr return charstring {
382 return hex2str(g_pars.imsi) & "@" & mp_s6b_nai_realm;
383}
384
Pau Espin Pedrol6601f222024-03-05 18:51:09 +0100385private function f_DIA_SWx_tx_MAA_success(PDU_DIAMETER rx_mar) runs on EPDG_ConnHdlr {
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200386 var template (omit) AVP avp;
387 var octetstring sess_id;
388 var template (value) GenericAVP sip_auth_data_item;
Pau Espin Pedrol6601f222024-03-05 18:51:09 +0100389
390 avp := f_DIAMETER_get_avp(rx_mar, c_AVP_Code_BASE_NONE_Session_Id);
391 sess_id := valueof(avp.avp_data.avp_BASE_NONE_Session_Id);
392 sip_auth_data_item := ts_AVP_3GPP_SIPAuthDataItem(0,
393 g_pars.vec.rand,
394 g_pars.vec.ik,
395 g_pars.vec.ck,
396 g_pars.vec.autn,
397 g_pars.vec.auts);
398 /* Send MAA to translator; expect it to show up on GSUP side */
399 SWx.send(ts_DIA_SWx_MAA(g_pars.imsi, sip_auth_data_item,
400 sess_id := sess_id,
401 hbh_id := rx_mar.hop_by_hop_id,
402 ete_id := rx_mar.end_to_end_id));
403}
404
405private function f_DIA_SWx_tx_MAA_error(PDU_DIAMETER rx_mar, template (value) GenericAVP result) runs on EPDG_ConnHdlr {
406 var template (omit) AVP avp;
407 var octetstring sess_id;
408 var template (value) GenericAVP sip_auth_data_item;
409
410 avp := f_DIAMETER_get_avp(rx_mar, c_AVP_Code_BASE_NONE_Session_Id);
411 sess_id := valueof(avp.avp_data.avp_BASE_NONE_Session_Id);
412 sip_auth_data_item := ts_AVP_3GPP_SIPAuthDataItem(0,
413 g_pars.vec.rand,
414 g_pars.vec.ik,
415 g_pars.vec.ck,
416 g_pars.vec.autn,
417 g_pars.vec.auts);
418 SWx.send(ts_DIA_SWx_MAA_result(g_pars.imsi, result,
419 sess_id := sess_id,
420 hbh_id := rx_mar.hop_by_hop_id,
421 ete_id := rx_mar.end_to_end_id));
422}
423
424/* Diameter SWx MAR + MAA. */
425private altstep as_DIA_SWx_MA_success() runs on EPDG_ConnHdlr {
426 var PDU_DIAMETER rx_dia;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200427 [] SWx.receive(tr_DIA_SWx_MAR(g_pars.imsi)) -> value rx_dia {
Pau Espin Pedrol6601f222024-03-05 18:51:09 +0100428 f_DIA_SWx_tx_MAA_success(rx_dia);
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200429 setverdict(pass);
430 }
431 [] SWx.receive(PDU_DIAMETER:?) -> value rx_dia {
432 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter msg rx: ", rx_dia));
433 }
434}
435
436/* Diameter SWx SAR + SAA. */
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100437private altstep as_DIA_SWx_SA_success(template (present) CxDx_3GPP_Server_Assignment_Type server_ass_type := ?) runs on EPDG_ConnHdlr {
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200438 var PDU_DIAMETER rx_dia;
439 var template (omit) AVP avp;
440 var octetstring sess_id;
441 [] SWx.receive(tr_DIA_SWx_SAR(g_pars.imsi)) -> value rx_dia {
442 avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_BASE_NONE_Session_Id);
443 sess_id := valueof(avp.avp_data.avp_BASE_NONE_Session_Id);
444 /* Send SAA to translator; expect it to show up on GSUP side */
445 SWx.send(ts_DIA_SWx_SAA(g_pars.imsi,
Pau Espin Pedrol9b2ebc02024-03-05 13:25:19 +0100446 IPv4,
447 g_pars.apn,
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200448 sess_id := sess_id,
449 hbh_id := rx_dia.hop_by_hop_id,
450 ete_id := rx_dia.end_to_end_id));
451 setverdict(pass);
452 }
453 [] SWx.receive(PDU_DIAMETER:?) -> value rx_dia {
454 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter msg rx: ", rx_dia));
455 }
456}
457
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200458/* Send AAR as PGW to AAA server, expect back AAA */
459private function f_S6b_AA_success() runs on EPDG_ConnHdlr {
460 var PDU_DIAMETER rx_dia;
461 var UINT32 hbh_id := f_rnd_octstring(4);
462 var UINT32 ete_id := f_rnd_octstring(4);
Pau Espin Pedrol009ab6f2024-03-05 13:25:19 +0100463 var template (value) MIPv4_NONE_MIP_Home_Agent_Address pgw_addr;
464
465 pgw_addr := ts_AVP_Home_Agent_Address(IP, f_inet_addr(mp_s2b_local_ip));
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200466
467 /* Unlike AAR, AAA contains no IMSI. Register ete_id in DIAMETER_Emulation,
468 * so AIA is forwarded back to us in DIAMETER port instead of MTC_CT.DIAMETER_UNIT.
469 */
470 f_epdg_connhldr_S6b_expect_eteid(ete_id);
471
Pau Espin Pedrol8586b262024-02-09 18:12:21 +0100472 S6b.send(ts_DIA_S6b_AAR(f_nai(),
Pau Espin Pedrol2c2e1872023-10-23 18:31:03 +0200473 int2oct(DIA_TS29_373_MIP6_Feature_Vector_GTPv2_SUPPORTED, 8),
Pau Espin Pedrol009ab6f2024-03-05 13:25:19 +0100474 g_pars.apn,
475 pgw_addr,
476 hbh_id := hbh_id, ete_id := ete_id));
Pau Espin Pedrolc119ba02024-01-29 11:55:39 +0100477
478 /* AAR in S6b in AAA-Server triggers Service-Assignment Request/Answer towards HSS: */
479 as_DIA_SWx_SA_success();
480
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200481 alt {
482 [] S6b.receive(tr_DIA_S6b_AAA) -> value rx_dia {}
483 [] S6b.receive(PDU_DIAMETER:?) -> value rx_dia {
484 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter S6b msg rx: ", rx_dia));
485 }
486 }
487}
488
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100489/* Send STR as PGW to AAA server, expect back STA */
490private function f_S6b_ST_success() runs on EPDG_ConnHdlr {
491 var PDU_DIAMETER rx_dia;
492 var UINT32 hbh_id := f_rnd_octstring(4);
493 var UINT32 ete_id := f_rnd_octstring(4);
494
495 /* Unlike STR, STA contains no IMSI. Register ete_id in DIAMETER_Emulation,
496 * so AIA is forwarded back to us in DIAMETER port instead of MTC_CT.DIAMETER_UNIT.
497 */
498 f_epdg_connhldr_S6b_expect_eteid(ete_id);
499
500 S6b.send(ts_DIA_S6b_STR(g_pars.imsi, DIAMETER_LOGOUT,
501 hbh_id := hbh_id, ete_id := ete_id));
502 alt {
503 [] S6b.receive(tr_DIA_S6b_STA(DIAMETER_SUCCESS)) -> value rx_dia {}
504 [] S6b.receive(PDU_DIAMETER:?) -> value rx_dia {
505 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter S6b msg rx: ", rx_dia));
506 }
507 }
508}
509
Pau Espin Pedrolf2925862024-02-22 20:12:30 +0100510private function f_exp_tr_GTP2C_APCO_in_CreateSessionReq()
511 runs on EPDG_ConnHdlr return template (present) APCO {
512 var template ProtocolIDs_and_ContainerIDs protos, protosV4, protosV6, protosV46;
513 protosV4 := {tr_GTP2C_PCO_P_DNS_IPv4(''O), tr_GTP2C_PCO_P_PCSCF_IPv4(''O)};
514 protosV6 := {tr_GTP2C_PCO_P_DNS_IPv6(''O), tr_GTP2C_PCO_P_PCSCF_IPv6(''O)};
515 protosV46 := {tr_GTP2C_PCO_P_DNS_IPv4(''O), tr_GTP2C_PCO_P_PCSCF_IPv4(''O),
516 tr_GTP2C_PCO_P_DNS_IPv6(''O), tr_GTP2C_PCO_P_PCSCF_IPv6(''O)}
517 /* TODO: pick proto based on req_type v4, v6 or v4v6 */
518 protos := protosV4;
519 return tr_GTP2C_APCO('0000'B, protos);
520}
521
522private function f_GTPv2C_gen_APCO_response(APCO apco_req) runs on EPDG_ConnHdlr return template (value) APCO {
523 var ProtocolIDs_and_ContainerIDs proto_list_resp := {};
524
525 for (var integer i := 0; i < lengthof(apco_req.protocolIDs_and_ContainerIDs); i := i + 1) {
526 var ProtocolID_or_ContainerID proto_req := apco_req.protocolIDs_and_ContainerIDs[i];
527 select (proto_req.protocolID_or_ContainerID) {
528 case (PCO_P_to_OCT2(PCO_P_DNS_IPv4_ADDR)) {
529 proto_list_resp := proto_list_resp & { valueof(ts_GTP2C_PCO_P_DNS_IPv4(f_inet_addr(mp_s2b_dns_ipv4))) };
530 }
531 case (PCO_P_to_OCT2(PCO_P_DNS_IPv6_ADDR)) {
532 proto_list_resp := proto_list_resp & { valueof(ts_GTP2C_PCO_P_DNS_IPv6(f_inet_addr(mp_s2b_dns_ipv6))) };
533 }
534 case (PCO_P_to_OCT2(PCO_P_PCSCF_IPv4_ADDR)) {
535 proto_list_resp := proto_list_resp & { valueof(ts_GTP2C_PCO_P_PCSCF_IPv4(f_inet_addr(mp_s2b_pcscf_ipv4))) };
536 }
537 case (PCO_P_to_OCT2(PCO_P_PCSCF_ADDR)) {
538 proto_list_resp := proto_list_resp & { valueof(ts_GTP2C_PCO_P_PCSCF_IPv6(f_inet_addr(mp_s2b_pcscf_ipv6))) };
539 }
540 case else {
541 log("Ignoring unknown PCO Protocol ID: ", proto_req);
542 }
543 }
544 }
545
546 return ts_GTP2C_APCO(apco_req.instance, proto_list_resp);
547}
548
Pau Espin Pedrol7b2cc922024-02-28 16:14:15 +0100549private function f_EPDG_ConnHdlr_parse_CreateSessionReq(PDU_GTPCv2 rx_msg) runs on EPDG_ConnHdlr {
550 var BearerContextIEs rx_bctx_ies;
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +0100551 var FullyQualifiedTEID rx_fteid_gtpu;
Pau Espin Pedrol7b2cc922024-02-28 16:14:15 +0100552
553 /* Parse TEIC and Bearer EBI and TEID and store it in g_pars */
554 g_pars.teic_remote := rx_msg.gtpcv2_pdu.createSessionRequest.fullyQualifiedTEID[0].tEID_GRE_Key;
555 rx_bctx_ies := rx_msg.gtpcv2_pdu.createSessionRequest.bearerContextGrouped[0].bearerContextIEs;
556 g_pars.bearer.ebi := rx_bctx_ies.ePS_Bearer_ID.ePS_Bearer_ID_Value;
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +0100557
558 rx_fteid_gtpu := rx_bctx_ies.fullyQualifiedTEID[0];
559 g_pars.bearer.teid_remote := rx_fteid_gtpu.tEID_GRE_Key;
560 if (rx_fteid_gtpu.v4_Flag == '1'B) {
561 g_pars.bearer.gtpu_addr_remote := f_inet_ntoa(rx_fteid_gtpu.iPv4_Address);
562 }
563 /*if (rx_fteid_gtpu.v6_Flag == '1'B) {
564 g_gtpu6_remote := rx_fteid_gtpu.iPv6_Address;
565 }*/
Pau Espin Pedrol7b2cc922024-02-28 16:14:15 +0100566
567 /* allocate + register TEID-C on local side */
568 g_pars.teic_local := f_gtp2_allocate_teid();
569 g_pars.bearer.teid_local := g_pars.teic_local;
570}
571
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100572/* ePDG Creates session at the PGW. PGW sends Diameter s6b AAR + AAA. */
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200573private altstep as_GTP2C_CreateSession_success() runs on EPDG_ConnHdlr {
574 var PDU_GTPCv2 rx_msg;
575 var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
576 var template (value) PDN_AddressAllocation paa;
Pau Espin Pedrol8c746492023-10-23 20:56:09 +0200577 var template (value) BearerContextIEs bctx_ies;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200578
Pau Espin Pedrolf2925862024-02-22 20:12:30 +0100579 [] GTP2.receive(tr_GTP2C_CreateSessionReq(g_pars.imsi, apco := f_exp_tr_GTP2C_APCO_in_CreateSessionReq())) -> value rx_msg {
Pau Espin Pedrol7b2cc922024-02-28 16:14:15 +0100580 f_EPDG_ConnHdlr_parse_CreateSessionReq(rx_msg);
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200581
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200582 /* Upon rx of CreateSession, emulate PGW asking the AAA server. */
583 f_S6b_AA_success();
584
Pau Espin Pedrol24b08592024-02-09 18:48:53 +0100585 fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S2b_PGW_GTPC, g_pars.teic_local, 1,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200586 f_inet_addr(mp_s2b_local_ip), omit);
Pau Espin Pedrol24b08592024-02-09 18:48:53 +0100587 fteid_u_ie := ts_GTP2C_FTEID(FTEID_IF_S2bU_PGW_GTPU, g_pars.bearer.teid_local, 4,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200588 f_inet_addr(mp_s2b_local_ip), omit);
589 paa := ts_GTP2C_PdnAddrAlloc_v4(f_inet_addr(g_pars.ue_ip));
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200590 bctx_ies := ts_GTP2C_BcContextIE(ebi := g_pars.bearer.ebi,
Pau Espin Pedrol8c746492023-10-23 20:56:09 +0200591 teid_list := { fteid_u_ie },
592 qos := ts_GTP2C_BearerQos('09'O, 0,0,0,0),
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200593 charging_id := ts_GTP2C_ChargingID(g_pars.teic_local));
Pau Espin Pedrolfa2b3842023-12-13 18:49:19 +0100594 GTP2.send(ts_GTP2C_CreateSessionResp(g_pars.teic_remote, rx_msg.sequenceNumber,
Pau Espin Pedrol7b2cc922024-02-28 16:14:15 +0100595 Request_accepted,
Pau Espin Pedrolfa2b3842023-12-13 18:49:19 +0100596 { fteid_c_ie }, paa,
Pau Espin Pedrolf2925862024-02-22 20:12:30 +0100597 { ts_GTP2C_BcGrouped(bctx_ies) },
598 f_GTPv2C_gen_APCO_response(rx_msg.gtpcv2_pdu.createSessionRequest.aPCO) ));
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200599 setverdict(pass);
600 }
601 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
602 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
603 }
604}
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100605
Pau Espin Pedrol7b2cc922024-02-28 16:14:15 +0100606/* ePDG Creates session at the PGW. PGW sends Diameter s6b AAR + AAA. */
607private altstep as_GTP2C_CreateSession_error(GTP2C_Cause resp_cause, boolean do_s6b_aar := false) runs on EPDG_ConnHdlr {
608 var PDU_GTPCv2 rx_msg;
609 var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
610 var template (value) PDN_AddressAllocation paa;
611 var template (value) BearerContextIEs bctx_ies;
612
613 [] GTP2.receive(tr_GTP2C_CreateSessionReq(g_pars.imsi, apco := f_exp_tr_GTP2C_APCO_in_CreateSessionReq())) -> value rx_msg {
614 f_EPDG_ConnHdlr_parse_CreateSessionReq(rx_msg);
615
616 /* Upon rx of CreateSession, emulate PGW asking the AAA server. */
617 if (do_s6b_aar) {
618 f_S6b_AA_success();
619 }
620
621 fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S2b_PGW_GTPC, g_pars.teic_local, 1,
622 f_inet_addr(mp_s2b_local_ip), omit);
623 fteid_u_ie := ts_GTP2C_FTEID(FTEID_IF_S2bU_PGW_GTPU, g_pars.bearer.teid_local, 4,
624 f_inet_addr(mp_s2b_local_ip), omit);
625 GTP2.send(ts_GTP2C_CreateSessionResp(g_pars.teic_remote, rx_msg.sequenceNumber,
626 resp_cause));
627 setverdict(pass);
628 }
629 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
630 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
631 }
632}
633
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100634/* ePDG Deletes session at the PGW. PGW sends Diameter s6b AAR + AAA. */
635private altstep as_GTP2C_DeleteSession_success() runs on EPDG_ConnHdlr {
636 var PDU_GTPCv2 rx_msg;
637 var BearerContextIEs rx_bctx_ies;
638 var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
639 var template (value) PDN_AddressAllocation paa;
640 var template (value) BearerContextIEs bctx_ies;
641
642 [] GTP2.receive(tr_GTP2C_DeleteSessionReq(g_pars.teic_local)) -> value rx_msg {
643 /* Upon rx of DeleteSession, emulate PGW requesting the AAA server for Sesssion Termination. */
644 f_S6b_ST_success();
645
646 GTP2.send(ts_GTP2C_DeleteSessionResp(g_pars.teic_remote,
647 rx_msg.sequenceNumber,
648 Request_accepted));
649 setverdict(pass);
650 }
651 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
652 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
653 }
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200654}
655
Pau Espin Pedrol14abac52024-02-05 21:05:17 +0100656/* Expect CreateBearerResponse */
657private altstep as_GTP2C_CreateBearer_success() runs on EPDG_ConnHdlr {
658 var PDU_GTPCv2 rx_msg;
659
660 [] GTP2.receive(tr_GTP2C_CreateBearerResp(g_pars.teic_local)) -> value rx_msg {
661 setverdict(pass);
662 }
663 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
664 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
665 }
666}
667private function f_GTP2C_CreateBearer_success(uint4_t dedicated_bearer_id := 6) runs on EPDG_ConnHdlr {
668
669 var template (value) FullyQualifiedTEID fteid_u_ie := ts_GTP2C_FTEID(FTEID_IF_S2bU_ePDG_GTPU, g_pars.bearer.teid_local, dedicated_bearer_id,
670 f_inet_addr(mp_s2b_local_ip), omit);
671 var template (value) FullyQualifiedTEID_List teid_list := { fteid_u_ie };
672
673 var template (value) FullyQualifiedPDN_ConnectionSetID pgw_fq_csid := ts_GTP2C_FQCSID_IPv4(f_inet_addr(mp_s2b_local_ip), int2oct(dedicated_bearer_id, 2));
674 var template (value) FullyQualifiedPDN_ConnectionSetID_List csid_list := { pgw_fq_csid };
675
676 var template (value) BearerContextGrouped_List bcg_list := {
677 ts_GTP2C_BcGrouped({
678 ePS_Bearer_ID := ts_GTP2C_EpsBearerId(dedicated_bearer_id),
679 cause := omit,
680 ePS_Bearer_TFT := omit,
681 fullyQualifiedTEID := teid_list,
682 bearerLevel_QoS := ts_GTP2C_BearerQos('09'O, 0,0,0,0),
683 chargingID := ts_GTP2C_ChargingID(f_rnd_octstring(4)),
684 bearerFlags := omit,
685 transactionIdentifier := omit,
686 protocolConfigOptions := omit,
687 rAN_NASCause := omit,
688 additionalProtocolConfigOptions := omit,
689 extendedProtocolConfigOptions := omit
690 })
691 };
692 GTP2.send(ts_GTP2C_CreateBearerReq(g_pars.teic_remote, omit, g_pars.bearer.ebi,
693 dedicated_bearer_id, bcg_list, csid_list));
694 as_GTP2C_CreateBearer_success();
695}
696
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200697/* Expect DeleteBearerResponse */
698private altstep as_GTP2C_DeleteBearer_success() runs on EPDG_ConnHdlr {
699 var PDU_GTPCv2 rx_msg;
700 var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
701 var template (value) PDN_AddressAllocation paa;
702
703 [] GTP2.receive(tr_GTP2C_DeleteBearerResp(g_pars.teic_local)) -> value rx_msg {
704 setverdict(pass);
705 }
706 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
707 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
708 }
709}
710private function f_GTP2C_DeleteBearer_success() runs on EPDG_ConnHdlr {
711 var integer proc_trans_id := 3;
712 GTP2.send(ts_GTP2C_DeleteBearerReq(g_pars.teic_remote, proc_trans_id, g_pars.bearer.ebi, Access_changed_from_Non_3GPP_to_3GPP));
Pau Espin Pedrolcbe6eba2024-02-06 12:53:14 +0100713 as_GSUP_CancelLocation_success();
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200714 as_GTP2C_DeleteBearer_success();
715}
716
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +0100717private template (value) Gtp1uPeer ts_GtpPeerU(octetstring ip) := {
718 connId := 1,
719 remName := f_inet_ntoa(ip),
720 remPort := GTP1U_PORT
721}
722private function f_GTP1U_send(octetstring payload) runs on EPDG_ConnHdlr {
723 var Gtp1uPeer peer := valueof(ts_GtpPeerU(f_inet_addr(g_pars.bearer.gtpu_addr_remote)));
724 GTP2.send(ts_GTP1U_GPDU(peer, 0 /*seq*/, g_pars.bearer.teid_remote, payload));
725}
726private function f_GTP1U_echo_ping_pong(uint16_t seq_nr := 0) runs on EPDG_ConnHdlr {
727 var Gtp1uPeer peer := valueof(ts_GtpPeerU(f_inet_addr(g_pars.bearer.gtpu_addr_remote)));
728 GTP2.send(ts_GTPU_PING(peer, seq := seq_nr));
729 GTP2.receive(tr_GTPU_PONG(peer));
730}
Pau Espin Pedrolbf03d772024-03-01 16:15:21 +0100731private altstep as_GTPU_rx_icmp4(template (present) PDU_ICMP expected := ?) runs on EPDG_ConnHdlr {
732 var Gtp1uUnitdata rx_msg;
733 var template (value) Gtp1uPeer peer := ts_GtpPeerU(f_inet_addr(g_pars.bearer.gtpu_addr_remote));
734
735 [] GTP2.receive(tr_GTPU_GPDU(peer, g_pars.bearer.teid_local)) -> value rx_msg {
736 /*TODO: verify gtpu txseq:
737 if (f_verify_gtpu_txseq(ud.gtpu, use_gtpu_txseq) == false) {
738 setverdict(fail);
739 stop;
740 }
741 */
742 var octetstring gpdu := rx_msg.gtpu.gtpu_IEs.g_PDU_IEs.data;
743 var IPv4_packet ip4 := f_IPv4_dec(gpdu);
744 if (ip4.header.ver != 4) {
745 repeat;
746 }
747 var PDU_ICMP icmp4 := f_dec_PDU_ICMP(ip4.payload);
748 if (not match(icmp4, expected)) {
749 repeat;
750 }
751 }
752 [] GTP2.receive(Gtp1uUnitdata:?) -> value rx_msg {
753 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP msg rx: ", rx_msg));
754 }
755}
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +0100756
Pau Espin Pedrol6601f222024-03-05 18:51:09 +0100757private function f_GSUP_tx_SAI_REQ() runs on EPDG_ConnHdlr {
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200758 var GSUP_PDU rx_gsup;
Pau Espin Pedrolc2cfd552024-02-07 17:51:55 +0100759 var template (value) GSUP_IEs pdp_info;
Pau Espin Pedrolc2cfd552024-02-07 17:51:55 +0100760 pdp_info := { ts_GSUP_IE_PDP_CONTEXT_ID('00'O),
761 ts_GSUP_IE_PDP_ADDRESS(ts_EuaIPv4Dyn),
762 ts_GSUP_IE_APN(f_enc_dns_hostname(g_pars.apn)) };
763 GSUP.send(ts_GSUP_SAI_REQ_PDP_INFO(g_pars.imsi, pdp_info));
Pau Espin Pedrol6601f222024-03-05 18:51:09 +0100764}
765
766
767private altstep as_GSUP_rx_SAI_RES() runs on EPDG_ConnHdlr {
768 var GSUP_PDU rx_gsup;
769 var template (present) GSUP_IE auth_tuple_ie := tr_GSUP_IE_AuthTuple3G(
770 g_pars.vec.rand,
771 g_pars.vec.ik,
772 g_pars.vec.ck,
773 g_pars.vec.autn,
774 g_pars.vec.rand & g_pars.vec.auts);
775
776 [] GSUP.receive(tr_GSUP_SAI_RES(g_pars.imsi, auth_tuple_ie)) -> value rx_gsup {
777 }
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200778 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
779 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200780 }
Pau Espin Pedrol6601f222024-03-05 18:51:09 +0100781}
782
783private altstep as_GSUP_rx_SAI_ERR(template (present) integer cause := ?) runs on EPDG_ConnHdlr {
784 var GSUP_PDU rx_gsup;
785
786 [] GSUP.receive(tr_GSUP_SAI_ERR(g_pars.imsi, cause)) -> value rx_gsup {
787 }
788 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
789 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
790 }
791}
792
793/* GSUP AuthInfo Req + Resp, triggers SWx MAR + MAA. */
794private function f_GSUP_AI_success() runs on EPDG_ConnHdlr {
795 f_GSUP_tx_SAI_REQ();
796 as_DIA_SWx_MA_success();
797 as_GSUP_rx_SAI_RES();
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200798 setverdict(pass);
799}
800
801/* GSUP LU Req + Resp, triggers SWx SAR + SAA (Server Assignment). */
802private function f_GSUP_LU_success() runs on EPDG_ConnHdlr {
803 var GSUP_PDU rx_gsup;
804 var template octetstring destination_name := *;
805 GSUP.send(ts_GSUP_UL_REQ(g_pars.imsi));
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100806 as_DIA_SWx_SA_success(REGISTRATION);
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200807 /* Expect a positive response back to the translator */
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200808 alt {
809 [] GSUP.receive(tr_GSUP_UL_RES(g_pars.imsi, destination_name));
810 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
811 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
812 }
813 }
814 setverdict(pass);
815}
816
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200817/* GSUP TunnelEPDG Tunnel Req + Resp, triggers S2b CreateSession Req + Response. */
818private function f_GSUP_EPDGTunnel_success() runs on EPDG_ConnHdlr {
819 var GSUP_PDU rx_gsup;
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +0100820 var template (value) PCO_DATA pco := PCO_Types.ts_PCO({ ts_PCO_P_DNS_IPv4, ts_PCO_P_PCSCF_IPv4 });
Pau Espin Pedrolce1d3cb2024-02-21 17:40:59 +0100821 GSUP.send(ts_GSUP_EPDGTunnel_REQ(g_pars.imsi, pco));
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100822 as_GTP2C_CreateSession_success();
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200823 /* Expect a positive response back to the translator; */
Pau Espin Pedrolf2925862024-02-22 20:12:30 +0100824 var template (present) GSUP_IEs exp_pdp_info := {
Pau Espin Pedrola6b0c1c2024-01-22 20:02:06 +0100825 tr_GSUP_IE_PDP_CONTEXT_ID(?),
Pau Espin Pedrol78598b52024-02-14 19:21:42 +0100826 tr_GSUP_IE_PDP_ADDRESS(tr_GSUP_PDP_Address_IPv4(f_inet_addr(g_pars.ue_ip))),
827 tr_GSUP_IE_APN(f_enc_dns_hostname(g_pars.apn)),
Pau Espin Pedrola6b0c1c2024-01-22 20:02:06 +0100828 tr_GSUP_IE_PDP_QOS(?),
829 tr_GSUP_IE_Charging_Characteristics(?)
830 };
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +0100831 var template (present) PCO_DATA exp_pco := PCO_Types.tr_PCO({
Pau Espin Pedrolf2925862024-02-22 20:12:30 +0100832 tr_PCO_P_DNS_IPv4(f_inet_addr(mp_s2b_dns_ipv4)),
833 tr_PCO_P_PCSCF_IPv4(f_inet_addr(mp_s2b_pcscf_ipv4))
834 });
835 /* TODO: check for v6 and v4v6 types ^ */
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200836 alt {
Pau Espin Pedrolf2925862024-02-22 20:12:30 +0100837 [] GSUP.receive(tr_GSUP_EPDGTunnel_RES(g_pars.imsi, exp_pdp_info));
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200838 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
839 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
840 }
841 }
842 setverdict(pass);
843}
844
Pau Espin Pedrol7b2cc922024-02-28 16:14:15 +0100845/* GSUP TunnelEPDG Tunnel Req + Resp, triggers S2b CreateSession Req + Response (rejected). */
846private function f_GSUP_EPDGTunnel_error() runs on EPDG_ConnHdlr {
847 var GSUP_PDU rx_gsup;
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +0100848 var template (value) PCO_DATA pco := PCO_Types.ts_PCO({ ts_PCO_P_DNS_IPv4, ts_PCO_P_PCSCF_IPv4 });
Pau Espin Pedrol7b2cc922024-02-28 16:14:15 +0100849 GSUP.send(ts_GSUP_EPDGTunnel_REQ(g_pars.imsi, pco));
850 as_GTP2C_CreateSession_error(APN_access_denied__no_subscription);
851 alt {
852 [] GSUP.receive(tr_GSUP_EPDGTunnel_ERR(g_pars.imsi));
853 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
854 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
855 }
856 }
857 setverdict(pass);
858}
859
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100860/* GSUP Purge MS Req + Resp, triggers S2b DeleteSession Req + Response. */
861private function f_GSUP_PurgeMS_success() runs on EPDG_ConnHdlr {
862 var GSUP_PDU rx_gsup;
863 GSUP.send(ts_GSUP_PURGE_MS_REQ(g_pars.imsi, OSMO_GSUP_CN_DOMAIN_PS));
864 as_GTP2C_DeleteSession_success();
865 /* ePDG internally sends STR to its AAA-Server. Since all sessions
866 become inactive, AAA-Server sends SAR(USER_DEREGISTRATION) to HSS: */
867
868 /* Expect a positive response back to the translator; */
869 as_DIA_SWx_SA_success(USER_DEREGISTRATION);
870 alt {
871 [] GSUP.receive(tr_GSUP_PURGE_MS_RES(g_pars.imsi));
872 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
873 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
874 }
875 }
876 setverdict(pass);
877}
878
Pau Espin Pedrolcbe6eba2024-02-06 12:53:14 +0100879/* Expect CancelLocationReq */
880private altstep as_GSUP_CancelLocation_success() runs on EPDG_ConnHdlr {
881 var GSUP_PDU rx_gsup;
882
883 [] GSUP.receive(tr_GSUP_CL_REQ(g_pars.imsi)) -> value rx_gsup {
884 GSUP.send(ts_GSUP_CL_RES(g_pars.imsi));
885 }
886 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
887 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
888 }
889}
890
Pau Espin Pedrolaf8ba582024-02-05 21:05:10 +0100891private function f_initial_attach() runs on EPDG_ConnHdlr {
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200892 f_GSUP_AI_success();
893 f_GSUP_LU_success();
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200894 f_GSUP_EPDGTunnel_success();
Pau Espin Pedrolaf8ba582024-02-05 21:05:10 +0100895}
896
897private function f_TC_authinfo_normal(charstring id) runs on EPDG_ConnHdlr {
898 f_initial_attach();
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100899 f_GSUP_PurgeMS_success();
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200900}
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200901testcase TC_authinfo_normal() runs on MTC_CT {
902 var EPDG_ConnHdlrPars pars := f_init_pars();
903 var EPDG_ConnHdlr vc_conn;
904 f_init();
905 vc_conn := f_start_handler(refers(f_TC_authinfo_normal), pars);
906 vc_conn.done;
907 setverdict(pass);
908}
909
Pau Espin Pedrol6601f222024-03-05 18:51:09 +0100910private function f_TC_authinfo_MAA_unknown_user(charstring id) runs on EPDG_ConnHdlr {
911 var PDU_DIAMETER rx_dia;
912 var DIAMETER_ExperimentalResultcode exp_result_code := DIAMETER_ERROR_USER_UNKNOWN;
913 f_GSUP_tx_SAI_REQ();
914
915 SWx.receive(tr_DIA_SWx_MAR(g_pars.imsi)) -> value rx_dia;
916 f_DIA_SWx_tx_MAA_error(rx_dia,
917 ts_AVP_ExperimentalResult(vendor_id_3GPP,
918 int2oct(enum2int(exp_result_code), 4)));
919 /* cause 2 = IMSI_UNKNOWN */
920 as_GSUP_rx_SAI_ERR(2);
921}
922testcase TC_authinfo_MAA_unknown_user() runs on MTC_CT {
923 var EPDG_ConnHdlrPars pars := f_init_pars();
924 var EPDG_ConnHdlr vc_conn;
925 f_init();
926 vc_conn := f_start_handler(refers(f_TC_authinfo_MAA_unknown_user), pars);
927 vc_conn.done;
928 setverdict(pass);
929}
930
Pau Espin Pedrol14abac52024-02-05 21:05:17 +0100931private function f_TC_ho_lte_to_wifi(charstring id) runs on EPDG_ConnHdlr {
932 f_initial_attach();
933 /* Whenever UE comes from 3GPP, PGW may activate a dedicated S2b bearer
934 * and notify ePDG with a Create Bearer Request */
935 f_GTP2C_CreateBearer_success();
936 f_GSUP_PurgeMS_success();
937}
Pau Espin Pedrol14abac52024-02-05 21:05:17 +0100938testcase TC_ho_lte_to_wifi() runs on MTC_CT {
939 var EPDG_ConnHdlrPars pars := f_init_pars();
940 var EPDG_ConnHdlr vc_conn;
941 f_init();
942 vc_conn := f_start_handler(refers(f_TC_ho_lte_to_wifi), pars);
943 vc_conn.done;
944 setverdict(pass);
945}
946
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200947private function f_TC_ho_wifi_to_lte(charstring id) runs on EPDG_ConnHdlr {
Pau Espin Pedrolaf8ba582024-02-05 21:05:10 +0100948 f_initial_attach();
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200949 /* Whenever UE goes back to 3GPP, PGW will notify ePDG with a Delete Bearer Request
950 * cause="Access changed from non-3gpp to 3gpp" */
951 f_GTP2C_DeleteBearer_success();
952}
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200953testcase TC_ho_wifi_to_lte() runs on MTC_CT {
954 var EPDG_ConnHdlrPars pars := f_init_pars();
955 var EPDG_ConnHdlr vc_conn;
956 f_init();
957 vc_conn := f_start_handler(refers(f_TC_ho_wifi_to_lte), pars);
958 vc_conn.done;
959 setverdict(pass);
960}
961
Pau Espin Pedrol7b2cc922024-02-28 16:14:15 +0100962private function f_TC_s2b_CreateSession_rejected(charstring id) runs on EPDG_ConnHdlr {
963 f_GSUP_AI_success();
964 f_GSUP_LU_success();
965 f_GSUP_EPDGTunnel_error();
966}
967testcase TC_s2b_CreateSession_rejected() runs on MTC_CT {
968 var EPDG_ConnHdlrPars pars := f_init_pars();
969 var EPDG_ConnHdlr vc_conn;
970 f_init();
971 vc_conn := f_start_handler(refers(f_TC_s2b_CreateSession_rejected), pars);
972 vc_conn.done;
973 setverdict(pass);
974}
975
Pau Espin Pedrol285a2b62024-02-27 18:25:45 +0100976private function f_TC_concurrent_ues(charstring id) runs on EPDG_ConnHdlr {
977 COORD.send(COORD_CMD_READY);
978 COORD.receive(COORD_CMD_START);
979 f_initial_attach();
980 COORD.send(COORD_CMD_ATTACHED);
981 COORD.receive(COORD_CMD_STOP);
982 f_GSUP_PurgeMS_success();
983}
984private function f_TC_concurrent_ues_MTC(integer num_ues) runs on MTC_CT {
985 var EPDG_ConnHdlrList vc_conn_list := {};
986 var EPDG_ConnHdlr vc_conn;
987 f_init(t_guard := 100.0);
988
989 for (var integer i := 0; i < num_ues; i := i + 1) {
990 var EPDG_ConnHdlrPars pars := f_init_pars(i);
991 vc_conn := f_start_handler(refers(f_TC_concurrent_ues), pars);
992 vc_conn_list := vc_conn_list & { vc_conn };
993 }
994
995 for (var integer i := 0; i < num_ues; i := i + 1) {
996 COORD.receive(COORD_CMD_READY) from vc_conn_list[i];
997 }
998
999 for (var integer i := 0; i < num_ues; i := i + 1) {
1000 COORD.send(COORD_CMD_START) to vc_conn_list[i];
1001 f_sleep(0.1);
1002 }
1003
1004 for (var integer i := 0; i < num_ues; i := i + 1) {
1005 COORD.receive(COORD_CMD_ATTACHED) from vc_conn_list[i];
1006 }
1007
1008 log("All attached!");
1009 f_sleep(1.0);
1010
1011 for (var integer i := 0; i < num_ues; i := i + 1) {
1012 COORD.send(COORD_CMD_STOP) to vc_conn_list[i];
1013 }
1014
1015 for (var integer i := 0; i < num_ues; i := i + 1) {
1016 vc_conn_list[i].done;
1017 }
1018
1019 setverdict(pass);
1020}
1021testcase TC_concurrent_ues2() runs on MTC_CT {
1022 f_TC_concurrent_ues_MTC(2)
1023}
1024testcase TC_concurrent_ues100() runs on MTC_CT {
1025 f_TC_concurrent_ues_MTC(100)
1026}
1027
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +01001028private function f_TC_upf_echo_req(charstring id) runs on EPDG_ConnHdlr {
1029 f_initial_attach();
1030 /* Dispatch Echo Resp to this component: */
1031 f_gtp2_register_teid('00000000'O);
1032 f_GTP1U_echo_ping_pong(seq_nr := 0);
1033 /* Send one again, to validate it works several times: */
1034 f_GTP1U_echo_ping_pong(seq_nr := 1);
1035 f_GSUP_PurgeMS_success();
1036}
1037testcase TC_upf_echo_req() runs on MTC_CT {
1038 var EPDG_ConnHdlrPars pars := f_init_pars();
1039 var EPDG_ConnHdlr vc_conn;
1040 f_init();
1041 vc_conn := f_start_handler(refers(f_TC_upf_echo_req), pars);
1042 vc_conn.done;
1043 setverdict(pass);
1044}
1045
Pau Espin Pedrolbf03d772024-03-01 16:15:21 +01001046private function f_TC_mt_ipv4_echo_req(charstring id) runs on EPDG_ConnHdlr {
1047 f_initial_attach();
1048 /* Dispatch Echo Resp to this component: */
1049 f_gtp2_register_teid('00000000'O);
1050 var octetstring echo_req := f_gen_icmpv4_echo(f_inet_addr(mp_upf_gtpu_local_ip), f_inet_addr(g_pars.ue_ip));
1051 f_GTP1U_send(echo_req);
1052 as_GTPU_rx_icmp4((tr_ICMPv4_ERP, tr_ICMPv4_DU));
1053 f_GSUP_PurgeMS_success();
1054}
1055testcase TC_mt_ipv4_echo_req() runs on MTC_CT {
1056 var EPDG_ConnHdlrPars pars := f_init_pars();
1057 var EPDG_ConnHdlr vc_conn;
1058 f_init();
1059 vc_conn := f_start_handler(refers(f_TC_mt_ipv4_echo_req), pars);
1060 vc_conn.done;
1061 setverdict(pass);
1062}
1063
Pau Espin Pedrol965ac642023-10-16 18:12:45 +02001064control {
1065 execute ( TC_authinfo_normal() );
Pau Espin Pedrol6601f222024-03-05 18:51:09 +01001066 execute ( TC_authinfo_MAA_unknown_user() );
Pau Espin Pedrol14abac52024-02-05 21:05:17 +01001067 execute ( TC_ho_lte_to_wifi() );
Pau Espin Pedrold4a20082023-10-23 19:59:24 +02001068 execute ( TC_ho_wifi_to_lte() );
Pau Espin Pedrol7b2cc922024-02-28 16:14:15 +01001069 execute ( TC_s2b_CreateSession_rejected() );
Pau Espin Pedrol285a2b62024-02-27 18:25:45 +01001070 execute ( TC_concurrent_ues2() );
1071 execute ( TC_concurrent_ues100() );
Pau Espin Pedrola9b65f12024-02-29 21:08:15 +01001072 execute ( TC_upf_echo_req() );
Pau Espin Pedrolbf03d772024-03-01 16:15:21 +01001073 execute ( TC_mt_ipv4_echo_req() );
Pau Espin Pedrol965ac642023-10-16 18:12:45 +02001074}
1075
1076}