blob: a42ca1eae5dab24c217848be23fdd2e749458dbf [file] [log] [blame]
Harald Welte714ded92017-12-08 14:00:22 +01001module RSL_Emulation {
2
3import from General_Types all;
4import from Osmocom_Types all;
5import from GSM_Types all;
6import from GSM_RR_Types all;
7import from RSL_Types all;
8import from IPA_Types all;
9import from IPA_Emulation all;
10
11
12/* General "base class" component definition, of which specific implementations
13 * derive themselves by means of the "extends" feature */
14type component RSL_DchanHdlr {
15 /* port facing up towards dedicated channel handler */
16 port RSL_DCHAN_PT RSL;
17 var RslChannelNr g_chan_nr;
18};
19
20type record RSLDC_ChanRqd {
21 OCT1 ra,
22 GsmFrameNumber fn
23};
24
25template RSLDC_ChanRqd ts_RSLDC_ChanRqd(OCT1 ra, GsmFrameNumber fn) := {
26 ra := ra,
27 fn := fn
28}
29
30type port RSL_DCHAN_PT message {
31 inout RSLDC_ChanRqd, RSL_Message;
32} with { extension "internal" };
33
34/***********************************************************************
35 * Client Component for a single dedicated channel
36 ***********************************************************************/
37
38private function f_rx_or_fail(template RSL_Message exp_rx) runs on RSL_DchanHdlr return RSL_Message
39{
40 var RSL_Message rx_rsl;
41 timer T := 10.0;
42
43 /* request a channel to be established */
44 T.start;
45 alt {
46 [] RSL.receive(exp_rx) -> value rx_rsl {
47 T.stop;
48 return rx_rsl;
49 }
50 [] RSL.receive {
51 setverdict(fail, "Unexpected RSL message on DCHAN");
52 self.stop;
53 }
54 [] T.timeout {
55 setverdict(fail, "Timeout waiting for RSL on DCHAN");
56 self.stop;
57 }
58 }
59 /* never reached */
60 return rx_rsl;
61}
62
63/* establish a dedicated channel using 'ra' */
64function f_chan_est(OCT1 ra, octetstring est_l3, template RslLinkId link_id, GsmFrameNumber fn := 23)
65runs on RSL_DchanHdlr {
66 var RSL_Message rx_rsl;
67 var GsmRrMessage rr;
68
69 /* request a channel to be established */
70 RSL.send(ts_RSLDC_ChanRqd(ra, fn));
71 /* expect immediate assignment */
72 rx_rsl := f_rx_or_fail(tr_RSL_IMM_ASSIGN);
73 rr := dec_GsmRrMessage(rx_rsl.ies[1].body.full_imm_ass_info.payload);
74 g_chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
75 RSL.send(ts_RSL_EST_IND(g_chan_nr, valueof(link_id), est_l3));
76}
77
78function f_deact_chan(RSL_Cause cause) runs on RSL_DchanHdlr
79{
80 var RSL_Message rx_rsl;
81
82 RSL.send(ts_RSL_CONN_FAIL_IND(g_chan_nr, cause));
83 rx_rsl := f_rx_or_fail(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL));
84 /* FIXME RSL.send(ts_RSL_RF_CHAN_REL_ACK()) */
85}
86
87
88
89/***********************************************************************
90 * Main Component
91 ***********************************************************************/
92
93private type record ConnectionData {
94 /* component reference to the client component */
95 RSL_DchanHdlr comp_ref,
96 /* RSL (dedicated) Channel number we're handling */
97 uint8_t trx_nr optional,
98 IpaStreamId stream_id optional,
99 RslChannelNr chan_nr optional,
100 /* Random Reference */
101 OCT1 ra optional,
102 GsmFrameNumber ra_fn optional
103};
104
105private function f_cid_by_comp_ref(RSL_DchanHdlr comp_ref)
106runs on RSL_Emulation_CT return integer {
107 var integer i;
108 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
109 if (ispresent(ConnectionTable[i].comp_ref) and
110 ConnectionTable[i].comp_ref == comp_ref) {
111 return i;
112 }
113 }
114 log("No Dchan handler for ", comp_ref);
115 return -1;
116}
117
118private function f_cid_by_chan_nr(uint8_t trx_nr, RslChannelNr chan_nr)
119runs on RSL_Emulation_CT return integer {
120 var integer i;
121 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
122 if (ispresent(ConnectionTable[i].chan_nr) and
123 ConnectionTable[i].chan_nr == chan_nr and ConnectionTable[i].trx_nr == trx_nr) {
124 return i;
125 }
126 }
127 log("No Dchan handler for ", trx_nr, chan_nr);
128 return -1;
129}
130
131private function f_cid_by_ra_fn(OCT1 ra, GsmFrameNumber fn)
132runs on RSL_Emulation_CT return integer {
133 var integer i;
134 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
135 if (ispresent(ConnectionTable[i].ra) and
136 ConnectionTable[i].ra == ra and ConnectionTable[i].ra_fn == fn) {
137 return i;
138 }
139 }
140 log("No Dchan handler for ", ra, fn);
141 return -1;
142}
143
144/* create an ew client with given RA and FN */
145private function f_cid_create(OCT1 ra, GsmFrameNumber fn, RSL_DchanHdlr comp_ref)
146runs on RSL_Emulation_CT return integer {
147 var integer i;
148 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
149 if (not ispresent(ConnectionTable[i].ra)) {
150 ConnectionTable[i].ra := ra;
151 ConnectionTable[i].ra_fn := fn;
152 ConnectionTable[i].comp_ref := comp_ref;
153 return i;
154 }
155 }
156 log("No free entry in conn table for ", ra, fn);
157 return -1;
158}
159
160private function f_cid_clear(integer cid)
161runs on RSL_Emulation_CT {
162 ConnectionTable[cid].ra := omit;
163 ConnectionTable[cid].ra_fn := omit;
164 ConnectionTable[cid].ra_fn := omit;
165 ConnectionTable[cid].trx_nr := omit;
166 ConnectionTable[cid].stream_id := omit;
167 ConnectionTable[cid].chan_nr := omit;
168}
169
170type component RSL_Emulation_CT {
171 /* port facing down towards IPA emulation */
172 port IPA_RSL_PT IPA_PT;
173 /* port facing up towards dedicated channel handler */
174 port RSL_DCHAN_PT CLIENT_PT;
175
176 /* state of all concurrent connections / dedicated channels */
177 var ConnectionData ConnectionTable[64];
178}
179
180
181/* template for an ASP_RSL_Unitdata as we receive it from the IPA_Emulateion component */
182private template ASP_RSL_Unitdata tr_RSL(template RSL_Message rsl, template IpaStreamId sid := ?) := {
183 streamId := sid,
184 rsl := rsl
185}
186
Harald Welte714ded92017-12-08 14:00:22 +0100187private function f_trx_by_streamId(IpaStreamId id) return integer {
188 return enum2int(id);
189}
190
191
192function main() runs on RSL_Emulation_CT {
193 var ASP_RSL_Unitdata rx_rsl;
194 var RSL_Message rx_rsl_msg;
195 var RSLDC_ChanRqd chan_rqd;
196 var RSL_DchanHdlr vc_conn;
197 var integer cid;
198 var integer i;
199
200 while (true) {
201 alt {
Harald Welte624f9632017-12-16 19:26:04 +0100202 [] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) {
203 }
Harald Welte714ded92017-12-08 14:00:22 +0100204 [] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) {
Harald Welte7ae019e2017-12-09 00:54:15 +0100205 IPA_PT.send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,ts_RSL_PAGING_LOAD_IND(23)));
Harald Welte714ded92017-12-08 14:00:22 +0100206 }
207 [] IPA_PT.receive(tr_RSL(tr_RSL_IMM_ASSIGN)) -> value rx_rsl {
208 var GsmRrMessage rr;
209 var OCT1 ra;
210 var GsmFrameNumber fn;
211 log("IMM ASS INFO ", rx_rsl.rsl.ies[1].body);
212 rr := dec_GsmRrMessage(rx_rsl.rsl.ies[1].body.full_imm_ass_info.payload);
213 if (ischosen(rr.payload.imm_ass)) {
214 ra := bit2oct(rr.payload.imm_ass.req_ref.ra);
215 fn := 23; //FIXME(rr.payload.imm_ass);
216 /* lookup client based on RA+time, deliver to client */
217 cid := f_cid_by_ra_fn(ra, fn);
218 if (cid == -1) {
219 setverdict(fail, "IMM ASS for unknown DChan");
220 }
221 /* update client with trx_nr */
222 ConnectionTable[cid].trx_nr := f_trx_by_streamId(rx_rsl.streamId);
223 ConnectionTable[cid].stream_id := rx_rsl.streamId;
224 /* update client with chan_nr */
225 ConnectionTable[cid].chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
226 /* TODO: add timer to time-out ConnectionTable entries which
227 * never get followed-up to */
228 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
229 } else if (ischosen(rr.payload.imm_ass_rej)) {
230 for (i := 0; i < sizeof(rr.payload.imm_ass_rej.payload); i := i + 1) {
231 ra := bit2oct(rr.payload.imm_ass_rej.payload[i].req_ref.ra);
232 fn := 23; //FIXME();
233 /* lookup client based on RA+time, deliver to client */
234 cid := f_cid_by_ra_fn(ra, fn);
235 if (cid != -1) {
236 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
237 /* delete ClientTable entry, as it failed */
238 f_cid_clear(cid);
239 }
240 }
241 }
242 }
243
244 [] IPA_PT.receive(tr_RSL(tr_RSL_PAGING_CMD(?, ?))) -> value rx_rsl {
245 log("PAGING IDENTITY ", rx_rsl.rsl.ies[2].body.other);
246 /* broadcast to all clients? */
247 for (i := 0; i < sizeof(ConnectionTable); i := i + 1) {
248 if (ispresent(ConnectionTable[i].comp_ref)) {
249 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[i].comp_ref;
250 }
251 }
252 }
253
254 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeT(?))) -> value rx_rsl {
255 log("Ingnoring TRX Mgmt ", rx_rsl.rsl);
256 }
257
258 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeC(?))) -> value rx_rsl {
259 log("Ignoring Common Channel Mgmt ", rx_rsl.rsl);
260 }
261
262 /* blindly acknowledge all channel activations */
263 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV))) -> value rx_rsl {
264 var RslChannelNr chan_nr := rx_rsl.rsl.ies[0].body.chan_nr;
Harald Welte7ae019e2017-12-09 00:54:15 +0100265 IPA_PT.send(ts_ASP_RSL_UD(rx_rsl.streamId, ts_RSL_CHAN_ACT_ACK(chan_nr, 23)));
Harald Welte714ded92017-12-08 14:00:22 +0100266 }
267
268 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeDR(?))) -> value rx_rsl {
269 /* dispatch to channel based on ChanId */
270 cid := f_cid_by_chan_nr(f_trx_by_streamId(rx_rsl.streamId),
271 rx_rsl.rsl.ies[0].body.chan_nr);
272 if (cid != -1) {
273 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
274 } else {
275 setverdict(fail, "RSL for unknown Dchan");
276 }
277 }
278
279 [] IPA_PT.receive {
280 setverdict(fail, "Received unknown primitive from IPA");
281 self.stop;
282 }
283
284 [] CLIENT_PT.receive(RSLDC_ChanRqd:?) -> value chan_rqd sender vc_conn {
285 /* Store the knowledge that this sender has requested a certain RQ+time */
286 f_cid_create(chan_rqd.ra, chan_rqd.fn, vc_conn);
Harald Welte7ae019e2017-12-09 00:54:15 +0100287 IPA_PT.send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
Harald Welte714ded92017-12-08 14:00:22 +0100288 ts_RSL_CHAN_RQD(chan_rqd.ra, chan_rqd.fn)));
289 }
290
291 [] CLIENT_PT.receive(tr_RSL_MsgType(?)) -> value rx_rsl_msg sender vc_conn {
292 /* forward to BSC */
293 cid := f_cid_by_comp_ref(vc_conn);
Harald Welte7ae019e2017-12-09 00:54:15 +0100294 IPA_PT.send(ts_ASP_RSL_UD(ConnectionTable[cid].stream_id, rx_rsl_msg));
Harald Welte714ded92017-12-08 14:00:22 +0100295 }
296
297 }
298 }
299}
300
301
302}