blob: 55d2ee7c8437cd203bd3dcf8b967f305ab013fda [file] [log] [blame]
Harald Welte34b5a952019-05-27 11:54:11 +02001/* PCU Interface codec poart in TTCN-3
2 * (C) 2018 Harald Welte <laforge@gnumonks.org>
3 * contributions by sysmocom - s.f.m.c. GmbH
4 * All rights reserved.
5 *
6 * Released under the terms of GNU General Public License, Version 2 or
7 * (at your option) any later version.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
Harald Welte883340c2018-02-28 18:59:29 +010012module PCUIF_CodecPort {
13
14import from Osmocom_Types all;
15import from PCUIF_Types all;
16import from UD_PortType all;
17import from UD_Types all;
Philipp Maier3b4abb82023-06-23 16:27:46 +020018import from General_Types all;
Harald Welte883340c2018-02-28 18:59:29 +010019
20type record PCUIF_send_data {
21 PCUIF_Message data,
22 integer id
23};
24
25private function PCUIF_to_UD(in PCUIF_send_data pin, out UD_send_data pout) {
26 pout.id := pin.id;
Vadim Yanitskiy204fe622021-03-23 04:49:41 +010027 pout.data := enc_PCUIF_Message(pin.data);
Harald Welte883340c2018-02-28 18:59:29 +010028} with { extension "prototype(fast)" };
29
Vadim Yanitskiy799cd3f2019-09-18 15:22:32 +070030private function fix_padding(inout PCUIF_data data) {
31 data.data := substr(data.data, 0, data.len);
32}
33
Harald Welte883340c2018-02-28 18:59:29 +010034private function UD_to_PCUIF(in UD_send_data pin, out PCUIF_send_data pout) {
35 pout.id := pin.id;
36 pout.data := dec_PCUIF_Message(pin.data);
Vadim Yanitskiy799cd3f2019-09-18 15:22:32 +070037
38 /* HACK: fix padding in decoded message. Due to a bug in TITAN, we
39 * cannot just use its 'PADDING' attribute because it breaks decoding. */
40 if (ischosen(pout.data.u.data_req)) { fix_padding(pout.data.u.data_req); }
Vadim Yanitskiy799cd3f2019-09-18 15:22:32 +070041 if (ischosen(pout.data.u.data_ind)) { fix_padding(pout.data.u.data_ind); }
Harald Welte883340c2018-02-28 18:59:29 +010042} with { extension "prototype(fast)" };
43
44type port PCUIF_CODEC_PT message {
45 out UD_close, UD_listen, UD_shutdown, UD_connect, PCUIF_send_data;
46 in UD_listen_result, UD_connect_result, UD_connected, PCUIF_send_data;
47} with { extension "user UD_PT
48 out (
49 UD_close -> UD_close:simple;
50 UD_listen -> UD_listen:simple;
51 UD_shutdown -> UD_shutdown:simple;
52 UD_connect -> UD_connect:simple;
53 PCUIF_send_data -> UD_send_data: function(PCUIF_to_UD)
54 )
55 in (
56 UD_listen_result -> UD_listen_result:simple;
57 UD_connect_result -> UD_connect_result:simple;
58 UD_send_data -> PCUIF_send_data: function(UD_to_PCUIF);
59 UD_connected -> UD_connected:simple
60 )"
61};
62
63template PCUIF_send_data t_SD_PCUIF(integer id, template PCUIF_Message pdu) := {
64 data := pdu,
65 id := id
66}
67
68template PCUIF_send_data t_SD_PCUIF_MSGT(integer id, template PCUIF_MsgType msg_type,
69 template uint8_t bts_nr := ?) := {
70 data := {
71 msg_type := msg_type,
72 bts_nr := bts_nr,
73 spare := ?,
74 u := ?
75 },
76 id := id
77}
78
79function f_pcuif_connect(PCUIF_CODEC_PT pt, charstring sock) return integer {
80 var UD_connect_result res;
81 timer T := 5.0;
82
83 T.start;
84 pt.send(UD_connect:{sock, -1});
85 alt {
86 [] pt.receive(UD_connect_result:?) -> value res {
87 if (ispresent(res.result) and ispresent(res.result.result_code) and
88 res.result.result_code == ERROR) {
Pau Espin Pedrolb1eaa6f2018-05-24 12:59:42 +020089 if (ispresent(res.result.err)) {
Max68b47432019-03-14 16:30:21 +010090 setverdict(fail, "Error connecting to PCU socket ", sock, ": ", res.result.err);
Pau Espin Pedrolb1eaa6f2018-05-24 12:59:42 +020091 } else {
Max68b47432019-03-14 16:30:21 +010092 setverdict(fail, "Error connecting to PCU socket ", sock);
Pau Espin Pedrolb1eaa6f2018-05-24 12:59:42 +020093 }
Daniel Willmanne4ff5372018-07-05 17:35:03 +020094 mtc.stop;
Harald Welte883340c2018-02-28 18:59:29 +010095 } else {
96 return res.id;
97 }
98 }
99 [] T.timeout {
Max68b47432019-03-14 16:30:21 +0100100 setverdict(fail, "Timeout connecting to PCU socket ", sock);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200101 mtc.stop;
Harald Welte883340c2018-02-28 18:59:29 +0100102 }
103 }
104 return -23;
105}
106
Harald Weltec8effb72019-05-27 18:23:04 +0200107function f_pcuif_close(PCUIF_CODEC_PT pt, integer id)
108{
109 pt.send(UD_close:{id := id});
110}
111
Harald Weltee1fd9162019-02-18 19:47:53 +0100112function f_pcuif_listen(PCUIF_CODEC_PT pt, charstring sock) return integer {
113 var UD_listen_result res;
114 var UD_connected udc;
115 timer T := 5.0;
116
117 pt.send(UD_listen:{sock});
118 T.start;
119 alt {
120 [] pt.receive(UD_listen_result:?) -> value res {
121 if (ispresent(res.result) and ispresent (res.result.result_code) and
122 res.result.result_code == ERROR) {
123 if (ispresent(res.result.err)) {
Max68b47432019-03-14 16:30:21 +0100124 setverdict(fail, "Error listening on PCU socket ", sock, ": ", res.result.err);
Harald Weltee1fd9162019-02-18 19:47:53 +0100125 } else {
Max68b47432019-03-14 16:30:21 +0100126 setverdict(fail, "Error listening on PCU socket ", sock);
Harald Weltee1fd9162019-02-18 19:47:53 +0100127 }
128 mtc.stop;
129 } else {
130 return res.id;
131 }
132 }
133 [] T.timeout {
Max68b47432019-03-14 16:30:21 +0100134 setverdict(fail, "Timeout waiting for PCU socket ", sock, " connection");
Harald Weltee1fd9162019-02-18 19:47:53 +0100135 mtc.stop;
136 }
137 }
138 return -23;
139}
140
Harald Welte883340c2018-02-28 18:59:29 +0100141function f_PCUIF_tx_imm_ass_pch(PCUIF_CODEC_PT pt, integer conn_id, octetstring imm_ass, hexstring imsi,
Philipp Maier83697dd2023-08-08 17:23:19 +0200142 uint8_t bts_nr := 0, boolean wait_for_cnf := true, OCT4 msg_id := '01020304'O) {
Harald Welte883340c2018-02-28 18:59:29 +0100143 timer T := 3.0;
Philipp Maier3b4abb82023-06-23 16:27:46 +0200144
Vadim Yanitskiy8f86bbe2023-12-15 15:19:09 +0700145 var PCUIF_pch pch := {
146 msg_id := msg_id,
147 imsi := hex2str(imsi),
148 data := imm_ass,
149 confirm := true
150 };
151 pt.send(t_SD_PCUIF(conn_id, ts_PCUIF_DATA_REQ(bts_nr, 0, 0, 0, 0, PCU_IF_SAPI_PCH_2, enc_PCUIF_pch(pch))));
Philipp Maierca058272021-06-23 10:35:23 +0200152
153 /* Exit early when the caller is not interested in the confirmation message */
154 if (wait_for_cnf == false) {
Philipp Maier83697dd2023-08-08 17:23:19 +0200155 return;
Philipp Maierca058272021-06-23 10:35:23 +0200156 }
157
Harald Welte883340c2018-02-28 18:59:29 +0100158 T.start;
159 alt {
Vadim Yanitskiy8f86bbe2023-12-15 15:19:09 +0700160 [] pt.receive(t_SD_PCUIF(conn_id, tr_PCUIF_DATA_CNF_2(bts_nr, PCU_IF_SAPI_PCH_2))) {
161 log("IMM.ASS was sent on PCH");
Harald Welte883340c2018-02-28 18:59:29 +0100162 }
163 [] pt.receive { repeat; }
164 [] T.timeout {
Philipp Maiera4f465a2023-08-03 12:05:14 +0200165 setverdict(fail, "Timeout waiting for PCU DATA.cnf (PCH)");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200166 mtc.stop;
Harald Welte883340c2018-02-28 18:59:29 +0100167 }
168 }
Harald Welte883340c2018-02-28 18:59:29 +0100169}
170
Philipp Maier896cbc92023-08-22 17:02:27 +0200171/* This function can be used to transmit arbitrary GSM MAC blocks via the AGCH. The BTS will only confirm those MAC
172 * blocks that contain actually a valid immediate assignment message. Otherweise no confirmation is sent back */
173function f_PCUIF_tx_mac_block_agch(PCUIF_CODEC_PT pt, integer conn_id, octetstring mac_block, boolean confirm := true,
174 uint8_t bts_nr := 0, boolean wait_for_cnf := true, OCT4 msg_id := '01020304'O) {
Philipp Maier896cbc92023-08-22 17:02:27 +0200175 timer T := 3.0;
176
Vadim Yanitskiy8f86bbe2023-12-15 15:19:09 +0700177 var PCUIF_agch agch := {
178 msg_id := msg_id,
179 data := mac_block,
180 confirm := confirm
181 };
182 pt.send(t_SD_PCUIF(conn_id, ts_PCUIF_DATA_REQ(bts_nr, 0, 0, 0, 0, PCU_IF_SAPI_AGCH_2, enc_PCUIF_agch(agch))));
Philipp Maier896cbc92023-08-22 17:02:27 +0200183
184 /* Exit early when the caller is not interested in the confirmation message */
185 if (wait_for_cnf == false) {
186 return;
187 }
188
189 T.start;
190 alt {
Vadim Yanitskiy8f86bbe2023-12-15 15:19:09 +0700191 [] pt.receive(t_SD_PCUIF(conn_id, tr_PCUIF_DATA_CNF_2(bts_nr, PCU_IF_SAPI_AGCH_2))) {
192 log("IMM.ASS was sent on AGCH");
Philipp Maier896cbc92023-08-22 17:02:27 +0200193 }
194 [] pt.receive { repeat; }
195 [] T.timeout {
196 setverdict(fail, "Timeout waiting for PCU DATA.cnf (AGCH)");
197 mtc.stop;
198 }
199 }
200 return;
201}
Harald Welte883340c2018-02-28 18:59:29 +0100202
203
204
205}