blob: b41cd25ef370f964574cd108af25d2c9ccb3ebda [file] [log] [blame]
Harald Welte1733a382017-07-23 17:26:17 +02001module BSSGP_Emulation {
Harald Welte1733a382017-07-23 17:26:17 +02002
Harald Welte853c0ad2018-02-15 17:45:29 +01003import from NS_Types all;
4import from NS_Emulation all;
5import from BSSGP_Types all;
6import from Osmocom_Gb_Types all;
7import from IPL4asp_Types all;
Harald Welte1733a382017-07-23 17:26:17 +02008
Harald Welte853c0ad2018-02-15 17:45:29 +01009type record BssgpStatusIndication {
10 Nsei nsei,
11 BssgpBvci bvci,
12 BvcState state
13}
14
15template BssgpStatusIndication t_BssgpStsInd(template Nsei nsei, template BssgpBvci bvci, template BvcState state) := {
16 nsei := nsei,
17 bvci := bvci,
18 state := state
19}
20
21type enumerated BvcState {
22 BVC_S_BLOCKED,
23 BVC_S_UNBLOCKED
24};
25
26/* port from our (internal) point of view */
27type port BSSGP_SP_PT message {
28 in PDU_BSSGP;
29 out PDU_BSSGP,
30 NsStatusIndication,
31 BssgpStatusIndication,
32 ASP_Event;
33} with { extension "internal" };
34
35/* port from the user point of view */
36type port BSSGP_PT message {
37 in ASP_Event,
38 NsStatusIndication,
39 BssgpStatusIndication,
40 PDU_BSSGP;
41 out PDU_BSSGP;
42} with { extension "internal" };
43
44function BssgpStart(boolean sgsn_role := false) runs on BSSGP_CT {
45 g_sgsn_role := sgsn_role
46 f_init();
47 f_ScanEvents();
48}
49
50private function f_init() runs on BSSGP_CT {
51 /* Connect the UDP socket */
52 f_change_state(BVC_S_BLOCKED);
53}
54
55type component BSSGP_CT {
56 /* UDP port towards the bottom (IUT) */
57 port NS_PT BSCP;
58 /* NS-User SAP towards the user */
59 port BSSGP_SP_PT BSSGP_SP;
60
61 var boolean g_sgsn_role := true;
62 var BvcState g_ptp_bvc_state := BVC_S_BLOCKED;
63 timer g_T1 := 15.0;
64 timer g_T2 := 60.0;
65}
66
67modulepar {
68 Nsvci mp_nsei := 96;
69 Nsvci mp_bvci := 196;
70 BssgpCellId mp_cellid := { ra_id := { lai := { mcc_mnc := '26242F'H, lac := 13135}, rac := 0 }, cell_id := 20960 };
71};
72
73function f_BnsUdReq(template PDU_BSSGP pdu, BssgpBvci bvci := mp_bvci) return NsUnitdataRequest {
74 var NsUnitdataRequest udr := {
Harald Welte1733a382017-07-23 17:26:17 +020075 bvci := bvci,
Harald Welte853c0ad2018-02-15 17:45:29 +010076 nsei := mp_nsei,
77 /* for some weird reason we get "Dynamic test case error: Text encoder: Encoding an
78 * unbound integer value." when trying to send the reocrd rather than the octetstring */
79 //sdu := omit,
80 //bssgp := valueof(pdu)
81 sdu := enc_PDU_BSSGP(valueof(pdu)),
82 bssgp := omit
83 }
84 return udr;
85}
86
87function f_BnsUdInd(template PDU_BSSGP pdu, template BssgpBvci bvci := mp_bvci) return template NsUnitdataIndication {
88 var template NsUnitdataIndication udi := {
89 bvci := bvci,
90 nsei := mp_nsei,
91 sdu := *,
92 bssgp := pdu
93 }
94 return udi;
95}
96
97private function f_change_state(BvcState new_state) runs on BSSGP_CT {
98 log("BSSGP State Transition: ", g_ptp_bvc_state, " -> ", new_state);
99 g_ptp_bvc_state := new_state;
100 BSSGP_SP.send(t_BssgpStsInd(mp_nsei, mp_bvci, g_ptp_bvc_state));
101}
102
103private function f_sendReset() runs on BSSGP_CT {
104 var PDU_BSSGP pdu := valueof(ts_BVC_RESET(BSSGP_CAUSE_OM_INTERVENTION, mp_bvci, mp_cellid));
105 log("PDU: ", pdu);
106 log("ENC: ", enc_PDU_BSSGP(pdu));
107
108 /* BVC-RESET is always sent via the SIGNALLING BVCI, see Table 5.4.1 */
109 BSCP.send(f_BnsUdReq(pdu, 0));
110 g_T2.start;
111 //f_change_state(BVC_S_WAIT_RESET);
112}
113
114private function f_sendUnblock() runs on BSSGP_CT {
115 BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK(mp_bvci), 0));
116 g_T1.start;
117}
118
119private function f_sendBlock(BssgpCause cause) runs on BSSGP_CT {
120 BSCP.send(f_BnsUdReq(t_BVC_BLOCK(mp_bvci, cause), 0));
121 g_T1.start;
122}
123
124private function f_sendStatus(BssgpCause cause, PDU_BSSGP pdu) runs on BSSGP_CT {
125 /* FIXME: Make sure correct Signaling or PTP BVCI is used! */
126 BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(mp_bvci, cause, pdu)));
127}
128
129altstep as_allstate() runs on BSSGP_CT {
130 var NsUnitdataIndication udi;
131 var NsStatusIndication nsi;
132 var ASP_Event evt;
133
134 /* Respond to BLOCK for wrong NSVCI */
135 [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(?, ?), 0)) -> value udi {
136 log("Rx BVC-BLOCK for unknown BVCI");
137 f_sendStatus(BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp);
Harald Welte1733a382017-07-23 17:26:17 +0200138 }
139
Harald Welte853c0ad2018-02-15 17:45:29 +0100140 /* Respond to RESET with correct BVCI/CellID */
141 [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, mp_bvci, mp_cellid), 0)) -> value udi {
142 log("Rx BVC-RESET for Our BVCI=", mp_bvci);
143 BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(mp_bvci, mp_cellid), 0));
144 f_change_state(BVC_S_UNBLOCKED);
Harald Welte1733a382017-07-23 17:26:17 +0200145 }
146
Harald Welte853c0ad2018-02-15 17:45:29 +0100147 /* Respond to RESET for signalling BVCI 0 */
148 [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, 0, mp_cellid), 0)) -> value udi {
149 log("Rx BVC-RESET for Signaling BVCI=0");
150 BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(0, mp_cellid), 0));
Harald Welte1733a382017-07-23 17:26:17 +0200151 }
152
Harald Welte853c0ad2018-02-15 17:45:29 +0100153 /* Respond to RESET with wrong NSEI/NSVCI */
154 [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, ?, ?), 0)) -> value udi {
155 log("Rx BVC-RESET for unknown BVCI");
156 f_sendStatus(BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp);
Harald Welte1733a382017-07-23 17:26:17 +0200157 }
158
Harald Welte853c0ad2018-02-15 17:45:29 +0100159 /* default case of handling unknown PDUs */
160 [] BSCP.receive(f_BnsUdInd(?, ?)) -> value udi {
161 log("Rx Unexpected BSSGP PDU ", udi.bssgp," in state ", g_ptp_bvc_state);
162 f_sendStatus(BSSGP_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, udi.bssgp);
Harald Welte1733a382017-07-23 17:26:17 +0200163 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100164 /* Forwarding of ASP_Event and NsStatusIndication to user */
165 [] BSCP.receive(ASP_Event:?) -> value evt { BSSGP_SP.send(evt); }
166 [] BSCP.receive(NsStatusIndication:?) -> value nsi {
167 /* if we just became NS-unblocked, send a BCC-RESET */
168 if (nsi.old_state != NSE_S_ALIVE_UNBLOCKED and nsi.new_state == NSE_S_ALIVE_UNBLOCKED) {
169 if (g_sgsn_role == false) {
170 f_sendReset();
Harald Welte1733a382017-07-23 17:26:17 +0200171 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100172 /* Idea: We coudl send BVC-UNBLOCK here like some SGSN do */
Harald Welte1733a382017-07-23 17:26:17 +0200173 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100174 BSSGP_SP.send(nsi);
Harald Welte1733a382017-07-23 17:26:17 +0200175 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100176}
Harald Welte1733a382017-07-23 17:26:17 +0200177
Harald Welte853c0ad2018-02-15 17:45:29 +0100178private function f_ScanEvents() runs on BSSGP_CT {
179 var NsUnitdataIndication udi;
180 var PDU_BSSGP bs_pdu;
181 var default d;
Harald Welte1733a382017-07-23 17:26:17 +0200182
Harald Welte13d391e2017-07-23 19:52:33 +0200183
Harald Welte853c0ad2018-02-15 17:45:29 +0100184 log("matching against ", tr_BVC_RESET(?, mp_bvci, mp_cellid));
Harald Welte13d391e2017-07-23 19:52:33 +0200185
Harald Welte853c0ad2018-02-15 17:45:29 +0100186 d := activate(as_allstate());
Harald Welte1733a382017-07-23 17:26:17 +0200187
Harald Welte853c0ad2018-02-15 17:45:29 +0100188 while (true) {
189 if (g_ptp_bvc_state == BVC_S_BLOCKED) {
190 alt {
191 [] g_T1.timeout {
192 f_sendUnblock();
Harald Welte1733a382017-07-23 17:26:17 +0200193 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100194 [] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK_ACK(mp_bvci), 0)) {
195 g_T1.stop;
196 f_change_state(BVC_S_UNBLOCKED);
197 }
198 [not g_sgsn_role] BSCP.receive(f_BnsUdInd(tr_BVC_RESET_ACK(mp_bvci, omit), 0)) {
199 f_sendUnblock();
200 }
201 }
202 } else if (g_ptp_bvc_state == BVC_S_UNBLOCKED) {
203 alt {
204 /* bogus unblock, just respond with ACK */
205 [] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK(mp_bvci), 0)) -> value udi {
206 BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK_ACK(mp_bvci), 0));
207 }
208 /* Respond to BLOCK with BLOCK-ACK + change state */
209 [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(mp_bvci, ?), 0)) -> value udi {
210 BSCP.send(f_BnsUdReq(t_BVC_BLOCK_ACK(mp_bvci), 0));
211 g_T1.stop;
212 f_change_state(BVC_S_BLOCKED);
213 }
214 [] g_T1.timeout {
215 f_sendBlock(BSSGP_CAUSE_OM_INTERVENTION);
216 }
217 [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK_ACK(mp_bvci), 0)) -> value udi {
218 g_T1.stop;
219 f_change_state(BVC_S_BLOCKED);
220 }
221 [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET_ACK(mp_bvci, mp_cellid), 0)) -> value udi {
222 g_T2.stop;
223 f_change_state(BVC_S_UNBLOCKED);
224 }
Harald Welte13d391e2017-07-23 19:52:33 +0200225
Harald Welte853c0ad2018-02-15 17:45:29 +0100226 /* simply acknowledge all Flow Control Messages */
Harald Weltee0abc472018-02-05 09:13:31 +0100227/*
Harald Welte853c0ad2018-02-15 17:45:29 +0100228 [g_sgsn_role] BSCP.receive(f_BnsUdInd(t_BVC_FC_BVC)) {
229 BSCP.send(f_BnsUdReq(t_BVC_FC_BVC_ACK));
230 }
231 [g_sgsn_role] BSCP.receive(f_BnsUdInd(t_BVC_FC_MS)) {
232 BSCP.send(f_BnsUdReq(t_BVC_FC_MS_ACK));
233 }
Harald Weltee0abc472018-02-05 09:13:31 +0100234*/
Harald Welte13d391e2017-07-23 19:52:33 +0200235
Harald Welte853c0ad2018-02-15 17:45:29 +0100236 /* BSSGP-UNITDATA PDUs from network to NS-UNITDATA.ind to user */
237 [not g_sgsn_role] BSCP.receive(f_BnsUdInd(tr_BSSGP_DL_UD)) -> value udi {
238 BSSGP_SP.send(udi.bssgp);
Harald Welte1733a382017-07-23 17:26:17 +0200239 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100240 [g_sgsn_role] BSCP.receive(f_BnsUdInd(tr_BSSGP_UL_UD)) -> value udi {
241 BSSGP_SP.send(udi.bssgp);
242 }
243 /* pass virtually any PDU from user to NS-UNITDATA PDU on network */
244 [] BSSGP_SP.receive(PDU_BSSGP:?) -> value bs_pdu {
245 BSCP.send(f_BnsUdReq(bs_pdu));
246 }
Harald Welte1733a382017-07-23 17:26:17 +0200247
Harald Welte853c0ad2018-02-15 17:45:29 +0100248 }
Harald Welte1733a382017-07-23 17:26:17 +0200249 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100250
251 } /* while */
252 //deactivate(d);
253}
254
255
Harald Welte1733a382017-07-23 17:26:17 +0200256}