aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libmsc
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/libmsc')
-rw-r--r--openbsc/src/libmsc/Makefile.am2
-rw-r--r--openbsc/src/libmsc/a_iface.c45
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c239
-rw-r--r--openbsc/src/libmsc/gsm_04_11.c8
-rw-r--r--openbsc/src/libmsc/gsm_subscriber.c27
-rw-r--r--openbsc/src/libmsc/mncc_builtin.c7
-rw-r--r--openbsc/src/libmsc/msc_ifaces.c83
-rw-r--r--openbsc/src/libmsc/osmo_msc.c22
-rw-r--r--openbsc/src/libmsc/silent_call.c9
-rw-r--r--openbsc/src/libmsc/smpp_openbsc.c4
-rw-r--r--openbsc/src/libmsc/vty_interface_layer3.c14
11 files changed, 276 insertions, 184 deletions
diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am
index 3f4174ca5..7ab30d029 100644
--- a/openbsc/src/libmsc/Makefile.am
+++ b/openbsc/src/libmsc/Makefile.am
@@ -23,6 +23,7 @@ noinst_LIBRARIES = \
$(NULL)
libmsc_a_SOURCES = \
+ a_iface.c \
auth.c \
db.c \
gsm_04_08.c \
@@ -32,6 +33,7 @@ libmsc_a_SOURCES = \
mncc.c \
mncc_builtin.c \
mncc_sock.c \
+ msc_ifaces.c \
rrlp.c \
silent_call.c \
sms_queue.c \
diff --git a/openbsc/src/libmsc/a_iface.c b/openbsc/src/libmsc/a_iface.c
new file mode 100644
index 000000000..1f471f97b
--- /dev/null
+++ b/openbsc/src/libmsc/a_iface.c
@@ -0,0 +1,45 @@
+/* A-interface implementation, from MSC to BSC */
+
+/* (C) 2016 by sysmocom s.m.f.c GmbH <info@sysmocom.de>
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+
+#include <openbsc/debug.h>
+
+#include <openbsc/gsm_data.h>
+#include <openbsc/msc_ifaces.h>
+#include <openbsc/debug.h>
+
+int a_tx(struct msgb *msg)
+{
+ LOGP(DMSC, LOGL_ERROR, "message to be sent to BSC, but A-interface"
+ " not implemented.\n%s\n", osmo_hexdump(msg->data, msg->len));
+ return -1;
+}
+
+int msc_gsm0808_tx_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
+ const uint8_t *key, int len, int include_imeisv)
+{
+ /* TODO generalize for A- and Iu interfaces, don't name after 08.08 */
+ LOGP(DMSC, LOGL_ERROR, "gsm0808_cipher_mode(): message to be sent to"
+ " BSC, but A interface not yet implemented.\n");
+ return -1;
+}
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 9591ddb0a..f8d47e4da 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -59,6 +59,7 @@
#include <osmocom/abis/e1_input.h>
#include <osmocom/core/bitvec.h>
#include <openbsc/vlr.h>
+#include <openbsc/msc_ifaces.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/gsm0480.h>
@@ -71,10 +72,17 @@
#include <assert.h>
+
+/* These debug statements were removed during the BSC/MSC split. It may make
+ * sense to replace them with debug statements that do not access BTS data. */
+#define BEFORE_MSCSPLIT 0
+
void *tall_locop_ctx;
void *tall_authciphop_ctx;
+#if BEFORE_MSCSPLIT
static int tch_rtp_signal(struct gsm_lchan *lchan, int signal);
+#endif
static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn,
uint32_t send_tmsi);
@@ -87,29 +95,6 @@ struct gsm_lai {
uint16_t lac;
};
-static int apply_codec_restrictions(struct gsm_bts *bts,
- struct gsm_mncc_bearer_cap *bcap)
-{
- int i, j;
-
- /* remove unsupported speech versions from list */
- for (i = 0, j = 0; bcap->speech_ver[i] >= 0; i++) {
- if (bcap->speech_ver[i] == GSM48_BCAP_SV_FR)
- bcap->speech_ver[j++] = GSM48_BCAP_SV_FR;
- if (bcap->speech_ver[i] == GSM48_BCAP_SV_EFR && bts->codec.efr)
- bcap->speech_ver[j++] = GSM48_BCAP_SV_EFR;
- if (bcap->speech_ver[i] == GSM48_BCAP_SV_AMR_F && bts->codec.amr)
- bcap->speech_ver[j++] = GSM48_BCAP_SV_AMR_F;
- if (bcap->speech_ver[i] == GSM48_BCAP_SV_HR && bts->codec.hr)
- bcap->speech_ver[j++] = GSM48_BCAP_SV_HR;
- if (bcap->speech_ver[i] == GSM48_BCAP_SV_AMR_H && bts->codec.amr)
- bcap->speech_ver[j++] = GSM48_BCAP_SV_AMR_H;
- }
- bcap->speech_ver[j] = -1;
-
- return 0;
-}
-
static uint32_t new_callref = 0x80000001;
void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg)
@@ -126,27 +111,6 @@ static int gsm48_conn_sendmsg(struct msgb *msg, struct gsm_subscriber_connection
* work that the caller no longer has to do */
if (trans) {
gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
- msg->lchan = trans->conn->lchan;
- }
-
- if (msg->lchan) {
- struct e1inp_sign_link *sign_link =
- msg->lchan->ts->trx->rsl_link;
-
- msg->dst = sign_link;
- if (gsm48_hdr_pdisc(gh) == GSM48_PDISC_CC)
- DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) "
- "Sending '%s' to MS.\n",
- sign_link->trx->bts->nr,
- sign_link->trx->nr, msg->lchan->ts->nr,
- gh->proto_discr & 0xf0,
- gsm48_cc_msg_name(gh->msg_type));
- else
- DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
- "Sending 0x%02x to MS.\n",
- sign_link->trx->bts->nr,
- sign_link->trx->nr, msg->lchan->ts->nr,
- gh->proto_discr, gh->msg_type);
}
return gsm0808_submit_dtap(conn, msg, 0, 0);
@@ -187,7 +151,6 @@ void gsm0408_clear_all_trans(struct gsm_network *net, int protocol)
/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause)
{
- struct gsm_bts *bts = conn->bts;
struct msgb *msg;
msg = gsm48_create_loc_upd_rej(cause);
@@ -196,11 +159,8 @@ int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause)
return -1;
}
- msg->lchan = conn->lchan;
-
- LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT "
- "LAC=%u BTS=%u\n", vlr_subscr_name(conn->vsub),
- bts->location_area_code, bts->nr);
+ LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT\n",
+ vlr_subscr_name(conn->vsub));
return gsm48_conn_sendmsg(msg, conn, NULL);
}
@@ -214,8 +174,6 @@ static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn,
struct gsm48_loc_area_id *lai;
uint8_t *mid;
- msg->lchan = conn->lchan;
-
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
@@ -223,7 +181,7 @@ static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn,
lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
gsm48_generate_lai(lai, conn->network->country_code,
conn->network->network_code,
- conn->bts->location_area_code);
+ conn->lac);
if (send_tmsi == GSM_RESERVED_TMSI) {
/* we did not allocate a TMSI to the MS, so we need to
@@ -258,8 +216,6 @@ static int mm_tx_identity_req(struct gsm_subscriber_connection *conn, uint8_t id
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ID REQ");
struct gsm48_hdr *gh;
- msg->lchan = conn->lchan;
-
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_ID_REQ;
@@ -437,8 +393,6 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
int tzunits;
int dst = 0;
- msg->lchan = conn->lchan;
-
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_INFO;
@@ -588,7 +542,6 @@ int gsm48_tx_mm_auth_req(struct gsm_subscriber_connection *conn, uint8_t *rand,
if (autn)
DEBUGP(DMM, " AUTH REQ (autn = %s)\n", osmo_hexdump_nospc(autn, 16));
- msg->lchan = conn->lchan;
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_AUTH_REQ;
@@ -669,7 +622,7 @@ accept_reuse:
* b) Try to parse the TMSI. If we do not have one reject
* c) Check that we know the subscriber with the TMSI otherwise reject
* with a HLR cause
- * d) Set the subscriber on the gsm_lchan and accept
+ * d) Set the subscriber on the conn and accept
*
* Keep this function non-static for direct invocation by unit tests.
*/
@@ -699,14 +652,14 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms
DEBUGP(DMM, "<- CM SERVICE REQUEST ");
if (msg->data_len < sizeof(struct gsm48_service_request*)) {
DEBUGPC(DMM, "wrong sized message\n");
- return gsm48_tx_mm_serv_rej(conn,
- GSM48_REJECT_INCORRECT_MESSAGE);
+ return msc_gsm48_tx_mm_serv_rej(conn,
+ GSM48_REJECT_INCORRECT_MESSAGE);
}
if (msg->data_len < req->mi_len + 6) {
DEBUGPC(DMM, "does not fit in packet\n");
- return gsm48_tx_mm_serv_rej(conn,
- GSM48_REJECT_INCORRECT_MESSAGE);
+ return msc_gsm48_tx_mm_serv_rej(conn,
+ GSM48_REJECT_INCORRECT_MESSAGE);
}
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
@@ -722,8 +675,8 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms
mi_string);
} else {
DEBUGPC(DMM, "mi_type is not expected: %d\n", mi_type);
- return gsm48_tx_mm_serv_rej(conn,
- GSM48_REJECT_INCORRECT_MESSAGE);
+ return msc_gsm48_tx_mm_serv_rej(conn,
+ GSM48_REJECT_INCORRECT_MESSAGE);
}
osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_IDENTITY, (classmark2 + classmark2_len));
@@ -748,8 +701,12 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms
return rc;
}
+#if BEFORE_MSCSPLIT
+ /* see mail on openbsc@ 9 Feb 2016 22:30:15 +0100
+ * We need to hook sending of MRPCI to Siemens BS11 somewhere else */
if (is_siemens_bts(conn->bts))
send_siemens_mrpci(msg->lchan, classmark2-1);
+#endif
vlr_proc_acc_req(conn->conn_fsm,
SUBSCR_CONN_E_ACCEPTED,
@@ -801,7 +758,6 @@ static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, s
break;
}
-
/* TODO? We used to remember the subscriber's classmark1 here and
* stored it in the old sqlite db, but now we store it in a conn that
* will be discarded anyway: */
@@ -1195,8 +1151,6 @@ int gsm48_send_rr_app_info(struct gsm_subscriber_connection *conn, uint8_t apdu_
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 APP INF");
struct gsm48_hdr *gh;
- msg->lchan = conn->lchan;
-
DEBUGP(DRR, "TX APPLICATION INFO id=0x%02x, len=%u\n",
apdu_id, apdu_len);
@@ -1288,8 +1242,6 @@ static int gsm48_tx_simple(struct gsm_subscriber_connection *conn,
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 TX SIMPLE");
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- msg->lchan = conn->lchan;
-
gh->proto_discr = pdisc;
gh->msg_type = msg_type;
@@ -1311,6 +1263,7 @@ static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
struct msgb *msg;
unsigned char *data;
+#if BEFORE_MSCSPLIT
if (trans)
if (trans->conn && trans->conn->lchan)
DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
@@ -1328,6 +1281,7 @@ static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
else
DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) "
"Sending '%s' to MNCC.\n", get_mncc_name(msg_type));
+#endif
mncc->msg_type = msg_type;
@@ -1371,8 +1325,10 @@ void _gsm48_cc_trans_free(struct gsm_trans *trans)
}
if (trans->cc.state != GSM_CSTATE_NULL)
new_cc_state(trans, GSM_CSTATE_NULL);
+#if BEFORE_MSCSPLIT
if (trans->conn)
trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref);
+#endif
}
static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
@@ -1386,13 +1342,12 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
OSMO_ASSERT(!transt->conn);
- /* check all tranactions (without lchan) for subscriber */
switch (event) {
case GSM_PAGING_SUCCEEDED:
DEBUGP(DCC, "Paging subscr %s succeeded!\n",
vlr_subscr_msisdn_or_name(transt->vsub));
OSMO_ASSERT(conn);
- /* Assign lchan */
+ /* Assign conn */
transt->conn = conn;
/* send SETUP request to called party */
gsm48_cc_tx_setup(transt, &transt->cc.msg);
@@ -1421,6 +1376,7 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable);
+#if BEFORE_MSCSPLIT
/* handle audio path for handover */
static int switch_for_handover(struct gsm_lchan *old_lchan,
struct gsm_lchan *new_lchan)
@@ -1488,77 +1444,6 @@ static void maybe_switch_for_handover(struct gsm_lchan *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;
- int rc;
- struct gsm_network *net;
- struct gsm_trans *trans;
-
- 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;
-
- switch (signal) {
- case S_ABISIP_CRCX_ACK:
- /* in case we don't use direct BTS-to-BTS RTP */
- /* the BTS has successfully bound a TCH to a local ip/port,
- * which means we can connect our UDP socket to it */
- if (lchan->abis_ip.rtp_socket) {
- rtp_socket_free(lchan->abis_ip.rtp_socket);
- lchan->abis_ip.rtp_socket = NULL;
- }
-
- lchan->abis_ip.rtp_socket = rtp_socket_create();
- if (!lchan->abis_ip.rtp_socket)
- return -EIO;
-
- rc = rtp_socket_connect(lchan->abis_ip.rtp_socket,
- lchan->abis_ip.bound_ip,
- lchan->abis_ip.bound_port);
- if (rc < 0)
- return -EIO;
-
- /* check if any transactions on this lchan still have
- * a tch_recv_mncc request pending */
- net = lchan->ts->trx->bts->network;
- llist_for_each_entry(trans, &net->trans_list, entry) {
- if (trans->conn && trans->conn->lchan == lchan && trans->tch_recv) {
- DEBUGP(DCC, "pending tch_recv_mncc request\n");
- tch_recv_mncc(net, trans->callref, 1);
- }
- }
-
- /*
- * TODO: this appears to be too early? Why not until after
- * the handover detect or the handover complete?
- *
- * 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.
- */
- maybe_switch_for_handover(lchan);
- break;
- case S_ABISIP_DLCX_IND:
- /* the BTS tells us a RTP stream has been disconnected */
- if (lchan->abis_ip.rtp_socket) {
- rtp_socket_free(lchan->abis_ip.rtp_socket);
- lchan->abis_ip.rtp_socket = NULL;
- }
-
- break;
- }
-
- return 0;
-}
/* map two ipaccess RTP streams onto each other */
static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
@@ -1647,6 +1532,7 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
return 0;
}
+#endif
/* bridge channels of two transactions */
static int tch_bridge(struct gsm_network *net, struct gsm_mncc_bridge *bridge)
@@ -1663,13 +1549,19 @@ static int tch_bridge(struct gsm_network *net, struct gsm_mncc_bridge *bridge)
/* Which subscriber do we want to track trans1 or trans2? */
log_set_context(LOG_CTX_VLR_SUBSCR, trans1->vsub);
+#if BEFORE_MSCSPLIT
/* through-connect channel */
return tch_map(trans1->conn->lchan, trans2->conn->lchan);
+#else
+ /* not implemented yet! */
+ return -1;
+#endif
}
/* enable receive of channels to MNCC upqueue */
static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)
{
+#if BEFORE_MSCSPLIT
struct gsm_trans *trans;
struct gsm_lchan *lchan;
struct gsm_bts *bts;
@@ -1738,6 +1630,10 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)
}
return 0;
+#else
+ /* not implemented yet! */
+ return -1;
+#endif
}
static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
@@ -1877,7 +1773,11 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
memset(&setup, 0, sizeof(struct gsm_mncc));
setup.callref = trans->callref;
+#if BEFORE_MSCSPLIT
setup.lchan_type = trans->conn->lchan->type;
+#else
+ setup.lchan_type = GSM_LCHAN_NONE;
+#endif
tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
/* emergency setup is identified by msg_type */
if (msg_type == GSM48_MT_CC_EMERG_SETUP)
@@ -1893,7 +1793,6 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
setup.fields |= MNCC_F_BEARER_CAP;
gsm48_decode_bearer_cap(&setup.bearer_cap,
TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- apply_codec_restrictions(trans->conn->bts, &setup.bearer_cap);
}
/* facility */
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
@@ -2033,7 +1932,11 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
memset(&call_conf, 0, sizeof(struct gsm_mncc));
call_conf.callref = trans->callref;
+#if BEFORE_MSCSPLIT
call_conf.lchan_type = trans->conn->lchan->type;
+#else
+ call_conf.lchan_type = GSM_LCHAN_NONE;
+#endif
tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
#if 0
/* repeat */
@@ -2047,7 +1950,6 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
call_conf.fields |= MNCC_F_BEARER_CAP;
gsm48_decode_bearer_cap(&call_conf.bearer_cap,
TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- apply_codec_restrictions(trans->conn->bts, &call_conf.bearer_cap);
}
/* cause */
if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
@@ -2737,7 +2639,6 @@ static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
modify.fields |= MNCC_F_BEARER_CAP;
gsm48_decode_bearer_cap(&modify.bearer_cap,
TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap);
}
new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
@@ -2780,7 +2681,6 @@ static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg
modify.fields |= MNCC_F_BEARER_CAP;
gsm48_decode_bearer_cap(&modify.bearer_cap,
TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap);
}
new_cc_state(trans, GSM_CSTATE_ACTIVE);
@@ -2821,7 +2721,6 @@ static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
modify.fields |= GSM48_IE_BEARER_CAP;
gsm48_decode_bearer_cap(&modify.bearer_cap,
TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap);
}
/* cause */
if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
@@ -2926,6 +2825,7 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
{
+#if BEFORE_MSCSPLIT
struct gsm_mncc *mode = arg;
struct gsm_lchan *lchan = trans->conn->lchan;
@@ -2941,8 +2841,14 @@ static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
return gsm0808_assign_req(trans->conn, mode->lchan_mode,
trans->conn->lchan->type != GSM_LCHAN_TCH_H);
+#else
+ /* not implemented yet! */
+ return -1;
+#endif
+
}
+#if BEFORE_MSCSPLIT
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)
@@ -2999,9 +2905,11 @@ 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);
}
+#endif
static int tch_rtp_create(struct gsm_network *net, uint32_t callref)
{
+#if BEFORE_MSCSPLIT
struct gsm_bts *bts;
struct gsm_lchan *lchan;
struct gsm_trans *trans;
@@ -3055,10 +2963,15 @@ static int tch_rtp_create(struct gsm_network *net, uint32_t callref)
mncc_recv_rtp_sock(trans->net, trans, MNCC_RTP_CREATE);
return 0;
+#else
+ /* not implemented yet! */
+ return -1;
+#endif
}
static int tch_rtp_connect(struct gsm_network *net, void *arg)
{
+#if BEFORE_MSCSPLIT
struct gsm_lchan *lchan;
struct gsm_trans *trans;
struct gsm_mncc_rtp *rtp = arg;
@@ -3096,8 +3009,13 @@ static int tch_rtp_connect(struct gsm_network *net, void *arg)
*/
trans->conn->mncc_rtp_connect_pending = 1;
return rsl_ipacc_mdcx(lchan, rtp->ip, rtp->port, 0);
+#else
+ /* not implemented yet! */
+ return -1;
+#endif
}
+#if BEFORE_MSCSPLIT
static int tch_rtp_signal(struct gsm_lchan *lchan, int signal)
{
struct gsm_network *net;
@@ -3145,6 +3063,7 @@ static int tch_rtp_signal(struct gsm_lchan *lchan, int signal)
return 0;
}
+#endif
static struct downstate {
@@ -3214,7 +3133,9 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
int i, rc = 0;
struct gsm_trans *trans = NULL, *transt;
struct gsm_subscriber_connection *conn = NULL;
+#if BEFORE_MSCSPLIT
struct gsm_bts *bts = NULL;
+#endif
struct gsm_mncc *data = arg, rel;
DEBUGP(DMNCC, "receive message %s\n", get_mncc_name(msg_type));
@@ -3252,6 +3173,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n");
return 0;
}
+#if BEFORE_MSCSPLIT
if (!trans->conn->lchan) {
LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without lchan\n");
return 0;
@@ -3281,6 +3203,10 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
}
return -EINVAL;
+#else
+ /* not implemented yet! */
+ return -1;
+#endif
}
memset(&rel, 0, sizeof(struct gsm_mncc));
@@ -3356,14 +3282,15 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
return -ENOMEM;
}
- /* Find lchan */
+
+ /* Find conn */
conn = connection_for_subscr(vsub);
- /* If subscriber has no lchan */
+ /* If subscriber has no conn */
if (!conn) {
/* find transaction with this subscriber already paging */
llist_for_each_entry(transt, &net->trans_list, entry) {
- /* Transaction of our lchan? */
+ /* Transaction of our conn? */
if (transt == trans ||
transt->vsub != vsub)
continue;
@@ -3395,6 +3322,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
vlr_subscr_put(vsub);
return 0;
}
+
/* Assign lchan */
trans->conn = msc_subscr_conn_get(conn);
vlr_subscr_put(vsub);
@@ -3408,7 +3336,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
/* if paging did not respond yet */
if (!conn) {
- DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
+ DEBUGP(DCC, "(sub %s) "
"Received '%s' from MNCC in paging state\n",
vlr_subscr_msisdn_or_name(trans->vsub),
get_mncc_name(msg_type));
@@ -3423,9 +3351,8 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
return rc;
}
- DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) "
+ DEBUGP(DCC, "(ti %02x sub %s) "
"Received '%s' from MNCC in state %d (%s)\n",
- conn->bts->nr, conn->lchan->ts->trx->nr, conn->lchan->ts->nr,
trans->transaction_id,
vlr_subscr_msisdn_or_name(trans->conn->vsub),
get_mncc_name(msg_type), trans->cc.state,
@@ -3522,12 +3449,14 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m
/* Find transaction */
trans = trans_find_by_id(conn, GSM48_PDISC_CC, transaction_id);
+#if BEFORE_MSCSPLIT
DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
"Received '%s' from MS in state %d (%s)\n",
conn->bts->nr, conn->lchan->ts->trx->nr, conn->lchan->ts->nr,
transaction_id, vlr_subscr_msisdn_or_name(conn->vsub),
gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0,
gsm48_cc_state_name(trans?(trans->cc.state):0));
+#endif
/* Create transaction */
if (!trans) {
@@ -3845,6 +3774,7 @@ int msc_vlr_start(struct gsm_network *net)
net->gsup_server_port);
}
+#if BEFORE_MSCSPLIT
/*
* This will be run by the linker when loading the DSO. We use it to
* do system initialization, e.g. registration of signal handlers.
@@ -3853,3 +3783,4 @@ static __attribute__((constructor)) void on_dso_load_0408(void)
{
osmo_signal_register_handler(SS_ABISIP, handle_abisip_signal, NULL);
}
+#endif
diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c
index 6ad944b50..3255a3b6f 100644
--- a/openbsc/src/libmsc/gsm_04_11.c
+++ b/openbsc/src/libmsc/gsm_04_11.c
@@ -878,7 +878,7 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
}
/* Take a SMS in gsm_sms structure and send it through an already
- * existing lchan. We also assume that the caller ensured this lchan already
+ * existing conn. We also assume that the caller ensured this conn already
* has a SAPI3 RLL connection! */
int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
{
@@ -1004,7 +1004,7 @@ int gsm411_send_sms_subscr(struct vlr_subscr *vsub,
struct gsm_subscriber_connection *conn;
void *res;
- /* check if we already have an open lchan to the subscriber.
+ /* check if we already have an open conn to the subscriber.
* if yes, send the SMS this way */
conn = connection_for_subscr(vsub);
if (conn) {
@@ -1016,8 +1016,8 @@ int gsm411_send_sms_subscr(struct vlr_subscr *vsub,
/* if not, we have to start paging */
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS: no connection open, start paging %s\n",
vlr_subscr_name(vsub));
- res = subscr_request_channel(vsub, RSL_CHANNEED_SDCCH,
- paging_cb_send_sms, sms);
+ res = subscr_request_conn(vsub, RSL_CHANNEED_SDCCH, paging_cb_send_sms,
+ sms);
if (!res) {
send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY);
sms_free(sms);
diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c
index e9b2e0e5d..f425058f0 100644
--- a/openbsc/src/libmsc/gsm_subscriber.c
+++ b/openbsc/src/libmsc/gsm_subscriber.c
@@ -46,21 +46,6 @@ void *tall_sub_req_ctx;
int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
gsm_cbfn *cb, void *cb_data);
-
-/*
- * Struct for pending channel requests. This is managed in the
- * llist_head requests of each subscriber. The reference counting
- * should work in such a way that a subscriber with a pending request
- * remains in memory.
- */
-struct subscr_request {
- struct llist_head entry;
-
- /* the callback data */
- gsm_cbfn *cbfn;
- void *param;
-};
-
static struct bsc_subscr *vlr_subscr_to_bsc_sub(struct llist_head *bsc_subscribers,
struct vlr_subscr *vsub)
{
@@ -74,6 +59,10 @@ static struct bsc_subscr *vlr_subscr_to_bsc_sub(struct llist_head *bsc_subscribe
return sub;
}
+#if 0
+TODO implement paging response in libmsc!
+Excluding this to be able to link without libbsc:
+
/*
* We got the channel assigned and can now hand this channel
* over to one of our callbacks.
@@ -139,9 +128,16 @@ struct subscr_request *subscr_request_channel(struct vlr_subscr *vsub,
if (!vsub->cs.is_paging) {
LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n",
vlr_subscr_name(vsub));
+#if 0
+ TODO implement paging response in libmsc!
+ Excluding this to be able to link without libbsc:
+
bsub = vlr_subscr_to_bsc_sub(net->bsc_subscribers, vsub);
rc = paging_request(net, bsub, channel_type, NULL, NULL);
bsc_subscr_put(bsub);
+#else
+ rc = -ENOTSUP;
+#endif
if (rc <= 0) {
LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n",
vlr_subscr_name(vsub), rc);
@@ -181,3 +177,4 @@ struct gsm_subscriber_connection *connection_for_subscr(struct vlr_subscr *vsub)
return NULL;
}
+#endif
diff --git a/openbsc/src/libmsc/mncc_builtin.c b/openbsc/src/libmsc/mncc_builtin.c
index 067cc92f8..7f613c4a4 100644
--- a/openbsc/src/libmsc/mncc_builtin.c
+++ b/openbsc/src/libmsc/mncc_builtin.c
@@ -207,9 +207,11 @@ static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
bridge.callref[1] = call->remote_ref;
DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
+#if BEFORE_MSCSPLIT
/* in direct mode, we always have to bridge the channels */
if (ipacc_rtp_direct)
return mncc_tx_to_cc(call->net, MNCC_BRIDGE, &bridge);
+#endif
/* proxy mode */
if (!net->handover.active) {
@@ -293,11 +295,16 @@ static int mncc_rcv_data(struct gsm_call *call, int msg_type,
return -EIO;
}
+#if BEFORE_MSCSPLIT
/* RTP socket of remote end has meanwhile died */
if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
return -EIO;
return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
+#else
+ /* not implemented yet! */
+ return -1;
+#endif
}
diff --git a/openbsc/src/libmsc/msc_ifaces.c b/openbsc/src/libmsc/msc_ifaces.c
new file mode 100644
index 000000000..500c99c2e
--- /dev/null
+++ b/openbsc/src/libmsc/msc_ifaces.c
@@ -0,0 +1,83 @@
+/* Implementation for MSC decisions which interface to send messages out on. */
+
+/* (C) 2016 by sysmocom s.m.f.c GmbH <info@sysmocom.de>
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <osmocom/core/logging.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/msc_ifaces.h>
+
+static int msc_tx(struct gsm_subscriber_connection *conn, struct msgb *msg)
+{
+ switch (conn->via_ran) {
+ case RAN_GERAN_A:
+ msg->dst = conn;
+ return a_tx(msg);
+
+ case RAN_UTRAN_IU:
+ msg->dst = conn->iu.ue_ctx;
+ return iu_tx(msg, 0);
+
+ default:
+ LOGP(DMSC, LOGL_ERROR,
+ "msc_tx(): conn->via_ran invalid (%d)\n",
+ conn->via_ran);
+ return -1;
+ }
+}
+
+
+int msc_tx_dtap(struct gsm_subscriber_connection *conn,
+ struct msgb *msg)
+{
+ return msc_tx(conn, msg);
+}
+
+
+/* 9.2.5 CM service accept */
+int msc_gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn)
+{
+ struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACC");
+ struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+
+ gh->proto_discr = GSM48_PDISC_MM;
+ gh->msg_type = GSM48_MT_MM_CM_SERV_ACC;
+
+ DEBUGP(DMM, "-> CM SERVICE ACCEPT\n");
+
+ return msc_tx_dtap(conn, msg);
+}
+
+/* 9.2.6 CM service reject */
+int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
+ enum gsm48_reject_value value)
+{
+ struct msgb *msg;
+
+ msg = gsm48_create_mm_serv_rej(value);
+ if (!msg) {
+ LOGP(DMM, LOGL_ERROR, "Failed to allocate CM Service Reject.\n");
+ return -1;
+ }
+
+ DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
+
+ return msc_tx_dtap(conn, msg);
+}
diff --git a/openbsc/src/libmsc/osmo_msc.c b/openbsc/src/libmsc/osmo_msc.c
index 21c8ec246..ab53b0be7 100644
--- a/openbsc/src/libmsc/osmo_msc.c
+++ b/openbsc/src/libmsc/osmo_msc.c
@@ -21,6 +21,7 @@
*
*/
+#include <openbsc/osmo_msc.h>
#include <openbsc/bsc_api.h>
#include <openbsc/debug.h>
#include <openbsc/transaction.h>
@@ -69,9 +70,10 @@ static void subscr_conn_bump(struct gsm_subscriber_connection *conn)
osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_BUMP, NULL);
}
-/* Receive a COMPLETE LAYER3 INFO from BSC */
-static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
- uint16_t chosen_channel)
+/* receive a Level 3 Complete message and return MSC_CONN_ACCEPT or
+ * MSC_CONN_REJECT */
+enum msc_compl_l3_rc msc_compl_l3(struct gsm_subscriber_connection *conn,
+ struct msgb *msg, uint16_t chosen_channel)
{
/* Ownership of the gsm_subscriber_connection is still a bit mucky
* between libbsc and libmsc. In libmsc, we use ref counting, but not
@@ -87,7 +89,7 @@ static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg
/* keep the use_count reserved, libbsc will discard. If we
* released the ref count and discarded here, libbsc would
* double-free. And we will not change bsc_api semantics. */
- return BSC_API_CONN_POL_REJECT;
+ return MSC_CONN_REJECT;
}
DEBUGP(DMM, "compl_l3: Keeping conn\n");
@@ -96,7 +98,7 @@ static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg
/* If this should be kept, the conn->conn_fsm has placed a use_count */
msc_subscr_conn_put(conn);
- return BSC_API_CONN_POL_ACCEPT;
+ return MSC_CONN_ACCEPT;
#if 0
/*
@@ -105,14 +107,14 @@ static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg
* pending transaction or ongoing operation.
*/
if (conn->silent_call)
- return BSC_API_CONN_POL_ACCEPT;
- if (conn->sec_operation || conn->anch_operation)
- return BSC_API_CONN_POL_ACCEPT;
+ return MSC_CONN_ACCEPT;
+ if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
+ return MSC_CONN_ACCEPT;
if (trans_has_conn(conn))
- return BSC_API_CONN_POL_ACCEPT;
+ return MSC_CONN_ACCEPT;
LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n");
- return BSC_API_CONN_POL_REJECT;
+ return MSC_CONN_REJECT;
#endif
}
diff --git a/openbsc/src/libmsc/silent_call.c b/openbsc/src/libmsc/silent_call.c
index 6f3fbf264..76816c29d 100644
--- a/openbsc/src/libmsc/silent_call.c
+++ b/openbsc/src/libmsc/silent_call.c
@@ -52,8 +52,10 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event,
switch (event) {
case GSM_PAGING_SUCCEEDED:
+#if BEFORE_MSCSPLIT
DEBUGPC(DLSMS, "success, using Timeslot %u on ARFCN %u\n",
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
+#endif
conn->silent_call = 1;
msc_subscr_conn_get(conn);
/* increment lchan reference count */
@@ -126,7 +128,10 @@ int gsm_silent_call_start(struct vlr_subscr *vsub, void *data, int type)
{
struct subscr_request *req;
- req = subscr_request_channel(vsub, type, paging_cb_silent, data);
+ /* FIXME the VTY command allows selecting a silent call channel type.
+ * This doesn't apply to the situation after MSCSPLIT with an
+ * A-interface. */
+ req = subscr_request_conn(vsub, type, paging_cb_silent, data);
return req != NULL;
}
@@ -143,8 +148,10 @@ int gsm_silent_call_stop(struct vlr_subscr *vsub)
if (!conn->silent_call)
return -EINVAL;
+#if BEFORE_MSCSPLIT
DEBUGPC(DLSMS, "Stopping silent call using Timeslot %u on ARFCN %u\n",
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
+#endif
conn->silent_call = 0;
msc_subscr_conn_put(conn);
diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c
index f06eb7d93..42ba7f990 100644
--- a/openbsc/src/libmsc/smpp_openbsc.c
+++ b/openbsc/src/libmsc/smpp_openbsc.c
@@ -423,6 +423,7 @@ void append_tlv_u16(tlv_t **req_tlv, uint16_t tag, uint16_t val)
build_tlv(req_tlv, &tlv);
}
+#if BEFORE_MSCSPLIT
/* Append the Osmocom vendor-specific additional TLVs to a SMPP msg */
static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan)
{
@@ -461,6 +462,7 @@ static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan)
(uint8_t *)vsub->imei, imei_len+1);
}
}
+#endif
struct {
uint32_t smpp_status_code;
@@ -680,8 +682,10 @@ static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms,
memcpy(deliver.short_message, sms->user_data, deliver.sm_length);
}
+#if BEFORE_MSCSPLIT
if (esme->acl && esme->acl->osmocom_ext && conn->lchan)
append_osmo_tlvs(&deliver.tlv, conn->lchan);
+#endif
ret = smpp_tx_deliver(esme, &deliver);
if (ret < 0)
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index faadbb16e..df2d1e4ad 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -559,6 +559,7 @@ DEFUN(ena_subscr_handover,
SUBSCR_HELP "Handover the active connection\n"
"Number of the BTS to handover to\n")
{
+#if BEFORE_MSCSPLIT
int ret;
struct gsm_subscriber_connection *conn;
struct gsm_bts *bts;
@@ -602,6 +603,10 @@ DEFUN(ena_subscr_handover,
vlr_subscr_put(vsub);
return CMD_SUCCESS;
+#else
+ vty_out(vty, "%% Not implemented!%s", VTY_NEWLINE);
+ return -1;
+#endif
}
#define A3A8_ALG_TYPES "(none|xor|comp128v1)"
@@ -647,6 +652,7 @@ DEFUN(subscriber_update,
static int scall_cbfn(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
+#if BEFORE_MSCSPLIT
struct scall_signal_data *sigdata = signal_data;
struct vty *vty = sigdata->data;
@@ -661,6 +667,10 @@ static int scall_cbfn(unsigned int subsys, unsigned int signal,
break;
}
return 0;
+#else
+ /* not implemented yet! */
+ return -1;
+#endif
}
DEFUN(show_stats,
@@ -670,7 +680,11 @@ DEFUN(show_stats,
{
struct gsm_network *net = gsmnet_from_vty(vty);
+#if 0
+ TODO implement statistics specifically for libmsc!
+ Excluding this to be able to link without libbsc:
openbsc_vty_print_statistics(vty, net);
+#endif
vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s",
net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current,
net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current,