blob: 5c554c2b67b71d4a7202f69df99d32c024d7defa [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;
15 import from UD_Types all;
Harald Welte9e4725d2017-07-16 23:18:09 +020016 import from Osmocom_Types all;
Harald Weltee613f962018-04-18 22:38:16 +020017 import from Osmocom_Types all;
Harald Welte9e4725d2017-07-16 23:18:09 +020018 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 Welte6fc784e2018-02-25 23:31:37 +010035 function f_L1CTL_getMsgLen(in octetstring stream, inout ro_integer args) return integer {
36 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 Yanitskiy1acc7bb2020-11-14 04:24:57 +070045 function f_L1CTL_FBSB(L1CTL_PT pt, GsmBandArfcn arfcn,
46 L1ctlCcchMode ccch_mode := CCCH_MODE_COMBINED,
47 integer rxlev_exp := 57)
48 {
Harald Welte3757e602018-03-10 17:12:02 +010049 timer T := 15.0;
Harald Welte8fe9eba2018-03-09 17:03:49 +010050 for (var integer i := 0; i < 10; i := i+1) {
Stefan Sperling02585902018-08-30 17:03:50 +020051 var L1ctlDlMessage dl;
Pau Espin Pedrol752ffd52018-06-07 13:55:45 +020052 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 +010053 T.start
54 alt {
Harald Weltef8df4cb2018-03-10 15:15:08 +010055 [] pt.receive(tr_L1CTL_FBSB_CONF(0)) { return; };
Stefan Sperling02585902018-08-30 17:03:50 +020056 [i >= 9] pt.receive(tr_L1CTL_FBSB_CONF(?)) -> value dl {
57 setverdict(fail, "FBSB Failed with non-zero return code ", dl.payload.fbsb_conf.result);
Daniel Willmanne4ff5372018-07-05 17:35:03 +020058 mtc.stop;
Harald Welte7d7d26c2018-02-22 18:52:28 +010059 };
Harald Weltef8df4cb2018-03-10 15:15:08 +010060 [] pt.receive(tr_L1CTL_FBSB_CONF(?)) {
Harald Welte3757e602018-03-10 17:12:02 +010061 f_sleep(1.0);
Harald Weltef8df4cb2018-03-10 15:15:08 +010062 }
Harald Welte9e4725d2017-07-16 23:18:09 +020063 [] pt.receive { repeat; };
Harald Welte3757e602018-03-10 17:12:02 +010064 [] T.timeout {
Vadim Yanitskiyde8af3d2019-06-12 01:34:05 +070065 setverdict(fail, "Timeout waiting for L1CTL_FBSB_CONF");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020066 mtc.stop;
Harald Welte3757e602018-03-10 17:12:02 +010067 };
68 }
69 }
70 }
71
72 function f_L1CTL_CCCH_MODE(L1CTL_PT pt, L1ctlCcchMode ccch_mode) {
73 timer T := 2.0;
74 pt.send(ts_L1CTL_CCCH_MODE_REQ(ccch_mode));
75 T.start;
76 alt {
77 [] pt.receive(tr_L1CTL_CCCH_MODE_CONF) { }
78 [] pt.receive { repeat; }
79 [] T.timeout {
Vadim Yanitskiyde8af3d2019-06-12 01:34:05 +070080 setverdict(fail, "Timeout waiting for L1CTL_CCCH_MODE_CONF");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020081 mtc.stop;
Harald Welte8fe9eba2018-03-09 17:03:49 +010082 }
Harald Welte9e4725d2017-07-16 23:18:09 +020083 }
84 }
85
Vadim Yanitskiy52787bf2020-10-19 17:34:52 +070086 function f_L1CTL_TCH_MODE(L1CTL_PT pt, L1ctlTchMode tch_mode) {
87 timer T := 2.0;
88 pt.send(ts_L1CTL_TCH_MODE_REQ(tch_mode));
89 T.start;
90 alt {
91 [] pt.receive(tr_L1CTL_MsgType(L1CTL_TCH_MODE_CONF)) { }
92 [] pt.receive { repeat; }
93 [] T.timeout {
94 setverdict(fail, "Timeout waiting for L1CTL_TCH_MODE_CONF");
95 mtc.stop;
96 }
97 }
98 }
99
Vadim Yanitskiye432ba92019-05-31 18:44:13 +0700100 function f_L1CTL_RACH(L1CTL_PT pt, uint8_t ra, uint8_t combined := 1, uint16_t offset := 0,
101 template (value) RslChannelNr chan_nr := ts_RslChanNr_RACH(0),
102 template (value) RslLinkId link_id := ts_RslLinkID_DCCH(0))
103 return GsmFrameNumber {
Harald Welte9e4725d2017-07-16 23:18:09 +0200104 var L1ctlDlMessage rc;
105 var GsmFrameNumber fn;
106 timer T := 2.0;
107 T.start
Vadim Yanitskiye432ba92019-05-31 18:44:13 +0700108 pt.send(ts_L1CTL_RACH_REQ(ra, combined, offset, chan_nr, link_id))
Harald Welte9e4725d2017-07-16 23:18:09 +0200109 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700110 [] pt.receive(tr_L1CTL_RACH_CONF) -> value rc { fn := rc.dl_info.frame_nr };
111 [] pt.receive { repeat; };
112 [] T.timeout {
113 setverdict(fail, "Timeout waiting for L1CTL_RACH_CONF");
114 mtc.stop;
115 }
Harald Welte9e4725d2017-07-16 23:18:09 +0200116 }
117 return fn;
118 }
119
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +0700120 function f_L1CTL_EXT_RACH(
121 L1CTL_PT pt, uint16_t ra11, L1ctlRachSynchSeq seq,
122 uint8_t combined := 1, uint16_t offset := 0
123 ) return GsmFrameNumber {
124 var L1ctlDlMessage rc;
125 var GsmFrameNumber fn;
126 timer T := 2.0;
127
128 T.start;
129 pt.send(ts_L1CTL_EXT_RACH_REQ(ra11, seq, combined, offset));
130 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700131 [] pt.receive(tr_L1CTL_RACH_CONF) -> value rc { fn := rc.dl_info.frame_nr };
132 [] pt.receive { repeat; };
133 [] T.timeout {
134 setverdict(fail, "Timeout waiting for (extended) L1CTL_RACH_CONF");
135 mtc.stop;
136 }
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +0700137 }
138
139 return fn;
140 }
141
Harald Welte37052732018-03-09 19:38:46 +0100142 function f_L1CTL_PARAM(L1CTL_PT pt, uint8_t ta, uint8_t tx_power) {
Harald Weltef8df4cb2018-03-10 15:15:08 +0100143 pt.send(ts_L1CTL_PAR_REQ(ta, tx_power));
Harald Welte37052732018-03-09 19:38:46 +0100144 }
145
Harald Welte9e4725d2017-07-16 23:18:09 +0200146 function f_L1CTL_WAIT_IMM_ASS(L1CTL_PT pt, uint8_t ra, GsmFrameNumber rach_fn) return ImmediateAssignment {
Vadim Yanitskiy23b74402019-09-09 16:43:29 +0200147 var template GsmRrMessage rr_imm_ass;
Harald Welte9e4725d2017-07-16 23:18:09 +0200148 var L1ctlDlMessage dl;
149 var GsmRrMessage rr;
150 timer T := 10.0;
Vadim Yanitskiy23b74402019-09-09 16:43:29 +0200151
152 /* Prepare generic template (for both CS and PS) */
153 rr_imm_ass := tr_IMM_ASS(ra, rach_fn);
154 rr_imm_ass.payload.imm_ass.ded_or_tbf := ?;
155 rr_imm_ass.payload.imm_ass.pkt_chan_desc := *;
156 rr_imm_ass.payload.imm_ass.chan_desc := *;
157
Harald Welte9e4725d2017-07-16 23:18:09 +0200158 T.start;
159 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700160 [] pt.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
161 rr := dec_GsmRrMessage(dl.payload.data_ind.payload);
162 log("PCH/AGCH DL RR: ", rr);
163 if (match(rr, rr_imm_ass)) {
164 log("Received IMM.ASS for our RACH!");
165 } else {
166 repeat;
167 }
168 };
169 [] pt.receive { repeat };
170 [] T.timeout {
171 setverdict(fail, "Timeout waiting for IMM ASS");
172 mtc.stop;
173 }
Harald Welte9e4725d2017-07-16 23:18:09 +0200174 }
175 T.stop;
176 return rr.payload.imm_ass;
177 }
178
Harald Welteb669ee02018-03-09 12:50:02 +0100179 function f_L1CTL_WAIT_IMM_ASS_TBF_DL(L1CTL_PT pt, GprsTlli tlli) return ImmediateAssignment {
Vadim Yanitskiy6edd4f52019-09-09 01:51:09 +0200180 var template PacketDlAssign dl_ass := tr_PacketDlAssign(tlli);
181 var template IaRestOctets rest := tr_IaRestOctets_DLAss(dl_ass);
Harald Welteb669ee02018-03-09 12:50:02 +0100182 var L1ctlDlMessage dl;
183 var GsmRrMessage rr;
184 timer T := 10.0;
185 T.start;
186 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700187 [] pt.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
188 /* TODO: use decmatch tr_IaRestOctets_DLAss(...) instead */
189 rr := dec_GsmRrMessage(dl.payload.data_ind.payload);
190 log("PCH/AGCN DL RR: ", rr);
191 if (match(rr, tr_IMM_TBF_ASS(dl := true, rest := rest))) {
192 log("Received IMM.ASS for our TLLI!");
193 } else {
194 repeat;
195 }
196 };
197 [] pt.receive { repeat };
198 [] T.timeout {
199 setverdict(fail, "Timeout waiting for TBF IMM ASS");
200 mtc.stop;
201 }
Harald Welteb669ee02018-03-09 12:50:02 +0100202 }
203 T.stop;
204 return rr.payload.imm_ass;
205 }
206
Harald Welteb3c226e2017-07-30 17:18:01 +0200207 function f_L1CTL_TBF_CFG(L1CTL_PT pt, boolean is_uplink, TfiUsfArr tfi_usf) {
208 timer T := 2.0;
209 T.start;
Harald Weltef8df4cb2018-03-10 15:15:08 +0100210 pt.send(ts_L1CTL_TBF_CFG_REQ(is_uplink, tfi_usf));
Harald Welteb3c226e2017-07-30 17:18:01 +0200211 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700212 [] pt.receive(tr_L1CTL_TBF_CFG_CONF(is_uplink)) {}
213 [] pt.receive { repeat };
214 [] T.timeout {
215 setverdict(fail, "Timeout waiting for L1CTL_TBF_CFG_CONF");
216 mtc.stop;
217 };
Harald Welteb3c226e2017-07-30 17:18:01 +0200218 }
219 T.stop;
220 }
221
Harald Welte9e4725d2017-07-16 23:18:09 +0200222 /* Send DM_EST_REQ from parameters derived from IMM ASS */
Vadim Yanitskiy204d1b82020-05-27 19:40:01 +0700223 function f_L1CTL_DM_EST_REQ_IA(L1CTL_PT pt, ImmediateAssignment imm_ass, L1ctlMA ma := {}) {
224 /* FIXME: handle Packet Channel Description */
225 if (imm_ass.ded_or_tbf.tbf == true) {
226 setverdict(fail, "TBF assignment is not handled by ", __SCOPE__);
227 mtc.stop;
228 }
229
230 /* Single channel or frequency hopping? */
231 if (not imm_ass.chan_desc.h) {
232 pt.send(ts_L1CTL_DM_EST_REQ_H0(imm_ass.chan_desc.chan_nr,
233 imm_ass.chan_desc.tsc,
234 imm_ass.chan_desc.arfcn));
235 } else {
236 /* TODO: we probably want to apply a bitmask from imm_ass.mobile_allocation
237 * on the list of channels, if it's present. Use all channels for now. */
238 pt.send(ts_L1CTL_DM_EST_REQ_H1(imm_ass.chan_desc.chan_nr,
239 imm_ass.chan_desc.tsc,
240 imm_ass.chan_desc.maio_hsn.hsn,
241 imm_ass.chan_desc.maio_hsn.maio,
242 ma));
243 }
Harald Welte9e4725d2017-07-16 23:18:09 +0200244 }
245
Harald Welte3dc20462018-03-10 23:03:38 +0100246 /* Send DM_REL_REQ from parameters derived from IMM ASS */
247 function f_L1CTL_DM_REL_REQ(L1CTL_PT pt, RslChannelNr chan_nr) {
248 pt.send(ts_L1CTL_DM_REL_REQ(chan_nr));
249 }
250
Harald Welteaca6e072018-03-10 17:15:38 +0100251 function f_L1CTL_RESET(L1CTL_PT pt, L1ctlResetType res_type := L1CTL_RES_T_FULL) {
252 timer T := 2.0;
253 pt.send(t_L1ctlResetReq(res_type));
254 T.start;
255 alt {
Vadim Yanitskiye7c4a992020-10-19 13:10:23 +0700256 [] pt.receive(tr_L1CTL_MsgType(L1CTL_RESET_CONF)) { }
257 [] pt.receive { repeat; }
258 [] T.timeout {
259 setverdict(fail, "Timeout waiting for L1CTL_RESET_CONF");
260 mtc.stop;
261 }
Harald Welteaca6e072018-03-10 17:15:38 +0100262 }
Harald Weltee613f962018-04-18 22:38:16 +0200263 }
Harald Welteaca6e072018-03-10 17:15:38 +0100264
Harald Weltee613f962018-04-18 22:38:16 +0200265 function f_L1CTL_CRYPTO_REQ(L1CTL_PT pt, RslChannelNr chan_nr, uint8_t algo, octetstring key) {
266 pt.send(ts_L1CTL_CRYPTO_REQ(chan_nr, algo, key));
Harald Welteaca6e072018-03-10 17:15:38 +0100267 }
268
Harald Weltef68765d2017-08-20 22:54:57 +0200269 function f_connect_reset(L1CTL_PT pt, charstring l1ctl_sock_path := m_l1ctl_sock_path) {
Harald Welte6fc784e2018-02-25 23:31:37 +0100270 var f_UD_getMsgLen vl_f := refers(f_L1CTL_getMsgLen);
271 f_L1CTL_setGetMsgLen(pt, -1, vl_f, {});
Harald Welted1209a62017-07-29 12:55:06 +0200272 pt.send(L1CTL_connect:{path:=l1ctl_sock_path});
273 pt.receive(L1CTL_connect_result:{result_code := SUCCESS, err:=omit});
Harald Welte6fc784e2018-02-25 23:31:37 +0100274 f_L1CTL_setGetMsgLen(pt, 0, vl_f, {});
Harald Welteaca6e072018-03-10 17:15:38 +0100275 f_L1CTL_RESET(pt);
Harald Welted1209a62017-07-29 12:55:06 +0200276 }
Harald Welte9e4725d2017-07-16 23:18:09 +0200277
Harald Welte52c713c2017-07-16 15:44:44 +0200278 private function L1CTL_to_UD_connect(in L1CTL_connect pin, out UD_connect pout) {
279 pout.path := pin.path;
280 pout.id := 0;
281 } with { extension "prototype(fast)" }
282
283 private function UD_to_L1CTL_connect_result(in UD_connect_result pin, out L1CTL_connect_result pout) {
284 pout.result_code := pin.result.result_code;
285 pout.err := pin.result.err;
286 } with { extension "prototype(fast)" }
287
288 private function L1CTL_to_UD_ul(in L1ctlUlMessage pin, out UD_send_data pout) {
289 var L1ctlUlMessageLV msg_lv := { msg := pin };
290 pout.data := enc_L1ctlUlMessageLV(msg_lv);
291 pout.id := 0;
292 } with { extension "prototype(fast)" }
293
294 private function UD_to_L1CTL_dl(in UD_send_data pin, out L1ctlDlMessage pout) {
295 var L1ctlDlMessageLV msg_lv := dec_L1ctlDlMessageLV(pin.data);
296 pout:= msg_lv.msg;
297 } with { extension "prototype(fast)" }
298
299 type port L1CTL_PT message {
300 out L1ctlUlMessage
301 out L1CTL_connect
302 in L1ctlDlMessage
303 in L1CTL_connect_result
304 in UD_listen_result
305 in UD_connected
306 } with { extension "user UD_PT
307 out(L1ctlUlMessage -> UD_send_data: function(L1CTL_to_UD_ul);
308 L1CTL_connect -> UD_connect: function(L1CTL_to_UD_connect))
309 in(UD_send_data -> L1ctlDlMessage: function(UD_to_L1CTL_dl);
310 UD_connect_result -> L1CTL_connect_result: function(UD_to_L1CTL_connect_result);
311 UD_listen_result -> UD_listen_result: simple;
312 UD_connected -> UD_connected: simple
313 )" }
314}