blob: 85129e8be0bba64c4f93ae5379e1970b373cce54 [file] [log] [blame]
Harald Welte4029e8c2017-11-23 22:00:42 +01001module MGCP_Templates {
2
Harald Welte35bb7162018-01-03 21:07:52 +01003/* MGCP Templates, building on top of MGCP_Types (Osmocom) and SDP_Types from Ericsson.
4 *
5 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
6 * All rights reserved.
7 *
8 * Released under the terms of GNU General Public License, Version 2 or
9 * (at your option) any later version.
10 */
11
12
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010013import from MGCP_Types all;
14import from SDP_Types all;
Pau Espin Pedrol1158cc62024-03-21 17:21:35 +010015import from SDP_Templates all;
Harald Welte4029e8c2017-11-23 22:00:42 +010016
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010017function f_mgcp_par_append(inout template MgcpParameterList list, template MgcpParameter par) {
18 var integer len := lengthof(list);
19 list[len] := par;
20}
Harald Welte4029e8c2017-11-23 22:00:42 +010021
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010022/* 3.2.2.6 Connection Mode (sendonly, recvonly, sendrecv, confrnce, inactive, loopback,
23 * conttest, netwloop, netwtest) */
24template MgcpParameter t_MgcpParConnMode(template MgcpConnectionMode mode) := { "M", mode };
Harald Welte4029e8c2017-11-23 22:00:42 +010025
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010026/* 3.2.2.2 CallId: maximum 32 hex chars */
27template MgcpParameter ts_MgcpParCallId(MgcpCallId cid) := {
28 code := "C",
29 val := hex2str(cid)
30};
Harald Welte4029e8c2017-11-23 22:00:42 +010031
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010032/* 3.2.2.18 RequestIdentifier: Maximum 32 hex chars */
33template MgcpParameter ts_MgcpParReqId(MgcpRequestId rid) := {
34 code := "X",
35 val := hex2str(rid)
36};
Harald Welte4029e8c2017-11-23 22:00:42 +010037
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010038/* 3.2.1.3 SpecificEndpointId */
39template MgcpParameter ts_MgcpParSpecEP(MgcpEndpoint ep) := {
40 code := "Z",
41 val := ep
42};
Harald Welte363cb0a2018-01-30 19:35:53 +010043
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010044/* 3.2.2.10: LocalConnectionOptions (codec, packetization, bandwidth, ToS, eco, gain, silence, ...) */
45template MgcpParameter t_MgcpParLocConnOpt(template charstring lco) := { "L", lco };
Harald Welte4029e8c2017-11-23 22:00:42 +010046
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010047/* 3.2.2.5: ConnectionId: maximum 32 hex chars */
48template MgcpParameter ts_MgcpParConnectionId(MgcpConnectionId cid) := {
49 code := "I",
50 val := hex2str(cid)
51};
Harald Welte4029e8c2017-11-23 22:00:42 +010052
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010053/* Osmocom extension: X-Osmux: {*,%u} */
54template MgcpParameter ts_MgcpParOsmuxCID(MgcpOsmuxCID osmux_cid) := {
55 code := "X-OSMUX",
56 val := f_mgcp_osmux_cid_encode(osmux_cid)
57};
Pau Espin Pedrolb2c6b382019-05-14 13:40:49 +020058
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010059/* Osmocom extension: X-Osmux: {*,%u} */
60template MgcpParameter t_MgcpParOsmoIGN(template charstring val) := {
61 code := "X-OSMO-IGN",
62 val := val
63};
Pau Espin Pedrolbefd3aa2020-09-21 10:54:42 +020064
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010065/* osmo-bsc_mgcp implements L/C/M/X only, osmo-mgw adds 'I' */
66/* SDP: osmo-bsc_mgcp implements Tx of v,o,s,c,t,m,a */
Harald Welte4029e8c2017-11-23 22:00:42 +010067
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010068template (value) MgcpResponse
69ts_MgcpResp_Err(template (value) MgcpTransId trans_id,
70 template (value) MgcpResponseCode code,
71 template (value) charstring string := "FAIL") := {
72 line := {
73 code := code,
Harald Welte4029e8c2017-11-23 22:00:42 +010074 trans_id := trans_id,
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010075 string := string
76 },
77 params := {},
78 sdp := omit
79}
80template MgcpResponse
81tr_MgcpResp_Err(template (present) MgcpResponseCode code) := {
82 line := {
83 code := code,
84 trans_id := ?,
85 string := ?
86 },
87 params := {},
88 sdp := omit
89}
Harald Welte4029e8c2017-11-23 22:00:42 +010090
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010091template MgcpCommandLine t_MgcpCmdLine(template charstring verb, template MgcpTransId trans_id, template charstring ep) := {
92 verb := verb,
93 trans_id := trans_id,
94 ep := ep,
95 ver := "1.0"
96};
Pau Espin Pedrolb26d4462023-06-15 11:38:02 +020097
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +010098template MgcpCommand ts_AUEP(MgcpTransId trans_id, charstring ep) := {
99 line := t_MgcpCmdLine("AUEP", trans_id, ep),
100 params := omit,
101 sdp := omit
102}
Pau Espin Pedrolb26d4462023-06-15 11:38:02 +0200103
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100104template MgcpResponse tr_AUEP_ACK := {
105 line := {
106 code := "200",
107 trans_id := ?,
108 string := "OK"
109 },
110 params:= *,
111 sdp := omit
112}
Harald Welte4029e8c2017-11-23 22:00:42 +0100113
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100114template MgcpCommand ts_CRCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
115 line := t_MgcpCmdLine("CRCX", trans_id, ep),
116 params := {
117 t_MgcpParConnMode(mode),
118 ts_MgcpParCallId(call_id),
119 //t_MgcpParReqId(omit),
120 t_MgcpParLocConnOpt("p:20, a:AMR")
121 },
122 sdp := sdp
123}
Philipp Maier45635f42018-06-05 17:28:02 +0200124
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100125template MgcpCommand ts_CRCX_no_lco(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
126 line := t_MgcpCmdLine("CRCX", trans_id, ep),
127 params := {
128 t_MgcpParConnMode(mode),
129 ts_MgcpParCallId(call_id)
130 },
131 sdp := sdp
132}
Pau Espin Pedrolb2c6b382019-05-14 13:40:49 +0200133
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100134template MgcpCommand ts_CRCX_osmux(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, MgcpOsmuxCID osmux_cid, template SDP_Message sdp := omit) := {
135 line := t_MgcpCmdLine("CRCX", trans_id, ep),
136 params := {
137 t_MgcpParConnMode(mode),
138 ts_MgcpParCallId(call_id),
139 //t_MgcpParReqId(omit),
140 t_MgcpParLocConnOpt("p:20, a:AMR"),
141 ts_MgcpParOsmuxCID(osmux_cid)
142 },
143 sdp := sdp
144}
Harald Welte90029572017-11-24 23:39:50 +0100145
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100146template MgcpCommand tr_CRCX(template MgcpEndpoint ep := ?, template SDP_Message sdp := *) := {
147 line := t_MgcpCmdLine("CRCX", ?, ep),
148 params := *,
149 sdp := sdp
150}
Harald Welte4029e8c2017-11-23 22:00:42 +0100151
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100152template MgcpResponse tr_CRCX_ACK := {
153 line := {
154 code := "200",
155 trans_id := ?,
156 string := "OK"
157 },
158 params:= { { "I", ? }, *},
159 sdp := ?
160}
Pau Espin Pedrolb2c6b382019-05-14 13:40:49 +0200161
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100162template MgcpResponse tr_CRCX_ACK_osmux := {
163 line := {
164 code := "200",
165 trans_id := ?,
166 string := "OK"
167 },
168 params:= { { "I", ? }, {"X-OSMUX", ?}, *},
169 sdp := ?
170}
Harald Welte90029572017-11-24 23:39:50 +0100171
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100172template MgcpResponse ts_CRCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := {
173 line := {
174 code := "200",
175 trans_id := trans_id,
176 string := "OK"
177 },
178 params:= { ts_MgcpParConnectionId(conn_id) },
179 sdp := sdp
180}
Pau Espin Pedrolc6a53db2019-05-20 19:31:47 +0200181
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100182template MgcpResponse ts_CRCX_ACK_osmux(MgcpTransId trans_id, MgcpConnectionId conn_id, MgcpOsmuxCID osmux_cid, template SDP_Message sdp := omit) := {
183 line := {
184 code := "200",
185 trans_id := trans_id,
186 string := "OK"
187 },
188 params:= {
189 ts_MgcpParConnectionId(conn_id),
190 ts_MgcpParOsmuxCID(osmux_cid)
191 },
192 sdp := sdp
193}
Harald Welte4029e8c2017-11-23 22:00:42 +0100194
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100195template MgcpCommand ts_MDCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := {
196 line := t_MgcpCmdLine("MDCX", trans_id, ep),
197 params := {
198 t_MgcpParConnMode(mode),
199 ts_MgcpParCallId(call_id),
200 ts_MgcpParConnectionId(conn_id),
201 //t_MgcpParReqId(omit),
202 t_MgcpParLocConnOpt("p:20, a:AMR")
203 },
204 sdp := sdp
205}
Pau Espin Pedrolb2c6b382019-05-14 13:40:49 +0200206
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100207template MgcpCommand ts_MDCX_osmux(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, MgcpConnectionId conn_id, MgcpOsmuxCID osmux_cid, template SDP_Message sdp := omit) := {
208 line := t_MgcpCmdLine("MDCX", trans_id, ep),
209 params := {
210 t_MgcpParConnMode(mode),
211 ts_MgcpParCallId(call_id),
212 ts_MgcpParConnectionId(conn_id),
213 //t_MgcpParReqId(omit),
214 t_MgcpParLocConnOpt("p:20, a:AMR"),
215 ts_MgcpParOsmuxCID(osmux_cid)
216 },
217 sdp := sdp
218}
Harald Welte90029572017-11-24 23:39:50 +0100219
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100220template MgcpCommand tr_MDCX(template SDP_Message sdp := *) := {
221 line := t_MgcpCmdLine("MDCX", ?, ?),
222 params := *,
223 sdp := sdp
224}
Harald Weltebb7523b2018-03-29 08:52:01 +0200225
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100226template MgcpResponse tr_MDCX_ACK := {
227 line := {
228 code := "200",
229 trans_id := ?,
230 string := "OK"
231 },
232 params := *,
233 sdp := ?
234}
Harald Welte90029572017-11-24 23:39:50 +0100235
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100236template MgcpResponse ts_MDCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := ts_CRCX_ACK(trans_id, conn_id, sdp);
237template MgcpResponse ts_MDCX_ACK_osmux(MgcpTransId trans_id, MgcpConnectionId conn_id, MgcpOsmuxCID osmux_cid, template SDP_Message sdp := omit) := ts_CRCX_ACK_osmux(trans_id, conn_id, osmux_cid, sdp);
Harald Welte4029e8c2017-11-23 22:00:42 +0100238
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100239/* have a function that generates a template, rather than a template in order to handle
240 * optional parameters */
241function ts_DLCX(MgcpTransId trans_id, charstring ep, template MgcpCallId call_id := omit,
242 template MgcpConnectionId conn_id := omit) return template MgcpCommand {
243 var template MgcpCommand cmd;
244 cmd.line := t_MgcpCmdLine("DLCX", trans_id, ep);
245 cmd.params := {};
246 cmd.sdp := omit;
247 if (isvalue(call_id)) {
248 f_mgcp_par_append(cmd.params, ts_MgcpParCallId(valueof(call_id)));
249 if (isvalue(conn_id)) {
250 f_mgcp_par_append(cmd.params, ts_MgcpParConnectionId(valueof(conn_id)));
Harald Welte4029e8c2017-11-23 22:00:42 +0100251 }
252 }
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100253 return cmd;
254}
Harald Welte4029e8c2017-11-23 22:00:42 +0100255
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100256template MgcpCommand tr_DLCX(template MgcpEndpoint ep := ?) := {
257 line := t_MgcpCmdLine("DLCX", ?, ep),
258 params := *,
259 sdp := *
260}
261
262template MgcpResponse tr_DLCX_ACK := {
263 line := {
264 code := ("200", "250"),
265 trans_id := ?,
266 string := "OK"
267 },
268 params:= *,
269 sdp := *
270}
271
272template MgcpResponse ts_DLCX_ACK2(MgcpTransId trans_id) := {
273 line := {
274 code := "250",
275 trans_id := trans_id,
276 string := "OK"
277 },
278 params:= { /* list of ConnectionIDs */ },
279 sdp := omit
280}
281
282
283
284template MgcpResponse ts_DLCX_ACK(MgcpTransId trans_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := ts_CRCX_ACK(trans_id, conn_id, sdp);
285
286template MgcpCommand tr_RSIP := {
287 line := t_MgcpCmdLine("RSIP", ?, ?),
288 params := *,
289 sdp := *
290}
291
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100292function f_mgcp_addr2addrtype(charstring addr) return charstring {
293 for (var integer i := 0; i < lengthof(addr); i := i + 1) {
294 if (addr[i] == ":") {
295 return "IP6";
Harald Welte4029e8c2017-11-23 22:00:42 +0100296 }
297 }
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100298 return "IP4";
299}
300
301/* -1 is wildcard, positive is translated as string */
302function f_mgcp_osmux_cid_encode(MgcpOsmuxCID osmux_cid) return charstring {
303 if (osmux_cid == -1) {
304 return "*";
305 }
306 return int2str(osmux_cid);
307}
308
309function f_mgcp_osmux_cid_decode(charstring osmux_cid) return MgcpOsmuxCID {
310 if (osmux_cid == "*") {
311 return -1;
312 }
313 return str2int(osmux_cid);
314}
315
316function f_mgcp_contains_par(MgcpMessage msg, MgcpInfoCode code) return boolean {
317 var MgcpParameterList pars;
318 if (ischosen(msg.command)) {
319 pars := msg.command.params;
320 } else {
321 pars := msg.response.params;
322 }
323 for (var integer i := 0; i < lengthof(pars); i := i + 1) {
324 var MgcpParameter par := pars[i];
325 if (par.code == code) {
326 return true;
Harald Welte4029e8c2017-11-23 22:00:42 +0100327 }
328 }
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100329 return false;
330}
331
332function f_mgcp_extract_par(MgcpMessage msg, MgcpInfoCode code) return charstring {
333 var MgcpParameterList pars;
334 if (ischosen(msg.command)) {
335 pars := msg.command.params;
336 } else {
337 pars := msg.response.params;
338 }
339 for (var integer i := 0; i < lengthof(pars); i := i + 1) {
340 var MgcpParameter par := pars[i];
341 if (par.code == code) {
342 return par.val;
Philipp Maierc8c0b402019-03-07 10:48:45 +0100343 }
344 }
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100345 setverdict(fail, "Could not extract parameters for code ", code);
346 return "";
347}
Harald Welte4029e8c2017-11-23 22:00:42 +0100348
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100349function f_MgcpResp_extract_par(MgcpResponse resp, MgcpInfoCode code) return charstring {
350 var MgcpMessage msg := {
351 response := resp
352 }
353 return f_mgcp_extract_par(msg, code);
354}
355
356function f_MgcpCmd_extract_par(MgcpCommand cmd, MgcpInfoCode code) return charstring {
357 var MgcpMessage msg := {
358 command := cmd
359 }
360 return f_mgcp_extract_par(msg, code);
361}
362
363function f_MgcpCmd_contains_par(MgcpCommand cmd, MgcpInfoCode code) return boolean {
364 var MgcpMessage msg := {
365 command := cmd
366 }
367 return f_mgcp_contains_par(msg, code);
368}
369
370function f_MgcpResp_extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
371 return str2hex(f_MgcpResp_extract_par(resp, "I"));
372}
373
374function f_MgcpCmd_extract_call_id(MgcpCommand cmd) return MgcpCallId {
375 return str2hex(f_MgcpCmd_extract_par(cmd, "C"));
376}
377
378function f_MgcpCmd_extract_conn_id(MgcpCommand cmd) return MgcpConnectionId {
379 return str2hex(f_MgcpCmd_extract_par(cmd, "I"));
380}
381
382function f_MgcpCmd_extract_osmux_cid(MgcpCommand cmd) return MgcpOsmuxCID {
383 return f_mgcp_osmux_cid_decode(f_MgcpCmd_extract_par(cmd, "X-OSMUX"));
384}
385
386
387function f_mgcp_alloc_tid() return MgcpTransId {
388 return int2str(float2int(rnd()*2147483647.0));
389}
390
391function f_mgcp_alloc_call_id() return MgcpCallId {
392 return int2hex(float2int(rnd()*2147483647.0), 8);
393}
394
395function f_mgcp_alloc_conn_id() return MgcpConnectionId {
396 return int2hex(float2int(rnd()*2147483647.0), 8);
397}
398
399/* those verbs that related to a connection (and hence have ConnectionId) */
400template MgcpVerb tr_MgcpVerb_ConnectionOriented := ("CRCX", "MDCX", "DLCX", "AUCX");
401/* entire command template matching only connection oriented verbs */
402template MgcpCommand tr_MgcpCommand_CO := {
403 line := {
404 verb := tr_MgcpVerb_ConnectionOriented,
405 trans_id := ?,
406 ep := ?,
407 ver := ?
408 },
409 params := *,
410 sdp := *
411}
412
413function f_mgcp_find_param_entry(MgcpParameterList pars, MgcpInfoCode code, out charstring ret)
414return boolean {
415 for (var integer i := 0; i < sizeof(pars); i := i+1) {
416 if (pars[i].code == code) {
417 ret := pars[i].val;
418 return true;
Pau Espin Pedrol384e9492020-09-03 17:05:19 +0200419 }
Pau Espin Pedrol384e9492020-09-03 17:05:19 +0200420 }
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100421 return false;
422}
Pau Espin Pedrol384e9492020-09-03 17:05:19 +0200423
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100424function f_mgcp_find_param(MgcpMessage msg, MgcpInfoCode code, out charstring ret)
425return boolean {
426 var MgcpParameterList pars;
427 if (ischosen(msg.command)) {
428 pars := msg.command.params;
429 } else {
430 pars := msg.response.params;
Pau Espin Pedrolb2c6b382019-05-14 13:40:49 +0200431 }
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100432 return f_mgcp_find_param_entry(pars, code, ret);
433}
Pau Espin Pedrolb2c6b382019-05-14 13:40:49 +0200434
Pau Espin Pedrola907b9f2024-03-21 16:13:56 +0100435/* template to determine if a MGCP endpoint is a wildcard endpoint */
436template charstring t_MGCP_EP_wildcard := (pattern "\*@*", pattern "rtpbridge/\*@*");
Harald Welte363cb0a2018-01-30 19:35:53 +0100437
Harald Welteb71901a2018-01-26 19:16:05 +0100438
Harald Welte4029e8c2017-11-23 22:00:42 +0100439}