blob: e9894d1e7caeff5ab05d02a0f7d7cb0509bdd786 [file] [log] [blame]
Harald Welted86cdc62017-11-22 00:45:07 +01001module IPA_Emulation {
2
3import from IPA_Types all;
4import from IPA_CodecPort all;
5import from IPA_CodecPort_CtrlFunct all;
6import from IPL4asp_Types all;
7import from MTP3asp_Types all;
8import from MTP3asp_PortType all;
9
Harald Weltec82eef42017-11-24 20:40:12 +010010import from MGCP_Types all;
11
Harald Welted86cdc62017-11-22 00:45:07 +010012modulepar {
Harald Welte92632e12017-11-25 02:31:20 +010013 /* Use Osmocom extended IPA mux header */
14 boolean mp_ipa_mgcp_uses_osmo_ext := true;
Harald Welted86cdc62017-11-22 00:45:07 +010015}
Harald Welted86cdc62017-11-22 00:45:07 +010016
Harald Welteb3414b22017-11-23 18:22:10 +010017type enumerated IpaMode {
18 IPA_MODE_CLIENT,
19 IPA_MODE_SERVER
20}
21
Harald Weltec76f29f2017-11-22 12:46:46 +010022type record ASP_IPA_Unitdata {
23 IpaStreamId streamId,
Harald Weltec82eef42017-11-24 20:40:12 +010024 IpaExtStreamId streamIdExt optional,
Harald Weltec76f29f2017-11-22 12:46:46 +010025 octetstring payload
26}
27
Harald Welte1dd8f372017-11-25 02:25:27 +010028template ASP_IPA_Unitdata t_ASP_IPA_UD(IpaStreamId sid, octetstring pl,
29 template IpaExtStreamId esid := omit) := {
30 streamId := sid,
31 streamIdExt := esid,
32 payload := pl
33}
34
Harald Weltec76f29f2017-11-22 12:46:46 +010035type port IPA_SP_PT message {
36 inout ASP_IPA_Unitdata;
37} with { extension "internal" }
38
Harald Weltec82eef42017-11-24 20:40:12 +010039type port IPA_MGCP_PT message {
40 inout MgcpCommand, MgcpResponse;
41} with { extension "internal" }
42
Harald Welted86cdc62017-11-22 00:45:07 +010043type component IPA_Emulation_CT {
44 /* down-facing port to IPA codec port */
45 port IPA_CODEC_PT IPA_PORT;
46 /* up-facing port to SCCP */
47 port MTP3asp_SP_PT MTP3_SP_PORT;
Harald Weltec82eef42017-11-24 20:40:12 +010048 /* up-facing port for MGCP */
49 port IPA_MGCP_PT IPA_MGCP_PORT;
Harald Weltec76f29f2017-11-22 12:46:46 +010050 /* up-facing port for other streams */
51 port IPA_SP_PT IPA_SP_PORT;
Harald Welted86cdc62017-11-22 00:45:07 +010052
53 var boolean g_initialized := false;
54 var ConnectionId g_ipa_conn_id := -1;
Harald Weltec82eef42017-11-24 20:40:12 +010055 /* Are we a BSC/MGW (truel) or MSC (false) */
56 var boolean g_is_bsc_mgw;
Harald Welteb3414b22017-11-23 18:22:10 +010057
58 var IpaMode g_mode;
Harald Welted86cdc62017-11-22 00:45:07 +010059}
60
61function f_connect(charstring remote_host, PortNumber remote_port,
62 charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
63 var Result res;
64 res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
65 local_host, local_port, 0, { tcp:={} });
66 g_ipa_conn_id := res.connId;
Harald Weltec82eef42017-11-24 20:40:12 +010067 g_is_bsc_mgw := true;
Harald Welted86cdc62017-11-22 00:45:07 +010068}
69
Harald Welteb3414b22017-11-23 18:22:10 +010070function f_bind(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
71 var Result res;
72 res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
73 local_host, local_port, { tcp:={} });
74 g_ipa_conn_id := res.connId;
Harald Weltec82eef42017-11-24 20:40:12 +010075 g_is_bsc_mgw := false;
Harald Welteb3414b22017-11-23 18:22:10 +010076}
77
Harald Welted86cdc62017-11-22 00:45:07 +010078template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
79 sio := { '10'B, '00'B, '0011'B },
80 opc := opc,
81 dpc := 0,
82 sls := 0,
83 data := data
84}
85
86
87private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := {
88 len := 0, /* overwritten by codec */
89 tag := tag,
90 data := payload
91}
92
93/* build IPA CCM ID RESP response from IPA CCM GET */
94private function f_ccm_make_id_resp(PDU_IPA_CCM get) return PDU_IPA_CCM {
95 var integer i;
96 var PDU_IPA_CCM resp := {
97 msg_type := IPAC_MSGT_ID_RESP,
98 u := {
99 resp := {}
100 }
101 }
102
103 for (i := 0; i < sizeof(get.u.get); i := i + 1) {
104 var IpaCcmIdTag tag := get.u.get[i].tag;
105 var charstring foo;
106 select (tag) {
107 case (IPAC_IDTAG_UNIT) {
108 foo := "0/1/2";
109 }
110 case (IPAC_IDTAG_UNITNAME) {
111 foo := "mahlzeit";
112 }
113 case else {
114 foo := "foo";
115 }
116 }
117 resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo));
118 }
119
120 return resp;
121}
122
123/* transmit IPA CCM message */
124private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100125 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_CCM, enc_PDU_IPA_CCM(ccm)));
Harald Welted86cdc62017-11-22 00:45:07 +0100126 log("CCM Tx:", ccm);
127 IPA_PORT.send(ipa_tx);
128}
129
130template PDU_IPA_CCM ts_IPA_PONG := {
131 msg_type := IPAC_MSGT_PONG,
132 u := omit
133}
134
135template PDU_IPA_CCM ts_IPA_ACK := {
136 msg_type := IPAC_MSGT_ID_ACK,
137 u := omit
138}
139
Harald Welteb3414b22017-11-23 18:22:10 +0100140template PDU_IPA_CCM ts_IPA_ID_GET := {
141 msg_type := IPAC_MSGT_ID_GET,
142 u := {
143 get := {
144 { 1, IPAC_IDTAG_UNITNAME }
145 }
146 }
147}
148
Harald Welted86cdc62017-11-22 00:45:07 +0100149/* receive IPA CCM message */
150private function f_ccm_rx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
151 select (ccm.msg_type) {
152 case (IPAC_MSGT_PING) {
153 f_ccm_tx(valueof(ts_IPA_PONG));
154 }
155 case (IPAC_MSGT_ID_ACK) {
156 f_ccm_tx(valueof(ts_IPA_ACK));
157 }
158 case (IPAC_MSGT_ID_GET) {
159 f_ccm_tx(f_ccm_make_id_resp(ccm));
160 }
161 case else {
162 log("Unknown/unsupported IPA CCM message type", ccm);
163 }
164 }
165}
166
Harald Weltec76f29f2017-11-22 12:46:46 +0100167private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata {
168 var ASP_IPA_Unitdata ret := {
169 streamId := ipa_rx.streamId,
Harald Welte2a8f8472017-11-23 21:11:34 +0100170 streamIdExt := ipa_rx.streamIdExt,
Harald Weltec76f29f2017-11-22 12:46:46 +0100171 payload := ipa_rx.msg
172 }
173 return ret;
174}
175
176private function f_from_asp(ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
Harald Weltec82eef42017-11-24 20:40:12 +0100177 var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
178 ipa_tx.streamIdExt));
Harald Weltec76f29f2017-11-22 12:46:46 +0100179 return ret;
180}
Harald Welted86cdc62017-11-22 00:45:07 +0100181
Harald Welteb3414b22017-11-23 18:22:10 +0100182function main_client(charstring remote_host, PortNumber remote_port,
183 charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
184 g_mode := IPA_MODE_CLIENT;
185 f_connect(remote_host, remote_port, local_host, local_port);
186 ScanEvents();
187}
188
189function main_server(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
190 g_mode := IPA_MODE_SERVER;
191 f_bind(local_host, local_port);
192 ScanEvents();
193}
194
Harald Weltec82eef42017-11-24 20:40:12 +0100195private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
196 var charstring msg_ch := oct2char(msg);
197 if (g_is_bsc_mgw) {
198 log("============");
199 log(msg_ch);
200 IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
201 } else {
202 IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
203 }
204}
205
Harald Welte92632e12017-11-25 02:31:20 +0100206private function f_mgcp_to_ud(octetstring payload) runs on IPA_Emulation_CT return ASP_IPA_Unitdata {
207 if (mp_ipa_mgcp_uses_osmo_ext) {
208 return valueof(t_ASP_IPA_UD(IPAC_PROTO_MGCP_OLD, payload));
209 } else {
210 return valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_MGCP));
211 }
212}
213
Harald Welteb3414b22017-11-23 18:22:10 +0100214private function ScanEvents() runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100215 var IPA_RecvFrom ipa_rx;
Harald Weltec76f29f2017-11-22 12:46:46 +0100216 var ASP_IPA_Unitdata ipa_ud;
Harald Welted86cdc62017-11-22 00:45:07 +0100217 var ASP_MTP3_TRANSFERreq mtp_req;
Harald Welteb3414b22017-11-23 18:22:10 +0100218 var ASP_Event asp_evt;
Harald Weltec82eef42017-11-24 20:40:12 +0100219 var MgcpCommand mgcp_cmd;
220 var MgcpResponse mgcp_rsp;
Harald Welte1dd8f372017-11-25 02:25:27 +0100221 var octetstring payload;
Harald Welted86cdc62017-11-22 00:45:07 +0100222
223 while (true) {
224 alt {
225 /* Received IPA -> up into SCCP stack */
226 [] IPA_PORT.receive(IPA_RecvFrom: ?) -> value ipa_rx {
227 select (ipa_rx.streamId) {
228 case (IPAC_PROTO_CCM) {
229 var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
230 log("CCM Rx:", ccm);
231 f_ccm_rx(ccm);
Harald Weltec82eef42017-11-24 20:40:12 +0100232 } case (IPAC_PROTO_SCCP) {
Harald Welted86cdc62017-11-22 00:45:07 +0100233 var ASP_MTP3_TRANSFERind mtp;
234 mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
235 MTP3_SP_PORT.send(mtp);
Harald Weltec82eef42017-11-24 20:40:12 +0100236 } case (IPAC_PROTO_MGCP_OLD) {
237 f_mgcp_to_user(ipa_rx.msg);
238 } case (IPAC_PROTO_OSMO) {
239 select (ipa_rx.streamIdExt) {
240 case (IPAC_PROTO_EXT_MGCP) {
241 f_mgcp_to_user(ipa_rx.msg);
242 } case else {
243 IPA_SP_PORT.send(f_to_asp(ipa_rx));
244 }
Harald Welted86cdc62017-11-22 00:45:07 +0100245 }
Harald Weltec82eef42017-11-24 20:40:12 +0100246 } case else {
Harald Weltec76f29f2017-11-22 12:46:46 +0100247 IPA_SP_PORT.send(f_to_asp(ipa_rx));
Harald Welted86cdc62017-11-22 00:45:07 +0100248 }
249 }
250 }
251
Harald Welteb3414b22017-11-23 18:22:10 +0100252 /* server only */
253 [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
254 log("IPA: Connected");
255 g_ipa_conn_id := asp_evt.connOpened.connId;
256 if (g_mode == IPA_MODE_SERVER) {
257 f_ccm_tx(valueof(ts_IPA_ID_GET));
258 }
259 }
260
261 [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
262 log("IPA: Closed");
263 g_ipa_conn_id := -1;
264 self.stop;
265 }
266
Harald Welted86cdc62017-11-22 00:45:07 +0100267 /* Received SCCP -> down into IPA */
268 [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
Harald Weltec82eef42017-11-24 20:40:12 +0100269 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
270 mtp_req.data));
Harald Welted86cdc62017-11-22 00:45:07 +0100271 IPA_PORT.send(ipa_tx);
272 }
Harald Weltec76f29f2017-11-22 12:46:46 +0100273
Harald Weltec82eef42017-11-24 20:40:12 +0100274 /* Received MGCP -> down into IPA */
275 [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
Harald Welte92632e12017-11-25 02:31:20 +0100276 payload := char2oct(enc_MgcpCommand(mgcp_cmd));
277 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100278 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
279 }
280 [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
Harald Welte1dd8f372017-11-25 02:25:27 +0100281 payload := char2oct(enc_MgcpResponse(mgcp_rsp));
Harald Welte92632e12017-11-25 02:31:20 +0100282 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100283 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
284 }
285
286
287 /* Received MISC (RSL/OML/CTRL) -> down into IPA */
Harald Weltec76f29f2017-11-22 12:46:46 +0100288 [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
289 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
290 }
291
292
Harald Welted86cdc62017-11-22 00:45:07 +0100293 }
294 }
295}
296
297}