diff options
author | Thorsten Alteholz <debian@alteholz.de> | 2018-07-16 23:05:59 +0200 |
---|---|---|
committer | Thorsten Alteholz <debian@alteholz.de> | 2018-07-16 23:05:59 +0200 |
commit | 6ffa57f2e1d6d9bd830a55bd9440da31f49b9a37 (patch) | |
tree | 434bcd011a3227a1231de2d04600130205c4f359 | |
parent | 85dc7be98492c3f82f8b9b40300e59a8f49fef0c (diff) |
Import Upstream version 1.1.0
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[] = |