summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorsten Alteholz <debian@alteholz.de>2018-07-16 23:05:59 +0200
committerThorsten Alteholz <debian@alteholz.de>2018-07-16 23:05:59 +0200
commit6ffa57f2e1d6d9bd830a55bd9440da31f49b9a37 (patch)
tree434bcd011a3227a1231de2d04600130205c4f359
parent85dc7be98492c3f82f8b9b40300e59a8f49fef0c (diff)
Import Upstream version 1.1.0
-rw-r--r--debian/changelog64
-rw-r--r--debian/control1
-rwxr-xr-xdebian/rules3
-rw-r--r--openbsc/configure.ac27
-rw-r--r--openbsc/include/openbsc/Makefile.am1
-rw-r--r--openbsc/include/openbsc/abis_nm.h9
-rw-r--r--openbsc/include/openbsc/acc_ramp.h161
-rw-r--r--openbsc/include/openbsc/bsc_msc_data.h5
-rw-r--r--openbsc/include/openbsc/bsc_nat.h13
-rw-r--r--openbsc/include/openbsc/chan_alloc.h6
-rw-r--r--openbsc/include/openbsc/gsm_04_80.h9
-rw-r--r--openbsc/include/openbsc/gsm_data.h28
-rw-r--r--openbsc/include/openbsc/gsm_data_shared.h22
-rw-r--r--openbsc/include/openbsc/mgcp.h6
-rw-r--r--openbsc/include/openbsc/mgcp_internal.h14
-rw-r--r--openbsc/include/openbsc/pcuif_proto.h6
-rw-r--r--openbsc/include/openbsc/rest_octets.h7
-rw-r--r--openbsc/src/ipaccess/network_listen.c6
-rw-r--r--openbsc/src/libbsc/Makefile.am1
-rw-r--r--openbsc/src/libbsc/abis_nm.c44
-rw-r--r--openbsc/src/libbsc/abis_nm_vty.c1
-rw-r--r--openbsc/src/libbsc/abis_om2000_vty.c2
-rw-r--r--openbsc/src/libbsc/abis_rsl.c38
-rw-r--r--openbsc/src/libbsc/acc_ramp.c364
-rw-r--r--openbsc/src/libbsc/bsc_ctrl_commands.c90
-rw-r--r--openbsc/src/libbsc/bsc_init.c23
-rw-r--r--openbsc/src/libbsc/bsc_vty.c156
-rw-r--r--openbsc/src/libbsc/chan_alloc.c85
-rw-r--r--openbsc/src/libbsc/net_init.c24
-rw-r--r--openbsc/src/libbsc/paging.c13
-rw-r--r--openbsc/src/libbsc/pcu_sock.c5
-rw-r--r--openbsc/src/libbsc/rest_octets.c7
-rw-r--r--openbsc/src/libbsc/system_information.c49
-rw-r--r--openbsc/src/libcommon-cs/common_cs.c6
-rw-r--r--openbsc/src/libcommon-cs/common_cs_vty.c19
-rw-r--r--openbsc/src/libcommon/gsm_data.c17
-rw-r--r--openbsc/src/libcommon/gsm_data_shared.c24
-rw-r--r--openbsc/src/libiu/iu.c6
-rw-r--r--openbsc/src/libmgcp/mgcp_network.c42
-rw-r--r--openbsc/src/libmgcp/mgcp_osmux.c17
-rw-r--r--openbsc/src/libmgcp/mgcp_protocol.c62
-rw-r--r--openbsc/src/libmgcp/mgcp_vty.c76
-rw-r--r--openbsc/src/libmsc/Makefile.am1
-rw-r--r--openbsc/src/libmsc/auth.c34
-rw-r--r--openbsc/src/libmsc/ctrl_commands.c8
-rw-r--r--openbsc/src/libmsc/db.c55
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c10
-rw-r--r--openbsc/src/libmsc/smpp_smsc.c9
-rw-r--r--openbsc/src/libmsc/smpp_vty.c2
-rw-r--r--openbsc/src/libmsc/ussd.c23
-rw-r--r--openbsc/src/libmsc/vty_interface_layer3.c14
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_api.c47
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_bssap.c46
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_ctrl.c7
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_filter.c16
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_grace.c17
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_msc.c6
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_sccp.c2
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_vty.c32
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c10
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_nat.c8
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c114
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_nat_vty.c79
-rw-r--r--openbsc/tests/channel/Makefile.am5
-rw-r--r--openbsc/tests/channel/channel_test.c46
-rw-r--r--openbsc/tests/ctrl_test_runner.py27
-rw-r--r--openbsc/tests/db/Makefile.am1
-rw-r--r--openbsc/tests/gsm0408/gsm0408_test.c99
-rw-r--r--openbsc/tests/gsm0408/gsm0408_test.ok6
-rw-r--r--openbsc/tests/mgcp/Makefile.am1
-rw-r--r--openbsc/tests/mgcp/mgcp_test.c4
-rw-r--r--openbsc/tests/mm_auth/mm_auth_test.c2
-rw-r--r--openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.c3
73 files changed, 1817 insertions, 476 deletions
diff --git a/debian/changelog b/debian/changelog
index 08636ef..a157b2e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,66 @@
-openbsc (1.0.0) UNRELEASED; urgency=medium
+openbsc (1.1.0) unstable; urgency=medium
+
+ [ Neels Hofmeyr ]
+ * debian/rules: show testsuite.log when tests are failing
+ * vty: skip installing cmds now always installed by default
+ * vty: skip installing cmds now always installed by default
+ * sms.db: silence libdbi warnings on out-of-range index
+ * fix build: gprs_ra_id_by_bts(): ensure to init all values
+ * backport support for 3-digit MNC with leading zeros
+ * Migrate from OpenSSL to osmo_get_rand_id()
+
+ [ Harald Welte ]
+ * osmo-bsc: Print NOTICE message on unimplemented BSSMAP UDT
+ * osmo-bsc-sccplite: Implement incoming RESET procedure
+ * mgcp_transcoding_test: Add LIBOSMOABIS_CFLAGS
+ * sysinfo: Fix regression causing missing L2 Pseudo-Length in SI5/SI6
+ (Closes: #3059)
+
+ [ Pau Espin Pedrol ]
+ * Use type bool for boolean fields in gsm48_si_ro_info
+ * vty: Add cmd to configure 3g Early Classmark Sending
+ * mgcp_protocol: Don't print osmux stats if it is off
+ * bsc: Improve handling of paging_request return value
+ * bsc: paging: Fix losing paging messages for BTS
+ * libbsc: set_net_mcc_mnc_apply: Fix memleak on parsing incorrect mcc mnc
+ * bsc_nat: ctrl: fix memleak on reply receival
+ * bsc_nat: forward_to_bsc: remove one level of indentation
+ * bsc_nat: forward_to_bsc: Fix memleak on send failure
+ * bsc_nat: Drop redundant ccon ptr in bsc_cmd_list
+ * bsc_nat: ctrl: Fix crash on receveing bsc reply
+ * nat: Add jitter buffer on the uplink receiver
+ * smpp_smsc_conf: Fix heap-use-after-free
+ * chan_alloc.c: Fix log var formatting issues
+ * mgcp: switch to new osmux output APIs
+ * debian/changelog: change last release for unreleased to unstable
+
+ [ Max ]
+ * Fix tests after rate_ctr change
+
+ [ Vadim Yanitskiy ]
+ * libmsc: add support for both comp128v2 and comp128v3
+ * gsm_04_80.h: use '#pragma once' instead of includes
+ * gsm_04_80.h: cosmetic: whitespace fix
+ * src/libmsc/ussd.c: drop useless forward declaration
+
+ [ Stefan Sperling ]
+ * Make "waiting indicator" of IMMEDIATE ASSIGN REJECT dynamic.
+ * bts chan_load: ignore unusable BTS
+ * Add stat items for the BTS's channel load average and T3122.
+ * Add support for Access Control Class ramping.
+ * fix a format string error in bts_update_t3122_chan_load()
+ * fix initialization of acc ramping
+ * only log actual access control class ramping changes
+ * ensure that acc_ramp_init() is only called once
+ * trigger acc ramping based on trx rf-locked state
+ * rename helper functions in the acc ramp code to avoid confusion
+ * trigger acc ramping on state-changed-event reports
+ * only trigger acc ramping if trx 0 is usable and unlocked
+ * fix handling of state changes in acc ramping
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 04 May 2018 12:45:08 +0200
+
+openbsc (1.0.0) unstable; urgency=medium
[ Holger Hans Peter Freyther ]
* Revert "gprs: Use RAND_bytes for p-tmsi"
diff --git a/debian/control b/debian/control
index e31d0c4..76b7d2a 100644
--- a/debian/control
+++ b/debian/control
@@ -14,7 +14,6 @@ Build-Depends: debhelper (>= 9),
libosmo-netif-dev,
libdbd-sqlite3,
libpcap-dev,
- libssl-dev,
libsmpp34-dev
Standards-Version: 3.9.8
Vcs-Git: git://bs11-abis.gnumonks.org/openbsc.git
diff --git a/debian/rules b/debian/rules
index 05bbbef..ef08596 100755
--- a/debian/rules
+++ b/debian/rules
@@ -27,3 +27,6 @@ override_dh_auto_configure:
echo $(VERSION) > openbsc/.tarball-version
dh_auto_configure --sourcedirectory=openbsc -- --enable-nat --enable-osmo-bsc --enable-smpp
+# Print test results in case of a failure
+override_dh_auto_test:
+ dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
diff --git a/openbsc/configure.ac b/openbsc/configure.ac
index a0df05f..2c3045a 100644
--- a/openbsc/configure.ac
+++ b/openbsc/configure.ac
@@ -39,20 +39,19 @@ AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
-PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.9.5)
-PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
-PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl)
-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(LIBCRYPTO, libcrypto >= 0.9.5)
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.11.0)
+PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.11.0)
+PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 0.11.0)
+PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.11.0)
+PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.11.0)
+PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.5.0)
+PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.2.0)
# Enabke/disable the NAT?
AC_ARG_ENABLE([nat], [AS_HELP_STRING([--enable-nat], [Build the BSC NAT. Requires SCCP])],
[osmo_ac_build_nat="$enableval"],[osmo_ac_build_nat="no"])
if test "$osmo_ac_build_nat" = "yes" ; then
- PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.0.2)
+ PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.9.0)
fi
AM_CONDITIONAL(BUILD_NAT, test "x$osmo_ac_build_nat" = "xyes")
AC_SUBST(osmo_ac_build_nat)
@@ -61,7 +60,7 @@ AC_SUBST(osmo_ac_build_nat)
AC_ARG_ENABLE([osmo-bsc], [AS_HELP_STRING([--enable-osmo-bsc], [Build the Osmo BSC])],
[osmo_ac_build_bsc="$enableval"],[osmo_ac_build_bsc="no"])
if test "$osmo_ac_build_bsc" = "yes" ; then
- PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.0.6)
+ PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.9.0)
fi
AM_CONDITIONAL(BUILD_BSC, test "x$osmo_ac_build_bsc" = "xyes")
AC_SUBST(osmo_ac_build_bsc)
@@ -70,7 +69,7 @@ AC_SUBST(osmo_ac_build_bsc)
AC_ARG_ENABLE([smpp], [AS_HELP_STRING([--enable-smpp], [Build the SMPP interface])],
[osmo_ac_build_smpp="$enableval"],[osmo_ac_build_smpp="no"])
if test "$osmo_ac_build_smpp" = "yes" ; then
- PKG_CHECK_MODULES(LIBSMPP34, libsmpp34 >= 1.12)
+ PKG_CHECK_MODULES(LIBSMPP34, libsmpp34 >= 1.13.0)
AC_DEFINE(BUILD_SMPP, 1, [Define if we want to build SMPP])
fi
AM_CONDITIONAL(BUILD_SMPP, test "x$osmo_ac_build_smpp" = "xyes")
@@ -96,9 +95,9 @@ AC_SUBST(osmo_ac_mgcp_transcoding)
AC_ARG_ENABLE([iu], [AS_HELP_STRING([--enable-iu], [Build 3G support, aka IuPS and IuCS interfaces])],
[osmo_ac_iu="$enableval"],[osmo_ac_iu="no"])
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?
+ PKG_CHECK_MODULES(LIBASN1C, libasn1c >= 0.9.31)
+ PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.3.0)
+ PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 0.9.0)
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/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index 126b115..1fa30d5 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -2,6 +2,7 @@ noinst_HEADERS = \
abis_nm.h \
abis_om2000.h \
abis_rsl.h \
+ acc_ramp.h \
arfcn_range_encode.h \
auth.h \
bsc_msc.h \
diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h
index db2a659..d7ab7d5 100644
--- a/openbsc/include/openbsc/abis_nm.h
+++ b/openbsc/include/openbsc/abis_nm.h
@@ -31,13 +31,6 @@
/* max number of attributes represented as 3GPP TS 52.021 ยง9.4.62 SW Description array */
#define MAX_BTS_ATTR 5
-struct cell_global_id {
- uint16_t mcc;
- uint16_t mnc;
- uint16_t lac;
- uint16_t ci;
-};
-
/* The BCCH info from an ip.access test, in host byte order
* and already parsed... */
struct ipac_bcch_info {
@@ -52,7 +45,7 @@ struct ipac_bcch_info {
uint16_t frame_offset;
uint32_t frame_nr_offset;
uint8_t bsic;
- struct cell_global_id cgi;
+ struct osmo_cell_global_id cgi;
uint8_t ba_list_si2[16];
uint8_t ba_list_si2bis[16];
uint8_t ba_list_si2ter[16];
diff --git a/openbsc/include/openbsc/acc_ramp.h b/openbsc/include/openbsc/acc_ramp.h
new file mode 100644
index 0000000..efb12b0
--- /dev/null
+++ b/openbsc/include/openbsc/acc_ramp.h
@@ -0,0 +1,161 @@
+/* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * Author: Stefan Sperling <ssperling@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <osmocom/core/timer.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+
+/*!
+ * Access control class (ACC) ramping is used to slowly make the cell available to
+ * an increasing number of MS. This avoids overload at startup time in cases where
+ * a lot of MS would discover the new cell and try to connect to it all at once.
+ */
+
+#define ACC_RAMP_STEP_SIZE_MIN 1 /* allow at most 1 new ACC per ramp step */
+#define ACC_RAMP_STEP_SIZE_DEFAULT ACC_RAMP_STEP_SIZE_MIN
+#define ACC_RAMP_STEP_SIZE_MAX 10 /* allow all ACC in one step (effectively disables ramping) */
+
+#define ACC_RAMP_STEP_INTERVAL_MIN 30 /* 30 seconds */
+#define ACC_RAMP_STEP_INTERVAL_MAX 600 /* 10 minutes */
+
+/*!
+ * Data structure used to manage ACC ramping. Please avoid setting or reading fields
+ * in this structure directly. Use the accessor functions below instead.
+ */
+struct acc_ramp {
+ struct gsm_bts *bts; /*!< backpointer to BTS using this ACC ramp */
+
+ bool acc_ramping_enabled; /*!< whether ACC ramping is enabled */
+
+ /*!
+ * Bitmask which keeps track of access control classes that are currently denied
+ * access. The function acc_ramp_apply() uses this mask to modulate bits from
+ * octets 2 and 3 in RACH Control Parameters (see 3GPP 44.018 10.5.2.29).
+ * Ramping is only concerned with ACCs 0-9. While any of the bits 0-9 is set,
+ * the corresponding ACC is barred.
+ * ACCs 11-15 should always be allowed, and ACC 10 denies emergency calls for
+ * all ACCs from 0-9 inclusive; these ACCs are ignored in this implementation.
+ */
+ uint16_t barred_accs;
+
+ /*!
+ * This controls the maximum number of ACCs to allow per ramping step (1 - 10).
+ * The compile-time default value is ACC_RAMP_STEP_SIZE_DEFAULT.
+ * This value can be changed by VTY configuration.
+ * A value of ACC_RAMP_STEP_SIZE_MAX effectively disables ramping.
+ */
+ unsigned int step_size;
+
+ /*!
+ * Ramping step interval in seconds.
+ * This value depends on the current BTS channel load average, unless
+ * it has been overriden by VTY configuration.
+ */
+ unsigned int step_interval_sec;
+ bool step_interval_is_fixed;
+ struct osmo_timer_list step_timer;
+};
+
+/*!
+ * Enable or disable ACC ramping.
+ * When enabled, ramping begins once acc_ramp_start() is called.
+ * When disabled, an ACC ramping process in progress will continue
+ * unless acc_ramp_abort() is called as well.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ */
+static inline void acc_ramp_set_enabled(struct acc_ramp *acc_ramp, bool enable)
+{
+ acc_ramp->acc_ramping_enabled = enable;
+}
+
+/*!
+ * Return true if ACC ramping is currently enabled, else false.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ */
+static inline bool acc_ramp_is_enabled(struct acc_ramp *acc_ramp)
+{
+ return acc_ramp->acc_ramping_enabled;
+}
+
+/*!
+ * Return the current ACC ramp step size.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ */
+static inline unsigned int acc_ramp_get_step_size(struct acc_ramp *acc_ramp)
+{
+ return acc_ramp->step_size;
+}
+
+/*!
+ * Return the current ACC ramp step interval (in seconds)
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ */
+static inline unsigned int acc_ramp_get_step_interval(struct acc_ramp *acc_ramp)
+{
+ return acc_ramp->step_interval_sec;
+}
+
+/*!
+ * If the step interval is dynamic, return true, else return false.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ */
+static inline bool acc_ramp_step_interval_is_dynamic(struct acc_ramp *acc_ramp)
+{
+ return !(acc_ramp->step_interval_is_fixed);
+}
+
+/*!
+ * Return bitmasks which correspond to access control classes that are currently
+ * denied access. Ramping is only concerned with those bits which control access
+ * for ACCs 0-9, and any of the other bits will always be set to zero in these masks, i.e.
+ * it is safe to OR these bitmasks with the corresponding fields in struct gsm48_rach_control.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ */
+static inline uint8_t acc_ramp_get_barred_t2(struct acc_ramp *acc_ramp)
+{
+ return ((acc_ramp->barred_accs >> 8) & 0x03);
+};
+static inline uint8_t acc_ramp_get_barred_t3(struct acc_ramp *acc_ramp)
+{
+ return (acc_ramp->barred_accs & 0xff);
+}
+
+/*!
+ * Potentially mark certain Access Control Classes (ACCs) as barred in accordance to ACC ramping.
+ * \param[in] rach_control RACH control parameters in which barred ACCs will be configured.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ */
+static inline void acc_ramp_apply(struct gsm48_rach_control *rach_control, struct acc_ramp *acc_ramp)
+{
+ rach_control->t2 |= acc_ramp_get_barred_t2(acc_ramp);
+ rach_control->t3 |= acc_ramp_get_barred_t3(acc_ramp);
+}
+
+void acc_ramp_init(struct acc_ramp *acc_ramp, struct gsm_bts *bts);
+int acc_ramp_set_step_size(struct acc_ramp *acc_ramp, unsigned int step_size);
+int acc_ramp_set_step_interval(struct acc_ramp *acc_ramp, unsigned int step_interval);
+void acc_ramp_set_step_interval_dynamic(struct acc_ramp *acc_ramp);
+void acc_ramp_trigger(struct acc_ramp *acc_ramp);
+void acc_ramp_abort(struct acc_ramp *acc_ramp);
diff --git a/openbsc/include/openbsc/bsc_msc_data.h b/openbsc/include/openbsc/bsc_msc_data.h
index 38e87cf..1b1ffc2 100644
--- a/openbsc/include/openbsc/bsc_msc_data.h
+++ b/openbsc/include/openbsc/bsc_msc_data.h
@@ -31,6 +31,7 @@
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/gsm23003.h>
#include <regex.h>
@@ -74,8 +75,7 @@ struct bsc_msc_data {
struct osmo_timer_list pong_timer;
int advanced_ping;
struct bsc_msc_connection *msc_con;
- int core_mnc;
- int core_mcc;
+ struct osmo_plmn_id core_plmn;
int core_lac;
int core_ci;
int rtp_base;
@@ -138,5 +138,6 @@ int osmo_bsc_audio_init(struct gsm_network *network);
struct bsc_msc_data *osmo_msc_data_find(struct gsm_network *, int);
struct bsc_msc_data *osmo_msc_data_alloc(struct gsm_network *, int);
+void bsc_notify_and_close_conns(struct bsc_msc_connection *msc_con);
#endif
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index 94ab0e5..5171c3e 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -70,9 +70,6 @@ struct bsc_cmd_list {
/* The NATed ID used on the bsc_con*/
int nat_id;
- /* The control connection from which the command originated */
- struct ctrl_connection *ccon;
-
/* The command from the control connection */
struct ctrl_cmd *cmd;
};
@@ -178,6 +175,16 @@ struct bsc_config {
/* Osmux is enabled/disabled per BSC */
int osmux;
+
+ /* Use a jitterbuffer on the bts-side receiver */
+ bool bts_use_jibuf;
+ /* Minimum and maximum buffer size for the jitter buffer, in ms */
+ uint32_t bts_jitter_delay_min;
+ uint32_t bts_jitter_delay_max;
+ /* Enabled if explicitly configured through VTY: */
+ bool bts_use_jibuf_override;
+ bool bts_jitter_delay_min_override;
+ bool bts_jitter_delay_max_override;
};
struct bsc_lac_entry {
diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h
index 78242e5..0ba3f96 100644
--- a/openbsc/include/openbsc/chan_alloc.h
+++ b/openbsc/include/openbsc/chan_alloc.h
@@ -37,17 +37,13 @@ void lchan_reset(struct gsm_lchan *lchan);
/* Release the given lchan */
int lchan_release(struct gsm_lchan *lchan, int sacch_deact, enum rsl_rel_mode release_mode);
-struct load_counter {
- unsigned int total;
- unsigned int used;
-};
-
struct pchan_load {
struct load_counter pchan[_GSM_PCHAN_MAX];
};
void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts);
void network_chan_load(struct pchan_load *pl, struct gsm_network *net);
+void bts_update_t3122_chan_load(struct gsm_bts *bts);
int trx_is_usable(struct gsm_bts_trx *trx);
diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h
index d65f640..ce1b5c2 100644
--- a/openbsc/include/openbsc/gsm_04_80.h
+++ b/openbsc/include/openbsc/gsm_04_80.h
@@ -1,5 +1,4 @@
-#ifndef _GSM_04_80_H
-#define _GSM_04_80_H
+#pragma once
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/protocol/gsm_04_80.h>
@@ -8,10 +7,10 @@
struct gsm_subscriber_connection;
int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
- const struct msgb *in_msg, const char* response_text,
+ const struct msgb *in_msg, const char* response_text,
const struct ss_request *req);
int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
- const struct msgb *msg,
+ const struct msgb *msg,
const struct ss_request *request);
int msc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level,
@@ -21,5 +20,3 @@ int msc_send_ussd_release_complete(struct gsm_subscriber_connection *conn);
int bsc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level,
const char *text);
int bsc_send_ussd_release_complete(struct gsm_subscriber_connection *conn);
-
-#endif
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 57fa301..2e1e64f 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -10,6 +10,8 @@
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/select.h>
#include <osmocom/core/stats.h>
+#include <osmocom/core/stat_item.h>
+#include <osmocom/gsm/gsm23003.h>
#include <osmocom/crypt/auth.h>
@@ -54,6 +56,8 @@ enum gsm_auth_algo {
AUTH_ALGO_NONE,
AUTH_ALGO_XOR,
AUTH_ALGO_COMP128v1,
+ AUTH_ALGO_COMP128v2,
+ AUTH_ALGO_COMP128v3,
};
struct gsm_auth_info {
@@ -173,6 +177,10 @@ struct gsm_subscriber_connection {
#define ROLE_BSC
#include "gsm_data_shared.h"
+enum {
+ BTS_STAT_CHAN_LOAD_AVERAGE,
+ BTS_STAT_T3122,
+};
enum {
BSC_CTR_CHREQ_TOTAL,
@@ -310,9 +318,8 @@ struct gsm_tz {
};
struct gsm_network {
- /* global parameters */
- uint16_t country_code;
- uint16_t network_code;
+ struct osmo_plmn_id plmn;
+
char *name_long;
char *name_short;
enum gsm_auth_policy auth_policy;
@@ -370,6 +377,9 @@ struct gsm_network {
/* timer to expire old location updates */
struct osmo_timer_list subscr_expire_timer;
+ /* Timer for periodic channel load measurements to maintain each BTS's T3122. */
+ struct osmo_timer_list t3122_chan_load_timer;
+
/* Radio Resource Location Protocol (TS 04.31) */
struct {
enum rrlp_mode mode;
@@ -419,6 +429,16 @@ struct gsm_network {
struct llist_head *bsc_subscribers;
};
+static inline const struct osmo_location_area_id *bts_lai(struct gsm_bts *bts)
+{
+ static struct osmo_location_area_id lai;
+ lai = (struct osmo_location_area_id){
+ .plmn = bts->network->plmn,
+ .lac = bts->location_area_code,
+ };
+ return &lai;
+}
+
struct osmo_esme;
enum gsm_sms_source_id {
@@ -558,7 +578,7 @@ enum bts_gprs_mode bts_gprs_mode_parse(const char *arg, int *valid);
const char *bts_gprs_mode_name(enum bts_gprs_mode mode);
int bts_gprs_mode_is_compat(struct gsm_bts *bts, enum bts_gprs_mode mode);
-int gsm48_ra_id_by_bts(uint8_t *buf, struct gsm_bts *bts);
+void gsm48_ra_id_by_bts(struct gsm48_ra_id *buf, struct gsm_bts *bts);
void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts);
struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan);
diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h
index c19b125..ddd5991 100644
--- a/openbsc/include/openbsc/gsm_data_shared.h
+++ b/openbsc/include/openbsc/gsm_data_shared.h
@@ -24,6 +24,8 @@
#include <osmocom/gsm/lapdm.h>
#endif
+#include <openbsc/acc_ramp.h>
+
/* 16 is the max. number of SI2quater messages according to 3GPP TS 44.018 Table 10.5.2.33b.1:
4-bit index is used (2#1111 = 10#15) */
#define SI2Q_MAX_NUM 16
@@ -674,6 +676,12 @@ struct bts_location {
double height;
};
+/* Channel load counter */
+struct load_counter {
+ unsigned int total;
+ unsigned int used;
+};
+
/* One BTS */
struct gsm_bts {
/* list header in net->bts_list */
@@ -839,6 +847,9 @@ struct gsm_bts {
int force_combined_si;
int bcch_change_mark;
+ /* access control class ramping */
+ struct acc_ramp acc_ramp;
+
#ifdef ROLE_BSC
/* Abis NM queue */
struct llist_head abis_queue;
@@ -877,6 +888,7 @@ struct gsm_bts {
} data;
} si_common;
bool early_classmark_allowed;
+ bool early_classmark_allowed_3g;
/* for testing only: Have an infinitely long radio link timeout */
bool infinite_radio_link_timeout;
@@ -900,6 +912,16 @@ struct gsm_bts {
char *pcu_sock_path;
struct pcu_sock_state *pcu_state;
+ struct osmo_stat_item_group *bts_statg;
+
+ /* BTS-specific overrides for timer values from struct gsm_network. */
+ uint8_t T3122; /* ASSIGMENT REJECT wait indication */
+
+ /* Periodic channel load measurements are used to maintain T3122. */
+ struct load_counter chan_load_samples[7];
+ int chan_load_samples_idx;
+ uint8_t chan_load_avg; /* current channel load average in percent (0 - 100). */
+
#endif /* ROLE_BSC */
void *role;
};
diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h
index b2262bc..4d1c5ef 100644
--- a/openbsc/include/openbsc/mgcp.h
+++ b/openbsc/include/openbsc/mgcp.h
@@ -236,6 +236,12 @@ struct mgcp_config {
* message.
*/
uint16_t osmux_dummy;
+
+ /* Use a jitterbuffer on the bts-side receiver */
+ bool bts_use_jibuf;
+ /* Minimum and maximum buffer size for the jitter buffer, in ms */
+ uint32_t bts_jitter_delay_min;
+ uint32_t bts_jitter_delay_max;
};
/* config management */
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index 7c89d10..cd6365f 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -25,6 +25,7 @@
#include <string.h>
#include <osmocom/core/select.h>
+#include <osmocom/netif/jibuf.h>
#define CI_UNUSED 0
@@ -205,6 +206,14 @@ struct mgcp_endpoint {
uint32_t octets;
} stats;
} osmux;
+
+ /* Jitter buffer */
+ struct osmo_jibuf* bts_jb;
+ /* Use a jitterbuffer on the bts-side receiver */
+ bool bts_use_jibuf;
+ /* Minimum and maximum buffer size for the jitter buffer, in ms */
+ uint32_t bts_jitter_delay_min;
+ uint32_t bts_jitter_delay_max;
};
#define for_each_line(line, save) \
@@ -340,3 +349,8 @@ static inline const char *mgcp_bts_src_addr(struct mgcp_endpoint *endp)
return endp->cfg->bts_ports.bind_addr;
return endp->cfg->source_addr;
}
+
+/**
+ * Internal jitter buffer related
+ */
+void mgcp_dejitter_udp_send(struct msgb *msg, void *data);
diff --git a/openbsc/include/openbsc/pcuif_proto.h b/openbsc/include/openbsc/pcuif_proto.h
index eb28d66..2e3f782 100644
--- a/openbsc/include/openbsc/pcuif_proto.h
+++ b/openbsc/include/openbsc/pcuif_proto.h
@@ -1,7 +1,7 @@
#ifndef _PCUIF_PROTO_H
#define _PCUIF_PROTO_H
-#define PCU_IF_VERSION 0x08
+#define PCU_IF_VERSION 0x09
/* msg_type */
#define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */
@@ -106,7 +106,9 @@ struct gsm_pcu_if_info_ind {
struct gsm_pcu_if_info_trx trx[8]; /* TRX infos per BTS */
uint8_t bsic;
/* RAI */
- uint16_t mcc, mnc, lac, rac;
+ uint16_t mcc, mnc;
+ uint8_t mnc_3_digits;
+ uint16_t lac, rac;
/* NSE */
uint16_t nsei;
uint8_t nse_timer[7];
diff --git a/openbsc/include/openbsc/rest_octets.h b/openbsc/include/openbsc/rest_octets.h
index ca7b57c..0ae65f3 100644
--- a/openbsc/include/openbsc/rest_octets.h
+++ b/openbsc/include/openbsc/rest_octets.h
@@ -40,15 +40,16 @@ struct gsm48_lsa_params {
struct gsm48_si_ro_info {
struct gsm48_si_selection_params selection_params;
struct gsm48_si_power_offset power_offset;
- uint8_t si2ter_indicator;
- uint8_t early_cm_ctrl;
+ bool si2ter_indicator;
+ bool early_cm_ctrl;
struct {
uint8_t where:3,
present:1;
} scheduling;
struct gsm48_si3_gprs_ind gprs_ind;
/* SI 3 specific */
- uint8_t si2quater_indicator;
+ bool early_cm_restrict_3g;
+ bool si2quater_indicator;
/* SI 4 specific */
struct gsm48_lsa_params lsa_params;
uint16_t cell_id;
diff --git a/openbsc/src/ipaccess/network_listen.c b/openbsc/src/ipaccess/network_listen.c
index 3b44ceb..43d82a9 100644
--- a/openbsc/src/ipaccess/network_listen.c
+++ b/openbsc/src/ipaccess/network_listen.c
@@ -185,10 +185,10 @@ static int test_rep(void *_msg)
DEBUGP(DNM, "BCCH Info parsing failed\n");
break;
}
- DEBUGP(DNM, "==> ARFCN %u, RxLev %2u, RxQual %2u: %3d-%d, LAC %d CI %d BSIC %u\n",
+ DEBUGP(DNM, "==> ARFCN %u, RxLev %2u, RxQual %2u: %s, LAC %d CI %d BSIC %u\n",
binfo.arfcn, binfo.rx_lev, binfo.rx_qual,
- binfo.cgi.mcc, binfo.cgi.mnc,
- binfo.cgi.lac, binfo.cgi.ci, binfo.bsic);
+ osmo_plmn_name(&binfo.cgi.lai.plmn),
+ binfo.cgi.lai.lac, binfo.cgi.cell_identity, binfo.bsic);
if (binfo.arfcn != last_arfcn) {
/* report is on a new arfcn, need to clear channel list */
diff --git a/openbsc/src/libbsc/Makefile.am b/openbsc/src/libbsc/Makefile.am
index e78bde6..666e8b3 100644
--- a/openbsc/src/libbsc/Makefile.am
+++ b/openbsc/src/libbsc/Makefile.am
@@ -23,6 +23,7 @@ libbsc_a_SOURCES = \
abis_om2000.c \
abis_om2000_vty.c \
abis_rsl.c \
+ acc_ramp.c \
bsc_rll.c \
bsc_subscriber.c \
paging.c \
diff --git a/openbsc/src/libbsc/abis_nm.c b/openbsc/src/libbsc/abis_nm.c
index f24f6bf..cbb255a 100644
--- a/openbsc/src/libbsc/abis_nm.c
+++ b/openbsc/src/libbsc/abis_nm.c
@@ -2785,23 +2785,29 @@ int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
{
- /* we simply reuse the GSM48 function and overwrite the RAC
- * with the Cell ID */
- gsm48_ra_id_by_bts(buf, bts);
- *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
+ struct gsm48_ra_id *_buf = (struct gsm48_ra_id*)buf;
+ uint16_t ci = htons(bts->cell_identity);
+ /* we simply reuse the GSM48 function and write the Cell ID over the position where the RAC
+ * starts */
+ gsm48_ra_id_by_bts(_buf, bts);
+ memcpy(&_buf->rac, &ci, sizeof(ci));
}
void gsm_trx_lock_rf(struct gsm_bts_trx *trx, bool locked, const char *reason)
{
uint8_t new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
- LOGP(DNM, LOGL_NOTICE, "(bts=%d,trx=%d) Changing adm. state %s -> %s [%s]\n", trx->bts->nr, trx->nr,
- get_value_string(abis_nm_adm_state_names, trx->mo.nm_state.administrative),
- get_value_string(abis_nm_adm_state_names, new_state), reason);
- trx->mo.nm_state.administrative = new_state;
- if (!trx->bts || !trx->bts->oml_link)
+ if (!trx->bts || !trx->bts->oml_link) {
+ /* Set initial state which will be sent when BTS connects. */
+ trx->mo.nm_state.administrative = new_state;
return;
+ }
+
+ LOGP(DNM, LOGL_NOTICE, "(bts=%d,trx=%d) Requesting administrative state change %s -> %s [%s]\n",
+ trx->bts->nr, trx->nr,
+ get_value_string(abis_nm_adm_state_names, trx->mo.nm_state.administrative),
+ get_value_string(abis_nm_adm_state_names, new_state), reason);
abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
trx->bts->bts_nr, trx->nr, 0xff,
@@ -2822,23 +2828,11 @@ const char *ipacc_testres_name(uint8_t res)
return get_value_string(ipacc_testres_names, res);
}
-void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
+void ipac_parse_cgi(struct osmo_cell_global_id *cid, const uint8_t *buf)
{
- cid->mcc = (buf[0] & 0xf) * 100;
- cid->mcc += (buf[0] >> 4) * 10;
- cid->mcc += (buf[1] & 0xf) * 1;
-
- if (buf[1] >> 4 == 0xf) {
- cid->mnc = (buf[2] & 0xf) * 10;
- cid->mnc += (buf[2] >> 4) * 1;
- } else {
- cid->mnc = (buf[2] & 0xf) * 100;
- cid->mnc += (buf[2] >> 4) * 10;
- cid->mnc += (buf[1] >> 4) * 1;
- }
-
- cid->lac = ntohs(*((uint16_t *)&buf[3]));
- cid->ci = ntohs(*((uint16_t *)&buf[5]));
+ osmo_plmn_from_bcd(buf, &cid->lai.plmn);
+ cid->lai.lac = ntohs(*((uint16_t *)&buf[3]));
+ cid->cell_identity = ntohs(*((uint16_t *)&buf[5]));
}
/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
diff --git a/openbsc/src/libbsc/abis_nm_vty.c b/openbsc/src/libbsc/abis_nm_vty.c
index 6ec0a4a..4dae212 100644
--- a/openbsc/src/libbsc/abis_nm_vty.c
+++ b/openbsc/src/libbsc/abis_nm_vty.c
@@ -183,7 +183,6 @@ int abis_nm_vty_init(void)
install_element(ENABLE_NODE, &oml_classnum_inst_cmd);
install_node(&oml_node, dummy_config_write);
- vty_install_default(OML_NODE);
install_element(OML_NODE, &oml_chg_adm_state_cmd);
install_element(OML_NODE, &oml_opstart_cmd);
diff --git a/openbsc/src/libbsc/abis_om2000_vty.c b/openbsc/src/libbsc/abis_om2000_vty.c
index a6bc4c7..11dd131 100644
--- a/openbsc/src/libbsc/abis_om2000_vty.c
+++ b/openbsc/src/libbsc/abis_om2000_vty.c
@@ -582,7 +582,6 @@ int abis_om2k_vty_init(void)
install_element(ENABLE_NODE, &om2k_classnum_inst_cmd);
install_node(&om2k_node, dummy_config_write);
- vty_install_default(OM2K_NODE);
install_element(OM2K_NODE, &om2k_reset_cmd);
install_element(OM2K_NODE, &om2k_start_cmd);
install_element(OM2K_NODE, &om2k_status_cmd);
@@ -596,7 +595,6 @@ int abis_om2k_vty_init(void)
install_element(OM2K_NODE, &om2k_conf_req_cmd);
install_node(&om2k_con_group_node, dummy_config_write);
- vty_install_default(OM2K_CON_GROUP_NODE);
install_element(OM2K_CON_GROUP_NODE, &cfg_om2k_con_path_dec_cmd);
install_element(OM2K_CON_GROUP_NODE, &cfg_om2k_con_path_conc_cmd);
diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c
index 0ce2748..f05344a 100644
--- a/openbsc/src/libbsc/abis_rsl.c
+++ b/openbsc/src/libbsc/abis_rsl.c
@@ -1744,8 +1744,7 @@ static void t3109_expired(void *data)
/* Format an IMM ASS REJ according to 04.08 Chapter 9.1.20 */
static int rsl_send_imm_ass_rej(struct gsm_bts *bts,
- unsigned int num_req_refs,
- struct gsm48_req_ref *rqd_refs,
+ struct gsm48_req_ref *rqd_ref,
uint8_t wait_ind)
{
uint8_t buf[GSM_MACBLOCK_LEN];
@@ -1757,25 +1756,22 @@ static int rsl_send_imm_ass_rej(struct gsm_bts *bts,
iar->msg_type = GSM48_MT_RR_IMM_ASS_REJ;
iar->page_mode = GSM48_PM_SAME;
- memcpy(&iar->req_ref1, &rqd_refs[0], sizeof(iar->req_ref1));
+ /*
+ * Set all request references and wait indications to the same value.
+ * 3GPP TS 44.018 v4.5.0 release 4 (section 9.1.20.2) requires that
+ * we duplicate reference and wait indication to fill the message.
+ * The BTS will aggregate up to 4 of our ASS REJ messages if possible.
+ */
+ memcpy(&iar->req_ref1, rqd_ref, sizeof(iar->req_ref1));
iar->wait_ind1 = wait_ind;
- if (num_req_refs >= 2)
- memcpy(&iar->req_ref2, &rqd_refs[1], sizeof(iar->req_ref2));
- else
- memcpy(&iar->req_ref2, &rqd_refs[0], sizeof(iar->req_ref2));
+ memcpy(&iar->req_ref2, rqd_ref, sizeof(iar->req_ref2));
iar->wait_ind2 = wait_ind;
- if (num_req_refs >= 3)
- memcpy(&iar->req_ref3, &rqd_refs[2], sizeof(iar->req_ref3));
- else
- memcpy(&iar->req_ref3, &rqd_refs[0], sizeof(iar->req_ref3));
+ memcpy(&iar->req_ref3, rqd_ref, sizeof(iar->req_ref3));
iar->wait_ind3 = wait_ind;
- if (num_req_refs >= 4)
- memcpy(&iar->req_ref4, &rqd_refs[3], sizeof(iar->req_ref4));
- else
- memcpy(&iar->req_ref4, &rqd_refs[0], sizeof(iar->req_ref4));
+ memcpy(&iar->req_ref4, rqd_ref, sizeof(iar->req_ref4));
iar->wait_ind4 = wait_ind;
/* we need to subtract 1 byte from sizeof(*iar) since ia includes the l2_plen field */
@@ -1870,12 +1866,18 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
/* check availability / allocate channel */
lchan = lchan_alloc(bts, lctype, is_lu);
if (!lchan) {
+ uint8_t wait_ind;
LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n",
msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra);
rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL]);
- /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */
- if (bts->network->T3122)
- rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff);
+ if (bts->T3122)
+ wait_ind = bts->T3122;
+ else if (bts->network->T3122)
+ wait_ind = bts->network->T3122 & 0xff;
+ else
+ wait_ind = GSM_T3122_DEFAULT;
+ /* The BTS will gather multiple CHAN RQD and reject up to 4 MS at the same time. */
+ rsl_send_imm_ass_rej(bts, rqd_ref, wait_ind);
return 0;
}
diff --git a/openbsc/src/libbsc/acc_ramp.c b/openbsc/src/libbsc/acc_ramp.c
new file mode 100644
index 0000000..c90d087
--- /dev/null
+++ b/openbsc/src/libbsc/acc_ramp.c
@@ -0,0 +1,364 @@
+/* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * Author: Stefan Sperling <ssperling@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <strings.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/acc_ramp.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/chan_alloc.h>
+#include <openbsc/signal.h>
+#include <openbsc/abis_nm.h>
+
+/*
+ * Check if an ACC has been permanently barred for a BTS,
+ * e.g. with the 'rach access-control-class' VTY command.
+ */
+static bool acc_is_permanently_barred(struct gsm_bts *bts, unsigned int acc)
+{
+ OSMO_ASSERT(acc >= 0 && acc <= 9);
+ if (acc == 8 || acc == 9)
+ return (bts->si_common.rach_control.t2 & (1 << (acc - 8)));
+ return (bts->si_common.rach_control.t3 & (1 << (acc)));
+}
+
+static void allow_one_acc(struct acc_ramp *acc_ramp, unsigned int acc)
+{
+ OSMO_ASSERT(acc >= 0 && acc <= 9);
+ if (acc_ramp->barred_accs & (1 << acc))
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d) ACC RAMP: allowing Access Control Class %u\n", acc_ramp->bts->nr, acc);
+ acc_ramp->barred_accs &= ~(1 << acc);
+}
+
+static void barr_one_acc(struct acc_ramp *acc_ramp, unsigned int acc)
+{
+ OSMO_ASSERT(acc >= 0 && acc <= 9);
+ if ((acc_ramp->barred_accs & (1 << acc)) == 0)
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d) ACC RAMP: barring Access Control Class %u\n", acc_ramp->bts->nr, acc);
+ acc_ramp->barred_accs |= (1 << acc);
+}
+
+static void barr_all_accs(struct acc_ramp *acc_ramp)
+{
+ unsigned int acc;
+ for (acc = 0; acc < 10; acc++) {
+ if (!acc_is_permanently_barred(acc_ramp->bts, acc))
+ barr_one_acc(acc_ramp, acc);
+ }
+}
+
+static void allow_all_accs(struct acc_ramp *acc_ramp)
+{
+ unsigned int acc;
+ for (acc = 0; acc < 10; acc++) {
+ if (!acc_is_permanently_barred(acc_ramp->bts, acc))
+ allow_one_acc(acc_ramp, acc);
+ }
+}
+
+static unsigned int get_next_step_interval(struct acc_ramp *acc_ramp)
+{
+ struct gsm_bts *bts = acc_ramp->bts;
+ uint64_t load;
+
+ if (acc_ramp->step_interval_is_fixed)
+ return acc_ramp->step_interval_sec;
+
+ /* Scale the step interval to current channel load average. */
+ load = (bts->chan_load_avg << 8); /* convert to fixed-point */
+ acc_ramp->step_interval_sec = ((load * ACC_RAMP_STEP_INTERVAL_MAX) / 100) >> 8;
+ if (acc_ramp->step_interval_sec < ACC_RAMP_STEP_SIZE_MIN)
+ acc_ramp->step_interval_sec = ACC_RAMP_STEP_INTERVAL_MIN;
+ else if (acc_ramp->step_interval_sec > ACC_RAMP_STEP_INTERVAL_MAX)
+ acc_ramp->step_interval_sec = ACC_RAMP_STEP_INTERVAL_MAX;
+
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d) ACC RAMP: step interval set to %u seconds based on %u%% channel load average\n",
+ bts->nr, acc_ramp->step_interval_sec, bts->chan_load_avg);
+ return acc_ramp->step_interval_sec;
+}
+
+static void do_acc_ramping_step(void *data)
+{
+ struct acc_ramp *acc_ramp = data;
+ int i;
+
+ /* Shortcut in case we only do one ramping step. */
+ if (acc_ramp->step_size == ACC_RAMP_STEP_SIZE_MAX) {
+ allow_all_accs(acc_ramp);
+ gsm_bts_set_system_infos(acc_ramp->bts);
+ return;
+ }
+
+ /* Allow 'step_size' ACCs, starting from ACC0. ACC9 will be allowed last. */
+ for (i = 0; i < acc_ramp->step_size; i++) {
+ int idx = ffs(acc_ramp_get_barred_t3(acc_ramp));
+ if (idx > 0) {
+ /* One of ACC0-ACC7 is still bared. */
+ unsigned int acc = idx - 1;
+ if (!acc_is_permanently_barred(acc_ramp->bts, acc))
+ allow_one_acc(acc_ramp, acc);
+ } else {
+ idx = ffs(acc_ramp_get_barred_t2(acc_ramp));
+ if (idx == 1 || idx == 2) {
+ /* ACC8 or ACC9 is still barred. */
+ unsigned int acc = idx - 1 + 8;
+ if (!acc_is_permanently_barred(acc_ramp->bts, acc))
+ allow_one_acc(acc_ramp, acc);
+ } else {
+ /* All ACCs are now allowed. */
+ break;
+ }
+ }
+ }
+
+ gsm_bts_set_system_infos(acc_ramp->bts);
+
+ /* If we have not allowed all ACCs yet, schedule another ramping step. */
+ if (acc_ramp_get_barred_t2(acc_ramp) != 0x00 ||
+ acc_ramp_get_barred_t3(acc_ramp) != 0x00)
+ osmo_timer_schedule(&acc_ramp->step_timer, get_next_step_interval(acc_ramp), 0);
+}
+
+/* Implements osmo_signal_cbfn() -- trigger or abort ACC ramping upon changes RF lock state. */
+static int acc_ramp_nm_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
+{
+ struct nm_statechg_signal_data *nsd = signal_data;
+ struct acc_ramp *acc_ramp = handler_data;
+ struct gsm_bts_trx *trx = NULL;
+ bool trigger_ramping = false, abort_ramping = false;
+
+ /* Handled signals map to an Administrative State Change ACK, or a State Changed Event Report. */
+ if (signal != S_NM_STATECHG_ADM && signal != S_NM_STATECHG_OPER)
+ return 0;
+
+ if (nsd->obj_class != NM_OC_RADIO_CARRIER)
+ return 0;
+
+ trx = nsd->obj;
+
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d,trx=%d) ACC RAMP: administrative state %s -> %s\n",
+ acc_ramp->bts->nr, trx->nr,
+ get_value_string(abis_nm_adm_state_names, nsd->old_state->administrative),
+ get_value_string(abis_nm_adm_state_names, nsd->new_state->administrative));
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d,trx=%d) ACC RAMP: operational state %s -> %s\n",
+ acc_ramp->bts->nr, trx->nr,
+ abis_nm_opstate_name(nsd->old_state->operational),
+ abis_nm_opstate_name(nsd->new_state->operational));
+
+ /* We only care about state changes of the first TRX. */
+ if (trx->nr != 0)
+ return 0;
+
+ /* RSL must already be up. We cannot send RACH system information to the BTS otherwise. */
+ if (trx->rsl_link == NULL) {
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d,trx=%d) ACC RAMP: ignoring state change because RSL link is down\n",
+ acc_ramp->bts->nr, trx->nr);
+ return 0;
+ }
+
+ /* Trigger or abort ACC ramping based on the new state of this TRX. */
+ if (nsd->old_state->administrative != nsd->new_state->administrative) {
+ switch (nsd->new_state->administrative) {
+ case NM_STATE_UNLOCKED:
+ if (nsd->old_state->operational != nsd->new_state->operational) {
+ /*
+ * Administrative and operational state have both changed.
+ * Trigger ramping only if TRX 0 will be both enabled and unlocked.
+ */
+ if (nsd->new_state->operational == NM_OPSTATE_ENABLED)
+ trigger_ramping = true;
+ else
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d,trx=%d) ACC RAMP: ignoring state change "
+ "because TRX is transitioning into operational state '%s'\n",
+ acc_ramp->bts->nr, trx->nr,
+ abis_nm_opstate_name(nsd->new_state->operational));
+ } else {
+ /*
+ * Operational state has not changed.
+ * Trigger ramping only if TRX 0 is already usable.
+ */
+ if (trx_is_usable(trx))
+ trigger_ramping = true;
+ else
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d,trx=%d) ACC RAMP: ignoring state change "
+ "because TRX is not usable\n", acc_ramp->bts->nr, trx->nr);
+ }
+ break;
+ case NM_STATE_LOCKED:
+ case NM_STATE_SHUTDOWN:
+ abort_ramping = true;
+ break;
+ case NM_STATE_NULL:
+ default:
+ LOGP(DRSL, LOGL_NOTICE, "(bts=%d) ACC RAMP: unrecognized administrative state '0x%x' "
+ "reported for TRX 0\n", acc_ramp->bts->nr, nsd->new_state->administrative);
+ break;
+ }
+ }
+ if (nsd->old_state->operational != nsd->new_state->operational) {
+ switch (nsd->new_state->operational) {
+ case NM_OPSTATE_ENABLED:
+ if (nsd->old_state->administrative != nsd->new_state->administrative) {
+ /*
+ * Administrative and operational state have both changed.
+ * Trigger ramping only if TRX 0 will be both enabled and unlocked.
+ */
+ if (nsd->new_state->administrative == NM_STATE_UNLOCKED)
+ trigger_ramping = true;
+ else
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d,trx=%d) ACC RAMP: ignoring state change "
+ "because TRX is transitioning into administrative state '%s'\n",
+ acc_ramp->bts->nr, trx->nr,
+ get_value_string(abis_nm_adm_state_names, nsd->new_state->administrative));
+ } else {
+ /*
+ * Administrative state has not changed.
+ * Trigger ramping only if TRX 0 is already unlocked.
+ */
+ if (trx->mo.nm_state.administrative == NM_STATE_UNLOCKED)
+ trigger_ramping = true;
+ else
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d,trx=%d) ACC RAMP: ignoring state change "
+ "because TRX is in administrative state '%s'\n",
+ acc_ramp->bts->nr, trx->nr,
+ get_value_string(abis_nm_adm_state_names, trx->mo.nm_state.administrative));
+ }
+ break;
+ case NM_OPSTATE_DISABLED:
+ abort_ramping = true;
+ break;
+ case NM_OPSTATE_NULL:
+ default:
+ LOGP(DRSL, LOGL_NOTICE, "(bts=%d) ACC RAMP: unrecognized operational state '0x%x' "
+ "reported for TRX 0\n", acc_ramp->bts->nr, nsd->new_state->administrative);
+ break;
+ }
+ }
+
+ if (trigger_ramping)
+ acc_ramp_trigger(acc_ramp);
+ else if (abort_ramping)
+ acc_ramp_abort(acc_ramp);
+
+ return 0;
+}
+
+/*!
+ * Initialize an acc_ramp data structure.
+ * Storage for this structure must be provided by the caller.
+ *
+ * By default, ACC ramping is disabled and all ACCs are allowed.
+ *
+ * \param[in] acc_ramp Pointer to acc_ramp structure to be initialized.
+ * \param[in] bts BTS which uses this ACC ramp data structure.
+ */
+void acc_ramp_init(struct acc_ramp *acc_ramp, struct gsm_bts *bts)
+{
+ acc_ramp->bts = bts;
+ acc_ramp_set_enabled(acc_ramp, false);
+ acc_ramp->step_size = ACC_RAMP_STEP_SIZE_DEFAULT;
+ acc_ramp->step_interval_sec = ACC_RAMP_STEP_INTERVAL_MIN;
+ acc_ramp->step_interval_is_fixed = false;
+ allow_all_accs(acc_ramp);
+ osmo_timer_setup(&acc_ramp->step_timer, do_acc_ramping_step, acc_ramp);
+ osmo_signal_register_handler(SS_NM, acc_ramp_nm_sig_cb, acc_ramp);
+}
+
+/*!
+ * Change the ramping step size which controls how many ACCs will be allowed per ramping step.
+ * Returns negative on error (step_size out of range), else zero.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ * \param[in] step_size The new step size value.
+ */
+int acc_ramp_set_step_size(struct acc_ramp *acc_ramp, unsigned int step_size)
+{
+ if (step_size < ACC_RAMP_STEP_SIZE_MIN || step_size > ACC_RAMP_STEP_SIZE_MAX)
+ return -ERANGE;
+
+ acc_ramp->step_size = step_size;
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d) ACC RAMP: ramping step size set to %u\n", acc_ramp->bts->nr, step_size);
+ return 0;
+}
+
+/*!
+ * Change the ramping step interval to a fixed value. Unless this function is called,
+ * the interval is automatically scaled to the BTS channel load average.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ * \param[in] step_interval The new fixed step interval in seconds.
+ */
+int acc_ramp_set_step_interval(struct acc_ramp *acc_ramp, unsigned int step_interval)
+{
+ if (step_interval < ACC_RAMP_STEP_INTERVAL_MIN || step_interval > ACC_RAMP_STEP_INTERVAL_MAX)
+ return -ERANGE;
+
+ acc_ramp->step_interval_sec = step_interval;
+ acc_ramp->step_interval_is_fixed = true;
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d) ACC RAMP: ramping step interval set to %u seconds\n",
+ acc_ramp->bts->nr, step_interval);
+ return 0;
+}
+
+/*!
+ * Clear a previously set fixed ramping step interval, so that the interval
+ * is again automatically scaled to the BTS channel load average.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ */
+void acc_ramp_set_step_interval_dynamic(struct acc_ramp *acc_ramp)
+{
+ acc_ramp->step_interval_is_fixed = false;
+ LOGP(DRSL, LOGL_DEBUG, "(bts=%d) ACC RAMP: ramping step interval set to 'dynamic'\n",
+ acc_ramp->bts->nr);
+}
+
+/*!
+ * Determine if ACC ramping should be started according to configuration, and
+ * begin the ramping process if the necessary conditions are present.
+ * Perform at least one ramping step to allow 'step_size' ACCs.
+ * If 'step_size' is ACC_RAMP_STEP_SIZE_MAX, or if ACC ramping is disabled,
+ * all ACCs will be allowed immediately.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ */
+void acc_ramp_trigger(struct acc_ramp *acc_ramp)
+{
+ /* Abort any previously running ramping process and allow all available ACCs. */
+ acc_ramp_abort(acc_ramp);
+
+ if (acc_ramp_is_enabled(acc_ramp)) {
+ /* Set all available ACCs to barred and start ramping up. */
+ barr_all_accs(acc_ramp);
+ do_acc_ramping_step(acc_ramp);
+ }
+}
+
+/*!
+ * Abort the ramping process and allow all available ACCs immediately.
+ * \param[in] acc_ramp Pointer to acc_ramp structure.
+ */
+void acc_ramp_abort(struct acc_ramp *acc_ramp)
+{
+ if (osmo_timer_pending(&acc_ramp->step_timer))
+ osmo_timer_del(&acc_ramp->step_timer);
+
+ allow_all_accs(acc_ramp);
+}
+
diff --git a/openbsc/src/libbsc/bsc_ctrl_commands.c b/openbsc/src/libbsc/bsc_ctrl_commands.c
index 641fe2b..e6c49d1 100644
--- a/openbsc/src/libbsc/bsc_ctrl_commands.c
+++ b/openbsc/src/libbsc/bsc_ctrl_commands.c
@@ -22,6 +22,7 @@
#include <time.h>
#include <osmocom/ctrl/control_cmd.h>
+#include <osmocom/gsm/gsm48.h>
#include <openbsc/ipaccess.h>
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
@@ -65,8 +66,62 @@ static int verify_vty_description_string(struct ctrl_cmd *cmd,
return 0;
}
-CTRL_CMD_DEFINE_RANGE(net_mnc, "mnc", struct gsm_network, network_code, 0, 999);
-CTRL_CMD_DEFINE_RANGE(net_mcc, "mcc", struct gsm_network, country_code, 1, 999);
+CTRL_CMD_DEFINE(net_mcc, "mcc");
+static int get_net_mcc(struct ctrl_cmd *cmd, void *_data)
+{
+ struct gsm_network *net = cmd->node;
+ cmd->reply = talloc_asprintf(cmd, "%s", osmo_mcc_name(net->plmn.mcc));
+ if (!cmd->reply) {
+ cmd->reply = "OOM";
+ return CTRL_CMD_ERROR;
+ }
+ return CTRL_CMD_REPLY;
+}
+static int set_net_mcc(struct ctrl_cmd *cmd, void *_data)
+{
+ struct gsm_network *net = cmd->node;
+ uint16_t mcc;
+ if (osmo_mcc_from_str(cmd->value, &mcc))
+ return -1;
+ net->plmn.mcc = mcc;
+ return get_net_mcc(cmd, _data);
+}
+static int verify_net_mcc(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (osmo_mcc_from_str(value, NULL))
+ return -1;
+ return 0;
+}
+
+CTRL_CMD_DEFINE(net_mnc, "mnc");
+static int get_net_mnc(struct ctrl_cmd *cmd, void *_data)
+{
+ struct gsm_network *net = cmd->node;
+ cmd->reply = talloc_asprintf(cmd, "%s", osmo_mnc_name(net->plmn.mnc, net->plmn.mnc_3_digits));
+ if (!cmd->reply) {
+ cmd->reply = "OOM";
+ return CTRL_CMD_ERROR;
+ }
+ return CTRL_CMD_REPLY;
+}
+static int set_net_mnc(struct ctrl_cmd *cmd, void *_data)
+{
+ struct gsm_network *net = cmd->node;
+ struct osmo_plmn_id plmn = net->plmn;
+ if (osmo_mnc_from_str(cmd->value, &plmn.mnc, &plmn.mnc_3_digits)) {
+ cmd->reply = "Error while decoding MNC";
+ return CTRL_CMD_ERROR;
+ }
+ net->plmn = plmn;
+ return get_net_mnc(cmd, _data);
+}
+static int verify_net_mnc(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (osmo_mnc_from_str(value, NULL, NULL))
+ return -1;
+ return 0;
+}
+
CTRL_CMD_VTY_STRING(net_short_name, "short-name", struct gsm_network, name_short);
CTRL_CMD_VTY_STRING(net_long_name, "long-name", struct gsm_network, name_long);
@@ -101,6 +156,7 @@ CTRL_CMD_DEFINE_WO_NOVRF(net_apply_config, "apply-configuration");
static int verify_net_mcc_mnc_apply(struct ctrl_cmd *cmd, const char *value, void *d)
{
char *tmp, *saveptr, *mcc, *mnc;
+ int rc = 0;
tmp = talloc_strdup(cmd, value);
if (!tmp)
@@ -108,39 +164,47 @@ static int verify_net_mcc_mnc_apply(struct ctrl_cmd *cmd, const char *value, voi
mcc = strtok_r(tmp, ",", &saveptr);
mnc = strtok_r(NULL, ",", &saveptr);
- talloc_free(tmp);
- if (!mcc || !mnc)
- return 1;
- return 0;
+ if (osmo_mcc_from_str(mcc, NULL) || osmo_mnc_from_str(mnc, NULL, NULL))
+ rc = -1;
+
+ talloc_free(tmp);
+ return rc;
}
static int set_net_mcc_mnc_apply(struct ctrl_cmd *cmd, void *data)
{
struct gsm_network *net = cmd->node;
char *tmp, *saveptr, *mcc_str, *mnc_str;
- int mcc, mnc;
+ struct osmo_plmn_id plmn;
tmp = talloc_strdup(cmd, cmd->value);
if (!tmp)
goto oom;
-
mcc_str = strtok_r(tmp, ",", &saveptr);
mnc_str = strtok_r(NULL, ",", &saveptr);
- mcc = atoi(mcc_str);
- mnc = atoi(mnc_str);
+ if (osmo_mcc_from_str(mcc_str, &plmn.mcc)) {
+ cmd->reply = "Error while decoding MCC";
+ talloc_free(tmp);
+ return CTRL_CMD_ERROR;
+ }
+
+ if (osmo_mnc_from_str(mnc_str, &plmn.mnc, &plmn.mnc_3_digits)) {
+ cmd->reply = "Error while decoding MNC";
+ talloc_free(tmp);
+ return CTRL_CMD_ERROR;
+ }
talloc_free(tmp);
- if (net->network_code == mnc && net->country_code == mcc) {
+ if (!osmo_plmn_cmp(&net->plmn, &plmn)) {
cmd->reply = "Nothing changed";
return CTRL_CMD_REPLY;
}
- net->network_code = mnc;
- net->country_code = mcc;
+ net->plmn = plmn;
return set_net_apply_config(cmd, data);
diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c
index 36531d2..21ed2e1 100644
--- a/openbsc/src/libbsc/bsc_init.c
+++ b/openbsc/src/libbsc/bsc_init.c
@@ -305,15 +305,24 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx)
unsigned int i;
LOGP(DRSL, LOGL_NOTICE, "bootstrapping RSL for BTS/TRX (%u/%u) "
- "on ARFCN %u using MCC=%u MNC=%u LAC=%u CID=%u BSIC=%u\n",
- trx->bts->nr, trx->nr, trx->arfcn, bsc_gsmnet->country_code,
- bsc_gsmnet->network_code, trx->bts->location_area_code,
+ "on ARFCN %u using MCC-MNC %s LAC=%u CID=%u BSIC=%u\n",
+ trx->bts->nr, trx->nr, trx->arfcn,
+ osmo_plmn_name(&bsc_gsmnet->plmn),
+ trx->bts->location_area_code,
trx->bts->cell_identity, trx->bts->bsic);
if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
rsl_nokia_si_begin(trx);
}
+ /*
+ * Trigger ACC ramping before sending system information to BTS.
+ * This ensures that RACH control in system information is configured correctly.
+ * TRX 0 should be usable and unlocked, otherwise starting ACC ramping is pointless.
+ */
+ if (trx_is_usable(trx) && trx->mo.nm_state.administrative == NM_STATE_UNLOCKED)
+ acc_ramp_trigger(&trx->bts->acc_ramp);
+
gsm_bts_trx_set_system_infos(trx);
if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
@@ -379,8 +388,10 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
if (isd->link_type == E1INP_SIGN_OML)
rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL]);
- else if (isd->link_type == E1INP_SIGN_RSL)
+ else if (isd->link_type == E1INP_SIGN_RSL) {
rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL]);
+ acc_ramp_abort(&trx->bts->acc_ramp);
+ }
/*
* free all allocated channels. change the nm_state so the
@@ -507,6 +518,10 @@ static int bootstrap_bts(struct gsm_bts *bts)
bts->si_common.ncc_permitted = 0xff;
+ bts->chan_load_samples_idx = 0;
+
+ /* ACC ramping is initialized from vty/config */
+
/* Initialize the BTS state */
gsm_bts_mo_reset(bts);
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 5fb1c5d..c71ea4a 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -56,6 +56,7 @@
#include <openbsc/bsc_msc_data.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/pcu_if.h>
+#include <openbsc/acc_ramp.h>
#include <openbsc/common_cs.h>
@@ -163,9 +164,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net)
{
struct pchan_load pl;
- vty_out(vty, "BSC is on Country Code %u, Network Code %u "
- "and has %u BTS%s", net->country_code, net->network_code,
- net->num_bts, VTY_NEWLINE);
+ vty_out(vty, "BSC is on MCC-MNC %s and has %u BTS%s",
+ osmo_plmn_name(&net->plmn), net->num_bts, VTY_NEWLINE);
vty_out(vty, " Long network name: '%s'%s",
net->name_long, VTY_NEWLINE);
vty_out(vty, " Short network name: '%s'%s",
@@ -260,6 +260,18 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
VTY_NEWLINE);
vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s",
bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
+ vty_out(vty, " Access Control Class ramping: %senabled%s",
+ acc_ramp_is_enabled(&bts->acc_ramp) ? "" : "not ", VTY_NEWLINE);
+ if (acc_ramp_is_enabled(&bts->acc_ramp)) {
+ if (!acc_ramp_step_interval_is_dynamic(&bts->acc_ramp))
+ vty_out(vty, " Access Control Class ramping step interval: %u seconds%s",
+ acc_ramp_get_step_interval(&bts->acc_ramp), VTY_NEWLINE);
+ else
+ vty_out(vty, " Access Control Class ramping step interval: dynamic%s", VTY_NEWLINE);
+ vty_out(vty, " enabling %u Access Control Class%s per ramping step%s",
+ acc_ramp_get_step_size(&bts->acc_ramp),
+ acc_ramp_get_step_size(&bts->acc_ramp) > 1 ? "es" : "", VTY_NEWLINE);
+ }
vty_out(vty, "RACH TX-Integer: %u%s", bts->si_common.rach_control.tx_integer,
VTY_NEWLINE);
vty_out(vty, "RACH Max transmissions: %u%s",
@@ -283,8 +295,11 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
bts->si_common.chan_desc.bs_ag_blks_res, VTY_NEWLINE);
vty_out(vty, "System Information present: 0x%08x, static: 0x%08x%s",
bts->si_valid, bts->si_mode_static, VTY_NEWLINE);
- vty_out(vty, "Early Classmark Sending: %s%s",
+ vty_out(vty, "Early Classmark Sending: 2G %s, 3G %s%s%s",
bts->early_classmark_allowed ? "allowed" : "forbidden",
+ bts->early_classmark_allowed_3g ? "allowed" : "forbidden",
+ bts->early_classmark_allowed_3g && !bts->early_classmark_allowed ?
+ " (forbidden by 2G bit)" : "",
VTY_NEWLINE);
if (bts->pcu_sock_path)
vty_out(vty, "PCU Socket Path: %s%s", bts->pcu_sock_path, VTY_NEWLINE);
@@ -660,6 +675,15 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
for (i = 0; i < 8; i++)
if ((i != 2) && (bts->si_common.rach_control.t2 & (0x1 << i)))
vty_out(vty, " rach access-control-class %d barred%s", i+8, VTY_NEWLINE);
+ vty_out(vty, " %saccess-control-class-ramping%s", acc_ramp_is_enabled(&bts->acc_ramp) ? "" : "no ", VTY_NEWLINE);
+ if (!acc_ramp_step_interval_is_dynamic(&bts->acc_ramp)) {
+ vty_out(vty, " access-control-class-ramping-step-interval %u%s",
+ acc_ramp_get_step_interval(&bts->acc_ramp), VTY_NEWLINE);
+ } else {
+ vty_out(vty, " access-control-class-ramping-step-interval dynamic%s", VTY_NEWLINE);
+ }
+ vty_out(vty, " access-control-class-ramping-step-size %u%s", acc_ramp_get_step_size(&bts->acc_ramp),
+ VTY_NEWLINE);
for (i = SYSINFO_TYPE_1; i < _MAX_SYSINFO_TYPE; i++) {
if (bts->si_mode_static & (1 << i)) {
vty_out(vty, " system-information %s mode static%s",
@@ -672,6 +696,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
}
vty_out(vty, " early-classmark-sending %s%s",
bts->early_classmark_allowed ? "allowed" : "forbidden", VTY_NEWLINE);
+ vty_out(vty, " early-classmark-sending-3g %s%s",
+ bts->early_classmark_allowed_3g ? "allowed" : "forbidden", VTY_NEWLINE);
switch (bts->type) {
case GSM_BTS_TYPE_NANOBTS:
case GSM_BTS_TYPE_OSMOBTS:
@@ -813,8 +839,9 @@ static int config_write_net(struct vty *vty)
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
vty_out(vty, "network%s", VTY_NEWLINE);
- vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE);
- vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE);
+ vty_out(vty, " network country code %s%s", osmo_mcc_name(gsmnet->plmn.mcc), VTY_NEWLINE);
+ vty_out(vty, " mobile network code %s%s",
+ osmo_mnc_name(gsmnet->plmn.mnc, gsmnet->plmn.mnc_3_digits), VTY_NEWLINE);
vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE);
vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE);
vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE);
@@ -1592,7 +1619,7 @@ DECLARE_TIMER(3113, "Set the time to try paging a subscriber")
DECLARE_TIMER(3115, "Currently not used")
DECLARE_TIMER(3117, "Currently not used")
DECLARE_TIMER(3119, "Currently not used")
-DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT")
+DECLARE_TIMER(3122, "Default waiting time (seconds) after IMM ASS REJECT")
DECLARE_TIMER(3141, "Currently not used")
DEFUN_DEPRECATED(cfg_net_dtx,
@@ -1624,6 +1651,11 @@ DEFUN(cfg_bts,
/* allocate a new one */
bts = gsm_bts_alloc_register(gsmnet, GSM_BTS_TYPE_UNKNOWN,
HARDCODED_BSIC);
+ /*
+ * Initalize bts->acc_ramp here. Else we could segfault while
+ * processing a configuration file with ACC ramping settings.
+ */
+ acc_ramp_init(&bts->acc_ramp, bts);
} else
bts = gsm_bts_num(gsmnet, bts_nr);
@@ -2770,6 +2802,22 @@ DEFUN(cfg_bts_early_cm, cfg_bts_early_cm_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_early_cm_3g, cfg_bts_early_cm_3g_cmd,
+ "early-classmark-sending-3g (allowed|forbidden)",
+ "3G Early Classmark Sending\n"
+ "3G Early Classmark Sending is allowed\n"
+ "3G Early Classmark Sending is forbidden\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (!strcmp(argv[0], "allowed"))
+ bts->early_classmark_allowed_3g = true;
+ else
+ bts->early_classmark_allowed_3g = false;
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_bts_neigh_mode, cfg_bts_neigh_mode_cmd,
"neighbor-list mode (automatic|manual|manual-si5)",
"Neighbor List\n" "Mode of Neighbor List generation\n"
@@ -2987,6 +3035,92 @@ DEFUN(cfg_bts_pcu_sock, cfg_bts_pcu_sock_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_acc_ramping,
+ cfg_bts_acc_ramping_cmd,
+ "access-control-class-ramping",
+ "Enable Access Control Class ramping\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (!acc_ramp_is_enabled(&bts->acc_ramp))
+ acc_ramp_set_enabled(&bts->acc_ramp, true);
+
+ /*
+ * ACC ramping takes effect either when the BTS reconnects RSL,
+ * or when RF administrative state changes to 'unlocked'.
+ */
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_acc_ramping, cfg_bts_no_acc_ramping_cmd,
+ "no access-control-class-ramping",
+ NO_STR
+ "Disable Access Control Class ramping\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (acc_ramp_is_enabled(&bts->acc_ramp)) {
+ acc_ramp_abort(&bts->acc_ramp);
+ acc_ramp_set_enabled(&bts->acc_ramp, false);
+ gsm_bts_set_system_infos(bts);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_acc_ramping_step_interval,
+ cfg_bts_acc_ramping_step_interval_cmd,
+ "access-control-class-ramping-step-interval (<"
+ OSMO_STRINGIFY_VAL(ACC_RAMP_STEP_INTERVAL_MIN) "-"
+ OSMO_STRINGIFY_VAL(ACC_RAMP_STEP_INTERVAL_MAX) ">|dynamic)",
+ "Configure Access Control Class ramping step interval\n"
+ "Set a fixed step interval (in seconds)\n"
+ "Use dynamic step interval based on BTS channel load\n")
+{
+ struct gsm_bts *bts = vty->index;
+ bool dynamic = (strcmp(argv[0], "dynamic") == 0);
+ int error;
+
+ if (dynamic) {
+ acc_ramp_set_step_interval_dynamic(&bts->acc_ramp);
+ return CMD_SUCCESS;
+ }
+
+ error = acc_ramp_set_step_interval(&bts->acc_ramp, atoi(argv[0]));
+ if (error != 0) {
+ if (error == -ERANGE)
+ vty_out(vty, "Unable to set ACC ramp step interval: value out of range%s", VTY_NEWLINE);
+ else
+ vty_out(vty, "Unable to set ACC ramp step interval: unknown error%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_acc_ramping_step_size,
+ cfg_bts_acc_ramping_step_size_cmd,
+ "access-control-class-ramping-step-size (<"
+ OSMO_STRINGIFY_VAL(ACC_RAMP_STEP_SIZE_MIN) "-"
+ OSMO_STRINGIFY_VAL(ACC_RAMP_STEP_SIZE_MAX) ">)",
+ "Configure Access Control Class ramping step size\n"
+ "Set the number of Access Control Classes to enable per ramping step\n")
+{
+ struct gsm_bts *bts = vty->index;
+ int error;
+
+ error = acc_ramp_set_step_size(&bts->acc_ramp, atoi(argv[0]));
+ if (error != 0) {
+ if (error == -ERANGE)
+ vty_out(vty, "Unable to set ACC ramp step size: value out of range%s", VTY_NEWLINE);
+ else
+ vty_out(vty, "Unable to set ACC ramp step size: unknown error%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
#define EXCL_RFLOCK_STR "Exclude this BTS from the global RF Lock\n"
DEFUN(cfg_bts_excl_rf_lock,
@@ -4229,7 +4363,6 @@ int bsc_vty_init(struct gsm_network *network)
install_element(GSMNET_NODE, &cfg_bts_cmd);
install_node(&bts_node, config_write_bts);
- vty_install_default(BTS_NODE);
install_element(BTS_NODE, &cfg_bts_type_cmd);
install_element(BTS_NODE, &cfg_description_cmd);
install_element(BTS_NODE, &cfg_no_description_cmd);
@@ -4292,6 +4425,7 @@ int bsc_vty_init(struct gsm_network *network)
install_element(BTS_NODE, &cfg_bts_si_mode_cmd);
install_element(BTS_NODE, &cfg_bts_si_static_cmd);
install_element(BTS_NODE, &cfg_bts_early_cm_cmd);
+ install_element(BTS_NODE, &cfg_bts_early_cm_3g_cmd);
install_element(BTS_NODE, &cfg_bts_neigh_mode_cmd);
install_element(BTS_NODE, &cfg_bts_neigh_cmd);
install_element(BTS_NODE, &cfg_bts_si5_neigh_cmd);
@@ -4333,10 +4467,13 @@ int bsc_vty_init(struct gsm_network *network)
install_element(BTS_NODE, &cfg_bts_amr_hr_hyst3_cmd);
install_element(BTS_NODE, &cfg_bts_amr_hr_start_mode_cmd);
install_element(BTS_NODE, &cfg_bts_pcu_sock_cmd);
+ install_element(BTS_NODE, &cfg_bts_acc_ramping_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_acc_ramping_cmd);
+ install_element(BTS_NODE, &cfg_bts_acc_ramping_step_interval_cmd);
+ install_element(BTS_NODE, &cfg_bts_acc_ramping_step_size_cmd);
install_element(BTS_NODE, &cfg_trx_cmd);
install_node(&trx_node, dummy_config_write);
- vty_install_default(TRX_NODE);
install_element(TRX_NODE, &cfg_trx_arfcn_cmd);
install_element(TRX_NODE, &cfg_description_cmd);
install_element(TRX_NODE, &cfg_no_description_cmd);
@@ -4348,7 +4485,6 @@ int bsc_vty_init(struct gsm_network *network)
install_element(TRX_NODE, &cfg_ts_cmd);
install_node(&ts_node, dummy_config_write);
- vty_install_default(TS_NODE);
install_element(TS_NODE, &cfg_ts_pchan_cmd);
install_element(TS_NODE, &cfg_ts_pchan_compat_cmd);
install_element(TS_NODE, &cfg_ts_tsc_cmd);
diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c
index 33b79a0..52a8259 100644
--- a/openbsc/src/libbsc/chan_alloc.c
+++ b/openbsc/src/libbsc/chan_alloc.c
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <inttypes.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/chan_alloc.h>
@@ -541,3 +542,87 @@ void network_chan_load(struct pchan_load *pl, struct gsm_network *net)
bts_chan_load(pl, bts);
}
+/* Update T3122 wait indicator based on samples of BTS channel load. */
+void
+bts_update_t3122_chan_load(struct gsm_bts *bts)
+{
+ struct pchan_load pl;
+ uint64_t used = 0;
+ uint32_t total = 0;
+ uint64_t load;
+ uint64_t wait_ind;
+ static const uint8_t min_wait_ind = GSM_T3122_DEFAULT;
+ static const uint8_t max_wait_ind = 128; /* max wait ~2 minutes */
+ int i;
+
+ /* Ignore BTS that are not in operation, in order to not flood the log with "bogus channel load"
+ * messages */
+ if (!trx_is_usable(bts->c0))
+ return;
+
+ /* Sum up current load across all channels. */
+ memset(&pl, 0, sizeof(pl));
+ bts_chan_load(&pl, bts);
+ for (i = 0; i < ARRAY_SIZE(pl.pchan); i++) {
+ struct load_counter *lc = &pl.pchan[i];
+
+ /* Ignore samples too large for fixed-point calculations (shouldn't happen). */
+ if (lc->used > UINT16_MAX || lc->total > UINT16_MAX) {
+ LOGP(DRLL, LOGL_NOTICE, "(bts=%d) numbers in channel load sample "
+ "too large (used=%u / total=%u)\n", bts->nr, lc->used, lc->total);
+ continue;
+ }
+
+ used += lc->used;
+ total += lc->total;
+ }
+
+ /* Check for invalid samples (shouldn't happen). */
+ if (total == 0 || used > total) {
+ LOGP(DRLL, LOGL_NOTICE, "(bts=%d) bogus channel load sample (used=%"PRIu64" / total=%"PRIu32")\n",
+ bts->nr, used, total);
+ bts->T3122 = 0; /* disable override of network-wide default value */
+ bts->chan_load_samples_idx = 0; /* invalidate other samples collected so far */
+ return;
+ }
+
+ /* If we haven't got enough samples yet, store measurement for later use. */
+ if (bts->chan_load_samples_idx < ARRAY_SIZE(bts->chan_load_samples)) {
+ struct load_counter *sample = &bts->chan_load_samples[bts->chan_load_samples_idx++];
+ sample->total = (unsigned int)total;
+ sample->used = (unsigned int)used;
+ return;
+ }
+
+ /* We have enough samples and will overwrite our current samples later. */
+ bts->chan_load_samples_idx = 0;
+
+ /* Add all previous samples to the current sample. */
+ for (i = 0; i < ARRAY_SIZE(bts->chan_load_samples); i++) {
+ struct load_counter *sample = &bts->chan_load_samples[i];
+ total += sample->total;
+ used += sample->used;
+ }
+
+ used <<= 8; /* convert to fixed-point */
+
+ /* Log channel load average. */
+ load = ((used / total) * 100);
+ LOGP(DRLL, LOGL_DEBUG, "(bts=%d) channel load average is %"PRIu64".%.2"PRIu64"%%\n",
+ bts->nr, (load & 0xffffff00) >> 8, (load & 0xff) / 10);
+ bts->chan_load_avg = ((load & 0xffffff00) >> 8);
+ OSMO_ASSERT(bts->chan_load_avg <= 100);
+ osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_CHAN_LOAD_AVERAGE], bts->chan_load_avg);
+
+ /* Calculate new T3122 wait indicator. */
+ wait_ind = ((used / total) * max_wait_ind);
+ wait_ind >>= 8; /* convert from fixed-point to integer */
+ if (wait_ind < min_wait_ind)
+ wait_ind = min_wait_ind;
+ else if (wait_ind > max_wait_ind)
+ wait_ind = max_wait_ind;
+
+ LOGP(DRLL, LOGL_DEBUG, "(bts=%d) T3122 wait indicator set to %"PRIu64" seconds\n", bts->nr, wait_ind);
+ bts->T3122 = (uint8_t)wait_ind;
+ osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_T3122], wait_ind);
+}
diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c
index 9d54319..08e2bd6 100644
--- a/openbsc/src/libbsc/net_init.c
+++ b/openbsc/src/libbsc/net_init.c
@@ -20,6 +20,22 @@
#include <openbsc/common_cs.h>
#include <openbsc/osmo_bsc.h>
#include <openbsc/bsc_msc_data.h>
+#include <openbsc/chan_alloc.h>
+
+/* XXX hard-coded for now */
+#define T3122_CHAN_LOAD_SAMPLE_INTERVAL 1 /* in seconds */
+
+static void update_t3122_chan_load_timer(void *data)
+{
+ struct gsm_network *net = data;
+ struct gsm_bts *bts;
+
+ llist_for_each_entry(bts, &net->bts_list, list)
+ bts_update_t3122_chan_load(bts);
+
+ /* Keep this timer ticking. */
+ osmo_timer_schedule(&net->t3122_chan_load_timer, T3122_CHAN_LOAD_SAMPLE_INTERVAL, 0);
+}
struct gsm_network *bsc_network_init(void *ctx,
uint16_t country_code,
@@ -66,6 +82,14 @@ struct gsm_network *bsc_network_init(void *ctx,
INIT_LLIST_HEAD(&net->bts_list);
+ /*
+ * At present all BTS in the network share one channel load timeout.
+ * If this becomes a problem for networks with a lot of BTS, this
+ * code could be refactored to run the timeout individually per BTS.
+ */
+ osmo_timer_setup(&net->t3122_chan_load_timer, update_t3122_chan_load_timer, net);
+ osmo_timer_schedule(&net->t3122_chan_load_timer, T3122_CHAN_LOAD_SAMPLE_INTERVAL, 0);
+
/* init statistics */
net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0);
if (!net->bsc_ctrs) {
diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c
index 78e39c5..9bf1a57 100644
--- a/openbsc/src/libbsc/paging.c
+++ b/openbsc/src/libbsc/paging.c
@@ -326,6 +326,9 @@ int paging_request_bts(struct gsm_bts *bts, struct bsc_subscr *bsub,
return 1;
}
+/*! Page a request on all BTS within Location Area
+ * \returns Amount of BTS to which the paging request was sent, negative on error.
+ */
int paging_request(struct gsm_network *network, struct bsc_subscr *bsub,
int type, gsm_cbfn *cbfn, void *data)
{
@@ -343,12 +346,12 @@ int paging_request(struct gsm_network *network, struct bsc_subscr *bsub,
break;
rc = paging_request_bts(bts, bsub, type, cbfn, data);
- if (rc < 0) {
- paging_request_stop(&network->bts_list, NULL, bsub,
- NULL, NULL);
+ if (rc >= 0)
+ num_pages += rc;
+ else if (rc == -EEXIST)
+ num_pages += 1;
+ else
return rc;
- }
- num_pages += rc;
} while (1);
if (num_pages == 0)
diff --git a/openbsc/src/libbsc/pcu_sock.c b/openbsc/src/libbsc/pcu_sock.c
index 98e12fa..e2066ba 100644
--- a/openbsc/src/libbsc/pcu_sock.c
+++ b/openbsc/src/libbsc/pcu_sock.c
@@ -152,8 +152,9 @@ static int pcu_tx_info_ind(struct gsm_bts *bts)
info_ind->flags |= PCU_IF_FLAG_SYSMO;
/* RAI */
- info_ind->mcc = bts->network->country_code;
- info_ind->mnc = bts->network->network_code;
+ info_ind->mcc = bts->network->plmn.mcc;
+ info_ind->mnc = bts->network->plmn.mnc;
+ info_ind->mnc_3_digits = bts->network->plmn.mnc_3_digits;
info_ind->lac = bts->location_area_code;
info_ind->rac = bts->gprs.rac;
diff --git a/openbsc/src/libbsc/rest_octets.c b/openbsc/src/libbsc/rest_octets.c
index 7b77ce2..49c38b5 100644
--- a/openbsc/src/libbsc/rest_octets.c
+++ b/openbsc/src/libbsc/rest_octets.c
@@ -495,9 +495,12 @@ int rest_octets_si3(uint8_t *data, const struct gsm48_si_ro_info *si3)
/* GPRS Indicator */
append_gprs_ind(&bv, &si3->gprs_ind);
- /* 3G Early Classmark Sending Restriction controlled by
+ /* 3G Early Classmark Sending Restriction. If H, then controlled by
* early_cm_ctrl above */
- bitvec_set_bit(&bv, H);
+ if (si3->early_cm_restrict_3g)
+ bitvec_set_bit(&bv, L);
+ else
+ bitvec_set_bit(&bv, H);
if (si3->si2quater_indicator) {
bitvec_set_bit(&bv, H); /* indicator struct present */
diff --git a/openbsc/src/libbsc/system_information.c b/openbsc/src/libbsc/system_information.c
index abb1a6d..a6226a4 100644
--- a/openbsc/src/libbsc/system_information.c
+++ b/openbsc/src/libbsc/system_information.c
@@ -37,6 +37,7 @@
#include <openbsc/abis_rsl.h>
#include <openbsc/rest_octets.h>
#include <openbsc/arfcn_range_encode.h>
+#include <openbsc/acc_ramp.h>
/*
* DCS1800 and PCS1900 have overlapping ARFCNs. We would need to set the
@@ -662,6 +663,8 @@ static int generate_si1(enum osmo_sysinfo_type t, struct gsm_bts *bts)
list_arfcn(si1->cell_channel_description, 0xce, "Serving cell:");
si1->rach_control = bts->si_common.rach_control;
+ if (acc_ramp_is_enabled(&bts->acc_ramp))
+ acc_ramp_apply(&si1->rach_control, &bts->acc_ramp);
/*
* SI1 Rest Octets (10.5.2.32), contains NCH position and band
@@ -692,6 +695,8 @@ static int generate_si2(enum osmo_sysinfo_type t, struct gsm_bts *bts)
si2->ncc_permitted = bts->si_common.ncc_permitted;
si2->rach_control = bts->si_common.rach_control;
+ if (acc_ramp_is_enabled(&bts->acc_ramp))
+ acc_ramp_apply(&si2->rach_control, &bts->acc_ramp);
return sizeof(*si2);
}
@@ -725,6 +730,8 @@ static int generate_si2bis(enum osmo_sysinfo_type t, struct gsm_bts *bts)
bts->si_valid &= ~(1 << SYSINFO_TYPE_2bis);
si2b->rach_control = bts->si_common.rach_control;
+ if (acc_ramp_is_enabled(&bts->acc_ramp))
+ acc_ramp_apply(&si2b->rach_control, &bts->acc_ramp);
return sizeof(*si2b);
}
@@ -802,8 +809,8 @@ static struct gsm48_si_ro_info si_info = {
.power_offset = {
.present = 0,
},
- .si2ter_indicator = 0,
- .early_cm_ctrl = 1,
+ .si2ter_indicator = false,
+ .early_cm_ctrl = true,
.scheduling = {
.present = 0,
},
@@ -812,7 +819,8 @@ static struct gsm48_si_ro_info si_info = {
.ra_colour = 0,
.present = 1,
},
- .si2quater_indicator = 0,
+ .early_cm_restrict_3g = false,
+ .si2quater_indicator = false,
.lsa_params = {
.present = 0,
},
@@ -833,31 +841,32 @@ static int generate_si3(enum osmo_sysinfo_type t, struct gsm_bts *bts)
si3->header.system_information = GSM48_MT_RR_SYSINFO_3;
si3->cell_identity = htons(bts->cell_identity);
- gsm48_generate_lai(&si3->lai, bts->network->country_code,
- bts->network->network_code,
- bts->location_area_code);
+ gsm48_generate_lai2(&si3->lai, bts_lai(bts));
si3->control_channel_desc = bts->si_common.chan_desc;
si3->cell_options = bts->si_common.cell_options;
si3->cell_sel_par = bts->si_common.cell_sel_par;
si3->rach_control = bts->si_common.rach_control;
+ if (acc_ramp_is_enabled(&bts->acc_ramp))
+ acc_ramp_apply(&si3->rach_control, &bts->acc_ramp);
/* allow/disallow DTXu */
gsm48_set_dtx(&si3->cell_options, bts->dtxu, bts->dtxu, true);
if (GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_2ter)) {
LOGP(DRR, LOGL_INFO, "SI 2ter is included.\n");
- si_info.si2ter_indicator = 1;
+ si_info.si2ter_indicator = true;
} else {
- si_info.si2ter_indicator = 0;
+ si_info.si2ter_indicator = false;
}
if (GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_2quater)) {
LOGP(DRR, LOGL_INFO, "SI 2quater is included, based on %zu EARFCNs and %zu UARFCNs.\n",
si2q_earfcn_count(&bts->si_common.si2quater_neigh_list), bts->si_common.uarfcn_length);
- si_info.si2quater_indicator = 1;
+ si_info.si2quater_indicator = true;
} else {
- si_info.si2quater_indicator = 0;
+ si_info.si2quater_indicator = false;
}
si_info.early_cm_ctrl = bts->early_classmark_allowed;
+ si_info.early_cm_restrict_3g = !bts->early_classmark_allowed_3g;
/* SI3 Rest Octets (10.5.2.34), containing
CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME
@@ -884,11 +893,11 @@ static int generate_si4(enum osmo_sysinfo_type t, struct gsm_bts *bts)
si4->header.skip_indicator = 0;
si4->header.system_information = GSM48_MT_RR_SYSINFO_4;
- gsm48_generate_lai(&si4->lai, bts->network->country_code,
- bts->network->network_code,
- bts->location_area_code);
+ gsm48_generate_lai2(&si4->lai, bts_lai(bts));
si4->cell_sel_par = bts->si_common.cell_sel_par;
si4->rach_control = bts->si_common.rach_control;
+ if (acc_ramp_is_enabled(&bts->acc_ramp))
+ acc_ramp_apply(&si4->rach_control, &bts->acc_ramp);
/* Optional: CBCH Channel Description + CBCH Mobile Allocation */
cbch_lchan = gsm_bts_get_cbch(bts);
@@ -931,7 +940,7 @@ static int generate_si5(enum osmo_sysinfo_type t, struct gsm_bts *bts)
break;
}
- si5 = (struct gsm48_system_information_type_5 *) GSM_BTS_SI(bts, t);
+ si5 = (struct gsm48_system_information_type_5 *) output;
/* l2 pseudo length, not part of msg: 18 */
si5->rr_protocol_discriminator = GSM48_PDISC_RR;
@@ -967,7 +976,7 @@ static int generate_si5bis(enum osmo_sysinfo_type t, struct gsm_bts *bts)
break;
}
- si5b = (struct gsm48_system_information_type_5bis *) GSM_BTS_SI(bts, t);
+ si5b = (struct gsm48_system_information_type_5bis *) output;
/* l2 pseudo length, not part of msg: 18 */
si5b->rr_protocol_discriminator = GSM48_PDISC_RR;
@@ -981,7 +990,7 @@ static int generate_si5bis(enum osmo_sysinfo_type t, struct gsm_bts *bts)
if (n) {
/* indicate in SI5 and SI5bis: there is an extension */
struct gsm48_system_information_type_5 *si5 =
- (struct gsm48_system_information_type_5 *) GSM_BTS_SI(bts, SYSINFO_TYPE_5);
+ (struct gsm48_system_information_type_5 *) GSM_BTS_SI(bts, SYSINFO_TYPE_5)+1;
si5->bcch_frequency_list[0] |= 0x20;
si5b->bcch_frequency_list[0] |= 0x20;
} else
@@ -1011,7 +1020,7 @@ static int generate_si5ter(enum osmo_sysinfo_type t, struct gsm_bts *bts)
break;
}
- si5t = (struct gsm48_system_information_type_5ter *) GSM_BTS_SI(bts, t);
+ si5t = (struct gsm48_system_information_type_5ter *) output;
/* l2 pseudo length, not part of msg: 18 */
si5t->rr_protocol_discriminator = GSM48_PDISC_RR;
@@ -1049,16 +1058,14 @@ static int generate_si6(enum osmo_sysinfo_type t, struct gsm_bts *bts)
break;
}
- si6 = (struct gsm48_system_information_type_6 *) GSM_BTS_SI(bts, t);
+ si6 = (struct gsm48_system_information_type_6 *) output;
/* l2 pseudo length, not part of msg: 11 */
si6->rr_protocol_discriminator = GSM48_PDISC_RR;
si6->skip_indicator = 0;
si6->system_information = GSM48_MT_RR_SYSINFO_6;
si6->cell_identity = htons(bts->cell_identity);
- gsm48_generate_lai(&si6->lai, bts->network->country_code,
- bts->network->network_code,
- bts->location_area_code);
+ gsm48_generate_lai2(&si6->lai, bts_lai(bts));
si6->cell_options = bts->si_common.cell_options;
si6->ncc_permitted = bts->si_common.ncc_permitted;
/* allow/disallow DTXu */
diff --git a/openbsc/src/libcommon-cs/common_cs.c b/openbsc/src/libcommon-cs/common_cs.c
index d299427..d8d5ec7 100644
--- a/openbsc/src/libcommon-cs/common_cs.c
+++ b/openbsc/src/libcommon-cs/common_cs.c
@@ -63,8 +63,10 @@ struct gsm_network *gsm_network_init(void *ctx,
net->auto_create_subscr = true;
net->auto_assign_exten = true;
- net->country_code = country_code;
- net->network_code = network_code;
+ net->plmn = (struct osmo_plmn_id){
+ .mcc = country_code,
+ .mnc = network_code,
+ };
INIT_LLIST_HEAD(&net->trans_list);
INIT_LLIST_HEAD(&net->upqueue);
diff --git a/openbsc/src/libcommon-cs/common_cs_vty.c b/openbsc/src/libcommon-cs/common_cs_vty.c
index bcc001d..c323b11 100644
--- a/openbsc/src/libcommon-cs/common_cs_vty.c
+++ b/openbsc/src/libcommon-cs/common_cs_vty.c
@@ -60,8 +60,14 @@ DEFUN(cfg_net_ncc,
"Network Country Code to use\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ uint16_t mcc;
- gsmnet->country_code = atoi(argv[0]);
+ if (osmo_mcc_from_str(argv[0], &mcc)) {
+ vty_out(vty, "%% Error decoding MCC: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ gsmnet->plmn.mcc = mcc;
return CMD_SUCCESS;
}
@@ -75,8 +81,16 @@ DEFUN(cfg_net_mnc,
"Mobile Network Code to use\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ uint16_t mnc;
+ bool mnc_3_digits;
+
+ if (osmo_mnc_from_str(argv[0], &mnc, &mnc_3_digits)) {
+ vty_out(vty, "%% Error decoding MNC: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
- gsmnet->network_code = atoi(argv[0]);
+ gsmnet->plmn.mnc = mnc;
+ gsmnet->plmn.mnc_3_digits = mnc_3_digits;
return CMD_SUCCESS;
}
@@ -292,7 +306,6 @@ int common_cs_vty_init(struct gsm_network *network,
install_element(CONFIG_NODE, &cfg_net_cmd);
install_node(&net_node, config_write_net);
- vty_install_default(GSMNET_NODE);
install_element(GSMNET_NODE, &cfg_net_ncc_cmd);
install_element(GSMNET_NODE, &cfg_net_mnc_cmd);
install_element(GSMNET_NODE, &cfg_net_name_short_cmd);
diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c
index f1049e9..b45a4d3 100644
--- a/openbsc/src/libcommon/gsm_data.c
+++ b/openbsc/src/libcommon/gsm_data.c
@@ -300,6 +300,7 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ
bts->dtxd = false;
bts->gprs.ctrl_ack_type_use_block = true; /* use RLC/MAC control block */
bts->neigh_list_manual_mode = 0;
+ bts->early_classmark_allowed_3g = true; /* 3g Early Classmark Sending controlled by bts->early_classmark_allowed param */
bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */
bts->si_common.cell_sel_par.rxlev_acc_min = 0;
bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list;
@@ -337,19 +338,21 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ
void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts)
{
- raid->mcc = bts->network->country_code;
- raid->mnc = bts->network->network_code;
- raid->lac = bts->location_area_code;
- raid->rac = bts->gprs.rac;
+ *raid = (struct gprs_ra_id){
+ .mcc = bts->network->plmn.mcc,
+ .mnc = bts->network->plmn.mnc,
+ .mnc_3_digits = bts->network->plmn.mnc_3_digits,
+ .lac = bts->location_area_code,
+ .rac = bts->gprs.rac,
+ };
}
-int gsm48_ra_id_by_bts(uint8_t *buf, struct gsm_bts *bts)
+void gsm48_ra_id_by_bts(struct gsm48_ra_id *buf, struct gsm_bts *bts)
{
struct gprs_ra_id raid;
gprs_ra_id_by_bts(&raid, bts);
-
- return gsm48_construct_ra(buf, &raid);
+ gsm48_encode_ra(buf, &raid);
}
int gsm_parse_reg(void *ctx, regex_t *reg, char **str, int argc, const char **argv)
diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c
index 2696273..75fe0b0 100644
--- a/openbsc/src/libcommon/gsm_data_shared.c
+++ b/openbsc/src/libcommon/gsm_data_shared.c
@@ -30,10 +30,24 @@
#include <osmocom/core/talloc.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/abis_nm.h>
-#include <osmocom/core/statistics.h>
+#include <osmocom/core/counter.h>
+#include <osmocom/core/stats.h>
#include <openbsc/gsm_data.h>
+static const struct osmo_stat_item_desc bts_stat_desc[] = {
+ { "chanloadavg", "Channel load average.", "%", 16, 0 },
+ { "T3122", "T3122 IMMEDIATE ASSIGNMENT REJECT wait indicator.", "s", 16, GSM_T3122_DEFAULT },
+};
+
+static const struct osmo_stat_item_group_desc bts_statg_desc = {
+ .group_name_prefix = "bts",
+ .group_description = "base transceiver station",
+ .class_id = OSMO_STATS_CLASS_GLOBAL,
+ .num_items = ARRAY_SIZE(bts_stat_desc),
+ .item_desc = bts_stat_desc,
+};
+
void gsm_abis_mo_reset(struct gsm_abis_mo *mo)
{
mo->nm_state.operational = NM_OPSTATE_NULL;
@@ -347,9 +361,12 @@ struct gsm_bts *gsm_bts_alloc(void *ctx, uint8_t bts_num)
memcpy(&bts->gprs.cell.rlc_cfg, &rlc_cfg_default,
sizeof(bts->gprs.cell.rlc_cfg));
+ bts->bts_statg = osmo_stat_item_group_alloc(bts, &bts_statg_desc, 0);
+
/* create our primary TRX */
bts->c0 = gsm_bts_trx_alloc(bts);
if (!bts->c0) {
+ osmo_stat_item_group_free(bts->bts_statg);
talloc_free(bts);
return NULL;
}
@@ -364,6 +381,11 @@ struct gsm_bts *gsm_bts_alloc(void *ctx, uint8_t bts_num)
/* si handling */
bts->bcch_change_mark = 1;
+ bts->chan_load_avg = 0;
+
+ /* timer overrides */
+ bts->T3122 = 0; /* not overriden by default */
+
return bts;
}
diff --git a/openbsc/src/libiu/iu.c b/openbsc/src/libiu/iu.c
index 8ba6fa4..b4e7ac8 100644
--- a/openbsc/src/libiu/iu.c
+++ b/openbsc/src/libiu/iu.c
@@ -57,8 +57,7 @@
* PLMN identity is a BCD representation of the MCC and MNC.
* See iu_grnc_id_parse(). */
struct iu_grnc_id {
- uint16_t mcc;
- uint16_t mnc;
+ struct osmo_plmn_id plmn;
uint16_t rnc_id;
};
@@ -265,8 +264,7 @@ static int iu_grnc_id_parse(struct iu_grnc_id *dst,
" should be 3, is %d\n", src->pLMNidentity.size);
return -1;
}
- gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0],
- &dst->mcc, &dst->mnc);
+ osmo_plmn_from_bcd(&src->pLMNidentity.buf[0], &dst->plmn);
dst->rnc_id = (uint16_t)src->rNC_ID;
return 0;
}
diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c
index abce6e4..799d998 100644
--- a/openbsc/src/libmgcp/mgcp_network.c
+++ b/openbsc/src/libmgcp/mgcp_network.c
@@ -580,6 +580,36 @@ static int mgcp_send_transcoder(struct mgcp_rtp_end *end,
return rc;
}
+void mgcp_dejitter_udp_send(struct msgb *msg, void *data)
+{
+ struct mgcp_rtp_end *rtp_end = (struct mgcp_rtp_end *) data;
+
+ int rc = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr,
+ rtp_end->rtp_port, (char*) msg->data, msg->len);
+ if (rc != msg->len)
+ LOGP(DMGCP, LOGL_ERROR,
+ "Failed to send data after jitter buffer: %d\n", rc);
+ msgb_free(msg);
+}
+
+static int enqueue_dejitter(struct osmo_jibuf *jb, struct mgcp_rtp_end *rtp_end, char *buf, int len)
+{
+ struct msgb *msg;
+ msg = msgb_alloc(len, "mgcp-jibuf");
+ if (!msg)
+ return -1;
+
+ memcpy(msg->data, buf, len);
+ msgb_put(msg, len);
+
+ if (osmo_jibuf_enqueue(jb, msg) < 0) {
+ rtp_end->dropped_packets += 1;
+ msgb_free(msg);
+ }
+
+ return len;
+}
+
int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
struct sockaddr_in *addr, char *buf, int rc)
{
@@ -587,6 +617,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
struct mgcp_rtp_end *rtp_end;
struct mgcp_rtp_state *rtp_state;
int tap_idx;
+ struct osmo_jibuf *jb;
/* For loop toggle the destination and then dispatch. */
if (tcfg->audio_loop)
@@ -600,10 +631,12 @@ int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
rtp_end = &endp->net_end;
rtp_state = &endp->bts_state;
tap_idx = MGCP_TAP_NET_OUT;
+ jb = endp->bts_jb;
} else {
rtp_end = &endp->bts_end;
rtp_state = &endp->net_state;
tap_idx = MGCP_TAP_BTS_OUT;
+ jb = NULL;
}
if (!rtp_end->output_enabled)
@@ -621,9 +654,12 @@ int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, len);
forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx],
buf, len);
- rc = mgcp_udp_send(rtp_end->rtp.fd,
- &rtp_end->addr,
- rtp_end->rtp_port, buf, len);
+ if (jb)
+ rc = enqueue_dejitter(jb, rtp_end, buf, len);
+ else
+ rc = mgcp_udp_send(rtp_end->rtp.fd,
+ &rtp_end->addr,
+ rtp_end->rtp_port, buf, len);
if (rc <= 0)
return rc;
diff --git a/openbsc/src/libmgcp/mgcp_osmux.c b/openbsc/src/libmgcp/mgcp_osmux.c
index c52984b..69124d2 100644
--- a/openbsc/src/libmgcp/mgcp_osmux.c
+++ b/openbsc/src/libmgcp/mgcp_osmux.c
@@ -267,7 +267,6 @@ int osmux_read_from_bsc_nat_cb(struct osmo_fd *ofd, unsigned int what)
{
struct msgb *msg;
struct osmux_hdr *osmuxh;
- struct llist_head list;
struct sockaddr_in addr;
struct mgcp_config *cfg = ofd->data;
uint32_t rem;
@@ -297,8 +296,7 @@ int osmux_read_from_bsc_nat_cb(struct osmo_fd *ofd, unsigned int what)
endp->osmux.stats.chunks++;
rem = msg->len;
- osmux_xfrm_output(osmuxh, &endp->osmux.out, &list);
- osmux_tx_sched(&list, scheduled_tx_bts_cb, endp);
+ osmux_xfrm_output_sched(&endp->osmux.out, osmuxh);
}
out:
msgb_free(msg);
@@ -359,7 +357,6 @@ int osmux_read_from_bsc_cb(struct osmo_fd *ofd, unsigned int what)
{
struct msgb *msg;
struct osmux_hdr *osmuxh;
- struct llist_head list;
struct sockaddr_in addr;
struct mgcp_config *cfg = ofd->data;
uint32_t rem;
@@ -389,8 +386,7 @@ int osmux_read_from_bsc_cb(struct osmo_fd *ofd, unsigned int what)
endp->osmux.stats.chunks++;
rem = msg->len;
- osmux_xfrm_output(osmuxh, &endp->osmux.out, &list);
- osmux_tx_sched(&list, scheduled_tx_net_cb, endp);
+ osmux_xfrm_output_sched(&endp->osmux.out, osmuxh);
}
out:
msgb_free(msg);
@@ -470,9 +466,13 @@ int osmux_enable_endpoint(struct mgcp_endpoint *endp, struct in_addr *addr, uint
switch (endp->cfg->role) {
case MGCP_BSC_NAT:
endp->type = MGCP_OSMUX_BSC_NAT;
+ osmux_xfrm_output_set_tx_cb(&endp->osmux.out,
+ scheduled_tx_net_cb, endp);
break;
case MGCP_BSC:
endp->type = MGCP_OSMUX_BSC;
+ osmux_xfrm_output_set_tx_cb(&endp->osmux.out,
+ scheduled_tx_bts_cb, endp);
break;
}
endp->osmux.state = OSMUX_STATE_ENABLED;
@@ -484,6 +484,11 @@ void osmux_disable_endpoint(struct mgcp_endpoint *endp)
{
LOGP(DMGCP, LOGL_INFO, "Releasing endpoint %u using Osmux CID %u\n",
ENDPOINT_NUMBER(endp), endp->osmux.cid);
+
+ /* We are closing, we don't need pending RTP packets to be transmitted */
+ osmux_xfrm_output_set_tx_cb(&endp->osmux.out, NULL, NULL);
+ osmux_xfrm_output_flush(&endp->osmux.out);
+
osmux_xfrm_input_close_circuit(endp->osmux.in, endp->osmux.cid);
endp->osmux.state = OSMUX_STATE_DISABLED;
endp->osmux.cid = -1;
diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c
index 7cc6256..84dbc1f 100644
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ b/openbsc/src/libmgcp/mgcp_protocol.c
@@ -827,6 +827,12 @@ mgcp_header_done:
goto error2;
}
+ /* Apply Jiter buffer settings for this endpoint, they can be overriden by CRCX policy later */
+ endp->bts_use_jibuf = endp->cfg->bts_use_jibuf;
+ endp->bts_jitter_delay_min = endp->cfg->bts_jitter_delay_min;
+ endp->bts_jitter_delay_max = endp->cfg->bts_jitter_delay_max;
+
+
endp->allocated = 1;
/* set up RTP media parameters */
@@ -862,6 +868,13 @@ mgcp_header_done:
case MGCP_POLICY_DEFER:
/* stop processing */
create_transcoder(endp);
+ /* Set up jitter buffer if required after policy has updated jibuf endp values */
+ if (endp->bts_use_jibuf) {
+ endp->bts_jb = osmo_jibuf_alloc(tcfg->endpoints);
+ osmo_jibuf_set_min_delay(endp->bts_jb, endp->bts_jitter_delay_min);
+ osmo_jibuf_set_max_delay(endp->bts_jb, endp->bts_jitter_delay_max);
+ osmo_jibuf_set_dequeue_cb(endp->bts_jb, mgcp_dejitter_udp_send, &endp->net_end);
+ }
return NULL;
break;
case MGCP_POLICY_CONT:
@@ -870,6 +883,14 @@ mgcp_header_done:
}
}
+ /* Set up jitter buffer if required after policy has updated jibuf endp values */
+ if (endp->bts_use_jibuf) {
+ endp->bts_jb = osmo_jibuf_alloc(tcfg->endpoints);
+ osmo_jibuf_set_min_delay(endp->bts_jb, endp->bts_jitter_delay_min);
+ osmo_jibuf_set_max_delay(endp->bts_jb, endp->bts_jitter_delay_max);
+ osmo_jibuf_set_dequeue_cb(endp->bts_jb, mgcp_dejitter_udp_send, &endp->net_end);
+ }
+
LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
ENDPOINT_NUMBER(endp), endp->ci,
endp->net_end.local_port, endp->bts_end.local_port);
@@ -1333,6 +1354,9 @@ int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
void mgcp_release_endp(struct mgcp_endpoint *endp)
{
LOGP(DMGCP, LOGL_DEBUG, "Releasing endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
+ if (endp->bts_jb)
+ osmo_jibuf_delete(endp->bts_jb);
+ endp->bts_jb = NULL;
endp->ci = CI_UNUSED;
endp->allocated = 0;
@@ -1548,24 +1572,26 @@ void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
msg += nchars;
size -= nchars;
- /* Error Counter */
- nchars = snprintf(msg, size,
- "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
- endp->net_state.in_stream.err_ts_counter,
- endp->net_state.out_stream.err_ts_counter,
- endp->bts_state.in_stream.err_ts_counter,
- endp->bts_state.out_stream.err_ts_counter);
- if (nchars < 0 || nchars >= size)
- goto truncate;
-
- msg += nchars;
- size -= nchars;
-
- if (endp->osmux.state == OSMUX_STATE_ENABLED) {
- snprintf(msg, size,
- "\r\nX-Osmux-ST: CR=%u, BR=%u",
- endp->osmux.stats.chunks,
- endp->osmux.stats.octets);
+ if (endp->cfg->osmux != OSMUX_USAGE_OFF) {
+ /* Error Counter */
+ nchars = snprintf(msg, size,
+ "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
+ endp->net_state.in_stream.err_ts_counter,
+ endp->net_state.out_stream.err_ts_counter,
+ endp->bts_state.in_stream.err_ts_counter,
+ endp->bts_state.out_stream.err_ts_counter);
+ if (nchars < 0 || nchars >= size)
+ goto truncate;
+
+ msg += nchars;
+ size -= nchars;
+
+ if (endp->osmux.state == OSMUX_STATE_ENABLED) {
+ snprintf(msg, size,
+ "\r\nX-Osmux-ST: CR=%u, BR=%u",
+ endp->osmux.stats.chunks,
+ endp->osmux.stats.octets);
+ }
}
truncate:
msg[size - 1] = '\0';
diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c
index 7d4b2da..6d1a7ac 100644
--- a/openbsc/src/libmgcp/mgcp_vty.c
+++ b/openbsc/src/libmgcp/mgcp_vty.c
@@ -29,6 +29,7 @@
#include <openbsc/vty.h>
#include <string.h>
+#include <inttypes.h>
#define RTCP_OMIT_STR "Drop RTCP packets in both directions\n"
#define RTP_PATCH_STR "Modify RTP packet header in both directions\n"
@@ -164,6 +165,13 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, " osmux dummy %s%s",
g_cfg->osmux_dummy ? "on" : "off", VTY_NEWLINE);
}
+ if (g_cfg->bts_use_jibuf)
+ vty_out(vty, " bts-jitter-buffer%s", VTY_NEWLINE);
+ if (g_cfg->bts_jitter_delay_min)
+ vty_out(vty, " bts-jitter-delay-min %"PRIu32"%s", g_cfg->bts_jitter_delay_min, VTY_NEWLINE);
+ if (g_cfg->bts_jitter_delay_max)
+ vty_out(vty, " bts-jitter-delay-max %"PRIu32"%s", g_cfg->bts_jitter_delay_max, VTY_NEWLINE);
+
return CMD_SUCCESS;
}
@@ -241,6 +249,11 @@ DEFUN(show_mcgp, show_mgcp_cmd,
if (g_cfg->osmux)
vty_out(vty, "Osmux used CID: %d%s", osmux_used_cid(), VTY_NEWLINE);
+ vty_out(vty, "Jitter Buffer by default on Uplink : %s%s",
+ g_cfg->bts_use_jibuf ? "on" : "off", VTY_NEWLINE);
+ if (g_cfg->bts_use_jibuf)
+ vty_out(vty, "Jitter Buffer delays: min=%"PRIu32" max=%"PRIu32"%s",
+ g_cfg->bts_jitter_delay_min, g_cfg->bts_jitter_delay_max, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -1333,6 +1346,63 @@ DEFUN(cfg_mgcp_osmux_dummy,
return CMD_SUCCESS;
}
+#define DEJITTER_STR "Uplink Jitter Buffer"
+DEFUN(cfg_mgcp_bts_use_jibuf,
+ cfg_mgcp_bts_use_jibuf_cmd,
+ "bts-jitter-buffer",
+ DEJITTER_STR "\n")
+{
+ g_cfg->bts_use_jibuf = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_no_bts_use_jibuf,
+ cfg_mgcp_no_bts_use_jibuf_cmd,
+ "no bts-jitter-buffer",
+ NO_STR DEJITTER_STR "\n")
+{
+ g_cfg->bts_use_jibuf = false;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_bts_jitter_delay_min,
+ cfg_mgcp_bts_jitter_delay_min_cmd,
+ "bts-jitter-buffer-delay-min <1-65535>",
+ DEJITTER_STR " Minimum Delay in ms\n" "Minimum Delay in ms\n")
+{
+ g_cfg->bts_jitter_delay_min = atoi(argv[0]);
+ if (!g_cfg->bts_jitter_delay_min) {
+ vty_out(vty, "bts-jitter-buffer-delay-min cannot be zero.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (g_cfg->bts_jitter_delay_min && g_cfg->bts_jitter_delay_max &&
+ g_cfg->bts_jitter_delay_min > g_cfg->bts_jitter_delay_max) {
+ vty_out(vty, "bts-jitter-buffer-delay-min cannot be bigger than " \
+ "bts-jitter-buffer-delay-max.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_bts_jitter_delay_max,
+ cfg_mgcp_bts_jitter_delay_max_cmd,
+ "bts-jitter-buffer-delay-max <1-65535>",
+ DEJITTER_STR " Maximum Delay in ms\n" "Maximum Delay in ms\n")
+{
+ g_cfg->bts_jitter_delay_max = atoi(argv[0]);
+ if (!g_cfg->bts_jitter_delay_max) {
+ vty_out(vty, "bts-jitter-buffer-delay-max cannot be zero.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (g_cfg->bts_jitter_delay_min && g_cfg->bts_jitter_delay_max &&
+ g_cfg->bts_jitter_delay_min > g_cfg->bts_jitter_delay_max) {
+ vty_out(vty, "bts-jitter-buffer-delay-max cannot be smaller than " \
+ "bts-jitter-buffer-delay-min.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
int mgcp_vty_init(void)
{
install_element_ve(&show_mgcp_cmd);
@@ -1345,7 +1415,6 @@ int mgcp_vty_init(void)
install_element(CONFIG_NODE, &cfg_mgcp_cmd);
install_node(&mgcp_node, config_write_mgcp);
- vty_install_default(MGCP_NODE);
install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd);
install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd);
install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd);
@@ -1400,11 +1469,14 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_bts_use_jibuf_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_no_bts_use_jibuf_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_bts_jitter_delay_min_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_bts_jitter_delay_max_cmd);
install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
install_node(&trunk_node, config_write_trunk);
- vty_install_default(TRUNK_NODE);
install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_cmd);
install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_once_cmd);
install_element(TRUNK_NODE, &cfg_trunk_no_rtp_keepalive_cmd);
diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am
index c219a35..f746f82 100644
--- a/openbsc/src/libmsc/Makefile.am
+++ b/openbsc/src/libmsc/Makefile.am
@@ -10,7 +10,6 @@ AM_CFLAGS = \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(COVERAGE_CFLAGS) \
- $(LIBCRYPTO_CFLAGS) \
$(LIBSMPP34_CFLAGS) \
$(NULL)
diff --git a/openbsc/src/libmsc/auth.c b/openbsc/src/libmsc/auth.c
index 19def1e..85477a3 100644
--- a/openbsc/src/libmsc/auth.c
+++ b/openbsc/src/libmsc/auth.c
@@ -25,11 +25,10 @@
#include <openbsc/auth.h>
#include <openbsc/gsm_data.h>
+#include <osmocom/gsm/comp128v23.h>
#include <osmocom/gsm/comp128.h>
#include <osmocom/core/utils.h>
-#include <openssl/rand.h>
-
#include <stdlib.h>
const struct value_string auth_action_names[] = {
@@ -62,7 +61,8 @@ _use_xor(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple)
}
static int
-_use_comp128_v1(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple)
+_use_comp128(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple,
+ enum gsm_auth_algo algo)
{
if (ainfo->a3a8_ki_len != A38_COMP128_KEY_LEN) {
LOGP(DMM, LOGL_ERROR, "Invalid COMP128v1 key (len=%d) %s\n",
@@ -71,7 +71,23 @@ _use_comp128_v1(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple)
return -1;
}
- comp128(ainfo->a3a8_ki, atuple->vec.rand, atuple->vec.sres, atuple->vec.kc);
+ switch (algo) {
+ case AUTH_ALGO_COMP128v1:
+ comp128(ainfo->a3a8_ki, atuple->vec.rand,
+ atuple->vec.sres, atuple->vec.kc);
+ break;
+ case AUTH_ALGO_COMP128v2:
+ comp128v2(ainfo->a3a8_ki, atuple->vec.rand,
+ atuple->vec.sres, atuple->vec.kc);
+ break;
+ case AUTH_ALGO_COMP128v3:
+ comp128v3(ainfo->a3a8_ki, atuple->vec.rand,
+ atuple->vec.sres, atuple->vec.kc);
+ break;
+ default:
+ /* Unsupported version */
+ return -ENOTSUP;
+ }
return 0;
}
@@ -123,8 +139,10 @@ int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
}
atuple->use_count = 1;
- if (RAND_bytes(atuple->vec.rand, sizeof(atuple->vec.rand)) != 1) {
- LOGP(DMM, LOGL_NOTICE, "RAND_bytes failed, can't generate new auth tuple\n");
+ rc = osmo_get_rand_id(atuple->vec.rand, sizeof(atuple->vec.rand));
+ if (rc < 0) {
+ LOGP(DMM, LOGL_NOTICE, "osmo_get_rand_id failed, can't generate new auth tuple: %s\n",
+ strerror(-rc));
return AUTH_ERROR;
}
@@ -139,7 +157,9 @@ int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
break;
case AUTH_ALGO_COMP128v1:
- if (_use_comp128_v1(&ainfo, atuple))
+ case AUTH_ALGO_COMP128v2:
+ case AUTH_ALGO_COMP128v3:
+ if (_use_comp128(&ainfo, atuple, ainfo.auth_algo))
return AUTH_NOT_AVAIL;
break;
diff --git a/openbsc/src/libmsc/ctrl_commands.c b/openbsc/src/libmsc/ctrl_commands.c
index c99dde4..8e4e8b6 100644
--- a/openbsc/src/libmsc/ctrl_commands.c
+++ b/openbsc/src/libmsc/ctrl_commands.c
@@ -41,6 +41,10 @@ static bool alg_supported(const char *alg)
return true;
if (strcasecmp(alg, "comp128v1") == 0)
return true;
+ if (strcasecmp(alg, "comp128v2") == 0)
+ return true;
+ if (strcasecmp(alg, "comp128v3") == 0)
+ return true;
return false;
}
@@ -118,6 +122,10 @@ static int set_subscriber_modify(struct ctrl_cmd *cmd, void *data)
ainfo.auth_algo = AUTH_ALGO_XOR;
else if (strcasecmp(alg, "comp128v1") == 0)
ainfo.auth_algo = AUTH_ALGO_COMP128v1;
+ else if (strcasecmp(alg, "comp128v2") == 0)
+ ainfo.auth_algo = AUTH_ALGO_COMP128v2;
+ else if (strcasecmp(alg, "comp128v3") == 0)
+ ainfo.auth_algo = AUTH_ALGO_COMP128v3;
rc = osmo_hexparse(ki, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki));
if (rc < 0) {
diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c
index 4ba12ca..0b61b4f 100644
--- a/openbsc/src/libmsc/db.c
+++ b/openbsc/src/libmsc/db.c
@@ -41,8 +41,6 @@
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/utils.h>
-#include <openssl/rand.h>
-
/* Semi-Private-Interface (SPI) for the subscriber code */
void subscr_direct_free(struct gsm_subscriber *subscr);
@@ -183,6 +181,13 @@ static const char *create_stmts[] = {
")",
};
+static inline int next_row(dbi_result result)
+{
+ if (!dbi_result_has_next_row(result))
+ return 0;
+ return dbi_result_next_row(result);
+}
+
void db_error_func(dbi_conn conn, void *data)
{
const char *msg;
@@ -310,7 +315,7 @@ static int update_db_revision_3(void)
"Failed fetch messages from the old SMS table (upgrade from rev 3).\n");
goto rollback;
}
- while (dbi_result_next_row(result)) {
+ while (next_row(result)) {
sms = sms_from_result_v3(result);
if (db_sms_store(sms) != 0) {
LOGP(DDB, LOGL_ERROR, "Failed to store message to the new SMS table(upgrade from rev 3).\n");
@@ -456,7 +461,7 @@ static int update_db_revision_4(void)
"Failed fetch messages from the old SMS table (upgrade from rev 4).\n");
goto rollback;
}
- while (dbi_result_next_row(result)) {
+ while (next_row(result)) {
sms = sms_from_result_v4(result);
if (db_sms_store(sms) != 0) {
LOGP(DDB, LOGL_ERROR, "Failed to store message to the new SMS table(upgrade from rev 4).\n");
@@ -532,7 +537,7 @@ static int check_db_revision(void)
if (!result)
return -EINVAL;
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
return -EINVAL;
}
@@ -726,7 +731,7 @@ static int get_equipment_by_subscr(struct gsm_subscriber *subscr)
if (!result)
return -EIO;
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
return -ENOENT;
}
@@ -774,7 +779,7 @@ int db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
if (!result)
return -EIO;
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
return -ENOENT;
}
@@ -860,7 +865,7 @@ int db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
if (!result)
return -EIO;
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
return -ENOENT;
}
@@ -1050,7 +1055,7 @@ struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field,
LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber.\n");
return NULL;
}
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
DEBUGP(DDB, "Failed to find the Subscriber. '%u' '%s'\n",
field, id);
dbi_result_free(result);
@@ -1086,7 +1091,7 @@ int db_subscriber_update(struct gsm_subscriber *subscr)
LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber: %llu\n", subscr->id);
return -EIO;
}
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
DEBUGP(DDB, "Failed to find the Subscriber. %llu\n",
subscr->id);
dbi_result_free(result);
@@ -1279,7 +1284,7 @@ int db_subscriber_list_active(void (*cb)(struct gsm_subscriber*,void*), void *cl
return -1;
}
- while (dbi_result_next_row(result)) {
+ while (next_row(result)) {
struct gsm_subscriber *subscr;
subscr = subscr_alloc();
@@ -1357,7 +1362,7 @@ int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsi
return -EIO;
}
- while (dbi_result_next_row(result))
+ while (next_row(result))
callback(priv, dbi_result_get_ulonglong(result, "id"));
dbi_result_free(result);
@@ -1371,8 +1376,9 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber)
char *tmsi_quoted;
for (;;) {
- if (RAND_bytes((uint8_t *) &subscriber->tmsi, sizeof(subscriber->tmsi)) != 1) {
- LOGP(DDB, LOGL_ERROR, "RAND_bytes failed\n");
+ int rc = osmo_get_rand_id((uint8_t *) &subscriber->tmsi, sizeof(subscriber->tmsi));
+ if (rc < 0) {
+ LOGP(DDB, LOGL_ERROR, "osmo_get_rand_id() failed: %s\n", strerror(-rc));
return 1;
}
if (subscriber->tmsi == GSM_RESERVED_TMSI)
@@ -1396,7 +1402,7 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber)
dbi_result_free(result);
continue;
}
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
DEBUGP(DDB, "Allocated TMSI %u for IMSI %s.\n",
subscriber->tmsi, subscriber->imsi);
@@ -1429,7 +1435,7 @@ int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber, uint64_t smin,
dbi_result_free(result);
continue;
}
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
break;
}
@@ -1451,8 +1457,9 @@ int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t *token
uint32_t try;
for (;;) {
- if (RAND_bytes((uint8_t *) &try, sizeof(try)) != 1) {
- LOGP(DDB, LOGL_ERROR, "RAND_bytes failed\n");
+ int rc = osmo_get_rand_id((uint8_t *) &try, sizeof(try));
+ if (rc < 0) {
+ LOGP(DDB, LOGL_ERROR, "osmo_get_rand_id() failed: %s\n", strerror(-rc));
return 1;
}
if (!try) /* 0 is an invalid token */
@@ -1470,7 +1477,7 @@ int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t *token
dbi_result_free(result);
continue;
}
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
break;
}
@@ -1530,7 +1537,7 @@ int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM230
LOGP(DDB, LOGL_ERROR, "Failed to query Equipment by IMEI.\n");
return 1;
}
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
LOGP(DDB, LOGL_ERROR, "Failed to find the Equipment.\n");
dbi_result_free(result);
return 1;
@@ -1686,7 +1693,7 @@ struct gsm_sms *db_sms_get(struct gsm_network *net, unsigned long long id)
if (!result)
return NULL;
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
return NULL;
}
@@ -1715,7 +1722,7 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long mi
if (!result)
return NULL;
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
return NULL;
}
@@ -1745,7 +1752,7 @@ struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net,
if (!result)
return NULL;
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
return NULL;
}
@@ -1774,7 +1781,7 @@ struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr)
if (!result)
return NULL;
- if (!dbi_result_next_row(result)) {
+ if (!next_row(result)) {
dbi_result_free(result);
return NULL;
}
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 9d19025..006de7f 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -82,12 +82,6 @@ static int gsm48_tx_simple(struct gsm_subscriber_connection *conn,
static void schedule_reject(struct gsm_subscriber_connection *conn);
static void release_anchor(struct gsm_subscriber_connection *conn);
-struct gsm_lai {
- uint16_t mcc;
- uint16_t mnc;
- uint16_t lac;
-};
-
static int apply_codec_restrictions(struct gsm_bts *bts,
struct gsm_mncc_bearer_cap *bcap)
{
@@ -512,9 +506,7 @@ static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn)
gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
- gsm48_generate_lai(lai, conn->network->country_code,
- conn->network->network_code,
- conn->bts->location_area_code);
+ gsm48_generate_lai2(lai, bts_lai(conn->bts));
if (conn->subscr->tmsi == GSM_RESERVED_TMSI) {
uint8_t mi[10];
diff --git a/openbsc/src/libmsc/smpp_smsc.c b/openbsc/src/libmsc/smpp_smsc.c
index 83c29f6..e4acd3a 100644
--- a/openbsc/src/libmsc/smpp_smsc.c
+++ b/openbsc/src/libmsc/smpp_smsc.c
@@ -972,14 +972,19 @@ struct smsc *smpp_smsc_alloc_init(void *ctx)
/*! \brief Set the SMPP address and port without binding. */
int smpp_smsc_conf(struct smsc *smsc, const char *bind_addr, uint16_t port)
{
+ smsc->listen_port = port;
+
+ /* Avoid use-after-free if bind_addr == smsc->bind_addr */
+ if (smsc->bind_addr == bind_addr)
+ return 0;
+
talloc_free((void*)smsc->bind_addr);
smsc->bind_addr = NULL;
if (bind_addr) {
- smsc->bind_addr = talloc_strdup(smsc, bind_addr);
+ smsc->bind_addr = bind_addr ? talloc_strdup(smsc, bind_addr) : NULL;
if (!smsc->bind_addr)
return -ENOMEM;
}
- smsc->listen_port = port;
return 0;
}
diff --git a/openbsc/src/libmsc/smpp_vty.c b/openbsc/src/libmsc/smpp_vty.c
index 13467f1..0a84358 100644
--- a/openbsc/src/libmsc/smpp_vty.c
+++ b/openbsc/src/libmsc/smpp_vty.c
@@ -579,7 +579,6 @@ static int config_write_esme(struct vty *v)
int smpp_vty_init(void)
{
install_node(&smpp_node, config_write_smpp);
- vty_install_default(SMPP_NODE);
install_element(CONFIG_NODE, &cfg_smpp_cmd);
install_element(SMPP_NODE, &cfg_smpp_first_cmd);
@@ -592,7 +591,6 @@ int smpp_vty_init(void)
install_element(SMPP_NODE, &cfg_no_esme_cmd);
install_node(&esme_node, config_write_esme);
- vty_install_default(SMPP_ESME_NODE);
install_element(SMPP_ESME_NODE, &cfg_esme_passwd_cmd);
install_element(SMPP_ESME_NODE, &cfg_esme_no_passwd_cmd);
install_element(SMPP_ESME_NODE, &cfg_esme_route_pfx_cmd);
diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c
index f12c1f2..488e813 100644
--- a/openbsc/src/libmsc/ussd.c
+++ b/openbsc/src/libmsc/ussd.c
@@ -37,8 +37,16 @@
/* Declarations of USSD strings to be recognised */
const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
-/* Forward declarations of network-specific handler functions */
-static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req);
+/* A network-specific handler function */
+static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req)
+{
+ char *own_number = conn->subscr->extension;
+ char response_string[GSM_EXTENSION_LENGTH + 20];
+
+ /* Need trailing CR as EOT character */
+ snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
+ return gsm0480_send_ussd_response(conn, msg, response_string, req);
+}
/* Entrypoint - handler function common to all mobile-originated USSDs */
@@ -82,14 +90,3 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
msc_release_connection(conn);
return rc;
}
-
-/* A network-specific handler function */
-static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req)
-{
- char *own_number = conn->subscr->extension;
- char response_string[GSM_EXTENSION_LENGTH + 20];
-
- /* Need trailing CR as EOT character */
- snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
- return gsm0480_send_ussd_response(conn, msg, response_string, req);
-}
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index f66769b..a97e1ec 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -775,11 +775,13 @@ DEFUN(ena_subscr_handover,
return CMD_SUCCESS;
}
-#define A3A8_ALG_TYPES "(none|xor|comp128v1)"
+#define A3A8_ALG_TYPES "(none|xor|comp128v1|comp128v2|comp128v3)"
#define A3A8_ALG_HELP \
"Use No A3A8 algorithm\n" \
"Use XOR algorithm\n" \
- "Use COMP128v1 algorithm\n"
+ "Use COMP128v1 algorithm\n" \
+ "Use COMP128v2 algorithm\n" \
+ "Use COMP128v3 algorithm\n"
DEFUN(ena_subscr_a3a8,
ena_subscr_a3a8_cmd,
@@ -811,6 +813,12 @@ DEFUN(ena_subscr_a3a8,
} else if (!strcasecmp(alg_str, "comp128v1")) {
ainfo.auth_algo = AUTH_ALGO_COMP128v1;
minlen = maxlen = A38_COMP128_KEY_LEN;
+ } else if (!strcasecmp(alg_str, "comp128v2")) {
+ ainfo.auth_algo = AUTH_ALGO_COMP128v2;
+ minlen = maxlen = A38_COMP128_KEY_LEN;
+ } else if (!strcasecmp(alg_str, "comp128v3")) {
+ ainfo.auth_algo = AUTH_ALGO_COMP128v3;
+ minlen = maxlen = A38_COMP128_KEY_LEN;
} else {
/* Unknown method */
subscr_put(subscr);
@@ -1282,7 +1290,6 @@ int bsc_vty_init_extra(void)
install_element(CONFIG_NODE, &cfg_mncc_int_cmd);
install_node(&mncc_int_node, config_write_mncc_int);
- vty_install_default(MNCC_INT_NODE);
install_element(MNCC_INT_NODE, &mnccint_def_codec_f_cmd);
install_element(MNCC_INT_NODE, &mnccint_def_codec_h_cmd);
install_element(MNCC_INT_NODE, &mnccint_meas_feed_cmd);
@@ -1294,7 +1301,6 @@ int bsc_vty_init_extra(void)
install_element(CONFIG_NODE, &cfg_nitb_cmd);
install_node(&nitb_node, config_write_nitb);
- vty_install_default(NITB_NODE);
install_element(NITB_NODE, &cfg_nitb_subscr_create_cmd);
install_element(NITB_NODE, &cfg_nitb_subscr_random_cmd);
install_element(NITB_NODE, &cfg_nitb_no_subscr_create_cmd);
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_api.c b/openbsc/src/osmo-bsc/osmo_bsc_api.c
index bac5e47..25d48c3 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_api.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_api.c
@@ -51,32 +51,20 @@ static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t ca
static int complete_layer3(struct gsm_subscriber_connection *conn,
struct msgb *msg, struct bsc_msc_data *msc);
-static uint16_t get_network_code_for_msc(struct bsc_msc_data *msc)
+static struct osmo_cell_global_id *cgi_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts)
{
- if (msc->core_mnc != -1)
- return msc->core_mnc;
- return msc->network->network_code;
-}
-
-static uint16_t get_country_code_for_msc(struct bsc_msc_data *msc)
-{
- if (msc->core_mcc != -1)
- return msc->core_mcc;
- return msc->network->country_code;
-}
-
-static uint16_t get_lac_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts)
-{
- if (msc->core_lac != -1)
- return msc->core_lac;
- return bts->location_area_code;
-}
+ static struct osmo_cell_global_id cgi;
+ cgi.lai.plmn = msc->network->plmn;
+ if (msc->core_plmn.mcc != GSM_MCC_MNC_INVALID)
+ cgi.lai.plmn.mcc = msc->core_plmn.mcc;
+ if (msc->core_plmn.mnc != GSM_MCC_MNC_INVALID) {
+ cgi.lai.plmn.mnc = msc->core_plmn.mnc;
+ cgi.lai.plmn.mnc_3_digits = msc->core_plmn.mnc_3_digits;
+ }
+ cgi.lai.lac = (msc->core_lac != -1) ? msc->core_lac : bts->location_area_code;
+ cgi.cell_identity = (msc->core_ci != -1) ? msc->core_ci : bts->cell_identity;
-static uint16_t get_ci_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts)
-{
- if (msc->core_ci != -1)
- return msc->core_ci;
- return bts->cell_identity;
+ return &cgi;
}
static void bsc_maybe_lu_reject(struct gsm_subscriber_connection *conn, int con_type, int cause)
@@ -239,10 +227,6 @@ static int complete_layer3(struct gsm_subscriber_connection *conn,
char *imsi = NULL;
struct timeval tv;
struct msgb *resp;
- uint16_t network_code;
- uint16_t country_code;
- uint16_t lac;
- uint16_t ci;
enum bsc_con ret;
int send_ping = msc->advanced_ping;
@@ -281,14 +265,9 @@ static int complete_layer3(struct gsm_subscriber_connection *conn,
/* check return value, if failed check msg for and send USSD */
- network_code = get_network_code_for_msc(conn->sccp_con->msc);
- country_code = get_country_code_for_msc(conn->sccp_con->msc);
- lac = get_lac_for_msc(conn->sccp_con->msc, conn->bts);
- ci = get_ci_for_msc(conn->sccp_con->msc, conn->bts);
-
bsc_scan_bts_msg(conn, msg);
- resp = gsm0808_create_layer3(msg, network_code, country_code, lac, ci);
+ resp = gsm0808_create_layer3_2(msg, cgi_for_msc(conn->sccp_con->msc, conn->bts), NULL);
if (!resp) {
LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n");
sccp_connection_free(conn->sccp_con->sccp);
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
index 100f664..26278d9 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_bssap.c
@@ -29,6 +29,7 @@
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/sccp/sccp.h>
/*
* helpers for the assignment command
@@ -96,6 +97,35 @@ static int bssmap_handle_reset_ack(struct bsc_msc_data *msc,
return 0;
}
+static int bssmap_send_reset_ack(struct bsc_msc_data *msc)
+{
+ struct msgb *resp;
+ int rc;
+
+ LOGP(DMSC, LOGL_NOTICE, "Tx RESET-ACK to MSC\n");
+
+ resp = gsm0808_create_reset_ack();
+ OSMO_ASSERT(resp);
+
+ rc = sccp_write(resp, &sccp_ssn_bssap, &sccp_ssn_bssap, 0, msc->msc_con);
+ msgb_free(resp);
+ return rc;
+}
+
+static int bssmap_handle_reset(struct bsc_msc_data *msc,
+ struct msgb *msg, unsigned int length)
+{
+ LOGP(DMSC, LOGL_NOTICE, "Rx RESET from MSC\n");
+
+ /* Instruct the BSC to close all open SCCP connections and to close all
+ * active radio channels on the BTS side as well */
+ bsc_notify_and_close_conns(msc->msc_con);
+
+ /* Inform the MSC that we have received the reset request and
+ * that we acted accordingly */
+ return bssmap_send_reset_ack(msc);
+}
+
/* GSM 08.08 ยง 3.2.1.19 */
static int bssmap_handle_paging(struct bsc_msc_data *msc,
struct msgb *msg, unsigned int payload_length)
@@ -108,6 +138,7 @@ static int bssmap_handle_paging(struct bsc_msc_data *msc,
uint8_t data_length;
const uint8_t *data;
uint8_t chan_needed = RSL_CHANNEED_ANY;
+ int rc;
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0);
@@ -169,8 +200,14 @@ static int bssmap_handle_paging(struct bsc_msc_data *msc,
subscr->tmsi = tmsi;
LOGP(DMSC, LOGL_INFO, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
- bsc_grace_paging_request(msc->network->bsc_data->rf_ctrl->policy,
+ rc = bsc_grace_paging_request(msc->network->bsc_data->rf_ctrl->policy,
subscr, chan_needed, msc);
+ if (rc <= 0) {
+ LOGP(DMSC, LOGL_ERROR, "Paging request failed (%d): IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n",
+ rc, mi_string, tmsi, tmsi, lac);
+ return -1;
+ }
+
return 0;
}
@@ -404,9 +441,16 @@ 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;
+ default:
+ LOGP(DMSC, LOGL_NOTICE, "Received unimplemented BSSMAP UDT %s\n",
+ gsm0808_bssmap_name(msg->l4h[0]));
+ break;
}
return ret;
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c b/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c
index 423ed34..54f2e0d 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c
@@ -186,10 +186,11 @@ static void generate_location_state_trap(struct gsm_bts *bts, struct bsc_msc_con
policy = osmo_bsc_rf_get_policy_name(osmo_bsc_rf_get_policy_by_bts(bts));
cmd->reply = talloc_asprintf_append(cmd->reply,
- ",%s,%s,%s,%d,%d",
+ ",%s,%s,%s,%s,%s",
oper, admin, policy,
- bts->network->country_code,
- bts->network->network_code);
+ osmo_mcc_name(bts->network->plmn.mcc),
+ osmo_mnc_name(bts->network->plmn.mnc,
+ bts->network->plmn.mnc_3_digits));
osmo_bsc_send_trap(cmd, msc_con);
talloc_free(cmd);
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_filter.c b/openbsc/src/osmo-bsc/osmo_bsc_filter.c
index 2c84b16..0c4b3e3 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_filter.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_filter.c
@@ -33,20 +33,16 @@ static void handle_lu_request(struct gsm_subscriber_connection *conn,
struct gsm48_hdr *gh;
struct gsm48_loc_upd_req *lu;
struct gsm48_loc_area_id lai;
- struct gsm_network *net;
if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) {
LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg));
return;
}
- net = conn->bts->network;
-
gh = msgb_l3(msg);
lu = (struct gsm48_loc_upd_req *) gh->data;
- gsm48_generate_lai(&lai, net->country_code, net->network_code,
- conn->bts->location_area_code);
+ gsm48_generate_lai2(&lai, bts_lai(conn->bts));
if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) {
LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n");
@@ -319,9 +315,9 @@ static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn,
static int has_core_identity(struct bsc_msc_data *msc)
{
- if (msc->core_mnc != -1)
+ if (msc->core_plmn.mnc != GSM_MCC_MNC_INVALID)
return 1;
- if (msc->core_mcc != -1)
+ if (msc->core_plmn.mcc != GSM_MCC_MNC_INVALID)
return 1;
if (msc->core_lac != -1)
return 1;
@@ -336,7 +332,6 @@ static int has_core_identity(struct bsc_msc_data *msc)
int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
struct bsc_msc_data *msc;
- struct gsm_network *net;
struct gsm48_loc_area_id *lai;
struct gsm48_hdr *gh;
uint8_t pdisc;
@@ -356,7 +351,6 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
return 0;
mtype = gsm48_hdr_msg_type(gh);
- net = conn->bts->network;
msc = conn->sccp_con->msc;
if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) {
@@ -364,9 +358,7 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) {
/* overwrite LAI in the message */
lai = (struct gsm48_loc_area_id *) &gh->data[0];
- gsm48_generate_lai(lai, net->country_code,
- net->network_code,
- conn->bts->location_area_code);
+ gsm48_generate_lai2(lai, bts_lai(conn->bts));
}
}
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_grace.c b/openbsc/src/osmo-bsc/osmo_bsc_grace.c
index 63afa20..bb2634f 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_grace.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_grace.c
@@ -37,14 +37,18 @@ int bsc_grace_allow_new_connection(struct gsm_network *network, struct gsm_bts *
static int normal_paging(struct bsc_subscr *subscr, int chan_needed,
struct bsc_msc_data *msc)
{
+ int rc, num_pages = 0;
/* we can't page by lac.. we need to page everything */
if (msc->core_lac != -1) {
struct gsm_bts *bts;
- llist_for_each_entry(bts, &msc->network->bts_list, list)
- paging_request_bts(bts, subscr, chan_needed, NULL, msc);
+ llist_for_each_entry(bts, &msc->network->bts_list, list) {
+ rc = paging_request_bts(bts, subscr, chan_needed, NULL, msc);
+ if (rc > 0)
+ num_pages += rc;
+ }
- return 0;
+ return num_pages;
}
return paging_request(msc->network, subscr, chan_needed, NULL, msc);
@@ -54,6 +58,7 @@ static int locked_paging(struct bsc_subscr *subscr, int chan_needed,
struct bsc_msc_data *msc)
{
struct gsm_bts *bts = NULL;
+ int rc, num_pages = 0;
/*
* Check if there is any BTS that is on for the given lac. Start
@@ -73,11 +78,13 @@ static int locked_paging(struct bsc_subscr *subscr, int chan_needed,
/*
* now page on this bts
*/
- paging_request_bts(bts, subscr, chan_needed, NULL, msc);
+ rc = paging_request_bts(bts, subscr, chan_needed, NULL, msc);
+ if (rc > 0)
+ num_pages += rc;
};
/* All bts are either off or in the grace period */
- return 0;
+ return num_pages;
}
/**
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_msc.c b/openbsc/src/osmo-bsc/osmo_bsc_msc.c
index 8d02624..b2f8806 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_msc.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_msc.c
@@ -570,8 +570,10 @@ struct bsc_msc_data *osmo_msc_data_alloc(struct gsm_network *net, int nr)
INIT_LLIST_HEAD(&msc_data->dests);
msc_data->ping_timeout = 20;
msc_data->pong_timeout = 5;
- msc_data->core_mnc = -1;
- msc_data->core_mcc = -1;
+ msc_data->core_plmn = (struct osmo_plmn_id){
+ .mcc = GSM_MCC_MNC_INVALID,
+ .mnc = GSM_MCC_MNC_INVALID,
+ };
msc_data->core_ci = -1;
msc_data->core_lac = -1;
msc_data->rtp_base = 4000;
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
index e242390..8388f88 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
@@ -287,7 +287,7 @@ static void bsc_notify_msc_lost(struct osmo_bsc_sccp_con *con)
bsc_send_ussd_release_complete(conn);
}
-static void bsc_notify_and_close_conns(struct bsc_msc_connection *msc_con)
+void bsc_notify_and_close_conns(struct bsc_msc_connection *msc_con)
{
struct osmo_bsc_sccp_con *con, *tmp;
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_vty.c b/openbsc/src/osmo-bsc/osmo_bsc_vty.c
index 2e2e99b..e124b31 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_vty.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_vty.c
@@ -27,6 +27,7 @@
#include <openbsc/bsc_msg_filter.h>
#include <osmocom/core/talloc.h>
+#include <osmocom/gsm/gsm48.h>
#include <osmocom/vty/logging.h>
#include <time.h>
@@ -110,12 +111,12 @@ static void write_msc(struct vty *vty, struct bsc_msc_data *msc)
if (msc->bsc_key_present)
vty_out(vty, " auth-key %s%s",
osmo_hexdump(msc->bsc_key, sizeof(msc->bsc_key)), VTY_NEWLINE);
- if (msc->core_mnc != -1)
- vty_out(vty, " core-mobile-network-code %d%s",
- msc->core_mnc, VTY_NEWLINE);
- if (msc->core_mcc != -1)
- vty_out(vty, " core-mobile-country-code %d%s",
- msc->core_mcc, VTY_NEWLINE);
+ if (msc->core_plmn.mnc != GSM_MCC_MNC_INVALID)
+ vty_out(vty, " core-mobile-network-code %s%s",
+ osmo_mnc_name(msc->core_plmn.mnc, msc->core_plmn.mnc_3_digits), VTY_NEWLINE);
+ if (msc->core_plmn.mcc != GSM_MCC_MNC_INVALID)
+ vty_out(vty, " core-mobile-country-code %s%s",
+ osmo_mcc_name(msc->core_plmn.mcc), VTY_NEWLINE);
if (msc->core_lac != -1)
vty_out(vty, " core-location-area-code %d%s",
msc->core_lac, VTY_NEWLINE);
@@ -264,7 +265,15 @@ DEFUN(cfg_net_bsc_ncc,
"Use this network code for the core network\n" "MNC value\n")
{
struct bsc_msc_data *data = bsc_msc_data(vty);
- data->core_mnc = atoi(argv[0]);
+ uint16_t mnc;
+ bool mnc_3_digits;
+
+ if (osmo_mnc_from_str(argv[0], &mnc, &mnc_3_digits)) {
+ vty_out(vty, "%% Error decoding MNC: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ data->core_plmn.mnc = mnc;
+ data->core_plmn.mnc_3_digits = mnc_3_digits;
return CMD_SUCCESS;
}
@@ -273,8 +282,13 @@ DEFUN(cfg_net_bsc_mcc,
"core-mobile-country-code <1-999>",
"Use this country code for the core network\n" "MCC value\n")
{
+ uint16_t mcc;
struct bsc_msc_data *data = bsc_msc_data(vty);
- data->core_mcc = atoi(argv[0]);
+ if (osmo_mcc_from_str(argv[0], &mcc)) {
+ vty_out(vty, "%% Error decoding MCC: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ data->core_plmn.mcc = mcc;
return CMD_SUCCESS;
}
@@ -883,7 +897,6 @@ int bsc_vty_init_extra(void)
install_element(CONFIG_NODE, &cfg_net_bsc_cmd);
install_node(&bsc_node, config_write_bsc);
- vty_install_default(BSC_NODE);
install_element(BSC_NODE, &cfg_net_bsc_mid_call_text_cmd);
install_element(BSC_NODE, &cfg_net_bsc_mid_call_timeout_cmd);
install_element(BSC_NODE, &cfg_net_rf_socket_cmd);
@@ -895,7 +908,6 @@ int bsc_vty_init_extra(void)
install_element(BSC_NODE, &cfg_bsc_no_acc_lst_name_cmd);
install_node(&msc_node, config_write_msc);
- vty_install_default(MSC_NODE);
install_element(MSC_NODE, &cfg_net_bsc_token_cmd);
install_element(MSC_NODE, &cfg_net_bsc_key_cmd);
install_element(MSC_NODE, &cfg_net_bsc_no_key_cmd);
diff --git a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c
index 4884786..8cf4e94 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_mgcp_utils.c
@@ -585,6 +585,16 @@ static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int
if (state == MGCP_ENDP_CRCX) {
struct sockaddr_in sock;
+ /* set up jitter buffer parameters */
+ if (bsc_endp->bsc->cfg->bts_use_jibuf_override)
+ mgcp_endp->bts_use_jibuf = bsc_endp->bsc->cfg->bts_use_jibuf;
+
+ if (bsc_endp->bsc->cfg->bts_jitter_delay_min_override)
+ mgcp_endp->bts_jitter_delay_min = bsc_endp->bsc->cfg->bts_jitter_delay_min;
+
+ if (bsc_endp->bsc->cfg->bts_jitter_delay_max_override)
+ mgcp_endp->bts_jitter_delay_max = bsc_endp->bsc->cfg->bts_jitter_delay_max;
+
/* Annotate the allocated Osmux CID until the bsc confirms that
* it agrees to use Osmux for this voice flow.
*/
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c
index daa066d..57b51a2 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c
@@ -74,8 +74,6 @@
#include <osmocom/abis/ipa.h>
-#include <openssl/rand.h>
-
#include "../../bscconfig.h"
#define SCCP_CLOSE_TIME 20
@@ -221,7 +219,7 @@ static void send_id_req(struct bsc_nat *nat, struct bsc_connection *bsc)
buf = v_put(buf, 0x23);
mrand = bsc->last_rand;
- if (RAND_bytes(mrand, 16) != 1)
+ if (osmo_get_rand_id(mrand, 16) < 0)
goto failed_random;
memcpy(buf, mrand, 16);
@@ -232,7 +230,7 @@ static void send_id_req(struct bsc_nat *nat, struct bsc_connection *bsc)
failed_random:
/* the timeout will trigger and close this connection */
- LOGP(DNAT, LOGL_ERROR, "Failed to read from urandom.\n");
+ LOGP(DNAT, LOGL_ERROR, "osmo_get_rand_id() failed.\n");
return;
}
@@ -938,7 +936,7 @@ void bsc_close_connection(struct bsc_connection *connection)
llist_for_each_entry_safe(cmd_entry, cmd_tmp, &connection->cmd_pending, list_entry) {
cmd_entry->cmd->type = CTRL_TYPE_ERROR;
cmd_entry->cmd->reply = "BSC closed the connection";
- ctrl_cmd_send(&cmd_entry->ccon->write_queue, cmd_entry->cmd);
+ ctrl_cmd_send(&cmd_entry->cmd->ccon->write_queue, cmd_entry->cmd);
bsc_nat_ctrl_del_pending(cmd_entry);
}
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c b/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c
index 128ea65..61ac887 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c
@@ -79,7 +79,6 @@ void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending)
{
llist_del(&pending->list_entry);
osmo_timer_del(&pending->timeout);
- talloc_free(pending->cmd);
talloc_free(pending);
}
@@ -102,7 +101,7 @@ int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg)
{
struct ctrl_cmd *cmd;
struct bsc_cmd_list *pending;
- char *var, *id;
+ char *var;
cmd = ctrl_cmd_parse(bsc, msg);
msgb_free(msg);
@@ -142,14 +141,13 @@ int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg)
/* Find the pending command */
pending = bsc_get_pending(bsc, cmd->id);
if (pending) {
- id = talloc_strdup(cmd, pending->cmd->id);
- if (!id) {
+ osmo_talloc_replace_string(cmd, &cmd->id, pending->cmd->id);
+ if (!cmd->id) {
cmd->type = CTRL_TYPE_ERROR;
cmd->reply = "OOM";
goto err;
}
- cmd->id = id;
- ctrl_cmd_send(&pending->ccon->write_queue, cmd);
+ ctrl_cmd_send(&pending->cmd->ccon->write_queue, cmd);
bsc_nat_ctrl_del_pending(pending);
} else {
/* We need to handle TRAPS here */
@@ -177,7 +175,7 @@ static void pending_timeout_cb(void *data)
LOGP(DNAT, LOGL_ERROR, "Command timed out\n");
pending->cmd->type = CTRL_TYPE_ERROR;
pending->cmd->reply = "Command timed out";
- ctrl_cmd_send(&pending->ccon->write_queue, pending->cmd);
+ ctrl_cmd_send(&pending->cmd->ccon->write_queue, pending->cmd);
bsc_nat_ctrl_del_pending(pending);
}
@@ -189,7 +187,7 @@ static void ctrl_conn_closed_cb(struct ctrl_connection *connection)
llist_for_each_entry(bsc, &g_nat->bsc_connections, list_entry) {
llist_for_each_entry_safe(pending, tmp, &bsc->cmd_pending, list_entry) {
- if (pending->ccon == connection)
+ if (pending->cmd->ccon == connection)
bsc_nat_ctrl_del_pending(pending);
}
}
@@ -220,7 +218,7 @@ static int forward_to_bsc(struct ctrl_cmd *cmd)
int ret = CTRL_CMD_HANDLED;
struct ctrl_cmd *bsc_cmd = NULL;
struct bsc_connection *bsc;
- struct bsc_cmd_list *pending;
+ struct bsc_cmd_list *pending = NULL;
unsigned int nr;
char *bsc_variable;
@@ -236,62 +234,70 @@ static int forward_to_bsc(struct ctrl_cmd *cmd)
continue;
if (!bsc->authenticated)
continue;
- if (bsc->cfg->nr == nr) {
- /* Add pending command to list */
- pending = talloc_zero(bsc, struct bsc_cmd_list);
- if (!pending) {
- cmd->reply = "OOM";
- goto err;
- }
+ if (bsc->cfg->nr != nr)
+ continue;
- pending->nat_id = get_next_free_bsc_id(bsc);
- if (pending->nat_id < 0) {
- cmd->reply = "No free ID found";
- goto err;
- }
+ /* Add pending command to list */
+ pending = talloc_zero(bsc, struct bsc_cmd_list);
+ if (!pending) {
+ cmd->reply = "OOM";
+ goto err;
+ }
- bsc_cmd = ctrl_cmd_cpy(bsc, cmd);
- if (!bsc_cmd) {
- cmd->reply = "Could not forward command";
- goto err;
- }
+ pending->nat_id = get_next_free_bsc_id(bsc);
+ if (pending->nat_id < 0) {
+ cmd->reply = "No free ID found";
+ goto err;
+ }
- talloc_free(bsc_cmd->id);
- bsc_cmd->id = talloc_asprintf(bsc_cmd, "%i", pending->nat_id);
- if (!bsc_cmd->id) {
- cmd->reply = "OOM";
- goto err;
- }
+ bsc_cmd = ctrl_cmd_cpy(bsc, cmd);
+ if (!bsc_cmd) {
+ cmd->reply = "Could not forward command";
+ goto err;
+ }
- talloc_free(bsc_cmd->variable);
- bsc_cmd->variable = talloc_strdup(bsc_cmd, bsc_variable);
- if (!bsc_cmd->variable) {
- cmd->reply = "OOM";
- goto err;
- }
+ talloc_free(bsc_cmd->id);
+ bsc_cmd->id = talloc_asprintf(bsc_cmd, "%i", pending->nat_id);
+ if (!bsc_cmd->id) {
+ cmd->reply = "OOM";
+ goto err;
+ }
- if (ctrl_cmd_send(&bsc->write_queue, bsc_cmd)) {
- cmd->reply = "Sending failed";
- goto err;
- }
- pending->ccon = cmd->ccon;
- pending->ccon->closed_cb = ctrl_conn_closed_cb;
- pending->cmd = cmd;
-
- /* Setup the timeout */
- osmo_timer_setup(&pending->timeout, pending_timeout_cb,
- pending);
- /* TODO: Make timeout configurable */
- osmo_timer_schedule(&pending->timeout, 10, 0);
- llist_add_tail(&pending->list_entry, &bsc->cmd_pending);
-
- goto done;
+ talloc_free(bsc_cmd->variable);
+ bsc_cmd->variable = talloc_strdup(bsc_cmd, bsc_variable);
+ if (!bsc_cmd->variable) {
+ cmd->reply = "OOM";
+ goto err;
}
+
+ if (ctrl_cmd_send(&bsc->write_queue, bsc_cmd)) {
+ cmd->reply = "Sending failed";
+ goto err;
+ }
+
+ /* caller owns cmd param and will destroy it after we return */
+ pending->cmd = ctrl_cmd_cpy(pending, cmd);
+ if (!pending->cmd) {
+ cmd->reply = "Could not answer command";
+ goto err;
+ }
+ cmd->ccon->closed_cb = ctrl_conn_closed_cb;
+ pending->cmd->ccon = cmd->ccon;
+
+ /* Setup the timeout */
+ osmo_timer_setup(&pending->timeout, pending_timeout_cb,
+ pending);
+ /* TODO: Make timeout configurable */
+ osmo_timer_schedule(&pending->timeout, 10, 0);
+ llist_add_tail(&pending->list_entry, &bsc->cmd_pending);
+
+ goto done;
}
/* We end up here if there's no bsc to handle our LAC */
cmd->reply = "no BSC with this nr";
err:
ret = CTRL_CMD_ERROR;
+ talloc_free(pending);
done:
talloc_free(bsc_cmd);
return ret;
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
index a11ae15..e51de53 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
@@ -40,6 +40,7 @@
#include <stdlib.h>
#include <stdbool.h>
+#include <inttypes.h>
static struct bsc_nat *_nat;
@@ -173,6 +174,12 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
vty_out(vty, " osmux only%s", VTY_NEWLINE);
break;
}
+ if (bsc->bts_use_jibuf_override)
+ vty_out(vty, " %sbts-jitter-buffer%s", bsc->bts_use_jibuf? "" : "no ", VTY_NEWLINE);
+ if (bsc->bts_jitter_delay_min_override)
+ vty_out(vty, " bts-jitter-delay-min %"PRIu32"%s", bsc->bts_jitter_delay_min, VTY_NEWLINE);
+ if (bsc->bts_jitter_delay_max_override)
+ vty_out(vty, " bts-jitter-delay-max %"PRIu32"%s", bsc->bts_jitter_delay_max, VTY_NEWLINE);
}
static int config_write_bsc(struct vty *vty)
@@ -1231,6 +1238,71 @@ DEFUN(cfg_bsc_osmux,
return CMD_SUCCESS;
}
+#define DEJITTER_STR "Uplink Jitter Buffer"
+DEFUN(cfg_bsc_bts_use_jibuf,
+ cfg_bsc_bts_use_jibuf_cmd,
+ "bts-jitter-buffer",
+ DEJITTER_STR "\n")
+{
+ struct bsc_config *conf = vty->index;
+ conf->bts_use_jibuf = true;
+ conf->bts_use_jibuf_override = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bsc_no_bts_use_jibuf,
+ cfg_bsc_no_bts_use_jibuf_cmd,
+ "no bts-jitter-buffer",
+ NO_STR DEJITTER_STR "\n")
+{
+ struct bsc_config *conf = vty->index;
+ conf->bts_use_jibuf = false;
+ conf->bts_use_jibuf_override = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bsc_bts_jitter_delay_min,
+ cfg_bsc_bts_jitter_delay_min_cmd,
+ "bts-jitter-buffer-delay-min <1-65535>",
+ DEJITTER_STR " Minimum Delay in ms\n" "Minimum Delay in ms\n")
+{
+ struct bsc_config *conf = vty->index;
+ conf->bts_jitter_delay_min = atoi(argv[0]);
+ if (!conf->bts_jitter_delay_min) {
+ vty_out(vty, "bts-jitter-buffer-delay-min cannot be zero.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (conf->bts_jitter_delay_min && conf->bts_jitter_delay_max &&
+ conf->bts_jitter_delay_min > conf->bts_jitter_delay_max) {
+ vty_out(vty, "bts-jitter-buffer-delay-min cannot be bigger than " \
+ "bts-jitter-buffer-delay-max.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ conf->bts_jitter_delay_min_override = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bsc_bts_jitter_delay_max,
+ cfg_bsc_bts_jitter_delay_max_cmd,
+ "bts-jitter-buffer-delay-max <1-65535>",
+ DEJITTER_STR " Maximum Delay in ms\n" "Maximum Delay in ms\n")
+{
+ struct bsc_config *conf = vty->index;
+ conf->bts_jitter_delay_max = atoi(argv[0]);
+ if (!conf->bts_jitter_delay_max) {
+ vty_out(vty, "bts-jitter-buffer-delay-max cannot be zero.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (conf->bts_jitter_delay_min && conf->bts_jitter_delay_max &&
+ conf->bts_jitter_delay_min > conf->bts_jitter_delay_max) {
+ vty_out(vty, "bts-jitter-buffer-delay-max cannot be smaller than " \
+ "bts-jitter-buffer-delay-min.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ conf->bts_jitter_delay_max_override = true;
+ return CMD_SUCCESS;
+}
+
int bsc_nat_vty_init(struct bsc_nat *nat)
{
_nat = nat;
@@ -1257,7 +1329,6 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
/* nat group */
install_element(CONFIG_NODE, &cfg_nat_cmd);
install_node(&nat_node, config_write_nat);
- vty_install_default(NAT_NODE);
install_element(NAT_NODE, &cfg_nat_msc_ip_cmd);
install_element(NAT_NODE, &cfg_nat_msc_port_cmd);
install_element(NAT_NODE, &cfg_nat_auth_time_cmd);
@@ -1299,14 +1370,12 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(NAT_NODE, &cfg_nat_pgroup_cmd);
install_element(NAT_NODE, &cfg_nat_no_pgroup_cmd);
install_node(&pgroup_node, config_write_pgroup);
- vty_install_default(PGROUP_NODE);
install_element(PGROUP_NODE, &cfg_pgroup_lac_cmd);
install_element(PGROUP_NODE, &cfg_pgroup_no_lac_cmd);
/* BSC subgroups */
install_element(NAT_NODE, &cfg_bsc_cmd);
install_node(&bsc_node, NULL);
- vty_install_default(NAT_BSC_NODE);
install_element(NAT_BSC_NODE, &cfg_bsc_token_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_auth_key_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_no_auth_key_cmd);
@@ -1321,6 +1390,10 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(NAT_BSC_NODE, &cfg_bsc_paging_grp_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_no_paging_grp_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_osmux_cmd);
+ install_element(NAT_BSC_NODE, &cfg_bsc_bts_use_jibuf_cmd);
+ install_element(NAT_BSC_NODE, &cfg_bsc_no_bts_use_jibuf_cmd);
+ install_element(NAT_BSC_NODE, &cfg_bsc_bts_jitter_delay_min_cmd);
+ install_element(NAT_BSC_NODE, &cfg_bsc_bts_jitter_delay_max_cmd);
mgcp_vty_init();
diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am
index ca470ac..5fec00a 100644
--- a/openbsc/tests/channel/Makefile.am
+++ b/openbsc/tests/channel/Makefile.am
@@ -23,6 +23,10 @@ channel_test_SOURCES = \
channel_test.c \
$(NULL)
+channel_test_LDFLAGS = \
+ -Wl,--wrap=paging_request \
+ $(NULL)
+
channel_test_LDADD = \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libbsc/libbsc.a \
@@ -30,6 +34,7 @@ channel_test_LDADD = \
$(top_builddir)/src/libcommon/libcommon.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
$(LIBCRYPTO_LIBS) \
-ldbi \
$(NULL)
diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c
index cf19aab..428182f 100644
--- a/openbsc/tests/channel/channel_test.c
+++ b/openbsc/tests/channel/channel_test.c
@@ -48,8 +48,10 @@ static int subscr_cb(unsigned int hook, unsigned int event, struct msgb *msg, vo
return 0;
}
-/* mock object for testing, directly invoke the cb... maybe later through the timer */
-int paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_cbfn *cbfn, void *data)
+/* override, requires '-Wl,--wrap=paging_request'.
+/ mock object for testing, directly invoke the cb... maybe later through the timer */
+int __real_paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_cbfn *cbfn, void *data);
+int __wrap_paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_cbfn *cbfn, void *data)
{
s_data = data;
s_cbfn = cbfn;
@@ -59,28 +61,23 @@ int paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_c
}
-void test_request_chan(void)
+void test_request_chan(struct gsm_network *net)
{
- struct gsm_network *network;
struct gsm_bts *bts;
printf("Testing the gsm_subscriber chan logic\n");
- /* Create a dummy network */
- network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
- if (!network)
- exit(1);
- bts = gsm_bts_alloc(network, 0);
+ bts = gsm_bts_alloc(net, 0);
bts->location_area_code = 23;
- s_conn.network = network;
+ s_conn.network = net;
/* Create a dummy subscriber */
struct gsm_subscriber *subscr = subscr_alloc();
subscr->lac = 23;
- subscr->group = network->subscr_group;
+ subscr->group = net->subscr_group;
OSMO_ASSERT(subscr->group);
- OSMO_ASSERT(subscr->group->net == network);
+ OSMO_ASSERT(subscr->group->net == net);
/* Ask for a channel... */
struct subscr_request *sr;
@@ -93,20 +90,15 @@ void test_request_chan(void)
}
-void test_bts_debug_print(void)
+void test_bts_debug_print(struct gsm_network *net)
{
- struct gsm_network *network;
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
printf("Testing the lchan printing:");
- /* Create a dummy network */
- network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
- if (!network)
- exit(1);
/* Add a BTS with some reasonanbly non-zero id */
- bts = gsm_bts_alloc(network, 45);
+ bts = gsm_bts_alloc(net, 45);
/* Add a second TRX to test on multiple TRXs */
gsm_bts_trx_alloc(bts);
@@ -154,22 +146,28 @@ void test_dyn_ts_subslots(void)
int main(int argc, char **argv)
{
+ struct gsm_network *network;
+
osmo_init_logging(&log_info);
- test_request_chan();
+ /* Create a dummy network */
+ network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
+ if (!network)
+ return EXIT_FAILURE;
+
+ test_request_chan(network);
test_dyn_ts_subslots();
- test_bts_debug_print();
+ test_bts_debug_print(network);
return EXIT_SUCCESS;
}
-void _abis_nm_sendmsg() {}
void sms_alloc() {}
void sms_free() {}
-void gsm_net_update_ctype(struct gsm_network *network) {}
void gsm48_secure_channel() {}
-void paging_request_stop() {}
void vty_out() {}
+void switch_trau_mux() {}
+void rtp_socket_free() {}
struct tlv_definition nm_att_tlvdef;
diff --git a/openbsc/tests/ctrl_test_runner.py b/openbsc/tests/ctrl_test_runner.py
index fb69027..cf83fad 100644
--- a/openbsc/tests/ctrl_test_runner.py
+++ b/openbsc/tests/ctrl_test_runner.py
@@ -375,27 +375,32 @@ class TestCtrlBSC(TestCtrlBase):
r = self.do_get('mcc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mcc')
- self.assertEquals(r['value'], '23')
+ self.assertEquals(r['value'], '023')
r = self.do_set('mcc', '023')
r = self.do_get('mcc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mcc')
- self.assertEquals(r['value'], '23')
+ self.assertEquals(r['value'], '023')
def testMnc(self):
r = self.do_set('mnc', '9')
r = self.do_get('mnc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mnc')
- self.assertEquals(r['value'], '9')
+ self.assertEquals(r['value'], '09')
r = self.do_set('mnc', '09')
r = self.do_get('mnc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mnc')
- self.assertEquals(r['value'], '9')
+ self.assertEquals(r['value'], '09')
+ r = self.do_set('mnc', '009')
+ r = self.do_get('mnc')
+ self.assertEquals(r['mtype'], 'GET_REPLY')
+ self.assertEquals(r['var'], 'mnc')
+ self.assertEquals(r['value'], '009')
def testMccMncApply(self):
# Test some invalid input
@@ -432,7 +437,7 @@ class TestCtrlBSC(TestCtrlBase):
r = self.do_get('mnc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mnc')
- self.assertEquals(r['value'], '4')
+ self.assertEquals(r['value'], '04')
r = self.do_get('mcc')
self.assertEquals(r['mtype'], 'GET_REPLY')
@@ -448,7 +453,7 @@ class TestCtrlBSC(TestCtrlBase):
r = self.do_get('mnc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mnc')
- self.assertEquals(r['value'], '3')
+ self.assertEquals(r['value'], '03')
r = self.do_get('mcc')
self.assertEquals(r['mtype'], 'GET_REPLY')
@@ -496,6 +501,16 @@ class TestCtrlNITB(TestCtrlBase):
self.assertEquals(r['var'], 'subscriber-modify-v1')
self.assertEquals(r['value'], 'OK')
+ r = self.do_set('subscriber-modify-v1', '2620345,445566,comp128v2,00112233445566778899AABBCCDDEEFF')
+ self.assertEquals(r['mtype'], 'SET_REPLY')
+ self.assertEquals(r['var'], 'subscriber-modify-v1')
+ self.assertEquals(r['value'], 'OK')
+
+ r = self.do_set('subscriber-modify-v1', '2620345,445566,comp128v3,00112233445566778899AABBCCDDEEFF')
+ self.assertEquals(r['mtype'], 'SET_REPLY')
+ self.assertEquals(r['var'], 'subscriber-modify-v1')
+ self.assertEquals(r['value'], 'OK')
+
r = self.do_set('subscriber-modify-v1', '2620345,445566,none')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'subscriber-modify-v1')
diff --git a/openbsc/tests/db/Makefile.am b/openbsc/tests/db/Makefile.am
index 0eed5cd..7099645 100644
--- a/openbsc/tests/db/Makefile.am
+++ b/openbsc/tests/db/Makefile.am
@@ -43,6 +43,5 @@ db_test_LDADD = \
$(LIBOSMOGSM_LIBS) \
$(LIBSMPP34_LIBS) \
$(LIBOSMOVTY_LIBS) \
- $(LIBCRYPTO_LIBS) \
-ldbi \
$(NULL)
diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c
index 3882f05..6f48599 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.c
+++ b/openbsc/tests/gsm0408/gsm0408_test.c
@@ -145,31 +145,37 @@ static inline void _bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t
}
}
-static inline void test_si2q_segfault(void)
+static inline struct gsm_bts *bts_init(void *ctx, struct gsm_network *net, const char *msg)
{
- struct gsm_bts *bts;
- struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
- printf("Test SI2quater UARFCN (same scrambling code and diversity):\n");
-
- if (!network)
+ struct gsm_bts *bts = gsm_bts_alloc(net, 0);
+ if (!bts) {
+ printf("BTS allocation failure in %s()\n", msg);
exit(1);
- bts = gsm_bts_alloc(network, 0);
+ }
+ printf("BTS allocation OK in %s()\n", msg);
+
+ bts->network = net;
+
+ return bts;
+}
+
+static inline void test_si2q_segfault(struct gsm_network *net)
+{
+ struct gsm_bts *bts = bts_init(tall_bsc_ctx, net, __func__);
+ printf("Test SI2quater UARFCN (same scrambling code and diversity):\n");
_bts_uarfcn_add(bts, 10564, 319, 0);
_bts_uarfcn_add(bts, 10612, 319, 0);
gen(bts, __func__);
+
+ talloc_free(bts);
}
-static inline void test_si2q_mu(void)
+static inline void test_si2q_mu(struct gsm_network *net)
{
- struct gsm_bts *bts;
- struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
+ struct gsm_bts *bts = bts_init(tall_bsc_ctx, net, __func__);
printf("Test SI2quater multiple UARFCNs:\n");
- if (!network)
- exit(1);
- bts = gsm_bts_alloc(network, 0);
-
_bts_uarfcn_add(bts, 10564, 318, 0);
_bts_uarfcn_add(bts, 10612, 319, 0);
_bts_uarfcn_add(bts, 10612, 31, 0);
@@ -177,19 +183,15 @@ static inline void test_si2q_mu(void)
_bts_uarfcn_add(bts, 10613, 64, 0);
_bts_uarfcn_add(bts, 10613, 164, 0);
_bts_uarfcn_add(bts, 10613, 14, 0);
+
+ talloc_free(bts);
}
-static inline void test_si2q_u(void)
+static inline void test_si2q_u(struct gsm_network *net)
{
- struct gsm_bts *bts;
- struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
+ struct gsm_bts *bts = bts_init(tall_bsc_ctx, net, __func__);
printf("Testing SYSINFO_TYPE_2quater UARFCN generation:\n");
- if (!network)
- exit(1);
-
- bts = gsm_bts_alloc(network, 0);
-
/* first generate invalid SI as no UARFCN added */
gen(bts, __func__);
@@ -205,19 +207,15 @@ static inline void test_si2q_u(void)
_bts_uarfcn_add(bts, 1982, 223, 1);
_bts_uarfcn_add(bts, 1982, 14, 0);
_bts_uarfcn_add(bts, 1982, 88, 0);
+
+ talloc_free(bts);
}
-static inline void test_si2q_e(void)
+static inline void test_si2q_e(struct gsm_network *net)
{
- struct gsm_bts *bts;
- struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
+ struct gsm_bts *bts = bts_init(tall_bsc_ctx, net, __func__);
printf("Testing SYSINFO_TYPE_2quater EARFCN generation:\n");
- if (!network)
- exit(1);
-
- bts = gsm_bts_alloc(network, 0);
-
bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list;
bts->si_common.si2quater_neigh_list.meas_bw = bts->si_common.data.meas_bw_list;
bts->si_common.si2quater_neigh_list.length = MAX_EARFCN_LIST;
@@ -238,19 +236,15 @@ static inline void test_si2q_e(void)
add_earfcn_b(bts, 1965, OSMO_EARFCN_MEAS_INVALID);
add_earfcn_b(bts, 1967, 4);
add_earfcn_b(bts, 1982, 3);
+
+ talloc_free(bts);
}
-static inline void test_si2q_long(void)
+static inline void test_si2q_long(struct gsm_network *net)
{
- struct gsm_bts *bts;
- struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
+ struct gsm_bts *bts = bts_init(tall_bsc_ctx, net, __func__);
printf("Testing SYSINFO_TYPE_2quater combined EARFCN & UARFCN generation:\n");
- if (!network)
- exit(1);
-
- bts = gsm_bts_alloc(network, 0);
-
bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list;
bts->si_common.si2quater_neigh_list.meas_bw = bts->si_common.data.meas_bw_list;
bts->si_common.si2quater_neigh_list.length = MAX_EARFCN_LIST;
@@ -286,6 +280,8 @@ static inline void test_si2q_long(void)
_bts_uarfcn_add(bts, 1976, 224, 1);
_bts_uarfcn_add(bts, 1976, 225, 1);
_bts_uarfcn_add(bts, 1976, 226, 1);
+
+ talloc_free(bts);
}
static void test_mi_functionality(void)
@@ -671,10 +667,10 @@ static void test_gsm411_rp_ref_wrap(void)
OSMO_ASSERT(res == 1);
}
-static void test_si_ba_ind(void)
+static void test_si_ba_ind(struct gsm_network *net)
{
- struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
- struct gsm_bts *bts = gsm_bts_alloc(network, 0);
+ struct gsm_bts *bts = bts_init(tall_bsc_ctx, net, __func__);
+
const struct gsm48_system_information_type_2 *si2 =
(struct gsm48_system_information_type_2 *) GSM_BTS_SI(bts, SYSINFO_TYPE_2);
const struct gsm48_system_information_type_2bis *si2bis =
@@ -690,7 +686,6 @@ static void test_si_ba_ind(void)
int rc;
- bts->network = network;
bts->c0->arfcn = 23;
printf("Testing if BA-IND is set as expected in SI2xxx and SI5xxx\n");
@@ -734,9 +729,17 @@ static void test_si_ba_ind(void)
int main(int argc, char **argv)
{
+ struct gsm_network *net;
+
osmo_init_logging(&log_info);
log_set_log_level(osmo_stderr_target, LOGL_INFO);
+ net = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
+ if (!net) {
+ printf("Network init failure.\n");
+ return EXIT_FAILURE;
+ }
+
test_location_area_identifier();
test_mi_functionality();
@@ -746,13 +749,13 @@ int main(int argc, char **argv)
test_range_encoding();
test_gsm411_rp_ref_wrap();
- test_si2q_segfault();
- test_si2q_e();
- test_si2q_u();
- test_si2q_mu();
- test_si2q_long();
+ test_si2q_segfault(net);
+ test_si2q_e(net);
+ test_si2q_u(net);
+ test_si2q_mu(net);
+ test_si2q_long(net);
- test_si_ba_ind();
+ test_si_ba_ind(net);
printf("Done.\n");
diff --git a/openbsc/tests/gsm0408/gsm0408_test.ok b/openbsc/tests/gsm0408/gsm0408_test.ok
index 4fff78f..1039883 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.ok
+++ b/openbsc/tests/gsm0408/gsm0408_test.ok
@@ -62,6 +62,7 @@ testing RP-Reference wrap
Allocated reference: 255
Allocated reference: 0
Allocated reference: 1
+BTS allocation OK in test_si2q_segfault()
Test SI2quater UARFCN (same scrambling code and diversity):
generating SI2quater for 0 EARFCNs and 1 UARFCNs...
generated valid SI2quater [00/00]: [23] 59 06 07 40 00 25 52 88 0a 7e 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
@@ -69,6 +70,7 @@ generating SI2quater for 0 EARFCNs and 2 UARFCNs...
generated valid SI2quater [00/00]: [23] 59 06 07 40 00 25 52 e8 0a 7f 52 88 0a 7e 0b 2b 2b 2b 2b 2b 2b 2b 2b
generating SI2quater for 0 EARFCNs and 2 UARFCNs...
generated valid SI2quater [00/00]: [23] 59 06 07 40 00 25 52 e8 0a 7f 52 88 0a 7e 0b 2b 2b 2b 2b 2b 2b 2b 2b
+BTS allocation OK in test_si2q_e()
Testing SYSINFO_TYPE_2quater EARFCN generation:
generating SI2quater for 0 EARFCNs and 0 UARFCNs...
generated invalid SI2quater [00/00]: [23] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
@@ -92,6 +94,7 @@ generated valid SI2quater [01/01]: [23] 59 06 07 42 20 04 86 59 83 d7 e0 50 0b 2
added EARFCN 1982 - generating SI2quater for 7 EARFCNs and 0 UARFCNs...
generated valid SI2quater [00/01]: [23] 59 06 07 40 20 04 86 59 83 be cc 1e 31 07 91 a8 3c ca 0f 5a 0a 03 2b
generated valid SI2quater [01/01]: [23] 59 06 07 42 20 04 86 59 83 d7 e4 1e fa c2 80 2b 2b 2b 2b 2b 2b 2b 2b
+BTS allocation OK in test_si2q_u()
Testing SYSINFO_TYPE_2quater UARFCN generation:
generating SI2quater for 0 EARFCNs and 0 UARFCNs...
generated invalid SI2quater [00/00]: [23] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
@@ -117,6 +120,7 @@ generating SI2quater for 0 EARFCNs and 10 UARFCNs...
generated valid SI2quater [00/00]: [23] 59 06 07 40 00 25 0f 7c 50 1c 3b 31 fa dd 88 85 7b c4 1c 2b 2b 2b 2b
generating SI2quater for 0 EARFCNs and 11 UARFCNs...
generated valid SI2quater [00/00]: [23] 59 06 07 40 00 25 0f 7c 58 1c 3b 25 7a ea 08 91 fb c4 1f b0 2b 2b 2b
+BTS allocation OK in test_si2q_mu()
Test SI2quater multiple UARFCNs:
generating SI2quater for 0 EARFCNs and 1 UARFCNs...
generated valid SI2quater [00/00]: [23] 59 06 07 40 00 25 52 88 0a 7c 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
@@ -134,6 +138,7 @@ generated valid SI2quater [01/01]: [23] 59 06 07 42 20 25 52 e8 28 81 df 7f fa 3
generating SI2quater for 0 EARFCNs and 7 UARFCNs...
generated valid SI2quater [00/01]: [23] 59 06 07 40 20 25 52 ea 10 81 ce a9 74 08 1f fa 54 ba 82 52 03 2b 2b
generated valid SI2quater [01/01]: [23] 59 06 07 42 20 25 52 e8 30 81 d3 7f fd b2 86 54 a2 02 9f 03 2b 2b 2b
+BTS allocation OK in test_si2q_long()
Testing SYSINFO_TYPE_2quater combined EARFCN & UARFCN generation:
generating SI2quater for 17 EARFCNs and 1 UARFCNs...
generated valid SI2quater [00/04]: [23] 59 06 07 40 80 25 0f 70 0c 1a 10 99 66 0f 04 83 c1 1c bb 2b 03 2b 2b
@@ -201,6 +206,7 @@ generated valid SI2quater [02/05]: [23] 59 06 07 44 a0 04 86 59 83 c2 ec 20 ff 6
generated valid SI2quater [03/05]: [23] 59 06 07 46 a0 04 86 59 84 21 54 21 4f 61 0a 99 08 55 b7 2e ca c1 2b
generated valid SI2quater [04/05]: [23] 59 06 07 48 a0 04 86 59 84 2b 54 21 27 61 09 59 08 4b b7 2e ca c1 2b
generated valid SI2quater [05/05]: [23] 59 06 07 4a a0 04 86 59 84 26 53 97 65 60 2b 2b 2b 2b 2b 2b 2b 2b 2b
+BTS allocation OK in test_si_ba_ind()
Testing if BA-IND is set as expected in SI2xxx and SI5xxx
SI2: 59 06 1a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
SI2bis: 59 06 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
diff --git a/openbsc/tests/mgcp/Makefile.am b/openbsc/tests/mgcp/Makefile.am
index 4b18036..33e921f 100644
--- a/openbsc/tests/mgcp/Makefile.am
+++ b/openbsc/tests/mgcp/Makefile.am
@@ -10,6 +10,7 @@ AM_CFLAGS = \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_FLAGS) \
$(LIBOSMONETIF_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) \
$(LIBOSMOSCCP_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(LIBBCG729_CFLAGS) \
diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c
index 43a453a..570a0c9 100644
--- a/openbsc/tests/mgcp/mgcp_test.c
+++ b/openbsc/tests/mgcp/mgcp_test.c
@@ -268,7 +268,9 @@ static void test_strline(void)
"C: 2\r\n"
#define DLCX_RET "250 7 OK\r\n" \
- "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n" \
+ "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
+
+ #define DLCX_RET_OSMUX DLCX_RET \
"X-Osmo-CP: EC TIS=0, TOS=0, TIR=0, TOR=0\r\n"
#define RQNT "RQNT 186908780 1@mgw MGCP 1.0\r\n" \
diff --git a/openbsc/tests/mm_auth/mm_auth_test.c b/openbsc/tests/mm_auth/mm_auth_test.c
index b8777a8..ebd122f 100644
--- a/openbsc/tests/mm_auth/mm_auth_test.c
+++ b/openbsc/tests/mm_auth/mm_auth_test.c
@@ -121,7 +121,7 @@ int auth_get_tuple_for_subscr_verbose(struct gsm_auth_tuple *atuple,
}
/* override libssl RAND_bytes() to get testable crypto results */
-int RAND_bytes(uint8_t *rand, int len)
+int osmo_get_rand_id(uint8_t *rand, size_t len)
{
memset(rand, 23, len);
return 1;
diff --git a/openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.c b/openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.c
index ec3eb2c..e34b19b 100644
--- a/openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.c
+++ b/openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.c
@@ -210,8 +210,7 @@ int main(int argc, char **argv)
bts->rach_ldavg_slots = -1;
bts->c0->arfcn = 866;
bts->cell_identity = 1337;
- bts->network->country_code = 1;
- bts->network->network_code = 1;
+ bts->network->plmn = (struct osmo_plmn_id){ .mcc=1, .mnc=1 };
bts->location_area_code = 1;
bts->gprs.rac = 0;
uint8_t attr_bts_expected[] =