mgcp: use osmo-mgw to switch rtp streams
in the current implementation we still use osmo-bsc_mgcp, which has many problems and is also obsoleted by osmo-mgw. integrate osmo-mgw and re-implement the current switching using an osmo fsm. Depends: osmo-mgw Iab6a6038e7610c62f34e642cd49c93d11151252c Depends: osmo-iuh I3c1a0455c5f25cae41ee19229d6daf299e023062 Closes: OS#2605 Change-Id: Ieea9630358b3963261fa1993cf1f3b563ff23538
This commit is contained in:
parent
629c479edd
commit
387edd67ac
|
@ -39,6 +39,7 @@ noinst_HEADERS = \
|
||||||
mncc.h \
|
mncc.h \
|
||||||
mncc_int.h \
|
mncc_int.h \
|
||||||
msc_ifaces.h \
|
msc_ifaces.h \
|
||||||
|
msc_mgcp.h \
|
||||||
network_listen.h \
|
network_listen.h \
|
||||||
oap_client.h \
|
oap_client.h \
|
||||||
openbscdefines.h \
|
openbscdefines.h \
|
||||||
|
|
|
@ -196,9 +196,17 @@ struct gsm_subscriber_connection {
|
||||||
struct gsm_encr encr;
|
struct gsm_encr encr;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
struct mgcp_ctx *mgcp_ctx;
|
||||||
unsigned int mgcp_rtp_endpoint;
|
unsigned int mgcp_rtp_endpoint;
|
||||||
uint16_t port_subscr;
|
|
||||||
uint16_t port_cn;
|
uint16_t local_port_ran;
|
||||||
|
char local_addr_ran[INET_ADDRSTRLEN];
|
||||||
|
uint16_t remote_port_ran;
|
||||||
|
char remote_addr_ran[INET_ADDRSTRLEN];
|
||||||
|
uint16_t local_port_cn;
|
||||||
|
char local_addr_cn[INET_ADDRSTRLEN];
|
||||||
|
uint16_t remote_port_cn;
|
||||||
|
char remote_addr_cn[INET_ADDRSTRLEN];
|
||||||
} rtp;
|
} rtp;
|
||||||
|
|
||||||
/* which Iu-CS connection, if any. */
|
/* which Iu-CS connection, if any. */
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <osmocom/msc/transaction.h>
|
||||||
|
|
||||||
int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
|
int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
|
||||||
uint16_t *lac);
|
uint16_t *lac);
|
||||||
|
|
||||||
struct gsm_subscriber_connection *subscr_conn_lookup_iu(struct gsm_network *network,
|
struct gsm_subscriber_connection *subscr_conn_lookup_iu(struct gsm_network *network,
|
||||||
struct ranap_ue_conn_ctx *ue);
|
struct ranap_ue_conn_ctx *ue);
|
||||||
|
int iu_rab_act_cs(struct gsm_trans *trans);
|
||||||
|
|
|
@ -37,7 +37,3 @@ int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
|
||||||
enum gsm48_reject_value value);
|
enum gsm48_reject_value value);
|
||||||
|
|
||||||
int msc_tx_common_id(struct gsm_subscriber_connection *conn);
|
int msc_tx_common_id(struct gsm_subscriber_connection *conn);
|
||||||
int msc_call_assignment(struct gsm_trans *trans);
|
|
||||||
int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2);
|
|
||||||
void msc_call_release(struct gsm_trans *trans);
|
|
||||||
int msc_call_connect(struct gsm_trans *trans, uint16_t port, uint32_t ip);
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* (C) 2017 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* Author: Philipp Maier
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <osmocom/mgcp_client/mgcp_client.h>
|
||||||
|
#include <osmocom/msc/gsm_data.h>
|
||||||
|
|
||||||
|
/* MGCP state handler context. This context information stores all information
|
||||||
|
* to handle the direction of the RTP streams via MGCP. There is one instance
|
||||||
|
* of this context struct per subscriber connection.
|
||||||
|
* (see also struct gsm_subscriber_connection) */
|
||||||
|
struct mgcp_ctx {
|
||||||
|
/* FSM instance, which handles the connection switching procedure */
|
||||||
|
struct osmo_fsm_inst *fsm;
|
||||||
|
|
||||||
|
/* RTP endpoint number. This number number identifies the endpoint
|
||||||
|
* on the MGW on which the RAN and CN connection is created. This
|
||||||
|
* endpoint number is assigned and released automatically. */
|
||||||
|
uint16_t rtp_endpoint;
|
||||||
|
|
||||||
|
/* Set to true, when the context information is no longer needed */
|
||||||
|
bool free_ctx;
|
||||||
|
|
||||||
|
/* RTP connection identifiers */
|
||||||
|
char conn_id_ran[MGCP_CONN_ID_LENGTH];
|
||||||
|
char conn_id_cn[MGCP_CONN_ID_LENGTH];
|
||||||
|
|
||||||
|
/* Copy of the pointer and the data with context information
|
||||||
|
* needed to process the AoIP and MGCP requests (system data) */
|
||||||
|
struct mgcp_client *mgcp;
|
||||||
|
struct gsm_trans *trans;
|
||||||
|
mgcp_trans_id_t mgw_pending_trans;
|
||||||
|
};
|
||||||
|
|
||||||
|
int msc_mgcp_call_assignment(struct gsm_trans *trans);
|
||||||
|
int msc_mgcp_ass_complete(struct gsm_subscriber_connection *conn, uint16_t port, char *addr);
|
||||||
|
int msc_mgcp_call_complete(struct gsm_trans *trans, uint16_t port, char *addr);
|
||||||
|
int msc_mgcp_call_release(struct gsm_trans *trans);
|
|
@ -41,6 +41,7 @@ libmsc_a_SOURCES = \
|
||||||
mncc_builtin.c \
|
mncc_builtin.c \
|
||||||
mncc_sock.c \
|
mncc_sock.c \
|
||||||
msc_ifaces.c \
|
msc_ifaces.c \
|
||||||
|
msc_mgcp.c \
|
||||||
rrlp.c \
|
rrlp.c \
|
||||||
silent_call.c \
|
silent_call.c \
|
||||||
sms_queue.c \
|
sms_queue.c \
|
||||||
|
|
|
@ -396,8 +396,21 @@ int a_iface_tx_assignment(const struct gsm_trans *trans)
|
||||||
/* Package RTP-Address data */
|
/* Package RTP-Address data */
|
||||||
memset(&rtp_addr_in, 0, sizeof(rtp_addr_in));
|
memset(&rtp_addr_in, 0, sizeof(rtp_addr_in));
|
||||||
rtp_addr_in.sin_family = AF_INET;
|
rtp_addr_in.sin_family = AF_INET;
|
||||||
rtp_addr_in.sin_port = osmo_htons(conn->rtp.port_subscr);
|
rtp_addr_in.sin_port = osmo_htons(conn->rtp.local_port_ran);
|
||||||
rtp_addr_in.sin_addr.s_addr = osmo_htonl(mgcp_client_remote_addr_n(gsm_network->mgw.client));
|
rtp_addr_in.sin_addr.s_addr = inet_addr(conn->rtp.local_addr_ran);
|
||||||
|
|
||||||
|
if (rtp_addr_in.sin_addr.s_addr == INADDR_NONE) {
|
||||||
|
LOGP(DMSC, LOGL_ERROR,
|
||||||
|
"(subscriber:%s) Invalid RTP-Address -- assignment not sent!\n",
|
||||||
|
vlr_subscr_name(trans->vsub));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (rtp_addr_in.sin_port == 0) {
|
||||||
|
LOGP(DMSC, LOGL_ERROR,
|
||||||
|
"(subscriber:%s) Invalid RTP-Port -- assignment not sent!\n",
|
||||||
|
vlr_subscr_name(trans->vsub));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&rtp_addr, 0, sizeof(rtp_addr));
|
memset(&rtp_addr, 0, sizeof(rtp_addr));
|
||||||
memcpy(&rtp_addr, &rtp_addr_in, sizeof(rtp_addr_in));
|
memcpy(&rtp_addr, &rtp_addr_in, sizeof(rtp_addr_in));
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <osmocom/core/byteswap.h>
|
#include <osmocom/core/byteswap.h>
|
||||||
#include <osmocom/msc/a_reset.h>
|
#include <osmocom/msc/a_reset.h>
|
||||||
#include <osmocom/msc/transaction.h>
|
#include <osmocom/msc/transaction.h>
|
||||||
|
#include <osmocom/msc/msc_mgcp.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
@ -596,11 +597,7 @@ static int bssmap_rx_ass_compl(const struct osmo_sccp_user *scu, const struct a_
|
||||||
* transport address element */
|
* transport address element */
|
||||||
if (rtp_addr.ss_family == AF_INET) {
|
if (rtp_addr.ss_family == AF_INET) {
|
||||||
rtp_addr_in = (struct sockaddr_in *)&rtp_addr;
|
rtp_addr_in = (struct sockaddr_in *)&rtp_addr;
|
||||||
conn->rtp.port_subscr = osmo_ntohs(rtp_addr_in->sin_port);
|
msc_mgcp_ass_complete(conn, osmo_ntohs(rtp_addr_in->sin_port), inet_ntoa(rtp_addr_in->sin_addr));
|
||||||
/* FIXME: We also get the IP-Address of the remote (e.g. BTS)
|
|
||||||
* end with the response. Currently we just ignore that address.
|
|
||||||
* Instead we expect that our local MGCP gateway and the code
|
|
||||||
* controlling it, magically knows the IP of the remote end. */
|
|
||||||
} else {
|
} else {
|
||||||
LOGP(DMSC, LOGL_ERROR, "Unsopported addressing scheme. (supports only IPV4)\n");
|
LOGP(DMSC, LOGL_ERROR, "Unsopported addressing scheme. (supports only IPV4)\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
#include <osmocom/core/talloc.h>
|
#include <osmocom/core/talloc.h>
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/byteswap.h>
|
||||||
#include <osmocom/gsm/tlv.h>
|
#include <osmocom/gsm/tlv.h>
|
||||||
#include <osmocom/crypt/auth.h>
|
#include <osmocom/crypt/auth.h>
|
||||||
#ifdef BUILD_IU
|
#ifdef BUILD_IU
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
|
|
||||||
#include <osmocom/msc/msc_ifaces.h>
|
#include <osmocom/msc/msc_ifaces.h>
|
||||||
#include <osmocom/msc/a_iface.h>
|
#include <osmocom/msc/a_iface.h>
|
||||||
|
#include <osmocom/msc/msc_mgcp.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
@ -1332,8 +1334,8 @@ void _gsm48_cc_trans_free(struct gsm_trans *trans)
|
||||||
{
|
{
|
||||||
gsm48_stop_cc_timer(trans);
|
gsm48_stop_cc_timer(trans);
|
||||||
|
|
||||||
/* Make sure call also gets released on the mgcp side */
|
/* Initiate the teardown of the related connections on the MGW */
|
||||||
msc_call_release(trans);
|
msc_mgcp_call_release(trans);
|
||||||
|
|
||||||
/* send release to L4, if callref still exists */
|
/* send release to L4, if callref still exists */
|
||||||
if (trans->callref) {
|
if (trans->callref) {
|
||||||
|
@ -1394,6 +1396,7 @@ static int tch_bridge(struct gsm_network *net, struct gsm_mncc_bridge *bridge)
|
||||||
{
|
{
|
||||||
struct gsm_trans *trans1 = trans_find_by_callref(net, bridge->callref[0]);
|
struct gsm_trans *trans1 = trans_find_by_callref(net, bridge->callref[0]);
|
||||||
struct gsm_trans *trans2 = trans_find_by_callref(net, bridge->callref[1]);
|
struct gsm_trans *trans2 = trans_find_by_callref(net, bridge->callref[1]);
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (!trans1 || !trans2)
|
if (!trans1 || !trans2)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -1404,7 +1407,18 @@ static int tch_bridge(struct gsm_network *net, struct gsm_mncc_bridge *bridge)
|
||||||
/* Which subscriber do we want to track trans1 or trans2? */
|
/* Which subscriber do we want to track trans1 or trans2? */
|
||||||
log_set_context(LOG_CTX_VLR_SUBSCR, trans1->vsub);
|
log_set_context(LOG_CTX_VLR_SUBSCR, trans1->vsub);
|
||||||
|
|
||||||
return msc_call_bridge(trans1, trans2);
|
/* Bridge RTP streams */
|
||||||
|
rc = msc_mgcp_call_complete(trans1, trans2->conn->rtp.local_port_cn,
|
||||||
|
trans2->conn->rtp.local_addr_cn);
|
||||||
|
if (rc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
rc = msc_mgcp_call_complete(trans2, trans1->conn->rtp.local_port_cn,
|
||||||
|
trans1->conn->rtp.local_addr_cn);
|
||||||
|
if (rc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
|
static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
|
||||||
|
@ -1747,7 +1761,7 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
|
||||||
|
|
||||||
/* Assign call (if not done yet) */
|
/* Assign call (if not done yet) */
|
||||||
if (trans->assignment_done == false) {
|
if (trans->assignment_done == false) {
|
||||||
rc = msc_call_assignment(trans);
|
rc = msc_mgcp_call_assignment(trans);
|
||||||
trans->assignment_done = true;
|
trans->assignment_done = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1789,7 +1803,7 @@ static int gsm48_cc_tx_call_proc_and_assign(struct gsm_trans *trans, void *arg)
|
||||||
|
|
||||||
/* Assign call (if not done yet) */
|
/* Assign call (if not done yet) */
|
||||||
if (trans->assignment_done == false) {
|
if (trans->assignment_done == false) {
|
||||||
rc = msc_call_assignment(trans);
|
rc = msc_mgcp_call_assignment(trans);
|
||||||
trans->assignment_done = true;
|
trans->assignment_done = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2673,8 +2687,23 @@ static void mncc_recv_rtp_sock(struct gsm_network *net, struct gsm_trans *trans,
|
||||||
* (0 if unknown) */
|
* (0 if unknown) */
|
||||||
msg_type = GSM_TCHF_FRAME;
|
msg_type = GSM_TCHF_FRAME;
|
||||||
|
|
||||||
uint32_t addr = mgcp_client_remote_addr_n(net->mgw.client);
|
uint32_t addr = inet_addr(trans->conn->rtp.local_addr_cn);
|
||||||
uint16_t port = trans->conn->rtp.port_cn;
|
uint16_t port = trans->conn->rtp.local_port_cn;
|
||||||
|
|
||||||
|
LOGP(DMNCC, LOGL_ERROR, "RTP create for non-existing trans\n");
|
||||||
|
|
||||||
|
if (addr == INADDR_NONE) {
|
||||||
|
LOGP(DMNCC, LOGL_ERROR,
|
||||||
|
"(subscriber:%s) external MNCC is signalling invalid IP-Address\n",
|
||||||
|
vlr_subscr_name(trans->vsub));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (port == 0) {
|
||||||
|
LOGP(DMNCC, LOGL_ERROR,
|
||||||
|
"(subscriber:%s) external MNCC is signalling invalid Port\n",
|
||||||
|
vlr_subscr_name(trans->vsub));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: This has to be set to some meaningful value,
|
/* FIXME: This has to be set to some meaningful value,
|
||||||
* before the MSC-Split, this value was pulled from
|
* before the MSC-Split, this value was pulled from
|
||||||
|
@ -2714,15 +2743,15 @@ static int tch_rtp_create(struct gsm_network *net, uint32_t callref)
|
||||||
|
|
||||||
trans->conn->mncc_rtp_bridge = 1;
|
trans->conn->mncc_rtp_bridge = 1;
|
||||||
|
|
||||||
/* When we call msc_call_assignment() we will trigger, depending
|
/* When we call msc_mgcp_call_assignment() we will trigger, depending
|
||||||
* on the RAN type the call assignment on the A or Iu interface.
|
* on the RAN type the call assignment on the A or Iu interface.
|
||||||
* msc_call_assignment() also takes care about sending the CRCX
|
* msc_mgcp_call_assignment() also takes care about sending the CRCX
|
||||||
* command to the MGCP-GW. The CRCX will return the port number,
|
* command to the MGCP-GW. The CRCX will return the port number,
|
||||||
* where the PBX (e.g. Asterisk) will send its RTP stream to. We
|
* where the PBX (e.g. Asterisk) will send its RTP stream to. We
|
||||||
* have to return this port number back to the MNCC by sending
|
* have to return this port number back to the MNCC by sending
|
||||||
* it back with the TCH_RTP_CREATE message. To make sure that
|
* it back with the TCH_RTP_CREATE message. To make sure that
|
||||||
* this message is sent AFTER the response to CRCX from the
|
* this message is sent AFTER the response to CRCX from the
|
||||||
* MGCP-GW has arrived, we need will instruct msc_call_assignment()
|
* MGCP-GW has arrived, we need will instruct msc_mgcp_call_assignment()
|
||||||
* to take care of this by setting trans->tch_rtp_create to true.
|
* to take care of this by setting trans->tch_rtp_create to true.
|
||||||
* This will make sure that gsm48_tch_rtp_create() (below) is
|
* This will make sure that gsm48_tch_rtp_create() (below) is
|
||||||
* called as soon as the local port number has become known. */
|
* called as soon as the local port number has become known. */
|
||||||
|
@ -2730,7 +2759,7 @@ static int tch_rtp_create(struct gsm_network *net, uint32_t callref)
|
||||||
|
|
||||||
/* Assign call (if not done yet) */
|
/* Assign call (if not done yet) */
|
||||||
if (trans->assignment_done == false) {
|
if (trans->assignment_done == false) {
|
||||||
rc = msc_call_assignment(trans);
|
rc = msc_mgcp_call_assignment(trans);
|
||||||
trans->assignment_done = true;
|
trans->assignment_done = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2757,6 +2786,7 @@ static int tch_rtp_connect(struct gsm_network *net, void *arg)
|
||||||
{
|
{
|
||||||
struct gsm_trans *trans;
|
struct gsm_trans *trans;
|
||||||
struct gsm_mncc_rtp *rtp = arg;
|
struct gsm_mncc_rtp *rtp = arg;
|
||||||
|
struct in_addr addr;
|
||||||
|
|
||||||
/* Find callref */
|
/* Find callref */
|
||||||
trans = trans_find_by_callref(net, rtp->callref);
|
trans = trans_find_by_callref(net, rtp->callref);
|
||||||
|
@ -2772,8 +2802,8 @@ static int tch_rtp_connect(struct gsm_network *net, void *arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
msc_call_connect(trans, rtp->port, rtp->ip);
|
addr.s_addr = osmo_htonl(rtp->ip);
|
||||||
return 0;
|
return msc_mgcp_call_complete(trans, rtp->port, inet_ntoa(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct downstate {
|
static struct downstate {
|
||||||
|
|
|
@ -30,8 +30,22 @@
|
||||||
|
|
||||||
#include <osmocom/msc/gsm_data.h>
|
#include <osmocom/msc/gsm_data.h>
|
||||||
#include <osmocom/msc/gsm_subscriber.h>
|
#include <osmocom/msc/gsm_subscriber.h>
|
||||||
|
#include <osmocom/msc/transaction.h>
|
||||||
#include <osmocom/msc/osmo_msc.h>
|
#include <osmocom/msc/osmo_msc.h>
|
||||||
#include <osmocom/msc/vlr.h>
|
#include <osmocom/msc/vlr.h>
|
||||||
|
#include <osmocom/core/byteswap.h>
|
||||||
|
|
||||||
|
#include "../../bscconfig.h"
|
||||||
|
|
||||||
|
#ifdef BUILD_IU
|
||||||
|
#include <osmocom/ranap/iu_client.h>
|
||||||
|
extern struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id,
|
||||||
|
uint32_t rtp_ip,
|
||||||
|
uint16_t rtp_port,
|
||||||
|
bool use_x213_nsap);
|
||||||
|
#else
|
||||||
|
#include <osmocom/msc/iu_dummy.h>
|
||||||
|
#endif /* BUILD_IU */
|
||||||
|
|
||||||
/* For A-interface see libbsc/bsc_api.c subscr_con_allocate() */
|
/* For A-interface see libbsc/bsc_api.c subscr_con_allocate() */
|
||||||
static struct gsm_subscriber_connection *subscr_conn_allocate_iu(struct gsm_network *network,
|
static struct gsm_subscriber_connection *subscr_conn_allocate_iu(struct gsm_network *network,
|
||||||
|
@ -187,3 +201,53 @@ int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int iu_rab_act_cs(struct gsm_trans *trans)
|
||||||
|
{
|
||||||
|
struct gsm_subscriber_connection *conn;
|
||||||
|
struct msgb *msg;
|
||||||
|
bool use_x213_nsap;
|
||||||
|
uint32_t conn_id;
|
||||||
|
struct ranap_ue_conn_ctx *uectx;
|
||||||
|
uint8_t rab_id;
|
||||||
|
uint32_t rtp_ip;
|
||||||
|
uint16_t rtp_port;
|
||||||
|
|
||||||
|
conn = trans->conn;
|
||||||
|
uectx = conn->iu.ue_ctx;
|
||||||
|
rab_id = conn->iu.rab_id;
|
||||||
|
rtp_ip = osmo_htonl(inet_addr(conn->rtp.local_addr_ran));
|
||||||
|
rtp_port = conn->rtp.local_port_ran;
|
||||||
|
conn_id = uectx->conn_id;
|
||||||
|
|
||||||
|
if (rtp_ip == INADDR_NONE) {
|
||||||
|
LOGP(DIUCS, LOGL_DEBUG,
|
||||||
|
"Assigning RAB: conn_id=%u, rab_id=%d, invalid RTP IP-Address\n",
|
||||||
|
conn_id, rab_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (rtp_port == 0) {
|
||||||
|
LOGP(DIUCS, LOGL_DEBUG,
|
||||||
|
"Assigning RAB: conn_id=%u, rab_id=%d, invalid RTP Port\n",
|
||||||
|
conn_id, rab_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
use_x213_nsap =
|
||||||
|
(uectx->rab_assign_addr_enc == RANAP_NSAP_ADDR_ENC_X213);
|
||||||
|
|
||||||
|
LOGP(DIUCS, LOGL_DEBUG,
|
||||||
|
"Assigning RAB: conn_id=%u, rab_id=%d, rtp=%x:%u, use_x213_nsap=%d\n",
|
||||||
|
conn_id, rab_id, rtp_ip, rtp_port, use_x213_nsap);
|
||||||
|
|
||||||
|
msg = ranap_new_msg_rab_assign_voice(rab_id, rtp_ip, rtp_port,
|
||||||
|
use_x213_nsap);
|
||||||
|
msg->l2h = msg->data;
|
||||||
|
|
||||||
|
if (ranap_iu_rab_act(uectx, msg))
|
||||||
|
LOGP(DIUCS, LOGL_ERROR,
|
||||||
|
"Failed to send RAB Assignment: conn_id=%d rab_id=%d rtp=%x:%u\n",
|
||||||
|
conn_id, rab_id, rtp_ip, rtp_port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
#include <osmocom/ranap/ranap_ies_defs.h>
|
#include <osmocom/ranap/ranap_ies_defs.h>
|
||||||
#include <osmocom/ranap/iu_client.h>
|
#include <osmocom/ranap/iu_client.h>
|
||||||
|
#include <osmocom/ranap/RANAP_IuTransportAssociation.h>
|
||||||
|
#include <osmocom/ranap/iu_helpers.h>
|
||||||
|
|
||||||
#include <osmocom/msc/debug.h>
|
#include <osmocom/msc/debug.h>
|
||||||
#include <osmocom/msc/gsm_data.h>
|
#include <osmocom/msc/gsm_data.h>
|
||||||
|
@ -36,22 +38,54 @@
|
||||||
#include <osmocom/msc/vlr.h>
|
#include <osmocom/msc/vlr.h>
|
||||||
#include <osmocom/msc/iucs_ranap.h>
|
#include <osmocom/msc/iucs_ranap.h>
|
||||||
#include <osmocom/msc/osmo_msc.h>
|
#include <osmocom/msc/osmo_msc.h>
|
||||||
|
#include <osmocom/msc/msc_mgcp.h>
|
||||||
|
|
||||||
|
#include <asn1c/asn1helpers.h>
|
||||||
|
|
||||||
/* To continue authorization after a Security Mode Complete */
|
/* To continue authorization after a Security Mode Complete */
|
||||||
int gsm0408_authorize(struct gsm_subscriber_connection *conn);
|
int gsm0408_authorize(struct gsm_subscriber_connection *conn);
|
||||||
|
|
||||||
static int iucs_rx_rab_assign(struct gsm_subscriber_connection *conn,
|
static int iucs_rx_rab_assign(struct gsm_subscriber_connection *conn, RANAP_RAB_SetupOrModifiedItemIEs_t * setup_ies)
|
||||||
RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
|
|
||||||
{
|
{
|
||||||
uint8_t rab_id;
|
uint8_t rab_id;
|
||||||
RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem;
|
RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem;
|
||||||
|
RANAP_TransportLayerAddress_t *transp_layer_addr;
|
||||||
|
RANAP_IuTransportAssociation_t *transp_assoc;
|
||||||
|
uint16_t port = 0;
|
||||||
|
int rc;
|
||||||
|
char addr[INET_ADDRSTRLEN];
|
||||||
|
|
||||||
rab_id = item->rAB_ID.buf[0];
|
rab_id = item->rAB_ID.buf[0];
|
||||||
|
|
||||||
LOGP(DIUCS, LOGL_NOTICE,
|
LOGP(DIUCS, LOGL_NOTICE,
|
||||||
"Received RAB assignment event for %s rab_id=%hhd\n",
|
"Received RAB assignment event for %s rab_id=%hhd\n", vlr_subscr_name(conn->vsub), rab_id);
|
||||||
vlr_subscr_name(conn->vsub), rab_id);
|
|
||||||
|
|
||||||
|
if (item->iuTransportAssociation && item->transportLayerAddress) {
|
||||||
|
transp_layer_addr = item->transportLayerAddress;
|
||||||
|
transp_assoc = item->iuTransportAssociation;
|
||||||
|
|
||||||
|
rc = ranap_transp_assoc_decode(&port, transp_assoc);
|
||||||
|
if (rc != 0) {
|
||||||
|
LOGP(DIUCS, LOGL_ERROR,
|
||||||
|
"Unable to decode RTP port in RAB assignment (%s rab_id=%hhd)\n",
|
||||||
|
vlr_subscr_name(conn->vsub), rab_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ranap_transp_layer_addr_decode(addr, sizeof(addr), transp_layer_addr);
|
||||||
|
if (rc != 0) {
|
||||||
|
LOGP(DIUCS, LOGL_ERROR,
|
||||||
|
"Unable to decode IP-Address in RAB assignment (%s rab_id=%hhd)\n",
|
||||||
|
vlr_subscr_name(conn->vsub), rab_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return msc_mgcp_ass_complete(conn, port, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGP(DIUCS, LOGL_ERROR,
|
||||||
|
"RAB assignment lacks RTP connection information. (%s rab_id=%hhd)\n",
|
||||||
|
vlr_subscr_name(conn->vsub), rab_id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,15 +29,12 @@
|
||||||
#include <osmocom/msc/vlr.h>
|
#include <osmocom/msc/vlr.h>
|
||||||
#include <osmocom/msc/a_iface.h>
|
#include <osmocom/msc/a_iface.h>
|
||||||
#include <osmocom/msc/gsm_04_08.h>
|
#include <osmocom/msc/gsm_04_08.h>
|
||||||
|
#include <osmocom/msc/msc_mgcp.h>
|
||||||
|
|
||||||
#include "../../bscconfig.h"
|
#include "../../bscconfig.h"
|
||||||
|
|
||||||
#ifdef BUILD_IU
|
#ifdef BUILD_IU
|
||||||
#include <osmocom/ranap/iu_client.h>
|
#include <osmocom/ranap/iu_client.h>
|
||||||
extern struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id,
|
|
||||||
uint32_t rtp_ip,
|
|
||||||
uint16_t rtp_port,
|
|
||||||
bool use_x213_nsap);
|
|
||||||
#else
|
#else
|
||||||
#include <osmocom/msc/iu_dummy.h>
|
#include <osmocom/msc/iu_dummy.h>
|
||||||
#endif /* BUILD_IU */
|
#endif /* BUILD_IU */
|
||||||
|
@ -141,286 +138,3 @@ int msc_tx_common_id(struct gsm_subscriber_connection *conn)
|
||||||
vlr_subscr_name(conn->vsub), conn->vsub->imsi);
|
vlr_subscr_name(conn->vsub), conn->vsub->imsi);
|
||||||
return ranap_iu_tx_common_id(conn->iu.ue_ctx, conn->vsub->imsi);
|
return ranap_iu_tx_common_id(conn->iu.ue_ctx, conn->vsub->imsi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iu_rab_act_cs(struct ranap_ue_conn_ctx *uectx, uint8_t rab_id,
|
|
||||||
uint32_t rtp_ip, uint16_t rtp_port)
|
|
||||||
{
|
|
||||||
#ifdef BUILD_IU
|
|
||||||
struct msgb *msg;
|
|
||||||
bool use_x213_nsap;
|
|
||||||
uint32_t conn_id = uectx->conn_id;
|
|
||||||
|
|
||||||
use_x213_nsap = (uectx->rab_assign_addr_enc == RANAP_NSAP_ADDR_ENC_X213);
|
|
||||||
|
|
||||||
LOGP(DIUCS, LOGL_DEBUG, "Assigning RAB: conn_id=%u, rab_id=%d,"
|
|
||||||
" rtp=%x:%u, use_x213_nsap=%d\n", conn_id, rab_id, rtp_ip,
|
|
||||||
rtp_port, use_x213_nsap);
|
|
||||||
|
|
||||||
msg = ranap_new_msg_rab_assign_voice(rab_id, rtp_ip, rtp_port,
|
|
||||||
use_x213_nsap);
|
|
||||||
msg->l2h = msg->data;
|
|
||||||
|
|
||||||
if (ranap_iu_rab_act(uectx, msg))
|
|
||||||
LOGP(DIUCS, LOGL_ERROR, "Failed to send RAB Assignment:"
|
|
||||||
" conn_id=%d rab_id=%d rtp=%x:%u\n",
|
|
||||||
conn_id, rab_id, rtp_ip, rtp_port);
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
LOGP(DMSC, LOGL_ERROR, "Cannot send Iu RAB Assignment: built without Iu support\n");
|
|
||||||
return -ENOTSUP;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv)
|
|
||||||
{
|
|
||||||
struct gsm_trans *trans = priv;
|
|
||||||
struct gsm_subscriber_connection *conn = trans->conn;
|
|
||||||
uint32_t rtp_ip;
|
|
||||||
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",
|
|
||||||
vlr_subscr_name(trans->vsub));
|
|
||||||
goto rab_act_cs_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->rtp.port_cn = r->audio_port;
|
|
||||||
|
|
||||||
rtp_ip = mgcp_client_remote_addr_n(conn->network->mgw.client);
|
|
||||||
|
|
||||||
if (trans->conn->via_ran == RAN_UTRAN_IU) {
|
|
||||||
/* Assign a voice channel via RANAP on 3G */
|
|
||||||
if (iu_rab_act_cs(conn->iu.ue_ctx, conn->iu.rab_id, rtp_ip, conn->rtp.port_subscr))
|
|
||||||
goto rab_act_cs_error;
|
|
||||||
} else if (trans->conn->via_ran == RAN_GERAN_A) {
|
|
||||||
/* Assign a voice channel via A on 2G */
|
|
||||||
if (a_iface_tx_assignment(trans))
|
|
||||||
goto rab_act_cs_error;
|
|
||||||
} else
|
|
||||||
goto rab_act_cs_error;
|
|
||||||
|
|
||||||
/* Respond back to MNCC (if requested) */
|
|
||||||
if (trans->tch_rtp_create) {
|
|
||||||
if (gsm48_tch_rtp_create(trans))
|
|
||||||
goto rab_act_cs_error;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
rab_act_cs_error:
|
|
||||||
/* FIXME abort call, invalidate conn, ... */
|
|
||||||
LOGP(DMSC, LOGL_ERROR, "%s: failure during assignment\n",
|
|
||||||
vlr_subscr_name(trans->vsub));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int msc_call_assignment(struct gsm_trans *trans)
|
|
||||||
{
|
|
||||||
struct gsm_subscriber_connection *conn;
|
|
||||||
struct mgcp_client *mgcp;
|
|
||||||
struct msgb *msg;
|
|
||||||
uint16_t bts_base;
|
|
||||||
|
|
||||||
if (!trans)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!trans->conn)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
conn = trans->conn;
|
|
||||||
mgcp = conn->network->mgw.client;
|
|
||||||
|
|
||||||
#ifdef BUILD_IU
|
|
||||||
/* FIXME: HACK. where to scope the RAB Id? At the conn / subscriber / ranap_ue_conn_ctx? */
|
|
||||||
static uint8_t next_iu_rab_id = 1;
|
|
||||||
if (conn->via_ran == RAN_UTRAN_IU)
|
|
||||||
conn->iu.rab_id = next_iu_rab_id ++;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
conn->rtp.mgcp_rtp_endpoint =
|
|
||||||
mgcp_client_next_endpoint(conn->network->mgw.client);
|
|
||||||
|
|
||||||
/* This will calculate the port we assign to the BTS via AoIP
|
|
||||||
* assignment command (or rab-assignment on 3G) The BTS will send
|
|
||||||
* its RTP traffic to that port on the MGCPGW side. The MGCPGW only
|
|
||||||
* gets the endpoint ID via the CRCX. It will do the same calculation
|
|
||||||
* on his side too to get knowledge of the rtp port. */
|
|
||||||
bts_base = mgcp_client_conf_actual(mgcp)->bts_base;
|
|
||||||
conn->rtp.port_subscr = bts_base + 2 * conn->rtp.mgcp_rtp_endpoint;
|
|
||||||
|
|
||||||
/* Establish the RTP stream first as looping back to the originator.
|
|
||||||
* The MDCX will patch through to the counterpart. TODO: play a ring
|
|
||||||
* tone instead. */
|
|
||||||
msg = mgcp_msg_crcx(mgcp, conn->rtp.mgcp_rtp_endpoint,
|
|
||||||
conn->rtp.mgcp_rtp_endpoint, MGCP_CONN_LOOPBACK);
|
|
||||||
return mgcp_client_tx(mgcp, msg, mgcp_response_rab_act_cs_crcx, trans);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv);
|
|
||||||
|
|
||||||
static void mgcp_bridge(struct gsm_trans *from, struct gsm_trans *to,
|
|
||||||
enum bridge_state state,
|
|
||||||
enum mgcp_connection_mode mode)
|
|
||||||
{
|
|
||||||
struct gsm_subscriber_connection *conn1 = from->conn;
|
|
||||||
struct gsm_subscriber_connection *conn2 = to->conn;
|
|
||||||
struct mgcp_client *mgcp = conn1->network->mgw.client;
|
|
||||||
const char *ip;
|
|
||||||
struct msgb *msg;
|
|
||||||
|
|
||||||
OSMO_ASSERT(mgcp);
|
|
||||||
|
|
||||||
from->bridge.peer = to;
|
|
||||||
from->bridge.state = state;
|
|
||||||
|
|
||||||
/* Loop back to the same MGCP GW */
|
|
||||||
ip = mgcp_client_remote_addr_str(mgcp);
|
|
||||||
|
|
||||||
msg = mgcp_msg_mdcx(mgcp,
|
|
||||||
conn1->rtp.mgcp_rtp_endpoint,
|
|
||||||
ip, conn2->rtp.port_cn,
|
|
||||||
mode);
|
|
||||||
if (mgcp_client_tx(mgcp, msg, mgcp_response_bridge_mdcx, from))
|
|
||||||
LOGP(DMGCP, LOGL_ERROR,
|
|
||||||
"Failed to send MDCX message for %s\n",
|
|
||||||
vlr_subscr_name(from->vsub));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv)
|
|
||||||
{
|
|
||||||
struct gsm_trans *trans = priv;
|
|
||||||
struct gsm_trans *peer = trans->bridge.peer;
|
|
||||||
|
|
||||||
switch (trans->bridge.state) {
|
|
||||||
case BRIDGE_STATE_LOOPBACK_PENDING:
|
|
||||||
trans->bridge.state = BRIDGE_STATE_LOOPBACK_ESTABLISHED;
|
|
||||||
|
|
||||||
switch (peer->bridge.state) {
|
|
||||||
case BRIDGE_STATE_LOOPBACK_PENDING:
|
|
||||||
/* Wait until the other is done as well. */
|
|
||||||
return;
|
|
||||||
case BRIDGE_STATE_LOOPBACK_ESTABLISHED:
|
|
||||||
/* Now that both are in loopback, switch both to
|
|
||||||
* forwarding. */
|
|
||||||
mgcp_bridge(trans, peer, BRIDGE_STATE_BRIDGE_PENDING,
|
|
||||||
MGCP_CONN_RECV_SEND);
|
|
||||||
mgcp_bridge(peer, trans, BRIDGE_STATE_BRIDGE_PENDING,
|
|
||||||
MGCP_CONN_RECV_SEND);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOGP(DMGCP, LOGL_ERROR,
|
|
||||||
"Unexpected bridge state: %d for %s\n",
|
|
||||||
trans->bridge.state, vlr_subscr_name(trans->vsub));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BRIDGE_STATE_BRIDGE_PENDING:
|
|
||||||
trans->bridge.state = BRIDGE_STATE_BRIDGE_ESTABLISHED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
LOGP(DMGCP, LOGL_ERROR,
|
|
||||||
"Unexpected bridge state: %d for %s\n",
|
|
||||||
trans->bridge.state, vlr_subscr_name(trans->vsub));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int msc_call_connect(struct gsm_trans *trans, uint16_t port, uint32_t ip)
|
|
||||||
{
|
|
||||||
/* With this function we inform the MGCP-GW where (ip/port) it
|
|
||||||
* has to send its outgoing voic traffic. The receiving end will
|
|
||||||
* usually be a PBX (e.g. Asterisk). The IP-Address we tell, will
|
|
||||||
* not only be used to direct the traffic, it will also be used
|
|
||||||
* as a filter to make sure only RTP packets from the right
|
|
||||||
* remote end will reach the BSS. This is also the reason why
|
|
||||||
* inbound audio will not work until this step is performed */
|
|
||||||
|
|
||||||
/* NOTE: This function is used when msc_call_bridge(), is not
|
|
||||||
* applicable. This is usually the case when an external MNCC
|
|
||||||
* is in use */
|
|
||||||
|
|
||||||
struct gsm_subscriber_connection *conn;
|
|
||||||
struct mgcp_client *mgcp;
|
|
||||||
struct msgb *msg;
|
|
||||||
|
|
||||||
if (!trans)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!trans->conn)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!trans->conn->network)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!trans->conn->network->mgw.client)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mgcp = trans->conn->network->mgw.client;
|
|
||||||
|
|
||||||
struct in_addr ip_addr;
|
|
||||||
ip_addr.s_addr = ntohl(ip);
|
|
||||||
|
|
||||||
conn = trans->conn;
|
|
||||||
|
|
||||||
msg = mgcp_msg_mdcx(mgcp,
|
|
||||||
conn->rtp.mgcp_rtp_endpoint,
|
|
||||||
inet_ntoa(ip_addr), port, MGCP_CONN_RECV_SEND);
|
|
||||||
if (mgcp_client_tx(mgcp, msg, NULL, trans))
|
|
||||||
LOGP(DMGCP, LOGL_ERROR,
|
|
||||||
"Failed to send MDCX message for %s\n",
|
|
||||||
vlr_subscr_name(trans->vsub));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2)
|
|
||||||
{
|
|
||||||
if (!trans1)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!trans2)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* First setup as loopback and configure the counterparts' endpoints,
|
|
||||||
* so that when transmission starts the originating addresses are
|
|
||||||
* already known to be valid. The mgcp callback will continue. */
|
|
||||||
mgcp_bridge(trans1, trans2, BRIDGE_STATE_LOOPBACK_PENDING,
|
|
||||||
MGCP_CONN_LOOPBACK);
|
|
||||||
mgcp_bridge(trans2, trans1, BRIDGE_STATE_LOOPBACK_PENDING,
|
|
||||||
MGCP_CONN_LOOPBACK);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void msc_call_release(struct gsm_trans *trans)
|
|
||||||
{
|
|
||||||
struct msgb *msg;
|
|
||||||
struct gsm_subscriber_connection *conn;
|
|
||||||
struct mgcp_client *mgcp;
|
|
||||||
|
|
||||||
if (!trans)
|
|
||||||
return;
|
|
||||||
if (!trans->conn)
|
|
||||||
return;
|
|
||||||
if (!trans->conn->network)
|
|
||||||
return;
|
|
||||||
|
|
||||||
conn = trans->conn;
|
|
||||||
mgcp = conn->network->mgw.client;
|
|
||||||
|
|
||||||
/* Send DLCX */
|
|
||||||
msg = mgcp_msg_dlcx(mgcp, conn->rtp.mgcp_rtp_endpoint,
|
|
||||||
conn->rtp.mgcp_rtp_endpoint);
|
|
||||||
if (mgcp_client_tx(mgcp, msg, NULL, NULL))
|
|
||||||
LOGP(DMGCP, LOGL_ERROR,
|
|
||||||
"Failed to send DLCX message for %s\n",
|
|
||||||
vlr_subscr_name(trans->vsub));
|
|
||||||
|
|
||||||
/* Release endpoint id */
|
|
||||||
mgcp_client_release_endpoint(conn->rtp.mgcp_rtp_endpoint, mgcp);
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,8 +31,8 @@ AM_LDFLAGS = \
|
||||||
-Wl,--wrap=msc_stop_paging \
|
-Wl,--wrap=msc_stop_paging \
|
||||||
-Wl,--wrap=gsm340_gen_scts \
|
-Wl,--wrap=gsm340_gen_scts \
|
||||||
-Wl,--wrap=RAND_bytes \
|
-Wl,--wrap=RAND_bytes \
|
||||||
-Wl,--wrap=msc_call_assignment \
|
-Wl,--wrap=msc_mgcp_call_release \
|
||||||
-Wl,--wrap=msc_call_release \
|
-Wl,--wrap=msc_mgcp_call_assignment \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
LDADD = \
|
LDADD = \
|
||||||
|
|
|
@ -556,18 +556,18 @@ int __wrap_a_iface_tx_clear_cmd(struct gsm_subscriber_connection *conn)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* override, requires '-Wl,--wrap=msc_call_assignment' */
|
/* override, requires '-Wl,--wrap=msc_mgcp_call_assignment' */
|
||||||
int __real_msc_call_assignment(struct gsm_trans *trans);
|
int __real_msc_mgcp_call_assignment(struct gsm_trans *trans);
|
||||||
int __wrap_msc_call_assignment(struct gsm_trans *trans)
|
int __wrap_msc_mgcp_call_assignment(struct gsm_trans *trans)
|
||||||
{
|
{
|
||||||
log("MS <--Call Assignment-- MSC: subscr=%s callref=0x%x",
|
log("MS <--Call Assignment-- MSC: subscr=%s callref=0x%x",
|
||||||
vlr_subscr_name(trans->vsub), trans->callref);
|
vlr_subscr_name(trans->vsub), trans->callref);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* override, requires '-Wl,--wrap=msc_call_release' */
|
/* override, requires '-Wl,--wrap=msc_mgcp_call_release' */
|
||||||
void __real_msc_call_release(struct gsm_trans *trans);
|
void __real_msc_mgcp_call_release(struct gsm_trans *trans);
|
||||||
void __wrap_msc_call_release(struct gsm_trans *trans)
|
void __wrap_msc_mgcp_call_release(struct gsm_trans *trans)
|
||||||
{
|
{
|
||||||
log("MS <--Call Release-- MSC: subscr=%s callref=0x%x",
|
log("MS <--Call Release-- MSC: subscr=%s callref=0x%x",
|
||||||
vlr_subscr_name(trans->vsub), trans->callref);
|
vlr_subscr_name(trans->vsub), trans->callref);
|
||||||
|
|
Loading…
Reference in New Issue