blob: 854b4baa547fd95a684fe9ebd7a7da0cbda737ba [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-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2012 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#include <ctype.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <time.h>
28#include <limits.h>
29#include <unistd.h>
30#include <errno.h>
31
32#include <osmocom/core/msgb.h>
33#include <osmocom/core/talloc.h>
34#include <osmocom/core/select.h>
35
36#include <osmocom/legacy_mgcp/mgcp.h>
37#include <osmocom/legacy_mgcp/mgcp_internal.h>
38
39#define for_each_non_empty_line(line, save) \
40 for (line = strtok_r(NULL, "\r\n", &save); line;\
41 line = strtok_r(NULL, "\r\n", &save))
42
43
44static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
45
46struct mgcp_request {
47 char *name;
48 struct msgb *(*handle_request) (struct mgcp_parse_data *data);
49 char *debug_name;
50};
51
52#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
53 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
54
55static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
56static struct msgb *handle_create_con(struct mgcp_parse_data *data);
57static struct msgb *handle_delete_con(struct mgcp_parse_data *data);
58static struct msgb *handle_modify_con(struct mgcp_parse_data *data);
59static struct msgb *handle_rsip(struct mgcp_parse_data *data);
60static struct msgb *handle_noti_req(struct mgcp_parse_data *data);
61
62static void create_transcoder(struct mgcp_endpoint *endp);
63static void delete_transcoder(struct mgcp_endpoint *endp);
64
65static int setup_rtp_processing(struct mgcp_endpoint *endp);
66
67static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
68
69/* Display an mgcp message on the log output */
70void display_mgcp_message(unsigned char *message, unsigned int len,
71 char *preamble)
72{
73 unsigned char line[80];
74 unsigned char *ptr;
75 unsigned int consumed = 0;
76 unsigned int consumed_line = 0;
77 unsigned int line_count = 0;
78
79 if (!log_check_level(DLMGCP, LOGL_DEBUG))
80 return;
81
82 while (1) {
83 memset(line, 0, sizeof(line));
84 ptr = line;
85 consumed_line = 0;
86 do {
87 if (*message != '\n' && *message != '\r') {
88 *ptr = *message;
89 ptr++;
90 }
91 message++;
92 consumed++;
93 consumed_line++;
94 } while (*message != '\n' && consumed < len
95 && consumed_line < sizeof(line));
96
97 if (strlen((const char *)line)) {
98 LOGP(DLMGCP, LOGL_DEBUG, "%s: line #%02u: %s\n",
99 preamble, line_count, line);
100 line_count++;
101 }
102
103 if (consumed >= len)
104 return;
105 }
106}
107
108static int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
109{
110 const size_t line_len = strlen(line);
111 if (line[0] != '\0' && line_len < 2) {
112 LOGP(DLMGCP, LOGL_ERROR,
113 "Wrong MGCP option format: '%s' on 0x%x\n",
114 line, ENDPOINT_NUMBER(endp));
115 return 0;
116 }
117
118 return 1;
119}
120
121static uint32_t generate_call_id(struct mgcp_config *cfg)
122{
123 int i;
124
125 /* use the call id */
126 ++cfg->last_call_id;
127
128 /* handle wrap around */
129 if (cfg->last_call_id == CI_UNUSED)
130 ++cfg->last_call_id;
131
132 /* callstack can only be of size number_of_endpoints */
133 /* verify that the call id is free, e.g. in case of overrun */
134 for (i = 1; i < cfg->trunk.number_endpoints; ++i)
135 if (cfg->trunk.endpoints[i].ci == cfg->last_call_id)
136 return generate_call_id(cfg);
137
138 return cfg->last_call_id;
139}
140
141/*
142 * array of function pointers for handling various
143 * messages. In the future this might be binary sorted
144 * for performance reasons.
145 */
146static const struct mgcp_request mgcp_requests [] = {
147 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
148 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
149 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
150 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
151 MGCP_REQUEST("RQNT", handle_noti_req, "NotificationRequest")
152
153 /* SPEC extension */
154 MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
155};
156
157static struct msgb *mgcp_msgb_alloc(void)
158{
159 struct msgb *msg;
160 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
161 if (!msg)
162 LOGP(DLMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
163
164 return msg;
165}
166
167static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
168{
169 struct msgb *msg = mgcp_msgb_alloc();
170 if (!msg)
171 return NULL;
172
173 msg->l2h = msgb_put(msg, strlen(endp->last_response));
174 memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
Philipp Maier2fb853f2017-08-18 11:16:16 +0200175 display_mgcp_message(msg->l2h, msgb_l2len(msg), "Retransmitted response");
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200176 return msg;
177}
178
179static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
180 const char *txt, const char *msg,
181 const char *trans, const char *param,
182 const char *sdp)
183{
184 int len;
185 struct msgb *res;
186
187 res = mgcp_msgb_alloc();
188 if (!res)
189 return NULL;
190
191 len = snprintf((char *) res->data, 2048, "%d %s%s%s\r\n%s",
192 code, trans, txt, param ? param : "", sdp ? sdp : "");
193 if (len < 0) {
194 LOGP(DLMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
195 msgb_free(res);
196 return NULL;
197 }
198
199 res->l2h = msgb_put(res, len);
200 LOGP(DLMGCP, LOGL_DEBUG, "Generated response: code=%d\n", code);
201 display_mgcp_message(res->l2h, msgb_l2len(res), "Generated response");
202
203 /*
204 * Remember the last transmission per endpoint.
205 */
206 if (endp) {
207 struct mgcp_trunk_config *tcfg = endp->tcfg;
208 talloc_free(endp->last_response);
209 talloc_free(endp->last_trans);
210 endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
211 endp->last_response = talloc_strndup(tcfg->endpoints,
212 (const char *) res->l2h,
213 msgb_l2len(res));
214 }
215
216 return res;
217}
218
219static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
220 int code, const char *msg,
221 const char *trans, const char *param)
222{
223 return create_resp(endp, code, " OK", msg, trans, param, NULL);
224}
225
226static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
227 int code, const char *msg, const char *trans)
228{
229 return create_ok_resp_with_param(endp, code, msg, trans, NULL);
230}
231
232static struct msgb *create_err_response(struct mgcp_endpoint *endp,
233 int code, const char *msg, const char *trans)
234{
235 return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
236}
237
238static int write_response_sdp(struct mgcp_endpoint *endp,
239 char *sdp_record, size_t size, const char *addr)
240{
241 const char *fmtp_extra;
242 const char *audio_name;
243 int payload_type;
244 int len;
245 int nchars;
246
247 endp->cfg->get_net_downlink_format_cb(endp, &payload_type,
248 &audio_name, &fmtp_extra);
249
250 len = snprintf(sdp_record, size,
251 "v=0\r\n"
252 "o=- %u 23 IN IP4 %s\r\n"
253 "s=-\r\n"
254 "c=IN IP4 %s\r\n"
255 "t=0 0\r\n",
256 endp->ci, addr, addr);
257
258 if (len < 0 || len >= size)
259 goto buffer_too_small;
260
261 if (payload_type >= 0) {
262 nchars = snprintf(sdp_record + len, size - len,
263 "m=audio %d RTP/AVP %d\r\n",
264 endp->net_end.local_port, payload_type);
265 if (nchars < 0 || nchars >= size - len)
266 goto buffer_too_small;
267
268 len += nchars;
269
270 if (audio_name && endp->tcfg->audio_send_name) {
271 nchars = snprintf(sdp_record + len, size - len,
272 "a=rtpmap:%d %s\r\n",
273 payload_type, audio_name);
274
275 if (nchars < 0 || nchars >= size - len)
276 goto buffer_too_small;
277
278 len += nchars;
279 }
280
281 if (fmtp_extra) {
282 nchars = snprintf(sdp_record + len, size - len,
283 "%s\r\n", fmtp_extra);
284
285 if (nchars < 0 || nchars >= size - len)
286 goto buffer_too_small;
287
288 len += nchars;
289 }
290 }
291 if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
292 nchars = snprintf(sdp_record + len, size - len,
293 "a=ptime:%d\r\n",
294 endp->bts_end.packet_duration_ms);
295 if (nchars < 0 || nchars >= size - len)
296 goto buffer_too_small;
297
298 len += nchars;
299 }
300
301 return len;
302
303buffer_too_small:
304 LOGP(DLMGCP, LOGL_ERROR, "SDP buffer too small: %zu (needed %d)\n",
305 size, len);
306 return -1;
307}
308
309static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
310 const char *msg, const char *trans_id)
311{
312 const char *addr = endp->cfg->local_ip;
313 char sdp_record[4096];
314 int len;
315 int nchars;
316 char osmux_extension[strlen("\nX-Osmux: 255") + 1];
317
318 if (!addr)
319 addr = mgcp_net_src_addr(endp);
320
321 if (endp->osmux.state == OSMUX_STATE_NEGOTIATING) {
322 sprintf(osmux_extension, "\nX-Osmux: %u", endp->osmux.cid);
323 endp->osmux.state = OSMUX_STATE_ACTIVATING;
324 } else {
325 osmux_extension[0] = '\0';
326 }
327
328 len = snprintf(sdp_record, sizeof(sdp_record),
329 "I: %u%s\n\n", endp->ci, osmux_extension);
330 if (len < 0)
331 return NULL;
332
333 nchars = write_response_sdp(endp, sdp_record + len,
334 sizeof(sdp_record) - len - 1, addr);
335 if (nchars < 0)
336 return NULL;
337
338 len += nchars;
339
340 sdp_record[sizeof(sdp_record) - 1] = '\0';
341
342 return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
343}
344
345static void send_dummy(struct mgcp_endpoint *endp)
346{
347 if (endp->osmux.state != OSMUX_STATE_DISABLED)
348 osmux_send_dummy(endp);
349 else
350 mgcp_send_dummy(endp);
351}
352
353/*
354 * handle incoming messages:
355 * - this can be a command (four letters, space, transaction id)
356 * - or a response (three numbers, space, transaction id)
357 */
358struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
359{
360 struct mgcp_parse_data pdata;
361 int i, code, handled = 0;
362 struct msgb *resp = NULL;
363 char *data;
364
365 if (msgb_l2len(msg) < 4) {
366 LOGP(DLMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len);
367 return NULL;
368 }
369
370 if (mgcp_msg_terminate_nul(msg))
371 return NULL;
372
373 display_mgcp_message(msg->l2h, msgb_l2len(msg), "Received message");
374
Harald Welte9bf7c532017-11-17 14:14:31 +0100375 /* attempt to treat it as a response */
376 if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200377 LOGP(DLMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
378 return NULL;
379 }
380
381 msg->l3h = &msg->l2h[4];
382
383
384 /*
385 * Check for a duplicate message and respond.
386 */
387 memset(&pdata, 0, sizeof(pdata));
388 pdata.cfg = cfg;
389 data = strline_r((char *) msg->l3h, &pdata.save);
390 pdata.found = mgcp_analyze_header(&pdata, data);
391 if (pdata.endp && pdata.trans
392 && pdata.endp->last_trans
393 && strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
394 return do_retransmission(pdata.endp);
395 }
396
397 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
398 if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[0], 4) == 0) {
399 handled = 1;
400 resp = mgcp_requests[i].handle_request(&pdata);
401 break;
402 }
403 }
404
405 if (!handled)
406 LOGP(DLMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
407
408 return resp;
409}
410
411/**
412 * We have a null terminated string with the endpoint name here. We only
413 * support two kinds. Simple ones as seen on the BSC level and the ones
414 * seen on the trunk side.
415 */
416static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
417 const char *mgcp)
418{
419 char *rest = NULL;
420 struct mgcp_trunk_config *tcfg;
421 int trunk, endp;
422
423 trunk = strtoul(mgcp + 6, &rest, 10);
424 if (rest == NULL || rest[0] != '/' || trunk < 1) {
425 LOGP(DLMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
426 return NULL;
427 }
428
429 endp = strtoul(rest + 1, &rest, 10);
430 if (rest == NULL || rest[0] != '@') {
431 LOGP(DLMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
432 return NULL;
433 }
434
435 /* signalling is on timeslot 1 */
436 if (endp == 1)
437 return NULL;
438
439 tcfg = mgcp_trunk_num(cfg, trunk);
440 if (!tcfg) {
441 LOGP(DLMGCP, LOGL_ERROR, "The trunk %d is not declared.\n", trunk);
442 return NULL;
443 }
444
445 if (!tcfg->endpoints) {
446 LOGP(DLMGCP, LOGL_ERROR, "Endpoints of trunk %d not allocated.\n", trunk);
447 return NULL;
448 }
449
450 if (endp < 1 || endp >= tcfg->number_endpoints) {
451 LOGP(DLMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n", mgcp);
452 return NULL;
453 }
454
455 return &tcfg->endpoints[endp];
456}
457
458static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
459{
460 char *endptr = NULL;
461 unsigned int gw = INT_MAX;
462
463 if (strncmp(mgcp, "ds/e1", 5) == 0)
464 return find_e1_endpoint(cfg, mgcp);
465
466 gw = strtoul(mgcp, &endptr, 16);
467 if (gw > 0 && gw < cfg->trunk.number_endpoints && endptr[0] == '@')
468 return &cfg->trunk.endpoints[gw];
469
470 LOGP(DLMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
471 return NULL;
472}
473
474/**
475 * @returns 0 when the status line was complete and transaction_id and
476 * endp out parameters are set.
477 */
478static int mgcp_analyze_header(struct mgcp_parse_data *pdata, char *data)
479{
480 int i = 0;
481 char *elem, *save = NULL;
482
483 OSMO_ASSERT(data);
484 pdata->trans = "000000";
485
486 for (elem = strtok_r(data, " ", &save); elem;
487 elem = strtok_r(NULL, " ", &save)) {
488 switch (i) {
489 case 0:
490 pdata->trans = elem;
491 break;
492 case 1:
493 pdata->endp = find_endpoint(pdata->cfg, elem);
494 if (!pdata->endp) {
495 LOGP(DLMGCP, LOGL_ERROR,
496 "Unable to find Endpoint `%s'\n", elem);
497 return -1;
498 }
499 break;
500 case 2:
501 if (strcmp("MGCP", elem)) {
502 LOGP(DLMGCP, LOGL_ERROR,
503 "MGCP header parsing error\n");
504 return -1;
505 }
506 break;
507 case 3:
508 if (strcmp("1.0", elem)) {
509 LOGP(DLMGCP, LOGL_ERROR, "MGCP version `%s' "
510 "not supported\n", elem);
511 return -1;
512 }
513 break;
514 }
515 i++;
516 }
517
518 if (i != 4) {
519 LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
520 pdata->trans = "000000";
521 pdata->endp = NULL;
522 return -1;
523 }
524
525 return 0;
526}
527
528static int verify_call_id(const struct mgcp_endpoint *endp,
529 const char *callid)
530{
531 if (strcmp(endp->callid, callid) != 0) {
532 LOGP(DLMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
533 ENDPOINT_NUMBER(endp), endp->callid, callid);
534 return -1;
535 }
536
537 return 0;
538}
539
540static int verify_ci(const struct mgcp_endpoint *endp,
541 const char *_ci)
542{
543 uint32_t ci = strtoul(_ci, NULL, 10);
544
545 if (ci != endp->ci) {
546 LOGP(DLMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
547 ENDPOINT_NUMBER(endp), endp->ci, _ci);
548 return -1;
549 }
550
551 return 0;
552}
553
554static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
555{
556 if (p->found != 0)
557 return create_err_response(NULL, 500, "AUEP", p->trans);
558 else
559 return create_ok_response(p->endp, 200, "AUEP", p->trans);
560}
561
562static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp)
563{
564 int ret = 0;
565 if (strcmp(msg, "recvonly") == 0)
566 endp->conn_mode = MGCP_CONN_RECV_ONLY;
567 else if (strcmp(msg, "sendrecv") == 0)
568 endp->conn_mode = MGCP_CONN_RECV_SEND;
569 else if (strcmp(msg, "sendonly") == 0)
570 endp->conn_mode = MGCP_CONN_SEND_ONLY;
571 else if (strcmp(msg, "loopback") == 0)
572 endp->conn_mode = MGCP_CONN_LOOPBACK;
573 else {
574 LOGP(DLMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
575 ret = -1;
576 }
577
578 endp->net_end.output_enabled =
579 endp->conn_mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
580 endp->bts_end.output_enabled =
581 endp->conn_mode & MGCP_CONN_RECV_ONLY ? 1 : 0;
582
583 LOGP(DLMGCP, LOGL_DEBUG, "endpoint %x connection mode '%s' %d output_enabled net %d bts %d\n",
584 ENDPOINT_NUMBER(endp),
585 msg, endp->conn_mode, endp->net_end.output_enabled,
586 endp->bts_end.output_enabled);
587
588 return ret;
589}
590
591static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
592 struct mgcp_port_range *range,
593 int (*alloc)(struct mgcp_endpoint *endp, int port))
594{
595 int i;
596
597 if (range->mode == PORT_ALLOC_STATIC) {
598 end->local_alloc = PORT_ALLOC_STATIC;
599 return 0;
600 }
601
602 /* attempt to find a port */
603 for (i = 0; i < 200; ++i) {
604 int rc;
605
606 if (range->last_port >= range->range_end)
607 range->last_port = range->range_start;
608
609 rc = alloc(endp, range->last_port);
610
611 range->last_port += 2;
612 if (rc == 0) {
613 end->local_alloc = PORT_ALLOC_DYNAMIC;
614 return 0;
615 }
616
617 }
618
619 LOGP(DLMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
620 ENDPOINT_NUMBER(endp));
621 return -1;
622}
623
624static int allocate_ports(struct mgcp_endpoint *endp)
625{
626 if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
627 mgcp_bind_net_rtp_port) != 0)
628 return -1;
629
630 if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
631 mgcp_bind_bts_rtp_port) != 0) {
632 mgcp_rtp_end_reset(&endp->net_end);
633 return -1;
634 }
635
636 if (endp->cfg->transcoder_ip && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
637 if (allocate_port(endp, &endp->trans_net,
638 &endp->cfg->transcoder_ports,
639 mgcp_bind_trans_net_rtp_port) != 0) {
640 mgcp_rtp_end_reset(&endp->net_end);
641 mgcp_rtp_end_reset(&endp->bts_end);
642 return -1;
643 }
644
645 if (allocate_port(endp, &endp->trans_bts,
646 &endp->cfg->transcoder_ports,
647 mgcp_bind_trans_bts_rtp_port) != 0) {
648 mgcp_rtp_end_reset(&endp->net_end);
649 mgcp_rtp_end_reset(&endp->bts_end);
650 mgcp_rtp_end_reset(&endp->trans_net);
651 return -1;
652 }
653
654 /* remember that we have set up transcoding */
655 endp->type = MGCP_RTP_TRANSCODED;
656 }
657
658 return 0;
659}
660
661/* Set the LCO from a string (see RFC 3435).
662 * The string is stored in the 'string' field. A NULL string is handled excatly
663 * like an empty string, the 'string' field is never NULL after this function
664 * has been called. */
665static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
666 const char *options)
667{
668 char *p_opt, *a_opt;
669 char codec[9];
670
671 talloc_free(lco->string);
672 talloc_free(lco->codec);
673 lco->codec = NULL;
674 lco->pkt_period_min = lco->pkt_period_max = 0;
675 lco->string = talloc_strdup(ctx, options ? options : "");
676
677 p_opt = strstr(lco->string, "p:");
678 if (p_opt && sscanf(p_opt, "p:%d-%d",
679 &lco->pkt_period_min, &lco->pkt_period_max) == 1)
680 lco->pkt_period_max = lco->pkt_period_min;
681
682 a_opt = strstr(lco->string, "a:");
683 if (a_opt && sscanf(a_opt, "a:%8[^,]", codec) == 1)
684 lco->codec = talloc_strdup(ctx, codec);
685}
686
687void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
688 struct mgcp_rtp_end *rtp)
689{
690 struct mgcp_trunk_config *tcfg = endp->tcfg;
691
692 int patch_ssrc = expect_ssrc_change && tcfg->force_constant_ssrc;
693
694 rtp->force_aligned_timing = tcfg->force_aligned_timing;
695 rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
696
697 LOGP(DLMGCP, LOGL_DEBUG,
698 "Configuring RTP endpoint: local port %d%s%s\n",
699 ntohs(rtp->rtp_port),
700 rtp->force_aligned_timing ? ", force constant timing" : "",
701 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
702}
703
704uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
705 struct mgcp_rtp_end *rtp)
706{
707 int f = 0;
708
709 /* Get the number of frames per channel and packet */
710 if (rtp->frames_per_packet)
711 f = rtp->frames_per_packet;
712 else if (rtp->packet_duration_ms && rtp->codec.frame_duration_num) {
713 int den = 1000 * rtp->codec.frame_duration_num;
714 f = (rtp->packet_duration_ms * rtp->codec.frame_duration_den + den/2)
715 / den;
716 }
717
718 return rtp->codec.rate * f * rtp->codec.frame_duration_num / rtp->codec.frame_duration_den;
719}
720
721static int mgcp_parse_osmux_cid(const char *line)
722{
723 int osmux_cid;
724
725 if (sscanf(line + 2, "Osmux: %u", &osmux_cid) != 1)
726 return -1;
727
728 if (osmux_cid > OSMUX_CID_MAX) {
729 LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
730 osmux_cid, OSMUX_CID_MAX);
731 return -1;
732 }
733 LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
734
735 return osmux_cid;
736}
737
738static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
739{
740 if (!endp->cfg->osmux_init) {
741 if (osmux_init(OSMUX_ROLE_BSC, endp->cfg) < 0) {
742 LOGP(DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
743 return -1;
744 }
745 LOGP(DLMGCP, LOGL_NOTICE, "OSMUX socket has been set up\n");
746 }
747
748 return mgcp_parse_osmux_cid(line);
749}
750
751static struct msgb *handle_create_con(struct mgcp_parse_data *p)
752{
753 struct mgcp_trunk_config *tcfg;
754 struct mgcp_endpoint *endp = p->endp;
755 int error_code = 400;
756
757 const char *local_options = NULL;
758 const char *callid = NULL;
759 const char *mode = NULL;
760 char *line;
761 int have_sdp = 0, osmux_cid = -1;
762
763 if (p->found != 0)
764 return create_err_response(NULL, 510, "CRCX", p->trans);
765
766 /* parse CallID C: and LocalParameters L: */
767 for_each_line(line, p->save) {
768 if (!mgcp_check_param(endp, line))
769 continue;
770
771 switch (line[0]) {
772 case 'L':
773 local_options = (const char *) line + 3;
774 break;
775 case 'C':
776 callid = (const char *) line + 3;
777 break;
778 case 'M':
779 mode = (const char *) line + 3;
780 break;
781 case 'X':
782 /* Osmux is not enabled in this bsc, ignore it so the
783 * bsc-nat knows that we don't want to use Osmux.
784 */
785 if (!p->endp->cfg->osmux)
786 break;
787
788 if (strncmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0)
789 osmux_cid = mgcp_osmux_setup(endp, line);
790 break;
791 case '\0':
792 have_sdp = 1;
793 goto mgcp_header_done;
794 default:
795 LOGP(DLMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
796 *line, *line, ENDPOINT_NUMBER(endp));
797 break;
798 }
799 }
800
801mgcp_header_done:
802 tcfg = p->endp->tcfg;
803
804 /* Check required data */
805 if (!callid || !mode) {
806 LOGP(DLMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
807 ENDPOINT_NUMBER(endp));
808 return create_err_response(endp, 400, "CRCX", p->trans);
809 }
810
811 if (endp->allocated) {
812 if (tcfg->force_realloc) {
813 LOGP(DLMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
814 ENDPOINT_NUMBER(endp));
815 mgcp_release_endp(endp);
816 if (p->cfg->realloc_cb)
817 p->cfg->realloc_cb(tcfg, ENDPOINT_NUMBER(endp));
818 } else {
819 LOGP(DLMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
820 ENDPOINT_NUMBER(endp));
821 return create_err_response(endp, 400, "CRCX", p->trans);
822 }
823 }
824
825 /* copy some parameters */
826 endp->callid = talloc_strdup(tcfg->endpoints, callid);
827
828 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
829 local_options);
830
831 if (parse_conn_mode(mode, endp) != 0) {
832 error_code = 517;
833 goto error2;
834 }
835
836 /* initialize */
837 endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
838 mgcp_rtp_end_config(endp, 0, &endp->net_end);
839 mgcp_rtp_end_config(endp, 0, &endp->bts_end);
840
841 /* set to zero until we get the info */
842 memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
843
844 /* bind to the port now */
845 if (allocate_ports(endp) != 0)
846 goto error2;
847
848 /* assign a local call identifier or fail */
849 endp->ci = generate_call_id(p->cfg);
850 if (endp->ci == CI_UNUSED)
851 goto error2;
852
853 /* Annotate Osmux circuit ID and set it to negotiating state until this
854 * is fully set up from the dummy load.
855 */
856 endp->osmux.state = OSMUX_STATE_DISABLED;
857 if (osmux_cid >= 0) {
858 endp->osmux.cid = osmux_cid;
859 endp->osmux.state = OSMUX_STATE_NEGOTIATING;
860 } else if (endp->cfg->osmux == OSMUX_USAGE_ONLY) {
861 LOGP(DLMGCP, LOGL_ERROR,
862 "Osmux only and no osmux offered on 0x%x\n", ENDPOINT_NUMBER(endp));
863 goto error2;
864 }
865
Pau Espin Pedrolba61f682018-05-16 14:03:38 +0200866 /* Apply Jiter buffer settings for this endpoint, they can be overriden by CRCX policy later */
867 endp->bts_use_jibuf = endp->cfg->bts_use_jibuf;
868 endp->bts_jitter_delay_min = endp->cfg->bts_jitter_delay_min;
869 endp->bts_jitter_delay_max = endp->cfg->bts_jitter_delay_max;
870
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200871 endp->allocated = 1;
872
873 /* set up RTP media parameters */
874 mgcp_set_audio_info(p->cfg, &endp->bts_end.codec, tcfg->audio_payload, tcfg->audio_name);
875 endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
876 tcfg->audio_fmtp_extra);
877 if (have_sdp)
878 mgcp_parse_sdp_data(endp, &endp->net_end, p);
879 else if (endp->local_options.codec)
880 mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
881 PTYPE_UNDEFINED, endp->local_options.codec);
882
883 if (p->cfg->bts_force_ptime) {
884 endp->bts_end.packet_duration_ms = p->cfg->bts_force_ptime;
885 endp->bts_end.force_output_ptime = 1;
886 }
887
888 if (setup_rtp_processing(endp) != 0)
889 goto error2;
890
891 /* policy CB */
892 if (p->cfg->policy_cb) {
893 int rc;
894 rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
895 MGCP_ENDP_CRCX, p->trans);
896 switch (rc) {
897 case MGCP_POLICY_REJECT:
898 LOGP(DLMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
899 ENDPOINT_NUMBER(endp));
900 mgcp_release_endp(endp);
901 return create_err_response(endp, 400, "CRCX", p->trans);
902 break;
903 case MGCP_POLICY_DEFER:
904 /* stop processing */
905 create_transcoder(endp);
Pau Espin Pedrolba61f682018-05-16 14:03:38 +0200906 /* Set up jitter buffer if required after policy has updated jibuf endp values */
907 if (endp->bts_use_jibuf) {
908 endp->bts_jb = osmo_jibuf_alloc(tcfg->endpoints);
909 osmo_jibuf_set_min_delay(endp->bts_jb, endp->bts_jitter_delay_min);
910 osmo_jibuf_set_max_delay(endp->bts_jb, endp->bts_jitter_delay_max);
911 osmo_jibuf_set_dequeue_cb(endp->bts_jb, mgcp_dejitter_udp_send, &endp->net_end);
912 }
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200913 return NULL;
914 break;
915 case MGCP_POLICY_CONT:
916 /* just continue */
917 break;
918 }
919 }
920
Pau Espin Pedrolba61f682018-05-16 14:03:38 +0200921 /* Set up jitter buffer if required after policy has updated jibuf endp values */
922 if (endp->bts_use_jibuf) {
923 endp->bts_jb = osmo_jibuf_alloc(tcfg->endpoints);
924 osmo_jibuf_set_min_delay(endp->bts_jb, endp->bts_jitter_delay_min);
925 osmo_jibuf_set_max_delay(endp->bts_jb, endp->bts_jitter_delay_max);
926 osmo_jibuf_set_dequeue_cb(endp->bts_jb, mgcp_dejitter_udp_send, &endp->net_end);
927 }
928
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200929 LOGP(DLMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
930 ENDPOINT_NUMBER(endp), endp->ci,
931 endp->net_end.local_port, endp->bts_end.local_port);
932 if (p->cfg->change_cb)
933 p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
934
935 if (endp->conn_mode & MGCP_CONN_RECV_ONLY && tcfg->keepalive_interval != 0) {
936 send_dummy(endp);
937 }
938
939 create_transcoder(endp);
940 return create_response_with_sdp(endp, "CRCX", p->trans);
941error2:
942 mgcp_release_endp(endp);
943 LOGP(DLMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
944 return create_err_response(endp, error_code, "CRCX", p->trans);
945}
946
947static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
948{
949 struct mgcp_endpoint *endp = p->endp;
950 int error_code = 500;
951 int silent = 0;
952 int have_sdp = 0;
953 char *line;
954 const char *local_options = NULL;
955
956 if (p->found != 0)
957 return create_err_response(NULL, 510, "MDCX", p->trans);
958
959 if (endp->ci == CI_UNUSED) {
960 LOGP(DLMGCP, LOGL_ERROR, "Endpoint is not "
961 "holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
962 return create_err_response(endp, 400, "MDCX", p->trans);
963 }
964
965 for_each_line(line, p->save) {
966 if (!mgcp_check_param(endp, line))
967 continue;
968
969 switch (line[0]) {
970 case 'C': {
971 if (verify_call_id(endp, line + 3) != 0)
972 goto error3;
973 break;
974 }
975 case 'I': {
976 if (verify_ci(endp, line + 3) != 0)
977 goto error3;
978 break;
979 }
980 case 'L':
981 local_options = (const char *) line + 3;
982 break;
983 case 'M':
984 if (parse_conn_mode(line + 3, endp) != 0) {
985 error_code = 517;
986 goto error3;
987 }
988 endp->orig_mode = endp->conn_mode;
989 break;
990 case 'Z':
991 silent = strcmp("noanswer", line + 3) == 0;
992 break;
993 case '\0':
994 /* SDP file begins */
995 have_sdp = 1;
996 mgcp_parse_sdp_data(endp, &endp->net_end, p);
997 /* This will exhaust p->save, so the loop will
998 * terminate next time.
999 */
1000 break;
1001 default:
1002 LOGP(DLMGCP, LOGL_NOTICE, "Unhandled MGCP option: '%c'/%d on 0x%x\n",
1003 line[0], line[0], ENDPOINT_NUMBER(endp));
1004 break;
1005 }
1006 }
1007
1008 set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
1009 local_options);
1010
1011 if (!have_sdp && endp->local_options.codec)
1012 mgcp_set_audio_info(p->cfg, &endp->net_end.codec,
1013 PTYPE_UNDEFINED, endp->local_options.codec);
1014
1015 if (setup_rtp_processing(endp) != 0)
1016 goto error3;
1017
1018 /* policy CB */
1019 if (p->cfg->policy_cb) {
1020 int rc;
1021 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
1022 MGCP_ENDP_MDCX, p->trans);
1023 switch (rc) {
1024 case MGCP_POLICY_REJECT:
1025 LOGP(DLMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
1026 ENDPOINT_NUMBER(endp));
1027 if (silent)
1028 goto out_silent;
1029 return create_err_response(endp, 400, "MDCX", p->trans);
1030 break;
1031 case MGCP_POLICY_DEFER:
1032 /* stop processing */
1033 LOGP(DLMGCP, LOGL_DEBUG, "endp %x MDCX defer\n",
1034 ENDPOINT_NUMBER(endp));
1035 return NULL;
1036 break;
1037 case MGCP_POLICY_CONT:
1038 /* just continue */
1039 break;
1040 }
1041 }
1042
1043 mgcp_rtp_end_config(endp, 1, &endp->net_end);
1044 mgcp_rtp_end_config(endp, 1, &endp->bts_end);
1045
1046 /* modify */
1047 LOGP(DLMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
1048 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
1049 if (p->cfg->change_cb)
1050 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
1051
1052 if (endp->conn_mode & MGCP_CONN_RECV_ONLY &&
1053 endp->tcfg->keepalive_interval != 0)
1054 send_dummy(endp);
1055
1056 if (silent)
1057 goto out_silent;
1058
1059 return create_response_with_sdp(endp, "MDCX", p->trans);
1060
1061error3:
1062 return create_err_response(endp, error_code, "MDCX", p->trans);
1063
1064
1065out_silent:
1066 LOGP(DLMGCP, LOGL_DEBUG, "endp %x Modify endpoint: silent exit\n",
1067 ENDPOINT_NUMBER(endp));
1068 return NULL;
1069}
1070
1071static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
1072{
1073 struct mgcp_endpoint *endp = p->endp;
1074 int error_code = 400;
1075 int silent = 0;
1076 char *line;
1077 char stats[1048];
1078
1079 if (p->found != 0)
1080 return create_err_response(NULL, error_code, "DLCX", p->trans);
1081
1082 if (!p->endp->allocated) {
1083 LOGP(DLMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n",
1084 ENDPOINT_NUMBER(endp));
1085 return create_err_response(endp, 400, "DLCX", p->trans);
1086 }
1087
1088 for_each_line(line, p->save) {
1089 if (!mgcp_check_param(endp, line))
1090 continue;
1091
1092 switch (line[0]) {
1093 case 'C':
1094 if (verify_call_id(endp, line + 3) != 0)
1095 goto error3;
1096 break;
1097 case 'I':
1098 if (verify_ci(endp, line + 3) != 0)
1099 goto error3;
1100 break;
1101 case 'Z':
1102 silent = strcmp("noanswer", line + 3) == 0;
1103 break;
1104 default:
1105 LOGP(DLMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
1106 line[0], line[0], ENDPOINT_NUMBER(endp));
1107 break;
1108 }
1109 }
1110
1111 /* policy CB */
1112 if (p->cfg->policy_cb) {
1113 int rc;
1114 rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
1115 MGCP_ENDP_DLCX, p->trans);
1116 switch (rc) {
1117 case MGCP_POLICY_REJECT:
1118 LOGP(DLMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
1119 ENDPOINT_NUMBER(endp));
1120 if (silent)
1121 goto out_silent;
1122 return create_err_response(endp, 400, "DLCX", p->trans);
1123 break;
1124 case MGCP_POLICY_DEFER:
1125 /* stop processing */
1126 delete_transcoder(endp);
1127 return NULL;
1128 break;
1129 case MGCP_POLICY_CONT:
1130 /* just continue */
1131 break;
1132 }
1133 }
1134
1135 /* free the connection */
1136 LOGP(DLMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
1137 ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
1138
1139 /* save the statistics of the current call */
1140 mgcp_format_stats(endp, stats, sizeof(stats));
1141
1142 delete_transcoder(endp);
1143 mgcp_release_endp(endp);
1144 if (p->cfg->change_cb)
1145 p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
1146
1147 if (silent)
1148 goto out_silent;
1149 return create_ok_resp_with_param(endp, 250, "DLCX", p->trans, stats);
1150
1151error3:
1152 return create_err_response(endp, error_code, "DLCX", p->trans);
1153
1154out_silent:
1155 return NULL;
1156}
1157
1158static struct msgb *handle_rsip(struct mgcp_parse_data *p)
1159{
1160 if (p->found != 0) {
1161 LOGP(DLMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
1162 return NULL;
1163 }
1164
1165 if (p->cfg->reset_cb)
1166 p->cfg->reset_cb(p->endp->tcfg);
1167 return NULL;
1168}
1169
1170static char extract_tone(const char *line)
1171{
1172 const char *str = strstr(line, "D/");
1173 if (!str)
1174 return CHAR_MAX;
1175
1176 return str[2];
1177}
1178
1179/*
1180 * This can request like DTMF detection and forward, fax detection... it
1181 * can also request when the notification should be send and such. We don't
1182 * do this right now.
1183 */
1184static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
1185{
1186 int res = 0;
1187 char *line;
1188 char tone = CHAR_MAX;
1189
1190 if (p->found != 0)
1191 return create_err_response(NULL, 400, "RQNT", p->trans);
1192
1193 for_each_line(line, p->save) {
1194 switch (line[0]) {
1195 case 'S':
1196 tone = extract_tone(line);
1197 break;
1198 }
1199 }
1200
1201 /* we didn't see a signal request with a tone */
1202 if (tone == CHAR_MAX)
1203 return create_ok_response(p->endp, 200, "RQNT", p->trans);
1204
1205 if (p->cfg->rqnt_cb)
1206 res = p->cfg->rqnt_cb(p->endp, tone);
1207
1208 return res == 0 ?
1209 create_ok_response(p->endp, 200, "RQNT", p->trans) :
1210 create_err_response(p->endp, res, "RQNT", p->trans);
1211}
1212
1213static void mgcp_keepalive_timer_cb(void *_tcfg)
1214{
1215 struct mgcp_trunk_config *tcfg = _tcfg;
1216 int i;
1217 LOGP(DLMGCP, LOGL_DEBUG, "Triggered trunk %d keepalive timer.\n",
1218 tcfg->trunk_nr);
1219
1220 if (tcfg->keepalive_interval <= 0)
1221 return;
1222
1223 for (i = 1; i < tcfg->number_endpoints; ++i) {
1224 struct mgcp_endpoint *endp = &tcfg->endpoints[i];
1225 if (endp->conn_mode == MGCP_CONN_RECV_ONLY)
1226 send_dummy(endp);
1227 }
1228
1229 LOGP(DLMGCP, LOGL_DEBUG, "Rescheduling trunk %d keepalive timer.\n",
1230 tcfg->trunk_nr);
1231 osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval, 0);
1232}
1233
1234void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval)
1235{
1236 tcfg->keepalive_interval = interval;
1237 osmo_timer_setup(&tcfg->keepalive_timer, mgcp_keepalive_timer_cb, tcfg);
1238
1239 if (interval <= 0)
1240 osmo_timer_del(&tcfg->keepalive_timer);
1241 else
1242 osmo_timer_schedule(&tcfg->keepalive_timer,
1243 tcfg->keepalive_interval, 0);
1244}
1245
1246struct mgcp_config *mgcp_config_alloc(void)
1247{
1248 struct mgcp_config *cfg;
1249
1250 cfg = talloc_zero(NULL, struct mgcp_config);
1251 if (!cfg) {
1252 LOGP(DLMGCP, LOGL_FATAL, "Failed to allocate config.\n");
1253 return NULL;
1254 }
1255
1256 cfg->source_port = 2427;
1257 cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
1258 cfg->osmux_addr = talloc_strdup(cfg, "0.0.0.0");
1259
1260 cfg->transcoder_remote_base = 4000;
1261
1262 cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
1263 cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
1264
1265 cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
1266 cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
1267
1268 cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
1269
1270 /* default trunk handling */
1271 cfg->trunk.cfg = cfg;
1272 cfg->trunk.trunk_nr = 0;
1273 cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
1274 cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
1275 cfg->trunk.audio_payload = 126;
1276 cfg->trunk.audio_send_ptime = 1;
1277 cfg->trunk.audio_send_name = 1;
1278 cfg->trunk.omit_rtcp = 0;
1279 mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
1280
1281 INIT_LLIST_HEAD(&cfg->trunks);
1282
1283 return cfg;
1284}
1285
1286struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
1287{
1288 struct mgcp_trunk_config *trunk;
1289
1290 trunk = talloc_zero(cfg, struct mgcp_trunk_config);
1291 if (!trunk) {
1292 LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate.\n");
1293 return NULL;
1294 }
1295
1296 trunk->cfg = cfg;
1297 trunk->trunk_type = MGCP_TRUNK_E1;
1298 trunk->trunk_nr = nr;
1299 trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
1300 trunk->audio_payload = 126;
1301 trunk->audio_send_ptime = 1;
1302 trunk->audio_send_name = 1;
1303 trunk->number_endpoints = 33;
1304 trunk->omit_rtcp = 0;
1305 mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
1306 llist_add_tail(&trunk->entry, &cfg->trunks);
1307 return trunk;
1308}
1309
1310struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
1311{
1312 struct mgcp_trunk_config *trunk;
1313
1314 llist_for_each_entry(trunk, &cfg->trunks, entry)
1315 if (trunk->trunk_nr == index)
1316 return trunk;
1317
1318 return NULL;
1319}
1320
1321static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
1322{
1323 codec->payload_type = -1;
1324 talloc_free(codec->subtype_name);
1325 codec->subtype_name = NULL;
1326 talloc_free(codec->audio_name);
1327 codec->audio_name = NULL;
1328 codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
1329 codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
1330 codec->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
1331 codec->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
1332}
1333
1334static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
1335{
1336 if (end->local_alloc == PORT_ALLOC_DYNAMIC) {
1337 mgcp_free_rtp_port(end);
1338 end->local_port = 0;
1339 }
1340
1341 end->packets = 0;
1342 end->octets = 0;
1343 end->dropped_packets = 0;
1344 memset(&end->addr, 0, sizeof(end->addr));
1345 end->rtp_port = end->rtcp_port = 0;
1346 end->local_alloc = -1;
1347 talloc_free(end->fmtp_extra);
1348 end->fmtp_extra = NULL;
1349 talloc_free(end->rtp_process_data);
1350 end->rtp_process_data = NULL;
1351
1352 /* Set default values */
1353 end->frames_per_packet = 0; /* unknown */
1354 end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
1355 end->output_enabled = 0;
1356
1357 mgcp_rtp_codec_reset(&end->codec);
1358 mgcp_rtp_codec_reset(&end->alt_codec);
1359}
1360
1361static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
1362{
1363 mgcp_rtp_end_reset(end);
1364 end->rtp.fd = -1;
1365 end->rtcp.fd = -1;
1366}
1367
1368int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
1369{
1370 int i;
1371
1372 /* Initialize all endpoints */
1373 tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
1374 sizeof(struct mgcp_endpoint),
1375 tcfg->number_endpoints, "endpoints");
1376 if (!tcfg->endpoints)
1377 return -1;
1378
1379 for (i = 0; i < tcfg->number_endpoints; ++i) {
1380 tcfg->endpoints[i].osmux.allocated_cid = -1;
1381 tcfg->endpoints[i].ci = CI_UNUSED;
1382 tcfg->endpoints[i].cfg = tcfg->cfg;
1383 tcfg->endpoints[i].tcfg = tcfg;
1384 mgcp_rtp_end_init(&tcfg->endpoints[i].net_end);
1385 mgcp_rtp_end_init(&tcfg->endpoints[i].bts_end);
1386 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_net);
1387 mgcp_rtp_end_init(&tcfg->endpoints[i].trans_bts);
1388 }
1389
1390 return 0;
1391}
1392
1393void mgcp_release_endp(struct mgcp_endpoint *endp)
1394{
1395 LOGP(DLMGCP, LOGL_DEBUG, "Releasing endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
Pau Espin Pedrolba61f682018-05-16 14:03:38 +02001396 if (endp->bts_jb)
1397 osmo_jibuf_delete(endp->bts_jb);
1398 endp->bts_jb = NULL;
Neels Hofmeyre9920f22017-07-10 15:07:22 +02001399 endp->ci = CI_UNUSED;
1400 endp->allocated = 0;
1401
1402 talloc_free(endp->callid);
1403 endp->callid = NULL;
1404
1405 talloc_free(endp->local_options.string);
1406 endp->local_options.string = NULL;
1407 talloc_free(endp->local_options.codec);
1408 endp->local_options.codec = NULL;
1409
1410 mgcp_rtp_end_reset(&endp->bts_end);
1411 mgcp_rtp_end_reset(&endp->net_end);
1412 mgcp_rtp_end_reset(&endp->trans_net);
1413 mgcp_rtp_end_reset(&endp->trans_bts);
1414 endp->type = MGCP_RTP_DEFAULT;
1415
1416 memset(&endp->net_state, 0, sizeof(endp->net_state));
1417 memset(&endp->bts_state, 0, sizeof(endp->bts_state));
1418
1419 endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
1420
1421 if (endp->osmux.state == OSMUX_STATE_ENABLED)
1422 osmux_disable_endpoint(endp);
1423
1424 /* release the circuit ID if it had been allocated */
1425 osmux_release_cid(endp);
1426
1427 memset(&endp->taps, 0, sizeof(endp->taps));
1428}
1429
1430void mgcp_initialize_endp(struct mgcp_endpoint *endp)
1431{
1432 return mgcp_release_endp(endp);
1433}
1434
1435static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
1436{
1437 struct sockaddr_in addr;
1438
1439 memset(&addr, 0, sizeof(addr));
1440 addr.sin_family = AF_INET;
1441 addr.sin_addr = cfg->transcoder_in;
1442 addr.sin_port = htons(2427);
1443 return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
1444 (struct sockaddr *) &addr, sizeof(addr));
1445}
1446
1447static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
1448 const char *msg, const char *mode)
1449{
1450 char buf[2096];
1451 int len;
1452 int nchars;
1453
1454 /* hardcoded to AMR right now, we do not know the real type at this point */
1455 len = snprintf(buf, sizeof(buf),
1456 "%s 42 %x@mgw MGCP 1.0\r\n"
1457 "C: 4256\r\n"
1458 "M: %s\r\n"
1459 "\r\n",
1460 msg, endpoint, mode);
1461
1462 if (len < 0)
1463 return;
1464
1465 nchars = write_response_sdp(endp, buf + len, sizeof(buf) + len - 1, NULL);
1466 if (nchars < 0)
1467 return;
1468
1469 len += nchars;
1470
1471 buf[sizeof(buf) - 1] = '\0';
1472
1473 send_trans(endp->cfg, buf, len);
1474}
1475
1476static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
1477{
1478 char buf[2096];
1479 int len;
1480
1481 len = snprintf(buf, sizeof(buf),
1482 "DLCX 43 %x@mgw MGCP 1.0\r\n"
1483 "C: 4256\r\n"
1484 , endpoint);
1485
1486 if (len < 0)
1487 return;
1488
1489 buf[sizeof(buf) - 1] = '\0';
1490
1491 send_trans(endp->cfg, buf, len);
1492}
1493
1494static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
1495{
1496 return write(cfg->gw_fd.bfd.fd, buf, len);
1497}
1498
1499int mgcp_send_reset_all(struct mgcp_config *cfg)
1500{
1501 static const char mgcp_reset[] = {
1502 "RSIP 1 *@mgw MGCP 1.0\r\n"
1503 };
1504
1505 return send_agent(cfg, mgcp_reset, sizeof mgcp_reset -1);
1506}
1507
1508int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
1509{
1510 char buf[128];
1511 int len;
1512
1513 len = snprintf(buf, sizeof(buf),
1514 "RSIP 39 %x@mgw MGCP 1.0\r\n"
1515 , endpoint);
1516 if (len < 0)
1517 return len;
1518
1519 buf[sizeof(buf) - 1] = '\0';
1520
1521 return send_agent(endp->cfg, buf, len);
1522}
1523
1524static int setup_rtp_processing(struct mgcp_endpoint *endp)
1525{
1526 int rc = 0;
1527 struct mgcp_config *cfg = endp->cfg;
1528
1529 if (endp->type != MGCP_RTP_DEFAULT)
1530 return 0;
1531
1532 if (endp->conn_mode == MGCP_CONN_LOOPBACK)
1533 return 0;
1534
1535 if (endp->conn_mode & MGCP_CONN_SEND_ONLY)
1536 rc |= cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end);
1537 else
1538 rc |= cfg->setup_rtp_processing_cb(endp, &endp->net_end, NULL);
1539
1540 if (endp->conn_mode & MGCP_CONN_RECV_ONLY)
1541 rc |= cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end);
1542 else
1543 rc |= cfg->setup_rtp_processing_cb(endp, &endp->bts_end, NULL);
1544 return rc;
1545}
1546
1547static void create_transcoder(struct mgcp_endpoint *endp)
1548{
1549 int port;
1550 int in_endp = ENDPOINT_NUMBER(endp);
1551 int out_endp = endp_back_channel(in_endp);
1552
1553 if (endp->type != MGCP_RTP_TRANSCODED)
1554 return;
1555
1556 send_msg(endp, in_endp, endp->trans_bts.local_port, "CRCX", "sendrecv");
1557 send_msg(endp, in_endp, endp->trans_bts.local_port, "MDCX", "sendrecv");
1558 send_msg(endp, out_endp, endp->trans_net.local_port, "CRCX", "sendrecv");
1559 send_msg(endp, out_endp, endp->trans_net.local_port, "MDCX", "sendrecv");
1560
1561 port = rtp_calculate_port(in_endp, endp->cfg->transcoder_remote_base);
1562 endp->trans_bts.rtp_port = htons(port);
1563 endp->trans_bts.rtcp_port = htons(port + 1);
1564
1565 port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
1566 endp->trans_net.rtp_port = htons(port);
1567 endp->trans_net.rtcp_port = htons(port + 1);
1568}
1569
1570static void delete_transcoder(struct mgcp_endpoint *endp)
1571{
1572 int in_endp = ENDPOINT_NUMBER(endp);
1573 int out_endp = endp_back_channel(in_endp);
1574
1575 if (endp->type != MGCP_RTP_TRANSCODED)
1576 return;
1577
1578 send_dlcx(endp, in_endp);
1579 send_dlcx(endp, out_endp);
1580}
1581
1582int mgcp_reset_transcoder(struct mgcp_config *cfg)
1583{
1584 if (!cfg->transcoder_ip)
1585 return 0;
1586
1587 static const char mgcp_reset[] = {
1588 "RSIP 1 13@mgw MGCP 1.0\r\n"
1589 };
1590
1591 return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
1592}
1593
1594void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
1595{
1596 uint32_t expected, jitter;
1597 int ploss;
1598 int nchars;
1599 mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
1600 &expected, &ploss);
1601 jitter = mgcp_state_calc_jitter(&endp->net_state);
1602
1603 nchars = snprintf(msg, size,
1604 "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1605 endp->bts_end.packets, endp->bts_end.octets,
1606 endp->net_end.packets, endp->net_end.octets,
1607 ploss, jitter);
1608 if (nchars < 0 || nchars >= size)
1609 goto truncate;
1610
1611 msg += nchars;
1612 size -= nchars;
1613
Pau Espin Pedrolc3eed402018-02-20 12:04:28 +01001614 if (endp->cfg->osmux != OSMUX_USAGE_OFF) {
1615 /* Error Counter */
1616 nchars = snprintf(msg, size,
1617 "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
1618 endp->net_state.in_stream.err_ts_counter,
1619 endp->net_state.out_stream.err_ts_counter,
1620 endp->bts_state.in_stream.err_ts_counter,
1621 endp->bts_state.out_stream.err_ts_counter);
1622 if (nchars < 0 || nchars >= size)
1623 goto truncate;
Neels Hofmeyre9920f22017-07-10 15:07:22 +02001624
Pau Espin Pedrolc3eed402018-02-20 12:04:28 +01001625 msg += nchars;
1626 size -= nchars;
Neels Hofmeyre9920f22017-07-10 15:07:22 +02001627
Pau Espin Pedrolc3eed402018-02-20 12:04:28 +01001628 if (endp->osmux.state == OSMUX_STATE_ENABLED) {
1629 snprintf(msg, size,
1630 "\r\nX-Osmux-ST: CR=%u, BR=%u",
1631 endp->osmux.stats.chunks,
1632 endp->osmux.stats.octets);
1633 }
Neels Hofmeyre9920f22017-07-10 15:07:22 +02001634 }
1635truncate:
1636 msg[size - 1] = '\0';
1637}
1638
1639int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1640 uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter)
1641{
1642 char *line, *save;
1643 int rc;
1644
1645 /* initialize with bad values */
1646 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1647 *loss = INT_MAX;
1648
1649
1650 line = strtok_r((char *) msg->l2h, "\r\n", &save);
1651 if (!line)
1652 return -1;
1653
1654 /* this can only parse the message that is created above... */
1655 for_each_non_empty_line(line, save) {
1656 switch (line[0]) {
1657 case 'P':
1658 rc = sscanf(line, "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1659 ps, os, pr, _or, loss, jitter);
1660 return rc == 6 ? 0 : -1;
1661 }
1662 }
1663
1664 return -1;
1665}