blob: b72fc5008873dfbc8aa15187368d7eb556239937 [file] [log] [blame]
Neels Hofmeyre9920f22017-07-10 15:07:22 +02001/* mgcp_utils - common functions to setup an MGCP connection
2 */
3/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <osmocom/core/linuxlist.h>
22#include <osmocom/core/select.h>
23#include <osmocom/core/write_queue.h>
24#include <osmocom/core/msgb.h>
25#include <osmocom/core/logging.h>
26
Neels Hofmeyre9920f22017-07-10 15:07:22 +020027#include <osmocom/legacy_mgcp/mgcp.h>
28#include <osmocom/legacy_mgcp/mgcp_internal.h>
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +020029#include <osmocom/mgcp_client/mgcp_client.h>
30#include <osmocom/mgcp_client/mgcp_client_internal.h>
Neels Hofmeyre9920f22017-07-10 15:07:22 +020031
32#include <netinet/in.h>
33#include <arpa/inet.h>
34
35#include <errno.h>
36#include <unistd.h>
37#include <string.h>
38
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +020039void mgcp_client_conf_init(struct mgcp_client_conf *conf)
Neels Hofmeyre9920f22017-07-10 15:07:22 +020040{
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +020041 /* NULL and -1 default to MGCP_CLIENT_*_DEFAULT values */
42 *conf = (struct mgcp_client_conf){
Neels Hofmeyre9920f22017-07-10 15:07:22 +020043 .local_addr = NULL,
44 .local_port = -1,
45 .remote_addr = NULL,
46 .remote_port = -1,
47 .first_endpoint = 0,
48 .last_endpoint = 0,
49 .bts_base = 0,
50 };
51}
52
53/* Test if a given endpoint id is currently in use */
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +020054static bool endpoint_in_use(uint16_t id, struct mgcp_client *client)
Neels Hofmeyre9920f22017-07-10 15:07:22 +020055{
56 struct mgcp_inuse_endpoint *endpoint;
57 llist_for_each_entry(endpoint, &client->inuse_endpoints, entry) {
58 if (endpoint->id == id)
59 return true;
60 }
61
62 return false;
63}
64
65/* Find and seize an unsused endpoint id */
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +020066int mgcp_client_next_endpoint(struct mgcp_client *client)
Neels Hofmeyre9920f22017-07-10 15:07:22 +020067{
68 int i;
69 uint16_t first_endpoint = client->actual.first_endpoint;
70 uint16_t last_endpoint = client->actual.last_endpoint;
71 struct mgcp_inuse_endpoint *endpoint;
72
73 /* Use the maximum permitted range if the VTY
74 * configuration does not specify a range */
75 if (client->actual.last_endpoint == 0) {
76 first_endpoint = 1;
77 last_endpoint = 65534;
78 }
79
80 /* Test the permitted endpoint range for an endpoint
81 * number that is not in use. When a suitable endpoint
82 * number can be found, seize it by adding it to the
83 * inuse list. */
84 for (i=first_endpoint;i<last_endpoint;i++)
85 {
86 if (endpoint_in_use(i,client) == false) {
87 endpoint = talloc_zero(client, struct mgcp_inuse_endpoint);
88 endpoint->id = i;
89 llist_add_tail(&endpoint->entry, &client->inuse_endpoints);
90 return endpoint->id;
91 }
92 }
93
94 /* All endpoints are busy! */
95 return -EINVAL;
96}
97
98/* Release a seized endpoint id to make it available again for other calls */
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +020099void mgcp_client_release_endpoint(uint16_t id, struct mgcp_client *client)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200100{
101 struct mgcp_inuse_endpoint *endpoint;
102 struct mgcp_inuse_endpoint *endpoint_tmp;
103 llist_for_each_entry_safe(endpoint, endpoint_tmp, &client->inuse_endpoints, entry) {
104 if (endpoint->id == id) {
105 llist_del(&endpoint->entry);
106 talloc_free(endpoint);
107 }
108 }
109}
110
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200111static void mgcp_client_handle_response(struct mgcp_client *mgcp,
112 struct mgcp_response_pending *pending,
113 struct mgcp_response *response)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200114{
115 if (!pending) {
116 LOGP(DLMGCP, LOGL_ERROR,
117 "Cannot handle NULL response\n");
118 return;
119 }
120 if (pending->response_cb)
121 pending->response_cb(response, pending->priv);
122 else
123 LOGP(DLMGCP, LOGL_INFO, "MGCP response ignored (NULL cb)\n");
124 talloc_free(pending);
125}
126
127static int mgcp_response_parse_head(struct mgcp_response *r, struct msgb *msg)
128{
129 int comment_pos;
130 char *end;
131
132 if (mgcp_msg_terminate_nul(msg))
133 goto response_parse_failure;
134
135 r->body = (char *)msg->data;
136
137 if (sscanf(r->body, "%3d %u %n",
138 &r->head.response_code, &r->head.trans_id,
139 &comment_pos) != 2)
140 goto response_parse_failure;
141
142 r->head.comment = r->body + comment_pos;
143 end = strchr(r->head.comment, '\r');
144 if (!end)
145 goto response_parse_failure;
146 /* Mark the end of the comment */
147 *end = '\0';
148 r->body = end + 1;
149 if (r->body[0] == '\n')
150 r->body ++;
151 return 0;
152
153response_parse_failure:
154 LOGP(DLMGCP, LOGL_ERROR,
155 "Failed to parse MGCP response header\n");
156 return -EINVAL;
157}
158
159/* TODO undup against mgcp_protocol.c:mgcp_check_param() */
160static bool mgcp_line_is_valid(const char *line)
161{
162 const size_t line_len = strlen(line);
163 if (line[0] == '\0')
164 return true;
165
166 if (line_len < 2
167 || line[1] != '=') {
168 LOGP(DLMGCP, LOGL_ERROR,
169 "Wrong MGCP option format: '%s'\n",
170 line);
171 return false;
172 }
173
174 return true;
175}
176
177/* Parse a line like "m=audio 16002 RTP/AVP 98" */
178static int mgcp_parse_audio(struct mgcp_response *r, const char *line)
179{
180 if (sscanf(line, "m=audio %hu",
181 &r->audio_port) != 1)
182 goto response_parse_failure;
183
184 return 0;
185
186response_parse_failure:
187 LOGP(DLMGCP, LOGL_ERROR,
188 "Failed to parse MGCP response header\n");
189 return -EINVAL;
190}
191
192int mgcp_response_parse_params(struct mgcp_response *r)
193{
194 char *line;
195 int rc;
196 OSMO_ASSERT(r->body);
197 char *data = strstr(r->body, "\n\n");
198
199 if (!data) {
200 LOGP(DLMGCP, LOGL_ERROR,
201 "MGCP response: cannot find start of parameters\n");
202 return -EINVAL;
203 }
204
205 /* Advance to after the \n\n, replace the second \n with \0. That's
206 * where the parameters start. */
207 data ++;
208 *data = '\0';
209 data ++;
210
211 for_each_line(line, data) {
212 if (!mgcp_line_is_valid(line))
213 return -EINVAL;
214
215 switch (line[0]) {
216 case 'm':
217 rc = mgcp_parse_audio(r, line);
218 if (rc)
219 return rc;
220 break;
221 default:
222 /* skip unhandled parameters */
223 break;
224 }
225 }
226 return 0;
227}
228
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200229static struct mgcp_response_pending *mgcp_client_response_pending_get(
230 struct mgcp_client *mgcp,
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200231 struct mgcp_response *r)
232{
233 struct mgcp_response_pending *pending;
234 if (!r)
235 return NULL;
236 llist_for_each_entry(pending, &mgcp->responses_pending, entry) {
237 if (pending->trans_id == r->head.trans_id) {
238 llist_del(&pending->entry);
239 return pending;
240 }
241 }
242 return NULL;
243}
244
245/* Feed an MGCP message into the receive processing.
246 * Parse the head and call any callback registered for the transaction id found
247 * in the MGCP message. This is normally called directly from the internal
248 * mgcp_do_read that reads from the socket connected to the MGCP gateway. This
249 * function is published mainly to be able to feed data from the test suite.
250 */
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200251int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200252{
253 struct mgcp_response r = { 0 };
254 struct mgcp_response_pending *pending;
255 int rc;
256
257 rc = mgcp_response_parse_head(&r, msg);
258 if (rc) {
259 LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response\n");
260 return -1;
261 }
262
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200263 pending = mgcp_client_response_pending_get(mgcp, &r);
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200264 if (!pending) {
265 LOGP(DLMGCP, LOGL_ERROR,
266 "Cannot find matching MGCP transaction for trans_id %d\n",
267 r.head.trans_id);
268 return -1;
269 }
270
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200271 mgcp_client_handle_response(mgcp, pending, &r);
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200272 return 0;
273}
274
275static int mgcp_do_read(struct osmo_fd *fd)
276{
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200277 struct mgcp_client *mgcp = fd->data;
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200278 struct msgb *msg;
279 int ret;
280
281 msg = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
282 if (!msg) {
283 LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
284 return -1;
285 }
286
287 ret = read(fd->fd, msg->data, 4096 - 128);
288 if (ret <= 0) {
289 LOGP(DLMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno));
290 msgb_free(msg);
291 return -1;
292 } else if (ret > 4096 - 128) {
293 LOGP(DLMGCP, LOGL_ERROR, "Too much data: %d\n", ret);
294 msgb_free(msg);
295 return -1;
296 }
297
298 msg->l2h = msgb_put(msg, ret);
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200299 ret = mgcp_client_rx(mgcp, msg);
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200300 talloc_free(msg);
301 return ret;
302}
303
304static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
305{
306 int ret;
307 static char strbuf[4096];
308 unsigned int l = msg->len < sizeof(strbuf) ? msg->len : sizeof(strbuf);
309 unsigned int i;
310
311 strncpy(strbuf, (const char*)msg->data, l);
312 for (i = 0; i < sizeof(strbuf); i++) {
313 if (strbuf[i] == '\n' || strbuf[i] == '\r') {
314 strbuf[i] = '\0';
315 break;
316 }
317 }
318 DEBUGP(DLMGCP, "Tx MGCP msg to MGCP GW: '%s'\n", strbuf);
319
320 LOGP(DLMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
321
322 ret = write(fd->fd, msg->data, msg->len);
323 if (ret != msg->len)
324 LOGP(DLMGCP, LOGL_ERROR, "Failed to forward message to MGCP"
325 " GW: %s\n", strerror(errno));
326
327 return ret;
328}
329
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200330struct mgcp_client *mgcp_client_init(void *ctx,
331 struct mgcp_client_conf *conf)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200332{
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200333 struct mgcp_client *mgcp;
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200334
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200335 mgcp = talloc_zero(ctx, struct mgcp_client);
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200336
337 INIT_LLIST_HEAD(&mgcp->responses_pending);
338 INIT_LLIST_HEAD(&mgcp->inuse_endpoints);
339
340 mgcp->next_trans_id = 1;
341
342 mgcp->actual.local_addr = conf->local_addr ? conf->local_addr :
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200343 MGCP_CLIENT_LOCAL_ADDR_DEFAULT;
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200344 mgcp->actual.local_port = conf->local_port >= 0 ? (uint16_t)conf->local_port :
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200345 MGCP_CLIENT_LOCAL_PORT_DEFAULT;
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200346
347 mgcp->actual.remote_addr = conf->remote_addr ? conf->remote_addr :
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200348 MGCP_CLIENT_REMOTE_ADDR_DEFAULT;
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200349 mgcp->actual.remote_port = conf->remote_port >= 0 ? (uint16_t)conf->remote_port :
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200350 MGCP_CLIENT_REMOTE_PORT_DEFAULT;
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200351
352 mgcp->actual.first_endpoint = conf->first_endpoint > 0 ? (uint16_t)conf->first_endpoint : 0;
353 mgcp->actual.last_endpoint = conf->last_endpoint > 0 ? (uint16_t)conf->last_endpoint : 0;
354 mgcp->actual.bts_base = conf->bts_base > 0 ? (uint16_t)conf->bts_base : 4000;
355
356 return mgcp;
357}
358
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200359int mgcp_client_connect(struct mgcp_client *mgcp)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200360{
361 int on;
362 struct sockaddr_in addr;
363 struct osmo_wqueue *wq;
364 int rc;
365
366 if (!mgcp) {
367 LOGP(DLMGCP, LOGL_FATAL, "MGCPGW client not initialized properly\n");
368 return -EINVAL;
369 }
370
371 wq = &mgcp->wq;
372
373 wq->bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
374 if (wq->bfd.fd < 0) {
375 LOGP(DLMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
376 return -errno;
377 }
378
379 on = 1;
380 if (setsockopt(wq->bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
381 LOGP(DLMGCP, LOGL_FATAL,
382 "Failed to initialize socket for MGCP GW: %s\n",
383 strerror(errno));
384 rc = -errno;
385 goto error_close_fd;
386 }
387
388 /* bind socket */
389 memset(&addr, 0, sizeof(addr));
390 addr.sin_family = AF_INET;
391 inet_aton(mgcp->actual.local_addr, &addr.sin_addr);
392 addr.sin_port = htons(mgcp->actual.local_port);
393 if (bind(wq->bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
394 LOGP(DLMGCP, LOGL_FATAL,
395 "Failed to bind for MGCP GW to %s %u\n",
396 mgcp->actual.local_addr, mgcp->actual.local_port);
397 rc = -errno;
398 goto error_close_fd;
399 }
400
401 /* connect to the remote */
402 inet_aton(mgcp->actual.remote_addr, &addr.sin_addr);
403 addr.sin_port = htons(mgcp->actual.remote_port);
404 if (connect(wq->bfd.fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
405 LOGP(DLMGCP, LOGL_FATAL,
406 "Failed to connect to MGCP GW at %s %u: %s\n",
407 mgcp->actual.remote_addr, mgcp->actual.remote_port,
408 strerror(errno));
409 rc = -errno;
410 goto error_close_fd;
411 }
412
413 mgcp->remote_addr = htonl(addr.sin_addr.s_addr);
414
415 osmo_wqueue_init(wq, 10);
416 wq->bfd.when = BSC_FD_READ;
417 wq->bfd.data = mgcp;
418 wq->read_cb = mgcp_do_read;
419 wq->write_cb = mgcp_do_write;
420
421 if (osmo_fd_register(&wq->bfd) != 0) {
422 LOGP(DLMGCP, LOGL_FATAL, "Failed to register BFD\n");
423 rc = -EIO;
424 goto error_close_fd;
425 }
426 LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s:%u -> %s:%u\n",
427 mgcp->actual.local_addr, mgcp->actual.local_port,
428 mgcp->actual.remote_addr, mgcp->actual.remote_port);
429
430 return 0;
431error_close_fd:
432 close(wq->bfd.fd);
433 wq->bfd.fd = -1;
434 return rc;
435}
436
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200437const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200438{
439 return mgcp->actual.remote_addr;
440}
441
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200442uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200443{
444 return mgcp->actual.remote_port;
445}
446
447/* Return the MGCP GW binary IPv4 address in network byte order. */
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200448uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200449{
450 return mgcp->remote_addr;
451}
452
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200453struct mgcp_response_pending * mgcp_client_pending_add(
454 struct mgcp_client *mgcp,
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200455 mgcp_trans_id_t trans_id,
456 mgcp_response_cb_t response_cb,
457 void *priv)
458{
459 struct mgcp_response_pending *pending;
460
461 pending = talloc_zero(mgcp, struct mgcp_response_pending);
462 pending->trans_id = trans_id;
463 pending->response_cb = response_cb;
464 pending->priv = priv;
465 llist_add_tail(&pending->entry, &mgcp->responses_pending);
466
467 return pending;
468}
469
470/* Send the MGCP message in msg to the MGCP GW and handle a response with
471 * response_cb. NOTE: the response_cb still needs to call
472 * mgcp_response_parse_params(response) to get the parsed parameters -- to
473 * potentially save some CPU cycles, only the head line has been parsed when
474 * the response_cb is invoked. */
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200475int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
476 mgcp_response_cb_t response_cb, void *priv)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200477{
478 struct mgcp_response_pending *pending;
479 mgcp_trans_id_t trans_id;
480 int rc;
481
482 trans_id = msg->cb[MSGB_CB_MGCP_TRANS_ID];
483 if (!trans_id) {
484 LOGP(DLMGCP, LOGL_ERROR,
485 "Unset transaction id in mgcp send request\n");
486 talloc_free(msg);
487 return -EINVAL;
488 }
489
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200490 pending = mgcp_client_pending_add(mgcp, trans_id, response_cb, priv);
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200491
492 if (msgb_l2len(msg) > 4096) {
493 LOGP(DLMGCP, LOGL_ERROR,
494 "Cannot send, MGCP message too large: %u\n",
495 msgb_l2len(msg));
496 msgb_free(msg);
497 rc = -EINVAL;
498 goto mgcp_tx_error;
499 }
500
501 rc = osmo_wqueue_enqueue(&mgcp->wq, msg);
502 if (rc) {
503 LOGP(DLMGCP, LOGL_FATAL, "Could not queue message to MGCP GW\n");
504 msgb_free(msg);
505 goto mgcp_tx_error;
506 } else
507 LOGP(DLMGCP, LOGL_INFO, "Queued %u bytes for MGCP GW\n",
508 msgb_l2len(msg));
509 return 0;
510
511mgcp_tx_error:
512 /* Pass NULL to response cb to indicate an error */
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200513 mgcp_client_handle_response(mgcp, pending, NULL);
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200514 return -1;
515}
516
517static struct msgb *mgcp_msg_from_buf(mgcp_trans_id_t trans_id,
518 const char *buf, int len)
519{
520 struct msgb *msg;
521
522 if (len > (4096 - 128)) {
523 LOGP(DLMGCP, LOGL_ERROR, "Cannot send to MGCP GW:"
524 " message too large: %d\n", len);
525 return NULL;
526 }
527
528 msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
529 OSMO_ASSERT(msg);
530
531 char *dst = (char*)msgb_put(msg, len);
532 memcpy(dst, buf, len);
533 msg->l2h = msg->data;
534 msg->cb[MSGB_CB_MGCP_TRANS_ID] = trans_id;
535
536 return msg;
537}
538
539static struct msgb *mgcp_msg_from_str(mgcp_trans_id_t trans_id,
540 const char *fmt, ...)
541{
542 static char compose[4096 - 128];
543 va_list ap;
544 int len;
545 OSMO_ASSERT(fmt);
546
547 va_start(ap, fmt);
548 len = vsnprintf(compose, sizeof(compose), fmt, ap);
549 va_end(ap);
550 if (len >= sizeof(compose)) {
551 LOGP(DLMGCP, LOGL_ERROR,
552 "Message too large: trans_id=%u len=%d\n",
553 trans_id, len);
554 return NULL;
555 }
556 if (len < 1) {
557 LOGP(DLMGCP, LOGL_ERROR,
558 "Failed to compose message: trans_id=%u len=%d\n",
559 trans_id, len);
560 return NULL;
561 }
562 return mgcp_msg_from_buf(trans_id, compose, len);
563}
564
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200565static mgcp_trans_id_t mgcp_client_next_trans_id(struct mgcp_client *mgcp)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200566{
567 /* avoid zero trans_id to distinguish from unset trans_id */
568 if (!mgcp->next_trans_id)
569 mgcp->next_trans_id ++;
570 return mgcp->next_trans_id ++;
571}
572
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200573struct msgb *mgcp_msg_crcx(struct mgcp_client *mgcp,
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200574 uint16_t rtp_endpoint, unsigned int call_id,
575 enum mgcp_connection_mode mode)
576{
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200577 mgcp_trans_id_t trans_id = mgcp_client_next_trans_id(mgcp);
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200578 return mgcp_msg_from_str(trans_id,
579 "CRCX %u %x@mgw MGCP 1.0\r\n"
580 "C: %x\r\n"
581 "L: p:20, a:AMR, nt:IN\r\n"
582 "M: %s\r\n"
583 ,
584 trans_id,
585 rtp_endpoint,
586 call_id,
587 mgcp_cmode_name(mode));
588}
589
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200590struct msgb *mgcp_msg_mdcx(struct mgcp_client *mgcp,
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200591 uint16_t rtp_endpoint, const char *rtp_conn_addr,
592 uint16_t rtp_port, enum mgcp_connection_mode mode)
593
594{
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200595 mgcp_trans_id_t trans_id = mgcp_client_next_trans_id(mgcp);
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200596 return mgcp_msg_from_str(trans_id,
597 "MDCX %u %x@mgw MGCP 1.0\r\n"
598 "M: %s\r\n"
599 "\r\n"
600 "c=IN IP4 %s\r\n"
601 "m=audio %u RTP/AVP 255\r\n"
602 ,
603 trans_id,
604 rtp_endpoint,
605 mgcp_cmode_name(mode),
606 rtp_conn_addr,
607 rtp_port);
608}
609
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200610struct msgb *mgcp_msg_dlcx(struct mgcp_client *mgcp, uint16_t rtp_endpoint,
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200611 unsigned int call_id)
612{
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200613 mgcp_trans_id_t trans_id = mgcp_client_next_trans_id(mgcp);
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200614 return mgcp_msg_from_str(trans_id,
615 "DLCX %u %x@mgw MGCP 1.0\r\n"
616 "C: %x\r\n", trans_id, rtp_endpoint, call_id);
617}
618
Neels Hofmeyr3a8e7232017-09-04 01:02:56 +0200619struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp)
Neels Hofmeyre9920f22017-07-10 15:07:22 +0200620{
621 return &mgcp->actual;
622}