summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCiaby <ciaby@rhizomatica.org>2015-08-06 18:52:06 +0200
committerCiaby <ciaby@rhizomatica.org>2015-08-06 18:54:22 +0200
commite0d60333a25d7c44ec0ba8956bc9716f536a2d1b (patch)
tree089f4dbf657c704a401dbe38823b7409f97b67fc
parent43726c309318cd0165025c54b993fc12310ee2b2 (diff)
parent14a088a92162fd6abb3031e025ce59fba40af718 (diff)
Merge branch 'zecke/features/rtp-bridge' into ciaby/2015-07-28ciaby/2015-08-06
-rw-r--r--openbsc/include/openbsc/gsm_data.h5
-rw-r--r--openbsc/include/openbsc/mncc.h14
-rw-r--r--openbsc/src/libbsc/paging.c29
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c243
-rw-r--r--openbsc/src/libmsc/gsm_subscriber.c19
-rw-r--r--openbsc/src/libmsc/mncc.c3
-rw-r--r--openbsc/src/libmsc/silent_call.c7
-rw-r--r--openbsc/src/libmsc/smpp_openbsc.c2
-rw-r--r--openbsc/src/libmsc/vty_interface_layer3.c10
9 files changed, 295 insertions, 37 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 90f3c80..c167c49 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -120,6 +120,11 @@ struct gsm_subscriber_connection {
/* Are we part of a special "silent" call */
int silent_call;
+ /* MNCC rtp bridge markers */
+ int mncc_rtp_bridge;
+ int mncc_rtp_create_pending;
+ int mncc_rtp_connect_pending;
+
/* bsc structures */
struct osmo_bsc_sccp_con *sccp_con;
diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index 94ed685..46ba237 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -92,6 +92,9 @@ struct gsm_call {
#define MNCC_FRAME_RECV 0x0201
#define MNCC_FRAME_DROP 0x0202
#define MNCC_LCHAN_MODIFY 0x0203
+#define MNCC_RTP_CREATE 0x0204
+#define MNCC_RTP_CONNECT 0x0205
+#define MNCC_RTP_FREE 0x0206
#define GSM_TCHF_FRAME 0x0300
#define GSM_TCHF_FRAME_EFR 0x0301
@@ -163,7 +166,7 @@ struct gsm_data_frame {
unsigned char data[0];
};
-#define MNCC_SOCK_VERSION 2
+#define MNCC_SOCK_VERSION 5
struct gsm_mncc_hello {
uint32_t msg_type;
uint32_t version;
@@ -179,6 +182,15 @@ struct gsm_mncc_hello {
uint32_t lchan_type_offset;
};
+struct gsm_mncc_rtp {
+ uint32_t msg_type;
+ uint32_t callref;
+ uint32_t ip;
+ uint16_t port;
+ uint32_t payload_type;
+ uint32_t payload_msg_type;
+};
+
char *get_mncc_name(int value);
void mncc_set_cause(struct gsm_mncc *data, int loc, int val);
void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg);
diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c
index 8bc10e6..9ae28e0 100644
--- a/openbsc/src/libbsc/paging.c
+++ b/openbsc/src/libbsc/paging.c
@@ -341,8 +341,10 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
break;
rc = paging_request_bts(bts, subscr, type, cbfn, data);
- if (rc < 0)
+ if (rc < 0) {
+ paging_request_stop(NULL, subscr, NULL, NULL);
return rc;
+ }
num_pages += rc;
} while (1);
@@ -389,28 +391,21 @@ void paging_request_stop(struct gsm_bts *_bts, struct gsm_subscriber *subscr,
struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
- struct gsm_bts *bts = NULL;
+ struct gsm_bts *bts;
log_set_context(BSC_CTX_SUBSCR, subscr);
+ /* Stop this first and dispatch the request */
if (_bts)
_paging_request_stop(_bts, subscr, conn, msg);
- do {
- /*
- * FIXME: Don't use the lac of the subscriber...
- * as it might have magically changed the lac.. use the
- * location area of the _bts as reconfiguration of the
- * network is probably happening less often.
- */
- bts = gsm_bts_by_lac(subscr->group->net, subscr->lac, bts);
- if (!bts)
- break;
-
- /* Stop paging */
- if (bts != _bts)
- _paging_request_stop(bts, subscr, NULL, NULL);
- } while (1);
+ /* Make sure to cancel this everywhere else */
+ llist_for_each_entry(bts, &subscr->group->net->bts_list, list) {
+ /* Sort of an optimization. */
+ if (bts == _bts)
+ continue;
+ _paging_request_stop(bts, subscr, NULL, NULL);
+ }
}
void paging_update_buffer_space(struct gsm_bts *bts, uint16_t free_slots)
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 02ffe58..f71d43c 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -67,6 +67,8 @@
void *tall_locop_ctx;
void *tall_authciphop_ctx;
+static int tch_rtp_signal(struct gsm_lchan *lchan, int signal);
+
static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn);
static int gsm48_tx_simple(struct gsm_subscriber_connection *conn,
uint8_t pdisc, uint8_t msg_type);
@@ -1463,6 +1465,15 @@ static int switch_for_handover(struct gsm_lchan *old_lchan,
{
struct rtp_socket *old_rs, *new_rs, *other_rs;
+ /* Ask the new socket to send to the already known port. */
+ if (new_lchan->conn->mncc_rtp_bridge) {
+ LOGP(DHO, LOGL_DEBUG, "Forwarding RTP\n");
+ rsl_ipacc_mdcx(new_lchan,
+ old_lchan->abis_ip.connect_ip,
+ old_lchan->abis_ip.connect_port, 0);
+ return 0;
+ }
+
if (ipacc_rtp_direct) {
LOGP(DHO, LOGL_ERROR, "unable to handover in direct RTP mode\n");
return 0;
@@ -1507,11 +1518,19 @@ static int switch_for_handover(struct gsm_lchan *old_lchan,
return 0;
}
+static void maybe_switch_for_handover(struct gsm_lchan *lchan)
+{
+ struct gsm_lchan *old_lchan;
+ old_lchan = bsc_handover_pending(lchan);
+ if (old_lchan)
+ switch_for_handover(old_lchan, lchan);
+}
+
/* some other part of the code sends us a signal */
static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
- struct gsm_lchan *lchan = signal_data, *old_lchan;
+ struct gsm_lchan *lchan = signal_data;
int rc;
struct gsm_network *net;
struct gsm_trans *trans;
@@ -1519,6 +1538,10 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
if (subsys != SS_ABISIP)
return 0;
+ /* RTP bridge handling */
+ if (lchan->conn && lchan->conn->mncc_rtp_bridge)
+ return tch_rtp_signal(lchan, signal);
+
/* in case we use direct BTS-to-BTS RTP */
if (ipacc_rtp_direct)
return 0;
@@ -1560,9 +1583,7 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
* Do we have a handover pending for this new lchan? In that
* case re-route the audio from the old channel to the new one.
*/
- old_lchan = bsc_handover_pending(lchan);
- if (old_lchan)
- switch_for_handover(old_lchan, lchan);
+ maybe_switch_for_handover(lchan);
break;
case S_ABISIP_DLCX_IND:
/* the BTS tells us a RTP stream has been disconnected */
@@ -2905,11 +2926,218 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
{
struct gsm_mncc *mode = arg;
+ struct gsm_lchan *lchan = trans->conn->lchan;
+
+ /*
+ * We were forced to make an assignment a lot earlier and
+ * we should avoid sending another assignment that might
+ * even lead to a different kind of lchan (TCH/F vs. TCH/H).
+ * In case of rtp-bridge it is too late to change things
+ * here.
+ */
+ if (trans->conn->mncc_rtp_bridge && lchan->tch_mode != GSM48_CMODE_SIGN)
+ return 0;
return gsm0808_assign_req(trans->conn, mode->lchan_mode,
trans->conn->lchan->type != GSM_LCHAN_TCH_H);
}
+static void mncc_recv_rtp(struct gsm_network *net, uint32_t callref,
+ int cmd, uint32_t addr, uint16_t port, uint32_t payload_type,
+ uint32_t payload_msg_type)
+{
+ uint8_t data[sizeof(struct gsm_mncc)];
+ struct gsm_mncc_rtp *rtp;
+
+ memset(&data, 0, sizeof(data));
+ rtp = (struct gsm_mncc_rtp *) &data[0];
+
+ rtp->callref = callref;
+ rtp->msg_type = cmd;
+ rtp->ip = addr;
+ rtp->port = port;
+ rtp->payload_type = payload_type;
+ rtp->payload_msg_type = payload_msg_type;
+ mncc_recvmsg(net, NULL, cmd, (struct gsm_mncc *)data);
+}
+
+static void mncc_recv_rtp_sock(struct gsm_network *net, struct gsm_trans *trans, int cmd)
+{
+ struct gsm_lchan *lchan;
+ int msg_type;
+
+ lchan = trans->conn->lchan;
+ switch (lchan->abis_ip.rtp_payload) {
+ case RTP_PT_GSM_FULL:
+ msg_type = GSM_TCHF_FRAME;
+ break;
+ case RTP_PT_GSM_EFR:
+ msg_type = GSM_TCHF_FRAME_EFR;
+ break;
+ case RTP_PT_GSM_HALF:
+ msg_type = GSM_TCHH_FRAME;
+ break;
+ case RTP_PT_AMR:
+ msg_type = GSM_TCH_FRAME_AMR;
+ break;
+ default:
+ LOGP(DMNCC, LOGL_ERROR, "%s unknown payload type %d\n",
+ gsm_lchan_name(lchan), lchan->abis_ip.rtp_payload);
+ msg_type = 0;
+ break;
+ }
+
+ return mncc_recv_rtp(net, trans->callref, cmd,
+ lchan->abis_ip.bound_ip,
+ lchan->abis_ip.bound_port,
+ lchan->abis_ip.rtp_payload,
+ msg_type);
+}
+
+static void mncc_recv_rtp_err(struct gsm_network *net, uint32_t callref, int cmd)
+{
+ return mncc_recv_rtp(net, callref, cmd, 0, 0, 0, 0);
+}
+
+static int tch_rtp_create(struct gsm_network *net, uint32_t callref)
+{
+ struct gsm_bts *bts;
+ struct gsm_lchan *lchan;
+ struct gsm_trans *trans;
+
+ /* Find callref */
+ trans = trans_find_by_callref(net, callref);
+ if (!trans) {
+ LOGP(DMNCC, LOGL_ERROR, "RTP create for non-existing trans\n");
+ mncc_recv_rtp_err(net, callref, MNCC_RTP_CREATE);
+ return -EIO;
+ }
+ log_set_context(BSC_CTX_SUBSCR, trans->subscr);
+ if (!trans->conn) {
+ LOGP(DMNCC, LOGL_NOTICE, "RTP create for trans without conn\n");
+ mncc_recv_rtp_err(net, callref, MNCC_RTP_CREATE);
+ return 0;
+ }
+
+ lchan = trans->conn->lchan;
+ bts = lchan->ts->trx->bts;
+ if (!is_ipaccess_bts(bts)) {
+ /*
+ * I want this to be straight forward and have no audio flow
+ * through the nitb/osmo-mss system. This currently means that
+ * this will not work with BS11/Nokia type BTS. We would need
+ * to have a trau<->rtp bridge for these but still preferable
+ * in another process.
+ */
+ LOGP(DMNCC, LOGL_ERROR, "RTP create only works with IP systems\n");
+ mncc_recv_rtp_err(net, callref, MNCC_RTP_CREATE);
+ return -EINVAL;
+ }
+
+ trans->conn->mncc_rtp_bridge = 1;
+ /*
+ * *sigh* we need to pick a codec now. Pick the most generic one
+ * right now and hope we could fix that later on. This is very
+ * similiar to the above routine.
+ * TODO: Use the default codec version...
+ */
+ if (lchan->tch_mode == GSM48_CMODE_SIGN) {
+ trans->conn->mncc_rtp_create_pending = 1;
+ /* TODO... transport or fix the default type... */
+ return gsm0808_assign_req(trans->conn, GSM48_CMODE_SPEECH_V1,
+ lchan->type != GSM_LCHAN_TCH_H);
+ }
+
+ mncc_recv_rtp_sock(trans->net, trans, MNCC_RTP_CREATE);
+ return 0;
+}
+
+static int tch_rtp_connect(struct gsm_network *net, void *arg)
+{
+ struct gsm_lchan *lchan;
+ struct gsm_trans *trans;
+ struct gsm_mncc_rtp *rtp = arg;
+
+ /* Find callref */
+ trans = trans_find_by_callref(net, rtp->callref);
+ if (!trans) {
+ LOGP(DMNCC, LOGL_ERROR, "RTP connect for non-existing trans\n");
+ mncc_recv_rtp_err(net, rtp->callref, MNCC_RTP_CONNECT);
+ return -EIO;
+ }
+ log_set_context(BSC_CTX_SUBSCR, trans->subscr);
+ if (!trans->conn) {
+ LOGP(DMNCC, LOGL_ERROR, "RTP connect for trans without conn\n");
+ mncc_recv_rtp_err(net, rtp->callref, MNCC_RTP_CONNECT);
+ return 0;
+ }
+
+ lchan = trans->conn->lchan;
+
+ /* TODO: Check if payload_msg_type is compatible with what we have */
+ if (rtp->payload_type != lchan->abis_ip.rtp_payload) {
+ LOGP(DMNCC, LOGL_ERROR, "RTP connect with different RTP payload\n");
+ mncc_recv_rtp_err(net, rtp->callref, MNCC_RTP_CONNECT);
+ }
+
+ /*
+ * FIXME: payload2 can't be sent with MDCX as the osmo-bts code
+ * complains about both rtp and rtp payload2 being present in the
+ * same package!
+ */
+ trans->conn->mncc_rtp_connect_pending = 1;
+ return rsl_ipacc_mdcx(lchan, rtp->ip, rtp->port, 0);
+}
+
+static int tch_rtp_signal(struct gsm_lchan *lchan, int signal)
+{
+ struct gsm_network *net;
+ struct gsm_trans *tmp, *trans = NULL;
+
+ net = lchan->ts->trx->bts->network;
+ llist_for_each_entry(tmp, &net->trans_list, entry) {
+ if (!tmp->conn)
+ continue;
+ if (tmp->conn->lchan != lchan && tmp->conn->ho_lchan != lchan)
+ continue;
+ trans = tmp;
+ break;
+ }
+
+ if (!trans) {
+ LOGP(DMNCC, LOGL_ERROR, "%s IPA abis signal but no transaction.\n",
+ gsm_lchan_name(lchan));
+ return 0;
+ }
+
+ switch (signal) {
+ case S_ABISIP_CRCX_ACK:
+ if (lchan->conn->mncc_rtp_create_pending) {
+ lchan->conn->mncc_rtp_create_pending = 0;
+ LOGP(DMNCC, LOGL_NOTICE, "%s sending pending RTP create ind.\n",
+ gsm_lchan_name(lchan));
+ mncc_recv_rtp_sock(net, trans, MNCC_RTP_CREATE);
+ }
+ /*
+ * TODO: this appears to be too early? Why not until after
+ * the handover detect or the handover complete?
+ */
+ maybe_switch_for_handover(lchan);
+ break;
+ case S_ABISIP_MDCX_ACK:
+ if (lchan->conn->mncc_rtp_connect_pending) {
+ lchan->conn->mncc_rtp_connect_pending = 0;
+ LOGP(DMNCC, LOGL_NOTICE, "%s sending pending RTP connect ind.\n",
+ gsm_lchan_name(lchan));
+ mncc_recv_rtp_sock(net, trans, MNCC_RTP_CONNECT);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+
static struct downstate {
uint32_t states;
int type;
@@ -2990,6 +3218,13 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
return tch_recv_mncc(net, data->callref, 0);
case MNCC_FRAME_RECV:
return tch_recv_mncc(net, data->callref, 1);
+ case MNCC_RTP_CREATE:
+ return tch_rtp_create(net, data->callref);
+ case MNCC_RTP_CONNECT:
+ return tch_rtp_connect(net, arg);
+ case MNCC_RTP_FREE:
+ /* unused right now */
+ return -EIO;
case GSM_TCHF_FRAME:
case GSM_TCHF_FRAME_EFR:
case GSM_TCHH_FRAME:
diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c
index ff77aa5..ccba360 100644
--- a/openbsc/src/libmsc/gsm_subscriber.c
+++ b/openbsc/src/libmsc/gsm_subscriber.c
@@ -99,6 +99,14 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
return 0;
}
+ /*
+ * Stop paging on all other BTS. E.g. if this is
+ * the first timeout on a BTS then the others will
+ * timeout soon as well. Let's just stop everything
+ * and forget we wanted to page.
+ */
+ paging_request_stop(NULL, subscr, NULL, NULL);
+
/* Inform parts of the system we don't know */
sig_data.subscr = subscr;
sig_data.bts = conn ? conn->bts : NULL;
@@ -111,15 +119,6 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
&sig_data
);
- /*
- * Stop paging on all other BTS. E.g. if this is
- * the first timeout on a BTS then the others will
- * timeout soon as well. Let's just stop everything
- * and forget we wanted to page.
- */
- paging_request_stop(NULL, subscr, NULL, NULL);
- subscr->is_paging = 0;
-
llist_for_each_entry_safe(request, tmp, &subscr->requests, entry) {
llist_del(&request->entry);
request->cbfn(hooknum, event, msg, data, request->param);
@@ -127,6 +126,7 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
}
/* balanced with the moment we start paging */
+ subscr->is_paging = 0;
subscr_put(subscr);
return 0;
}
@@ -368,6 +368,7 @@ static void subscr_expire_callback(void *data, long long unsigned int id)
LOGP(DMM, LOGL_DEBUG, "Not expiring subscriber %s (ID %llu)\n",
subscr_name(s), id);
subscr_update_expire_lu(s, conn->bts);
+ subscr_put(s);
return;
}
diff --git a/openbsc/src/libmsc/mncc.c b/openbsc/src/libmsc/mncc.c
index 73db5f0..2767faa 100644
--- a/openbsc/src/libmsc/mncc.c
+++ b/openbsc/src/libmsc/mncc.c
@@ -83,6 +83,9 @@ static struct mncc_names {
{"MNCC_FRAME_RECV", 0x0201},
{"MNCC_FRAME_DROP", 0x0202},
{"MNCC_LCHAN_MODIFY", 0x0203},
+ {"MNCC_RTP_CREATE", 0x0204},
+ {"MNCC_RTP_CONNECT", 0x0205},
+ {"MNCC_RTP_FREE", 0x0206},
{"GSM_TCHF_FRAME", 0x0300},
{"GSM_TCHF_FRAME_EFR", 0x0301},
diff --git a/openbsc/src/libmsc/silent_call.c b/openbsc/src/libmsc/silent_call.c
index 010c2b4..e9ece18 100644
--- a/openbsc/src/libmsc/silent_call.c
+++ b/openbsc/src/libmsc/silent_call.c
@@ -118,11 +118,10 @@ int silent_call_reroute(struct gsm_subscriber_connection *conn, struct msgb *msg
/* initiate a silent call with a given subscriber */
int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data, int type)
{
- int rc;
+ struct subscr_request *req;
- rc = paging_request(subscr->group->net, subscr, type,
- paging_cb_silent, data);
- return rc;
+ req = subscr_request_channel(subscr, type, paging_cb_silent, data);
+ return req != NULL;
}
/* end a silent call with a given subscriber */
diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c
index 057a9d0..a2fa0f4 100644
--- a/openbsc/src/libmsc/smpp_openbsc.c
+++ b/openbsc/src/libmsc/smpp_openbsc.c
@@ -110,6 +110,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
/* ERROR: we cannot have both! */
LOGP(DLSMS, LOGL_ERROR, "SMPP Cannot have payload in "
"TLV _and_ in the header\n");
+ subscr_put(dest);
return ESME_ROPTPARNOTALLWD;
}
sms_msg = t->value.octet;
@@ -120,6 +121,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
} else {
LOGP(DLSMS, LOGL_ERROR,
"SMPP neither message payload nor valid sm_length.\n");
+ subscr_put(dest);
return ESME_RINVPARLEN;
}
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index 71fff93..f49c53a 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -58,8 +58,10 @@ extern struct gsm_network *gsmnet_from_vty(struct vty *v);
static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr)
{
int rc;
+ int reqs;
struct gsm_auth_info ainfo;
struct gsm_auth_tuple atuple;
+ struct llist_head *entry;
char expire_time[200];
vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
@@ -107,8 +109,12 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr)
"%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
expire_time[sizeof(expire_time) - 1] = '\0';
vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
- vty_out(vty, " Paging: %s paging%s",
- subscr->is_paging ? "is" : "not", VTY_NEWLINE);
+
+ reqs = 0;
+ llist_for_each(entry, &subscr->requests)
+ reqs += 1;
+ vty_out(vty, " Paging: %s paging Requests: %d%s",
+ subscr->is_paging ? "is" : "not", reqs, VTY_NEWLINE);
vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
}