From 7c8a62a9406ab33feecd890b044f001aee7fadd9 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Fri, 14 Oct 2016 17:56:17 +0200 Subject: mgcp: handle responses from the MGCP GW Change-Id: I5c0493feaec775461b5a017c36b93cc2ad63c896 --- openbsc/include/openbsc/mgcp_internal.h | 2 + openbsc/include/openbsc/mgcpgw_client.h | 59 +++++++-- openbsc/src/libmgcp/mgcp_common.c | 21 ++++ openbsc/src/libmgcp/mgcp_protocol.c | 16 +-- openbsc/src/libmgcp/mgcpgw_client.c | 207 ++++++++++++++++++++++++++++---- openbsc/src/libmsc/msc_ifaces.c | 48 +++++++- openbsc/src/osmo-msc/msc_main.c | 13 +- openbsc/tests/db/db_test.c | 12 +- 8 files changed, 309 insertions(+), 69 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 6997b02e5..b58eb9b58 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -332,3 +332,5 @@ static inline const char *mgcp_bts_src_addr(struct mgcp_endpoint *endp) return endp->cfg->bts_ports.bind_addr; return endp->cfg->source_addr; } + +int mgcp_msg_terminate_nul(struct msgb *msg); diff --git a/openbsc/include/openbsc/mgcpgw_client.h b/openbsc/include/openbsc/mgcpgw_client.h index c21011898..60e648d9b 100644 --- a/openbsc/include/openbsc/mgcpgw_client.h +++ b/openbsc/include/openbsc/mgcpgw_client.h @@ -1,6 +1,9 @@ #pragma once #include + +#include + enum mgcp_connection_mode; struct msgb; @@ -11,8 +14,6 @@ struct mgcpgw_client; #define MGCPGW_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1" #define MGCPGW_CLIENT_REMOTE_PORT_DEFAULT 2427 -typedef void (* mgcp_rx_cb_t )(struct msgb *msg, void *priv); - struct mgcpgw_client_conf { const char *local_addr; int local_port; @@ -20,11 +21,35 @@ struct mgcpgw_client_conf { int remote_port; }; +struct mgcp_response_head { + int response_code; + unsigned int trans_id; + const char *comment; +}; + +struct mgcp_response { + char *data; + struct mgcp_response_head head; + uint16_t audio_port; +}; + +/* Invoked when an MGCP response is received or sending failed. When the + * response is passed as NULL, this indicates failure during transmission. */ +typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv); + +struct mgcp_response_pending { + struct llist_head entry; + + unsigned int trans_id; + mgcp_response_cb_t response_cb; + void *priv; +}; + + void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf); struct mgcpgw_client *mgcpgw_client_init(void *ctx, - struct mgcpgw_client_conf *conf, - mgcp_rx_cb_t rx_cb, void *rx_cb_priv); + struct mgcpgw_client_conf *conf); const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp); uint16_t mgcpgw_client_remote_port(struct mgcpgw_client *mgcp); @@ -32,16 +57,28 @@ uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp); unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client); -int mgcpgw_client_tx_crcx(struct mgcpgw_client *client, +int mgcp_response_parse_params(struct mgcp_response *r); + +int mgcpgw_client_tx_crcx(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, uint16_t rtp_endpoint, unsigned int call_id, enum mgcp_connection_mode mode); -int mgcpgw_client_tx_mdcx(struct mgcpgw_client *client, uint16_t rtp_endpoint, - const char *rtp_conn_addr, uint16_t rtp_port, - enum mgcp_connection_mode mode); +int mgcpgw_client_tx_mdcx(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, + uint16_t rtp_endpoint, const char *rtp_conn_addr, + uint16_t rtp_port, enum mgcp_connection_mode mode); -int mgcpgw_client_tx_str(struct mgcpgw_client *mgcp, const char *fmt, ...); -int mgcpgw_client_tx_buf(struct mgcpgw_client *mgcp, const char *buf, int len); -int mgcpgw_client_tx(struct mgcpgw_client *mgcp, struct msgb *msg); +int mgcpgw_client_tx_str(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, + unsigned int trans_id, + const char *fmt, ...); +int mgcpgw_client_tx_buf(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, + const char *buf, int len, + unsigned int trans_id); +int mgcpgw_client_tx(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, + struct msgb *msg, unsigned int trans_id); void mgcpgw_client_vty_init(int node, struct mgcpgw_client_conf *conf); int mgcpgw_client_config_write(struct vty *vty, const char *indent); diff --git a/openbsc/src/libmgcp/mgcp_common.c b/openbsc/src/libmgcp/mgcp_common.c index 9f104739a..4d7d36ab8 100644 --- a/openbsc/src/libmgcp/mgcp_common.c +++ b/openbsc/src/libmgcp/mgcp_common.c @@ -20,6 +20,8 @@ * */ +#include + #include #include @@ -30,3 +32,22 @@ const struct value_string mgcp_connection_mode_strs[] = { { MGCP_CONN_RECV_ONLY, "recvonly" }, { MGCP_CONN_LOOPBACK, "loopback" }, }; + +/* Ensure that the msg->l2h is NUL terminated. */ +int mgcp_msg_terminate_nul(struct msgb *msg) +{ + unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */ + if (tail[-1] == '\0') + /* nothing to do */; + else if (msgb_tailroom(msg) > 0) + tail[0] = '\0'; + else if (tail[-1] == '\r' || tail[-1] == '\n') + tail[-1] = '\0'; + else { + LOGP(DMGCP, LOGL_ERROR, "Cannot NUL terminate MGCP message: " + "Length: %d, Buffer size: %d\n", + msgb_l2len(msg), msg->data_len); + return -ENOTSUP; + } + return 0; +} diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index 0eed5a3f7..39d9ff56e 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -318,29 +318,17 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg) int i, code, handled = 0; struct msgb *resp = NULL; char *data; - unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */ if (msgb_l2len(msg) < 4) { LOGP(DMGCP, LOGL_ERROR, "msg too short: %d\n", msg->len); return NULL; } - /* Ensure that the msg->l2h is NUL terminated. */ - if (tail[-1] == '\0') - /* nothing to do */; - else if (msgb_tailroom(msg) > 0) - tail[0] = '\0'; - else if (tail[-1] == '\r' || tail[-1] == '\n') - tail[-1] = '\0'; - else { - LOGP(DMGCP, LOGL_ERROR, "Cannot NUL terminate MGCP message: " - "Length: %d, Buffer size: %d\n", - msgb_l2len(msg), msg->data_len); + if (mgcp_msg_terminate_nul(msg)) return NULL; - } /* attempt to treat it as a response */ - if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) { + if (sscanf((const char *)&msg->l2h[0], "%3d %u*s", &code) == 1) { LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code); return NULL; } diff --git a/openbsc/src/libmgcp/mgcpgw_client.c b/openbsc/src/libmgcp/mgcpgw_client.c index 025bed136..7b50007d6 100644 --- a/openbsc/src/libmgcp/mgcpgw_client.c +++ b/openbsc/src/libmgcp/mgcpgw_client.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -38,10 +39,9 @@ struct mgcpgw_client { struct mgcpgw_client_conf actual; uint32_t remote_addr; struct osmo_wqueue wq; - mgcp_rx_cb_t rx_cb; - void *rx_cb_priv; unsigned int next_trans_id; uint16_t next_endpoint; + struct llist_head responses_pending; }; void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf) @@ -60,6 +60,138 @@ unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client) return client->next_endpoint ++; } +static void mgcpgw_client_handle_response(struct mgcpgw_client *mgcp, + struct mgcp_response_pending *pending, + struct mgcp_response *response) +{ + if (!pending) + return; + if (pending->response_cb) + pending->response_cb(response, pending->priv); + else + LOGP(DMGCP, LOGL_INFO, "MGCP response ignored (NULL cb)\n"); + talloc_free(pending); +} + +static int mgcp_response_parse_head(struct mgcp_response *r, struct msgb *msg) +{ + int comment_pos; + + if (mgcp_msg_terminate_nul(msg)) + goto response_parse_failure; + + r->data = (char *)msg->data; + + if (sscanf(r->data, "%3d %u %n", + &r->head.response_code, &r->head.trans_id, + &comment_pos) != 2) + goto response_parse_failure; + + r->head.comment = r->data + comment_pos; + return 0; + +response_parse_failure: + LOGP(DMGCP, LOGL_ERROR, + "Failed to parse MGCP response header\n"); + return -EINVAL; +} + +/* TODO undup against mgcp_protocol.c:mgcp_check_param() */ +static bool mgcp_line_is_valid(const char *line) +{ + const size_t line_len = strlen(line); + if (line[0] == '\0') + return true; + + if (line_len < 2 + || line[1] != '=') { + LOGP(DMGCP, LOGL_ERROR, + "Wrong MGCP option format: '%s'\n", + line); + return false; + } + + return true; +} + +/* Parse a line like "m=audio 16002 RTP/AVP 98" */ +static int mgcp_parse_audio(struct mgcp_response *r, const char *line) +{ + if (sscanf(line, "m=audio %hu", + &r->audio_port) != 1) + goto response_parse_failure; + + return 0; + +response_parse_failure: + LOGP(DMGCP, LOGL_ERROR, + "Failed to parse MGCP response header\n"); + return -EINVAL; +} + +int mgcp_response_parse_params(struct mgcp_response *r) +{ + char *line; + char *data = r->data; + int rc; + for_each_line(line, data) { + if (!mgcp_line_is_valid(line)) + return -EINVAL; + + switch (line[0]) { + case 'm': + rc = mgcp_parse_audio(r, line); + if (rc) + return rc; + break; + default: + /* skip unhandled parameters */ + break; + } + } + return 0; +} + +static struct mgcp_response_pending *mgcpgw_client_response_pending_get( + struct mgcpgw_client *mgcp, + struct mgcp_response *r) +{ + struct mgcp_response_pending *pending; + if (!r) + return NULL; + llist_for_each_entry(pending, &mgcp->responses_pending, entry) { + if (pending->trans_id == r->head.trans_id) { + llist_del(&pending->entry); + return pending; + } + } + return NULL; +} + +static int mgcpgw_client_read(struct mgcpgw_client *mgcp, struct msgb *msg) +{ + struct mgcp_response r; + struct mgcp_response_pending *pending; + int rc; + + rc = mgcp_response_parse_head(&r, msg); + if (rc) { + LOGP(DMGCP, LOGL_ERROR, "Cannot parse MGCP response\n"); + return -1; + } + + pending = mgcpgw_client_response_pending_get(mgcp, &r); + if (!pending) { + LOGP(DMGCP, LOGL_ERROR, + "Cannot find matching MGCP transaction for trans_id %d\n", + r.head.trans_id); + return -1; + } + + mgcpgw_client_handle_response(mgcp, pending, &r); + return 0; +} + static int mgcp_do_read(struct osmo_fd *fd) { struct mgcpgw_client *mgcp = fd->data; @@ -84,9 +216,9 @@ static int mgcp_do_read(struct osmo_fd *fd) } msg->l2h = msgb_put(msg, ret); - if (mgcp->rx_cb) - mgcp->rx_cb(msg, mgcp->rx_cb_priv); - return 0; + ret = mgcpgw_client_read(mgcp, msg); + talloc_free(msg); + return ret; } static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg) @@ -109,8 +241,7 @@ static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg) } struct mgcpgw_client *mgcpgw_client_init(void *ctx, - struct mgcpgw_client_conf *conf, - mgcp_rx_cb_t rx_cb, void *rx_cb_priv) + struct mgcpgw_client_conf *conf) { int on; struct sockaddr_in addr; @@ -119,6 +250,8 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx, mgcp = talloc_zero(ctx, struct mgcpgw_client); + INIT_LLIST_HEAD(&mgcp->responses_pending); + mgcp->next_trans_id = 1; mgcp->next_endpoint = 1; @@ -132,8 +265,6 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx, mgcp->actual.remote_port = conf->remote_port >= 0 ? (uint16_t)conf->remote_port : MGCPGW_CLIENT_REMOTE_PORT_DEFAULT; - mgcp->rx_cb = rx_cb; - mgcp->rx_cb_priv = rx_cb_priv; wq = &mgcp->wq; wq->bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); @@ -214,30 +345,48 @@ uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp) return mgcp->remote_addr; } -int mgcpgw_client_tx(struct mgcpgw_client *mgcp, struct msgb *msg) +int mgcpgw_client_tx(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, + struct msgb *msg, unsigned int trans_id) { + struct mgcp_response_pending *pending; int rc; + pending = talloc_zero(mgcp, struct mgcp_response_pending); + pending->trans_id = trans_id; + pending->response_cb = response_cb; + pending->priv = priv; + llist_add_tail(&pending->entry, &mgcp->responses_pending); + if (msgb_l2len(msg) > 4096) { LOGP(DMGCP, LOGL_ERROR, "Cannot send, MGCP message too large: %u\n", msgb_l2len(msg)); msgb_free(msg); - return -EINVAL; + rc = -EINVAL; + goto mgcp_tx_error; } rc = osmo_wqueue_enqueue(&mgcp->wq, msg); if (rc) { LOGP(DMGCP, LOGL_FATAL, "Could not queue message to MGCP GW\n"); msgb_free(msg); - return rc; + goto mgcp_tx_error; } else LOGP(DMGCP, LOGL_INFO, "Queued %u bytes for MGCP GW\n", msgb_l2len(msg)); return 0; + +mgcp_tx_error: + /* Pass NULL to response cb to indicate an error */ + mgcpgw_client_handle_response(mgcp, pending, NULL); + return -1; } -int mgcpgw_client_tx_buf(struct mgcpgw_client *mgcp, const char *buf, int len) +int mgcpgw_client_tx_buf(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, + const char *buf, int len, + unsigned int trans_id) { struct msgb *msg; @@ -254,10 +403,13 @@ int mgcpgw_client_tx_buf(struct mgcpgw_client *mgcp, const char *buf, int len) memcpy(dst, buf, len); msg->l2h = msg->data; - return mgcpgw_client_tx(mgcp, msg); + return mgcpgw_client_tx(mgcp, response_cb, priv, msg, trans_id); } -int mgcpgw_client_tx_str(struct mgcpgw_client *mgcp, const char *fmt, ...) +int mgcpgw_client_tx_str(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, + unsigned int trans_id, + const char *fmt, ...) { char compose[4096 - 128]; va_list ap; @@ -271,37 +423,44 @@ int mgcpgw_client_tx_str(struct mgcpgw_client *mgcp, const char *fmt, ...) return -EMSGSIZE; if (len < 1) return -EIO; - return mgcpgw_client_tx_buf(mgcp, compose, len); + return mgcpgw_client_tx_buf(mgcp, response_cb, priv, compose, len, trans_id); } -int mgcpgw_client_tx_crcx(struct mgcpgw_client *client, +int mgcpgw_client_tx_crcx(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, uint16_t rtp_endpoint, unsigned int call_id, enum mgcp_connection_mode mode) { - return mgcpgw_client_tx_str(client, + unsigned int trans_id = mgcp->next_trans_id ++; + return mgcpgw_client_tx_str(mgcp, + response_cb, priv, trans_id, "CRCX %u %x@mgw MGCP 1.0\r\n" "C: %x\r\n" "L: p:20, a:AMR, nt:IN\r\n" "M: %s\r\n" , - client->next_trans_id ++, + trans_id, rtp_endpoint, call_id, mgcp_cmode_name(mode)); } -int mgcpgw_client_tx_mdcx(struct mgcpgw_client *client, uint16_t rtp_endpoint, - const char *rtp_conn_addr, uint16_t rtp_port, - enum mgcp_connection_mode mode) +int mgcpgw_client_tx_mdcx(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, + uint16_t rtp_endpoint, const char *rtp_conn_addr, + uint16_t rtp_port, enum mgcp_connection_mode mode) + { - return mgcpgw_client_tx_str(client, + unsigned int trans_id = mgcp->next_trans_id ++; + return mgcpgw_client_tx_str(mgcp, + response_cb, priv, trans_id, "MDCX %u %x@mgw MGCP 1.0\r\n" "M: %s\r\n" "\r\n" "c=IN IP4 %s\r\n" "m=audio %u RTP/AVP 255\r\n" , - client->next_trans_id ++, + trans_id, rtp_endpoint, mgcp_cmode_name(mode), rtp_conn_addr, diff --git a/openbsc/src/libmsc/msc_ifaces.c b/openbsc/src/libmsc/msc_ifaces.c index ea68af9cb..f75d425ca 100644 --- a/openbsc/src/libmsc/msc_ifaces.c +++ b/openbsc/src/libmsc/msc_ifaces.c @@ -128,6 +128,32 @@ static int iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id, return iu_rab_act(uectx, msg); } +static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv) +{ + struct gsm_trans *trans = priv; + int rc; + + if (r->head.response_code != 200) { + LOGP(DMGCP, LOGL_ERROR, + "MGCPGW response yields error: %d %s\n", + r->head.response_code, r->head.comment); + goto rab_act_cs_error; + } + + rc = mgcp_response_parse_params(r); + if (rc) { + LOGP(DMGCP, LOGL_ERROR, + "Cannot parse MGCP response, for %s\n", + subscr_name(trans->subscr)); + goto rab_act_cs_error; + } + + +rab_act_cs_error: + /* FIXME abort call, invalidate conn, ... */ + return; +} + static int conn_iu_rab_act_cs(struct gsm_trans *trans) { struct gsm_subscriber_connection *conn = trans->conn; @@ -149,6 +175,7 @@ static int conn_iu_rab_act_cs(struct gsm_trans *trans) * The MDCX will patch through to the counterpart. TODO: play a ring * tone instead. */ mgcpgw_client_tx_crcx(conn->network->mgcpgw.client, + mgcp_response_rab_act_cs_crcx, trans, conn->iu.mgcp_rtp_endpoint, trans->callref, MGCP_CONN_LOOPBACK); @@ -190,6 +217,11 @@ int msc_call_assignment(struct gsm_trans *trans) } } +static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv) +{ + /* TODO */ +} + int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2) { struct gsm_subscriber_connection *conn1 = trans1->conn; @@ -202,17 +234,25 @@ int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2) /* First setup the counterparts' endpoints, so that when transmission * starts the originating addresses are already known to be valid. */ - mgcpgw_client_tx_mdcx(mgcp, conn1->iu.mgcp_rtp_endpoint, + mgcpgw_client_tx_mdcx(mgcp, + mgcp_response_bridge_mdcx, trans1, + conn1->iu.mgcp_rtp_endpoint, ip, conn2->iu.mgcp_rtp_port_cn, MGCP_CONN_LOOPBACK); - mgcpgw_client_tx_mdcx(mgcp, conn2->iu.mgcp_rtp_endpoint, + mgcpgw_client_tx_mdcx(mgcp, + mgcp_response_bridge_mdcx, trans2, + conn2->iu.mgcp_rtp_endpoint, ip, conn1->iu.mgcp_rtp_port_cn, MGCP_CONN_LOOPBACK); /* Now enable sending to and receiving from the peer. */ - mgcpgw_client_tx_mdcx(mgcp, conn1->iu.mgcp_rtp_endpoint, + mgcpgw_client_tx_mdcx(mgcp, + mgcp_response_bridge_mdcx, trans1, + conn1->iu.mgcp_rtp_endpoint, ip, conn2->iu.mgcp_rtp_port_cn, MGCP_CONN_RECV_SEND); - mgcpgw_client_tx_mdcx(mgcp, conn2->iu.mgcp_rtp_endpoint, + mgcpgw_client_tx_mdcx(mgcp, + mgcp_response_bridge_mdcx, trans2, + conn2->iu.mgcp_rtp_endpoint, ip, conn1->iu.mgcp_rtp_port_cn, MGCP_CONN_RECV_SEND); diff --git a/openbsc/src/osmo-msc/msc_main.c b/openbsc/src/osmo-msc/msc_main.c index 6a8297f8d..f1128988e 100644 --- a/openbsc/src/osmo-msc/msc_main.c +++ b/openbsc/src/osmo-msc/msc_main.c @@ -96,16 +96,6 @@ void *tall_map_ctx = NULL; void *tall_upq_ctx = NULL; /* end deps from libbsc legacy. */ -static void mgcp_rx_cb(struct msgb *msg, void *priv) -{ - static char strbuf[4096]; - unsigned int l = msg->len < sizeof(strbuf)-1 ? msg->len : sizeof(strbuf)-1; - strncpy(strbuf, (const char*)msg->data, l); - strbuf[l] = '\0'; - DEBUGP(DMGCP, "Rx MGCP msg from MGCP GW: '%s'\n", strbuf); - talloc_free(msg); -} - static struct { const char *database_name; const char *config_file; @@ -470,8 +460,7 @@ TODO: we probably want some of the _net_ ctrl commands from bsc_base_ctrl_cmds_i * should try to use the nanoseconds part of the current time. */ msc_network->mgcpgw.client = mgcpgw_client_init( - msc_network, &msc_network->mgcpgw.conf, - mgcp_rx_cb, NULL); + msc_network, &msc_network->mgcpgw.conf); if (db_init(msc_cmdline_config.database_name)) { printf("DB: Failed to init database: %s\n", diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c index 2720b25e1..f1eadc268 100644 --- a/openbsc/tests/db/db_test.c +++ b/openbsc/tests/db/db_test.c @@ -264,18 +264,22 @@ void vlr_proc_acc_req() {} void vlr_init() {} unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client) { return 0; } -int mgcpgw_client_tx_crcx(struct mgcpgw_client *client, +int mgcpgw_client_tx_crcx(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, uint16_t rtp_endpoint, unsigned int call_id, enum mgcp_connection_mode mode) { return -ENOTSUP; } -int mgcpgw_client_tx_mdcx(struct mgcpgw_client *client, uint16_t rtp_endpoint, - const char *rtp_conn_addr, uint16_t rtp_port, - enum mgcp_connection_mode mode) +int mgcpgw_client_tx_mdcx(struct mgcpgw_client *mgcp, + mgcp_response_cb_t response_cb, void *priv, + uint16_t rtp_endpoint, const char *rtp_conn_addr, + uint16_t rtp_port, enum mgcp_connection_mode mode) { return -ENOTSUP; } const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp) { return "0.0.0.0"; } uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp) { return 0; } +int mgcp_response_parse_params(struct mgcp_response *r) +{ return -EINVAL; } struct RANAP_Cause; int iu_tx_release(struct ue_conn_ctx *ctx, const struct RANAP_Cause *cause) { return 0; } -- cgit v1.2.3