blob: a48e205085e3f26c531aa933d5f82be3b0857e44 [file] [log] [blame]
Neels Hofmeyre9920f22017-07-10 15:07:22 +02001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* The protocol implementation */
3
4/*
5 * (C) 2009-2014 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2011 by On-Waves
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24
25#include <osmocom/core/talloc.h>
26
27#include <osmocom/legacy_mgcp/mgcp.h>
28#include <osmocom/legacy_mgcp/mgcp_internal.h>
29#include <osmocom/legacy_mgcp/vty.h>
30
31#include <string.h>
32
33#define RTCP_OMIT_STR "Drop RTCP packets in both directions\n"
34#define RTP_PATCH_STR "Modify RTP packet header in both directions\n"
35#define RTP_KEEPALIVE_STR "Send dummy UDP packet to net RTP destination\n"
36
37static struct mgcp_config *g_cfg = NULL;
38
39static struct mgcp_trunk_config *find_trunk(struct mgcp_config *cfg, int nr)
40{
41 struct mgcp_trunk_config *trunk;
42
43 if (nr == 0)
44 trunk = &cfg->trunk;
45 else
46 trunk = mgcp_trunk_num(cfg, nr);
47
48 return trunk;
49}
50
51/*
52 * vty code for mgcp below
53 */
54struct cmd_node mgcp_node = {
55 MGCP_NODE,
56 "%s(config-mgcp)# ",
57 1,
58};
59
60struct cmd_node trunk_node = {
61 TRUNK_NODE,
62 "%s(config-mgcp-trunk)# ",
63 1,
64};
65
66static int config_write_mgcp(struct vty *vty)
67{
68 vty_out(vty, "mgcp%s", VTY_NEWLINE);
69 if (g_cfg->local_ip)
70 vty_out(vty, " local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
71 if (g_cfg->bts_ip && strlen(g_cfg->bts_ip) != 0)
72 vty_out(vty, " bts ip %s%s", g_cfg->bts_ip, VTY_NEWLINE);
73 vty_out(vty, " bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE);
74 vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
75
76 if (g_cfg->bts_ports.mode == PORT_ALLOC_STATIC)
77 vty_out(vty, " rtp bts-base %u%s", g_cfg->bts_ports.base_port, VTY_NEWLINE);
78 else
79 vty_out(vty, " rtp bts-range %u %u%s",
80 g_cfg->bts_ports.range_start, g_cfg->bts_ports.range_end, VTY_NEWLINE);
81 if (g_cfg->bts_ports.bind_addr)
82 vty_out(vty, " rtp bts-bind-ip %s%s", g_cfg->bts_ports.bind_addr, VTY_NEWLINE);
83
84 if (g_cfg->net_ports.mode == PORT_ALLOC_STATIC)
85 vty_out(vty, " rtp net-base %u%s", g_cfg->net_ports.base_port, VTY_NEWLINE);
86 else
87 vty_out(vty, " rtp net-range %u %u%s",
88 g_cfg->net_ports.range_start, g_cfg->net_ports.range_end, VTY_NEWLINE);
89 if (g_cfg->net_ports.bind_addr)
90 vty_out(vty, " rtp net-bind-ip %s%s", g_cfg->net_ports.bind_addr, VTY_NEWLINE);
91
92 vty_out(vty, " rtp ip-dscp %d%s", g_cfg->endp_dscp, VTY_NEWLINE);
93 if (g_cfg->trunk.keepalive_interval == MGCP_KEEPALIVE_ONCE)
94 vty_out(vty, " rtp keep-alive once%s", VTY_NEWLINE);
95 else if (g_cfg->trunk.keepalive_interval)
96 vty_out(vty, " rtp keep-alive %d%s",
97 g_cfg->trunk.keepalive_interval, VTY_NEWLINE);
98 else
99 vty_out(vty, " no rtp keep-alive%s", VTY_NEWLINE);
100
101 if (g_cfg->trunk.omit_rtcp)
102 vty_out(vty, " rtcp-omit%s", VTY_NEWLINE);
103 else
104 vty_out(vty, " no rtcp-omit%s", VTY_NEWLINE);
105 if (g_cfg->trunk.force_constant_ssrc || g_cfg->trunk.force_aligned_timing) {
106 vty_out(vty, " %srtp-patch ssrc%s",
107 g_cfg->trunk.force_constant_ssrc ? "" : "no ", VTY_NEWLINE);
108 vty_out(vty, " %srtp-patch timestamp%s",
109 g_cfg->trunk.force_aligned_timing ? "" : "no ", VTY_NEWLINE);
110 } else
111 vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
112 if (g_cfg->trunk.audio_payload != -1)
113 vty_out(vty, " sdp audio-payload number %d%s",
114 g_cfg->trunk.audio_payload, VTY_NEWLINE);
115 if (g_cfg->trunk.audio_name)
116 vty_out(vty, " sdp audio-payload name %s%s",
117 g_cfg->trunk.audio_name, VTY_NEWLINE);
118 if (g_cfg->trunk.audio_fmtp_extra)
119 vty_out(vty, " sdp audio fmtp-extra %s%s",
120 g_cfg->trunk.audio_fmtp_extra, VTY_NEWLINE);
121 vty_out(vty, " %ssdp audio-payload send-ptime%s",
122 g_cfg->trunk.audio_send_ptime ? "" : "no ", VTY_NEWLINE);
123 vty_out(vty, " %ssdp audio-payload send-name%s",
124 g_cfg->trunk.audio_send_name ? "" : "no ", VTY_NEWLINE);
125 vty_out(vty, " loop %u%s", !!g_cfg->trunk.audio_loop, VTY_NEWLINE);
126 vty_out(vty, " number endpoints %u%s", g_cfg->trunk.number_endpoints - 1, VTY_NEWLINE);
127 vty_out(vty, " %sallow-transcoding%s",
128 g_cfg->trunk.no_audio_transcoding ? "no " : "", VTY_NEWLINE);
129 if (g_cfg->call_agent_addr)
130 vty_out(vty, " call-agent ip %s%s", g_cfg->call_agent_addr, VTY_NEWLINE);
131 if (g_cfg->transcoder_ip)
132 vty_out(vty, " transcoder-mgw %s%s", g_cfg->transcoder_ip, VTY_NEWLINE);
133
134 if (g_cfg->transcoder_ports.mode == PORT_ALLOC_STATIC)
135 vty_out(vty, " rtp transcoder-base %u%s", g_cfg->transcoder_ports.base_port, VTY_NEWLINE);
136 else
137 vty_out(vty, " rtp transcoder-range %u %u%s",
138 g_cfg->transcoder_ports.range_start, g_cfg->transcoder_ports.range_end, VTY_NEWLINE);
139 if (g_cfg->bts_force_ptime > 0)
140 vty_out(vty, " rtp force-ptime %d%s", g_cfg->bts_force_ptime, VTY_NEWLINE);
141 vty_out(vty, " transcoder-remote-base %u%s", g_cfg->transcoder_remote_base, VTY_NEWLINE);
142
143 switch (g_cfg->osmux) {
144 case OSMUX_USAGE_ON:
145 vty_out(vty, " osmux on%s", VTY_NEWLINE);
146 break;
147 case OSMUX_USAGE_ONLY:
148 vty_out(vty, " osmux only%s", VTY_NEWLINE);
149 break;
150 case OSMUX_USAGE_OFF:
151 default:
152 vty_out(vty, " osmux off%s", VTY_NEWLINE);
153 break;
154 }
155 if (g_cfg->osmux) {
156 vty_out(vty, " osmux bind-ip %s%s",
157 g_cfg->osmux_addr, VTY_NEWLINE);
158 vty_out(vty, " osmux batch-factor %d%s",
159 g_cfg->osmux_batch, VTY_NEWLINE);
160 vty_out(vty, " osmux batch-size %u%s",
161 g_cfg->osmux_batch_size, VTY_NEWLINE);
162 vty_out(vty, " osmux port %u%s",
163 g_cfg->osmux_port, VTY_NEWLINE);
164 vty_out(vty, " osmux dummy %s%s",
165 g_cfg->osmux_dummy ? "on" : "off", VTY_NEWLINE);
166 }
167 return CMD_SUCCESS;
168}
169
170static void dump_rtp_end(const char *end_name, struct vty *vty,
171 struct mgcp_rtp_state *state, struct mgcp_rtp_end *end)
172{
173 struct mgcp_rtp_codec *codec = &end->codec;
174
175 vty_out(vty,
176 " %s%s"
177 " Timestamp Errs: %d->%d%s"
178 " Dropped Packets: %d%s"
179 " Payload Type: %d Rate: %u Channels: %d %s"
180 " Frame Duration: %u Frame Denominator: %u%s"
181 " FPP: %d Packet Duration: %u%s"
182 " FMTP-Extra: %s Audio-Name: %s Sub-Type: %s%s"
183 " Output-Enabled: %d Force-PTIME: %d%s",
184 end_name, VTY_NEWLINE,
185 state->in_stream.err_ts_counter,
186 state->out_stream.err_ts_counter, VTY_NEWLINE,
187 end->dropped_packets, VTY_NEWLINE,
188 codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
189 codec->frame_duration_num, codec->frame_duration_den, VTY_NEWLINE,
190 end->frames_per_packet, end->packet_duration_ms, VTY_NEWLINE,
191 end->fmtp_extra, codec->audio_name, codec->subtype_name, VTY_NEWLINE,
192 end->output_enabled, end->force_output_ptime, VTY_NEWLINE);
193}
194
195static void dump_trunk(struct vty *vty, struct mgcp_trunk_config *cfg, int verbose)
196{
197 int i;
198
199 vty_out(vty, "%s trunk nr %d with %d endpoints:%s",
200 cfg->trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1",
201 cfg->trunk_nr, cfg->number_endpoints - 1, VTY_NEWLINE);
202
203 if (!cfg->endpoints) {
204 vty_out(vty, "No endpoints allocated yet.%s", VTY_NEWLINE);
205 return;
206 }
207
208 for (i = 1; i < cfg->number_endpoints; ++i) {
209 struct mgcp_endpoint *endp = &cfg->endpoints[i];
210 vty_out(vty,
211 " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s "
212 "traffic received bts: %u remote: %u transcoder: %u/%u%s",
213 i, endp->ci,
214 ntohs(endp->net_end.rtp_port), ntohs(endp->net_end.rtcp_port),
215 ntohs(endp->bts_end.rtp_port), ntohs(endp->bts_end.rtcp_port),
216 inet_ntoa(endp->bts_end.addr),
217 endp->bts_end.packets, endp->net_end.packets,
218 endp->trans_net.packets, endp->trans_bts.packets,
219 VTY_NEWLINE);
220
221 if (verbose && endp->allocated) {
222 dump_rtp_end("Net->BTS", vty, &endp->bts_state, &endp->bts_end);
223 dump_rtp_end("BTS->Net", vty, &endp->net_state, &endp->net_end);
224 }
225 }
226}
227
228DEFUN(show_mcgp, show_mgcp_cmd,
229 "show mgcp [stats]",
230 SHOW_STR
231 "Display information about the MGCP Media Gateway\n"
232 "Include Statistics\n")
233{
234 struct mgcp_trunk_config *trunk;
235 int show_stats = argc >= 1;
236
237 dump_trunk(vty, &g_cfg->trunk, show_stats);
238
239 llist_for_each_entry(trunk, &g_cfg->trunks, entry)
240 dump_trunk(vty, trunk, show_stats);
241
242 if (g_cfg->osmux)
243 vty_out(vty, "Osmux used CID: %d%s", osmux_used_cid(), VTY_NEWLINE);
244
245 return CMD_SUCCESS;
246}
247
248DEFUN(cfg_mgcp,
249 cfg_mgcp_cmd,
250 "mgcp",
251 "Configure the MGCP")
252{
253 vty->node = MGCP_NODE;
254 return CMD_SUCCESS;
255}
256
257DEFUN(cfg_mgcp_local_ip,
258 cfg_mgcp_local_ip_cmd,
259 "local ip A.B.C.D",
260 "Local options for the SDP record\n"
261 IP_STR
262 "IPv4 Address to use in SDP record\n")
263{
264 osmo_talloc_replace_string(g_cfg, &g_cfg->local_ip, argv[0]);
265 return CMD_SUCCESS;
266}
267
268DEFUN(cfg_mgcp_bts_ip,
269 cfg_mgcp_bts_ip_cmd,
270 "bts ip A.B.C.D",
271 "BTS Audio source/destination options\n"
272 IP_STR
273 "IPv4 Address of the BTS\n")
274{
275 osmo_talloc_replace_string(g_cfg, &g_cfg->bts_ip, argv[0]);
276 inet_aton(g_cfg->bts_ip, &g_cfg->bts_in);
277 return CMD_SUCCESS;
278}
279
280#define BIND_STR "Listen/Bind related socket option\n"
281DEFUN(cfg_mgcp_bind_ip,
282 cfg_mgcp_bind_ip_cmd,
283 "bind ip A.B.C.D",
284 BIND_STR
285 IP_STR
286 "IPv4 Address to bind to\n")
287{
288 osmo_talloc_replace_string(g_cfg, &g_cfg->source_addr, argv[0]);
289 return CMD_SUCCESS;
290}
291
292DEFUN(cfg_mgcp_bind_port,
293 cfg_mgcp_bind_port_cmd,
294 "bind port <0-65534>",
295 BIND_STR
296 "Port information\n"
297 "UDP port to listen for MGCP messages\n")
298{
299 unsigned int port = atoi(argv[0]);
300 g_cfg->source_port = port;
301 return CMD_SUCCESS;
302}
303
304DEFUN(cfg_mgcp_bind_early,
305 cfg_mgcp_bind_early_cmd,
306 "bind early (0|1)",
307 BIND_STR
308 "Bind local ports on start up\n"
309 "Bind on demand\n" "Bind on startup\n")
310{
311 vty_out(vty, "bind early is deprecated, remove it from the config.\n");
312 return CMD_WARNING;
313}
314
315static void parse_base(struct mgcp_port_range *range, const char **argv)
316{
317 unsigned int port = atoi(argv[0]);
318 range->mode = PORT_ALLOC_STATIC;
319 range->base_port = port;
320}
321
322static void parse_range(struct mgcp_port_range *range, const char **argv)
323{
324 range->mode = PORT_ALLOC_DYNAMIC;
325 range->range_start = atoi(argv[0]);
326 range->range_end = atoi(argv[1]);
327 range->last_port = g_cfg->bts_ports.range_start;
328}
329
330
331#define RTP_STR "RTP configuration\n"
332#define BTS_START_STR "First UDP port allocated for the BTS side\n"
333#define NET_START_STR "First UDP port allocated for the NET side\n"
334#define UDP_PORT_STR "UDP Port number\n"
335DEFUN(cfg_mgcp_rtp_bts_base_port,
336 cfg_mgcp_rtp_bts_base_port_cmd,
337 "rtp bts-base <0-65534>",
338 RTP_STR
339 BTS_START_STR
340 UDP_PORT_STR)
341{
342 parse_base(&g_cfg->bts_ports, argv);
343 return CMD_SUCCESS;
344}
345
346#define RANGE_START_STR "Start of the range of ports\n"
347#define RANGE_END_STR "End of the range of ports\n"
348DEFUN(cfg_mgcp_rtp_bts_range,
349 cfg_mgcp_rtp_bts_range_cmd,
350 "rtp bts-range <0-65534> <0-65534>",
351 RTP_STR "Range of ports to use for the BTS side\n"
352 RANGE_START_STR RANGE_END_STR)
353{
354 parse_range(&g_cfg->bts_ports, argv);
355 return CMD_SUCCESS;
356}
357
358DEFUN(cfg_mgcp_rtp_net_range,
359 cfg_mgcp_rtp_net_range_cmd,
360 "rtp net-range <0-65534> <0-65534>",
361 RTP_STR "Range of ports to use for the NET side\n"
362 RANGE_START_STR RANGE_END_STR)
363{
364 parse_range(&g_cfg->net_ports, argv);
365 return CMD_SUCCESS;
366}
367
368DEFUN(cfg_mgcp_rtp_net_base_port,
369 cfg_mgcp_rtp_net_base_port_cmd,
370 "rtp net-base <0-65534>",
371 RTP_STR NET_START_STR UDP_PORT_STR)
372{
373 parse_base(&g_cfg->net_ports, argv);
374 return CMD_SUCCESS;
375}
376
377ALIAS_DEPRECATED(cfg_mgcp_rtp_bts_base_port, cfg_mgcp_rtp_base_port_cmd,
378 "rtp base <0-65534>",
379 RTP_STR BTS_START_STR UDP_PORT_STR)
380
381DEFUN(cfg_mgcp_rtp_transcoder_range,
382 cfg_mgcp_rtp_transcoder_range_cmd,
383 "rtp transcoder-range <0-65534> <0-65534>",
384 RTP_STR "Range of ports to use for the Transcoder\n"
385 RANGE_START_STR RANGE_END_STR)
386{
387 parse_range(&g_cfg->transcoder_ports, argv);
388 return CMD_SUCCESS;
389}
390
391DEFUN(cfg_mgcp_rtp_transcoder_base,
392 cfg_mgcp_rtp_transcoder_base_cmd,
393 "rtp transcoder-base <0-65534>",
394 RTP_STR "First UDP port allocated for the Transcoder side\n"
395 UDP_PORT_STR)
396{
397 parse_base(&g_cfg->transcoder_ports, argv);
398 return CMD_SUCCESS;
399}
400
401DEFUN(cfg_mgcp_rtp_bts_bind_ip,
402 cfg_mgcp_rtp_bts_bind_ip_cmd,
403 "rtp bts-bind-ip A.B.C.D",
404 RTP_STR "Bind endpoints facing the BTS\n" "Address to bind to\n")
405{
406 osmo_talloc_replace_string(g_cfg, &g_cfg->bts_ports.bind_addr, argv[0]);
407 return CMD_SUCCESS;
408}
409
410DEFUN(cfg_mgcp_rtp_no_bts_bind_ip,
411 cfg_mgcp_rtp_no_bts_bind_ip_cmd,
412 "no rtp bts-bind-ip",
413 NO_STR RTP_STR "Bind endpoints facing the BTS\n" "Address to bind to\n")
414{
415 talloc_free(g_cfg->bts_ports.bind_addr);
416 g_cfg->bts_ports.bind_addr = NULL;
417 return CMD_SUCCESS;
418}
419
420DEFUN(cfg_mgcp_rtp_net_bind_ip,
421 cfg_mgcp_rtp_net_bind_ip_cmd,
422 "rtp net-bind-ip A.B.C.D",
423 RTP_STR "Bind endpoints facing the Network\n" "Address to bind to\n")
424{
425 osmo_talloc_replace_string(g_cfg, &g_cfg->net_ports.bind_addr, argv[0]);
426 return CMD_SUCCESS;
427}
428
429DEFUN(cfg_mgcp_rtp_no_net_bind_ip,
430 cfg_mgcp_rtp_no_net_bind_ip_cmd,
431 "no rtp net-bind-ip",
432 NO_STR RTP_STR "Bind endpoints facing the Network\n" "Address to bind to\n")
433{
434 talloc_free(g_cfg->net_ports.bind_addr);
435 g_cfg->net_ports.bind_addr = NULL;
436 return CMD_SUCCESS;
437}
438
439DEFUN(cfg_mgcp_rtp_ip_dscp,
440 cfg_mgcp_rtp_ip_dscp_cmd,
441 "rtp ip-dscp <0-255>",
442 RTP_STR
443 "Apply IP_TOS to the audio stream (including Osmux)\n" "The DSCP value\n")
444{
445 int dscp = atoi(argv[0]);
446 g_cfg->endp_dscp = dscp;
447 return CMD_SUCCESS;
448}
449
450ALIAS_DEPRECATED(cfg_mgcp_rtp_ip_dscp, cfg_mgcp_rtp_ip_tos_cmd,
451 "rtp ip-tos <0-255>",
452 RTP_STR
453 "Apply IP_TOS to the audio stream\n" "The DSCP value\n")
454
455#define FORCE_PTIME_STR "Force a fixed ptime for packets sent to the BTS"
456DEFUN(cfg_mgcp_rtp_force_ptime,
457 cfg_mgcp_rtp_force_ptime_cmd,
458 "rtp force-ptime (10|20|40)",
459 RTP_STR FORCE_PTIME_STR
460 "The required ptime (packet duration) in ms\n"
461 "10 ms\n20 ms\n40 ms\n")
462{
463 g_cfg->bts_force_ptime = atoi(argv[0]);
464 return CMD_SUCCESS;
465}
466
467DEFUN(cfg_mgcp_no_rtp_force_ptime,
468 cfg_mgcp_no_rtp_force_ptime_cmd,
469 "no rtp force-ptime",
470 NO_STR RTP_STR FORCE_PTIME_STR)
471{
472 g_cfg->bts_force_ptime = 0;
473 return CMD_SUCCESS;
474}
475
476DEFUN(cfg_mgcp_sdp_fmtp_extra,
477 cfg_mgcp_sdp_fmtp_extra_cmd,
478 "sdp audio fmtp-extra .NAME",
479 "Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
480 "Extra Information\n")
481{
482 char *txt = argv_concat(argv, argc, 0);
483 if (!txt)
484 return CMD_WARNING;
485
486 osmo_talloc_replace_string(g_cfg, &g_cfg->trunk.audio_fmtp_extra, txt);
487 talloc_free(txt);
488 return CMD_SUCCESS;
489}
490
491DEFUN(cfg_mgcp_allow_transcoding,
492 cfg_mgcp_allow_transcoding_cmd,
493 "allow-transcoding",
494 "Allow transcoding\n")
495{
496 g_cfg->trunk.no_audio_transcoding = 0;
497 return CMD_SUCCESS;
498}
499
500DEFUN(cfg_mgcp_no_allow_transcoding,
501 cfg_mgcp_no_allow_transcoding_cmd,
502 "no allow-transcoding",
503 NO_STR "Allow transcoding\n")
504{
505 g_cfg->trunk.no_audio_transcoding = 1;
506 return CMD_SUCCESS;
507}
508
509#define SDP_STR "SDP File related options\n"
510#define AUDIO_STR "Audio payload options\n"
511DEFUN(cfg_mgcp_sdp_payload_number,
512 cfg_mgcp_sdp_payload_number_cmd,
513 "sdp audio-payload number <0-255>",
514 SDP_STR AUDIO_STR
515 "Number\n" "Payload number\n")
516{
517 unsigned int payload = atoi(argv[0]);
518 g_cfg->trunk.audio_payload = payload;
519 return CMD_SUCCESS;
520}
521
522ALIAS_DEPRECATED(cfg_mgcp_sdp_payload_number, cfg_mgcp_sdp_payload_number_cmd_old,
523 "sdp audio payload number <0-255>",
524 SDP_STR AUDIO_STR AUDIO_STR "Number\n" "Payload number\n")
525
526
527DEFUN(cfg_mgcp_sdp_payload_name,
528 cfg_mgcp_sdp_payload_name_cmd,
529 "sdp audio-payload name NAME",
530 SDP_STR AUDIO_STR "Name\n" "Payload name\n")
531{
532 osmo_talloc_replace_string(g_cfg, &g_cfg->trunk.audio_name, argv[0]);
533 return CMD_SUCCESS;
534}
535
536ALIAS_DEPRECATED(cfg_mgcp_sdp_payload_name, cfg_mgcp_sdp_payload_name_cmd_old,
537 "sdp audio payload name NAME",
538 SDP_STR AUDIO_STR AUDIO_STR "Name\n" "Payload name\n")
539
540DEFUN(cfg_mgcp_sdp_payload_send_ptime,
541 cfg_mgcp_sdp_payload_send_ptime_cmd,
542 "sdp audio-payload send-ptime",
543 SDP_STR AUDIO_STR
544 "Send SDP ptime (packet duration) attribute\n")
545{
546 g_cfg->trunk.audio_send_ptime = 1;
547 return CMD_SUCCESS;
548}
549
550DEFUN(cfg_mgcp_no_sdp_payload_send_ptime,
551 cfg_mgcp_no_sdp_payload_send_ptime_cmd,
552 "no sdp audio-payload send-ptime",
553 NO_STR SDP_STR AUDIO_STR
554 "Send SDP ptime (packet duration) attribute\n")
555{
556 g_cfg->trunk.audio_send_ptime = 0;
557 return CMD_SUCCESS;
558}
559
560DEFUN(cfg_mgcp_sdp_payload_send_name,
561 cfg_mgcp_sdp_payload_send_name_cmd,
562 "sdp audio-payload send-name",
563 SDP_STR AUDIO_STR
564 "Send SDP rtpmap with the audio name\n")
565{
566 g_cfg->trunk.audio_send_name = 1;
567 return CMD_SUCCESS;
568}
569
570DEFUN(cfg_mgcp_no_sdp_payload_send_name,
571 cfg_mgcp_no_sdp_payload_send_name_cmd,
572 "no sdp audio-payload send-name",
573 NO_STR SDP_STR AUDIO_STR
574 "Send SDP rtpmap with the audio name\n")
575{
576 g_cfg->trunk.audio_send_name = 0;
577 return CMD_SUCCESS;
578}
579
580DEFUN(cfg_mgcp_loop,
581 cfg_mgcp_loop_cmd,
582 "loop (0|1)",
583 "Loop audio for all endpoints on main trunk\n"
584 "Don't Loop\n" "Loop\n")
585{
586 if (g_cfg->osmux) {
587 vty_out(vty, "Cannot use `loop' with `osmux'.%s", VTY_NEWLINE);
588 return CMD_WARNING;
589 }
590 g_cfg->trunk.audio_loop = atoi(argv[0]);
591 return CMD_SUCCESS;
592}
593
594DEFUN(cfg_mgcp_force_realloc,
595 cfg_mgcp_force_realloc_cmd,
596 "force-realloc (0|1)",
597 "Force endpoint reallocation when the endpoint is still seized\n"
598 "Don't force reallocation\n" "force reallocation\n")
599{
600 g_cfg->trunk.force_realloc = atoi(argv[0]);
601 return CMD_SUCCESS;
602}
603
604DEFUN(cfg_mgcp_number_endp,
605 cfg_mgcp_number_endp_cmd,
606 "number endpoints <0-65534>",
607 "Number options\n" "Endpoints available\n" "Number endpoints\n")
608{
609 /* + 1 as we start counting at one */
610 g_cfg->trunk.number_endpoints = atoi(argv[0]) + 1;
611 return CMD_SUCCESS;
612}
613
614DEFUN(cfg_mgcp_omit_rtcp,
615 cfg_mgcp_omit_rtcp_cmd,
616 "rtcp-omit",
617 RTCP_OMIT_STR)
618{
619 g_cfg->trunk.omit_rtcp = 1;
620 return CMD_SUCCESS;
621}
622
623DEFUN(cfg_mgcp_no_omit_rtcp,
624 cfg_mgcp_no_omit_rtcp_cmd,
625 "no rtcp-omit",
626 NO_STR RTCP_OMIT_STR)
627{
628 g_cfg->trunk.omit_rtcp = 0;
629 return CMD_SUCCESS;
630}
631
632DEFUN(cfg_mgcp_patch_rtp_ssrc,
633 cfg_mgcp_patch_rtp_ssrc_cmd,
634 "rtp-patch ssrc",
635 RTP_PATCH_STR
636 "Force a fixed SSRC\n"
637 )
638{
639 g_cfg->trunk.force_constant_ssrc = 1;
640 return CMD_SUCCESS;
641}
642
643DEFUN(cfg_mgcp_no_patch_rtp_ssrc,
644 cfg_mgcp_no_patch_rtp_ssrc_cmd,
645 "no rtp-patch ssrc",
646 NO_STR RTP_PATCH_STR
647 "Force a fixed SSRC\n"
648 )
649{
650 g_cfg->trunk.force_constant_ssrc = 0;
651 return CMD_SUCCESS;
652}
653
654DEFUN(cfg_mgcp_patch_rtp_ts,
655 cfg_mgcp_patch_rtp_ts_cmd,
656 "rtp-patch timestamp",
657 RTP_PATCH_STR
658 "Adjust RTP timestamp\n"
659 )
660{
661 g_cfg->trunk.force_aligned_timing = 1;
662 return CMD_SUCCESS;
663}
664
665DEFUN(cfg_mgcp_no_patch_rtp_ts,
666 cfg_mgcp_no_patch_rtp_ts_cmd,
667 "no rtp-patch timestamp",
668 NO_STR RTP_PATCH_STR
669 "Adjust RTP timestamp\n"
670 )
671{
672 g_cfg->trunk.force_aligned_timing = 0;
673 return CMD_SUCCESS;
674}
675
676DEFUN(cfg_mgcp_no_patch_rtp,
677 cfg_mgcp_no_patch_rtp_cmd,
678 "no rtp-patch",
679 NO_STR RTP_PATCH_STR)
680{
681 g_cfg->trunk.force_constant_ssrc = 0;
682 g_cfg->trunk.force_aligned_timing = 0;
683 return CMD_SUCCESS;
684}
685
686DEFUN(cfg_mgcp_rtp_keepalive,
687 cfg_mgcp_rtp_keepalive_cmd,
688 "rtp keep-alive <1-120>",
689 RTP_STR RTP_KEEPALIVE_STR
690 "Keep alive interval in secs\n"
691 )
692{
693 mgcp_trunk_set_keepalive(&g_cfg->trunk, atoi(argv[0]));
694 return CMD_SUCCESS;
695}
696
697DEFUN(cfg_mgcp_rtp_keepalive_once,
698 cfg_mgcp_rtp_keepalive_once_cmd,
699 "rtp keep-alive once",
700 RTP_STR RTP_KEEPALIVE_STR
701 "Send dummy packet only once after CRCX/MDCX\n"
702 )
703{
704 mgcp_trunk_set_keepalive(&g_cfg->trunk, MGCP_KEEPALIVE_ONCE);
705 return CMD_SUCCESS;
706}
707
708DEFUN(cfg_mgcp_no_rtp_keepalive,
709 cfg_mgcp_no_rtp_keepalive_cmd,
710 "no rtp keep-alive",
711 NO_STR RTP_STR RTP_KEEPALIVE_STR
712 )
713{
714 mgcp_trunk_set_keepalive(&g_cfg->trunk, 0);
715 return CMD_SUCCESS;
716}
717
718
719
720#define CALL_AGENT_STR "Callagent information\n"
721DEFUN(cfg_mgcp_agent_addr,
722 cfg_mgcp_agent_addr_cmd,
723 "call-agent ip A.B.C.D",
724 CALL_AGENT_STR IP_STR
725 "IPv4 Address of the callagent\n")
726{
727 osmo_talloc_replace_string(g_cfg, &g_cfg->call_agent_addr, argv[0]);
728 return CMD_SUCCESS;
729}
730
731ALIAS_DEPRECATED(cfg_mgcp_agent_addr, cfg_mgcp_agent_addr_cmd_old,
732 "call agent ip A.B.C.D",
733 CALL_AGENT_STR CALL_AGENT_STR IP_STR
734 "IPv4 Address of the callagent\n")
735
736
737DEFUN(cfg_mgcp_transcoder,
738 cfg_mgcp_transcoder_cmd,
739 "transcoder-mgw A.B.C.D",
740 "Use a MGW to detranscoder RTP\n"
741 "The IP address of the MGW")
742{
743 osmo_talloc_replace_string(g_cfg, &g_cfg->transcoder_ip, argv[0]);
744 inet_aton(g_cfg->transcoder_ip, &g_cfg->transcoder_in);
745
746 return CMD_SUCCESS;
747}
748
749DEFUN(cfg_mgcp_no_transcoder,
750 cfg_mgcp_no_transcoder_cmd,
751 "no transcoder-mgw",
752 NO_STR "Disable the transcoding\n")
753{
754 if (g_cfg->transcoder_ip) {
755 LOGP(DLMGCP, LOGL_NOTICE, "Disabling transcoding on future calls.\n");
756 talloc_free(g_cfg->transcoder_ip);
757 g_cfg->transcoder_ip = NULL;
758 }
759
760 return CMD_SUCCESS;
761}
762
763DEFUN(cfg_mgcp_transcoder_remote_base,
764 cfg_mgcp_transcoder_remote_base_cmd,
765 "transcoder-remote-base <0-65534>",
766 "Set the base port for the transcoder\n" "The RTP base port on the transcoder")
767{
768 g_cfg->transcoder_remote_base = atoi(argv[0]);
769 return CMD_SUCCESS;
770}
771
772DEFUN(cfg_mgcp_trunk, cfg_mgcp_trunk_cmd,
773 "trunk <1-64>",
774 "Configure a SS7 trunk\n" "Trunk Nr\n")
775{
776 struct mgcp_trunk_config *trunk;
777 int index = atoi(argv[0]);
778
779 trunk = mgcp_trunk_num(g_cfg, index);
780 if (!trunk)
781 trunk = mgcp_trunk_alloc(g_cfg, index);
782
783 if (!trunk) {
784 vty_out(vty, "%%Unable to allocate trunk %u.%s",
785 index, VTY_NEWLINE);
786 return CMD_WARNING;
787 }
788
789 vty->node = TRUNK_NODE;
790 vty->index = trunk;
791 return CMD_SUCCESS;
792}
793
794static int config_write_trunk(struct vty *vty)
795{
796 struct mgcp_trunk_config *trunk;
797
798 llist_for_each_entry(trunk, &g_cfg->trunks, entry) {
799 vty_out(vty, " trunk %d%s", trunk->trunk_nr, VTY_NEWLINE);
800 vty_out(vty, " sdp audio-payload number %d%s",
801 trunk->audio_payload, VTY_NEWLINE);
802 vty_out(vty, " sdp audio-payload name %s%s",
803 trunk->audio_name, VTY_NEWLINE);
804 vty_out(vty, " %ssdp audio-payload send-ptime%s",
805 trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
806 vty_out(vty, " %ssdp audio-payload send-name%s",
807 trunk->audio_send_name ? "" : "no ", VTY_NEWLINE);
808
809 if (trunk->keepalive_interval == MGCP_KEEPALIVE_ONCE)
810 vty_out(vty, " rtp keep-alive once%s", VTY_NEWLINE);
811 else if (trunk->keepalive_interval)
812 vty_out(vty, " rtp keep-alive %d%s",
813 trunk->keepalive_interval, VTY_NEWLINE);
814 else
815 vty_out(vty, " no rtp keep-alive%s", VTY_NEWLINE);
816 vty_out(vty, " loop %d%s",
817 trunk->audio_loop, VTY_NEWLINE);
818 vty_out(vty, " force-realloc %d%s",
819 trunk->force_realloc, VTY_NEWLINE);
820 if (trunk->omit_rtcp)
821 vty_out(vty, " rtcp-omit%s", VTY_NEWLINE);
822 else
823 vty_out(vty, " no rtcp-omit%s", VTY_NEWLINE);
824 if (trunk->force_constant_ssrc || trunk->force_aligned_timing) {
825 vty_out(vty, " %srtp-patch ssrc%s",
826 trunk->force_constant_ssrc ? "" : "no ", VTY_NEWLINE);
827 vty_out(vty, " %srtp-patch timestamp%s",
828 trunk->force_aligned_timing ? "" : "no ", VTY_NEWLINE);
829 } else
830 vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
831 if (trunk->audio_fmtp_extra)
832 vty_out(vty, " sdp audio fmtp-extra %s%s",
833 trunk->audio_fmtp_extra, VTY_NEWLINE);
834 vty_out(vty, " %sallow-transcoding%s",
835 trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
836 }
837
838 return CMD_SUCCESS;
839}
840
841DEFUN(cfg_trunk_sdp_fmtp_extra,
842 cfg_trunk_sdp_fmtp_extra_cmd,
843 "sdp audio fmtp-extra .NAME",
844 "Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
845 "Extra Information\n")
846{
847 struct mgcp_trunk_config *trunk = vty->index;
848 char *txt = argv_concat(argv, argc, 0);
849 if (!txt)
850 return CMD_WARNING;
851
852 osmo_talloc_replace_string(g_cfg, &trunk->audio_fmtp_extra, txt);
853 talloc_free(txt);
854 return CMD_SUCCESS;
855}
856
857DEFUN(cfg_trunk_payload_number,
858 cfg_trunk_payload_number_cmd,
859 "sdp audio-payload number <0-255>",
860 SDP_STR AUDIO_STR "Number\n" "Payload Number\n")
861{
862 struct mgcp_trunk_config *trunk = vty->index;
863 unsigned int payload = atoi(argv[0]);
864
865 trunk->audio_payload = payload;
866 return CMD_SUCCESS;
867}
868
869ALIAS_DEPRECATED(cfg_trunk_payload_number, cfg_trunk_payload_number_cmd_old,
870 "sdp audio payload number <0-255>",
871 SDP_STR AUDIO_STR AUDIO_STR "Number\n" "Payload Number\n")
872
873DEFUN(cfg_trunk_payload_name,
874 cfg_trunk_payload_name_cmd,
875 "sdp audio-payload name NAME",
876 SDP_STR AUDIO_STR "Payload\n" "Payload Name\n")
877{
878 struct mgcp_trunk_config *trunk = vty->index;
879
880 osmo_talloc_replace_string(g_cfg, &trunk->audio_name, argv[0]);
881 return CMD_SUCCESS;
882}
883
884ALIAS_DEPRECATED(cfg_trunk_payload_name, cfg_trunk_payload_name_cmd_old,
885 "sdp audio payload name NAME",
886 SDP_STR AUDIO_STR AUDIO_STR "Payload\n" "Payload Name\n")
887
888
889DEFUN(cfg_trunk_loop,
890 cfg_trunk_loop_cmd,
891 "loop (0|1)",
892 "Loop audio for all endpoints on this trunk\n"
893 "Don't Loop\n" "Loop\n")
894{
895 struct mgcp_trunk_config *trunk = vty->index;
896
897 if (g_cfg->osmux) {
898 vty_out(vty, "Cannot use `loop' with `osmux'.%s", VTY_NEWLINE);
899 return CMD_WARNING;
900 }
901 trunk->audio_loop = atoi(argv[0]);
902 return CMD_SUCCESS;
903}
904
905DEFUN(cfg_trunk_sdp_payload_send_ptime,
906 cfg_trunk_sdp_payload_send_ptime_cmd,
907 "sdp audio-payload send-ptime",
908 SDP_STR AUDIO_STR
909 "Send SDP ptime (packet duration) attribute\n")
910{
911 struct mgcp_trunk_config *trunk = vty->index;
912 trunk->audio_send_ptime = 1;
913 return CMD_SUCCESS;
914}
915
916DEFUN(cfg_trunk_no_sdp_payload_send_ptime,
917 cfg_trunk_no_sdp_payload_send_ptime_cmd,
918 "no sdp audio-payload send-ptime",
919 NO_STR SDP_STR AUDIO_STR
920 "Send SDP ptime (packet duration) attribute\n")
921{
922 struct mgcp_trunk_config *trunk = vty->index;
923 trunk->audio_send_ptime = 0;
924 return CMD_SUCCESS;
925}
926
927DEFUN(cfg_trunk_sdp_payload_send_name,
928 cfg_trunk_sdp_payload_send_name_cmd,
929 "sdp audio-payload send-name",
930 SDP_STR AUDIO_STR
931 "Send SDP rtpmap with the audio name\n")
932{
933 struct mgcp_trunk_config *trunk = vty->index;
934 trunk->audio_send_name = 1;
935 return CMD_SUCCESS;
936}
937
938DEFUN(cfg_trunk_no_sdp_payload_send_name,
939 cfg_trunk_no_sdp_payload_send_name_cmd,
940 "no sdp audio-payload send-name",
941 NO_STR SDP_STR AUDIO_STR
942 "Send SDP rtpmap with the audio name\n")
943{
944 struct mgcp_trunk_config *trunk = vty->index;
945 trunk->audio_send_name = 0;
946 return CMD_SUCCESS;
947}
948
949DEFUN(cfg_trunk_omit_rtcp,
950 cfg_trunk_omit_rtcp_cmd,
951 "rtcp-omit",
952 RTCP_OMIT_STR)
953{
954 struct mgcp_trunk_config *trunk = vty->index;
955 trunk->omit_rtcp = 1;
956 return CMD_SUCCESS;
957}
958
959DEFUN(cfg_trunk_no_omit_rtcp,
960 cfg_trunk_no_omit_rtcp_cmd,
961 "no rtcp-omit",
962 NO_STR RTCP_OMIT_STR)
963{
964 struct mgcp_trunk_config *trunk = vty->index;
965 trunk->omit_rtcp = 0;
966 return CMD_SUCCESS;
967}
968
969DEFUN(cfg_trunk_patch_rtp_ssrc,
970 cfg_trunk_patch_rtp_ssrc_cmd,
971 "rtp-patch ssrc",
972 RTP_PATCH_STR
973 "Force a fixed SSRC\n"
974 )
975{
976 struct mgcp_trunk_config *trunk = vty->index;
977 trunk->force_constant_ssrc = 1;
978 return CMD_SUCCESS;
979}
980
981DEFUN(cfg_trunk_no_patch_rtp_ssrc,
982 cfg_trunk_no_patch_rtp_ssrc_cmd,
983 "no rtp-patch ssrc",
984 NO_STR RTP_PATCH_STR
985 "Force a fixed SSRC\n"
986 )
987{
988 struct mgcp_trunk_config *trunk = vty->index;
989 trunk->force_constant_ssrc = 0;
990 return CMD_SUCCESS;
991}
992
993DEFUN(cfg_trunk_patch_rtp_ts,
994 cfg_trunk_patch_rtp_ts_cmd,
995 "rtp-patch timestamp",
996 RTP_PATCH_STR
997 "Adjust RTP timestamp\n"
998 )
999{
1000 struct mgcp_trunk_config *trunk = vty->index;
1001 trunk->force_aligned_timing = 1;
1002 return CMD_SUCCESS;
1003}
1004
1005DEFUN(cfg_trunk_no_patch_rtp_ts,
1006 cfg_trunk_no_patch_rtp_ts_cmd,
1007 "no rtp-patch timestamp",
1008 NO_STR RTP_PATCH_STR
1009 "Adjust RTP timestamp\n"
1010 )
1011{
1012 struct mgcp_trunk_config *trunk = vty->index;
1013 trunk->force_aligned_timing = 0;
1014 return CMD_SUCCESS;
1015}
1016
1017DEFUN(cfg_trunk_no_patch_rtp,
1018 cfg_trunk_no_patch_rtp_cmd,
1019 "no rtp-patch",
1020 NO_STR RTP_PATCH_STR)
1021{
1022 struct mgcp_trunk_config *trunk = vty->index;
1023 trunk->force_constant_ssrc = 0;
1024 trunk->force_aligned_timing = 0;
1025 return CMD_SUCCESS;
1026}
1027
1028DEFUN(cfg_trunk_rtp_keepalive,
1029 cfg_trunk_rtp_keepalive_cmd,
1030 "rtp keep-alive <1-120>",
1031 RTP_STR RTP_KEEPALIVE_STR
1032 "Keep-alive interval in secs\n"
1033 )
1034{
1035 struct mgcp_trunk_config *trunk = vty->index;
1036 mgcp_trunk_set_keepalive(trunk, atoi(argv[0]));
1037 return CMD_SUCCESS;
1038}
1039
1040DEFUN(cfg_trunk_rtp_keepalive_once,
1041 cfg_trunk_rtp_keepalive_once_cmd,
1042 "rtp keep-alive once",
1043 RTP_STR RTP_KEEPALIVE_STR
1044 "Send dummy packet only once after CRCX/MDCX\n"
1045 )
1046{
1047 struct mgcp_trunk_config *trunk = vty->index;
1048 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
1049 return CMD_SUCCESS;
1050}
1051
1052DEFUN(cfg_trunk_no_rtp_keepalive,
1053 cfg_trunk_no_rtp_keepalive_cmd,
1054 "no rtp keep-alive",
1055 NO_STR RTP_STR RTP_KEEPALIVE_STR
1056 )
1057{
1058 struct mgcp_trunk_config *trunk = vty->index;
1059 mgcp_trunk_set_keepalive(trunk, 0);
1060 return CMD_SUCCESS;
1061}
1062
1063DEFUN(cfg_trunk_allow_transcoding,
1064 cfg_trunk_allow_transcoding_cmd,
1065 "allow-transcoding",
1066 "Allow transcoding\n")
1067{
1068 struct mgcp_trunk_config *trunk = vty->index;
1069 trunk->no_audio_transcoding = 0;
1070 return CMD_SUCCESS;
1071}
1072
1073DEFUN(cfg_trunk_no_allow_transcoding,
1074 cfg_trunk_no_allow_transcoding_cmd,
1075 "no allow-transcoding",
1076 NO_STR "Allow transcoding\n")
1077{
1078 struct mgcp_trunk_config *trunk = vty->index;
1079 trunk->no_audio_transcoding = 1;
1080 return CMD_SUCCESS;
1081}
1082
1083DEFUN(loop_endp,
1084 loop_endp_cmd,
1085 "loop-endpoint <0-64> NAME (0|1)",
1086 "Loop a given endpoint\n" "Trunk number\n"
1087 "The name in hex of the endpoint\n" "Disable the loop\n" "Enable the loop\n")
1088{
1089 struct mgcp_trunk_config *trunk;
1090 struct mgcp_endpoint *endp;
1091
1092 trunk = find_trunk(g_cfg, atoi(argv[0]));
1093 if (!trunk) {
1094 vty_out(vty, "%%Trunk %d not found in the config.%s",
1095 atoi(argv[0]), VTY_NEWLINE);
1096 return CMD_WARNING;
1097 }
1098
1099 if (!trunk->endpoints) {
1100 vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
1101 trunk->trunk_nr, VTY_NEWLINE);
1102 return CMD_WARNING;
1103 }
1104
1105 int endp_no = strtoul(argv[1], NULL, 16);
1106 if (endp_no < 1 || endp_no >= trunk->number_endpoints) {
1107 vty_out(vty, "Loopback number %s/%d is invalid.%s",
1108 argv[1], endp_no, VTY_NEWLINE);
1109 return CMD_WARNING;
1110 }
1111
1112
1113 endp = &trunk->endpoints[endp_no];
1114 int loop = atoi(argv[2]);
1115
1116 if (loop)
1117 endp->conn_mode = MGCP_CONN_LOOPBACK;
1118 else
1119 endp->conn_mode = endp->orig_mode;
1120
1121 /* Handle it like a MDCX, switch on SSRC patching if enabled */
1122 mgcp_rtp_end_config(endp, 1, &endp->bts_end);
1123 mgcp_rtp_end_config(endp, 1, &endp->net_end);
1124
1125 return CMD_SUCCESS;
1126}
1127
1128DEFUN(tap_call,
1129 tap_call_cmd,
1130 "tap-call <0-64> ENDPOINT (bts-in|bts-out|net-in|net-out) A.B.C.D <0-65534>",
1131 "Forward data on endpoint to a different system\n" "Trunk number\n"
1132 "The endpoint in hex\n"
1133 "Forward the data coming from the bts\n"
1134 "Forward the data coming from the bts leaving to the network\n"
1135 "Forward the data coming from the net\n"
1136 "Forward the data coming from the net leaving to the bts\n"
1137 "destination IP of the data\n" "destination port\n")
1138{
1139 struct mgcp_rtp_tap *tap;
1140 struct mgcp_trunk_config *trunk;
1141 struct mgcp_endpoint *endp;
1142 int port = 0;
1143
1144 trunk = find_trunk(g_cfg, atoi(argv[0]));
1145 if (!trunk) {
1146 vty_out(vty, "%%Trunk %d not found in the config.%s",
1147 atoi(argv[0]), VTY_NEWLINE);
1148 return CMD_WARNING;
1149 }
1150
1151 if (!trunk->endpoints) {
1152 vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
1153 trunk->trunk_nr, VTY_NEWLINE);
1154 return CMD_WARNING;
1155 }
1156
1157 int endp_no = strtoul(argv[1], NULL, 16);
1158 if (endp_no < 1 || endp_no >= trunk->number_endpoints) {
1159 vty_out(vty, "Endpoint number %s/%d is invalid.%s",
1160 argv[1], endp_no, VTY_NEWLINE);
1161 return CMD_WARNING;
1162 }
1163
1164 endp = &trunk->endpoints[endp_no];
1165
1166 if (strcmp(argv[2], "bts-in") == 0) {
1167 port = MGCP_TAP_BTS_IN;
1168 } else if (strcmp(argv[2], "bts-out") == 0) {
1169 port = MGCP_TAP_BTS_OUT;
1170 } else if (strcmp(argv[2], "net-in") == 0) {
1171 port = MGCP_TAP_NET_IN;
1172 } else if (strcmp(argv[2], "net-out") == 0) {
1173 port = MGCP_TAP_NET_OUT;
1174 } else {
1175 vty_out(vty, "Unknown mode... tricked vty?%s", VTY_NEWLINE);
1176 return CMD_WARNING;
1177 }
1178
1179 tap = &endp->taps[port];
1180 memset(&tap->forward, 0, sizeof(tap->forward));
1181 inet_aton(argv[3], &tap->forward.sin_addr);
1182 tap->forward.sin_port = htons(atoi(argv[4]));
1183 tap->enabled = 1;
1184 return CMD_SUCCESS;
1185}
1186
1187DEFUN(free_endp, free_endp_cmd,
1188 "free-endpoint <0-64> NUMBER",
1189 "Free the given endpoint\n" "Trunk number\n"
1190 "Endpoint number in hex.\n")
1191{
1192 struct mgcp_trunk_config *trunk;
1193 struct mgcp_endpoint *endp;
1194
1195 trunk = find_trunk(g_cfg, atoi(argv[0]));
1196 if (!trunk) {
1197 vty_out(vty, "%%Trunk %d not found in the config.%s",
1198 atoi(argv[0]), VTY_NEWLINE);
1199 return CMD_WARNING;
1200 }
1201
1202 if (!trunk->endpoints) {
1203 vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
1204 trunk->trunk_nr, VTY_NEWLINE);
1205 return CMD_WARNING;
1206 }
1207
1208 int endp_no = strtoul(argv[1], NULL, 16);
1209 if (endp_no < 1 || endp_no >= trunk->number_endpoints) {
1210 vty_out(vty, "Endpoint number %s/%d is invalid.%s",
1211 argv[1], endp_no, VTY_NEWLINE);
1212 return CMD_WARNING;
1213 }
1214
1215 endp = &trunk->endpoints[endp_no];
1216 mgcp_release_endp(endp);
1217 return CMD_SUCCESS;
1218}
1219
1220DEFUN(reset_endp, reset_endp_cmd,
1221 "reset-endpoint <0-64> NUMBER",
1222 "Reset the given endpoint\n" "Trunk number\n"
1223 "Endpoint number in hex.\n")
1224{
1225 struct mgcp_trunk_config *trunk;
1226 struct mgcp_endpoint *endp;
1227 int endp_no, rc;
1228
1229 trunk = find_trunk(g_cfg, atoi(argv[0]));
1230 if (!trunk) {
1231 vty_out(vty, "%%Trunk %d not found in the config.%s",
1232 atoi(argv[0]), VTY_NEWLINE);
1233 return CMD_WARNING;
1234 }
1235
1236 if (!trunk->endpoints) {
1237 vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
1238 trunk->trunk_nr, VTY_NEWLINE);
1239 return CMD_WARNING;
1240 }
1241
1242 endp_no = strtoul(argv[1], NULL, 16);
1243 if (endp_no < 1 || endp_no >= trunk->number_endpoints) {
1244 vty_out(vty, "Endpoint number %s/%d is invalid.%s",
1245 argv[1], endp_no, VTY_NEWLINE);
1246 return CMD_WARNING;
1247 }
1248
1249 endp = &trunk->endpoints[endp_no];
1250 rc = mgcp_send_reset_ep(endp, ENDPOINT_NUMBER(endp));
1251 if (rc < 0) {
1252 vty_out(vty, "Error %d sending reset.%s", rc, VTY_NEWLINE);
1253 return CMD_WARNING;
1254 }
1255 return CMD_SUCCESS;
1256}
1257
1258DEFUN(reset_all_endp, reset_all_endp_cmd,
1259 "reset-all-endpoints",
1260 "Reset all endpoints\n")
1261{
1262 int rc;
1263
1264 rc = mgcp_send_reset_all(g_cfg);
1265 if (rc < 0) {
1266 vty_out(vty, "Error %d during endpoint reset.%s",
1267 rc, VTY_NEWLINE);
1268 return CMD_WARNING;
1269 }
1270 return CMD_SUCCESS;
1271}
1272
1273#define OSMUX_STR "RTP multiplexing\n"
1274DEFUN(cfg_mgcp_osmux,
1275 cfg_mgcp_osmux_cmd,
1276 "osmux (on|off|only)",
1277 OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n" "Only use OSMUX\n")
1278{
1279 if (strcmp(argv[0], "off") == 0) {
1280 g_cfg->osmux = OSMUX_USAGE_OFF;
1281 return CMD_SUCCESS;
1282 }
1283
1284 if (strcmp(argv[0], "on") == 0)
1285 g_cfg->osmux = OSMUX_USAGE_ON;
1286 else if (strcmp(argv[0], "only") == 0)
1287 g_cfg->osmux = OSMUX_USAGE_ONLY;
1288
1289 if (g_cfg->trunk.audio_loop) {
1290 vty_out(vty, "Cannot use `loop' with `osmux'.%s",
1291 VTY_NEWLINE);
1292 return CMD_WARNING;
1293 }
1294
1295 return CMD_SUCCESS;
1296}
1297
1298DEFUN(cfg_mgcp_osmux_ip,
1299 cfg_mgcp_osmux_ip_cmd,
1300 "osmux bind-ip A.B.C.D",
1301 OSMUX_STR IP_STR "IPv4 Address to bind to\n")
1302{
1303 osmo_talloc_replace_string(g_cfg, &g_cfg->osmux_addr, argv[0]);
1304 return CMD_SUCCESS;
1305}
1306
1307DEFUN(cfg_mgcp_osmux_batch_factor,
1308 cfg_mgcp_osmux_batch_factor_cmd,
1309 "osmux batch-factor <1-8>",
1310 OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
1311{
1312 g_cfg->osmux_batch = atoi(argv[0]);
1313 return CMD_SUCCESS;
1314}
1315
1316DEFUN(cfg_mgcp_osmux_batch_size,
1317 cfg_mgcp_osmux_batch_size_cmd,
1318 "osmux batch-size <1-65535>",
1319 OSMUX_STR "batch size\n" "Batch size in bytes\n")
1320{
1321 g_cfg->osmux_batch_size = atoi(argv[0]);
1322 return CMD_SUCCESS;
1323}
1324
1325DEFUN(cfg_mgcp_osmux_port,
1326 cfg_mgcp_osmux_port_cmd,
1327 "osmux port <1-65535>",
1328 OSMUX_STR "port\n" "UDP port\n")
1329{
1330 g_cfg->osmux_port = atoi(argv[0]);
1331 return CMD_SUCCESS;
1332}
1333
1334DEFUN(cfg_mgcp_osmux_dummy,
1335 cfg_mgcp_osmux_dummy_cmd,
1336 "osmux dummy (on|off)",
1337 OSMUX_STR "Dummy padding\n" "Enable dummy padding\n" "Disable dummy padding\n")
1338{
1339 if (strcmp(argv[0], "on") == 0)
1340 g_cfg->osmux_dummy = 1;
1341 else if (strcmp(argv[0], "off") == 0)
1342 g_cfg->osmux_dummy = 0;
1343
1344 return CMD_SUCCESS;
1345}
1346
1347int mgcp_vty_init(void)
1348{
1349 install_element_ve(&show_mgcp_cmd);
1350 install_element(ENABLE_NODE, &loop_endp_cmd);
1351 install_element(ENABLE_NODE, &tap_call_cmd);
1352 install_element(ENABLE_NODE, &free_endp_cmd);
1353 install_element(ENABLE_NODE, &reset_endp_cmd);
1354 install_element(ENABLE_NODE, &reset_all_endp_cmd);
1355
1356 install_element(CONFIG_NODE, &cfg_mgcp_cmd);
1357 install_node(&mgcp_node, config_write_mgcp);
1358
1359 vty_install_default(MGCP_NODE);
1360 install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd);
1361 install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd);
1362 install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd);
1363 install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd);
1364 install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd);
1365 install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd);
1366 install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_base_port_cmd);
1367 install_element(MGCP_NODE, &cfg_mgcp_rtp_net_base_port_cmd);
1368 install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_range_cmd);
1369 install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_bind_ip_cmd);
1370 install_element(MGCP_NODE, &cfg_mgcp_rtp_no_bts_bind_ip_cmd);
1371 install_element(MGCP_NODE, &cfg_mgcp_rtp_net_range_cmd);
1372 install_element(MGCP_NODE, &cfg_mgcp_rtp_net_bind_ip_cmd);
1373 install_element(MGCP_NODE, &cfg_mgcp_rtp_no_net_bind_ip_cmd);
1374 install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_range_cmd);
1375 install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_base_cmd);
1376 install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
1377 install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
1378 install_element(MGCP_NODE, &cfg_mgcp_rtp_force_ptime_cmd);
1379 install_element(MGCP_NODE, &cfg_mgcp_no_rtp_force_ptime_cmd);
1380 install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_cmd);
1381 install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_once_cmd);
1382 install_element(MGCP_NODE, &cfg_mgcp_no_rtp_keepalive_cmd);
1383 install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd);
1384 install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd_old);
1385 install_element(MGCP_NODE, &cfg_mgcp_transcoder_cmd);
1386 install_element(MGCP_NODE, &cfg_mgcp_no_transcoder_cmd);
1387 install_element(MGCP_NODE, &cfg_mgcp_transcoder_remote_base_cmd);
1388 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
1389 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
1390 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd_old);
1391 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd_old);
1392 install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
1393 install_element(MGCP_NODE, &cfg_mgcp_force_realloc_cmd);
1394 install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
1395 install_element(MGCP_NODE, &cfg_mgcp_omit_rtcp_cmd);
1396 install_element(MGCP_NODE, &cfg_mgcp_no_omit_rtcp_cmd);
1397 install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_ssrc_cmd);
1398 install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ssrc_cmd);
1399 install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_ts_cmd);
1400 install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ts_cmd);
1401 install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_cmd);
1402 install_element(MGCP_NODE, &cfg_mgcp_sdp_fmtp_extra_cmd);
1403 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_send_ptime_cmd);
1404 install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_ptime_cmd);
1405 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_send_name_cmd);
1406 install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
1407 install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
1408 install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
1409 install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
1410 install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
1411 install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
1412 install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
1413 install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
1414 install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
1415
1416
1417 install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
1418 install_node(&trunk_node, config_write_trunk);
1419 vty_install_default(TRUNK_NODE);
1420 install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_cmd);
1421 install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_once_cmd);
1422 install_element(TRUNK_NODE, &cfg_trunk_no_rtp_keepalive_cmd);
1423 install_element(TRUNK_NODE, &cfg_trunk_payload_number_cmd);
1424 install_element(TRUNK_NODE, &cfg_trunk_payload_name_cmd);
1425 install_element(TRUNK_NODE, &cfg_trunk_payload_number_cmd_old);
1426 install_element(TRUNK_NODE, &cfg_trunk_payload_name_cmd_old);
1427 install_element(TRUNK_NODE, &cfg_trunk_loop_cmd);
1428 install_element(TRUNK_NODE, &cfg_trunk_omit_rtcp_cmd);
1429 install_element(TRUNK_NODE, &cfg_trunk_no_omit_rtcp_cmd);
1430 install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ssrc_cmd);
1431 install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ssrc_cmd);
1432 install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ts_cmd);
1433 install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ts_cmd);
1434 install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_cmd);
1435 install_element(TRUNK_NODE, &cfg_trunk_sdp_fmtp_extra_cmd);
1436 install_element(TRUNK_NODE, &cfg_trunk_sdp_payload_send_ptime_cmd);
1437 install_element(TRUNK_NODE, &cfg_trunk_no_sdp_payload_send_ptime_cmd);
1438 install_element(TRUNK_NODE, &cfg_trunk_sdp_payload_send_name_cmd);
1439 install_element(TRUNK_NODE, &cfg_trunk_no_sdp_payload_send_name_cmd);
1440 install_element(TRUNK_NODE, &cfg_trunk_allow_transcoding_cmd);
1441 install_element(TRUNK_NODE, &cfg_trunk_no_allow_transcoding_cmd);
1442
1443 return 0;
1444}
1445
1446static int allocate_trunk(struct mgcp_trunk_config *trunk)
1447{
1448 int i;
1449 struct mgcp_config *cfg = trunk->cfg;
1450
1451 if (mgcp_endpoints_allocate(trunk) != 0) {
1452 LOGP(DLMGCP, LOGL_ERROR,
1453 "Failed to allocate %d endpoints on trunk %d.\n",
1454 trunk->number_endpoints, trunk->trunk_nr);
1455 return -1;
1456 }
1457
1458 /* early bind */
1459 for (i = 1; i < trunk->number_endpoints; ++i) {
1460 struct mgcp_endpoint *endp = &trunk->endpoints[i];
1461
1462 if (cfg->bts_ports.mode == PORT_ALLOC_STATIC) {
1463 cfg->last_bts_port += 2;
1464 if (mgcp_bind_bts_rtp_port(endp, cfg->last_bts_port) != 0) {
1465 LOGP(DLMGCP, LOGL_FATAL,
1466 "Failed to bind: %d\n", cfg->last_bts_port);
1467 return -1;
1468 }
1469 endp->bts_end.local_alloc = PORT_ALLOC_STATIC;
1470 }
1471
1472 if (cfg->net_ports.mode == PORT_ALLOC_STATIC) {
1473 cfg->last_net_port += 2;
1474 if (mgcp_bind_net_rtp_port(endp, cfg->last_net_port) != 0) {
1475 LOGP(DLMGCP, LOGL_FATAL,
1476 "Failed to bind: %d\n", cfg->last_net_port);
1477 return -1;
1478 }
1479 endp->net_end.local_alloc = PORT_ALLOC_STATIC;
1480 }
1481
1482 if (trunk->trunk_type == MGCP_TRUNK_VIRTUAL &&
1483 cfg->transcoder_ip && cfg->transcoder_ports.mode == PORT_ALLOC_STATIC) {
1484 int rtp_port;
1485
1486 /* network side */
1487 rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp),
1488 cfg->transcoder_ports.base_port);
1489 if (mgcp_bind_trans_net_rtp_port(endp, rtp_port) != 0) {
1490 LOGP(DLMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
1491 return -1;
1492 }
1493 endp->trans_net.local_alloc = PORT_ALLOC_STATIC;
1494
1495 /* bts side */
1496 rtp_port = rtp_calculate_port(endp_back_channel(ENDPOINT_NUMBER(endp)),
1497 cfg->transcoder_ports.base_port);
1498 if (mgcp_bind_trans_bts_rtp_port(endp, rtp_port) != 0) {
1499 LOGP(DLMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
1500 return -1;
1501 }
1502 endp->trans_bts.local_alloc = PORT_ALLOC_STATIC;
1503 }
1504 }
1505
1506 return 0;
1507}
1508
1509int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
1510 enum mgcp_role role)
1511{
1512 int rc;
1513 struct mgcp_trunk_config *trunk;
1514
1515 cfg->osmux_port = OSMUX_PORT;
1516 cfg->osmux_batch = 4;
1517 cfg->osmux_batch_size = OSMUX_BATCH_DEFAULT_MAX;
1518
1519 g_cfg = cfg;
1520 rc = vty_read_config_file(config_file, NULL);
1521 if (rc < 0) {
1522 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1523 return rc;
1524 }
1525
1526
1527 if (!g_cfg->bts_ip)
1528 fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
1529
1530 if (!g_cfg->source_addr) {
1531 fprintf(stderr, "You need to specify a bind address.\n");
1532 return -1;
1533 }
1534
1535 /* initialize the last ports */
1536 g_cfg->last_bts_port = rtp_calculate_port(0, g_cfg->bts_ports.base_port);
1537 g_cfg->last_net_port = rtp_calculate_port(0, g_cfg->net_ports.base_port);
1538
1539 if (allocate_trunk(&g_cfg->trunk) != 0) {
1540 LOGP(DLMGCP, LOGL_ERROR, "Failed to initialize the virtual trunk.\n");
1541 return -1;
1542 }
1543
1544 llist_for_each_entry(trunk, &g_cfg->trunks, entry) {
1545 if (allocate_trunk(trunk) != 0) {
1546 LOGP(DLMGCP, LOGL_ERROR,
1547 "Failed to initialize E1 trunk %d.\n", trunk->trunk_nr);
1548 return -1;
1549 }
1550 }
1551 cfg->role = role;
1552
1553 return 0;
1554}
1555