aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--TODO-RELEASE9
-rw-r--r--configure.ac26
-rw-r--r--contrib/osmo-bsc.spec.in16
-rw-r--r--debian/changelog387
-rw-r--r--debian/control10
-rw-r--r--doc/manuals/chapters/bts-examples.adoc117
-rw-r--r--doc/manuals/chapters/control.adoc32
-rw-r--r--doc/manuals/chapters/handover_inter_bsc.dot2
-rw-r--r--doc/manuals/chapters/interf_meas.adoc72
-rw-r--r--doc/manuals/chapters/power_control.adoc67
-rw-r--r--doc/manuals/osmobsc-usermanual.adoc2
-rw-r--r--include/osmocom/bsc/Makefile.am1
-rw-r--r--include/osmocom/bsc/assignment_fsm.h2
-rw-r--r--include/osmocom/bsc/bsc_stats.h6
-rw-r--r--include/osmocom/bsc/bsc_subscriber.h2
-rw-r--r--include/osmocom/bsc/bts.h67
-rw-r--r--include/osmocom/bsc/bts_trx.h1
-rw-r--r--include/osmocom/bsc/chan_counts.h76
-rw-r--r--include/osmocom/bsc/gsm_04_08_rr.h3
-rw-r--r--include/osmocom/bsc/gsm_data.h30
-rw-r--r--include/osmocom/bsc/handover.h2
-rw-r--r--include/osmocom/bsc/lchan_fsm.h6
-rw-r--r--include/osmocom/bsc/lchan_rtp_fsm.h2
-rw-r--r--include/osmocom/bsc/lcs_loc_req.h2
-rw-r--r--include/osmocom/bsc/lcs_ta_req.h2
-rw-r--r--include/osmocom/bsc/neighbor_ident.h4
-rw-r--r--include/osmocom/bsc/timeslot_fsm.h2
-rw-r--r--m4/ax_check_compile_flag.m474
-rw-r--r--src/ipaccess/ipaccess-config.c57
-rw-r--r--src/osmo-bsc/Makefile.am2
-rw-r--r--src/osmo-bsc/abis_nm.c18
-rw-r--r--src/osmo-bsc/abis_om2000.c11
-rw-r--r--src/osmo-bsc/abis_rsl.c241
-rw-r--r--src/osmo-bsc/assignment_fsm.c20
-rw-r--r--src/osmo-bsc/bsc_ctrl_commands.c120
-rw-r--r--src/osmo-bsc/bsc_ctrl_lookup.c4
-rw-r--r--src/osmo-bsc/bsc_init.c45
-rw-r--r--src/osmo-bsc/bsc_stats.c87
-rw-r--r--src/osmo-bsc/bsc_subscr_conn_fsm.c181
-rw-r--r--src/osmo-bsc/bts.c256
-rw-r--r--src/osmo-bsc/bts_ipaccess_nanobts.c8
-rw-r--r--src/osmo-bsc/bts_trx.c48
-rw-r--r--src/osmo-bsc/bts_vty.c163
-rw-r--r--src/osmo-bsc/chan_counts.c142
-rw-r--r--src/osmo-bsc/gsm_08_08.c26
-rw-r--r--src/osmo-bsc/gsm_data.c28
-rw-r--r--src/osmo-bsc/handover_decision_2.c63
-rw-r--r--src/osmo-bsc/handover_fsm.c41
-rw-r--r--src/osmo-bsc/lchan_fsm.c28
-rw-r--r--src/osmo-bsc/lchan_rtp_fsm.c2
-rw-r--r--src/osmo-bsc/lcs_loc_req.c4
-rw-r--r--src/osmo-bsc/lcs_ta_req.c24
-rw-r--r--src/osmo-bsc/neighbor_ident.c1
-rw-r--r--src/osmo-bsc/neighbor_ident_ctrl.c713
-rw-r--r--src/osmo-bsc/neighbor_ident_vty.c69
-rw-r--r--src/osmo-bsc/net_init.c14
-rw-r--r--src/osmo-bsc/nm_bts_fsm.c18
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c31
-rw-r--r--src/osmo-bsc/osmo_bsc_ctrl.c21
-rw-r--r--src/osmo-bsc/osmo_bsc_main.c145
-rw-r--r--src/osmo-bsc/paging.c7
-rw-r--r--src/osmo-bsc/pcu_sock.c4
-rw-r--r--src/osmo-bsc/timeslot_fsm.c16
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/acch_overpower.vty88
-rwxr-xr-xtests/ctrl_test_runner.py212
-rw-r--r--tests/handover/handover_test.c4
-rw-r--r--tests/nanobts_omlattr/nanobts_omlattr_test.c2
-rw-r--r--tests/nanobts_omlattr/nanobts_omlattr_test.ok4
-rw-r--r--tests/power_ctrl.vty39
-rw-r--r--tests/timer.vty6
72 files changed, 3370 insertions, 669 deletions
diff --git a/.gitignore b/.gitignore
index e504f4cf6..0bbe4782b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ debian/*.log
*.o
*.lo
*.a
+*.la
.deps
Makefile
Makefile.in
@@ -47,7 +48,6 @@ hlr.sqlite3
src/utils/bs11_config
src/ipaccess/ipaccess-config
src/ipaccess/abisip-find
-src/ipaccess/ipaccess-firmware
src/ipaccess/ipaccess-proxy
src/utils/isdnsync
src/osmo-bsc_nat/osmo-bsc_nat
diff --git a/TODO-RELEASE b/TODO-RELEASE
index 89bc1cb9d..d0852fc9b 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -7,12 +7,3 @@
# If any interfaces have been added since the last public release: c:r:a + 1.
# If any interfaces have been removed or changed since the last public release: c:r:0.
#library what description / commit summary line
-libosmocore >1.5.1 needs osmo_bts_features_name(), osmo_bts_features_desc()
-libosmogsm >1.5.1 enum entry GSM0808_FE_IE_LAST_USED_EUTRAN_PLMN_ID
-libosmogsm >1.5.1 introduced struct needed gsm0808_old_bss_to_new_bss_info->last_eutran_plmn_id
-libosmo-mgcp-client >1.8.0 need osmo_mgcpc_ep_ci_get_remote_rtp_info()
-libosmovty >1.5.1 needs vty_read_config_filep()
-libosmosgsm >1.5.1 needs GSM_PCHAN_OSMO_DYN
-libosmocore >1.5.1 RSL_IPAC_EIE_OSMO*, struct osmo_preproc_*
-libosmocore >1.5.1 needs osmo_str_to_int()
-libosmocore >1.5.1 needs new osmo_stat_item implementation (omits FIFO size for stat item)
diff --git a/configure.ac b/configure.ac
index 195acfe80..c4eac4a95 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,11 +36,6 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
fi
PKG_PROG_PKG_CONFIG([0.20])
-dnl check for AX_CHECK_COMPILE_FLAG
-m4_ifdef([AX_CHECK_COMPILE_FLAG], [], [
- AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.])
- ])
-
dnl checks for libraries
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
@@ -51,14 +46,14 @@ AC_ARG_ENABLE([ipaccess-utils], [AS_HELP_STRING([--enable-ipaccess-utils], [Buil
AM_CONDITIONAL(BUILD_IPA_UTILS, test "x$osmo_ac_ipa_utils" = "xyes")
AC_SUBST(osmo_ac_ipa_utils)
-PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
-PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
-PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
-PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0)
-PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0)
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.6.0)
+PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.6.0)
+PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.6.0)
+PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.6.0)
+PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
-PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.4.0)
-PKG_CHECK_MODULES(LIBOSMOMGCPCLIENT, libosmo-mgcp-client >= 1.8.0)
+PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.5.0)
+PKG_CHECK_MODULES(LIBOSMOMGCPCLIENT, libosmo-mgcp-client >= 1.9.0)
dnl checks for header files
AC_HEADER_STDC
@@ -120,13 +115,6 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],
CFLAGS="$saved_CFLAGS"
AC_SUBST(SYMBOL_VISIBILITY)
-AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
-AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
-AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"])
-AX_CHECK_COMPILE_FLAG([-Wnull-dereference], [CFLAGS="$CFLAGS -Wnull-dereference"])
-AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"])
-AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"])
-
# Coverage build taken from WebKit's configure.in
AC_MSG_CHECKING([whether to enable code coverage support])
AC_ARG_ENABLE(coverage,
diff --git a/contrib/osmo-bsc.spec.in b/contrib/osmo-bsc.spec.in
index 9f7ef4862..187242c9b 100644
--- a/contrib/osmo-bsc.spec.in
+++ b/contrib/osmo-bsc.spec.in
@@ -31,15 +31,15 @@ BuildRequires: pkgconfig >= 0.20
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libcrypto) >= 0.9.5
-BuildRequires: pkgconfig(libosmo-mgcp-client) >= 1.8.0
+BuildRequires: pkgconfig(libosmo-mgcp-client) >= 1.9.0
BuildRequires: pkgconfig(libosmo-netif) >= 1.1.0
-BuildRequires: pkgconfig(libosmo-sigtran) >= 1.4.0
-BuildRequires: pkgconfig(libosmoabis) >= 1.1.0
-BuildRequires: pkgconfig(libosmocore) >= 1.5.0
-BuildRequires: pkgconfig(libosmoctrl) >= 1.5.0
-BuildRequires: pkgconfig(libosmogb) >= 1.5.0
-BuildRequires: pkgconfig(libosmogsm) >= 1.5.0
-BuildRequires: pkgconfig(libosmovty) >= 1.5.0
+BuildRequires: pkgconfig(libosmo-sigtran) >= 1.5.0
+BuildRequires: pkgconfig(libosmoabis) >= 1.2.0
+BuildRequires: pkgconfig(libosmocore) >= 1.6.0
+BuildRequires: pkgconfig(libosmoctrl) >= 1.6.0
+BuildRequires: pkgconfig(libosmogb) >= 1.6.0
+BuildRequires: pkgconfig(libosmogsm) >= 1.6.0
+BuildRequires: pkgconfig(libosmovty) >= 1.6.0
BuildRequires: pkgconfig(talloc)
%{?systemd_requires}
diff --git a/debian/changelog b/debian/changelog
index 8fc8b7618..40b509d93 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,390 @@
+osmo-bsc (1.8.0) unstable; urgency=medium
+
+ [ Harald Welte ]
+ * remove obsolete dependency on libosmo-sccp
+ * manual: Include QoS chapter and add osmo-bsc specific example
+
+ [ Javi ]
+ * Add vty command for Ericsson RBS2000 sync
+ * Add command to enable RX diversity to RBS2000
+
+ [ Oliver Smith ]
+ * stats: T3122 related: num_values 16 -> 60
+ * src/utils/meas_vis.c: fix bs_power -> bs_power_db
+ * handover_test: fix ts_str may be uninitialized
+ * bsc_ctrl_commands: fix uninitialized value (mode)
+ * Revert "Turn some compiler warnings into errors"
+
+ [ Neels Hofmeyr ]
+ * refactor handover penalty timers
+ * drop neighbor_ident_test.c
+ * fix/refactor neighbor config
+ * debug log, lchan_fsm: explain leaving wait_rll_rtp_establish state
+ * fixup for neighbor config for coverity
+ * drop unused func decl rsl_lchan_mark_broken()
+ * drop unused gsm_bts_trx->description
+ * deprecation: use osmo_bts_features_*()
+ * fix wrong ARFCNs in local-cell neighbor config
+ * update neighbor ARFCNs on startup and config changes
+ * manual: Location Services: clarify BSC side address
+ * abis_nm_ipaccess_rsl_connect(): use msgb to compose attr
+ * Lb: stop RESET FSM when sccp_user is unbound
+ * Lb: RESET FSM: never send sccp_user == NULL
+ * Lb: add missing X12 timer configurability
+ * Lb: make sure we never have missing timer configurability
+ * gsm_lchan_name_compute with ctx
+ * log: drop duplicate logging in ts_setup_lchans()
+ * comment: tweak pchan_subslots() description
+ * lchan_release(): do not release UNUSED lchan
+ * lchan_fsm: mode modify: fix missing timeouts and error transitions
+ * fix test_gsm48_multirate_config: dump the complete AMR lv buffer
+ * test_gsm48_multirate_config: rather keep 4x amr_mode
+ * assignment_fsm: fix failure log message for lchan unavailable
+ * select_codecs(): do not confuse bool 'true' with integer value 1
+ * gsm48_send_rr_ass_cmd(): rename dest_lchan to current_lchan
+ * gsm48_send_rr_ass_cmd(): rename lchan to new_lchan
+ * log: show src file,line of lchan_set_last_error
+ * add missing arg braces in LOG_LCHAN macro
+ * gscon MGCP: properly skip redundant MDCX towards MSC
+ * cosmetic: rename FOR_* to ACTIVATE_FOR_*
+ * cosmetic: rename lchan_activate_mode to lchan_activate_for
+ * lchan and assignment FSMs: make Channel Mode Modify more sane
+ * assignment_fsm: tweak error log msg for mixed modes
+ * handover_test: ack release only when lchan is still waiting
+ * hodec2: remove code dup of rxlev averaging
+ * handover_test: add bspower to meas-rep cmd
+ * add test_bs_power.ho_vty to show BS Power HO oscillation
+ * assignment_fsm: send BSSMAP response only after Assignment Request
+ * cosmetic scoping in reuse_existing_lchan()
+ * potential segfault: vty chan act: do not set AMR bits for EFR
+ * make sure channel mode and s15_s0 are updated only after an ACK
+ * remove special case from assignment_count_result()
+ * eliminate lchan->rsl_cmode
+ * move lchan->csd_mode into channel_mode_and_rate
+ * AMR config cleanup step 1: split lchan_mr_config()
+ * AMR config cleanup step 2: filter modes also for VTY
+ * AMR config cleanup step 3: generate AMR LV on msg composition
+ * handover dot charts: fix wrong transitions regarding MGW
+ * handover_test: fix naming/wording: 'handover-req' should be 'handover-cmd'
+ * assignment_fsm: tweak state transitions (prep for reassignment)
+ * assignment_fsm: allow assignment to a specific lchan
+ * vty: actually trigger Assignment for 'assignment', not HO
+ * hodec 2: do intra-cell congestion resolution by Assignment
+ * RSL link: explicitly select rsl_link based on lchan
+ * add chan_mode_to_chan_type()
+ * gsm48_lchan2chan_desc(): expose TSC as param
+ * allow explixit TSC Set and TSC on chan activ / modif / assignment
+ * VTY: dump TSC Set and TSC for each timeslot
+ * add fields to reflect nr of lchans in ts struct
+ * replace ts_*_for_each_lchan() with ts_for_n_lchans()
+ * ensure chan_mode comparisons in non-VAMOS mode
+ * lchan_fsm: introduce lchan.modify.ch_mode_rate to allow tweaking
+ * Drop duplicated arfcn_range_encode.c available in libosmocore
+ * fixup for Mode Modify TSC
+ * fix rc handling in channel_mode_from_lchan()
+ * drop unused func decl gsm_lchan_as_pchan2chan_nr()
+ * handover: apply meas report BS Power to RXLEV, fix ho oscillation
+ * change bs_power to bs_power_db
+ * meas rep logging: replace a dozen DEBUGPC() with one DEBUGP()
+ * meas rep logging: use log_check_level() to skip a logging loop
+ * fixup: pass tsc = -1 for previous default training sequence code
+ * hodec2: add handover_test cases for upgrade of TCH/H -> TCH/F
+ * cosmetic prep: hodec2: move is_upgrade_to_tchf() further up
+ * hodec2: fix is_upgrade_to_tchf() for requirement A
+ * allow mode modify when RTP stream is active
+ * implement Channel Mode Modify to VAMOS mode
+ * vty: add lchan modify '(vamos|non-vamos)' command
+ * add lchan->vamos.is_secondary flag
+ * vty-test: osmo-bsc.vty: test doc of lchan activate cmd
+ * lchan_fsm: introduce lchan.activate.ch_mode_rate to allow tweaking
+ * add missing AMR config for RTP activation after mode modify
+ * implement CHANnel ACTIVate to VAMOS mode
+ * RR Assignment for VAMOS: send TSC Set
+ * add VAMOS secondary lchans to timeslot struct
+ * update the lchan name to always reflect VAMOS shadowness
+ * rsl_lchan_lookup(): turn cbits if-cascade into a switch()
+ * rsl_lchan_lookup(): add comment explaining ts_is_capable_of_pchan()
+ * RSL chan_nr: replace OSMO_ASSERT with error handling
+ * RSL: rx and tx VAMOS Channel Number cbits for VAMOS lchans
+ * VTY: 'show lchan': show that lchan is in VAMOS mode
+ * VTY: add 'vamos-subslot' to activate a secondary lchan
+ * VTY: add lchan re-assignment command
+ * log: assignment_fsm: drop newline from assignment_fail
+ * log: assignment_fsm: tweak err msg for incompatible chan
+ * clarify bts_chan_load
+ * get_any_lchan(): reduce minor code dup
+ * cosmetic loop simplification in gsm48_multirate_config()
+ * RSL: set default TEI according to TRX number
+ * lchan_fsm: lchan_fail() strings should not have a terminating newline
+ * gsm_data.h: add comments about immutable activ/modif/assign request info
+ * hodec2: implement upgrade TCH/H -> TCH/F (without AFS bias)
+ * fixup for vamos: fix wrong cbits in rsl_lchan_lookup()
+ * vty: reassign: add missing check for valid target lchan
+ * hodec2: don't apply AFS bias to same-cell lchans
+ * rsl_data_request() check lchan pointer before access
+ * rsl_lchan_lookup: drop redundant condition
+ * rewire build_encr_info() to return errors
+ * dissolve gsm0808_cipher_mode() into bssmap_handle_cipher_mode()
+ * implement A5/4 in Ciphering Mode procedure
+ * support A5/4 in inter-BSC Handover
+ * use osmo_select_shutdown to get rid of SIGTERM sleep
+ * vty: allow 5 encryption algo entries
+ * hodec2: add test case showing low rxlev tch/h<->tch/f oscillation
+ * hodec2: add test case showing low rxqual tch/h<->tch/f oscillation
+ * handover_decision_2.c: add is_low_rxlev()
+ * hodec2: fix low rxlev tch/h<->tch/f oscillation
+ * handover_decision_2.c: add current_rxqual()
+ * hodec2: fix low rxqual tch/h<->tch/f oscillation
+ * vty: fix doc: default value for 'nri bitlen'
+ * vty: add vty doc test for 'nri null' commands
+ * hodec2: [1/2] implement automatic choice between FULL and SUBSET measurements
+ * hodec2: [2/2] implement automatic choice between FULL and SUBSET measurements
+ * hodec1: use same automatic FULL/SUBSET choice as in hodec2
+ * lchan: call reset() upon alloc
+ * RES IND: parse msg and store interference levels in lchans
+ * RES IND: add VTY: bts / channel allocator avoid-interference (0|1)
+ * RES IND: add test_resource_indication.ho_vty
+ * RES IND: pick lchan with least interference
+ * ensure trigger_ho() returns zero only when HO or AS was indeed triggered
+ * handover_test: also show when an lchan is busy
+ * switch handover penalty timers to CLOCK_MONOTONIC
+ * handover_test: add fake-time 'wait'
+ * test_penalty_timer.ho_vty: show lchan recovery
+ * handover tests: test passing of penalty timeout
+ * hodec2: add low-rxqual-assignment penalty timer (1/2)
+ * hodec2: add low-rxqual-assignment penalty timer (2/2)
+ * separate 'interference-meas level-bounds' cfg and used
+ * vty 'interference-meas level-bounds': explain duality in ordering
+ * add test_dyn_ts_favor_static_ts_as_target.ho_vty
+ * extend test_dyn_ts_favor_half_used_tch_h_as_target.ho_vty
+ * RES IND: allow empty Resource Information IE
+ * RES IND: tweak error code on missing Resource Information IE
+ * fix CM Re-Establishment Request: allocate new A conn
+ * log: fix missing newline in lchan_select.c
+ * debug log: indicate change of primary lchan on a conn
+ * vty: lchan deact: allow omitting the lchan type arg
+ * vty: improve err msg for invalid subslot nr
+ * coverity: quench null deref warning in gscon_change_primary_lchan()
+ * lchan_fsm_post_activ_ack(): return upon release
+ * introduce gsm48_lchan_and_pchan2chan_desc()
+ * error log: improve lchan lookup error msg
+ * early IMM ASS 1/n: add vty config option
+ * early IMM ASS 2/n: implement 'pre-chan-ack'
+ * early IMM ASS 3/n: implement 'pre-ts-ack'
+ * stat_item desc: add explicit indexes for clarity
+ * vty: add "msc N bssmap reset" command
+ * move BSC level stats and rate counters to new bsc_stats.[hc]
+ * add stat items bsc.0.num_msc:connected, .num_msc:total
+ * add stat_items for BTS and TRX connection stati
+ * fixup for Early IMM ASS: use proper TSC
+ * add CTRL 'rf_states' and 'bts.N.rf_states'
+ * add CTRL bts.N.trx.M.rf_locked (RW)
+ * fixup comments for 'rf_states' CTRL command
+ * fix comment in lchan_fsm.c: s/modification/activation
+ * fix TSC / TSC Set used for Handover
+ * tsc fixup: tweak condition for coverity
+ * drop obsolete comment
+ * stat: add bts.N.num_trx:total
+ * stat: add bts.N.num_trx:rsl_connected
+ * constify lchan_state_is()
+ * add chreq:successful_<reason> rate counters
+ * drop unused gsm48_tx_mm_serv_ack()
+ * for linter: s/while(0)/while (0)
+ * cosmetic tweaks on handover counting code
+ * tweak intra-bsc ho counter descriptions
+ * implement incoming_intra_bsc_ho:* rate counters
+ * refactor lchan counting
+ * add time_cc API: cumlative counter for time, reported as rate_ctr
+ * implement all_allocated:{sdcch,tch} rate counters
+ * implement all_allocated:{static_sdcch,static_tch} rate counters
+ * implement bts.N.cm_serv_rej:<cause> rate counters
+ * move time_cc to libosmocore osmo_time_cc
+
+ [ Keith ]
+ * Ignore CHANnel ReQuireD with Access Delay IE > 63
+ * Fix MEAS parsing, as Ericsson RBS reports TA shifted by 2 bits.
+ * Add vty command to manually force MS Uplink Power
+ * Implement MS Uplink Power Control Loop
+
+ [ Vadim Yanitskiy ]
+ * [hopping] vty: ensure no duplicate hopping ARFCN entries
+ * [hopping] generate_cell_chan_list(): make some pointers const
+ * [hopping] gsm48_send_rr_ass_cmd(): use Cell Channel Description from SI1
+ * [hopping] generate_ma_for_ts() returns no meaningful value
+ * abis_nm: rework warnings about unknown / not supported features
+ * abis_nm: cosmetic: use osmo_bts_feature_name()
+ * [hopping] Rework generation of Cell/Mobile Allocation
+ * [hopping] bootstrap_rsl(): do not call generate_ma_for_ts() again
+ * vty: deprecate BTS type 'sysmobts' in favor of 'osmo-bts'
+ * Replace all references to 'sysmobts' with 'osmo-bts'
+ * VTY: fix NULL-pointer dereference in lchan_act_single()
+ * bts_uptime(): do not spam logs with 'OML link uptime unavailable'
+ * Make interference measurement parameters configurable
+ * VTY: fix typo in a command description: s/send/sent/
+ * PCUIF protocol: add message definition for interference report
+ * abis_rsl: fix rsl_rx_ccch_load(): properly check the message length
+ * gsm_data.h: remove declaration of non-existing ts_pchan()
+ * power_control: omit BS Power Parameters IE if the maximum is 0 dB
+ * power_control: implement BCCH carrier power reduction operation
+ * power_control: constrain BS power reduction on BCCH carrier
+ * lchan_fsm: fix potential NULL-pointer dereference
+ * gsm_04_08_rr: silently ignore RR UTRAN Classmark Change
+ * rsl_rx_resource_indication(): check result of rsl_tlv_parse()
+ * rsl_lchan_lookup(): fix handling of ABIS_RSL_CHAN_NR_CBITS_OSMO_PDCH
+ * [overpower] VTY: cosmetic: fix lower case in command description
+ * [overpower] VTY: fix copy-pasted warning message
+ * [overpower] VTY: add more ACCH overpower related parameters
+ * [overpower] Add VTY transcript tests for all commands
+ * .gitignore: also ignore *.la files
+ * .gitignore: remove non-existing ipaccess-firmware binary
+ * lchan_fsm: cosmetic: move a 'case' below the 'default' branch
+ * rsl_tx_chan_activ(): fix manual channel activation for nanoBTS
+ * abis_rsl: do not pass lchan to print_meas_rep_buf()
+ * abis_rsl: print_meas_rep_{buf,uni}() accept const *mr
+ * abis_rsl: permit simultaneous ACCH repetition and overpower
+ * ipaccess-config: reduce verbosity of the OML logging
+ * ipaccess-config: fix wrong flag name in ipa_nvflag_strs[]
+ * ipaccess-config: warn about unknown flag name
+ * doc/manuals: add documentation for interference reporting
+ * gsm_data: use ascending order for interference boundaries
+ * doc/manuals: add documentation for Temporary ACCH Overpower
+ * doc/manuals: fix wrong CI in the inter-BSC handover diagram
+ * tests/Makefile.am: do not try removing non-existing files
+ * abis_rsl: simplify checking if channel mode is AMR
+ * abis_rsl: cosmetic: fix coding style rep_acch_cap_for_bts()
+ * bts_vty: fix tabs-vs-spaces issues in cfg_bts_rep_dl_facch
+ * struct gsm_bts: simplify comments for ACCH repetition/overpower
+ * struct gsm_bts: s/repeated_acch_policy/rep_acch_cap/g
+ * struct gsm_bts: s/temporary_overpower/top_acch_cap/g
+ * abis_rsl: {rep,top}_acch_cap_for_bts(): make *lchan const
+ * abis_rsl: s/*_acch_cap_for_bts/put_*_acch_cap_ie/g
+ * [overpower] Allow configuring specific channel mode(s)
+ * [overpower] By default, permit only for speech channels using AMR
+
+ [ Alexander Chemeris ]
+ * stats: Count transitions from BORKEN state due to LCHAN_EV_TS_ERROR signal.
+
+ [ Pau Espin Pedrol ]
+ * cosmetic: Fix typo in func description
+ * bssap: pass whole tlv_parsed to event GSCON_EV_A_COMMON_ID_IND
+ * Send EUTRAN neighs based on whether Common Id msg contained Last used E-UTRAN PLMN ID
+ * Revert "update neighbor ARFCNs on startup and config changes"
+ * SRVCC: Parse Last Used E-UTRAN PLMN Id in Handover Request
+ * SRVCC: Forward Last EUTRAN PLMN Id in Handover Required
+ * osmo-bsc: Avoid erroring every few secs about unconnected BTS
+ * Fix bts->description field not printed in config write
+ * ipaccess-config: Clean up sign_link setup helper
+ * bsc: Clean up TS selection in ipaccess_sign_link_up/down
+ * bsc: Use osmo_clock_gettime everywhere
+ * ctrl: Introduce CTRL SET cmd to apply VTY cfg file
+ * ctrl: Avoid fclose() on NULL pointer
+ * Use new stat item/ctr getter APIs
+ * vty: Drop unused old node enum fields
+ * Introduce VTY command to disable srvcc fast-return on target BTS
+ * Introduce counters to track SRVCC procedures
+ * pcuif_proto.h: Add new container messages
+ * Support proto IPAC_PROTO_EXT_PCU BSC<->PCU
+ * lchan-select: Avoid setting variable for no reason
+ * assignment_fsm: Fix null pointer dereference rx ASSIGNMENT_EV_LCHAN_ERROR
+ * assignment_fsm: Add assert to guard ptr access
+ * Rename osmo dyn ts enums to contain SDCCH8
+ * Support SDCCH8 in osmo dyn ts
+ * lchan_fsm: Allow rx LCHAN_EV_RLL_REL_IND in WAIT_RF_RELEASE_ACK
+ * doc: bts.adoc: Update dyn ts section to include SDCCH8 support
+ * lchan_fsm: Improve timeout logging line in state WAIT_RLL_RTP_ESTABLISH
+ * Avoid switching dyn ts to sdcch8 if it starves later TCH
+ * cosmetic: Small improvements to _select_sdcch_for_call
+ * Add new lchan_select_set_type() API helper
+ * _select_sdcch_for_call: Avoid 2nd lchan lookup when finally selecting it
+ * lchan_fsm: Allow rx LCHAN_EV_RLL_REL_IND in state BORKEN
+ * abis_rsl: Log chan rqd reason on resource exhaustion log message
+ * Fix recent regression in CHREQ allocation
+ * Split bsc_vty.c creating bts_vty.c
+ * Split bts_vty.c creating bts_trx_vty.c
+ * Introduce libbsc to avoid linking long lists of .o files
+ * Introduce VTY option to forbid use of TCH for non-voicecall signalling
+ * Clarify string name for GSM_CHREQ_REASON_CALL
+ * doc: Improve ACC ramp documentation
+ * doc: manual: Fix typo in text
+ * vty: Fix wrong TSC sent when activating lchan through VTY
+ * vty: Fix wrongs params passed in vty warning message
+ * cosmetic: power_ctrl_params_def: Fix typo in comment
+ * doc: power_control.adoc: Improve VTY snippet foot notes
+ * MS Power Control Loop: Support set up of C/I parameters for osmo-bts
+ * doc: power_control.adoc: Add small time graph showcasing P_CON_INTERVAL
+ * lchan_fsm: Fix comment
+ * lchan_fsm: Fix comment
+ * lchan_fsm: Avoid inheriting bs_power from old lchan
+ * Support Neighbor Address Resolution over PCUIF IPA multiplex
+ * Power Control Loop: Set P_CON_INTERVAL to 1 by default
+ * MS Power Control Loop: Support turn off C/I based logic
+ * bts_vty: Print C/I power params for osmo-bts only
+ * MS Power Control Loop: Allow Turn off/on C/I independent from value setting
+ * cosmetic: fix comment typos in signal.h
+ * cosmetic: Fix typo in comment
+ * MS Power Control Loop: Use P_CON_INTERVAL=2 by default
+ * bts_trx: Fix timeslot_fsm not properly freed during trx free() [1/4]
+ * Move global var bsc_gsmnet into libbsc [2/4]
+ * Move ts_fsm_init to static constructor [3/4]
+ * Get rid of lots of stubs [4/4]
+ * nm_channel_fsm: drop ipa link if SetChannelAttr fails
+ * gitignore: Fix typo
+ * jenkins.sh: Fix typo
+ * Set subslots_per_pchan[GSM_PCHAN_OSMO_DYN] = 8
+ * timeslot_fsm: Add assert to make sure we never go out of bounds in ts->lchan array
+ * Set subslots_per_pchan_vamos[GSM_PCHAN_OSMO_DYN] = 0
+ * assignment_fsm: Log modified lchan in assignment_fsm_allstate_action()
+ * lchan_fsm: Fix possible NULL ptr dereference in _lchan_on_mode_modify_failure()
+ * Properly handle dyn TS TCH with vamos after updating subslots_per_pchan
+
+ [ Michael Iedema ]
+ * stats: add BTS uptime counter
+
+ [ Philipp Maier ]
+ * bts.adoc: fix typo BGSGP -> BSSGP
+ * handover_cfg: add missing VTY_CMD_PREFIX in comment
+ * bsc_ctrl_commands: add command to write vty config
+ * control.adoc: add doc for apply-config-file
+ * bsc_vty: add vty option to allow call-reestablishment
+ * handover_ctrl: add control interface for handover settings
+ * running.adoc: explain mgw reset-endpoint VTY setting
+ * osmo_bsc_main: remove unused commandline option -l
+ * bty_vty: add VTY settungs for temporary overpower
+ * osmo_bsc_main: integrate MGW pooling into osmo-bsc
+ * osmo_bsc_msc: do not initalize MGCP proxy for AoIP MSCs
+ * doc/mgwpool: update documentation
+ * assignment_fsm: make assignment_fsm_timer_cb static
+ * assignment_fsm: make assignment_fsm_allstate_action static
+ * assignment_fsm: Check for conn->lchan
+ * osmo_bsc_main: remove code dup in bootstrap_bts()
+ * bts: set R99 MSC flag in SI13 in bts_alloc
+ * bts: set pwrc value in bts_alloc
+ * bts: set acs value in bts_alloc
+ * drop chan_load_samples_idx initalization from bootstrap_bts()
+ * bts: set ncc_permitted from bts_alloc
+ * osmo_bsc_main: remove not longer needed fixme note
+ * osmo_bsc_main: remove unused option -t --testmode
+ * bsc_subscr_conn_fsm: fix mgw-pool ref counting
+ * neighbor_ident: add comment about Neighbor Address Resolution Service
+ * control.adoc: improve description of command bts.N.send-new-system-informations
+ * heighbor_ident: add/del neighbor cells via ctrl interface
+ * bsc_ctrl_commands: change neighbor-list mode/arfcn via control interface
+ * control.adoc: comment out fixme note
+ * osmo_bsc_main: bootstrap_bts: print errornous ARFCN number
+ * osmo_bsc_main: separate checks from bootstrap_bts
+ * osmo_bsc_main: move inp_sig_cb() below check_bts and bootstrap_bts
+ * osmo_bsc_ctrl: make sure strtok results are checked
+ * osmo_bsc_main: call bootstrap_bts when OML TEI comes up
+ * osmo_bsc_main: move generate_ma_for_bts() into bootstrap_bts()
+
+ [ Eric ]
+ * vty: allow A5/4 encryption in config
+
+ [ Daniel Willmann ]
+ * bts: Clear BTS_STAT_CHAN_*_{TOTAL,USED} on bts disconnect
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 16 Nov 2021 17:21:59 +0100
+
osmo-bsc (1.7.0) unstable; urgency=medium
[ Harald Welte ]
diff --git a/debian/control b/debian/control
index a135119ee..7ed469461 100644
--- a/debian/control
+++ b/debian/control
@@ -12,12 +12,12 @@ Build-Depends: debhelper (>=9),
python3-minimal,
libcdk5-dev,
libtalloc-dev,
- libosmocore-dev (>= 1.5.0),
- libosmo-sigtran-dev (>= 1.4.0),
- libosmo-abis-dev (>= 1.1.0),
+ libosmocore-dev (>= 1.6.0),
+ libosmo-sigtran-dev (>= 1.5.0),
+ libosmo-abis-dev (>= 1.2.0),
libosmo-netif-dev (>= 1.1.0),
- libosmo-mgcp-client-dev (>= 1.8.0),
- osmo-gsm-manuals-dev (>= 1.1.0)
+ libosmo-mgcp-client-dev (>= 1.9.0),
+ osmo-gsm-manuals-dev (>= 1.2.0)
Standards-Version: 3.9.8
Vcs-Git: git://git.osmocom.org/osmo-bsc.git
Vcs-Browser: https://git.osmocom.org/osmo-bsc/
diff --git a/doc/manuals/chapters/bts-examples.adoc b/doc/manuals/chapters/bts-examples.adoc
index 58cb3ab17..836dec03d 100644
--- a/doc/manuals/chapters/bts-examples.adoc
+++ b/doc/manuals/chapters/bts-examples.adoc
@@ -174,3 +174,120 @@ network
For building a multi-TRX setup, you also need to connect the TIB cables
between the two nanoBTS units, as well as the coaxial/RF AUX cabling.
====
+
+=== Example configuration for OsmoBSC with E1 BTS
+
+The following configuration sample illustrates the usage of BTSs that are
+connected via an E1/T1 backhaul.
+
+.OsmoBSC configured for single-TRX E1 Ericsson DUG20
+====
+----
+e1_input <1>
+ e1_line 0 driver dahdi
+ e1_line 0 port 3
+network
+ network country code 1
+ mobile network code 1
+ encryption a5 0
+ neci 1
+ handover 0
+ bts 0
+ type rbs2000
+ band GSM900
+ om2000 version-limit oml gen 12 rev 10 <2>
+ cell_identity 0
+ location_area_code 1
+ training_sequence_code 7
+ base_station_id_code 63
+ ms max power 15
+ cell reselection hysteresis 4
+ rxlev access min 0
+ channel allocator ascending
+ rach tx integer 9
+ rach max transmission 7
+ oml e1 line 0 timeslot 1 sub-slot full <3>
+ oml e1 tei 62 <4>
+ gprs mode none
+ is-connection-list add 4 512 12 <5>
+ is-connection-list add 16 524 12
+ is-connection-list add 28 536 12
+ is-connection-list add 40 548 12
+ trx 0
+ rf_locked 0
+ arfcn 123
+ nominal power 42
+ max_power_red 12
+ rsl e1 line 0 timeslot 1 sub-slot full <6>
+ rsl e1 tei 0 <7>
+ timeslot 0
+ phys_chan_config CCCH+SDCCH4
+ hopping enabled 0
+ e1 line 0 timeslot 1 sub-slot full <8>
+ timeslot 1
+ phys_chan_config TCH/F
+ hopping enabled 0
+ e1 line 0 timeslot 2 sub-slot 1 <9>
+ timeslot 2
+ phys_chan_config TCH/F
+ hopping enabled 0
+ e1 line 0 timeslot 2 sub-slot 2
+ timeslot 3
+ phys_chan_config TCH/F
+ hopping enabled 0
+ e1 line 0 timeslot 2 sub-slot 3
+ timeslot 4
+ phys_chan_config TCH/F
+ hopping enabled 0
+ e1 line 0 timeslot 3 sub-slot 0
+ timeslot 5
+ phys_chan_config TCH/F
+ hopping enabled 0
+ e1 line 0 timeslot 3 sub-slot 1
+ timeslot 6
+ phys_chan_config TCH/F
+ hopping enabled 0
+ e1 line 0 timeslot 3 sub-slot 2
+ timeslot 7
+ phys_chan_config TCH/F
+ hopping enabled 0
+ e1 line 0 timeslot 3 sub-slot 3
+----
+====
+
+<1> In this example we use a dahdi E1 card. This card has 4 ports. Here we use port numer 3. It should be noted that the dahdi driver also requires additional configuration, which is not covered by this manual.
+
+<2> In this example we use an E1 Ericsson DUG20, which uses an OML dialect, called "OM2000".
+
+<3> The first usable timeslot on an E1 line is TS1. In this example we will assume that TS1-TS3 are connected to the BTS stright through. TS1 will handle all signaling traffic. Here we assign this timeslot to OML.
+
+<4> OML always requires a TEI (Terminal Equipment Identifier) to set up. This number can be found in the manual of the BTS.
+
+<5> This BTS has an built in “Interface Switch” (IS) that offers flexible way to reconfigure the interconnection between the internal components of the BTS and the external E1 line. This depends on the exact BTS type and configuration.
+
+<6> Similar to OML we assign TS1 to RSL as well.
+
+<7> Like with OML, RSL also requires a TEI to be configured. Usually each TRX will have a specific TEI assigned.
+
+<8> CCCH+SDCCH4 will also be mapped on TS1. The traffic for those control channels will be multiplexed alongside the RSL and OML traffic.
+
+<9> The bandwidth of one E1 timeslot matches the bandwidth of 4 GSM air interface timeslots. The E1 timeslot is split up into four sub-slots, which are then assigned to one GSM air interface timeslot each. Since the first timeslot on the first TRX is already used for signaling we begin the sub-slot counting with sub-slot 1 for alignment reasons.
+
+=== E1 Line number and MGCP trunk number
+The switching of the voice channels is done via OsmoMGW, which acts as a media
+converter between E1 and VoIP (RTP). OsmoBSC will use the E1 line number to
+address the trunk via MGCP.
+
+When configuring OsmoMGW, one needs to make sure that the trunk number that is
+set up on OsmoMGW, matches the line number that is set up on OsmoBSC. When those
+numbers mismatch the trunk cannot be addressed correctly.
+
+.OsmoMGW trunk configuration that matches the OsmoBSC configuration above
+====
+----
+ trunk 0
+ rtp keep-alive once
+ no rtp keep-alive
+ line 0
+----
+==== \ No newline at end of file
diff --git a/doc/manuals/chapters/control.adoc b/doc/manuals/chapters/control.adoc
index 258512636..09e828e9e 100644
--- a/doc/manuals/chapters/control.adoc
+++ b/doc/manuals/chapters/control.adoc
@@ -32,7 +32,7 @@ TRX-specific commands are additionally prefixed with TRX number e. g.
|bts.N.location-area-code|RW|No|"<lac>"|Set/Get LAC (value between (0, 65535)).
|bts.N.cell-identity|RW|No|"<id>"|Set/Get Cell Identity (value between (0, 65535)).
|bts.N.apply-configuration|WO|No|Ignored|Restart BTS via OML.
-|bts.N.send-new-system-informations|WO|No|Ignored|Regenerate System Information messages for given BTS.
+|bts.N.send-new-system-informations|WO|No|Ignored|Regenerate and resend System Information messages for given BTS.
|bts.N.channel-load|RO|No|"<name>,<used>,<total>"|See <<chanlo>> for details.
|bts.N.oml-connection-state|RO|No|"connected", "disconnected", "degraded"|Indicate the status of OML connection of BTS.
|bts.N.oml-uptime|RO|No|<uptime>|Return OML link uptime in seconds.
@@ -68,6 +68,9 @@ TRX-specific commands are additionally prefixed with TRX number e. g.
|[bts.N.]handover2.penalty-time.failed-assignment|RW|No|<0-99999>,"default"|Time to suspend handover for a subscriber after a failed re-assignment within this cell.
|[bts.N.]handover2.retries|RW|No|<0-9>,"default"|Number of times to immediately retry a failed handover/assignment, before a penalty time is applied.
|handover2.congestion-check|RW|No|"disabled",<1-999>,"now"|Congestion check interval in seconds, "now" triggers immediate congestion check.
+|bts.N.neighbor-list.mode|WO|No|"automatic","manual","manual-si5"|Mode of Neighbor List generation.
+|bts.N.neighbor-list.add|WO|No|<0-1023>|Add to manual neighbor list.
+|bts.N.neighbor-list.del|WO|No|<0-1023>|Delete from manual neighbor list.
|===
[[notif]]
@@ -120,4 +123,29 @@ RF Ctrl is enabled in the BSC Configuration.
Set/Get the value of maximum power reduction. Even values between 0 and 22 are
accepted.
-FIXME: add variables defined in src/ctrl/control_if.c?
+=== add/del neighbor cell
+
+The control interface allows for editing the neighbor cell configuration. Neighbor
+cells can be added or removed during runtime. It is also possible to clear the
+entire neighbor list if necessary.
+
+.Variables available over control interface
+[options="header",width="100%",cols="20%,5%,5%,50%,20%"]
+|===
+|Name|Access|Trap|Value|Comment
+|bts.N.neighbor-bts.add|WO|No|"<num>"|Add neighbor cell by local BTS number.
+|bts.N.neighbor-bts.del|WO|No|"<num>"|Delete neighbor cell by local BTS number.
+|bts.N.neighbor-lac.add|WO|No|"<lac>[-<arfcn>-<bsic>]"|Add neighbor cell by LAC.
+|bts.N.neighbor-lac.del|WO|No|"<lac>[-<arfcn>-<bsic>]"|Delete neighbor cell by LAC.
+|bts.N.neighbor-lac-ci.add|WO|No|"<lac>-<ci>[-<arfcn>-<bsic>]"|Add neighbor cell by LAC and CI.
+|bts.N.neighbor-lac-ci.del|WO|No|"<lac>-<ci>[-<arfcn>-<bsic>]"|Delete neighbor cell by LAC and CI.
+|bts.N.neighbor-cgi.add|WO|No|"<mcc>-<mnc>-<lac>-<ci>[-<arfcn>-<bsic>]"|Add neighbor cell by cgi.
+|bts.N.neighbor-cgi.del|WO|No|"<mcc>-<mnc>-<lac>-<ci>[-<arfcn>-<bsic>]"|Delete neighbor cell by cgi.
+|bts.N.neighbor-cgi-ps.add|WO|No|"<mcc>-<mnc>-<lac>-<rac>-<ci>[-<arfcn>-<bsic>]"|Add neighbor cell by cgi (Packet Switched, with RAC)
+|bts.N.neighbor-cgi-ps.del|WO|No|"<mcc>-<mnc>-<lac>-<rac>-<ci>[-<arfcn>-<bsic>]"|Delete neighbor cell by cgi (Packet Switched, with RAC).
+|bts.N.neighbor-clear|WO|No|Ignored|Delete all neighbor cells.
+|===
+
+NOTE: The bsic-number (<bsic>) can also be set to "any" if no explcit bsic shall be given
+
+//FIXME: add variables defined in src/ctrl/control_if.c?
diff --git a/doc/manuals/chapters/handover_inter_bsc.dot b/doc/manuals/chapters/handover_inter_bsc.dot
index 42decef32..3ff8093d0 100644
--- a/doc/manuals/chapters/handover_inter_bsc.dot
+++ b/doc/manuals/chapters/handover_inter_bsc.dot
@@ -27,7 +27,7 @@ BTS_a1 -> BTS_b0 [label="(5) BSC decides to do\ninter-BSC Handover",style=dashed
{BSC_a,BSC_b} -> MSC [arrowhead=none,label=A]
-BSC_a -> MSC [label="(6) --> Handover Required\nto LAC=42 CI=6\n(10) <-- Handover Command",style=dashed,constraint=false,arrowhead=none]
+BSC_a -> MSC [label="(6) --> Handover Required\nto LAC=42 CI=3\n(10) <-- Handover Command",style=dashed,constraint=false,arrowhead=none]
MSC -> BSC_b [label="(7) <-- Handover Request\n(9) --> Handover Request ACK",style=dashed,constraint=false,arrowhead=none]
BSC_b -> BTS_b0 [label="(8) activate new lchan",style=dashed,constraint=false]
diff --git a/doc/manuals/chapters/interf_meas.adoc b/doc/manuals/chapters/interf_meas.adoc
new file mode 100644
index 000000000..c82ff4907
--- /dev/null
+++ b/doc/manuals/chapters/interf_meas.adoc
@@ -0,0 +1,72 @@
+== Interference reporting
+
+According to 3GPP 48.058, section 6.1, the BTS shall periodically report the
+interference levels on *idle* channels using the "Radio resource indication"
+procedure. This is done by sending the `RF RESource INDication` message,
+which is specified in sections 8.6.1 and 9.3.21.
+
+// TODO: BSC -> MSC reporting (3GPP TS 48.008, section 3.1.3)
+
+=== Interference reporting parameters
+
+The interference band is calculated by the BTS based on the `Interference level
+Boundaries` and the `Averaging period`. These parameters are sent by the BSC
+over the A-bis/OML, and can be configured via the VTY interface.
+
+Below are the default values for them:
+
+----
+network
+ bts 0
+ interference-meas avg-period 6 <1>
+ interference-meas level-bounds -115 <2> -109 -103 -97 -91 -85 <3>
+----
+<1> Averaging period (`Intave`) in SACCH multiframe periods (480ms).
+<2> Interference level boundary `0` (in dBm).
+<3> Interference level boundary `X5` (in dBm).
+
+The `Intave` parameter defines the averaging and reporting period. With the
+default value of 6 SACCH multiframe periods the BTS is instructed to report
+averaged interference levels approximately every 3 seconds.
+
+According to 3GPP TS 48.008, there exist five interference bands and six
+`Interference level Boundaries` (`0`, `X1`, ... `X5`). The BTS shall map the
+averaged interference levels (initially in dBm) into these 5 bands.
+
+----
+-115 dBm -109 dBm -103 dBm -97 dBm -91 dBm -85 dBm
+ | <1> | <2> | <3> | <4> | <5> | <6>
+ +----------+----------+----------+----------+----------+
+ | band 1 | band 2 | band 3 | band 4 | band 5 |
+ +----------+----------+----------+----------+----------+
+----
+<1> Interference level boundary `0` (outer).
+<2> Interference level boundary `X1`.
+<3> Interference level boundary `X2`.
+<4> Interference level boundary `X3`.
+<5> Interference level boundary `X4`.
+<6> Interference level boundary `X5` (outer).
+
+Unfortunately, it's not clearly defined by 3GPP how the BTS is supposed to map
+dBm values outside of the outer boundaries (`0` and `X5`) to band values. The
+ip.access nanoBTS, for example, would map values -120 dBm and -75 dBm to bands
+1 and 5, respectively. osmo-bts replicates this behavior.
+
+=== PDCH and dynamic timeslot handling
+
+The BTS may optionally report interference levels for PDCH timeslots. This
+may be useful for the BSC to determine whether dynamic PDCH timeslots might
+be better used for new circuit switched connections, or whether alternative
+PDCH resources should be allocated for interference reasons.
+
+NOTE: Currently osmo-bsc makes no use of PDCH interference reports, neither
+they get forwarded to the BSC co-located PCU over the PCUIF.
+
+For dynamic timeslots (`TCH/F_TCH/H_SDCCH/8_PDCH` and `TCH/F_PDCH`), the
+following expectations apply:
+
+* when in TCH/F mode: no interference reports, because the only sub-channel is active;
+* when in TCH/H mode: interference reports for *inactive* sub-channels only;
+* when in SDCCH mode: interference reports for *inactive* sub-channels only;
+* when in PDCH mode: optional interference reports;
+** measurements can be performed during IDLE TDMA frames.
diff --git a/doc/manuals/chapters/power_control.adoc b/doc/manuals/chapters/power_control.adoc
index f94dd2edb..f5f94f6a4 100644
--- a/doc/manuals/chapters/power_control.adoc
+++ b/doc/manuals/chapters/power_control.adoc
@@ -565,3 +565,70 @@ Got message: b'GET_REPLY 3652121201381481804 bts.0.c0-power-reduction 4 <2>'
----
<1> Remote address of the host running osmo-bsc (localhost in this example)
<2> Maximum BCCH carrier power reduction currently applied
+
+=== Temporary ACCH overpower
+
+Temporary overpower (TOP) is a power control technique that allows to improve
+SACCH/FACCH performance in case of bad C/I. The key idea of TOP is to
+increment the BS transmit power by 2..4 dB only for FACCH/SACCH bursts, while
+keeping all voice bursts at the lower (normal) level as determined by the
+downlink power control loop. This allows to reduce call drop rate and
+increase capacity in deployments with tight frequency reuse.
+
+NOTE: It's not possible to increase the current BS power beyond the maximum
+transmit power level supported by the PHY. Thus if the BTS is already
+transmitting at full power, the overpower logic cannot increase it even
+further. This is also why TOP must be employed *together with BS power
+control*, either static or dynamic.
+
+The main area of use for TOP is traffic channels employing the AMR (Adaptive
+Multi Rate) codec, which is more robust to interference than the associated
+signalling channels. While AMR provides sufficient speech quality even at
+very low C/I levels, the associated signalling channels may be suffering from
+channel coding errors. This imbalance can be compensated by employing TOP,
+which can be efficiently combined with the ACCH repetition technique.
+
+This feature requires no support on the mobile station side and can be used
+with UEs implementing the most recent 3GPP relese features, as well as legacy
+UEs. However, it needs to be implemented in the BTS. Given that TOP itself
+is not specified in 3GPP specifications, osmo-bsc uses Osmocom specific
+A-bis/RSL IEs in order to activate it. Therefore, only the recent osmo-bts
+versions may be instructed to activate this feature. Make sure that feature
+#023 "FACCH/SACCH Temporary overpower" is present in the feature vector.
+This can be checked by issuing `show bts` command in OsmoBSC's VTY interface.
+
+TOP is disabled by default. Below is a configuration example enabling it:
+
+----
+network
+ bts 0
+ overpower dl-acch 2 <1>
+ overpower rxqual 4 <2>
+ overpower chan-mode speech-amr <3>
+----
+<1> Overpower of maximum 2 dB for both SACCH and FACCH.
+<2> Enable TOP only if RxQual is worse than 4 (BER >= 1.6%).
+<3> Permit TOP only for speech channels using AMR codec.
+
+For advanced use cases, OsmoBSC can be configured to:
+
+* enable TOP only for FACCH or SACCH selectively, and/or
+* keep TOP enabled permanently regardless of the reported RxQual, and/or
+* permit TOP for any kind of dedicated channels.
+
+----
+OsmoBSC(config-net-bts)# overpower ?
+ dl-acch Enable overpower for both SACCH and FACCH
+ dl-sacch Enable overpower for SACCH only
+ dl-facch Enable overpower for FACCH only
+
+OsmoBSC(config-net-bts)# overpower rxqual 0?
+ 0 BER >= 0% (always on)
+
+OsmoBSC(config-net-bts)# overpower chan-mode ?
+ speech-amr Speech channels using AMR codec (default)
+ any Any kind of channel mode
+----
+
+These parameters are indicated to the BTS during a logical channel activation
+or modifications procedures, so they can be changed at run-time.
diff --git a/doc/manuals/osmobsc-usermanual.adoc b/doc/manuals/osmobsc-usermanual.adoc
index 120fe2c21..0afa0158c 100644
--- a/doc/manuals/osmobsc-usermanual.adoc
+++ b/doc/manuals/osmobsc-usermanual.adoc
@@ -26,6 +26,8 @@ include::{srcdir}/chapters/bsc.adoc[]
include::{srcdir}/chapters/power_control.adoc[]
+include::{srcdir}/chapters/interf_meas.adoc[]
+
include::{srcdir}/chapters/handover.adoc[]
include::{srcdir}/chapters/smscb.adoc[]
diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am
index 3bccf44fd..3ddad45db 100644
--- a/include/osmocom/bsc/Makefile.am
+++ b/include/osmocom/bsc/Makefile.am
@@ -16,6 +16,7 @@ noinst_HEADERS = \
bts_trx.h \
bts_ipaccess_nanobts_omlattr.h \
chan_alloc.h \
+ chan_counts.h \
codec_pref.h \
ctrl.h \
debug.h \
diff --git a/include/osmocom/bsc/assignment_fsm.h b/include/osmocom/bsc/assignment_fsm.h
index 3a64f7dd1..6c429e418 100644
--- a/include/osmocom/bsc/assignment_fsm.h
+++ b/include/osmocom/bsc/assignment_fsm.h
@@ -17,7 +17,7 @@
conn->assignment.new_lchan ? " of " : "", \
conn->assignment.new_lchan ? gsm_lchan_name(conn->assignment.new_lchan) : "", \
## args); \
- } while(0)
+ } while (0)
enum assignment_fsm_state {
ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE,
diff --git a/include/osmocom/bsc/bsc_stats.h b/include/osmocom/bsc/bsc_stats.h
index 4250079bf..801a2c153 100644
--- a/include/osmocom/bsc/bsc_stats.h
+++ b/include/osmocom/bsc/bsc_stats.h
@@ -76,11 +76,16 @@ enum {
BSC_CTR_PAGING_ATTEMPTED,
BSC_CTR_PAGING_DETACHED,
BSC_CTR_PAGING_RESPONDED,
+ BSC_CTR_PAGING_EXPIRED,
BSC_CTR_PAGING_NO_ACTIVE_PAGING,
BSC_CTR_UNKNOWN_UNIT_ID,
BSC_CTR_MSCPOOL_SUBSCR_NO_MSC,
BSC_CTR_MSCPOOL_EMERG_FORWARDED,
BSC_CTR_MSCPOOL_EMERG_LOST,
+ BSC_CTR_ALL_ALLOCATED_SDCCH,
+ BSC_CTR_ALL_ALLOCATED_STATIC_SDCCH,
+ BSC_CTR_ALL_ALLOCATED_TCH,
+ BSC_CTR_ALL_ALLOCATED_STATIC_TCH,
};
extern const struct rate_ctr_desc bsc_ctr_description[];
@@ -105,3 +110,4 @@ enum {
extern const struct osmo_stat_item_group_desc bsc_statg_desc;
void bsc_update_connection_stats(struct gsm_network *net);
+void bsc_update_time_cc_all_allocated(struct gsm_network *net);
diff --git a/include/osmocom/bsc/bsc_subscriber.h b/include/osmocom/bsc/bsc_subscriber.h
index 6fffafdb3..f9e8eb2a8 100644
--- a/include/osmocom/bsc/bsc_subscriber.h
+++ b/include/osmocom/bsc/bsc_subscriber.h
@@ -17,6 +17,8 @@ struct bsc_subscr {
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
uint32_t tmsi;
+
+ uint32_t active_paging_requests;
};
const char *bsc_subscr_name(struct bsc_subscr *bsub);
diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h
index 68654f2cc..c4ee39daf 100644
--- a/include/osmocom/bsc/bts.h
+++ b/include/osmocom/bsc/bts.h
@@ -27,6 +27,13 @@ enum bts_counter_id {
BTS_CTR_CHREQ_ATTEMPTED_OTHER,
BTS_CTR_CHREQ_ATTEMPTED_UNKNOWN,
BTS_CTR_CHREQ_SUCCESSFUL,
+ BTS_CTR_CHREQ_SUCCESSFUL_EMERG,
+ BTS_CTR_CHREQ_SUCCESSFUL_CALL,
+ BTS_CTR_CHREQ_SUCCESSFUL_LOCATION_UPD,
+ BTS_CTR_CHREQ_SUCCESSFUL_PAG,
+ BTS_CTR_CHREQ_SUCCESSFUL_PDCH,
+ BTS_CTR_CHREQ_SUCCESSFUL_OTHER,
+ BTS_CTR_CHREQ_SUCCESSFUL_UNKNOWN,
BTS_CTR_CHREQ_NO_CHANNEL,
BTS_CTR_CHREQ_MAX_DELAY_EXCEEDED,
BTS_CTR_CHAN_RF_FAIL,
@@ -124,6 +131,13 @@ enum bts_counter_id {
BTS_CTR_INTRA_BSC_HO_TIMEOUT,
BTS_CTR_INTRA_BSC_HO_FAILED,
BTS_CTR_INTRA_BSC_HO_ERROR,
+ BTS_CTR_INCOMING_INTRA_BSC_HO_ATTEMPTED,
+ BTS_CTR_INCOMING_INTRA_BSC_HO_COMPLETED,
+ BTS_CTR_INCOMING_INTRA_BSC_HO_STOPPED,
+ BTS_CTR_INCOMING_INTRA_BSC_HO_NO_CHANNEL,
+ BTS_CTR_INCOMING_INTRA_BSC_HO_TIMEOUT,
+ BTS_CTR_INCOMING_INTRA_BSC_HO_FAILED,
+ BTS_CTR_INCOMING_INTRA_BSC_HO_ERROR,
BTS_CTR_INTER_BSC_HO_OUT_ATTEMPTED,
BTS_CTR_INTER_BSC_HO_OUT_COMPLETED,
BTS_CTR_INTER_BSC_HO_OUT_STOPPED,
@@ -144,6 +158,35 @@ enum bts_counter_id {
BTS_CTR_SRVCC_TIMEOUT,
BTS_CTR_SRVCC_FAILED,
BTS_CTR_SRVCC_ERROR,
+ BTS_CTR_ALL_ALLOCATED_SDCCH,
+ BTS_CTR_ALL_ALLOCATED_STATIC_SDCCH,
+ BTS_CTR_ALL_ALLOCATED_TCH,
+ BTS_CTR_ALL_ALLOCATED_STATIC_TCH,
+ BTS_CTR_CM_SERV_REJ,
+ BTS_CTR_CM_SERV_REJ_IMSI_UNKNOWN_IN_HLR,
+ BTS_CTR_CM_SERV_REJ_ILLEGAL_MS,
+ BTS_CTR_CM_SERV_REJ_IMSI_UNKNOWN_IN_VLR,
+ BTS_CTR_CM_SERV_REJ_IMEI_NOT_ACCEPTED,
+ BTS_CTR_CM_SERV_REJ_ILLEGAL_ME,
+ BTS_CTR_CM_SERV_REJ_PLMN_NOT_ALLOWED,
+ BTS_CTR_CM_SERV_REJ_LOC_NOT_ALLOWED,
+ BTS_CTR_CM_SERV_REJ_ROAMING_NOT_ALLOWED,
+ BTS_CTR_CM_SERV_REJ_NETWORK_FAILURE,
+ BTS_CTR_CM_SERV_REJ_SYNCH_FAILURE,
+ BTS_CTR_CM_SERV_REJ_CONGESTION,
+ BTS_CTR_CM_SERV_REJ_SRV_OPT_NOT_SUPPORTED,
+ BTS_CTR_CM_SERV_REJ_RQD_SRV_OPT_NOT_SUPPORTED,
+ BTS_CTR_CM_SERV_REJ_SRV_OPT_TMP_OUT_OF_ORDER,
+ BTS_CTR_CM_SERV_REJ_CALL_CAN_NOT_BE_IDENTIFIED,
+ BTS_CTR_CM_SERV_REJ_INCORRECT_MESSAGE,
+ BTS_CTR_CM_SERV_REJ_INVALID_MANDANTORY_INF,
+ BTS_CTR_CM_SERV_REJ_MSG_TYPE_NOT_IMPLEMENTED,
+ BTS_CTR_CM_SERV_REJ_MSG_TYPE_NOT_COMPATIBLE,
+ BTS_CTR_CM_SERV_REJ_INF_ELEME_NOT_IMPLEMENTED,
+ BTS_CTR_CM_SERV_REJ_CONDTIONAL_IE_ERROR,
+ BTS_CTR_CM_SERV_REJ_MSG_NOT_COMPATIBLE,
+ BTS_CTR_CM_SERV_REJ_PROTOCOL_ERROR,
+ BTS_CTR_CM_SERV_REJ_RETRY_IN_NEW_CELL,
};
extern const struct rate_ctr_desc bts_ctr_description[];
@@ -547,14 +590,16 @@ struct gsm_bts {
struct llist_head oml_fail_rep;
struct llist_head chan_rqd_queue;
- /* osmocom specific FACCH/SACCH repetition mode flags set by VTY to
- * enable/disable certain ACCH repeation features individually */
- struct abis_rsl_osmo_rep_acch_cap repeated_acch_policy;
+ /* ACCH Repetition capabilities */
+ struct abis_rsl_osmo_rep_acch_cap rep_acch_cap;
- /* osmocom specific FACCH/SACCH temporary overpower value. This value
- * is set to a constant value by the VTY. Temporary overpower is only
- * applied when FACCH/SACCH repetition is not applicable or disabled */
- struct abis_rsl_osmo_temp_ovp_acch_cap temporary_overpower;
+ /* ACCH Temporary overpower capabilities */
+ struct abis_rsl_osmo_temp_ovp_acch_cap top_acch_cap;
+ /* Channel mode(s) for which to allow TOP */
+ enum {
+ TOP_ACCH_CHAN_MODE_ANY = 0, /* Any kind of channel mode */
+ TOP_ACCH_CHAN_MODE_SPEECH_V3, /* Speech channels using AMR codec */
+ } top_acch_chan_mode;
/* MS/BS Power Control parameters */
struct gsm_power_ctrl_params ms_power_ctrl;
@@ -576,6 +621,11 @@ struct gsm_bts {
/* At what point in the channel allocation sequence to dispatch the Immediate Assignment (Abis optimization) */
enum imm_ass_time imm_ass_time;
+
+ struct osmo_time_cc all_allocated_sdcch;
+ struct osmo_time_cc all_allocated_static_sdcch;
+ struct osmo_time_cc all_allocated_tch;
+ struct osmo_time_cc all_allocated_static_tch;
};
#define GSM_BTS_SI2Q(bts, i) (struct gsm48_system_information_type_2quater *)((bts)->si_buf[SYSINFO_TYPE_2quater][i])
@@ -667,6 +717,7 @@ static inline const struct osmo_location_area_id *bts_lai(struct gsm_bts *bts)
}
struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, struct gsm_bts_sm *bts_sm, uint8_t bts_num);
+int gsm_bts_check_cfg(struct gsm_bts *bts);
char *gsm_bts_name(const struct gsm_bts *bts);
@@ -712,8 +763,6 @@ void gsm_bts_set_radio_link_timeout(struct gsm_bts *bts, int value);
void gsm_bts_all_ts_dispatch(struct gsm_bts *bts, uint32_t ts_ev, void *data);
-int bts_count_free_ts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan);
-
int gsm_bts_set_system_infos(struct gsm_bts *bts);
int gsm_bts_set_c0_power_red(struct gsm_bts *bts, const uint8_t red);
diff --git a/include/osmocom/bsc/bts_trx.h b/include/osmocom/bsc/bts_trx.h
index 4d705d0d9..c8df9d9c4 100644
--- a/include/osmocom/bsc/bts_trx.h
+++ b/include/osmocom/bsc/bts_trx.h
@@ -95,7 +95,6 @@ void gsm_trx_lock_rf(struct gsm_bts_trx *trx, bool locked, const char *reason);
bool trx_is_usable(const struct gsm_bts_trx *trx);
void gsm_trx_all_ts_dispatch(struct gsm_bts_trx *trx, uint32_t ts_ev, void *data);
-int trx_count_free_ts(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan);
bool trx_has_valid_pchan_config(const struct gsm_bts_trx *trx);
int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx);
diff --git a/include/osmocom/bsc/chan_counts.h b/include/osmocom/bsc/chan_counts.h
new file mode 100644
index 000000000..31a1adc92
--- /dev/null
+++ b/include/osmocom/bsc/chan_counts.h
@@ -0,0 +1,76 @@
+/* API to count total, allocated and free channels of all types */
+#pragma once
+
+struct gsm_bts;
+struct gsm_bts_trx;
+
+/* First array index to chan_counts.val. */
+enum chan_counts_dim1 {
+ CHAN_COUNTS1_ALL = 0,
+ CHAN_COUNTS1_STATIC = 1,
+ CHAN_COUNTS1_DYNAMIC = 2,
+ _CHAN_COUNTS1_NUM
+};
+
+/* Second array index to chan_counts.val. */
+enum chan_counts_dim2 {
+ /* The maximum possible nr of lchans of this type. Counts all dynamic timeslots as if they are fully available
+ * for this type, regardless of the current pchan mode. (For CHAN_COUNTS1_STATIC, of course no dyn TS are counted
+ * at all.) */
+ CHAN_COUNTS2_MAX_TOTAL = 0,
+ /* Like MAX_TOTAL, but as soon as dynamic timeslots are switched to a specific pchan kind, current_total shrinks
+ * to count only currently present lchans (used and unused). */
+ CHAN_COUNTS2_CURRENT_TOTAL = 1,
+ /* Currently used lchans of this type. To get currently free lchans, calculate CURRENT_TOTAL - ALLOCATED. */
+ CHAN_COUNTS2_ALLOCATED = 2,
+ /* Currently assignable lchans of this type, same as CURRENT_TOTAL - ALLOCATED. */
+ CHAN_COUNTS2_FREE = 3,
+ _CHAN_COUNTS2_NUM
+};
+
+struct chan_counts {
+ unsigned int val[_CHAN_COUNTS1_NUM][_CHAN_COUNTS2_NUM][_GSM_LCHAN_MAX];
+};
+
+void chan_counts_for_bts(struct chan_counts *bts_counts, const struct gsm_bts *bts);
+void chan_counts_for_trx(struct chan_counts *trx_counts, const struct gsm_bts_trx *trx);
+
+static inline void chan_counts_zero(struct chan_counts *counts)
+{
+ *counts = (struct chan_counts){0};
+}
+
+static inline void chan_counts_dim3_add(struct chan_counts *dst,
+ enum chan_counts_dim1 dst_dim1, enum chan_counts_dim2 dst_dim2,
+ const struct chan_counts *add,
+ enum chan_counts_dim1 add_dim1, enum chan_counts_dim2 add_dim2)
+{
+ int i;
+ for (i = 0; i < _GSM_LCHAN_MAX; i++)
+ dst->val[dst_dim1][dst_dim2][i] += add->val[add_dim1][add_dim2][i];
+}
+
+static inline void chan_counts_dim3_sub(struct chan_counts *dst,
+ enum chan_counts_dim1 dst_dim1, enum chan_counts_dim2 dst_dim2,
+ const struct chan_counts *sub,
+ enum chan_counts_dim1 sub_dim1, enum chan_counts_dim2 sub_dim2)
+{
+ int i;
+ for (i = 0; i < _GSM_LCHAN_MAX; i++)
+ dst->val[dst_dim1][dst_dim2][i] -= sub->val[sub_dim1][sub_dim2][i];
+}
+
+static inline void chan_counts_dim2_add(struct chan_counts *dst, enum chan_counts_dim1 dst_dim1,
+ const struct chan_counts *add, enum chan_counts_dim1 add_dim1)
+{
+ int i;
+ for (i = 0; i < _CHAN_COUNTS2_NUM; i++)
+ chan_counts_dim3_add(dst, dst_dim1, i, add, add_dim1, i);
+}
+
+static inline void chan_counts_add(struct chan_counts *dst, const struct chan_counts *add)
+{
+ int i;
+ for (i = 0; i < _CHAN_COUNTS1_NUM; i++)
+ chan_counts_dim2_add(dst, i, add, i);
+}
diff --git a/include/osmocom/bsc/gsm_04_08_rr.h b/include/osmocom/bsc/gsm_04_08_rr.h
index 5ddee7fc3..1f50ef982 100644
--- a/include/osmocom/bsc/gsm_04_08_rr.h
+++ b/include/osmocom/bsc/gsm_04_08_rr.h
@@ -33,9 +33,6 @@ int gsm48_send_rr_app_info(struct gsm_lchan *lchan, uint8_t apdu_id, uint8_t apd
int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t mode);
int gsm48_rx_rr_modif_ack(struct msgb *msg);
int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg);
-int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn);
-int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
- enum gsm48_reject_value value);
struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value);
struct msgb *gsm48_create_loc_upd_rej(uint8_t cause);
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index cb560286e..910c3d33a 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -18,6 +18,7 @@
#include <osmocom/gsm/gsm48.h>
#include <osmocom/core/fsm.h>
#include <osmocom/core/tdef.h>
+#include <osmocom/core/time_cc.h>
#include <osmocom/crypt/auth.h>
@@ -55,6 +56,26 @@ struct smlc_config;
#define OBSC_LINKID_CB(__msgb) (__msgb)->cb[3]
+/* Data Link Connection Identifier (DLCI) is defined in 3GPP TS 48.006, section 9.3.2.
+ * .... .SSS - SAPI value used on the radio link;
+ * CC.. .... - control channel identification:
+ * 00.. .... - indicates that the control channel is not further specified,
+ * 10.. .... - represents the FACCH or the SDCCH,
+ * 11.. .... - represents the SACCH,
+ * other values are reserved. */
+#define RSL_LINK_ID2DLCI(link_id) \
+ ((link_id & 0x40 ? 0xc0 : 0x80) | (link_id & 0x07))
+
+/* RSL Link Identifier is defined in 3GPP TS 3GPP TS 48.058, section 9.3.2.
+ * .... .SSS - SAPI value used on the radio link;
+ * ...P P... - priority for SAPI0 messages;
+ * CC.. .... - control channel identification:
+ * 00.. .... - main signalling channel (FACCH or SDCCH),
+ * 01.. .... - SACCH,
+ * other values are reserved. */
+#define DLCI2RSL_LINK_ID(dlci) \
+ ((dlci & 0xc0) == 0xc0 ? 0x40 : 0x00) | (dlci & 0x07)
+
/* 3-bit long values */
#define EARFCN_PRIO_INVALID 8
#define EARFCN_MEAS_BW_INVALID 8
@@ -403,6 +424,8 @@ struct gsm_subscriber_connection {
bool last_eutran_plmn_valid; /* Is information stored in field below available? */
struct osmo_plmn_id last_eutran_plmn;
} fast_return;
+
+ enum gsm0808_cause clear_cause;
};
@@ -617,6 +640,8 @@ enum imm_ass_time {
struct lchan_activate_info {
enum lchan_activate_for activ_for;
+ /* If activ_for == ACTIVATE_FOR_MS_CHANNEL_REQUEST, the original CHREQ reason. */
+ enum gsm_chreq_reason_t chreq_reason;
struct gsm_subscriber_connection *for_conn;
struct channel_mode_and_rate ch_mode_rate;
struct gsm_encr encr;
@@ -1258,6 +1283,11 @@ struct gsm_network {
struct osmo_nri_ranges *null_nri_ranges;
struct smlc_config *smlc;
+
+ struct osmo_time_cc all_allocated_sdcch;
+ struct osmo_time_cc all_allocated_static_sdcch;
+ struct osmo_time_cc all_allocated_tch;
+ struct osmo_time_cc all_allocated_static_tch;
};
struct gsm_audio_support {
diff --git a/include/osmocom/bsc/handover.h b/include/osmocom/bsc/handover.h
index f67149142..58fea353e 100644
--- a/include/osmocom/bsc/handover.h
+++ b/include/osmocom/bsc/handover.h
@@ -17,7 +17,7 @@
else \
LOGP(DHODEC, level, "%s: " fmt, \
handover_status(conn), ## args); \
- } while(0)
+ } while (0)
struct gsm_network;
struct gsm_lchan;
diff --git a/include/osmocom/bsc/lchan_fsm.h b/include/osmocom/bsc/lchan_fsm.h
index e7a06d56a..eb8312e03 100644
--- a/include/osmocom/bsc/lchan_fsm.h
+++ b/include/osmocom/bsc/lchan_fsm.h
@@ -10,14 +10,14 @@
LOGPFSML((lchan)->fi, level, "(type=%s) " fmt, gsm_lchant_name((lchan)->type), ## args); \
else \
LOGP(DRSL, level, "%s (not initialized) " fmt, gsm_lchan_name(lchan), ## args); \
- } while(0)
+ } while (0)
#define LCHAN_SET_LAST_ERROR(LCHAN, fmt, args...) do { \
if ((LCHAN)->last_error) \
talloc_free((LCHAN)->last_error); \
(LCHAN)->last_error = talloc_asprintf((LCHAN)->ts->trx, fmt, ##args); \
LOG_LCHAN(LCHAN, LOGL_ERROR, "%s\n", (LCHAN)->last_error); \
- } while(0)
+ } while (0)
enum lchan_fsm_state {
LCHAN_ST_UNUSED,
@@ -72,7 +72,7 @@ static inline const char *lchan_state_name(struct gsm_lchan *lchan)
return lchan->fi ? osmo_fsm_inst_state_name(lchan->fi) : "NULL";
}
-static inline bool lchan_state_is(struct gsm_lchan *lchan, uint32_t state)
+static inline bool lchan_state_is(const struct gsm_lchan *lchan, uint32_t state)
{
return (!lchan->fi && state == LCHAN_ST_UNUSED)
|| (lchan->fi && lchan->fi->state == state);
diff --git a/include/osmocom/bsc/lchan_rtp_fsm.h b/include/osmocom/bsc/lchan_rtp_fsm.h
index 6ff8fe362..18ab348f2 100644
--- a/include/osmocom/bsc/lchan_rtp_fsm.h
+++ b/include/osmocom/bsc/lchan_rtp_fsm.h
@@ -7,7 +7,7 @@
else \
LOGP(DLMGCP, level, "%s (not initialized) " fmt, gsm_lchan_name(lchan), \
## args); \
- } while(0)
+ } while (0)
struct gsm_lchan;
struct mgcp_conn_peer;
diff --git a/include/osmocom/bsc/lcs_loc_req.h b/include/osmocom/bsc/lcs_loc_req.h
index ba677e867..86540f278 100644
--- a/include/osmocom/bsc/lcs_loc_req.h
+++ b/include/osmocom/bsc/lcs_loc_req.h
@@ -8,7 +8,7 @@
LOGPFSML((LOC_REQ)->fi, level, fmt, ## args); \
else \
LOGP(DLCS, level, "LCS Perf Loc Req: " fmt, ## args); \
- } while(0)
+ } while (0)
struct lcs_ta_req;
diff --git a/include/osmocom/bsc/lcs_ta_req.h b/include/osmocom/bsc/lcs_ta_req.h
index b9b7a4e58..bdfc14f60 100644
--- a/include/osmocom/bsc/lcs_ta_req.h
+++ b/include/osmocom/bsc/lcs_ta_req.h
@@ -11,7 +11,7 @@
LOGPFSML((TA_REQ)->fi, level, fmt, ## args); \
else \
LOGP(DLCS, level, "LCS TA Req: " fmt, ## args); \
- } while(0)
+ } while (0)
enum lcs_ta_req_fsm_event {
LCS_TA_REQ_EV_GOT_TA,
diff --git a/include/osmocom/bsc/neighbor_ident.h b/include/osmocom/bsc/neighbor_ident.h
index 58300ba48..c6a2c4237 100644
--- a/include/osmocom/bsc/neighbor_ident.h
+++ b/include/osmocom/bsc/neighbor_ident.h
@@ -77,6 +77,10 @@ void neighbor_ident_vty_init();
void neighbor_ident_vty_write_bts(struct vty *vty, const char *indent, struct gsm_bts *bts);
void neighbor_ident_vty_write_network(struct vty *vty, const char *indent);
+int neighbor_ident_add_neighbor(struct vty *vty, struct gsm_bts *bts, struct neighbor *n);
+int neighbor_ident_del_neighbor(struct vty *vty, struct gsm_bts *bts, struct neighbor *n);
+int neighbor_ident_ctrl_init(void);
+
int neighbors_check_cfg();
#define CELL_AB_VTY_PARAMS "arfcn <0-1023> bsic (<0-63>|any)"
diff --git a/include/osmocom/bsc/timeslot_fsm.h b/include/osmocom/bsc/timeslot_fsm.h
index 5e621888f..526f3cf00 100644
--- a/include/osmocom/bsc/timeslot_fsm.h
+++ b/include/osmocom/bsc/timeslot_fsm.h
@@ -17,7 +17,7 @@
gsm_ts_name(ts), \
## args, \
(!fmt || !*fmt || fmt[strlen(fmt)-1] != '\n') ? "\n" : ""); \
- } while(0)
+ } while (0)
enum ts_fsm_state {
TS_ST_NOT_INITIALIZED,
diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4
deleted file mode 100644
index ca3639715..000000000
--- a/m4/ax_check_compile_flag.m4
+++ /dev/null
@@ -1,74 +0,0 @@
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
-#
-# DESCRIPTION
-#
-# Check whether the given FLAG works with the current language's compiler
-# or gives an error. (Warnings, however, are ignored)
-#
-# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
-# success/failure.
-#
-# If EXTRA-FLAGS is defined, it is added to the current language's default
-# flags (e.g. CFLAGS) when the check is done. The check is thus made with
-# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
-# force the compiler to issue an error when a bad flag is given.
-#
-# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
-#
-# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
-# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
-# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU 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 General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 4
-
-AC_DEFUN([AX_CHECK_COMPILE_FLAG],
-[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
-AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
-AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
- ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
- _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
- AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
- [AS_VAR_SET(CACHEVAR,[yes])],
- [AS_VAR_SET(CACHEVAR,[no])])
- _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
-AS_VAR_IF(CACHEVAR,yes,
- [m4_default([$2], :)],
- [m4_default([$3], :)])
-AS_VAR_POPDEF([CACHEVAR])dnl
-])dnl AX_CHECK_COMPILE_FLAGS
diff --git a/src/ipaccess/ipaccess-config.c b/src/ipaccess/ipaccess-config.c
index ada23ead2..06fc9eb85 100644
--- a/src/ipaccess/ipaccess-config.c
+++ b/src/ipaccess/ipaccess-config.c
@@ -268,6 +268,8 @@ static int nwl_sig_cb(unsigned int subsys, unsigned int signal,
return 0;
}
+static const struct value_string ipa_nvflag_strs[];
+
static int print_attr_rep(struct msgb *mb)
{
/* Parse using nanoBTS own formatting for Get Attribute Response */
@@ -281,6 +283,7 @@ static int print_attr_rep(struct msgb *mb)
char oml_ip[20] = {0};
uint16_t oml_port = 0;
char unit_id[40] = {0};
+ unsigned int indent = 0;
abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
@@ -290,8 +293,49 @@ static int print_attr_rep(struct msgb *mb)
abis_nm_tlv_attr_unit_id(&tp, unit_id, sizeof(unit_id));
- fprintf(stdout, "{ \"primary_oml_ip\": \"%s\", \"primary_oml_port\": %" PRIu16 ", \"unit_id\": \"%s\" }\n",
- oml_ip, oml_port, unit_id);
+#define ENDL(last) \
+ fprintf(stdout, "%s\n", last ? "" : ",")
+#define print_offset(fmt, args...) \
+ fprintf(stdout, "%*s" fmt, indent * 4, "", ## args)
+#define print_field(field, fmt, args...) \
+ print_offset("\"%s\": \"" fmt "\"", field, ## args)
+
+ print_offset("{\n");
+ indent++;
+
+ print_field("primary_oml_ip", "%s", oml_ip); ENDL(false);
+ print_field("primary_oml_port", "%u", oml_port); ENDL(false);
+ print_field("unit_id", "%s", unit_id); ENDL(false);
+
+ uint16_t Fx = (TLVP_VAL(&tp, NM_ATT_IPACC_NV_FLAGS)[2] << 8)
+ | (TLVP_VAL(&tp, NM_ATT_IPACC_NV_FLAGS)[0] << 0);
+ uint16_t Mx = (TLVP_VAL(&tp, NM_ATT_IPACC_NV_FLAGS)[3] << 8)
+ | (TLVP_VAL(&tp, NM_ATT_IPACC_NV_FLAGS)[1] << 0);
+ const struct value_string *nvflag = ipa_nvflag_strs;
+
+ print_offset("\"nv_flags\": {\n");
+ indent++;
+
+ while (nvflag->value && nvflag->str) {
+ const char *val = (Fx & nvflag->value) ? "yes" : "no";
+ if (~Mx & nvflag->value)
+ val = "unknown";
+ print_field(nvflag->str, "%s", val);
+
+ nvflag++;
+
+ if (nvflag->value && nvflag->str)
+ ENDL(false); /* more fields to print */
+ else
+ ENDL(true); /* this was the last field */
+ }
+
+ indent--;
+ print_offset("}\n");
+
+ indent--;
+ print_offset("}\n");
+
return 0;
}
@@ -501,7 +545,7 @@ static const struct value_string ipa_nvflag_strs[] = {
{ 0x0002, "static-gw" },
{ 0x0004, "no-dhcp-vsi" },
{ 0x0008, "dhcp-enabled" },
- { 0x0040, "led-disabled" },
+ { 0x0040, "led-enabled" },
{ 0x0100, "secondary-oml-enabled" },
{ 0x0200, "diag-enabled" },
{ 0x0400, "cli-enabled" },
@@ -516,8 +560,10 @@ static int ipa_nvflag_set(uint16_t *flags, uint16_t *mask, const char *name, int
{
int rc;
rc = get_string_value(ipa_nvflag_strs, name);
- if (rc < 0)
+ if (rc < 0) {
+ fprintf(stderr, "Unknown attribute '%s'\n", name);
return rc;
+ }
*mask |= rc;
if (en)
@@ -541,6 +587,7 @@ static void bootstrap_om(struct gsm_bts_trx *trx)
if (get_attr) {
msgb_put_u8(nmsg_get, NM_ATT_IPACC_PRIM_OML_CFG);
msgb_put_u8(nmsg_get, NM_ATT_IPACC_UNIT_ID);
+ msgb_put_u8(nmsg_get, NM_ATT_IPACC_NV_FLAGS);
}
if (unit_id) {
len = strlen(unit_id);
@@ -925,7 +972,7 @@ static const struct log_info_cat log_categories[] = {
.name = "DNM",
.description = "A-bis Network Management / O&M (NM/OML)",
.color = "\033[1;36m",
- .loglevel = LOGL_DEBUG,
+ .loglevel = LOGL_NOTICE,
.enabled = 1,
},
};
diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am
index 19af5694f..583fb79d9 100644
--- a/src/osmo-bsc/Makefile.am
+++ b/src/osmo-bsc/Makefile.am
@@ -57,6 +57,7 @@ libbsc_la_SOURCES = \
bts_vty.c \
bts_trx_vty.c \
chan_alloc.c \
+ chan_counts.c \
codec_pref.c \
e1_config.c \
gsm_04_08_rr.c \
@@ -78,6 +79,7 @@ libbsc_la_SOURCES = \
meas_rep.c \
neighbor_ident.c \
neighbor_ident_vty.c \
+ neighbor_ident_ctrl.c \
net_init.c \
nm_common_fsm.c \
nm_bb_transc_fsm.c \
diff --git a/src/osmo-bsc/abis_nm.c b/src/osmo-bsc/abis_nm.c
index 7c0439413..1c21bc265 100644
--- a/src/osmo-bsc/abis_nm.c
+++ b/src/osmo-bsc/abis_nm.c
@@ -51,6 +51,7 @@
#include <osmocom/bsc/bts.h>
#include <osmocom/bsc/nm_common_fsm.h>
#include <osmocom/gsm/bts_features.h>
+#include <osmocom/bsc/ipaccess.h>
#define OM_ALLOC_SIZE 1024
#define OM_HEADROOM_SIZE 128
@@ -1342,13 +1343,6 @@ static int sw_activate(struct abis_nm_sw *sw)
return abis_nm_sendmsg(sw->bts, msg);
}
-struct sdp_firmware {
- char magic[4];
- char more_magic[4];
- unsigned int header_length;
- unsigned int file_length;
-} __attribute__ ((packed));
-
static int parse_sdp_header(struct abis_nm_sw *sw)
{
const struct gsm_abis_mo *mo = &sw->bts->mo;
@@ -1363,18 +1357,20 @@ static int parse_sdp_header(struct abis_nm_sw *sw)
}
if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
- LOGPMO(mo, DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
+ LOGPMO(mo, DNM, LOGL_ERROR, "The magic number is wrong.\n");
return -1;
}
if (firmware_header.more_magic[0] != 0x10 ||
- firmware_header.more_magic[1] != 0x02 ||
- firmware_header.more_magic[2] != 0x00 ||
- firmware_header.more_magic[3] != 0x00) {
+ firmware_header.more_magic[1] != 0x02) {
LOGPMO(mo, DNM, LOGL_ERROR, "The more magic number is wrong.\n");
return -1;
}
+ if (firmware_header.more_more_magic != 0x0000) {
+ LOGPMO(mo, DNM, LOGL_ERROR, "The more more magic number is wrong.\n");
+ return -1;
+ }
if (fstat(sw->fd, &stat) == -1) {
LOGPMO(mo, DNM, LOGL_ERROR, "Could not stat the file.\n");
diff --git a/src/osmo-bsc/abis_om2000.c b/src/osmo-bsc/abis_om2000.c
index 8ee6371c0..fc40cc4a7 100644
--- a/src/osmo-bsc/abis_om2000.c
+++ b/src/osmo-bsc/abis_om2000.c
@@ -2965,11 +2965,13 @@ int abis_om2k_rcvmsg(struct msgb *msg)
switch (msg_type) {
case OM2K_MSGT_CAL_TIME_REQ:
rc = abis_om2k_cal_time_resp(bts);
- break;
+ /* we receive this from MOs without FSM (https://osmocom.org/issues/4670) */
+ goto no_mo;
case OM2K_MSGT_FAULT_REP:
display_fault_maps(msg->l2h, msgb_l2len(msg), &o2h->mo);
rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_FAULT_REP_ACK);
- break;
+ /* we receive this from MOs without FSM (https://osmocom.org/issues/4643) */
+ goto no_mo;
case OM2K_MSGT_NEGOT_REQ:
rc = om2k_rx_negot_req(msg);
break;
@@ -3042,17 +3044,18 @@ int abis_om2k_rcvmsg(struct msgb *msg)
if (!mo) {
LOGP(DNM, LOGL_ERROR, "Couldn't resolve MO for OM2K msg "
"%s: %s\n", get_value_string(om2k_msgcode_vals, msg_type), msgb_hexdump(msg));
- return 0;
+ goto no_mo;
}
if (!mo->fsm) {
LOGP(DNM, LOGL_ERROR, "MO object should not generate any message. fsm == NULL "
"%s: %s\n", get_value_string(om2k_msgcode_vals, msg_type), msgb_hexdump(msg));
- return 0;
+ goto no_mo;
}
/* Dispatch message to that MO */
om2k_mo_fsm_recvmsg(bts, mo, &odm);
+no_mo:
msgb_free(msg);
return rc;
}
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index 0e2ffc698..402ea27bc 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -56,6 +56,7 @@
#include <osmocom/bsc/smscb.h>
#include <osmocom/bsc/bts.h>
#include <osmocom/bsc/power_control.h>
+#include <osmocom/bsc/chan_counts.h>
static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan,
struct gsm_meas_rep *resp)
@@ -525,11 +526,11 @@ static int put_mr_config_for_bts(struct msgb *msg, const struct gsm48_multi_rate
/* indicate FACCH/SACCH Repetition to be performed by BTS,
* see also: 3GPP TS 44.006, section 10 and 11 */
-static void rep_acch_cap_for_bts(struct gsm_lchan *lchan,
- struct msgb *msg)
+static void put_rep_acch_cap_ie(const struct gsm_lchan *lchan,
+ struct msgb *msg)
{
struct abis_rsl_osmo_rep_acch_cap *cap;
- struct gsm_bts *bts = lchan->ts->trx->bts;
+ const struct gsm_bts *bts = lchan->ts->trx->bts;
/* The RSL_IE_OSMO_REP_ACCH_CAP IE is a proprietary IE, that can only
* be used with osmo-bts type BTSs */
@@ -539,7 +540,7 @@ static void rep_acch_cap_for_bts(struct gsm_lchan *lchan,
cap = (struct abis_rsl_osmo_rep_acch_cap*) msg->tail;
msgb_tlv_put(msg, RSL_IE_OSMO_REP_ACCH_CAP, sizeof(*cap),
- (uint8_t*) &bts->repeated_acch_policy);
+ (uint8_t *)&bts->rep_acch_cap);
if (!(lchan->conn && lchan->conn->cm3_valid
&& lchan->conn->cm3.repeated_acch_capability)) {
@@ -553,32 +554,31 @@ static void rep_acch_cap_for_bts(struct gsm_lchan *lchan,
}
/* indicate Temporary overpower of SACCH and FACCH channels */
-static void top_acch_cap_for_bts(struct gsm_lchan *lchan, struct msgb *msg)
+static void put_top_acch_cap_ie(const struct gsm_lchan *lchan,
+ const struct rsl_ie_chan_mode *cm,
+ struct msgb *msg)
{
- struct abis_rsl_osmo_temp_ovp_acch_cap cap;
- struct gsm_bts *bts = lchan->ts->trx->bts;
- bool acch_rep_enabled;
- bool acch_rep_supp_by_ms;
+ const struct gsm_bts *bts = lchan->ts->trx->bts;
/* The BTS_FEAT_ACCH_TEMP_OVP IE is a proprietary IE, that can only be used with osmo-bts type BTSs */
if (!(bts->model->type == GSM_BTS_TYPE_OSMOBTS && osmo_bts_has_feature(&bts->features, BTS_FEAT_ACCH_TEMP_OVP)))
return;
- memcpy(&cap, &bts->temporary_overpower, sizeof(cap));
-
- /* The user has enabled one of the two downlink related ACCH repetition features. */
- acch_rep_enabled = bts->repeated_acch_policy.dl_sacch || bts->repeated_acch_policy.dl_facch_all
- || bts->repeated_acch_policy.dl_facch_cmd;
-
- /* The MS indicates support for ACCH repetition */
- acch_rep_supp_by_ms = lchan->conn && lchan->conn->cm3_valid && lchan->conn->cm3.repeated_acch_capability;
-
- /* If the MS fully supports repeated ACCH capabilites as specified in 3GPP TS 44.006, section 10 and 11. and if
- * ACCH repetition is enabled for this BTS, then we will not apply temporary overpower. */
- if (acch_rep_enabled && acch_rep_supp_by_ms)
- cap.overpower_db = 0;
+ /* Check if TOP is permitted for the given Channel Mode */
+ switch (bts->top_acch_chan_mode) {
+ case TOP_ACCH_CHAN_MODE_SPEECH_V3:
+ if (cm->spd_ind != RSL_CMOD_SPD_SPEECH)
+ return;
+ if (cm->chan_rate != RSL_CMOD_SP_GSM3)
+ return;
+ break;
+ case TOP_ACCH_CHAN_MODE_ANY:
+ break;
+ }
- msgb_tlv_put(msg, RSL_IE_OSMO_TEMP_OVP_ACCH_CAP, sizeof(cap), (uint8_t*) &cap);
+ msgb_tlv_put(msg, RSL_IE_OSMO_TEMP_OVP_ACCH_CAP,
+ sizeof(bts->top_acch_cap),
+ (void *)&bts->top_acch_cap);
}
/* Write RSL_IE_OSMO_TRAINING_SEQUENCE to msgb. The tsc_set argument's range is 1-4, tsc argument range is 0-7. */
@@ -691,13 +691,19 @@ int rsl_tx_chan_activ(struct gsm_lchan *lchan, uint8_t act_type, uint8_t ho_ref)
if (bts->type == GSM_BTS_TYPE_BS11)
ta <<= 2;
msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
+ } else if ((act_type & 0x06) == 0x00) {
+ /* Note '4)' in section 8.4.1: The Timing Advance element must be
+ * included if activation type is intra cell channel change. */
+ LOG_LCHAN(lchan, LOGL_NOTICE, "Timing Advance IE shall be present, "
+ "but the actual value is not known => assuming 0\n");
+ msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, 0);
}
/* BS/MS Power Control Parameters (if supported by BTS model) */
add_power_control_params(msg, RSL_IE_BS_POWER_PARAM, lchan);
add_power_control_params(msg, RSL_IE_MS_POWER_PARAM, lchan);
- if (gsm48_chan_mode_to_non_vamos(lchan->activate.ch_mode_rate.chan_mode) == GSM48_CMODE_SPEECH_AMR) {
+ if (cm.chan_rate == RSL_CMOD_SP_GSM3) {
rc = put_mr_config_for_bts(msg, &lchan->activate.mr_conf_filtered,
(lchan->type == GSM_LCHAN_TCH_F) ? &bts->mr_full : &bts->mr_half);
if (rc) {
@@ -707,8 +713,8 @@ int rsl_tx_chan_activ(struct gsm_lchan *lchan, uint8_t act_type, uint8_t ho_ref)
}
}
- rep_acch_cap_for_bts(lchan, msg);
- top_acch_cap_for_bts(lchan, msg);
+ put_rep_acch_cap_ie(lchan, msg);
+ put_top_acch_cap_ie(lchan, &cm, msg);
/* Selecting a specific TSC Set is only applicable to VAMOS mode */
if (lchan->activate.info.vamos && lchan->activate.tsc_set >= 1)
@@ -769,7 +775,7 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan)
}
}
- if (gsm48_chan_mode_to_non_vamos(lchan->modify.ch_mode_rate.chan_mode) == GSM48_CMODE_SPEECH_AMR) {
+ if (cm.chan_rate == RSL_CMOD_SP_GSM3) {
rc = put_mr_config_for_bts(msg, &lchan->modify.mr_conf_filtered,
(lchan->type == GSM_LCHAN_TCH_F) ? &bts->mr_full : &bts->mr_half);
if (rc) {
@@ -779,8 +785,8 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan)
}
}
- rep_acch_cap_for_bts(lchan, msg);
- top_acch_cap_for_bts(lchan, msg);
+ put_rep_acch_cap_ie(lchan, msg);
+ put_top_acch_cap_ie(lchan, &cm, msg);
/* Selecting a specific TSC Set is only applicable to VAMOS mode. Send this Osmocom specific IE only to OsmoBTS
* types. */
@@ -1015,6 +1021,106 @@ int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci)
}
+/* For 3GPP TS 52.402 unsuccReqsForService, we need to decode the DTAP and count CM Service Reject messages. */
+static void count_unsucc_reqs_for_service(const struct msgb *msg)
+{
+ struct gsm_bts *bts = msg->lchan->ts->trx->bts;
+ const struct gsm48_hdr *gh;
+ uint8_t pdisc, mtype;
+ uint8_t cause;
+
+ if (msgb_l3len(msg) < sizeof(*gh))
+ return;
+
+ gh = msgb_l3(msg);
+ pdisc = gsm48_hdr_pdisc(gh);
+ mtype = gsm48_hdr_msg_type(gh);
+
+ if (pdisc != GSM48_PDISC_MM || mtype != GSM48_MT_MM_CM_SERV_REJ)
+ return;
+
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ));
+
+ cause = gh->data[0];
+ switch (cause) {
+ case GSM48_REJECT_IMSI_UNKNOWN_IN_HLR:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_IMSI_UNKNOWN_IN_HLR));
+ break;
+ case GSM48_REJECT_ILLEGAL_MS:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_ILLEGAL_MS));
+ break;
+ case GSM48_REJECT_IMSI_UNKNOWN_IN_VLR:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_IMSI_UNKNOWN_IN_VLR));
+ break;
+ case GSM48_REJECT_IMEI_NOT_ACCEPTED:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_IMEI_NOT_ACCEPTED));
+ break;
+ case GSM48_REJECT_ILLEGAL_ME:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_ILLEGAL_ME));
+ break;
+ case GSM48_REJECT_PLMN_NOT_ALLOWED:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_PLMN_NOT_ALLOWED));
+ break;
+ case GSM48_REJECT_LOC_NOT_ALLOWED:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_LOC_NOT_ALLOWED));
+ break;
+ case GSM48_REJECT_ROAMING_NOT_ALLOWED:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_ROAMING_NOT_ALLOWED));
+ break;
+ case GSM48_REJECT_NETWORK_FAILURE:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_NETWORK_FAILURE));
+ break;
+ case GSM48_REJECT_SYNCH_FAILURE:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_SYNCH_FAILURE));
+ break;
+ case GSM48_REJECT_CONGESTION:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_CONGESTION));
+ break;
+ case GSM48_REJECT_SRV_OPT_NOT_SUPPORTED:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_SRV_OPT_NOT_SUPPORTED));
+ break;
+ case GSM48_REJECT_RQD_SRV_OPT_NOT_SUPPORTED:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_RQD_SRV_OPT_NOT_SUPPORTED));
+ break;
+ case GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_SRV_OPT_TMP_OUT_OF_ORDER));
+ break;
+ case GSM48_REJECT_CALL_CAN_NOT_BE_IDENTIFIED:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_CALL_CAN_NOT_BE_IDENTIFIED));
+ break;
+ case GSM48_REJECT_INCORRECT_MESSAGE:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_INCORRECT_MESSAGE));
+ break;
+ case GSM48_REJECT_INVALID_MANDANTORY_INF:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_INVALID_MANDANTORY_INF));
+ break;
+ case GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_MSG_TYPE_NOT_IMPLEMENTED));
+ break;
+ case GSM48_REJECT_MSG_TYPE_NOT_COMPATIBLE:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_MSG_TYPE_NOT_COMPATIBLE));
+ break;
+ case GSM48_REJECT_INF_ELEME_NOT_IMPLEMENTED:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_INF_ELEME_NOT_IMPLEMENTED));
+ break;
+ case GSM48_REJECT_CONDTIONAL_IE_ERROR:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_CONDTIONAL_IE_ERROR));
+ break;
+ case GSM48_REJECT_MSG_NOT_COMPATIBLE:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_MSG_NOT_COMPATIBLE));
+ break;
+ default:
+ if (cause >= 48 && cause <= 63) {
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_RETRY_IN_NEW_CELL));
+ break;
+ }
+ /* else fall thru */
+ case GSM48_REJECT_PROTOCOL_ERROR:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CM_SERV_REJ_PROTOCOL_ERROR));
+ break;
+ }
+}
+
/* Send "DATA REQUEST" message with given L3 Info payload */
/* Chapter 8.3.1 */
int rsl_data_request(struct msgb *msg, uint8_t link_id)
@@ -1027,6 +1133,8 @@ int rsl_data_request(struct msgb *msg, uint8_t link_id)
return -EINVAL;
}
+ count_unsucc_reqs_for_service(msg);
+
chan_nr = gsm_lchan2chan_nr(msg->lchan, true);
if (chan_nr < 0) {
msgb_free(msg);
@@ -1162,7 +1270,9 @@ static int rsl_rx_conn_fail(struct msgb *msg)
return 0;
}
-static void print_meas_rep_uni(struct osmo_strbuf *sb, struct gsm_meas_rep_unidir *mru, const char *prefix)
+static void print_meas_rep_uni(struct osmo_strbuf *sb,
+ const struct gsm_meas_rep_unidir *mru,
+ const char *prefix)
{
OSMO_STRBUF_PRINTF(*sb, "RXL-FULL-%s=%3ddBm RXL-SUB-%s=%3ddBm ",
prefix, rxlev2dbm(mru->full.rx_lev),
@@ -1171,21 +1281,11 @@ static void print_meas_rep_uni(struct osmo_strbuf *sb, struct gsm_meas_rep_unidi
prefix, mru->full.rx_qual, prefix, mru->sub.rx_qual);
}
-static int print_meas_rep_buf(char *buf, size_t len, struct gsm_lchan *lchan, struct gsm_meas_rep *mr)
+static int print_meas_rep_buf(char *buf, size_t len, const struct gsm_meas_rep *mr)
{
- const char *name = "";
- struct bsc_subscr *bsub = NULL;
struct osmo_strbuf sb = { .buf = buf, .len = len };
- if (lchan && lchan->conn) {
- bsub = lchan->conn->bsub;
- if (bsub) {
- name = bsc_subscr_name(bsub);
- } else
- name = lchan->name;
- }
-
- OSMO_STRBUF_PRINTF(sb, "[%s] MEASUREMENT RESULT NR=%d ", name, mr->nr);
+ OSMO_STRBUF_PRINTF(sb, "MEASUREMENT RESULT NR=%d ", mr->nr);
if (mr->flags & MEAS_REP_F_DL_DTX)
OSMO_STRBUF_PRINTF(sb, "DTXd ");
@@ -1216,31 +1316,36 @@ static int print_meas_rep_buf(char *buf, size_t len, struct gsm_lchan *lchan, st
return sb.chars_needed;
}
-static char *print_meas_rep_c(void *ctx, struct gsm_lchan *lchan, struct gsm_meas_rep *mr)
+static char *print_meas_rep_c(void *ctx, const struct gsm_meas_rep *mr)
{
/* A naive count of required characters gets me to ~200, so 256 should be safe to get a large enough buffer on
* the first time. */
- OSMO_NAME_C_IMPL(ctx, 256, "ERROR", print_meas_rep_buf, lchan, mr)
+ OSMO_NAME_C_IMPL(ctx, 256, "ERROR", print_meas_rep_buf, mr)
}
-static void print_meas_rep(struct gsm_lchan *lchan, struct gsm_meas_rep *mr)
+static void print_meas_rep(struct gsm_lchan *lchan, const struct gsm_meas_rep *mr)
{
int i;
+ const char *name = "";
struct bsc_subscr *bsub = NULL;
if (lchan && lchan->conn) {
bsub = lchan->conn->bsub;
- if (bsub)
+ if (bsub) {
log_set_context(LOG_CTX_BSC_SUBSCR, bsub);
+ name = bsc_subscr_name(bsub);
+ } else {
+ name = lchan->name;
+ }
}
- DEBUGP(DMEAS, "%s\n", print_meas_rep_c(OTC_SELECT, lchan, mr));
+ DEBUGP(DMEAS, "[%s] %s\n", name, print_meas_rep_c(OTC_SELECT, mr));
if (mr->num_cell != 7
&& log_check_level(DMEAS, LOGL_DEBUG)) {
for (i = 0; i < mr->num_cell; i++) {
- struct gsm_meas_rep_cell *mrc = &mr->cell[i];
- DEBUGP(DMEAS, "IDX=%u ARFCN=%u BSIC=%u => %d dBm\n",
+ const struct gsm_meas_rep_cell *mrc = &mr->cell[i];
+ DEBUGP(DMEAS, "IDX=%u ARFCN=%u BSIC=%u RXLEV=%ddBm\n",
mrc->neigh_idx, mrc->arfcn, mrc->bsic, rxlev2dbm(mrc->rxlev));
}
}
@@ -1958,6 +2063,7 @@ static bool force_free_lchan_for_emergency(struct chan_rqd *rqd)
struct gsm_lchan *_select_sdcch_for_call(struct gsm_bts *bts, const struct chan_rqd *rqd, enum gsm_chan_t lctype)
{
+ struct chan_counts bts_counts;
struct gsm_lchan *lchan = NULL;
int free_tchf, free_tchh;
bool needs_dyn_switch;
@@ -1969,8 +2075,9 @@ struct gsm_lchan *_select_sdcch_for_call(struct gsm_bts *bts, const struct chan_
needs_dyn_switch = lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN &&
lchan->ts->pchan_is != GSM_PCHAN_SDCCH8_SACCH8C;
- free_tchf = bts_count_free_ts(bts, GSM_PCHAN_TCH_F);
- free_tchh = bts_count_free_ts(bts, GSM_PCHAN_TCH_H);
+ chan_counts_for_bts(&bts_counts, bts);
+ free_tchf = bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F];
+ free_tchh = bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H];
if (free_tchf == 0 && free_tchh == 0) {
LOG_BTS(bts, DRSL, LOGL_INFO,
"CHAN RQD: 0x%x Requesting %s reason=call but no TCH available\n",
@@ -2091,6 +2198,7 @@ void abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts)
gsm_chreq_name(rqd->reason), rqd->ref.ra, rqd->ta);
info = (struct lchan_activate_info){
.activ_for = ACTIVATE_FOR_MS_CHANNEL_REQUEST,
+ .chreq_reason = rqd->reason,
.ch_mode_rate = {
.chan_mode = GSM48_CMODE_SIGN,
.chan_rate = CH_RATE_SDCCH,
@@ -2106,6 +2214,35 @@ void abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts)
return;
}
+static void imm_ass_rate_ctr(struct gsm_lchan *lchan)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_SUCCESSFUL));
+ switch (lchan->activate.info.chreq_reason) {
+ case GSM_CHREQ_REASON_EMERG:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_SUCCESSFUL_EMERG));
+ break;
+ case GSM_CHREQ_REASON_CALL:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_SUCCESSFUL_CALL));
+ break;
+ case GSM_CHREQ_REASON_LOCATION_UPD:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_SUCCESSFUL_LOCATION_UPD));
+ break;
+ case GSM_CHREQ_REASON_PAG:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_SUCCESSFUL_PAG));
+ break;
+ case GSM_CHREQ_REASON_PDCH:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_SUCCESSFUL_PDCH));
+ break;
+ case GSM_CHREQ_REASON_OTHER:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_SUCCESSFUL_OTHER));
+ break;
+ default:
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_SUCCESSFUL_UNKNOWN));
+ break;
+ }
+}
+
int rsl_tx_imm_assignment(struct gsm_lchan *lchan)
{
int rc;
@@ -2150,7 +2287,7 @@ int rsl_tx_imm_assignment(struct gsm_lchan *lchan)
rc = rsl_imm_assign_cmd(bts, sizeof(*ia)+ia->mob_alloc_len, (uint8_t *) ia);
if (!rc)
- rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_SUCCESSFUL));
+ imm_ass_rate_ctr(lchan);
return rc;
}
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index 1449bdbae..0243058b3 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -74,7 +74,7 @@ static const struct osmo_tdef_state_timeout assignment_fsm_timeouts[32] = {
osmo_fsm_inst_state_name(fi), gsm0808_cause_name(cause), ## args); \
assignment_count_result(CTR_ASSIGNMENT_ERROR); \
on_assignment_failure(_conn); \
- } while(0)
+ } while (0)
/* Assume presence of local var 'conn' as struct gsm_subscriber_connection */
#define assignment_count(counter) do { \
@@ -88,17 +88,25 @@ static const struct osmo_tdef_state_timeout assignment_fsm_timeouts[32] = {
switch (gsm48_chan_mode_to_non_vamos(conn->assignment.req.ch_mode_rate_list[0].chan_mode)) { \
case GSM48_CMODE_SIGN: \
rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_##counter##_SIGN)); \
+ LOG_ASSIGNMENT(conn, LOGL_DEBUG, "incrementing rate counter: bts%u %s %s\n", \
+ bts->nr, \
+ bts_ctr_description[BTS_##counter##_SIGN].name, \
+ bts_ctr_description[BTS_##counter##_SIGN].description); \
break; \
case GSM48_CMODE_SPEECH_V1: \
case GSM48_CMODE_SPEECH_EFR: \
case GSM48_CMODE_SPEECH_AMR: \
rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_##counter##_SPEECH)); \
+ LOG_ASSIGNMENT(conn, LOGL_DEBUG, "incrementing rate counter: bts%u %s %s\n", \
+ bts->nr, \
+ bts_ctr_description[BTS_##counter##_SPEECH].name, \
+ bts_ctr_description[BTS_##counter##_SPEECH].description); \
break; \
default: \
break; \
} \
} \
- } while(0)
+ } while (0)
#define assignment_count_result(counter) do { \
if (!conn->assignment.result_rate_ctr_done) { \
@@ -109,7 +117,7 @@ static const struct osmo_tdef_state_timeout assignment_fsm_timeouts[32] = {
"result rate counter already recorded, NOT counting as: %s %s\n", \
bsc_ctr_description[BSC_##counter].name, \
bsc_ctr_description[BSC_##counter].description); \
- } while(0)
+ } while (0)
void assignment_reset(struct gsm_subscriber_connection *conn)
{
@@ -287,10 +295,10 @@ static void assignment_success(struct gsm_subscriber_connection *conn)
conn->user_plane.msc_assigned_rtp_port = conn->assignment.req.msc_rtp_port;
}
+ assignment_count_result(CTR_ASSIGNMENT_COMPLETED);
+
LOG_ASSIGNMENT(conn, LOGL_DEBUG, "Assignment successful\n");
osmo_fsm_inst_term(conn->assignment.fi, OSMO_FSM_TERM_REGULAR, 0);
-
- assignment_count_result(CTR_ASSIGNMENT_COMPLETED);
}
static void assignment_fsm_update_id(struct gsm_subscriber_connection *conn)
@@ -959,7 +967,7 @@ static void assignment_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t ev
assignment_fail(new_lchan->activate.gsm0808_error_cause,
"Failed to %s lchan %s",
conn->assignment.new_lchan ? "activate" : "modify",
- conn->assignment.new_lchan ? gsm_lchan_name(conn->assignment.new_lchan) : "");
+ gsm_lchan_name(new_lchan));
return;
default:
diff --git a/src/osmo-bsc/bsc_ctrl_commands.c b/src/osmo-bsc/bsc_ctrl_commands.c
index a94baae25..fb8bd0cec 100644
--- a/src/osmo-bsc/bsc_ctrl_commands.c
+++ b/src/osmo-bsc/bsc_ctrl_commands.c
@@ -35,6 +35,7 @@
#include <osmocom/bsc/osmo_bsc_rf.h>
#include <osmocom/bsc/bsc_msc_data.h>
#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/neighbor_ident.h>
static int verify_net_apply_config_file(struct ctrl_cmd *cmd, const char *value, void *_data)
{
@@ -667,6 +668,120 @@ static int set_bts_c0_power_red(struct ctrl_cmd *cmd, void *data)
CTRL_CMD_DEFINE(bts_c0_power_red, "c0-power-reduction");
+static int verify_bts_neighbor_list_add_del(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ int arfcn;
+
+ if (osmo_str_to_int(&arfcn, value, 10, 0, 1023) < 0) {
+ cmd->reply = "Invalid ARFCN value";
+ return 1;
+ }
+
+ return 0;
+}
+
+static int set_bts_neighbor_list_add_del(struct ctrl_cmd *cmd, void *data, bool add)
+{
+ struct gsm_bts *bts = cmd->node;
+ struct bitvec *bv = &bts->si_common.neigh_list;
+ int arfcn_int;
+ uint16_t arfcn;
+ enum gsm_band unused;
+
+ if (osmo_str_to_int(&arfcn_int, cmd->value, 10, 0, 1023) < 0) {
+ cmd->reply = "Failed to parse ARFCN value";
+ return CTRL_CMD_ERROR;
+ }
+ arfcn = (uint16_t) arfcn_int;
+
+ if (bts->neigh_list_manual_mode == NL_MODE_AUTOMATIC) {
+ cmd->reply = "Neighbor list not in manual mode";
+ return CTRL_CMD_ERROR;
+ }
+
+ if (gsm_arfcn2band_rc(arfcn, &unused) < 0) {
+ cmd->reply = "Invalid arfcn detected";
+ return CTRL_CMD_ERROR;
+ }
+
+ if (add)
+ bitvec_set_bit_pos(bv, arfcn, 1);
+ else
+ bitvec_set_bit_pos(bv, arfcn, 0);
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+static int verify_bts_neighbor_list_add(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ return verify_bts_neighbor_list_add_del(cmd, value, _data);
+}
+
+static int set_bts_neighbor_list_add(struct ctrl_cmd *cmd, void *data)
+{
+ return set_bts_neighbor_list_add_del(cmd, data, true);
+}
+
+CTRL_CMD_DEFINE_WO(bts_neighbor_list_add, "neighbor-list add");
+
+static int verify_bts_neighbor_list_del(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ return verify_bts_neighbor_list_add_del(cmd, value, _data);
+}
+
+static int set_bts_neighbor_list_del(struct ctrl_cmd *cmd, void *data)
+{
+ return set_bts_neighbor_list_add_del(cmd, data, false);
+}
+
+CTRL_CMD_DEFINE_WO(bts_neighbor_list_del, "neighbor-list del");
+
+static int verify_bts_neighbor_list_mode(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (!strcmp(value, "automatic"))
+ return 0;
+ if (!strcmp(value, "manual"))
+ return 0;
+ if (!strcmp(value, "manual-si5"))
+ return 0;
+
+ cmd->reply = "Invalid mode";
+ return 1;
+}
+
+static int set_bts_neighbor_list_mode(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ int mode = NL_MODE_AUTOMATIC;
+
+ if (!strcmp(cmd->value, "automatic"))
+ mode = NL_MODE_AUTOMATIC;
+ else if (!strcmp(cmd->value, "manual"))
+ mode = NL_MODE_MANUAL;
+ else if (!strcmp(cmd->value, "manual-si5"))
+ mode = NL_MODE_MANUAL_SI5SEP;
+
+ switch (mode) {
+ case NL_MODE_MANUAL_SI5SEP:
+ case NL_MODE_MANUAL:
+ /* make sure we clear the current list when switching to
+ * manual mode */
+ if (bts->neigh_list_manual_mode == 0)
+ memset(&bts->si_common.data.neigh_list, 0, sizeof(bts->si_common.data.neigh_list));
+ break;
+ default:
+ break;
+ }
+
+ bts->neigh_list_manual_mode = mode;
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+CTRL_CMD_DEFINE_WO(bts_neighbor_list_mode, "neighbor-list mode");
+
int bsc_base_ctrl_cmds_install(void)
{
int rc = 0;
@@ -691,6 +806,11 @@ int bsc_base_ctrl_cmds_install(void)
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_rf_state);
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_rf_states);
rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_c0_power_red);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_neighbor_list_add);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_neighbor_list_del);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_neighbor_list_mode);
+
+ rc |= neighbor_ident_ctrl_init();
rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_max_power);
rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_arfcn);
diff --git a/src/osmo-bsc/bsc_ctrl_lookup.c b/src/osmo-bsc/bsc_ctrl_lookup.c
index 4328d76eb..6a11e321e 100644
--- a/src/osmo-bsc/bsc_ctrl_lookup.c
+++ b/src/osmo-bsc/bsc_ctrl_lookup.c
@@ -15,10 +15,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#include <errno.h>
diff --git a/src/osmo-bsc/bsc_init.c b/src/osmo-bsc/bsc_init.c
index bf150cb40..0412f6b6b 100644
--- a/src/osmo-bsc/bsc_init.c
+++ b/src/osmo-bsc/bsc_init.c
@@ -120,6 +120,51 @@ static struct gsm_network *bsc_network_init(void *ctx)
if (!net->bts_unknown_statg)
goto err_free_all;
+ net->all_allocated_sdcch = (struct osmo_time_cc){
+ .cfg = {
+ .gran_usec = 1*1000000,
+ .forget_sum_usec = 60*1000000,
+ .rate_ctr = rate_ctr_group_get_ctr(net->bsc_ctrs, BSC_CTR_ALL_ALLOCATED_SDCCH),
+ .T_gran = -16,
+ .T_round_threshold = -17,
+ .T_forget_sum = -18,
+ .T_defs = net->T_defs,
+ },
+ };
+ net->all_allocated_static_sdcch = (struct osmo_time_cc){
+ .cfg = {
+ .gran_usec = 1*1000000,
+ .forget_sum_usec = 60*1000000,
+ .rate_ctr = rate_ctr_group_get_ctr(net->bsc_ctrs, BSC_CTR_ALL_ALLOCATED_STATIC_SDCCH),
+ .T_gran = -16,
+ .T_round_threshold = -17,
+ .T_forget_sum = -18,
+ .T_defs = net->T_defs,
+ },
+ };
+ net->all_allocated_tch = (struct osmo_time_cc){
+ .cfg = {
+ .gran_usec = 1*1000000,
+ .forget_sum_usec = 60*1000000,
+ .rate_ctr = rate_ctr_group_get_ctr(net->bsc_ctrs, BSC_CTR_ALL_ALLOCATED_TCH),
+ .T_gran = -16,
+ .T_round_threshold = -17,
+ .T_forget_sum = -18,
+ .T_defs = net->T_defs,
+ },
+ };
+ net->all_allocated_static_tch = (struct osmo_time_cc){
+ .cfg = {
+ .gran_usec = 1*1000000,
+ .forget_sum_usec = 60*1000000,
+ .rate_ctr = rate_ctr_group_get_ctr(net->bsc_ctrs, BSC_CTR_ALL_ALLOCATED_STATIC_TCH),
+ .T_gran = -16,
+ .T_round_threshold = -17,
+ .T_forget_sum = -18,
+ .T_defs = net->T_defs,
+ },
+ };
+
INIT_LLIST_HEAD(&net->bts_rejected);
gsm_net_update_ctype(net);
diff --git a/src/osmo-bsc/bsc_stats.c b/src/osmo-bsc/bsc_stats.c
index 717680956..b48c90a00 100644
--- a/src/osmo-bsc/bsc_stats.c
+++ b/src/osmo-bsc/bsc_stats.c
@@ -25,6 +25,7 @@
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/chan_counts.h>
const struct rate_ctr_desc bsc_ctr_description[] = {
[BSC_CTR_ASSIGNMENT_ATTEMPTED] = {"assignment:attempted", "Assignment attempts"},
@@ -35,13 +36,13 @@ const struct rate_ctr_desc bsc_ctr_description[] = {
[BSC_CTR_ASSIGNMENT_FAILED] = {"assignment:failed", "Received Assignment Failure message"},
[BSC_CTR_ASSIGNMENT_ERROR] = {"assignment:error", "Assignment failed for other reason"},
- [BSC_CTR_HANDOVER_ATTEMPTED] = {"handover:attempted", "Intra-BSC handover attempts"},
- [BSC_CTR_HANDOVER_COMPLETED] = {"handover:completed", "Intra-BSC handover completed"},
+ [BSC_CTR_HANDOVER_ATTEMPTED] = {"handover:attempted", "Handover attempts"},
+ [BSC_CTR_HANDOVER_COMPLETED] = {"handover:completed", "Handover completed"},
[BSC_CTR_HANDOVER_STOPPED] = {"handover:stopped", "Connection ended during HO"},
[BSC_CTR_HANDOVER_NO_CHANNEL] = {"handover:no_channel", "Failure to allocate lchan for HO"},
[BSC_CTR_HANDOVER_TIMEOUT] = {"handover:timeout", "Handover timed out"},
[BSC_CTR_HANDOVER_FAILED] = {"handover:failed", "Received Handover Fail messages"},
- [BSC_CTR_HANDOVER_ERROR] = {"handover:error", "Re-assignment failed for other reason"},
+ [BSC_CTR_HANDOVER_ERROR] = {"handover:error", "Handover failed for other reason"},
[BSC_CTR_INTRA_CELL_HO_ATTEMPTED] = {"intra_cell_ho:attempted", "Intra-Cell handover attempts"},
[BSC_CTR_INTRA_CELL_HO_COMPLETED] = {"intra_cell_ho:completed", "Intra-Cell handover completed"},
@@ -49,15 +50,15 @@ const struct rate_ctr_desc bsc_ctr_description[] = {
[BSC_CTR_INTRA_CELL_HO_NO_CHANNEL] = {"intra_cell_ho:no_channel", "Failure to allocate lchan for HO"},
[BSC_CTR_INTRA_CELL_HO_TIMEOUT] = {"intra_cell_ho:timeout", "Handover timed out"},
[BSC_CTR_INTRA_CELL_HO_FAILED] = {"intra_cell_ho:failed", "Received Handover Fail messages"},
- [BSC_CTR_INTRA_CELL_HO_ERROR] = {"intra_cell_ho:error", "Re-assignment failed for other reason"},
+ [BSC_CTR_INTRA_CELL_HO_ERROR] = {"intra_cell_ho:error", "Intra-cell handover failed for other reason"},
- [BSC_CTR_INTRA_BSC_HO_ATTEMPTED] = {"intra_bsc_ho:attempted", "Intra-BSC handover attempts"},
- [BSC_CTR_INTRA_BSC_HO_COMPLETED] = {"intra_bsc_ho:completed", "Intra-BSC handover completed"},
+ [BSC_CTR_INTRA_BSC_HO_ATTEMPTED] = {"intra_bsc_ho:attempted", "Intra-BSC inter-cell handover attempts"},
+ [BSC_CTR_INTRA_BSC_HO_COMPLETED] = {"intra_bsc_ho:completed", "Intra-BSC inter-cell handover completed"},
[BSC_CTR_INTRA_BSC_HO_STOPPED] = {"intra_bsc_ho:stopped", "Connection ended during HO"},
[BSC_CTR_INTRA_BSC_HO_NO_CHANNEL] = {"intra_bsc_ho:no_channel", "Failure to allocate lchan for HO"},
[BSC_CTR_INTRA_BSC_HO_TIMEOUT] = {"intra_bsc_ho:timeout", "Handover timed out"},
[BSC_CTR_INTRA_BSC_HO_FAILED] = {"intra_bsc_ho:failed", "Received Handover Fail messages"},
- [BSC_CTR_INTRA_BSC_HO_ERROR] = {"intra_bsc_ho:error", "Re-assignment failed for other reason"},
+ [BSC_CTR_INTRA_BSC_HO_ERROR] = {"intra_bsc_ho:error", "Intra-BSC inter-cell HO failed for other reason"},
[BSC_CTR_INTER_BSC_HO_OUT_ATTEMPTED] = {"interbsc_ho_out:attempted",
"Attempts to handover to remote BSS"},
@@ -92,6 +93,7 @@ const struct rate_ctr_desc bsc_ctr_description[] = {
[BSC_CTR_PAGING_ATTEMPTED] = {"paging:attempted", "Paging attempts for a subscriber"},
[BSC_CTR_PAGING_DETACHED] = {"paging:detached", "Paging request send failures because no responsible BTS was found"},
[BSC_CTR_PAGING_RESPONDED] = {"paging:responded", "Paging attempts with successful response"},
+ [BSC_CTR_PAGING_EXPIRED] = {"paging:expired", "Paging Request expired because of timeout T3113"},
[BSC_CTR_PAGING_NO_ACTIVE_PAGING] = {"paging:no_active_paging", "Paging response without an active paging request (arrived after paging expiration?)"},
[BSC_CTR_UNKNOWN_UNIT_ID] = {"abis:unknown_unit_id", "Connection attempts from unknown IPA CCM Unit ID"},
@@ -102,6 +104,12 @@ const struct rate_ctr_desc bsc_ctr_description[] = {
"Emergency call requests forwarded to an MSC (see also per-MSC counters"},
[BSC_CTR_MSCPOOL_EMERG_LOST] = {"mscpool:emerg:lost",
"Emergency call requests lost because no MSC was found available"},
+ [BSC_CTR_ALL_ALLOCATED_SDCCH] = {"all_allocated:sdcch", "Cumulative counter of seconds where all SDCCH channels were allocated"},
+ [BSC_CTR_ALL_ALLOCATED_STATIC_SDCCH] = {"all_allocated:static_sdcch",
+ "Cumulative counter of seconds where all non-dynamic SDCCH channels were allocated"},
+ [BSC_CTR_ALL_ALLOCATED_TCH] = {"all_allocated:tch", "Cumulative counter of seconds where all TCH channels were allocated"},
+ [BSC_CTR_ALL_ALLOCATED_STATIC_TCH] = {"all_allocated:static_tch",
+ "Cumulative counter of seconds where all non-dynamic TCH channels were allocated"},
};
const struct rate_ctr_group_desc bsc_ctrg_desc = {
@@ -185,4 +193,69 @@ void bsc_update_connection_stats(struct gsm_network *net)
osmo_stat_item_set(osmo_stat_item_group_get_item(net->bsc_statg, BSC_STAT_NUM_TRX_RSL_CONNECTED),
trx_rsl_connected_total);
osmo_stat_item_set(osmo_stat_item_group_get_item(net->bsc_statg, BSC_STAT_NUM_TRX_TOTAL), num_trx_total);
+
+ /* Make sure to notice cells that become disconnected */
+ bsc_update_time_cc_all_allocated(net);
+}
+
+void bsc_update_time_cc_all_allocated(struct gsm_network *net)
+{
+ struct gsm_bts *bts;
+ struct gsm_bts_trx *trx;
+
+ struct chan_counts bsc_counts;
+ chan_counts_zero(&bsc_counts);
+
+ llist_for_each_entry(bts, &net->bts_list, list) {
+ struct chan_counts bts_counts;
+ chan_counts_zero(&bts_counts);
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ struct chan_counts trx_counts;
+ chan_counts_for_trx(&trx_counts, trx);
+ chan_counts_add(&bts_counts, &trx_counts);
+ }
+
+ osmo_time_cc_set_flag(&bts->all_allocated_sdcch,
+ bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_SDCCH]
+ && !bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_SDCCH]);
+
+ osmo_time_cc_set_flag(&bts->all_allocated_static_sdcch,
+ bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_SDCCH]
+ && !bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_SDCCH]);
+
+ osmo_time_cc_set_flag(&bts->all_allocated_tch,
+ (bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_F]
+ + bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_H])
+ && !(bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F]
+ + bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H]));
+
+ osmo_time_cc_set_flag(&bts->all_allocated_static_tch,
+ (bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_F]
+ + bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_H])
+ && !(bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F]
+ + bts_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H]));
+
+ chan_counts_add(&bsc_counts, &bts_counts);
+ }
+
+ osmo_time_cc_set_flag(&net->all_allocated_sdcch,
+ bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_SDCCH]
+ && !bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_SDCCH]);
+
+ osmo_time_cc_set_flag(&net->all_allocated_static_sdcch,
+ bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_SDCCH]
+ && !bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_SDCCH]);
+
+ osmo_time_cc_set_flag(&net->all_allocated_tch,
+ (bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_F]
+ + bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_H])
+ && !(bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F]
+ + bsc_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H]));
+
+ osmo_time_cc_set_flag(&net->all_allocated_static_tch,
+ (bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_F]
+ + bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_MAX_TOTAL][GSM_LCHAN_TCH_H])
+ && !(bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F]
+ + bsc_counts.val[CHAN_COUNTS1_STATIC][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H]));
}
diff --git a/src/osmo-bsc/bsc_subscr_conn_fsm.c b/src/osmo-bsc/bsc_subscr_conn_fsm.c
index 1e61d3f78..33dd28318 100644
--- a/src/osmo-bsc/bsc_subscr_conn_fsm.c
+++ b/src/osmo-bsc/bsc_subscr_conn_fsm.c
@@ -67,7 +67,8 @@ enum gscon_fsm_states {
ST_ASSIGNMENT,
ST_HANDOVER,
/* BSSMAP CLEAR has been received */
- ST_CLEARING,
+ ST_WAIT_CLEAR_CMD,
+ ST_WAIT_SCCP_RLSD,
};
static const struct value_string gscon_fsm_event_names[] = {
@@ -95,7 +96,8 @@ static const struct value_string gscon_fsm_event_names[] = {
struct osmo_tdef_state_timeout conn_fsm_timeouts[32] = {
[ST_WAIT_CC] = { .T = -3210 },
- [ST_CLEARING] = { .T = -4 },
+ [ST_WAIT_CLEAR_CMD] = { .T = -4 },
+ [ST_WAIT_SCCP_RLSD] = { .T = -4 },
};
/* Transition to a state, using the T timer defined in conn_fsm_timeouts.
@@ -141,31 +143,77 @@ int gscon_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg)
static void gscon_bssmap_clear(struct gsm_subscriber_connection *conn,
enum gsm0808_cause cause)
{
+ /* already clearing? */
+ switch (conn->fi->state) {
+ case ST_WAIT_CLEAR_CMD:
+ case ST_WAIT_SCCP_RLSD:
+ return;
+ default:
+ break;
+ }
+ conn->clear_cause = cause;
+ conn_fsm_state_chg(ST_WAIT_CLEAR_CMD);
+}
+
+static void gscon_fsm_wait_clear_cmd_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
struct msgb *resp;
int rc;
-
- if (conn->rx_clear_command) {
- LOGPFSML(conn->fi, LOGL_DEBUG, "Not sending BSSMAP CLEAR REQUEST, already got CLEAR COMMAND from MSC\n");
- return;
- }
+ struct gsm_subscriber_connection *conn = fi->priv;
+ enum gsm0808_cause cause = conn->clear_cause;
if (!conn->sccp.msc) {
- LOGPFSML(conn->fi, LOGL_ERROR, "Unable to deliver BSSMAP Clear Request message, no MSC for this conn\n");
- return;
+ LOGPFSML(fi, LOGL_ERROR, "Unable to deliver BSSMAP Clear Request message, no MSC for this conn\n");
+ goto nothing_sent;
}
- LOGPFSML(conn->fi, LOGL_DEBUG, "Tx BSSMAP CLEAR REQUEST(%s) to MSC\n", gsm0808_cause_name(cause));
+ LOGPFSML(fi, LOGL_DEBUG, "Tx BSSMAP CLEAR REQUEST(%s) to MSC\n", gsm0808_cause_name(cause));
resp = gsm0808_create_clear_rqst(cause);
if (!resp) {
- LOGPFSML(conn->fi, LOGL_ERROR, "Unable to compose BSSMAP Clear Request message\n");
- return;
+ LOGPFSML(fi, LOGL_ERROR, "Unable to compose BSSMAP Clear Request message\n");
+ goto nothing_sent;
}
rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_CLEAR_RQST));
rc = osmo_bsc_sigtran_send(conn, resp);
- if (rc < 0)
+ if (rc < 0) {
LOGPFSML(conn->fi, LOGL_ERROR, "Unable to deliver BSSMAP Clear Request message\n");
+ goto nothing_sent;
+ }
+ return;
+
+nothing_sent:
+ /* Normally, we request a CLEAR from the MSC and terminate as soon as the CLEAR COMMAND has been issued by the
+ * MSC. But if we are trying to clear without being able to send anything to the MSC, we might as well shut down
+ * the conn right away now. */
+ conn_fsm_state_chg(ST_WAIT_SCCP_RLSD);
+}
+
+void gscon_fsm_wait_sccp_rlsd_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+
+ /* According to 3GPP 48.008 3.1.9.1. "The BSS need not wait for the radio channel
+ * release to be completed or for the guard timer to expire before returning the
+ * CLEAR COMPLETE message" */
+ if (!gscon_sigtran_send(conn, gsm0808_create_clear_complete()))
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_CLEAR_COMPLETE));
+
+ /* Give the handover_fsm a chance to book this as handover success before tearing down everything,
+ * making it look like a sudden death failure. */
+ if (conn->ho.fi)
+ osmo_fsm_inst_dispatch(conn->ho.fi, HO_EV_CONN_RELEASING, NULL);
+
+ if (conn->lcs.loc_req)
+ osmo_fsm_inst_dispatch(conn->lcs.loc_req->fi, LCS_LOC_REQ_EV_CONN_CLEAR, NULL);
+
+ gscon_release_lchans(conn, true, bsc_gsm48_rr_cause_from_gsm0808_cause(conn->clear_cause));
+ osmo_mgcpc_ep_clear(conn->user_plane.mgw_endpoint);
+
+ /* If there is no SCCP connection at all, then no need to wait for an SCCP RLSD. */
+ if (!conn->sccp.msc || conn->sccp.state != SUBSCR_SCCP_ST_CONNECTED)
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
}
/* forward MO DTAP from RSL side to BSSAP side */
@@ -354,8 +402,6 @@ static void gscon_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
osmo_fsm_inst_state_name(conn->fi));
}
gscon_bssmap_clear(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
- if (conn->fi->state != ST_CLEARING)
- osmo_fsm_inst_state_chg(fi, ST_CLEARING, 60, -4);
return;
default:
OSMO_ASSERT(false);
@@ -375,7 +421,6 @@ static void gscon_fsm_wait_cc(struct osmo_fsm_inst *fi, uint32_t event, void *da
confirmed connection, then instead simply drop the connection */
LOGPFSML(fi, LOGL_INFO,
"Connection confirmed but lchan was dropped previously, clearing conn\n");
- osmo_fsm_inst_state_chg(conn->fi, ST_CLEARING, 60, -4);
gscon_bssmap_clear(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
break;
}
@@ -521,6 +566,11 @@ struct osmo_mgcpc_ep *gscon_ensure_mgw_endpoint(struct gsm_subscriber_connection
const char *epname;
struct mgcp_client *mgcp_client = NULL;
+ if (!conn) {
+ LOG_LCHAN(for_lchan, LOGL_ERROR, "no conn!\n");
+ return NULL;
+ }
+
if (conn->user_plane.mgw_endpoint)
return conn->user_plane.mgw_endpoint;
@@ -665,13 +715,13 @@ static const struct osmo_fsm_state gscon_fsm_states[] = {
.name = "INIT",
.in_event_mask = S(GSCON_EV_MO_COMPL_L3) | S(GSCON_EV_A_CONN_IND)
| S(GSCON_EV_HANDOVER_END),
- .out_state_mask = S(ST_WAIT_CC) | S(ST_ACTIVE) | S(ST_CLEARING),
+ .out_state_mask = S(ST_WAIT_CC) | S(ST_ACTIVE) | S(ST_WAIT_CLEAR_CMD) | S(ST_WAIT_SCCP_RLSD),
.action = gscon_fsm_init,
},
[ST_WAIT_CC] = {
.name = "WAIT_CC",
.in_event_mask = S(GSCON_EV_A_CONN_CFM),
- .out_state_mask = S(ST_ACTIVE) | S(ST_CLEARING),
+ .out_state_mask = S(ST_ACTIVE) | S(ST_WAIT_CLEAR_CMD) | S(ST_WAIT_SCCP_RLSD),
.action = gscon_fsm_wait_cc,
},
[ST_ACTIVE] = {
@@ -681,26 +731,32 @@ static const struct osmo_fsm_state gscon_fsm_states[] = {
| S(GSCON_EV_LCS_LOC_REQ_END)
| S(GSCON_EV_MO_COMPL_L3)
,
- .out_state_mask = S(ST_CLEARING) | S(ST_ASSIGNMENT) |
+ .out_state_mask = S(ST_WAIT_CLEAR_CMD) | S(ST_WAIT_SCCP_RLSD) | S(ST_ASSIGNMENT) |
S(ST_HANDOVER),
.action = gscon_fsm_active,
},
[ST_ASSIGNMENT] = {
.name = "ASSIGNMENT",
.in_event_mask = EV_TRANSPARENT_SCCP | S(GSCON_EV_ASSIGNMENT_END),
- .out_state_mask = S(ST_ACTIVE) | S(ST_CLEARING),
+ .out_state_mask = S(ST_ACTIVE) | S(ST_WAIT_CLEAR_CMD) | S(ST_WAIT_SCCP_RLSD),
.action = gscon_fsm_assignment,
},
[ST_HANDOVER] = {
.name = "HANDOVER",
.in_event_mask = EV_TRANSPARENT_SCCP | S(GSCON_EV_HANDOVER_END),
- .out_state_mask = S(ST_ACTIVE) | S(ST_CLEARING),
+ .out_state_mask = S(ST_ACTIVE) | S(ST_WAIT_CLEAR_CMD) | S(ST_WAIT_SCCP_RLSD),
.action = gscon_fsm_handover,
},
- [ST_CLEARING] = {
- .name = "CLEARING",
- /* dead end state */
- },
+ [ST_WAIT_CLEAR_CMD] = {
+ .name = "WAIT_CLEAR_CMD",
+ .onenter = gscon_fsm_wait_clear_cmd_onenter,
+ .out_state_mask = S(ST_WAIT_SCCP_RLSD),
+ },
+ [ST_WAIT_SCCP_RLSD] = {
+ .name = "WAIT_SCCP_RLSD",
+ .onenter = gscon_fsm_wait_sccp_rlsd_onenter,
+ .in_event_mask = S(GSCON_EV_HANDOVER_END),
+ },
};
void gscon_change_primary_lchan(struct gsm_subscriber_connection *conn, struct gsm_lchan *new_lchan)
@@ -757,11 +813,6 @@ void gscon_lchan_releasing(struct gsm_subscriber_connection *conn, struct gsm_lc
yet so we cannot release it. First wait for the CC, and release in gscon_fsm_wait_cc(). */
break;
default:
- /* Ensure that the FSM is in ST_CLEARING. */
- osmo_fsm_inst_state_chg(conn->fi, ST_CLEARING, 60, -4);
- /* fall thru, omit an error log if already in ST_CLEARING */
- case ST_CLEARING:
- /* Request a Clear Command from the MSC. */
gscon_bssmap_clear(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
break;
}
@@ -800,8 +851,7 @@ void gscon_forget_lchan(struct gsm_subscriber_connection *conn, struct gsm_lchan
osmo_fsm_inst_name(conn->fi), detach_label);
}
- if ((conn->fi && conn->fi->state != ST_CLEARING)
- && !conn->lchan
+ if (!conn->lchan
&& !conn->ho.new_lchan
&& !conn->assignment.new_lchan
&& !conn->lcs.loc_req)
@@ -836,44 +886,19 @@ void gscon_forget_mgw_endpoint_ci(struct gsm_subscriber_connection *conn, struct
static void gscon_fsm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct gsm_subscriber_connection *conn = fi->priv;
- const enum gsm0808_cause *cause_0808;
const struct tlv_parsed *tp;
struct osmo_mobile_identity mi_imsi;
/* Regular allstate event processing */
switch (event) {
case GSCON_EV_A_CLEAR_CMD:
- conn->rx_clear_command = true;
-
- /* Give the handover_fsm a chance to book this as handover success before tearing down everything,
- * making it look like a sudden death failure. */
- if (conn->ho.fi)
- osmo_fsm_inst_dispatch(conn->ho.fi, HO_EV_CONN_RELEASING, NULL);
-
- if (conn->lcs.loc_req)
- osmo_fsm_inst_dispatch(conn->lcs.loc_req->fi, LCS_LOC_REQ_EV_CONN_CLEAR, NULL);
-
OSMO_ASSERT(data);
- cause_0808 = data;
- /* MSC tells us to cleanly shut down */
- if (conn->fi->state != ST_CLEARING)
- osmo_fsm_inst_state_chg(fi, ST_CLEARING, 60, -4);
- LOGPFSML(fi, LOGL_DEBUG, "Releasing all lchans (if any) after BSSMAP Clear Command\n");
- gscon_release_lchans(conn, true, bsc_gsm48_rr_cause_from_gsm0808_cause(*cause_0808));
- /* FIXME: Release all terestrial resources in ST_CLEARING */
- /* According to 3GPP 48.008 3.1.9.1. "The BSS need not wait for the radio channel
- * release to be completed or for the guard timer to expire before returning the
- * CLEAR COMPLETE message" */
-
- /* Close MGCP connections */
- osmo_mgcpc_ep_clear(conn->user_plane.mgw_endpoint);
-
- rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_CLEAR_COMPLETE));
- gscon_sigtran_send(conn, gsm0808_create_clear_complete());
+ conn->clear_cause = *(const enum gsm0808_cause *)data;
+ conn_fsm_state_chg(ST_WAIT_SCCP_RLSD);
break;
case GSCON_EV_A_DISC_IND:
- /* MSC or SIGTRAN network has hard-released SCCP connection,
- * terminate the FSM now. */
+ /* MSC or SIGTRAN network has hard-released SCCP connection, terminate the FSM now.
+ * Cleanup is done in gscon_pre_term() and gscon_cleanup(). */
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, data);
break;
case GSCON_EV_FORGET_MGW_ENDPOINT:
@@ -955,8 +980,21 @@ static void gscon_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cau
static void gscon_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
{
struct gsm_subscriber_connection *conn = fi->priv;
+ struct mgcp_client *mgcp_client;
+
+ /* Put MGCP client back into MGW pool */
+ mgcp_client = osmo_mgcpc_ep_client(conn->user_plane.mgw_endpoint);
+ mgcp_client_pool_put(mgcp_client);
osmo_mgcpc_ep_clear(conn->user_plane.mgw_endpoint);
+ conn->user_plane.mgw_endpoint = NULL;
+ conn->user_plane.mgw_endpoint = NULL;
+
+ if (conn->ho.fi)
+ osmo_fsm_inst_dispatch(conn->ho.fi, HO_EV_CONN_RELEASING, NULL);
+
+ if (conn->lcs.loc_req)
+ osmo_fsm_inst_dispatch(conn->lcs.loc_req->fi, LCS_LOC_REQ_EV_CONN_CLEAR, NULL);
if (conn->lcls.fi) {
/* request termination of LCLS FSM */
@@ -965,9 +1003,7 @@ static void gscon_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause ca
}
LOGPFSML(fi, LOGL_DEBUG, "Releasing all lchans (if any) because this conn is terminating\n");
- /* when things go smoothly, the lchan should have been released before FSM instance termination. So if this is
- * necessary it's probably "abnormal". */
- gscon_release_lchans(conn, true, GSM48_RR_CAUSE_ABNORMAL_UNSPEC);
+ gscon_release_lchans(conn, true, bsc_gsm48_rr_cause_from_gsm0808_cause(conn->clear_cause));
/* drop pending messages */
gscon_dtap_queue_flush(conn, 0);
@@ -997,8 +1033,9 @@ static int gscon_timer_cb(struct osmo_fsm_inst *fi)
case -4:
/* The MSC has sent a BSSMAP Clear Command, we acknowledged that, but the conn was never
* disconnected. */
- LOGPFSML(fi, LOGL_ERROR, "Long after a BSSMAP Clear Command, the conn is still not"
- " released. For sanity, discarding this conn now.\n");
+ LOGPFSML(fi, LOGL_ERROR, "Long after expecting %s, the conn is still not"
+ " released. For sanity, discarding this conn now.\n",
+ fi->state == ST_WAIT_CLEAR_CMD ? "BSSMAP Clear Command" : "SCCP RLSD");
a_reset_conn_fail(conn->sccp.msc);
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
break;
@@ -1046,6 +1083,9 @@ struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *ne
INIT_LLIST_HEAD(&conn->hodec2.penalty_timers);
conn->sccp.conn_id = -1;
+ /* Default clear cause (on RR translates to GSM48_RR_CAUSE_ABNORMAL_UNSPEC) */
+ conn->clear_cause = GSM0808_CAUSE_EQUIPMENT_FAILURE;
+
/* don't allocate from 'conn' context, as gscon_cleanup() will call talloc_free(conn) before
* libosmocore will call talloc_free(conn->fi), i.e. avoid use-after-free during cleanup */
conn->fi = osmo_fsm_inst_alloc(&gscon_fsm, net, conn, LOGL_DEBUG, NULL);
@@ -1128,16 +1168,16 @@ static void rll_ind_cb(struct gsm_lchan *lchan, uint8_t link_id, void *_data, en
switch (rllr_ind) {
case BSC_RLLR_IND_EST_CONF:
- rsl_data_request(msg, OBSC_LINKID_CB(msg));
+ rsl_data_request(msg, link_id);
break;
case BSC_RLLR_IND_REL_IND:
- bsc_sapi_n_reject(lchan->conn, OBSC_LINKID_CB(msg),
+ bsc_sapi_n_reject(lchan->conn, RSL_LINK_ID2DLCI(link_id),
GSM0808_CAUSE_MS_NOT_EQUIPPED);
msgb_free(msg);
break;
case BSC_RLLR_IND_ERR_IND:
case BSC_RLLR_IND_TIMEOUT:
- bsc_sapi_n_reject(lchan->conn, OBSC_LINKID_CB(msg),
+ bsc_sapi_n_reject(lchan->conn, RSL_LINK_ID2DLCI(link_id),
GSM0808_CAUSE_BSS_NOT_EQUIPPED);
msgb_free(msg);
break;
@@ -1177,7 +1217,7 @@ static void gsm0808_send_rsl_dtap(struct gsm_subscriber_connection *conn,
rc = rll_establish(msg->lchan, sapi, rll_ind_cb, msg);
if (rc) {
msgb_free(msg);
- bsc_sapi_n_reject(conn, link_id, GSM0808_CAUSE_BSS_NOT_EQUIPPED);
+ bsc_sapi_n_reject(conn, RSL_LINK_ID2DLCI(link_id), GSM0808_CAUSE_BSS_NOT_EQUIPPED);
goto failed_to_send;
}
return;
@@ -1192,7 +1232,6 @@ static void gsm0808_send_rsl_dtap(struct gsm_subscriber_connection *conn,
failed_to_send:
LOGPFSML(conn->fi, LOGL_ERROR, "Tx BSSMAP CLEAR REQUEST to MSC\n");
gscon_bssmap_clear(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
- osmo_fsm_inst_state_chg(conn->fi, ST_ACTIVE, 0, 0);
}
void gscon_submit_rsl_dtap(struct gsm_subscriber_connection *conn,
diff --git a/src/osmo-bsc/bts.c b/src/osmo-bsc/bts.c
index fe18b59d3..1461585d2 100644
--- a/src/osmo-bsc/bts.c
+++ b/src/osmo-bsc/bts.c
@@ -211,6 +211,51 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, struct gsm_bts_sm *bts_sm
}
bts->bts_statg = osmo_stat_item_group_alloc(bts, &bts_statg_desc, bts->nr);
+ bts->all_allocated_sdcch = (struct osmo_time_cc){
+ .cfg = {
+ .gran_usec = 1*1000000,
+ .forget_sum_usec = 60*1000000,
+ .rate_ctr = rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_ALL_ALLOCATED_SDCCH),
+ .T_gran = -16,
+ .T_round_threshold = -17,
+ .T_forget_sum = -18,
+ .T_defs = net->T_defs,
+ },
+ };
+ bts->all_allocated_static_sdcch = (struct osmo_time_cc){
+ .cfg = {
+ .gran_usec = 1*1000000,
+ .forget_sum_usec = 60*1000000,
+ .rate_ctr = rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_ALL_ALLOCATED_STATIC_SDCCH),
+ .T_gran = -16,
+ .T_round_threshold = -17,
+ .T_forget_sum = -18,
+ .T_defs = net->T_defs,
+ },
+ };
+ bts->all_allocated_tch = (struct osmo_time_cc){
+ .cfg = {
+ .gran_usec = 1*1000000,
+ .forget_sum_usec = 60*1000000,
+ .rate_ctr = rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_ALL_ALLOCATED_TCH),
+ .T_gran = -16,
+ .T_round_threshold = -17,
+ .T_forget_sum = -18,
+ .T_defs = net->T_defs,
+ },
+ };
+ bts->all_allocated_static_tch = (struct osmo_time_cc){
+ .cfg = {
+ .gran_usec = 1*1000000,
+ .forget_sum_usec = 60*1000000,
+ .rate_ctr = rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_ALL_ALLOCATED_STATIC_TCH),
+ .T_gran = -16,
+ .T_round_threshold = -17,
+ .T_forget_sum = -18,
+ .T_defs = net->T_defs,
+ },
+ };
+
/* create our primary TRX */
bts->c0 = gsm_bts_trx_alloc(bts);
if (!bts->c0) {
@@ -352,7 +397,12 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, struct gsm_bts_sm *bts_sm
acc_mgr_init(&bts->acc_mgr, bts);
acc_ramp_init(&bts->acc_ramp, bts);
- bts->repeated_acch_policy.rxqual = 4;
+ /* Default RxQual threshold for ACCH repetition/overpower */
+ bts->rep_acch_cap.rxqual = 4;
+ bts->top_acch_cap.rxqual = 4;
+
+ /* Permit ACCH overpower only for speech channels using AMR */
+ bts->top_acch_chan_mode = TOP_ACCH_CHAN_MODE_SPEECH_V3;
/* MS Power Control parameters (defaults) */
power_ctrl_params_def_reset(&bts->ms_power_ctrl, GSM_PWR_CTRL_DIR_UL);
@@ -371,6 +421,61 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, struct gsm_bts_sm *bts_sm
return bts;
}
+/* Validate BTS configuration (ARFCN settings and physical channel configuration) */
+int gsm_bts_check_cfg(struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx;
+
+ if (!bts->model)
+ return -EFAULT;
+
+ switch (bts->band) {
+ case GSM_BAND_1800:
+ if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) {
+ LOGP(DNM, LOGL_ERROR, "(bts=%u) GSM1800 channel (%u) must be between 512-885.\n",
+ bts->nr, bts->c0->arfcn);
+ return -EINVAL;
+ }
+ break;
+ case GSM_BAND_1900:
+ if (bts->c0->arfcn < 512 || bts->c0->arfcn > 810) {
+ LOGP(DNM, LOGL_ERROR, "(bts=%u) GSM1900 channel (%u) must be between 512-810.\n",
+ bts->nr, bts->c0->arfcn);
+ return -EINVAL;
+ }
+ break;
+ case GSM_BAND_900:
+ if ((bts->c0->arfcn > 124 && bts->c0->arfcn < 955) ||
+ bts->c0->arfcn > 1023) {
+ LOGP(DNM, LOGL_ERROR, "(bts=%u) GSM900 channel (%u) must be between 0-124, 955-1023.\n",
+ bts->nr, bts->c0->arfcn);
+ return -EINVAL;
+ }
+ break;
+ case GSM_BAND_850:
+ if (bts->c0->arfcn < 128 || bts->c0->arfcn > 251) {
+ LOGP(DNM, LOGL_ERROR, "(bts=%u) GSM850 channel (%u) must be between 128-251.\n",
+ bts->nr, bts->c0->arfcn);
+ return -EINVAL;
+ }
+ break;
+ default:
+ LOGP(DNM, LOGL_ERROR, "(bts=%u) Unsupported frequency band.\n", bts->nr);
+ return -EINVAL;
+ }
+
+ /* Verify the physical channel mapping */
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (!trx_has_valid_pchan_config(trx)) {
+ LOGP(DNM, LOGL_ERROR, "TRX %u has invalid timeslot "
+ "configuration\n", trx->nr);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static char ts2str[255];
char *gsm_bts_name(const struct gsm_bts *bts)
@@ -717,19 +822,6 @@ void gsm_bts_all_ts_dispatch(struct gsm_bts *bts, uint32_t ts_ev, void *data)
gsm_trx_all_ts_dispatch(trx, ts_ev, data);
}
-
-/* Count number of free TS of given pchan type */
-int bts_count_free_ts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan)
-{
- struct gsm_bts_trx *trx;
- int count = 0;
-
- llist_for_each_entry(trx, &bts->trx_list, list)
- count += trx_count_free_ts(trx, pchan);
-
- return count;
-}
-
/* set all system information types for a BTS */
int gsm_bts_set_system_infos(struct gsm_bts *bts)
{
@@ -847,6 +939,27 @@ const struct rate_ctr_desc bts_ctr_description[] = {
[BTS_CTR_CHREQ_SUCCESSFUL] = \
{ "chreq:successful",
"Successful channel requests (immediate assign sent)" },
+ [BTS_CTR_CHREQ_SUCCESSFUL_EMERG] = \
+ { "chreq:successful_emerg",
+ "Sent Immediate Assignment for EMERG" },
+ [BTS_CTR_CHREQ_SUCCESSFUL_CALL] = \
+ { "chreq:successful_call",
+ "Sent Immediate Assignment for CALL" },
+ [BTS_CTR_CHREQ_SUCCESSFUL_LOCATION_UPD] = \
+ { "chreq:successful_location_upd",
+ "Sent Immediate Assignment for LOCATION_UPD" },
+ [BTS_CTR_CHREQ_SUCCESSFUL_PAG] = \
+ { "chreq:successful_pag",
+ "Sent Immediate Assignment for PAG" },
+ [BTS_CTR_CHREQ_SUCCESSFUL_PDCH] = \
+ { "chreq:successful_pdch",
+ "Sent Immediate Assignment for PDCH" },
+ [BTS_CTR_CHREQ_SUCCESSFUL_OTHER] = \
+ { "chreq:successful_other",
+ "Sent Immediate Assignment for OTHER" },
+ [BTS_CTR_CHREQ_SUCCESSFUL_UNKNOWN] = \
+ { "chreq:successful_unknown",
+ "Sent Immediate Assignment for UNKNOWN" },
[BTS_CTR_CHREQ_NO_CHANNEL] = \
{ "chreq:no_channel",
"Sent to MS no channel available" },
@@ -1123,10 +1236,10 @@ const struct rate_ctr_desc bts_ctr_description[] = {
[BTS_CTR_INTRA_BSC_HO_ATTEMPTED] = \
{ "intra_bsc_ho:attempted",
- "Intra-BSC handover attempts" },
+ "Intra-BSC inter-cell handover attempts" },
[BTS_CTR_INTRA_BSC_HO_COMPLETED] = \
{ "intra_bsc_ho:completed",
- "Intra-BSC handover completed" },
+ "Intra-BSC inter-cell handover completed" },
[BTS_CTR_INTRA_BSC_HO_STOPPED] = \
{ "intra_bsc_ho:stopped",
"Connection ended during HO" },
@@ -1141,7 +1254,29 @@ const struct rate_ctr_desc bts_ctr_description[] = {
"Received Handover Fail messages" },
[BTS_CTR_INTRA_BSC_HO_ERROR] = \
{ "intra_bsc_ho:error",
- "Re-assignment failed for other reason" },
+ "Intra-BSC inter-cell HO failed for other reason" },
+
+ [BTS_CTR_INCOMING_INTRA_BSC_HO_ATTEMPTED] = \
+ { "incoming_intra_bsc_ho:attempted",
+ "Incoming intra-BSC inter-cell handover attempts" },
+ [BTS_CTR_INCOMING_INTRA_BSC_HO_COMPLETED] = \
+ { "incoming_intra_bsc_ho:completed",
+ "Incoming intra-BSC inter-cell handover completed" },
+ [BTS_CTR_INCOMING_INTRA_BSC_HO_STOPPED] = \
+ { "incoming_intra_bsc_ho:stopped",
+ "Connection ended during HO" },
+ [BTS_CTR_INCOMING_INTRA_BSC_HO_NO_CHANNEL] = \
+ { "incoming_intra_bsc_ho:no_channel",
+ "Failure to allocate lchan for HO" },
+ [BTS_CTR_INCOMING_INTRA_BSC_HO_TIMEOUT] = \
+ { "incoming_intra_bsc_ho:timeout",
+ "Handover timed out" },
+ [BTS_CTR_INCOMING_INTRA_BSC_HO_FAILED] = \
+ { "incoming_intra_bsc_ho:failed",
+ "Received Handover Fail messages" },
+ [BTS_CTR_INCOMING_INTRA_BSC_HO_ERROR] = \
+ { "incoming_intra_bsc_ho:error",
+ "Incoming intra-BSC inter-cell HO failed for other reason" },
[BTS_CTR_INTER_BSC_HO_OUT_ATTEMPTED] = \
{ "interbsc_ho_out:attempted",
@@ -1204,6 +1339,93 @@ const struct rate_ctr_desc bts_ctr_description[] = {
[BTS_CTR_SRVCC_ERROR] = \
{ "srvcc:error",
"Re-assignment failed for other reason" },
+ [BTS_CTR_ALL_ALLOCATED_SDCCH] = \
+ { "all_allocated:sdcch",
+ "Cumulative counter of seconds where all SDCCH channels were allocated" },
+ [BTS_CTR_ALL_ALLOCATED_STATIC_SDCCH] = \
+ { "all_allocated:static_sdcch",
+ "Cumulative counter of seconds where all non-dynamic SDCCH channels were allocated" },
+ [BTS_CTR_ALL_ALLOCATED_TCH] = \
+ { "all_allocated:tch",
+ "Cumulative counter of seconds where all TCH channels were allocated" },
+ [BTS_CTR_ALL_ALLOCATED_STATIC_TCH] = \
+ { "all_allocated:static_tch",
+ "Cumulative counter of seconds where all non-dynamic TCH channels were allocated" },
+
+ [BTS_CTR_CM_SERV_REJ] = \
+ { "cm_serv_rej", "MSC sent CM Service Reject" },
+ [BTS_CTR_CM_SERV_REJ_IMSI_UNKNOWN_IN_HLR] = \
+ { "cm_serv_rej:imsi_unknown_in_hlr",
+ "MSC sent CM Service Reject with cause IMSI_UNKNOWN_IN_HLR" },
+ [BTS_CTR_CM_SERV_REJ_ILLEGAL_MS] = \
+ { "cm_serv_rej:illegal_ms",
+ "MSC sent CM Service Reject with cause ILLEGAL_MS" },
+ [BTS_CTR_CM_SERV_REJ_IMSI_UNKNOWN_IN_VLR] = \
+ { "cm_serv_rej:imsi_unknown_in_vlr",
+ "MSC sent CM Service Reject with cause IMSI_UNKNOWN_IN_VLR" },
+ [BTS_CTR_CM_SERV_REJ_IMEI_NOT_ACCEPTED] = \
+ { "cm_serv_rej:imei_not_accepted",
+ "MSC sent CM Service Reject with cause IMEI_NOT_ACCEPTED" },
+ [BTS_CTR_CM_SERV_REJ_ILLEGAL_ME] = \
+ { "cm_serv_rej:illegal_me",
+ "MSC sent CM Service Reject with cause ILLEGAL_ME" },
+ [BTS_CTR_CM_SERV_REJ_PLMN_NOT_ALLOWED] = \
+ { "cm_serv_rej:plmn_not_allowed",
+ "MSC sent CM Service Reject with cause PLMN_NOT_ALLOWED" },
+ [BTS_CTR_CM_SERV_REJ_LOC_NOT_ALLOWED] = \
+ { "cm_serv_rej:loc_not_allowed",
+ "MSC sent CM Service Reject with cause LOC_NOT_ALLOWED" },
+ [BTS_CTR_CM_SERV_REJ_ROAMING_NOT_ALLOWED] = \
+ { "cm_serv_rej:roaming_not_allowed",
+ "MSC sent CM Service Reject with cause ROAMING_NOT_ALLOWED" },
+ [BTS_CTR_CM_SERV_REJ_NETWORK_FAILURE] = \
+ { "cm_serv_rej:network_failure",
+ "MSC sent CM Service Reject with cause NETWORK_FAILURE" },
+ [BTS_CTR_CM_SERV_REJ_SYNCH_FAILURE] = \
+ { "cm_serv_rej:synch_failure",
+ "MSC sent CM Service Reject with cause SYNCH_FAILURE" },
+ [BTS_CTR_CM_SERV_REJ_CONGESTION] = \
+ { "cm_serv_rej:congestion",
+ "MSC sent CM Service Reject with cause CONGESTION" },
+ [BTS_CTR_CM_SERV_REJ_SRV_OPT_NOT_SUPPORTED] = \
+ { "cm_serv_rej:srv_opt_not_supported",
+ "MSC sent CM Service Reject with cause SRV_OPT_NOT_SUPPORTED" },
+ [BTS_CTR_CM_SERV_REJ_RQD_SRV_OPT_NOT_SUPPORTED] = \
+ { "cm_serv_rej:rqd_srv_opt_not_supported",
+ "MSC sent CM Service Reject with cause RQD_SRV_OPT_NOT_SUPPORTED" },
+ [BTS_CTR_CM_SERV_REJ_SRV_OPT_TMP_OUT_OF_ORDER] = \
+ { "cm_serv_rej:srv_opt_tmp_out_of_order",
+ "MSC sent CM Service Reject with cause SRV_OPT_TMP_OUT_OF_ORDER" },
+ [BTS_CTR_CM_SERV_REJ_CALL_CAN_NOT_BE_IDENTIFIED] = \
+ { "cm_serv_rej:call_can_not_be_identified",
+ "MSC sent CM Service Reject with cause CALL_CAN_NOT_BE_IDENTIFIED" },
+ [BTS_CTR_CM_SERV_REJ_INCORRECT_MESSAGE] = \
+ { "cm_serv_rej:incorrect_message",
+ "MSC sent CM Service Reject with cause INCORRECT_MESSAGE" },
+ [BTS_CTR_CM_SERV_REJ_INVALID_MANDANTORY_INF] = \
+ { "cm_serv_rej:invalid_mandantory_inf",
+ "MSC sent CM Service Reject with cause INVALID_MANDANTORY_INF" },
+ [BTS_CTR_CM_SERV_REJ_MSG_TYPE_NOT_IMPLEMENTED] = \
+ { "cm_serv_rej:msg_type_not_implemented",
+ "MSC sent CM Service Reject with cause MSG_TYPE_NOT_IMPLEMENTED" },
+ [BTS_CTR_CM_SERV_REJ_MSG_TYPE_NOT_COMPATIBLE] = \
+ { "cm_serv_rej:msg_type_not_compatible",
+ "MSC sent CM Service Reject with cause MSG_TYPE_NOT_COMPATIBLE" },
+ [BTS_CTR_CM_SERV_REJ_INF_ELEME_NOT_IMPLEMENTED] = \
+ { "cm_serv_rej:inf_eleme_not_implemented",
+ "MSC sent CM Service Reject with cause INF_ELEME_NOT_IMPLEMENTED" },
+ [BTS_CTR_CM_SERV_REJ_CONDTIONAL_IE_ERROR] = \
+ { "cm_serv_rej:condtional_ie_error",
+ "MSC sent CM Service Reject with cause CONDTIONAL_IE_ERROR" },
+ [BTS_CTR_CM_SERV_REJ_MSG_NOT_COMPATIBLE] = \
+ { "cm_serv_rej:msg_not_compatible",
+ "MSC sent CM Service Reject with cause MSG_NOT_COMPATIBLE" },
+ [BTS_CTR_CM_SERV_REJ_PROTOCOL_ERROR] = \
+ { "cm_serv_rej:protocol_error",
+ "MSC sent CM Service Reject with cause PROTOCOL_ERROR" },
+ [BTS_CTR_CM_SERV_REJ_RETRY_IN_NEW_CELL] = \
+ { "cm_serv_rej:retry_in_new_cell",
+ "MSC sent CM Service Reject with cause 00110000..00111111, Retry upon entry in a new cell" },
};
const struct rate_ctr_group_desc bts_ctrg_desc = {
diff --git a/src/osmo-bsc/bts_ipaccess_nanobts.c b/src/osmo-bsc/bts_ipaccess_nanobts.c
index 9607068d5..1df6537f6 100644
--- a/src/osmo-bsc/bts_ipaccess_nanobts.c
+++ b/src/osmo-bsc/bts_ipaccess_nanobts.c
@@ -696,6 +696,14 @@ ipaccess_sign_link_up(void *unit_data, struct e1inp_line *line,
DEBUGP(DLINP, "%s: Identified BTS %u/%u/%u\n", e1inp_signtype_name(type),
dev->site_id, dev->bts_id, dev->trx_id);
+ /* Check if this BTS has a valid configuration. If not we will drop it
+ * immediately. */
+ if (gsm_bts_check_cfg(bts) != 0) {
+ LOGP(DLINP, LOGL_NOTICE, "(bts=%u) BTS config invalid, dropping BTS!\n", bts->nr);
+ ipaccess_drop_oml_deferred(bts);
+ return NULL;
+ }
+
switch(type) {
case E1INP_SIGN_OML:
/* remove old OML signal link for this BTS. */
diff --git a/src/osmo-bsc/bts_trx.c b/src/osmo-bsc/bts_trx.c
index f30c748d6..0333f703a 100644
--- a/src/osmo-bsc/bts_trx.c
+++ b/src/osmo-bsc/bts_trx.c
@@ -292,54 +292,6 @@ void gsm_trx_all_ts_dispatch(struct gsm_bts_trx *trx, uint32_t ts_ev, void *data
}
}
-int trx_count_free_ts(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan)
-{
- struct gsm_bts_trx_ts *ts;
- struct gsm_lchan *lchan;
- int j;
- int count = 0;
-
- if (!trx_is_usable(trx))
- return 0;
-
- for (j = 0; j < ARRAY_SIZE(trx->ts); j++) {
- ts = &trx->ts[j];
- if (!ts_is_usable(ts))
- continue;
-
- if (ts->pchan_is == GSM_PCHAN_PDCH) {
- /* Dynamic timeslots in PDCH mode will become TCH if needed. */
- switch (ts->pchan_on_init) {
- case GSM_PCHAN_TCH_F_PDCH:
- if (pchan == GSM_PCHAN_TCH_F)
- count++;
- continue;
-
- case GSM_PCHAN_OSMO_DYN:
- if (pchan == GSM_PCHAN_TCH_F)
- count++;
- else if (pchan == GSM_PCHAN_TCH_H)
- count += 2;
- continue;
-
- default:
- /* Not dynamic, not applicable. */
- continue;
- }
- }
-
- if (ts->pchan_is != pchan)
- continue;
-
- ts_for_n_lchans(lchan, ts, ts->max_primary_lchans) {
- if (lchan_state_is(lchan, LCHAN_ST_UNUSED))
- count++;
- }
- }
-
- return count;
-}
-
bool trx_has_valid_pchan_config(const struct gsm_bts_trx *trx)
{
bool combined = false;
diff --git a/src/osmo-bsc/bts_vty.c b/src/osmo-bsc/bts_vty.c
index 3696ca877..0c7259b7d 100644
--- a/src/osmo-bsc/bts_vty.c
+++ b/src/osmo-bsc/bts_vty.c
@@ -650,11 +650,11 @@ DEFUN_USRATTR(cfg_bts_rep_dl_facch,
}
if (!strcmp(argv[0], "command")) {
- bts->repeated_acch_policy.dl_facch_cmd = true;
- bts->repeated_acch_policy.dl_facch_all = false;
+ bts->rep_acch_cap.dl_facch_cmd = true;
+ bts->rep_acch_cap.dl_facch_all = false;
} else {
- bts->repeated_acch_policy.dl_facch_cmd = true;
- bts->repeated_acch_policy.dl_facch_all = true;
+ bts->rep_acch_cap.dl_facch_cmd = true;
+ bts->rep_acch_cap.dl_facch_all = true;
}
return CMD_SUCCESS;
}
@@ -668,8 +668,8 @@ DEFUN_USRATTR(cfg_bts_rep_no_dl_facch,
{
struct gsm_bts *bts = vty->index;
- bts->repeated_acch_policy.dl_facch_cmd = false;
- bts->repeated_acch_policy.dl_facch_all = false;
+ bts->rep_acch_cap.dl_facch_cmd = false;
+ bts->rep_acch_cap.dl_facch_all = false;
return CMD_SUCCESS;
}
@@ -691,9 +691,9 @@ DEFUN_USRATTR(cfg_bts_rep_ul_dl_sacch,
}
if (strcmp(argv[0], "ul-sacch") == 0)
- bts->repeated_acch_policy.ul_sacch = true;
+ bts->rep_acch_cap.ul_sacch = true;
else
- bts->repeated_acch_policy.dl_sacch = true;
+ bts->rep_acch_cap.dl_sacch = true;
return CMD_SUCCESS;
}
@@ -709,28 +709,32 @@ DEFUN_USRATTR(cfg_bts_rep_no_ul_dl_sacch,
struct gsm_bts *bts = vty->index;
if (strcmp(argv[0], "ul-sacch") == 0)
- bts->repeated_acch_policy.ul_sacch = false;
+ bts->rep_acch_cap.ul_sacch = false;
else
- bts->repeated_acch_policy.dl_sacch = false;
+ bts->rep_acch_cap.dl_sacch = false;
return CMD_SUCCESS;
}
+/* See 3GPP TS 45.008, section 8.2.4 */
+#define RXQUAL_THRESH_CMD \
+ "rxqual (0|1|2|3|4|5|6|7)"
+#define RXQUAL_THRESH_CMD_DESC \
+ "Set RxQual (BER) threshold (default 4)\n" \
+ "BER >= 0% (always on)\n" \
+ "BER >= 0.2%\n" \
+ "BER >= 0.4%\n" \
+ "BER >= 0.8%\n" \
+ "BER >= 1.6% (default)\n" \
+ "BER >= 3.2%\n" \
+ "BER >= 6.4%\n" \
+ "BER >= 12.8%\n"
+
DEFUN_USRATTR(cfg_bts_rep_rxqual,
cfg_bts_rep_rxqual_cmd,
X(BSC_VTY_ATTR_NEW_LCHAN),
- "repeat rxqual (0|1|2|3|4|5|6|7)",
- REP_ACCH_STR
- "Set UL-SACCH/DL-FACCH rxqual threshold-ber\n"
- "0 disabled (always on)\n"
- "1 BER >= 0.2%\n"
- "2 BER >= 0.4%\n"
- "3 BER >= 0.8%\n"
- "4 BER >= 1.6% (default)\n"
- "5 BER >= 3.2%\n"
- "6 BER >= 6.4%\n"
- "7 BER >= 12.8%\n")
- /* See also: GSM 05.08, section 8.2.4 */
+ "repeat " RXQUAL_THRESH_CMD,
+ REP_ACCH_STR RXQUAL_THRESH_CMD_DESC)
{
struct gsm_bts *bts = vty->index;
@@ -741,7 +745,7 @@ DEFUN_USRATTR(cfg_bts_rep_rxqual,
}
/* See also: GSM 05.08, section 8.2.4 */
- bts->repeated_acch_policy.rxqual = atoi(argv[0]);
+ bts->rep_acch_cap.rxqual = atoi(argv[0]);
return CMD_SUCCESS;
}
@@ -751,20 +755,31 @@ DEFUN_USRATTR(cfg_bts_rep_rxqual,
DEFUN_USRATTR(cfg_bts_top_dl_acch,
cfg_bts_top_dl_acch_cmd,
X(BSC_VTY_ATTR_NEW_LCHAN),
- "overpower dl-acch <1-4>",
+ "overpower (dl-acch|dl-sacch|dl-facch) <1-4>",
TOP_ACCH_STR
- "Enable ACCH overpower for this BTS\n"
+ "Enable overpower for both SACCH and FACCH\n"
+ "Enable overpower for SACCH only\n"
+ "Enable overpower for FACCH only\n"
"Overpower value in dB\n")
{
struct gsm_bts *bts = vty->index;
if (bts->model->type != GSM_BTS_TYPE_OSMOBTS) {
- vty_out(vty, "%% repeated ACCH not supported by BTS %u%s",
+ vty_out(vty, "%% ACCH overpower is not supported by BTS %u%s",
bts->nr, VTY_NEWLINE);
return CMD_WARNING;
}
- bts->temporary_overpower.overpower_db = atoi(argv[0]);
+ bts->top_acch_cap.sacch_enable = 0;
+ bts->top_acch_cap.facch_enable = 0;
+
+ if (!strcmp(argv[0], "dl-acch") || !strcmp(argv[0], "dl-sacch"))
+ bts->top_acch_cap.sacch_enable = 1;
+ if (!strcmp(argv[0], "dl-acch") || !strcmp(argv[0], "dl-facch"))
+ bts->top_acch_cap.facch_enable = 1;
+
+ bts->top_acch_cap.overpower_db = atoi(argv[1]);
+
return CMD_SUCCESS;
}
@@ -777,7 +792,56 @@ DEFUN_USRATTR(cfg_bts_top_no_dl_acch,
{
struct gsm_bts *bts = vty->index;
- bts->temporary_overpower.overpower_db = 0;
+ bts->top_acch_cap.overpower_db = 0;
+ bts->top_acch_cap.sacch_enable = 0;
+ bts->top_acch_cap.facch_enable = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_USRATTR(cfg_bts_top_dl_acch_rxqual,
+ cfg_bts_top_dl_acch_rxqual_cmd,
+ X(BSC_VTY_ATTR_NEW_LCHAN),
+ "overpower " RXQUAL_THRESH_CMD,
+ TOP_ACCH_STR RXQUAL_THRESH_CMD_DESC)
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (bts->model->type != GSM_BTS_TYPE_OSMOBTS) {
+ vty_out(vty, "%% ACCH overpower is not supported by BTS %u%s",
+ bts->nr, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->top_acch_cap.rxqual = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+static const struct value_string top_acch_chan_mode_name[] = {
+ { TOP_ACCH_CHAN_MODE_ANY, "any" },
+ { TOP_ACCH_CHAN_MODE_SPEECH_V3, "speech-amr" },
+ { 0, NULL }
+};
+
+DEFUN_USRATTR(cfg_bts_top_dl_acch_chan_mode,
+ cfg_bts_top_dl_acch_chan_mode_cmd,
+ X(BSC_VTY_ATTR_NEW_LCHAN),
+ "overpower chan-mode (speech-amr|any)",
+ TOP_ACCH_STR
+ "Allow temporary overpower for specific Channel mode(s)\n"
+ "Speech channels using AMR codec (default)\n"
+ "Any kind of channel mode\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (bts->model->type != GSM_BTS_TYPE_OSMOBTS) {
+ vty_out(vty, "%% ACCH overpower is not supported by BTS %u%s",
+ bts->nr, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->top_acch_chan_mode = get_string_value(top_acch_chan_mode_name, argv[0]);
return CMD_SUCCESS;
}
@@ -4257,21 +4321,42 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
ho_vty_write_bts(vty, bts);
- if (bts->temporary_overpower.overpower_db > 0)
- vty_out(vty, " overpower dl-acch %u%s", bts->temporary_overpower.overpower_db, VTY_NEWLINE);
+ if (bts->top_acch_cap.overpower_db > 0) {
+ const struct abis_rsl_osmo_temp_ovp_acch_cap *top = \
+ &bts->top_acch_cap;
+ const char *mode = NULL;
+
+ if (top->sacch_enable && top->facch_enable)
+ mode = "dl-acch";
+ else if (top->sacch_enable)
+ mode = "dl-sacch";
+ else if (top->facch_enable)
+ mode = "dl-facch";
+ else /* shall not happen */
+ OSMO_ASSERT(0);
+
+ vty_out(vty, " overpower %s %u%s",
+ mode, top->overpower_db, VTY_NEWLINE);
+ vty_out(vty, " overpower rxqual %u%s",
+ top->rxqual, VTY_NEWLINE);
+ vty_out(vty, " overpower chan-mode %s%s",
+ get_value_string(top_acch_chan_mode_name,
+ bts->top_acch_chan_mode),
+ VTY_NEWLINE);
+ }
- if (bts->repeated_acch_policy.dl_facch_all)
+ if (bts->rep_acch_cap.dl_facch_all)
vty_out(vty, " repeat dl-facch all%s", VTY_NEWLINE);
- else if (bts->repeated_acch_policy.dl_facch_cmd)
+ else if (bts->rep_acch_cap.dl_facch_cmd)
vty_out(vty, " repeat dl-facch command%s", VTY_NEWLINE);
- if (bts->repeated_acch_policy.dl_sacch)
+ if (bts->rep_acch_cap.dl_sacch)
vty_out(vty, " repeat dl-sacch%s", VTY_NEWLINE);
- if (bts->repeated_acch_policy.ul_sacch)
+ if (bts->rep_acch_cap.ul_sacch)
vty_out(vty, " repeat ul-sacch%s", VTY_NEWLINE);
- if (bts->repeated_acch_policy.ul_sacch
- || bts->repeated_acch_policy.dl_facch_cmd
- || bts->repeated_acch_policy.dl_facch_cmd)
- vty_out(vty, " repeat rxqual %u%s", bts->repeated_acch_policy.rxqual, VTY_NEWLINE);
+ if (bts->rep_acch_cap.ul_sacch
+ || bts->rep_acch_cap.dl_facch_cmd
+ || bts->rep_acch_cap.dl_facch_cmd)
+ vty_out(vty, " repeat rxqual %u%s", bts->rep_acch_cap.rxqual, VTY_NEWLINE);
if (bts->interf_meas_params_cfg.avg_period != interf_meas_params_def.avg_period) {
vty_out(vty, " interference-meas avg-period %u%s",
@@ -4477,6 +4562,8 @@ int bts_vty_init(void)
install_element(BTS_NODE, &cfg_bts_rep_rxqual_cmd);
install_element(BTS_NODE, &cfg_bts_top_dl_acch_cmd);
install_element(BTS_NODE, &cfg_bts_top_no_dl_acch_cmd);
+ install_element(BTS_NODE, &cfg_bts_top_dl_acch_rxqual_cmd);
+ install_element(BTS_NODE, &cfg_bts_top_dl_acch_chan_mode_cmd);
install_element(BTS_NODE, &cfg_bts_interf_meas_avg_period_cmd);
install_element(BTS_NODE, &cfg_bts_interf_meas_level_bounds_cmd);
install_element(BTS_NODE, &cfg_bts_srvcc_fast_return_cmd);
diff --git a/src/osmo-bsc/chan_counts.c b/src/osmo-bsc/chan_counts.c
new file mode 100644
index 000000000..99e6e7649
--- /dev/null
+++ b/src/osmo-bsc/chan_counts.c
@@ -0,0 +1,142 @@
+/* count total, allocated and free channels of all types.
+ *
+ * (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/bts_trx.h>
+#include <osmocom/bsc/lchan_fsm.h>
+#include <osmocom/bsc/chan_counts.h>
+
+static const unsigned int lchans_per_pchan[_GSM_PCHAN_MAX][_GSM_LCHAN_MAX] = {
+ [GSM_PCHAN_NONE] = {0},
+ [GSM_PCHAN_CCCH] = { [GSM_LCHAN_CCCH] = 1, },
+ [GSM_PCHAN_PDCH] = { [GSM_LCHAN_PDTCH] = 1, },
+ [GSM_PCHAN_CCCH_SDCCH4] = {
+ [GSM_LCHAN_CCCH] = 1,
+ [GSM_LCHAN_SDCCH] = 3,
+ },
+ [GSM_PCHAN_TCH_F] = { [GSM_LCHAN_TCH_F] = 1, },
+ [GSM_PCHAN_TCH_H] = { [GSM_LCHAN_TCH_H] = 2, },
+ [GSM_PCHAN_SDCCH8_SACCH8C] = { [GSM_LCHAN_SDCCH] = 8, },
+ [GSM_PCHAN_CCCH_SDCCH4_CBCH] = {
+ [GSM_LCHAN_CCCH] = 1,
+ [GSM_LCHAN_SDCCH] = 3,
+ [GSM_LCHAN_CBCH] = 1,
+ },
+ [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = {
+ [GSM_LCHAN_SDCCH] = 8,
+ [GSM_LCHAN_CBCH] = 1,
+ },
+ [GSM_PCHAN_OSMO_DYN] = {
+ [GSM_LCHAN_TCH_F] = 1,
+ [GSM_LCHAN_TCH_H] = 2,
+ [GSM_LCHAN_SDCCH] = 8,
+ [GSM_LCHAN_PDTCH] = 1,
+ },
+ [GSM_PCHAN_TCH_F_PDCH] = {
+ [GSM_LCHAN_TCH_F] = 1,
+ [GSM_LCHAN_PDTCH] = 1,
+ },
+};
+
+static inline void chan_counts_per_pchan_add(struct chan_counts *dst,
+ enum chan_counts_dim1 dim1, enum chan_counts_dim2 dim2,
+ enum gsm_phys_chan_config pchan)
+{
+ int i;
+ for (i = 0; i < _GSM_LCHAN_MAX; i++)
+ dst->val[dim1][dim2][i] += lchans_per_pchan[pchan][i];
+}
+
+void chan_counts_for_trx(struct chan_counts *trx_counts, const struct gsm_bts_trx *trx)
+{
+ const struct gsm_bts_trx_ts *ts;
+ const struct gsm_lchan *lchan;
+ int i;
+
+ chan_counts_zero(trx_counts);
+
+ if (!trx_is_usable(trx))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
+ bool ts_is_dynamic;
+ struct chan_counts ts_count = {0};
+ ts = &trx->ts[i];
+ if (!ts_is_usable(ts))
+ continue;
+
+ /* Count the full potential nr of lchans for dynamic TS */
+ chan_counts_per_pchan_add(&ts_count, CHAN_COUNTS1_ALL, CHAN_COUNTS2_MAX_TOTAL, ts->pchan_on_init);
+
+ switch (ts->pchan_on_init) {
+ case GSM_PCHAN_TCH_F_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
+ ts_is_dynamic = true;
+ break;
+ default:
+ ts_is_dynamic = false;
+ break;
+ }
+
+ if (ts_is_dynamic && ts->pchan_is == GSM_PCHAN_PDCH) {
+ /* Dynamic timeslots in PDCH mode can become TCH or SDCCH immediately,
+ * so set CURRENT_TOTAL = MAX_TOTAL. */
+ chan_counts_dim3_add(&ts_count, CHAN_COUNTS1_ALL, CHAN_COUNTS2_CURRENT_TOTAL,
+ &ts_count, CHAN_COUNTS1_ALL, CHAN_COUNTS2_MAX_TOTAL);
+ } else {
+ /* Static TS, or dyn TS that are currently fixed on a specific pchan: count lchans for the
+ * current pchan mode. */
+ chan_counts_per_pchan_add(&ts_count, CHAN_COUNTS1_ALL, CHAN_COUNTS2_CURRENT_TOTAL, ts->pchan_is);
+ }
+
+ /* Count currently allocated lchans */
+ ts_for_n_lchans(lchan, ts, ts->max_primary_lchans) {
+ if (!lchan_state_is(lchan, LCHAN_ST_UNUSED))
+ ts_count.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_ALLOCATED][lchan->type]++;
+ }
+
+ chan_counts_dim3_add(&ts_count, CHAN_COUNTS1_ALL, CHAN_COUNTS2_FREE,
+ &ts_count, CHAN_COUNTS1_ALL, CHAN_COUNTS2_CURRENT_TOTAL);
+ chan_counts_dim3_sub(&ts_count, CHAN_COUNTS1_ALL, CHAN_COUNTS2_FREE,
+ &ts_count, CHAN_COUNTS1_ALL, CHAN_COUNTS2_ALLOCATED);
+
+ if (ts_is_dynamic)
+ chan_counts_dim2_add(trx_counts, CHAN_COUNTS1_DYNAMIC, &ts_count, CHAN_COUNTS1_ALL);
+ else
+ chan_counts_dim2_add(trx_counts, CHAN_COUNTS1_STATIC, &ts_count, CHAN_COUNTS1_ALL);
+ chan_counts_dim2_add(trx_counts, CHAN_COUNTS1_ALL, &ts_count, CHAN_COUNTS1_ALL);
+ }
+}
+
+void chan_counts_for_bts(struct chan_counts *bts_counts, const struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx;
+ chan_counts_zero(bts_counts);
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ struct chan_counts trx_counts;
+ chan_counts_for_trx(&trx_counts, trx);
+ chan_counts_add(bts_counts, &trx_counts);
+ }
+}
diff --git a/src/osmo-bsc/gsm_08_08.c b/src/osmo-bsc/gsm_08_08.c
index 91c90fedd..a99db4316 100644
--- a/src/osmo-bsc/gsm_08_08.c
+++ b/src/osmo-bsc/gsm_08_08.c
@@ -101,23 +101,6 @@ void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, struct msgb *
msgb_free(resp);
}
-/* 9.2.5 CM service accept */
-int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACK");
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
-
- msg->lchan = conn->lchan;
-
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_CM_SERV_ACC;
-
- DEBUGP(DMM, "-> CM SERVICE ACK\n");
-
- gscon_submit_rsl_dtap(conn, msg, 0, 0);
- return 0;
-}
-
static bool is_cm_service_for_emerg(struct msgb *msg)
{
struct gsm48_service_request *cm;
@@ -553,15 +536,6 @@ early_exit:
return rc;
}
-/* Data Link Connection Identifier (DLCI) is defined in 3GPP TS 48.006, section 9.3.2.
- * .... .SSS - SAPI value used on the radio link;
- * CC.. .... - control channel identification:
- * 00.. .... - indicates that the control channel is not further specified,
- * 10.. .... - represents the FACCH or the SDCCH,
- * 11.. .... - represents the SACCH,
- * other values are reserved. */
-#define RSL_LINK_ID2DLCI(link_id) \
- (link_id & 0x40 ? 0xc0 : 0x80) | (link_id & 0x07)
/*! MS->BSC/MSC: Um L3 message. */
void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg)
diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c
index 5d5707262..38d8a7c63 100644
--- a/src/osmo-bsc/gsm_data.c
+++ b/src/osmo-bsc/gsm_data.c
@@ -609,7 +609,7 @@ static const uint8_t subslots_per_pchan[] = {
[GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4,
[GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8,
/* Dyn TS: maximum allowed subslots */
- [GSM_PCHAN_OSMO_DYN] = 2,
+ [GSM_PCHAN_OSMO_DYN] = 8,
[GSM_PCHAN_TCH_F_PDCH] = 1,
};
@@ -633,7 +633,7 @@ static const uint8_t subslots_per_pchan_vamos[] = {
[GSM_PCHAN_SDCCH8_SACCH8C] = 0,
[GSM_PCHAN_CCCH_SDCCH4_CBCH] = 0,
[GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 0,
- [GSM_PCHAN_OSMO_DYN] = 2,
+ [GSM_PCHAN_OSMO_DYN] = 0,
[GSM_PCHAN_TCH_F_PDCH] = 2,
};
@@ -1120,12 +1120,12 @@ enum gsm48_rr_cause bsc_gsm48_rr_cause_from_rsl_cause(uint8_t c)
const struct gsm_interf_meas_params interf_meas_params_def = {
.avg_period = 6, /* 6 SACCH periods */
.bounds_dbm = {
- 85, /* 0: -85 dBm */
- 91, /* X1: -91 dBm */
- 97, /* X2: -97 dBm */
- 103, /* X3: -103 dBm */
- 109, /* X4: -109 dBm */
- 115, /* X5: -115 dBm */
+ 115, /* 0: -115 dBm */
+ 109, /* X1: -109 dBm */
+ 103, /* X2: -103 dBm */
+ 97, /* X3: -97 dBm */
+ 91, /* X4: -91 dBm */
+ 85, /* X5: -85 dBm */
},
};
@@ -1200,7 +1200,7 @@ const struct gsm_power_ctrl_params power_ctrl_params_def = {
* above the target.
*/
.ci_fr_meas = { /* FR: Target C/I = 15 dB, Soft blocking threshold = 10 dB */
- .enabled = true,
+ .enabled = false,
.lower_thresh = 13,
.upper_thresh = 17,
@@ -1222,7 +1222,7 @@ const struct gsm_power_ctrl_params power_ctrl_params_def = {
.h_reqt = 6, /* TODO: investigate a reasonable default value */
},
.ci_hr_meas = { /* HR: Target C/I = 18 dB, Soft blocking threshold = 13 dB */
- .enabled = true,
+ .enabled = false,
.lower_thresh = 16,
.upper_thresh = 21,
@@ -1244,7 +1244,7 @@ const struct gsm_power_ctrl_params power_ctrl_params_def = {
.h_reqt = 6, /* TODO: investigate a reasonable default value */
},
.ci_amr_fr_meas = { /* AMR-FR: Target C/I = 9 dB, Soft blocking threshold = 4 dB */
- .enabled = true,
+ .enabled = false,
.lower_thresh = 7,
.upper_thresh = 11,
@@ -1266,7 +1266,7 @@ const struct gsm_power_ctrl_params power_ctrl_params_def = {
.h_reqt = 6, /* TODO: investigate a reasonable default value */
},
.ci_amr_hr_meas = { /* AMR-HR: Target C/I = 15 dB, Soft blocking threshold = 10 dB */
- .enabled = true,
+ .enabled = false,
.lower_thresh = 13,
.upper_thresh = 17,
@@ -1288,7 +1288,7 @@ const struct gsm_power_ctrl_params power_ctrl_params_def = {
.h_reqt = 6, /* TODO: investigate a reasonable default value */
},
.ci_sdcch_meas = { /* SDCCH: Target C/I = 14 dB, Soft blocking threshold = 9 dB */
- .enabled = true,
+ .enabled = false,
.lower_thresh = 12,
.upper_thresh = 16,
@@ -1310,7 +1310,7 @@ const struct gsm_power_ctrl_params power_ctrl_params_def = {
.h_reqt = 6, /* TODO: investigate a reasonable default value */
},
.ci_gprs_meas = { /* GPRS: Target C/I = 20 dB, Soft blocking threshold = 15 dB */
- .enabled = true,
+ .enabled = false,
.lower_thresh = 18,
.upper_thresh = 24,
diff --git a/src/osmo-bsc/handover_decision_2.c b/src/osmo-bsc/handover_decision_2.c
index d08173cb9..14bc2d4b0 100644
--- a/src/osmo-bsc/handover_decision_2.c
+++ b/src/osmo-bsc/handover_decision_2.c
@@ -42,6 +42,7 @@
#include <osmocom/bsc/timeslot_fsm.h>
#include <osmocom/bsc/bts.h>
#include <osmocom/bsc/lchan_select.h>
+#include <osmocom/bsc/chan_counts.h>
#define LOGPHOBTS(bts, level, fmt, args...) \
LOGP(DHODEC, level, "(BTS %u) " fmt, bts->nr, ## args)
@@ -86,7 +87,7 @@
LOGPHOLCHANTOBTS((candidate)->current.lchan, (candidate)->target.bts, level, fmt, ## args); \
else if ((candidate)->target.cell_ids.id_list_len) \
LOGPHOLCHANTOREMOTE((candidate)->current.lchan, &(candidate)->target.cell_ids, level, fmt, ## args); \
- } while(0)
+ } while (0)
#define REQUIREMENT_A_TCHF 0x01
@@ -990,12 +991,15 @@ static inline void debug_candidate(struct ho_candidate *candidate)
static void candidate_set_free_tch(struct ho_candidate *c)
{
+ struct chan_counts bts_counts;
struct gsm_lchan *next_lchan;
- c->current.free_tchf = bts_count_free_ts(c->current.bts, GSM_PCHAN_TCH_F);
+ chan_counts_for_bts(&bts_counts, c->current.bts);
+ c->current.free_tchf = bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F];
c->current.min_free_tchf = ho_get_hodec2_tchf_min_slots(c->current.bts->ho);
- c->current.free_tchh = bts_count_free_ts(c->current.bts, GSM_PCHAN_TCH_H);
+ c->current.free_tchh = bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H];
c->current.min_free_tchh = ho_get_hodec2_tchh_min_slots(c->current.bts->ho);
+
switch (c->current.lchan->ts->pchan_is) {
case GSM_PCHAN_TCH_F:
c->current.free_tch = c->current.free_tchf;
@@ -1023,26 +1027,39 @@ static void candidate_set_free_tch(struct ho_candidate *c)
break;
}
- c->target.free_tchf = bts_count_free_ts(c->target.bts, GSM_PCHAN_TCH_F);
- c->target.min_free_tchf = ho_get_hodec2_tchf_min_slots(c->target.bts->ho);
- c->target.free_tchh = bts_count_free_ts(c->target.bts, GSM_PCHAN_TCH_H);
- c->target.min_free_tchh = ho_get_hodec2_tchh_min_slots(c->target.bts->ho);
+ /* For inter-BSC handover, the target BTS is in a different BSC and hence NULL here. */
+ if (c->target.bts) {
+ chan_counts_for_bts(&bts_counts, c->target.bts);
+ c->target.free_tchf = bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F];
+ c->target.min_free_tchf = ho_get_hodec2_tchf_min_slots(c->target.bts->ho);
+ c->target.free_tchh = bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H];
+ c->target.min_free_tchh = ho_get_hodec2_tchh_min_slots(c->target.bts->ho);
- /* Would the next TCH/F lchan occupy a dynamic timeslot that currently counts for free TCH/H timeslots? */
- next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_F, false);
- if (next_lchan && next_lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN)
- c->target.next_tchf_reduces_tchh = 2;
- else
- c->target.next_tchf_reduces_tchh = 0;
+ /* Would the next TCH/F lchan occupy a dynamic timeslot that currently counts for free TCH/H timeslots?
+ */
+ next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_F, false);
+ if (next_lchan && next_lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN)
+ c->target.next_tchf_reduces_tchh = 2;
+ else
+ c->target.next_tchf_reduces_tchh = 0;
+
+ /* Would the next TCH/H lchan occupy a dynamic timeslot that currently counts for free TCH/F timeslots?
+ * Note that a dyn TS already in TCH/H mode (half occupied) would not reduce free TCH/F. */
+ next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_H, false);
+ if (next_lchan && next_lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN
+ && next_lchan->ts->pchan_is != GSM_PCHAN_TCH_H)
+ c->target.next_tchh_reduces_tchf = 1;
+ else
+ c->target.next_tchh_reduces_tchf = 0;
+ } else {
- /* Would the next TCH/H lchan occupy a dynamic timeslot that currently counts for free TCH/F timeslots?
- * Note that a dyn TS already in TCH/H mode (half occupied) would not reduce free TCH/F. */
- next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_H, false);
- if (next_lchan && next_lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN
- && next_lchan->ts->pchan_is != GSM_PCHAN_TCH_H)
- c->target.next_tchh_reduces_tchf = 1;
- else
+ c->target.free_tchf = 0;
+ c->target.min_free_tchf = 0;
c->target.next_tchh_reduces_tchf = 0;
+ c->target.free_tchh = 0;
+ c->target.min_free_tchh = 0;
+ c->target.next_tchf_reduces_tchh = 0;
+ }
}
/* add candidate for re-assignment within the current cell */
@@ -1928,6 +1945,7 @@ exit:
static void bts_congestion_check(struct gsm_bts *bts)
{
+ struct chan_counts bts_counts;
int min_free_tchf, min_free_tchh;
int free_tchf, free_tchh;
@@ -1955,8 +1973,9 @@ static void bts_congestion_check(struct gsm_bts *bts)
return;
}
- free_tchf = bts_count_free_ts(bts, GSM_PCHAN_TCH_F);
- free_tchh = bts_count_free_ts(bts, GSM_PCHAN_TCH_H);
+ chan_counts_for_bts(&bts_counts, bts);
+ free_tchf = bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F];
+ free_tchh = bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H];
LOGPHOBTS(bts, LOGL_INFO, "Congestion check: (free/want-free) TCH/F=%d/%d TCH/H=%d/%d\n",
free_tchf, min_free_tchf, free_tchh, min_free_tchh);
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c
index 255478f97..37e74176d 100644
--- a/src/osmo-bsc/handover_fsm.c
+++ b/src/osmo-bsc/handover_fsm.c
@@ -90,7 +90,7 @@
bsc_ctr_description[counter].name, \
bsc_ctr_description[counter].description); \
rate_ctr_inc(rate_ctr_group_get_ctr(conn->network->bsc_ctrs, counter)); \
- } while(0)
+ } while (0)
/* Assume presence of local var 'conn' as struct gsm_subscriber_connection.
* Handles bts == NULL gracefully
@@ -106,12 +106,15 @@
rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, counter)); \
else \
rate_ctr_inc(rate_ctr_group_get_ctr(conn->network->bts_unknown_ctrs, counter)); \
- } while(0)
+ } while (0)
+/* Count handover result on both bts and bsc level.
+ * Call with 'counter' being the counter name without the "BSC_"/"BTS_" part,
+ * e.g. ho_count(conn_get_bts(conn), CTR_HANDOVER_ATTEMPTED); */
#define ho_count(bts, counter) do { \
- ho_count_bsc(BSC_##counter); \
- ho_count_bts(bts, BTS_##counter); \
-} while(0)
+ ho_count_bsc(BSC_##counter); \
+ ho_count_bts(bts, BTS_##counter); \
+ } while (0)
static uint8_t g_next_ho_ref = 1;
@@ -212,12 +215,12 @@ static const struct osmo_tdef_state_timeout ho_fsm_timeouts[32] = {
LOG_HO(conn, LOGL_ERROR, "Handover failed in state %s, %s: " fmt "\n", \
osmo_fsm_inst_state_name(conn->fi), handover_result_name(result), ## args); \
handover_end(conn, result); \
- } while(0)
+ } while (0)
#define ho_success() do { \
LOG_HO(conn, LOGL_DEBUG, "Handover succeeded\n"); \
handover_end(conn, HO_RESULT_OK); \
- } while(0)
+ } while (0)
/* issue handover to a cell identified by ARFCN and BSIC */
int handover_request(struct handover_out_req *req)
@@ -384,6 +387,7 @@ static void handover_start_intra_bsc(struct gsm_subscriber_connection *conn)
} else {
ho_count(bts, CTR_INTRA_BSC_HO_ATTEMPTED);
ho_fsm_update_id(fi, "intraBSC");
+ ho_count_bts(ho->new_bts, BTS_CTR_INCOMING_INTRA_BSC_HO_ATTEMPTED);
}
if (!ho->new_lchan) {
@@ -748,6 +752,23 @@ void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn,
lchan_activate(ho->new_lchan, &info);
}
+/* Create functions result_counter_{BSC,BTS}_{HANDOVER,...}(), to evaluate the handover result and return
+ * BSC_CTR_HANDOVER_ATTEMPTED,
+ * BSC_CTR_HANDOVER_COMPLETED,
+ * BSC_CTR_HANDOVER_STOPPED,
+ * BSC_CTR_HANDOVER_NO_CHANNEL,
+ * BSC_CTR_HANDOVER_TIMEOUT,
+ * BSC_CTR_HANDOVER_FAILED,
+ * BSC_CTR_HANDOVER_ERROR,
+ * or
+ * BTS_CTR_HANDOVER_ATTEMPTED,
+ * BTS_CTR_HANDOVER_COMPLETED,
+ * BTS_CTR_HANDOVER_STOPPED,
+ * BTS_CTR_HANDOVER_NO_CHANNEL,
+ * BTS_CTR_HANDOVER_TIMEOUT,
+ * BTS_CTR_HANDOVER_FAILED,
+ * BTS_CTR_HANDOVER_ERROR,
+ */
#define FUNC_RESULT_COUNTER(obj, name) \
static int result_counter_##obj##_##name(enum handover_result result) \
{ \
@@ -773,6 +794,7 @@ FUNC_RESULT_COUNTER(BSC, INTRA_CELL_HO)
FUNC_RESULT_COUNTER(BSC, INTRA_BSC_HO)
FUNC_RESULT_COUNTER(BSC, INTER_BSC_HO_IN)
+/* INTRA_BSC_HO_OUT does not have a NO_CHANNEL result, so can't do this with FUNC_RESULT_COUNTER() macro. */
static int result_counter_BSC_INTER_BSC_HO_OUT(enum handover_result result) {
switch (result) {
case HO_RESULT_OK:
@@ -808,8 +830,10 @@ static int result_counter_bsc(enum handover_scope scope, enum handover_result re
FUNC_RESULT_COUNTER(BTS, HANDOVER)
FUNC_RESULT_COUNTER(BTS, INTRA_CELL_HO)
FUNC_RESULT_COUNTER(BTS, INTRA_BSC_HO)
+FUNC_RESULT_COUNTER(BTS, INCOMING_INTRA_BSC_HO)
FUNC_RESULT_COUNTER(BTS, INTER_BSC_HO_IN)
+/* INTRA_BSC_HO_OUT does not have a NO_CHANNEL result, so can't do this with FUNC_RESULT_COUNTER() macro. */
static int result_counter_BTS_INTER_BSC_HO_OUT(enum handover_result result) {
switch (result) {
case HO_RESULT_OK:
@@ -998,6 +1022,9 @@ void handover_end(struct gsm_subscriber_connection *conn, enum handover_result r
ho_count_bsc(result_counter_bsc(ho->scope, result));
ho_count_bts(bts, result_counter_BTS_HANDOVER(result));
ho_count_bts(bts, result_counter_bts(ho->scope, result));
+ /* For inter-cell HO, also increment the "INCOMING" counters on the target BTS. */
+ if (ho->scope & HO_INTRA_BSC)
+ ho_count_bts(ho->new_bts, result_counter_BTS_INCOMING_INTRA_BSC_HO(result));
if (ho->scope & HO_INTER_BSC_IN && conn->fast_return.last_eutran_plmn_valid) {
/* From outside local BSC and with Last EUTRAN PLMN Id => SRVCC */
ho_count_bsc(result_counter_BSC_SRVCC(result));
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index 2f6248708..84f8dc5ef 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -40,6 +40,7 @@
#include <osmocom/bsc/bsc_msc_data.h>
#include <osmocom/bsc/codec_pref.h>
#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/bsc_stats.h>
static struct osmo_fsm lchan_fsm;
@@ -97,6 +98,11 @@ static void _lchan_on_mode_modify_failure(struct gsm_lchan *lchan, enum lchan_mo
case MODIFY_FOR_ASSIGNMENT:
LOG_LCHAN(lchan, LOGL_NOTICE, "Signalling Assignment FSM of error (%s)\n",
lchan->last_error ? : "unknown error");
+ if (!for_conn) {
+ LOG_LCHAN(lchan, LOGL_ERROR, "lchan Channel Mode Modify failed, "
+ "but modify request has no conn\n");
+ break;
+ }
_osmo_fsm_inst_dispatch(for_conn->assignment.fi, ASSIGNMENT_EV_LCHAN_ERROR, lchan,
file, line);
return;
@@ -297,7 +303,7 @@ struct osmo_tdef_state_timeout lchan_fsm_timeouts[32] = {
else \
LOG_LCHAN(_lchan, LOGL_DEBUG, "After failure handling, already in state %s\n", \
osmo_fsm_state_name(fsm, state_chg)); \
- } while(0)
+ } while (0)
/* Which state to transition to when lchan_fail() is called in a given state. */
uint32_t lchan_fsm_on_error[34] = {
@@ -472,8 +478,11 @@ static void lchan_reset(struct gsm_lchan *lchan)
{
LOG_LCHAN(lchan, LOGL_DEBUG, "Clearing lchan state\n");
- if (lchan->conn)
- gscon_forget_lchan(lchan->conn, lchan);
+ if (lchan->conn) {
+ struct gsm_subscriber_connection *conn = lchan->conn;
+ lchan_forget_conn(lchan);
+ gscon_forget_lchan(conn, lchan);
+ }
if (lchan->rqd_ref) {
talloc_free(lchan->rqd_ref);
@@ -512,6 +521,8 @@ static void lchan_fsm_unused_onenter(struct osmo_fsm_inst *fi, uint32_t prev_sta
lchan_reset(lchan);
osmo_fsm_inst_dispatch(lchan->ts->fi, TS_EV_LCHAN_UNUSED, lchan);
+ bsc_update_time_cc_all_allocated(bts->network);
+
/* Poll the channel request queue, so that waiting calls can make use of the lchan that just
* has become unused now. */
abis_rsl_chan_rqd_queue_poll(bts);
@@ -627,6 +638,10 @@ static void lchan_fsm_unused(struct osmo_fsm_inst *fi, uint32_t event, void *dat
lchan->release.requested = false;
lchan->activate.info = *info;
+ /* To avoid confusion, invalidate info.chreq_reason value if it isn't for a CHREQ */
+ if (lchan->activate.info.activ_for != ACTIVATE_FOR_MS_CHANNEL_REQUEST)
+ lchan->activate.info.chreq_reason = -1;
+
lchan->activate.concluded = false;
lchan_fsm_state_chg(LCHAN_ST_WAIT_TS_READY);
break;
@@ -688,6 +703,8 @@ static void lchan_fsm_wait_ts_ready_onenter(struct osmo_fsm_inst *fi, uint32_t p
return;
}
+ bsc_update_time_cc_all_allocated(bts->network);
+
lchan->conn = info->for_conn;
/* If there is a previous lchan, and the new lchan is on the same cell as previous one,
@@ -806,8 +823,8 @@ static void lchan_fsm_wait_activ_ack_onenter(struct osmo_fsm_inst *fi, uint32_t
act_type = lchan->conn->ho.async ? RSL_ACT_INTER_ASYNC : RSL_ACT_INTER_SYNC;
ho_ref = lchan->conn->ho.ho_ref;
break;
- default:
case ACTIVATE_FOR_ASSIGNMENT:
+ default:
act_type = RSL_ACT_INTRA_NORM_ASS;
break;
}
@@ -1378,8 +1395,9 @@ static void lchan_fsm_wait_rf_release_ack_onenter(struct osmo_fsm_inst *fi, uint
* lchan_reset(), we make sure it does. But in case of releases from error handling, the
* conn might as well notice now already that its lchan is becoming unusable. */
if (lchan->conn) {
- gscon_forget_lchan(lchan->conn, lchan);
+ struct gsm_subscriber_connection *conn = lchan->conn;
lchan_forget_conn(lchan);
+ gscon_forget_lchan(conn, lchan);
}
rc = rsl_tx_rf_chan_release(lchan);
diff --git a/src/osmo-bsc/lchan_rtp_fsm.c b/src/osmo-bsc/lchan_rtp_fsm.c
index 7bd8209c7..62cd100f8 100644
--- a/src/osmo-bsc/lchan_rtp_fsm.c
+++ b/src/osmo-bsc/lchan_rtp_fsm.c
@@ -66,7 +66,7 @@ struct osmo_tdef_state_timeout lchan_rtp_fsm_timeouts[32] = {
LCHAN_SET_LAST_ERROR(_lchan, "lchan-rtp failure in state %s: " fmt, \
osmo_fsm_state_name(fi->fsm, state_was), ## args); \
osmo_fsm_inst_dispatch(_lchan->fi, LCHAN_EV_RTP_ERROR, 0); \
- } while(0)
+ } while (0)
/* Called from lchan_fsm_init(), does not need to be visible in lchan_rtp_fsm.h */
void lchan_rtp_fsm_init()
diff --git a/src/osmo-bsc/lcs_loc_req.c b/src/osmo-bsc/lcs_loc_req.c
index 7153ce6b7..d2ea72d65 100644
--- a/src/osmo-bsc/lcs_loc_req.c
+++ b/src/osmo-bsc/lcs_loc_req.c
@@ -81,7 +81,7 @@ static const struct osmo_tdef_state_timeout lcs_loc_req_fsm_timeouts[32] = {
.cause_val = cause, \
}; \
lcs_loc_req_fsm_state_chg(lcs_loc_req->fi, LCS_LOC_REQ_ST_FAILED); \
- } while(0)
+ } while (0)
static struct lcs_loc_req *lcs_loc_req_alloc(struct osmo_fsm_inst *parent_fi, uint32_t parent_event_term)
{
@@ -110,7 +110,7 @@ static bool parse_bssmap_perf_loc_req(struct lcs_loc_req *lcs_loc_req, struct ms
#define PARSE_ERR(ERRMSG) do { \
lcs_loc_req_fail(LCS_CAUSE_PROTOCOL_ERROR, "rx BSSMAP Perform Location Request: " ERRMSG); \
return false; \
- } while(0)
+ } while (0)
payload_length = msg->tail - msg->l4h;
if (tlv_parse2(tp_arr, 1, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0) <= 0)
diff --git a/src/osmo-bsc/lcs_ta_req.c b/src/osmo-bsc/lcs_ta_req.c
index bcee6e1c8..f0bb02eb6 100644
--- a/src/osmo-bsc/lcs_ta_req.c
+++ b/src/osmo-bsc/lcs_ta_req.c
@@ -63,7 +63,7 @@ static const struct osmo_tdef_state_timeout lcs_ta_req_fsm_timeouts[32] = {
lcs_ta_req ? osmo_fsm_inst_state_name(lcs_ta_req->fi) : "NULL", ## args); \
lcs_ta_req->failure_cause = cause; \
lcs_ta_req_fsm_state_chg(lcs_ta_req->fi, LCS_TA_REQ_ST_FAILED); \
- } while(0)
+ } while (0)
static struct osmo_fsm lcs_ta_req_fsm;
@@ -122,17 +122,6 @@ void lcs_ta_req_wait_ta_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
return;
}
- paging = (struct bsc_paging_params){
- .reason = BSC_PAGING_FOR_LCS,
- .msc = loc_req->conn->sccp.msc,
- .bsub = loc_req->conn->bsub,
- .tmsi = GSM_RESERVED_TMSI,
- .imsi = loc_req->req.imsi,
- .chan_needed = RSL_CHANNEED_ANY,
- };
- if (paging.bsub)
- bsc_subscr_get(paging.bsub, BSUB_USE_PAGING_START);
-
/* Do we already have an active lchan with knowledge of TA? */
lchan = loc_req->conn->lchan;
if (lchan) {
@@ -147,6 +136,17 @@ void lcs_ta_req_wait_ta_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
return;
}
+ paging = (struct bsc_paging_params){
+ .reason = BSC_PAGING_FOR_LCS,
+ .msc = loc_req->conn->sccp.msc,
+ .bsub = loc_req->conn->bsub,
+ .tmsi = GSM_RESERVED_TMSI,
+ .imsi = loc_req->req.imsi,
+ .chan_needed = RSL_CHANNEED_ANY,
+ };
+ if (paging.bsub)
+ bsc_subscr_get(paging.bsub, BSUB_USE_PAGING_START);
+
if (!loc_req->req.cell_id_present) {
LOG_LCS_TA_REQ(lcs_ta_req, LOGL_DEBUG,
"No Cell Identity in BSSMAP Location Request, paging entire BSS\n");
diff --git a/src/osmo-bsc/neighbor_ident.c b/src/osmo-bsc/neighbor_ident.c
index c66d3ac55..44b0b4381 100644
--- a/src/osmo-bsc/neighbor_ident.c
+++ b/src/osmo-bsc/neighbor_ident.c
@@ -489,6 +489,7 @@ int neighbor_ctrl_cmds_install(struct gsm_network *net)
struct ctrl_handle *neighbor_controlif_setup(struct gsm_network *net)
{
+ /* See also osmobsc-usermanual.pdf, section 14.1 Neighbor Address Resolution Service */
return ctrl_interface_setup_dynip2(net, net->neigh_ctrl.addr, net->neigh_ctrl.port,
NULL, _LAST_CTRL_NODE_NEIGHBOR);
}
diff --git a/src/osmo-bsc/neighbor_ident_ctrl.c b/src/osmo-bsc/neighbor_ident_ctrl.c
new file mode 100644
index 000000000..8e5e04875
--- /dev/null
+++ b/src/osmo-bsc/neighbor_ident_ctrl.c
@@ -0,0 +1,713 @@
+/* CTRL interface implementation to manage identity of neighboring BSS cells for inter-BSC handover. */
+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier <pmaier@sysmocom.de>
+ *
+ * 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 <errno.h>
+#include <time.h>
+
+#include <osmocom/ctrl/control_cmd.h>
+#include <osmocom/bsc/neighbor_ident.h>
+#include <osmocom/bsc/gsm_data.h>
+#include <osmocom/bsc/bsc_msc_data.h>
+#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/vty.h>
+
+/* Continue to parse ARFCN and BSIC, which are optional parameters at the end of the parameter string in most of the
+ * commands. The result is ignored when parameter n is set to NULL. */
+static int continue_parse_arfcn_and_bsic(char **saveptr, struct neighbor *n)
+{
+ int arfcn;
+ int bsic;
+ char *tok;
+
+ tok = strtok_r(NULL, "-", saveptr);
+
+ /* No ARFCN and BSIC persent - stop */
+ if (!tok)
+ return 0;
+
+ if (osmo_str_to_int(&arfcn, tok, 10, 0, 1023) < 0)
+ return -EINVAL;
+
+ tok = strtok_r(NULL, "-", saveptr);
+
+ /* When an ARFCN is given, then the BSIC parameter is
+ * mandatory */
+ if (!tok)
+ return -EINVAL;
+
+ if (strcmp(tok, "any") == 0) {
+ bsic = BSIC_ANY;
+ } else {
+ if (osmo_str_to_int(&bsic, tok, 10, 0, 63) < 0)
+ return 1;
+ }
+
+ /* Make sure there are no excess parameters */
+ if (strtok_r(NULL, "-", saveptr))
+ return -EINVAL;
+
+ if (n) {
+ n->cell_id.ab_present = true;
+ n->cell_id.ab.arfcn = arfcn;
+ n->cell_id.ab.bsic = bsic;
+ }
+
+ return 0;
+}
+
+/* This and the following: Add/Remove a BTS as neighbor */
+static int verify_neighbor_bts(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ struct gsm_bts *bts = cmd->node;
+ const int neigh_bts_nr = atoi(value);
+ struct gsm_bts *neigh_bts = gsm_bts_num(bts->network, neigh_bts_nr);
+
+ if (!neigh_bts) {
+ cmd->reply = "Invalid Neighbor BTS number - no such BTS";
+ return 1;
+ }
+
+ return 0;
+}
+
+static int verify_neighbor_bts_add(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ return verify_neighbor_bts(cmd, value, _data);
+}
+
+static int set_neighbor_bts_add(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ const int bts_nr = atoi(cmd->value);
+ int rc;
+
+ struct neighbor n = {
+ .type = NEIGHBOR_TYPE_BTS_NR,
+ .bts_nr = bts_nr,
+ };
+ rc = neighbor_ident_add_neighbor(NULL, bts, &n);
+ if (rc != CMD_SUCCESS) {
+ cmd->reply = "Failed to add neighbor";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+/* Parameter format: "<num>"
+ * num: BTS number (0-255) */
+CTRL_CMD_DEFINE_WO(neighbor_bts_add, "neighbor-bts add");
+
+static int verify_neighbor_bts_del(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ return verify_neighbor_bts(cmd, value, _data);
+}
+
+static int set_neighbor_bts_del(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ const int bts_nr = atoi(cmd->value);
+ int rc;
+
+ struct neighbor n = {
+ .type = NEIGHBOR_TYPE_BTS_NR,
+ .bts_nr = bts_nr,
+ };
+ rc = neighbor_ident_del_neighbor(NULL, bts, &n);
+ if (rc != CMD_SUCCESS) {
+ cmd->reply = "Failed to delete neighbor";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+/* Parameter format: (see "add" command above) */
+CTRL_CMD_DEFINE_WO(neighbor_bts_del, "neighbor-bts del");
+
+/* This and the following: Add/Remove a LAC as neighbor */
+static int parse_lac(void *ctx, struct neighbor *n, const char *value)
+{
+ char *tmp = NULL, *tok, *saveptr;
+ int rc = 0;
+ int lac;
+
+ if (n)
+ memset(n, 0, sizeof(*n));
+
+ tmp = talloc_strdup(ctx, value);
+ if (!tmp)
+ return -EINVAL;
+
+ /* Parse LAC */
+ tok = strtok_r(tmp, "-", &saveptr);
+ if (tok) {
+ if (osmo_str_to_int(&lac, tok, 10, 0, 65535) < 0) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Optional parameters: ARFCN and BSIC */
+ if (continue_parse_arfcn_and_bsic(&saveptr, n)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (n) {
+ n->type = NEIGHBOR_TYPE_CELL_ID;
+ n->cell_id.id.id_discr = CELL_IDENT_LAC;
+ n->cell_id.id.id.lac = lac;
+ }
+
+exit:
+ talloc_free(tmp);
+ return rc;
+}
+
+static int verify_neighbor_lac_add(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (parse_lac(cmd, NULL, value))
+ return 1;
+ return 0;
+}
+
+static int set_neighbor_lac_add(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ int rc;
+
+ struct neighbor n;
+
+ parse_lac(cmd, &n, cmd->value);
+ rc = neighbor_ident_add_neighbor(NULL, bts, &n);
+ if (rc != CMD_SUCCESS) {
+ cmd->reply = "Failed to add neighbor";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+/* Parameter format: "<lac>[-<arfcn>-<bsic>]"
+ * lac: Location area of neighbor cell (0-65535)
+ * arfcn: ARFCN of neighbor cell (0-1023)
+ * bsic: BSIC of neighbor cell */
+CTRL_CMD_DEFINE_WO(neighbor_lac_add, "neighbor-lac add");
+
+static int verify_neighbor_lac_del(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (parse_lac(cmd, NULL, value))
+ return 1;
+ return 0;
+}
+
+static int set_neighbor_lac_del(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ int rc;
+
+ struct neighbor n;
+ parse_lac(cmd, &n, cmd->value);
+ rc = neighbor_ident_del_neighbor(NULL, bts, &n);
+ if (rc != CMD_SUCCESS) {
+ cmd->reply = "Failed to delete neighbor";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+/* Parameter format: (see "add" command above) */
+CTRL_CMD_DEFINE_WO(neighbor_lac_del, "neighbor-lac del");
+
+/* This and the following: Add/Remove a LAC-CI as neighbor */
+static int parse_lac_ci(void *ctx, struct neighbor *n, const char *value)
+{
+ char *tmp = NULL, *tok, *saveptr;
+ int rc = 0;
+ int lac;
+ int ci;
+
+ if (n)
+ memset(n, 0, sizeof(*n));
+
+ tmp = talloc_strdup(ctx, value);
+ if (!tmp)
+ return -EINVAL;
+
+ /* Parse LAC */
+ tok = strtok_r(tmp, "-", &saveptr);
+ if (tok) {
+ if (osmo_str_to_int(&lac, tok, 10, 0, 65535) < 0) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Parse CI */
+ tok = strtok_r(NULL, "-", &saveptr);
+ if (tok) {
+ if (osmo_str_to_int(&ci, tok, 10, 0, 65535) < 0) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Optional parameters: ARFCN and BSIC */
+ if (continue_parse_arfcn_and_bsic(&saveptr, n)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (n) {
+ n->type = NEIGHBOR_TYPE_CELL_ID;
+ n->cell_id.id.id_discr = CELL_IDENT_LAC_AND_CI;
+ n->cell_id.id.id.lac = lac;
+ n->cell_id.id.id.ci = ci;
+ }
+
+exit:
+ talloc_free(tmp);
+ return rc;
+}
+
+static int verify_neighbor_lac_ci_add(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (parse_lac_ci(cmd, NULL, value))
+ return 1;
+ return 0;
+}
+
+static int set_neighbor_lac_ci_add(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ int rc;
+
+ struct neighbor n;
+
+ parse_lac_ci(cmd, &n, cmd->value);
+ rc = neighbor_ident_add_neighbor(NULL, bts, &n);
+ if (rc != CMD_SUCCESS) {
+ cmd->reply = "Failed to add neighbor";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+/* Parameter format: "<lac>-<ci>[-<arfcn>-<bsic>]"
+ * lac: Location area of neighbor cell (0-65535)
+ * ci: Cell ID of neighbor cell (0-65535)
+ * arfcn: ARFCN of neighbor cell (0-1023)
+ * bsic: BSIC of neighbor cell */
+CTRL_CMD_DEFINE_WO(neighbor_lac_ci_add, "neighbor-lac-ci add");
+
+static int verify_neighbor_lac_ci_del(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (parse_lac_ci(cmd, NULL, value))
+ return 1;
+ return 0;
+}
+
+static int set_neighbor_lac_ci_del(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ int rc;
+
+ struct neighbor n;
+ parse_lac_ci(cmd, &n, cmd->value);
+ rc = neighbor_ident_del_neighbor(NULL, bts, &n);
+ if (rc != CMD_SUCCESS) {
+ cmd->reply = "Failed to delete neighbor";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+/* Parameter format: (see "add" command above) */
+CTRL_CMD_DEFINE_WO(neighbor_lac_ci_del, "neighbor-lac-ci del");
+
+/* This and the following: Add/Remove a CGI as neighbor */
+static int parse_cgi(void *ctx, struct neighbor *n, const char *value)
+{
+ char *tmp = NULL, *tok, *saveptr;
+ int rc = 0;
+ uint16_t mcc;
+ uint16_t mnc;
+ bool mnc_3_digits;
+ int lac;
+ int ci;
+
+ if (n)
+ memset(n, 0, sizeof(*n));
+
+ tmp = talloc_strdup(ctx, value);
+ if (!tmp)
+ return -EINVAL;
+
+ /* Parse MCC */
+ tok = strtok_r(tmp, "-", &saveptr);
+ if (tok) {
+ if (osmo_mcc_from_str(tok, &mcc)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Parse MNC */
+ tok = strtok_r(NULL, "-", &saveptr);
+ if (tok) {
+ if (osmo_mnc_from_str(tok, &mnc, &mnc_3_digits)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Parse LAC */
+ tok = strtok_r(NULL, "-", &saveptr);
+ if (tok) {
+ if (osmo_str_to_int(&lac, tok, 10, 0, 65535) < 0) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Parse CI */
+ tok = strtok_r(NULL, "-", &saveptr);
+ if (tok) {
+ if (osmo_str_to_int(&ci, tok, 10, 0, 65535) < 0) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Optional parameters: ARFCN and BSIC */
+ if (continue_parse_arfcn_and_bsic(&saveptr, n)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (n) {
+ n->type = NEIGHBOR_TYPE_CELL_ID;
+ n->cell_id.id.id_discr = CELL_IDENT_WHOLE_GLOBAL;
+ n->cell_id.id.id.global.lai.lac = lac;
+ n->cell_id.id.id.global.lai.plmn.mcc = mcc;
+ n->cell_id.id.id.global.lai.plmn.mnc = mnc;
+ n->cell_id.id.id.global.lai.plmn.mnc_3_digits = mnc_3_digits;
+ n->cell_id.id.id.global.cell_identity = ci;
+ }
+
+exit:
+ talloc_free(tmp);
+ return rc;
+}
+
+static int verify_neighbor_cgi_add(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (parse_cgi(cmd, NULL, value))
+ return 1;
+ return 0;
+}
+
+static int set_neighbor_cgi_add(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ int rc;
+
+ struct neighbor n;
+
+ parse_cgi(cmd, &n, cmd->value);
+ rc = neighbor_ident_add_neighbor(NULL, bts, &n);
+ if (rc != CMD_SUCCESS) {
+ cmd->reply = "Failed to add neighbor";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+/* Parameter format: "<mcc>-<mnc>-<lac>-<ci>[-<arfcn>-<bsic>]"
+ * mcc: Mobile country code of neighbor cell (0-999)
+ * mnc: Mobile network code of neighbor cell (0-999)
+ * lac: Location area of neighbor cell (0-65535)
+ * ci: Cell ID of neighbor cell (0-65535)
+ * arfcn: ARFCN of neighbor cell (0-1023)
+ * bsic: BSIC of neighbor cell */
+CTRL_CMD_DEFINE_WO(neighbor_cgi_add, "neighbor-cgi add");
+
+static int verify_neighbor_cgi_del(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (parse_cgi(cmd, NULL, value))
+ return 1;
+ return 0;
+}
+
+static int set_neighbor_cgi_del(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ int rc;
+
+ struct neighbor n;
+ parse_cgi(cmd, &n, cmd->value);
+ rc = neighbor_ident_del_neighbor(NULL, bts, &n);
+ if (rc != CMD_SUCCESS) {
+ cmd->reply = "Failed to delete neighbor";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+/* Parameter format: (see "add" command above) */
+CTRL_CMD_DEFINE_WO(neighbor_cgi_del, "neighbor-cgi del");
+
+/* This and the following: Add/Remove a CGI-PS as neighbor */
+static int parse_cgi_ps(void *ctx, struct neighbor *n, const char *value)
+{
+ char *tmp = NULL, *tok, *saveptr;
+ int rc = 0;
+ uint16_t mcc;
+ uint16_t mnc;
+ bool mnc_3_digits;
+ int lac;
+ int rac;
+ int ci;
+
+ if (n)
+ memset(n, 0, sizeof(*n));
+
+ tmp = talloc_strdup(ctx, value);
+ if (!tmp)
+ return -EINVAL;
+
+ /* Parse MCC */
+ tok = strtok_r(tmp, "-", &saveptr);
+ if (tok) {
+ if (osmo_mcc_from_str(tok, &mcc)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Parse MNC */
+ tok = strtok_r(NULL, "-", &saveptr);
+ if (tok) {
+ if (osmo_mnc_from_str(tok, &mnc, &mnc_3_digits)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Parse LAC */
+ tok = strtok_r(NULL, "-", &saveptr);
+ if (tok) {
+ if (osmo_str_to_int(&lac, tok, 10, 0, 65535) < 0) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Parse RAC */
+ tok = strtok_r(NULL, "-", &saveptr);
+ if (tok) {
+ if (osmo_str_to_int(&rac, tok, 10, 0, 255) < 0) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Parse CI */
+ tok = strtok_r(NULL, "-", &saveptr);
+ if (tok) {
+ if (osmo_str_to_int(&ci, tok, 10, 0, 65535) < 0) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* Optional parameters: ARFCN and BSIC */
+ if (continue_parse_arfcn_and_bsic(&saveptr, n)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (n) {
+ n->type = NEIGHBOR_TYPE_CELL_ID;
+ n->cell_id.id.id_discr = CELL_IDENT_WHOLE_GLOBAL_PS;
+ n->cell_id.id.id.global_ps.rai.lac.lac = lac;
+ n->cell_id.id.id.global_ps.rai.rac = lac;
+ n->cell_id.id.id.global_ps.rai.lac.plmn.mcc = mcc;
+ n->cell_id.id.id.global_ps.rai.lac.plmn.mnc = mnc;
+ n->cell_id.id.id.global_ps.rai.lac.plmn.mnc_3_digits = mnc_3_digits;
+ n->cell_id.id.id.global_ps.cell_identity = ci;
+ }
+
+exit:
+ talloc_free(tmp);
+ return rc;
+}
+
+static int verify_neighbor_cgi_ps_add(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (parse_cgi_ps(cmd, NULL, value))
+ return 1;
+ return 0;
+}
+
+static int set_neighbor_cgi_ps_add(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ int rc;
+
+ struct neighbor n;
+
+ parse_cgi_ps(cmd, &n, cmd->value);
+ rc = neighbor_ident_add_neighbor(NULL, bts, &n);
+ if (rc != CMD_SUCCESS) {
+ cmd->reply = "Failed to add neighbor";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+/* Parameter format: "<mcc>-<mnc>-<lac>-<rac>-<ci>[-<arfcn>-<bsic>]"
+ * mcc: Mobile country code of neighbor cell (0-999)
+ * mnc: Mobile network code of neighbor cell (0-999)
+ * lac: Location area of neighbor cell (0-65535)
+ * rac: Routing area of neighbor cell (0-65535)
+ * ci: Cell ID of neighbor cell (0-65535)
+ * arfcn: ARFCN of neighbor cell (0-1023)
+ * bsic: BSIC of neighbor cell */
+CTRL_CMD_DEFINE_WO(neighbor_cgi_ps_add, "neighbor-cgi-ps add");
+
+static int verify_neighbor_cgi_ps_del(struct ctrl_cmd *cmd, const char *value, void *_data)
+{
+ if (parse_cgi_ps(cmd, NULL, value))
+ return 1;
+ return 0;
+}
+
+static int set_neighbor_cgi_ps_del(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ int rc;
+
+ struct neighbor n;
+ parse_cgi_ps(cmd, &n, cmd->value);
+ rc = neighbor_ident_del_neighbor(NULL, bts, &n);
+ if (rc != CMD_SUCCESS) {
+ cmd->reply = "Failed to delete neighbor";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+/* Parameter format: (see "add" command above) */
+CTRL_CMD_DEFINE_WO(neighbor_cgi_ps_del, "neighbor-cgi-ps del");
+
+/* This and the following: clear all neighbor cell information */
+static int set_neighbor_clear(struct ctrl_cmd *cmd, void *data)
+{
+ struct gsm_bts *bts = cmd->node;
+ struct neighbor *neighbor;
+ struct neighbor *neighbor_tmp;
+
+ llist_for_each_entry_safe(neighbor, neighbor_tmp, &bts->neighbors, entry) {
+ llist_del(&neighbor->entry);
+ talloc_free(neighbor);
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
+CTRL_CMD_DEFINE_WO_NOVRF(neighbor_clear, "neighbor-clear");
+
+/* Register control interface commands implemented above */
+int neighbor_ident_ctrl_init(void)
+{
+ int rc = 0;
+
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_bts_add);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_bts_del);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_lac_add);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_lac_del);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_lac_ci_add);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_lac_ci_del);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_cgi_add);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_cgi_del);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_cgi_ps_add);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_cgi_ps_del);
+ rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_neighbor_clear);
+
+ return rc;
+}
diff --git a/src/osmo-bsc/neighbor_ident_vty.c b/src/osmo-bsc/neighbor_ident_vty.c
index b500b34a4..e40fa8c09 100644
--- a/src/osmo-bsc/neighbor_ident_vty.c
+++ b/src/osmo-bsc/neighbor_ident_vty.c
@@ -146,23 +146,32 @@ void neighbor_ident_vty_parse_arfcn_bsic(struct cell_ab *ab, const char **argv)
};
}
-static int add_neighbor(struct vty *vty, struct neighbor *n)
+#define LOGPORVTY(vty, fmt, args...) \
+{ \
+ if (vty) \
+ vty_out(vty, "%% " fmt "%s", ## args, VTY_NEWLINE); \
+ else \
+ LOGP(DLINP, LOGL_NOTICE, fmt "\n", ## args); \
+} while (0) \
+
+/* Delete a neighbor from neighborlist. When the parameter *vty is set to NULL all error messages are redirected to the
+ * logtext. */
+int neighbor_ident_add_neighbor(struct vty *vty, struct gsm_bts *bts, struct neighbor *n)
{
- struct gsm_bts *bts = vty->index;
struct neighbor *neighbor;
- OSMO_ASSERT((vty->node == BTS_NODE) && bts);
+ OSMO_ASSERT(bts);
+ OSMO_ASSERT(!vty || (vty->node == BTS_NODE));
llist_for_each_entry(neighbor, &bts->neighbors, entry) {
/* Check against duplicates */
if (neighbor_same(neighbor, n, false)) {
/* Found a match on Cell ID or BTS number, without ARFCN+BSIC. If they are fully identical, ignore the
* duplicate. If the ARFCN+BSIC part differs, it's an error. */
- vty_out(vty, "%% BTS %u already had neighbor %s%s", bts->nr, neighbor_to_str_c(OTC_SELECT, neighbor),
- VTY_NEWLINE);
+ LOGPORVTY(vty, "BTS %u already had neighbor %s", bts->nr, neighbor_to_str_c(OTC_SELECT, neighbor));
if (!neighbor_same(neighbor, n, true)) {
- vty_out(vty, "%% ERROR: duplicate Cell ID in neighbor config, with differing ARFCN+BSIC: %s%s",
- neighbor_to_str_c(OTC_SELECT, n), VTY_NEWLINE);
+ LOGPORVTY(vty, "ERROR: duplicate Cell ID in neighbor config, with differing ARFCN+BSIC: %s",
+ neighbor_to_str_c(OTC_SELECT, n));
return CMD_WARNING;
}
/* Exact same neighbor again, just ignore. */
@@ -173,9 +182,9 @@ static int add_neighbor(struct vty *vty, struct neighbor *n)
if (n->type == NEIGHBOR_TYPE_CELL_ID
&& n->cell_id.ab_present && neighbor->cell_id.ab_present
&& cell_ab_match(&n->cell_id.ab, &neighbor->cell_id.ab, true)) {
- vty_out(vty, "%% Error: only one Cell Identifier entry is allowed per remote neighbor."
- " Already have: BTS %u -> %s%s", bts->nr,
- neighbor_to_str_c(OTC_SELECT, neighbor), VTY_NEWLINE);
+ LOGPORVTY(vty, "Error: only one Cell Identifier entry is allowed per remote neighbor."
+ " Already have: BTS %u -> %s", bts->nr,
+ neighbor_to_str_c(OTC_SELECT, neighbor));
return CMD_WARNING;
}
}
@@ -186,12 +195,14 @@ static int add_neighbor(struct vty *vty, struct neighbor *n)
return CMD_SUCCESS;
}
-static int del_neighbor(struct vty *vty, struct neighbor *n)
+/* Delete a neighbor from neighborlist. When the parameter *vty is set to NULL all error messages are redirected to the
+ * logtext. */
+int neighbor_ident_del_neighbor(struct vty *vty, struct gsm_bts *bts, struct neighbor *n)
{
- struct gsm_bts *bts = vty->index;
struct neighbor *neighbor;
- OSMO_ASSERT((vty->node == BTS_NODE) && bts);
+ OSMO_ASSERT(bts);
+ OSMO_ASSERT(!vty || (vty->node == BTS_NODE));
llist_for_each_entry(neighbor, &bts->neighbors, entry) {
if (neighbor->type != n->type)
@@ -216,8 +227,8 @@ static int del_neighbor(struct vty *vty, struct neighbor *n)
return CMD_SUCCESS;
}
- vty_out(vty, "%% Error: no such neighbor on BTS %d: %s%s",
- bts->nr, neighbor_to_str_c(OTC_SELECT, n), VTY_NEWLINE);
+ LOGPORVTY(vty, "Error: no such neighbor on BTS %d: %s",
+ bts->nr, neighbor_to_str_c(OTC_SELECT, n));
return CMD_WARNING;
}
@@ -271,7 +282,7 @@ DEFUN(cfg_neighbor_add_bts_nr, cfg_neighbor_add_bts_nr_cmd,
.type = NEIGHBOR_TYPE_BTS_NR,
.bts_nr = atoi(argv[0]),
};
- return add_neighbor(vty, &n);
+ return neighbor_ident_add_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_add_lac, cfg_neighbor_add_lac_cmd,
@@ -283,7 +294,7 @@ DEFUN(cfg_neighbor_add_lac, cfg_neighbor_add_lac_cmd,
};
if (neighbor_ident_vty_parse_lac(vty, &n.cell_id.id, argv))
return CMD_WARNING;
- return add_neighbor(vty, &n);
+ return neighbor_ident_add_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_add_lac_ci, cfg_neighbor_add_lac_ci_cmd,
@@ -295,7 +306,7 @@ DEFUN(cfg_neighbor_add_lac_ci, cfg_neighbor_add_lac_ci_cmd,
};
if (neighbor_ident_vty_parse_lac_ci(vty, &n.cell_id.id, argv))
return CMD_WARNING;
- return add_neighbor(vty, &n);
+ return neighbor_ident_add_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_add_cgi, cfg_neighbor_add_cgi_cmd,
@@ -307,7 +318,7 @@ DEFUN(cfg_neighbor_add_cgi, cfg_neighbor_add_cgi_cmd,
};
if (neighbor_ident_vty_parse_cgi(vty, &n.cell_id.id, argv))
return CMD_WARNING;
- return add_neighbor(vty, &n);
+ return neighbor_ident_add_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_add_cgi_ps, cfg_neighbor_add_cgi_ps_cmd,
@@ -319,7 +330,7 @@ DEFUN(cfg_neighbor_add_cgi_ps, cfg_neighbor_add_cgi_ps_cmd,
};
if (neighbor_ident_vty_parse_cgi_ps(vty, &n.cell_id.id, argv))
return CMD_WARNING;
- return add_neighbor(vty, &n);
+ return neighbor_ident_add_neighbor(vty, vty->index, &n);
}
static int neighbor_del_all(struct vty *vty)
@@ -354,7 +365,7 @@ DEFUN(cfg_neighbor_add_lac_arfcn_bsic, cfg_neighbor_add_lac_arfcn_bsic_cmd,
if (neighbor_ident_vty_parse_lac(vty, &n.cell_id.id, argv))
return CMD_WARNING;
neighbor_ident_vty_parse_arfcn_bsic(&n.cell_id.ab, argv + LAC_ARGC);
- return add_neighbor(vty, &n);
+ return neighbor_ident_add_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_add_lac_ci_arfcn_bsic, cfg_neighbor_add_lac_ci_arfcn_bsic_cmd,
@@ -368,7 +379,7 @@ DEFUN(cfg_neighbor_add_lac_ci_arfcn_bsic, cfg_neighbor_add_lac_ci_arfcn_bsic_cmd
if (neighbor_ident_vty_parse_lac_ci(vty, &n.cell_id.id, argv))
return CMD_WARNING;
neighbor_ident_vty_parse_arfcn_bsic(&n.cell_id.ab, argv + LAC_CI_ARGC);
- return add_neighbor(vty, &n);
+ return neighbor_ident_add_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_add_cgi_arfcn_bsic, cfg_neighbor_add_cgi_arfcn_bsic_cmd,
@@ -382,7 +393,7 @@ DEFUN(cfg_neighbor_add_cgi_arfcn_bsic, cfg_neighbor_add_cgi_arfcn_bsic_cmd,
if (neighbor_ident_vty_parse_cgi(vty, &n.cell_id.id, argv))
return CMD_WARNING;
neighbor_ident_vty_parse_arfcn_bsic(&n.cell_id.ab, argv + CGI_ARGC);
- return add_neighbor(vty, &n);
+ return neighbor_ident_add_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_add_cgi_ps_arfcn_bsic, cfg_neighbor_add_cgi_ps_arfcn_bsic_cmd,
@@ -396,7 +407,7 @@ DEFUN(cfg_neighbor_add_cgi_ps_arfcn_bsic, cfg_neighbor_add_cgi_ps_arfcn_bsic_cmd
if (neighbor_ident_vty_parse_cgi_ps(vty, &n.cell_id.id, argv))
return CMD_WARNING;
neighbor_ident_vty_parse_arfcn_bsic(&n.cell_id.ab, argv + CGI_PS_ARGC);
- return add_neighbor(vty, &n);
+ return neighbor_ident_add_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_del_bts_nr, cfg_neighbor_del_bts_nr_cmd,
@@ -407,7 +418,7 @@ DEFUN(cfg_neighbor_del_bts_nr, cfg_neighbor_del_bts_nr_cmd,
.type = NEIGHBOR_TYPE_BTS_NR,
.bts_nr = atoi(argv[0]),
};
- return del_neighbor(vty, &n);
+ return neighbor_ident_del_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_del_lac, cfg_neighbor_del_lac_cmd,
@@ -419,7 +430,7 @@ DEFUN(cfg_neighbor_del_lac, cfg_neighbor_del_lac_cmd,
};
if (neighbor_ident_vty_parse_lac(vty, &n.cell_id.id, argv))
return CMD_WARNING;
- return del_neighbor(vty, &n);
+ return neighbor_ident_del_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_del_lac_ci, cfg_neighbor_del_lac_ci_cmd,
@@ -431,7 +442,7 @@ DEFUN(cfg_neighbor_del_lac_ci, cfg_neighbor_del_lac_ci_cmd,
};
if (neighbor_ident_vty_parse_lac_ci(vty, &n.cell_id.id, argv))
return CMD_WARNING;
- return del_neighbor(vty, &n);
+ return neighbor_ident_del_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_del_cgi, cfg_neighbor_del_cgi_cmd,
@@ -443,7 +454,7 @@ DEFUN(cfg_neighbor_del_cgi, cfg_neighbor_del_cgi_cmd,
};
if (neighbor_ident_vty_parse_cgi(vty, &n.cell_id.id, argv))
return CMD_WARNING;
- return del_neighbor(vty, &n);
+ return neighbor_ident_del_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_del_cgi_ps, cfg_neighbor_del_cgi_ps_cmd,
@@ -455,7 +466,7 @@ DEFUN(cfg_neighbor_del_cgi_ps, cfg_neighbor_del_cgi_ps_cmd,
};
if (neighbor_ident_vty_parse_cgi_ps(vty, &n.cell_id.id, argv))
return CMD_WARNING;
- return del_neighbor(vty, &n);
+ return neighbor_ident_del_neighbor(vty, vty->index, &n);
}
DEFUN(cfg_neighbor_del_arfcn_bsic, cfg_neighbor_del_arfcn_bsic_cmd,
diff --git a/src/osmo-bsc/net_init.c b/src/osmo-bsc/net_init.c
index 6d88adb3f..ec2f881e3 100644
--- a/src/osmo-bsc/net_init.c
+++ b/src/osmo-bsc/net_init.c
@@ -56,6 +56,20 @@ static struct osmo_tdef gsm_network_T_defs[] = {
{ .T=-12, .default_val=5, .desc="Timeout for obtaining TA after BSSLAP TA Request" },
{ .T=-13, .default_val=5, .desc="Timeout for RR Channel Mode Modify ACK (BSC <-> MS)" },
{ .T=-14, .default_val=5, .desc="Timeout for RSL Channel Mode Modify ACK (BSC <-> BTS)" },
+ { .T = -16, .default_val = 1000, .unit = OSMO_TDEF_MS,
+ .desc = "Granularity for all_allocated:* rate counters: amount of milliseconds that one counter increment"
+ " represents. See also X17, X18" },
+ { .T = -17, .default_val = 0, .unit = OSMO_TDEF_MS,
+ .desc = "Rounding threshold for all_allocated:* rate counters: round up to the next counter increment"
+ " after this many milliseconds. If set to half of X16 (or 0), employ the usual round() behavior:"
+ " round up after half of a granularity period. If set to 1, behave like ceil(): already"
+ " increment the counter immediately when all channels are allocated. If set >= X16, behave like"
+ " floor(): only increment after a full X16 period of all channels being occupied."
+ " See also X16, X18" },
+ { .T = -18, .default_val = 60000, .unit = OSMO_TDEF_MS,
+ .desc = "Forget-sum period for all_allocated:* rate counters:"
+ " after this amount of idle time, forget internally cumulated time remainders. Zero to always"
+ " keep remainders. See also X16, X17." },
{ .T=-3111, .default_val=4, .desc="Wait time after lchan was released in error (should be T3111 + 2s)" },
{ .T=-3210, .default_val=20, .desc="After L3 Complete, wait for MSC to confirm" },
{}
diff --git a/src/osmo-bsc/nm_bts_fsm.c b/src/osmo-bsc/nm_bts_fsm.c
index eda74fd5a..b9ed5a04e 100644
--- a/src/osmo-bsc/nm_bts_fsm.c
+++ b/src/osmo-bsc/nm_bts_fsm.c
@@ -366,15 +366,15 @@ static struct osmo_fsm_state nm_bts_fsm_states[] = {
.action = st_op_disabled_offline,
},
[NM_BTS_ST_OP_ENABLED] = {
- .in_event_mask =
- X(NM_EV_STATE_CHG_REP),
- .out_state_mask =
- X(NM_BTS_ST_OP_DISABLED_NOTINSTALLED) |
- X(NM_BTS_ST_OP_DISABLED_DEPENDENCY) |
- X(NM_BTS_ST_OP_DISABLED_OFFLINE),
- .name = "ENABLED",
- .onenter = st_op_enabled_on_enter,
- .action = st_op_enabled,
+ .in_event_mask =
+ X(NM_EV_STATE_CHG_REP),
+ .out_state_mask =
+ X(NM_BTS_ST_OP_DISABLED_NOTINSTALLED) |
+ X(NM_BTS_ST_OP_DISABLED_DEPENDENCY) |
+ X(NM_BTS_ST_OP_DISABLED_OFFLINE),
+ .name = "ENABLED",
+ .onenter = st_op_enabled_on_enter,
+ .action = st_op_enabled,
},
};
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index aab251424..3f5605286 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -114,8 +114,7 @@ static int bssmap_handle_reset(struct bsc_msc_data *msc,
/* Page a subscriber based on TMSI and LAC via the specified BTS.
* The msc parameter is the MSC which issued the corresponding paging request.
* Log an error if paging failed. */
-static void
-page_subscriber(const struct bsc_paging_params *params, struct gsm_bts *bts, uint32_t lac)
+static void page_subscriber(const struct bsc_paging_params *params, struct gsm_bts *bts, uint32_t lac)
{
int ret;
@@ -132,16 +131,14 @@ page_subscriber(const struct bsc_paging_params *params, struct gsm_bts *bts, uin
"Paging request failed, or repeated paging on LAC %u\n", lac);
}
-static void
-page_all_bts(const struct bsc_paging_params *params)
+static void page_all_bts(const struct bsc_paging_params *params)
{
struct gsm_bts *bts;
llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list)
page_subscriber(params, bts, GSM_LAC_RESERVED_ALL_BTS);
}
-static void
-page_cgi(const struct bsc_paging_params *params)
+static void page_cgi(const struct bsc_paging_params *params)
{
int i;
for (i = 0; i < params->cil.id_list_len; i++) {
@@ -170,8 +167,7 @@ page_cgi(const struct bsc_paging_params *params)
}
}
-static void
-page_lac_and_ci(const struct bsc_paging_params *params)
+static void page_lac_and_ci(const struct bsc_paging_params *params)
{
int i;
@@ -193,8 +189,7 @@ page_lac_and_ci(const struct bsc_paging_params *params)
}
}
-static void
-page_ci(const struct bsc_paging_params *params)
+static void page_ci(const struct bsc_paging_params *params)
{
int i;
@@ -214,8 +209,7 @@ page_ci(const struct bsc_paging_params *params)
}
}
-static void
-page_lai_and_lac(const struct bsc_paging_params *params)
+static void page_lai_and_lac(const struct bsc_paging_params *params)
{
int i;
@@ -242,8 +236,7 @@ page_lai_and_lac(const struct bsc_paging_params *params)
}
}
-static void
-page_lac(const struct bsc_paging_params *params)
+static void page_lac(const struct bsc_paging_params *params)
{
int i;
@@ -1215,16 +1208,6 @@ static int bssmap_rcvmsg_dt1(struct gsm_subscriber_connection *conn,
return ret;
}
-/* RSL Link Identifier is defined in 3GPP TS 3GPP TS 48.058, section 9.3.2.
- * .... .SSS - SAPI value used on the radio link;
- * ...P P... - priority for SAPI0 messages;
- * CC.. .... - control channel identification:
- * 00.. .... - main signalling channel (FACCH or SDCCH),
- * 01.. .... - SACCH,
- * other values are reserved. */
-#define DLCI2RSL_LINK_ID(dlci) \
- ((dlci & 0xc0) == 0xc0 ? 0x40 : 0x00) | (dlci & 0x07)
-
static int dtap_rcvmsg(struct gsm_subscriber_connection *conn,
struct msgb *msg, unsigned int length)
{
diff --git a/src/osmo-bsc/osmo_bsc_ctrl.c b/src/osmo-bsc/osmo_bsc_ctrl.c
index 1eea6901b..969efb5a3 100644
--- a/src/osmo-bsc/osmo_bsc_ctrl.c
+++ b/src/osmo-bsc/osmo_bsc_ctrl.c
@@ -428,6 +428,20 @@ static int set_bts_loc(struct ctrl_cmd *cmd, void *data)
if (!tmp)
goto oom;
+ tstamp = strtok_r(tmp, ",", &saveptr);
+ valid = strtok_r(NULL, ",", &saveptr);
+ lat = strtok_r(NULL, ",", &saveptr);
+ lon = strtok_r(NULL, ",", &saveptr);
+ height = strtok_r(NULL, "\0", &saveptr);
+
+ /* Check if one of the strtok results was NULL. This will probably never occur since we will only see verified
+ * input in this code path */
+ if ((tstamp == NULL) || (valid == NULL) || (lat == NULL) || (lon == NULL) || (height == NULL)) {
+ talloc_free(tmp);
+ cmd->reply = "parse error";
+ return CTRL_CMD_ERROR;
+ }
+
curloc = talloc_zero(tall_bsc_ctx, struct bts_location);
if (!curloc) {
talloc_free(tmp);
@@ -435,13 +449,6 @@ static int set_bts_loc(struct ctrl_cmd *cmd, void *data)
}
INIT_LLIST_HEAD(&curloc->list);
-
- tstamp = strtok_r(tmp, ",", &saveptr);
- valid = strtok_r(NULL, ",", &saveptr);
- lat = strtok_r(NULL, ",", &saveptr);
- lon = strtok_r(NULL, ",", &saveptr);
- height = strtok_r(NULL, "\0", &saveptr);
-
curloc->tstamp = atol(tstamp);
curloc->valid = get_string_value(bts_loc_fix_names, valid);
curloc->lat = atof(lat);
diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c
index 92b74753f..167b0a3cc 100644
--- a/src/osmo-bsc/osmo_bsc_main.c
+++ b/src/osmo-bsc/osmo_bsc_main.c
@@ -108,7 +108,6 @@ static void print_help()
printf(" -c --config-file filename The config file to use.\n");
printf(" -e --log-level number Set a global loglevel.\n");
printf(" -r --rf-ctl NAME A unix domain socket to listen for cmds.\n");
- printf(" -t --testmode A special mode to provoke failures at the MSC.\n");
printf("\nVTY reference generation:\n");
printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n");
@@ -155,13 +154,12 @@ static void handle_options(int argc, char **argv)
{"version", 0, 0, 'V' },
{"log-level", 1, 0, 'e'},
{"rf-ctl", 1, 0, 'r'},
- {"testmode", 0, 0, 't'},
{"vty-ref-mode", 1, &long_option, 1},
{"vty-ref-xml", 0, &long_option, 2},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "hd:DsTVc:e:r:t",
+ c = getopt_long(argc, argv, "hd:DsTVc:e:r:",
long_options, &option_index);
if (c == -1)
break;
@@ -391,12 +389,49 @@ static void update_connection_stats_cb(void *data)
osmo_timer_schedule(&update_connection_stats_timer, 1, 0);
}
+static void bootstrap_bts(struct gsm_bts *bts)
+{
+ unsigned int n = 0;
+
+ /* Control Channel Description is set from vty/config */
+
+ /* Determine the value of CCCH_CONF. Is TS0/C0 combined? */
+ if (bts->c0->ts[0].pchan_from_config != GSM_PCHAN_CCCH) {
+ bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
+
+ /* Limit reserved block to 2 on combined channel according to
+ 3GPP TS 44.018 Table 10.5.2.11.1 */
+ if (bts->si_common.chan_desc.bs_ag_blks_res > 2) {
+ LOGP(DNM, LOGL_NOTICE, "CCCH is combined with SDCCHs, "
+ "reducing BS-AG-BLKS-RES value %d -> 2\n",
+ bts->si_common.chan_desc.bs_ag_blks_res);
+ bts->si_common.chan_desc.bs_ag_blks_res = 2;
+ }
+ } else { /* Non-combined TS0/C0 configuration */
+ /* There can be additional CCCHs on even timeslot numbers */
+ n += (bts->c0->ts[2].pchan_from_config == GSM_PCHAN_CCCH);
+ n += (bts->c0->ts[4].pchan_from_config == GSM_PCHAN_CCCH);
+ n += (bts->c0->ts[6].pchan_from_config == GSM_PCHAN_CCCH);
+ bts->si_common.chan_desc.ccch_conf = (n << 1);
+ }
+
+ /* ACC ramping is initialized from vty/config */
+
+ /* Initialize the BTS state */
+ gsm_bts_sm_mo_reset(bts->site_mgr);
+
+ /* Generate Mobile Allocation bit-masks for all timeslots.
+ * This needs to be done here, because it's used for TS configuration. */
+ generate_ma_for_bts(bts);
+}
+
/* Callback function to be called every time we receive a signal from INPUT */
static int inp_sig_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
struct input_signal_data *isd = signal_data;
struct gsm_bts_trx *trx = isd->trx;
+ int rc;
if (subsys != SS_L_INPUT)
return -EINVAL;
@@ -406,12 +441,24 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
switch (signal) {
case S_L_INP_TEI_UP:
if (isd->link_type == E1INP_SIGN_OML) {
- /* Generate Mobile Allocation bit-masks for all timeslots.
- * This needs to be done here, because it's used for TS configuration. */
- generate_ma_for_bts(trx->bts);
+ /* Check parameters and apply vty config dependent parameters */
+ rc = gsm_bts_check_cfg(trx->bts);
+ if (rc < 0) {
+ LOGP(DNM, LOGL_ERROR, "(bts=%u) Error in BTS configuration -- cannot bootstrap BTS\n",
+ trx->bts->nr);
+ return rc;
+ }
+ bootstrap_bts(trx->bts);
}
- if (isd->link_type == E1INP_SIGN_RSL)
+ if (isd->link_type == E1INP_SIGN_RSL) {
+ rc = gsm_bts_check_cfg(trx->bts);
+ if (rc < 0) {
+ LOGP(DNM, LOGL_ERROR, "(bts=%u) Error in BTS configuration -- cannot bootstrap RSL\n",
+ trx->bts->nr);
+ return rc;
+ }
bootstrap_rsl(trx);
+ }
break;
case S_L_INP_TEI_DN:
LOG_TRX(trx, DLMI, LOGL_ERROR, "Lost E1 %s link\n", e1inp_signtype_name(isd->link_type));
@@ -438,84 +485,6 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
return 0;
}
-static int bootstrap_bts(struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx;
- unsigned int n = 0;
-
- if (!bts->model)
- return -EFAULT;
-
- switch (bts->band) {
- case GSM_BAND_1800:
- if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) {
- LOGP(DNM, LOGL_ERROR, "GSM1800 channel must be between 512-885.\n");
- return -EINVAL;
- }
- break;
- case GSM_BAND_1900:
- if (bts->c0->arfcn < 512 || bts->c0->arfcn > 810) {
- LOGP(DNM, LOGL_ERROR, "GSM1900 channel must be between 512-810.\n");
- return -EINVAL;
- }
- break;
- case GSM_BAND_900:
- if ((bts->c0->arfcn > 124 && bts->c0->arfcn < 955) ||
- bts->c0->arfcn > 1023) {
- LOGP(DNM, LOGL_ERROR, "GSM900 channel must be between 0-124, 955-1023.\n");
- return -EINVAL;
- }
- break;
- case GSM_BAND_850:
- if (bts->c0->arfcn < 128 || bts->c0->arfcn > 251) {
- LOGP(DNM, LOGL_ERROR, "GSM850 channel must be between 128-251.\n");
- return -EINVAL;
- }
- break;
- default:
- LOGP(DNM, LOGL_ERROR, "Unsupported frequency band.\n");
- return -EINVAL;
- }
-
- /* Verify the physical channel mapping */
- llist_for_each_entry(trx, &bts->trx_list, list) {
- if (!trx_has_valid_pchan_config(trx)) {
- LOGP(DNM, LOGL_ERROR, "TRX %u has invalid timeslot "
- "configuration\n", trx->nr);
- return -EINVAL;
- }
- }
-
- /* Control Channel Description is set from vty/config */
-
- /* Determine the value of CCCH_CONF. Is TS0/C0 combined? */
- if (bts->c0->ts[0].pchan_from_config != GSM_PCHAN_CCCH) {
- bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
-
- /* Limit reserved block to 2 on combined channel according to
- 3GPP TS 44.018 Table 10.5.2.11.1 */
- if (bts->si_common.chan_desc.bs_ag_blks_res > 2) {
- LOGP(DNM, LOGL_NOTICE, "CCCH is combined with SDCCHs, "
- "reducing BS-AG-BLKS-RES value %d -> 2\n",
- bts->si_common.chan_desc.bs_ag_blks_res);
- bts->si_common.chan_desc.bs_ag_blks_res = 2;
- }
- } else { /* Non-combined TS0/C0 configuration */
- /* There can be additional CCCHs on even timeslot numbers */
- n += (bts->c0->ts[2].pchan_from_config == GSM_PCHAN_CCCH);
- n += (bts->c0->ts[4].pchan_from_config == GSM_PCHAN_CCCH);
- n += (bts->c0->ts[6].pchan_from_config == GSM_PCHAN_CCCH);
- bts->si_common.chan_desc.ccch_conf = (n << 1);
- }
-
- /* ACC ramping is initialized from vty/config */
-
- /* Initialize the BTS state */
- gsm_bts_sm_mo_reset(bts->site_mgr);
-
- return 0;
-}
-
static int bsc_network_configure(const char *config_file)
{
struct gsm_bts *bts;
@@ -537,11 +506,12 @@ static int bsc_network_configure(const char *config_file)
osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
- rc = bootstrap_bts(bts);
+ rc = gsm_bts_check_cfg(bts);
if (rc < 0) {
- LOGP(DNM, LOGL_FATAL, "Error bootstrapping BTS\n");
+ LOGP(DNM, LOGL_FATAL, "(bts=%u) cannot bootstrap BTS, invalid BTS configuration\n", bts->nr);
return rc;
}
+ bootstrap_bts(bts);
rc = e1_reconfig_bts(bts);
if (rc < 0) {
LOGP(DNM, LOGL_FATAL, "Error enabling E1 input driver\n");
@@ -921,6 +891,7 @@ int main(int argc, char **argv)
rate_ctr_init(tall_bsc_ctx);
osmo_fsm_set_dealloc_ctx(OTC_SELECT);
+ osmo_fsm_log_timeouts(true);
/* Allocate global gsm_network struct */
rc = bsc_network_alloc();
diff --git a/src/osmo-bsc/paging.c b/src/osmo-bsc/paging.c
index 04512be92..721ea31f2 100644
--- a/src/osmo-bsc/paging.c
+++ b/src/osmo-bsc/paging.c
@@ -66,6 +66,7 @@ void *tall_paging_ctx = NULL;
static void paging_remove_request(struct gsm_bts_paging_state *paging_bts,
struct gsm_paging_request *to_be_deleted)
{
+ to_be_deleted->bsub->active_paging_requests--;
osmo_timer_del(&to_be_deleted->T3113);
llist_del(&to_be_deleted->entry);
bsc_subscr_put(to_be_deleted->bsub, BSUB_USE_PAGING_REQUEST);
@@ -284,6 +285,11 @@ static void paging_T3113_expired(void *data)
/* must be destroyed before calling cbfn, to prevent double free */
rate_ctr_inc(rate_ctr_group_get_ctr(req->bts->bts_ctrs, BTS_CTR_PAGING_EXPIRED));
+ /* If last BTS paging times out (active_paging_requests will be
+ * decremented in paging_remove_request below): */
+ if (req->bsub->active_paging_requests == 1)
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_PAGING_EXPIRED));
+
/* destroy it now. Do not access req afterwards */
paging_remove_request(&req->bts->paging, req);
@@ -341,6 +347,7 @@ static int _paging_request(const struct bsc_paging_params *params, struct gsm_bt
}
LOG_PAGING_BTS(params, bts, DPAG, LOGL_DEBUG, "Start paging\n");
+ params->bsub->active_paging_requests++;
req = talloc_zero(tall_paging_ctx, struct gsm_paging_request);
OSMO_ASSERT(req);
req->reason = params->reason;
diff --git a/src/osmo-bsc/pcu_sock.c b/src/osmo-bsc/pcu_sock.c
index 6f7ee7715..d6dd9a74f 100644
--- a/src/osmo-bsc/pcu_sock.c
+++ b/src/osmo-bsc/pcu_sock.c
@@ -15,10 +15,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#include <stdio.h>
diff --git a/src/osmo-bsc/timeslot_fsm.c b/src/osmo-bsc/timeslot_fsm.c
index 76ac1af44..86fea3c8d 100644
--- a/src/osmo-bsc/timeslot_fsm.c
+++ b/src/osmo-bsc/timeslot_fsm.c
@@ -201,19 +201,24 @@ void ts_set_pchan_is(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan_
{
int i;
struct gsm_lchan *lchan;
+ uint8_t max_lchans_possible_vamos;
+
ts->pchan_is = pchan_is;
ts->max_primary_lchans = pchan_subslots(ts->pchan_is);
- LOG_TS(ts, LOGL_DEBUG, "pchan_is=%s max_primary_lchans=%d max_lchans_possible=%d\n",
- gsm_pchan_name(ts->pchan_is), ts->max_primary_lchans, ts->max_lchans_possible);
+ max_lchans_possible_vamos = pchan_subslots_vamos(ts->pchan_is);
+ LOG_TS(ts, LOGL_DEBUG, "pchan_is=%s max_primary_lchans=%d max_lchans_possible=%d (%u VAMOS)\n",
+ gsm_pchan_name(ts->pchan_is), ts->max_primary_lchans, ts->max_lchans_possible,
+ max_lchans_possible_vamos);
switch (ts->pchan_is) {
case GSM_PCHAN_TCH_F:
case GSM_PCHAN_TCH_H:
for (i = 0; i < ts->max_lchans_possible; i++) {
lchan = &ts->lchan[i];
- if (i < ts->max_primary_lchans)
- lchan->vamos.is_secondary = false;
- else
+ if (i >= ts->max_primary_lchans &&
+ (i - ts->max_primary_lchans) < (int)max_lchans_possible_vamos)
lchan->vamos.is_secondary = true;
+ else
+ lchan->vamos.is_secondary = false;
lchan_fsm_update_id(lchan);
}
break;
@@ -243,6 +248,7 @@ static void ts_setup_lchans(struct gsm_bts_trx_ts *ts)
ts->max_lchans_possible = max_lchans + max_lchans_vamos;
ts->max_primary_lchans = 0;
+ OSMO_ASSERT(ts->max_lchans_possible <= TS_MAX_LCHAN);
for (i = 0; i < ts->max_lchans_possible; i++) {
/* If we receive more than one Channel OPSTART ACK, don't fail on the second init. */
if (ts->lchan[i].fi)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0831dee5d..a5f92efcc 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -42,6 +42,7 @@ EXTRA_DIST = \
timer.vty \
power_ctrl.vty \
interf_meas.vty \
+ acch_overpower.vty \
ctrl/osmo-bsc-neigh-test.cfg \
ctrl/osmo-bsc-apply-config-file.cfg \
ctrl/osmo-bsc-apply-config-file-invalid.cfg \
@@ -60,7 +61,6 @@ python-tests: $(BUILT_SOURCES)
osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
$(srcdir)/vty_test_runner.py -w $(abs_top_builddir) -v
$(srcdir)/ctrl_test_runner.py -w $(abs_top_builddir) -v
- rm -f $(top_builddir)/sms.db $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count
else
python-tests: $(BUILT_SOURCES)
echo "Not running python-based tests (determined at configure-time)"
diff --git a/tests/acch_overpower.vty b/tests/acch_overpower.vty
new file mode 100644
index 000000000..70090a438
--- /dev/null
+++ b/tests/acch_overpower.vty
@@ -0,0 +1,88 @@
+OsmoBSC> enable
+
+OsmoBSC# ### Default configuration (overpower disabled)
+OsmoBSC# show running-config
+... !overpower
+
+OsmoBSC# configure terminal
+OsmoBSC(config)# network
+OsmoBSC(config-net)# bts 0
+OsmoBSC(config-net-bts)# list with-flags
+...
+ . ..l overpower (dl-acch|dl-sacch|dl-facch) <1-4>
+ . ..l no overpower dl-acch
+ . ..l overpower rxqual (0|1|2|3|4|5|6|7)
+ . ..l overpower chan-mode (speech-amr|any)
+...
+
+OsmoBSC(config-net-bts)# overpower?
+ overpower Temporary ACCH overpower
+OsmoBSC(config-net-bts)# overpower ?
+ dl-acch Enable overpower for both SACCH and FACCH
+ dl-sacch Enable overpower for SACCH only
+ dl-facch Enable overpower for FACCH only
+ rxqual Set RxQual (BER) threshold (default 4)
+ chan-mode Allow temporary overpower for specific Channel mode(s)
+
+OsmoBSC(config-net-bts)# overpower dl-acch ?
+ <1-4> Overpower value in dB
+OsmoBSC(config-net-bts)# overpower dl-acch 2
+OsmoBSC(config-net-bts)# show running-config
+...
+ overpower dl-acch 2
+ overpower rxqual 4
+ overpower chan-mode speech-amr
+...
+OsmoBSC(config-net-bts)# overpower dl-sacch 3
+OsmoBSC(config-net-bts)# show running-config
+...
+ overpower dl-sacch 3
+ overpower rxqual 4
+ overpower chan-mode speech-amr
+...
+OsmoBSC(config-net-bts)# overpower dl-facch 4
+OsmoBSC(config-net-bts)# show running-config
+...
+ overpower dl-facch 4
+ overpower rxqual 4
+ overpower chan-mode speech-amr
+...
+
+OsmoBSC(config-net-bts)# overpower rxqual ?
+ 0 BER >= 0% (always on)
+ 1 BER >= 0.2%
+ 2 BER >= 0.4%
+ 3 BER >= 0.8%
+ 4 BER >= 1.6% (default)
+ 5 BER >= 3.2%
+ 6 BER >= 6.4%
+ 7 BER >= 12.8%
+OsmoBSC(config-net-bts)# overpower rxqual 0
+OsmoBSC(config-net-bts)# show running-config
+...
+ overpower dl-facch 4
+ overpower rxqual 0
+ overpower chan-mode speech-amr
+...
+OsmoBSC(config-net-bts)# overpower rxqual 7
+OsmoBSC(config-net-bts)# show running-config
+...
+ overpower dl-facch 4
+ overpower rxqual 7
+ overpower chan-mode speech-amr
+...
+
+OsmoBSC(config-net-bts)# overpower chan-mode ?
+ speech-amr Speech channels using AMR codec (default)
+ any Any kind of channel mode
+OsmoBSC(config-net-bts)# overpower chan-mode any
+OsmoBSC(config-net-bts)# show running-config
+...
+ overpower dl-facch 4
+ overpower rxqual 7
+ overpower chan-mode any
+...
+
+OsmoBSC(config-net-bts)# no overpower dl-acch
+OsmoBSC(config-net-bts)# show running-config
+... !overpower
diff --git a/tests/ctrl_test_runner.py b/tests/ctrl_test_runner.py
index bd2cb1061..4c07d5e1e 100755
--- a/tests/ctrl_test_runner.py
+++ b/tests/ctrl_test_runner.py
@@ -525,6 +525,46 @@ class TestCtrlBSC(TestCtrlBase):
self.assertEqual(r['var'], 'apply-config-file')
self.assertEqual(r['value'], 'OK')
+ def testNeighborList(self):
+ # Enter manual neighbor-list mode
+ r = self.do_set('bts.0.neighbor-list.mode', 'manual')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-list.mode')
+ self.assertEqual(r['value'], 'OK')
+
+ # Add an ARFCN
+ r = self.do_set('bts.0.neighbor-list.add', '123')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-list.add')
+ self.assertEqual(r['value'], 'OK')
+
+ # Delete the ARFCN again
+ r = self.do_set('bts.0.neighbor-list.del', '123')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-list.del')
+ self.assertEqual(r['value'], 'OK')
+
+ # Go back to automatic neighbor-list mode
+ r = self.do_set('bts.0.neighbor-list.mode', 'automatic')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-list.mode')
+ self.assertEqual(r['value'], 'OK')
+
+ # This must not work as we are in automatic neighbor-list mode
+ r = self.do_set('bts.0.neighbor-list.add', '123')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'ERROR')
+ self.assertEqual(r['error'], 'Neighbor list not in manual mode')
+
+ # Try an invalid neighbor-list mode
+ r = self.do_set('bts.0.neighbor-list.mode', 'qwertzuiop')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'ERROR')
+ self.assertEqual(r['error'], 'Invalid mode')
class TestCtrlBSCNeighbor(TestCtrlBase):
@@ -562,6 +602,177 @@ class TestCtrlBSCNeighbor(TestCtrlBase):
self.assertEqual(r['var'], 'neighbor_resolve_cgi_ps_from_lac_ci.1.6969.23.32')
self.assertEqual(r['value'], '023-42-423-2-5')
+
+class TestCtrlBSCNeighborCell(TestCtrlBase):
+
+ def tearDown(self):
+ TestCtrlBase.tearDown(self)
+ os.unlink("tmp_dummy_sock")
+
+ def ctrl_command(self):
+ return ["./src/osmo-bsc/osmo-bsc", "-r", "tmp_dummy_sock", "-c",
+ "tests/ctrl/osmo-bsc-neigh-test.cfg"]
+
+ def ctrl_app(self):
+ return (4249, "./src/osmo-bsc/osmo-bsc", "OsmoBSC", "bsc")
+
+ def testCtrlAddDelBTS(self):
+ r = self.do_set('bts.0.neighbor-bts.add', '1')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-bts.add')
+ self.assertEqual(r['value'], 'OK')
+ r = self.do_set('bts.0.neighbor-bts.del', '1')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-bts.del')
+ self.assertEqual(r['value'], 'OK')
+
+ def testCtrlAddDelLAC(self):
+ # without ARFCN+BSIC:
+ r = self.do_set('bts.0.neighbor-lac.add', '100')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-lac.add')
+ self.assertEqual(r['value'], 'OK')
+ r = self.do_set('bts.0.neighbor-lac.del', '100')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-lac.del')
+ self.assertEqual(r['value'], 'OK')
+
+ # with ARFCN+BSIC:
+ r = self.do_set('bts.0.neighbor-lac.add', '100-123-4')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-lac.add')
+ self.assertEqual(r['value'], 'OK')
+ r = self.do_set('bts.0.neighbor-lac.del', '100-123-4')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-lac.del')
+ self.assertEqual(r['value'], 'OK')
+
+ def testCtrlAddDelLACCI(self):
+ # without ARFCN+BSIC:
+ r = self.do_set('bts.0.neighbor-lac-ci.add', '100-200')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-lac-ci.add')
+ self.assertEqual(r['value'], 'OK')
+ r = self.do_set('bts.0.neighbor-lac-ci.del', '100-200')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-lac-ci.del')
+ self.assertEqual(r['value'], 'OK')
+
+ # with ARFCN+BSIC:
+ r = self.do_set('bts.0.neighbor-lac-ci.add', '100-200-123-any')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-lac-ci.add')
+ self.assertEqual(r['value'], 'OK')
+ r = self.do_set('bts.0.neighbor-lac-ci.del', '100-200-123-any')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-lac-ci.del')
+ self.assertEqual(r['value'], 'OK')
+
+ def testCtrlAddDelCGI(self):
+ # without ARFCN+BSIC:
+ r = self.do_set('bts.0.neighbor-cgi.add', '001-01-100-200')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-cgi.add')
+ self.assertEqual(r['value'], 'OK')
+ r = self.do_set('bts.0.neighbor-cgi.del', '001-01-100-200')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-cgi.del')
+ self.assertEqual(r['value'], 'OK')
+
+ # with ARFCN+BSIC:
+ r = self.do_set('bts.0.neighbor-cgi.add', '001-01-100-200-123-4')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-cgi.add')
+ self.assertEqual(r['value'], 'OK')
+ r = self.do_set('bts.0.neighbor-cgi.del', '001-01-100-200-123-4')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-cgi.del')
+ self.assertEqual(r['value'], 'OK')
+
+ def testCtrlAddDelCGIPS(self):
+ # without ARFCN+BSIC:
+ r = self.do_set('bts.0.neighbor-cgi-ps.add', '001-01-100-33-200')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-cgi-ps.add')
+ self.assertEqual(r['value'], 'OK')
+ r = self.do_set('bts.0.neighbor-cgi-ps.del', '001-01-100-33-200')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-cgi-ps.del')
+ self.assertEqual(r['value'], 'OK')
+
+ # with ARFCN+BSIC:
+ r = self.do_set('bts.0.neighbor-cgi-ps.add', '001-01-100-33-200-123-any')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-cgi-ps.add')
+ self.assertEqual(r['value'], 'OK')
+ r = self.do_set('bts.0.neighbor-cgi-ps.del', '001-01-100-33-200-123-any')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-cgi-ps.del')
+ self.assertEqual(r['value'], 'OK')
+
+ def testCtrlClearNeighbors(self):
+ r = self.do_set('bts.0.neighbor-clear', 'ignored')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'SET_REPLY')
+ self.assertEqual(r['var'], 'bts.0.neighbor-clear')
+ self.assertEqual(r['value'], 'OK')
+
+ def testCtrlErrs(self):
+ # Missing BSIC
+ r = self.do_set('bts.0.neighbor-lac.add', '100-123')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'ERROR')
+ self.assertEqual(r['error'], 'Value failed verification.')
+
+ # Short value (missing RAC)
+ r = self.do_set('bts.0.neighbor-cgi-ps.del', '001-01-100-200-123-1')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'ERROR')
+ self.assertEqual(r['error'], 'Value failed verification.')
+
+ # Long value
+ r = self.do_set('bts.0.neighbor-cgi-ps.del', '001-01-100-33-200-123-1-2')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'ERROR')
+ self.assertEqual(r['error'], 'Value failed verification.')
+
+ # Out of range values
+ r = self.do_set('bts.0.neighbor-cgi.add', '100001-1123401-100-200')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'ERROR')
+ self.assertEqual(r['error'], 'Value failed verification.')
+
+ # Garbage
+ r = self.do_set('bts.0.neighbor-lac-ci.add', '0G1-Z1-1U0-a3-2p0')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'ERROR')
+ self.assertEqual(r['error'], 'Value failed verification.')
+
+ # Delete something that shouldn't be there
+ r = self.do_set('bts.0.neighbor-cgi-ps.del', '001-01-100-33-200-123-any')
+ print('respose: ' + str(r))
+ self.assertEqual(r['mtype'], 'ERROR')
+ self.assertEqual(r['error'], 'Failed to delete neighbor')
+
+
def add_bsc_test(suite, workdir, klass):
if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc/osmo-bsc")):
print("Skipping the BSC test")
@@ -601,5 +812,6 @@ if __name__ == '__main__':
suite = unittest.TestSuite()
add_bsc_test(suite, workdir, TestCtrlBSC)
add_bsc_test(suite, workdir, TestCtrlBSCNeighbor)
+ add_bsc_test(suite, workdir, TestCtrlBSCNeighborCell)
res = unittest.TextTestRunner(verbosity=verbose_level).run(suite)
sys.exit(len(res.errors) + len(res.failures))
diff --git a/tests/handover/handover_test.c b/tests/handover/handover_test.c
index 17bc048be..dd2f16aea 100644
--- a/tests/handover/handover_test.c
+++ b/tests/handover/handover_test.c
@@ -1710,3 +1710,7 @@ const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgc
};
return &ret;
}
+struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep)
+{
+ return NULL;
+}
diff --git a/tests/nanobts_omlattr/nanobts_omlattr_test.c b/tests/nanobts_omlattr/nanobts_omlattr_test.c
index 0b9f6d9bb..1b3cc8e5f 100644
--- a/tests/nanobts_omlattr/nanobts_omlattr_test.c
+++ b/tests/nanobts_omlattr/nanobts_omlattr_test.c
@@ -163,7 +163,7 @@ int main(int argc, char **argv)
bts->location_area_code = 1;
bts->gprs.rac = 0;
uint8_t attr_bts_expected[] =
- { 0x19, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x73, 0x18, 0x06, 0x0e, 0x00,
+ { 0x19, 0x73, 0x6d, 0x67, 0x61, 0x5b, 0x55, 0x18, 0x06, 0x0e, 0x00,
0x02, 0x01, 0x20, 0x33, 0x1e, 0x24, 0x24, 0xa8, 0x34, 0x21,
0xa8, 0x1f, 0x3f, 0x25,
0x00, 0x01, 0x0a, 0x0c, 0x0a, 0x0b, 0x01, 0x2a, 0x5a, 0x2b,
diff --git a/tests/nanobts_omlattr/nanobts_omlattr_test.ok b/tests/nanobts_omlattr/nanobts_omlattr_test.ok
index 2f3ff771e..e1029a4bf 100644
--- a/tests/nanobts_omlattr/nanobts_omlattr_test.ok
+++ b/tests/nanobts_omlattr/nanobts_omlattr_test.ok
@@ -1,6 +1,6 @@
Testing nanobts_attr_bts_get()...
-result= 19555b61676d7318060e00020120331e2424a83421a81f3f2500010a0c0a0b012a5a2b03e80a0d230a080362093f99000700f11000010539
-expected=19555b61676d7318060e00020120331e2424a83421a81f3f2500010a0c0a0b012a5a2b03e80a0d230a080362093f99000700f11000010539
+result= 19736d67615b5518060e00020120331e2424a83421a81f3f2500010a0c0a0b012a5a2b03e80a0d230a080362093f99000700f11000010539
+expected=19736d67615b5518060e00020120331e2424a83421a81f3f2500010a0c0a0b012a5a2b03e80a0d230a080362093f99000700f11000010539
ok.
Testing nanobts_attr_nse_get()...
diff --git a/tests/power_ctrl.vty b/tests/power_ctrl.vty
index 374002d82..f0ef46e31 100644
--- a/tests/power_ctrl.vty
+++ b/tests/power_ctrl.vty
@@ -143,22 +143,22 @@ OsmoBSC(config-ms-power-ctrl)# show running-config
rxlev-thresh-comp lower 10 12 upper 19 20
rxqual-thresh lower 3 upper 0
rxqual-thresh-comp lower 5 7 upper 15 18
- ci-thresh fr-efr enable
+ ci-thresh fr-efr disable
ci-thresh fr-efr lower 13 upper 17
ci-thresh-comp fr-efr lower 5 7 upper 15 18
- ci-thresh hr enable
+ ci-thresh hr disable
ci-thresh hr lower 16 upper 21
ci-thresh-comp hr lower 5 7 upper 15 18
- ci-thresh amr-fr enable
+ ci-thresh amr-fr disable
ci-thresh amr-fr lower 7 upper 11
ci-thresh-comp amr-fr lower 5 7 upper 15 18
- ci-thresh amr-hr enable
+ ci-thresh amr-hr disable
ci-thresh amr-hr lower 13 upper 17
ci-thresh-comp amr-hr lower 5 7 upper 15 18
- ci-thresh sdcch enable
+ ci-thresh sdcch disable
ci-thresh sdcch lower 12 upper 16
ci-thresh-comp sdcch lower 5 7 upper 15 18
- ci-thresh gprs enable
+ ci-thresh gprs disable
ci-thresh gprs lower 18 upper 24
ci-thresh-comp gprs lower 5 7 upper 15 18
...
@@ -304,12 +304,37 @@ OsmoBSC(config-net-bts)# show running-config
rxqual-thresh-comp lower 5 7 upper 15 18
...
-OsmoBSC(config-net-bts)# ### Check 'ci-thresh-comp disable all' works properly:
+OsmoBSC(config-net-bts)# ### Check 'ci-thresh-comp (enable|disable) all' works properly:
OsmoBSC(config-net-bts)# ms-power-control
OsmoBSC(config-ms-power-ctrl)# show running-config
...
ms-power-control
...
+ ci-thresh fr-efr disable
+ ci-thresh fr-efr lower 13 upper 17
+ ci-thresh-comp fr-efr lower 5 7 upper 15 18
+ ci-thresh hr disable
+ ci-thresh hr lower 16 upper 21
+ ci-thresh-comp hr lower 5 7 upper 15 18
+ ci-thresh amr-fr disable
+ ci-thresh amr-fr lower 7 upper 11
+ ci-thresh-comp amr-fr lower 5 7 upper 15 18
+ ci-thresh amr-hr disable
+ ci-thresh amr-hr lower 13 upper 17
+ ci-thresh-comp amr-hr lower 5 7 upper 15 18
+ ci-thresh sdcch disable
+ ci-thresh sdcch lower 12 upper 16
+ ci-thresh-comp sdcch lower 5 7 upper 15 18
+ ci-thresh gprs disable
+ ci-thresh gprs lower 18 upper 24
+ ci-thresh-comp gprs lower 5 7 upper 15 18
+...
+
+OsmoBSC(config-ms-power-ctrl)# ci-thresh all enable
+OsmoBSC(config-ms-power-ctrl)# show running-config
+...
+ ms-power-control
+...
ci-thresh fr-efr enable
ci-thresh fr-efr lower 13 upper 17
ci-thresh-comp fr-efr lower 5 7 upper 15 18
diff --git a/tests/timer.vty b/tests/timer.vty
index 71dd2c19f..12c13adb1 100644
--- a/tests/timer.vty
+++ b/tests/timer.vty
@@ -29,6 +29,9 @@ net: X11 = 5 s Timeout for Perform Location Response from SMLC (default: 5 s)
net: X12 = 5 s Timeout for obtaining TA after BSSLAP TA Request (default: 5 s)
net: X13 = 5 s Timeout for RR Channel Mode Modify ACK (BSC <-> MS) (default: 5 s)
net: X14 = 5 s Timeout for RSL Channel Mode Modify ACK (BSC <-> BTS) (default: 5 s)
+net: X16 = 1000 ms Granularity for all_allocated:* rate counters: amount of milliseconds that one counter increment represents. See also X17, X18 (default: 1000 ms)
+net: X17 = 0 ms Rounding threshold for all_allocated:* rate counters: round up to the next counter increment after this many milliseconds. If set to half of X16 (or 0), employ the usual round() behavior: round up after half of a granularity period. If set to 1, behave like ceil(): already increment the counter immediately when all channels are allocated. If set >= X16, behave like floor(): only increment after a full X16 period of all channels being occupied. See also X16, X18 (default: 0 ms)
+net: X18 = 60000 ms Forget-sum period for all_allocated:* rate counters: after this amount of idle time, forget internally cumulated time remainders. Zero to always keep remainders. See also X16, X17. (default: 60000 ms)
net: X3111 = 4 s Wait time after lchan was released in error (should be T3111 + 2s) (default: 4 s)
net: X3210 = 20 s After L3 Complete, wait for MSC to confirm (default: 20 s)
mgw: X2427 = 5 s timeout for MGCP response from MGW (default: 5 s)
@@ -78,6 +81,9 @@ net: X11 = 5 s Timeout for Perform Location Response from SMLC (default: 5 s)
net: X12 = 5 s Timeout for obtaining TA after BSSLAP TA Request (default: 5 s)
net: X13 = 5 s Timeout for RR Channel Mode Modify ACK (BSC <-> MS) (default: 5 s)
net: X14 = 5 s Timeout for RSL Channel Mode Modify ACK (BSC <-> BTS) (default: 5 s)
+net: X16 = 1000 ms Granularity for all_allocated:* rate counters: amount of milliseconds that one counter increment represents. See also X17, X18 (default: 1000 ms)
+net: X17 = 0 ms Rounding threshold for all_allocated:* rate counters: round up to the next counter increment after this many milliseconds. If set to half of X16 (or 0), employ the usual round() behavior: round up after half of a granularity period. If set to 1, behave like ceil(): already increment the counter immediately when all channels are allocated. If set >= X16, behave like floor(): only increment after a full X16 period of all channels being occupied. See also X16, X18 (default: 0 ms)
+net: X18 = 60000 ms Forget-sum period for all_allocated:* rate counters: after this amount of idle time, forget internally cumulated time remainders. Zero to always keep remainders. See also X16, X17. (default: 60000 ms)
net: X3111 = 4 s Wait time after lchan was released in error (should be T3111 + 2s) (default: 4 s)
net: X3210 = 20 s After L3 Complete, wait for MSC to confirm (default: 20 s)
mgw: X2427 = 5 s timeout for MGCP response from MGW (default: 5 s)