2016-03-21 15:42:43 +00:00
|
|
|
/*
|
2017-03-10 15:05:17 +00:00
|
|
|
* (C) 2016-2017 by Holger Hans Peter Freyther
|
2016-03-21 15:42:43 +00:00
|
|
|
*
|
|
|
|
* All Rights Reserved
|
|
|
|
*
|
|
|
|
* 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 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/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "mncc.h"
|
2016-03-22 18:17:17 +00:00
|
|
|
#include "mncc_protocol.h"
|
2016-03-21 15:42:43 +00:00
|
|
|
#include "app.h"
|
|
|
|
#include "logging.h"
|
2016-03-22 19:56:45 +00:00
|
|
|
#include "call.h"
|
2016-03-21 15:42:43 +00:00
|
|
|
|
2016-03-23 16:41:23 +00:00
|
|
|
#include <osmocom/gsm/protocol/gsm_03_40.h>
|
|
|
|
|
2016-03-21 15:42:43 +00:00
|
|
|
#include <osmocom/core/socket.h>
|
2016-03-22 19:56:45 +00:00
|
|
|
#include <osmocom/core/utils.h>
|
2016-03-21 15:42:43 +00:00
|
|
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2016-03-23 16:41:23 +00:00
|
|
|
extern void *tall_mncc_ctx;
|
|
|
|
|
2016-03-22 19:56:45 +00:00
|
|
|
static void close_connection(struct mncc_connection *conn);
|
|
|
|
|
2016-04-04 10:36:31 +00:00
|
|
|
static void mncc_leg_release(struct mncc_call_leg *leg)
|
|
|
|
{
|
|
|
|
osmo_timer_del(&leg->cmd_timeout);
|
|
|
|
call_leg_release(&leg->base);
|
|
|
|
}
|
|
|
|
|
2016-03-23 16:08:03 +00:00
|
|
|
static void cmd_timeout(void *data)
|
|
|
|
{
|
|
|
|
struct mncc_call_leg *leg = data;
|
2016-03-27 14:43:45 +00:00
|
|
|
struct call_leg *other_leg;
|
2016-03-23 16:08:03 +00:00
|
|
|
|
2019-08-06 14:45:12 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "command(0x%x) never arrived for leg(%u)\n",
|
2016-03-23 16:08:03 +00:00
|
|
|
leg->rsp_wanted, leg->callref);
|
2016-03-27 14:43:45 +00:00
|
|
|
|
|
|
|
other_leg = call_leg_other(&leg->base);
|
|
|
|
if (other_leg)
|
|
|
|
other_leg->release_call(other_leg);
|
2016-04-04 10:36:31 +00:00
|
|
|
mncc_leg_release(leg);
|
2016-03-23 16:08:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void start_cmd_timer(struct mncc_call_leg *leg, uint32_t expected_next)
|
|
|
|
{
|
|
|
|
leg->rsp_wanted = expected_next;
|
|
|
|
|
|
|
|
leg->cmd_timeout.cb = cmd_timeout;
|
|
|
|
leg->cmd_timeout.data = leg;
|
2018-10-02 12:23:00 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "Starting Timer for %s\n", osmo_mncc_name(expected_next));
|
2016-03-23 16:08:03 +00:00
|
|
|
osmo_timer_schedule(&leg->cmd_timeout, 5, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void stop_cmd_timer(struct mncc_call_leg *leg, uint32_t got_res)
|
|
|
|
{
|
|
|
|
if (leg->rsp_wanted != got_res) {
|
2019-08-06 14:45:12 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Wanted response(%s) but got(%s) for leg(%u)\n",
|
2018-10-02 12:23:00 +00:00
|
|
|
osmo_mncc_name(leg->rsp_wanted), osmo_mncc_name(got_res), leg->callref);
|
2016-03-23 16:08:03 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGP(DMNCC, LOGL_DEBUG,
|
2018-10-02 12:23:00 +00:00
|
|
|
"Got response(%s), stopping timer on leg(%u)\n",
|
|
|
|
osmo_mncc_name(got_res), leg->callref);
|
2016-03-23 16:08:03 +00:00
|
|
|
osmo_timer_del(&leg->cmd_timeout);
|
|
|
|
}
|
2016-03-22 19:56:45 +00:00
|
|
|
|
2018-03-19 09:00:01 +00:00
|
|
|
/* Find a MNCC Call leg (whether MO or MT) by given callref */
|
2016-03-22 20:03:19 +00:00
|
|
|
static struct mncc_call_leg *mncc_find_leg(uint32_t callref)
|
2016-03-22 19:56:45 +00:00
|
|
|
{
|
|
|
|
struct call *call;
|
|
|
|
|
|
|
|
llist_for_each_entry(call, &g_call_list, entry) {
|
|
|
|
if (call->initial && call->initial->type == CALL_TYPE_MNCC) {
|
|
|
|
struct mncc_call_leg *leg = (struct mncc_call_leg *) call->initial;
|
2016-03-22 20:03:19 +00:00
|
|
|
if (leg->callref == callref)
|
2016-03-22 19:56:45 +00:00
|
|
|
return leg;
|
|
|
|
}
|
|
|
|
if (call->remote && call->remote->type == CALL_TYPE_MNCC) {
|
|
|
|
struct mncc_call_leg *leg = (struct mncc_call_leg *) call->remote;
|
2016-03-22 20:03:19 +00:00
|
|
|
if (leg->callref == callref)
|
2016-03-22 19:56:45 +00:00
|
|
|
return leg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-04-19 08:22:57 +00:00
|
|
|
/* Find a MNCC Call leg (by callref) which is not yet in release */
|
|
|
|
static struct mncc_call_leg *mncc_find_leg_not_released(uint32_t callref)
|
|
|
|
{
|
|
|
|
struct mncc_call_leg *leg = mncc_find_leg(callref);
|
|
|
|
if (!leg)
|
|
|
|
return NULL;
|
|
|
|
if (leg->base.in_release)
|
|
|
|
return NULL;
|
|
|
|
return leg;
|
|
|
|
}
|
|
|
|
|
2017-02-22 12:37:06 +00:00
|
|
|
static void mncc_fill_header(struct gsm_mncc *mncc, uint32_t msg_type, uint32_t callref)
|
2016-03-22 19:56:45 +00:00
|
|
|
{
|
2018-08-31 13:44:30 +00:00
|
|
|
struct mncc_call_leg *mncc_leg;
|
|
|
|
|
2017-02-22 12:37:06 +00:00
|
|
|
mncc->msg_type = msg_type;
|
|
|
|
mncc->callref = callref;
|
2018-05-23 22:37:08 +00:00
|
|
|
if (MNCC_DISC_REQ == msg_type || MNCC_REL_REQ == msg_type) {
|
2018-08-31 13:44:30 +00:00
|
|
|
mncc_leg = mncc_find_leg(callref);
|
2018-05-23 22:37:08 +00:00
|
|
|
mncc->fields |= MNCC_F_CAUSE;
|
|
|
|
mncc->cause.coding = GSM48_CAUSE_CODING_GSM;
|
|
|
|
mncc->cause.location = GSM48_CAUSE_LOC_PUN_S_LU;
|
2018-08-31 13:44:30 +00:00
|
|
|
mncc->cause.value = mncc_leg->base.cause;
|
2018-05-23 22:37:08 +00:00
|
|
|
}
|
2017-02-22 12:37:06 +00:00
|
|
|
}
|
2016-03-22 19:56:45 +00:00
|
|
|
|
2021-01-14 02:26:35 +00:00
|
|
|
static int mncc_write(struct mncc_connection *conn, struct gsm_mncc *mncc)
|
2017-02-22 12:37:06 +00:00
|
|
|
{
|
|
|
|
int rc;
|
2016-03-22 19:56:45 +00:00
|
|
|
|
2023-09-07 03:20:03 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "tx MNCC %s with SDP=%s\n", osmo_mncc_name(mncc->msg_type),
|
|
|
|
osmo_quote_str(mncc->sdp, -1));
|
|
|
|
|
2016-03-22 19:56:45 +00:00
|
|
|
/*
|
|
|
|
* TODO: we need to put cause in here for release or such? shall we return a
|
|
|
|
* static struct?
|
|
|
|
*/
|
2017-02-22 12:37:06 +00:00
|
|
|
rc = write(conn->fd.fd, mncc, sizeof(*mncc));
|
|
|
|
if (rc != sizeof(*mncc)) {
|
2021-01-14 02:21:23 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Failed to send message for call(%u)\n", mncc->callref);
|
2016-03-22 19:56:45 +00:00
|
|
|
close_connection(conn);
|
|
|
|
}
|
2021-01-14 02:26:35 +00:00
|
|
|
|
|
|
|
return rc;
|
2016-03-22 19:56:45 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 02:26:35 +00:00
|
|
|
static int mncc_send(struct mncc_connection *conn, uint32_t msg_type, uint32_t callref)
|
2017-02-22 12:37:06 +00:00
|
|
|
{
|
|
|
|
struct gsm_mncc mncc = { 0, };
|
|
|
|
|
|
|
|
mncc_fill_header(&mncc, msg_type, callref);
|
2021-01-14 02:26:35 +00:00
|
|
|
return mncc_write(conn, &mncc);
|
2017-02-22 12:37:06 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 02:35:19 +00:00
|
|
|
static int mncc_rtp_write(struct mncc_connection *conn, struct gsm_mncc_rtp *rtp)
|
2016-03-22 19:56:45 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
2023-09-07 03:20:03 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "tx MNCC %s with SDP=%s\n", osmo_mncc_name(rtp->msg_type),
|
|
|
|
osmo_quote_str(rtp->sdp, -1));
|
|
|
|
|
2021-02-02 15:43:40 +00:00
|
|
|
rc = write(conn->fd.fd, rtp, sizeof(*rtp));
|
2021-01-14 02:35:19 +00:00
|
|
|
if (rc != sizeof(*rtp)) {
|
2021-02-02 15:41:44 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Failed to send message for call(%u): %d\n", rtp->callref, rc);
|
2016-03-22 19:56:45 +00:00
|
|
|
close_connection(conn);
|
|
|
|
}
|
2021-01-14 02:26:35 +00:00
|
|
|
|
|
|
|
return rc;
|
2016-03-22 19:56:45 +00:00
|
|
|
}
|
|
|
|
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
static int mncc_rtp_send(struct mncc_connection *conn, uint32_t msg_type, uint32_t callref, const char *sdp)
|
2021-01-14 02:35:19 +00:00
|
|
|
{
|
|
|
|
struct gsm_mncc_rtp mncc = { 0, };
|
|
|
|
|
|
|
|
mncc.msg_type = msg_type;
|
|
|
|
mncc.callref = callref;
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
if (sdp)
|
|
|
|
OSMO_STRLCPY_ARRAY(mncc.sdp, sdp);
|
2021-01-14 02:35:19 +00:00
|
|
|
|
|
|
|
return mncc_rtp_write(conn, &mncc);
|
|
|
|
}
|
|
|
|
|
2019-08-06 14:45:12 +00:00
|
|
|
/* Send a MNCC_RTP_CONNECT to the MSC for the given call legs */
|
2016-03-31 14:06:04 +00:00
|
|
|
static bool send_rtp_connect(struct mncc_call_leg *leg, struct call_leg *other)
|
2016-03-24 20:02:36 +00:00
|
|
|
{
|
2016-03-25 20:30:59 +00:00
|
|
|
struct gsm_mncc_rtp mncc = { 0, };
|
|
|
|
int rc;
|
2020-09-09 15:39:09 +00:00
|
|
|
char ip_addr[INET6_ADDRSTRLEN];
|
2016-03-24 20:02:36 +00:00
|
|
|
|
2016-03-25 20:30:59 +00:00
|
|
|
/*
|
|
|
|
* Send RTP CONNECT and we handle the general failure of it by
|
|
|
|
* tearing down the call.
|
|
|
|
*/
|
|
|
|
mncc.msg_type = MNCC_RTP_CONNECT;
|
|
|
|
mncc.callref = leg->callref;
|
2020-09-09 15:39:09 +00:00
|
|
|
mncc.addr = other->addr;
|
2016-03-25 20:30:59 +00:00
|
|
|
mncc.payload_type = other->payload_type;
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
|
|
|
|
/* Forward whichever SDP was last received on the other call leg */
|
|
|
|
OSMO_STRLCPY_ARRAY(mncc.sdp, other->rx_sdp);
|
|
|
|
|
2016-03-24 20:02:36 +00:00
|
|
|
/*
|
2016-03-25 20:30:59 +00:00
|
|
|
* FIXME: mncc.payload_msg_type should already be compatible.. but
|
|
|
|
* payload_type should be different..
|
2016-03-24 20:02:36 +00:00
|
|
|
*/
|
2020-09-09 15:39:09 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "SEND rtp_connect: IP=(%s) PORT=(%u)\n",
|
|
|
|
osmo_sockaddr_ntop((const struct sockaddr*)&other->addr, ip_addr),
|
|
|
|
osmo_sockaddr_port((const struct sockaddr*)&other->addr));
|
2021-01-14 02:35:19 +00:00
|
|
|
rc = mncc_rtp_write(leg->conn, &mncc);
|
2016-03-25 20:30:59 +00:00
|
|
|
if (rc != sizeof(mncc)) {
|
2019-08-06 14:45:12 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Failed to send message for call(%u)\n",
|
2016-03-25 20:30:59 +00:00
|
|
|
leg->callref);
|
|
|
|
close_connection(leg->conn);
|
2016-03-31 14:06:04 +00:00
|
|
|
return false;
|
2016-03-25 20:30:59 +00:00
|
|
|
}
|
2016-03-31 14:06:04 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-30 13:58:55 +00:00
|
|
|
static void update_rtp(struct call_leg *_leg) {
|
|
|
|
|
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
|
2019-08-06 14:45:12 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "UPDATE RTP for LEG Type (%u)\n", _leg->type);
|
2019-07-30 13:58:55 +00:00
|
|
|
|
|
|
|
if (_leg->type == CALL_TYPE_MNCC) {
|
|
|
|
leg = (struct mncc_call_leg *) _leg;
|
|
|
|
struct call_leg *other = call_leg_other(&leg->base);
|
2019-08-08 23:14:43 +00:00
|
|
|
if (!other)
|
|
|
|
goto ret_release;
|
2019-07-30 13:58:55 +00:00
|
|
|
send_rtp_connect(leg, other);
|
2019-08-08 23:14:43 +00:00
|
|
|
} else if (_leg->type == CALL_TYPE_SIP) {
|
2019-07-30 13:58:55 +00:00
|
|
|
leg = (struct mncc_call_leg *) call_leg_other(_leg);
|
2019-08-08 23:14:43 +00:00
|
|
|
if (!leg)
|
|
|
|
goto ret_release;
|
2019-07-30 13:58:55 +00:00
|
|
|
send_rtp_connect(leg, _leg);
|
2019-08-08 23:14:43 +00:00
|
|
|
} else {
|
|
|
|
OSMO_ASSERT(false);
|
2019-07-30 13:58:55 +00:00
|
|
|
}
|
2019-08-08 23:14:43 +00:00
|
|
|
return;
|
|
|
|
ret_release:
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Failed to find other leg.\n");
|
|
|
|
_leg->release_call(_leg);
|
2019-07-30 13:58:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-19 09:00:01 +00:00
|
|
|
/* CONNECT call-back for MNCC call leg */
|
2016-03-31 14:06:04 +00:00
|
|
|
static void mncc_call_leg_connect(struct call_leg *_leg)
|
|
|
|
{
|
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
struct call_leg *other;
|
|
|
|
|
|
|
|
OSMO_ASSERT(_leg->type == CALL_TYPE_MNCC);
|
|
|
|
leg = (struct mncc_call_leg *) _leg;
|
|
|
|
|
|
|
|
other = call_leg_other(_leg);
|
2016-03-31 17:36:27 +00:00
|
|
|
OSMO_ASSERT(other);
|
2016-03-31 14:06:04 +00:00
|
|
|
|
|
|
|
if (!send_rtp_connect(leg, other))
|
|
|
|
return;
|
2016-03-24 20:02:36 +00:00
|
|
|
|
|
|
|
start_cmd_timer(leg, MNCC_SETUP_COMPL_IND);
|
|
|
|
mncc_send(leg->conn, MNCC_SETUP_RSP, leg->callref);
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:00:01 +00:00
|
|
|
/* RING call-back for MNCC call leg */
|
2016-03-24 20:02:36 +00:00
|
|
|
static void mncc_call_leg_ring(struct call_leg *_leg)
|
|
|
|
{
|
2017-03-08 09:24:14 +00:00
|
|
|
struct gsm_mncc out_mncc = { 0, };
|
2016-03-24 20:02:36 +00:00
|
|
|
struct mncc_call_leg *leg;
|
2017-03-10 15:05:17 +00:00
|
|
|
struct call_leg *other_leg;
|
2016-03-24 20:02:36 +00:00
|
|
|
|
|
|
|
OSMO_ASSERT(_leg->type == CALL_TYPE_MNCC);
|
|
|
|
leg = (struct mncc_call_leg *) _leg;
|
|
|
|
|
2017-03-08 09:24:14 +00:00
|
|
|
mncc_fill_header(&out_mncc, MNCC_ALERT_REQ, leg->callref);
|
|
|
|
/* GSM 04.08 10.5.4.21 */
|
|
|
|
out_mncc.fields |= MNCC_F_PROGRESS;
|
2019-08-06 14:45:12 +00:00
|
|
|
out_mncc.progress.coding = GSM48_CAUSE_CODING_GSM; /* Standard defined for the GSM PLMNS */
|
2018-05-23 22:37:08 +00:00
|
|
|
out_mncc.progress.location = GSM48_CAUSE_LOC_PRN_S_LU; /* Private network serving the local user */
|
|
|
|
out_mncc.progress.descr = GSM48_PROGR_IN_BAND_AVAIL; /* In-band information or appropriate pattern now available */
|
2017-03-08 09:24:14 +00:00
|
|
|
|
2021-01-14 02:21:23 +00:00
|
|
|
mncc_write(leg->conn, &out_mncc);
|
2017-03-10 15:05:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have remote IP/port let's connect it already.
|
|
|
|
* FIXME: We would like to keep this as recvonly...
|
|
|
|
*/
|
|
|
|
other_leg = call_leg_other(&leg->base);
|
2020-09-09 15:39:09 +00:00
|
|
|
if (other_leg && other_leg->addr.ss_family != AF_UNSPEC &&
|
|
|
|
osmo_sockaddr_port((const struct sockaddr *)&other_leg->addr) != 0)
|
2017-03-10 15:05:17 +00:00
|
|
|
send_rtp_connect(leg, other_leg);
|
2016-03-24 20:02:36 +00:00
|
|
|
}
|
2016-03-22 19:56:45 +00:00
|
|
|
|
2018-03-19 09:00:01 +00:00
|
|
|
/* RELEASE call-back for MNCC call leg */
|
2016-03-22 20:03:19 +00:00
|
|
|
static void mncc_call_leg_release(struct call_leg *_leg)
|
2016-03-22 19:56:45 +00:00
|
|
|
{
|
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
|
|
|
|
OSMO_ASSERT(_leg->type == CALL_TYPE_MNCC);
|
|
|
|
leg = (struct mncc_call_leg *) _leg;
|
|
|
|
|
|
|
|
/* drop it directly, if not connected */
|
2016-03-23 16:05:16 +00:00
|
|
|
if (leg->conn->state != MNCC_READY) {
|
|
|
|
LOGP(DMNCC, LOGL_DEBUG,
|
2019-08-06 14:45:12 +00:00
|
|
|
"MNCC not connected releasing leg(%u)\n", leg->callref);
|
2016-04-04 10:36:31 +00:00
|
|
|
return mncc_leg_release(leg);
|
2016-03-23 16:05:16 +00:00
|
|
|
}
|
2016-03-22 19:56:45 +00:00
|
|
|
|
|
|
|
switch (leg->state) {
|
|
|
|
case MNCC_CC_INITIAL:
|
2016-03-23 16:05:16 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG,
|
|
|
|
"Releasing call in initial-state leg(%u)\n", leg->callref);
|
2016-03-31 12:17:58 +00:00
|
|
|
if (leg->dir == MNCC_DIR_MO) {
|
|
|
|
mncc_send(leg->conn, MNCC_REJ_REQ, leg->callref);
|
|
|
|
osmo_timer_del(&leg->cmd_timeout);
|
2016-04-04 10:36:31 +00:00
|
|
|
mncc_leg_release(leg);
|
2016-03-31 12:17:58 +00:00
|
|
|
} else {
|
|
|
|
leg->base.in_release = true;
|
|
|
|
start_cmd_timer(leg, MNCC_REL_CNF);
|
|
|
|
mncc_send(leg->conn, MNCC_REL_REQ, leg->callref);
|
|
|
|
}
|
2016-03-22 19:56:45 +00:00
|
|
|
break;
|
2016-03-24 17:26:24 +00:00
|
|
|
case MNCC_CC_PROCEEDING:
|
2016-03-24 20:02:36 +00:00
|
|
|
case MNCC_CC_CONNECTED:
|
2019-08-06 17:27:42 +00:00
|
|
|
case MNCC_CC_HOLD:
|
2016-03-24 17:26:24 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG,
|
2018-09-01 07:05:39 +00:00
|
|
|
"Releasing call in non-initial leg(%u) cause(%s)\n", leg->callref, gsm48_cc_cause_name(leg->base.cause));
|
2016-03-24 17:26:24 +00:00
|
|
|
leg->base.in_release = true;
|
|
|
|
start_cmd_timer(leg, MNCC_REL_IND);
|
|
|
|
mncc_send(leg->conn, MNCC_DISC_REQ, leg->callref);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Unknown state leg(%u) state(%d)\n",
|
|
|
|
leg->callref, leg->state);
|
|
|
|
break;
|
2016-03-22 19:56:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:00:01 +00:00
|
|
|
/* Close the MNCC connection/socket */
|
2016-03-22 18:17:17 +00:00
|
|
|
static void close_connection(struct mncc_connection *conn)
|
|
|
|
{
|
2019-08-28 13:09:38 +00:00
|
|
|
if (conn->fd.fd < 0)
|
|
|
|
return;
|
|
|
|
|
2016-03-22 18:17:17 +00:00
|
|
|
osmo_fd_unregister(&conn->fd);
|
|
|
|
close(conn->fd.fd);
|
2019-08-28 13:09:38 +00:00
|
|
|
conn->fd.fd = -1;
|
2016-03-22 18:17:17 +00:00
|
|
|
osmo_timer_schedule(&conn->reconnect, 5, 0);
|
|
|
|
conn->state = MNCC_DISCONNECTED;
|
|
|
|
if (conn->on_disconnect)
|
|
|
|
conn->on_disconnect(conn);
|
|
|
|
}
|
|
|
|
|
2016-03-31 14:06:04 +00:00
|
|
|
static void continue_mo_call(struct mncc_call_leg *leg)
|
2016-03-23 16:41:23 +00:00
|
|
|
{
|
|
|
|
char *dest, *source;
|
|
|
|
|
2016-03-24 17:26:24 +00:00
|
|
|
/* TODO.. continue call obviously only for MO call right now */
|
|
|
|
mncc_send(leg->conn, MNCC_CALL_PROC_REQ, leg->callref);
|
|
|
|
leg->state = MNCC_CC_PROCEEDING;
|
|
|
|
|
2016-03-23 16:41:23 +00:00
|
|
|
if (leg->called.type == GSM340_TYPE_INTERNATIONAL)
|
2016-04-04 17:52:41 +00:00
|
|
|
dest = talloc_asprintf(leg, "+%.32s", leg->called.number);
|
2016-03-23 16:41:23 +00:00
|
|
|
else
|
2016-04-04 17:52:41 +00:00
|
|
|
dest = talloc_asprintf(leg, "%.32s", leg->called.number);
|
2016-04-01 13:35:29 +00:00
|
|
|
|
|
|
|
if (leg->conn->app->use_imsi_as_id)
|
2016-04-04 17:52:41 +00:00
|
|
|
source = talloc_asprintf(leg, "%.16s", leg->imsi);
|
2016-04-01 13:35:29 +00:00
|
|
|
else
|
2016-04-04 17:52:41 +00:00
|
|
|
source = talloc_asprintf(leg, "%.32s", leg->calling.number);
|
2016-03-23 16:41:23 +00:00
|
|
|
|
|
|
|
app_route_call(leg->base.call, source, dest);
|
|
|
|
}
|
|
|
|
|
2016-03-31 14:06:04 +00:00
|
|
|
static void continue_mt_call(struct mncc_call_leg *leg)
|
|
|
|
{
|
|
|
|
struct call_leg *other_leg;
|
|
|
|
|
|
|
|
/* TODO.. check codec selection */
|
|
|
|
other_leg = call_leg_other(&leg->base);
|
|
|
|
if (!other_leg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* assume the type is compatible */
|
|
|
|
other_leg->payload_type = leg->base.payload_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void continue_call(struct mncc_call_leg *leg)
|
|
|
|
{
|
|
|
|
if (leg->dir == MNCC_DIR_MO)
|
|
|
|
return continue_mo_call(leg);
|
|
|
|
return continue_mt_call(leg);
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_rtp_connect(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-25 20:30:59 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc_rtp *rtp;
|
2016-03-25 20:30:59 +00:00
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
struct call_leg *other_leg;
|
|
|
|
|
|
|
|
if (rc < sizeof(*rtp)) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "gsm_mncc_rtp of wrong size %d < %zu\n",
|
|
|
|
rc, sizeof(*rtp));
|
|
|
|
return close_connection(conn);
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
rtp = (const struct gsm_mncc_rtp *) buf;
|
2019-04-19 08:22:57 +00:00
|
|
|
leg = mncc_find_leg_not_released(rtp->callref);
|
2016-03-25 20:30:59 +00:00
|
|
|
if (!leg) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "leg(%u) can not be found\n", rtp->callref);
|
2021-01-14 02:26:35 +00:00
|
|
|
mncc_send(conn, MNCC_REJ_REQ, rtp->callref);
|
|
|
|
return;
|
2016-03-25 20:30:59 +00:00
|
|
|
}
|
|
|
|
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
call_leg_rx_sdp(&leg->base, rtp->sdp);
|
|
|
|
|
2016-03-25 20:30:59 +00:00
|
|
|
/* extract information about where the RTP is */
|
2020-09-09 15:39:09 +00:00
|
|
|
if (rtp->addr.ss_family != AF_UNSPEC ||
|
|
|
|
osmo_sockaddr_port((const struct sockaddr *)&rtp->addr) != 0 ||
|
|
|
|
rtp->payload_type != 0)
|
2016-03-25 20:30:59 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "leg(%u) rtp connect failed\n", rtp->callref);
|
|
|
|
|
|
|
|
other_leg = call_leg_other(&leg->base);
|
|
|
|
if (other_leg)
|
|
|
|
other_leg->release_call(other_leg);
|
|
|
|
leg->base.release_call(&leg->base);
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_rtp_create(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-22 19:56:45 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc_rtp *rtp;
|
2016-03-22 19:56:45 +00:00
|
|
|
struct mncc_call_leg *leg;
|
2020-09-09 15:39:09 +00:00
|
|
|
char ip_addr[INET6_ADDRSTRLEN];
|
2016-03-22 19:56:45 +00:00
|
|
|
|
|
|
|
if (rc < sizeof(*rtp)) {
|
2016-03-23 16:05:16 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "gsm_mncc_rtp of wrong size %d < %zu\n",
|
2016-03-22 19:56:45 +00:00
|
|
|
rc, sizeof(*rtp));
|
|
|
|
return close_connection(conn);
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
rtp = (const struct gsm_mncc_rtp *) buf;
|
2019-04-19 08:22:57 +00:00
|
|
|
leg = mncc_find_leg_not_released(rtp->callref);
|
2016-03-22 19:56:45 +00:00
|
|
|
if (!leg) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "call(%u) can not be found\n", rtp->callref);
|
2021-01-14 02:26:35 +00:00
|
|
|
mncc_send(conn, MNCC_REJ_REQ, rtp->callref);
|
|
|
|
return;
|
2016-03-22 19:56:45 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 16:35:42 +00:00
|
|
|
/* extract information about where the RTP is */
|
2020-09-09 15:39:09 +00:00
|
|
|
leg->base.addr = rtp->addr;
|
2016-03-24 16:35:42 +00:00
|
|
|
leg->base.payload_type = rtp->payload_type;
|
|
|
|
leg->base.payload_msg_type = rtp->payload_msg_type;
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
call_leg_rx_sdp(&leg->base, rtp->sdp);
|
2016-03-24 16:35:42 +00:00
|
|
|
|
2016-03-22 19:56:45 +00:00
|
|
|
/* TODO.. now we can continue with the call */
|
2019-08-07 00:13:06 +00:00
|
|
|
LOGP(DMNCC, LOGL_INFO,
|
2019-08-06 14:45:12 +00:00
|
|
|
"RTP continue leg(%u) ip(%s), port(%u) pt(%u) ptm(%u)\n",
|
2020-09-09 15:39:09 +00:00
|
|
|
leg->callref,
|
|
|
|
osmo_sockaddr_ntop((const struct sockaddr*)&leg->base.addr, ip_addr),
|
|
|
|
osmo_sockaddr_port((const struct sockaddr*)&leg->base.addr),
|
2016-03-24 16:35:42 +00:00
|
|
|
leg->base.payload_type, leg->base.payload_msg_type);
|
2016-03-23 16:08:03 +00:00
|
|
|
stop_cmd_timer(leg, MNCC_RTP_CREATE);
|
2016-03-23 16:41:23 +00:00
|
|
|
continue_call(leg);
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static int continue_setup(struct mncc_connection *conn, const struct gsm_mncc *mncc)
|
2016-03-23 16:41:23 +00:00
|
|
|
{
|
2018-11-10 22:49:18 +00:00
|
|
|
switch (mncc->called.plan) {
|
|
|
|
case GSM340_PLAN_UNKNOWN:
|
|
|
|
case GSM340_PLAN_ISDN:
|
|
|
|
return 1;
|
|
|
|
default:
|
2016-03-23 16:41:23 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR,
|
2018-11-10 22:49:18 +00:00
|
|
|
"leg(%u) has unsupported(%d) dial plan.\n",
|
2016-03-23 16:41:23 +00:00
|
|
|
mncc->callref, mncc->called.plan);
|
|
|
|
return 0;
|
|
|
|
}
|
2016-03-22 19:56:45 +00:00
|
|
|
}
|
|
|
|
|
2019-01-22 14:56:58 +00:00
|
|
|
static const struct gsm_mncc_number emergency_number = {
|
|
|
|
.type = CALL_TYPE_MNCC,
|
|
|
|
.plan = GSM48_NPI_UNKNOWN,
|
|
|
|
.number = "emergency",
|
|
|
|
};
|
|
|
|
|
2018-03-19 09:00:01 +00:00
|
|
|
/* Check + Process MNCC_SETUP_IND (MO call) */
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_setup(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-22 19:56:45 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2019-01-22 14:56:58 +00:00
|
|
|
const struct gsm_mncc_number *called;
|
2016-03-22 19:56:45 +00:00
|
|
|
struct call *call;
|
|
|
|
struct mncc_call_leg *leg;
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
struct call_leg *other_leg;
|
|
|
|
const char *sdp = NULL;
|
2021-10-27 13:40:21 +00:00
|
|
|
struct osmo_gcr_parsed gcr;
|
2016-03-22 19:56:45 +00:00
|
|
|
|
2019-11-28 13:57:51 +00:00
|
|
|
if (rc < sizeof(*data)) {
|
2016-03-23 16:05:16 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "gsm_mncc of wrong size %d vs. %zu\n",
|
2016-03-22 19:56:45 +00:00
|
|
|
rc, sizeof(*data));
|
|
|
|
return close_connection(conn);
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
data = (const struct gsm_mncc *) buf;
|
2019-01-22 14:56:58 +00:00
|
|
|
called = &data->called;
|
2016-03-22 19:56:45 +00:00
|
|
|
|
|
|
|
/* screen arguments */
|
|
|
|
if ((data->fields & MNCC_F_CALLED) == 0) {
|
2019-01-22 14:56:58 +00:00
|
|
|
if (!data->emergency) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR,
|
|
|
|
"MNCC leg(%u) without called addr fields(%u)\n",
|
|
|
|
data->callref, data->fields);
|
2021-01-14 02:26:35 +00:00
|
|
|
mncc_send(conn, MNCC_REJ_REQ, data->callref);
|
|
|
|
return;
|
2019-01-22 14:56:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Emergency without a called number present. Use the standard "emergency" number. */
|
|
|
|
called = &emergency_number;
|
2016-03-22 19:56:45 +00:00
|
|
|
}
|
2019-01-22 14:56:58 +00:00
|
|
|
|
2016-03-22 19:56:45 +00:00
|
|
|
if ((data->fields & MNCC_F_CALLING) == 0) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR,
|
2016-03-23 16:05:16 +00:00
|
|
|
"MNCC leg(%u) without calling addr fields(%u)\n",
|
2016-03-22 19:56:45 +00:00
|
|
|
data->callref, data->fields);
|
2021-01-14 02:26:35 +00:00
|
|
|
mncc_send(conn, MNCC_REJ_REQ, data->callref);
|
|
|
|
return;
|
2016-03-22 19:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO.. bearer caps and better audio handling */
|
2016-03-23 16:41:23 +00:00
|
|
|
if (!continue_setup(conn, data)) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR,
|
|
|
|
"MNCC screening parameters failed leg(%u)\n", data->callref);
|
2021-01-14 02:26:35 +00:00
|
|
|
mncc_send(conn, MNCC_REJ_REQ, data->callref);
|
|
|
|
return;
|
2016-03-23 16:41:23 +00:00
|
|
|
}
|
2016-03-22 19:56:45 +00:00
|
|
|
|
2021-10-27 13:40:21 +00:00
|
|
|
/* Decode the Global Call Reference (if present) */
|
|
|
|
if (data->fields & MNCC_F_GCR) {
|
|
|
|
if (osmo_dec_gcr(&gcr, data->gcr, sizeof(data->gcr)) < 0) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR,
|
|
|
|
"MNCC leg(%u) failed to parse GCR\n", data->callref);
|
|
|
|
mncc_send(conn, MNCC_REJ_REQ, data->callref);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-22 19:56:45 +00:00
|
|
|
/* Create an RTP port and then allocate a call */
|
2016-03-26 17:52:22 +00:00
|
|
|
call = call_mncc_create();
|
2016-03-22 19:56:45 +00:00
|
|
|
if (!call) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR,
|
2016-03-23 16:05:16 +00:00
|
|
|
"MNCC leg(%u) failed to allocate call\n", data->callref);
|
2021-01-14 02:26:35 +00:00
|
|
|
mncc_send(conn, MNCC_REJ_REQ, data->callref);
|
|
|
|
return;
|
2016-03-22 19:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
leg = (struct mncc_call_leg *) call->initial;
|
2016-03-24 20:02:36 +00:00
|
|
|
leg->base.connect_call = mncc_call_leg_connect;
|
|
|
|
leg->base.ring_call = mncc_call_leg_ring;
|
2016-03-22 19:56:45 +00:00
|
|
|
leg->base.release_call = mncc_call_leg_release;
|
2019-07-30 13:58:55 +00:00
|
|
|
leg->base.update_rtp = update_rtp;
|
2016-03-22 19:56:45 +00:00
|
|
|
leg->callref = data->callref;
|
|
|
|
leg->conn = conn;
|
|
|
|
leg->state = MNCC_CC_INITIAL;
|
2016-03-31 12:17:58 +00:00
|
|
|
leg->dir = MNCC_DIR_MO;
|
2019-01-22 14:56:58 +00:00
|
|
|
memcpy(&leg->called, called, sizeof(leg->called));
|
2016-03-22 19:56:45 +00:00
|
|
|
memcpy(&leg->calling, &data->calling, sizeof(leg->calling));
|
2016-03-23 16:07:00 +00:00
|
|
|
memcpy(&leg->imsi, data->imsi, sizeof(leg->imsi));
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
call_leg_rx_sdp(&leg->base, data->sdp);
|
2016-03-22 19:56:45 +00:00
|
|
|
|
2021-10-27 13:40:21 +00:00
|
|
|
if (data->fields & MNCC_F_GCR) {
|
|
|
|
leg->base.call->gcr_present = true;
|
|
|
|
leg->base.call->gcr = gcr;
|
|
|
|
}
|
|
|
|
|
2019-08-07 00:13:06 +00:00
|
|
|
LOGP(DMNCC, LOGL_INFO,
|
2016-03-23 16:05:16 +00:00
|
|
|
"Created call(%u) with MNCC leg(%u) IMSI(%.16s)\n",
|
|
|
|
call->id, leg->callref, data->imsi);
|
|
|
|
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
other_leg = call_leg_other(&leg->base);
|
|
|
|
if (other_leg && *other_leg->rx_sdp && other_leg->rx_sdp_changed) {
|
|
|
|
sdp = other_leg->rx_sdp;
|
|
|
|
other_leg->rx_sdp_changed = false;
|
|
|
|
}
|
|
|
|
|
2016-03-23 16:08:03 +00:00
|
|
|
start_cmd_timer(leg, MNCC_RTP_CREATE);
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
mncc_rtp_send(conn, MNCC_RTP_CREATE, data->callref, sdp);
|
2016-03-22 19:56:45 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:00:01 +00:00
|
|
|
/*! Find MNCC Call leg by given MNCC message
|
|
|
|
* \param conn MNCC socket/connection
|
|
|
|
* \param[in] buf buffer containing MNCC message
|
|
|
|
* \param[in] rc length of message in \a buf
|
|
|
|
* \param[out] mncc return pointer to MNCC message
|
|
|
|
* \returns call leg (if found) or NULL */
|
2016-03-24 20:37:10 +00:00
|
|
|
static struct mncc_call_leg *find_leg(struct mncc_connection *conn,
|
2018-03-19 09:03:26 +00:00
|
|
|
const char *buf, int rc, const struct gsm_mncc **mncc)
|
2016-03-24 20:01:18 +00:00
|
|
|
{
|
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
|
2019-11-28 13:57:51 +00:00
|
|
|
if (rc < sizeof(**mncc)) {
|
2016-03-24 20:01:18 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "gsm_mncc of wrong size %d vs. %zu\n",
|
2016-03-24 20:37:10 +00:00
|
|
|
rc, sizeof(**mncc));
|
|
|
|
close_connection(conn);
|
|
|
|
return NULL;
|
2016-03-24 20:01:18 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
*mncc = (const struct gsm_mncc *) buf;
|
2016-03-24 20:37:10 +00:00
|
|
|
leg = mncc_find_leg((*mncc)->callref);
|
2016-03-24 20:01:18 +00:00
|
|
|
if (!leg) {
|
2016-03-24 20:37:10 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "call(%u) can not be found\n", (*mncc)->callref);
|
|
|
|
return NULL;
|
2016-03-24 20:01:18 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 20:37:10 +00:00
|
|
|
return leg;
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_disc_ind(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-24 20:37:10 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2016-03-24 20:37:10 +00:00
|
|
|
struct mncc_call_leg *leg;
|
2016-03-26 05:20:54 +00:00
|
|
|
struct call_leg *other_leg;
|
2016-03-24 20:37:10 +00:00
|
|
|
|
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
|
|
|
return;
|
|
|
|
|
2018-08-31 14:01:12 +00:00
|
|
|
LOGP(DMNCC,
|
2018-09-01 07:05:39 +00:00
|
|
|
LOGL_DEBUG, "Rcvd MNCC_DISC_IND, Cause: %s\n", gsm48_cc_cause_name(data->cause.value));
|
2016-03-24 20:01:18 +00:00
|
|
|
LOGP(DMNCC,
|
|
|
|
LOGL_DEBUG, "leg(%u) was disconnected. Releasing\n", data->callref);
|
|
|
|
leg->base.in_release = true;
|
|
|
|
start_cmd_timer(leg, MNCC_REL_CNF);
|
|
|
|
mncc_send(leg->conn, MNCC_REL_REQ, leg->callref);
|
2016-03-26 05:20:54 +00:00
|
|
|
|
|
|
|
other_leg = call_leg_other(&leg->base);
|
2018-09-03 09:30:22 +00:00
|
|
|
if (other_leg) {
|
2018-08-31 13:44:30 +00:00
|
|
|
other_leg->cause = data->cause.value;
|
2016-03-26 05:20:54 +00:00
|
|
|
other_leg->release_call(other_leg);
|
2018-09-03 09:30:22 +00:00
|
|
|
}
|
2016-03-24 20:01:18 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_rel_ind(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-24 17:26:24 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2016-03-24 17:26:24 +00:00
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
|
2016-03-24 20:37:10 +00:00
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
2016-03-24 17:26:24 +00:00
|
|
|
return;
|
|
|
|
|
2018-09-01 07:05:39 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "Rcvd MNCC_REL_IND, Cause: %s\n", gsm48_cc_cause_name(data->cause.value));
|
2018-08-31 14:01:12 +00:00
|
|
|
|
2016-03-24 17:26:24 +00:00
|
|
|
if (leg->base.in_release)
|
|
|
|
stop_cmd_timer(leg, MNCC_REL_IND);
|
2016-03-24 17:48:45 +00:00
|
|
|
else {
|
|
|
|
struct call_leg *other_leg;
|
|
|
|
other_leg = call_leg_other(&leg->base);
|
2018-09-03 09:30:22 +00:00
|
|
|
if (other_leg) {
|
2018-08-31 13:44:30 +00:00
|
|
|
other_leg->cause = data->cause.value;
|
2016-03-24 17:48:45 +00:00
|
|
|
other_leg->release_call(other_leg);
|
2018-09-03 09:30:22 +00:00
|
|
|
}
|
2016-03-24 17:48:45 +00:00
|
|
|
}
|
2016-03-24 17:26:24 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) was released.\n", data->callref);
|
2016-04-04 10:36:31 +00:00
|
|
|
mncc_leg_release(leg);
|
2016-03-24 17:26:24 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_rel_cnf(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-24 20:01:18 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2016-03-24 20:01:18 +00:00
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
|
2016-03-24 20:37:10 +00:00
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
2016-03-24 20:01:18 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
stop_cmd_timer(leg, MNCC_REL_CNF);
|
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) was cnf released.\n", data->callref);
|
2016-04-04 10:36:31 +00:00
|
|
|
mncc_leg_release(leg);
|
2016-03-24 20:01:18 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_stp_cmpl_ind(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-24 20:02:36 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2016-03-24 20:02:36 +00:00
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
|
2016-03-24 20:37:10 +00:00
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
2016-03-24 20:02:36 +00:00
|
|
|
return;
|
|
|
|
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
call_leg_rx_sdp(&leg->base, data->sdp);
|
|
|
|
|
2019-08-07 00:13:06 +00:00
|
|
|
LOGP(DMNCC, LOGL_INFO, "leg(%u) is now connected.\n", leg->callref);
|
2016-03-24 20:02:36 +00:00
|
|
|
stop_cmd_timer(leg, MNCC_SETUP_COMPL_IND);
|
|
|
|
leg->state = MNCC_CC_CONNECTED;
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_rej_ind(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-27 14:49:23 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2016-03-27 14:49:23 +00:00
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
struct call_leg *other_leg;
|
|
|
|
|
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
|
|
|
return;
|
|
|
|
|
2018-08-31 13:44:30 +00:00
|
|
|
leg->cause = data->cause.value;
|
2016-03-27 14:49:23 +00:00
|
|
|
other_leg = call_leg_other(&leg->base);
|
2018-09-03 09:30:22 +00:00
|
|
|
if (other_leg) {
|
2018-08-31 13:44:30 +00:00
|
|
|
other_leg->cause = data->cause.value;
|
2016-03-27 14:49:23 +00:00
|
|
|
other_leg->release_call(other_leg);
|
2018-09-03 09:30:22 +00:00
|
|
|
}
|
2018-09-01 07:05:39 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) was rejected with cause(%s).\n", data->callref, gsm48_cc_cause_name(leg->cause));
|
2016-04-04 10:36:31 +00:00
|
|
|
mncc_leg_release(leg);
|
2016-03-27 14:49:23 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_cnf_ind(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-31 14:06:04 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2016-03-31 14:06:04 +00:00
|
|
|
struct mncc_call_leg *leg;
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
struct call_leg *other_leg;
|
|
|
|
const char *sdp = NULL;
|
2016-03-31 14:06:04 +00:00
|
|
|
|
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
|
|
|
return;
|
|
|
|
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
call_leg_rx_sdp(&leg->base, data->sdp);
|
|
|
|
|
|
|
|
/* Forward SDP received from the other side */
|
|
|
|
other_leg = call_leg_other(&leg->base);
|
|
|
|
if (other_leg && *other_leg->rx_sdp && other_leg->rx_sdp_changed) {
|
|
|
|
sdp = other_leg->rx_sdp;
|
|
|
|
other_leg->rx_sdp_changed = false;
|
|
|
|
}
|
|
|
|
|
2016-03-31 14:06:04 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG,
|
2019-08-06 14:45:12 +00:00
|
|
|
"leg(%u) confirmed. creating RTP socket.\n",
|
2016-03-31 14:06:04 +00:00
|
|
|
leg->callref);
|
|
|
|
|
|
|
|
start_cmd_timer(leg, MNCC_RTP_CREATE);
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
mncc_rtp_send(conn, MNCC_RTP_CREATE, data->callref, sdp);
|
2016-03-31 14:06:04 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_alrt_ind(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-31 14:06:04 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2016-03-31 14:06:04 +00:00
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
struct call_leg *other_leg;
|
|
|
|
|
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
|
|
|
return;
|
|
|
|
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
call_leg_rx_sdp(&leg->base, data->sdp);
|
|
|
|
|
2016-03-31 14:06:04 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG,
|
|
|
|
"leg(%u) is alerting.\n", leg->callref);
|
|
|
|
|
|
|
|
other_leg = call_leg_other(&leg->base);
|
|
|
|
if (!other_leg) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "leg(%u) other leg gone!\n",
|
|
|
|
leg->callref);
|
|
|
|
mncc_call_leg_release(&leg->base);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
other_leg->ring_call(other_leg);
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_hold_ind(struct mncc_connection *conn, const char *buf, int rc)
|
2016-04-04 10:38:10 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2016-04-04 10:38:10 +00:00
|
|
|
struct mncc_call_leg *leg;
|
2019-07-30 14:30:56 +00:00
|
|
|
struct call_leg *other_leg;
|
|
|
|
|
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
LOGP(DMNCC, LOGL_DEBUG,
|
2019-08-06 14:45:12 +00:00
|
|
|
"leg(%u) is requesting hold.\n", leg->callref);
|
2019-07-30 14:30:56 +00:00
|
|
|
other_leg = call_leg_other(&leg->base);
|
2019-08-07 01:20:53 +00:00
|
|
|
if (!other_leg) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "leg(%u) other leg gone!\n",
|
|
|
|
leg->callref);
|
|
|
|
mncc_send(leg->conn, MNCC_HOLD_REJ, leg->callref);
|
|
|
|
return;
|
|
|
|
}
|
2019-07-30 14:30:56 +00:00
|
|
|
other_leg->hold_call(other_leg);
|
|
|
|
mncc_send(leg->conn, MNCC_HOLD_CNF, leg->callref);
|
|
|
|
leg->state = MNCC_CC_HOLD;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void check_retrieve_ind(struct mncc_connection *conn, const char *buf, int rc)
|
|
|
|
{
|
|
|
|
const struct gsm_mncc *data;
|
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
struct call_leg *other_leg;
|
2016-04-04 10:38:10 +00:00
|
|
|
|
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
LOGP(DMNCC, LOGL_DEBUG,
|
2019-08-06 14:45:12 +00:00
|
|
|
"leg(%u) is requesting unhold.\n", leg->callref);
|
2019-07-30 14:30:56 +00:00
|
|
|
other_leg = call_leg_other(&leg->base);
|
2019-08-07 01:20:53 +00:00
|
|
|
if (!other_leg) {
|
|
|
|
/* The SIP leg went away while we were holding! */
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "leg(%u) other leg gone!\n",
|
|
|
|
leg->callref);
|
|
|
|
mncc_send(leg->conn, MNCC_RETRIEVE_CNF, leg->callref);
|
|
|
|
mncc_call_leg_release(&leg->base);
|
|
|
|
return;
|
|
|
|
}
|
2019-07-30 14:30:56 +00:00
|
|
|
other_leg->retrieve_call(other_leg);
|
|
|
|
mncc_send(leg->conn, MNCC_RETRIEVE_CNF, leg->callref);
|
|
|
|
/* In case of call waiting/swap, At this point we need to tell the MSC to send
|
|
|
|
* audio to the port of the original call
|
|
|
|
*/
|
|
|
|
leg->state = MNCC_CC_CONNECTED;
|
|
|
|
send_rtp_connect(leg, other_leg);
|
2016-04-04 10:38:10 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_stp_cnf(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-31 14:06:04 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2016-03-31 14:06:04 +00:00
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
struct call_leg *other_leg;
|
|
|
|
|
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
|
|
|
return;
|
|
|
|
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
call_leg_rx_sdp(&leg->base, data->sdp);
|
|
|
|
|
2016-03-31 14:06:04 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) setup completed\n", leg->callref);
|
|
|
|
|
|
|
|
other_leg = call_leg_other(&leg->base);
|
|
|
|
if (!other_leg) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "leg(%u) other leg gone!\n",
|
|
|
|
leg->callref);
|
|
|
|
mncc_call_leg_release(&leg->base);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!send_rtp_connect(leg, other_leg))
|
|
|
|
return;
|
|
|
|
leg->state = MNCC_CC_CONNECTED;
|
|
|
|
mncc_send(leg->conn, MNCC_SETUP_COMPL_REQ, leg->callref);
|
|
|
|
|
|
|
|
other_leg->connect_call(other_leg);
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_dtmf_start(struct mncc_connection *conn, const char *buf, int rc)
|
2017-02-22 12:37:06 +00:00
|
|
|
{
|
|
|
|
struct gsm_mncc out_mncc = { 0, };
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2017-02-22 12:37:06 +00:00
|
|
|
struct mncc_call_leg *leg;
|
2017-02-22 12:50:11 +00:00
|
|
|
struct call_leg *other_leg;
|
2017-02-22 12:37:06 +00:00
|
|
|
|
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
|
|
|
return;
|
|
|
|
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
call_leg_rx_sdp(&leg->base, data->sdp);
|
|
|
|
|
2017-02-22 12:37:06 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) DTMF key=%c\n", leg->callref, data->keypad);
|
|
|
|
|
2017-02-22 12:50:11 +00:00
|
|
|
other_leg = call_leg_other(&leg->base);
|
|
|
|
if (other_leg && other_leg->dtmf)
|
|
|
|
other_leg->dtmf(other_leg, data->keypad);
|
|
|
|
|
2017-02-22 12:37:06 +00:00
|
|
|
mncc_fill_header(&out_mncc, MNCC_START_DTMF_RSP, leg->callref);
|
|
|
|
out_mncc.fields |= MNCC_F_KEYPAD;
|
|
|
|
out_mncc.keypad = data->keypad;
|
2021-01-14 02:21:23 +00:00
|
|
|
mncc_write(conn, &out_mncc);
|
2017-02-22 12:37:06 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_dtmf_stop(struct mncc_connection *conn, const char *buf, int rc)
|
2017-02-22 12:37:06 +00:00
|
|
|
{
|
|
|
|
struct gsm_mncc out_mncc = { 0, };
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc *data;
|
2017-02-22 12:37:06 +00:00
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
|
|
|
|
leg = find_leg(conn, buf, rc, &data);
|
|
|
|
if (!leg)
|
|
|
|
return;
|
|
|
|
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
call_leg_rx_sdp(&leg->base, data->sdp);
|
|
|
|
|
2017-02-22 12:37:06 +00:00
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) DTMF key=%c\n", leg->callref, data->keypad);
|
|
|
|
|
|
|
|
mncc_fill_header(&out_mncc, MNCC_STOP_DTMF_RSP, leg->callref);
|
|
|
|
out_mncc.fields |= MNCC_F_KEYPAD;
|
|
|
|
out_mncc.keypad = data->keypad;
|
2021-01-14 02:21:23 +00:00
|
|
|
mncc_write(conn, &out_mncc);
|
2017-02-22 12:37:06 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
static void check_hello(struct mncc_connection *conn, const char *buf, int rc)
|
2016-03-22 18:17:17 +00:00
|
|
|
{
|
2018-03-19 09:03:26 +00:00
|
|
|
const struct gsm_mncc_hello *hello;
|
2016-03-22 18:17:17 +00:00
|
|
|
|
|
|
|
if (rc != sizeof(*hello)) {
|
2016-03-23 16:05:16 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Hello shorter than expected %d vs. %zu\n",
|
2016-03-22 18:17:17 +00:00
|
|
|
rc, sizeof(*hello));
|
|
|
|
return close_connection(conn);
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:03:26 +00:00
|
|
|
hello = (const struct gsm_mncc_hello *) buf;
|
2016-03-22 18:17:17 +00:00
|
|
|
LOGP(DMNCC, LOGL_NOTICE, "Got hello message version %d\n", hello->version);
|
|
|
|
|
|
|
|
if (hello->version != MNCC_SOCK_VERSION) {
|
|
|
|
LOGP(DMNCC, LOGL_NOTICE, "Incompatible version(%d) expected %d\n",
|
|
|
|
hello->version, MNCC_SOCK_VERSION);
|
|
|
|
return close_connection(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
conn->state = MNCC_READY;
|
|
|
|
}
|
|
|
|
|
2016-04-04 17:52:41 +00:00
|
|
|
int mncc_create_remote_leg(struct mncc_connection *conn, struct call *call)
|
2016-03-27 15:02:39 +00:00
|
|
|
{
|
|
|
|
struct mncc_call_leg *leg;
|
|
|
|
struct gsm_mncc mncc = { 0, };
|
2021-10-27 13:40:21 +00:00
|
|
|
struct msgb *msg;
|
2016-03-27 15:02:39 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
leg = talloc_zero(call, struct mncc_call_leg);
|
|
|
|
if (!leg) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Failed to allocate leg call(%u)\n",
|
|
|
|
call->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
leg->base.type = CALL_TYPE_MNCC;
|
|
|
|
leg->base.connect_call = mncc_call_leg_connect;
|
|
|
|
leg->base.ring_call = mncc_call_leg_ring;
|
|
|
|
leg->base.release_call = mncc_call_leg_release;
|
|
|
|
leg->base.call = call;
|
2019-07-30 13:58:55 +00:00
|
|
|
leg->base.update_rtp = update_rtp;
|
2016-03-27 15:02:39 +00:00
|
|
|
|
|
|
|
leg->callref = call->id;
|
|
|
|
|
|
|
|
leg->conn = conn;
|
|
|
|
leg->state = MNCC_CC_INITIAL;
|
2016-03-31 12:17:58 +00:00
|
|
|
leg->dir = MNCC_DIR_MT;
|
2016-03-27 15:02:39 +00:00
|
|
|
|
|
|
|
mncc.msg_type = MNCC_SETUP_REQ;
|
|
|
|
mncc.callref = leg->callref;
|
|
|
|
|
|
|
|
mncc.fields |= MNCC_F_CALLING;
|
2018-05-23 22:37:08 +00:00
|
|
|
mncc.calling.plan = GSM48_NPI_ISDN_E164;
|
2019-01-28 11:16:24 +00:00
|
|
|
|
|
|
|
if (call->source && call->source[0] == '+') {
|
|
|
|
mncc.calling.type = GSM48_TON_INTERNATIONAL;
|
|
|
|
OSMO_STRLCPY_ARRAY(mncc.calling.number, call->source + 1);
|
|
|
|
} else {
|
|
|
|
mncc.calling.type = GSM48_TON_UNKNOWN;
|
|
|
|
OSMO_STRLCPY_ARRAY(mncc.calling.number, call->source);
|
|
|
|
}
|
2016-03-27 15:02:39 +00:00
|
|
|
|
2016-04-01 13:35:29 +00:00
|
|
|
if (conn->app->use_imsi_as_id) {
|
2016-04-04 17:52:41 +00:00
|
|
|
snprintf(mncc.imsi, 15, "%s", call->dest);
|
2016-04-01 13:35:29 +00:00
|
|
|
} else {
|
|
|
|
mncc.fields |= MNCC_F_CALLED;
|
2018-05-23 22:37:08 +00:00
|
|
|
mncc.called.plan = GSM48_NPI_ISDN_E164;
|
|
|
|
mncc.called.type = GSM48_TON_UNKNOWN;
|
2019-02-14 21:52:21 +00:00
|
|
|
OSMO_STRLCPY_ARRAY(mncc.called.number, call->dest);
|
2016-04-01 13:35:29 +00:00
|
|
|
}
|
2016-03-27 15:02:39 +00:00
|
|
|
|
2021-10-27 13:40:21 +00:00
|
|
|
/* Encode the Global Call Reference (if present) */
|
|
|
|
if (call->gcr_present) {
|
|
|
|
msg = msgb_alloc(sizeof(mncc.gcr), "MNCC GCR");
|
2022-10-03 01:32:00 +00:00
|
|
|
if (msg == NULL || (rc = osmo_enc_gcr(msg, &call->gcr)) == 0) {
|
2021-10-27 13:40:21 +00:00
|
|
|
LOGP(DMNCC, LOGL_ERROR, "MNCC leg(%u) failed to encode GCR\n", call->id);
|
2022-10-03 01:32:00 +00:00
|
|
|
} else {
|
2021-10-27 13:40:21 +00:00
|
|
|
memcpy(&mncc.gcr[0], msg->data, rc);
|
2022-10-03 01:32:00 +00:00
|
|
|
mncc.fields |= MNCC_F_GCR;
|
|
|
|
}
|
2021-10-27 13:40:21 +00:00
|
|
|
msgb_free(msg);
|
|
|
|
}
|
|
|
|
|
forward SDP between SIP and MNCC
We have added support for sending SDP via MNCC a long time ago, but so
far the SDP section remained empty. Now, implement actually forwarding
SDP codec information between SIP and MNCC.
The aim is to let the MSC know about all codec choices the remote SIP
call leg has to offer, so that finding a codec match between local and
remote call leg becomes possible.
Store any SDP info contained in incoming SIP and MNCC messages, and send
the stored SDP to the other call leg in all outgoing SIP and MNCC
messages.
In sdp_create_file(), we used to compose fixed SDP -- instead, take the
other call leg's SDP as-is, only make sure to modify the mode (e.g.
"a=sendrecv") to reflect the current call hold state.
The RTP address and codec info in the MNCC structures is now essentially
a redundant / possibly less accurate copy of the SDP info, but leave all
of that as-is, for backwards compat.
There is codec checking that may reject unexpected codecs. The
overall/future aim is to leave all codec checking up to the MSC, but so
far just leave current behaviour unchanged, until we notice problems.
Related: SYS#5066
Related: osmo-ttcn3-hacks Ib2ae8449e673f5027f01d428d3718c006f76d93e
Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
2019-08-15 04:12:54 +00:00
|
|
|
/* The call->initial leg is a SIP call leg that starts an MT call. There was SDP received in the SIP INVITE that
|
|
|
|
* started this call. This here will be the call->remote, always forwarding the SDP that came in on
|
|
|
|
* call->initial. */
|
|
|
|
if (call->initial && call->initial->rx_sdp_changed) {
|
|
|
|
OSMO_STRLCPY_ARRAY(mncc.sdp, call->initial->rx_sdp);
|
|
|
|
call->initial->rx_sdp_changed = false;
|
|
|
|
}
|
|
|
|
|
2016-03-27 15:02:39 +00:00
|
|
|
/*
|
|
|
|
* TODO/FIXME:
|
|
|
|
* - Screening, redirect?
|
|
|
|
*/
|
2021-01-14 02:36:18 +00:00
|
|
|
rc = mncc_write(conn, &mncc);
|
2016-03-27 15:02:39 +00:00
|
|
|
if (rc != sizeof(mncc)) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Failed to send message leg(%u)\n",
|
|
|
|
leg->callref);
|
|
|
|
talloc_free(leg);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
call->remote = &leg->base;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-21 15:42:43 +00:00
|
|
|
static void mncc_reconnect(void *data)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct mncc_connection *conn = data;
|
|
|
|
|
|
|
|
rc = osmo_sock_unix_init_ofd(&conn->fd, SOCK_SEQPACKET, 0,
|
|
|
|
conn->app->mncc.path, OSMO_SOCK_F_CONNECT);
|
|
|
|
if (rc < 0) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Failed to connect(%s). Retrying\n",
|
|
|
|
conn->app->mncc.path);
|
2016-03-22 18:17:17 +00:00
|
|
|
conn->state = MNCC_DISCONNECTED;
|
2019-08-28 13:09:38 +00:00
|
|
|
conn->fd.fd = -1;
|
2016-03-21 15:42:43 +00:00
|
|
|
osmo_timer_schedule(&conn->reconnect, 5, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGP(DMNCC, LOGL_NOTICE, "Reconnected to %s\n", conn->app->mncc.path);
|
2016-03-22 18:17:17 +00:00
|
|
|
conn->state = MNCC_WAIT_VERSION;
|
2016-03-21 15:42:43 +00:00
|
|
|
}
|
|
|
|
|
2023-09-07 03:20:03 +00:00
|
|
|
static inline void log_mncc(const char *label, const uint8_t *buf, size_t buflen)
|
|
|
|
{
|
|
|
|
uint32_t msg_type;
|
|
|
|
const struct gsm_mncc *gsm_mncc;
|
|
|
|
const struct gsm_mncc_rtp *gsm_mncc_rtp;
|
|
|
|
const char *sdp = NULL;
|
|
|
|
|
|
|
|
/* Any size errors will be logged elsewhere already, so just exit here if the buffer is too small. */
|
|
|
|
if (buflen < 4)
|
|
|
|
return;
|
|
|
|
memcpy(&msg_type, buf, 4);
|
|
|
|
|
|
|
|
switch (msg_type) {
|
|
|
|
case MNCC_SETUP_IND:
|
|
|
|
case MNCC_DISC_IND:
|
|
|
|
case MNCC_REL_IND:
|
|
|
|
case MNCC_REJ_IND:
|
|
|
|
case MNCC_REL_CNF:
|
|
|
|
case MNCC_SETUP_COMPL_IND:
|
|
|
|
case MNCC_SETUP_CNF:
|
|
|
|
case MNCC_CALL_CONF_IND:
|
|
|
|
case MNCC_ALERT_IND:
|
|
|
|
case MNCC_HOLD_IND:
|
|
|
|
case MNCC_RETRIEVE_IND:
|
|
|
|
if (buflen < sizeof(gsm_mncc))
|
|
|
|
return;
|
|
|
|
gsm_mncc = (void *)buf;
|
|
|
|
sdp = gsm_mncc->sdp;
|
|
|
|
break;
|
|
|
|
case MNCC_RTP_CREATE:
|
|
|
|
case MNCC_RTP_CONNECT:
|
|
|
|
if (buflen < sizeof(gsm_mncc_rtp))
|
|
|
|
return;
|
|
|
|
gsm_mncc_rtp = (void *)buf;
|
|
|
|
sdp = gsm_mncc_rtp->sdp;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (sdp)
|
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "%sMNCC %s with SDP=%s\n", label, osmo_mncc_name(msg_type),
|
|
|
|
osmo_quote_str(sdp, -1));
|
|
|
|
else
|
|
|
|
LOGP(DMNCC, LOGL_DEBUG, "%sMNCC %s\n", label, osmo_mncc_name(msg_type));
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:00:01 +00:00
|
|
|
/* osmo-fd read call-back for MNCC socket: read MNCC message + dispatch it */
|
2016-03-21 15:42:43 +00:00
|
|
|
static int mncc_data(struct osmo_fd *fd, unsigned int what)
|
|
|
|
{
|
|
|
|
char buf[4096];
|
2016-03-22 18:17:17 +00:00
|
|
|
uint32_t msg_type;
|
2016-03-21 15:42:43 +00:00
|
|
|
int rc;
|
|
|
|
struct mncc_connection *conn = fd->data;
|
|
|
|
|
|
|
|
rc = read(fd->fd, buf, sizeof(buf));
|
|
|
|
if (rc <= 0) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Failed to read %d/%s. Re-connecting.\n",
|
|
|
|
rc, strerror(errno));
|
2016-03-22 18:17:17 +00:00
|
|
|
goto bad_data;
|
2016-03-21 15:42:43 +00:00
|
|
|
}
|
2016-03-22 18:17:17 +00:00
|
|
|
if (rc <= 4) {
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Data too short with: %d\n", rc);
|
|
|
|
goto bad_data;
|
|
|
|
}
|
|
|
|
|
2023-09-07 03:20:03 +00:00
|
|
|
log_mncc("rx ", (void *)buf, rc);
|
2018-05-23 21:23:19 +00:00
|
|
|
|
2023-09-07 03:20:03 +00:00
|
|
|
/* Handle the received MNCC message */
|
|
|
|
memcpy(&msg_type, buf, 4);
|
2016-03-22 18:17:17 +00:00
|
|
|
switch (msg_type) {
|
|
|
|
case MNCC_SOCKET_HELLO:
|
|
|
|
check_hello(conn, buf, rc);
|
|
|
|
break;
|
2016-03-22 19:56:45 +00:00
|
|
|
case MNCC_SETUP_IND:
|
|
|
|
check_setup(conn, buf, rc);
|
|
|
|
break;
|
|
|
|
case MNCC_RTP_CREATE:
|
|
|
|
check_rtp_create(conn, buf, rc);
|
|
|
|
break;
|
2016-03-25 20:30:59 +00:00
|
|
|
case MNCC_RTP_CONNECT:
|
|
|
|
check_rtp_connect(conn, buf, rc);
|
|
|
|
break;
|
2016-03-24 20:01:18 +00:00
|
|
|
case MNCC_DISC_IND:
|
|
|
|
check_disc_ind(conn, buf, rc);
|
|
|
|
break;
|
2016-03-24 17:26:24 +00:00
|
|
|
case MNCC_REL_IND:
|
|
|
|
check_rel_ind(conn, buf, rc);
|
|
|
|
break;
|
2016-03-27 14:49:23 +00:00
|
|
|
case MNCC_REJ_IND:
|
|
|
|
check_rej_ind(conn, buf, rc);
|
|
|
|
break;
|
2016-03-24 20:01:18 +00:00
|
|
|
case MNCC_REL_CNF:
|
|
|
|
check_rel_cnf(conn, buf, rc);
|
|
|
|
break;
|
2016-03-24 20:02:36 +00:00
|
|
|
case MNCC_SETUP_COMPL_IND:
|
|
|
|
check_stp_cmpl_ind(conn, buf, rc);
|
|
|
|
break;
|
2016-03-31 14:06:04 +00:00
|
|
|
case MNCC_SETUP_CNF:
|
|
|
|
check_stp_cnf(conn, buf, rc);
|
|
|
|
break;
|
|
|
|
case MNCC_CALL_CONF_IND:
|
|
|
|
check_cnf_ind(conn, buf, rc);
|
|
|
|
break;
|
|
|
|
case MNCC_ALERT_IND:
|
|
|
|
check_alrt_ind(conn, buf, rc);
|
|
|
|
break;
|
2016-04-04 10:38:10 +00:00
|
|
|
case MNCC_HOLD_IND:
|
|
|
|
check_hold_ind(conn, buf, rc);
|
|
|
|
break;
|
2019-07-30 14:30:56 +00:00
|
|
|
case MNCC_RETRIEVE_IND:
|
|
|
|
check_retrieve_ind(conn, buf, rc);
|
|
|
|
break;
|
2017-02-22 12:37:06 +00:00
|
|
|
case MNCC_START_DTMF_IND:
|
|
|
|
check_dtmf_start(conn, buf, rc);
|
|
|
|
break;
|
|
|
|
case MNCC_STOP_DTMF_IND:
|
|
|
|
check_dtmf_stop(conn, buf, rc);
|
|
|
|
break;
|
2016-03-22 18:17:17 +00:00
|
|
|
default:
|
|
|
|
LOGP(DMNCC, LOGL_ERROR, "Unhandled message type %d/0x%x\n",
|
|
|
|
msg_type, msg_type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
2016-03-21 15:42:43 +00:00
|
|
|
|
2016-03-22 18:17:17 +00:00
|
|
|
bad_data:
|
|
|
|
close_connection(conn);
|
2016-03-21 15:42:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mncc_connection_init(struct mncc_connection *conn, struct app_config *cfg)
|
|
|
|
{
|
|
|
|
conn->reconnect.cb = mncc_reconnect;
|
|
|
|
conn->reconnect.data = conn;
|
|
|
|
conn->fd.cb = mncc_data;
|
|
|
|
conn->fd.data = conn;
|
2019-08-28 13:09:38 +00:00
|
|
|
conn->fd.fd = -1;
|
2016-03-21 15:42:43 +00:00
|
|
|
conn->app = cfg;
|
2016-03-22 18:17:17 +00:00
|
|
|
conn->state = MNCC_DISCONNECTED;
|
2016-03-21 15:42:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mncc_connection_start(struct mncc_connection *conn)
|
|
|
|
{
|
|
|
|
LOGP(DMNCC, LOGL_NOTICE, "Scheduling MNCC connect\n");
|
|
|
|
osmo_timer_schedule(&conn->reconnect, 0, 0);
|
|
|
|
}
|
2016-04-04 18:17:29 +00:00
|
|
|
|
|
|
|
const struct value_string mncc_conn_state_vals[] = {
|
|
|
|
{ MNCC_DISCONNECTED, "DISCONNECTED" },
|
|
|
|
{ MNCC_WAIT_VERSION, "WAITING" },
|
|
|
|
{ MNCC_READY, "READY" },
|
|
|
|
{ 0, NULL },
|
|
|
|
};
|