aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2017-04-09 12:32:51 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2017-08-30 14:12:37 +0200
commitefe85d33d4948a20de1baec2e8956113714ec72e (patch)
tree144135f7b5ae2584ca71377c424024c9b535ed73
parent868dd5d8d31f756e404a7bfb7896aed21d20f905 (diff)
Implement AoIP, port to M3UA SIGTRAN (large addition and refactoring)
This was originally a long series of commits converging to the final result seen in this patch. It does not make much sense to review the smaller steps' trial and error, we need to review this entire change as a whole. Implement AoIP in osmo-msc and osmo-bsc. Change over to the new libosmo-sigtran API with support for proper SCCP/M3UA/SCTP stacking, as mandated by 3GPP specifications for the IuCS and IuPS interfaces. From here on, a separate osmo-stp process is required for SCCP routing between OsmoBSC / OsmoHNBGW <-> OsmoMSC / OsmoSGSN jenkins.sh: build from libosmo-sccp and osmo-iuh master branches now for new M3UA SIGTRAN. Patch-by: pmaier, nhofmeyr, laforge Change-Id: I5ae4e05ee7c57cad341ea5e86af37c1f6b0ffa77
-rw-r--r--configure.ac2
-rwxr-xr-xcontrib/jenkins.sh9
-rw-r--r--doc/examples/osmo-bsc/osmo-bsc.cfg8
-rw-r--r--include/openbsc/Makefile.am4
-rw-r--r--include/openbsc/a_iface.h76
-rw-r--r--include/openbsc/a_iface_bssap.h41
-rw-r--r--include/openbsc/a_reset.h63
-rw-r--r--include/openbsc/bsc_msc.h12
-rw-r--r--include/openbsc/bsc_msc_data.h32
-rw-r--r--include/openbsc/debug.h1
-rw-r--r--include/openbsc/gsm_04_08.h2
-rw-r--r--include/openbsc/gsm_data.h39
-rw-r--r--include/openbsc/gsm_data_shared.h10
-rw-r--r--include/openbsc/iu.h13
-rw-r--r--include/openbsc/mgcpgw_client.h28
-rw-r--r--include/openbsc/msc_ifaces.h20
-rw-r--r--include/openbsc/osmo_bsc.h6
-rw-r--r--include/openbsc/osmo_bsc_reset.h34
-rw-r--r--include/openbsc/osmo_bsc_sigtran.h48
-rw-r--r--include/openbsc/osmo_msc.h7
-rw-r--r--include/openbsc/transaction.h10
-rw-r--r--src/gprs/Makefile.am2
-rw-r--r--src/gprs/sgsn_main.c17
-rw-r--r--src/libbsc/abis_rsl.c3
-rw-r--r--src/libbsc/bsc_vty.c81
-rw-r--r--src/libbsc/handover_logic.c3
-rw-r--r--src/libcommon-cs/Makefile.am1
-rw-r--r--src/libcommon-cs/a_reset.c224
-rw-r--r--src/libcommon-cs/common_cs.c2
-rw-r--r--src/libcommon/common_vty.c20
-rw-r--r--src/libcommon/debug.c6
-rw-r--r--src/libiu/iu.c138
-rw-r--r--src/libiu/iu_vty.c27
-rw-r--r--src/libmgcp/mgcp_protocol.c44
-rw-r--r--src/libmgcp/mgcpgw_client.c95
-rw-r--r--src/libmgcp/mgcpgw_client_vty.c51
-rw-r--r--src/libmsc/Makefile.am2
-rw-r--r--src/libmsc/a_iface.c582
-rw-r--r--src/libmsc/a_iface_bssap.c717
-rw-r--r--src/libmsc/gsm_04_08.c207
-rw-r--r--src/libmsc/gsm_subscriber.c3
-rw-r--r--src/libmsc/iucs.c24
-rw-r--r--src/libmsc/msc_ifaces.c214
-rw-r--r--src/libmsc/msc_vty.c28
-rw-r--r--src/libmsc/osmo_msc.c23
-rw-r--r--src/libmsc/subscr_conn.c3
-rw-r--r--src/osmo-bsc/Makefile.am4
-rw-r--r--src/osmo-bsc/osmo_bsc_api.c41
-rw-r--r--src/osmo-bsc/osmo_bsc_audio.c70
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c307
-rw-r--r--src/osmo-bsc/osmo_bsc_main.c10
-rw-r--r--src/osmo-bsc/osmo_bsc_msc.c62
-rw-r--r--src/osmo-bsc/osmo_bsc_reset.c190
-rw-r--r--src/osmo-bsc/osmo_bsc_sccp.c328
-rw-r--r--src/osmo-bsc/osmo_bsc_sigtran.c561
-rw-r--r--src/osmo-bsc/osmo_bsc_vty.c94
-rw-r--r--src/osmo-bsc_mgcp/Makefile.am1
-rw-r--r--src/osmo-bsc_nat/Makefile.am1
-rw-r--r--src/osmo-msc/msc_main.c81
-rw-r--r--tests/msc_vlr/Makefile.am7
-rw-r--r--tests/msc_vlr/msc_vlr_test_gsm_authen.c36
-rw-r--r--tests/msc_vlr/msc_vlr_test_gsm_authen.err34
-rw-r--r--tests/msc_vlr/msc_vlr_test_gsm_ciph.c30
-rw-r--r--tests/msc_vlr/msc_vlr_test_gsm_ciph.err28
-rw-r--r--tests/msc_vlr/msc_vlr_test_hlr_reject.c22
-rw-r--r--tests/msc_vlr/msc_vlr_test_hlr_reject.err22
-rw-r--r--tests/msc_vlr/msc_vlr_test_hlr_timeout.c4
-rw-r--r--tests/msc_vlr/msc_vlr_test_hlr_timeout.err4
-rw-r--r--tests/msc_vlr/msc_vlr_test_ms_timeout.c6
-rw-r--r--tests/msc_vlr/msc_vlr_test_ms_timeout.err6
-rw-r--r--tests/msc_vlr/msc_vlr_test_no_authen.c26
-rw-r--r--tests/msc_vlr/msc_vlr_test_no_authen.err26
-rw-r--r--tests/msc_vlr/msc_vlr_test_reject_concurrency.c30
-rw-r--r--tests/msc_vlr/msc_vlr_test_reject_concurrency.err38
-rw-r--r--tests/msc_vlr/msc_vlr_test_rest.c13
-rw-r--r--tests/msc_vlr/msc_vlr_test_rest.err13
-rw-r--r--tests/msc_vlr/msc_vlr_test_umts_authen.c23
-rw-r--r--tests/msc_vlr/msc_vlr_test_umts_authen.err15
-rw-r--r--tests/msc_vlr/msc_vlr_tests.c37
-rw-r--r--tests/msc_vlr/msc_vlr_tests.h32
80 files changed, 4478 insertions, 706 deletions
diff --git a/configure.ac b/configure.ac
index b0d6b236d..90a95e67f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,6 +46,7 @@ PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.9.5)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.2.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.6.4)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.0.1)
+PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran) # TODO version?
PKG_CHECK_MODULES(LIBCRYPTO, libcrypto >= 0.9.5)
# Enabke/disable the NAT?
@@ -98,7 +99,6 @@ AC_ARG_ENABLE([iu], [AS_HELP_STRING([--enable-iu], [Build 3G support, aka IuPS a
if test "x$osmo_ac_iu" = "xyes" ; then
PKG_CHECK_MODULES(LIBASN1C, libasn1c) # TODO version?
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap) # TODO version?
- PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran) # TODO version?
AC_DEFINE(BUILD_IU, 1, [Define if we want to build IuPS and IuCS interfaces support])
fi
AM_CONDITIONAL(BUILD_IU, test "x$osmo_ac_iu" = "xyes")
diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh
index 7734965f4..2b667ad04 100755
--- a/contrib/jenkins.sh
+++ b/contrib/jenkins.sh
@@ -24,21 +24,16 @@ verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
-if [ "x$IU" = "x--enable-iu" ]; then
- sccp_branch="old_sua"
- osmo_iuh_branch="old_sua"
-fi
-
osmo-build-dep.sh libosmo-abis
osmo-build-dep.sh libosmo-netif
-osmo-build-dep.sh libosmo-sccp $sccp_branch
+osmo-build-dep.sh libosmo-sccp
PARALLEL_MAKE="" osmo-build-dep.sh libsmpp34
osmo-build-dep.sh openggsn
if [ "x$IU" = "x--enable-iu" ]; then
osmo-build-dep.sh libasn1c
#osmo-build-dep.sh asn1c aper-prefix # only needed for make regen in osmo-iuh
- osmo-build-dep.sh osmo-iuh $osmo_iuh_branch
+ osmo-build-dep.sh osmo-iuh
fi
set +x
diff --git a/doc/examples/osmo-bsc/osmo-bsc.cfg b/doc/examples/osmo-bsc/osmo-bsc.cfg
index 534605a70..7c10e9dea 100644
--- a/doc/examples/osmo-bsc/osmo-bsc.cfg
+++ b/doc/examples/osmo-bsc/osmo-bsc.cfg
@@ -81,7 +81,15 @@ network
timeslot 7
phys_chan_config TCH/F
hopping enabled 0
+cs7 instance 1
+ point-code 3.0.0
+ sccp-address bsc_local
+ point-code 3.0.0
+ sccp-address msc_remote
+ point-code 1.0.0
msc
+ bsc-addr bsc_local
+ msc-addr msc_remote
ip.access rtp-base 4000
timeout-ping 20
timeout-pong 5
diff --git a/include/openbsc/Makefile.am b/include/openbsc/Makefile.am
index 995f02d09..25709f1d2 100644
--- a/include/openbsc/Makefile.am
+++ b/include/openbsc/Makefile.am
@@ -2,6 +2,8 @@ noinst_HEADERS = \
abis_nm.h \
abis_om2000.h \
abis_rsl.h \
+ a_iface.h \
+ a_iface_bssap.h \
arfcn_range_encode.h \
auth.h \
bsc_msc.h \
@@ -66,8 +68,10 @@ noinst_HEADERS = \
openbscdefines.h \
osmo_bsc.h \
osmo_bsc_grace.h \
+ a_reset.h \
osmo_bsc_rf.h \
osmo_msc.h \
+ osmo_bsc_sigtran.h \
bsc_msc_data.h \
osmux.h \
paging.h \
diff --git a/include/openbsc/a_iface.h b/include/openbsc/a_iface.h
new file mode 100644
index 000000000..149f1c71e
--- /dev/null
+++ b/include/openbsc/a_iface.h
@@ -0,0 +1,76 @@
+/* (C) 2017 by Sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <openbsc/a_reset.h>
+
+/* A struct to keep a context information about the BSCs we are associated with */
+struct bsc_context {
+ struct llist_head list;
+
+ /* Holds a copy of the sccp address of the BSC,
+ * this address will become known as soon as
+ * a remote BSC tries to make a connection or
+ * sends a RESET request via UNIDATA */
+ struct osmo_sccp_addr bsc_addr;
+
+ /* Holds a copy of the our local MSC address,
+ * this will be the sccp-address that is associated
+ * with the A interface */
+ struct osmo_sccp_addr msc_addr;
+
+ /* A pointer to the reset handler FSM, the
+ * state machine is allocated when the BSC
+ * is registerd. */
+ struct a_reset_ctx *reset;
+
+ /* A pointer to the sccp_user that is associated
+ * with the A interface. We need this information
+ * to send the resets and to send paging requests */
+ struct osmo_sccp_user *sccp_user;
+};
+
+/* Initalize A interface connection between to MSC and BSC */
+int a_init(struct osmo_sccp_instance *sccp, struct gsm_network *network);
+
+/* Send DTAP message via A-interface */
+int a_iface_tx_dtap(struct msgb *msg);
+
+/* Send Cipher mode command via A-interface */
+int a_iface_tx_cipher_mode(const struct gsm_subscriber_connection *conn,
+ int cipher, const const uint8_t *key, int len, int include_imeisv);
+
+/* Page a subscriber via A-interface */
+int a_iface_tx_paging(const char *imsi, uint32_t tmsi, uint16_t lac);
+
+/* Send assignment request via A-interface */
+int a_iface_tx_assignment(const struct gsm_trans *trans);
+
+/* Send clear command via A-interface */
+int a_iface_tx_clear_cmd(struct gsm_subscriber_connection *conn);
+
+/* Clear all subscriber connections on a specified BSC
+ * (Helper function for a_iface_bssap.c) */
+void a_clear_all(struct osmo_sccp_user *scu, const struct osmo_sccp_addr *bsc_addr);
+
+/* Delete info of a closed connection from the active connection list
+ * (Helper function for a_iface_bssap.c) */
+void a_delete_bsc_con(uint32_t conn_id);
diff --git a/include/openbsc/a_iface_bssap.h b/include/openbsc/a_iface_bssap.h
new file mode 100644
index 000000000..237c618fd
--- /dev/null
+++ b/include/openbsc/a_iface_bssap.h
@@ -0,0 +1,41 @@
+/* (C) 2017 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+/* Note: The structs and functions presented in this header file are intended
+ * to be used only by a_iface.c. */
+
+/* A structure to hold tha most basic information about a sigtran connection
+ * we use this struct internally here to pass connection data around */
+struct a_conn_info {
+ struct osmo_sccp_addr *msc_addr;
+ struct osmo_sccp_addr *bsc_addr;
+ uint32_t conn_id;
+ struct gsm_network *network;
+ struct a_reset_ctx *reset;
+};
+
+/* Receive incoming connection less data messages via sccp */
+void sccp_rx_udt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg);
+
+/* Receive incoming connection oriented data messages via sccp */
+int sccp_rx_dt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg);
+
diff --git a/include/openbsc/a_reset.h b/include/openbsc/a_reset.h
new file mode 100644
index 000000000..7aaab0620
--- /dev/null
+++ b/include/openbsc/a_reset.h
@@ -0,0 +1,63 @@
+/* (C) 2017 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+
+
+/* Reset context data (callbacks, state machine etc...) */
+struct a_reset_ctx {
+
+ /* FSM instance, which handles the reset procedure */
+ struct osmo_fsm_inst *fsm;
+
+ /* Connection failure counter. When this counter
+ * reaches a certain threshold, the reset procedure
+ * will be triggered */
+ int conn_loss_counter;
+
+ /* A human readable name to display in the logs */
+ char name[256];
+
+ /* Callback function to be called when a connection
+ * failure is detected and a rest must occur */
+ void (*cb)(void *priv);
+
+ /* Privated data for the callback function */
+ void *priv;
+};
+
+/* Create and start state machine which handles the reset/reset-ack procedure */
+struct a_reset_ctx *a_reset_alloc(const void *ctx, const char *name, void *cb, void *priv);
+
+/* Tear down state machine */
+void a_reset_free(struct a_reset_ctx *reset);
+
+/* Confirm that we sucessfully received a reset acknowlege message */
+void a_reset_ack_confirm(struct a_reset_ctx *reset);
+
+/* Report a failed connection */
+void a_reset_conn_fail(struct a_reset_ctx *reset);
+
+/* Report a successful connection */
+void a_reset_conn_success(struct a_reset_ctx *reset);
+
+/* Check if we have a connection to a specified msc */
+bool a_reset_conn_ready(struct a_reset_ctx *reset);
diff --git a/include/openbsc/bsc_msc.h b/include/openbsc/bsc_msc.h
index 39258d364..380eb17c1 100644
--- a/include/openbsc/bsc_msc.h
+++ b/include/openbsc/bsc_msc.h
@@ -24,6 +24,8 @@
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
+#include <osmocom/sigtran/sccp_sap.h>
+#include <openbsc/a_reset.h>
#include <netinet/in.h>
@@ -37,6 +39,7 @@ struct bsc_msc_dest {
struct bsc_msc_connection {
+ /* FIXME: Remove stuff that is no longer needed! */
struct osmo_wqueue write_queue;
int is_connected;
int is_authenticated;
@@ -52,6 +55,15 @@ struct bsc_msc_connection {
struct osmo_timer_list timeout_timer;
struct msgb *pending_msg;
+
+ /* Sigtran connection data */
+ struct osmo_sccp_instance *sccp;
+ struct osmo_sccp_user *sccp_user;
+ struct osmo_sccp_addr g_calling_addr;
+ struct osmo_sccp_addr g_called_addr;
+ struct a_reset_ctx *reset;
+
+ int conn_id_counter;
};
struct bsc_msc_connection *bsc_msc_create(void *ctx, struct llist_head *dest);
diff --git a/include/openbsc/bsc_msc_data.h b/include/openbsc/bsc_msc_data.h
index 38e87cfb9..4a283d165 100644
--- a/include/openbsc/bsc_msc_data.h
+++ b/include/openbsc/bsc_msc_data.h
@@ -32,6 +32,14 @@
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
+
+#include <osmocom/sigtran/osmo_ss7.h>
+#include <osmocom/sigtran/sccp_sap.h>
+#include <osmocom/sigtran/sccp_helpers.h>
+#include <osmocom/sigtran/protocol/sua.h>
+#include <osmocom/sigtran/protocol/m3ua.h>
+#include <osmocom/core/fsm.h>
+
#include <regex.h>
struct osmo_bsc_rf;
@@ -103,6 +111,30 @@ struct bsc_msc_data {
char *ussd_grace_txt;
char *acc_lst_name;
+
+ /* Sigtran connection data */
+ struct {
+ uint32_t cs7_instance;
+ bool cs7_instance_valid;
+ struct osmo_sccp_instance *sccp;
+ struct osmo_sccp_user *sccp_user;
+
+ /* Holds a copy of the our local MSC address,
+ * this will be the sccp-address that is associated
+ * with the A interface of this particular BSC,
+ * this address is filled up by the VTY interface */
+ struct osmo_sccp_addr bsc_addr;
+ char *bsc_addr_name;
+
+ /* Holds a copy of the MSC address. This is the
+ * address of the MSC that handles the calls of
+ * this BSC. The address is configured via the
+ * VTY interface */
+ struct osmo_sccp_addr msc_addr;
+ char *msc_addr_name;
+
+ struct a_reset_ctx *reset;
+ } a;
};
/*
diff --git a/include/openbsc/debug.h b/include/openbsc/debug.h
index de00b2930..65e197d52 100644
--- a/include/openbsc/debug.h
+++ b/include/openbsc/debug.h
@@ -40,6 +40,7 @@ enum {
DPCU,
DVLR,
DIUCS,
+ DSIGTRAN,
Debug_LastEntry,
};
diff --git a/include/openbsc/gsm_04_08.h b/include/openbsc/gsm_04_08.h
index 6d6ead183..ca251b00b 100644
--- a/include/openbsc/gsm_04_08.h
+++ b/include/openbsc/gsm_04_08.h
@@ -80,4 +80,6 @@ void allocate_security_operation(struct gsm_subscriber_connection *conn);
int gsm48_multirate_config(uint8_t *lv, const struct amr_multirate_conf *mr, const struct amr_mode *modes);
+int gsm48_tch_rtp_create(struct gsm_trans *trans);
+
#endif
diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h
index f4de38105..43fc6d330 100644
--- a/include/openbsc/gsm_data.h
+++ b/include/openbsc/gsm_data.h
@@ -12,12 +12,14 @@
#include <osmocom/core/stats.h>
#include <osmocom/crypt/auth.h>
+#include <osmocom/sigtran/sccp_sap.h>
#include <openbsc/common.h>
#include <openbsc/rest_octets.h>
#include <openbsc/common_cs.h>
#include <openbsc/mgcpgw_client.h>
+
/** annotations for msgb ownership */
#define __uses
@@ -193,14 +195,33 @@ struct gsm_subscriber_connection {
uint16_t lac;
struct gsm_encr encr;
+ struct {
+ unsigned int mgcp_rtp_endpoint;
+ uint16_t port_subscr;
+ uint16_t port_cn;
+ } rtp;
+
/* which Iu-CS connection, if any. */
struct {
struct ue_conn_ctx *ue_ctx;
- unsigned int mgcp_rtp_endpoint;
- uint16_t mgcp_rtp_port_ue;
- uint16_t mgcp_rtp_port_cn;
uint8_t rab_id;
} iu;
+
+ struct {
+ /* A pointer to the SCCP user that handles
+ * the SCCP connections for this subscriber
+ * connection */
+ struct osmo_sccp_user *scu;
+
+ /* The address of the BSC that is associated
+ * with this subscriber connection */
+ struct osmo_sccp_addr bsc_addr;
+
+ /* The connection identifier that is used
+ * to reference the SCCP connection that is
+ * associated with this subscriber connection */
+ int conn_id;
+ } a;
};
@@ -470,8 +491,20 @@ struct gsm_network {
} mgcpgw;
struct {
+ /* CS7 instance id number (set via VTY) */
+ uint32_t cs7_instance;
enum nsap_addr_enc rab_assign_addr_enc;
+ struct osmo_sccp_instance *sccp;
} iu;
+
+ struct {
+ /* CS7 instance id number (set via VTY) */
+ uint32_t cs7_instance;
+ /* A list with the context information about
+ * all BSCs we have connections with */
+ struct llist_head bscs;
+ struct osmo_sccp_instance *sccp;
+ } a;
};
struct osmo_esme;
diff --git a/include/openbsc/gsm_data_shared.h b/include/openbsc/gsm_data_shared.h
index 60da2e5c0..bed46d254 100644
--- a/include/openbsc/gsm_data_shared.h
+++ b/include/openbsc/gsm_data_shared.h
@@ -252,6 +252,16 @@ struct gsm_lchan {
uint8_t speech_mode;
#ifdef ROLE_BSC
struct rtp_socket *rtp_socket;
+
+ /* info we need to postpone the AoIP
+ * assignment completed message */
+ struct {
+ uint8_t rr_cause;
+ uint8_t chosen_channel;
+ uint8_t encr_alg_id;
+ uint8_t speech_mode;
+ bool valid;
+ } ass_compl;
#else
struct osmo_rtp_socket *rtp_socket;
#endif
diff --git a/include/openbsc/iu.h b/include/openbsc/iu.h
index 5b298301d..08e4cd06b 100644
--- a/include/openbsc/iu.h
+++ b/include/openbsc/iu.h
@@ -5,13 +5,15 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/gsm48.h>
+#include <osmocom/sigtran/sccp_sap.h>
#include <openbsc/common.h>
struct sgsn_pdp_ctx;
struct msgb;
-struct osmo_sccp_link;
struct gsm_auth_tuple;
+struct osmo_sccp_addr;
+struct osmo_ss7_instance;
struct RANAP_RAB_SetupOrModifiedItemIEs_s;
struct RANAP_GlobalRNC_ID;
@@ -23,7 +25,10 @@ extern int asn1_xer_print;
struct ue_conn_ctx {
struct llist_head list;
- struct osmo_sccp_link *link;
+ /* TODO: It's not needed to store the full SCCP address for each
+ * UE. Rather than that, a pointer to the RNC should be far
+ * sufficient */
+ struct osmo_sccp_addr sccp_addr;
uint32_t conn_id;
int integrity_active;
struct gprs_ra_id ra_id;
@@ -53,11 +58,9 @@ typedef int (* iu_event_cb_t )(struct ue_conn_ctx *ue_ctx,
typedef int (* iu_rab_ass_resp_cb_t )(struct ue_conn_ctx *ue_ctx, uint8_t rab_id,
struct RANAP_RAB_SetupOrModifiedItemIEs_s *setup_ies);
-int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port,
+int iu_init(void *ctx, struct osmo_sccp_instance *sccp,
iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb);
-void iu_link_del(struct osmo_sccp_link *link);
-
int iu_tx(struct msgb *msg, uint8_t sapi);
int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac);
diff --git a/include/openbsc/mgcpgw_client.h b/include/openbsc/mgcpgw_client.h
index b353db0a4..b1b5fd42b 100644
--- a/include/openbsc/mgcpgw_client.h
+++ b/include/openbsc/mgcpgw_client.h
@@ -3,11 +3,11 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/write_queue.h>
enum mgcp_connection_mode;
struct msgb;
-struct mgcpgw_client;
struct vty;
#define MGCPGW_CLIENT_LOCAL_ADDR_DEFAULT "0.0.0.0"
@@ -24,6 +24,9 @@ struct mgcpgw_client_conf {
int local_port;
const char *remote_addr;
int remote_port;
+ uint16_t first_endpoint;
+ uint16_t last_endpoint;
+ uint16_t bts_base;
};
struct mgcp_response_head {
@@ -38,6 +41,20 @@ struct mgcp_response {
uint16_t audio_port;
};
+struct mgcpgw_client {
+ struct mgcpgw_client_conf actual;
+ uint32_t remote_addr;
+ struct osmo_wqueue wq;
+ mgcp_trans_id_t next_trans_id;
+ struct llist_head responses_pending;
+ struct llist_head inuse_endpoints;
+};
+
+struct mgcp_inuse_endpoint {
+ struct llist_head entry;
+ uint16_t id;
+};
+
/* Invoked when an MGCP response is received or sending failed. When the
* response is passed as NULL, this indicates failure during transmission. */
typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv);
@@ -61,7 +78,11 @@ const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp);
uint16_t mgcpgw_client_remote_port(struct mgcpgw_client *mgcp);
uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp);
-unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client);
+/* Find and seize an unsused endpoint id */
+int mgcpgw_client_next_endpoint(struct mgcpgw_client *client);
+
+/* Release a seized endpoint id to make it available again for other calls */
+void mgcpgw_client_release_endpoint(uint16_t id, struct mgcpgw_client *client);
int mgcp_response_parse_params(struct mgcp_response *r);
@@ -76,6 +97,9 @@ struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode);
+struct msgb *mgcp_msg_dlcx(struct mgcpgw_client *mgcp, uint16_t rtp_endpoint,
+ unsigned int call_id);
+
void mgcpgw_client_vty_init(int node, struct mgcpgw_client_conf *conf);
int mgcpgw_client_config_write(struct vty *vty, const char *indent);
diff --git a/include/openbsc/msc_ifaces.h b/include/openbsc/msc_ifaces.h
index 2965c72c5..a1071ae9b 100644
--- a/include/openbsc/msc_ifaces.h
+++ b/include/openbsc/msc_ifaces.h
@@ -28,20 +28,6 @@
/* Each main linkage must implement this function (see comment above). */
extern int iu_tx(struct msgb *msg, uint8_t sapi);
-/* So far this is a dummy implemented in libmsc/a_iface.c. When A-interface
- * gets implemented, it should be in a separate lib (like libiu), this function
- * should move there, and the following comment should remain here: "
- * Each main linkage must implement this function (see comment above).
- * " */
-extern int a_tx(struct msgb *msg);
-
-/* So far this is a dummy implemented in libmsc/a_iface.c. When A-interface
- * gets implemented, it should be in a separate lib (like libiu), this function
- * should move there, and the following comment should remain here: "
- * Each main linkage must implement this function (see comment above).
- * " */
-extern int a_page(const char *imsi, uint32_t tmsi, uint16_t lac);
-
int msc_tx_dtap(struct gsm_subscriber_connection *conn,
struct msgb *msg);
@@ -49,10 +35,8 @@ int msc_gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn);
int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
enum gsm48_reject_value value);
-/* TODO: specific to A interface, move this away */
-int msc_gsm0808_tx_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
- const uint8_t *key, int len, int include_imeisv);
-
int msc_tx_common_id(struct gsm_subscriber_connection *conn);
int msc_call_assignment(struct gsm_trans *trans);
int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2);
+void msc_call_release(struct gsm_trans *trans);
+int msc_call_connect(struct gsm_trans *trans, uint16_t port, uint32_t ip);
diff --git a/include/openbsc/osmo_bsc.h b/include/openbsc/osmo_bsc.h
index 9e688fd59..5ebea5079 100644
--- a/include/openbsc/osmo_bsc.h
+++ b/include/openbsc/osmo_bsc.h
@@ -26,6 +26,7 @@ struct osmo_bsc_sccp_con {
/* for audio handling */
uint16_t cic;
+ uint32_t rtp_ip;
int rtp_port;
/* for advanced ping/pong */
@@ -44,6 +45,9 @@ struct osmo_bsc_sccp_con {
uint8_t new_subscriber;
struct bsc_filter_state filter_state;
+
+ /* Sigtran connection ID */
+ int conn_id;
};
struct bsc_api *osmo_bsc_api();
@@ -60,7 +64,7 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn);
int bsc_handle_udt(struct bsc_msc_data *msc, struct msgb *msg, unsigned int length);
-int bsc_handle_dt1(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned int len);
+int bsc_handle_dt(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned int len);
int bsc_ctrl_cmds_install();
diff --git a/include/openbsc/osmo_bsc_reset.h b/include/openbsc/osmo_bsc_reset.h
new file mode 100644
index 000000000..578f763e6
--- /dev/null
+++ b/include/openbsc/osmo_bsc_reset.h
@@ -0,0 +1,34 @@
+/* (C) 2017 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* Create and start state machine which handles the reset/reset-ack procedure */
+void start_reset_fsm(struct bsc_msc_data *msc);
+
+/* Confirm that we sucessfully received a reset acknowlege message */
+void reset_ack_confirm(struct bsc_msc_data *msc);
+
+/* Report a failed connection */
+void report_conn_fail(struct bsc_msc_data *msc);
+
+/* Report a successful connection */
+void report_conn_success(struct bsc_msc_data *msc);
+
+/* Check if we have a connection to a specified msc */
+bool sccp_conn_ready(struct bsc_msc_data *msc);
diff --git a/include/openbsc/osmo_bsc_sigtran.h b/include/openbsc/osmo_bsc_sigtran.h
new file mode 100644
index 000000000..fbcfcb3fc
--- /dev/null
+++ b/include/openbsc/osmo_bsc_sigtran.h
@@ -0,0 +1,48 @@
+/* (C) 2017 by Sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <openbsc/gsm_data.h>
+#include <openbsc/bsc_msc_data.h>
+
+/* Allocate resources to make a new connection oriented sigtran connection
+ * (not the connection ittself!) */
+enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc);
+
+/* Open a new connection oriented sigtran connection */
+int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb *msg);
+
+/* Send data to MSC */
+int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg);
+
+/* Delete a connection from the list with open connections
+ * (called by osmo_bsc_api.c on failing open connections and
+ * locally, when a connection is closed by the MSC */
+int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *sccp);
+
+/* Initalize osmo sigtran backhaul */
+int osmo_bsc_sigtran_init(struct llist_head *mscs);
+
+/* Close all open sigtran connections and channels */
+void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc);
+
+/* Send reset-ack to MSC */
+void osmo_bsc_sigtran_tx_reset_ack(const struct bsc_msc_data *msc);
diff --git a/include/openbsc/osmo_msc.h b/include/openbsc/osmo_msc.h
index bc96f1d5a..cdfd27f11 100644
--- a/include/openbsc/osmo_msc.h
+++ b/include/openbsc/osmo_msc.h
@@ -63,6 +63,8 @@ int msc_create_conn_fsm(struct gsm_subscriber_connection *conn, const char *id);
int msc_vlr_alloc(struct gsm_network *net);
int msc_vlr_start(struct gsm_network *net);
+void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci);
+int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause);
int msc_compl_l3(struct gsm_subscriber_connection *conn,
struct msgb *msg, uint16_t chosen_channel);
void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id,
@@ -70,6 +72,11 @@ void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id,
void msc_cipher_mode_compl(struct gsm_subscriber_connection *conn,
struct msgb *msg, uint8_t alg_id);
void msc_rx_sec_mode_compl(struct gsm_subscriber_connection *conn);
+void msc_classmark_chg(struct gsm_subscriber_connection *conn,
+ const uint8_t *cm2, uint8_t cm2_len,
+ const uint8_t *cm3, uint8_t cm3_len);
+void msc_assign_fail(struct gsm_subscriber_connection *conn,
+ uint8_t cause, uint8_t *rr_cause);
void msc_subscr_conn_init(void);
bool msc_subscr_conn_is_accepted(struct gsm_subscriber_connection *conn);
diff --git a/include/openbsc/transaction.h b/include/openbsc/transaction.h
index 713d878f3..4930fbd32 100644
--- a/include/openbsc/transaction.h
+++ b/include/openbsc/transaction.h
@@ -46,6 +46,16 @@ struct gsm_trans {
/* is thats one paging? */
struct subscr_request *paging_request;
+ /* bearer capabilities (rate and codec) */
+ struct gsm_mncc_bearer_cap bearer_cap;
+
+ /* status of the assignment, true when done */
+ bool assignment_done;
+
+ /* if true, TCH_RTP_CREATE is sent after the
+ * assignment is done */
+ bool tch_rtp_create;
+
union {
struct {
diff --git a/src/gprs/Makefile.am b/src/gprs/Makefile.am
index cb0997902..e05eb79ff 100644
--- a/src/gprs/Makefile.am
+++ b/src/gprs/Makefile.am
@@ -34,6 +34,7 @@ OSMO_LIBS = \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOGB_LIBS) \
$(LIBGTP_LIBS) \
+ $(LIBOSMOSIGTRAN_LIBS) \
$(NULL)
bin_PROGRAMS = \
@@ -128,5 +129,6 @@ osmo_gtphub_LDADD = \
$(LIBOSMOVTY_LIBS) \
$(LIBCARES_LIBS) \
$(LIBGTP_LIBS) \
+ $(LIBOSMOSIGTRAN_LIBS) \
-lrt \
$(NULL)
diff --git a/src/gprs/sgsn_main.c b/src/gprs/sgsn_main.c
index d5d43ad2a..d56af0ed4 100644
--- a/src/gprs/sgsn_main.c
+++ b/src/gprs/sgsn_main.c
@@ -63,6 +63,8 @@
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
+#include <osmocom/sigtran/protocol/m3ua.h>
+
#include <gtp.h>
#include "../../bscconfig.h"
@@ -326,6 +328,7 @@ int main(int argc, char **argv)
{
struct ctrl_handle *ctrl;
struct gsm_network dummy_network;
+ struct osmo_sccp_instance *sccp;
int rc;
srand(time(NULL));
@@ -348,6 +351,7 @@ int main(int argc, char **argv)
osmo_stats_vty_add_cmds(&gprs_log_info);
sgsn_vty_init(&sgsn_inst.cfg);
ctrl_vty_init(tall_bsc_ctx);
+ osmo_ss7_init();
handle_options(argc, argv);
@@ -436,7 +440,18 @@ int main(int argc, char **argv)
}
#ifdef BUILD_IU
- iu_init(tall_bsc_ctx, "127.0.0.2", 14001, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event);
+ sccp = osmo_sccp_simple_client(tall_bsc_ctx, "OsmoSGSN",
+ 2 /* FIXME: configurable */,
+ OSMO_SS7_ASP_PROT_M3UA, 0,
+ "127.0.0.4" /* FIXME: configurable */,
+ M3UA_PORT,
+ "127.0.0.1" /* FIXME: configurable */);
+ if (!sccp) {
+ printf("Setting up SCCP client failed.\n");
+ return 8;
+ }
+
+ iu_init(tall_bsc_ctx, sccp, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event);
#endif
if (daemonize) {
diff --git a/src/libbsc/abis_rsl.c b/src/libbsc/abis_rsl.c
index 4f687a039..66cda8200 100644
--- a/src/libbsc/abis_rsl.c
+++ b/src/libbsc/abis_rsl.c
@@ -2327,6 +2327,8 @@ static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv)
DEBUGPC(DRSL, "REMOTE_PORT=%u ", port);
lchan->abis_ip.connect_port = port;
}
+
+ DEBUGPC(DRSL, "\n");
}
/*! \brief Issue IPA RSL CRCX to configure RTP on BTS side
@@ -2558,7 +2560,6 @@ static int abis_rsl_rx_ipacc(struct msgb *msg)
rllh->c.msg_type);
break;
}
- DEBUGPC(DRSL, "\n");
return rc;
}
diff --git a/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c
index bd363ae55..d55c6eb30 100644
--- a/src/libbsc/bsc_vty.c
+++ b/src/libbsc/bsc_vty.c
@@ -57,6 +57,7 @@
#include <openbsc/pcu_if.h>
#include <openbsc/common_cs.h>
#include <openbsc/vlr.h>
+#include <openbsc/handover.h>
#include <inttypes.h>
@@ -1341,6 +1342,83 @@ DEFUN(show_lchan_summary,
return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
}
+DEFUN(show_subscr_conn,
+ show_subscr_conn_cmd,
+ "show conns",
+ SHOW_STR "Display currently active subscriber connections\n")
+{
+ struct gsm_subscriber_connection *conn;
+ struct gsm_network *net = gsmnet_from_vty(vty);
+ bool no_conns = true;
+ unsigned int count = 0;
+
+ vty_out(vty, "Active subscriber connections: %s", VTY_NEWLINE);
+
+ llist_for_each_entry(conn, &net->subscr_conns, entry) {
+ vty_out(vty, "conn nr #%u:%s", count, VTY_NEWLINE);
+ lchan_dump_full_vty(vty, conn->lchan);
+ no_conns = false;
+ count++;
+ }
+
+ if (no_conns)
+ vty_out(vty, "None%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(handover_subscr_conn,
+ handover_subscr_conn_cmd,
+ "handover <0-255> <0-255> <0-7> LCHAN_NR <0-255>",
+ "Handover subscriber connection to other BTS\n"
+ "BTS Number (current)\n" "TRX Number\n" "Timeslot Number\n"
+ LCHAN_NR_STR "BTS Number (new)\n")
+{
+ struct gsm_network *net = gsmnet_from_vty(vty);
+ struct gsm_subscriber_connection *conn;
+ struct gsm_bts *bts;
+ struct gsm_bts *new_bts = NULL;
+ unsigned int bts_nr = atoi(argv[0]);
+ unsigned int trx_nr = atoi(argv[1]);
+ unsigned int ts_nr = atoi(argv[2]);
+ unsigned int ss_nr = atoi(argv[3]);
+ unsigned int bts_nr_new = atoi(argv[4]);
+
+ /* Lookup the BTS where we want to handover to */
+ llist_for_each_entry(bts, &net->bts_list, list) {
+ if (bts->nr == bts_nr_new) {
+ new_bts = bts;
+ break;
+ }
+ }
+
+ if (!new_bts) {
+ vty_out(vty, "Unable to trigger handover,"
+ "specified bts #%u does not exist %s", bts_nr_new,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Find the connection/lchan that we want to handover */
+ llist_for_each_entry(conn, &net->subscr_conns, entry) {
+ if (conn->bts->nr == bts_nr &&
+ conn->lchan->ts->trx->nr == trx_nr &&
+ conn->lchan->ts->nr == ts_nr && conn->lchan->nr == ss_nr) {
+ vty_out(vty, "starting handover for lchan %s...%s",
+ conn->lchan->name, VTY_NEWLINE);
+ lchan_dump_full_vty(vty, conn->lchan);
+ bsc_handover_start(conn->lchan, new_bts);
+ return CMD_SUCCESS;
+ }
+ }
+
+ vty_out(vty, "Unable to trigger handover,"
+ "specified connection (bts=%u,trx=%u,ts=%u,ss=%u) does not exist%s",
+ bts_nr, trx_nr, ts_nr, ss_nr, VTY_NEWLINE);
+
+ return CMD_WARNING;
+}
+
static void paging_dump_vty(struct vty *vty, struct gsm_paging_request *pag)
{
vty_out(vty, "Paging on BTS %u%s", pag->bts->nr, VTY_NEWLINE);
@@ -4153,6 +4231,9 @@ int bsc_vty_init(struct gsm_network *network)
install_element_ve(&show_lchan_cmd);
install_element_ve(&show_lchan_summary_cmd);
+ install_element_ve(&show_subscr_conn_cmd);
+ install_element_ve(&handover_subscr_conn_cmd);
+
install_element_ve(&show_paging_cmd);
install_element_ve(&show_paging_group_cmd);
diff --git a/src/libbsc/handover_logic.c b/src/libbsc/handover_logic.c
index 57d1dcd31..14566cfa1 100644
--- a/src/libbsc/handover_logic.c
+++ b/src/libbsc/handover_logic.c
@@ -101,7 +101,8 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
if (bsc_ho_by_old_lchan(old_lchan))
return -EBUSY;
- DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n",
+ DEBUGP(DHO, "Beginning with handover operation"
+ "(old_lchan on BTS %u, new BTS %u) ...\n",
old_lchan->ts->trx->bts->nr, bts->nr);
rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED]);
diff --git a/src/libcommon-cs/Makefile.am b/src/libcommon-cs/Makefile.am
index f3921ba5f..21c27455d 100644
--- a/src/libcommon-cs/Makefile.am
+++ b/src/libcommon-cs/Makefile.am
@@ -16,5 +16,6 @@ AM_CFLAGS = \
noinst_LIBRARIES = libcommon-cs.a
libcommon_cs_a_SOURCES = \
+ a_reset.c \
common_cs.c \
common_cs_vty.c
diff --git a/src/libcommon-cs/a_reset.c b/src/libcommon-cs/a_reset.c
new file mode 100644
index 000000000..c0294c797
--- /dev/null
+++ b/src/libcommon-cs/a_reset.c
@@ -0,0 +1,224 @@
+/* (C) 2017 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/fsm.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <openbsc/debug.h>
+#include <openbsc/bsc_msc_data.h>
+#include <openbsc/osmo_bsc_sigtran.h>
+
+#define RESET_RESEND_INTERVAL 2 /* sec */
+#define RESET_RESEND_TIMER_NO 1234 /* FIXME: dig out the real timer number */
+#define BAD_CONNECTION_THRESOLD 3 /* connection failures */
+
+enum fsm_states {
+ ST_DISC, /* Disconnected from remote end */
+ ST_CONN, /* We have a confirmed connection */
+};
+
+static const struct value_string fsm_state_names[] = {
+ {ST_DISC, "ST_DISC (disconnected)"},
+ {ST_CONN, "ST_CONN (connected)"},
+ {0, NULL},
+};
+
+enum fsm_evt {
+ EV_RESET_ACK, /* got reset acknowlegement from remote end */
+ EV_N_DISCONNECT, /* lost a connection */
+ EV_N_CONNECT, /* made a successful connection */
+};
+
+static const struct value_string fsm_evt_names[] = {
+ {EV_RESET_ACK, "EV_RESET_ACK"},
+ {EV_N_DISCONNECT, "EV_N_DISCONNECT"},
+ {EV_N_CONNECT, "EV_N_CONNECT"},
+ {0, NULL},
+};
+
+/* Disconnected state */
+static void fsm_disc_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct a_reset_ctx *reset = (struct a_reset_ctx *)data;
+ OSMO_ASSERT(reset);
+
+ LOGP(DMSC, LOGL_NOTICE, "(%s) fsm-state (msc-reset): %s, fsm-event: %s\n", reset->name,
+ get_value_string(fsm_state_names, ST_CONN), get_value_string(fsm_evt_names, event));
+
+ reset->conn_loss_counter = 0;
+ osmo_fsm_inst_state_chg(fi, ST_CONN, 0, 0);
+}
+
+/* Connected state */
+static void fsm_conn_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct a_reset_ctx *reset = (struct a_reset_ctx *)data;
+ OSMO_ASSERT(reset);
+
+ LOGP(DMSC, LOGL_NOTICE, "(%s) fsm-state (msc-reset): %s, fsm-event: %s\n", reset->name,
+ get_value_string(fsm_state_names, ST_CONN), get_value_string(fsm_evt_names, event));
+
+ switch (event) {
+ case EV_N_DISCONNECT:
+ if (reset->conn_loss_counter >= BAD_CONNECTION_THRESOLD) {
+ LOGP(DMSC, LOGL_NOTICE, "(%s) SIGTRAN connection down, reconnecting...\n", reset->name);
+ osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
+ } else
+ reset->conn_loss_counter++;
+ break;
+ case EV_N_CONNECT:
+ reset->conn_loss_counter = 0;
+ break;
+ }
+}
+
+/* Timer callback to retransmit the reset signal */
+static int fsm_reset_ack_timeout_cb(struct osmo_fsm_inst *fi)
+{
+ struct a_reset_ctx *reset = (struct a_reset_ctx *)fi->priv;
+
+ LOGP(DMSC, LOGL_NOTICE, "(%s) reset-ack timeout (T%i) in state %s, resending...\n", reset->name, fi->T,
+ get_value_string(fsm_state_names, fi->state));
+
+ reset->cb(reset->priv);
+
+ osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
+ return 0;
+}
+
+static struct osmo_fsm_state fsm_states[] = {
+ [ST_DISC] = {
+ .in_event_mask = (1 << EV_RESET_ACK),
+ .out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),
+ .name = "DISC",
+ .action = fsm_disc_cb,
+ },
+ [ST_CONN] = {
+ .in_event_mask = (1 << EV_N_DISCONNECT) | (1 << EV_N_CONNECT),
+ .out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),
+ .name = "CONN",
+ .action = fsm_conn_cb,
+ },
+};
+
+/* State machine definition */
+static struct osmo_fsm fsm = {
+ .name = "FSM RESET",
+ .states = fsm_states,
+ .num_states = ARRAY_SIZE(fsm_states),
+ .log_subsys = DMSC,
+ .timer_cb = fsm_reset_ack_timeout_cb,
+};
+
+/* Create and start state machine which handles the reset/reset-ack procedure */
+struct a_reset_ctx *a_reset_alloc(const void *ctx, const char *name, void *cb, void *priv)
+{
+ OSMO_ASSERT(name);
+
+ struct a_reset_ctx *reset;
+
+ /* Register the fsm description (if not already done) */
+ if (osmo_fsm_find_by_name(fsm.name) != &fsm)
+ osmo_fsm_register(&fsm);
+
+ /* Allocate and configure a new fsm instance */
+ reset = talloc_zero(ctx, struct a_reset_ctx);
+ OSMO_ASSERT(reset);
+ reset->priv = priv;
+ reset->cb = cb;
+ strncpy(reset->name, name, sizeof(reset->name));
+ reset->conn_loss_counter = 0;
+ reset->fsm = osmo_fsm_inst_alloc(&fsm, NULL, NULL, LOGL_DEBUG, "FSM RESET INST");
+ OSMO_ASSERT(reset->fsm);
+ reset->fsm->priv = reset;
+ LOGP(DMSC, LOGL_NOTICE, "(%s) reset handler fsm created.\n", reset->name);
+
+ /* kick off reset-ack sending mechanism */
+ osmo_fsm_inst_state_chg(reset->fsm, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
+
+ return reset;
+}
+
+/* Tear down state machine */
+void a_reset_free(struct a_reset_ctx *reset)
+{
+ OSMO_ASSERT(reset);
+ OSMO_ASSERT(reset->fsm);
+
+ osmo_fsm_inst_free(reset->fsm);
+ reset->fsm = NULL;
+
+ memset(reset, 0, sizeof(*reset));
+ talloc_free(reset);
+
+ LOGP(DMSC, LOGL_NOTICE, "(%s) reset handler fsm destroyed.\n", reset->name);
+}
+
+/* Confirm that we sucessfully received a reset acknowlege message */
+void a_reset_ack_confirm(struct a_reset_ctx *reset)
+{
+ OSMO_ASSERT(reset);
+ OSMO_ASSERT(reset->fsm);
+
+ osmo_fsm_inst_dispatch(reset->fsm, EV_RESET_ACK, reset);
+}
+
+/* Report a failed connection */
+void a_reset_conn_fail(struct a_reset_ctx *reset)
+{
+ /* If no reset context is supplied, just drop the info */
+ if (!reset)
+ return;
+
+ OSMO_ASSERT(reset->fsm);
+
+ osmo_fsm_inst_dispatch(reset->fsm, EV_N_DISCONNECT, reset);
+}
+
+/* Report a successful connection */
+void a_reset_conn_success(struct a_reset_ctx *reset)
+{
+ /* If no reset context is supplied, just drop the info */
+ if (!reset)
+ return;
+
+ OSMO_ASSERT(reset->fsm);
+
+ osmo_fsm_inst_dispatch(reset->fsm, EV_N_CONNECT, reset);
+}
+
+/* Check if we have a connection to a specified msc */
+bool a_reset_conn_ready(struct a_reset_ctx *reset)
+{
+ /* If no reset context is supplied, we assume that
+ * the connection can't be ready! */
+ if (!reset)
+ return false;
+
+ OSMO_ASSERT(reset->fsm);
+ if (reset->fsm->state == ST_CONN)
+ return true;
+
+ return false;
+}
diff --git a/src/libcommon-cs/common_cs.c b/src/libcommon-cs/common_cs.c
index 99206c86c..d6dff95df 100644
--- a/src/libcommon-cs/common_cs.c
+++ b/src/libcommon-cs/common_cs.c
@@ -78,6 +78,8 @@ struct gsm_network *gsm_network_init(void *ctx,
net->dyn_ts_allow_tch_f = true;
+ INIT_LLIST_HEAD(&net->a.bscs);
+
return net;
}
diff --git a/src/libcommon/common_vty.c b/src/libcommon/common_vty.c
index 6e1c10b00..1443791f0 100644
--- a/src/libcommon/common_vty.c
+++ b/src/libcommon/common_vty.c
@@ -34,6 +34,7 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/buffer.h>
#include <osmocom/vty/vty.h>
+#include <osmocom/sigtran/osmo_ss7.h>
int bsc_vty_go_parent(struct vty *vty)
@@ -117,13 +118,15 @@ int bsc_vty_go_parent(struct vty *vty)
case MSC_NODE:
case MNCC_INT_NODE:
case NITB_NODE:
- default:
- if (bsc_vty_is_config_node(vty, vty->node))
- vty->node = CONFIG_NODE;
- else
- vty->node = ENABLE_NODE;
-
+ vty->node = CONFIG_NODE;
vty->index = NULL;
+ break;
+ case SUBSCR_NODE:
+ vty->node = ENABLE_NODE;
+ vty->index = NULL;
+ break;
+ default:
+ osmo_ss7_vty_go_parent(vty);
}
return vty->node;
@@ -131,6 +134,11 @@ int bsc_vty_go_parent(struct vty *vty)
int bsc_vty_is_config_node(struct vty *vty, int node)
{
+ /* Check if libosmo-sccp declares the node in
+ * question as config node */
+ if (osmo_ss7_is_config_node(vty, node))
+ return 1;
+
switch (node) {
/* add items that are not config */
case OML_NODE:
diff --git a/src/libcommon/debug.c b/src/libcommon/debug.c
index 7dbbc6ac0..723641335 100644
--- a/src/libcommon/debug.c
+++ b/src/libcommon/debug.c
@@ -189,6 +189,12 @@ static const struct log_info_cat default_categories[] = {
.description = "Iu-CS Protocol",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
+ [DSIGTRAN] = {
+ .name = "DSIGTRAN",
+ .description = "SIGTRAN Signalling Transport",
+ .color = "\033[1;29m",
+ .enabled = 1, .loglevel = LOGL_DEBUG,
+ },
};
static int filter_fn(const struct log_context *ctx, struct log_target *tar)
diff --git a/src/libiu/iu.c b/src/libiu/iu.c
index 5d56a4a37..779497745 100644
--- a/src/libiu/iu.c
+++ b/src/libiu/iu.c
@@ -36,9 +36,10 @@
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gprs/gprs_msgb.h>
-#include <osmocom/sigtran/sua.h>
+#include <osmocom/sigtran/osmo_ss7.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/sigtran/sccp_helpers.h>
+#include <osmocom/sigtran/protocol/m3ua.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/iu.h>
@@ -63,7 +64,7 @@ struct iu_grnc_id {
};
/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has
- * called us and is currently reachable at the given osmo_sccp_link. So, when we
+ * called us and is currently reachable at the given osmo_sccp_addr. So, when we
* know a LAC for a subscriber, we can page it at the RNC matching that LAC or
* RAC. An HNB-GW typically presents itself as if it were a single RNC, even
* though it may have several RNCs in hNodeBs connected to it. Those will then
@@ -75,7 +76,7 @@ struct iu_rnc {
uint16_t rnc_id;
uint16_t lac; /* Location Area Code (used for CS and PS) */
uint8_t rac; /* Routing Area Code (used for PS only) */
- struct osmo_sccp_link *link;
+ struct osmo_sccp_addr sccp_addr;
};
void *talloc_iu_ctx;
@@ -97,6 +98,9 @@ iu_event_cb_t global_iu_event_cb = NULL;
static LLIST_HEAD(ue_conn_ctx_list);
static LLIST_HEAD(rnc_list);
+static struct osmo_sccp_instance *g_sccp;
+static struct osmo_sccp_user *g_scu;
+
const struct value_string iu_event_type_names[] = {
OSMO_VALUE_STRING(IU_EVENT_RAB_ASSIGN),
OSMO_VALUE_STRING(IU_EVENT_SECURITY_MODE_COMPLETE),
@@ -105,38 +109,37 @@ const struct value_string iu_event_type_names[] = {
{ 0, NULL }
};
-struct ue_conn_ctx *ue_conn_ctx_alloc(struct osmo_sccp_link *link, uint32_t conn_id)
+struct ue_conn_ctx *ue_conn_ctx_alloc(struct osmo_sccp_addr *addr, uint32_t conn_id)
{
struct ue_conn_ctx *ctx = talloc_zero(talloc_iu_ctx, struct ue_conn_ctx);
- ctx->link = link;
+ ctx->sccp_addr = *addr;
ctx->conn_id = conn_id;
llist_add(&ctx->list, &ue_conn_ctx_list);
return ctx;
}
-struct ue_conn_ctx *ue_conn_ctx_find(struct osmo_sccp_link *link,
- uint32_t conn_id)
+struct ue_conn_ctx *ue_conn_ctx_find(uint32_t conn_id)
{
struct ue_conn_ctx *ctx;
llist_for_each_entry(ctx, &ue_conn_ctx_list, list) {
- if (ctx->link == link && ctx->conn_id == conn_id)
+ if (ctx->conn_id == conn_id)
return ctx;
}
return NULL;
}
static struct iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac,
- struct osmo_sccp_link *link)
+ struct osmo_sccp_addr *addr)
{
struct iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct iu_rnc);
rnc->rnc_id = rnc_id;
rnc->lac = lac;
rnc->rac = rac;
- rnc->link = link;
+ rnc->sccp_addr = *addr;
llist_add(&rnc->entry, &rnc_list);
LOGP(DRANAP, LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n",
@@ -146,7 +149,7 @@ static struct iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac,
}
static struct iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac,
- uint8_t rac, struct osmo_sccp_link *link)
+ uint8_t rac, struct osmo_sccp_addr *addr)
{
struct iu_rnc *rnc;
llist_for_each_entry(rnc, &rnc_list, entry) {
@@ -165,42 +168,16 @@ static struct iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac,
rnc->lac = lac;
rnc->rac = rac;
- if (link && rnc->link != link)
- LOGP(DRANAP, LOGL_NOTICE, "RNC %d on new link"
+ if (addr && memcmp(&rnc->sccp_addr, addr, sizeof(*addr)))
+ LOGP(DRANAP, LOGL_NOTICE, "RNC %d on New SCCP Addr %s"
" (LAC=%d RAC=%d)\n",
- rnc->rnc_id, rnc->lac, rnc->rac);
- rnc->link = link;
+ rnc->rnc_id, osmo_sccp_addr_dump(addr), rnc->lac, rnc->rac);
+ rnc->sccp_addr = *addr;
return rnc;
}
/* Not found, make a new one. */
- return iu_rnc_alloc(rnc_id, lac, rac, link);
-}
-
-/* Discard/invalidate all ue_conn_ctx and iu_rnc entries that reference the
- * given link, since this link is invalid and about to be deallocated. For
- * each ue_conn_ctx, invoke the iu_event_cb_t with IU_EVENT_LINK_INVALIDATED.
- */
-void iu_link_del(struct osmo_sccp_link *link)
-{
- struct iu_rnc *rnc, *rnc_next;
- llist_for_each_entry_safe(rnc, rnc_next, &rnc_list, entry) {
- if (!rnc->link)
- continue;
- if (rnc->link != link)
- continue;
- rnc->link = NULL;
- llist_del(&rnc->entry);
- talloc_free(rnc);
- }
-
- struct ue_conn_ctx *uec, *uec_next;
- llist_for_each_entry_safe(uec, uec_next, &ue_conn_ctx_list, list) {
- if (uec->link != link)
- continue;
- uec->link = NULL;
- global_iu_event_cb(uec, IU_EVENT_LINK_INVALIDATED, NULL);
- }
+ return iu_rnc_alloc(rnc_id, lac, rac, addr);
}
/***********************************************************************
@@ -219,7 +196,7 @@ int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg)
OSMO_SCU_PRIM_N_DATA,
PRIM_OP_REQUEST,
msg);
- return osmo_sua_user_link_down(ue_ctx->link, &prim->oph);
+ return osmo_sccp_user_sap_down(g_scu, &prim->oph);
}
int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id)
@@ -244,7 +221,7 @@ int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp,
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
OSMO_SCU_PRIM_N_DATA,
PRIM_OP_REQUEST, msg);
- osmo_sua_user_link_down(uectx->link, &prim->oph);
+ osmo_sccp_user_sap_down(g_scu, &prim->oph);
return 0;
}
@@ -254,8 +231,8 @@ int iu_tx_common_id(struct ue_conn_ctx *uectx, const char *imsi)
struct msgb *msg;
struct osmo_scu_prim *prim;
- LOGP(DRANAP, LOGL_INFO, "Transmitting RANAP CommonID (SUA link %p conn_id %u)\n",
- uectx->link, uectx->conn_id);
+ LOGP(DRANAP, LOGL_INFO, "Transmitting RANAP CommonID (SCCP conn_id %u)\n",
+ uectx->conn_id);
msg = ranap_new_msg_common_id(imsi);
msg->l2h = msg->data;
@@ -264,7 +241,7 @@ int iu_tx_common_id(struct ue_conn_ctx *uectx, const char *imsi)
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
OSMO_SCU_PRIM_N_DATA,
PRIM_OP_REQUEST, msg);
- osmo_sua_user_link_down(uectx->link, &prim->oph);
+ osmo_sccp_user_sap_down(g_scu, &prim->oph);
return 0;
}
@@ -325,7 +302,7 @@ static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *i
memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size);
/* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */
- iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, ue_conn->link);
+ iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, &ue_conn->sccp_addr);
ue_conn->ra_id = ra_id;
/* Feed into the MM layer */
@@ -387,8 +364,8 @@ int iu_tx(struct msgb *msg_nas, uint8_t sapi)
struct msgb *msg;
struct osmo_scu_prim *prim;
- LOGP(DRANAP, LOGL_INFO, "Transmitting L3 Message as RANAP DT (SUA link %p conn_id %u)\n",
- uectx->link, uectx->conn_id);
+ LOGP(DRANAP, LOGL_INFO, "Transmitting L3 Message as RANAP DT (SCCP conn_id %u)\n",
+ uectx->conn_id);
msg = ranap_new_msg_dt(sapi, msg_nas->data, msgb_length(msg_nas));
msgb_free(msg_nas);
@@ -398,7 +375,7 @@ int iu_tx(struct msgb *msg_nas, uint8_t sapi)
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
OSMO_SCU_PRIM_N_DATA,
PRIM_OP_REQUEST, msg);
- osmo_sua_user_link_down(uectx->link, &prim->oph);
+ osmo_sccp_user_sap_down(g_scu, &prim->oph);
return 0;
}
@@ -417,6 +394,9 @@ int iu_tx_release(struct ue_conn_ctx *ctx, const struct RANAP_Cause *cause)
if (!cause)
cause = &default_cause;
+ LOGP(DRANAP, LOGL_INFO, "Transmitting Iu Release (SCCP conn_id %u)\n",
+ ctx->conn_id);
+
msg = ranap_new_msg_iu_rel_cmd(cause);
msg->l2h = msg->data;
prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
@@ -424,7 +404,7 @@ int iu_tx_release(struct ue_conn_ctx *ctx, const struct RANAP_Cause *cause)
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
OSMO_SCU_PRIM_N_DATA,
PRIM_OP_REQUEST, msg);
- return osmo_sua_user_link_down(ctx->link, &prim->oph);
+ return osmo_sccp_user_sap_down(g_scu, &prim->oph);
}
static int ranap_handle_co_iu_rel_req(struct ue_conn_ctx *ctx, RANAP_Iu_ReleaseRequestIEs_t *ies)
@@ -595,21 +575,28 @@ static void cn_ranap_handle_cl(void *ctx, ranap_message *message)
* Paging
***********************************************************************/
-/* Send a paging command down a given SUA link. tmsi and paging_cause are
+struct osmo_sccp_addr local_sccp_addr = {
+ .presence = OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC,
+ .ri = OSMO_SCCP_RI_SSN_PC,
+ .ssn = OSMO_SCCP_SSN_RANAP,
+ .pc = 1,
+};
+
+/* Send a paging command down a given SCCP User. tmsi and paging_cause are
* optional and may be passed NULL and 0, respectively, to disable their use.
* See enum RANAP_PagingCause.
*
* If TMSI is given, the IMSI is not sent over the air interface. Nevertheless,
* the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */
-static int iu_tx_paging_cmd(struct osmo_sccp_link *link,
+static int iu_tx_paging_cmd(struct osmo_sccp_addr *called_addr,
const char *imsi, const uint32_t *tmsi,
bool is_ps, uint32_t paging_cause)
{
struct msgb *msg;
msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps? 1 : 0, paging_cause);
msg->l2h = msg->data;
- return osmo_sccp_tx_unitdata_ranap(link, 1, 2, msg->data,
- msgb_length(msg));
+ osmo_sccp_tx_unitdata_msg(g_scu, &local_sccp_addr, called_addr, msg);
+ return 0;
}
static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi,
@@ -634,22 +621,18 @@ static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi,
}
llist_for_each_entry(rnc, &rnc_list, entry) {
- if (!rnc->link) {
- /* Not actually connected, don't count it. */
- continue;
- }
if (rnc->lac != lac)
continue;
if (is_ps && rnc->rac != rac)
continue;
/* Found a match! */
- if (iu_tx_paging_cmd(rnc->link, imsi, tmsi_or_ptimsi, is_ps, 0)
+ if (iu_tx_paging_cmd(&rnc->sccp_addr, imsi, tmsi_or_ptimsi, is_ps, 0)
== 0) {
LOGP(DRANAP, LOGL_DEBUG,
- "%s: Paged for IMSI %s on RNC %d, on SUA link %p\n",
+ "%s: Paged for IMSI %s on RNC %d, on SCCP addr %s\n",
is_ps? "IuPS" : "IuCS",
- imsi, rnc->rnc_id, rnc->link);
+ imsi, rnc->rnc_id, osmo_sccp_addr_dump(&rnc->sccp_addr));
pagings_sent ++;
}
}
@@ -692,8 +675,8 @@ int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t ra
*
***********************************************************************/
-int tx_unitdata(struct osmo_sccp_link *link);
-int tx_conn_req(struct osmo_sccp_link *link, uint32_t conn_id);
+int tx_unitdata(struct osmo_sccp_user *scu);
+int tx_conn_req(struct osmo_sccp_user *scu, uint32_t conn_id);
struct osmo_prim_hdr *make_conn_req(uint32_t conn_id);
struct osmo_prim_hdr *make_dt1_req(uint32_t conn_id, const uint8_t *data, unsigned int len);
@@ -711,8 +694,9 @@ struct osmo_prim_hdr *make_conn_resp(struct osmo_scu_connect_param *param)
return &prim->oph;
}
-static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link)
+static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
{
+ struct osmo_sccp_user *scu = _scu;
struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;
struct osmo_prim_hdr *resp = NULL;
int rc;
@@ -734,10 +718,10 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link)
"Received invalid N-CONNECT.ind\n");
return 0;
}
- ue = ue_conn_ctx_alloc(link, prim->u.connect.conn_id);
- /* first ensure the local SUA/SCCP socket is ACTIVE */
+ ue = ue_conn_ctx_alloc(&prim->u.connect.calling_addr, prim->u.connect.conn_id);
+ /* first ensure the local SCCP socket is ACTIVE */
resp = make_conn_resp(&prim->u.connect);
- osmo_sua_user_link_down(link, resp);
+ osmo_sccp_user_sap_down(scu, resp);
/* then handle the RANAP payload */
rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
break;
@@ -745,7 +729,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link)
/* indication of disconnect */
DEBUGP(DRANAP, "N-DISCONNECT.ind(%u)\n",
prim->u.disconnect.conn_id);
- ue = ue_conn_ctx_find(link, prim->u.disconnect.conn_id);
+ ue = ue_conn_ctx_find(prim->u.disconnect.conn_id);
rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
@@ -753,14 +737,14 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link)
DEBUGP(DRANAP, "N-DATA.ind(%u, %s)\n", prim->u.data.conn_id,
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
/* resolve UE context */
- ue = ue_conn_ctx_find(link, prim->u.data.conn_id);
+ ue = ue_conn_ctx_find(prim->u.data.conn_id);
rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
/* connection-less data received */
DEBUGP(DRANAP, "N-UNITDATA.ind(%s)\n",
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
- rc = ranap_cn_rx_cl(cn_ranap_handle_cl, link, msgb_l2(oph->msg), msgb_l2len(oph->msg));
+ rc = ranap_cn_rx_cl(cn_ranap_handle_cl, scu, msgb_l2(oph->msg), msgb_l2len(oph->msg));
break;
default:
rc = -1;
@@ -771,17 +755,17 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link)
return rc;
}
-int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port,
+int iu_init(void *ctx, struct osmo_sccp_instance *sccp,
iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb)
{
- struct osmo_sccp_user *user;
talloc_iu_ctx = talloc_named_const(ctx, 1, "iu");
talloc_asn1_ctx = talloc_named_const(talloc_iu_ctx, 1, "asn1");
global_iu_recv_cb = iu_recv_cb;
global_iu_event_cb = iu_event_cb;
- osmo_sua_set_log_area(DSUA);
- user = osmo_sua_user_create(talloc_iu_ctx, sccp_sap_up, talloc_iu_ctx);
- return osmo_sua_server_listen(user, listen_addr, listen_port);
+ g_sccp = sccp;
+ g_scu = osmo_sccp_user_bind(g_sccp, "OsmoMSC-Iu", sccp_sap_up, OSMO_SCCP_SSN_RANAP);
+
+ return 0;
}
diff --git a/src/libiu/iu_vty.c b/src/libiu/iu_vty.c
index 73ad126ba..3fd3cd15c 100644
--- a/src/libiu/iu_vty.c
+++ b/src/libiu/iu_vty.c
@@ -23,6 +23,8 @@
#include <osmocom/core/logging.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/logging.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+#include <osmocom/sigtran/sccp_sap.h>
#include <openbsc/iu.h>
@@ -52,9 +54,10 @@ DEFUN(logging_asn_xer_print,
return CMD_SUCCESS;
}
+#define IU_STR "Iu interface protocol options\n"
DEFUN(cfg_iu_rab_assign_addr_enc, cfg_iu_rab_assign_addr_enc_cmd,
"iu rab-assign-addr-enc (x213|v4raw)",
- "Iu interface protocol options\n"
+ IU_STR
"Choose RAB Assignment's Transport Layer Address encoding\n"
"ITU-T X.213 compliant address encoding (default)\n"
"32bit length raw IPv4 address (for ip.access nano3G)\n")
@@ -72,6 +75,24 @@ DEFUN(cfg_iu_rab_assign_addr_enc, cfg_iu_rab_assign_addr_enc_cmd,
return CMD_SUCCESS;
}
+extern struct osmo_sccp_addr local_sccp_addr;
+
+/* Note from the future: change-id Ib8c4fcdb4766c5e575618b95ce16dce51063206b will move this file to
+ * osmo-iuh, and there, change-id I3bb7fc1cd5261d214c6ba0cccfe95f637e6db087 will drop this vty command
+ * and use the point code defined via libosmo-sccp vty commands instead. */
+DEFUN(cfg_iu_local_addr_pc, cfg_iu_local_addr_pc_cmd,
+ "iu local-address point-code PC",
+ IU_STR "Local SCCP Address\n" "Set local point code\n" "point code\n")
+{
+ local_sccp_addr.presence = OSMO_SCCP_ADDR_T_PC | OSMO_SCCP_ADDR_T_SSN;
+ local_sccp_addr.ri = OSMO_SCCP_RI_SSN_PC;
+ local_sccp_addr.pc = osmo_ss7_pointcode_parse(NULL, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+/* TODO: GT address configuration, in line with 4.5.1.1.1 of TS 25.410 */
+
int iu_vty_config_write(struct vty *vty, const char *indent)
{
if (!g_rab_assign_addr_enc) {
@@ -95,6 +116,9 @@ int iu_vty_config_write(struct vty *vty, const char *indent)
return CMD_WARNING;
}
+ vty_out(vty, "%siu local-address point-code %s%s", indent,
+ osmo_ss7_pointcode_print(NULL, local_sccp_addr.pc), VTY_NEWLINE);
+
return CMD_SUCCESS;
}
@@ -105,4 +129,5 @@ void iu_vty_init(int iu_parent_node, enum nsap_addr_enc *rab_assign_addr_enc)
install_element(CFG_LOG_NODE, &logging_asn_debug_cmd);
install_element(CFG_LOG_NODE, &logging_asn_xer_print_cmd);
install_element(iu_parent_node, &cfg_iu_rab_assign_addr_enc_cmd);
+ install_element(iu_parent_node, &cfg_iu_local_addr_pc_cmd);
}
diff --git a/src/libmgcp/mgcp_protocol.c b/src/libmgcp/mgcp_protocol.c
index 96542c5a0..c8b6e8660 100644
--- a/src/libmgcp/mgcp_protocol.c
+++ b/src/libmgcp/mgcp_protocol.c
@@ -66,6 +66,45 @@ static int setup_rtp_processing(struct mgcp_endpoint *endp);
static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data);
+/* Display an mgcp message on the log output */
+void display_mgcp_message(unsigned char *message, unsigned int len,
+ char *preamble)
+{
+ unsigned char line[80];
+ unsigned char *ptr;
+ unsigned int consumed = 0;
+ unsigned int consumed_line = 0;
+ unsigned int line_count = 0;
+
+ if (!log_check_level(DMGCP, LOGL_DEBUG))
+ return;
+
+ while (1) {
+ memset(line, 0, sizeof(line));
+ ptr = line;
+ consumed_line = 0;
+ do {
+ if (*message != '\n' && *message != '\r') {
+ *ptr = *message;
+ ptr++;
+ }
+ message++;
+ consumed++;
+ consumed_line++;
+ } while (*message != '\n' && consumed < len
+ && consumed_line < sizeof(line));
+
+ if (strlen((const char *)line)) {
+ LOGP(DMGCP, LOGL_DEBUG, "%s: line #%02u: %s\n",
+ preamble, line_count, line);
+ line_count++;
+ }
+
+ if (consumed >= len)
+ return;
+ }
+}
+
static int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
{
const size_t line_len = strlen(line);
@@ -157,7 +196,8 @@ static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
}
res->l2h = msgb_put(res, len);
- LOGP(DMGCP, LOGL_DEBUG, "Generated response: code: %d for '%s'\n", code, res->l2h);
+ LOGP(DMGCP, LOGL_DEBUG, "Generated response: code=%d\n", code);
+ display_mgcp_message(res->l2h, msgb_l2len(res), "Generated response");
/*
* Remember the last transmission per endpoint.
@@ -329,6 +369,8 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
if (mgcp_msg_terminate_nul(msg))
return NULL;
+ display_mgcp_message(msg->l2h, msgb_l2len(msg), "Received message");
+
/* attempt to treat it as a response */
if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
diff --git a/src/libmgcp/mgcpgw_client.c b/src/libmgcp/mgcpgw_client.c
index 9f0c84de2..1910a9f35 100644
--- a/src/libmgcp/mgcpgw_client.c
+++ b/src/libmgcp/mgcpgw_client.c
@@ -35,15 +35,6 @@
#include <unistd.h>
#include <string.h>
-struct mgcpgw_client {
- struct mgcpgw_client_conf actual;
- uint32_t remote_addr;
- struct osmo_wqueue wq;
- mgcp_trans_id_t next_trans_id;
- uint16_t next_endpoint;
- struct llist_head responses_pending;
-};
-
void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf)
{
/* NULL and -1 default to MGCPGW_CLIENT_*_DEFAULT values */
@@ -52,12 +43,68 @@ void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf)
.local_port = -1,
.remote_addr = NULL,
.remote_port = -1,
+ .first_endpoint = 0,
+ .last_endpoint = 0,
+ .bts_base = 0,
};
}
-unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client)
+/* Test if a given endpoint id is currently in use */
+static bool endpoint_in_use(uint16_t id, struct mgcpgw_client *client)
{
- return client->next_endpoint ++;
+ struct mgcp_inuse_endpoint *endpoint;
+ llist_for_each_entry(endpoint, &client->inuse_endpoints, entry) {
+ if (endpoint->id == id)
+ return true;
+ }
+
+ return false;
+}
+
+/* Find and seize an unsused endpoint id */
+int mgcpgw_client_next_endpoint(struct mgcpgw_client *client)
+{
+ int i;
+ uint16_t first_endpoint = client->actual.first_endpoint;
+ uint16_t last_endpoint = client->actual.last_endpoint;
+ struct mgcp_inuse_endpoint *endpoint;
+
+ /* Use the maximum permitted range if the VTY
+ * configuration does not specify a range */
+ if (client->actual.last_endpoint == 0) {
+ first_endpoint = 1;
+ last_endpoint = 65534;
+ }
+
+ /* Test the permitted endpoint range for an endpoint
+ * number that is not in use. When a suitable endpoint
+ * number can be found, seize it by adding it to the
+ * inuse list. */
+ for (i=first_endpoint;i<last_endpoint;i++)
+ {
+ if (endpoint_in_use(i,client) == false) {
+ endpoint = talloc_zero(client, struct mgcp_inuse_endpoint);
+ endpoint->id = i;
+ llist_add_tail(&endpoint->entry, &client->inuse_endpoints);
+ return endpoint->id;
+ }
+ }
+
+ /* All endpoints are busy! */
+ return -EINVAL;
+}
+
+/* Release a seized endpoint id to make it available again for other calls */
+void mgcpgw_client_release_endpoint(uint16_t id, struct mgcpgw_client *client)
+{
+ struct mgcp_inuse_endpoint *endpoint;
+ struct mgcp_inuse_endpoint *endpoint_tmp;
+ llist_for_each_entry_safe(endpoint, endpoint_tmp, &client->inuse_endpoints, entry) {
+ if (endpoint->id == id) {
+ llist_del(&endpoint->entry);
+ talloc_free(endpoint);
+ }
+ }
}
static void mgcpgw_client_handle_response(struct mgcpgw_client *mgcp,
@@ -257,9 +304,16 @@ static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
{
int ret;
static char strbuf[4096];
- unsigned int l = msg->len < sizeof(strbuf)-1 ? msg->len : sizeof(strbuf)-1;
+ unsigned int l = msg->len < sizeof(strbuf) ? msg->len : sizeof(strbuf);
+ unsigned int i;
+
strncpy(strbuf, (const char*)msg->data, l);
- strbuf[l] = '\0';
+ for (i = 0; i < sizeof(strbuf); i++) {
+ if (strbuf[i] == '\n' || strbuf[i] == '\r') {
+ strbuf[i] = '\0';
+ break;
+ }
+ }
DEBUGP(DMGCP, "Tx MGCP msg to MGCP GW: '%s'\n", strbuf);
LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
@@ -280,9 +334,9 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx,
mgcp = talloc_zero(ctx, struct mgcpgw_client);
INIT_LLIST_HEAD(&mgcp->responses_pending);
+ INIT_LLIST_HEAD(&mgcp->inuse_endpoints);
mgcp->next_trans_id = 1;
- mgcp->next_endpoint = 1;
mgcp->actual.local_addr = conf->local_addr ? conf->local_addr :
MGCPGW_CLIENT_LOCAL_ADDR_DEFAULT;
@@ -294,6 +348,10 @@ struct mgcpgw_client *mgcpgw_client_init(void *ctx,
mgcp->actual.remote_port = conf->remote_port >= 0 ? (uint16_t)conf->remote_port :
MGCPGW_CLIENT_REMOTE_PORT_DEFAULT;
+ mgcp->actual.first_endpoint = conf->first_endpoint > 0 ? (uint16_t)conf->first_endpoint : 0;
+ mgcp->actual.last_endpoint = conf->last_endpoint > 0 ? (uint16_t)conf->last_endpoint : 0;
+ mgcp->actual.bts_base = conf->bts_base > 0 ? (uint16_t)conf->bts_base : 4000;
+
return mgcp;
}
@@ -547,3 +605,12 @@ struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
rtp_conn_addr,
rtp_port);
}
+
+struct msgb *mgcp_msg_dlcx(struct mgcpgw_client *mgcp, uint16_t rtp_endpoint,
+ unsigned int call_id)
+{
+ mgcp_trans_id_t trans_id = mgcpgw_client_next_trans_id(mgcp);
+ return mgcp_msg_from_str(trans_id,
+ "DLCX %u %x@mgw MGCP 1.0\r\n"
+ "C: %x\r\n", trans_id, rtp_endpoint, call_id);
+}
diff --git a/src/libmgcp/mgcpgw_client_vty.c b/src/libmgcp/mgcpgw_client_vty.c
index a42ee4e5d..806800078 100644
--- a/src/libmgcp/mgcpgw_client_vty.c
+++ b/src/libmgcp/mgcpgw_client_vty.c
@@ -79,10 +79,46 @@ DEFUN(cfg_mgcpgw_remote_port, cfg_mgcpgw_remote_port_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_mgcpgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
+ "mgcpgw endpoint-range <1-65534> <1-65534>",
+ MGCPGW_STR "usable range of endpoint identifiers\n"
+ "set first useable endpoint identifier\n"
+ "set the last useable endpoint identifier\n")
+{
+ uint16_t first_endpoint = atoi(argv[0]);
+ uint16_t last_endpoint = atoi(argv[1]);
+
+ if (last_endpoint < first_endpoint) {
+ vty_out(vty, "last endpoint must be greater than first endpoint!%s",
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ global_mgcpgw_client_conf->first_endpoint = first_endpoint;
+ global_mgcpgw_client_conf->last_endpoint = last_endpoint;
+ return CMD_SUCCESS;
+}
+
+#define BTS_START_STR "First UDP port allocated for the BTS side\n"
+#define UDP_PORT_STR "UDP Port number\n"
+DEFUN(cfg_mgcp_rtp_bts_base_port,
+ cfg_mgcp_rtp_bts_base_port_cmd,
+ "mgcpgw bts-base <0-65534>",
+ MGCPGW_STR
+ BTS_START_STR
+ UDP_PORT_STR)
+{
+ global_mgcpgw_client_conf->bts_base = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
int mgcpgw_client_config_write(struct vty *vty, const char *indent)
{
const char *addr;
int port;
+ uint16_t first_endpoint;
+ uint16_t last_endpoint;
+ uint16_t bts_base;
addr = global_mgcpgw_client_conf->local_addr;
if (addr)
@@ -102,6 +138,19 @@ int mgcpgw_client_config_write(struct vty *vty, const char *indent)
vty_out(vty, "%smgcpgw remote-port %u%s", indent,
(uint16_t)port, VTY_NEWLINE);
+ first_endpoint = global_mgcpgw_client_conf->first_endpoint;
+ last_endpoint = global_mgcpgw_client_conf->last_endpoint;
+ if (last_endpoint != 0) {
+ vty_out(vty, "%smgcpgw endpoint-range %u %u%s", indent,
+ first_endpoint, last_endpoint, VTY_NEWLINE);
+ }
+
+ bts_base = global_mgcpgw_client_conf->bts_base;
+ if (bts_base) {
+ vty_out(vty, "%smgcpgw bts-base %u%s", indent,
+ bts_base, VTY_NEWLINE);
+ }
+
return CMD_SUCCESS;
}
@@ -113,4 +162,6 @@ void mgcpgw_client_vty_init(int node, struct mgcpgw_client_conf *conf)
install_element(node, &cfg_mgcpgw_local_port_cmd);
install_element(node, &cfg_mgcpgw_remote_ip_cmd);
install_element(node, &cfg_mgcpgw_remote_port_cmd);
+ install_element(node, &cfg_mgcpgw_endpoint_range_cmd);
+ install_element(node, &cfg_mgcp_rtp_bts_base_port_cmd);
}
diff --git a/src/libmsc/Makefile.am b/src/libmsc/Makefile.am
index 4726bbe4b..9f246b3d8 100644
--- a/src/libmsc/Makefile.am
+++ b/src/libmsc/Makefile.am
@@ -13,6 +13,7 @@ AM_CFLAGS = \
$(LIBCRYPTO_CFLAGS) \
$(LIBSMPP34_CFLAGS) \
$(LIBASN1C_CFLAGS) \
+ $(LIBOSMOSIGTRAN_CFLAGS) \
$(NULL)
noinst_HEADERS = \
@@ -25,6 +26,7 @@ noinst_LIBRARIES = \
libmsc_a_SOURCES = \
a_iface.c \
+ a_iface_bssap.c \
auth.c \
msc_vty.c \
db.c \
diff --git a/src/libmsc/a_iface.c b/src/libmsc/a_iface.c
index caf9d4b06..93e8ab5e9 100644
--- a/src/libmsc/a_iface.c
+++ b/src/libmsc/a_iface.c
@@ -1,9 +1,8 @@
-/* A-interface implementation, from MSC to BSC */
-
-/* (C) 2016 by sysmocom s.m.f.c GmbH <info@sysmocom.de>
- *
+/* (C) 2017 by sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
+ * Author: Philipp Maier
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
@@ -19,35 +18,574 @@
*
*/
+#include <osmocom/core/utils.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/logging.h>
-
+#include <osmocom/sigtran/sccp_helpers.h>
+#include <osmocom/sigtran/sccp_sap.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+#include <osmocom/sigtran/protocol/m3ua.h>
+#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/gsm0808_utils.h>
#include <openbsc/debug.h>
-
-#include <openbsc/gsm_data.h>
#include <openbsc/msc_ifaces.h>
-#include <openbsc/debug.h>
+#include <openbsc/a_iface.h>
+#include <openbsc/a_iface_bssap.h>
+#include <openbsc/transaction.h>
+#include <openbsc/mgcpgw_client.h>
+#include <osmocom/core/byteswap.h>
+#include <osmocom/sccp/sccp_types.h>
+#include <openbsc/a_reset.h>
+#include <openbsc/osmo_msc.h>
+
+/* A pointer to the GSM network we work with. By the current paradigm,
+ * there can only be one gsm_network per MSC. The pointer is set once
+ * when calling a_init() */
+static struct gsm_network *gsm_network = NULL;
+
+/* A struct to track currently active connections. We need that information
+ * to handle failure sitautions. In case of a problem, we must know which
+ * connections are currently open and which BSC is responsible. We also need
+ * the data to perform our connection checks (a_reset). All other logic will
+ * look at the connection ids and addresses that are supplied by the
+ * primitives */
+struct bsc_conn {
+ struct llist_head list;
+ uint32_t conn_id; /* Connection identifier */
+};
+
+/* Internal list with connections we currently maintain. This
+ * list is of type struct bsc_conn (see above) */
+static LLIST_HEAD(active_connections);
+
+/* Record info of a new active connection in the active connection list */
+static void record_bsc_con(const void *ctx, uint32_t conn_id)
+{
+ struct bsc_conn *conn;
+
+ conn = talloc_zero(ctx, struct bsc_conn);
+ OSMO_ASSERT(conn);
+
+ conn->conn_id = conn_id;
+
+ llist_add_tail(&conn->list, &active_connections);
+}
+
+/* Delete info of a closed connection from the active connection list */
+void a_delete_bsc_con(uint32_t conn_id)
+{
+ struct bsc_conn *conn;
+ struct bsc_conn *conn_temp;
+
+ LOGP(DMSC, LOGL_DEBUG,
+ "Removing connection from active sccp-connection list (conn_id=%i)\n",
+ conn_id);
+
+ llist_for_each_entry_safe(conn, conn_temp, &active_connections, list) {
+ if (conn->conn_id == conn_id) {
+ llist_del(&conn->list);
+ talloc_free(conn);
+ }
+ }
+}
+
+/* Check if a specified connection id has an active SCCP connection */
+static bool check_connection_active(uint32_t conn_id)
+{
+ struct bsc_conn *conn;
+
+ /* Find the address for the current connection id */
+ llist_for_each_entry(conn, &active_connections, list) {
+ if (conn->conn_id == conn_id) {
+ return true;
+ }
+ }
+
+ return false;
+}
-int a_tx(struct msgb *msg)
+/* Get the reset context for a specifiec calling (BSC) address */
+static struct a_reset_ctx *get_reset_ctx_by_sccp_addr(const struct osmo_sccp_addr *addr)
{
- 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;
+ struct bsc_context *bsc_ctx;
+ struct osmo_ss7_instance *ss7;
+
+ if (!addr)
+ return NULL;
+
+ llist_for_each_entry(bsc_ctx, &gsm_network->a.bscs, list) {
+ if (memcmp(&bsc_ctx->bsc_addr, addr, sizeof(*addr)) == 0)
+ return bsc_ctx->reset;
+ }
+
+ ss7 = osmo_ss7_instance_find(gsm_network->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+ LOGP(DMSC, LOGL_ERROR, "The calling BSC (%s) is unknown to this MSC ...\n",
+ osmo_sccp_addr_name(ss7, addr));
+ return NULL;
}
-int a_page(const char *imsi, uint32_t tmsi, uint16_t lac)
+/* Send DTAP message via A-interface */
+int a_iface_tx_dtap(struct msgb *msg)
{
- LOGP(DMSC, LOGL_ERROR, "Paging to be sent to BSC, but A-interface"
- " not implemented: IMSI %s TMSI 0x%08x LAC %u\n",
- imsi, tmsi, lac);
- return -1;
+ struct gsm_subscriber_connection *conn;
+ struct msgb *msg_resp;
+
+ /* FIXME: Set this to some meaninful value! */
+ uint8_t link_id = 0x00;
+ OSMO_ASSERT(msg);
+ conn = (struct gsm_subscriber_connection *)msg->dst;
+ OSMO_ASSERT(conn);
+ OSMO_ASSERT(conn->a.scu);
+
+ LOGP(DMSC, LOGL_DEBUG, "Passing DTAP message from MSC to BSC (conn_id=%i)\n", conn->a.conn_id);
+
+ msg->l3h = msg->data;
+ msg_resp = gsm0808_create_dtap(msg, link_id);
+ if (!msg_resp) {
+ LOGP(DMSC, LOGL_ERROR, "Unable to generate BSSMAP DTAP message!\n");
+ return -EINVAL;
+ } else
+ LOGP(DMSC, LOGL_DEBUG, "Massage will be sent as BSSMAP DTAP message!\n");
+
+ LOGP(DMSC, LOGL_DEBUG, "N-DATA.req(%u, %s)\n", conn->a.conn_id, osmo_hexdump(msg_resp->data, msg_resp->len));
+ return osmo_sccp_tx_data_msg(conn->a.scu, conn->a.conn_id, msg_resp);
}
-int msc_gsm0808_tx_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
- const uint8_t *key, int len, int include_imeisv)
+/* Send Cipher mode command via A-interface */
+int a_iface_tx_cipher_mode(const struct gsm_subscriber_connection *conn,
+ int cipher, const 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;
+ struct msgb *msg_resp;
+ struct gsm0808_encrypt_info ei;
+
+ OSMO_ASSERT(conn);
+
+ LOGP(DMSC, LOGL_DEBUG, "Passing Cipher mode command message from MSC to BSC (conn_id=%i)\n", conn->a.conn_id);
+ uint8_t crm = 0x01;
+ uint8_t *crm_ptr = NULL;
+
+ /* Setup encryption information */
+ if (len > ENCRY_INFO_KEY_MAXLEN || !key) {
+ LOGP(DMSC, LOGL_ERROR,
+ "Cipher mode command message could not be generated due to invalid key! (conn_id=%i)\n",
+ conn->a.conn_id);
+ return -EINVAL;
+ } else {
+ memcpy(&ei.key, key, len);
+ ei.key_len = len;
+ }
+
+ if (include_imeisv)
+ crm_ptr = &crm;
+
+ ei.perm_algo[0] = (uint8_t) (1 << cipher);
+ ei.perm_algo_len = 1;
+
+ msg_resp = gsm0808_create_cipher(&ei, crm_ptr);
+ LOGP(DMSC, LOGL_DEBUG, "N-DATA.req(%u, %s)\n", conn->a.conn_id, osmo_hexdump(msg_resp->data, msg_resp->len));
+
+ return osmo_sccp_tx_data_msg(conn->a.scu, conn->a.conn_id, msg_resp);
+}
+
+/* Page a subscriber via A-interface */
+int a_iface_tx_paging(const char *imsi, uint32_t tmsi, uint16_t lac)
+{
+ struct bsc_context *bsc_ctx;
+ struct gsm0808_cell_id_list cil;
+ struct msgb *msg;
+ int page_count = 0;
+ struct osmo_ss7_instance *ss7;
+
+ OSMO_ASSERT(imsi);
+
+ cil.id_discr = CELL_IDENT_LAC;
+ cil.id_list_lac[0] = lac;
+ cil.id_list_len = 1;
+
+ ss7 = osmo_ss7_instance_find(gsm_network->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+
+ /* Deliver paging request to all known BSCs */
+ llist_for_each_entry(bsc_ctx, &gsm_network->a.bscs, list) {
+ if (a_reset_conn_ready(bsc_ctx->reset)) {
+ LOGP(DMSC, LOGL_DEBUG,
+ "Passing paging message from MSC %s to BSC %s (imsi=%s, tmsi=0x%08x, lac=%u)\n",
+ osmo_sccp_addr_name(ss7, &bsc_ctx->msc_addr),
+ osmo_sccp_addr_name(ss7, &bsc_ctx->bsc_addr), imsi, tmsi, lac);
+ msg = gsm0808_create_paging(imsi, &tmsi, &cil, NULL);
+ osmo_sccp_tx_unitdata_msg(bsc_ctx->sccp_user,
+ &bsc_ctx->msc_addr, &bsc_ctx->bsc_addr, msg);
+ page_count++;
+ } else {
+ LOGP(DMSC, LOGL_DEBUG,
+ "Connection down, dropping paging from MSC %s to BSC %s (imsi=%s, tmsi=0x%08x, lac=%u)\n",
+ osmo_sccp_addr_name(ss7, &bsc_ctx->msc_addr),
+ osmo_sccp_addr_name(ss7, &bsc_ctx->bsc_addr), imsi, tmsi, lac);
+ }
+ }
+
+ if (page_count <= 0)
+ LOGP(DMSC, LOGL_ERROR, "Could not deliver paging because none of the associated BSCs is available!\n");
+
+ return page_count;
+}
+
+/* Convert speech version field */
+static uint8_t convert_Abis_sv_to_A_sv(int speech_ver)
+{
+ /* The speech versions that are transmitted in the Bearer capability
+ * information element, that is transmitted on the Abis interfece
+ * use a different encoding than the permitted speech version
+ * identifier, that is signalled in the channel type element on the A
+ * interface. (See also 3GPP TS 48.008, 3.2.2.1 and 3GPP TS 24.008,
+ * 10.5.103 */
+
+ switch (speech_ver) {
+ case GSM48_BCAP_SV_FR:
+ return GSM0808_PERM_FR1;
+ break;
+ case GSM48_BCAP_SV_HR:
+ return GSM0808_PERM_HR1;
+ break;
+ case GSM48_BCAP_SV_EFR:
+ return GSM0808_PERM_FR2;
+ break;
+ case GSM48_BCAP_SV_AMR_F:
+ return GSM0808_PERM_FR3;
+ break;
+ case GSM48_BCAP_SV_AMR_H:
+ return GSM0808_PERM_HR3;
+ break;
+ case GSM48_BCAP_SV_AMR_OFW:
+ return GSM0808_PERM_FR4;
+ break;
+ case GSM48_BCAP_SV_AMR_OHW:
+ return GSM0808_PERM_HR4;
+ break;
+ case GSM48_BCAP_SV_AMR_FW:
+ return GSM0808_PERM_FR5;
+ break;
+ case GSM48_BCAP_SV_AMR_OH:
+ return GSM0808_PERM_HR6;
+ break;
+ }
+
+ /* If nothing matches, tag the result as invalid */
+ LOGP(DMSC, LOGL_ERROR, "Invalid permitted speech version / rate detected, discarding.\n");
+ return 0xFF;
+}
+
+/* Convert speech preference field */
+static uint8_t convert_Abis_prev_to_A_pref(int radio)
+{
+ /* The Radio channel requirement field that is transmitted in the
+ * Bearer capability information element, that is transmitted on the
+ * Abis interfece uses a different encoding than the Channel rate and
+ * type field that is signalled in the channel type element on the A
+ * interface. (See also 3GPP TS 48.008, 3.2.2.1 and 3GPP TS 24.008,
+ * 10.5.102 */
+
+ switch (radio) {
+ case GSM48_BCAP_RRQ_FR_ONLY:
+ return GSM0808_SPEECH_FULL_BM;
+ case GSM48_BCAP_RRQ_DUAL_FR:
+ return GSM0808_SPEECH_FULL_PREF;
+ case GSM48_BCAP_RRQ_DUAL_HR:
+ return GSM0808_SPEECH_HALF_PREF;
+ }
+
+ LOGP(DMSC, LOGL_ERROR, "Invalid speech version / rate combination preference, defaulting to full rate.\n");
+ return GSM0808_SPEECH_FULL_BM;
+}
+
+/* Assemble the channel type field */
+static int enc_channel_type(struct gsm0808_channel_type *ct, const struct gsm_mncc_bearer_cap *bc)
+{
+ unsigned int i;
+ uint8_t sv;
+ unsigned int count = 0;
+ bool only_gsm_hr = true;
+
+ OSMO_ASSERT(ct);
+ OSMO_ASSERT(bc);
+
+ ct->ch_indctr = GSM0808_CHAN_SPEECH;
+
+ for (i = 0; i < ARRAY_SIZE(bc->speech_ver); i++) {
+ if (bc->speech_ver[i] == -1)
+ break;
+ sv = convert_Abis_sv_to_A_sv(bc->speech_ver[i]);
+ if (sv != 0xFF) {
+ /* Detect if something else than
+ * GSM HR V1 is supported */
+ if (sv == GSM0808_PERM_HR2 ||
+ sv == GSM0808_PERM_HR3 || sv == GSM0808_PERM_HR4 || sv == GSM0808_PERM_HR6)
+ only_gsm_hr = false;
+
+ ct->perm_spch[count] = sv;
+ count++;
+ }
+ }
+ ct->perm_spch_len = count;
+
+ if (only_gsm_hr)
+ /* Note: We must avoid the usage of GSM HR1 as this
+ * codec only offers very poor audio quality. If the
+ * MS only supports GSM HR1 (and full rate), and has
+ * a preference for half rate. Then we will ignore the
+ * preference and assume a preference for full rate. */
+ ct->ch_rate_type = GSM0808_SPEECH_FULL_BM;
+ else
+ ct->ch_rate_type = convert_Abis_prev_to_A_pref(bc->radio);
+
+ if (count)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+/* Assemble the speech codec field */
+static int enc_speech_codec_list(struct gsm0808_speech_codec_list *scl, const struct gsm0808_channel_type *ct)
+{
+ unsigned int i;
+ int rc;
+
+ memset(scl, 0, sizeof(*scl));
+ for (i = 0; i < ct->perm_spch_len; i++) {
+ rc = gsm0808_speech_codec_from_chan_type(&scl->codec[i], ct->perm_spch[i]);
+ if (rc != 0)
+ return -EINVAL;
+ }
+ scl->len = i;
+
+ return 0;
+}
+
+/* Send assignment request via A-interface */
+int a_iface_tx_assignment(const struct gsm_trans *trans)
+{
+ struct gsm_subscriber_connection *conn;
+ struct gsm0808_channel_type ct;
+ struct gsm0808_speech_codec_list scl;
+ uint32_t *ci_ptr = NULL;
+ struct msgb *msg;
+ struct sockaddr_storage rtp_addr;
+ struct sockaddr_in rtp_addr_in;
+ int rc;
+
+ OSMO_ASSERT(trans);
+ conn = trans->conn;
+ OSMO_ASSERT(conn);
+
+ LOGP(DMSC, LOGL_ERROR, "Sending assignment command to BSC (conn_id %u)\n", conn->a.conn_id);
+
+ /* Channel type */
+ rc = enc_channel_type(&ct, &trans->bearer_cap);
+ if (rc < 0) {
+ LOGP(DMSC, LOGL_ERROR, "Faild to generate channel type -- assignment not sent!\n");
+ return -EINVAL;
+ }
+
+ /* Speech codec list */
+ rc = enc_speech_codec_list(&scl, &ct);
+ if (rc < 0) {
+ LOGP(DMSC, LOGL_ERROR, "Faild to generate Speech codec list -- assignment not sent!\n");
+ return -EINVAL;
+ }
+
+ /* Package RTP-Address data */
+ memset(&rtp_addr_in, 0, sizeof(rtp_addr_in));
+ rtp_addr_in.sin_family = AF_INET;
+ rtp_addr_in.sin_port = osmo_htons(conn->rtp.port_subscr);
+ rtp_addr_in.sin_addr.s_addr = osmo_htonl(mgcpgw_client_remote_addr_n(gsm_network->mgcpgw.client));
+
+ memset(&rtp_addr, 0, sizeof(rtp_addr));
+ memcpy(&rtp_addr, &rtp_addr_in, sizeof(rtp_addr_in));
+
+ msg = gsm0808_create_ass(&ct, NULL, &rtp_addr, &scl, ci_ptr);
+
+ LOGP(DMSC, LOGL_DEBUG, "N-DATA.req(%u, %s)\n", conn->a.conn_id, osmo_hexdump(msg->data, msg->len));
+ return osmo_sccp_tx_data_msg(conn->a.scu, conn->a.conn_id, msg);
+}
+
+/* Send clear command via A-interface */
+int a_iface_tx_clear_cmd(struct gsm_subscriber_connection *conn)
+{
+ struct msgb *msg;
+
+ LOGP(DMSC, LOGL_NOTICE, "Sending clear command to BSC (conn_id=%u)\n", conn->a.conn_id);
+
+ msg = gsm0808_create_clear_command(GSM0808_CAUSE_CALL_CONTROL);
+ return osmo_sccp_tx_data_msg(conn->a.scu, conn->a.conn_id, msg);
+}
+
+/* Callback function: Close all open connections */
+static void a_reset_cb(const void *priv)
+{
+ struct msgb *msg;
+ struct bsc_context *bsc_ctx = (struct bsc_context*) priv;
+ struct osmo_ss7_instance *ss7;
+
+ /* Skip if the A interface is not properly initalized yet */
+ if (!gsm_network)
+ return;
+
+ /* Clear all now orphaned subscriber connections */
+ a_clear_all(bsc_ctx->sccp_user, &bsc_ctx->bsc_addr);
+
+ /* Send reset to the remote BSC */
+ ss7 = osmo_ss7_instance_find(gsm_network->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+ LOGP(DMSC, LOGL_NOTICE, "Sending RESET to BSC %s\n", osmo_sccp_addr_name(ss7, &bsc_ctx->bsc_addr));
+ msg = gsm0808_create_reset();
+ osmo_sccp_tx_unitdata_msg(bsc_ctx->sccp_user, &bsc_ctx->msc_addr,
+ &bsc_ctx->bsc_addr, msg);
+}
+
+/* Add a new BSC connection to our internal list with known BSCs */
+static void add_bsc(const struct osmo_sccp_addr *msc_addr, const struct osmo_sccp_addr *bsc_addr,
+ struct osmo_sccp_user *scu)
+{
+ struct bsc_context *bsc_ctx;
+ struct osmo_ss7_instance *ss7;
+
+ OSMO_ASSERT(bsc_addr);
+ OSMO_ASSERT(msc_addr);
+ OSMO_ASSERT(scu);
+
+ /* Check if we already know this BSC, if yes, skip adding it. */
+ if (get_reset_ctx_by_sccp_addr(bsc_addr))
+ return;
+
+ ss7 = osmo_ss7_instance_find(gsm_network->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+ LOGP(DMSC, LOGL_NOTICE, "Adding new BSC connection for BSC %s...\n", osmo_sccp_addr_name(ss7, bsc_addr));
+
+ /* Generate and fill up a new bsc context */
+ bsc_ctx = talloc_zero(gsm_network, struct bsc_context);
+ OSMO_ASSERT(bsc_ctx);
+ memcpy(&bsc_ctx->bsc_addr, bsc_addr, sizeof(*bsc_addr));
+ memcpy(&bsc_ctx->msc_addr, msc_addr, sizeof(*msc_addr));
+ bsc_ctx->sccp_user = scu;
+ llist_add_tail(&bsc_ctx->list, &gsm_network->a.bscs);
+
+ /* Start reset procedure to make the new connection active */
+ bsc_ctx->reset = a_reset_alloc(bsc_ctx, osmo_sccp_addr_name(ss7, bsc_addr), a_reset_cb, bsc_ctx);
+}
+
+/* Callback function, called by the SSCP stack when data arrives */
+static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
+{
+ struct osmo_sccp_user *scu = _scu;
+ struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph;
+ int rc = 0;
+ struct a_conn_info a_conn_info;
+ memset(&a_conn_info, 0, sizeof(a_conn_info));
+ a_conn_info.network = gsm_network;
+ a_conn_info.reset = NULL;
+
+ switch (OSMO_PRIM_HDR(&scu_prim->oph)) {
+ case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION):
+ /* Handle inbound connection indication */
+ add_bsc(&scu_prim->u.connect.called_addr, &scu_prim->u.connect.calling_addr, scu);
+ a_conn_info.conn_id = scu_prim->u.connect.conn_id;
+ a_conn_info.msc_addr = &scu_prim->u.connect.called_addr;
+ a_conn_info.bsc_addr = &scu_prim->u.connect.calling_addr;
+ a_conn_info.reset = get_reset_ctx_by_sccp_addr(&scu_prim->u.unitdata.calling_addr);
+
+ if (a_reset_conn_ready(a_conn_info.reset) == false) {
+ rc = osmo_sccp_tx_disconn(scu, a_conn_info.conn_id, a_conn_info.msc_addr,
+ SCCP_RETURN_CAUSE_UNQUALIFIED);
+ break;
+ }
+
+ osmo_sccp_tx_conn_resp(scu, scu_prim->u.connect.conn_id, &scu_prim->u.connect.called_addr, NULL, 0);
+ if (msgb_l2len(oph->msg) > 0) {
+ LOGP(DMSC, LOGL_DEBUG, "N-CONNECT.ind(%u, %s)\n",
+ scu_prim->u.connect.conn_id, osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
+ rc = sccp_rx_dt(scu, &a_conn_info, oph->msg);
+ } else
+ LOGP(DMSC, LOGL_DEBUG, "N-CONNECT.ind(%u)\n", scu_prim->u.connect.conn_id);
+
+ record_bsc_con(scu, scu_prim->u.connect.conn_id);
+ break;
+
+ case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
+ /* Handle incoming connection oriented data */
+ a_conn_info.conn_id = scu_prim->u.data.conn_id;
+ LOGP(DMSC, LOGL_DEBUG, "N-DATA.ind(%u, %s)\n",
+ scu_prim->u.data.conn_id, osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
+ sccp_rx_dt(scu, &a_conn_info, oph->msg);
+ break;
+
+ case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
+ /* Handle inbound UNITDATA */
+ add_bsc(&scu_prim->u.unitdata.called_addr, &scu_prim->u.unitdata.calling_addr, scu);
+ a_conn_info.msc_addr = &scu_prim->u.unitdata.called_addr;
+ a_conn_info.bsc_addr = &scu_prim->u.unitdata.calling_addr;
+ a_conn_info.reset = get_reset_ctx_by_sccp_addr(&scu_prim->u.unitdata.calling_addr);
+ DEBUGP(DMSC, "N-UNITDATA.ind(%s)\n", osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
+ sccp_rx_udt(scu, &a_conn_info, oph->msg);
+ break;
+
+ default:
+ LOGP(DMSC, LOGL_ERROR, "Unhandled SIGTRAN primitive: %u:%u\n", oph->primitive, oph->operation);
+ break;
+ }
+
+ return rc;
+}
+
+/* Clear all subscriber connections on a specified BSC */
+void a_clear_all(struct osmo_sccp_user *scu, const struct osmo_sccp_addr *bsc_addr)
+{
+ struct gsm_subscriber_connection *conn;
+ struct gsm_subscriber_connection *conn_temp;
+ struct gsm_network *network = gsm_network;
+
+ OSMO_ASSERT(scu);
+ OSMO_ASSERT(bsc_addr);
+
+ llist_for_each_entry_safe(conn, conn_temp, &network->subscr_conns, entry) {
+ /* Clear only A connections and connections that actually
+ * belong to the specified BSC */
+ if (conn->via_ran == RAN_GERAN_A && memcmp(bsc_addr, &conn->a.bsc_addr, sizeof(conn->a.bsc_addr)) == 0) {
+ LOGP(DMSC, LOGL_NOTICE, "Dropping orphaned subscriber connection (conn_id %i)\n",
+ conn->a.conn_id);
+ msc_clear_request(conn, GSM48_CC_CAUSE_SWITCH_CONG);
+
+ /* If there is still an SCCP connection active, remove it now */
+ if (check_connection_active(conn->a.conn_id)) {
+ osmo_sccp_tx_disconn(scu, conn->a.conn_id, bsc_addr,
+ SCCP_RELEASE_CAUSE_END_USER_ORIGINATED);
+ a_delete_bsc_con(conn->a.conn_id);
+ }
+ }
+ }
+}
+
+/* Initalize A interface connection between to MSC and BSC */
+int a_init(struct osmo_sccp_instance *sccp, struct gsm_network *network)
+{
+ OSMO_ASSERT(sccp);
+ OSMO_ASSERT(network);
+
+ /* FIXME: Remove hardcoded parameters, use parameters in parameter list */
+ LOGP(DMSC, LOGL_NOTICE, "Initalizing SCCP connection to stp...\n");
+
+ /* Set GSM network variable, there can only be
+ * one network by design */
+ if (gsm_network != NULL) {
+ OSMO_ASSERT(gsm_network == network);
+ } else
+ gsm_network = network;
+
+ /* SCCP Protocol stack */
+ osmo_sccp_user_bind(sccp, "OsmoMSC-A", sccp_sap_up, SCCP_SSN_BSSAP);
+
+ return 0;
}
diff --git a/src/libmsc/a_iface_bssap.c b/src/libmsc/a_iface_bssap.c
new file mode 100644
index 000000000..561ccdeb0
--- /dev/null
+++ b/src/libmsc/a_iface_bssap.c
@@ -0,0 +1,717 @@
+/* (C) 2017 by Sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/sigtran/sccp_helpers.h>
+#include <osmocom/sccp/sccp_types.h>
+#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/gsm/gsm0808_utils.h>
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/a_iface_bssap.h>
+#include <openbsc/a_iface.h>
+#include <openbsc/iu.h>
+#include <openbsc/osmo_msc.h>
+#include <osmocom/core/byteswap.h>
+#include <openbsc/a_reset.h>
+
+#define IP_V4_ADDR_LEN 4
+
+/*
+ * Helper functions to lookup and allocate subscribers
+ */
+
+/* Allocate a new subscriber connection */
+static struct gsm_subscriber_connection *subscr_conn_allocate_a(const struct a_conn_info *a_conn_info,
+ struct gsm_network *network,
+ uint16_t lac, struct osmo_sccp_user *scu, int conn_id)
+{
+ struct gsm_subscriber_connection *conn;
+
+ LOGP(DMSC, LOGL_NOTICE, "Allocating A-Interface subscriber conn: lac %i, conn_id %i\n", lac, conn_id);
+
+ conn = talloc_zero(network, struct gsm_subscriber_connection);
+ if (!conn)
+ return NULL;
+
+ conn->network = network;
+ conn->via_ran = RAN_GERAN_A;
+ conn->lac = lac;
+
+ conn->a.conn_id = conn_id;
+ conn->a.scu = scu;
+
+ /* Also backup the calling address of the BSC, this allows us to
+ * identify later which BSC is responsible for this subscriber connection */
+ memcpy(&conn->a.bsc_addr, a_conn_info->bsc_addr, sizeof(conn->a.bsc_addr));
+
+ llist_add_tail(&conn->entry, &network->subscr_conns);
+ LOGP(DMSC, LOGL_NOTICE, "A-Interface subscriber connection successfully allocated!\n");
+ return conn;
+}
+
+/* Return an existing A subscriber connection record for the given
+ * connection IDs, or return NULL if not found. */
+static struct gsm_subscriber_connection *subscr_conn_lookup_a(const struct gsm_network *network, int conn_id)
+{
+ struct gsm_subscriber_connection *conn;
+
+ OSMO_ASSERT(network);
+
+ DEBUGP(DMSC, "Looking for A subscriber: conn_id %i\n", conn_id);
+
+ /* FIXME: log_subscribers() is defined in iucs.c as static inline, if
+ * maybe this function should be public to reach it from here? */
+ /* log_subscribers(network); */
+
+ llist_for_each_entry(conn, &network->subscr_conns, entry) {
+ if (conn->via_ran == RAN_GERAN_A && conn->a.conn_id == conn_id) {
+ DEBUGP(DIUCS, "Found A subscriber for conn_id %i\n", conn_id);
+ return conn;
+ }
+ }
+ DEBUGP(DMSC, "No A subscriber found for conn_id %i\n", conn_id);
+ return NULL;
+}
+
+/*
+ * BSSMAP handling for UNITDATA
+ */
+
+/* Endpoint to handle BSSMAP reset */
+static void bssmap_rx_reset(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ struct gsm_network *network = a_conn_info->network;
+ struct osmo_ss7_instance *ss7;
+
+ ss7 = osmo_ss7_instance_find(network->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+
+ LOGP(DMSC, LOGL_NOTICE, "Rx RESET from BSC %s, sending RESET ACK\n",
+ osmo_sccp_addr_name(ss7, a_conn_info->bsc_addr));
+ osmo_sccp_tx_unitdata_msg(scu, a_conn_info->msc_addr, a_conn_info->bsc_addr, gsm0808_create_reset_ack());
+
+ /* Make sure all orphand subscriber connections will be cleard */
+ a_clear_all(scu, a_conn_info->bsc_addr);
+
+ msgb_free(msg);
+}
+
+/* Endpoint to handle BSSMAP reset acknowlegement */
+static void bssmap_rx_reset_ack(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info,
+ struct msgb *msg)
+{
+
+ struct gsm_network *network = a_conn_info->network;
+ struct osmo_ss7_instance *ss7;
+
+ ss7 = osmo_ss7_instance_find(network->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+
+ if (a_conn_info->reset == NULL) {
+ LOGP(DMSC, LOGL_ERROR, "Received RESET ACK from an unknown BSC %s, ignoring...\n",
+ osmo_sccp_addr_name(ss7, a_conn_info->bsc_addr));
+ goto fail;
+ }
+
+ LOGP(DMSC, LOGL_NOTICE, "Received RESET ACK from BSC %s\n", osmo_sccp_addr_name(ss7, a_conn_info->bsc_addr));
+
+ /* Confirm that we managed to get the reset ack message
+ * towards the connection reset logic */
+ a_reset_ack_confirm(a_conn_info->reset);
+
+fail:
+ msgb_free(msg);
+}
+
+/* Handle UNITDATA BSSMAP messages */
+static void bssmap_rcvmsg_udt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ /* Note: When in the MSC role, RESET ACK is the only valid message that
+ * can be received via UNITDATA */
+
+ if (msgb_l3len(msg) < 1) {
+ LOGP(DMSC, LOGL_NOTICE, "Error: No data received -- discarding message!\n");
+ return;
+ }
+
+ LOGP(DMSC, LOGL_NOTICE, "Rx BSC UDT BSSMAP %s\n", gsm0808_bssmap_name(msg->l3h[0]));
+
+ switch (msg->l3h[0]) {
+ case BSS_MAP_MSG_RESET:
+ bssmap_rx_reset(scu, a_conn_info, msg);
+ break;
+ case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
+ bssmap_rx_reset_ack(scu, a_conn_info, msg);
+ break;
+ default:
+ LOGP(DMSC, LOGL_NOTICE, "Unimplemented message format: %s -- message discarded!\n",
+ gsm0808_bssmap_name(msg->l3h[0]));
+ msgb_free(msg);
+ }
+}
+
+/* Receive incoming connection less data messages via sccp */
+void sccp_rx_udt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ /* Note: The only valid message type that can be received
+ * via UNITDATA are BSS Management messages */
+ struct bssmap_header *bs;
+
+ OSMO_ASSERT(scu);
+ OSMO_ASSERT(a_conn_info);
+ OSMO_ASSERT(msg);
+
+ LOGP(DMSC, LOGL_NOTICE, "Rx BSC UDT: %s\n", osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
+
+ if (msgb_l2len(msg) < sizeof(*bs)) {
+ LOGP(DMSC, LOGL_ERROR, "Error: Header is too short -- discarding message!\n");
+ msgb_free(msg);
+ return;
+ }
+
+ bs = (struct bssmap_header *)msgb_l2(msg);
+ if (bs->length < msgb_l2len(msg) - sizeof(*bs)) {
+ LOGP(DMSC, LOGL_ERROR, "Error: Message is too short -- discarding message!\n");
+ msgb_free(msg);
+ return;
+ }
+
+ switch (bs->type) {
+ case BSSAP_MSG_BSS_MANAGEMENT:
+ msg->l3h = &msg->l2h[sizeof(struct bssmap_header)];
+ bssmap_rcvmsg_udt(scu, a_conn_info, msg);
+ break;
+ default:
+ LOGP(DMSC, LOGL_ERROR,
+ "Error: Unimplemented message type: %s -- message discarded!\n", gsm0808_bssmap_name(bs->type));
+ msgb_free(msg);
+ }
+}
+
+/*
+ * BSSMAP handling for connection oriented data
+ */
+
+/* Endpoint to handle BSSMAP clear request */
+static int bssmap_rx_clear_rqst(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ struct gsm_network *network = a_conn_info->network;
+ struct tlv_parsed tp;
+ int rc;
+ struct msgb *msg_resp;
+ uint8_t cause;
+ struct gsm_subscriber_connection *conn;
+
+ LOGP(DMSC, LOGL_NOTICE, "BSC requested to clear connection (conn_id=%i)\n", a_conn_info->conn_id);
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_CAUSE)) {
+ LOGP(DMSC, LOGL_ERROR, "Cause code is missing -- discarding message!\n");
+ goto fail;
+ }
+ cause = TLVP_VAL(&tp, GSM0808_IE_CAUSE)[0];
+
+ /* Respond with clear command */
+ msg_resp = gsm0808_create_clear_command(GSM0808_CAUSE_CALL_CONTROL);
+ rc = osmo_sccp_tx_data_msg(scu, a_conn_info->conn_id, msg_resp);
+
+ /* If possible, inform the MSC about the clear request */
+ conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
+ if (!conn)
+ goto fail;
+ msc_clear_request(conn, cause);
+
+ msgb_free(msg);
+ return rc;
+
+fail:
+ msgb_free(msg);
+ return -EINVAL;
+}
+
+/* Endpoint to handle BSSMAP clear complete */
+static int bssmap_rx_clear_complete(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ int rc;
+
+ LOGP(DMSC, LOGL_NOTICE, "Releasing connection (conn_id=%i)\n", a_conn_info->conn_id);
+ rc = osmo_sccp_tx_disconn(scu, a_conn_info->conn_id,
+ a_conn_info->msc_addr, SCCP_RELEASE_CAUSE_END_USER_ORIGINATED);
+
+ /* Remove the record from the list with active connections. */
+ a_delete_bsc_con(a_conn_info->conn_id);
+
+ msgb_free(msg);
+ return rc;
+}
+
+/* Endpoint to handle layer 3 complete messages */
+static int bssmap_rx_l3_compl(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ struct tlv_parsed tp;
+ struct {
+ uint8_t ident;
+ struct gsm48_loc_area_id lai;
+ uint16_t ci;
+ } __attribute__ ((packed)) lai_ci;
+ uint16_t mcc;
+ uint16_t mnc;
+ uint16_t lac;
+ uint8_t data_length;
+ const uint8_t *data;
+ int rc;
+
+ struct gsm_network *network = a_conn_info->network;
+ struct gsm_subscriber_connection *conn;
+
+ LOGP(DMSC, LOGL_NOTICE, "BSC has completed layer 3 connection (conn_id=%i)\n", a_conn_info->conn_id);
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER)) {
+ LOGP(DMSC, LOGL_ERROR, "Mandatory CELL IDENTIFIER not present -- discarding message!\n");
+ goto fail;
+ }
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_INFORMATION)) {
+ LOGP(DMSC, LOGL_ERROR, "Mandatory LAYER 3 INFORMATION not present -- discarding message!\n");
+ goto fail;
+ }
+
+ /* Parse Cell ID element */
+ /* FIXME: Encapsulate this in a parser/generator function inside
+ * libosmocore, add support for all specified cell identification
+ * discriminators (see 3GPP ts 3.2.2.17 Cell Identifier) */
+ data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER);
+ data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER);
+ if (sizeof(lai_ci) != data_length) {
+ LOGP(DMSC, LOGL_ERROR,
+ "Unable to parse element CELL IDENTIFIER (wrong field length) -- discarding message!\n");
+ goto fail;
+ }
+ memcpy(&lai_ci, data, sizeof(lai_ci));
+ if (lai_ci.ident != CELL_IDENT_WHOLE_GLOBAL) {
+ LOGP(DMSC, LOGL_ERROR,
+ "Unable to parse element CELL IDENTIFIER (wrong cell identification discriminator) -- discarding message!\n");
+ goto fail;
+ }
+ if (gsm48_decode_lai(&lai_ci.lai, &mcc, &mnc, &lac) != 0) {
+ LOGP(DMSC, LOGL_ERROR,
+ "Unable to parse element CELL IDENTIFIER (lai decoding failed) -- discarding message!\n");
+ goto fail;
+ }
+
+ /* Parse Layer 3 Information element */
+ /* FIXME: This is probably to hackish, compiler also complains "assignment discards ‘const’ qualifier..." */
+ msg->l3h = TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION);
+ msg->tail = msg->l3h + TLVP_LEN(&tp, GSM0808_IE_LAYER_3_INFORMATION);
+
+ /* Create new subscriber context */
+ conn = subscr_conn_allocate_a(a_conn_info, network, lac, scu, a_conn_info->conn_id);
+
+ /* Handover location update to the MSC code */
+ /* msc_compl_l3() takes ownership of dtap_msg
+ * message buffer */
+ rc = msc_compl_l3(conn, msg, 0);
+ if (rc == MSC_CONN_ACCEPT) {
+ LOGP(DMSC, LOGL_NOTICE, "User has been accepted by MSC.\n");
+ return 0;
+ } else if (rc == MSC_CONN_REJECT)
+ LOGP(DMSC, LOGL_NOTICE, "User has been rejected by MSC.\n");
+ else
+ LOGP(DMSC, LOGL_NOTICE, "User has been rejected by MSC (unknown error)\n");
+
+ return -EINVAL;
+
+fail:
+ msgb_free(msg);
+ return -EINVAL;
+}
+
+/* Endpoint to handle BSSMAP classmark update */
+static int bssmap_rx_classmark_upd(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ struct gsm_network *network = a_conn_info->network;
+ struct gsm_subscriber_connection *conn;
+ struct tlv_parsed tp;
+ const uint8_t *cm2 = NULL;
+ const uint8_t *cm3 = NULL;
+ uint8_t cm2_len = 0;
+ uint8_t cm3_len = 0;
+
+ conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
+ if (!conn)
+ goto fail;
+
+ LOGP(DMSC, LOGL_NOTICE, "BSC sends clasmark update (conn_id=%i)\n", conn->a.conn_id);
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T2)) {
+ LOGP(DMSC, LOGL_ERROR, "Mandatory Classmark Information Type 2 not present -- discarding message!\n");
+ goto fail;
+ }
+
+ cm2 = TLVP_VAL(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T2);
+ cm2_len = TLVP_LEN(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T2);
+
+ if (TLVP_PRESENT(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T3)) {
+ cm3 = TLVP_VAL(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T3);
+ cm3_len = TLVP_LEN(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T3);
+ }
+
+ /* Inform MSC about the classmark change */
+ msc_classmark_chg(conn, cm2, cm2_len, cm3, cm3_len);
+
+ msgb_free(msg);
+ return 0;
+
+fail:
+ msgb_free(msg);
+ return -EINVAL;
+}
+
+/* Endpoint to handle BSSMAP cipher mode complete */
+static int bssmap_rx_ciph_compl(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info,
+ struct msgb *msg)
+{
+ /* FIXME: The field GSM0808_IE_LAYER_3_MESSAGE_CONTENTS is optional by
+ * means of the specification. So there can be messages without L3 info.
+ * In this case, the code will crash becrause msc_cipher_mode_compl()
+ * is not able to deal with msg = NULL and apperently
+ * msc_cipher_mode_compl() was never meant to be used without L3 data.
+ * This needs to be discussed further! */
+
+ struct gsm_network *network = a_conn_info->network;
+ struct gsm_subscriber_connection *conn;
+ struct tlv_parsed tp;
+ uint8_t alg_id = 1;
+
+ conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
+ if (!conn)
+ goto fail;
+
+ LOGP(DMSC, LOGL_NOTICE, "BSC sends cipher mode complete (conn_id=%i)\n", conn->a.conn_id);
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
+
+ if (TLVP_PRESENT(&tp, GSM0808_IE_CHOSEN_ENCR_ALG)) {
+ alg_id = TLVP_VAL(&tp, GSM0808_IE_CHOSEN_ENCR_ALG)[0] - 1;
+ }
+
+ if (TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_MESSAGE_CONTENTS)) {
+ msg->l3h = TLVP_VAL(&tp, GSM0808_IE_LAYER_3_MESSAGE_CONTENTS);
+ msg->tail = msg->l3h + TLVP_LEN(&tp, GSM0808_IE_LAYER_3_MESSAGE_CONTENTS);
+ } else {
+ msgb_free(msg);
+ msg = NULL;
+ }
+
+ /* Hand over cipher mode complete message to the MSC,
+ * msc_cipher_mode_compl() takes ownership for msg */
+ msc_cipher_mode_compl(conn, msg, alg_id);
+
+ return 0;
+fail:
+ msgb_free(msg);
+ return -EINVAL;
+}
+
+/* Endpoint to handle BSSMAP cipher mode reject */
+static int bssmap_rx_ciph_rej(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ struct gsm_network *network = a_conn_info->network;
+ struct gsm_subscriber_connection *conn;
+ struct tlv_parsed tp;
+ uint8_t cause;
+
+ conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
+ if (!conn)
+ goto fail;
+
+ LOGP(DMSC, LOGL_NOTICE, "BSC sends cipher mode reject (conn_id=%i)\n", conn->a.conn_id);
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
+ if (!TLVP_PRESENT(&tp, BSS_MAP_MSG_CIPHER_MODE_REJECT)) {
+ LOGP(DMSC, LOGL_ERROR, "Cause code is missing -- discarding message!\n");
+ goto fail;
+ }
+
+ cause = TLVP_VAL(&tp, BSS_MAP_MSG_CIPHER_MODE_REJECT)[0];
+ LOGP(DMSC, LOGL_NOTICE, "Cipher mode rejection cause: %i\n", cause);
+
+ /* FIXME: Can we do something meaningful here? e.g. report to the
+ * msc code somehow that the cipher mode command has failed. */
+
+ msgb_free(msg);
+ return 0;
+fail:
+ msgb_free(msg);
+ return -EINVAL;
+}
+
+/* Endpoint to handle BSSMAP assignment failure */
+static int bssmap_rx_ass_fail(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ struct gsm_network *network = a_conn_info->network;
+ struct gsm_subscriber_connection *conn;
+ struct tlv_parsed tp;
+ uint8_t cause;
+ uint8_t *rr_cause_ptr = NULL;
+ uint8_t rr_cause;
+
+ conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
+ if (!conn)
+ goto fail;
+
+ LOGP(DMSC, LOGL_NOTICE, "BSC sends assignment failure message (conn_id=%i)\n", conn->a.conn_id);
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_CAUSE)) {
+ LOGP(DMSC, LOGL_ERROR, "Cause code is missing -- discarding message!\n");
+ goto fail;
+ }
+ cause = TLVP_VAL(&tp, GSM0808_IE_CAUSE)[0];
+
+ if (TLVP_PRESENT(&tp, GSM0808_IE_RR_CAUSE)) {
+ rr_cause = TLVP_VAL(&tp, GSM0808_IE_RR_CAUSE)[0];
+ rr_cause_ptr = &rr_cause;
+ }
+
+ /* FIXME: In AoIP, the Assignment failure will carry also an optional
+ * Codec List (BSS Supported) element. It has to be discussed if we
+ * can ignore this element. If not, The msc_assign_fail() function
+ * call has to change. However msc_assign_fail() does nothing in the
+ * end. So probably we can just leave it as it is. Even for AoIP */
+
+ /* Inform the MSC about the assignment failure event */
+ msc_assign_fail(conn, cause, rr_cause_ptr);
+
+ msgb_free(msg);
+ return 0;
+fail:
+ msgb_free(msg);
+ return -EINVAL;
+}
+
+/* Endpoint to handle sapi "n" reject */
+static int bssmap_rx_sapi_n_rej(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info,
+ struct msgb *msg)
+{
+ struct gsm_network *network = a_conn_info->network;
+ struct gsm_subscriber_connection *conn;
+ struct tlv_parsed tp;
+ uint8_t dlci;
+
+ conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
+ if (!conn)
+ goto fail;
+
+ LOGP(DMSC, LOGL_NOTICE, "BSC sends sapi \"n\" reject message (conn_id=%i)\n", conn->a.conn_id);
+
+ /* Note: The MSC code seems not to care about the cause code, but by
+ * the specification it is mandatory, so we check its presence. See
+ * also 3GPP TS 48.008 3.2.1.34 SAPI "n" REJECT */
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_CAUSE)) {
+ LOGP(DMSC, LOGL_ERROR, "Cause code is missing -- discarding message!\n");
+ goto fail;
+ }
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_DLCI)) {
+ LOGP(DMSC, LOGL_ERROR, "DLCI is missing -- discarding message!\n");
+ goto fail;
+ }
+ dlci = TLVP_VAL(&tp, GSM0808_IE_DLCI)[0];
+
+ /* Inform the MSC about the sapi "n" reject event */
+ msc_sapi_n_reject(conn, dlci);
+
+ msgb_free(msg);
+ return 0;
+fail:
+ msgb_free(msg);
+ return -EINVAL;
+}
+
+/* Endpoint to handle assignment complete */
+static int bssmap_rx_ass_compl(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info,
+ struct msgb *msg)
+{
+ struct gsm_network *network = a_conn_info->network;
+ struct gsm_subscriber_connection *conn;
+ struct mgcpgw_client *mgcp;
+ struct tlv_parsed tp;
+ struct sockaddr_storage rtp_addr;
+ struct sockaddr_in *rtp_addr_in;
+ int rc;
+
+ conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
+ if (!conn)
+ goto fail;
+
+ mgcp = conn->network->mgcpgw.client;
+ OSMO_ASSERT(mgcp);
+
+ LOGP(DMSC, LOGL_NOTICE, "BSC sends assignment complete message (conn_id=%i)\n", conn->a.conn_id);
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
+
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_AOIP_TRASP_ADDR)) {
+ LOGP(DMSC, LOGL_ERROR, "AoIP transport identifier missing -- discarding message!\n");
+ goto fail;
+ }
+
+ /* Decode AoIP transport address element */
+ rc = gsm0808_dec_aoip_trasp_addr(&rtp_addr, TLVP_VAL(&tp, GSM0808_IE_AOIP_TRASP_ADDR),
+ TLVP_LEN(&tp, GSM0808_IE_AOIP_TRASP_ADDR));
+ if (rc < 0) {
+ LOGP(DMSC, LOGL_ERROR, "Unable to decode aoip transport address.\n");
+ goto fail;
+ }
+
+ /* use address / port supplied with the AoIP
+ * transport address element */
+ if (rtp_addr.ss_family == AF_INET) {
+ rtp_addr_in = (struct sockaddr_in *)&rtp_addr;
+ conn->rtp.port_subscr = osmo_ntohs(rtp_addr_in->sin_port);
+ /* FIXME: We also get the IP-Address of the remote (e.g. BTS)
+ * end with the response. Currently we just ignore that address.
+ * Instead we expect that our local MGCP gateway and the code
+ * controlling it, magically knows the IP of the remote end. */
+ } else {
+ LOGP(DMSC, LOGL_ERROR, "Unsopported addressing scheme. (supports only IPV4)\n");
+ goto fail;
+ }
+
+ /* FIXME: Seems to be related to authentication or,
+ encryption. Is this really in the right place? */
+ msc_rx_sec_mode_compl(conn);
+
+ msgb_free(msg);
+ return 0;
+fail:
+ msgb_free(msg);
+ return -EINVAL;
+}
+
+/* Handle incoming connection oriented BSSMAP messages */
+static int rx_bssmap(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ if (msgb_l3len(msg) < 1) {
+ LOGP(DMSC, LOGL_NOTICE, "Error: No data received -- discarding message!\n");
+ msgb_free(msg);
+ return -1;
+ }
+
+ LOGP(DMSC, LOGL_NOTICE, "Rx MSC DT1 BSSMAP %s\n", gsm0808_bssmap_name(msg->l3h[0]));
+
+ switch (msg->l3h[0]) {
+ case BSS_MAP_MSG_CLEAR_RQST:
+ return bssmap_rx_clear_rqst(scu, a_conn_info, msg);
+ break;
+ case BSS_MAP_MSG_CLEAR_COMPLETE:
+ return bssmap_rx_clear_complete(scu, a_conn_info, msg);
+ break;
+ case BSS_MAP_MSG_COMPLETE_LAYER_3:
+ return bssmap_rx_l3_compl(scu, a_conn_info, msg);
+ break;
+ case BSS_MAP_MSG_CLASSMARK_UPDATE:
+ return bssmap_rx_classmark_upd(scu, a_conn_info, msg);
+ break;
+ case BSS_MAP_MSG_CIPHER_MODE_COMPLETE:
+ return bssmap_rx_ciph_compl(scu, a_conn_info, msg);
+ break;
+ case BSS_MAP_MSG_CIPHER_MODE_REJECT:
+ return bssmap_rx_ciph_rej(scu, a_conn_info, msg);
+ break;
+ case BSS_MAP_MSG_ASSIGMENT_FAILURE:
+ return bssmap_rx_ass_fail(scu, a_conn_info, msg);
+ break;
+ case BSS_MAP_MSG_SAPI_N_REJECT:
+ return bssmap_rx_sapi_n_rej(scu, a_conn_info, msg);
+ break;
+ case BSS_MAP_MSG_ASSIGMENT_COMPLETE:
+ return bssmap_rx_ass_compl(scu, a_conn_info, msg);
+ break;
+ default:
+ LOGP(DMSC, LOGL_ERROR, "Unimplemented msg type: %s\n", gsm0808_bssmap_name(msg->l3h[0]));
+ msgb_free(msg);
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+/* Endpoint to handle regular BSSAP DTAP messages */
+static int rx_dtap(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ struct gsm_network *network = a_conn_info->network;
+ struct gsm_subscriber_connection *conn;
+
+ conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
+ if (!conn) {
+ msgb_free(msg);
+ return -EINVAL;
+ }
+
+ LOGP(DMSC, LOGL_NOTICE, "BSC sends layer 3 dtap (conn_id=%i)\n", conn->a.conn_id);
+
+ /* msc_dtap expects the dtap payload in l3h */
+ msg->l3h = msg->l2h + 3;
+
+ /* Forward dtap payload into the msc,
+ * msc_dtap() takes ownership for msg */
+ msc_dtap(conn, conn->a.conn_id, msg);
+
+ return 0;
+}
+
+/* Handle incoming connection oriented messages */
+int sccp_rx_dt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
+{
+ OSMO_ASSERT(scu);
+ OSMO_ASSERT(a_conn_info);
+ OSMO_ASSERT(msg);
+
+ LOGP(DMSC, LOGL_NOTICE, "Rx BSC DT: %s\n", osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
+
+ if (msgb_l2len(msg) < sizeof(struct bssmap_header)) {
+ LOGP(DMSC, LOGL_NOTICE, "The header is too short -- discarding message!\n");
+ msgb_free(msg);
+ }
+
+ switch (msg->l2h[0]) {
+ case BSSAP_MSG_BSS_MANAGEMENT:
+ msg->l3h = &msg->l2h[sizeof(struct bssmap_header)];
+ return rx_bssmap(scu, a_conn_info, msg);
+ break;
+ case BSSAP_MSG_DTAP:
+ return rx_dtap(scu, a_conn_info, msg);
+ break;
+ default:
+ LOGP(DMSC, LOGL_ERROR, "Unimplemented BSSAP msg type: %s\n", gsm0808_bssap_name(msg->l2h[0]));
+ msgb_free(msg);
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
diff --git a/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c
index 28cba5b85..b6746a564 100644
--- a/src/libmsc/gsm_04_08.c
+++ b/src/libmsc/gsm_04_08.c
@@ -79,6 +79,8 @@
#include <openbsc/iu.h>
#endif
+#include <openbsc/a_iface.h>
+
#include <assert.h>
@@ -1267,6 +1269,8 @@ static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
struct msgb *msg;
unsigned char *data;
+ DEBUGP(DMNCC, "transmit message %s\n", get_mncc_name(msg_type));
+
#if BEFORE_MSCSPLIT
/* Re-enable this log output once we can obtain this information via
* A-interface, see OS#2391. */
@@ -1324,6 +1328,9 @@ void _gsm48_cc_trans_free(struct gsm_trans *trans)
{
gsm48_stop_cc_timer(trans);
+ /* Make sure call also gets released on the mgcp side */
+ msc_call_release(trans);
+
/* send release to L4, if callref still exists */
if (trans->callref) {
/* Ressource unavailable */
@@ -1549,6 +1556,12 @@ 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);
+
+ /* Create a copy of the bearer capability
+ * in the transaction struct, so we can use
+ * this information later */
+ memcpy(&trans->bearer_cap,&setup.bearer_cap,
+ sizeof(trans->bearer_cap));
}
/* facility */
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
@@ -1682,6 +1695,7 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
struct tlv_parsed tp;
struct gsm_mncc call_conf;
+ int rc;
gsm48_stop_cc_timer(trans);
gsm48_start_cc_timer(trans, 0x310, GSM48_T310);
@@ -1702,6 +1716,12 @@ 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);
+
+ /* Create a copy of the bearer capability
+ * in the transaction struct, so we can use
+ * this information later */
+ memcpy(&trans->bearer_cap,&call_conf.bearer_cap,
+ sizeof(trans->bearer_cap));
}
/* cause */
if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
@@ -1721,7 +1741,18 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
- msc_call_assignment(trans);
+ /* Assign call (if not done yet) */
+ if (trans->assignment_done == false) {
+ rc = msc_call_assignment(trans);
+ trans->assignment_done = true;
+ }
+ else
+ rc = 0;
+
+ /* don't continue, if there were problems with
+ * the call assignment. */
+ if (rc)
+ return rc;
return mncc_recvmsg(trans->net, trans, MNCC_CALL_CONF_IND,
&call_conf);
@@ -1752,7 +1783,15 @@ static int gsm48_cc_tx_call_proc_and_assign(struct gsm_trans *trans, void *arg)
if (rc)
return rc;
- return msc_call_assignment(trans);
+ /* Assign call (if not done yet) */
+ if (trans->assignment_done == false) {
+ rc = msc_call_assignment(trans);
+ trans->assignment_done = true;
+ }
+ else
+ rc = 0;
+
+ return rc;
}
static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
@@ -2398,6 +2437,12 @@ 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);
+
+ /* Create a copy of the bearer capability
+ * in the transaction struct, so we can use
+ * this information later */
+ memcpy(&trans->bearer_cap,&modify.bearer_cap,
+ sizeof(trans->bearer_cap));
}
new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
@@ -2440,6 +2485,12 @@ 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);
+
+ /* Create a copy of the bearer capability
+ * in the transaction struct, so we can use
+ * this information later */
+ memcpy(&trans->bearer_cap,&modify.bearer_cap,
+ sizeof(trans->bearer_cap));
}
new_cc_state(trans, GSM_CSTATE_ACTIVE);
@@ -2480,6 +2531,12 @@ 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);
+
+ /* Create a copy of the bearer capability
+ * in the transaction struct, so we can use
+ * this information later */
+ memcpy(&trans->bearer_cap,&modify.bearer_cap,
+ sizeof(trans->bearer_cap));
}
/* cause */
if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
@@ -2582,6 +2639,139 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
return mncc_recvmsg(trans->net, trans, MNCC_USERINFO_IND, &user);
}
+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)
+{
+ int msg_type;
+
+ /* FIXME This has to be set to some meaningful value.
+ * Possible options are:
+ * GSM_TCHF_FRAME, GSM_TCHF_FRAME_EFR,
+ * GSM_TCHH_FRAME, GSM_TCH_FRAME_AMR
+ * (0 if unknown) */
+ msg_type = GSM_TCHF_FRAME;
+
+ uint32_t addr = mgcpgw_client_remote_addr_n(net->mgcpgw.client);
+ uint16_t port = trans->conn->rtp.port_cn;
+
+ /* FIXME: This has to be set to some meaningful value,
+ * before the MSC-Split, this value was pulled from
+ * lchan->abis_ip.rtp_payload */
+ uint32_t payload_type = 0;
+
+ return mncc_recv_rtp(net, trans->callref, cmd,
+ addr,
+ port,
+ payload_type,
+ 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_trans *trans;
+ int rc;
+
+ /* 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(LOG_CTX_VLR_SUBSCR, trans->vsub);
+ 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;
+ }
+
+ trans->conn->mncc_rtp_bridge = 1;
+
+ /* When we call msc_call_assignment() we will trigger, depending
+ * on the RAN type the call assignment on the A or Iu interface.
+ * msc_call_assignment() also takes care about sending the CRCX
+ * command to the MGCP-GW. The CRCX will return the port number,
+ * where the PBX (e.g. Asterisk) will send its RTP stream to. We
+ * have to return this port number back to the MNCC by sending
+ * it back with the TCH_RTP_CREATE message. To make sure that
+ * this message is sent AFTER the response to CRCX from the
+ * MGCP-GW has arrived, we need will instruct msc_call_assignment()
+ * to take care of this by setting trans->tch_rtp_create to true.
+ * This will make sure that gsm48_tch_rtp_create() (below) is
+ * called as soon as the local port number has become known. */
+ trans->tch_rtp_create = true;
+
+ /* Assign call (if not done yet) */
+ if (trans->assignment_done == false) {
+ rc = msc_call_assignment(trans);
+ trans->assignment_done = true;
+ }
+ else
+ rc = 0;
+
+ return rc;
+}
+
+/* Trigger TCH_RTP_CREATE acknowledgement */
+int gsm48_tch_rtp_create(struct gsm_trans *trans)
+{
+ /* This function is called as soon as the port, on which the
+ * mgcp-gw expects the incoming RTP stream from the remote
+ * end (e.g. Asterisk) is known. */
+
+ struct gsm_subscriber_connection *conn = trans->conn;
+ struct gsm_network *network = conn->network;
+
+ mncc_recv_rtp_sock(network, trans, MNCC_RTP_CREATE);
+ return 0;
+}
+
+static int tch_rtp_connect(struct gsm_network *net, void *arg)
+{
+ 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(LOG_CTX_VLR_SUBSCR, trans->vsub);
+ 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;
+ }
+
+ msc_call_connect(trans,rtp->port,rtp->ip);
+ return 0;
+}
+
static struct downstate {
uint32_t states;
int type;
@@ -2657,11 +2847,16 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
if (rc < 0)
disconnect_bridge(net, arg, -rc);
return rc;
- case MNCC_FRAME_DROP:
- case MNCC_FRAME_RECV:
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 MNCC_FRAME_DROP:
+ case MNCC_FRAME_RECV:
case GSM_TCHF_FRAME:
case GSM_TCHF_FRAME_EFR:
case GSM_TCHH_FRAME:
@@ -3211,8 +3406,8 @@ static int msc_vlr_set_ciph_mode(void *msc_conn_ref,
case RAN_GERAN_A:
DEBUGP(DMM, "-> CIPHER MODE COMMAND %s\n",
vlr_subscr_name(conn->vsub));
- return msc_gsm0808_tx_cipher_mode(conn, ciph, tuple->vec.kc, 8,
- retrieve_imeisv);
+ return a_iface_tx_cipher_mode(conn, ciph, tuple->vec.kc, 8,
+ retrieve_imeisv);
case RAN_UTRAN_IU:
#ifdef BUILD_IU
DEBUGP(DMM, "-> SECURITY MODE CONTROL %s\n",
diff --git a/src/libmsc/gsm_subscriber.c b/src/libmsc/gsm_subscriber.c
index ac6c96a88..73361a169 100644
--- a/src/libmsc/gsm_subscriber.c
+++ b/src/libmsc/gsm_subscriber.c
@@ -43,6 +43,7 @@
#include <openbsc/iu.h>
#include <openbsc/osmo_msc.h>
#include <openbsc/msc_ifaces.h>
+#include <openbsc/a_iface.h>
int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *data, void *param)
@@ -105,7 +106,7 @@ int msc_paging_request(struct vlr_subscr *vsub)
* Need to add BSC paging at some point. */
switch (vsub->cs.attached_via_ran) {
case RAN_GERAN_A:
- return a_page(vsub->imsi, vsub->tmsi, vsub->lac);
+ return a_iface_tx_paging(vsub->imsi, vsub->tmsi, vsub->lac);
case RAN_UTRAN_IU:
return iu_page_cs(vsub->imsi,
vsub->tmsi == GSM_RESERVED_TMSI?
diff --git a/src/libmsc/iucs.c b/src/libmsc/iucs.c
index aeda1406a..be026c857 100644
--- a/src/libmsc/iucs.c
+++ b/src/libmsc/iucs.c
@@ -40,8 +40,8 @@ static struct gsm_subscriber_connection *subscr_conn_allocate_iu(struct gsm_netw
{
struct gsm_subscriber_connection *conn;
- DEBUGP(DIUCS, "Allocating IuCS subscriber conn: lac %d, link_id %p, conn_id %" PRIx32 "\n",
- lac, ue->link, ue->conn_id);
+ DEBUGP(DIUCS, "Allocating IuCS subscriber conn: lac %d, conn_id %" PRIx32 "\n",
+ lac, ue->conn_id);
conn = talloc_zero(network, struct gsm_subscriber_connection);
if (!conn)
@@ -61,8 +61,7 @@ static int same_ue_conn(struct ue_conn_ctx *a, struct ue_conn_ctx *b)
{
if (a == b)
return 1;
- return (a->link == b->link)
- && (a->conn_id == b->conn_id);
+ return (a->conn_id == b->conn_id);
}
static inline void log_subscribers(struct gsm_network *network)
@@ -78,8 +77,7 @@ static inline void log_subscribers(struct gsm_network *network)
case RAN_UTRAN_IU:
DEBUGPC(DIUCS, " Iu");
if (conn->iu.ue_ctx) {
- DEBUGPC(DIUCS, " link %p, conn_id %d",
- conn->iu.ue_ctx->link,
+ DEBUGPC(DIUCS, " conn_id %d",
conn->iu.ue_ctx->conn_id
);
}
@@ -101,7 +99,7 @@ static inline void log_subscribers(struct gsm_network *network)
DEBUGP(DIUCS, "subscribers registered: %d\n", i);
}
-/* Return an existing IuCS subscriber connection record for the given link and
+/* Return an existing IuCS subscriber connection record for the given
* connection IDs, or return NULL if not found. */
struct gsm_subscriber_connection *subscr_conn_lookup_iu(
struct gsm_network *network,
@@ -109,8 +107,8 @@ struct gsm_subscriber_connection *subscr_conn_lookup_iu(
{
struct gsm_subscriber_connection *conn;
- DEBUGP(DIUCS, "Looking for IuCS subscriber: link_id %p, conn_id %" PRIx32 "\n",
- ue->link, ue->conn_id);
+ DEBUGP(DIUCS, "Looking for IuCS subscriber: conn_id %" PRIx32 "\n",
+ ue->conn_id);
log_subscribers(network);
llist_for_each_entry(conn, &network->subscr_conns, entry) {
@@ -118,12 +116,12 @@ struct gsm_subscriber_connection *subscr_conn_lookup_iu(
continue;
if (!same_ue_conn(conn->iu.ue_ctx, ue))
continue;
- DEBUGP(DIUCS, "Found IuCS subscriber for link_id %p, conn_id %" PRIx32 "\n",
- ue->link, ue->conn_id);
+ DEBUGP(DIUCS, "Found IuCS subscriber for conn_id %" PRIx32 "\n",
+ ue->conn_id);
return conn;
}
- DEBUGP(DIUCS, "No IuCS subscriber found for link_id %p, conn_id %" PRIx32 "\n",
- ue->link, ue->conn_id);
+ DEBUGP(DIUCS, "No IuCS subscriber found for conn_id %" PRIx32 "\n",
+ ue->conn_id);
return NULL;
}
diff --git a/src/libmsc/msc_ifaces.c b/src/libmsc/msc_ifaces.c
index 56cbd49d4..7d2e8981b 100644
--- a/src/libmsc/msc_ifaces.c
+++ b/src/libmsc/msc_ifaces.c
@@ -29,6 +29,7 @@
#include <openbsc/mgcp.h>
#include <openbsc/mgcpgw_client.h>
#include <openbsc/vlr.h>
+#include <openbsc/a_iface.h>
#include "../../bscconfig.h"
@@ -41,13 +42,18 @@ extern struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id,
static int msc_tx(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
+ if (!conn)
+ return -EINVAL;
+ if (!msg)
+ return -EINVAL;
+
DEBUGP(DMSC, "msc_tx %u bytes to %s via %s\n",
msg->len, vlr_subscr_name(conn->vsub),
ran_type_name(conn->via_ran));
switch (conn->via_ran) {
case RAN_GERAN_A:
msg->dst = conn;
- return a_tx(msg);
+ return a_iface_tx_dtap(msg);
case RAN_UTRAN_IU:
msg->dst = conn->iu.ue_ctx;
@@ -72,9 +78,15 @@ int msc_tx_dtap(struct gsm_subscriber_connection *conn,
/* 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));
+ struct msgb *msg;
+ struct gsm48_hdr *gh;
+
+ if (!conn)
+ return -EINVAL;
+ msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACC");
+
+ gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_CM_SERV_ACC;
@@ -89,6 +101,10 @@ int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
enum gsm48_reject_value value)
{
struct msgb *msg;
+
+ if (!conn)
+ return -EINVAL;
+
conn->received_cm_service_request = false;
msg = gsm48_create_mm_serv_rej(value);
@@ -104,6 +120,9 @@ int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
int msc_tx_common_id(struct gsm_subscriber_connection *conn)
{
+ if (!conn)
+ return -EINVAL;
+
/* Common ID is only sent over IuCS */
if (conn->via_ran != RAN_UTRAN_IU) {
LOGP(DMM, LOGL_INFO,
@@ -118,10 +137,10 @@ int msc_tx_common_id(struct gsm_subscriber_connection *conn)
return iu_tx_common_id(conn->iu.ue_ctx, conn->vsub->imsi);
}
-#ifdef BUILD_IU
-static void iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id,
- uint32_t rtp_ip, uint16_t rtp_port)
+static int iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id,
+ uint32_t rtp_ip, uint16_t rtp_port)
{
+#ifdef BUILD_IU
struct msgb *msg;
bool use_x213_nsap;
uint32_t conn_id = uectx->conn_id;
@@ -140,6 +159,11 @@ static void iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id,
LOGP(DIUCS, LOGL_ERROR, "Failed to send RAB Assignment:"
" conn_id=%d rab_id=%d rtp=%x:%u\n",
conn_id, rab_id, rtp_ip, rtp_port);
+ return 0;
+#else
+ LOGP(DMSC, LOGL_ERROR, "Cannot send Iu RAB Assignment: built without Iu support\n");
+ return -ENOTSUP;
+#endif
}
static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv)
@@ -165,71 +189,75 @@ static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv)
goto rab_act_cs_error;
}
- conn->iu.mgcp_rtp_port_cn = r->audio_port;
+ conn->rtp.port_cn = r->audio_port;
rtp_ip = mgcpgw_client_remote_addr_n(conn->network->mgcpgw.client);
- iu_rab_act_cs(uectx, conn->iu.rab_id, rtp_ip,
- conn->iu.mgcp_rtp_port_ue);
- /* use_x213_nsap == 0 for ip.access nano3G */
+
+ if (trans->conn->via_ran == RAN_UTRAN_IU) {
+ /* Assign a voice channel via RANAP on 3G */
+ if (iu_rab_act_cs(uectx, conn->iu.rab_id, rtp_ip, conn->rtp.port_subscr))
+ goto rab_act_cs_error;
+ } else if (trans->conn->via_ran == RAN_GERAN_A) {
+ /* Assign a voice channel via A on 2G */
+ if (a_iface_tx_assignment(trans))
+ goto rab_act_cs_error;
+ } else
+ goto rab_act_cs_error;
+
+ /* Respond back to MNCC (if requested) */
+ if (trans->tch_rtp_create) {
+ if (gsm48_tch_rtp_create(trans))
+ goto rab_act_cs_error;
+ }
+ return;
rab_act_cs_error:
/* FIXME abort call, invalidate conn, ... */
+ LOGP(DMSC, LOGL_ERROR, "%s: failure during assignment\n",
+ vlr_subscr_name(trans->vsub));
return;
}
-static int conn_iu_rab_act_cs(struct gsm_trans *trans)
+int msc_call_assignment(struct gsm_trans *trans)
{
- struct gsm_subscriber_connection *conn = trans->conn;
- struct mgcpgw_client *mgcp = conn->network->mgcpgw.client;
+ struct gsm_subscriber_connection *conn;
+ struct mgcpgw_client *mgcp;
struct msgb *msg;
+ uint16_t bts_base;
+
+ if (!trans)
+ return -EINVAL;
+ if (!trans->conn)
+ return -EINVAL;
- /* HACK. where to scope the RAB Id? At the conn / subscriber /
- * ue_conn_ctx? */
- static uint8_t next_rab_id = 1;
- conn->iu.rab_id = next_rab_id ++;
+ conn = trans->conn;
+ mgcp = conn->network->mgcpgw.client;
- conn->iu.mgcp_rtp_endpoint =
+#ifdef BUILD_IU
+ /* FIXME: HACK. where to scope the RAB Id? At the conn / subscriber / ue_conn_ctx? */
+ static uint8_t next_iu_rab_id = 1;
+ if (conn->via_ran == RAN_UTRAN_IU)
+ conn->iu.rab_id = next_iu_rab_id ++;
+#endif
+
+ conn->rtp.mgcp_rtp_endpoint =
mgcpgw_client_next_endpoint(conn->network->mgcpgw.client);
- /* HACK: the addresses should be known from CRCX response
- * and config. */
- conn->iu.mgcp_rtp_port_ue = 4000 + 2 * conn->iu.mgcp_rtp_endpoint;
+
+ /* This will calculate the port we assign to the BTS via AoIP
+ * assignment command (or rab-assignment on 3G) The BTS will send
+ * its RTP traffic to that port on the MGCPGW side. The MGCPGW only
+ * gets the endpoint ID via the CRCX. It will do the same calculation
+ * on his side too to get knowledge of the rtp port. */
+ bts_base = mgcp->actual.bts_base;
+ conn->rtp.port_subscr = bts_base + 2 * conn->rtp.mgcp_rtp_endpoint;
/* Establish the RTP stream first as looping back to the originator.
* The MDCX will patch through to the counterpart. TODO: play a ring
* tone instead. */
- msg = mgcp_msg_crcx(mgcp, conn->iu.mgcp_rtp_endpoint, trans->callref,
- MGCP_CONN_LOOPBACK);
+ msg = mgcp_msg_crcx(mgcp, conn->rtp.mgcp_rtp_endpoint,
+ conn->rtp.mgcp_rtp_endpoint, MGCP_CONN_LOOPBACK);
return mgcpgw_client_tx(mgcp, msg, mgcp_response_rab_act_cs_crcx, trans);
}
-#endif
-
-int msc_call_assignment(struct gsm_trans *trans)
-{
- struct gsm_subscriber_connection *conn = trans->conn;
-
- switch (conn->via_ran) {
- case RAN_GERAN_A:
- LOGP(DMSC, LOGL_ERROR,
- "msc_call_assignment(): A-interface BSSMAP Assignment"
- " Request not yet implemented\n");
- return -ENOTSUP;
-
- case RAN_UTRAN_IU:
-#ifdef BUILD_IU
- return conn_iu_rab_act_cs(trans);
-#else
- LOGP(DMSC, LOGL_ERROR,
- "msc_call_assignment(): cannot send RAB Activation, built without Iu support\n");
- return -ENOTSUP;
-#endif
-
- default:
- LOGP(DMSC, LOGL_ERROR,
- "msc_tx(): conn->via_ran invalid (%d)\n",
- conn->via_ran);
- return -EINVAL;
- }
-}
static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv);
@@ -252,8 +280,8 @@ static void mgcp_bridge(struct gsm_trans *from, struct gsm_trans *to,
ip = mgcpgw_client_remote_addr_str(mgcp);
msg = mgcp_msg_mdcx(mgcp,
- conn1->iu.mgcp_rtp_endpoint,
- ip, conn2->iu.mgcp_rtp_port_cn,
+ conn1->rtp.mgcp_rtp_endpoint,
+ ip, conn2->rtp.port_cn,
mode);
if (mgcpgw_client_tx(mgcp, msg, mgcp_response_bridge_mdcx, from))
LOGP(DMGCP, LOGL_ERROR,
@@ -302,8 +330,58 @@ static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv)
}
}
+int msc_call_connect(struct gsm_trans *trans, uint16_t port, uint32_t ip)
+{
+ /* With this function we inform the MGCP-GW where (ip/port) it
+ * has to send its outgoing voic traffic. The receiving end will
+ * usually be a PBX (e.g. Asterisk). The IP-Address we tell, will
+ * not only be used to direct the traffic, it will also be used
+ * as a filter to make sure only RTP packets from the right
+ * remote end will reach the BSS. This is also the reason why
+ * inbound audio will not work until this step is performed */
+
+ /* NOTE: This function is used when msc_call_bridge(), is not
+ * applicable. This is usually the case when an external MNCC
+ * is in use */
+
+ struct gsm_subscriber_connection *conn;
+ struct mgcpgw_client *mgcp;
+ struct msgb *msg;
+
+ if (!trans)
+ return -EINVAL;
+ if (!trans->conn)
+ return -EINVAL;
+ if (!trans->conn->network)
+ return -EINVAL;
+ if (!trans->conn->network->mgcpgw.client)
+ return -EINVAL;
+
+ mgcp = trans->conn->network->mgcpgw.client;
+
+ struct in_addr ip_addr;
+ ip_addr.s_addr = ntohl(ip);
+
+ conn = trans->conn;
+
+ msg = mgcp_msg_mdcx(mgcp,
+ conn->rtp.mgcp_rtp_endpoint,
+ inet_ntoa(ip_addr), port, MGCP_CONN_RECV_SEND);
+ if (mgcpgw_client_tx(mgcp, msg, NULL, trans))
+ LOGP(DMGCP, LOGL_ERROR,
+ "Failed to send MDCX message for %s\n",
+ vlr_subscr_name(trans->vsub));
+
+ return 0;
+}
+
int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2)
{
+ if (!trans1)
+ return -EINVAL;
+ if (!trans2)
+ return -EINVAL;
+
/* First setup as loopback and configure the counterparts' endpoints,
* so that when transmission starts the originating addresses are
* already known to be valid. The mgcp callback will continue. */
@@ -314,3 +392,31 @@ int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2)
return 0;
}
+
+void msc_call_release(struct gsm_trans *trans)
+{
+ struct msgb *msg;
+ struct gsm_subscriber_connection *conn;
+ struct mgcpgw_client *mgcp;
+
+ if (!trans)
+ return;
+ if (!trans->conn)
+ return;
+ if (!trans->conn->network)
+ return;
+
+ conn = trans->conn;
+ mgcp = conn->network->mgcpgw.client;
+
+ /* Send DLCX */
+ msg = mgcp_msg_dlcx(mgcp, conn->rtp.mgcp_rtp_endpoint,
+ conn->rtp.mgcp_rtp_endpoint);
+ if (mgcpgw_client_tx(mgcp, msg, NULL, NULL))
+ LOGP(DMGCP, LOGL_ERROR,
+ "Failed to send DLCX message for %s\n",
+ vlr_subscr_name(trans->vsub));
+
+ /* Release endpoint id */
+ mgcpgw_client_release_endpoint(conn->rtp.mgcp_rtp_endpoint, mgcp);
+}
diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c
index 82dc7d679..01e7e8295 100644
--- a/src/libmsc/msc_vty.c
+++ b/src/libmsc/msc_vty.c
@@ -64,6 +64,26 @@ DEFUN(cfg_msc_no_assign_tmsi, cfg_msc_no_assign_tmsi_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_msc_cs7_instance_a,
+ cfg_msc_cs7_instance_a_cmd,
+ "cs7-instance-a <0-15>",
+ "Set SS7 to be used by the A-Interface.\n" "SS7 instance reference number\n")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ gsmnet->a.cs7_instance = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_msc_cs7_instance_iu,
+ cfg_msc_cs7_instance_iu_cmd,
+ "cs7-instance-iu <0-15>",
+ "Set SS7 to be used by the Iu-Interface.\n" "SS7 instance reference number\n")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ gsmnet->iu.cs7_instance = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
static int config_write_msc(struct vty *vty)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -72,6 +92,11 @@ static int config_write_msc(struct vty *vty)
vty_out(vty, " %sassign-tmsi%s",
gsmnet->vlr->cfg.assign_tmsi? "" : "no ", VTY_NEWLINE);
+ vty_out(vty, " cs7-instance-a %u%s", gsmnet->a.cs7_instance,
+ VTY_NEWLINE);
+ vty_out(vty, " cs7-instance-iu %u%s", gsmnet->iu.cs7_instance,
+ VTY_NEWLINE);
+
mgcpgw_client_config_write(vty, " ");
#ifdef BUILD_IU
iu_vty_config_write(vty, " ");
@@ -123,6 +148,9 @@ void msc_vty_init(struct gsm_network *msc_network)
vty_install_default(MSC_NODE);
install_element(MSC_NODE, &cfg_msc_assign_tmsi_cmd);
install_element(MSC_NODE, &cfg_msc_no_assign_tmsi_cmd);
+ install_element(MSC_NODE, &cfg_msc_cs7_instance_a_cmd);
+ install_element(MSC_NODE, &cfg_msc_cs7_instance_iu_cmd);
+
mgcpgw_client_vty_init(MSC_NODE, &msc_network->mgcpgw.conf);
#ifdef BUILD_IU
iu_vty_init(MSC_NODE, &msc_network->iu.rab_assign_addr_enc);
diff --git a/src/libmsc/osmo_msc.c b/src/libmsc/osmo_msc.c
index ddc383612..866cfbd07 100644
--- a/src/libmsc/osmo_msc.c
+++ b/src/libmsc/osmo_msc.c
@@ -29,11 +29,12 @@
#include <openbsc/vlr.h>
#include <openbsc/osmo_msc.h>
#include <openbsc/iu.h>
+#include <openbsc/a_iface.h>
#include <openbsc/gsm_04_11.h>
/* Receive a SAPI-N-REJECT from BSC */
-static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
+void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
{
int sapi = dlci & 0x7;
@@ -106,24 +107,24 @@ void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct ms
}
/* Receive an ASSIGNMENT COMPLETE from BSC */
-static void msc_assign_compl(struct gsm_subscriber_connection *conn,
- uint8_t rr_cause, uint8_t chosen_channel,
- uint8_t encr_alg_id, uint8_t speec)
+void msc_assign_compl(struct gsm_subscriber_connection *conn,
+ uint8_t rr_cause, uint8_t chosen_channel,
+ uint8_t encr_alg_id, uint8_t speec)
{
LOGP(DRR, LOGL_DEBUG, "MSC assign complete (do nothing).\n");
}
/* Receive an ASSIGNMENT FAILURE from BSC */
-static void msc_assign_fail(struct gsm_subscriber_connection *conn,
- uint8_t cause, uint8_t *rr_cause)
+void msc_assign_fail(struct gsm_subscriber_connection *conn,
+ uint8_t cause, uint8_t *rr_cause)
{
LOGP(DRR, LOGL_DEBUG, "MSC assign failure (do nothing).\n");
}
/* Receive a CLASSMARK CHANGE from BSC */
-static void msc_classmark_chg(struct gsm_subscriber_connection *conn,
- const uint8_t *cm2, uint8_t cm2_len,
- const uint8_t *cm3, uint8_t cm3_len)
+void msc_classmark_chg(struct gsm_subscriber_connection *conn,
+ const uint8_t *cm2, uint8_t cm2_len,
+ const uint8_t *cm3, uint8_t cm3_len)
{
if (cm2 && cm2_len) {
if (cm2_len > sizeof(conn->classmark.classmark2)) {
@@ -250,7 +251,7 @@ void msc_subscr_con_free(struct gsm_subscriber_connection *conn)
}
/* Receive a CLEAR REQUEST from BSC */
-static int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
+int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
{
msc_subscr_conn_close(conn, cause);
return 1;
@@ -290,7 +291,7 @@ static void msc_subscr_conn_release_all(struct gsm_subscriber_connection *conn,
* says "unknown UE" for each release outcome. */
break;
case RAN_GERAN_A:
- /* future: a_iface_tx_clear_cmd(conn); */
+ a_iface_tx_clear_cmd(conn);
break;
default:
LOGP(DMM, LOGL_ERROR, "%s: Unknown RAN type, cannot tx release/clear\n",
diff --git a/src/libmsc/subscr_conn.c b/src/libmsc/subscr_conn.c
index 31decc7b3..cdeeae903 100644
--- a/src/libmsc/subscr_conn.c
+++ b/src/libmsc/subscr_conn.c
@@ -31,6 +31,8 @@
#include <openbsc/transaction.h>
#include <openbsc/signal.h>
#include <openbsc/iu.h>
+#include <openbsc/a_iface.h>
+
#define SUBSCR_CONN_TIMEOUT 5 /* seconds */
@@ -223,7 +225,6 @@ static void subscr_conn_fsm_cleanup(struct osmo_fsm_inst *fi,
if (!conn)
return;
-
conn->conn_fsm = NULL;
msc_subscr_conn_close(conn, cause);
msc_subscr_conn_put(conn);
diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am
index ae9410c9d..5642fb2ed 100644
--- a/src/osmo-bsc/Makefile.am
+++ b/src/osmo-bsc/Makefile.am
@@ -14,6 +14,7 @@ AM_CFLAGS = \
$(LIBOSMOSCCP_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
+ $(LIBOSMOSIGTRAN_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
@@ -30,7 +31,7 @@ osmo_bsc_SOURCES = \
osmo_bsc_api.c \
osmo_bsc_grace.c \
osmo_bsc_msc.c \
- osmo_bsc_sccp.c \
+ osmo_bsc_sigtran.c \
osmo_bsc_filter.c \
osmo_bsc_bssap.c \
osmo_bsc_audio.c \
@@ -52,4 +53,5 @@ osmo_bsc_LDADD = \
$(LIBOSMOCTRL_LIBS) \
$(COVERAGE_LDFLAGS) \
$(LIBOSMOABIS_LIBS) \
+ $(LIBOSMOSIGTRAN_LIBS) \
$(NULL)
diff --git a/src/osmo-bsc/osmo_bsc_api.c b/src/osmo-bsc/osmo_bsc_api.c
index 8c33e2b57..f7343f743 100644
--- a/src/osmo-bsc/osmo_bsc_api.c
+++ b/src/osmo-bsc/osmo_bsc_api.c
@@ -27,6 +27,7 @@
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/sccp/sccp.h>
+#include <openbsc/osmo_bsc_sigtran.h>
#define return_when_not_connected(conn) \
if (!conn->sccp_con) {\
@@ -45,7 +46,7 @@
LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n"); \
return; \
} \
- bsc_queue_for_msc(conn->sccp_con, resp);
+ osmo_bsc_sigtran_send(conn->sccp_con, resp);
static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause);
static int complete_layer3(struct gsm_subscriber_connection *conn,
@@ -263,7 +264,8 @@ static int complete_layer3(struct gsm_subscriber_connection *conn,
}
/* allocate resource for a new connection */
- ret = bsc_create_new_connection(conn, msc, send_ping);
+ //ret = bsc_create_new_connection(conn, msc, send_ping);
+ ret = osmo_bsc_sigtran_new_conn(conn, msc);
if (ret != BSC_CON_SUCCESS) {
/* allocation has failed */
@@ -292,13 +294,13 @@ static int complete_layer3(struct gsm_subscriber_connection *conn,
if (!resp) {
LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n");
sccp_connection_free(conn->sccp_con->sccp);
- bsc_delete_connection(conn->sccp_con);
+ osmo_bsc_sigtran_del_conn(conn->sccp_con);
return BSC_API_CONN_POL_REJECT;
}
- if (bsc_open_connection(conn->sccp_con, resp) != 0) {
+ if (osmo_bsc_sigtran_open_conn(conn->sccp_con, resp) != 0) {
sccp_connection_free(conn->sccp_con->sccp);
- bsc_delete_connection(conn->sccp_con);
+ osmo_bsc_sigtran_del_conn(conn->sccp_con);
msgb_free(resp);
return BSC_API_CONN_POL_REJECT;
}
@@ -433,11 +435,28 @@ static void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_
struct msgb *resp;
return_when_not_connected(conn);
- LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL\n");
-
- resp = gsm0808_create_assignment_completed(rr_cause, chosen_channel,
- encr_alg_id, speech_model);
- queue_msg_or_return(resp);
+ if (is_ipaccess_bts(conn->bts) && conn->sccp_con->rtp_ip) {
+ /* NOTE: In a network that makes use of an IPA base station
+ * and AoIP, we have to wait until the BTS reports its RTP
+ * IP/Port combination back to BSC via RSL. Unfortunately, the
+ * IPA protocol sends its Abis assignment complete message
+ * before it sends its RTP IP/Port via IPACC. So we will now
+ * postpone the AoIP assignment completed message until we
+ * know the RTP IP/Port combination. */
+ LOGP(DMSC, LOGL_INFO, "POSTPONE MSC ASSIGN COMPL\n");
+ conn->lchan->abis_ip.ass_compl.rr_cause = rr_cause;
+ conn->lchan->abis_ip.ass_compl.chosen_channel = chosen_channel;
+ conn->lchan->abis_ip.ass_compl.encr_alg_id = encr_alg_id;
+ conn->lchan->abis_ip.ass_compl.speech_mode = speech_model;
+ conn->lchan->abis_ip.ass_compl.valid = true;
+
+ } else {
+ /* NOTE: Send the A assignment complete message immediately. */
+ LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL\n");
+ resp = gsm0808_create_assignment_completed(rr_cause, chosen_channel,
+ encr_alg_id, speech_model);
+ queue_msg_or_return(resp);
+ }
}
static void bsc_assign_fail(struct gsm_subscriber_connection *conn,
@@ -474,7 +493,7 @@ static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t ca
return 1;
}
- bsc_queue_for_msc(sccp, resp);
+ osmo_bsc_sigtran_send(sccp, resp);
return 1;
}
diff --git a/src/osmo-bsc/osmo_bsc_audio.c b/src/osmo-bsc/osmo_bsc_audio.c
index 116020900..b4ffa88f1 100644
--- a/src/osmo-bsc/osmo_bsc_audio.c
+++ b/src/osmo-bsc/osmo_bsc_audio.c
@@ -26,15 +26,57 @@
#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
#include <openbsc/signal.h>
+#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/gsm/gsm0808_utils.h>
+#include <openbsc/osmo_bsc_sigtran.h>
#include <arpa/inet.h>
+/* Generate and send assignment complete message */
+static int send_aoip_ass_compl(struct gsm_subscriber_connection *conn, struct gsm_lchan *lchan)
+{
+ struct msgb *resp;
+ struct sockaddr_storage rtp_addr;
+ struct sockaddr_in rtp_addr_in;
+ struct gsm0808_speech_codec sc;
+
+ OSMO_ASSERT(lchan->abis_ip.ass_compl.valid == true);
+
+ /* Package RTP-Address data */
+ memset(&rtp_addr_in, 0, sizeof(rtp_addr_in));
+ rtp_addr_in.sin_family = AF_INET;
+ rtp_addr_in.sin_port = htons(lchan->abis_ip.bound_port);
+ rtp_addr_in.sin_addr.s_addr = htonl(lchan->abis_ip.bound_ip);
+ memset(&rtp_addr, 0, sizeof(rtp_addr));
+ memcpy(&rtp_addr, &rtp_addr_in, sizeof(rtp_addr_in));
+
+ /* Extrapolate speech codec from speech mode */
+ gsm0808_speech_codec_from_chan_type(&sc, lchan->abis_ip.ass_compl.speech_mode);
+
+ /* Generate message */
+ resp = gsm0808_create_ass_compl(lchan->abis_ip.ass_compl.rr_cause,
+ lchan->abis_ip.ass_compl.chosen_channel,
+ lchan->abis_ip.ass_compl.encr_alg_id,
+ lchan->abis_ip.ass_compl.speech_mode,
+ &rtp_addr,
+ &sc,
+ NULL);
+
+ if (!resp) {
+ LOGP(DMSC, LOGL_ERROR, "Failed to generate assignment completed message!\n"); \
+ return -EINVAL;
+ }
+
+ return osmo_bsc_sigtran_send(conn->sccp_con, resp);
+}
+
static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
struct gsm_subscriber_connection *con;
struct gsm_lchan *lchan = signal_data;
int rc;
+ uint32_t rtp_ip;
if (subsys != SS_ABISIP)
return 0;
@@ -49,11 +91,19 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
* TODO: handle handover here... then the audio should go to
* the old mgcp port..
*/
+
/* we can ask it to connect now */
LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n",
con->sccp_con->rtp_port, lchan->abis_ip.conn_id);
- rc = rsl_ipacc_mdcx(lchan, ntohl(INADDR_ANY),
+ /* If AoIP is in use, the rtp_ip, which has been communicated
+ * via the A interface as connect_ip */
+ if(con->sccp_con->rtp_ip)
+ rtp_ip = con->sccp_con->rtp_ip;
+ else
+ rtp_ip = ntohl(INADDR_ANY);
+
+ rc = rsl_ipacc_mdcx(lchan, rtp_ip,
con->sccp_con->rtp_port,
lchan->abis_ip.rtp_payload2);
if (rc < 0) {
@@ -61,6 +111,24 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
return rc;
}
break;
+
+ case S_ABISIP_MDCX_ACK:
+ if (con->ho_lchan) {
+ /* NOTE: When an ho_lchan exists, the MDCX is part of an
+ * handover operation (intra-bsc). This means we will not
+ * inform the MSC about the event, which means that no
+ * assignment complete message is transmitted */
+ LOGP(DMSC, LOGL_INFO," RTP connection handover complete\n");
+ } else if (is_ipaccess_bts(con->bts) && con->sccp_con->rtp_ip) {
+ /* NOTE: This is only relevant on AoIP networks with
+ * IPA based base stations. See also osmo_bsc_api.c,
+ * function bsc_assign_compl() */
+ LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL (POSTPONED)\n");
+ if (send_aoip_ass_compl(con, lchan) != 0)
+ return -EINVAL;
+ }
+ break;
+ break;
}
return 0;
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index 100f66441..4353b9ad0 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -29,11 +29,21 @@
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/gsm/gsm0808_utils.h>
+#include <openbsc/osmo_bsc_sigtran.h>
+#include <openbsc/a_reset.h>
+#include <osmocom/core/byteswap.h>
+
+#define IP_V4_ADDR_LEN 4
/*
* helpers for the assignment command
*/
-enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support *audio)
+
+/* Helper function for match_codec_pref(), looks up a matching permitted speech
+ * value for a given msc audio codec pref */
+enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support
+ *audio)
{
if (audio->hr) {
switch (audio->ver) {
@@ -47,8 +57,9 @@ enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support *a
return GSM0808_PERM_HR3;
break;
default:
- LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", audio->ver);
- return GSM0808_PERM_FR1;
+ LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n",
+ audio->ver);
+ return GSM0808_PERM_FR1;
}
} else {
switch (audio->ver) {
@@ -62,12 +73,15 @@ enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support *a
return GSM0808_PERM_FR3;
break;
default:
- LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", audio->ver);
+ LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n",
+ audio->ver);
return GSM0808_PERM_HR1;
}
}
}
+/* Helper function for match_codec_pref(), looks up a matching chan mode for
+ * a given permitted speech value */
enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
{
switch (speech) {
@@ -83,16 +97,130 @@ enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
case GSM0808_PERM_FR3:
return GSM48_CMODE_SPEECH_AMR;
break;
+ default:
+ LOGP(DMSC, LOGL_FATAL,
+ "Unsupported permitted speech selected, assuming AMR as channel mode...\n");
+ return GSM48_CMODE_SPEECH_AMR;
+ }
+}
+
+/* Helper function for match_codec_pref(), tests if a given audio support
+ * matches one of the permitted speech settings of the channel type element.
+ * The matched permitted speech value is then also compared against the
+ * speech codec list. (optional, only relevant for AoIP) */
+static bool test_codec_pref(const struct gsm0808_channel_type *ct,
+ const struct gsm0808_speech_codec_list *scl,
+ uint8_t perm_spch)
+{
+ unsigned int i;
+ bool match = false;
+ struct gsm0808_speech_codec sc;
+ int rc;
+
+ /* Try to finde the given permitted speech value in the
+ * codec list of the channel type element */
+ for (i = 0; i < ct->perm_spch_len; i++) {
+ if (ct->perm_spch[i] == perm_spch) {
+ match = true;
+ break;
+ }
+ }
+
+ /* If we do not have a speech codec list to test against,
+ * we just exit early (will be always the case in non-AoIP networks) */
+ if (!scl)
+ return match;
+
+ /* If we failed to match until here, there is no
+ * point in testing further */
+ if (match == false)
+ return false;
+
+ /* Extrapolate speech codec data */
+ rc = gsm0808_speech_codec_from_chan_type(&sc, perm_spch);
+ if (rc < 0)
+ return false;
+
+ /* Try to find extrapolated speech codec data in
+ * the speech codec list */
+ for (i = 0; i < scl->len; i++) {
+ if (memcmp(&sc, &scl->codec[i], sizeof(sc)) == 0)
+ return true;
}
- LOGP(DMSC, LOGL_FATAL, "Should not be reached.\n");
- return GSM48_CMODE_SPEECH_AMR;
+ return false;
+}
+
+/* Helper function for bssmap_handle_assignm_req(), matches the codec
+ * preferences from the MSC with the codec preferences */
+static int match_codec_pref(int *full_rate, enum gsm48_chan_mode *chan_mode,
+ const struct gsm0808_channel_type *ct,
+ const struct gsm0808_speech_codec_list *scl,
+ const struct bsc_msc_data *msc)
+{
+ unsigned int i;
+ uint8_t perm_spch;
+ bool match = false;
+
+ for (i = 0; i < msc->audio_length; i++) {
+ perm_spch = audio_support_to_gsm88(msc->audio_support[i]);
+ if (test_codec_pref(ct, scl, perm_spch)) {
+ match = true;
+ break;
+ }
+ }
+
+ /* Exit without result, in case no match can be deteched */
+ if (!match) {
+ *full_rate = -1;
+ *chan_mode = GSM48_CMODE_SIGN;
+ return -1;
+ }
+
+ /* Check if the result is a half or full rate codec */
+ if (perm_spch == GSM0808_PERM_HR1 || perm_spch == GSM0808_PERM_HR2
+ || perm_spch == GSM0808_PERM_HR3 || perm_spch == GSM0808_PERM_HR4
+ || perm_spch == GSM0808_PERM_HR6)
+ *full_rate = 0;
+ else
+ *full_rate = 1;
+
+ /* Lookup a channel mode for the selected codec */
+ *chan_mode = gsm88_to_chan_mode(perm_spch);
+
+ return 0;
}
static int bssmap_handle_reset_ack(struct bsc_msc_data *msc,
struct msgb *msg, unsigned int length)
{
- LOGP(DMSC, LOGL_NOTICE, "Reset ACK from MSC\n");
+ LOGP(DMSC, LOGL_NOTICE, "RESET ACK from MSC: %s\n",
+ osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance),
+ &msc->a.msc_addr));
+
+ /* Inform the FSM that controls the RESET/RESET-ACK procedure
+ * that we have successfully received the reset-ack message */
+ a_reset_ack_confirm(msc->a.reset);
+
+ return 0;
+}
+
+/* Handle MSC sided reset */
+static int bssmap_handle_reset(struct bsc_msc_data *msc,
+ struct msgb *msg, unsigned int length)
+{
+ LOGP(DMSC, LOGL_NOTICE, "RESET from MSC: %s\n",
+ osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance),
+ &msc->a.msc_addr));
+
+ /* Instruct the bsc to close all open sigtran connections and to
+ * close all active channels on the BTS side as well */
+ osmo_bsc_sigtran_reset(msc);
+
+ /* Inform the MSC that we have received the reset request and
+ * that we acted accordingly */
+ osmo_bsc_sigtran_tx_reset_ack(msc);
+
return 0;
}
@@ -199,7 +327,7 @@ static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn,
return -1;
}
- bsc_queue_for_msc(conn, resp);
+ osmo_bsc_sigtran_send(conn, resp);
return 0;
}
@@ -276,7 +404,7 @@ reject:
return -1;
}
- bsc_queue_for_msc(conn, resp);
+ osmo_bsc_sigtran_send(conn, resp);
return -1;
}
@@ -291,99 +419,141 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
struct msgb *resp;
struct bsc_msc_data *msc;
struct tlv_parsed tp;
- uint8_t *data;
- uint8_t timeslot;
- uint8_t multiplex;
+ uint8_t timeslot = 0;
+ uint8_t multiplex = 0;
enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN;
- int i, supported, port, full_rate = -1;
+ int port, full_rate = -1;
+ bool aoip = false;
+ struct sockaddr_storage rtp_addr;
+ struct sockaddr_in *rtp_addr_in;
+ struct gsm0808_channel_type ct;
+ struct gsm0808_speech_codec_list scl;
+ struct gsm0808_speech_codec_list *scl_ptr = NULL;
+ int rc;
+ const uint8_t *data;
+ char len;
if (!conn->conn) {
- LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
+ LOGP(DMSC, LOGL_ERROR,
+ "No lchan/msc_data in cipher mode command.\n");
return -1;
}
+ msc = conn->msc;
+
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0);
+ /* Check for channel type element, if its missing, immediately reject */
if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)) {
LOGP(DMSC, LOGL_ERROR, "Mandatory channel type not present.\n");
goto reject;
}
- if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
- LOGP(DMSC, LOGL_ERROR, "Identity code missing. Audio routing will not work.\n");
+ /* Detect if a CIC code is present, if so, we use the classic ip.access
+ * method to calculate the RTP port */
+ if (TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
+ conn->cic =
+ osmo_load16be(TLVP_VAL
+ (&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
+ timeslot = conn->cic & 0x1f;
+ multiplex = (conn->cic & ~0x1f) >> 5;
+ } else if (TLVP_PRESENT(&tp, GSM0808_IE_AOIP_TRASP_ADDR)) {
+ /* Decode AoIP transport address element */
+ data = TLVP_VAL(&tp, GSM0808_IE_AOIP_TRASP_ADDR);
+ len = TLVP_LEN(&tp, GSM0808_IE_AOIP_TRASP_ADDR);
+ rc = gsm0808_dec_aoip_trasp_addr(&rtp_addr, data, len);
+ if (rc < 0) {
+ LOGP(DMSC, LOGL_ERROR,
+ "Unable to decode aoip transport address.\n");
+ goto reject;
+ }
+ aoip = true;
+ } else {
+ LOGP(DMSC, LOGL_ERROR,
+ "transport address missing. Audio routing will not work.\n");
goto reject;
}
- conn->cic = osmo_load16be(TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
- timeslot = conn->cic & 0x1f;
- multiplex = (conn->cic & ~0x1f) >> 5;
+ /* Decode speech codec list (AoIP) */
+ if (aoip) {
+ /* Check for speech codec list element */
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_SPEECH_CODEC_LIST)) {
+ LOGP(DMSC, LOGL_ERROR,
+ "Mandatory speech codec list not present.\n");
+ goto reject;
+ }
- /*
- * Currently we only support a limited subset of all
- * possible channel types. The limitation ends by not using
- * multi-slot, limiting the channel coding, speech...
- */
- if (TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE) < 3) {
- LOGP(DMSC, LOGL_ERROR, "ChannelType len !=3 not supported: %d\n",
- TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE));
- goto reject;
+ /* Decode Speech Codec list */
+ data = TLVP_VAL(&tp, GSM0808_IE_SPEECH_CODEC_LIST);
+ len = TLVP_LEN(&tp, GSM0808_IE_SPEECH_CODEC_LIST);
+ rc = gsm0808_dec_speech_codec_list(&scl, data, len);
+ if (rc < 0) {
+ LOGP(DMSC, LOGL_ERROR,
+ "Unable to decode speech codec list\n");
+ goto reject;
+ }
+ scl_ptr = &scl;
}
- /*
- * Try to figure out if we support the proposed speech codecs. For
- * now we will always pick the full rate codecs.
- */
-
- data = (uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE);
- if ((data[0] & 0xf) != 0x1) {
- LOGP(DMSC, LOGL_ERROR, "ChannelType != speech: %d\n", data[0]);
+ /* Decode Channel Type element */
+ data = TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE);
+ len = TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE);
+ rc = gsm0808_dec_channel_type(&ct, data, len);
+ if (rc < 0) {
+ LOGP(DMSC, LOGL_ERROR, "unable to decode channel type.\n");
goto reject;
}
- /*
- * go through the list of preferred codecs of our gsm network
- * and try to find it among the permitted codecs. If we found
- * it we will send chan_mode to the right mode and break the
- * inner loop. The outer loop will exit due chan_mode having
- * the correct value.
- */
- full_rate = 0;
- msc = conn->msc;
- for (supported = 0;
- chan_mode == GSM48_CMODE_SIGN && supported < msc->audio_length;
- ++supported) {
-
- int perm_val = audio_support_to_gsm88(msc->audio_support[supported]);
- for (i = 2; i < TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE); ++i) {
- if ((data[i] & 0x7f) == perm_val) {
- chan_mode = gsm88_to_chan_mode(perm_val);
- full_rate = (data[i] & 0x4) == 0;
- break;
- } else if ((data[i] & 0x80) == 0x00) {
- break;
- }
- }
+ /* Currently we only support a limited subset of all
+ * possible channel types. The limitation ends by not using
+ * multi-slot, limiting the channel coding to speech */
+ if (ct.ch_indctr != GSM0808_CHAN_SPEECH) {
+ LOGP(DMSC, LOGL_ERROR,
+ "Unsupported channel type, currently only speech is supported!\n");
+ goto reject;
}
- if (chan_mode == GSM48_CMODE_SIGN) {
+ /* Match codec information from the assignment command against the
+ * local preferences of the BSC */
+ rc = match_codec_pref(&full_rate, &chan_mode, &ct, scl_ptr, msc);
+ if (rc < 0) {
LOGP(DMSC, LOGL_ERROR, "No supported audio type found.\n");
goto reject;
}
- /* map it to a MGCP Endpoint and a RTP port */
- port = mgcp_timeslot_to_endpoint(multiplex, timeslot);
- conn->rtp_port = rtp_calculate_port(port, msc->rtp_base);
+ if (aoip == false) {
+ /* map it to a MGCP Endpoint and a RTP port */
+ port = mgcp_timeslot_to_endpoint(multiplex, timeslot);
+ conn->rtp_port = rtp_calculate_port(port, msc->rtp_base);
+ conn->rtp_ip = 0;
+ } else {
+ /* use address / port supplied with the AoIP
+ * transport address element */
+ if (rtp_addr.ss_family == AF_INET) {
+ rtp_addr_in = (struct sockaddr_in *)&rtp_addr;
+ conn->rtp_port = osmo_ntohs(rtp_addr_in->sin_port);
+ memcpy(&conn->rtp_ip, &rtp_addr_in->sin_addr.s_addr,
+ IP_V4_ADDR_LEN);
+ conn->rtp_ip = osmo_ntohl(conn->rtp_ip);
+ } else {
+ LOGP(DMSC, LOGL_ERROR,
+ "Unsopported addressing scheme. (supports only IPV4)\n");
+ goto reject;
+ }
+ }
return gsm0808_assign_req(conn->conn, chan_mode, full_rate);
reject:
- resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
+ resp =
+ gsm0808_create_assignment_failure
+ (GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Channel allocation failure.\n");
return -1;
}
- bsc_queue_for_msc(conn, resp);
+ osmo_bsc_sigtran_send(conn, resp);
return -1;
}
@@ -404,6 +574,9 @@ static int bssmap_rcvmsg_udt(struct bsc_msc_data *msc,
case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
ret = bssmap_handle_reset_ack(msc, msg, length);
break;
+ case BSS_MAP_MSG_RESET:
+ ret = bssmap_handle_reset(msc, msg, length);
+ break;
case BSS_MAP_MSG_PAGING:
ret = bssmap_handle_paging(msc, msg, length);
break;
@@ -524,8 +697,8 @@ int bsc_handle_udt(struct bsc_msc_data *msc,
return 0;
}
-int bsc_handle_dt1(struct osmo_bsc_sccp_con *conn,
- struct msgb *msg, unsigned int len)
+int bsc_handle_dt(struct osmo_bsc_sccp_con *conn,
+ struct msgb *msg, unsigned int len)
{
if (len < sizeof(struct bssmap_header)) {
LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c
index 90651b95e..cf188a9e0 100644
--- a/src/osmo-bsc/osmo_bsc_main.c
+++ b/src/osmo-bsc/osmo_bsc_main.c
@@ -28,6 +28,7 @@
#include <openbsc/vty.h>
#include <openbsc/ipaccess.h>
#include <openbsc/ctrl.h>
+#include <openbsc/osmo_bsc_sigtran.h>
#include <osmocom/ctrl/control_cmd.h>
#include <osmocom/ctrl/control_if.h>
@@ -217,6 +218,10 @@ int main(int argc, char **argv)
bsc_msg_lst_vty_init(tall_bsc_ctx, &access_lists, BSC_NODE);
ctrl_vty_init(tall_bsc_ctx);
+ /* Initalize SS7 */
+ osmo_ss7_init();
+ osmo_ss7_vty_init_asp(tall_bsc_ctx);
+
INIT_LLIST_HEAD(&access_lists);
/* parse options */
@@ -269,9 +274,8 @@ int main(int argc, char **argv)
}
}
-
- if (osmo_bsc_sccp_init(bsc_gsmnet) != 0) {
- LOGP(DNM, LOGL_ERROR, "Failed to register SCCP.\n");
+ if (osmo_bsc_sigtran_init(&bsc_gsmnet->bsc_data->mscs) != 0) {
+ LOGP(DNM, LOGL_ERROR, "Failed to initalize sigtran backhaul.\n");
exit(1);
}
diff --git a/src/osmo-bsc/osmo_bsc_msc.c b/src/osmo-bsc/osmo_bsc_msc.c
index 8d02624b4..351fd2ced 100644
--- a/src/osmo-bsc/osmo_bsc_msc.c
+++ b/src/osmo-bsc/osmo_bsc_msc.c
@@ -42,7 +42,7 @@
#include <netinet/tcp.h>
#include <unistd.h>
-
+#if 0
static void initialize_if_needed(struct bsc_msc_connection *conn);
static void send_lacs(struct gsm_network *net, struct bsc_msc_connection *conn);
static void send_id_get_response(struct bsc_msc_data *data, int fd, struct msgb *inp);
@@ -52,6 +52,8 @@ static void schedule_ping_pong(struct bsc_msc_data *data);
/*
* MGCP forwarding code
*/
+
+#endif
static int mgcp_do_read(struct osmo_fd *fd)
{
struct bsc_msc_data *data = (struct bsc_msc_data *) fd->data;
@@ -93,6 +95,7 @@ static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
return ret;
}
+#if 0
static void mgcp_forward(struct bsc_msc_data *data, struct msgb *msg)
{
struct msgb *mgcp;
@@ -115,6 +118,7 @@ static void mgcp_forward(struct bsc_msc_data *data, struct msgb *msg)
msgb_free(mgcp);
}
}
+#endif
static int mgcp_create_port(struct bsc_msc_data *data)
{
@@ -168,6 +172,7 @@ static int mgcp_create_port(struct bsc_msc_data *data)
return 0;
}
+
/*
* Send data to the network
*/
@@ -183,6 +188,7 @@ int msc_queue_write(struct bsc_msc_connection *conn, struct msgb *msg, int proto
return 0;
}
+#if 0
int msc_queue_write_with_ping(struct bsc_msc_connection *conn,
struct msgb *msg, int proto)
{
@@ -356,10 +362,10 @@ static void msc_ping_timeout_cb(void *_data)
static void msc_pong_timeout_cb(void *_data)
{
- struct bsc_msc_data *data = (struct bsc_msc_data *) _data;
+// struct bsc_msc_data *data = (struct bsc_msc_data *) _data;
LOGP(DMSC, LOGL_ERROR, "MSC didn't answer PING. Closing connection.\n");
- bsc_msc_lost(data->msc_con);
+// bsc_msc_lost(data->msc_con);
}
static void msc_connection_connected(struct bsc_msc_connection *con)
@@ -368,12 +374,12 @@ static void msc_connection_connected(struct bsc_msc_connection *con)
struct bsc_msc_data *data;
int ret, on;
on = 1;
- ret = setsockopt(con->write_queue.bfd.fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
- if (ret != 0)
- LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
+// ret = setsockopt(con->write_queue.bfd.fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
+// if (ret != 0)
+// LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
- data = (struct bsc_msc_data *) con->write_queue.bfd.data;
- msc_ping_timeout_cb(data);
+// data = (struct bsc_msc_data *) con->write_queue.bfd.data;
+// msc_ping_timeout_cb(data);
sig.data = data;
osmo_signal_dispatch(SS_MSC, S_MSC_CONNECTED, &sig);
@@ -385,20 +391,20 @@ static void msc_connection_connected(struct bsc_msc_connection *con)
*/
static void msc_connection_was_lost(struct bsc_msc_connection *msc)
{
- struct msc_signal_data sig;
- struct bsc_msc_data *data;
+// struct msc_signal_data sig;
+// struct bsc_msc_data *data;
LOGP(DMSC, LOGL_ERROR, "Lost MSC connection. Freing stuff.\n");
- data = (struct bsc_msc_data *) msc->write_queue.bfd.data;
- osmo_timer_del(&data->ping_timer);
- osmo_timer_del(&data->pong_timer);
-
- sig.data = data;
- osmo_signal_dispatch(SS_MSC, S_MSC_LOST, &sig);
+// data = (struct bsc_msc_data *) msc->write_queue.bfd.data;
+// osmo_timer_del(&data->ping_timer);
+// osmo_timer_del(&data->pong_timer);
+//
+// sig.data = data;
+// osmo_signal_dispatch(SS_MSC, S_MSC_LOST, &sig);
msc->is_authenticated = 0;
- bsc_msc_schedule_connect(msc);
+// bsc_msc_schedule_connect(msc);
}
static void send_lacs(struct gsm_network *net, struct bsc_msc_connection *conn)
@@ -515,6 +521,8 @@ static void send_id_get_response(struct bsc_msc_data *data, int fd, struct msgb
osmo_signal_dispatch(SS_MSC, S_MSC_AUTHENTICATED, &sig);
}
+#endif
+
int osmo_bsc_msc_init(struct bsc_msc_data *data)
{
if (mgcp_create_port(data) != 0)
@@ -526,19 +534,24 @@ int osmo_bsc_msc_init(struct bsc_msc_data *data)
return -1;
}
- osmo_timer_setup(&data->ping_timer, msc_ping_timeout_cb, data);
- osmo_timer_setup(&data->pong_timer, msc_pong_timeout_cb, data);
+// osmo_timer_setup(&data->ping_timer, msc_ping_timeout_cb, data);
+// osmo_timer_setup(&data->pong_timer, msc_pong_timeout_cb, data);
data->msc_con->write_queue.bfd.data = data;
- data->msc_con->connection_loss = msc_connection_was_lost;
- data->msc_con->connected = msc_connection_connected;
- data->msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
- data->msc_con->write_queue.write_cb = msc_alink_do_write;
- bsc_msc_connect(data->msc_con);
+// data->msc_con->connection_loss = msc_connection_was_lost;
+// data->msc_con->connected = msc_connection_connected;
+// data->msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
+// data->msc_con->write_queue.write_cb = msc_alink_do_write;
+// bsc_msc_connect(data->msc_con);
+
+ data->msc_con->is_connected = 1;
+ data->msc_con->is_authenticated = 1;
+
return 0;
}
+
struct bsc_msc_data *osmo_msc_data_find(struct gsm_network *net, int nr)
{
struct bsc_msc_data *msc_data;
@@ -584,3 +597,4 @@ struct bsc_msc_data *osmo_msc_data_alloc(struct gsm_network *net, int nr)
return msc_data;
}
+
diff --git a/src/osmo-bsc/osmo_bsc_reset.c b/src/osmo-bsc/osmo_bsc_reset.c
new file mode 100644
index 000000000..0baf08089
--- /dev/null
+++ b/src/osmo-bsc/osmo_bsc_reset.c
@@ -0,0 +1,190 @@
+/* (C) 2017 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/fsm.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <openbsc/debug.h>
+#include <openbsc/bsc_msc_data.h>
+#include <openbsc/osmo_bsc_sigtran.h>
+
+#define RESET_RESEND_INTERVAL 2 /* sec */
+#define RESET_RESEND_TIMER_NO 1234 /* FIXME: dig out the real timer number */
+#define BAD_CONNECTION_THRESOLD 3 /* connection failures */
+
+enum fsm_states {
+ ST_DISC, /* Disconnected from MSC */
+ ST_CONN, /* We have a confirmed connection to the MSC */
+};
+
+static const struct value_string fsm_state_names[] = {
+ {ST_DISC, "ST_DISC (disconnected)"},
+ {ST_CONN, "ST_CONN (connected)"},
+ {0, NULL},
+};
+
+enum fsm_evt {
+ EV_RESET_ACK, /* got reset acknowlegement from the MSC */
+ EV_N_DISCONNECT, /* lost a connection */
+ EV_N_CONNECT, /* made a successful connection */
+};
+
+static const struct value_string fsm_evt_names[] = {
+ {EV_RESET_ACK, "EV_RESET_ACK"},
+ {EV_N_DISCONNECT, "EV_N_DISCONNECT"},
+ {EV_N_CONNECT, "EV_N_CONNECT"},
+ {0, NULL},
+};
+
+/* Disconnected state */
+static void fsm_disc_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct bsc_msc_data *msc = (struct bsc_msc_data *)data;
+
+ LOGP(DMSC, LOGL_NOTICE, "fsm-state (msc-reset): %s, fsm-event: %s, MSC No.: %i\n",
+ get_value_string(fsm_state_names, ST_DISC), get_value_string(fsm_evt_names, event), msc->nr);
+ msc->msc_con->msc_conn_loss_count = 0;
+ osmo_fsm_inst_state_chg(fi, ST_CONN, 0, 0);
+}
+
+/* Connected state */
+static void fsm_conn_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct bsc_msc_data *msc = (struct bsc_msc_data *)data;
+
+ LOGP(DMSC, LOGL_NOTICE, "fsm-state (msc-reset): %s, fsm-event: %s, MSC No.: %i\n",
+ get_value_string(fsm_state_names, ST_CONN), get_value_string(fsm_evt_names, event), msc->nr);
+
+ OSMO_ASSERT(msc);
+
+ switch (event) {
+ case EV_N_DISCONNECT:
+ if (msc->msc_con->msc_conn_loss_count >= BAD_CONNECTION_THRESOLD) {
+ LOGP(DMSC, LOGL_NOTICE, "SIGTRAN connection to MSC No.: %i down, reconnecting...\n", msc->nr);
+ osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
+ } else
+ msc->msc_con->msc_conn_loss_count++;
+ break;
+ case EV_N_CONNECT:
+ msc->msc_con->msc_conn_loss_count = 0;
+ break;
+ }
+}
+
+/* Timer callback to retransmit the reset signal */
+static int fsm_reset_ack_timeout_cb(struct osmo_fsm_inst *fi)
+{
+ struct bsc_msc_data *msc = (struct bsc_msc_data *)fi->priv;
+
+ LOGP(DMSC, LOGL_NOTICE, "reset-ack timeout (T%i) in state %s, MSC No.: %i, resending...\n", fi->T,
+ get_value_string(fsm_state_names, fi->state), msc->nr);
+
+ osmo_bsc_sigtran_reset(msc);
+ osmo_bsc_sigtran_tx_reset(msc);
+
+ osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
+ return 0;
+}
+
+static struct osmo_fsm_state fsm_states[] = {
+ [ST_DISC] = {
+ .in_event_mask = (1 << EV_RESET_ACK),
+ .out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),
+ .name = "DISC",
+ .action = fsm_disc_cb,
+ },
+ [ST_CONN] = {
+ .in_event_mask = (1 << EV_N_DISCONNECT) | (1 << EV_N_CONNECT),
+ .out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),
+ .name = "CONN",
+ .action = fsm_conn_cb,
+ },
+};
+
+/* State machine definition */
+static struct osmo_fsm fsm = {
+ .name = "FSM RESET",
+ .states = fsm_states,
+ .num_states = ARRAY_SIZE(fsm_states),
+ .log_subsys = DMSC,
+ .timer_cb = fsm_reset_ack_timeout_cb,
+};
+
+/* Create and start state machine which handles the reset/reset-ack procedure */
+void start_reset_fsm(struct bsc_msc_data *msc)
+{
+ OSMO_ASSERT(msc);
+ OSMO_ASSERT(msc->msc_con);
+
+ osmo_fsm_register(&fsm);
+ msc->msc_con->fsm_reset = osmo_fsm_inst_alloc(&fsm, NULL, NULL, LOGL_DEBUG, "FSM RESET INST");
+ OSMO_ASSERT(msc->msc_con->fsm_reset);
+
+ msc->msc_con->fsm_reset->priv = msc;
+
+ /* kick off reset-ack sending mechanism */
+ osmo_fsm_inst_state_chg(msc->msc_con->fsm_reset, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
+}
+
+/* Confirm that we sucessfully received a reset acknowlege message */
+void reset_ack_confirm(struct bsc_msc_data *msc)
+{
+ OSMO_ASSERT(msc);
+ OSMO_ASSERT(msc->msc_con);
+ OSMO_ASSERT(msc->msc_con->fsm_reset);
+
+ osmo_fsm_inst_dispatch(msc->msc_con->fsm_reset, EV_RESET_ACK, msc);
+}
+
+/* Report a failed connection */
+void report_conn_fail(struct bsc_msc_data *msc)
+{
+ OSMO_ASSERT(msc);
+ OSMO_ASSERT(msc->msc_con);
+ OSMO_ASSERT(msc->msc_con->fsm_reset);
+
+ osmo_fsm_inst_dispatch(msc->msc_con->fsm_reset, EV_N_DISCONNECT, msc);
+}
+
+/* Report a successful connection */
+void report_conn_success(struct bsc_msc_data *msc)
+{
+ OSMO_ASSERT(msc);
+ OSMO_ASSERT(msc->msc_con);
+ OSMO_ASSERT(msc->msc_con->fsm_reset);
+
+ osmo_fsm_inst_dispatch(msc->msc_con->fsm_reset, EV_N_CONNECT, msc);
+}
+
+/* Check if we have a connection to a specified msc */
+bool sccp_conn_ready(struct bsc_msc_data *msc)
+{
+ OSMO_ASSERT(msc);
+ OSMO_ASSERT(msc->msc_con);
+ OSMO_ASSERT(msc->msc_con->fsm_reset);
+ if (msc->msc_con->fsm_reset->state == ST_CONN)
+ return true;
+
+ return false;
+}
diff --git a/src/osmo-bsc/osmo_bsc_sccp.c b/src/osmo-bsc/osmo_bsc_sccp.c
deleted file mode 100644
index e242390ef..000000000
--- a/src/osmo-bsc/osmo_bsc_sccp.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/* Interaction with the SCCP subsystem */
-/*
- * (C) 2009-2014 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2014 by On-Waves
- * 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 <openbsc/gsm_data.h>
-#include <openbsc/osmo_bsc.h>
-#include <openbsc/osmo_bsc_grace.h>
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/gsm_04_80.h>
-#include <openbsc/debug.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/signal.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/gsm/gsm0808.h>
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-
-#include <osmocom/sccp/sccp.h>
-
-/* SCCP helper */
-#define SCCP_IT_TIMER 60
-
-static LLIST_HEAD(active_connections);
-
-static void free_queued(struct osmo_bsc_sccp_con *conn)
-{
- struct msgb *msg;
-
- while (!llist_empty(&conn->sccp_queue)) {
- /* this is not allowed to fail */
- msg = msgb_dequeue(&conn->sccp_queue);
- msgb_free(msg);
- }
-
- conn->sccp_queue_size = 0;
-}
-
-static void send_queued(struct osmo_bsc_sccp_con *conn)
-{
- struct msgb *msg;
-
- while (!llist_empty(&conn->sccp_queue)) {
- /* this is not allowed to fail */
- msg = msgb_dequeue(&conn->sccp_queue);
- sccp_connection_write(conn->sccp, msg);
- msgb_free(msg);
- conn->sccp_queue_size -= 1;
- }
-}
-
-static void msc_outgoing_sccp_data(struct sccp_connection *conn,
- struct msgb *msg, unsigned int len)
-{
- struct osmo_bsc_sccp_con *bsc_con =
- (struct osmo_bsc_sccp_con *) conn->data_ctx;
-
- bsc_handle_dt1(bsc_con, msg, len);
-}
-
-static void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
-{
- struct osmo_bsc_sccp_con *con_data;
-
- if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
- con_data = (struct osmo_bsc_sccp_con *) conn->data_ctx;
- if (con_data->conn) {
- LOGP(DMSC, LOGL_ERROR,
- "ERROR: The lchan is still associated.\n");
- gsm0808_clear(con_data->conn);
- bsc_subscr_con_free(con_data->conn);
- con_data->conn = NULL;
- }
-
- con_data->sccp = NULL;
- free_queued(con_data);
- sccp_connection_free(conn);
- bsc_delete_connection(con_data);
- } else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
- LOGP(DMSC, LOGL_DEBUG, "Connection established: %p\n", conn);
- con_data = (struct osmo_bsc_sccp_con *) conn->data_ctx;
-
- osmo_timer_del(&con_data->sccp_cc_timeout);
- osmo_timer_schedule(&con_data->sccp_it_timeout, SCCP_IT_TIMER, 0);
-
- send_queued(con_data);
- }
-}
-
-static void bsc_sccp_force_free(struct osmo_bsc_sccp_con *data)
-{
- if (data->conn) {
- gsm0808_clear(data->conn);
- bsc_subscr_con_free(data->conn);
- data->conn = NULL;
- }
-
- free_queued(data);
- sccp_connection_force_free(data->sccp);
- data->sccp = NULL;
- bsc_delete_connection(data);
-}
-
-static void sccp_it_timeout(void *_data)
-{
- struct osmo_bsc_sccp_con *data =
- (struct osmo_bsc_sccp_con *) _data;
-
- sccp_connection_send_it(data->sccp);
- osmo_timer_schedule(&data->sccp_it_timeout, SCCP_IT_TIMER, 0);
-}
-
-static void sccp_cc_timeout(void *_data)
-{
- struct osmo_bsc_sccp_con *data =
- (struct osmo_bsc_sccp_con *) _data;
-
- if (data->sccp->connection_state >= SCCP_CONNECTION_STATE_ESTABLISHED)
- return;
-
- LOGP(DMSC, LOGL_ERROR, "The connection was never established.\n");
- bsc_sccp_force_free(data);
-}
-
-static void msc_sccp_write_ipa(struct sccp_connection *conn, struct msgb *msg,
- void *global_ctx, void *ctx)
-{
- struct bsc_msc_connection *msc_con;
-
- if (conn) {
- struct osmo_bsc_sccp_con *bsc_con = conn->data_ctx;
- msc_con = bsc_con->msc->msc_con;
- if (bsc_con->send_ping) {
- bsc_con->send_ping = 0;
- msc_queue_write_with_ping(msc_con, msg, IPAC_PROTO_SCCP);
- return;
- }
- } else {
- msc_con = ctx;
- }
-
- msc_queue_write(msc_con, msg, IPAC_PROTO_SCCP);
-}
-
-static int msc_sccp_accept(struct sccp_connection *connection, void *data)
-{
- LOGP(DMSC, LOGL_DEBUG, "Rejecting incoming SCCP connection.\n");
- return -1;
-}
-
-static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
-{
- struct bsc_msc_data *msc = (struct bsc_msc_data *) msgb->cb[0];
- return bsc_handle_udt(msc, msgb, length);
-}
-
-int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
-{
- struct sccp_connection *sccp = conn->sccp;
-
- if (sccp->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) {
- LOGP(DMSC, LOGL_ERROR, "Connection closing, dropping packet on: %p\n", sccp);
- msgb_free(msg);
- } else if (sccp->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED
- && conn->sccp_queue_size == 0) {
- sccp_connection_write(sccp, msg);
- msgb_free(msg);
- } else if (conn->sccp_queue_size > 10) {
- LOGP(DMSC, LOGL_ERROR, "Connection closing, dropping packet on: %p\n", sccp);
- msgb_free(msg);
- } else {
- LOGP(DMSC, LOGL_DEBUG, "Queueing packet on %p. Queue size: %d\n", sccp, conn->sccp_queue_size);
- conn->sccp_queue_size += 1;
- msgb_enqueue(&conn->sccp_queue, msg);
- }
-
- return 0;
-}
-
-enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
- struct bsc_msc_data *msc, int send_ping)
-{
- struct osmo_bsc_sccp_con *bsc_con;
- struct sccp_connection *sccp;
-
- /* This should not trigger */
- if (!msc || !msc->msc_con->is_authenticated) {
- LOGP(DMSC, LOGL_ERROR,
- "How did this happen? MSC is not connected. Dropping.\n");
- return BSC_CON_REJECT_NO_LINK;
- }
-
- if (!bsc_grace_allow_new_connection(conn->bts->network, conn->bts)) {
- LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
- return BSC_CON_REJECT_RF_GRACE;
- }
-
- sccp = sccp_connection_socket();
- if (!sccp) {
- LOGP(DMSC, LOGL_ERROR, "Failed to allocate memory.\n");
- return BSC_CON_NO_MEM;
- }
-
- bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con);
- if (!bsc_con) {
- LOGP(DMSC, LOGL_ERROR, "Failed to allocate.\n");
- sccp_connection_free(sccp);
- return BSC_CON_NO_MEM;
- }
-
- /* callbacks */
- sccp->state_cb = msc_outgoing_sccp_state;
- sccp->data_cb = msc_outgoing_sccp_data;
- sccp->data_ctx = bsc_con;
-
- bsc_con->send_ping = send_ping;
-
- /* prepare the timers */
- osmo_timer_setup(&bsc_con->sccp_it_timeout, sccp_it_timeout, bsc_con);
- osmo_timer_setup(&bsc_con->sccp_cc_timeout, sccp_cc_timeout, bsc_con);
-
- INIT_LLIST_HEAD(&bsc_con->sccp_queue);
-
- bsc_con->sccp = sccp;
- bsc_con->msc = msc;
- bsc_con->conn = conn;
- llist_add_tail(&bsc_con->entry, &active_connections);
- conn->sccp_con = bsc_con;
- return BSC_CON_SUCCESS;
-}
-
-int bsc_open_connection(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
-{
- osmo_timer_schedule(&conn->sccp_cc_timeout, 10, 0);
- sccp_connection_connect(conn->sccp, &sccp_ssn_bssap, msg);
- msgb_free(msg);
- return 0;
-}
-
-int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp)
-{
- if (!sccp)
- return 0;
-
- if (sccp->conn)
- LOGP(DMSC, LOGL_ERROR, "Should have been cleared.\n");
-
- llist_del(&sccp->entry);
- osmo_timer_del(&sccp->sccp_it_timeout);
- osmo_timer_del(&sccp->sccp_cc_timeout);
- talloc_free(sccp);
- return 0;
-}
-
-static void bsc_notify_msc_lost(struct osmo_bsc_sccp_con *con)
-{
- struct gsm_subscriber_connection *conn = con->conn;
-
- /* send USSD notification if string configured and con->data is set */
- if (!conn)
- return;
-
- /* check for config string */
- if (!con->msc->ussd_msc_lost_txt)
- return;
- if (con->msc->ussd_msc_lost_txt[0] == '\0')
- return;
-
- /* send USSD notification */
- bsc_send_ussd_notify(conn, 1, conn->sccp_con->msc->ussd_msc_lost_txt);
- bsc_send_ussd_release_complete(conn);
-}
-
-static void bsc_notify_and_close_conns(struct bsc_msc_connection *msc_con)
-{
- struct osmo_bsc_sccp_con *con, *tmp;
-
- llist_for_each_entry_safe(con, tmp, &active_connections, entry) {
- if (con->msc->msc_con != msc_con)
- continue;
-
- bsc_notify_msc_lost(con);
- bsc_sccp_force_free(con);
- }
-}
-
-static int handle_msc_signal(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct msc_signal_data *msc;
-
- if (subsys != SS_MSC)
- return 0;
-
- msc = signal_data;
- if (signal == S_MSC_LOST)
- bsc_notify_and_close_conns(msc->data->msc_con);
-
- return 0;
-}
-
-int osmo_bsc_sccp_init(struct gsm_network *gsmnet)
-{
- sccp_set_log_area(DSCCP);
- sccp_system_init(msc_sccp_write_ipa, gsmnet);
- sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL);
- sccp_set_read(&sccp_ssn_bssap, msc_sccp_read, gsmnet);
-
- osmo_signal_register_handler(SS_MSC, handle_msc_signal, gsmnet);
-
- return 0;
-}
diff --git a/src/osmo-bsc/osmo_bsc_sigtran.c b/src/osmo-bsc/osmo_bsc_sigtran.c
new file mode 100644
index 000000000..0f6ca334f
--- /dev/null
+++ b/src/osmo-bsc/osmo_bsc_sigtran.c
@@ -0,0 +1,561 @@
+/* (C) 2017 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+#include <osmocom/sigtran/sccp_sap.h>
+#include <osmocom/sccp/sccp_types.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/core/msgb.h>
+#include <openbsc/bsc_msc_data.h>
+#include <openbsc/debug.h>
+#include <openbsc/osmo_bsc.h>
+#include <openbsc/osmo_bsc_grace.h>
+#include <openbsc/osmo_bsc_sigtran.h>
+#include <openbsc/a_reset.h>
+#include <openbsc/gsm_04_80.h>
+
+/* A pointer to a list with all involved MSCs
+ * (a copy of the pointer location submitted with osmo_bsc_sigtran_init() */
+static struct llist_head *msc_list;
+
+#define RESET_INTERVAL 1 /* sek */
+#define SCCP_MSG_MAXSIZE 1024
+#define CS7_POINTCODE_DEFAULT_OFFSET 2
+
+/* Internal list with connections we currently maintain. This
+ * list is of type struct osmo_bsc_sccp_con */
+static LLIST_HEAD(active_connections);
+
+/* The SCCP stack will not assign connection IDs to us automatically, we
+ * will do this ourselves using a counter variable, that counts one up
+ * for every new connection */
+static uint32_t conn_id_counter;
+
+/* Helper function to Check if the given connection id is already assigned */
+static struct osmo_bsc_sccp_con *get_bsc_conn_by_conn_id(int conn_id)
+{
+ conn_id &= 0xFFFFFF;
+ struct osmo_bsc_sccp_con *bsc_con;
+
+ llist_for_each_entry(bsc_con, &active_connections, entry) {
+ if (bsc_con->conn_id == conn_id)
+ return bsc_con;
+ }
+
+ return NULL;
+}
+
+/* Pick a free connection id */
+static int pick_free_conn_id(const struct bsc_msc_data *msc)
+{
+ int conn_id = conn_id_counter;
+ int i;
+
+ for (i = 0; i < 0xFFFFFF; i++) {
+ conn_id++;
+ conn_id &= 0xFFFFFF;
+ if (get_bsc_conn_by_conn_id(conn_id) == false) {
+ conn_id_counter = conn_id;
+ return conn_id;
+ }
+ }
+
+ return -1;
+}
+
+/* Send reset to MSC */
+static void osmo_bsc_sigtran_tx_reset(const struct bsc_msc_data *msc)
+{
+ struct osmo_ss7_instance *ss7;
+ struct msgb *msg;
+
+ ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+ LOGP(DMSC, LOGL_NOTICE, "Sending RESET to MSC: %s\n", osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
+ msg = gsm0808_create_reset();
+ osmo_sccp_tx_unitdata_msg(msc->a.sccp_user, &msc->a.bsc_addr,
+ &msc->a.msc_addr, msg);
+}
+
+/* Send reset-ack to MSC */
+void osmo_bsc_sigtran_tx_reset_ack(const struct bsc_msc_data *msc)
+{
+ struct osmo_ss7_instance *ss7;
+ struct msgb *msg;
+ OSMO_ASSERT(msc);
+
+ ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+ LOGP(DMSC, LOGL_NOTICE, "Sending RESET ACK to MSC: %s\n", osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
+ msg = gsm0808_create_reset_ack();
+ osmo_sccp_tx_unitdata_msg(msc->a.sccp_user, &msc->a.bsc_addr,
+ &msc->a.msc_addr, msg);
+}
+
+/* Find an MSC by its sigtran point code */
+static struct bsc_msc_data *get_msc_by_addr(const struct osmo_sccp_addr *msc_addr)
+{
+ struct osmo_ss7_instance *ss7;
+ struct bsc_msc_data *msc;
+ llist_for_each_entry(msc, msc_list, entry) {
+ if (memcmp(msc_addr, &msc->a.msc_addr, sizeof(*msc_addr)) == 0)
+ return msc;
+ }
+
+ ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+ LOGP(DMSC, LOGL_ERROR, "Unable to find MSC data under address: %s\n", osmo_sccp_addr_name(ss7, msc_addr));
+ return NULL;
+}
+
+/* Send data to MSC, use the connection id which MSC it is */
+static int handle_data_from_msc(int conn_id, struct msgb *msg)
+{
+ struct osmo_bsc_sccp_con *bsc_con = get_bsc_conn_by_conn_id(conn_id);
+ int rc = -EINVAL;
+
+ if (bsc_con) {
+ msg->l3h = msgb_l2(msg);
+ rc = bsc_handle_dt(bsc_con, msg, msgb_l2len(msg));
+ } else
+ LOGP(DMSC, LOGL_NOTICE, "incoming data from unknown connection id: %i\n", conn_id);
+
+ return rc;
+}
+
+/* Sent unitdata to MSC, use the point code to determine which MSC it is */
+static int handle_unitdata_from_msc(const struct osmo_sccp_addr *msc_addr, struct msgb *msg,
+ const struct osmo_sccp_user *scu)
+{
+ struct osmo_ss7_instance *ss7;
+ struct bsc_msc_data *msc = get_msc_by_addr(msc_addr);
+ int rc = -EINVAL;
+
+ if (msc) {
+ msg->l3h = msgb_l2(msg);
+ rc = bsc_handle_udt(msc, msg, msgb_l2len(msg));
+ } else {
+ ss7 = osmo_sccp_get_ss7(osmo_sccp_get_sccp(scu));
+ OSMO_ASSERT(ss7);
+ LOGP(DMSC, LOGL_NOTICE, "incoming unitdata data from unknown remote address: %s\n",
+ osmo_sccp_addr_name(ss7, msc_addr));
+ }
+ return rc;
+}
+
+/* Callback function, called by the SSCP stack when data arrives */
+static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
+{
+ struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph;
+ struct osmo_sccp_user *scu = _scu;
+ struct osmo_bsc_sccp_con *bsc_con;
+ int rc = 0;
+
+ switch (OSMO_PRIM_HDR(&scu_prim->oph)) {
+ case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
+ /* Handle inbound UNITDATA */
+ DEBUGP(DMSC, "N-UNITDATA.ind(%s)\n", osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
+ rc = handle_unitdata_from_msc(&scu_prim->u.unitdata.calling_addr, oph->msg, scu);
+ break;
+
+ case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION):
+ /* Handle (Reject) inbound connections */
+ DEBUGP(DMSC, "N-CONNECT.ind(X->%u)\n", scu_prim->u.connect.conn_id);
+ LOGP(DMSC, LOGL_DEBUG, "Rejecting inbound SCCP connection...\n");
+ rc = osmo_sccp_tx_disconn(scu, scu_prim->u.connect.conn_id, &scu_prim->u.connect.called_addr, 0);
+ break;
+
+ case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
+ /* Handle outbound connection confirmation */
+ if (msgb_l2len(oph->msg) > 0) {
+ DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id,
+ osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
+ rc = handle_data_from_msc(scu_prim->u.connect.conn_id, oph->msg);
+ } else
+ DEBUGP(DRANAP, "N-CONNECT.cnf(%u)\n", scu_prim->u.connect.conn_id);
+ break;
+
+ case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
+ /* Handle incoming connection oriented data */
+ DEBUGP(DMSC, "N-DATA.ind(%u, %s)\n", scu_prim->u.data.conn_id,
+ osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
+
+ /* Incoming data is a sign of a vital connection */
+ bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
+ if (bsc_con)
+ a_reset_conn_success(bsc_con->msc->a.reset);
+
+ rc = handle_data_from_msc(scu_prim->u.data.conn_id, oph->msg);
+ break;
+
+ case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
+ /* indication of disconnect */
+ if (msgb_l2len(oph->msg) > 0) {
+ DEBUGP(DMSC, "N-DISCONNECT.ind(%u, %s, cause=%i)\n", scu_prim->u.disconnect.conn_id,
+ osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), scu_prim->u.disconnect.cause);
+ handle_data_from_msc(scu_prim->u.disconnect.conn_id, oph->msg);
+ } else
+ DEBUGP(DRANAP, "N-DISCONNECT.ind(%u, cause=%i)\n", scu_prim->u.disconnect.conn_id,
+ scu_prim->u.disconnect.cause);
+
+ bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
+ if (bsc_con) {
+ /* We might have a connectivity problem. Maybe we need to go
+ * through the reset procedure again? */
+ if (scu_prim->u.disconnect.cause == 0)
+ a_reset_conn_fail(bsc_con->msc->a.reset);
+
+ rc = osmo_bsc_sigtran_del_conn(bsc_con);
+ }
+ break;
+
+ default:
+ LOGP(DMSC, LOGL_ERROR, "Unhandled SIGTRAN primitive: %u:%u\n", oph->primitive, oph->operation);
+ break;
+ }
+
+ msgb_free(oph->msg);
+ return rc;
+}
+
+/* Allocate resources to make a new connection oriented sigtran connection
+ * (not the connection ittself!) */
+enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc)
+{
+ struct osmo_ss7_instance *ss7;
+ struct osmo_bsc_sccp_con *bsc_con;
+ int conn_id;
+
+ OSMO_ASSERT(conn);
+ OSMO_ASSERT(msc);
+
+ ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+ LOGP(DMSC, LOGL_NOTICE, "Initializing resources for new SIGTRAN connection to MSC: %s...\n",
+ osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
+
+ if (a_reset_conn_ready(msc->a.reset) == false) {
+ LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
+ return BSC_CON_REJECT_NO_LINK;
+ }
+
+ if (!bsc_grace_allow_new_connection(conn->bts->network, conn->bts)) {
+ LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
+ return BSC_CON_REJECT_RF_GRACE;
+ }
+
+ bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con);
+ if (!bsc_con) {
+ LOGP(DMSC, LOGL_ERROR, "Failed to allocate new SIGTRAN connection.\n");
+ return BSC_CON_NO_MEM;
+ }
+
+ bsc_con->msc = msc;
+ bsc_con->conn = conn;
+ llist_add_tail(&bsc_con->entry, &active_connections);
+ conn->sccp_con = bsc_con;
+
+ /* Pick a free connection id */
+ conn_id = pick_free_conn_id(msc);
+ if (conn_id < 0)
+ return BSC_CON_REJECT_NO_LINK;
+ bsc_con->conn_id = conn_id;
+
+ LOGP(DMSC, LOGL_NOTICE, "Allocated new connection id: %i\n", conn_id);
+
+ return BSC_CON_SUCCESS;
+}
+
+/* Open a new connection oriented sigtran connection */
+int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb *msg)
+{
+ struct osmo_ss7_instance *ss7;
+ struct bsc_msc_data *msc;
+ int conn_id;
+ int rc;
+
+ OSMO_ASSERT(conn);
+ OSMO_ASSERT(msg);
+ OSMO_ASSERT(conn->msc);
+
+ msc = conn->msc;
+
+ if (a_reset_conn_ready(msc->a.reset) == false) {
+ LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
+ return -EINVAL;
+ }
+
+ conn_id = conn->conn_id;
+ ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+ LOGP(DMSC, LOGL_NOTICE, "Opening new SIGTRAN connection (id=%i) to MSC: %s\n", conn_id,
+ osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
+
+ rc = osmo_sccp_tx_conn_req_msg(msc->a.sccp_user, conn_id, &msc->a.bsc_addr,
+ &msc->a.msc_addr, msg);
+
+ return rc;
+}
+
+/* Send data to MSC */
+int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg)
+{
+ struct osmo_ss7_instance *ss7;
+ int conn_id;
+ int rc;
+ struct bsc_msc_data *msc;
+
+ OSMO_ASSERT(conn);
+ OSMO_ASSERT(msg);
+ OSMO_ASSERT(conn->msc);
+
+ msc = conn->msc;
+
+ if (a_reset_conn_ready(msc->a.reset) == false) {
+ LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
+ return -EINVAL;
+ }
+
+ conn_id = conn->conn_id;
+
+ ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
+ OSMO_ASSERT(ss7);
+ LOGP(DMSC, LOGL_DEBUG, "Sending connection (id=%i) oriented data to MSC: %si\n",
+ conn_id, osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
+
+ rc = osmo_sccp_tx_data_msg(msc->a.sccp_user, conn_id, msg);
+
+ return rc;
+}
+
+/* Delete a connection from the list with open connections
+ * (called by osmo_bsc_api.c on failing open connections and
+ * locally, when a connection is closed by the MSC */
+int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *conn)
+{
+ if (!conn)
+ return 0;
+
+ if (conn->conn) {
+ LOGP(DMSC, LOGL_ERROR,
+ "sccp connection (id=%i) not cleared (gsm subscriber connection still active) -- forcefully clearing it now!\n",
+ conn->conn_id);
+ bsc_subscr_con_free(conn->conn);
+ conn->conn = NULL;
+
+ /* This bahaviour might be caused by a bad connection. Maybe we
+ * will have to go through the reset procedure again */
+ a_reset_conn_fail(conn->msc->a.reset);
+ }
+
+ llist_del(&conn->entry);
+ talloc_free(conn);
+
+ return 0;
+}
+
+/* Send an USSD notification in case we loose the connection to the MSC */
+static void bsc_notify_msc_lost(const struct osmo_bsc_sccp_con *conn)
+{
+ struct gsm_subscriber_connection *subscr_conn;
+
+ /* Check if sccp conn is still present */
+ if (!conn)
+ return;
+ subscr_conn = conn->conn;
+
+ /* send USSD notification if string configured and conn->data is set */
+ if (!subscr_conn)
+ return;
+
+ /* check for config string */
+ if (!conn->msc->ussd_msc_lost_txt)
+ return;
+ if (conn->msc->ussd_msc_lost_txt[0] == '\0')
+ return;
+
+ /* send USSD notification */
+ bsc_send_ussd_notify(subscr_conn, 1, subscr_conn->sccp_con->msc->ussd_msc_lost_txt);
+ bsc_send_ussd_release_complete(subscr_conn);
+}
+
+/* Close all open sigtran connections and channels */
+void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc)
+{
+ struct osmo_bsc_sccp_con *conn;
+ struct osmo_bsc_sccp_con *conn_temp;
+ OSMO_ASSERT(msc);
+
+ /* Close all open connections */
+ llist_for_each_entry_safe(conn, conn_temp, &active_connections, entry) {
+
+ /* We only may close connections which actually belong to this
+ * MSC. All other open connections are left untouched */
+ if (conn->msc == msc) {
+ /* Notify active connection users via USSD that the MSC is down */
+ bsc_notify_msc_lost(conn);
+
+ /* Take down all occopied RF channels */
+ if (conn->conn)
+ gsm0808_clear(conn->conn);
+
+ /* Disconnect all Sigtran connections */
+ osmo_sccp_tx_disconn(msc->a.sccp_user, conn->conn_id, &msc->a.bsc_addr, 0);
+
+ /* Delete subscriber connection */
+ osmo_bsc_sigtran_del_conn(conn);
+ }
+ }
+}
+
+/* Callback function: Close all open connections */
+static void osmo_bsc_sigtran_reset_cb(const void *priv)
+{
+ struct bsc_msc_data *msc = (struct bsc_msc_data*) priv;
+
+ /* Shut down all ongoing traffic */
+ osmo_bsc_sigtran_reset(msc);
+
+ /* Send reset to MSC */
+ osmo_bsc_sigtran_tx_reset(msc);
+}
+
+/* Default point-code to be used as local address (BSC) */
+#define BSC_DEFAULT_PC "0.23.3"
+
+/* Default point-code to be used as remote address (MSC) */
+#define MSC_DEFAULT_PC "0.23.1"
+
+/* Initalize osmo sigtran backhaul */
+int osmo_bsc_sigtran_init(struct llist_head *mscs)
+{
+ bool free_attempt_used = false;
+ bool fail_on_next_invalid_cfg = false;
+
+ struct bsc_msc_data *msc;
+ char msc_name[32];
+ uint32_t default_pc;
+
+ OSMO_ASSERT(mscs);
+ msc_list = mscs;
+
+ llist_for_each_entry(msc, msc_list, entry) {
+ snprintf(msc_name, sizeof(msc_name), "msc-%u", msc->nr);
+ LOGP(DMSC, LOGL_NOTICE, "Initializing SCCP connection to MSC %s\n", msc_name);
+
+ /* Check if the VTY could determine a valid CS7 instance,
+ * use safe default in case none is set */
+ if (msc->a.cs7_instance_valid == false) {
+ msc->a.cs7_instance = 0;
+ if (fail_on_next_invalid_cfg)
+ goto fail_auto_cofiguration;
+ free_attempt_used = true;
+ }
+ LOGP(DMSC, LOGL_NOTICE, "CS7 Instance identifier, A-Interface: %u\n", msc->a.cs7_instance);
+
+ /* Pre-Check if there is an ss7 instance present */
+ if (osmo_ss7_instance_find(msc->a.cs7_instance) == NULL) {
+ if (fail_on_next_invalid_cfg)
+ goto fail_auto_cofiguration;
+ free_attempt_used = true;
+ }
+
+ /* SS7 Protocol stack */
+ default_pc = osmo_ss7_pointcode_parse(NULL, BSC_DEFAULT_PC);
+ msc->a.sccp =
+ osmo_sccp_simple_client_on_ss7_id(msc, msc->a.cs7_instance, msc_name, default_pc,
+ OSMO_SS7_ASP_PROT_M3UA, 0, NULL, 0, NULL);
+ if (!msc->a.sccp)
+ return -EINVAL;
+
+ /* Check if the sccp-address fullfills minimum requirements (SSN+PC is present,
+ * automatically recover addresses if the addresses are not set up properly) */
+ if (!osmo_sccp_check_addr(&msc->a.bsc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {
+ if (fail_on_next_invalid_cfg)
+ goto fail_auto_cofiguration;
+ free_attempt_used = true;
+
+ LOGP(DMSC, LOGL_NOTICE,
+ "A-interface: invalid or missing local (BSC) SCCP address (a.bsc_addr=%s)\n",
+ osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr));
+ osmo_sccp_local_addr_by_instance(&msc->a.bsc_addr, msc->a.sccp, SCCP_SSN_BSSAP);
+ LOGP(DMSC, LOGL_NOTICE,
+ "A-interface: using automatically generated local (BSC) SCCP address (a.bsc_addr=%s)\n",
+ osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr));
+ } else {
+ LOGP(DMSC, LOGL_NOTICE,
+ "A-interface: using local (BSC) automatically SCCP address (a.msc_addr=%s)\n",
+ osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr));
+ }
+
+ if (!osmo_sccp_check_addr(&msc->a.msc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {
+ if (fail_on_next_invalid_cfg)
+ goto fail_auto_cofiguration;
+ free_attempt_used = true;
+
+ LOGP(DMSC, LOGL_NOTICE,
+ "A-interface: invalid or missing remote (MSC) SCCP address for the MSC (a.msc_addr=%s)\n",
+ osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr));
+ osmo_sccp_local_addr_by_instance(&msc->a.msc_addr, msc->a.sccp, SCCP_SSN_BSSAP);
+ msc->a.msc_addr.pc = osmo_ss7_pointcode_parse(NULL, MSC_DEFAULT_PC);
+ LOGP(DMSC, LOGL_NOTICE,
+ "A-interface: using automatically generated remote (MSC) SCCP address (a.msc_addr=%s)\n",
+ osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr));
+ free_attempt_used = true;
+ } else {
+ LOGP(DMSC, LOGL_NOTICE,
+ "A-interface: using remote (MSC) automatically SCCP address (a.msc_addr=%s)\n",
+ osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr));
+ }
+
+ /* Bind SCCP user */
+ msc->a.sccp_user = osmo_sccp_user_bind(msc->a.sccp, msc_name, sccp_sap_up, msc->a.bsc_addr.ssn);
+ if (!msc->a.sccp_user)
+ return -EINVAL;
+
+ /* Start MSC-Reset procedure */
+ msc->a.reset = a_reset_alloc(msc, msc_name, osmo_bsc_sigtran_reset_cb, msc);
+ if (!msc->a.reset)
+ return -EINVAL;
+
+ /* If we have detected that the SS7 configuration of the MSC we have just initalized
+ * was incomplete or completely missing, we can not tolerate another incomplete
+ * configuration. The reson for this is that we do only specify exactly one default
+ * pointcode pair. We also specify localhost as default IP-Address. If we have wanted
+ * to support multiple MSCs with automatic configuration we would be forced to invent
+ * a complex ruleset how to allocate the pointcodes and respective IP-Addresses.
+ * Furthermore, the situation where a single BSC is connected to multiple MSCs
+ * is a very rare situation anyway. In this case we expect the user to experienced
+ * enough to create a valid SS7/CS7 VTY configuration that does not lack any
+ * components */
+ if (free_attempt_used)
+ fail_on_next_invalid_cfg = true;
+ }
+
+ return 0;
+
+fail_auto_cofiguration:
+ LOGP(DMSC, LOGL_ERROR,
+ "A-interface: More than one invalid/inclomplete configuration detected, unable to revover - check config file!\n");
+ return -EINVAL;
+}
diff --git a/src/osmo-bsc/osmo_bsc_vty.c b/src/osmo-bsc/osmo_bsc_vty.c
index 2e2e99bfd..8edcbf390 100644
--- a/src/osmo-bsc/osmo_bsc_vty.c
+++ b/src/osmo-bsc/osmo_bsc_vty.c
@@ -28,6 +28,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/vty/logging.h>
+#include <osmocom/sccp/sccp_types.h>
#include <time.h>
@@ -184,6 +185,16 @@ static void write_msc(struct vty *vty, struct bsc_msc_data *msc)
/* write amr options */
write_msc_amr_options(vty, msc);
+
+ /* write sccp connection configuration */
+ if (msc->a.bsc_addr_name) {
+ vty_out(vty, " bsc-addr %s%s",
+ msc->a.bsc_addr_name, VTY_NEWLINE);
+ }
+ if (msc->a.msc_addr_name) {
+ vty_out(vty, " msc-addr %s%s",
+ msc->a.msc_addr_name, VTY_NEWLINE);
+ }
}
static int config_write_msc(struct vty *vty)
@@ -685,6 +696,87 @@ DEFUN(cfg_msc_no_acc_lst_name,
return CMD_SUCCESS;
}
+/* Make sure only standard SSN numbers are used. If no ssn number is
+ * configured, silently apply the default SSN */
+static void enforce_standard_ssn(struct vty *vty, struct osmo_sccp_addr *addr)
+{
+ if (addr->presence & OSMO_SCCP_ADDR_T_SSN) {
+ if (addr->ssn != SCCP_SSN_BSSAP)
+ vty_out(vty,
+ "setting an SSN (%u) different from the standard (%u) is not allowd, will use standard SSN for address: %s%s",
+ addr->ssn, SCCP_SSN_BSSAP, osmo_sccp_addr_dump(addr), VTY_NEWLINE);
+ }
+
+ addr->presence |= OSMO_SCCP_ADDR_T_SSN;
+ addr->ssn = SCCP_SSN_BSSAP;
+}
+
+DEFUN(cfg_msc_cs7_bsc_addr,
+ cfg_msc_cs7_bsc_addr_cmd,
+ "bsc-addr NAME",
+ "Calling Address (local address of this BSC)\n" "SCCP address name\n")
+{
+ struct bsc_msc_data *msc = bsc_msc_data(vty);
+ const char *bsc_addr_name = argv[0];
+ struct osmo_ss7_instance *ss7;
+
+ ss7 = osmo_sccp_addr_by_name(&msc->a.bsc_addr, bsc_addr_name);
+ if (!ss7) {
+ vty_out(vty, "No sccp address %s found%s", bsc_addr_name,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Prevent mixing addresses from different CS7/SS7 instances */
+ if (msc->a.cs7_instance_valid) {
+ if (msc->a.cs7_instance != ss7->cfg.id) {
+ vty_out(vty,
+ "SCCP address %s from different CS7 instance%s",
+ bsc_addr_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ msc->a.cs7_instance = ss7->cfg.id;
+ msc->a.cs7_instance_valid = true;
+ enforce_standard_ssn(vty, &msc->a.bsc_addr);
+ msc->a.bsc_addr_name = talloc_strdup(msc, bsc_addr_name);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_msc_cs7_msc_addr,
+ cfg_msc_cs7_msc_addr_cmd,
+ "msc-addr NAME",
+ "Called Address (remote address of the MSC)\n" "SCCP address name\n")
+{
+ struct bsc_msc_data *msc = bsc_msc_data(vty);
+ const char *msc_addr_name = argv[0];
+ struct osmo_ss7_instance *ss7;
+
+ ss7 = osmo_sccp_addr_by_name(&msc->a.msc_addr, msc_addr_name);
+ if (!ss7) {
+ vty_out(vty, "No sccp address %s found%s", msc_addr_name,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Prevent mixing addresses from different CS7/SS7 instances */
+ if (msc->a.cs7_instance_valid) {
+ if (msc->a.cs7_instance != ss7->cfg.id) {
+ vty_out(vty,
+ "SCCP address %s from different CS7 instance%s",
+ msc_addr_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ msc->a.cs7_instance = ss7->cfg.id;
+ msc->a.cs7_instance_valid = true;
+ enforce_standard_ssn(vty, &msc->a.msc_addr);
+ msc->a.msc_addr_name = talloc_strdup(msc, msc_addr_name);
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_net_bsc_mid_call_text,
cfg_net_bsc_mid_call_text_cmd,
"mid-call-text .TEXT",
@@ -931,6 +1023,8 @@ int bsc_vty_init_extra(void)
install_element(MSC_NODE, &cfg_net_msc_amr_4_75_cmd);
install_element(MSC_NODE, &cfg_msc_acc_lst_name_cmd);
install_element(MSC_NODE, &cfg_msc_no_acc_lst_name_cmd);
+ install_element(MSC_NODE, &cfg_msc_cs7_bsc_addr_cmd);
+ install_element(MSC_NODE, &cfg_msc_cs7_msc_addr_cmd);
install_element_ve(&show_statistics_cmd);
install_element_ve(&show_mscs_cmd);
diff --git a/src/osmo-bsc_mgcp/Makefile.am b/src/osmo-bsc_mgcp/Makefile.am
index a19a4ebc0..b4e0d8564 100644
--- a/src/osmo-bsc_mgcp/Makefile.am
+++ b/src/osmo-bsc_mgcp/Makefile.am
@@ -31,5 +31,6 @@ osmo_bsc_mgcp_LDADD = \
$(LIBOSMONETIF_LIBS) \
$(LIBBCG729_LIBS) \
$(LIBRARY_GSM) \
+ $(LIBOSMOSIGTRAN_LIBS) \
-lrt \
$(NULL)
diff --git a/src/osmo-bsc_nat/Makefile.am b/src/osmo-bsc_nat/Makefile.am
index be33d289d..b7c13ad3e 100644
--- a/src/osmo-bsc_nat/Makefile.am
+++ b/src/osmo-bsc_nat/Makefile.am
@@ -53,6 +53,7 @@ osmo_bsc_nat_LDADD = \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOABIS_LIBS) \
$(LIBOSMONETIF_LIBS) \
+ $(LIBOSMOSIGTRAN_LIBS) \
$(LIBCRYPTO_LIBS) \
-lrt \
$(NULL)
diff --git a/src/osmo-msc/msc_main.c b/src/osmo-msc/msc_main.c
index 723c0e6e8..cd713eee6 100644
--- a/src/osmo-msc/msc_main.c
+++ b/src/osmo-msc/msc_main.c
@@ -63,6 +63,7 @@
#include <openbsc/ctrl.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/smpp.h>
+#include <osmocom/sigtran/osmo_ss7.h>
#include <openbsc/mgcpgw_client.h>
#include <openbsc/msc_ifaces.h>
@@ -70,6 +71,7 @@
#include <openbsc/iu.h>
#include <openbsc/iucs.h>
#include <openbsc/iucs_ranap.h>
+#include <openbsc/a_iface.h>
static const char * const osmomsc_copyright =
"OsmoMSC - Osmocom Circuit-Switched Core Network implementation\r\n"
@@ -310,8 +312,7 @@ static struct vty_app_info msc_vty_info = {
.is_config_node = bsc_vty_is_config_node,
};
-static int rcvmsg_iu_cs(struct msgb *msg, struct gprs_ra_id *ra_id,
- uint16_t *sai)
+static int rcvmsg_iu_cs(struct msgb *msg, struct gprs_ra_id *ra_id, uint16_t *sai)
{
DEBUGP(DIUCS, "got IuCS message"
" %d bytes: %s\n",
@@ -334,6 +335,68 @@ static int rx_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type,
return iucs_rx_ranap_event(msc_network, ctx, type, data);
}
+#define DEFAULT_M3UA_REMOTE_IP "127.0.0.1"
+#define DEFAULT_PC_A "0.23.1"
+#define DEFAULT_PC_IU "0.23.2"
+#define DEFAULT_PC_A_IU DEFAULT_PC_A
+
+static struct osmo_sccp_instance *sccp_setup(void *ctx, uint32_t cs7_instance,
+ const char *label, const char *default_pc_str)
+{
+ int default_pc = osmo_ss7_pointcode_parse(NULL, default_pc_str);
+ if (default_pc < 0)
+ return NULL;
+
+ return osmo_sccp_simple_client_on_ss7_id(ctx, cs7_instance, label, default_pc,
+ OSMO_SS7_ASP_PROT_M3UA,
+ 0, NULL, /* local: use arbitrary port and 0.0.0.0. */
+ 0, /* remote: use protocol default port */
+ DEFAULT_M3UA_REMOTE_IP);
+ /* Note: If a differing remote IP is to be used, it was already entered in the vty config at
+ * 'cs7' / 'asp' / 'remote-ip', and this default remote IP has no effect.
+ * Similarly, 'cs7' / 'listen' can specify the local IP address. */
+}
+
+static int ss7_setup(void *ctx)
+{
+ uint32_t cs7_instance_a = msc_network->a.cs7_instance;
+#if BUILD_IU
+ uint32_t cs7_instance_iu = msc_network->iu.cs7_instance;
+
+ if (cs7_instance_a == cs7_instance_iu) {
+ /* Create one single SCCP instance which will be used for both,
+ * Iu and A at the same time, under the same point-code */
+ LOGP(DMSC, LOGL_NOTICE, "CS7 Instance identifiers: A = Iu = %u\n", cs7_instance_a);
+
+ msc_network->a.sccp = sccp_setup(ctx, cs7_instance_a, "OsmoMSC-A-Iu", DEFAULT_PC_A_IU);
+ if (!msc_network->a.sccp)
+ return -EINVAL;
+
+ msc_network->iu.sccp = msc_network->a.sccp;
+ } else {
+ /* Create two separate SCCP instances to run A and Iu independently on different
+ * pointcodes */
+ LOGP(DMSC, LOGL_NOTICE, "CS7 Instance identifiers: A = %u, Iu = %u\n",
+ cs7_instance_a, cs7_instance_iu);
+
+ msc_network->a.sccp = sccp_setup(ctx, cs7_instance_a, "OsmoMSC-A", DEFAULT_PC_A);
+ if (!msc_network->a.sccp)
+ return -EINVAL;
+
+ msc_network->iu.sccp = sccp_setup(ctx, cs7_instance_iu, "OsmoMSC-Iu", DEFAULT_PC_IU);
+ if (!msc_network->iu.sccp)
+ return -EINVAL;
+ }
+#else
+ /* No Iu support, just open up an A instance */
+ msc_network->a.sccp = sccp_setup(ctx, cs7_instance_a, "OsmoMSC-A", DEFAULT_PC_A);
+ if (!msc_network->a.sccp)
+ return -EINVAL;
+#endif
+
+ return 0;
+}
+
int main(int argc, char **argv)
{
int rc;
@@ -349,6 +412,9 @@ int main(int argc, char **argv)
/* For --version, vty_init() must be called before handling options */
vty_init(&msc_vty_info);
+ osmo_ss7_init();
+ osmo_ss7_vty_init_asp(tall_msc_ctx);
+
/* Parse options */
handle_options(argc, argv);
@@ -491,14 +557,19 @@ TODO: we probably want some of the _net_ ctrl commands from bsc_base_ctrl_cmds_i
return 7;
}
- /* Set up A-Interface */
- /* TODO: implement A-Interface and remove above legacy stuff. */
+ if (ss7_setup(tall_msc_ctx)) {
+ printf("Setting up SCCP client failed.\n");
+ return 8;
+ }
#ifdef BUILD_IU
/* Set up IuCS */
- iu_init(tall_msc_ctx, "127.0.0.1", 14001, rcvmsg_iu_cs, rx_iu_event);
+ iu_init(tall_msc_ctx, msc_network->iu.sccp, rcvmsg_iu_cs, rx_iu_event);
#endif
+ /* Set up A interface */
+ a_init(msc_network->a.sccp, msc_network);
+
if (msc_cmdline_config.daemonize) {
rc = osmo_daemonize();
if (rc < 0) {
diff --git a/tests/msc_vlr/Makefile.am b/tests/msc_vlr/Makefile.am
index 17bfbdfa8..6d51d6eba 100644
--- a/tests/msc_vlr/Makefile.am
+++ b/tests/msc_vlr/Makefile.am
@@ -43,8 +43,8 @@ EXTRA_DIST = \
$(NULL)
COMMON_LDADD = \
- $(top_builddir)/src/libcommon-cs/libcommon-cs.a \
$(top_builddir)/src/libmsc/libmsc.a \
+ $(top_builddir)/src/libcommon-cs/libcommon-cs.a \
$(top_builddir)/src/libvlr/libvlr.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
@@ -73,8 +73,9 @@ COMMON_LDADD += \
COMMON_LDFLAGS = \
-Wl,--wrap=gsup_client_create \
-Wl,--wrap=gsup_client_send \
- -Wl,--wrap=a_tx \
- -Wl,--wrap=a_page \
+ -Wl,--wrap=a_iface_tx_dtap \
+ -Wl,--wrap=a_iface_tx_clear_cmd \
+ -Wl,--wrap=a_iface_tx_paging \
-Wl,--wrap=iu_tx \
-Wl,--wrap=iu_tx_release \
-Wl,--wrap=iu_tx_common_id \
diff --git a/tests/msc_vlr/msc_vlr_test_gsm_authen.c b/tests/msc_vlr/msc_vlr_test_gsm_authen.c
index 22e549b2f..44e405232 100644
--- a/tests/msc_vlr/msc_vlr_test_gsm_authen.c
+++ b/tests/msc_vlr/msc_vlr_test_gsm_authen.c
@@ -83,7 +83,9 @@ void test_gsm_authen()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -111,8 +113,10 @@ void test_gsm_authen()
btw("a USSD request is serviced");
dtap_expect_tx_ussd("Your extension is 46071\r");
+ expect_bssap_clear();
ms_sends_msg("0b3b1c15a11302010002013b300b04010f0406aa510c061b017f0100");
OSMO_ASSERT(dtap_tx_confirmed);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("all requests serviced, conn has been released");
EXPECT_CONN_COUNT(0);
@@ -191,14 +195,18 @@ void test_gsm_authen()
btw("MS also sends RP-ACK, MSC in turn sends CP-ACK for that");
dtap_expect_tx("0904");
+ expect_bssap_clear();
ms_sends_msg("890106020041020000");
VERBOSE_ASSERT(dtap_tx_confirmed, == true, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("SMS is done, conn is gone");
EXPECT_CONN_COUNT(0);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -283,7 +291,9 @@ void test_gsm_authen_tmsi()
vlr_subscr_put(vsub);
btw("MS sends TMSI Realloc Complete");
+ expect_bssap_clear();
ms_sends_msg("055b");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
EXPECT_CONN_COUNT(0);
@@ -318,8 +328,10 @@ void test_gsm_authen_tmsi()
btw("a USSD request is serviced");
dtap_expect_tx_ussd("Your extension is 46071\r");
+ expect_bssap_clear();
ms_sends_msg("0b3b1c15a11302010002013b300b04010f0406aa510c061b017f0100");
OSMO_ASSERT(dtap_tx_confirmed);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("all requests serviced, conn has been released");
EXPECT_CONN_COUNT(0);
@@ -398,8 +410,10 @@ void test_gsm_authen_tmsi()
btw("MS also sends RP-ACK, MSC in turn sends CP-ACK for that");
dtap_expect_tx("0904");
+ expect_bssap_clear();
ms_sends_msg("890106020041020000");
VERBOSE_ASSERT(dtap_tx_confirmed, == true, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("SMS is done, conn is gone");
EXPECT_CONN_COUNT(0);
@@ -408,7 +422,9 @@ void test_gsm_authen_tmsi()
* deallocated and we no longer know the TMSI. This case is covered by
* test_lu_unknown_tmsi(), so here I'd like to still have the TMSI.
BTW("subscriber detaches, using TMSI");
+ expect_bssap_clear();
ms_sends_msg("050130" "05f4" "03020100");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
*/
@@ -449,7 +465,9 @@ void test_gsm_authen_tmsi()
vlr_subscr_put(vsub);
btw("MS sends TMSI Realloc Complete");
+ expect_bssap_clear();
ms_sends_msg("055b");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
EXPECT_CONN_COUNT(0);
@@ -463,7 +481,9 @@ void test_gsm_authen_tmsi()
vlr_subscr_put(vsub);
BTW("subscriber detaches, using new TMSI");
+ expect_bssap_clear();
ms_sends_msg("050130" "05f4" "07060504");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -542,7 +562,9 @@ void test_gsm_authen_imei()
thwart_rx_non_initial_requests();
btw("MS replies with an Identity Response");
+ expect_bssap_clear();
ms_sends_msg("0559084a32244332244332");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -555,7 +577,9 @@ void test_gsm_authen_imei()
vlr_subscr_put(vsub);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -654,7 +678,9 @@ void test_gsm_authen_tmsi_imei()
vlr_subscr_put(vsub);
btw("MS sends TMSI Realloc Complete");
+ expect_bssap_clear();
ms_sends_msg("055b");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
EXPECT_CONN_COUNT(0);
@@ -667,7 +693,9 @@ void test_gsm_authen_tmsi_imei()
vlr_subscr_put(vsub);
BTW("subscriber detaches, using TMSI");
+ expect_bssap_clear();
ms_sends_msg("050130" "05f4" "03020100");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -749,7 +777,9 @@ void test_gsm_milenage_authen()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000000156f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -780,8 +810,10 @@ void test_gsm_milenage_authen()
btw("a USSD request is serviced");
dtap_expect_tx_ussd("Your extension is 42342\r");
+ expect_bssap_clear();
ms_sends_msg("0b3b1c15a11302010002013b300b04010f0406aa510c061b017f0100");
OSMO_ASSERT(dtap_tx_confirmed);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("all requests serviced, conn has been released");
EXPECT_CONN_COUNT(0);
@@ -863,15 +895,19 @@ void test_gsm_milenage_authen()
btw("MS also sends RP-ACK, MSC in turn sends CP-ACK for that");
dtap_expect_tx("0904");
+ expect_bssap_clear();
ms_sends_msg("890106020041020000");
VERBOSE_ASSERT(dtap_tx_confirmed, == true, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("SMS is done, conn is gone");
EXPECT_CONN_COUNT(0);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130"
"089910070000106005" /* IMSI */);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
diff --git a/tests/msc_vlr/msc_vlr_test_gsm_authen.err b/tests/msc_vlr/msc_vlr_test_gsm_authen.err
index b6b84edec..bca64a453 100644
--- a/tests/msc_vlr/msc_vlr_test_gsm_authen.err
+++ b/tests/msc_vlr/msc_vlr_test_gsm_authen.err
@@ -150,6 +150,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -157,6 +158,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -262,12 +264,14 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- all requests serviced, conn has been released
llist_count(&net->subscr_conns) == 0
---
@@ -407,6 +411,7 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -414,6 +419,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- SMS is done, conn is gone
llist_count(&net->subscr_conns) == 0
---
@@ -429,8 +435,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_gsm_authen: SUCCESS
@@ -620,12 +628,14 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
- Subscriber has the new TMSI
@@ -737,12 +747,14 @@ DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Removing from parent S
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- all requests serviced, conn has been released
llist_count(&net->subscr_conns) == 0
---
@@ -882,6 +894,7 @@ DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Removing from parent S
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -889,6 +902,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- SMS is done, conn is gone
llist_count(&net->subscr_conns) == 0
---
@@ -1041,12 +1055,14 @@ DVLR vlr_lu_fsm(50462976){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cause OSMO
DVLR vlr_lu_fsm(50462976){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(50462976){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
- subscriber has the new TMSI
@@ -1069,8 +1085,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_gsm_authen_tmsi: SUCCESS
@@ -1258,12 +1276,14 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -1284,8 +1304,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_gsm_authen_imei: SUCCESS
@@ -1504,12 +1526,14 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
- Subscriber has the IMEI and TMSI
@@ -1530,8 +1554,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_gsm_authen_tmsi_imei: SUCCESS
@@ -1671,6 +1697,7 @@ DVLR vlr_lu_fsm(901700000010650){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000010650){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000010650){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:42342, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 2
@@ -1678,6 +1705,7 @@ DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:42342 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -1783,12 +1811,14 @@ DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:42342, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:42342: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 1
+ bssap_clear_sent == 1
- all requests serviced, conn has been released
llist_count(&net->subscr_conns) == 0
---
@@ -1928,6 +1958,7 @@ DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:42342, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:42342: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -1935,6 +1966,7 @@ DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- SMS is done, conn is gone
llist_count(&net->subscr_conns) == 0
---
@@ -1950,8 +1982,10 @@ DREF VLR subscr MSISDN:42342 usage decreases to: 1
DREF VLR subscr MSISDN:42342 usage decreases to: 0
DREF freeing VLR subscr MSISDN:42342
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_gsm_milenage_authen: SUCCESS
diff --git a/tests/msc_vlr/msc_vlr_test_gsm_ciph.c b/tests/msc_vlr/msc_vlr_test_gsm_ciph.c
index 589f7da94..42e7c737c 100644
--- a/tests/msc_vlr/msc_vlr_test_gsm_ciph.c
+++ b/tests/msc_vlr/msc_vlr_test_gsm_ciph.c
@@ -87,7 +87,9 @@ void test_ciph()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -124,8 +126,10 @@ void test_ciph()
btw("a USSD request is serviced");
dtap_expect_tx_ussd("Your extension is 46071\r");
+ expect_bssap_clear();
ms_sends_msg("0b3b1c15a11302010002013b300b04010f0406aa510c061b017f0100");
OSMO_ASSERT(dtap_tx_confirmed);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("all requests serviced, conn has been released");
EXPECT_CONN_COUNT(0);
@@ -213,14 +217,18 @@ void test_ciph()
btw("MS also sends RP-ACK, MSC in turn sends CP-ACK for that");
dtap_expect_tx("0904");
+ expect_bssap_clear();
ms_sends_msg("890106020041020000");
VERBOSE_ASSERT(dtap_tx_confirmed, == true, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("SMS is done, conn is gone");
EXPECT_CONN_COUNT(0);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -310,7 +318,9 @@ void test_ciph_tmsi()
vlr_subscr_put(vsub);
btw("MS sends TMSI Realloc Complete");
+ expect_bssap_clear();
ms_sends_msg("055b");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
EXPECT_CONN_COUNT(0);
@@ -355,8 +365,10 @@ void test_ciph_tmsi()
btw("a USSD request is serviced");
dtap_expect_tx_ussd("Your extension is 46071\r");
+ expect_bssap_clear();
ms_sends_msg("0b3b1c15a11302010002013b300b04010f0406aa510c061b017f0100");
OSMO_ASSERT(dtap_tx_confirmed);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("all requests serviced, conn has been released");
EXPECT_CONN_COUNT(0);
@@ -444,14 +456,18 @@ void test_ciph_tmsi()
btw("MS also sends RP-ACK, MSC in turn sends CP-ACK for that");
dtap_expect_tx("0904");
+ expect_bssap_clear();
ms_sends_msg("890106020041020000");
VERBOSE_ASSERT(dtap_tx_confirmed, == true, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("SMS is done, conn is gone");
EXPECT_CONN_COUNT(0);
BTW("subscriber detaches, using TMSI");
+ expect_bssap_clear();
ms_sends_msg("050130" "05f4" "03020100");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -536,7 +552,9 @@ void test_ciph_imei()
thwart_rx_non_initial_requests();
btw("MS replies with an Identity Response");
+ expect_bssap_clear();
ms_sends_msg("0559084a32244332244332");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -549,7 +567,9 @@ void test_ciph_imei()
vlr_subscr_put(vsub);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -639,14 +659,18 @@ void test_ciph_imeisv()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
EXPECT_CONN_COUNT(0);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -749,7 +773,9 @@ void test_ciph_tmsi_imei()
vlr_subscr_put(vsub);
btw("MS sends TMSI Realloc Complete");
+ expect_bssap_clear();
ms_sends_msg("055b");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
EXPECT_CONN_COUNT(0);
@@ -762,7 +788,9 @@ void test_ciph_tmsi_imei()
vlr_subscr_put(vsub);
BTW("subscriber detaches, using TMSI");
+ expect_bssap_clear();
ms_sends_msg("050130" "05f4" "03020100");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -799,7 +827,9 @@ void test_lu_unknown_tmsi()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
diff --git a/tests/msc_vlr/msc_vlr_test_gsm_ciph.err b/tests/msc_vlr/msc_vlr_test_gsm_ciph.err
index bd8d1b9be..c219b496f 100644
--- a/tests/msc_vlr/msc_vlr_test_gsm_ciph.err
+++ b/tests/msc_vlr/msc_vlr_test_gsm_ciph.err
@@ -150,6 +150,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -157,6 +158,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -279,12 +281,14 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- all requests serviced, conn has been released
llist_count(&net->subscr_conns) == 0
---
@@ -441,6 +445,7 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -448,6 +453,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- SMS is done, conn is gone
llist_count(&net->subscr_conns) == 0
---
@@ -463,8 +469,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_ciph: SUCCESS
@@ -655,12 +663,14 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
- Subscriber has the new TMSI
@@ -789,12 +799,14 @@ DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Removing from parent S
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- all requests serviced, conn has been released
llist_count(&net->subscr_conns) == 0
---
@@ -951,6 +963,7 @@ DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Removing from parent S
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -958,6 +971,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- SMS is done, conn is gone
llist_count(&net->subscr_conns) == 0
---
@@ -973,8 +987,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_ciph_tmsi: SUCCESS
@@ -1162,12 +1178,14 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -1188,8 +1206,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_ciph_imei: SUCCESS
@@ -1379,6 +1399,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -1386,6 +1407,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -1402,8 +1424,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_ciph_imeisv: SUCCESS
@@ -1622,12 +1646,14 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
- Subscriber has the IMEI and TMSI
@@ -1648,8 +1674,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_ciph_tmsi_imei: SUCCESS
diff --git a/tests/msc_vlr/msc_vlr_test_hlr_reject.c b/tests/msc_vlr/msc_vlr_test_hlr_reject.c
index c4cf3534a..095da8172 100644
--- a/tests/msc_vlr/msc_vlr_test_hlr_reject.c
+++ b/tests/msc_vlr/msc_vlr_test_hlr_reject.c
@@ -38,9 +38,11 @@ void test_hlr_rej_auth_info_unknown_imsi()
btw("HLR sends _SEND_AUTH_INFO_ERROR = unknown IMSI");
auth_request_sent = false;
+ expect_bssap_clear();
gsup_rx("09" "010809710000004026f0" "020102", NULL);
VERBOSE_ASSERT(auth_request_sent, == false, "%d");
VERBOSE_ASSERT(lu_result_sent, == RES_REJECT, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -62,9 +64,11 @@ void test_hlr_rej_auth_info_net_fail()
btw("HLR sends _SEND_AUTH_INFO_ERROR = net fail");
auth_request_sent = false;
+ expect_bssap_clear();
gsup_rx("09" "010809710000004026f0" "020111", NULL);
VERBOSE_ASSERT(auth_request_sent, == false, "%d");
VERBOSE_ASSERT(lu_result_sent, == RES_REJECT, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -118,7 +122,9 @@ void test_hlr_rej_auth_info_net_fail_no_reuse_tuples()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -145,9 +151,11 @@ void test_hlr_rej_auth_info_net_fail_no_reuse_tuples()
btw("HLR sends _SEND_AUTH_INFO_ERROR = net fail");
auth_request_sent = false;
+ expect_bssap_clear();
gsup_rx("09" "010809710000004026f0" "020111", NULL);
VERBOSE_ASSERT(auth_request_sent, == false, "%d");
VERBOSE_ASSERT(lu_result_sent, == RES_REJECT, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -201,7 +209,9 @@ void test_hlr_rej_auth_info_unkown_imsi_no_reuse_tuples()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -229,9 +239,11 @@ void test_hlr_rej_auth_info_unkown_imsi_no_reuse_tuples()
btw("HLR sends _SEND_AUTH_INFO_ERROR = unknown IMSI");
auth_request_sent = false;
+ expect_bssap_clear();
gsup_rx("09" "010809710000004026f0" "020102", NULL);
VERBOSE_ASSERT(auth_request_sent, == false, "%d");
VERBOSE_ASSERT(lu_result_sent, == RES_REJECT, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -255,6 +267,7 @@ void test_hlr_acc_but_no_auth_tuples()
btw("from HLR, rx _SEND_AUTH_INFO_RESULT but it lacks auth tuples");
auth_request_sent = false;
+ expect_bssap_clear();
gsup_rx("0a"
/* imsi */
"0108" "09710000004026f0"
@@ -262,6 +275,7 @@ void test_hlr_acc_but_no_auth_tuples()
,NULL);
VERBOSE_ASSERT(auth_request_sent, == false, "%d");
VERBOSE_ASSERT(lu_result_sent, == RES_REJECT, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -315,7 +329,9 @@ void test_hlr_rej_auth_info_net_fail_reuse_tuples()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -357,7 +373,9 @@ void test_hlr_rej_auth_info_net_fail_reuse_tuples()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -379,9 +397,11 @@ void test_hlr_rej_lu()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR sends UPDATE_LOCATION_ERROR");
+ expect_bssap_clear();
gsup_rx("05" "010809710000004026f0" "020102",
NULL);
VERBOSE_ASSERT(lu_result_sent, == RES_REJECT, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -400,7 +420,9 @@ void test_hlr_no_insert_data()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR sends only _UPDATE_LOCATION_RESULT, no INSERT DATA");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
/* TODO should we wait for OSMO_GSUP_MSGT_INSERT_DATA_REQUEST? */
diff --git a/tests/msc_vlr/msc_vlr_test_hlr_reject.err b/tests/msc_vlr/msc_vlr_test_hlr_reject.err
index 9650df9de..c946c1efa 100644
--- a/tests/msc_vlr/msc_vlr_test_hlr_reject.err
+++ b/tests/msc_vlr/msc_vlr_test_hlr_reject.err
@@ -56,6 +56,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=IMSI:901700000004620, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF IMSI:901700000004620: MSC conn use - 1 == 0
DRLL subscr IMSI:901700000004620: Freeing subscriber connection
DREF VLR subscr IMSI:901700000004620 usage decreases to: 1
@@ -66,6 +67,7 @@ DREF freeing VLR subscr IMSI:901700000004620
<-- GSUP rx OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR: vlr_gsupc_read_cb() returns 0
auth_request_sent == 0
lu_result_sent == 2
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_hlr_rej_auth_info_unknown_imsi: SUCCESS
@@ -130,6 +132,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=IMSI:901700000004620, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF IMSI:901700000004620: MSC conn use - 1 == 0
DRLL subscr IMSI:901700000004620: Freeing subscriber connection
DREF VLR subscr IMSI:901700000004620 usage decreases to: 1
@@ -140,6 +143,7 @@ DREF freeing VLR subscr IMSI:901700000004620
<-- GSUP rx OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR: vlr_gsupc_read_cb() returns 0
auth_request_sent == 0
lu_result_sent == 2
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_hlr_rej_auth_info_net_fail: SUCCESS
@@ -281,6 +285,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -288,6 +293,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -427,6 +433,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -434,6 +441,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -578,6 +586,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -585,6 +594,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -650,6 +660,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -659,6 +670,7 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR: vlr_gsupc_read_cb() returns 0
auth_request_sent == 0
lu_result_sent == 2
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
DREF freeing VLR subscr MSISDN:46071
===== test_hlr_rej_auth_info_net_fail_no_reuse_tuples: SUCCESS
@@ -801,6 +813,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -808,6 +821,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -874,6 +888,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -883,6 +898,7 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR: vlr_gsupc_read_cb() returns 0
auth_request_sent == 0
lu_result_sent == 2
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
DREF freeing VLR subscr MSISDN:46071
===== test_hlr_rej_auth_info_unkown_imsi_no_reuse_tuples: SUCCESS
@@ -947,6 +963,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=IMSI:901700000004620, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF IMSI:901700000004620: MSC conn use - 1 == 0
DRLL subscr IMSI:901700000004620: Freeing subscriber connection
DREF VLR subscr IMSI:901700000004620 usage decreases to: 1
@@ -957,6 +974,7 @@ DREF freeing VLR subscr IMSI:901700000004620
<-- GSUP rx OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT: vlr_gsupc_read_cb() returns 0
auth_request_sent == 0
lu_result_sent == 2
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_hlr_acc_but_no_auth_tuples: SUCCESS
@@ -1024,6 +1042,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=IMSI:901700000004620, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF IMSI:901700000004620: MSC conn use - 1 == 0
DRLL subscr IMSI:901700000004620: Freeing subscriber connection
DREF VLR subscr IMSI:901700000004620 usage decreases to: 1
@@ -1033,6 +1052,7 @@ DREF VLR subscr IMSI:901700000004620 usage decreases to: 0
DREF freeing VLR subscr IMSI:901700000004620
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR: vlr_gsupc_read_cb() returns 0
lu_result_sent == 2
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_hlr_rej_lu: SUCCESS
@@ -1122,6 +1142,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=IMSI:901700000004620, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF IMSI:901700000004620: MSC conn use - 1 == 0
DRLL subscr IMSI:901700000004620: Freeing subscriber connection
DREF VLR subscr IMSI:901700000004620 usage decreases to: 2
@@ -1129,6 +1150,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr IMSI:901700000004620 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
diff --git a/tests/msc_vlr/msc_vlr_test_hlr_timeout.c b/tests/msc_vlr/msc_vlr_test_hlr_timeout.c
index 2872f0cf4..c2f17c85f 100644
--- a/tests/msc_vlr/msc_vlr_test_hlr_timeout.c
+++ b/tests/msc_vlr/msc_vlr_test_hlr_timeout.c
@@ -53,8 +53,10 @@ void test_hlr_timeout_lu_auth_info()
EXPECT_CONN_COUNT(1);
fake_time_passes(1, 235);
EXPECT_CONN_COUNT(1);
+ expect_bssap_clear();
fake_time_passes(1, 235);
btw("SUBSCR_CONN_TIMEOUT has passed, conn is gone.");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
VERBOSE_ASSERT(lu_result_sent, == RES_REJECT, "%d");
@@ -98,8 +100,10 @@ void test_hlr_timeout_lu_upd_loc_result()
fake_time_passes(1, 235);
EXPECT_CONN_COUNT(1);
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
+ expect_bssap_clear();
fake_time_passes(1, 235);
btw("SUBSCR_CONN_TIMEOUT has passed, conn is gone.");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
VERBOSE_ASSERT(lu_result_sent, == RES_REJECT, "%d");
diff --git a/tests/msc_vlr/msc_vlr_test_hlr_timeout.err b/tests/msc_vlr/msc_vlr_test_hlr_timeout.err
index f83cc2976..e34490d8c 100644
--- a/tests/msc_vlr/msc_vlr_test_hlr_timeout.err
+++ b/tests/msc_vlr/msc_vlr_test_hlr_timeout.err
@@ -64,6 +64,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=IMSI:901700000004620, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF IMSI:901700000004620: MSC conn use - 1 == 0
DRLL subscr IMSI:901700000004620: Freeing subscriber connection
DREF VLR subscr IMSI:901700000004620 usage decreases to: 0
@@ -73,6 +74,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Received Event SUBSCR_CONN_E_CN_CLOSE
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Event SUBSCR_CONN_E_CN_CLOSE not permitted
- SUBSCR_CONN_TIMEOUT has passed, conn is gone.
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
lu_result_sent == 2
===== test_hlr_timeout_lu_auth_info: SUCCESS
@@ -164,6 +166,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 0
@@ -173,6 +176,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Received Event SUBSCR_CONN_E_CN_CLOSE
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Event SUBSCR_CONN_E_CN_CLOSE not permitted
- SUBSCR_CONN_TIMEOUT has passed, conn is gone.
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
lu_result_sent == 2
===== test_hlr_timeout_lu_upd_loc_result: SUCCESS
diff --git a/tests/msc_vlr/msc_vlr_test_ms_timeout.c b/tests/msc_vlr/msc_vlr_test_ms_timeout.c
index 47ca9678f..d8a3a314e 100644
--- a/tests/msc_vlr/msc_vlr_test_ms_timeout.c
+++ b/tests/msc_vlr/msc_vlr_test_ms_timeout.c
@@ -73,8 +73,10 @@ void test_ms_timeout_lu_auth_resp()
fake_time_passes(1, 235);
EXPECT_CONN_COUNT(1);
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
+ expect_bssap_clear();
fake_time_passes(1, 235);
btw("SUBSCR_CONN_TIMEOUT has passed, conn is gone.");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
VERBOSE_ASSERT(lu_result_sent, == RES_REJECT, "%d");
@@ -132,7 +134,9 @@ void test_ms_timeout_cm_auth_resp()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -167,8 +171,10 @@ void test_ms_timeout_cm_auth_resp()
fake_time_passes(1, 235);
EXPECT_CONN_COUNT(1);
VERBOSE_ASSERT(cm_service_result_sent, == RES_NONE, "%d");
+ expect_bssap_clear();
fake_time_passes(1, 235);
btw("SUBSCR_CONN_TIMEOUT has passed, conn is gone.");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
VERBOSE_ASSERT(cm_service_result_sent, == RES_REJECT, "%d");
diff --git a/tests/msc_vlr/msc_vlr_test_ms_timeout.err b/tests/msc_vlr/msc_vlr_test_ms_timeout.err
index 1574ef9ee..e267c5b0c 100644
--- a/tests/msc_vlr/msc_vlr_test_ms_timeout.err
+++ b/tests/msc_vlr/msc_vlr_test_ms_timeout.err
@@ -84,6 +84,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=IMSI:901700000004620, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF IMSI:901700000004620: MSC conn use - 1 == 0
DRLL subscr IMSI:901700000004620: Freeing subscriber connection
DREF VLR subscr IMSI:901700000004620 usage decreases to: 0
@@ -93,6 +94,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Received Event SUBSCR_CONN_E_CN_CLOSE
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Event SUBSCR_CONN_E_CN_CLOSE not permitted
- SUBSCR_CONN_TIMEOUT has passed, conn is gone.
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
lu_result_sent == 2
===== test_ms_timeout_lu_auth_resp: SUCCESS
@@ -234,6 +236,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -241,6 +244,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -315,6 +319,7 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
@@ -323,6 +328,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Received Event SUBSCR_CONN_E_CN_CLOSE
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Event SUBSCR_CONN_E_CN_CLOSE not permitted
- SUBSCR_CONN_TIMEOUT has passed, conn is gone.
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
cm_service_result_sent == 2
DREF freeing VLR subscr MSISDN:46071
diff --git a/tests/msc_vlr/msc_vlr_test_no_authen.c b/tests/msc_vlr/msc_vlr_test_no_authen.c
index f5e2e2b62..34e392e72 100644
--- a/tests/msc_vlr/msc_vlr_test_no_authen.c
+++ b/tests/msc_vlr/msc_vlr_test_no_authen.c
@@ -53,10 +53,12 @@ void test_no_authen()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
BTW("after a while, a new conn sends a CM Service Request");
@@ -70,8 +72,10 @@ void test_no_authen()
btw("a USSD request is serviced");
dtap_expect_tx_ussd("Your extension is 46071\r");
+ expect_bssap_clear();
ms_sends_msg("0b3b1c15a11302010002013b300b04010f0406aa510c061b017f0100");
VERBOSE_ASSERT(dtap_tx_confirmed, == true, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("all requests serviced, conn has been released");
EXPECT_CONN_COUNT(0);
@@ -140,14 +144,18 @@ void test_no_authen()
btw("MS also sends RP-ACK, MSC in turn sends CP-ACK for that");
dtap_expect_tx("0904");
+ expect_bssap_clear();
ms_sends_msg("890106020041020000");
VERBOSE_ASSERT(dtap_tx_confirmed, == true, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("SMS is done, conn is gone");
EXPECT_CONN_COUNT(0);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -200,7 +208,9 @@ void test_no_authen_tmsi()
vlr_subscr_put(vsub);
btw("MS sends TMSI Realloc Complete");
+ expect_bssap_clear();
ms_sends_msg("055b");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
EXPECT_CONN_COUNT(0);
@@ -224,7 +234,9 @@ void test_no_authen_tmsi()
btw("a USSD request is serviced");
dtap_expect_tx_ussd("Your extension is 46071\r");
+ expect_bssap_clear();
ms_sends_msg("0b3b1c15a11302010002013b300b04010f0406aa510c061b017f0100");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("all requests serviced, conn has been released");
EXPECT_CONN_COUNT(0);
@@ -293,8 +305,10 @@ void test_no_authen_tmsi()
btw("MS also sends RP-ACK, MSC in turn sends CP-ACK for that");
dtap_expect_tx("0904");
+ expect_bssap_clear();
ms_sends_msg("890106020041020000");
VERBOSE_ASSERT(dtap_tx_confirmed, == true, "%d");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("SMS is done, conn is gone");
EXPECT_CONN_COUNT(0);
@@ -343,7 +357,9 @@ void test_no_authen_tmsi()
vlr_subscr_put(vsub);
btw("MS sends TMSI Realloc Complete");
+ expect_bssap_clear();
ms_sends_msg("055b");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
EXPECT_CONN_COUNT(0);
@@ -357,7 +373,9 @@ void test_no_authen_tmsi()
vlr_subscr_put(vsub);
BTW("subscriber detaches, using new TMSI");
+ expect_bssap_clear();
ms_sends_msg("050130" "05f4" "07060504");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -406,7 +424,9 @@ void test_no_authen_imei()
thwart_rx_non_initial_requests();
btw("MS replies with an Identity Response");
+ expect_bssap_clear();
ms_sends_msg("0559084a32244332244332");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -419,7 +439,9 @@ void test_no_authen_imei()
vlr_subscr_put(vsub);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -478,7 +500,9 @@ void test_no_authen_tmsi_imei()
thwart_rx_non_initial_requests();
btw("MS sends TMSI Realloc Complete");
+ expect_bssap_clear();
ms_sends_msg("055b");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -492,7 +516,9 @@ void test_no_authen_tmsi_imei()
vlr_subscr_put(vsub);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
diff --git a/tests/msc_vlr/msc_vlr_test_no_authen.err b/tests/msc_vlr/msc_vlr_test_no_authen.err
index 015e55b9d..4f4073683 100644
--- a/tests/msc_vlr/msc_vlr_test_no_authen.err
+++ b/tests/msc_vlr/msc_vlr_test_no_authen.err
@@ -103,6 +103,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -112,6 +113,7 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
- LU was successful, and the conn has already been closed
lu_result_sent == 1
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
---
- after a while, a new conn sends a CM Service Request
@@ -176,6 +178,7 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -183,6 +186,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- all requests serviced, conn has been released
llist_count(&net->subscr_conns) == 0
---
@@ -283,6 +287,7 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -290,6 +295,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- SMS is done, conn is gone
llist_count(&net->subscr_conns) == 0
---
@@ -305,8 +311,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_no_authen: SUCCESS
@@ -449,12 +457,14 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
- Subscriber has the new TMSI
@@ -527,12 +537,14 @@ DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Removing from parent S
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- all requests serviced, conn has been released
llist_count(&net->subscr_conns) == 0
---
@@ -633,6 +645,7 @@ DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Removing from parent S
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(50462976){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -640,6 +653,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- SMS is done, conn is gone
llist_count(&net->subscr_conns) == 0
---
@@ -776,12 +790,14 @@ DVLR vlr_lu_fsm(50462976){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cause OSMO
DVLR vlr_lu_fsm(50462976){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(50462976){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(50462976){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
- subscriber has the new TMSI
@@ -804,8 +820,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_no_authen_tmsi: SUCCESS
@@ -946,12 +964,14 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -972,8 +992,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_no_authen_imei: SUCCESS
@@ -1138,12 +1160,14 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -1165,8 +1189,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_no_authen_tmsi_imei: SUCCESS
diff --git a/tests/msc_vlr/msc_vlr_test_reject_concurrency.c b/tests/msc_vlr/msc_vlr_test_reject_concurrency.c
index 15988584a..2377c19b3 100644
--- a/tests/msc_vlr/msc_vlr_test_reject_concurrency.c
+++ b/tests/msc_vlr/msc_vlr_test_reject_concurrency.c
@@ -39,7 +39,9 @@ void test_reject_2nd_conn()
btw("Another Location Update Request from the same subscriber on another connection is rejected");
conn1 = g_conn;
g_conn = NULL;
+ expect_bssap_clear();
ms_sends_msg("050802008168000130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
VERBOSE_ASSERT(lu_result_sent, == RES_REJECT, "%d");
EXPECT_CONN_COUNT(1);
@@ -53,7 +55,9 @@ void test_reject_2nd_conn()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -83,7 +87,9 @@ void _normal_lu_part2()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -164,7 +170,7 @@ void _paging_resp_part1()
EXPECT_CONN_COUNT(1);
}
-void _paging_resp_part2(int expect_conn_count)
+void _paging_resp_part2(int expect_conn_count, bool expect_clear)
{
btw("MS replies with CP-ACK for received SMS");
ms_sends_msg("8904");
@@ -172,8 +178,12 @@ void _paging_resp_part2(int expect_conn_count)
btw("MS also sends RP-ACK, MSC in turn sends CP-ACK for that");
dtap_expect_tx("0904");
+ if (expect_clear)
+ expect_bssap_clear();
ms_sends_msg("890106020041020000");
VERBOSE_ASSERT(dtap_tx_confirmed, == true, "%d");
+ if (expect_clear)
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("SMS is done");
EXPECT_CONN_COUNT(expect_conn_count);
@@ -251,7 +261,9 @@ void test_reject_lu_during_cm()
EXPECT_CONN_COUNT(1);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -272,7 +284,9 @@ void test_reject_cm_during_cm()
EXPECT_CONN_COUNT(1);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -293,7 +307,9 @@ void test_reject_paging_resp_during_cm()
BTW("The original CM Service Request can conclude");
btw("a USSD request is serviced");
dtap_expect_tx_ussd("Your extension is 46071\r");
+ expect_bssap_clear();
ms_sends_msg("0b3b1c15a11302010002013b300b04010f0406aa510c061b017f0100");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("all requests serviced, conn has been released");
EXPECT_CONN_COUNT(0);
@@ -313,7 +329,7 @@ void test_reject_paging_resp_during_paging_resp()
BTW("MS sends another erratic Paging Response which is dropped silently");
ms_sends_msg("06270703305882089910070000006402");
- _paging_resp_part2(0);
+ _paging_resp_part2(0, true);
clear_vlr();
comment_end();
@@ -333,13 +349,13 @@ void test_reject_lu_during_paging_resp()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
EXPECT_CONN_COUNT(1);
- _paging_resp_part2(0);
+ _paging_resp_part2(0, true);
clear_vlr();
comment_end();
}
-void test_reject_cm_during_paging_resp()
+void test_accept_cm_during_paging_resp()
{
comment_start();
@@ -354,10 +370,12 @@ void test_reject_cm_during_paging_resp()
EXPECT_CONN_COUNT(1);
VERBOSE_ASSERT(g_conn->received_cm_service_request, == true, "%d");
- _paging_resp_part2(1);
+ _paging_resp_part2(1, false);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -373,7 +391,7 @@ msc_vlr_test_func_t msc_vlr_tests[] = {
test_reject_cm_during_cm,
test_reject_paging_resp_during_cm,
test_reject_lu_during_paging_resp,
- test_reject_cm_during_paging_resp,
+ test_accept_cm_during_paging_resp,
test_reject_paging_resp_during_paging_resp,
NULL
};
diff --git a/tests/msc_vlr/msc_vlr_test_reject_concurrency.err b/tests/msc_vlr/msc_vlr_test_reject_concurrency.err
index 7b0954fdc..00945cb89 100644
--- a/tests/msc_vlr/msc_vlr_test_reject_concurrency.err
+++ b/tests/msc_vlr/msc_vlr_test_reject_concurrency.err
@@ -64,6 +64,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=unknown, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -71,6 +72,7 @@ DREF VLR subscr IMSI:901700000004620 usage decreases to: 1
DRR 901700000004620: internal error during Location Updating attempt
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
lu_result_sent == 2
llist_count(&net->subscr_conns) == 1
---
@@ -133,6 +135,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -140,6 +143,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -255,6 +259,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -262,6 +267,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -383,6 +389,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -390,6 +397,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -506,6 +514,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -513,6 +522,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -618,6 +628,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -625,6 +636,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -694,6 +706,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_ACCEPTED}: Received Event SUBSCR_
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_ACCEPTED}: state_chg to SUBSCR_CONN_S_RELEASED
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Terminating (cause = OSMO_FSM_TERM_REGULAR)
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -704,6 +717,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_reject_lu_during_cm: SUCCESS
@@ -806,6 +820,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -813,6 +828,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -884,6 +900,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_ACCEPTED}: Received Event SUBSCR_
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_ACCEPTED}: state_chg to SUBSCR_CONN_S_RELEASED
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Terminating (cause = OSMO_FSM_TERM_REGULAR)
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -894,6 +911,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_reject_cm_during_cm: SUCCESS
@@ -996,6 +1014,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -1003,6 +1022,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -1082,12 +1102,14 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
+ bssap_clear_sent == 1
- all requests serviced, conn has been released
llist_count(&net->subscr_conns) == 0
DREF freeing VLR subscr MSISDN:46071
@@ -1192,6 +1214,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -1199,6 +1222,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -1303,6 +1327,7 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -1310,6 +1335,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- SMS is done
llist_count(&net->subscr_conns) == 0
DREF freeing VLR subscr MSISDN:46071
@@ -1318,7 +1344,7 @@ DREF freeing VLR subscr MSISDN:46071
full talloc report on 'msgb' (total 0 bytes in 1 blocks)
talloc_total_blocks(tall_bsc_ctx) == 9
-===== test_reject_cm_during_paging_resp
+===== test_accept_cm_during_paging_resp
---
- Subscriber does a normal LU
- Location Update Request
@@ -1414,6 +1440,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -1421,6 +1448,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -1541,6 +1569,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_COMMUNICATING}: Received Event SU
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_COMMUNICATING}: state_chg to SUBSCR_CONN_S_RELEASED
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Terminating (cause = OSMO_FSM_TERM_REGULAR)
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -1551,8 +1580,9 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
-===== test_reject_cm_during_paging_resp: SUCCESS
+===== test_accept_cm_during_paging_resp: SUCCESS
full talloc report on 'msgb' (total 0 bytes in 1 blocks)
talloc_total_blocks(tall_bsc_ctx) == 9
@@ -1653,6 +1683,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -1660,6 +1691,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -1763,6 +1795,7 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -1770,6 +1803,7 @@ DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- SMS is done
llist_count(&net->subscr_conns) == 0
DREF freeing VLR subscr MSISDN:46071
diff --git a/tests/msc_vlr/msc_vlr_test_rest.c b/tests/msc_vlr/msc_vlr_test_rest.c
index 5ccc951be..c5f7fcfb9 100644
--- a/tests/msc_vlr/msc_vlr_test_rest.c
+++ b/tests/msc_vlr/msc_vlr_test_rest.c
@@ -45,6 +45,7 @@ void test_early_stage()
btw("fake: acceptance");
g_conn->vsub = vlr_subscr_alloc(net->vlr);
+ g_conn->via_ran = RAN_GERAN_A;
OSMO_ASSERT(g_conn->vsub);
/* mark as silent call so it sticks around */
g_conn->silent_call = 1;
@@ -53,7 +54,9 @@ void test_early_stage()
EXPECT_ACCEPTED(true);
btw("CLOSE event marks conn_fsm as released and frees the conn");
+ expect_bssap_clear();
osmo_fsm_inst_dispatch(g_conn->conn_fsm, SUBSCR_CONN_E_CN_CLOSE, NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -65,7 +68,9 @@ void test_cm_service_without_lu()
comment_start();
btw("CM Service Request without a prior Location Updating");
+ expect_bssap_clear();
ms_sends_msg("05247803305886089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("conn was released");
EXPECT_CONN_COUNT(0);
@@ -98,7 +103,9 @@ void test_two_lu()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
@@ -126,14 +133,18 @@ void test_two_lu()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
EXPECT_CONN_COUNT(0);
BTW("subscriber detaches");
+ expect_bssap_clear();
ms_sends_msg("050130089910070000006402");
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -170,7 +181,9 @@ void test_lu_unknown_tmsi()
VERBOSE_ASSERT(lu_result_sent, == RES_NONE, "%d");
btw("HLR also sends GSUP _UPDATE_LOCATION_RESULT");
+ expect_bssap_clear();
gsup_rx("06010809710000004026f0", NULL);
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d");
btw("LU was successful, and the conn has already been closed");
VERBOSE_ASSERT(lu_result_sent, == RES_ACCEPT, "%d");
diff --git a/tests/msc_vlr/msc_vlr_test_rest.err b/tests/msc_vlr/msc_vlr_test_rest.err
index 6122040c9..1b5f3406d 100644
--- a/tests/msc_vlr/msc_vlr_test_rest.err
+++ b/tests/msc_vlr/msc_vlr_test_rest.err
@@ -28,13 +28,14 @@ DMM Subscr_Conn(test){SUBSCR_CONN_S_ACCEPTED}: Received Event SUBSCR_CONN_E_CN_C
DMM Subscr_Conn(test){SUBSCR_CONN_S_ACCEPTED}: state_chg to SUBSCR_CONN_S_RELEASED
DMM Subscr_Conn(test){SUBSCR_CONN_S_RELEASED}: Terminating (cause = OSMO_FSM_TERM_REGULAR)
DMM msc_subscr_conn_close(vsub=unknown, cause=2): no conn fsm, releasing directly without release event.
-DMM unknown: Unknown RAN type, cannot tx release/clear
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL subscr unknown: Freeing subscriber connection
DREF VLR subscr unknown usage decreases to: 0
DREF freeing VLR subscr unknown
DMM Subscr_Conn(test){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(test){SUBSCR_CONN_S_RELEASED}: Deallocated
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_early_stage: SUCCESS
@@ -70,11 +71,13 @@ DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000004620){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=unknown, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
- conn was released
llist_count(&net->subscr_conns) == 0
===== test_cm_service_without_lu: SUCCESS
@@ -187,6 +190,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -194,6 +198,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -300,6 +305,7 @@ DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000004620){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -307,6 +313,7 @@ DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000004620){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
@@ -323,8 +330,10 @@ DREF VLR subscr MSISDN:46071 usage decreases to: 1
DREF VLR subscr MSISDN:46071 usage decreases to: 0
DREF freeing VLR subscr MSISDN:46071
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_two_lu: SUCCESS
@@ -461,6 +470,7 @@ DVLR vlr_lu_fsm(591536962){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cause OSM
DVLR vlr_lu_fsm(591536962){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(591536962){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:46071, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:46071: MSC conn use - 1 == 0
DRLL subscr MSISDN:46071: Freeing subscriber connection
DREF VLR subscr MSISDN:46071 usage decreases to: 2
@@ -468,6 +478,7 @@ DMM Subscr_Conn(591536962){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(591536962){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF VLR subscr MSISDN:46071 usage decreases to: 1
<-- GSUP rx OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: vlr_gsupc_read_cb() returns 0
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
lu_result_sent == 1
llist_count(&net->subscr_conns) == 0
diff --git a/tests/msc_vlr/msc_vlr_test_umts_authen.c b/tests/msc_vlr/msc_vlr_test_umts_authen.c
index d026f0229..1175bf875 100644
--- a/tests/msc_vlr/msc_vlr_test_umts_authen.c
+++ b/tests/msc_vlr/msc_vlr_test_umts_authen.c
@@ -23,6 +23,19 @@
#include "msc_vlr_tests.h"
+#define ASSERT_RELEASE_CLEAR(via_ran) \
+ switch (via_ran) { \
+ case RAN_GERAN_A: \
+ VERBOSE_ASSERT(bssap_clear_sent, == true, "%d"); \
+ break; \
+ case RAN_UTRAN_IU: \
+ VERBOSE_ASSERT(iu_release_sent, == true, "%d"); \
+ break; \
+ default: \
+ OSMO_ASSERT(false); \
+ break; \
+ }
+
void _test_umts_authen(enum ran_type via_ran)
{
struct vlr_subscr *vsub;
@@ -167,7 +180,9 @@ void _test_umts_authen(enum ran_type via_ran)
vlr_subscr_put(vsub);
btw("MS sends TMSI Realloc Complete");
+ expect_release_clear(via_ran);
ms_sends_msg("055b");
+ ASSERT_RELEASE_CLEAR(via_ran);
btw("LU was successful, and the conn has already been closed");
EXPECT_CONN_COUNT(0);
@@ -210,8 +225,10 @@ void _test_umts_authen(enum ran_type via_ran)
btw("a USSD request is serviced");
dtap_expect_tx_ussd("Your extension is 42342\r");
+ expect_release_clear(via_ran);
ms_sends_msg("0b3b1c15a11302010002013b300b04010f0406aa510c061b017f0100");
OSMO_ASSERT(dtap_tx_confirmed);
+ ASSERT_RELEASE_CLEAR(via_ran);
btw("all requests serviced, conn has been released");
EXPECT_CONN_COUNT(0);
@@ -287,15 +304,19 @@ void _test_umts_authen(enum ran_type via_ran)
btw("MS also sends RP-ACK, MSC in turn sends CP-ACK for that");
dtap_expect_tx("0904");
+ expect_release_clear(via_ran);
ms_sends_msg("890106020041020000");
VERBOSE_ASSERT(dtap_tx_confirmed, == true, "%d");
+ ASSERT_RELEASE_CLEAR(via_ran);
btw("SMS is done, conn is gone");
EXPECT_CONN_COUNT(0);
BTW("subscriber detaches");
+ expect_release_clear(via_ran);
ms_sends_msg("050130"
"089910070000106005" /* IMSI */);
+ ASSERT_RELEASE_CLEAR(via_ran);
EXPECT_CONN_COUNT(0);
clear_vlr();
@@ -527,7 +548,9 @@ void _test_umts_authen_resync(enum ran_type via_ran)
vlr_subscr_put(vsub);
btw("MS sends TMSI Realloc Complete");
+ expect_release_clear(via_ran);
ms_sends_msg("055b");
+ ASSERT_RELEASE_CLEAR(via_ran);
btw("LU was successful, and the conn has already been closed");
EXPECT_CONN_COUNT(0);
diff --git a/tests/msc_vlr/msc_vlr_test_umts_authen.err b/tests/msc_vlr/msc_vlr_test_umts_authen.err
index f59612cef..57f5e8e85 100644
--- a/tests/msc_vlr/msc_vlr_test_umts_authen.err
+++ b/tests/msc_vlr/msc_vlr_test_umts_authen.err
@@ -164,12 +164,14 @@ DVLR vlr_lu_fsm(901700000010650){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000010650){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000010650){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:42342, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:42342: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
---
@@ -275,12 +277,14 @@ DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:42342, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:42342: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 1
+ bssap_clear_sent == 1
- all requests serviced, conn has been released
llist_count(&net->subscr_conns) == 0
---
@@ -421,6 +425,7 @@ DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Removing from p
DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Freeing instance
DVLR Process_Access_Request_VLR(901700000010650){PR_ARQ_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:42342, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:42342: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Deallocated
@@ -428,6 +433,7 @@ DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 1
dtap_tx_confirmed == 1
+ bssap_clear_sent == 1
- SMS is done, conn is gone
llist_count(&net->subscr_conns) == 0
---
@@ -443,8 +449,10 @@ DREF VLR subscr MSISDN:42342 usage decreases to: 1
DREF VLR subscr MSISDN:42342 usage decreases to: 0
DREF freeing VLR subscr MSISDN:42342
DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ bssap_clear_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_umts_authen_geran: SUCCESS
@@ -633,6 +641,7 @@ DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 1
+ iu_release_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
---
@@ -752,6 +761,7 @@ DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 1
+ iu_release_sent == 1
- all requests serviced, conn has been released
llist_count(&net->subscr_conns) == 0
---
@@ -907,6 +917,7 @@ DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 1
dtap_tx_confirmed == 1
+ iu_release_sent == 1
- SMS is done, conn is gone
llist_count(&net->subscr_conns) == 0
---
@@ -925,6 +936,7 @@ DMM msc_subscr_conn_close(vsub=unknown, cause=0): no conn fsm, releasing directl
- Iu Release --RAN_UTRAN_IU--> MS
DREF unknown: MSC conn use - 1 == 0
DRLL Freeing subscriber connection with NULL subscriber
+ iu_release_sent == 1
llist_count(&net->subscr_conns) == 0
===== test_umts_authen_utran: SUCCESS
@@ -1127,12 +1139,14 @@ DVLR vlr_lu_fsm(901700000010650){VLR_ULA_S_DONE}: fsm_lu_cleanup called with cau
DVLR vlr_lu_fsm(901700000010650){VLR_ULA_S_DONE}: Freeing instance
DVLR vlr_lu_fsm(901700000010650){VLR_ULA_S_DONE}: Deallocated
DMM msc_subscr_conn_close(vsub=MSISDN:42342, cause=2): no conn fsm, releasing directly without release event.
+- BSSAP Clear --RAN_GERAN_A--> MS
DREF MSISDN:42342: MSC conn use - 1 == 1
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Freeing instance
DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 1
+ bssap_clear_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
DREF freeing VLR subscr MSISDN:42342
@@ -1353,6 +1367,7 @@ DMM Subscr_Conn(901700000010650){SUBSCR_CONN_S_RELEASED}: Deallocated
DREF MSISDN:42342: MSC conn use - 1 == 0
DRLL subscr MSISDN:42342: Freeing subscriber connection
DREF VLR subscr MSISDN:42342 usage decreases to: 1
+ iu_release_sent == 1
- LU was successful, and the conn has already been closed
llist_count(&net->subscr_conns) == 0
DREF freeing VLR subscr MSISDN:42342
diff --git a/tests/msc_vlr/msc_vlr_tests.c b/tests/msc_vlr/msc_vlr_tests.c
index 6da34aed6..a45b10fbb 100644
--- a/tests/msc_vlr/msc_vlr_tests.c
+++ b/tests/msc_vlr/msc_vlr_tests.c
@@ -59,6 +59,11 @@ const char *auth_request_expect_autn;
bool cipher_mode_cmd_sent;
bool cipher_mode_cmd_sent_with_imeisv;
+bool iu_release_expected = false;
+bool iu_release_sent = false;
+bool bssap_clear_expected = false;
+bool bssap_clear_sent = false;
+
struct msgb *msgb_from_hex(const char *label, uint16_t size, const char *hex)
{
struct msgb *msg = msgb_alloc(size, label);
@@ -149,7 +154,6 @@ struct gsm_subscriber_connection *conn_new(void)
if (conn->via_ran == RAN_UTRAN_IU) {
struct ue_conn_ctx *ue_ctx = talloc_zero(conn, struct ue_conn_ctx);
*ue_ctx = (struct ue_conn_ctx){
- .link = (void*)0x23,
.conn_id = 42,
};
conn->iu.ue_ctx = ue_ctx;
@@ -298,9 +302,9 @@ int __wrap_iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac)
return _paging_sent(RAN_UTRAN_IU, imsi, tmsi ? *tmsi : GSM_RESERVED_TMSI, lac);
}
-/* override, requires '-Wl,--wrap=a_page' */
-int __real_a_page(const char *imsi, uint32_t tmsi, uint16_t lac);
-int __wrap_a_page(const char *imsi, uint32_t tmsi, uint16_t lac)
+/* override, requires '-Wl,--wrap=a_iface_tx_paging' */
+int __real_a_iface_tx_paging(const char *imsi, uint32_t tmsi, uint16_t lac);
+int __wrap_a_iface_tx_paging(const char *imsi, uint32_t tmsi, uint16_t lac)
{
return _paging_sent(RAN_GERAN_A, imsi, tmsi, lac);
}
@@ -333,6 +337,11 @@ void clear_vlr()
next_rand_byte = 0;
+ iu_release_expected = false;
+ iu_release_sent = false;
+ bssap_clear_expected = false;
+ bssap_clear_sent = false;
+
osmo_gettimeofday_override = false;
}
@@ -475,6 +484,9 @@ int __real_iu_tx_release(struct ue_conn_ctx *ctx, const struct RANAP_Cause *caus
int __wrap_iu_tx_release(struct ue_conn_ctx *ctx, const struct RANAP_Cause *cause)
{
btw("Iu Release --%s--> MS", ran_type_name(RAN_UTRAN_IU));
+ OSMO_ASSERT(iu_release_expected);
+ iu_release_expected = false;
+ iu_release_sent = true;
return 0;
}
@@ -486,13 +498,24 @@ int __wrap_iu_tx_common_id(struct ue_conn_ctx *ue_ctx, const char *imsi)
return 0;
}
-/* override, requires '-Wl,--wrap=a_tx' */
-int __real_a_tx(struct msgb *msg, uint8_t sapi);
-int __wrap_a_tx(struct msgb *msg, uint8_t sapi)
+/* override, requires '-Wl,--wrap=a_iface_tx_dtap' */
+int __real_a_iface_tx_dtap(struct msgb *msg);
+int __wrap_a_iface_tx_dtap(struct msgb *msg)
{
return _validate_dtap(msg, RAN_GERAN_A);
}
+/* override, requires '-Wl,--wrap=a_iface_tx_clear_cmd' */
+int __real_a_iface_tx_clear_cmd(struct gsm_subscriber_connection *conn);
+int __wrap_a_iface_tx_clear_cmd(struct gsm_subscriber_connection *conn)
+{
+ btw("BSSAP Clear --%s--> MS", ran_type_name(RAN_GERAN_A));
+ OSMO_ASSERT(bssap_clear_expected);
+ bssap_clear_expected = false;
+ bssap_clear_sent = true;
+ return 0;
+}
+
static int fake_vlr_tx_lu_acc(void *msc_conn_ref, uint32_t send_tmsi)
{
struct gsm_subscriber_connection *conn = msc_conn_ref;
diff --git a/tests/msc_vlr/msc_vlr_tests.h b/tests/msc_vlr/msc_vlr_tests.h
index ae0f83c9a..c2c5a58a7 100644
--- a/tests/msc_vlr/msc_vlr_tests.h
+++ b/tests/msc_vlr/msc_vlr_tests.h
@@ -79,6 +79,38 @@ extern bool cipher_mode_cmd_sent_with_imeisv;
extern bool paging_sent;
extern bool paging_stopped;
+extern bool iu_release_expected;
+extern bool iu_release_sent;
+extern bool bssap_clear_expected;
+extern bool bssap_clear_sent;
+
+static inline void expect_iu_release()
+{
+ iu_release_expected = true;
+ iu_release_sent = false;
+}
+
+static inline void expect_bssap_clear()
+{
+ bssap_clear_expected = true;
+ bssap_clear_sent = false;
+}
+
+static inline void expect_release_clear(enum ran_type via_ran)
+{
+ switch (via_ran) {
+ case RAN_GERAN_A:
+ expect_bssap_clear();
+ return;
+ case RAN_UTRAN_IU:
+ expect_iu_release();
+ return;
+ default:
+ OSMO_ASSERT(false);
+ break;
+ }
+}
+
struct msc_vlr_test_cmdline_opts {
bool verbose;
int run_test_nr;