blob: e7481ca903565d045a4eb7ef879c3ff459758a5a [file] [log] [blame]
Harald Welted27ab242019-07-26 13:45:18 +02001module DIAMETER_Emulation {
2
3/* DIAMETER Emulation, runs on top of DIAMETER_CodecPort. It multiplexes/demultiplexes
4 * the individual IMSIs/subscribers, so there can be separate TTCN-3 components handling
5 * each of them.
6 *
7 * The DIAMETER_Emulation.main() function processes DIAMETER primitives from the DIAMETER
8 * socket via the DIAMETER_CodecPort, and dispatches them to the per-IMSI components.
9 *
10 * For each new IMSI, the DiameterOps.create_cb() is called. It can create
11 * or resolve a TTCN-3 component, and returns a component reference to which that IMSI
12 * is routed/dispatched.
13 *
14 * If a pre-existing component wants to register to handle a future inbound IMSI, it can
15 * do so by registering an "expect" with the expected IMSI.
16 *
17 * Inbound DIAMETER messages without IMSI (such as RESET-IND/ACK) are dispatched to
18 * the DiameterOps.unitdata_cb() callback, which is registered with an argument to the
19 * main() function below.
20 *
Vadim Yanitskiyb46f01e2021-12-06 03:23:13 +030021 * Alternatively, all inbound DIAMETER PDUs can be routed to a single component
22 * regardless of the IMSI. This is called 'raw' mode and can be achieved by
23 * setting the 'raw' field in DIAMETEROps to true.
24 *
Harald Welted27ab242019-07-26 13:45:18 +020025 * (C) 2019 by Harald Welte <laforge@gnumonks.org>
26 * All rights reserved.
27 *
28 * Released under the terms of GNU General Public License, Version 2 or
29 * (at your option) any later version.
30 *
31 * SPDX-License-Identifier: GPL-2.0-or-later
32 */
33
34import from DIAMETER_CodecPort all;
35import from DIAMETER_CodecPort_CtrlFunct all;
36import from DIAMETER_Types all;
37import from DIAMETER_Templates all;
38import from Osmocom_Types all;
39import from IPL4asp_Types all;
Harald Welte61f73d52020-04-26 21:41:12 +020040import from Native_Functions all;
Harald Welted27ab242019-07-26 13:45:18 +020041
42type hexstring IMSI;
43
Harald Welted01b5d02020-04-26 22:05:53 +020044/* notify the recipient that a Capability Exchange happened */
45type record DiameterCapabilityExchgInd {
46 PDU_DIAMETER rx,
47 PDU_DIAMETER tx
48};
49
Harald Welted27ab242019-07-26 13:45:18 +020050type component DIAMETER_ConnHdlr {
51 port DIAMETER_Conn_PT DIAMETER;
52 /* procedure based port to register for incoming connections */
53 port DIAMETEREM_PROC_PT DIAMETER_PROC;
54}
55
56/* port between individual per-connection components and this dispatcher */
57type port DIAMETER_Conn_PT message {
Harald Welte0e038082019-08-18 19:38:54 +020058 inout PDU_DIAMETER;
Harald Welted27ab242019-07-26 13:45:18 +020059} with { extension "internal" };
60
61/* global test port e.g. for non-imsi/conn specific messages */
62type port DIAMETER_PT message {
Harald Welted01b5d02020-04-26 22:05:53 +020063 inout PDU_DIAMETER, DiameterCapabilityExchgInd;
Harald Welted27ab242019-07-26 13:45:18 +020064} with { extension "internal" };
65
66
67/* represents a single DIAMETER Association */
68type record AssociationData {
69 DIAMETER_ConnHdlr comp_ref,
70 hexstring imsi optional
71};
72
Pau Espin Pedroldb017f42023-08-25 19:22:25 +020073/* represents a single DIAMETER message identified by ete_id field */
74type record ETEIDData {
75 DIAMETER_ConnHdlr comp_ref,
76 UINT32 ete_id optional
77};
78
Harald Welted27ab242019-07-26 13:45:18 +020079type component DIAMETER_Emulation_CT {
80 /* Port facing to the UDP SUT */
81 port DIAMETER_CODEC_PT DIAMETER;
82 /* All DIAMETER_ConnHdlr DIAMETER ports connect here
83 * DIAMETER_Emulation_CT.main needs to figure out what messages
84 * to send where with CLIENT.send() to vc_conn */
85 port DIAMETER_Conn_PT DIAMETER_CLIENT;
86 /* currently tracked connections */
Pau Espin Pedrolb335f012022-04-11 12:07:41 +020087 var AssociationData DiameterAssocTable[256];
Pau Espin Pedroldb017f42023-08-25 19:22:25 +020088 /* Forward reply messages not containing IMSI to correct client port */
89 var ETEIDData DiameterETEIDTable[256];
Harald Welted27ab242019-07-26 13:45:18 +020090 /* pending expected CRCX */
Pau Espin Pedrolb335f012022-04-11 12:07:41 +020091 var ExpectData DiameterExpectTable[256];
Harald Welted27ab242019-07-26 13:45:18 +020092 /* procedure based port to register for incoming connections */
93 port DIAMETEREM_PROC_PT DIAMETER_PROC;
94 /* test port for unit data messages */
95 port DIAMETER_PT DIAMETER_UNIT;
96
97 var charstring g_diameter_id;
98 var integer g_diameter_conn_id := -1;
99}
100
101type function DIAMETERCreateCallback(PDU_DIAMETER msg, hexstring imsi, charstring id)
102runs on DIAMETER_Emulation_CT return DIAMETER_ConnHdlr;
103
104type function DIAMETERUnitdataCallback(PDU_DIAMETER msg)
105runs on DIAMETER_Emulation_CT return template PDU_DIAMETER;
106
107type record DIAMETEROps {
108 DIAMETERCreateCallback create_cb,
Vadim Yanitskiyb46f01e2021-12-06 03:23:13 +0300109 DIAMETERUnitdataCallback unitdata_cb,
110 /* If true, this parameter disables IMSI based routing, so that all incoming
111 * PDUs get routed to a single component connected via the DIAMETER_UNIT port. */
112 boolean raw
Harald Welted27ab242019-07-26 13:45:18 +0200113}
114
115type record DIAMETER_conn_parameters {
116 HostName remote_ip,
117 PortNumber remote_sctp_port,
118 HostName local_ip,
Harald Welte61f73d52020-04-26 21:41:12 +0200119 PortNumber local_sctp_port,
120 charstring origin_host,
121 charstring origin_realm,
Pau Espin Pedrol33b47492022-03-08 17:43:01 +0100122 uint32_t auth_app_id optional,
123 uint32_t vendor_app_id optional
Harald Welted27ab242019-07-26 13:45:18 +0200124}
125
126function tr_DIAMETER_RecvFrom_R(template PDU_DIAMETER msg)
127runs on DIAMETER_Emulation_CT return template DIAMETER_RecvFrom {
128 var template DIAMETER_RecvFrom mrf := {
129 connId := g_diameter_conn_id,
130 remName := ?,
131 remPort := ?,
132 locName := ?,
133 locPort := ?,
134 msg := msg
135 }
136 return mrf;
137}
138
139private function f_imsi_known(hexstring imsi)
140runs on DIAMETER_Emulation_CT return boolean {
141 var integer i;
Pau Espin Pedrole4361702022-04-11 11:59:40 +0200142 for (i := 0; i < sizeof(DiameterAssocTable); i := i+1) {
143 if (DiameterAssocTable[i].imsi == imsi) {
Harald Welted27ab242019-07-26 13:45:18 +0200144 return true;
145 }
146 }
147 return false;
148}
149
150private function f_comp_known(DIAMETER_ConnHdlr client)
151runs on DIAMETER_Emulation_CT return boolean {
152 var integer i;
Pau Espin Pedrole4361702022-04-11 11:59:40 +0200153 for (i := 0; i < sizeof(DiameterAssocTable); i := i+1) {
154 if (DiameterAssocTable[i].comp_ref == client) {
Harald Welted27ab242019-07-26 13:45:18 +0200155 return true;
156 }
157 }
158 return false;
159}
160
161private function f_comp_by_imsi(hexstring imsi)
162runs on DIAMETER_Emulation_CT return DIAMETER_ConnHdlr {
163 var integer i;
Pau Espin Pedrole4361702022-04-11 11:59:40 +0200164 for (i := 0; i < sizeof(DiameterAssocTable); i := i+1) {
165 if (DiameterAssocTable[i].imsi == imsi) {
166 return DiameterAssocTable[i].comp_ref;
Harald Welted27ab242019-07-26 13:45:18 +0200167 }
168 }
169 setverdict(fail, "DIAMETER Association Table not found by IMSI", imsi);
170 mtc.stop;
171}
172
173private function f_imsi_by_comp(DIAMETER_ConnHdlr client)
174runs on DIAMETER_Emulation_CT return hexstring {
175 var integer i;
Pau Espin Pedrole4361702022-04-11 11:59:40 +0200176 for (i := 0; i < sizeof(DiameterAssocTable); i := i+1) {
177 if (DiameterAssocTable[i].comp_ref == client) {
178 return DiameterAssocTable[i].imsi;
Harald Welted27ab242019-07-26 13:45:18 +0200179 }
180 }
181 setverdict(fail, "DIAMETER Association Table not found by component ", client);
182 mtc.stop;
183}
184
185private function f_imsi_table_add(DIAMETER_ConnHdlr comp_ref, hexstring imsi)
186runs on DIAMETER_Emulation_CT {
187 var integer i;
Pau Espin Pedrole4361702022-04-11 11:59:40 +0200188 for (i := 0; i < sizeof(DiameterAssocTable); i := i+1) {
189 if (not isvalue(DiameterAssocTable[i].imsi)) {
190 DiameterAssocTable[i].imsi := imsi;
191 DiameterAssocTable[i].comp_ref := comp_ref;
Harald Welted27ab242019-07-26 13:45:18 +0200192 return;
193 }
194 }
195 testcase.stop("DIAMETER Association Table full!");
196}
197
198private function f_imsi_table_del(DIAMETER_ConnHdlr comp_ref, hexstring imsi)
199runs on DIAMETER_Emulation_CT {
200 var integer i;
Pau Espin Pedrole4361702022-04-11 11:59:40 +0200201 for (i := 0; i < sizeof(DiameterAssocTable); i := i+1) {
202 if (DiameterAssocTable[i].comp_ref == comp_ref and
203 DiameterAssocTable[i].imsi == imsi) {
204 DiameterAssocTable[i].imsi := omit;
205 DiameterAssocTable[i].comp_ref := null;
Harald Welted27ab242019-07-26 13:45:18 +0200206 return;
207 }
208 }
209 setverdict(fail, "DIAMETER Association Table: Couldn't find to-be-deleted entry!");
210 mtc.stop;
211}
212
Harald Welted27ab242019-07-26 13:45:18 +0200213private function f_imsi_table_init()
214runs on DIAMETER_Emulation_CT {
Pau Espin Pedrole4361702022-04-11 11:59:40 +0200215 for (var integer i := 0; i < sizeof(DiameterAssocTable); i := i+1) {
216 DiameterAssocTable[i].comp_ref := null;
217 DiameterAssocTable[i].imsi := omit;
Harald Welted27ab242019-07-26 13:45:18 +0200218 }
219}
220
Pau Espin Pedroldb017f42023-08-25 19:22:25 +0200221/* End-to-End ID table matching. */
222private function f_ete_id_known(UINT32 ete_id)
223runs on DIAMETER_Emulation_CT return boolean {
224 var integer i;
225 for (i := 0; i < sizeof(DiameterETEIDTable); i := i+1) {
226 if (DiameterETEIDTable[i].ete_id == ete_id) {
227 return true;
228 }
229 }
230 return false;
231}
232
233private function f_comp_by_ete_id(UINT32 ete_id)
234runs on DIAMETER_Emulation_CT return DIAMETER_ConnHdlr {
235 var integer i;
236 for (i := 0; i < sizeof(DiameterETEIDTable); i := i+1) {
237 if (DiameterETEIDTable[i].ete_id == ete_id) {
238 return DiameterETEIDTable[i].comp_ref;
239 }
240 }
241 setverdict(fail, "DIAMETER ETEID Table not found by ete_id", ete_id);
242 mtc.stop;
243}
244
245private function f_eteid_table_add(DIAMETER_ConnHdlr comp_ref, UINT32 ete_id)
246runs on DIAMETER_Emulation_CT {
247 var integer i;
248 for (i := 0; i < sizeof(DiameterETEIDTable); i := i+1) {
249 if (not isvalue(DiameterETEIDTable[i].ete_id)) {
250 DiameterETEIDTable[i].ete_id := ete_id;
251 DiameterETEIDTable[i].comp_ref := comp_ref;
252 return;
253 }
254 }
255 testcase.stop("DIAMETER ETEID Table full!");
256}
257
258private function f_eteid_table_del(DIAMETER_ConnHdlr comp_ref, UINT32 ete_id)
259runs on DIAMETER_Emulation_CT {
260 var integer i;
261 for (i := 0; i < sizeof(DiameterETEIDTable); i := i+1) {
262 if (DiameterETEIDTable[i].comp_ref == comp_ref and
263 DiameterETEIDTable[i].ete_id == ete_id) {
264 DiameterETEIDTable[i].ete_id := omit;
265 DiameterETEIDTable[i].comp_ref := null;
266 return;
267 }
268 }
269 setverdict(fail, "DIAMETER ETEID Table: Couldn't find to-be-deleted entry!");
270 mtc.stop;
271}
272
273
274private function f_eteid_table_init()
275runs on DIAMETER_Emulation_CT {
276 for (var integer i := 0; i < sizeof(DiameterETEIDTable); i := i+1) {
277 DiameterETEIDTable[i].comp_ref := null;
278 DiameterETEIDTable[i].ete_id := omit;
279 }
280}
281
Harald Welted27ab242019-07-26 13:45:18 +0200282function f_DIAMETER_get_imsi(PDU_DIAMETER pdu) return template (omit) IMSI
283{
284 var template (omit) AVP imsi_avp;
285
286 imsi_avp := f_DIAMETER_get_avp(pdu, c_AVP_Code_BASE_NONE_User_Name);
287 if (istemplatekind(imsi_avp, "omit")) {
Harald Weltef9fb63e2020-04-26 18:07:19 +0200288 var template (omit) AVP sid_avp;
289 sid_avp := f_DIAMETER_get_avp(pdu, c_AVP_Code_DCC_NONE_Subscription_Id);
290 if (istemplatekind(sid_avp, "omit")) {
291 return omit;
292 }
293 var AVP_Grouped grp := valueof(sid_avp.avp_data.avp_DCC_NONE_Subscription_Id);
Pau Espin Pedrolb8cd34a2022-05-18 16:34:12 +0200294 if (not match(grp[0], tr_AVP_SubcrIdType(END_USER_IMSI))) {
Harald Weltef9fb63e2020-04-26 18:07:19 +0200295 return omit;
296 }
297 return str2hex(oct2char(grp[1].avp.avp_data.avp_DCC_NONE_Subscription_Id_Data));
Harald Welted27ab242019-07-26 13:45:18 +0200298 } else {
299 var octetstring imsi_oct := valueof(imsi_avp.avp_data.avp_BASE_NONE_User_Name);
300 return str2hex(oct2char(imsi_oct));
301 }
302}
303
304private template (value) SctpTuple ts_SCTP(template (omit) integer ppid := omit) := {
305 sinfo_stream := omit,
306 sinfo_ppid := ppid,
307 remSocks := omit,
308 assocId := omit
309};
310
311private template PortEvent tr_SctpAssocChange := {
312 sctpEvent := {
313 sctpAssocChange := ?
314 }
315}
316private template PortEvent tr_SctpPeerAddrChange := {
317 sctpEvent := {
318 sctpPeerAddrChange := ?
319 }
320}
321
322private function f_diameter_xceive(template (value) PDU_DIAMETER tx,
323 template PDU_DIAMETER rx_t := ?)
324runs on DIAMETER_Emulation_CT return PDU_DIAMETER {
325 timer T := 10.0;
326 var DIAMETER_RecvFrom mrf;
327
328 DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, tx));
Vadim Yanitskiy672a41e2023-02-14 04:52:56 +0700329 T.start;
Harald Welted27ab242019-07-26 13:45:18 +0200330 alt {
331 [] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(rx_t)) -> value mrf { }
Vadim Yanitskiy3148a0e2023-02-11 09:27:42 +0700332 [] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(?)) -> value mrf {
333 setverdict(fail, "Rx unexpected DIAMETER PDU: ", mrf);
334 mtc.stop;
335 }
Harald Welted27ab242019-07-26 13:45:18 +0200336 [] DIAMETER.receive(tr_SctpAssocChange) { repeat; }
337 [] DIAMETER.receive(tr_SctpPeerAddrChange) { repeat; }
338 [] T.timeout {
339 setverdict(fail, "Timeout waiting for ", rx_t);
340 mtc.stop;
341 }
342 }
343 return mrf.msg;
344}
345
346function main(DIAMETEROps ops, DIAMETER_conn_parameters p, charstring id) runs on DIAMETER_Emulation_CT {
Vadim Yanitskiyb94e4592023-02-11 08:09:09 +0700347 var boolean server_mode := p.remote_sctp_port == -1;
Harald Welted27ab242019-07-26 13:45:18 +0200348 var Result res;
349 g_diameter_id := id;
350 f_imsi_table_init();
Pau Espin Pedroldb017f42023-08-25 19:22:25 +0200351 f_eteid_table_init();
Harald Welted27ab242019-07-26 13:45:18 +0200352 f_expect_table_init();
353
354 map(self:DIAMETER, system:DIAMETER_CODEC_PT);
Vadim Yanitskiyb94e4592023-02-11 08:09:09 +0700355 if (server_mode) {
Harald Welted27ab242019-07-26 13:45:18 +0200356 res := DIAMETER_CodecPort_CtrlFunct.f_IPL4_listen(DIAMETER, p.local_ip, p.local_sctp_port, { sctp := valueof(ts_SCTP) });
357 } else {
358 res := DIAMETER_CodecPort_CtrlFunct.f_IPL4_connect(DIAMETER, p.remote_ip, p.remote_sctp_port,
359 p.local_ip, p.local_sctp_port, -1, { sctp := valueof(ts_SCTP) });
360 }
361 if (not ispresent(res.connId)) {
362 setverdict(fail, "Could not connect DIAMETER socket, check your configuration");
363 mtc.stop;
364 }
365 g_diameter_conn_id := res.connId;
366
Vadim Yanitskiyb94e4592023-02-11 08:09:09 +0700367 /* If in client mode, send CER immediately */
368 if (not server_mode) {
369 var template (value) PDU_DIAMETER req;
370 var PDU_DIAMETER rsp;
371
372 req := ts_DIA_CER(f_inet_addr(p.local_ip), p.vendor_app_id,
373 orig_host := p.origin_host, orig_realm := p.origin_realm);
374 rsp := f_diameter_xceive(req, tr_DIAMETER_A(Capabilities_Exchange, req.application_id));
375 /* notify our user that the CER->CEA exchange has happened */
376 DIAMETER_UNIT.send(DiameterCapabilityExchgInd:{rx := rsp, tx := valueof(req)});
377 }
378
Harald Welted27ab242019-07-26 13:45:18 +0200379 while (true) {
380 var DIAMETER_ConnHdlr vc_conn;
Harald Welted27ab242019-07-26 13:45:18 +0200381 var template IMSI imsi_t;
382 var hexstring imsi;
Pau Espin Pedroldb017f42023-08-25 19:22:25 +0200383 var UINT32 ete_id;
Harald Welted27ab242019-07-26 13:45:18 +0200384 var DIAMETER_RecvFrom mrf;
385 var PDU_DIAMETER msg;
386 var charstring vlr_name, mme_name;
387 var PortEvent port_evt;
388
389 alt {
390 [] DIAMETER.receive(PortEvent:{connOpened := ?}) -> value port_evt {
391 g_diameter_conn_id := port_evt.connOpened.connId;
392 }
393 [] DIAMETER.receive(PortEvent:?) { }
394 /* DIAMETER from client */
395 [] DIAMETER_CLIENT.receive(PDU_DIAMETER:?) -> value msg sender vc_conn {
396 /* Pass message through */
397 /* TODO: check which ConnectionID client has allocated + store in table? */
398 DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, msg));
399 }
400
401 /* handle CER/CEA handshake */
402 [] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(tr_DIAMETER_R(cmd_code := Capabilities_Exchange))) -> value mrf {
403 var template (value) PDU_DIAMETER resp;
Pau Espin Pedrol33b47492022-03-08 17:43:01 +0100404 resp := f_ts_DIA_CEA(mrf.msg.hop_by_hop_id, mrf.msg.end_to_end_id, p.origin_host,
405 p.origin_realm, f_inet_addr(p.local_ip), p.auth_app_id, p.vendor_app_id);
Harald Welted27ab242019-07-26 13:45:18 +0200406 DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, resp));
Harald Welted01b5d02020-04-26 22:05:53 +0200407 /* notify our user that the CER->CEA exchange has happened */
408 DIAMETER_UNIT.send(DiameterCapabilityExchgInd:{rx:=mrf.msg, tx:=valueof(resp)});
Harald Welted27ab242019-07-26 13:45:18 +0200409 }
Vadim Yanitskiy3f7a6dc2021-12-11 04:13:59 +0300410 /* handle DWR/DWA ping-pong */
411 [] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(tr_DIA_DWR)) -> value mrf {
412 var template (value) PDU_DIAMETER resp;
413 resp := ts_DIA_DWA('00000001'O, p.origin_host, p.origin_realm,
414 hbh_id := mrf.msg.hop_by_hop_id,
415 ete_id := mrf.msg.end_to_end_id);
416 DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, valueof(resp)));
417 }
Harald Welted27ab242019-07-26 13:45:18 +0200418
Vadim Yanitskiyb46f01e2021-12-06 03:23:13 +0300419 /* DIAMETER from the test suite */
420 [ops.raw] DIAMETER_UNIT.receive(PDU_DIAMETER:?) -> value msg {
421 DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, msg));
422 }
423 /* DIAMETER from remote peer (raw mode) */
424 [ops.raw] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(?)) -> value mrf {
425 DIAMETER_UNIT.send(mrf.msg);
426 }
427 /* DIAMETER from remote peer (IMSI based routing) */
428 [not ops.raw] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(?)) -> value mrf {
Harald Welted27ab242019-07-26 13:45:18 +0200429 imsi_t := f_DIAMETER_get_imsi(mrf.msg);
Pau Espin Pedroldb017f42023-08-25 19:22:25 +0200430 ete_id := mrf.msg.end_to_end_id;
431 if (f_ete_id_known(ete_id)) {
432 vc_conn := f_comp_by_ete_id(ete_id);
433 /* The ete_id is a single-time expect: */
434 f_eteid_table_del(vc_conn, ete_id);
435 DIAMETER_CLIENT.send(mrf.msg) to vc_conn;
436 } else if (isvalue(imsi_t)) {
Harald Welted27ab242019-07-26 13:45:18 +0200437 imsi := valueof(imsi_t);
438 if (f_imsi_known(imsi)) {
439 vc_conn := f_comp_by_imsi(imsi);
440 DIAMETER_CLIENT.send(mrf.msg) to vc_conn;
441 } else {
442 vc_conn := ops.create_cb.apply(mrf.msg, imsi, id);
443 f_imsi_table_add(vc_conn, imsi);
444 DIAMETER_CLIENT.send(mrf.msg) to vc_conn;
445 }
446 } else {
447 /* message contained no IMSI; is not IMSI-oriented */
448 var template PDU_DIAMETER resp := ops.unitdata_cb.apply(mrf.msg);
449 if (isvalue(resp)) {
450 DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, valueof(resp)));
451 }
452 }
453 }
454 [] DIAMETER.receive(tr_SctpAssocChange) { }
455 [] DIAMETER.receive(tr_SctpPeerAddrChange) { }
Pau Espin Pedroldb017f42023-08-25 19:22:25 +0200456 [] DIAMETER_PROC.getcall(DIAMETEREM_register_imsi:{?,?}) -> param(imsi, vc_conn) {
Harald Welted27ab242019-07-26 13:45:18 +0200457 f_create_expect(imsi, vc_conn);
Pau Espin Pedroldb017f42023-08-25 19:22:25 +0200458 DIAMETER_PROC.reply(DIAMETEREM_register_imsi:{imsi, vc_conn}) to vc_conn;
459 }
460 [] DIAMETER_PROC.getcall(DIAMETEREM_register_eteid:{?,?}) -> param(ete_id, vc_conn) {
461 f_eteid_table_add(vc_conn, ete_id);
462 DIAMETER_PROC.reply(DIAMETEREM_register_eteid:{ete_id, vc_conn}) to vc_conn;
Harald Welted27ab242019-07-26 13:45:18 +0200463 }
464
465 }
466
467 }
468}
469
Pau Espin Pedroldb017f42023-08-25 19:22:25 +0200470/* "E2E ID Expect" Handling */
471type record ExpectDataE2EID {
472 UINT32 ete_id optional,
473 DIAMETER_ConnHdlr vc_conn
474}
475
476signature DIAMETEREM_register_eteid(in UINT32 ete_id, in DIAMETER_ConnHdlr hdlr);
477
478/* client/conn_hdlr side function to use procedure port to create expect in emulation */
479function f_diameter_expect_eteid(UINT32 ete_id) runs on DIAMETER_ConnHdlr {
480 DIAMETER_PROC.call(DIAMETEREM_register_eteid:{ete_id, self}) {
481 [] DIAMETER_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
482 }
483}
484
485/* "IMSI Expect" Handling */
Harald Welted27ab242019-07-26 13:45:18 +0200486
487type record ExpectData {
488 hexstring imsi optional,
489 DIAMETER_ConnHdlr vc_conn
490}
491
Pau Espin Pedroldb017f42023-08-25 19:22:25 +0200492signature DIAMETEREM_register_imsi(in hexstring imsi, in DIAMETER_ConnHdlr hdlr);
Harald Welted27ab242019-07-26 13:45:18 +0200493
Pau Espin Pedrol69730a22022-04-11 12:00:53 +0200494/* Function that can be used as create_cb and will use the expect table */
Harald Welted27ab242019-07-26 13:45:18 +0200495function ExpectedCreateCallback(PDU_DIAMETER msg, hexstring imsi, charstring id)
496runs on DIAMETER_Emulation_CT return DIAMETER_ConnHdlr {
497 var DIAMETER_ConnHdlr ret := null;
498 var integer i;
499
500 for (i := 0; i < sizeof(DiameterExpectTable); i := i+1) {
501 if (not ispresent(DiameterExpectTable[i].imsi)) {
502 continue;
503 }
504 if (imsi == DiameterExpectTable[i].imsi) {
505 ret := DiameterExpectTable[i].vc_conn;
506 /* Release this entry */
507 DiameterExpectTable[i].imsi := omit;
508 DiameterExpectTable[i].vc_conn := null;
509 log("Found Expect[", i, "] for ", msg, " handled at ", ret);
510 return ret;
511 }
512 }
513 setverdict(fail, "Couldn't find Expect for ", msg);
514 mtc.stop;
515}
516
517private function f_create_expect(hexstring imsi, DIAMETER_ConnHdlr hdlr)
518runs on DIAMETER_Emulation_CT {
519 var integer i;
520
521 /* Check an entry like this is not already presnt */
522 for (i := 0; i < sizeof(DiameterExpectTable); i := i+1) {
523 if (imsi == DiameterExpectTable[i].imsi) {
524 setverdict(fail, "IMSI already present", imsi);
525 mtc.stop;
526 }
527 }
528 for (i := 0; i < sizeof(DiameterExpectTable); i := i+1) {
529 if (not ispresent(DiameterExpectTable[i].imsi)) {
530 DiameterExpectTable[i].imsi := imsi;
531 DiameterExpectTable[i].vc_conn := hdlr;
532 log("Created Expect[", i, "] for ", imsi, " to be handled at ", hdlr);
533 return;
534 }
535 }
536 testcase.stop("No space left in DiameterExpectTable")
537}
538
539/* client/conn_hdlr side function to use procedure port to create expect in emulation */
Pau Espin Pedroldb017f42023-08-25 19:22:25 +0200540function f_diameter_expect_imsi(hexstring imsi) runs on DIAMETER_ConnHdlr {
541 DIAMETER_PROC.call(DIAMETEREM_register_imsi:{imsi, self}) {
542 [] DIAMETER_PROC.getreply(DIAMETEREM_register_imsi:{?,?}) {};
Harald Welted27ab242019-07-26 13:45:18 +0200543 }
544}
545
546private function f_expect_table_init()
547runs on DIAMETER_Emulation_CT {
548 var integer i;
549 for (i := 0; i < sizeof(DiameterExpectTable); i := i + 1) {
550 DiameterExpectTable[i].imsi := omit;
551 }
552}
553
554function DummyUnitdataCallback(PDU_DIAMETER msg)
555runs on DIAMETER_Emulation_CT return template PDU_DIAMETER {
556 log("Ignoring DIAMETER ", msg);
557 return omit;
558}
559
Pau Espin Pedroldb017f42023-08-25 19:22:25 +0200560type port DIAMETEREM_PROC_PT procedure {
561 inout DIAMETEREM_register_imsi;
562 inout DIAMETEREM_register_eteid;
563} with { extension "internal" };
Harald Welted27ab242019-07-26 13:45:18 +0200564
Harald Welted01b5d02020-04-26 22:05:53 +0200565function f_diameter_wait_capability(DIAMETER_PT pt)
566{
567 /* Wait for the Capability Exchange with the DUT */
568 timer T := 10.0;
569 T.start;
570 alt {
571 [] pt.receive(DiameterCapabilityExchgInd:?) {}
572 [] pt.receive {
573 setverdict(fail, "Unexpected receive waiting for DiameterCapabilityExchgInd");
574 mtc.stop;
575 }
576 [] T.timeout {
577 setverdict(fail, "Timeout waiting for DiameterCapabilityExchgInd");
578 mtc.stop;
579 }
580 }
581}
582
583
Harald Welted27ab242019-07-26 13:45:18 +0200584}