blob: ed235d3effcfe8fc7c530dd5189e3c380b94dd91 [file] [log] [blame]
Harald Welte34b5a952019-05-27 11:54:11 +02001/* dual-faced port that wraps an Unixdomain port and encodes/decodes L1CTL
2 * (C) 2017-2019 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 Welte52c713c2017-07-16 15:44:44 +020012module L1CTL_PortType {
13 import from L1CTL_Types all;
14 import from UD_PortType all;
Harald Welteaaa0dfd2021-02-04 16:58:53 +010015 import from Socket_API_Definitions all;
Harald Welte52c713c2017-07-16 15:44:44 +020016 import from UD_Types all;
Harald Welte9e4725d2017-07-16 23:18:09 +020017 import from Osmocom_Types all;
18 import from GSM_Types all;
Harald Welte9419c8a2017-07-30 04:07:05 +020019 import from GSM_RR_Types all;
Harald Welte6fc784e2018-02-25 23:31:37 +010020 import from L1CTL_PortType_CtrlFunct all;
Harald Welte52c713c2017-07-16 15:44:44 +020021
22 type record L1CTL_connect {
23 charstring path
24 }
25
26 type record L1CTL_connect_result {
27 UD_Result_code result_code optional,
28 charstring err optional
29 }
30
Harald Weltef68765d2017-08-20 22:54:57 +020031 modulepar {
32 charstring m_l1ctl_sock_path := "/tmp/osmocom_l2";
33 }
34
Harald Welteaaa0dfd2021-02-04 16:58:53 +010035 function f_L1CTL_getMsgLen(in octetstring stream, inout Socket_API_Definitions.ro_integer args) return integer {
Harald Welte6fc784e2018-02-25 23:31:37 +010036 var integer stream_len := lengthof(stream);
37 var integer len;
38 if (stream_len < 2) {
Harald Welte6fc784e2018-02-25 23:31:37 +010039 return -1;
40 }
41 len := 2 + oct2int(substr(stream, 0, 2));
Harald Welte6fc784e2018-02-25 23:31:37 +010042 return len;
43 }
44
Vadim Yanitskiye243ef62021-11-06 16:32:06 +030045 function f_L1CTL_rx_data(L1CTL_PT pt,
46 template (present) RslChannelNr chan_nr := ?,
47 template (present) RslLinkId link_id := ?)
48 return L1ctlDlMessage {
49 var L1ctlDlMessage dl;
50 timer T := 2.0;
51
52 T.start;
53 alt {
54 [] pt.receive(tr_L1CTL_DATA_IND(chan_nr, link_id)) -> value dl {
55 return dl;
56 }
57 [] pt.receive { repeat; }
58 [] T.timeout {
59 setverdict(fail, "Timeout waiting for L1CTL DATA.ind");
60 mtc.stop;
61 }
62 }
63
64 /* Unreachable, make TITAN happy */
65 return dl;
66 }
67
Vadim Yanitskiy1acc7bb2020-11-14 04:24:57 +070068 function f_L1CTL_FBSB(L1CTL_PT pt, GsmBandArfcn arfcn,
69 L1ctlCcchMode ccch_mode := CCCH_MODE_COMBINED,
70 integer rxlev_exp := 57)
71 {
Harald Welte3757e602018-03-10 17:12:02 +010072 timer T := 15.0;
Harald Welte8fe9eba2018-03-09 17:03:49 +010073 for (var integer i := 0; i < 10; i := i+1) {
Stefan Sperling02585902018-08-30 17:03:50 +020074 var L1ctlDlMessage dl;
Pau Espin Pedrol752ffd52018-06-07 13:55:45 +020075 pt.send(ts_L1CTL_FBSB_REQ(arfcn, valueof(t_L1CTL_FBSB_F_ALL), 0, ccch_mode, rxlev_exp));
Harald Welte8fe9eba2018-03-09 17:03:49 +010076 T.start
77 alt {
Harald Weltef8df4cb2018-03-10 15:15:08 +010078 [] pt.receive(tr_L1CTL_FBSB_CONF(0)) { return; };
Stefan Sperling02585902018-08-30 17:03:50 +020079 [i >= 9] pt.receive(tr_L1CTL_FBSB_CONF(?)) -> value dl {
80 setverdict(fail, "FBSB Failed with non-zero return code ", dl.payload.fbsb_conf.result);
Daniel Willmanne4ff5372018-07-05 17:35:03 +020081 mtc.stop;
Harald Welte7d7d26c2018-02-22 18:52:28 +010082 };
Harald Weltef8df4cb2018-03-10 15:15:08 +010083 [] pt.receive(tr_L1CTL_FBSB_CONF(?)) {
Harald Welte3757e602018-03-10 17:12:02 +010084 f_sleep(1.0);
Harald Weltef8df4cb2018-03-10 15:15:08 +010085 }
Harald Welte9e4725d2017-07-16 23:18:09 +020086 [] pt.receive { repeat; };
Harald Welte3757e602018-03-10 17:12:02 +010087 [] T.timeout {
Vadim Yanitskiyde8af3d2019-06-12 01:34:05 +070088 setverdict(fail, "Timeout waiting for L1CTL_FBSB_CONF");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020089 mtc.stop;
Harald Welte3757e602018-03-10 17:12:02 +010090 };
91 }
92 }
93 }
94
95 function f_L1CTL_CCCH_MODE(L1CTL_PT pt, L1ctlCcchMode ccch_mode) {
96 timer T := 2.0;
97 pt.send(ts_L1CTL_CCCH_MODE_REQ(ccch_mode));
98 T.start;
99 alt {
100 [] pt.receive(tr_L1CTL_CCCH_MODE_CONF) { }
101 [] pt.receive { repeat; }
102 [] T.timeout {
Vadim Yanitskiyde8af3d2019-06-12 01:34:05 +0700103 setverdict(fail, "Timeout waiting for L1CTL_CCCH_MODE_CONF");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200104 mtc.stop;
Harald Welte8fe9eba2018-03-09 17:03:49 +0100105 }
Harald Welte9e4725d2017-07-16 23:18:09 +0200106 }
107 }
108
Vadim Yanitskiy52787bf2020-10-19 17:34:52 +0700109 function f_L1CTL_TCH_MODE(L1CTL_PT pt, L1ctlTchMode tch_mode) {
110 timer T := 2.0;
111 pt.send(ts_L1CTL_TCH_MODE_REQ(tch_mode));
112 T.start;
113 alt {
114 [] pt.receive(tr_L1CTL_MsgType(L1CTL_TCH_MODE_CONF)) { }
115 [] pt.receive { repeat; }
116 [] T.timeout {
117 setverdict(fail, "Timeout waiting for L1CTL_TCH_MODE_CONF");
118 mtc.stop;
119 }
120 }
121 }
122
Vadim Yanitskiye432ba92019-05-31 18:44:13 +0700123 function f_L1CTL_RACH(L1CTL_PT pt, uint8_t ra, uint8_t combined := 1, uint16_t offset := 0,
124 template (value) RslChannelNr chan_nr := ts_RslChanNr_RACH(0),
125 template (value) RslLinkId link_id := ts_RslLinkID_DCCH(0))
126 return GsmFrameNumber {
Harald Welte9e4725d2017-07-16 23:18:09 +0200127 var L1ctlDlMessage rc;
128 var GsmFrameNumber fn;
129 timer T := 2.0;
130 T.start
Vadim Yanitskiye432ba92019-05-31 18:44:13 +0700131 pt.send(ts_L1CTL_RACH_REQ(ra, combined, offset, chan_nr, link_id))
Harald Welte9e4725d2017-07-16 23:18:09 +0200132 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700133 [] pt.receive(tr_L1CTL_RACH_CONF) -> value rc { fn := rc.dl_info.frame_nr };
134 [] pt.receive { repeat; };
135 [] T.timeout {
136 setverdict(fail, "Timeout waiting for L1CTL_RACH_CONF");
137 mtc.stop;
138 }
Harald Welte9e4725d2017-07-16 23:18:09 +0200139 }
140 return fn;
141 }
142
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +0700143 function f_L1CTL_EXT_RACH(
144 L1CTL_PT pt, uint16_t ra11, L1ctlRachSynchSeq seq,
145 uint8_t combined := 1, uint16_t offset := 0
146 ) return GsmFrameNumber {
147 var L1ctlDlMessage rc;
148 var GsmFrameNumber fn;
149 timer T := 2.0;
150
151 T.start;
152 pt.send(ts_L1CTL_EXT_RACH_REQ(ra11, seq, combined, offset));
153 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700154 [] pt.receive(tr_L1CTL_RACH_CONF) -> value rc { fn := rc.dl_info.frame_nr };
155 [] pt.receive { repeat; };
156 [] T.timeout {
157 setverdict(fail, "Timeout waiting for (extended) L1CTL_RACH_CONF");
158 mtc.stop;
159 }
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +0700160 }
161
162 return fn;
163 }
164
Harald Welte37052732018-03-09 19:38:46 +0100165 function f_L1CTL_PARAM(L1CTL_PT pt, uint8_t ta, uint8_t tx_power) {
Harald Weltef8df4cb2018-03-10 15:15:08 +0100166 pt.send(ts_L1CTL_PAR_REQ(ta, tx_power));
Harald Welte37052732018-03-09 19:38:46 +0100167 }
168
Harald Welte9e4725d2017-07-16 23:18:09 +0200169 function f_L1CTL_WAIT_IMM_ASS(L1CTL_PT pt, uint8_t ra, GsmFrameNumber rach_fn) return ImmediateAssignment {
Vadim Yanitskiy23b74402019-09-09 16:43:29 +0200170 var template GsmRrMessage rr_imm_ass;
Harald Welte9e4725d2017-07-16 23:18:09 +0200171 var L1ctlDlMessage dl;
172 var GsmRrMessage rr;
173 timer T := 10.0;
Vadim Yanitskiy23b74402019-09-09 16:43:29 +0200174
175 /* Prepare generic template (for both CS and PS) */
176 rr_imm_ass := tr_IMM_ASS(ra, rach_fn);
177 rr_imm_ass.payload.imm_ass.ded_or_tbf := ?;
178 rr_imm_ass.payload.imm_ass.pkt_chan_desc := *;
179 rr_imm_ass.payload.imm_ass.chan_desc := *;
180
Harald Welte9e4725d2017-07-16 23:18:09 +0200181 T.start;
182 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700183 [] pt.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
184 rr := dec_GsmRrMessage(dl.payload.data_ind.payload);
185 log("PCH/AGCH DL RR: ", rr);
186 if (match(rr, rr_imm_ass)) {
187 log("Received IMM.ASS for our RACH!");
188 } else {
189 repeat;
190 }
191 };
192 [] pt.receive { repeat };
193 [] T.timeout {
194 setverdict(fail, "Timeout waiting for IMM ASS");
195 mtc.stop;
196 }
Harald Welte9e4725d2017-07-16 23:18:09 +0200197 }
198 T.stop;
199 return rr.payload.imm_ass;
200 }
201
Harald Welteb669ee02018-03-09 12:50:02 +0100202 function f_L1CTL_WAIT_IMM_ASS_TBF_DL(L1CTL_PT pt, GprsTlli tlli) return ImmediateAssignment {
Vadim Yanitskiy6edd4f52019-09-09 01:51:09 +0200203 var template PacketDlAssign dl_ass := tr_PacketDlAssign(tlli);
204 var template IaRestOctets rest := tr_IaRestOctets_DLAss(dl_ass);
Harald Welteb669ee02018-03-09 12:50:02 +0100205 var L1ctlDlMessage dl;
206 var GsmRrMessage rr;
207 timer T := 10.0;
208 T.start;
209 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700210 [] pt.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
211 /* TODO: use decmatch tr_IaRestOctets_DLAss(...) instead */
212 rr := dec_GsmRrMessage(dl.payload.data_ind.payload);
213 log("PCH/AGCN DL RR: ", rr);
214 if (match(rr, tr_IMM_TBF_ASS(dl := true, rest := rest))) {
215 log("Received IMM.ASS for our TLLI!");
216 } else {
217 repeat;
218 }
219 };
220 [] pt.receive { repeat };
221 [] T.timeout {
222 setverdict(fail, "Timeout waiting for TBF IMM ASS");
223 mtc.stop;
224 }
Harald Welteb669ee02018-03-09 12:50:02 +0100225 }
226 T.stop;
227 return rr.payload.imm_ass;
228 }
229
Harald Welteb3c226e2017-07-30 17:18:01 +0200230 function f_L1CTL_TBF_CFG(L1CTL_PT pt, boolean is_uplink, TfiUsfArr tfi_usf) {
231 timer T := 2.0;
232 T.start;
Harald Weltef8df4cb2018-03-10 15:15:08 +0100233 pt.send(ts_L1CTL_TBF_CFG_REQ(is_uplink, tfi_usf));
Harald Welteb3c226e2017-07-30 17:18:01 +0200234 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700235 [] pt.receive(tr_L1CTL_TBF_CFG_CONF(is_uplink)) {}
236 [] pt.receive { repeat };
237 [] T.timeout {
238 setverdict(fail, "Timeout waiting for L1CTL_TBF_CFG_CONF");
239 mtc.stop;
240 };
Harald Welteb3c226e2017-07-30 17:18:01 +0200241 }
242 T.stop;
243 }
244
Harald Welte9e4725d2017-07-16 23:18:09 +0200245 /* Send DM_EST_REQ from parameters derived from IMM ASS */
Vadim Yanitskiy204d1b82020-05-27 19:40:01 +0700246 function f_L1CTL_DM_EST_REQ_IA(L1CTL_PT pt, ImmediateAssignment imm_ass, L1ctlMA ma := {}) {
247 /* FIXME: handle Packet Channel Description */
248 if (imm_ass.ded_or_tbf.tbf == true) {
249 setverdict(fail, "TBF assignment is not handled by ", __SCOPE__);
250 mtc.stop;
251 }
252
253 /* Single channel or frequency hopping? */
254 if (not imm_ass.chan_desc.h) {
255 pt.send(ts_L1CTL_DM_EST_REQ_H0(imm_ass.chan_desc.chan_nr,
256 imm_ass.chan_desc.tsc,
257 imm_ass.chan_desc.arfcn));
258 } else {
259 /* TODO: we probably want to apply a bitmask from imm_ass.mobile_allocation
260 * on the list of channels, if it's present. Use all channels for now. */
261 pt.send(ts_L1CTL_DM_EST_REQ_H1(imm_ass.chan_desc.chan_nr,
262 imm_ass.chan_desc.tsc,
263 imm_ass.chan_desc.maio_hsn.hsn,
264 imm_ass.chan_desc.maio_hsn.maio,
265 ma));
266 }
Harald Welte9e4725d2017-07-16 23:18:09 +0200267 }
268
Harald Welte3dc20462018-03-10 23:03:38 +0100269 /* Send DM_REL_REQ from parameters derived from IMM ASS */
270 function f_L1CTL_DM_REL_REQ(L1CTL_PT pt, RslChannelNr chan_nr) {
271 pt.send(ts_L1CTL_DM_REL_REQ(chan_nr));
272 }
273
Harald Welteaca6e072018-03-10 17:15:38 +0100274 function f_L1CTL_RESET(L1CTL_PT pt, L1ctlResetType res_type := L1CTL_RES_T_FULL) {
275 timer T := 2.0;
276 pt.send(t_L1ctlResetReq(res_type));
277 T.start;
278 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700279 [] pt.receive(tr_L1CTL_MsgType(L1CTL_RESET_CONF)) { }
280 [] pt.receive { repeat; }
281 [] T.timeout {
282 setverdict(fail, "Timeout waiting for L1CTL_RESET_CONF");
283 mtc.stop;
284 }
Harald Welteaca6e072018-03-10 17:15:38 +0100285 }
Harald Weltee613f962018-04-18 22:38:16 +0200286 }
Harald Welteaca6e072018-03-10 17:15:38 +0100287
Harald Weltee613f962018-04-18 22:38:16 +0200288 function f_L1CTL_CRYPTO_REQ(L1CTL_PT pt, RslChannelNr chan_nr, uint8_t algo, octetstring key) {
289 pt.send(ts_L1CTL_CRYPTO_REQ(chan_nr, algo, key));
Harald Welteaca6e072018-03-10 17:15:38 +0100290 }
291
Harald Weltef68765d2017-08-20 22:54:57 +0200292 function f_connect_reset(L1CTL_PT pt, charstring l1ctl_sock_path := m_l1ctl_sock_path) {
Harald Welte6fc784e2018-02-25 23:31:37 +0100293 var f_UD_getMsgLen vl_f := refers(f_L1CTL_getMsgLen);
294 f_L1CTL_setGetMsgLen(pt, -1, vl_f, {});
Harald Welted1209a62017-07-29 12:55:06 +0200295 pt.send(L1CTL_connect:{path:=l1ctl_sock_path});
296 pt.receive(L1CTL_connect_result:{result_code := SUCCESS, err:=omit});
Harald Welte6fc784e2018-02-25 23:31:37 +0100297 f_L1CTL_setGetMsgLen(pt, 0, vl_f, {});
Harald Welteaca6e072018-03-10 17:15:38 +0100298 f_L1CTL_RESET(pt);
Harald Welted1209a62017-07-29 12:55:06 +0200299 }
Harald Welte9e4725d2017-07-16 23:18:09 +0200300
Harald Welte52c713c2017-07-16 15:44:44 +0200301 private function L1CTL_to_UD_connect(in L1CTL_connect pin, out UD_connect pout) {
302 pout.path := pin.path;
303 pout.id := 0;
304 } with { extension "prototype(fast)" }
305
306 private function UD_to_L1CTL_connect_result(in UD_connect_result pin, out L1CTL_connect_result pout) {
307 pout.result_code := pin.result.result_code;
308 pout.err := pin.result.err;
309 } with { extension "prototype(fast)" }
310
311 private function L1CTL_to_UD_ul(in L1ctlUlMessage pin, out UD_send_data pout) {
312 var L1ctlUlMessageLV msg_lv := { msg := pin };
313 pout.data := enc_L1ctlUlMessageLV(msg_lv);
314 pout.id := 0;
315 } with { extension "prototype(fast)" }
316
317 private function UD_to_L1CTL_dl(in UD_send_data pin, out L1ctlDlMessage pout) {
318 var L1ctlDlMessageLV msg_lv := dec_L1ctlDlMessageLV(pin.data);
319 pout:= msg_lv.msg;
320 } with { extension "prototype(fast)" }
321
322 type port L1CTL_PT message {
323 out L1ctlUlMessage
324 out L1CTL_connect
325 in L1ctlDlMessage
326 in L1CTL_connect_result
327 in UD_listen_result
328 in UD_connected
329 } with { extension "user UD_PT
330 out(L1ctlUlMessage -> UD_send_data: function(L1CTL_to_UD_ul);
331 L1CTL_connect -> UD_connect: function(L1CTL_to_UD_connect))
332 in(UD_send_data -> L1ctlDlMessage: function(UD_to_L1CTL_dl);
333 UD_connect_result -> L1CTL_connect_result: function(UD_to_L1CTL_connect_result);
334 UD_listen_result -> UD_listen_result: simple;
335 UD_connected -> UD_connected: simple
336 )" }
337}