aboutsummaryrefslogtreecommitdiffstats
path: root/include/osmocom/bsc
diff options
context:
space:
mode:
Diffstat (limited to 'include/osmocom/bsc')
-rw-r--r--include/osmocom/bsc/Makefile.am28
-rw-r--r--include/osmocom/bsc/a_reset.h4
-rw-r--r--include/osmocom/bsc/abis_nm.h16
-rw-r--r--include/osmocom/bsc/abis_om2000.h37
-rw-r--r--include/osmocom/bsc/abis_osmo.h (renamed from include/osmocom/bsc/openbscdefines.h)29
-rw-r--r--include/osmocom/bsc/abis_rsl.h38
-rw-r--r--include/osmocom/bsc/acc.h (renamed from include/osmocom/bsc/acc_ramp.h)98
-rw-r--r--include/osmocom/bsc/arfcn_range_encode.h26
-rw-r--r--include/osmocom/bsc/assignment_fsm.h13
-rw-r--r--include/osmocom/bsc/bsc_msc_data.h192
-rw-r--r--include/osmocom/bsc/bsc_msg_filter.h103
-rw-r--r--include/osmocom/bsc/bsc_stats.h116
-rw-r--r--include/osmocom/bsc/bsc_subscr_conn_fsm.h36
-rw-r--r--include/osmocom/bsc/bsc_subscriber.h63
-rw-r--r--include/osmocom/bsc/bss.h3
-rw-r--r--include/osmocom/bsc/bssmap_reset.h32
-rw-r--r--include/osmocom/bsc/bts.h862
-rw-r--r--include/osmocom/bsc/bts_ipaccess_nanobts_omlattr.h22
-rw-r--r--include/osmocom/bsc/bts_setup_ramp.h69
-rw-r--r--include/osmocom/bsc/bts_sm.h80
-rw-r--r--include/osmocom/bsc/bts_trx.h102
-rw-r--r--include/osmocom/bsc/chan_alloc.h3
-rw-r--r--include/osmocom/bsc/chan_counts.h111
-rw-r--r--include/osmocom/bsc/codec_pref.h17
-rw-r--r--include/osmocom/bsc/ctrl.h21
-rw-r--r--include/osmocom/bsc/data_rate_pref.h11
-rw-r--r--include/osmocom/bsc/debug.h12
-rw-r--r--include/osmocom/bsc/gsm_04_08_rr.h30
-rw-r--r--include/osmocom/bsc/gsm_04_80.h7
-rw-r--r--include/osmocom/bsc/gsm_08_08.h8
-rw-r--r--include/osmocom/bsc/gsm_data.h1507
-rw-r--r--include/osmocom/bsc/gsm_timers.h56
-rw-r--r--include/osmocom/bsc/handover.h21
-rw-r--r--include/osmocom/bsc/handover_cfg.h73
-rw-r--r--include/osmocom/bsc/handover_ctrl.h3
-rw-r--r--include/osmocom/bsc/handover_fsm.h22
-rw-r--r--include/osmocom/bsc/handover_vty.h2
-rw-r--r--include/osmocom/bsc/ipaccess.h4
-rw-r--r--include/osmocom/bsc/lb.h63
-rw-r--r--include/osmocom/bsc/lchan.h393
-rw-r--r--include/osmocom/bsc/lchan_fsm.h39
-rw-r--r--include/osmocom/bsc/lchan_rtp_fsm.h11
-rw-r--r--include/osmocom/bsc/lchan_select.h27
-rw-r--r--include/osmocom/bsc/lcs_loc_req.h57
-rw-r--r--include/osmocom/bsc/lcs_ta_req.h29
-rw-r--r--include/osmocom/bsc/meas_feed.h5
-rw-r--r--include/osmocom/bsc/meas_rep.h32
-rw-r--r--include/osmocom/bsc/mgw_endpoint_fsm.h59
-rw-r--r--include/osmocom/bsc/neighbor_ident.h105
-rw-r--r--include/osmocom/bsc/nm_common_fsm.h125
-rw-r--r--include/osmocom/bsc/osmo_bsc.h18
-rw-r--r--include/osmocom/bsc/osmo_bsc_grace.h5
-rw-r--r--include/osmocom/bsc/osmo_bsc_lcls.h20
-rw-r--r--include/osmocom/bsc/osmo_bsc_reset.h34
-rw-r--r--include/osmocom/bsc/osmo_bsc_rf.h5
-rw-r--r--include/osmocom/bsc/osmo_bsc_sigtran.h15
-rw-r--r--include/osmocom/bsc/osmux.h36
-rw-r--r--include/osmocom/bsc/paging.h113
-rw-r--r--include/osmocom/bsc/pcu_if.h25
-rw-r--r--include/osmocom/bsc/pcuif_proto.h189
-rw-r--r--include/osmocom/bsc/penalty_timers.h47
-rw-r--r--include/osmocom/bsc/power_control.h99
-rw-r--r--include/osmocom/bsc/rest_octets.h122
-rw-r--r--include/osmocom/bsc/signal.h47
-rw-r--r--include/osmocom/bsc/smscb.h73
-rw-r--r--include/osmocom/bsc/system_information.h13
-rw-r--r--include/osmocom/bsc/timeslot_fsm.h26
-rw-r--r--include/osmocom/bsc/ussd.h10
-rw-r--r--include/osmocom/bsc/vgcs_fsm.h121
-rw-r--r--include/osmocom/bsc/vty.h71
70 files changed, 3998 insertions, 1913 deletions
diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am
index 02a4ad8e2..a560f23d9 100644
--- a/include/osmocom/bsc/Makefile.am
+++ b/include/osmocom/bsc/Makefile.am
@@ -2,42 +2,50 @@ noinst_HEADERS = \
a_reset.h \
abis_nm.h \
abis_om2000.h \
+ abis_osmo.h \
abis_rsl.h \
- acc_ramp.h \
- arfcn_range_encode.h \
+ acc.h \
assignment_fsm.h \
- bsc_msg_filter.h \
bsc_rll.h \
+ bsc_stats.h \
bsc_subscriber.h \
bsc_subscr_conn_fsm.h \
bss.h \
+ bts.h \
+ bts_sm.h \
+ bts_setup_ramp.h \
+ bts_trx.h \
bts_ipaccess_nanobts_omlattr.h \
chan_alloc.h \
+ chan_counts.h \
codec_pref.h \
+ data_rate_pref.h \
ctrl.h \
debug.h \
e1_config.h \
gsm_04_08_rr.h \
- gsm_04_80.h \
gsm_data.h \
- gsm_timers.h \
handover.h \
handover_cfg.h \
+ handover_ctrl.h \
handover_decision.h \
handover_decision_2.h \
handover_fsm.h \
handover_vty.h \
ipaccess.h \
+ lb.h \
+ lchan.h \
lchan_fsm.h \
lchan_rtp_fsm.h \
lchan_select.h \
+ lcs_loc_req.h \
+ lcs_ta_req.h \
meas_feed.h \
meas_rep.h \
misdn.h \
- mgw_endpoint_fsm.h \
neighbor_ident.h \
network_listen.h \
- openbscdefines.h \
+ nm_common_fsm.h \
osmo_bsc.h \
osmo_bsc_grace.h \
osmo_bsc_rf.h \
@@ -47,14 +55,16 @@ noinst_HEADERS = \
paging.h \
pcu_if.h \
pcuif_proto.h \
- rest_octets.h \
+ bssmap_reset.h \
rs232.h \
signal.h \
system_information.h \
timeslot_fsm.h \
- ussd.h \
vty.h \
gsm_08_08.h \
penalty_timers.h \
osmo_bsc_lcls.h \
+ smscb.h \
+ power_control.h \
+ vgcs_fsm.h \
$(NULL)
diff --git a/include/osmocom/bsc/a_reset.h b/include/osmocom/bsc/a_reset.h
index a09972e18..dd44ea5c1 100644
--- a/include/osmocom/bsc/a_reset.h
+++ b/include/osmocom/bsc/a_reset.h
@@ -23,9 +23,9 @@
struct bsc_msc_data;
/* Create and start state machine which handles the reset/reset-ack procedure */
-void a_reset_alloc(struct bsc_msc_data *msc, const char *name, void *cb);
+void a_reset_alloc(struct bsc_msc_data *msc, const char *name);
-/* Confirm that we sucessfully received a reset acknowlege message */
+/* Confirm that we successfully received a reset acknowledge message */
void a_reset_ack_confirm(struct bsc_msc_data *msc);
/* Report a failed connection */
diff --git a/include/osmocom/bsc/abis_nm.h b/include/osmocom/bsc/abis_nm.h
index 45bbe2c02..f55c29c9d 100644
--- a/include/osmocom/bsc/abis_nm.h
+++ b/include/osmocom/bsc/abis_nm.h
@@ -1,4 +1,4 @@
-/* GSM Network Management messages on the A-bis interface
+/* GSM Network Management messages on the A-bis interface
* 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
@@ -27,9 +27,7 @@
#include <osmocom/gsm/protocol/gsm_12_21.h>
#include <osmocom/bsc/gsm_data.h>
-
-/* max number of attributes represented as 3GPP TS 52.021 ยง9.4.62 SW Description array */
-#define MAX_BTS_ATTR 5
+#include <osmocom/bsc/signal.h>
/* The BCCH info from an ip.access test, in host byte order
* and already parsed... */
@@ -88,7 +86,8 @@ int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len);
int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len);
int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb);
int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
- uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len);
+ uint8_t i2, uint8_t i3, int nack,
+ const uint8_t *attr, unsigned int attr_len);
int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *msg);
int abis_nm_event_reports(struct gsm_bts *bts, int on);
int abis_nm_reset_resource(struct gsm_bts *bts);
@@ -150,7 +149,7 @@ int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx);
int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
uint8_t *attr, uint8_t attr_len);
-int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
+int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
uint32_t ip, uint16_t port, uint8_t stream);
void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts);
int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf);
@@ -170,9 +169,14 @@ void abis_nm_queue_send_next(struct gsm_bts *bts); /* for bs11_config. */
int abis_nm_select_newest_sw(const struct abis_nm_sw_desc *sw, const size_t len);
+struct nm_fail_rep_signal_data *abis_nm_fail_evt_rep_parse(struct msgb *mb, struct gsm_bts *bts);
+
/* Helper functions for updating attributes */
int abis_nm_update_max_power_red(struct gsm_bts_trx *trx);
struct gsm_bts_trx_ts *abis_nm_get_ts(const struct msgb *oml_msg);
+#define LOGPFOH(ss, lvl, foh, fmt, args ...) LOGP(ss, lvl, "%s: " fmt, abis_nm_dump_foh(foh), ## args)
+#define DEBUGPFOH(ss, foh, fmt, args ...) LOGPFOH(ss, LOGL_DEBUG, foh, fmt, ## args)
+
#endif /* _NM_H */
diff --git a/include/osmocom/bsc/abis_om2000.h b/include/osmocom/bsc/abis_om2000.h
index b093a0350..a61601552 100644
--- a/include/osmocom/bsc/abis_om2000.h
+++ b/include/osmocom/bsc/abis_om2000.h
@@ -24,11 +24,13 @@
enum abis_om2k_mo_cls {
OM2K_MO_CLS_TRXC = 0x01,
+ OM2K_MO_CLS_TG = 0x02,
OM2K_MO_CLS_TS = 0x03,
OM2K_MO_CLS_TF = 0x04,
OM2K_MO_CLS_IS = 0x05,
OM2K_MO_CLS_CON = 0x06,
OM2K_MO_CLS_DP = 0x07,
+ OM2K_MO_CLS_MCTR = 0x08,
OM2K_MO_CLS_CF = 0x0a,
OM2K_MO_CLS_TX = 0x0b,
OM2K_MO_CLS_RX = 0x0c,
@@ -41,6 +43,17 @@ enum om2k_mo_state {
OM2K_MO_S_DISABLED,
};
+enum om2k_sync_src {
+ OM2K_SYNC_SRC_INTERNAL = 0x00,
+ OM2K_SYNC_SRC_EXTERNAL = 0x01,
+};
+
+enum om2k_rx_diversity {
+ OM2K_RX_DIVERSITY_B = 0x01,
+ OM2K_RX_DIVERSITY_A = 0x02,
+ OM2K_RX_DIVERSITY_AB = 0x03,
+};
+
/* on-wire format for IS conn group */
struct om2k_is_conn_grp {
uint16_t icp1;
@@ -111,19 +124,41 @@ int abis_om2k_tx_test_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo);
int abis_om2k_tx_op_info(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
uint8_t operational);
int abis_om2k_tx_cap_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo);
+int abis_om2k_tx_arb(struct gsm_bts *bts, struct abis_om2k_mo *mo, uint16_t req, uint8_t *buf, int buf_len);
int abis_om2k_tx_is_conf_req(struct gsm_bts *bts);
+int abis_om2k_tx_con_conf_req(struct gsm_bts *bts);
int abis_om2k_tx_tf_conf_req(struct gsm_bts *bts);
int abis_om2k_tx_rx_conf_req(struct gsm_bts_trx *trx);
int abis_om2k_tx_tx_conf_req(struct gsm_bts_trx *trx);
int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts);
-struct osmo_fsm_inst *om2k_bts_fsm_start(struct gsm_bts *bts);
+enum om2k_bts_state {
+ OM2K_BTS_S_INIT,
+ OM2K_BTS_S_WAIT_CF,
+ OM2K_BTS_S_WAIT_IS,
+ OM2K_BTS_S_WAIT_CON,
+ OM2K_BTS_S_WAIT_TF,
+ OM2K_BTS_S_WAIT_MCTR,
+ OM2K_BTS_S_WAIT_TRX_LAPD,
+ OM2K_BTS_S_WAIT_TRX,
+ OM2K_BTS_S_DONE,
+ OM2K_BTS_S_ERROR,
+};
+
void abis_om2k_bts_init(struct gsm_bts *bts);
+void om2k_bts_fsm_start(struct gsm_bts *bts);
+void om2k_bts_fsm_reset(struct gsm_bts *bts);
+
void abis_om2k_trx_init(struct gsm_bts_trx *trx);
+void om2k_trx_fsm_start(struct gsm_bts_trx *trx);
+void om2k_trx_fsm_reset(struct gsm_bts_trx *trx);
int abis_om2k_vty_init(void);
struct vty;
void abis_om2k_config_write_bts(struct vty *vty, struct gsm_bts *bts);
+void abis_om2k_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx);
+
+const char *abis_om2k_mo_name(const struct abis_om2k_mo *mo);
#endif /* OPENBCS_ABIS_OM2K_H */
diff --git a/include/osmocom/bsc/openbscdefines.h b/include/osmocom/bsc/abis_osmo.h
index c6ac153b8..97871ace0 100644
--- a/include/osmocom/bsc/openbscdefines.h
+++ b/include/osmocom/bsc/abis_osmo.h
@@ -1,6 +1,7 @@
-/*
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- *
+/* GSM Network Management messages on the A-bis interface
+ * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
+
+/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -18,17 +19,15 @@
*
*/
-#ifndef OPENBSCDEFINES_H
-#define OPENBSCDEFINES_H
+#pragma once
+
+#include <stdint.h>
+
+#include <osmocom/core/msgb.h>
+
+#include <osmocom/gsm/protocol/gsm_04_08.h>
-#ifdef BUILDING_ON_WINDOWS
- #ifdef BUILDING_OPENBSC
- #define BSC_API __declspec(dllexport)
- #else
- #define BSC_API __declspec(dllimport)
- #endif
-#else
- #define BSC_API __attribute__((visibility("default")))
-#endif
+struct gsm_bts;
-#endif
+int abis_osmo_rcvmsg(struct msgb *msg);
+int abis_osmo_sendmsg(struct gsm_bts *bts, struct msgb *msg);
diff --git a/include/osmocom/bsc/abis_rsl.h b/include/osmocom/bsc/abis_rsl.h
index 098d2e6ee..023793ae5 100644
--- a/include/osmocom/bsc/abis_rsl.h
+++ b/include/osmocom/bsc/abis_rsl.h
@@ -35,32 +35,45 @@ struct gsm_bts_trx_ts;
#define GSM48_LEN2PLEN(a) (((a) << 2) | 1)
+#define RSL_ALLOC_SIZE 1024
+#define RSL_ALLOC_HEADROOM 128
+
+#define rsl_msgb_alloc(args...) \
+ msgb_alloc_headroom(RSL_ALLOC_SIZE, RSL_ALLOC_HEADROOM, \
+ __FILE__ ":" OSMO_STRINGIFY_VAL(__LINE__))
+
const char *ip_to_a(uint32_t ip);
+struct e1inp_sign_link *rsl_chan_link(const struct gsm_lchan *lchan);
+
int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len);
int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type,
const uint8_t *data, int len);
int rsl_tx_chan_activ(struct gsm_lchan *lchan, uint8_t act_type, uint8_t ho_ref);
int rsl_chan_mode_modify_req(struct gsm_lchan *ts);
int rsl_encryption_cmd(struct msgb *msg);
-int rsl_paging_cmd(struct gsm_bts *bts, uint8_t paging_group, uint8_t len,
- uint8_t *ms_ident, uint8_t chan_needed, bool is_gprs);
-int rsl_imm_assign_cmd(struct gsm_bts *bts, uint8_t len, uint8_t *val);
+int rsl_paging_cmd(struct gsm_bts *bts, uint8_t paging_group,
+ const struct osmo_mobile_identity *mi,
+ uint8_t chan_needed, bool is_gprs);
+int rsl_notification_cmd(struct gsm_bts *bts, struct gsm_lchan *lchan, struct gsm0808_group_callref *gc, uint8_t *drx);
+int rsl_imm_assign_cmd(const struct gsm_bts *bts, uint8_t len, const uint8_t *val);
int rsl_tx_imm_assignment(struct gsm_lchan *lchan);
int rsl_tx_imm_ass_rej(struct gsm_bts *bts, struct gsm48_req_ref *rqd_ref);
int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, uint8_t power_command);
int rsl_data_request(struct msgb *msg, uint8_t link_id);
+int rsl_unit_data_request(struct msgb *msg, uint8_t link_id);
int rsl_establish_request(struct gsm_lchan *lchan, uint8_t link_id);
int rsl_relase_request(struct gsm_lchan *lchan, uint8_t link_id);
/* Ericcson vendor specific RSL extensions */
-int rsl_ericsson_imm_assign_cmd(struct gsm_bts *bts, uint32_t tlli, uint8_t len, uint8_t *val);
+int rsl_ericsson_imm_assign_cmd(const struct gsm_bts *bts, uint32_t msg_id, uint8_t len,
+ const uint8_t *val, uint8_t pag_grp, bool confirm);
/* Siemens vendor-specific RSL extensions */
int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci);
-/* ip.access specfic RSL extensions */
+/* ip.access specific RSL extensions */
struct msgb *rsl_make_ipacc_mdcx(const struct gsm_lchan *lchan, uint32_t dest_ip, uint16_t dest_port);
int rsl_tx_ipacc_crcx(const struct gsm_lchan *lchan);
int rsl_tx_ipacc_mdcx(const struct gsm_lchan *lchan);
@@ -72,8 +85,6 @@ int abis_rsl_rcvmsg(struct msgb *msg);
int rsl_release_request(struct gsm_lchan *lchan, uint8_t link_id,
enum rsl_rel_mode release_mode);
-int rsl_lchan_mark_broken(struct gsm_lchan *lchan, const char *broken);
-
/* to be provided by external code */
int rsl_deact_sacch(struct gsm_lchan *lchan);
@@ -85,12 +96,13 @@ int rsl_sacch_info_modify(struct gsm_lchan *lchan, uint8_t type,
const uint8_t *data, int len);
int rsl_chan_bs_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int db);
-int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm);
+int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan);
/* SMSCB functionality */
int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number,
struct rsl_ie_cb_cmd_type cb_command,
- const uint8_t *data, int len);
+ bool use_extended_cbch, const uint8_t *data, int len);
+int rsl_etws_pn_command(struct gsm_bts *bts, uint8_t chan_nr, const uint8_t *data, int len);
/* some Nokia specific stuff */
int rsl_nokia_si_begin(struct gsm_bts_trx *trx);
@@ -110,11 +122,19 @@ int rsl_tx_dyn_ts_pdch_act_deact(struct gsm_bts_trx_ts *ts, bool activate);
int rsl_forward_layer3_info(struct gsm_lchan *lchan, const uint8_t *l3_info, uint8_t l3_info_len);
+int ipacc_rtp_csd_fmt_transp(const struct channel_mode_and_rate *ch_mode_rate,
+ const enum rsl_ipac_rtp_csd_format_d format_d);
+int ipacc_rtp_csd_fmt_non_transp(const struct channel_mode_and_rate *ch_mode_rate,
+ const enum rsl_ipac_rtp_csd_format_d format_d);
+
int ipacc_speech_mode(enum gsm48_chan_mode tch_mode, enum gsm_chan_t type);
void ipacc_speech_mode_set_direction(uint8_t *speech_mode, bool send);
int ipacc_payload_type(enum gsm48_chan_mode tch_mode, enum gsm_chan_t type);
int rsl_tx_rf_chan_release(struct gsm_lchan *lchan);
+void abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts);
+void abis_rsl_chan_rqd_queue_flush(struct gsm_bts *bts);
+
#endif /* RSL_MT_H */
diff --git a/include/osmocom/bsc/acc_ramp.h b/include/osmocom/bsc/acc.h
index efb12b088..531a69acf 100644
--- a/include/osmocom/bsc/acc_ramp.h
+++ b/include/osmocom/bsc/acc.h
@@ -27,6 +27,40 @@
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
+#define ACC_MGR_QUANTUM_DEFAULT 20 /* 20 seconds */
+
+/* Manage rotating subset of allowed Access Class as per configuration */
+struct acc_mgr {
+ struct gsm_bts *bts; /*!< backpointer to BTS using this ACC manager */
+ /* Administrative Maximum Number of ACC 0-9 to be allowed at the same time.
+ Configurable through VTY cmd "access-control-class-roundrobin",
+ defaults to all allowed (10) */
+ uint8_t len_allowed_adm;
+ /* Further limiting the number of ACC to use. It may be lower due
+ to ramping, based for instance on channel or system load. */
+ uint8_t len_allowed_ramp;
+
+ /* Time until next subset is generated */
+ uint32_t rotation_time_sec;
+ struct osmo_timer_list rotate_timer;
+
+ /* Bitmask containing subset of allowed ACC 0-9 on current rotation iteration */
+ uint16_t allowed_subset_mask;
+ /* Number of bits (ACC) set in allowed_subset_mask: 0->min(len_allowed_ramp, len_allowed_adm) */
+ uint8_t allowed_subset_mask_count;
+ /* Number of ACC 0-9 allowed as per adminsitrative (permanent) config. */
+ uint8_t allowed_permanent_count;
+};
+
+void acc_mgr_init(struct acc_mgr *acc_mgr, struct gsm_bts *bts);
+uint8_t acc_mgr_get_len_allowed_adm(struct acc_mgr *acc_mgr);
+uint8_t acc_mgr_get_len_allowed_ramp(struct acc_mgr *acc_mgr);
+void acc_mgr_set_len_allowed_adm(struct acc_mgr *acc_mgr, uint8_t len_allowed_adm);
+void acc_mgr_set_len_allowed_ramp(struct acc_mgr *acc_mgr, uint8_t len_allowed_ramp);
+void acc_mgr_set_rotation_time(struct acc_mgr *acc_mgr, uint32_t rotation_time_sec);
+void acc_mgr_perm_subset_changed(struct acc_mgr *acc_mgr, struct gsm48_rach_control *rach_control);
+void acc_mgr_apply_acc(struct acc_mgr *acc_mgr, struct gsm48_rach_control *rach_control);
+
/*!
* Access control class (ACC) ramping is used to slowly make the cell available to
* an increasing number of MS. This avoids overload at startup time in cases where
@@ -37,9 +71,12 @@
#define ACC_RAMP_STEP_SIZE_DEFAULT ACC_RAMP_STEP_SIZE_MIN
#define ACC_RAMP_STEP_SIZE_MAX 10 /* allow all ACC in one step (effectively disables ramping) */
-#define ACC_RAMP_STEP_INTERVAL_MIN 30 /* 30 seconds */
+#define ACC_RAMP_STEP_INTERVAL_MIN 5 /* 5 seconds */
#define ACC_RAMP_STEP_INTERVAL_MAX 600 /* 10 minutes */
+#define ACC_RAMP_CHAN_LOAD_THRESHOLD_LOW 71
+#define ACC_RAMP_CHAN_LOAD_THRESHOLD_UP 89
+
/*!
* Data structure used to manage ACC ramping. Please avoid setting or reading fields
* in this structure directly. Use the accessor functions below instead.
@@ -50,17 +87,6 @@ struct acc_ramp {
bool acc_ramping_enabled; /*!< whether ACC ramping is enabled */
/*!
- * Bitmask which keeps track of access control classes that are currently denied
- * access. The function acc_ramp_apply() uses this mask to modulate bits from
- * octets 2 and 3 in RACH Control Parameters (see 3GPP 44.018 10.5.2.29).
- * Ramping is only concerned with ACCs 0-9. While any of the bits 0-9 is set,
- * the corresponding ACC is barred.
- * ACCs 11-15 should always be allowed, and ACC 10 denies emergency calls for
- * all ACCs from 0-9 inclusive; these ACCs are ignored in this implementation.
- */
- uint16_t barred_accs;
-
- /*!
* This controls the maximum number of ACCs to allow per ramping step (1 - 10).
* The compile-time default value is ACC_RAMP_STEP_SIZE_DEFAULT.
* This value can be changed by VTY configuration.
@@ -71,11 +97,20 @@ struct acc_ramp {
/*!
* Ramping step interval in seconds.
* This value depends on the current BTS channel load average, unless
- * it has been overriden by VTY configuration.
+ * it has been overridden by VTY configuration.
*/
unsigned int step_interval_sec;
- bool step_interval_is_fixed;
struct osmo_timer_list step_timer;
+
+ /*!
+ * Channel Load Upper/Lower Thresholds:
+ * They control how ramping subset size of allowed ACCs changes in
+ * relation to current channel load (%, 0-100): Under the lower
+ * threshold, subset size may be increased; above the upper threshold,
+ * subset size may be decreased.
+ */
+ unsigned int chan_load_lower_threshold;
+ unsigned int chan_load_upper_threshold;
};
/*!
@@ -118,44 +153,19 @@ static inline unsigned int acc_ramp_get_step_interval(struct acc_ramp *acc_ramp)
}
/*!
- * If the step interval is dynamic, return true, else return false.
- * \param[in] acc_ramp Pointer to acc_ramp structure.
- */
-static inline bool acc_ramp_step_interval_is_dynamic(struct acc_ramp *acc_ramp)
-{
- return !(acc_ramp->step_interval_is_fixed);
-}
-
-/*!
- * Return bitmasks which correspond to access control classes that are currently
- * denied access. Ramping is only concerned with those bits which control access
- * for ACCs 0-9, and any of the other bits will always be set to zero in these masks, i.e.
- * it is safe to OR these bitmasks with the corresponding fields in struct gsm48_rach_control.
+ * Return the current ACC ramp step interval (in seconds)
* \param[in] acc_ramp Pointer to acc_ramp structure.
*/
-static inline uint8_t acc_ramp_get_barred_t2(struct acc_ramp *acc_ramp)
-{
- return ((acc_ramp->barred_accs >> 8) & 0x03);
-};
-static inline uint8_t acc_ramp_get_barred_t3(struct acc_ramp *acc_ramp)
+static inline unsigned int acc_ramp_is_running(struct acc_ramp *acc_ramp)
{
- return (acc_ramp->barred_accs & 0xff);
+ return acc_ramp->step_interval_sec;
}
-/*!
- * Potentially mark certain Access Control Classes (ACCs) as barred in accordance to ACC ramping.
- * \param[in] rach_control RACH control parameters in which barred ACCs will be configured.
- * \param[in] acc_ramp Pointer to acc_ramp structure.
- */
-static inline void acc_ramp_apply(struct gsm48_rach_control *rach_control, struct acc_ramp *acc_ramp)
-{
- rach_control->t2 |= acc_ramp_get_barred_t2(acc_ramp);
- rach_control->t3 |= acc_ramp_get_barred_t3(acc_ramp);
-}
+void acc_ramp_global_init(void);
void acc_ramp_init(struct acc_ramp *acc_ramp, struct gsm_bts *bts);
int acc_ramp_set_step_size(struct acc_ramp *acc_ramp, unsigned int step_size);
int acc_ramp_set_step_interval(struct acc_ramp *acc_ramp, unsigned int step_interval);
-void acc_ramp_set_step_interval_dynamic(struct acc_ramp *acc_ramp);
+int acc_ramp_set_chan_load_thresholds(struct acc_ramp *acc_ramp, unsigned int low_threshold, unsigned int up_threshold);
void acc_ramp_trigger(struct acc_ramp *acc_ramp);
void acc_ramp_abort(struct acc_ramp *acc_ramp);
diff --git a/include/osmocom/bsc/arfcn_range_encode.h b/include/osmocom/bsc/arfcn_range_encode.h
deleted file mode 100644
index 7ec710c33..000000000
--- a/include/osmocom/bsc/arfcn_range_encode.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef ARFCN_RANGE_ENCODE_H
-#define ARFCN_RANGE_ENCODE_H
-
-#include <stdint.h>
-
-enum gsm48_range {
- ARFCN_RANGE_INVALID = -1,
- ARFCN_RANGE_128 = 127,
- ARFCN_RANGE_256 = 255,
- ARFCN_RANGE_512 = 511,
- ARFCN_RANGE_1024 = 1023,
-};
-
-#define RANGE_ENC_MAX_ARFCNS 29
-
-int range_enc_determine_range(const int *arfcns, int size, int *f0_out);
-int range_enc_arfcns(enum gsm48_range rng, const int *arfcns, int sze, int *out, int idx);
-int range_enc_find_index(enum gsm48_range rng, const int *arfcns, int size);
-int range_enc_filter_arfcns(int *arfcns, const int sze, const int f0, int *f0_included);
-
-int range_enc_range128(uint8_t *chan_list, int f0, int *w);
-int range_enc_range256(uint8_t *chan_list, int f0, int *w);
-int range_enc_range512(uint8_t *chan_list, int f0, int *w);
-int range_enc_range1024(uint8_t *chan_list, int f0, int f0_incl, int *w);
-
-#endif
diff --git a/include/osmocom/bsc/assignment_fsm.h b/include/osmocom/bsc/assignment_fsm.h
index 156da42fa..b1adf82b7 100644
--- a/include/osmocom/bsc/assignment_fsm.h
+++ b/include/osmocom/bsc/assignment_fsm.h
@@ -4,6 +4,7 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/bsc/debug.h>
+#include <osmocom/bsc/lchan.h>
/* This macro automatically includes a final \n, if omitted. */
#define LOG_ASSIGNMENT(conn, level, fmt, args...) do { \
@@ -17,18 +18,20 @@
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,
ASSIGNMENT_ST_WAIT_RR_ASS_COMPLETE,
ASSIGNMENT_ST_WAIT_LCHAN_ESTABLISHED,
ASSIGNMENT_ST_WAIT_MGW_ENDPOINT_TO_MSC,
+ ASSIGNMENT_ST_WAIT_LCHAN_MODIFIED,
};
enum assignment_fsm_event {
ASSIGNMENT_EV_LCHAN_ACTIVE,
ASSIGNMENT_EV_LCHAN_ESTABLISHED,
+ ASSIGNMENT_EV_LCHAN_MODIFIED,
ASSIGNMENT_EV_LCHAN_ERROR,
ASSIGNMENT_EV_MSC_MGW_OK,
ASSIGNMENT_EV_MSC_MGW_FAIL,
@@ -37,8 +40,14 @@ enum assignment_fsm_event {
ASSIGNMENT_EV_CONN_RELEASING,
};
-void assignment_fsm_init();
+void bssap_extend_osmux(struct msgb *msg, uint8_t cid);
+
+int reassignment_request_to_lchan(enum assign_for assign_for, struct gsm_lchan *lchan, struct gsm_lchan *to_lchan,
+ int tsc_set, int tsc);
+int reassignment_request_to_chan_type(enum assign_for assign_for, struct gsm_lchan *lchan,
+ enum gsm_chan_t new_lchan_type);
void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts *bts,
struct assignment_request *req);
void assignment_reset(struct gsm_subscriber_connection *conn);
+void assignment_fsm_update_id(struct gsm_subscriber_connection *conn);
diff --git a/include/osmocom/bsc/bsc_msc_data.h b/include/osmocom/bsc/bsc_msc_data.h
index 0c2094e3a..ae29725af 100644
--- a/include/osmocom/bsc/bsc_msc_data.h
+++ b/include/osmocom/bsc/bsc_msc_data.h
@@ -29,8 +29,11 @@
#define _OSMO_MSC_DATA_H
#include "debug.h"
+#include "osmo_bsc_lcls.h"
+#include "osmux.h"
#include <osmocom/core/timer.h>
+#include <osmocom/core/select.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
@@ -42,30 +45,98 @@
#include <osmocom/core/fsm.h>
#include <osmocom/gsm/gsm23003.h>
-#include <regex.h>
#include <errno.h>
struct osmo_bsc_rf;
struct gsm_network;
+/* Constants for the MSC rate counters */
enum {
- MSC_CON_TYPE_NORMAL,
- MSC_CON_TYPE_LOCAL,
+ /* Rx message counters */
+ MSC_CTR_BSSMAP_RX_UDT_RESET_ACKNOWLEDGE,
+ MSC_CTR_BSSMAP_RX_UDT_RESET,
+ MSC_CTR_BSSMAP_RX_UDT_PAGING,
+ MSC_CTR_BSSMAP_RX_UDT_UNKNOWN,
+ MSC_CTR_BSSMAP_RX_DT1_CLEAR_CMD,
+ MSC_CTR_BSSMAP_RX_DT1_CIPHER_MODE_CMD,
+ MSC_CTR_BSSMAP_RX_DT1_ASSIGNMENT_RQST,
+ MSC_CTR_BSSMAP_RX_DT1_LCLS_CONNECT_CTRL,
+ MSC_CTR_BSSMAP_RX_DT1_HANDOVER_RQST,
+ MSC_CTR_BSSMAP_RX_DT1_HANDOVER_CMD,
+ MSC_CTR_BSSMAP_RX_DT1_CLASSMARK_RQST,
+ MSC_CTR_BSSMAP_RX_DT1_CONFUSION,
+ MSC_CTR_BSSMAP_RX_DT1_COMMON_ID,
+ MSC_CTR_BSSMAP_RX_DT1_UNKNOWN,
+ MSC_CTR_BSSMAP_RX_DT1_DTAP,
+ MSC_CTR_BSSMAP_RX_DT1_DTAP_ERROR,
+ MSC_CTR_BSSMAP_RX_DT1_PERFORM_LOCATION_REQUEST,
+ MSC_CTR_BSSMAP_RX_DT1_PERFORM_LOCATION_ABORT,
+ MSC_CTR_BSSMAP_RX_DT1_VGCS_VBS_SETUP,
+ MSC_CTR_BSSMAP_RX_DT1_VGCS_VBS_ASSIGN_RQST,
+ MSC_CTR_BSSMAP_RX_DT1_UPLINK_RQST_ACKNOWLEDGE,
+ MSC_CTR_BSSMAP_RX_DT1_UPLINK_REJECT_CMD,
+ MSC_CTR_BSSMAP_RX_DT1_UPLINK_RELEASE_CMD,
+ MSC_CTR_BSSMAP_RX_DT1_UPLINK_SEIZED_CMD,
+ MSC_CTR_BSSMAP_RX_DT1_VGCS_ADDL_INFO,
+ MSC_CTR_BSSMAP_RX_DT1_VGCS_SMS,
+ MSC_CTR_BSSMAP_RX_DT1_NOTIFICATION_DATA,
+
+ /* Tx message counters (per connection type) */
+ MSC_CTR_BSSMAP_TX_BSS_MANAGEMENT,
+ MSC_CTR_BSSMAP_TX_DTAP,
+ MSC_CTR_BSSMAP_TX_UNKNOWN,
+ MSC_CTR_BSSMAP_TX_SHORT,
+ MSC_CTR_BSSMAP_TX_ERR_CONN_NOT_READY,
+ MSC_CTR_BSSMAP_TX_ERR_SEND,
+ MSC_CTR_BSSMAP_TX_SUCCESS,
+
+ /* Tx message counters (per message type) */
+ MSC_CTR_BSSMAP_TX_UDT_RESET,
+ MSC_CTR_BSSMAP_TX_UDT_RESET_ACK,
+ MSC_CTR_BSSMAP_TX_DT1_CLEAR_RQST,
+ MSC_CTR_BSSMAP_TX_DT1_CLEAR_COMPLETE,
+ MSC_CTR_BSSMAP_TX_DT1_ASSIGNMENT_FAILURE,
+ MSC_CTR_BSSMAP_TX_DT1_ASSIGNMENT_COMPLETE,
+ MSC_CTR_BSSMAP_TX_DT1_SAPI_N_REJECT,
+ MSC_CTR_BSSMAP_TX_DT1_CIPHER_COMPLETE,
+ MSC_CTR_BSSMAP_TX_DT1_CIPHER_REJECT,
+ MSC_CTR_BSSMAP_TX_DT1_CLASSMARK_UPDATE,
+ MSC_CTR_BSSMAP_TX_DT1_LCLS_CONNECT_CTRL_ACK,
+ MSC_CTR_BSSMAP_TX_DT1_HANDOVER_REQUIRED,
+ MSC_CTR_BSSMAP_TX_DT1_HANDOVER_PERFORMED,
+ MSC_CTR_BSSMAP_TX_DT1_HANDOVER_RQST_ACKNOWLEDGE,
+ MSC_CTR_BSSMAP_TX_DT1_HANDOVER_DETECT,
+ MSC_CTR_BSSMAP_TX_DT1_HANDOVER_COMPLETE,
+ MSC_CTR_BSSMAP_TX_DT1_HANDOVER_FAILURE,
+ MSC_CTR_BSSMAP_TX_DT1_DTAP,
+ MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS,
+ MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE,
+ MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_SETUP_ACK,
+ MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_SETUP_REFUSE,
+ MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_ASSIGN_RESULT,
+ MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_ASSIGN_FAIL,
+ MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_QUEUING_INDICATION,
+ MSC_CTR_BSSMAP_TX_DT1_UPLINK_RQST,
+ MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_ASSIGNMENT_STATUS,
+ MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_AREA_CELL_INFO,
+ MSC_CTR_BSSMAP_TX_DT1_UPLINK_RQST_CONFIRMATION,
+ MSC_CTR_BSSMAP_TX_DT1_UPLINK_RELEASE_INDICATION,
+ MSC_CTR_BSSMAP_TX_DT1_UPLINK_APP_DATA,
+
+ MSC_CTR_MSCPOOL_SUBSCR_NEW,
+ MSC_CTR_MSCPOOL_SUBSCR_REATTACH,
+ MSC_CTR_MSCPOOL_SUBSCR_KNOWN,
+ MSC_CTR_MSCPOOL_SUBSCR_PAGED,
+ MSC_CTR_MSCPOOL_SUBSCR_ATTACH_LOST,
+ MSC_CTR_MSCPOOL_EMERG_FORWARDED,
};
-enum bsc_lcls_mode {
- BSC_LCLS_MODE_DISABLED,
- BSC_LCLS_MODE_MGW_LOOP,
- BSC_LCLS_MODE_BTS_LOOP,
+/* Constants for the MSC stats */
+enum {
+ MSC_STAT_MSC_LINKS_ACTIVE,
+ MSC_STAT_MSC_LINKS_TOTAL,
};
-extern const struct value_string bsc_lcls_mode_names[];
-
-static inline const char *bsc_lcls_mode_name(enum bsc_lcls_mode m)
-{
- return get_value_string(bsc_lcls_mode_names, m);
-}
-
/*! /brief Information on a remote MSC for libbsc.
*/
struct bsc_msc_data {
@@ -75,39 +146,28 @@ struct bsc_msc_data {
struct gsm_network *network;
int allow_emerg;
- int type;
-
- /* local call routing */
- char *local_pref;
- regex_t local_pref_reg;
-
/* Connection data */
struct osmo_plmn_id core_plmn;
- int core_lac;
- int core_ci;
- int rtp_base;
- bool is_authenticated;
/* audio codecs */
struct gsm48_multi_rate_conf amr_conf;
- struct gsm_audio_support **audio_support;
+ bool amr_octet_aligned;
+
+ /* Practically, there can be only 5 entries in osmo-bsc: FR1 FR2 FR3 HR1 HR3. Historically, osmo-bsc allowed
+ * *any* number of entries -- we should not break too strictly on old cfg files. Theoretically, there should be
+ * room for FR1 to FR7 plus HR1 to HR7 less HR2. Let's just give ample room for all these aspects: */
+ struct gsm_audio_support audio_support[16];
int audio_length;
+
enum bsc_lcls_mode lcls_mode;
bool lcls_codec_mismatch_allow;
- /* ussd welcome text */
- char *ussd_welcome_txt;
-
int nr;
- /* ussd msc connection lost text */
- char *ussd_msc_lost_txt;
-
- /* ussd text when MSC has entered the grace period */
- char *ussd_grace_txt;
-
- char *acc_lst_name;
+ /* structures for keeping rate counters and gauge stats */
+ struct rate_ctr_group *msc_ctrs;
+ struct osmo_stat_item_group *msc_statg;
/* Sigtran connection data */
struct {
@@ -135,36 +195,31 @@ struct bsc_msc_data {
/* Pointer to the osmo-fsm that controls the
* BSSMAP RESET procedure */
- struct osmo_fsm_inst *reset_fsm;
+ struct bssmap_reset *bssmap_reset;
} a;
uint32_t x_osmo_ign;
bool x_osmo_ign_configured;
-};
-
-/*
- * Per BSC data.
- */
-struct osmo_bsc_data {
- struct gsm_network *network;
-
- /* msc configuration */
- struct llist_head mscs;
-
- /* rf ctl related bits */
- char *mid_call_txt;
- int mid_call_timeout;
- char *rf_ctrl_name;
- struct osmo_bsc_rf *rf_ctrl;
- int auto_off_timeout;
- /* ussd text when there is no MSC available */
- char *ussd_no_msc_txt;
+ /* Whether we want to use Osmux against this MSC. Controlled via VTY */
+ enum osmux_usage use_osmux;
+ /* Whether we detected the MSC supports Osmux (during BSSMAP_RESET) */
+ bool remote_supports_osmux;
- char *acc_lst_name;
+ /* Proxy between IPA/SCCPlite encapsulated MGCP and UDP */
+ struct {
+ /* local (BSC) IP address to be used */
+ char *local_addr;
+ /* local (BSC) UDP port to be used to talk with MGW */
+ uint16_t local_port;
+ /* UDP socket for proxying MGCP via SCCPlite/IPA */
+ struct osmo_fd ofd;
+ } mgcp_ipa;
+
+ struct osmo_nri_ranges *nri_ranges;
+ bool allow_attach;
};
-
int osmo_bsc_msc_init(struct bsc_msc_data *msc);
int osmo_bsc_sccp_init(struct gsm_network *gsmnet);
@@ -173,6 +228,9 @@ int osmo_bsc_audio_init(struct gsm_network *network);
struct bsc_msc_data *osmo_msc_data_find(struct gsm_network *, int);
struct bsc_msc_data *osmo_msc_data_alloc(struct gsm_network *, int);
+
+struct osmo_cell_global_id *cgi_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts);
+
/* Helper function to calculate the port number for a given
* timeslot/multiplex. This functionality is needed to support
* the sccp-lite scenario where the MGW is handled externally */
@@ -193,5 +251,25 @@ static inline int mgcp_port_to_cic(uint16_t port, uint16_t base)
return (port - base) / 2;
}
+static inline bool msc_is_aoip(const struct bsc_msc_data *msc)
+{
+ switch (msc->a.asp_proto) {
+ case OSMO_SS7_ASP_PROT_SUA:
+ case OSMO_SS7_ASP_PROT_M3UA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool msc_is_sccplite(const struct bsc_msc_data *msc)
+{
+ switch (msc->a.asp_proto) {
+ case OSMO_SS7_ASP_PROT_IPA:
+ return true;
+ default:
+ return false;
+ }
+}
#endif
diff --git a/include/osmocom/bsc/bsc_msg_filter.h b/include/osmocom/bsc/bsc_msg_filter.h
deleted file mode 100644
index fe8748526..000000000
--- a/include/osmocom/bsc/bsc_msg_filter.h
+++ /dev/null
@@ -1,103 +0,0 @@
-#pragma once
-
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/msgfile.h>
-#include <osmocom/core/linuxrbtree.h>
-#include <osmocom/core/linuxlist.h>
-
-#include <regex.h>
-
-struct vty;
-struct gsm48_hdr;
-
-struct bsc_filter_reject_cause {
- int lu_reject_cause;
- int cm_reject_cause;
-};
-
-struct bsc_filter_barr_entry {
- struct rb_node node;
-
- char *imsi;
- int cm_reject_cause;
- int lu_reject_cause;
-};
-
-enum bsc_filter_acc_ctr {
- ACC_LIST_LOCAL_FILTER,
- ACC_LIST_GLOBAL_FILTER,
-};
-
-struct bsc_msg_acc_lst {
- struct llist_head list;
-
- /* counter */
- struct rate_ctr_group *stats;
-
- /* the name of the list */
- const char *name;
- struct llist_head fltr_list;
-};
-
-struct bsc_msg_acc_lst_entry {
- struct llist_head list;
-
- /* the filter */
- char *imsi_allow;
- regex_t imsi_allow_re;
- char *imsi_deny;
- regex_t imsi_deny_re;
-
- /* reject reasons for the access lists */
- int cm_reject_cause;
- int lu_reject_cause;
-};
-
-enum {
- FLT_CON_TYPE_NONE,
- FLT_CON_TYPE_LU,
- FLT_CON_TYPE_CM_SERV_REQ,
- FLT_CON_TYPE_PAG_RESP,
- FLT_CON_TYPE_SSA,
- FLT_CON_TYPE_LOCAL_REJECT,
- FLT_CON_TYPE_OTHER,
-};
-
-
-struct bsc_filter_state {
- char *imsi;
- int imsi_checked;
- int con_type;
-};
-
-struct bsc_filter_request {
- void *ctx;
- struct rb_root *black_list;
- struct llist_head *access_lists;
- const char *local_lst_name;
- const char *global_lst_name;
- int bsc_nr;
-};
-
-/**
- * Content filtering.
- */
-int bsc_msg_filter_initial(struct gsm48_hdr *hdr, size_t size,
- struct bsc_filter_request *req,
- int *con_type, char **imsi,
- struct bsc_filter_reject_cause *cause);
-int bsc_msg_filter_data(struct gsm48_hdr *hdr, size_t size,
- struct bsc_filter_request *req,
- struct bsc_filter_state *state,
- struct bsc_filter_reject_cause *cause);
-
-/* IMSI allow/deny handling */
-struct bsc_msg_acc_lst *bsc_msg_acc_lst_find(struct llist_head *lst, const char *name);
-struct bsc_msg_acc_lst *bsc_msg_acc_lst_get(void *ctx, struct llist_head *lst, const char *name);
-void bsc_msg_acc_lst_delete(struct bsc_msg_acc_lst *lst);
-
-struct bsc_msg_acc_lst_entry *bsc_msg_acc_lst_entry_create(struct bsc_msg_acc_lst *);
-int bsc_msg_acc_lst_check_allow(struct bsc_msg_acc_lst *lst, const char *imsi);
-
-void bsc_msg_acc_lst_vty_init(void *ctx, struct llist_head *lst, int node);
-void bsc_msg_acc_lst_write(struct vty *vty);
diff --git a/include/osmocom/bsc/bsc_stats.h b/include/osmocom/bsc/bsc_stats.h
new file mode 100644
index 000000000..eae97509c
--- /dev/null
+++ b/include/osmocom/bsc/bsc_stats.h
@@ -0,0 +1,116 @@
+/* osmo-bsc statistics */
+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <osmocom/core/rate_ctr.h>
+
+struct osmo_stat_item_group_desc;
+struct gsm_network;
+struct gsm_bts;
+
+/* OsmoBSC rate_ctr indexes */
+enum {
+ BSC_CTR_ASSIGNMENT_ATTEMPTED,
+ BSC_CTR_ASSIGNMENT_COMPLETED,
+ BSC_CTR_ASSIGNMENT_STOPPED,
+ BSC_CTR_ASSIGNMENT_NO_CHANNEL,
+ BSC_CTR_ASSIGNMENT_TIMEOUT,
+ BSC_CTR_ASSIGNMENT_FAILED,
+ BSC_CTR_ASSIGNMENT_ERROR,
+ 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,
+ BSC_CTR_INTRA_CELL_HO_ATTEMPTED,
+ BSC_CTR_INTRA_CELL_HO_COMPLETED,
+ BSC_CTR_INTRA_CELL_HO_STOPPED,
+ BSC_CTR_INTRA_CELL_HO_NO_CHANNEL,
+ BSC_CTR_INTRA_CELL_HO_TIMEOUT,
+ BSC_CTR_INTRA_CELL_HO_FAILED,
+ BSC_CTR_INTRA_CELL_HO_ERROR,
+ BSC_CTR_INTRA_BSC_HO_ATTEMPTED,
+ BSC_CTR_INTRA_BSC_HO_COMPLETED,
+ BSC_CTR_INTRA_BSC_HO_STOPPED,
+ BSC_CTR_INTRA_BSC_HO_NO_CHANNEL,
+ BSC_CTR_INTRA_BSC_HO_TIMEOUT,
+ BSC_CTR_INTRA_BSC_HO_FAILED,
+ BSC_CTR_INTRA_BSC_HO_ERROR,
+ BSC_CTR_INTER_BSC_HO_OUT_ATTEMPTED,
+ BSC_CTR_INTER_BSC_HO_OUT_COMPLETED,
+ BSC_CTR_INTER_BSC_HO_OUT_STOPPED,
+ BSC_CTR_INTER_BSC_HO_OUT_TIMEOUT,
+ BSC_CTR_INTER_BSC_HO_OUT_FAILED,
+ BSC_CTR_INTER_BSC_HO_OUT_ERROR,
+ BSC_CTR_INTER_BSC_HO_IN_ATTEMPTED,
+ BSC_CTR_INTER_BSC_HO_IN_COMPLETED,
+ BSC_CTR_INTER_BSC_HO_IN_STOPPED,
+ BSC_CTR_INTER_BSC_HO_IN_NO_CHANNEL,
+ BSC_CTR_INTER_BSC_HO_IN_FAILED,
+ BSC_CTR_INTER_BSC_HO_IN_TIMEOUT,
+ BSC_CTR_INTER_BSC_HO_IN_ERROR,
+ BSC_CTR_SRVCC_ATTEMPTED,
+ BSC_CTR_SRVCC_COMPLETED,
+ BSC_CTR_SRVCC_STOPPED,
+ BSC_CTR_SRVCC_NO_CHANNEL,
+ BSC_CTR_SRVCC_TIMEOUT,
+ BSC_CTR_SRVCC_FAILED,
+ BSC_CTR_SRVCC_ERROR,
+ 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[];
+extern const struct rate_ctr_group_desc bsc_ctrg_desc;
+
+/* OsmoBSC stat_item indexes */
+enum {
+ BSC_STAT_NUM_BTS_OML_CONNECTED,
+ BSC_STAT_NUM_BTS_ALL_TRX_RSL_CONNECTED,
+ BSC_STAT_NUM_BTS_TOTAL,
+ BSC_STAT_NUM_TRX_RSL_CONNECTED,
+ BSC_STAT_NUM_TRX_TOTAL,
+ BSC_STAT_NUM_MSC_CONNECTED,
+ BSC_STAT_NUM_MSC_TOTAL,
+};
+
+/* BTS counter index if a BTS could not be found
+ * Currently we are limited to bts 0 - 255 in the VTY, but that might change in
+ * the future so use 2**16 */
+#define BTS_STAT_IDX_UNKNOWN (UINT16_MAX + 1)
+
+extern const struct osmo_stat_item_group_desc bsc_statg_desc;
+
+void bsc_update_connection_stats(struct gsm_network *net);
+
+void all_allocated_update_bts(struct gsm_bts *bts);
+void all_allocated_update_bsc(void);
diff --git a/include/osmocom/bsc/bsc_subscr_conn_fsm.h b/include/osmocom/bsc/bsc_subscr_conn_fsm.h
index f5ed7bdd8..766d56a49 100644
--- a/include/osmocom/bsc/bsc_subscr_conn_fsm.h
+++ b/include/osmocom/bsc/bsc_subscr_conn_fsm.h
@@ -1,17 +1,25 @@
#pragma once
+#include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/core/fsm.h>
+#include "osmocom/bsc/gsm_data.h"
+
+#define BSUB_USE_CONN "conn"
enum gscon_fsm_event {
/* local SCCP stack tells us incoming conn from MSC */
GSCON_EV_A_CONN_IND,
+ GSCON_EV_A_INITIAL_USER_DATA,
/* RSL side requests CONNECT to MSC */
- GSCON_EV_A_CONN_REQ,
+ GSCON_EV_MO_COMPL_L3,
/* MSC confirms the SCCP connection */
GSCON_EV_A_CONN_CFM,
/* MSC has sent BSSMAP CLEAR CMD */
GSCON_EV_A_CLEAR_CMD,
/* MSC SCCP disconnect indication */
GSCON_EV_A_DISC_IND,
+ /* MSC has sent a BSSMAP COMMON ID */
+ GSCON_EV_A_COMMON_ID_IND,
GSCON_EV_ASSIGNMENT_START,
GSCON_EV_ASSIGNMENT_END,
@@ -38,17 +46,17 @@ enum gscon_fsm_event {
GSCON_EV_FORGET_LCHAN,
GSCON_EV_FORGET_MGW_ENDPOINT,
+
+ GSCON_EV_LCS_LOC_REQ_END,
};
struct gsm_subscriber_connection;
struct gsm_network;
struct msgb;
-struct mgwep_ci;
+struct osmo_mgcpc_ep_ci;
struct assignment_request;
struct gsm_lchan;
-void bsc_subscr_conn_fsm_init();
-
/* Allocate a subscriber connection and its associated FSM */
struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *net);
void gscon_update_id(struct gsm_subscriber_connection *conn);
@@ -56,27 +64,37 @@ void gscon_update_id(struct gsm_subscriber_connection *conn);
void gscon_submit_rsl_dtap(struct gsm_subscriber_connection *conn,
struct msgb *msg, int link_id, int allow_sacch);
int gscon_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg);
+void gscon_bssmap_clear(struct gsm_subscriber_connection *conn, enum gsm0808_cause cause);
-struct mgw_endpoint *gscon_ensure_mgw_endpoint(struct gsm_subscriber_connection *conn,
- uint16_t msc_assigned_cic);
+struct osmo_mgcpc_ep *gscon_ensure_mgw_endpoint(struct gsm_subscriber_connection *conn,
+ uint16_t msc_assigned_cic, struct gsm_lchan *for_lchan);
bool gscon_connect_mgw_to_msc(struct gsm_subscriber_connection *conn,
struct gsm_lchan *for_lchan,
const char *addr, uint16_t port,
struct osmo_fsm_inst *notify,
uint32_t event_success, uint32_t event_failure,
void *notify_data,
- struct mgwep_ci **created_ci);
+ struct osmo_mgcpc_ep_ci **created_ci);
void gscon_start_assignment(struct gsm_subscriber_connection *conn,
struct assignment_request *req);
void gscon_change_primary_lchan(struct gsm_subscriber_connection *conn, struct gsm_lchan *new_lchan);
-void gscon_release_lchans(struct gsm_subscriber_connection *conn, bool do_rr_release);
+void gscon_release_lchans(struct gsm_subscriber_connection *conn, bool do_rr_release, enum gsm48_rr_cause cause_rr);
void gscon_lchan_releasing(struct gsm_subscriber_connection *conn, struct gsm_lchan *lchan);
void gscon_forget_lchan(struct gsm_subscriber_connection *conn, struct gsm_lchan *lchan);
-void gscon_forget_mgw_endpoint_ci(struct gsm_subscriber_connection *conn, struct mgwep_ci *ci);
+void gscon_forget_mgw_endpoint_ci(struct gsm_subscriber_connection *conn, struct osmo_mgcpc_ep_ci *ci);
bool gscon_is_aoip(struct gsm_subscriber_connection *conn);
bool gscon_is_sccplite(struct gsm_subscriber_connection *conn);
+
+
+static inline const struct osmo_plmn_id *gscon_last_eutran_plmn(const struct gsm_subscriber_connection *conn)
+{
+ return (conn && conn->fast_return.allowed &&
+ conn->fast_return.last_eutran_plmn_valid) ?
+ &conn->fast_return.last_eutran_plmn :
+ NULL;
+}
diff --git a/include/osmocom/bsc/bsc_subscriber.h b/include/osmocom/bsc/bsc_subscriber.h
index 93b353935..1fa00162d 100644
--- a/include/osmocom/bsc/bsc_subscriber.h
+++ b/include/osmocom/bsc/bsc_subscriber.h
@@ -5,40 +5,69 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/linuxrbtree.h>
+#include <osmocom/core/use_count.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
+#include <osmocom/gsm/gsm48.h>
struct log_target;
+struct gsm_bts;
+
+struct bsc_subscr_store {
+ struct llist_head bsub_list; /* list containing "struct bsc_subscr" */
+ /* rbtree root of 'struct bsc_subscr', ordered by tmsi */
+ struct rb_root bsub_tree_tmsi;
+};
+
+struct bsc_subscr_store *bsc_subscr_store_alloc(void *ctx);
struct bsc_subscr {
- struct llist_head entry;
- int use_count;
+ struct bsc_subscr_store *store; /* backpointer to "struct bsc_subscr_store" */
+ struct llist_head entry; /* entry in (struct bsc_subscr_store)->bsub_list */
+ /* entry in (struct bsc_subscr_store)->bsub_tree_tmsi. Inserted if tmsi != GSM_RESERVED_TMSI: */
+ struct rb_node node_tmsi;
+ struct osmo_use_count use_count;
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
+ char imei[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1];
uint32_t tmsi;
- uint16_t lac;
+
+ /* List head of (struct gsm_paging_request).bsub_entry */
+ uint32_t active_paging_requests_len;
+ struct llist_head active_paging_requests;
};
const char *bsc_subscr_name(struct bsc_subscr *bsub);
const char *bsc_subscr_id(struct bsc_subscr *bsub);
-struct bsc_subscr *bsc_subscr_find_or_create_by_imsi(struct llist_head *list,
- const char *imsi);
-struct bsc_subscr *bsc_subscr_find_or_create_by_tmsi(struct llist_head *list,
- uint32_t tmsi);
+struct bsc_subscr *bsc_subscr_find_or_create_by_imsi(struct bsc_subscr_store *bsubst,
+ const char *imsi,
+ const char *use_token);
+struct bsc_subscr *bsc_subscr_find_or_create_by_tmsi(struct bsc_subscr_store *bsubst,
+ uint32_t tmsi,
+ const char *use_token);
+struct bsc_subscr *bsc_subscr_find_or_create_by_mi(struct bsc_subscr_store *bsubst,
+ const struct osmo_mobile_identity *mi,
+ const char *use_token);
-struct bsc_subscr *bsc_subscr_find_by_imsi(struct llist_head *list,
- const char *imsi);
-struct bsc_subscr *bsc_subscr_find_by_tmsi(struct llist_head *list,
- uint32_t tmsi);
+struct bsc_subscr *bsc_subscr_find_by_imsi(struct bsc_subscr_store *bsubst,
+ const char *imsi,
+ const char *use_token);
+int bsc_subscr_set_tmsi(struct bsc_subscr *bsub, uint32_t tmsi);
void bsc_subscr_set_imsi(struct bsc_subscr *bsub, const char *imsi);
+void bsc_subscr_set_imei(struct bsc_subscr *bsub, const char *imei);
-struct bsc_subscr *_bsc_subscr_get(struct bsc_subscr *bsub,
- const char *file, int line);
-struct bsc_subscr *_bsc_subscr_put(struct bsc_subscr *bsub,
- const char *file, int line);
-#define bsc_subscr_get(bsub) _bsc_subscr_get(bsub, __FILE__, __LINE__)
-#define bsc_subscr_put(bsub) _bsc_subscr_put(bsub, __FILE__, __LINE__)
+#define bsc_subscr_get(bsc_subscr, use) \
+ OSMO_ASSERT(osmo_use_count_get_put(&(bsc_subscr)->use_count, use, 1) == 0)
+#define bsc_subscr_put(bsc_subscr, use) \
+ OSMO_ASSERT(osmo_use_count_get_put(&(bsc_subscr)->use_count, use, -1) == 0)
void log_set_filter_bsc_subscr(struct log_target *target,
struct bsc_subscr *bsub);
+
+struct gsm_paging_request;
+void bsc_subscr_add_active_paging_request(struct bsc_subscr *bsub, struct gsm_paging_request *req);
+void bsc_subscr_remove_active_paging_request(struct bsc_subscr *bsub, struct gsm_paging_request *req);
+void bsc_subscr_remove_active_paging_request_all(struct bsc_subscr *bsub);
+struct gsm_paging_request *bsc_subscr_find_req_by_bts(const struct bsc_subscr *bsub, const struct gsm_bts *bts);
diff --git a/include/osmocom/bsc/bss.h b/include/osmocom/bsc/bss.h
index ecb68d627..199f98145 100644
--- a/include/osmocom/bsc/bss.h
+++ b/include/osmocom/bsc/bss.h
@@ -11,9 +11,10 @@ extern int bsc_shutdown_net(struct gsm_network *net);
/* register all supported BTS */
extern int bts_init(void);
+extern int bts_model_unknown_init(void);
extern int bts_model_bs11_init(void);
extern int bts_model_rbs2k_init(void);
extern int bts_model_nanobts_init(void);
extern int bts_model_nokia_site_init(void);
-extern int bts_model_sysmobts_init(void);
+extern int bts_model_osmobts_init(void);
#endif
diff --git a/include/osmocom/bsc/bssmap_reset.h b/include/osmocom/bsc/bssmap_reset.h
new file mode 100644
index 000000000..c0de13c4d
--- /dev/null
+++ b/include/osmocom/bsc/bssmap_reset.h
@@ -0,0 +1,32 @@
+/* Manage RESET and disconnection detection on BSSMAP and BSSMAP-LE */
+#pragma once
+
+enum bssmap_reset_fsm_event {
+ BSSMAP_RESET_EV_RX_RESET,
+ BSSMAP_RESET_EV_RX_RESET_ACK,
+ BSSMAP_RESET_EV_CONN_CFM_SUCCESS,
+ BSSMAP_RESET_EV_CONN_CFM_FAILURE,
+};
+
+struct bssmap_reset_cfg {
+ int conn_cfm_failure_threshold;
+ struct {
+ void (*tx_reset)(void *data);
+ void (*tx_reset_ack)(void *data);
+ void (*link_up)(void *data);
+ void (*link_lost)(void *data);
+ } ops;
+ void *data;
+};
+
+struct bssmap_reset {
+ struct osmo_fsm_inst *fi;
+ struct bssmap_reset_cfg cfg;
+ int conn_cfm_failures;
+};
+
+struct bssmap_reset *bssmap_reset_alloc(void *ctx, const char *label, const struct bssmap_reset_cfg *cfg);
+bool bssmap_reset_is_conn_ready(const struct bssmap_reset *bssmap_reset);
+void bssmap_reset_resend_reset(struct bssmap_reset *bssmap_reset);
+void bssmap_reset_set_disconnected(struct bssmap_reset *bssmap_reset);
+void bssmap_reset_term_and_free(struct bssmap_reset *bssmap_reset);
diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h
new file mode 100644
index 000000000..e9634ee3e
--- /dev/null
+++ b/include/osmocom/bsc/bts.h
@@ -0,0 +1,862 @@
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/bitvec.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/bts_features.h>
+
+#include <osmocom/abis/e1_input.h>
+
+#include "osmocom/bsc/power_control.h"
+#include "osmocom/bsc/gsm_data.h"
+#include "osmocom/bsc/bts_trx.h"
+#include "osmocom/bsc/bts_sm.h"
+#include "osmocom/bsc/abis_om2000.h"
+#include "osmocom/bsc/paging.h"
+#include "osmocom/bsc/bts_setup_ramp.h"
+
+enum bts_counter_id {
+ BTS_CTR_CHREQ_TOTAL,
+ BTS_CTR_CHREQ_ATTEMPTED_EMERG,
+ BTS_CTR_CHREQ_ATTEMPTED_CALL,
+ BTS_CTR_CHREQ_ATTEMPTED_LOCATION_UPD,
+ BTS_CTR_CHREQ_ATTEMPTED_PAG,
+ BTS_CTR_CHREQ_ATTEMPTED_PDCH,
+ 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,
+ BTS_CTR_CHAN_RF_FAIL_TCH,
+ BTS_CTR_CHAN_RF_FAIL_SDCCH,
+ BTS_CTR_CHAN_RLL_ERR,
+ BTS_CTR_BTS_OML_FAIL,
+ BTS_CTR_BTS_RSL_FAIL,
+ BTS_CTR_CODEC_AMR_F,
+ BTS_CTR_CODEC_AMR_H,
+ BTS_CTR_CODEC_EFR,
+ BTS_CTR_CODEC_V1_FR,
+ BTS_CTR_CODEC_V1_HR,
+ BTS_CTR_PAGING_ATTEMPTED,
+ BTS_CTR_PAGING_ALREADY,
+ BTS_CTR_PAGING_RESPONDED,
+ BTS_CTR_PAGING_EXPIRED,
+ BTS_CTR_PAGING_NO_ACTIVE_PAGING,
+ BTS_CTR_PAGING_MSC_FLUSH,
+ BTS_CTR_PAGING_OVERLOAD,
+ BTS_CTR_CHAN_ACT_TOTAL,
+ BTS_CTR_CHAN_ACT_SDCCH,
+ BTS_CTR_CHAN_ACT_TCH,
+ BTS_CTR_CHAN_ACT_NACK,
+ BTS_CTR_CHAN_TCH_ACTIVE_MILLISECONDS_TOTAL,
+ BTS_CTR_CHAN_SDCCH_ACTIVE_MILLISECONDS_TOTAL,
+ BTS_CTR_CHAN_TCH_FULLY_ESTABLISHED,
+ BTS_CTR_CHAN_SDCCH_FULLY_ESTABLISHED,
+ BTS_CTR_RSL_UNKNOWN,
+ BTS_CTR_RSL_IPA_NACK,
+ BTS_CTR_RSL_DELETE_IND,
+ BTS_CTR_MODE_MODIFY_NACK,
+ BTS_CTR_LCHAN_BORKEN_FROM_UNUSED,
+ BTS_CTR_LCHAN_BORKEN_FROM_WAIT_ACTIV_ACK,
+ BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RF_RELEASE_ACK,
+ BTS_CTR_LCHAN_BORKEN_FROM_BORKEN,
+ BTS_CTR_LCHAN_BORKEN_FROM_UNKNOWN,
+ BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_ACK,
+ BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_NACK,
+ BTS_CTR_LCHAN_BORKEN_EV_RF_CHAN_REL_ACK,
+ BTS_CTR_LCHAN_BORKEN_EV_VTY,
+ BTS_CTR_LCHAN_BORKEN_EV_TEARDOWN,
+ BTS_CTR_LCHAN_BORKEN_EV_TS_ERROR,
+ BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RR_CHAN_MODE_MODIFY_ACK,
+ BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RSL_CHAN_MODE_MODIFY_ACK,
+ BTS_CTR_TS_BORKEN_FROM_NOT_INITIALIZED,
+ BTS_CTR_TS_BORKEN_FROM_UNUSED,
+ BTS_CTR_TS_BORKEN_FROM_WAIT_PDCH_ACT,
+ BTS_CTR_TS_BORKEN_FROM_PDCH,
+ BTS_CTR_TS_BORKEN_FROM_WAIT_PDCH_DEACT,
+ BTS_CTR_TS_BORKEN_FROM_IN_USE,
+ BTS_CTR_TS_BORKEN_FROM_BORKEN,
+ BTS_CTR_TS_BORKEN_FROM_UNKNOWN,
+ BTS_CTR_TS_BORKEN_EV_PDCH_ACT_ACK_NACK,
+ BTS_CTR_TS_BORKEN_EV_PDCH_DEACT_ACK_NACK,
+ BTS_CTR_TS_BORKEN_EV_TEARDOWN,
+ BTS_CTR_ASSIGNMENT_ATTEMPTED,
+ BTS_CTR_ASSIGNMENT_ATTEMPTED_SIGN,
+ BTS_CTR_ASSIGNMENT_ATTEMPTED_SPEECH,
+ BTS_CTR_ASSIGNMENT_COMPLETED,
+ BTS_CTR_ASSIGNMENT_COMPLETED_SIGN,
+ BTS_CTR_ASSIGNMENT_COMPLETED_SPEECH,
+ BTS_CTR_ASSIGNMENT_STOPPED,
+ BTS_CTR_ASSIGNMENT_STOPPED_SIGN,
+ BTS_CTR_ASSIGNMENT_STOPPED_SPEECH,
+ BTS_CTR_ASSIGNMENT_NO_CHANNEL,
+ BTS_CTR_ASSIGNMENT_NO_CHANNEL_SIGN,
+ BTS_CTR_ASSIGNMENT_NO_CHANNEL_SPEECH,
+ BTS_CTR_ASSIGNMENT_TIMEOUT,
+ BTS_CTR_ASSIGNMENT_TIMEOUT_SIGN,
+ BTS_CTR_ASSIGNMENT_TIMEOUT_SPEECH,
+ BTS_CTR_ASSIGNMENT_FAILED,
+ BTS_CTR_ASSIGNMENT_FAILED_SIGN,
+ BTS_CTR_ASSIGNMENT_FAILED_SPEECH,
+ BTS_CTR_ASSIGNMENT_ERROR,
+ BTS_CTR_ASSIGNMENT_ERROR_SIGN,
+ BTS_CTR_ASSIGNMENT_ERROR_SPEECH,
+ BTS_CTR_LOCATION_UPDATE_ACCEPT,
+ BTS_CTR_LOCATION_UPDATE_REJECT,
+ BTS_CTR_LOCATION_UPDATE_DETACH,
+ BTS_CTR_LOCATION_UPDATE_UNKNOWN,
+ 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,
+ BTS_CTR_INTRA_CELL_HO_ATTEMPTED,
+ BTS_CTR_INTRA_CELL_HO_COMPLETED,
+ BTS_CTR_INTRA_CELL_HO_STOPPED,
+ BTS_CTR_INTRA_CELL_HO_NO_CHANNEL,
+ BTS_CTR_INTRA_CELL_HO_TIMEOUT,
+ BTS_CTR_INTRA_CELL_HO_FAILED,
+ BTS_CTR_INTRA_CELL_HO_ERROR,
+ BTS_CTR_INTRA_BSC_HO_ATTEMPTED,
+ BTS_CTR_INTRA_BSC_HO_COMPLETED,
+ BTS_CTR_INTRA_BSC_HO_STOPPED,
+ BTS_CTR_INTRA_BSC_HO_NO_CHANNEL,
+ 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,
+ BTS_CTR_INTER_BSC_HO_OUT_TIMEOUT,
+ BTS_CTR_INTER_BSC_HO_OUT_FAILED,
+ BTS_CTR_INTER_BSC_HO_OUT_ERROR,
+ BTS_CTR_INTER_BSC_HO_IN_ATTEMPTED,
+ BTS_CTR_INTER_BSC_HO_IN_COMPLETED,
+ BTS_CTR_INTER_BSC_HO_IN_STOPPED,
+ BTS_CTR_INTER_BSC_HO_IN_NO_CHANNEL,
+ BTS_CTR_INTER_BSC_HO_IN_FAILED,
+ BTS_CTR_INTER_BSC_HO_IN_TIMEOUT,
+ BTS_CTR_INTER_BSC_HO_IN_ERROR,
+ BTS_CTR_SRVCC_ATTEMPTED,
+ BTS_CTR_SRVCC_COMPLETED,
+ BTS_CTR_SRVCC_STOPPED,
+ BTS_CTR_SRVCC_NO_CHANNEL,
+ 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[];
+extern const struct rate_ctr_group_desc bts_ctrg_desc;
+
+enum {
+ BTS_STAT_UPTIME_SECONDS,
+ BTS_STAT_CHAN_LOAD_AVERAGE,
+ BTS_STAT_CHAN_CCCH_SDCCH4_USED,
+ BTS_STAT_CHAN_CCCH_SDCCH4_TOTAL,
+ BTS_STAT_CHAN_TCH_F_USED,
+ BTS_STAT_CHAN_TCH_F_TOTAL,
+ BTS_STAT_CHAN_TCH_H_USED,
+ BTS_STAT_CHAN_TCH_H_TOTAL,
+ BTS_STAT_CHAN_SDCCH8_USED,
+ BTS_STAT_CHAN_SDCCH8_TOTAL,
+ BTS_STAT_CHAN_TCH_F_PDCH_USED,
+ BTS_STAT_CHAN_TCH_F_PDCH_TOTAL,
+ BTS_STAT_CHAN_CCCH_SDCCH4_CBCH_USED,
+ BTS_STAT_CHAN_CCCH_SDCCH4_CBCH_TOTAL,
+ BTS_STAT_CHAN_SDCCH8_CBCH_USED,
+ BTS_STAT_CHAN_SDCCH8_CBCH_TOTAL,
+ BTS_STAT_CHAN_OSMO_DYN_USED,
+ BTS_STAT_CHAN_OSMO_DYN_TOTAL,
+ BTS_STAT_T3122,
+ BTS_STAT_RACH_BUSY,
+ BTS_STAT_RACH_ACCESS,
+ BTS_STAT_OML_CONNECTED,
+ BTS_STAT_RSL_CONNECTED,
+ BTS_STAT_LCHAN_BORKEN,
+ BTS_STAT_TS_BORKEN,
+ BTS_STAT_NUM_TRX_RSL_CONNECTED,
+ BTS_STAT_NUM_TRX_TOTAL,
+ BTS_STAT_PAGING_REQ_QUEUE_LENGTH,
+ BTS_STAT_PAGING_AVAILABLE_SLOTS,
+ BTS_STAT_PAGING_T3113,
+};
+
+extern const struct osmo_stat_item_desc bts_stat_desc[];
+extern const struct osmo_stat_item_group_desc bts_statg_desc;
+
+enum gsm_bts_type {
+ GSM_BTS_TYPE_UNKNOWN,
+ GSM_BTS_TYPE_BS11,
+ GSM_BTS_TYPE_NANOBTS,
+ GSM_BTS_TYPE_RBS2000,
+ GSM_BTS_TYPE_NOKIA_SITE,
+ GSM_BTS_TYPE_OSMOBTS,
+ _NUM_GSM_BTS_TYPE
+};
+extern const struct value_string bts_type_names[_NUM_GSM_BTS_TYPE+1];
+extern const struct value_string bts_type_descs[_NUM_GSM_BTS_TYPE+1];
+
+enum gsm_bts_type_variant {
+ BTS_UNKNOWN,
+ BTS_OSMO_LITECELL15,
+ BTS_OSMO_OCTPHY,
+ BTS_OSMO_SYSMO,
+ BTS_OSMO_TRX,
+ _NUM_BTS_VARIANT
+};
+
+/* Used by OML layer for BTS Attribute reporting */
+enum bts_attribute {
+ BTS_TYPE_VARIANT,
+ BTS_SUB_MODEL,
+ TRX_PHY_VERSION,
+};
+
+enum bts_tch_signalling_policy {
+ BTS_TCH_SIGNALLING_NEVER,
+ BTS_TCH_SIGNALLING_EMERG,
+ BTS_TCH_SIGNALLING_VOICE,
+ BTS_TCH_SIGNALLING_ALWAYS,
+};
+
+struct vty;
+
+struct gsm_bts_model {
+ struct llist_head list;
+
+ enum gsm_bts_type type;
+ enum gsm_bts_type_variant variant;
+ const char *name;
+
+ bool started;
+ /* start the model itself */
+ int (*start)(struct gsm_network *net);
+
+ /* initialize a single BTS for this model */
+ int (*bts_init)(struct gsm_bts *bts);
+
+ /* initialize a single TRX for this model */
+ int (*trx_init)(struct gsm_bts_trx *trx);
+
+ int (*oml_rcvmsg)(struct msgb *msg);
+ char * (*oml_status)(const struct gsm_bts *bts);
+
+ void (*e1line_bind_ops)(struct e1inp_line *line);
+
+ /* (Optional) function for encoding MS/BS Power Control paramaters */
+ int (*power_ctrl_enc_rsl_params)(struct msgb *msg, const struct gsm_power_ctrl_params *cp);
+ /* (Optional) function for sending default MS/BS Power Control paramaters */
+ int (*power_ctrl_send_def_params)(const struct gsm_bts_trx *trx);
+ /* (Optional) function for toggling BCCH carrier power reduction operation */
+ int (*power_ctrl_send_c0_power_red)(const struct gsm_bts *bts, const uint8_t red);
+
+ void (*config_write_bts)(struct vty *vty, struct gsm_bts *bts);
+ void (*config_write_trx)(struct vty *vty, struct gsm_bts_trx *trx);
+ void (*config_write_ts)(struct vty *vty, struct gsm_bts_trx_ts *ts);
+
+ /* Should SI2bis and SI2ter be disabled by default on this BTS model? */
+ bool force_combined_si;
+
+ struct tlv_definition nm_att_tlvdef;
+
+ /* features of a given BTS model set via gsm_bts_model_register()
+ * locally, see doc/bts-features.txt */
+ struct bitvec features;
+ uint8_t _features_data[MAX_BTS_FEATURES/8];
+ /* BTS reports features during OML bring up */
+ bool features_get_reported;
+};
+
+struct gsm_gprs_cell {
+ struct gsm_abis_mo mo;
+ uint16_t bvci;
+ uint8_t timer[11];
+ struct gprs_rlc_cfg rlc_cfg;
+};
+
+/* One BTS */
+struct gsm_bts {
+ /* list header in net->bts_list */
+ struct llist_head list;
+
+ /* Geographical location of the BTS */
+ struct llist_head loc_list;
+
+ /* number of this BTS in network */
+ uint8_t nr;
+ /* human readable name / description */
+ char *description;
+ /* Cell Identity */
+ uint16_t cell_identity;
+ /* location area code of this BTS */
+ uint16_t location_area_code;
+ /* Base Station Identification Code (BSIC), lower 3 bits is BCC,
+ * which is used as TSC for the CCCH */
+ uint8_t bsic;
+ /* type of BTS */
+ enum gsm_bts_type type;
+ enum gsm_bts_type_variant variant;
+ struct gsm_bts_model *model;
+ enum gsm_band band;
+ char version[MAX_VERSION_LENGTH];
+ char sub_model[MAX_VERSION_LENGTH];
+
+ /* features of a given BTS either hardcoded or set/reported via OML,
+ * see doc/bts-features.txt */
+ struct bitvec features;
+ uint8_t _features_data[MAX_BTS_FEATURES/8];
+ /* Features have been reported by the BTS or were copied from the BTS
+ * model */
+ bool features_known;
+
+ /* Connected PCU version (if any) */
+ char pcu_version[MAX_VERSION_LENGTH];
+ /* PCU sign_link, over OML line: */
+ struct e1inp_sign_link *osmo_link;
+
+ /* maximum Tx power that the MS is permitted to use in this cell */
+ int ms_max_power;
+
+ /* how do we talk OML with this TRX? */
+ struct gsm_e1_subslot oml_e1_link;
+ uint8_t oml_tei;
+ struct e1inp_sign_link *oml_link;
+ /* Timer to use for deferred drop of OML link, see \ref ipaccess_drop_oml_deferred */
+ struct osmo_timer_list oml_drop_link_timer;
+ /* when OML link was established or lost */
+ time_t updowntime;
+
+ /* Abis network management O&M handle */
+ struct abis_nm_h *nmh;
+
+ struct gsm_abis_mo mo;
+
+ /* number of this BTS on given E1 link */
+ uint8_t bts_nr;
+
+ /* DTX features of this BTS */
+ enum gsm48_dtx_mode dtxu;
+ bool dtxd;
+
+ /* paging state and control */
+ struct gsm_bts_paging_state paging;
+
+ /* CCCH is on C0 */
+ struct gsm_bts_trx *c0;
+
+ struct gsm_bts_sm *site_mgr; /* backpointer */
+
+ /* bitmask of all SI that are present/valid in si_buf */
+ uint32_t si_valid;
+ /* 3GPP TS 44.018 Table 10.5.2.33b.1 INDEX and COUNT for SI2quater */
+ uint8_t si2q_index; /* distinguish individual SI2quater messages */
+ uint8_t si2q_count; /* si2q_index for the last (highest indexed) individual SI2quater message */
+ /* buffers where we put the pre-computed SI */
+ sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE][SI2Q_MAX_NUM];
+ /* offsets used while generating SI2quater */
+ size_t e_offset;
+ size_t u_offset;
+ /* 3GPP TS 08.58 ยง8.5.1 BCCH INFORMATION. Some nanoBTS fail upon
+ * receival of empty SI disabling unsupported SI. see OS#3707. */
+ bool si_unused_send_empty;
+
+ /* ip.access Unit ID's have Site/BTS/TRX layout */
+ union {
+ struct {
+ uint16_t site_id;
+ uint16_t bts_id;
+ uint32_t flags;
+ uint32_t rsl_ip;
+ } ip_access;
+ struct {
+ struct {
+ struct gsm_abis_mo mo;
+ } cclk;
+ struct {
+ struct gsm_abis_mo mo;
+ } rack;
+ struct gsm_envabtse envabtse[4];
+ } bs11;
+ struct {
+ struct osmo_fsm_inst *bts_fi;
+ struct {
+ struct om2k_mo om2k_mo;
+ struct gsm_abis_mo mo;
+ struct llist_head conn_groups;
+ } cf;
+ struct {
+ struct om2k_mo om2k_mo;
+ struct gsm_abis_mo mo;
+ struct llist_head conn_groups;
+ } is;
+ struct {
+ struct om2k_mo om2k_mo;
+ struct gsm_abis_mo mo;
+ struct llist_head conn_groups;
+ } con;
+ struct {
+ struct om2k_mo om2k_mo;
+ struct gsm_abis_mo mo;
+ } dp;
+ struct {
+ struct om2k_mo om2k_mo;
+ struct gsm_abis_mo mo;
+ } tf;
+ struct {
+ struct om2k_mo om2k_mo;
+ struct gsm_abis_mo mo;
+ } mctr;
+ uint32_t use_superchannel:1;
+ struct {
+ uint16_t limit;
+ uint16_t active;
+ } om2k_version[16];
+ enum om2k_sync_src sync_src;
+ } rbs2000;
+ struct {
+ uint8_t bts_type;
+ unsigned int configured:1, /* we sent the config data request */
+ skip_reset:1, /* skip reset at bootstrap */
+ no_loc_rel_cnf:1, /* don't wait for RSL REL CONF */
+ bts_reset_timer_cnf, /* timer for BTS RESET */
+ did_reset:1, /* we received a RESET ACK */
+ wait_reset:2; /* we are waiting for reset to complete */
+ struct osmo_timer_list reset_timer;
+ } nokia;
+ };
+
+ /* Not entirely sure how ip.access specific this is */
+ struct {
+ enum bts_gprs_mode mode;
+ struct gsm_gprs_cell cell;
+ uint8_t rac;
+ uint8_t net_ctrl_ord;
+ bool ctrl_ack_type_use_block;
+ bool egprs_pkt_chan_request;
+ struct {
+ bool active; /* CCN_ACTIVE */
+ bool forced_vty; /* set by VTY ? */
+ } ccn; /* TS 44.060 sec 8.8.2 */
+ struct {
+ uint8_t alpha; /* ALPHA*10, units of 0.1, range <0-10> */
+ } pwr_ctrl; /* TS 44.060 Table 12.9.1 */
+ } gprs;
+
+ /* CCCH Load Threshold: threshold (in percent) when BTS shall send CCCH LOAD IND */
+ uint8_t ccch_load_ind_thresh;
+ /* CCCH Load Indication Period: how often (secs) to send CCCH LOAD IND when over CCCH Load Threshold. */
+ uint8_t ccch_load_ind_period;
+
+ /* RACH NM values */
+ int rach_b_thresh;
+ int rach_ldavg_slots;
+
+ /* transceivers */
+ int num_trx;
+ struct llist_head trx_list;
+
+ /* SI related items */
+ int force_combined_si;
+ bool force_combined_si_set;
+ int bcch_change_mark;
+
+ /* Abis NM queue */
+ struct llist_head abis_queue;
+ int abis_nm_pend;
+
+ struct gsm_network *network;
+
+ /* should the channel allocator allocate channels from high TRX to TRX0,
+ * rather than starting from TRX0 and go upwards? */
+ bool chan_alloc_chan_req_reverse;
+ bool chan_alloc_assignment_reverse;
+ bool chan_alloc_handover_reverse;
+ bool chan_alloc_vgcs_reverse;
+
+ /* Whether to use dynamic allocation mode for assignment */
+ bool chan_alloc_assignment_dynamic;
+ /* Parameters used for dynamic mode of allocation */
+ struct {
+ bool sort_by_trx_power;
+ uint8_t ul_rxlev_thresh;
+ uint8_t ul_rxlev_avg_num;
+ uint8_t c0_chan_load_thresh;
+ } chan_alloc_dyn_params;
+
+ /* When true, interference measurements from the BTS are used in the channel allocator to favor lchans with less
+ * interference reported in RSL Resource Indication. */
+ bool chan_alloc_avoid_interf;
+
+ /* If SDCCHs are exhausted, when can we use TCH for signalling purposes. */
+ enum bts_tch_signalling_policy chan_alloc_tch_signalling_policy;
+
+ enum neigh_list_manual_mode neigh_list_manual_mode;
+ /* parameters from which we build SYSTEM INFORMATION */
+ struct {
+ struct gsm48_rach_control rach_control;
+ uint8_t ncc_permitted;
+ struct gsm48_cell_sel_par cell_sel_par;
+ struct osmo_gsm48_si_selection_params cell_ro_sel_par; /* rest octet */
+ struct gsm48_cell_options cell_options;
+ struct gsm48_control_channel_descr chan_desc;
+ struct bitvec neigh_list;
+ struct bitvec cell_alloc;
+ struct bitvec si5_neigh_list;
+ struct osmo_earfcn_si2q si2quater_neigh_list;
+ size_t uarfcn_length; /* index for uarfcn and scramble lists */
+ size_t cell_chan_num; /* number of channels in Cell Allocation */
+ struct {
+ /* bitmask large enough for all possible ARFCN's */
+ uint8_t neigh_list[1024/8];
+ uint8_t cell_alloc[1024/8];
+ /* If the user wants a different neighbor list in SI5 than in SI2 */
+ uint8_t si5_neigh_list[1024/8];
+ uint8_t meas_bw_list[MAX_EARFCN_LIST];
+ uint16_t earfcn_list[MAX_EARFCN_LIST];
+ uint16_t uarfcn_list[MAX_EARFCN_LIST];
+ uint16_t scramble_list[MAX_EARFCN_LIST];
+ } data;
+ } si_common;
+ /* NCH (Notification Channel) related parameters */
+ struct {
+ uint8_t num_blocks; /* NCH number of CCCH blocks (0 = no NCH) */
+ uint8_t first_block; /* NCH first block number */
+ } nch;
+ bool early_classmark_allowed;
+ bool early_classmark_allowed_3g;
+ /* for testing only: Have an infinitely long radio link timeout */
+ bool infinite_radio_link_timeout;
+
+ /* do we use static (user-defined) system information messages? (bitmask) */
+ uint32_t si_mode_static;
+
+ /* access control class ramping */
+ struct acc_mgr acc_mgr;
+ struct acc_ramp acc_ramp;
+
+ /* exclude the BTS from the global RF Lock handling */
+ int excl_from_rf_lock;
+
+ /* MGW specificities for this BTS: */
+ int mgw_pool_target; /* Pin to specific MGW. -1 = wildcard */
+ bool mgw_pool_target_strict; /* Only allow pinned MGW */
+
+ /* supported codecs beside FR */
+ struct bts_codec_conf codec;
+
+ /* BTS dependencies bit field */
+ uint32_t depends_on[256/(8*4)];
+
+ /* full and half rate multirate config */
+ struct amr_multirate_conf mr_full;
+ struct amr_multirate_conf mr_half;
+
+ /* osmux config: */
+ enum osmux_usage use_osmux;
+
+ struct rate_ctr_group *bts_ctrs;
+ struct osmo_stat_item_group *bts_statg;
+
+ struct handover_cfg *ho;
+
+ /* Local and remote neighbor configuration: a list of neighbors as written in the VTY config, not resolved to
+ * actual cells. Entries may point at non-existing BTS numbers, or yet unconfigured ARFCN+BSIC. The point of
+ * this list is to keep the config as the user entered it: a) to write it back exactly as entered, and b) to
+ * allow adding neighbor cells that will only be configured further down in the config file.
+ * An actual neighbor cell object (local or remote-BSS) is resolved "at runtime" whenever a neighbor is being
+ * looked up. */
+ struct llist_head neighbors;
+
+ /* BTS-specific overrides for timer values from struct gsm_network. */
+ uint8_t T3122; /* ASSIGNMENT REJECT wait indication */
+ bool T3113_dynamic; /* Calculate T3113 timeout dynamically based on BTS channel config and load */
+
+ /* Periodic channel load measurements are used to maintain T3122. */
+ struct load_counter chan_load_samples[7];
+ int chan_load_samples_idx;
+ uint8_t chan_load_avg; /* current channel load average in percent (0 - 100). */
+
+ /* cell broadcast system */
+ struct osmo_timer_list cbch_timer;
+ struct bts_smscb_chan_state cbch_basic;
+ struct bts_smscb_chan_state cbch_extended;
+ struct bts_etws_state etws;
+
+ struct llist_head oml_fail_rep;
+ struct llist_head chan_rqd_queue;
+
+ /* ACCH Repetition capabilities */
+ struct abis_rsl_osmo_rep_acch_cap rep_acch_cap;
+
+ /* 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;
+ struct gsm_power_ctrl_params bs_power_ctrl;
+
+ /* Maximum BCCH carrier power reduction */
+ uint8_t c0_max_power_red_db;
+
+ /* Interference Measurement Parameters, as read from VTY */
+ struct gsm_interf_meas_params interf_meas_params_cfg;
+ /* Interference Measurement Parameters, as last sent via OML */
+ struct gsm_interf_meas_params interf_meas_params_used;
+
+ /* We will ignore CHAN RQD with access delay greater than rach_max_delay */
+ uint8_t rach_max_delay;
+
+ /* We will ignore CHAN RQD sitting in the queue for period greater than rach_expiry_timeout */
+ uint8_t rach_expiry_timeout;
+
+ /* Is Fast return to LTE allowed during Chan Release in this BTS? */
+ bool srvcc_fast_return_allowed;
+
+ /* At what point in the channel allocation sequence to dispatch the Immediate Assignment (Abis optimization) */
+ enum imm_ass_time imm_ass_time;
+
+ struct chan_counts chan_counts;
+ struct all_allocated all_allocated;
+
+ struct bts_setup_ramp bts_setup_ramp;
+};
+
+#define GSM_BTS_SI2Q(bts, i) (struct gsm48_system_information_type_2quater *)((bts)->si_buf[SYSINFO_TYPE_2quater][i])
+#define GSM_BTS_HAS_SI(bts, i) ((bts)->si_valid & (1 << i))
+#define GSM_BTS_SI(bts, i) (void *)((bts)->si_buf[i][0])
+
+/* this actually refers to the IPA transport, not the BTS model */
+static inline bool is_ipa_abisip_bts(const struct gsm_bts *bts)
+{
+ switch (bts->type) {
+ case GSM_BTS_TYPE_NANOBTS:
+ case GSM_BTS_TYPE_OSMOBTS:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static inline bool is_nanobts(const struct gsm_bts *bts)
+{
+ switch (bts->type) {
+ case GSM_BTS_TYPE_NANOBTS:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static inline bool is_osmobts(const struct gsm_bts *bts)
+{
+ switch (bts->type) {
+ case GSM_BTS_TYPE_OSMOBTS:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static inline bool is_siemens_bts(const struct gsm_bts *bts)
+{
+ switch (bts->type) {
+ case GSM_BTS_TYPE_BS11:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static inline bool is_nokia_bts(const struct gsm_bts *bts)
+{
+ switch (bts->type) {
+ case GSM_BTS_TYPE_NOKIA_SITE:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static inline bool is_ericsson_bts(const struct gsm_bts *bts)
+{
+ switch (bts->type) {
+ case GSM_BTS_TYPE_RBS2000:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static inline bool is_e1_bts(const struct gsm_bts *bts)
+{
+ switch (bts->type) {
+ case GSM_BTS_TYPE_BS11:
+ case GSM_BTS_TYPE_RBS2000:
+ case GSM_BTS_TYPE_NOKIA_SITE:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static inline bool bsc_co_located_pcu(const struct gsm_bts *bts)
+{
+ switch (bts->type) {
+ case GSM_BTS_TYPE_RBS2000:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static inline const struct osmo_location_area_id *bts_lai(struct gsm_bts *bts)
+{
+ static struct osmo_location_area_id lai;
+ lai = (struct osmo_location_area_id){
+ .plmn = bts->network->plmn,
+ .lac = bts->location_area_code,
+ };
+ return &lai;
+}
+
+struct 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);
+
+bool gsm_bts_matches_lai(const struct gsm_bts *bts, const struct osmo_location_area_id *lai);
+bool gsm_bts_matches_cell_id(const struct gsm_bts *bts, const struct gsm0808_cell_id *cell_id);
+void gsm_bts_cell_id(struct gsm0808_cell_id *cell_id, const struct gsm_bts *bts);
+void gsm_bts_cell_id_list(struct gsm0808_cell_id_list2 *cell_id_list, const struct gsm_bts *bts);
+
+int gsm_bts_local_neighbor_add(struct gsm_bts *bts, struct gsm_bts *neighbor);
+int gsm_bts_local_neighbor_del(struct gsm_bts *bts, const struct gsm_bts *neighbor);
+
+/* return the gsm_lchan for the CBCH (if it exists at all) */
+struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts);
+
+int gsm_set_bts_model(struct gsm_bts *bts, struct gsm_bts_model *model);
+int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
+
+struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);
+
+int bts_gprs_mode_is_compat(struct gsm_bts *bts, enum bts_gprs_mode mode);
+
+#define BTS_STORE_UPTIME_INTERVAL 10 /* in seconds */
+void bts_store_uptime(struct gsm_bts *bts);
+
+unsigned long long bts_updowntime(const struct gsm_bts *bts);
+
+#define BTS_STORE_LCHAN_DURATIONS_INTERVAL 1 /* in seconds */
+void bts_store_lchan_durations(struct gsm_bts *bts);
+
+char *get_model_oml_status(const struct gsm_bts *bts);
+/* reset the state of all MO in the BTS */
+void gsm_bts_mo_reset(struct gsm_bts *bts);
+
+static inline bool gsm_bts_features_negotiated(struct gsm_bts *bts)
+{
+ return bts->mo.get_attr_rep_received || bts->mo.nm_state.operational == NM_OPSTATE_ENABLED;
+}
+
+/* dependency handling */
+void bts_depend_mark(struct gsm_bts *bts, int dep);
+void bts_depend_clear(struct gsm_bts *bts, int dep);
+int bts_depend_check(struct gsm_bts *bts);
+int bts_depend_is_depedency(struct gsm_bts *base, struct gsm_bts *other);
+
+int gsm_bts_get_radio_link_timeout(const struct gsm_bts *bts);
+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 gsm_bts_set_system_infos(struct gsm_bts *bts);
+
+int gsm_bts_send_c0_power_red(const struct gsm_bts *bts, const uint8_t red);
+int gsm_bts_set_c0_power_red(struct gsm_bts *bts, const uint8_t red);
+
+void gsm_bts_stats_reset(struct gsm_bts *bts);
+
+int gsm_bts_model_register(struct gsm_bts_model *model);
+struct gsm_bts_model *bts_model_find(enum gsm_bts_type type);
+
+enum gsm_bts_type str2btstype(const char *arg);
+const char *btstype2str(enum gsm_bts_type type);
+
+enum bts_attribute str2btsattr(const char *s);
+const char *btsatttr2str(enum bts_attribute v);
+
+enum gsm_bts_type_variant str2btsvariant(const char *arg);
+const char *btsvariant2str(enum gsm_bts_type_variant v);
+
+bool gsm_bts_check_ny1(const struct gsm_bts *bts);
diff --git a/include/osmocom/bsc/bts_ipaccess_nanobts_omlattr.h b/include/osmocom/bsc/bts_ipaccess_nanobts_omlattr.h
index bc7860b2d..9f51efd8b 100644
--- a/include/osmocom/bsc/bts_ipaccess_nanobts_omlattr.h
+++ b/include/osmocom/bsc/bts_ipaccess_nanobts_omlattr.h
@@ -23,10 +23,22 @@
#include <stdint.h>
#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/tlv.h>
-struct msgb *nanobts_attr_bts_get(struct gsm_bts *bts);
-struct msgb *nanobts_attr_nse_get(struct gsm_bts *bts);
-struct msgb *nanobts_attr_cell_get(struct gsm_bts *bts);
-struct msgb *nanobts_attr_nscv_get(struct gsm_bts *bts);
-struct msgb *nanobts_attr_radio_get(struct gsm_bts *bts,
+struct gsm_bts_sm;
+struct gsm_bts;
+struct gsm_bts_trx;
+struct gsm_gprs_nsvc;
+
+extern const struct tlv_definition ipacc_eie_tlv_def;
+
+int ipacc_parse_supp_features(const struct gsm_bts *bts,
+ const struct abis_om_fom_hdr *foh,
+ const uint8_t *data, uint16_t data_len);
+
+struct msgb *nanobts_gen_set_bts_attr(struct gsm_bts *bts);
+struct msgb *nanobts_gen_set_nse_attr(struct gsm_bts_sm *bts_sm);
+struct msgb *nanobts_gen_set_cell_attr(struct gsm_bts *bts);
+struct msgb *nanobts_gen_set_nsvc_attr(struct gsm_gprs_nsvc *nsvc);
+struct msgb *nanobts_gen_set_radio_attr(struct gsm_bts *bts,
struct gsm_bts_trx *trx);
diff --git a/include/osmocom/bsc/bts_setup_ramp.h b/include/osmocom/bsc/bts_setup_ramp.h
new file mode 100644
index 000000000..0278ee034
--- /dev/null
+++ b/include/osmocom/bsc/bts_setup_ramp.h
@@ -0,0 +1,69 @@
+/* (C) 2022 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * Author: Alexander Couzens <acouzens@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/timer.h>
+
+struct gsm_bts;
+struct gsm_network;
+
+enum bts_setup_ramp_state {
+ BTS_SETUP_RAMP_INIT, /*!< initial state */
+ BTS_SETUP_RAMP_WAIT, /*!< BTS has to wait, too many BTS configuring */
+ BTS_SETUP_RAMP_READY, /*!< BTS is allowed to configure */
+};
+
+struct bts_setup_ramp {
+ enum bts_setup_ramp_state state;
+ struct llist_head list;
+};
+
+struct bts_setup_ramp_net {
+ unsigned count; /*!< max count */
+ unsigned step_size; /*!< also the maximum concurrent bts to configure */
+
+ struct llist_head head;
+ struct osmo_timer_list timer;
+ unsigned int step_interval; /*!< in seconds */
+ bool enabled; /*!< enabled by vty */
+ bool active; /*!< if currently active */
+};
+
+void bts_setup_ramp_init_bts(struct gsm_bts *bts);
+void bts_setup_ramp_init_network(struct gsm_network *net);
+
+bool bts_setup_ramp_active(struct gsm_network *net);
+bool bts_setup_ramp_wait(struct gsm_bts *bts);
+void bts_setup_ramp_remove(struct gsm_bts *bts);
+int bts_setup_ramp_unblock_bts(struct gsm_bts *bts);
+
+/* vty related functions */
+void bts_setup_ramp_enable(struct gsm_network *net);
+void bts_setup_ramp_disable(struct gsm_network *net);
+void bts_setup_ramp_set_step_interval(struct gsm_network *net, unsigned int step_interval);
+void bts_setup_ramp_set_step_size(struct gsm_network *net, unsigned int step_size);
+
+const char *bts_setup_ramp_get_state_str(struct gsm_bts *bts);
diff --git a/include/osmocom/bsc/bts_sm.h b/include/osmocom/bsc/bts_sm.h
new file mode 100644
index 000000000..13be3d97e
--- /dev/null
+++ b/include/osmocom/bsc/bts_sm.h
@@ -0,0 +1,80 @@
+/* BTS Site Manager */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <stdint.h>
+
+#include "osmocom/bsc/gsm_data.h"
+
+struct gsm_bts;
+
+struct gsm_gprs_nse {
+ struct gsm_abis_mo mo;
+ uint16_t nsei;
+ uint8_t timer[7];
+};
+
+struct gsm_gprs_nsvc {
+ struct gsm_bts *bts;
+ /* data read via VTY config file, to configure the BTS
+ * via OML from BSC */
+ int id;
+ bool enabled;
+ uint16_t nsvci;
+ uint16_t local_port; /* on the BTS */
+ struct osmo_sockaddr remote;
+ struct gsm_abis_mo mo;
+};
+
+
+/* BTS Site Manager */
+struct gsm_bts_sm {
+ struct gsm_bts *bts[1]; /* only one bts supported so far */
+ struct gsm_abis_mo mo;
+ /* nanoBTS and old versions of osmo-bts behaves this way due to
+ broken FSMs not following TS 12.21: they never do
+ Dependency->Offline transition, but they should be OPSTARTed
+ nevertheless during Dependnecy state to work. This field is
+ used by all dependent NM objects. */
+ bool peer_has_no_avstate_offline;
+ struct {
+ struct gsm_gprs_nse nse;
+ struct gsm_gprs_nsvc nsvc[2];
+ } gprs;
+};
+
+static inline struct gsm_bts *gsm_bts_sm_get_bts(struct gsm_bts_sm *site_mgr) {
+ return site_mgr->bts[0];
+}
+
+struct gsm_bts_sm *gsm_bts_sm_alloc(struct gsm_network *net, uint8_t bts_num);
+
+void gsm_bts_sm_mo_reset(struct gsm_bts_sm *bts_sm);
+
+static inline struct gsm_gprs_nsvc *gsm_bts_sm_nsvc_num(struct gsm_bts_sm *bts_sm, uint8_t nsvc_num)
+{
+ if (nsvc_num >= ARRAY_SIZE(bts_sm->gprs.nsvc))
+ return NULL;
+ return &bts_sm->gprs.nsvc[nsvc_num];
+}
diff --git a/include/osmocom/bsc/bts_trx.h b/include/osmocom/bsc/bts_trx.h
new file mode 100644
index 000000000..8ded559a4
--- /dev/null
+++ b/include/osmocom/bsc/bts_trx.h
@@ -0,0 +1,102 @@
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/bitvec.h>
+#include <osmocom/gsm/tlv.h>
+
+#include <osmocom/abis/e1_input.h>
+
+#include "osmocom/bsc/gsm_data.h"
+#include "osmocom/bsc/abis_om2000.h"
+
+struct gsm_bts;
+
+#define TRX_NR_TS 8
+
+struct gsm_bts_bb_trx {
+ struct gsm_abis_mo mo;
+};
+
+/* One TRX in a BTS */
+struct gsm_bts_trx {
+ /* list header in bts->trx_list */
+ struct llist_head list;
+
+ struct gsm_bts *bts;
+ /* number of this TRX in the BTS */
+ uint8_t nr;
+ /* how do we talk RSL with this TRX? */
+ struct gsm_e1_subslot rsl_e1_link;
+ uint8_t rsl_tei_primary;
+ struct e1inp_sign_link *rsl_link_primary;
+
+ /* Timeout for initiating the RSL connection. */
+ struct osmo_timer_list rsl_connect_timeout;
+
+ /* Some BTS (specifically Ericsson RBS) have a per-TRX OML Link */
+ struct e1inp_sign_link *oml_link;
+
+ struct gsm_abis_mo mo;
+ struct gsm_bts_bb_trx bb_transc;
+
+ uint16_t arfcn;
+ int nominal_power; /* in dBm */
+ unsigned int max_power_red; /* in actual dB */
+
+ union {
+ struct {
+ struct {
+ struct gsm_abis_mo mo;
+ } bbsig;
+ struct {
+ struct gsm_abis_mo mo;
+ } pa;
+ } bs11;
+ struct {
+ unsigned int test_state;
+ uint8_t test_nr;
+ struct rxlev_stats rxlev_stat;
+ } ipaccess;
+ struct {
+ struct osmo_fsm_inst *trx_fi;
+ struct {
+ struct om2k_mo om2k_mo;
+ } trxc;
+ struct {
+ struct om2k_mo om2k_mo;
+ } rx;
+ struct {
+ struct om2k_mo om2k_mo;
+ } tx;
+ enum om2k_rx_diversity rx_diversity;
+ } rbs2000;
+ };
+ struct gsm_bts_trx_ts ts[TRX_NR_TS];
+
+ struct chan_counts chan_counts;
+ struct load_counter lchan_load;
+};
+
+static inline struct gsm_bts_trx *gsm_bts_bb_trx_get_trx(struct gsm_bts_bb_trx *bb_transc) {
+ return (struct gsm_bts_trx *)container_of(bb_transc, struct gsm_bts_trx, bb_transc);
+}
+
+struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
+char *gsm_trx_name(const struct gsm_bts_trx *trx);
+
+struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
+ int *rc);
+
+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);
+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_alloc.h b/include/osmocom/bsc/chan_alloc.h
index 97f6cb2db..b509e3e6d 100644
--- a/include/osmocom/bsc/chan_alloc.h
+++ b/include/osmocom/bsc/chan_alloc.h
@@ -24,9 +24,6 @@
struct gsm_subscriber_connection;
-/* Allocate a logical channel (SDCCH, TCH, ...) */
-struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type, int allow_bigger);
-
/* Free a logical channel (SDCCH, TCH, ...) */
void lchan_free(struct gsm_lchan *lchan);
diff --git a/include/osmocom/bsc/chan_counts.h b/include/osmocom/bsc/chan_counts.h
new file mode 100644
index 000000000..a830e8745
--- /dev/null
+++ b/include/osmocom/bsc/chan_counts.h
@@ -0,0 +1,111 @@
+/* API to count total, allocated and free channels of all types */
+#pragma once
+
+struct gsm_bts;
+struct gsm_bts_trx;
+struct gsm_bts_trx_ts;
+struct gsm_lchan;
+
+void chan_counts_sig_init(void);
+void chan_counts_ts_update(struct gsm_bts_trx_ts *ts);
+void chan_counts_ts_clear(struct gsm_bts_trx_ts *ts);
+void chan_counts_trx_update(struct gsm_bts_trx *trx);
+void chan_counts_bsc_verify(void);
+
+/* 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 {
+ /* Signed type, so that chan_counts_diff() can return negative values. */
+ int val[_CHAN_COUNTS1_NUM][_CHAN_COUNTS2_NUM][_GSM_LCHAN_MAX];
+};
+
+static inline void chan_counts_zero(struct chan_counts *counts)
+{
+ *counts = (struct chan_counts){0};
+}
+
+static inline bool chan_counts_is_zero(const struct chan_counts *counts)
+{
+ int i1, i2, i3;
+ for (i1 = 0; i1 < _CHAN_COUNTS1_NUM; i1++) {
+ for (i2 = 0; i2 < _CHAN_COUNTS2_NUM; i2++) {
+ for (i3 = 0; i3 < _GSM_LCHAN_MAX; i3++) {
+ if (counts->val[i1][i2][i3])
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+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_dim2_sub(struct chan_counts *dst, enum chan_counts_dim1 dst_dim1,
+ const struct chan_counts *sub, enum chan_counts_dim1 sub_dim1)
+{
+ int i;
+ for (i = 0; i < _CHAN_COUNTS2_NUM; i++)
+ chan_counts_dim3_sub(dst, dst_dim1, i, sub, sub_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);
+}
+
+static inline void chan_counts_sub(struct chan_counts *dst, const struct chan_counts *sub)
+{
+ int i;
+ for (i = 0; i < _CHAN_COUNTS1_NUM; i++)
+ chan_counts_dim2_sub(dst, i, sub, i);
+}
diff --git a/include/osmocom/bsc/codec_pref.h b/include/osmocom/bsc/codec_pref.h
index 51340c118..5944a4a1d 100644
--- a/include/osmocom/bsc/codec_pref.h
+++ b/include/osmocom/bsc/codec_pref.h
@@ -9,14 +9,23 @@ struct gsm_audio_support;
struct bts_codec_conf;
struct bsc_msc_data;
struct gsm_bts;
+struct channel_mode_and_rate;
-int match_codec_pref(enum gsm48_chan_mode *chan_mode,
- bool *full_rate,
- uint16_t *s15_s0,
+enum rate_pref {
+ RATE_PREF_NONE,
+ RATE_PREF_HR,
+ RATE_PREF_FR,
+};
+
+int match_codec_pref_data(struct channel_mode_and_rate *ch_mode_rate,
+ const struct gsm0808_channel_type *ct,
+ const bool full_rate);
+
+int match_codec_pref(struct channel_mode_and_rate *ch_mode_rate,
const struct gsm0808_channel_type *ct,
const struct gsm0808_speech_codec_list *scl,
const struct bsc_msc_data *msc,
- const struct gsm_bts *bts);
+ const struct gsm_bts *bts, enum rate_pref rate_pref);
void gen_bss_supported_codec_list(struct gsm0808_speech_codec_list *scl,
const struct bsc_msc_data *msc,
diff --git a/include/osmocom/bsc/ctrl.h b/include/osmocom/bsc/ctrl.h
index 04ca2cb5a..c61e01f85 100644
--- a/include/osmocom/bsc/ctrl.h
+++ b/include/osmocom/bsc/ctrl.h
@@ -1,9 +1,26 @@
#pragma once
#include <osmocom/ctrl/control_cmd.h>
+#include <osmocom/bsc/gsm_data.h>
+
+struct gsm_network;
+struct gsm_bts;
+struct bsc_msc_data;
+
+struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, uint16_t port);
+
+/* Used internally in different ctrl source code files: */
+int bsc_bts_ctrl_cmds_install(void);
+int bsc_bts_trx_ctrl_cmds_install(void);
+int bsc_bts_trx_ts_ctrl_cmds_install(void);
+int bsc_bts_trx_ts_lchan_ctrl_cmds_install(void);
+void ctrl_generate_bts_location_state_trap(struct gsm_bts *bts, struct bsc_msc_data *msc);
+void osmo_bsc_send_trap(struct ctrl_cmd *cmd, struct bsc_msc_data *msc_data);
+char *lchan_dump_full_ctrl(const void *t, struct gsm_lchan *lchan);
+char *ts_lchan_dump_full_ctrl(const void *t, struct gsm_bts_trx_ts *ts);
+char *trx_lchan_dump_full_ctrl(const void *t, struct gsm_bts_trx *trx);
+char *bts_lchan_dump_full_ctrl(const void *t, struct gsm_bts *bts);
-struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net,
- const char *bind_addr, uint16_t port);
enum bsc_ctrl_node {
CTRL_NODE_MSC = _LAST_CTRL_NODE,
diff --git a/include/osmocom/bsc/data_rate_pref.h b/include/osmocom/bsc/data_rate_pref.h
new file mode 100644
index 000000000..da3f1fde2
--- /dev/null
+++ b/include/osmocom/bsc/data_rate_pref.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <stdbool.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+
+struct gsm0808_channel_type;
+struct channel_mode_and_rate;
+
+int match_data_rate_pref(struct channel_mode_and_rate *ch_mode_rate,
+ const struct gsm0808_channel_type *ct,
+ const bool full_rate);
diff --git a/include/osmocom/bsc/debug.h b/include/osmocom/bsc/debug.h
index e78ba59a8..a61753ddf 100644
--- a/include/osmocom/bsc/debug.h
+++ b/include/osmocom/bsc/debug.h
@@ -19,7 +19,6 @@ enum {
DHO,
DHODEC,
DREF,
- DNAT,
DCTRL,
DFILTER,
DPCU,
@@ -27,5 +26,16 @@ enum {
DCHAN,
DTS,
DAS,
+ DCBS,
+ DLCS,
+ DASCI,
+ DRESET,
+ DLOOP,
Debug_LastEntry,
};
+
+#define LOG_BTS(bts, subsys, level, fmt, args...) \
+ LOGP(subsys, level, "(bts=%d) " fmt, (bts)->nr, ## args)
+
+#define LOG_TRX(trx, subsys, level, fmt, args...) \
+ LOGP(subsys, level, "(bts=%d,trx=%d) " fmt, (trx)->bts->nr, (trx)->nr, ## args)
diff --git a/include/osmocom/bsc/gsm_04_08_rr.h b/include/osmocom/bsc/gsm_04_08_rr.h
index 8e4f78785..75930baae 100644
--- a/include/osmocom/bsc/gsm_04_08_rr.h
+++ b/include/osmocom/bsc/gsm_04_08_rr.h
@@ -1,6 +1,10 @@
#pragma once
#include <stdint.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/bitvec.h>
+
+enum handover_scope;
struct amr_mode;
struct amr_multirate_conf;
@@ -11,35 +15,33 @@ struct gsm_lchan;
struct gsm_meas_rep;
struct gsm_network;
struct gsm_subscriber_connection;
-struct msgb;
void gsm_net_update_ctype(struct gsm_network *network);
enum gsm_chan_t get_ctype_by_chreq(struct gsm_network *network, uint8_t ra);
int get_reason_by_chreq(uint8_t ra, int neci);
-int gsm48_send_rr_release(struct gsm_lchan *lchan);
+int gsm48_send_rr_release(struct gsm_lchan *lchan, bool ui);
int send_siemens_mrpci(struct gsm_lchan *lchan,
uint8_t *classmark2_lv);
-int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn,
- struct msgb *msg, struct bsc_subscr *bsub);
int gsm48_send_rr_classmark_enquiry(struct gsm_lchan *lchan);
int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv);
-int gsm48_multirate_config(uint8_t *lv, const struct gsm48_multi_rate_conf *mr_conf,
+int gsm48_multirate_config(struct msgb *msg,
+ const struct gsm48_multi_rate_conf *mr_conf,
const struct amr_mode *modes, unsigned int num_modes);
-struct msgb *gsm48_make_ho_cmd(struct gsm_lchan *new_lchan, uint8_t power_command, uint8_t ho_ref);
-int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
- uint8_t power_command, uint8_t ho_ref);
+struct msgb *gsm48_make_ho_cmd(const struct gsm_lchan *new_lchan,
+ enum handover_scope ho_scope, bool async,
+ uint8_t power_command, uint8_t ho_ref);
int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, uint8_t power_command);
+int gsm48_send_rr_app_info(struct gsm_lchan *lchan, uint8_t apdu_id, uint8_t apdu_flags,
+ const uint8_t *apdu_data, ssize_t apdu_data_len);
int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t mode);
+int gsm48_send_uplink_release(struct gsm_lchan *lchan, uint8_t cause);
+int gsm48_send_uplink_busy(struct gsm_lchan *lchan);
+int gsm48_send_uplink_free(struct gsm_lchan *lchan, uint8_t acc_bit, uint8_t *uic);
int gsm48_rx_rr_modif_ack(struct msgb *msg);
+int neigh_list_get_arfcn(struct gsm_bts *bts, const struct bitvec *nbv, unsigned int idx);
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);
-int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type);
-int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
- char *mi_string, uint8_t *mi_type);
struct msgb *gsm48_create_loc_upd_rej(uint8_t cause);
struct msgb *gsm48_create_rr_status(uint8_t cause);
diff --git a/include/osmocom/bsc/gsm_04_80.h b/include/osmocom/bsc/gsm_04_80.h
deleted file mode 100644
index 649ffe19f..000000000
--- a/include/osmocom/bsc/gsm_04_80.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-struct gsm_subscriber_connection;
-
-int bsc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level,
- const char *text);
-int bsc_send_ussd_release_complete(struct gsm_subscriber_connection *conn);
diff --git a/include/osmocom/bsc/gsm_08_08.h b/include/osmocom/bsc/gsm_08_08.h
index 524129560..eb2f4da15 100644
--- a/include/osmocom/bsc/gsm_08_08.h
+++ b/include/osmocom/bsc/gsm_08_08.h
@@ -6,11 +6,11 @@
struct gsm_subscriber_connection;
-void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci);
-void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, struct msgb *msg, uint8_t chosen_encr);
-int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg, uint16_t chosen_channel);
+void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, uint8_t dlci, enum gsm0808_cause cause);
+void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, struct msgb *msg, uint8_t chosen_a5_n);
+int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_channel);
void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg);
-int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause);
void bsc_cm_update(struct gsm_subscriber_connection *conn,
const uint8_t *cm2, uint8_t cm2_len,
const uint8_t *cm3, uint8_t cm3_len);
+bool bsc_chan_ind_requires_rtp_stream(enum gsm0808_chan_indicator ch_indctr);
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 20901420e..bd51a42a6 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -2,45 +2,66 @@
#define _GSM_DATA_H
#include <stdint.h>
-#include <regex.h>
#include <sys/types.h>
#include <stdbool.h>
-#include <stdint.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/stat_item.h>
#include <osmocom/gsm/bts_features.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/protocol/gsm_48_049.h>
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/core/time_cc.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/linuxrbtree.h>
#include <osmocom/crypt/auth.h>
-#include <osmocom/bsc/rest_octets.h>
+#include <osmocom/gsm/gsm48_rest_octets.h>
#include <osmocom/core/bitvec.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/rxlev_stat.h>
#include <osmocom/gsm/protocol/gsm_08_58.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
+#include <osmocom/gsm/protocol/gsm_03_41.h>
#include <osmocom/abis/e1_input.h>
+#include <osmocom/bsc/bts_setup_ramp.h>
#include <osmocom/bsc/meas_rep.h>
-#include <osmocom/bsc/bsc_msg_filter.h>
-#include <osmocom/bsc/acc_ramp.h>
-#include <osmocom/bsc/gsm_timers.h>
-#include <osmocom/bsc/neighbor_ident.h>
+#include <osmocom/bsc/acc.h>
+#include <osmocom/bsc/osmux.h>
+#include <osmocom/bsc/chan_counts.h>
+#include <osmocom/bsc/lchan.h>
#define GSM_T3122_DEFAULT 10
+#define GSM_T3105_DEFAULT 100UL
+#define GSM_T3124_SDCCH 675UL
+#define GSM_T3124_OTHER_CH 320UL
+#define GSM_T3124_MAX GSM_T3124_SDCCH
+
+/* Some guess for delta (see comment below) */
+#define GSM_NY1_REQ_DELTA 1000UL
+/* Requirements: We want Ny1 to be as low as possible, while respecting T3105 * Ny1 > T3124 + delta
+ * with delta = time between expiration of T3124 and receiving HANDOVER FAILURE by the serving BSC. */
+#define GSM_NY1_DEFAULT ((unsigned long)((GSM_T3124_MAX + GSM_NY1_REQ_DELTA)/GSM_T3105_DEFAULT + 1))
+
+#define SCCP_CONN_ID_UNSET 0xFFFFFFFF
+#define SCCP_CONN_ID_MAX 0x00FFFFFE
+
struct mgcp_client_conf;
struct mgcp_client;
-struct mgcp_ctx;
struct gsm0808_cell_id;
-struct mgw_endpoint;
+struct osmo_mgcpc_ep;
+struct gsm_bts;
+struct gsm_bts_trx;
/** annotations for msgb ownership */
#define __uses
@@ -50,10 +71,30 @@ struct mgw_endpoint;
struct bsc_subscr;
struct gprs_ra_id;
struct handover;
+struct osmo_sccp_instance;
+struct smlc_config;
#define OBSC_LINKID_CB(__msgb) (__msgb)->cb[3]
-#define tmsi_from_string(str) strtoul(str, NULL, 10)
+/* 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
@@ -68,22 +109,6 @@ typedef int gsm_cbfn(unsigned int hooknum,
struct msgb *msg,
void *data, void *param);
-/* Maximum number of neighbor cells whose average we track */
-#define MAX_NEIGH_MEAS 10
-/* Maximum size of the averaging window for neighbor cells */
-#define MAX_WIN_NEIGH_AVG 10
-/* Maximum number of report history we store */
-#define MAX_MEAS_REP 10
-
-/* processed neighbor measurements for one cell */
-struct neigh_meas_proc {
- uint16_t arfcn;
- uint8_t bsic;
- uint8_t rxlev[MAX_WIN_NEIGH_AVG];
- unsigned int rxlev_cnt;
- uint8_t last_seen_nr;
-};
-
struct gsm_classmark {
bool classmark1_set;
struct gsm48_classmark1 classmark1;
@@ -99,22 +124,69 @@ enum subscr_sccp_state {
SUBSCR_SCCP_ST_CONNECTED
};
+enum assign_for {
+ ASSIGN_FOR_NONE,
+ ASSIGN_FOR_BSSMAP_REQ,
+ ASSIGN_FOR_CONGESTION_RESOLUTION,
+ ASSIGN_FOR_VTY,
+};
+
+extern const struct value_string assign_for_names[];
+static inline const char *assign_for_name(enum assign_for assign_for)
+{ return get_value_string(assign_for_names, assign_for); }
+
+/* Information retrieved during an Assignment Request from the MSC. This is storage of the Assignment instructions
+ * parsed from the Assignment Request message, to pass on until the gscon and assignment FSMs have decided whether an
+ * Assignment is actually going to be carried out. Should remain unchanged after initial decoding. */
struct assignment_request {
+ enum assign_for assign_for;
+
bool aoip;
+ bool vgcs;
uint16_t msc_assigned_cic;
- char msc_rtp_addr[INET_ADDRSTRLEN];
+ char msc_rtp_addr[INET6_ADDRSTRLEN];
uint16_t msc_rtp_port;
-
- enum gsm48_chan_mode chan_mode;
- bool full_rate;
- uint16_t s15_s0;
+ bool use_osmux;
+ uint8_t osmux_cid;
+
+ /* Rate/codec setting in preference order (need at least 1 !) */
+ int n_ch_mode_rate;
+ struct channel_mode_and_rate ch_mode_rate_list[3];
+
+ /* An assignment request usually requests to assign any available lchan, to match above requirements. This may
+ * also choose to just keep the current lchan and merely modify it as appropriate. In these cases, keep
+ * target_lchan == NULL.
+ * In some situations, an assignment to a specific target lchan is requested (congestion resolution, VAMOS
+ * multiplexing, user request via VTY). In these situations, select a target lchan beforehand and point
+ * target_lchan to it. */
+ struct gsm_lchan *target_lchan;
+
+ /* The TSC Set to use if 'use' is true, otherwise automatically determine the TSC Set value to use. Valid range
+ * is 1 to 4, as described in 3GPP TS 45.002. */
+ struct optional_val tsc_set;
+ /* The TSC to use if 'use' is true, otherwise automatically determine the TSC value to use. Valid range is 0 to
+ * 7, as described in 3GPP TS 45.002. */
+ struct optional_val tsc;
+
+ /* The "speech / data indicator" from 3GPP TS 48.008 ยง 3.2.2.11 Channel Type (speech/data/signalling). */
+ enum gsm0808_chan_indicator ch_indctr;
};
+/* State of an ongoing Assignment, while the assignment_fsm is still busy. This serves as state separation to keep the
+ * currently used lchan and gscon unmodified until the outcome of an Assignment is known. If the Assignment fails, this
+ * state is simply discarded, and the gscon carries on with the original lchan remaining unchanged. */
struct assignment_fsm_data {
+ /* The request as made by the caller, see GSCON_EV_ASSIGNMENT_START or reassignment_request_to_lchan() /
+ * reassignment_request_to_chan_type().
+ * conn->assignment.req is treated immutable: remains unchanged throughout the Assignment. The mutable fields
+ * are below: choices and automatic adjustments are stored in conn->assignment.*, not conn->assignment.req.
+ */
struct assignment_request req;
- bool requires_voice_stream;
+
+ enum gsm0808_chan_indicator ch_indctr;
+ struct channel_mode_and_rate selected_ch_mode_rate;
struct osmo_fsm_inst *fi;
struct gsm_lchan *new_lchan;
@@ -122,7 +194,7 @@ struct assignment_fsm_data {
/* Whether this assignment triggered creation of the MGW endpoint: if the assignment
* fails, we will release that again as soon as possible. (If false, the endpoint already
* existed before or isn't needed at all.)*/
- struct mgwep_ci *created_ci_for_msc;
+ struct osmo_mgcpc_ep_ci *created_ci_for_msc;
enum gsm0808_cause failure_cause;
enum gsm48_rr_cause rr_cause;
@@ -153,10 +225,16 @@ extern const struct value_string handover_scope_names[];
inline static const char *handover_scope_name(enum handover_scope val)
{ return get_value_string(handover_scope_names, val); }
+/* Cell ARFCN + BSIC. */
+struct cell_ab {
+ uint16_t arfcn;
+ uint8_t bsic;
+};
+
struct handover_out_req {
enum hodec_id from_hodec_id;
struct gsm_lchan *old_lchan;
- struct neighbor_ident_key target_nik;
+ struct cell_ab target_cell_ab;
enum gsm_chan_t new_lchan_type; /*< leave GSM_LCHAN_NONE to use same as old_lchan */
};
@@ -164,14 +242,24 @@ struct handover_in_req {
struct gsm0808_channel_type ct;
struct gsm0808_speech_codec_list scl;
struct gsm0808_encrypt_info ei;
+ /* The same information as in 'ei' but as the handy bitmask as on the wire. */
+ uint8_t ei_as_bitmask;
+ bool kc128_present;
+ uint8_t kc128[16];
struct gsm_classmark classmark;
+ /* chosen_encr_alg reflects the encoded value as in RSL_ENC_ALG_A5(a5_numer):
+ * chosen_encr_alg == 1 means A5/0 i.e. no encryption, chosen_encr_alg == 4 means A5/3.
+ * chosen_encr_alg == 0 means no such IE was present. */
+ uint8_t chosen_encr_alg;
struct gsm0808_cell_id cell_id_serving;
char cell_id_serving_name[64];
struct gsm0808_cell_id cell_id_target;
char cell_id_target_name[64];
uint16_t msc_assigned_cic;
- char msc_assigned_rtp_addr[INET_ADDRSTRLEN];
+ char msc_assigned_rtp_addr[INET6_ADDRSTRLEN];
uint16_t msc_assigned_rtp_port;
+ bool last_eutran_plmn_valid;
+ struct osmo_plmn_id last_eutran_plmn;
};
struct handover {
@@ -180,16 +268,35 @@ struct handover {
enum hodec_id from_hodec_id;
enum handover_scope scope;
enum gsm_chan_t new_lchan_type;
- struct neighbor_ident_key target_cell;
+ struct cell_ab target_cell_ab;
+
+ /* For inter-BSC handover, this may reflect more than one Cell ID. Must also be set for intra-BSC handover,
+ * because it is used as key for penalty timers (e.g. in handover decision 2). */
+ struct gsm0808_cell_id_list2 target_cell_ids;
uint8_t ho_ref;
struct gsm_bts *new_bts;
struct gsm_lchan *new_lchan;
bool async;
struct handover_in_req inter_bsc_in;
- struct mgwep_ci *created_ci_for_msc;
+ struct osmo_mgcpc_ep_ci *created_ci_for_msc;
};
+struct gsm_subscriber_connection;
+
+struct bscp_sccp_conn_node {
+ /* entry in (struct bsc_sccp_inst)->connections */
+ struct rb_node node;
+ /* Sigtran connection ID:
+ * if set: Range (0..SCCP_CONN_ID_MAX) (24 bit)
+ * if unset: SCCP_CONN_ID_UNSET (-1) if unset */
+ uint32_t conn_id;
+ /* backpointer where this sccp conn belongs to: */
+ struct gsm_subscriber_connection *gscon;
+};
+
+void bscp_sccp_conn_node_init(struct bscp_sccp_conn_node *sccp_conn, struct gsm_subscriber_connection *gscon);
+
/* active radio connection of a mobile subscriber */
struct gsm_subscriber_connection {
/* global linked list of subscriber_connections */
@@ -204,24 +311,26 @@ struct gsm_subscriber_connection {
/* back pointers */
struct gsm_network *network;
- /* the primary / currently active lchan to the BTS/subscriber */
+ /* the primary / currently active lchan to the BTS/subscriber. During Assignment and Handover, separate lchans
+ * are kept in the .assignment or .handover sub-structs, respectively, so that this lchan remains unaffected
+ * until Assignment or Handover have actually succeeded. */
struct gsm_lchan *lchan;
+ /* Only valid during an ongoing Assignment; might be overwritten at any time by a failed Assignment attempt.
+ * Once an Assignment was successful, all relevant state must be copied out of this sub-struct. */
struct assignment_fsm_data assignment;
- /* handover information, if a handover is pending for this conn. */
+ /* handover information, if a handover is pending for this conn. Valid only during an ongoing Handover
+ * operation. If a Handover was successful, all relevant state must be copied out of this sub-struct. */
struct handover ho;
- /* buffer/cache for classmark of the ME of the subscriber */
- struct gsm_classmark classmark;
-
/* Queue DTAP messages during handover/assignment (msgb_enqueue()/msgb_dequeue())*/
struct llist_head dtap_queue;
unsigned int dtap_queue_len;
struct {
int failures;
- struct penalty_timers *penalty_timers;
+ struct llist_head penalty_timers;
} hodec2;
/* "Codec List (MSC Preferred)" as received by the BSSAP Assignment Request. 3GPP 48.008
@@ -235,23 +344,12 @@ struct gsm_subscriber_connection {
/* flag to prevent multiple simultaneous ciphering commands */
int ciphering_handled;
- /* state related to welcome USSD */
- uint8_t new_subscriber;
-
- /* state related to osmo_bsc_filter.c */
- struct bsc_filter_state filter_state;
-
- /* SCCP connection associatd with this subscriber_connection */
+ /* SCCP connection associated with this subscriber_connection */
struct {
- /* for advanced ping/pong */
- int send_ping;
-
- /* SCCP connection realted */
+ /* SCCP connection related */
struct bsc_msc_data *msc;
-
- /* Sigtran connection ID */
- int conn_id;
enum subscr_sccp_state state;
+ struct bscp_sccp_conn_node conn;
} sccp;
/* for audio handling */
@@ -259,16 +357,16 @@ struct gsm_subscriber_connection {
uint16_t msc_assigned_cic;
/* RTP address where the MSC expects us to send the RTP stream coming from the BTS. */
- char msc_assigned_rtp_addr[INET_ADDRSTRLEN];
+ char msc_assigned_rtp_addr[INET6_ADDRSTRLEN];
uint16_t msc_assigned_rtp_port;
/* The endpoint at the MGW used to join both BTS and MSC side connections, e.g.
* "rtpbridge/23@mgw". */
- struct mgw_endpoint *mgw_endpoint;
+ struct osmo_mgcpc_ep *mgw_endpoint;
- /* The connection identifier of the mgw_endpoint used to transceive RTP towards the MSC.
+ /* The connection identifier of the osmo_mgcpc_ep used to transceive RTP towards the MSC.
* (The BTS side CI is handled by struct gsm_lchan and the lchan_fsm.) */
- struct mgwep_ci *mgw_endpoint_ci_msc;
+ struct osmo_mgcpc_ep_ci *mgw_endpoint_ci_msc;
} user_plane;
/* LCLS (local call, local switch) related state */
@@ -282,6 +380,93 @@ struct gsm_subscriber_connection {
/* pointer to "other" connection, if Call Leg Relocation was successful */
struct gsm_subscriber_connection *other;
} lcls;
+
+ /* MS Power Class, TS 05.05 sec 4.1.1 "Mobile station". 0 means unset. */
+ uint8_t ms_power_class:3;
+
+ bool rx_clear_command;
+
+ /* Location Services handling for this subscriber */
+ struct {
+ /* FSM to handle Perform Location Request coming in from the MSC via A interface,
+ * and receive BSSMAP-LE responses from the SMLC. */
+ struct lcs_loc_req *loc_req;
+
+ /* FSM to handle BSSLAP requests coming in from the SMLC via Lb interface.
+ * BSSLAP APDU are encapsulated in BSSMAP-LE Connection Oriented Information messages. */
+ struct lcs_bsslap *bsslap;
+
+ /* Lb interface to the SMLC: BSSMAP-LE/SCCP connection associated with this subscriber */
+ struct {
+ enum subscr_sccp_state state;
+ struct bscp_sccp_conn_node conn;
+ } lb;
+ } lcs;
+
+ struct gsm48_classmark3 cm3;
+ bool cm3_valid;
+
+ struct {
+ bool allowed; /* Is fast return to LTE allowed once the conn is released? */
+ 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;
+
+ /* VGCS/VBS "call controling" connection */
+ struct {
+ /* Features supported by MSC/BSC */
+ bool ff_present;
+ struct gsm0808_vgcs_feature_flags ff;
+ /* Group Call Reference IE */
+ struct gsm0808_group_callref gc_ie;
+ enum gsm0808_service_flag sf;
+ uint32_t call_ref;
+ /* Call (BSC) FSM */
+ struct osmo_fsm_inst *fi;
+ /* Current talker */
+ struct gsm_subscriber_connection *talker;
+ /* L3 info of link establihment (Talker established) */
+ struct llist_head l3_queue;
+ /* Flag and cause (Talker released) */
+ bool talker_rel;
+ uint8_t talker_cause;
+ /* Flag that states acknowledgement of the talker by MSC */
+ bool msc_ack;
+ /* List of VGCS/VBS "resource controling" connections */
+ struct llist_head chan_list;
+ } vgcs_call;
+
+ /* VGCS/VBS "resource controling" connection */
+ struct {
+ /* List entry of chan_list of "call controling" connection */
+ struct llist_head list;
+ /* Group Call Reference IE */
+ struct gsm0808_group_callref gc_ie;
+ enum gsm0808_service_flag sf;
+ uint32_t call_ref;
+ /* Channel type IE */
+ struct gsm0808_channel_type ct;
+ /* Channel mode and rate */
+ struct channel_mode_and_rate ch_mode_rate;
+ /* Cell Identifier IE */
+ struct gsm0808_cell_id ci;
+ char ci_str[16];
+ /* Assignment Requirements IE */
+ enum gsm0808_assignment_requirement ar;
+ /* Call Identifier IE */
+ uint32_t call_id;
+ /* Pointer to VGCS/VBS "call controling" gsconn */
+ struct gsm_subscriber_connection *call;
+ /* Cell (BTS) FSM */
+ struct osmo_fsm_inst *fi;
+ /* lchan to be assigned */
+ struct gsm_lchan *new_lchan;
+ /* MGW peer */
+ char msc_rtp_addr[INET6_ADDRSTRLEN];
+ uint16_t msc_rtp_port;
+ } vgcs_chan;
};
@@ -296,21 +481,10 @@ struct osmo_bsc_data;
struct osmo_bsc_sccp_con;
-/* Channel Request reason */
-enum gsm_chreq_reason_t {
- GSM_CHREQ_REASON_EMERG,
- GSM_CHREQ_REASON_PAG,
- GSM_CHREQ_REASON_CALL,
- GSM_CHREQ_REASON_LOCATION_UPD,
- GSM_CHREQ_REASON_OTHER,
- GSM_CHREQ_REASON_PDCH,
-};
-
/* lchans 0..3 are SDCCH in combined channel configuration,
use 4 as magic number for BCCH hack - see osmo-bts-../oml.c:opstart_compl() */
#define CCCH_LCHAN 4
-#define TRX_NR_TS 8
#define TS_MAX_LCHAN 8
#define HARDCODED_ARFCN 123
@@ -352,8 +526,24 @@ struct gsm_abis_mo {
struct abis_om_obj_inst obj_inst;
const char *name;
struct gsm_nm_state nm_state;
- struct tlv_parsed *nm_attr;
struct gsm_bts *bts;
+ struct osmo_fsm_inst *fi;
+ bool sw_act_rep_received;
+ bool opstart_sent;
+ bool adm_unlock_sent;
+ bool get_attr_sent;
+ bool get_attr_rep_received;
+ bool set_attr_sent;
+ bool set_attr_ack_received;
+ bool rsl_connect_sent;
+ bool rsl_connect_ack_received;
+ bool force_rf_lock;
+ /* vendor specific fields below */
+ union {
+ struct {
+ uint8_t obj_version;
+ } ipaccess;
+ };
};
/* Ericsson OM2000 Managed Object */
@@ -372,13 +562,29 @@ struct om2k_mo {
#define A38_XOR_MIN_KEY_LEN 12
#define A38_XOR_MAX_KEY_LEN 16
#define A38_COMP128_KEY_LEN 16
-#define RSL_ENC_ALG_A5(x) (x+1)
-#define MAX_EARFCN_LIST 32
-/* is the data link established? who established it? */
-#define LCHAN_SAPI_UNUSED 0
-#define LCHAN_SAPI_MS 1
-#define LCHAN_SAPI_NET 2
+/* There are these representations of A5/n:
+ *
+ * - (uint8_t)(1<<n), either as a single bit, or combined as a list of
+ * permitted algorithms.
+ * A5/0 == 0x01, A5/3 == 0x08, none = 0
+ *
+ * - n+1, used on the RSL wire.
+ * A5/0 == 1, A5/3 == 4, none = 0
+ *
+ * - n, used for human interaction and returned by select_best_cipher().
+ * A5/0 == 0, A5/3 == 3, none <= -1
+ *
+ * These macros convert from n to the other representations:
+ */
+#define ALG_A5_NR_TO_RSL(A5_N) ((int)(A5_N) >= 0 ? (A5_N)+1 : 0)
+#define ALG_A5_NR_TO_BSSAP(A5_N) ALG_A5_NR_TO_RSL(A5_N)
+#define ALG_A5_NR_TO_PERM_ALG_BITS(A5_N) ((int)(A5_N) >= 0 ? 1<<(A5_N) : 0)
+
+/* Up to 16 SI2quater are multiplexed; each fits 3 EARFCNS, so the practical maximum is 3*16.
+ * The real maximum that fits in a total of 16 SI2quater rest octets also depends on the bits left by other SI2quater
+ * rest octets elements, so to really fit 48 EARFCNs most other SI2quater elements need to be omitted. */
+#define MAX_EARFCN_LIST (3*16)
/* BTS ONLY */
#define MAX_NUM_UL_MEAS 104
@@ -418,199 +624,23 @@ struct amr_multirate_conf {
};
/* /BTS ONLY */
-enum lchan_csd_mode {
- LCHAN_CSD_M_NT,
- LCHAN_CSD_M_T_1200_75,
- LCHAN_CSD_M_T_600,
- LCHAN_CSD_M_T_1200,
- LCHAN_CSD_M_T_2400,
- LCHAN_CSD_M_T_9600,
- LCHAN_CSD_M_T_14400,
- LCHAN_CSD_M_T_29000,
- LCHAN_CSD_M_T_32000,
-};
-
-/* State of the SAPIs in the lchan */
-enum lchan_sapi_state {
- LCHAN_SAPI_S_NONE,
- LCHAN_SAPI_S_REQ,
- LCHAN_SAPI_S_ASSIGNED,
- LCHAN_SAPI_S_REL,
- LCHAN_SAPI_S_ERROR,
-};
-
-#define MAX_A5_KEY_LEN (128/8)
-
-struct gsm_encr {
- uint8_t alg_id;
- uint8_t key_len;
- uint8_t key[MAX_A5_KEY_LEN];
-};
-
-#define LOGPLCHAN(lchan, ss, level, fmt, args...) \
- LOGP(ss, level, "%s (ss=%d,%s) (%s) " fmt, \
- lchan ? gsm_ts_and_pchan_name(lchan->ts) : "-", \
- lchan ? lchan->nr : 0, \
- lchan ? gsm_lchant_name(lchan->type) : "-", \
- bsc_subscr_name(lchan && lchan->conn ? lchan->conn->bsub : NULL), \
- ## args)
-
-/* Iterate lchans that have an FSM allocated based based on explicit pchan kind
- * (GSM_PCHAN_* constant).
- * Remark: PDCH related lchans are not handled in BSC but in PCU, so trying to
- * iterate through GSM_PCHAN_PDCH is considered a void loop.
- */
-#define ts_as_pchan_for_each_lchan(lchan, ts, as_pchan) \
- for (lchan = (ts)->lchan; \
- ((lchan - (ts)->lchan) < ARRAY_SIZE((ts)->lchan)) \
- && lchan->fi \
- && lchan->nr < pchan_subslots(as_pchan); \
- lchan++)
-
-/* Iterate lchans that have an FSM allocated based on current PCHAN
- * mode set in \ref ts.
+/* Iterate at most N lchans of the given timeslot.
* usage:
* struct gsm_lchan *lchan;
* struct gsm_bts_trx_ts *ts = get_some_timeslot();
- * ts_for_each_lchan(lchan, ts) {
- * LOGPLCHAN(DMAIN, LOGL_DEBUG, "hello world\n");
+ * ts_for_n_lchans(lchan, ts, 3) {
+ * LOG_LCHAN(lchan, LOGL_DEBUG, "hello world\n");
* }
*/
-#define ts_for_each_lchan(lchan, ts) ts_as_pchan_for_each_lchan(lchan, ts, (ts)->pchan_is)
-
-/* Iterate over all possible lchans available that have an FSM allocated based
- * on PCHAN \ref ts (dynamic) configuration.
- * Iterate all lchan instances set up by this \ref ts type, including those
- * lchans currently disabled or in process of being enabled (e.g. due to dynamic
- * timeslot in switchover). Compare ts_for_each_lchan(), which iterates only the
- * enabled lchans.
- * For example, it is useful in case dynamic timeslot \ref ts is in process of
- * switching from configuration PDCH (no lchans) to TCH_F (1 lchan), where
- * pchan_is is still set to PDCH but \ref ts may contain already an \ref lchan
- * of type TCH_F which initiated the request to switch the \ts configuration.
- */
-#define ts_for_each_potential_lchan(lchan, ts) ts_as_pchan_for_each_lchan(lchan, ts, (ts)->pchan_on_init)
-
-enum lchan_activate_mode {
- FOR_NONE,
- FOR_MS_CHANNEL_REQUEST,
- FOR_ASSIGNMENT,
- FOR_HANDOVER,
- FOR_VTY,
-};
-
-extern const struct value_string lchan_activate_mode_names[];
-static inline const char *lchan_activate_mode_name(enum lchan_activate_mode activ_for)
-{ return get_value_string(lchan_activate_mode_names, activ_for); }
-
-struct lchan_activate_info {
- enum lchan_activate_mode activ_for;
- struct gsm_subscriber_connection *for_conn;
- /* This always is for a specific lchan, so its lchan->type indicates full or half rate.
- * When a dyn TS was selected, the lchan->type has been set to the desired rate. */
- enum gsm48_chan_mode chan_mode;
- uint16_t s15_s0;
- bool requires_voice_stream;
- bool wait_before_switching_rtp; /*< true = requires LCHAN_EV_READY_TO_SWITCH_RTP */
- uint16_t msc_assigned_cic;
- struct gsm_lchan *re_use_mgw_endpoint_from_lchan;
-};
-
-struct gsm_lchan {
- /* The TS that we're part of */
- struct gsm_bts_trx_ts *ts;
- /* The logical subslot number in the TS */
- uint8_t nr;
- char *name;
-
- char *last_error;
-
- struct osmo_fsm_inst *fi;
- struct osmo_fsm_inst *fi_rtp;
- struct mgwep_ci *mgw_endpoint_ci_bts;
-
- struct {
- struct lchan_activate_info info;
- bool activ_ack; /*< true as soon as RSL Chan Activ Ack is received */
- bool immediate_assignment_sent;
- /*! This flag ensures that when an lchan activation has succeeded, and we have already
- * sent ACKs like Immediate Assignment or BSSMAP Assignment Complete, and if other errors
- * occur later, e.g. during release, that we don't send a NACK out of context. */
- bool concluded;
- enum gsm0808_cause gsm0808_error_cause;
- } activate;
-
- struct {
- /* If an event to release the lchan comes in while still waiting for responses, just mark this
- * flag, so that the lchan will gracefully release at the next sensible junction. */
- bool requested;
- bool do_rr_release;
-
- /* There is an RSL error cause of value 0, so we need a separate flag. */
- bool in_error;
- /* RSL error code, RSL_ERR_* */
- uint8_t rsl_error_cause;
-
- /* If a release event is being handled, ignore other ricocheting release events until that
- * release handling has concluded. */
- bool in_release_handler;
- } release;
-
- /* The logical channel type */
- enum gsm_chan_t type;
- /* RSL channel mode */
- enum rsl_cmod_spd rsl_cmode;
- /* If TCH, traffic channel mode */
- enum gsm48_chan_mode tch_mode;
- enum lchan_csd_mode csd_mode;
- /* Power levels for MS and BTS */
- uint8_t bs_power;
- uint8_t ms_power;
- /* Encryption information */
- struct gsm_encr encr;
-
- /* AMR bits */
- uint8_t mr_ms_lv[7];
- uint8_t mr_bts_lv[7];
-
- /* Established data link layer services */
- uint8_t sapis[8];
-
- struct {
- uint32_t bound_ip; /*< where the BTS receives RTP */
- uint16_t bound_port;
- uint32_t connect_ip; /*< where the BTS sends RTP to (MGW) */
- uint16_t connect_port;
- uint16_t conn_id;
- uint8_t rtp_payload;
- uint8_t rtp_payload2;
- uint8_t speech_mode;
-
- /* info we need to postpone the AoIP
- * assignment completed message */
- struct {
- uint8_t rr_cause;
- bool valid;
- } ass_compl;
- } abis_ip;
-
- uint8_t rqd_ta;
-
- /* table of neighbor cell measurements */
- struct neigh_meas_proc neigh_meas[MAX_NEIGH_MEAS];
-
- /* cache of last measurement reports on this lchan */
- struct gsm_meas_rep meas_rep[MAX_MEAS_REP];
- int meas_rep_idx;
- int meas_rep_count;
- uint8_t meas_rep_last_seen_nr;
-
- /* GSM Random Access data */
- /* TODO: don't allocate this, rather keep an "is_present" flag */
- struct gsm48_req_ref *rqd_ref;
+#define ts_for_n_lchans(lchan, ts, N) \
+ for (lchan = (ts)->lchan; \
+ ((lchan - (ts)->lchan) < ARRAY_SIZE((ts)->lchan)) \
+ && lchan->fi \
+ && ((lchan - (ts)->lchan) < (N)); \
+ lchan++)
- struct gsm_subscriber_connection *conn;
-};
+#define INTERF_DBM_UNKNOWN 0
+#define INTERF_BAND_UNKNOWN 0xff
/* One Timeslot in a TRX */
struct gsm_bts_trx_ts {
@@ -625,7 +655,7 @@ struct gsm_bts_trx_ts {
* vty after OML activation. Gets written on vty 'write file'. */
enum gsm_phys_chan_config pchan_from_config;
/* When the timeslot OML is established, pchan_from_config is copied here. This is the pchan
- * currently in effect; for dynamic ts, this is the dyn kind (GSM_PCHAN_TCH_F_TCH_H_PDCH or
+ * currently in effect; for dynamic ts, this is the dyn kind (GSM_PCHAN_OSMO_DYN or
* GSM_PCHAN_TCH_F_PDCH) and does not show the pchan type currently active. */
enum gsm_phys_chan_config pchan_on_init;
/* This is the *actual* pchan type currently active. For dynamic timeslots, this reflects either
@@ -644,7 +674,6 @@ struct gsm_bts_trx_ts {
bool is_rsl_ready;
struct gsm_abis_mo mo;
- struct tlv_parsed nm_attr;
uint8_t nm_chan_comb;
int tsc; /* -1 == use BTS TSC */
@@ -670,169 +699,24 @@ struct gsm_bts_trx_ts {
} rbs2000;
};
- struct gsm_lchan lchan[TS_MAX_LCHAN];
-};
-
-/* One TRX in a BTS */
-struct gsm_bts_trx {
- /* list header in bts->trx_list */
- struct llist_head list;
-
- struct gsm_bts *bts;
- /* number of this TRX in the BTS */
- uint8_t nr;
- /* human readable name / description */
- char *description;
- /* how do we talk RSL with this TRX? */
- struct gsm_e1_subslot rsl_e1_link;
- uint8_t rsl_tei;
- struct e1inp_sign_link *rsl_link;
-
- /* Timeout for initiating the RSL connection. */
- struct osmo_timer_list rsl_connect_timeout;
-
- /* Some BTS (specifically Ericsson RBS) have a per-TRX OML Link */
- struct e1inp_sign_link *oml_link;
-
- struct gsm_abis_mo mo;
- struct tlv_parsed nm_attr;
- struct {
- struct gsm_abis_mo mo;
- } bb_transc;
-
- uint16_t arfcn;
- int nominal_power; /* in dBm */
- unsigned int max_power_red; /* in actual dB */
-
- union {
- struct {
- struct {
- struct gsm_abis_mo mo;
- } bbsig;
- struct {
- struct gsm_abis_mo mo;
- } pa;
- } bs11;
- struct {
- unsigned int test_state;
- uint8_t test_nr;
- struct rxlev_stats rxlev_stat;
- } ipaccess;
- struct {
- struct {
- struct om2k_mo om2k_mo;
- } trxc;
- struct {
- struct om2k_mo om2k_mo;
- } rx;
- struct {
- struct om2k_mo om2k_mo;
- } tx;
- } rbs2000;
- };
- struct gsm_bts_trx_ts ts[TRX_NR_TS];
-};
-
-#define GSM_BTS_SI2Q(bts, i) (struct gsm48_system_information_type_2quater *)((bts)->si_buf[SYSINFO_TYPE_2quater][i])
-#define GSM_BTS_HAS_SI(bts, i) ((bts)->si_valid & (1 << i))
-#define GSM_BTS_SI(bts, i) (void *)((bts)->si_buf[i][0])
-#define GSM_LCHAN_SI(lchan, i) (void *)((lchan)->si.buf[i][0])
-
-enum gsm_bts_type {
- GSM_BTS_TYPE_UNKNOWN,
- GSM_BTS_TYPE_BS11,
- GSM_BTS_TYPE_NANOBTS,
- GSM_BTS_TYPE_RBS2000,
- GSM_BTS_TYPE_NOKIA_SITE,
- GSM_BTS_TYPE_OSMOBTS,
- _NUM_GSM_BTS_TYPE
-};
-
-enum gsm_bts_type_variant {
- BTS_UNKNOWN,
- BTS_OSMO_LITECELL15,
- BTS_OSMO_OCTPHY,
- BTS_OSMO_SYSMO,
- BTS_OSMO_TRX,
- _NUM_BTS_VARIANT
-};
-
-/* Used by OML layer for BTS Attribute reporting */
-enum bts_attribute {
- BTS_TYPE_VARIANT,
- BTS_SUB_MODEL,
- TRX_PHY_VERSION,
-};
-
-struct vty;
-
-struct gsm_bts_model {
- struct llist_head list;
-
- enum gsm_bts_type type;
- enum gsm_bts_type_variant variant;
- const char *name;
+ /* Maximum BCCH carrier power reduction */
+ uint8_t c0_max_power_red_db;
- bool started;
- int (*start)(struct gsm_network *net);
- int (*oml_rcvmsg)(struct msgb *msg);
- char * (*oml_status)(const struct gsm_bts *bts);
-
- void (*e1line_bind_ops)(struct e1inp_line *line);
-
- void (*config_write_bts)(struct vty *vty, struct gsm_bts *bts);
- void (*config_write_trx)(struct vty *vty, struct gsm_bts_trx *trx);
- void (*config_write_ts)(struct vty *vty, struct gsm_bts_trx_ts *ts);
-
- /* Should SI2bis and SI2ter be disabled by default on this BTS model? */
- bool force_combined_si;
-
- struct tlv_definition nm_att_tlvdef;
-
- /* features of a given BTS model set via gsm_bts_model_register() locally */
- struct bitvec features;
- uint8_t _features_data[MAX_BTS_FEATURES/8];
-};
-
-
-
-/*
- * This keeps track of the paging status of one BTS. It
- * includes a number of pending requests, a back pointer
- * to the gsm_bts, a timer and some more state.
- */
-struct gsm_bts_paging_state {
- /* pending requests */
- struct llist_head pending_requests;
- struct gsm_bts *bts;
-
- struct osmo_timer_list work_timer;
- struct osmo_timer_list credit_timer;
-
- /* free chans needed */
- int free_chans_need;
+ /* Maximum number of lchans that could become usable, for example by switching a dynamic timeslot's type or by
+ * enabling VAMOS secondary lchans. This does include the maximum count of possible VAMOS secondary lchans. */
+ uint8_t max_lchans_possible;
+ /* Currently usable lchans, according to the current pchan mode (for dynamic timeslots, this may change).
+ * Does not include count of secondary VAMOS lchans. */
+ uint8_t max_primary_lchans;
+ struct gsm_lchan lchan[TS_MAX_LCHAN];
- /* load */
- uint16_t available_slots;
+ struct chan_counts chan_counts;
};
struct gsm_envabtse {
struct gsm_abis_mo mo;
};
-struct gsm_bts_gprs_nsvc {
- struct gsm_bts *bts;
- /* data read via VTY config file, to configure the BTS
- * via OML from BSC */
- int id;
- uint16_t nsvci;
- uint16_t local_port; /* on the BTS */
- uint16_t remote_port; /* on the SGSN */
- uint32_t remote_ip; /* on the SGSN */
-
- struct gsm_abis_mo mo;
-};
-
enum gprs_rlc_par {
RLC_T3142,
RLC_T3169,
@@ -906,265 +790,78 @@ struct load_counter {
unsigned int used;
};
-/* Useful to track N-N relations between BTS, for example neighbors. */
-struct gsm_bts_ref {
- struct llist_head entry;
- struct gsm_bts *bts;
+/* A single Page of a SMSCB message */
+struct bts_smscb_page {
+ /* SMSCB message we're part of */
+ struct bts_smscb_message *msg;
+ /* Page Number within message (1 to 15) */
+ uint8_t nr;
+ /* number of valid blocks in data (up to 4) */
+ uint8_t num_blocks;
+ /* up to four blocks of 22 bytes each */
+ uint8_t data[88];
};
-/* One BTS */
-struct gsm_bts {
- /* list header in net->bts_list */
+/* A SMSCB message (received from CBSP) */
+struct bts_smscb_message {
+ /* entry in bts_smscb_chan_state.messages */
struct llist_head list;
-
- /* Geographical location of the BTS */
- struct llist_head loc_list;
-
- /* number of ths BTS in network */
- uint8_t nr;
- /* human readable name / description */
- char *description;
- /* Cell Identity */
- uint16_t cell_identity;
- /* location area code of this BTS */
- uint16_t location_area_code;
- /* Base Station Identification Code (BSIC), lower 3 bits is BCC,
- * which is used as TSC for the CCCH */
- uint8_t bsic;
- /* type of BTS */
- enum gsm_bts_type type;
- enum gsm_bts_type_variant variant;
- struct gsm_bts_model *model;
- enum gsm_band band;
- char version[MAX_VERSION_LENGTH];
- char sub_model[MAX_VERSION_LENGTH];
-
- /* features of a given BTS set/reported via OML */
- struct bitvec features;
- uint8_t _features_data[MAX_BTS_FEATURES/8];
-
- /* Connected PCU version (if any) */
- char pcu_version[MAX_VERSION_LENGTH];
-
- /* maximum Tx power that the MS is permitted to use in this cell */
- int ms_max_power;
-
- /* how do we talk OML with this TRX? */
- struct gsm_e1_subslot oml_e1_link;
- uint8_t oml_tei;
- struct e1inp_sign_link *oml_link;
- /* Timer to use for deferred drop of OML link, see \ref ipaccess_drop_oml_deferred */
- struct osmo_timer_list oml_drop_link_timer;
- /* when OML link was established */
- time_t uptime;
-
- /* Abis network management O&M handle */
- struct abis_nm_h *nmh;
-
- struct gsm_abis_mo mo;
-
- /* number of this BTS on given E1 link */
- uint8_t bts_nr;
-
- /* DTX features of this BTS */
- enum gsm48_dtx_mode dtxu;
- bool dtxd;
-
- /* paging state and control */
- struct gsm_bts_paging_state paging;
-
- /* CCCH is on C0 */
- struct gsm_bts_trx *c0;
-
- struct {
- struct gsm_abis_mo mo;
- } site_mgr;
-
- /* bitmask of all SI that are present/valid in si_buf */
- uint32_t si_valid;
- /* 3GPP TS 44.018 Table 10.5.2.33b.1 INDEX and COUNT for SI2quater */
- uint8_t si2q_index; /* distinguish individual SI2quater messages */
- uint8_t si2q_count; /* si2q_index for the last (highest indexed) individual SI2quater message */
- /* buffers where we put the pre-computed SI */
- sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE][SI2Q_MAX_NUM];
- /* offsets used while generating SI2quater */
- size_t e_offset;
- size_t u_offset;
- /* 3GPP TS 08.58 ยง8.5.1 BCCH INFORMATION. Some nanoBTS fail upon
- * receival of empty SI disabling unsupported SI. see OS#3707. */
- bool si_unused_send_empty;
-
- /* ip.accesss Unit ID's have Site/BTS/TRX layout */
- union {
- struct {
- uint16_t site_id;
- uint16_t bts_id;
- uint32_t flags;
- uint32_t rsl_ip;
- } ip_access;
- struct {
- struct {
- struct gsm_abis_mo mo;
- } cclk;
- struct {
- struct gsm_abis_mo mo;
- } rack;
- struct gsm_envabtse envabtse[4];
- } bs11;
- struct {
- struct {
- struct om2k_mo om2k_mo;
- struct gsm_abis_mo mo;
- struct llist_head conn_groups;
- } cf;
- struct {
- struct om2k_mo om2k_mo;
- struct gsm_abis_mo mo;
- struct llist_head conn_groups;
- } is;
- struct {
- struct om2k_mo om2k_mo;
- struct gsm_abis_mo mo;
- struct llist_head conn_groups;
- } con;
- struct {
- struct om2k_mo om2k_mo;
- struct gsm_abis_mo mo;
- } dp;
- struct {
- struct om2k_mo om2k_mo;
- struct gsm_abis_mo mo;
- } tf;
- uint32_t use_superchannel:1;
- } rbs2000;
- struct {
- uint8_t bts_type;
- unsigned int configured:1,
- skip_reset:1,
- no_loc_rel_cnf:1,
- bts_reset_timer_cnf,
- did_reset:1,
- wait_reset:1;
- struct osmo_timer_list reset_timer;
- } nokia;
- };
-
- /* Not entirely sure how ip.access specific this is */
struct {
- uint8_t supports_egprs_11bit_rach;
- enum bts_gprs_mode mode;
- struct {
- struct gsm_abis_mo mo;
- uint16_t nsei;
- uint8_t timer[7];
- } nse;
- struct {
- struct gsm_abis_mo mo;
- uint16_t bvci;
- uint8_t timer[11];
- struct gprs_rlc_cfg rlc_cfg;
- } cell;
- struct gsm_bts_gprs_nsvc nsvc[2];
- uint8_t rac;
- uint8_t net_ctrl_ord;
- bool ctrl_ack_type_use_block;
- } gprs;
-
- /* RACH NM values */
- int rach_b_thresh;
- int rach_ldavg_slots;
-
- /* transceivers */
- int num_trx;
- struct llist_head trx_list;
-
- /* SI related items */
- int force_combined_si;
- bool force_combined_si_set;
- int bcch_change_mark;
-
- /* Abis NM queue */
- struct llist_head abis_queue;
- int abis_nm_pend;
+ /* input data from CBSP (CBC) side */
+ uint16_t msg_id;
+ uint16_t serial_nr;
+ enum cbsp_category category;
+ uint16_t rep_period;
+ uint16_t num_bcast_req;
+ uint8_t dcs;
+ } input;
+ /* how often have all pages of this message been broadcast? */
+ uint32_t bcast_count;
+ /* actual page data of this message */
+ uint8_t num_pages; /* up to 15 */
+ struct bts_smscb_page page[15];
+};
- struct gsm_network *network;
+/* per-channel (basic/extended) CBCH state for a single BTS */
+struct bts_smscb_chan_state {
+ /* back-pointer to BTS */
+ struct gsm_bts *bts;
+ /* list of bts_smscb_message */
+ struct llist_head messages;
+ /* scheduling array; pointer of SMSCB pages */
+ struct bts_smscb_page **sched_arr;
+ size_t sched_arr_size;
+ /* index of the next to be transmitted page into the scheduler array */
+ size_t next_idx;
+ /* number of messages we have to pause due to overflow */
+ uint8_t overflow;
+};
- /* should the channel allocator allocate channels from high TRX to TRX0,
- * rather than starting from TRX0 and go upwards? */
- int chan_alloc_reverse;
+#define ETWS_PRIM_NOTIF_SIZE 56
+#define ETWS_SEC_INFO_SIZE (ETWS_PRIM_NOTIF_SIZE - sizeof(struct gsm341_etws_message))
- enum neigh_list_manual_mode neigh_list_manual_mode;
- /* parameters from which we build SYSTEM INFORMATION */
+/* per-BTS ETWS/PWS (Emergency) state */
+struct bts_etws_state {
+ /* are we actively broadcasting emergency in this cell? */
+ bool active;
+ /* input parameters received from CBC */
struct {
- struct gsm48_rach_control rach_control;
- uint8_t ncc_permitted;
- struct gsm48_cell_sel_par cell_sel_par;
- struct gsm48_si_selection_params cell_ro_sel_par; /* rest octet */
- struct gsm48_cell_options cell_options;
- struct gsm48_control_channel_descr chan_desc;
- struct bitvec neigh_list;
- struct bitvec cell_alloc;
- struct bitvec si5_neigh_list;
- struct osmo_earfcn_si2q si2quater_neigh_list;
- size_t uarfcn_length; /* index for uarfcn and scramble lists */
- struct {
- /* bitmask large enough for all possible ARFCN's */
- uint8_t neigh_list[1024/8];
- uint8_t cell_alloc[1024/8];
- /* If the user wants a different neighbor list in SI5 than in SI2 */
- uint8_t si5_neigh_list[1024/8];
- uint8_t meas_bw_list[MAX_EARFCN_LIST];
- uint16_t earfcn_list[MAX_EARFCN_LIST];
- uint16_t uarfcn_list[MAX_EARFCN_LIST];
- uint16_t scramble_list[MAX_EARFCN_LIST];
- } data;
- } si_common;
- bool early_classmark_allowed;
- bool early_classmark_allowed_3g;
- /* for testing only: Have an infinitely long radio link timeout */
- bool infinite_radio_link_timeout;
-
- /* do we use static (user-defined) system information messages? (bitmask) */
- uint32_t si_mode_static;
-
- /* access control class ramping */
- struct acc_ramp acc_ramp;
-
- /* exclude the BTS from the global RF Lock handling */
- int excl_from_rf_lock;
-
- /* supported codecs beside FR */
- struct bts_codec_conf codec;
-
- /* BTS dependencies bit field */
- uint32_t depends_on[256/(8*4)];
-
- /* full and half rate multirate config */
- struct amr_multirate_conf mr_full;
- struct amr_multirate_conf mr_half;
-
- /* PCU socket state */
- char *pcu_sock_path;
- struct pcu_sock_state *pcu_state;
-
- struct rate_ctr_group *bts_ctrs;
- struct osmo_stat_item_group *bts_statg;
-
- struct handover_cfg *ho;
-
- /* A list of struct gsm_bts_ref, indicating neighbors of this BTS.
- * When the si_common neigh_list is in automatic mode, it is populated from this list as well as
- * gsm_network->neighbor_bss_cells. */
- struct llist_head local_neighbors;
-
- /* BTS-specific overrides for timer values from struct gsm_network. */
- uint8_t T3122; /* ASSIGMENT REJECT wait indication */
- bool T3113_dynamic; /* Calculate T3113 timeout dynamically based on BTS channel config and load */
+ uint16_t msg_id;
+ uint16_t serial_nr;
+ uint16_t warn_type;
+ uint8_t sec_info[ETWS_SEC_INFO_SIZE];
+ } input;
+ /* encoded ETWS primary notification */
+ uint8_t primary[ETWS_PRIM_NOTIF_SIZE];
+
+ /* timer running for the duration of the ETWS Primary Notification (PN) */
+ struct osmo_timer_list timer;
+};
- /* Periodic channel load measurements are used to maintain T3122. */
- struct load_counter chan_load_samples[7];
- int chan_load_samples_idx;
- uint8_t chan_load_avg; /* current channel load average in percent (0 - 100). */
+struct bts_oml_fail_rep {
+ struct llist_head list;
+ time_t time;
+ struct msgb *mb;
};
/* One rejected BTS */
@@ -1178,52 +875,30 @@ struct gsm_bts_rejected {
time_t time;
};
+extern struct osmo_tdef_group bsc_tdef_group[];
+
struct gsm_network *gsm_network_init(void *ctx);
-struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, uint8_t bts_num);
struct gsm_bts *gsm_bts_num(const struct gsm_network *net, int num);
-bool gsm_bts_matches_lai(const struct gsm_bts *bts, const struct osmo_location_area_id *lai);
-bool gsm_bts_matches_cell_id(const struct gsm_bts *bts, const struct gsm0808_cell_id *cell_id);
struct gsm_bts *gsm_bts_by_cell_id(const struct gsm_network *net,
const struct gsm0808_cell_id *cell_id,
int match_idx);
-int gsm_bts_local_neighbor_add(struct gsm_bts *bts, struct gsm_bts *neighbor);
-int gsm_bts_local_neighbor_del(struct gsm_bts *bts, const struct gsm_bts *neighbor);
-
-struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
-struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);
-
-enum gsm_bts_type str2btstype(const char *arg);
-const char *btstype2str(enum gsm_bts_type type);
-
-enum bts_attribute str2btsattr(const char *s);
-const char *btsatttr2str(enum bts_attribute v);
-
-enum gsm_bts_type_variant str2btsvariant(const char *arg);
-const char *btsvariant2str(enum gsm_bts_type_variant v);
extern const struct value_string gsm_chreq_descs[];
extern const struct value_string gsm_pchant_names[];
extern const struct value_string gsm_pchant_descs[];
-extern const struct value_string gsm_pchan_ids[];
const char *gsm_pchan_name(enum gsm_phys_chan_config c);
-static inline const char *gsm_pchan_id(enum gsm_phys_chan_config c)
-{ return get_value_string(gsm_pchan_ids, c); }
enum gsm_phys_chan_config gsm_pchan_parse(const char *name);
-const char *gsm_lchant_name(enum gsm_chan_t c);
const char *gsm_chreq_name(enum gsm_chreq_reason_t c);
-char *gsm_trx_name(const struct gsm_bts_trx *trx);
char *gsm_ts_name(const struct gsm_bts_trx_ts *ts);
char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts);
-char *gsm_lchan_name_compute(const struct gsm_lchan *lchan);
-
-static inline char *gsm_lchan_name(const struct gsm_lchan *lchan)
-{
- return lchan->name;
-}
void gsm_abis_mo_reset(struct gsm_abis_mo *mo);
+void gsm_mo_init(struct gsm_abis_mo *mo, struct gsm_bts *bts,
+ uint8_t obj_class, uint8_t p1, uint8_t p2, uint8_t p3);
+struct gsm_abis_mo *gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
+ const struct abis_om_obj_inst *obj_inst);
struct gsm_nm_state *
gsm_objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
const struct abis_om_obj_inst *obj_inst);
@@ -1231,196 +906,28 @@ void *
gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
const struct abis_om_obj_inst *obj_inst);
-/* reset the state of all MO in the BTS */
-void gsm_bts_mo_reset(struct gsm_bts *bts);
-
-uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan,
- uint8_t ts_nr, uint8_t lchan_nr);
-uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan);
-uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,
- enum gsm_phys_chan_config as_pchan);
-
-void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
- const struct gsm_lchan *lchan);
-void gsm48_lchan2chan_desc_as_configured(struct gsm48_chan_desc *cd, const struct gsm_lchan *lchan);
-
-/* return the gsm_lchan for the CBCH (if it exists at all) */
-struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts);
+int gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan,
+ uint8_t ts_nr, uint8_t lchan_nr, bool vamos_is_secondary);
+int gsm_lchan2chan_nr(const struct gsm_lchan *lchan, bool allow_osmo_cbits);
+int gsm_lchan_and_pchan2chan_nr(const struct gsm_lchan *lchan, enum gsm_phys_chan_config pchan, bool allow_osmo_cbits);
-/*
- * help with parsing regexps
- */
-int gsm_parse_reg(void *ctx, regex_t *reg, char **str,
- int argc, const char **argv) __attribute__ ((warn_unused_result));
-
-static inline uint8_t gsm_ts_tsc(const struct gsm_bts_trx_ts *ts)
-{
- if (ts->tsc != -1)
- return ts->tsc;
- else
- return ts->trx->bts->bsic & 7;
-}
+int gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
+ const struct gsm_lchan *lchan,
+ uint8_t tsc, bool allow_osmo_cbits);
+int gsm48_lchan_and_pchan2chan_desc(struct gsm48_chan_desc *cd,
+ const struct gsm_lchan *lchan,
+ enum gsm_phys_chan_config pchan,
+ uint8_t tsc, bool allow_osmo_cbits);
-struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
- int *rc);
+uint8_t gsm_ts_tsc(const struct gsm_bts_trx_ts *ts);
-enum gsm_phys_chan_config ts_pchan(struct gsm_bts_trx_ts *ts);
uint8_t pchan_subslots(enum gsm_phys_chan_config pchan);
+uint8_t pchan_subslots_vamos(enum gsm_phys_chan_config pchan);
bool ts_is_tch(struct gsm_bts_trx_ts *ts);
+struct gsm_bts *conn_get_bts(struct gsm_subscriber_connection *conn);
-static inline struct gsm_bts *conn_get_bts(struct gsm_subscriber_connection *conn) {
- OSMO_ASSERT(conn->lchan);
- return conn->lchan->ts->trx->bts;
-}
-
-enum {
- BTS_CTR_CHREQ_TOTAL,
- BTS_CTR_CHREQ_NO_CHANNEL,
- BTS_CTR_CHAN_RF_FAIL,
- BTS_CTR_CHAN_RLL_ERR,
- BTS_CTR_BTS_OML_FAIL,
- BTS_CTR_BTS_RSL_FAIL,
- BTS_CTR_CODEC_AMR_F,
- BTS_CTR_CODEC_AMR_H,
- BTS_CTR_CODEC_EFR,
- BTS_CTR_CODEC_V1_FR,
- BTS_CTR_CODEC_V1_HR,
- BTS_CTR_PAGING_ATTEMPTED,
- BTS_CTR_PAGING_ALREADY,
- BTS_CTR_PAGING_RESPONDED,
- BTS_CTR_PAGING_EXPIRED,
- BTS_CTR_CHAN_ACT_TOTAL,
- BTS_CTR_CHAN_ACT_NACK,
- BTS_CTR_RSL_UNKNOWN,
- BTS_CTR_RSL_IPA_NACK,
- BTS_CTR_MODE_MODIFY_NACK,
-};
-
-static const struct rate_ctr_desc bts_ctr_description[] = {
- [BTS_CTR_CHREQ_TOTAL] = {"chreq:total", "Received channel requests."},
- [BTS_CTR_CHREQ_NO_CHANNEL] = {"chreq:no_channel", "Sent to MS no channel available."},
- [BTS_CTR_CHAN_RF_FAIL] = {"chan:rf_fail", "Received a RF failure indication from BTS."},
- [BTS_CTR_CHAN_RLL_ERR] = {"chan:rll_err", "Received a RLL failure with T200 cause from BTS."},
- [BTS_CTR_BTS_OML_FAIL] = {"oml_fail", "Received a TEI down on a OML link."},
- [BTS_CTR_BTS_RSL_FAIL] = {"rsl_fail", "Received a TEI down on a OML link."},
- [BTS_CTR_CODEC_AMR_F] = {"codec:amr_f", "Count the usage of AMR/F codec by channel mode requested."},
- [BTS_CTR_CODEC_AMR_H] = {"codec:amr_h", "Count the usage of AMR/H codec by channel mode requested."},
- [BTS_CTR_CODEC_EFR] = {"codec:efr", "Count the usage of EFR codec by channel mode requested."},
- [BTS_CTR_CODEC_V1_FR] = {"codec:fr", "Count the usage of FR codec by channel mode requested."},
- [BTS_CTR_CODEC_V1_HR] = {"codec:hr", "Count the usage of HR codec by channel mode requested."},
-
- [BTS_CTR_PAGING_ATTEMPTED] = {"paging:attempted", "Paging attempts for a subscriber."},
- [BTS_CTR_PAGING_ALREADY] = {"paging:already", "Paging attempts ignored as subsciber was already being paged."},
- [BTS_CTR_PAGING_RESPONDED] = {"paging:responded", "Paging attempts with successful paging response."},
- [BTS_CTR_PAGING_EXPIRED] = {"paging:expired", "Paging Request expired because of timeout T3113."},
- [BTS_CTR_CHAN_ACT_TOTAL] = {"chan_act:total", "Total number of Channel Activations."},
- [BTS_CTR_CHAN_ACT_NACK] = {"chan_act:nack", "Number of Channel Activations that the BTS NACKed"},
- [BTS_CTR_RSL_UNKNOWN] = {"rsl:unknown", "Number of unknown/unsupported RSL messages received from BTS"},
- [BTS_CTR_RSL_IPA_NACK] = {"rsl:ipa_nack", "Number of IPA (RTP/dyn-PDCH) related NACKs received from BTS"},
- [BTS_CTR_MODE_MODIFY_NACK] = {"chan:mode_modify_nack", "Number of Channel Mode Modify NACKs received from BTS"},
-};
-
-static const struct rate_ctr_group_desc bts_ctrg_desc = {
- "bts",
- "base transceiver station",
- OSMO_STATS_CLASS_GLOBAL,
- ARRAY_SIZE(bts_ctr_description),
- bts_ctr_description,
-};
-
-enum {
- BTS_STAT_CHAN_LOAD_AVERAGE,
- BTS_STAT_T3122,
-};
-
-enum {
- BSC_CTR_ASSIGNMENT_ATTEMPTED,
- BSC_CTR_ASSIGNMENT_COMPLETED,
- BSC_CTR_ASSIGNMENT_STOPPED,
- BSC_CTR_ASSIGNMENT_NO_CHANNEL,
- BSC_CTR_ASSIGNMENT_TIMEOUT,
- BSC_CTR_ASSIGNMENT_FAILED,
- BSC_CTR_ASSIGNMENT_ERROR,
- 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,
- BSC_CTR_INTER_BSC_HO_OUT_ATTEMPTED,
- BSC_CTR_INTER_BSC_HO_OUT_COMPLETED,
- BSC_CTR_INTER_BSC_HO_OUT_STOPPED,
- BSC_CTR_INTER_BSC_HO_OUT_TIMEOUT,
- BSC_CTR_INTER_BSC_HO_OUT_ERROR,
- BSC_CTR_INTER_BSC_HO_IN_ATTEMPTED,
- BSC_CTR_INTER_BSC_HO_IN_COMPLETED,
- BSC_CTR_INTER_BSC_HO_IN_STOPPED,
- BSC_CTR_INTER_BSC_HO_IN_NO_CHANNEL,
- BSC_CTR_INTER_BSC_HO_IN_FAILED,
- BSC_CTR_INTER_BSC_HO_IN_TIMEOUT,
- BSC_CTR_INTER_BSC_HO_IN_ERROR,
- BSC_CTR_PAGING_ATTEMPTED,
- BSC_CTR_PAGING_DETACHED,
- BSC_CTR_PAGING_RESPONDED,
- BSC_CTR_UNKNOWN_UNIT_ID,
-};
-
-static const struct rate_ctr_desc bsc_ctr_description[] = {
- [BSC_CTR_ASSIGNMENT_ATTEMPTED] = {"assignment:attempted", "Assignment attempts."},
- [BSC_CTR_ASSIGNMENT_COMPLETED] = {"assignment:completed", "Assignment completed."},
- [BSC_CTR_ASSIGNMENT_STOPPED] = {"assignment:stopped", "Connection ended during Assignment."},
- [BSC_CTR_ASSIGNMENT_NO_CHANNEL] = {"assignment:no_channel", "Failure to allocate lchan for Assignment."},
- [BSC_CTR_ASSIGNMENT_TIMEOUT] = {"assignment:timeout", "Assignment timed out."},
- [BSC_CTR_ASSIGNMENT_FAILED] = {"assignment:failed", "Received Assignment Failure message."},
- [BSC_CTR_ASSIGNMENT_ERROR] = {"assignment:error", "Assigment 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_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-assigment failed for other reason."},
-
- [BSC_CTR_INTER_BSC_HO_OUT_ATTEMPTED] = {"interbsc_ho_out:attempted",
- "Attempts to handover to remote BSS."},
- [BSC_CTR_INTER_BSC_HO_OUT_COMPLETED] = {"interbsc_ho_out:completed",
- "Handover to remote BSS completed."},
- [BSC_CTR_INTER_BSC_HO_OUT_STOPPED] = {"interbsc_ho_out:stopped", "Connection ended during HO."},
- [BSC_CTR_INTER_BSC_HO_OUT_TIMEOUT] = {"interbsc_ho_out:timeout", "Handover timed out."},
- [BSC_CTR_INTER_BSC_HO_OUT_ERROR] = {"interbsc_ho_out:error",
- "Handover to remote BSS failed for other reason."},
-
- [BSC_CTR_INTER_BSC_HO_IN_ATTEMPTED] = {"interbsc_ho_in:attempted",
- "Attempts to handover from remote BSS."},
- [BSC_CTR_INTER_BSC_HO_IN_COMPLETED] = {"interbsc_ho_in:completed",
- "Handover from remote BSS completed."},
- [BSC_CTR_INTER_BSC_HO_IN_STOPPED] = {"interbsc_ho_in:stopped", "Connection ended during HO."},
- [BSC_CTR_INTER_BSC_HO_IN_NO_CHANNEL] = {"interbsc_ho_in:no_channel",
- "Failure to allocate lchan for HO."},
- [BSC_CTR_INTER_BSC_HO_IN_TIMEOUT] = {"interbsc_ho_in:timeout", "Handover from remote BSS timed out."},
- [BSC_CTR_INTER_BSC_HO_IN_FAILED] = {"interbsc_ho_in:failed", "Received Handover Fail message."},
- [BSC_CTR_INTER_BSC_HO_IN_ERROR] = {"interbsc_ho_in:error",
- "Handover from remote BSS failed for other reason."},
-
- [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_UNKNOWN_UNIT_ID] = {"abis:unknown_unit_id", "Connection attempts from unknown IPA CCM Unit ID."},
-};
-
-
-
-static const struct rate_ctr_group_desc bsc_ctrg_desc = {
- "bsc",
- "base station controller",
- OSMO_STATS_CLASS_GLOBAL,
- ARRAY_SIZE(bsc_ctr_description),
- bsc_ctr_description,
-};
+void conn_update_ms_power_class(struct gsm_subscriber_connection *conn, uint8_t power_class);
struct gsm_tz {
int override; /* if 0, use system's time zone instead. */
@@ -1429,13 +936,27 @@ struct gsm_tz {
int dst; /* daylight savings */
};
-struct gsm_network {
- /* TODO MSCSPLIT the gsm_network struct is basically a kitchen sink for
- * global settings and variables, "madly" mixing BSC and MSC stuff. Split
- * this in e.g. struct osmo_bsc and struct osmo_msc, with the things
- * these have in common, like country and network code, put in yet
- * separate structs and placed as members in osmo_bsc and osmo_msc. */
+struct all_allocated {
+ struct osmo_time_cc sdcch;
+ struct osmo_time_cc static_sdcch;
+ struct osmo_time_cc tch;
+ struct osmo_time_cc static_tch;
+};
+
+struct bsc_sccp_inst {
+ struct osmo_sccp_instance *sccp; /* backpointer */
+ /* rbtree root of 'struct bscp_sccp_conn_node' in this instance, ordered by conn_id */
+ struct rb_root connections;
+ uint32_t next_id; /* next id to allocate */
+};
+
+struct bsc_sccp_inst *bsc_sccp_inst_alloc(void *ctx);
+uint32_t bsc_sccp_inst_next_conn_id(struct bsc_sccp_inst *bsc_sccp);
+int bsc_sccp_inst_register_gscon(struct bsc_sccp_inst *bsc_sccp, struct bscp_sccp_conn_node *sccp_conn);
+void bsc_sccp_inst_unregister_gscon(struct bsc_sccp_inst *bsc_sccp, struct bscp_sccp_conn_node *sccp_conn);
+struct gsm_subscriber_connection *bsc_sccp_inst_get_gscon_by_conn_id(const struct bsc_sccp_inst *bsc_sccp, uint32_t conn_id);
+struct gsm_network {
struct osmo_plmn_id plmn;
/* bit-mask of permitted encryption algorithms. LSB=A5/0, MSB=A5/7 */
@@ -1448,27 +969,46 @@ struct gsm_network {
struct osmo_timer_list congestion_check_timer;
} hodec2;
+ /* structures for keeping rate counters and gauge stats */
struct rate_ctr_group *bsc_ctrs;
+ struct osmo_stat_item_group *bsc_statg;
unsigned int num_bts;
struct llist_head bts_list;
struct llist_head bts_rejected;
- /* shall reference gsm_network_T[] */
- struct T_def *T_defs;
+ /* BTS-based counters when we can't find the actual BTS
+ * e.g. when conn->lchan is NULL */
+ struct rate_ctr_group *bts_unknown_ctrs;
+ struct osmo_stat_item_group *bts_unknown_statg;
+
+ /* see gsm_network_T_defs */
+ struct osmo_tdef *T_defs;
enum gsm_chan_t ctype_by_chreq[_NUM_CHREQ_T];
/* Use a TCH for handling requests of type paging any */
int pag_any_tch;
- /* MSC data in case we are a true BSC */
- struct osmo_bsc_data *bsc_data;
+ /* msc configuration */
+ struct llist_head mscs;
+ unsigned int mscs_round_robin_next_nr;
+ /* Emergency calls potentially select a different set of MSCs, so to not mess up the normal round-robin
+ * behavior, emergency calls need a separate round-robin counter. */
+ unsigned int mscs_round_robin_next_emerg_nr;
+
+ /* rf ctl related bits */
+ int mid_call_timeout;
+ char *rf_ctrl_name;
+ struct osmo_bsc_rf *rf_ctrl;
+ int auto_off_timeout;
+
+ struct bsc_cbc_link *cbc;
/* control interface */
struct ctrl_handle *ctrl;
- /* Allow or disallow TCH/F on dynamic TCH/F_TCH/H_PDCH; OS#1778 */
+ /* Allow or disallow TCH/F on dynamic TCH/F_TCH/H_SDCCH8_PDCH; OS#1778 */
bool dyn_ts_allow_tch_f;
/* all active subscriber connections. */
@@ -1481,24 +1021,55 @@ struct gsm_network {
* OsmoMSC, this should be tied to the location area code (LAC). */
struct gsm_tz tz;
- /* List of all struct bsc_subscr used in libbsc. This llist_head is
- * allocated so that the llist_head pointer itself can serve as a
- * talloc context (useful to not have to pass the entire gsm_network
- * struct to the bsc_subscr_* API, and for bsc_susbscr unit tests to
- * not require gsm_data.h). In an MSC-without-BSC environment, this
- * pointer is NULL to indicate absence of a bsc_subscribers list. */
- struct llist_head *bsc_subscribers;
+ /* Keeps track of struct bsc_subcr. */
+ struct bsc_subscr_store *bsc_subscribers;
/* Timer for periodic channel load measurements to maintain each BTS's T3122. */
struct osmo_timer_list t3122_chan_load_timer;
+ /* Timer to write each BTS's uptime counter state to the stats system. */
+ struct osmo_timer_list bts_store_uptime_timer;
+
+ /* Timer to write each BTS's set of lchan duration counters' state to the stats system. */
+ struct osmo_timer_list bts_store_lchan_durations_timer;
+
struct {
+ /* Single MGCP client configuration under msc node (also required for
+ * MGCP proxy when sccp-lite is used) */
struct mgcp_client_conf *conf;
- struct mgcp_client *client;
+
+ /* MGW pool, also includes the single MGCP client as fallback if no
+ * pool is configured. */
+ struct mgcp_client_pool *mgw_pool;
+
+ /* Timer definitions, the same for all MGW pool members */
+ struct osmo_tdef *tdefs;
} mgw;
- /* Remote BSS Cell Identifier Lists */
- struct neighbor_ident_list *neighbor_bss_cells;
+ /* Remote BSS resolution sevice (CTRL iface) */
+ struct {
+ char *addr;
+ uint16_t port;
+ struct ctrl_handle *handle;
+ } neigh_ctrl;
+
+ /* Don't refuse to start with mutually exclusive codec settings */
+ bool allow_unusable_timeslots;
+
+ struct bts_setup_ramp_net bts_setup_ramp;
+
+ uint8_t nri_bitlen;
+ struct osmo_nri_ranges *null_nri_ranges;
+
+ struct smlc_config *smlc;
+
+ struct chan_counts chan_counts;
+ struct all_allocated all_allocated;
+
+ /* PCU socket state */
+ char *pcu_sock_path;
+ unsigned int pcu_sock_wqueue_len_max;
+ struct pcu_sock_state *pcu_state;
};
struct gsm_audio_support {
@@ -1506,152 +1077,56 @@ struct gsm_audio_support {
ver : 7;
};
-static inline const struct osmo_location_area_id *bts_lai(struct gsm_bts *bts)
-{
- static struct osmo_location_area_id lai;
- lai = (struct osmo_location_area_id){
- .plmn = bts->network->plmn,
- .lac = bts->location_area_code,
- };
- return &lai;
-}
+int gsm_audio_support_cmp(const struct gsm_audio_support *a, const struct gsm_audio_support *b);
extern void talloc_ctx_init(void *ctx_root);
-int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
-
enum gsm_bts_type parse_btstype(const char *arg);
const char *btstype2str(enum gsm_bts_type type);
struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac,
struct gsm_bts *start_bts);
extern void *tall_bsc_ctx;
-extern int ipacc_rtp_direct;
-
-/* this actaully refers to the IPA transport, not the BTS model */
-static inline int is_ipaccess_bts(struct gsm_bts *bts)
-{
- switch (bts->type) {
- case GSM_BTS_TYPE_NANOBTS:
- case GSM_BTS_TYPE_OSMOBTS:
- return 1;
- default:
- break;
- }
- return 0;
-}
-
-static inline int is_sysmobts_v2(struct gsm_bts *bts)
-{
- switch (bts->type) {
- case GSM_BTS_TYPE_OSMOBTS:
- return 1;
- default:
- break;
- }
- return 0;
-}
-
-static inline int is_siemens_bts(struct gsm_bts *bts)
-{
- switch (bts->type) {
- case GSM_BTS_TYPE_BS11:
- return 1;
- default:
- break;
- }
-
- return 0;
-}
-
-static inline int is_nokia_bts(struct gsm_bts *bts)
-{
- switch (bts->type) {
- case GSM_BTS_TYPE_NOKIA_SITE:
- return 1;
- default:
- break;
- }
-
- return 0;
-}
-
-static inline int is_e1_bts(struct gsm_bts *bts)
-{
- switch (bts->type) {
- case GSM_BTS_TYPE_BS11:
- case GSM_BTS_TYPE_RBS2000:
- case GSM_BTS_TYPE_NOKIA_SITE:
- return 1;
- default:
- break;
- }
-
- return 0;
-}
extern struct gsm_network *bsc_gsmnet;
enum bts_gprs_mode bts_gprs_mode_parse(const char *arg, int *valid);
const char *bts_gprs_mode_name(enum bts_gprs_mode mode);
-int bts_gprs_mode_is_compat(struct gsm_bts *bts, enum bts_gprs_mode mode);
void gsm48_ra_id_by_bts(struct gsm48_ra_id *buf, struct gsm_bts *bts);
void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts);
-int gsm_bts_model_register(struct gsm_bts_model *model);
-
struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *network);
-struct gsm_subscriber_connection *msc_subscr_con_allocate(struct gsm_network *network);
-void msc_subscr_con_free(struct gsm_subscriber_connection *conn);
-
struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_type type, uint8_t bsic);
struct gsm_bts *bsc_bts_alloc_register(struct gsm_network *net, enum gsm_bts_type type, uint8_t bsic);
void set_ts_e1link(struct gsm_bts_trx_ts *ts, uint8_t e1_nr,
uint8_t e1_ts, uint8_t e1_ts_ss);
-void gsm_trx_lock_rf(struct gsm_bts_trx *trx, bool locked, const char *reason);
-struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr);
-int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx);
-int gsm_bts_set_system_infos(struct gsm_bts *bts);
-
/* generic E1 line operations for all ISDN-based BTS. */
extern struct e1inp_line_ops bts_isdn_e1inp_line_ops;
-extern const struct value_string bts_type_names[_NUM_GSM_BTS_TYPE+1];
-extern const struct value_string bts_type_descs[_NUM_GSM_BTS_TYPE+1];
-
-char *get_model_oml_status(const struct gsm_bts *bts);
-
-unsigned long long bts_uptime(const struct gsm_bts *bts);
-
-/* control interface handling */
-int bsc_base_ctrl_cmds_install(void);
-
-/* dependency handling */
-void bts_depend_mark(struct gsm_bts *bts, int dep);
-void bts_depend_clear(struct gsm_bts *bts, int dep);
-int bts_depend_check(struct gsm_bts *bts);
-int bts_depend_is_depedency(struct gsm_bts *base, struct gsm_bts *other);
-
-int gsm_bts_get_radio_link_timeout(const struct gsm_bts *bts);
-void gsm_bts_set_radio_link_timeout(struct gsm_bts *bts, int value);
-
-bool classmark_is_r99(struct gsm_classmark *cm);
-
-bool trx_is_usable(const struct gsm_bts_trx *trx);
bool ts_is_usable(const struct gsm_bts_trx_ts *ts);
int gsm_lchan_type_by_pchan(enum gsm_phys_chan_config pchan);
enum gsm_phys_chan_config gsm_pchan_by_lchan_type(enum gsm_chan_t type);
-void gsm_bts_all_ts_dispatch(struct gsm_bts *bts, uint32_t ts_ev, void *data);
-void gsm_trx_all_ts_dispatch(struct gsm_bts_trx *trx, uint32_t ts_ev, void *data);
+enum gsm48_rr_cause bsc_gsm48_rr_cause_from_gsm0808_cause(enum gsm0808_cause c);
+enum gsm48_rr_cause bsc_gsm48_rr_cause_from_rsl_cause(uint8_t c);
+
+/* Interference Measurement Parameters */
+struct gsm_interf_meas_params {
+ /* Intave: Interference Averaging period (see 3GPP TS 45.008, table A.1) */
+ uint8_t avg_period; /* number of SACCH multiframes, 1 .. 31 */
+ /* Interference level Boundaries (see 3GPP TS 52.021, section 9.4.25) */
+ uint8_t bounds_dbm[6]; /* -x dBm values for boundaries 0 .. X5 */
+};
+
+extern const struct gsm_interf_meas_params interf_meas_params_def;
-int bts_count_free_ts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan);
+enum rsl_cmod_spd chan_mode_to_rsl_cmod_spd(enum gsm48_chan_mode chan_mode);
-struct osmo_cell_global_id *cgi_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts);
+int select_best_cipher(uint8_t msc_mask, uint8_t bsc_mask);
#endif /* _GSM_DATA_H */
diff --git a/include/osmocom/bsc/gsm_timers.h b/include/osmocom/bsc/gsm_timers.h
deleted file mode 100644
index 699c461ad..000000000
--- a/include/osmocom/bsc/gsm_timers.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* API to define Tnnn timers globally, configure in VTY and use for FSM state changes. */
-#pragma once
-
-#include <stdint.h>
-#include <osmocom/core/utils.h>
-
-struct osmo_fsm_inst;
-struct vty;
-
-enum T_unit {
- T_S = 0, /*< most T are in seconds, keep 0 as default. */
- T_MS, /*< milliseconds */
- T_M, /*< minutes */
- T_CUSTOM,
-};
-
-extern const struct value_string T_unit_names[];
-static inline const char *T_unit_name(enum T_unit val)
-{ return get_value_string(T_unit_names, val); }
-
-/* Define a GSM timer of the form Tnnn, with unit, default value and doc string. */
-struct T_def {
- const int T; /*< T1234 number */
- const int default_val; /*< timeout duration (according to unit), default value. */
- const enum T_unit unit;
- const char *desc;
- int val; /*< currently active value, e.g. set by user config. */
-};
-
-/* Iterate an array of struct T_def, the last item should be fully zero, i.e. "{}" */
-#define for_each_T_def(d, T_defs) \
- for (d = T_defs; d && (d->T || d->default_val || d->desc); d++)
-
-int T_def_get(const struct T_def *T_defs, int T, enum T_unit as_unit, int val_if_not_present);
-void T_defs_reset(struct T_def *T_defs);
-struct T_def *T_def_get_entry(struct T_def *T_defs, int T);
-
-void T_defs_vty_init(struct T_def *T_defs, int cfg_parent_node);
-void T_defs_vty_write(struct vty *vty, const char *indent);
-struct T_def *parse_T_arg(struct vty *vty, const char *T_str);
-
-struct state_timeout {
- int T;
- bool keep_timer;
-};
-
-const struct state_timeout *get_state_timeout(uint32_t state,
- const struct state_timeout *timeouts_array);
-
-#define fsm_inst_state_chg_T(fi, state, timeouts_array, T_defs, default_timeout) \
- _fsm_inst_state_chg_T(fi, state, timeouts_array, T_defs, default_timeout, \
- __FILE__, __LINE__)
-int _fsm_inst_state_chg_T(struct osmo_fsm_inst *fi, uint32_t state,
- const struct state_timeout *timeouts_array,
- const struct T_def *T_defs, int default_timeout,
- const char *file, int line);
diff --git a/include/osmocom/bsc/handover.h b/include/osmocom/bsc/handover.h
index 322913da4..58fea353e 100644
--- a/include/osmocom/bsc/handover.h
+++ b/include/osmocom/bsc/handover.h
@@ -10,11 +10,20 @@
#include <osmocom/bsc/neighbor_ident.h>
#include <osmocom/bsc/gsm_data.h>
+#define LOG_HO(conn, level, fmt, args...) do { \
+ if (conn->ho.fi) \
+ LOGPFSML(conn->ho.fi, level, "%s: " fmt, \
+ handover_status(conn), ## args); \
+ else \
+ LOGP(DHODEC, level, "%s: " fmt, \
+ handover_status(conn), ## args); \
+ } while (0)
+
struct gsm_network;
struct gsm_lchan;
struct gsm_bts;
struct gsm_subscriber_connection;
-struct gsm_meas_rep mr;
+struct gsm_meas_rep;
enum handover_result {
HO_RESULT_OK,
@@ -25,6 +34,8 @@ enum handover_result {
HO_RESULT_ERROR,
};
+const char *handover_status(struct gsm_subscriber_connection *conn);
+
extern const struct value_string handover_result_names[];
inline static const char *handover_result_name(enum handover_result val)
{ return get_value_string(handover_result_names, val); }
@@ -70,9 +81,11 @@ enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection
struct gsm_lchan *lchan);
void bsc_tx_bssmap_ho_failure(struct gsm_subscriber_connection *conn);
-struct gsm_bts *bts_by_neighbor_ident(const struct gsm_network *net,
- const struct neighbor_ident_key *search_for);
-struct neighbor_ident_key *bts_ident_key(const struct gsm_bts *bts);
+int find_handover_target_cell(struct gsm_bts **local_target_cell_p,
+ struct gsm0808_cell_id_list2 *remote_target_cells,
+ struct gsm_subscriber_connection *conn,
+ const struct cell_ab *search_for,
+ bool log_errors);
void handover_parse_inter_bsc_mt(struct gsm_subscriber_connection *conn,
struct msgb *ho_request_msg);
diff --git a/include/osmocom/bsc/handover_cfg.h b/include/osmocom/bsc/handover_cfg.h
index 92b5cd44c..7d68e6317 100644
--- a/include/osmocom/bsc/handover_cfg.h
+++ b/include/osmocom/bsc/handover_cfg.h
@@ -38,22 +38,10 @@ static inline int bool2i(bool arg)
return arg? 1 : 0;
}
-static inline bool a2tdma(const char *arg)
-{
- if (!strcmp(arg, "full"))
- return true;
- return false;
-}
-
-static inline const char *tdma2a(bool val)
-{
- return val? "full" : "subset";
-}
-
/* The HO_CFG_ONE_MEMBER macro gets redefined, depending on whether to define struct members,
* function declarations or definitions... It is of the format
* HO_CFG_ONE_MEMBER(TYPE, NAME, DEFAULT_VAL,
- * VTY_CMD, VTY_CMD_ARG, VTY_ARG_EVAL,
+ * VTY_CMD_PREFIX, VTY_CMD, VTY_CMD_ARG, VTY_ARG_EVAL,
* VTY_WRITE_FMT, VTY_WRITE_CONV,
* VTY_DOC)
* Then using HO_CFG_ALL_MEMBERS can save a lot of code dup in defining API declaration, API
@@ -96,22 +84,22 @@ static inline const char *tdma2a(bool val)
"handover1 ", "window rxlev averaging", "<1-10>", atoi, "%u", as_is, \
HO_CFG_STR_HANDOVER1 \
HO_CFG_STR_WIN_RXLEV \
- "How many RxLev measurements are used for averaging\n" \
+ "How many RxLev measurements to use for averaging\n" \
"RxLev averaging: " HO_CFG_STR_AVG_COUNT) \
\
HO_CFG_ONE_MEMBER(unsigned int, hodec1_rxqual_avg_win, 1, \
"handover1 ", "window rxqual averaging", "<1-10>", atoi, "%u", as_is, \
HO_CFG_STR_HANDOVER1 \
HO_CFG_STR_WIN_RXQUAL \
- "How many RxQual measurements are used for averaging\n" \
+ "How many RxQual measurements to use for averaging\n" \
"RxQual averaging: " HO_CFG_STR_AVG_COUNT) \
\
HO_CFG_ONE_MEMBER(unsigned int, hodec1_rxlev_neigh_avg_win, 10, \
"handover1 ", "window rxlev neighbor averaging", "<1-10>", atoi, "%u", as_is, \
HO_CFG_STR_HANDOVER1 \
HO_CFG_STR_WIN_RXLEV \
- "How many Neighbor RxLev measurements are used for averaging\n" \
- "How many Neighbor RxLev measurements are used for averaging\n" \
+ "How many Neighbor RxLev measurements to use for averaging\n" \
+ "How many Neighbor RxLev measurements to use for averaging\n" \
"Neighbor RxLev averaging: " HO_CFG_STR_AVG_COUNT) \
\
HO_CFG_ONE_MEMBER(unsigned int, hodec1_pwr_interval, 6, \
@@ -142,22 +130,22 @@ static inline const char *tdma2a(bool val)
"handover2 ", "window rxlev averaging", "<1-10>", atoi, "%u", as_is, \
HO_CFG_STR_HANDOVER2 \
HO_CFG_STR_WIN_RXLEV \
- "How many RxLev measurements are used for averaging\n" \
+ "How many RxLev measurements to use for averaging\n" \
"RxLev averaging: " HO_CFG_STR_AVG_COUNT) \
\
HO_CFG_ONE_MEMBER(unsigned int, hodec2_rxqual_avg_win, 1, \
"handover2 ", "window rxqual averaging", "<1-10>", atoi, "%u", as_is, \
HO_CFG_STR_HANDOVER2 \
HO_CFG_STR_WIN_RXQUAL \
- "How many RxQual measurements are used for averaging\n" \
+ "How many RxQual measurements to use for averaging\n" \
"RxQual averaging: " HO_CFG_STR_AVG_COUNT) \
\
HO_CFG_ONE_MEMBER(unsigned int, hodec2_rxlev_neigh_avg_win, 10, \
"handover2 ", "window rxlev neighbor averaging", "<1-10>", atoi, "%u", as_is, \
HO_CFG_STR_HANDOVER2 \
HO_CFG_STR_WIN_RXLEV \
- "How many Neighbor RxLev measurements are used for averaging\n" \
- "How many Neighbor RxLev measurements are used for averaging\n" \
+ "How many Neighbor RxLev measurements to use for averaging\n" \
+ "How many Neighbor RxLev measurements to use for averaging\n" \
"Neighbor RxLev averaging: " HO_CFG_STR_AVG_COUNT) \
\
HO_CFG_ONE_MEMBER(unsigned int, hodec2_pwr_interval, 6, \
@@ -184,14 +172,17 @@ static inline const char *tdma2a(bool val)
HO_CFG_ONE_MEMBER(bool, hodec2_as_active, 0, \
"handover2 ", "assignment", "0|1", a2bool, "%d", bool2i, \
HO_CFG_STR_HANDOVER2 \
- "Enable or disable in-call channel re-assignment\n" \
+ "Enable or disable in-call channel re-assignment within the same cell\n" \
"Disable in-call assignment\n" \
"Enable in-call assignment\n") \
\
- HO_CFG_ONE_MEMBER(bool, hodec2_full_tdma, subset, \
- "handover2 ", "tdma-measurement", "full|subset", a2tdma, "%s", tdma2a, \
+ HO_CFG_ONE_MEMBER(enum tdma_meas_set, hodec2_tdma_meas_set, subset, \
+ "handover2 ", "tdma-measurement", "auto|full|subset", \
+ tdma_meas_set_from_str, "%s", tdma_meas_set_name, \
HO_CFG_STR_HANDOVER2 \
"Define measurement set of TDMA frames\n" \
+ "Use full set when DTX is not in use, use subset when DTX is in use," \
+ " as indicated by each Measurement Report\n" \
"Full set of 102/104 TDMA frames\n" \
"Sub set of 4 TDMA frames (SACCH)\n") \
\
@@ -200,14 +191,17 @@ static inline const char *tdma2a(bool val)
HO_CFG_STR_HANDOVER2 \
HO_CFG_STR_MIN \
"How weak may RxLev of an MS become before triggering HO\n" \
- "minimum RxLev (dBm)\n") \
+ "minimum RxLev (dBm; note: negative values)\n") \
\
HO_CFG_ONE_MEMBER(int, hodec2_min_rxqual, 5, \
"handover2 ", "min rxqual", "<0-7>", atoi, "%d", as_is, \
HO_CFG_STR_HANDOVER2 \
HO_CFG_STR_MIN \
- "How bad may RxQual of an MS become before triggering HO\n" \
- "minimum RxQual\n") \
+ "How bad may RxQual of an MS become before triggering HO," \
+ " where 0 is the best quality (bit error rate < 0.2%) and" \
+ " 7 is the worst quality (bit error rate > 12.8%)," \
+ " see 3GPP TS 45.008 8.2.4.\n" \
+ "worst acceptable RxQual\n") \
\
HO_CFG_ONE_MEMBER(int, hodec2_afs_bias_rxlev, 0, \
"handover2 ", "afs-bias rxlev", "<0-20>", atoi, "%d", as_is, \
@@ -247,27 +241,44 @@ static inline const char *tdma2a(bool val)
"handover2 ", "penalty-time max-distance", "<0-99999>", atoi, "%d", as_is, \
HO_CFG_STR_HANDOVER2 \
HO_CFG_STR_PENALTY_TIME \
- "Time to suspend handovers after leaving this cell due to exceeding max distance\n" \
+ "Time to suspend handover for a subscriber after leaving this cell due to exceeding max distance;" \
+ " see also 'handover2 retries'\n" \
"Seconds\n") \
\
HO_CFG_ONE_MEMBER(int, hodec2_penalty_failed_ho, 60, \
"handover2 ", "penalty-time failed-ho", "<0-99999>", atoi, "%d", as_is, \
HO_CFG_STR_HANDOVER2 \
HO_CFG_STR_PENALTY_TIME \
- "Time to suspend handovers after handover failure to this cell\n" \
+ "Time to suspend handover for a subscriber after a failed handover into this cell;" \
+ " see also 'handover2 retries'\n" \
"Seconds\n") \
\
HO_CFG_ONE_MEMBER(int, hodec2_penalty_failed_as, 60, \
"handover2 ", "penalty-time failed-assignment", "<0-99999>", atoi, "%d", as_is, \
HO_CFG_STR_HANDOVER2 \
HO_CFG_STR_PENALTY_TIME \
- "Time to suspend handovers after assignment failure in this cell\n" \
+ "Time to suspend handover for a subscriber after a failed re-assignment within this cell;" \
+ " see also 'handover2 retries'\n" \
+ "Seconds\n") \
+ \
+ HO_CFG_ONE_MEMBER(int, hodec2_penalty_low_rxqual_as, 60, \
+ "handover2 ", "penalty-time low-rxqual-assignment", "<0-99999>", atoi, "%d", as_is, \
+ HO_CFG_STR_HANDOVER2 \
+ HO_CFG_STR_PENALTY_TIME \
+ "Time to suspend re-assignment after an lchan was re-assigned because of low RxQual\n" \
+ "Seconds\n") \
+ \
+ HO_CFG_ONE_MEMBER(int, hodec2_penalty_low_rxqual_ho, 60, \
+ "handover2 ", "penalty-time low-rxqual-ho", "<0-99999>", atoi, "%d", as_is, \
+ HO_CFG_STR_HANDOVER2 \
+ HO_CFG_STR_PENALTY_TIME \
+ "Time to suspend handover back to a cell after bad RxQual caused handover away from it\n" \
"Seconds\n") \
\
HO_CFG_ONE_MEMBER(int, hodec2_retries, 0, \
"handover2 ", "retries", "<0-9>", atoi, "%d", as_is, \
HO_CFG_STR_HANDOVER2 \
- "Immediately retry on handover/assignment failure\n" \
+ "Number of times to immediately retry a failed handover/assignment, before a penalty time is applied\n" \
"Number of retries\n") \
#define HO_CFG_ALL_MEMBERS \
diff --git a/include/osmocom/bsc/handover_ctrl.h b/include/osmocom/bsc/handover_ctrl.h
new file mode 100644
index 000000000..c0bd70c19
--- /dev/null
+++ b/include/osmocom/bsc/handover_ctrl.h
@@ -0,0 +1,3 @@
+#pragma once
+
+int bsc_ho_ctrl_cmds_install(void *ctx);
diff --git a/include/osmocom/bsc/handover_fsm.h b/include/osmocom/bsc/handover_fsm.h
index 4db08901d..03a8436ad 100644
--- a/include/osmocom/bsc/handover_fsm.h
+++ b/include/osmocom/bsc/handover_fsm.h
@@ -4,18 +4,6 @@
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/handover.h>
-const char *handover_status(struct gsm_subscriber_connection *conn);
-
-/* This macro automatically includes a final \n, if omitted. */
-#define LOG_HO(conn, level, fmt, args...) do { \
- if (conn->ho.fi) \
- LOGPFSML(conn->ho.fi, level, "%s: " fmt, \
- handover_status(conn), ## args); \
- else \
- LOGP(DHODEC, level, "%s: " fmt, \
- handover_status(conn), ## args); \
- } while(0)
-
/* Terminology:
* Intra-Cell: stays within one BTS, this should actually be an Assignment.
* Intra-BSC: stays within one BSC, but moves between BTSes.
@@ -28,10 +16,10 @@ enum handover_fsm_state {
HO_ST_NOT_STARTED,
HO_ST_WAIT_LCHAN_ACTIVE,
+ HO_ST_WAIT_MGW_ENDPOINT_TO_MSC,
HO_ST_WAIT_RR_HO_DETECT,
HO_ST_WAIT_RR_HO_COMPLETE,
HO_ST_WAIT_LCHAN_ESTABLISHED,
- HO_ST_WAIT_MGW_ENDPOINT_TO_MSC,
/* The inter-BSC Outgoing Handover FSM has completely separate states, but since it makes sense for it
* to also live in conn->ho.fi, it should share the same event enum. From there it is merely
@@ -46,11 +34,11 @@ enum handover_fsm_event {
HO_EV_LCHAN_ACTIVE,
HO_EV_LCHAN_ESTABLISHED,
HO_EV_LCHAN_ERROR,
+ HO_EV_MSC_MGW_OK,
+ HO_EV_MSC_MGW_FAIL,
HO_EV_RR_HO_DETECT,
HO_EV_RR_HO_COMPLETE,
HO_EV_RR_HO_FAIL,
- HO_EV_MSC_MGW_OK,
- HO_EV_MSC_MGW_FAIL,
HO_EV_CONN_RELEASING,
HO_OUT_EV_BSSMAP_HO_COMMAND,
@@ -67,9 +55,7 @@ struct handover_rr_detect_data {
const uint8_t *access_delay;
};
-void handover_fsm_init();
-
-void handover_request(struct handover_out_req *req);
+int handover_request(struct handover_out_req *req);
void handover_start(struct handover_out_req *req);
void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn,
struct msgb *ho_request_msg);
diff --git a/include/osmocom/bsc/handover_vty.h b/include/osmocom/bsc/handover_vty.h
index 6ad5276e2..1dd8bf08a 100644
--- a/include/osmocom/bsc/handover_vty.h
+++ b/include/osmocom/bsc/handover_vty.h
@@ -3,6 +3,6 @@
#include <osmocom/vty/vty.h>
#include <osmocom/bsc/handover_cfg.h>
-void ho_vty_init();
+void ho_vty_init(void);
void ho_vty_write_net(struct vty *vty, struct gsm_network *net);
void ho_vty_write_bts(struct vty *vty, struct gsm_bts *bts);
diff --git a/include/osmocom/bsc/ipaccess.h b/include/osmocom/bsc/ipaccess.h
index 692e79576..3853270ac 100644
--- a/include/osmocom/bsc/ipaccess.h
+++ b/include/osmocom/bsc/ipaccess.h
@@ -30,9 +30,9 @@ struct ipac_ext_lac_cmd {
uint8_t data[0];
} __attribute__((packed));
-void ipaccess_drop_oml(struct gsm_bts *bts);
+void ipaccess_drop_oml(struct gsm_bts *bts, const char *reason);
void ipaccess_drop_oml_deferred(struct gsm_bts *bts);
-void ipaccess_drop_rsl(struct gsm_bts_trx *trx);
+void ipaccess_drop_rsl(struct gsm_bts_trx *trx, const char *reason);
struct sdp_header_item {
struct sdp_header_entry header_entry;
diff --git a/include/osmocom/bsc/lb.h b/include/osmocom/bsc/lb.h
new file mode 100644
index 000000000..08206d4d8
--- /dev/null
+++ b/include/osmocom/bsc/lb.h
@@ -0,0 +1,63 @@
+/* Location Services (LCS): low level Lb/SCCP handling in OsmoBSC, API */
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <osmocom/core/rate_ctr.h>
+#include <osmocom/sigtran/sccp_sap.h>
+
+struct bssap_le_pdu;
+struct gsm_subscriber_connection;
+
+enum {
+ SMLC_CTR_BSSMAP_LE_RX_UNKNOWN_PEER,
+ SMLC_CTR_BSSMAP_LE_RX_UDT_RESET,
+ SMLC_CTR_BSSMAP_LE_RX_UDT_RESET_ACK,
+ SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG,
+ SMLC_CTR_BSSMAP_LE_RX_DT1_ERR_INVALID_MSG,
+ SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS,
+ SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE,
+ SMLC_CTR_BSSMAP_LE_RX_DT1_BSSLAP_TA_REQUEST,
+
+ SMLC_CTR_BSSMAP_LE_TX_ERR_INVALID_MSG,
+ SMLC_CTR_BSSMAP_LE_TX_ERR_CONN_NOT_READY,
+ SMLC_CTR_BSSMAP_LE_TX_ERR_SEND,
+ SMLC_CTR_BSSMAP_LE_TX_SUCCESS,
+
+ SMLC_CTR_BSSMAP_LE_TX_UDT_RESET,
+ SMLC_CTR_BSSMAP_LE_TX_UDT_RESET_ACK,
+ SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_REQUEST,
+ SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_ABORT,
+ SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_TA_RESPONSE,
+ SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_REJECT,
+ SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_RESET,
+ SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_ABORT,
+};
+
+struct smlc_config {
+ bool enable;
+
+ uint32_t cs7_instance;
+ bool cs7_instance_valid;
+ struct osmo_sccp_instance *sccp;
+ struct osmo_sccp_user *sccp_user;
+
+ struct osmo_sccp_addr bsc_addr;
+ char *bsc_addr_name;
+
+ struct osmo_sccp_addr smlc_addr;
+ char *smlc_addr_name;
+
+ /*! Lb link is ready when bssmap_reset_is_conn_ready(bssmap_reset) returns true. */
+ struct bssmap_reset *bssmap_reset;
+
+ struct rate_ctr_group *ctrs;
+};
+
+extern const struct rate_ctr_desc smlc_ctr_description[];
+extern const struct rate_ctr_group_desc smlc_ctrg_desc;
+
+int lb_init(void);
+int lb_start_or_stop(void);
+int lb_send(struct gsm_subscriber_connection *conn, const struct bssap_le_pdu *bssap_le);
+void lb_close_conn(struct gsm_subscriber_connection *conn);
diff --git a/include/osmocom/bsc/lchan.h b/include/osmocom/bsc/lchan.h
new file mode 100644
index 000000000..c0c57615d
--- /dev/null
+++ b/include/osmocom/bsc/lchan.h
@@ -0,0 +1,393 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <osmocom/core/utils.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/gsm/gsm23003.h>
+
+#include <osmocom/bsc/meas_rep.h>
+
+/* If .present is false, use the default value defined elsewhere. If true, use .val below.
+ * (A practical benefit of this is that the default initialization sets .present to false, so that even if a .val == 0
+ * is a valid value, a struct containing this as member does not need to explicitly set .val = INVALID_VAL_CONSTANT.) */
+struct optional_val {
+ bool present;
+ int val;
+};
+
+/* Maximum number of neighbor cells whose average we track */
+#define MAX_NEIGH_MEAS 10
+/* Maximum size of the averaging window for neighbor cells */
+#define MAX_WIN_NEIGH_AVG 10
+/* Maximum number of report history we store */
+#define MAX_MEAS_REP 10
+
+/* processed neighbor measurements for one cell */
+struct neigh_meas_proc {
+ uint16_t arfcn;
+ uint8_t bsic;
+ uint8_t rxlev[MAX_WIN_NEIGH_AVG];
+ unsigned int rxlev_cnt;
+ uint8_t last_seen_nr;
+};
+
+enum channel_rate {
+ CH_RATE_SDCCH,
+ CH_RATE_HALF,
+ CH_RATE_FULL,
+};
+
+enum channel_rate chan_t_to_chan_rate(enum gsm_chan_t chan_t);
+
+struct channel_mode_and_rate {
+ enum gsm48_chan_mode chan_mode;
+ enum channel_rate chan_rate;
+ uint16_t s15_s0;
+ /* only used for GSM48_CMODE_DATA_* */
+ bool data_transparent;
+ union {
+ enum rsl_cmod_csd_t t;
+ enum rsl_cmod_csd_nt nt;
+ } data_rate;
+};
+
+/* Channel Request reason */
+enum gsm_chreq_reason_t {
+ GSM_CHREQ_REASON_EMERG,
+ GSM_CHREQ_REASON_PAG,
+ GSM_CHREQ_REASON_CALL,
+ GSM_CHREQ_REASON_LOCATION_UPD,
+ GSM_CHREQ_REASON_OTHER,
+ GSM_CHREQ_REASON_PDCH,
+};
+
+static inline bool gsm_chreq_reason_is_voicecall(enum gsm_chreq_reason_t reason)
+{
+ return reason == GSM_CHREQ_REASON_EMERG || reason == GSM_CHREQ_REASON_CALL;
+}
+
+/* State of the SAPIs in the lchan */
+enum lchan_sapi_state {
+ LCHAN_SAPI_S_NONE,
+ LCHAN_SAPI_S_REQ,
+ LCHAN_SAPI_S_ASSIGNED,
+ LCHAN_SAPI_S_REL,
+ LCHAN_SAPI_S_ERROR,
+};
+
+/* is the data link established? who established it? */
+#define LCHAN_SAPI_UNUSED 0
+#define LCHAN_SAPI_MS 1
+#define LCHAN_SAPI_NET 2
+
+#define MAX_A5_KEY_LEN (128/8)
+
+struct gsm_encr {
+ uint8_t alg_a5_n; /* N: 0 (A5/0), 1 (A5/1), ... 7 (A5/7) */
+ uint8_t key_len;
+ uint8_t key[MAX_A5_KEY_LEN];
+ bool kc128_present;
+ uint8_t kc128[16];
+};
+
+enum lchan_activate_for {
+ ACTIVATE_FOR_NONE,
+ ACTIVATE_FOR_MS_CHANNEL_REQUEST,
+ ACTIVATE_FOR_ASSIGNMENT,
+ ACTIVATE_FOR_HANDOVER,
+ ACTIVATE_FOR_VGCS_CHANNEL,
+ ACTIVATE_FOR_VTY,
+ ACTIVATE_FOR_MODE_MODIFY_RTP,
+};
+
+enum lchan_type_for {
+ LCHAN_TYPE_FOR_NORMAL = 0,
+ LCHAN_TYPE_FOR_VAMOS,
+ LCHAN_TYPE_FOR_VGCS,
+ LCHAN_TYPE_FOR_VBS,
+};
+
+extern const struct value_string lchan_activate_mode_names[];
+static inline const char *lchan_activate_mode_name(enum lchan_activate_for activ_for)
+{ return get_value_string(lchan_activate_mode_names, activ_for); }
+
+enum imm_ass_time {
+ IMM_ASS_TIME_POST_CHAN_ACK = 0,
+ IMM_ASS_TIME_PRE_CHAN_ACK,
+ IMM_ASS_TIME_PRE_TS_ACK,
+};
+
+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;
+ enum gsm0808_chan_indicator ch_indctr;
+ bool wait_before_switching_rtp; /*< true = requires LCHAN_EV_READY_TO_SWITCH_RTP */
+ uint16_t msc_assigned_cic;
+ /* During intra-BSC handover, we keep the MGW endpoint intact and just re-route to the new lchan. This
+ * activate_info is for the new lchan, the re_use_mgw_endpoint_from_lchan points at the old lchan. */
+ struct gsm_lchan *re_use_mgw_endpoint_from_lchan;
+ bool ta_known;
+ uint8_t ta;
+
+ /* The TSC Set to use if 'use' is true, otherwise automatically determine the TSC Set value to use. Valid range
+ * is 1 to 4, as described in 3GPP TS 45.002. */
+ struct optional_val tsc_set;
+ /* The TSC to use if 'use' is true, otherwise automatically determine the TSC value to use. Valid range is 0 to
+ * 7, as described in 3GPP TS 45.002. */
+ struct optional_val tsc;
+
+ enum lchan_type_for type_for;
+
+ /* A copy of bts->imm_ass_time at the time where Channel Activation was requested. A change in the VTY
+ * configuration has immediate effect on the value, so make sure we don't get mixed up when it gets changed
+ * while a channel activation is in progress. */
+ enum imm_ass_time imm_ass_time;
+};
+
+enum lchan_modify_for {
+ MODIFY_FOR_NONE,
+ MODIFY_FOR_ASSIGNMENT,
+ MODIFY_FOR_VTY,
+};
+
+extern const struct value_string lchan_modify_for_names[];
+static inline const char *lchan_modify_for_name(enum lchan_modify_for modify_for)
+{ return get_value_string(lchan_modify_for_names, modify_for); }
+
+struct lchan_modify_info {
+ enum lchan_modify_for modify_for;
+ struct channel_mode_and_rate ch_mode_rate;
+ enum gsm0808_chan_indicator ch_indctr;
+ uint16_t msc_assigned_cic;
+
+ /* The TSC Set to use if 'use' is true, otherwise automatically determine the TSC Set value to use. Valid range
+ * is 1 to 4, as described in 3GPP TS 45.002. */
+ struct optional_val tsc_set;
+ /* The TSC to use if 'use' is true, otherwise automatically determine the TSC value to use. Valid range is 0 to
+ * 7, as described in 3GPP TS 45.002. */
+ struct optional_val tsc;
+
+ enum lchan_type_for type_for;
+};
+
+/* Measurement pre-processing state */
+struct gsm_power_ctrl_meas_proc_state {
+ /* Number of measurements processed */
+ unsigned int meas_num;
+ /* Algorithm specific data */
+ union {
+ struct {
+ /* Scaled up 100 times average value */
+ int Avg100;
+ } ewma;
+ };
+};
+
+struct lchan_power_ctrl_state {
+ /* Measurement pre-processing state (for dynamic mode) */
+ struct gsm_power_ctrl_meas_proc_state rxlev_meas_proc;
+ struct gsm_power_ctrl_meas_proc_state rxqual_meas_proc;
+ /* Number of SACCH blocks to skip (for dynamic mode) */
+ int skip_block_num;
+};
+
+struct gsm_lchan {
+ /* The TS that we're part of */
+ struct gsm_bts_trx_ts *ts;
+ /* The logical subslot number in the TS */
+ uint8_t nr;
+ char *name;
+
+ char *last_error;
+
+ struct osmo_fsm_inst *fi;
+ struct osmo_fsm_inst *fi_rtp;
+ struct osmo_mgcpc_ep_ci *mgw_endpoint_ci_bts;
+
+ struct {
+ /* The request as made by the caller, see lchan_activate().
+ * lchan->activate.info is treated immutable: remains unchanged throughout the Activation.
+ * The mutable versions are below: some values need automatic adjustments, in which case they are copied
+ * from immutable lchan->activate.info.* to lchan->activate.*, for example lchan->activate.ch_mode_rate
+ * is initially a copy of lchan->activate.info.ch_mode_rate, and is possibly adjusted afterwards. */
+ struct lchan_activate_info info;
+
+ struct channel_mode_and_rate ch_mode_rate;
+ struct gsm48_multi_rate_conf mr_conf_filtered;
+ enum gsm0808_chan_indicator ch_indctr;
+ bool activ_ack; /*< true as soon as RSL Chan Activ Ack is received */
+ bool immediate_assignment_sent;
+ /*! This flag ensures that when an lchan activation has succeeded, and we have already
+ * sent ACKs like Immediate Assignment or BSSMAP Assignment Complete, and if other errors
+ * occur later, e.g. during release, that we don't send a NACK out of context. */
+ bool concluded;
+ enum gsm0808_cause gsm0808_error_cause;
+ /* Actually used TSC Set. */
+ int tsc_set;
+ /* Actually used TSC. */
+ uint8_t tsc;
+ } activate;
+
+ struct {
+ /* The request as made by the caller, see lchan_mode_modify().
+ * lchan->modify.info is treated immutable: remains unchanged throughout the Mode Modify.
+ * The mutable versions are below: some values need automatic adjustments, in which case they are copied
+ * from immutable lchan->modify.info.* to lchan->modify.*, for example lchan->modify.ch_mode_rate
+ * is initially a copy of lchan->modify.info.ch_mode_rate, and is possibly adjusted afterwards. */
+ struct lchan_modify_info info;
+
+ struct channel_mode_and_rate ch_mode_rate;
+ struct gsm48_multi_rate_conf mr_conf_filtered;
+ enum gsm0808_chan_indicator ch_indctr;
+ /* Actually used TSC Set. */
+ int tsc_set;
+ /* Actually used TSC. */
+ uint8_t tsc;
+ bool concluded;
+ } modify;
+
+ struct {
+ /* If an event to release the lchan comes in while still waiting for responses, just mark this
+ * flag, so that the lchan will gracefully release at the next sensible junction. */
+ bool requested;
+ bool do_rr_release;
+ enum gsm48_rr_cause rr_cause;
+ bool last_eutran_plmn_valid;
+ struct osmo_plmn_id last_eutran_plmn;
+
+ /* There is an RSL error cause of value 0, so we need a separate flag. */
+ bool in_error;
+ /* RSL error code, RSL_ERR_* */
+ uint8_t rsl_error_cause;
+
+ /* If a release event is being handled, ignore other ricocheting release events until that
+ * release handling has concluded. */
+ bool in_release_handler;
+ } release;
+
+ /* The logical channel type */
+ enum gsm_chan_t type;
+ /* Power levels for MS and BTS */
+ uint8_t bs_power_db;
+ uint8_t ms_power;
+ /* Encryption information */
+ struct gsm_encr encr;
+
+ /* Established data link layer services */
+ uint8_t sapis[8];
+
+ struct {
+ uint32_t bound_ip; /*< where the BTS receives RTP */
+ uint16_t bound_port;
+ uint32_t connect_ip; /*< where the BTS sends RTP to (MGW) */
+ uint16_t connect_port;
+ uint16_t conn_id;
+ uint8_t rtp_payload;
+ uint8_t rtp_payload2;
+ uint8_t rtp_csd_fmt;
+ uint8_t speech_mode;
+
+ /* info we need to postpone the AoIP
+ * assignment completed message */
+ struct {
+ uint8_t rr_cause;
+ bool valid;
+ } ass_compl;
+
+ struct {
+ bool use;
+ uint8_t local_cid;
+ bool remote_cid_present;
+ uint8_t remote_cid;
+ } osmux;
+ } abis_ip;
+
+ /* At first, the Timing Advance from the initial Channel Request. Later, the Timing Advance value received from
+ * the most recent Measurement Report. */
+ uint8_t last_ta;
+
+ /* table of neighbor cell measurements */
+ struct neigh_meas_proc neigh_meas[MAX_NEIGH_MEAS];
+
+ /* cache of last measurement reports on this lchan */
+ struct gsm_meas_rep meas_rep[MAX_MEAS_REP];
+ int meas_rep_idx;
+ int meas_rep_count;
+ uint8_t meas_rep_last_seen_nr;
+
+ /* GSM Random Access data */
+ /* TODO: don't allocate this, rather keep an "is_present" flag */
+ struct gsm48_req_ref *rqd_ref;
+
+ struct gsm_subscriber_connection *conn;
+
+ /* After the Channel Activation ACK or RSL Mode Modify ACK is received, this reflects the actually used
+ * channel_mode_and_rate. */
+ struct channel_mode_and_rate current_ch_mode_rate;
+ struct gsm48_multi_rate_conf current_mr_conf;
+ enum gsm0808_chan_indicator current_ch_indctr;
+
+ /* Circuit-Switched TSC Set in use, or -1 if no specific TSC Set was requested. The valid range is 1-4 as
+ * described in the spec 3GPP TS 45.002. */
+ int tsc_set;
+ /* Training Sequence Code in use. The valid range is 0-7 as described in the spec 3GPP TS 45.002. */
+ uint8_t tsc;
+
+ struct {
+ /* Whether this lchan represents a secondary "shadow" lchan to multiplex a second MS onto a primary
+ * "normal" lchan */
+ bool is_secondary;
+
+ /* Whether this lchan is activated/modified into a mode that allows VAMOS multiplexing at this moment */
+ bool enabled;
+ } vamos;
+
+ /* dBm value of interference level as reported in the most recent Resource Indication, if any for this lchan. Or
+ * INTERF_DBM_UNKNOWN if this lchan was not included in the most recent Resource Indication.
+ * The range is typically -115 to -85 dBm, here stored 1:1 as a signed integer, to ease comparison. */
+ int16_t interf_dbm;
+ /* Actual reported interference band index, or INTERF_BAND_UNKNOWN if this lchan was not included in the most
+ * recent Resource Indication. */
+ uint8_t interf_band;
+ /* MS power control state */
+ struct lchan_power_ctrl_state ms_power_ctrl;
+ /* Timestamps and markers to track active state duration. */
+ struct timespec active_start;
+ struct timespec active_stored;
+};
+
+#define GSM_LCHAN_SI(lchan, i) (void *)((lchan)->si.buf[i][0])
+
+void lchan_init(struct gsm_lchan *lchan, struct gsm_bts_trx_ts *ts, unsigned int nr);
+
+void lchan_update_name(struct gsm_lchan *lchan);
+uint64_t gsm_lchan_active_duration_ms(const struct gsm_lchan *lchan);
+
+static inline char *gsm_lchan_name(const struct gsm_lchan *lchan)
+{
+ OSMO_ASSERT(lchan);
+ return lchan->name;
+}
+
+struct gsm_lchan *gsm_lchan_vamos_to_primary(const struct gsm_lchan *lchan_vamos);
+struct gsm_lchan *gsm_lchan_primary_to_vamos(const struct gsm_lchan *lchan_primary);
+
+void lchan_update_ms_power_ctrl_level(struct gsm_lchan *lchan, int ms_power_dbm);
+
+#define LOGPLCHAN(lchan, ss, level, fmt, args...) \
+ LOGP(ss, level, "%s (ss=%d,%s) (%s) " fmt, \
+ lchan ? gsm_ts_and_pchan_name(lchan->ts) : "-", \
+ lchan ? lchan->nr : 0, \
+ lchan ? gsm_chan_t_name(lchan->type) : "-", \
+ bsc_subscr_name(lchan && lchan->conn ? lchan->conn->bsub : NULL), \
+ ## args)
diff --git a/include/osmocom/bsc/lchan_fsm.h b/include/osmocom/bsc/lchan_fsm.h
index 55ab02400..3c7bbc143 100644
--- a/include/osmocom/bsc/lchan_fsm.h
+++ b/include/osmocom/bsc/lchan_fsm.h
@@ -6,11 +6,18 @@
/* This macro automatically includes a final \n, if omitted. */
#define LOG_LCHAN(lchan, level, fmt, args...) do { \
- if (lchan->fi) \
- LOGPFSML(lchan->fi, level, "(type=%s) " fmt, gsm_lchant_name(lchan->type), ## args); \
+ if ((lchan)->fi) \
+ LOGPFSML((lchan)->fi, level, "(type=%s) " fmt, gsm_chan_t_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)
enum lchan_fsm_state {
LCHAN_ST_UNUSED,
@@ -18,12 +25,16 @@ enum lchan_fsm_state {
LCHAN_ST_WAIT_TS_READY,
LCHAN_ST_WAIT_ACTIV_ACK, /*< After RSL Chan Act Ack, lchan is active but RTP not configured. */
LCHAN_ST_WAIT_RLL_RTP_ESTABLISH,
+ LCHAN_ST_WAIT_RR_CHAN_MODE_MODIFY_ACK,
+ LCHAN_ST_WAIT_RSL_CHAN_MODE_MODIFY_ACK,
LCHAN_ST_ESTABLISHED, /*< Active and RTP is fully configured. */
LCHAN_ST_WAIT_RLL_RTP_RELEASED,
LCHAN_ST_WAIT_BEFORE_RF_RELEASE,
LCHAN_ST_WAIT_RF_RELEASE_ACK,
LCHAN_ST_WAIT_AFTER_ERROR,
LCHAN_ST_BORKEN,
+ LCHAN_ST_RECOVER_WAIT_ACTIV_ACK, /*< Attempt to recover from BORKEN: first try to activate the lchan */
+ LCHAN_ST_RECOVER_WAIT_RF_RELEASE_ACK, /*< Attempt to recover from BORKEN: then try to release it */
};
enum lchan_fsm_event {
@@ -40,27 +51,28 @@ enum lchan_fsm_event {
LCHAN_EV_RLL_REL_CONF,
LCHAN_EV_RSL_RF_CHAN_REL_ACK,
LCHAN_EV_RLL_ERR_IND,
-
- /* FIXME: not yet implemented: Chan Mode Modify, see assignment_fsm_start(). */
- LCHAN_EV_CHAN_MODE_MODIF_ACK,
- LCHAN_EV_CHAN_MODE_MODIF_ERROR,
+ LCHAN_EV_RR_CHAN_MODE_MODIFY_ACK,
+ LCHAN_EV_RR_CHAN_MODE_MODIFY_ERROR,
+ LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK,
+ LCHAN_EV_RSL_CHAN_MODE_MODIFY_NACK,
+ LCHAN_EV_REQUEST_MODE_MODIFY,
};
-void lchan_fsm_init();
-
void lchan_fsm_alloc(struct gsm_lchan *lchan);
void lchan_release(struct gsm_lchan *lchan, bool do_rr_release,
- bool err, enum gsm48_rr_cause cause_rr);
+ bool err, enum gsm48_rr_cause cause_rr,
+ const struct osmo_plmn_id *last_eutran_plmn);
void lchan_activate(struct gsm_lchan *lchan, struct lchan_activate_info *info);
void lchan_ready_to_switch_rtp(struct gsm_lchan *lchan);
+void lchan_mode_modify(struct gsm_lchan *lchan, struct lchan_modify_info *info);
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);
@@ -68,6 +80,9 @@ static inline bool lchan_state_is(struct gsm_lchan *lchan, uint32_t state)
bool lchan_may_receive_data(struct gsm_lchan *lchan);
+bool lchan_is_asci(struct gsm_lchan *lchan);
+
void lchan_forget_conn(struct gsm_lchan *lchan);
-void lchan_set_last_error(struct gsm_lchan *lchan, const char *fmt, ...);
+void lchan_fsm_skip_error(struct gsm_lchan *lchan);
+void lchan_fsm_update_id(struct gsm_lchan *lchan);
diff --git a/include/osmocom/bsc/lchan_rtp_fsm.h b/include/osmocom/bsc/lchan_rtp_fsm.h
index fa0e74636..397b5e177 100644
--- a/include/osmocom/bsc/lchan_rtp_fsm.h
+++ b/include/osmocom/bsc/lchan_rtp_fsm.h
@@ -1,15 +1,19 @@
/* osmo-bsc API to manage lchans, logical channels in GSM cells. */
#pragma once
+#include <osmocom/bsc/lchan.h>
+
#define LOG_LCHAN_RTP(lchan, level, fmt, args...) do { \
if (lchan->fi_rtp) \
LOGPFSML(lchan->fi_rtp, level, fmt, ## args); \
else \
LOGP(DLMGCP, level, "%s (not initialized) " fmt, gsm_lchan_name(lchan), \
## args); \
- } while(0)
+ } while (0)
struct gsm_lchan;
+struct mgcp_conn_peer;
+enum mgcp_codecs;
enum lchan_rtp_fsm_state {
LCHAN_RTP_ST_WAIT_MGW_ENDPOINT_AVAILABLE,
@@ -40,6 +44,9 @@ enum lchan_rtp_fsm_event {
};
void lchan_rtp_fsm_start(struct gsm_lchan *lchan);
-struct mgwep_ci *lchan_use_mgw_endpoint_ci_bts(struct gsm_lchan *lchan);
+struct osmo_mgcpc_ep_ci *lchan_use_mgw_endpoint_ci_bts(struct gsm_lchan *lchan);
bool lchan_rtp_established(struct gsm_lchan *lchan);
void lchan_forget_mgw_endpoint(struct gsm_lchan *lchan);
+
+void mgcp_pick_codec(struct mgcp_conn_peer *verb_info, const struct gsm_lchan *lchan, bool bss_side);
+bool mgcp_codec_is_picked(const struct mgcp_conn_peer *verb_info, enum mgcp_codecs codec);
diff --git a/include/osmocom/bsc/lchan_select.h b/include/osmocom/bsc/lchan_select.h
index 4aecdf676..d6a1b2026 100644
--- a/include/osmocom/bsc/lchan_select.h
+++ b/include/osmocom/bsc/lchan_select.h
@@ -1,6 +1,29 @@
/* Select a suitable lchan from a given cell. */
#pragma once
-struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type);
+enum lchan_select_reason {
+ SELECT_FOR_MS_CHAN_REQ,
+ SELECT_FOR_ASSIGNMENT,
+ SELECT_FOR_HANDOVER,
+ SELECT_FOR_VGCS,
+};
+
+extern const struct value_string lchan_select_reason_names[];
+static inline const char *lchan_select_reason_name(enum lchan_select_reason reason)
+{ return get_value_string(lchan_select_reason_names, reason); }
+
+struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts,
+ enum gsm_chan_t type,
+ enum lchan_select_reason reason,
+ void *ctx);
+enum gsm_chan_t chan_mode_to_chan_type(enum gsm48_chan_mode chan_mode, enum channel_rate chan_rate);
struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,
- enum gsm48_chan_mode chan_mode, bool full_rate);
+ enum gsm48_chan_mode chan_mode,
+ enum channel_rate chan_rate,
+ enum lchan_select_reason reason,
+ void *ctx);
+struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts,
+ enum gsm_chan_t type,
+ enum lchan_select_reason reason,
+ void *ctx, bool log);
+void lchan_select_set_type(struct gsm_lchan *lchan, enum gsm_chan_t type);
diff --git a/include/osmocom/bsc/lcs_loc_req.h b/include/osmocom/bsc/lcs_loc_req.h
new file mode 100644
index 000000000..78f938116
--- /dev/null
+++ b/include/osmocom/bsc/lcs_loc_req.h
@@ -0,0 +1,57 @@
+/* Location Services (LCS): BSSMAP and BSSMAP-LE Perform Location Request handling in OsmoBSC, API */
+#pragma once
+
+#include <osmocom/gsm/bssmap_le.h>
+
+#define LOG_LCS_LOC_REQ(LOC_REQ, level, fmt, args...) do { \
+ if (LOC_REQ) \
+ LOGPFSML((LOC_REQ)->fi, level, fmt, ## args); \
+ else \
+ LOGP(DLCS, level, "LCS Perf Loc Req: " fmt, ## args); \
+ } while (0)
+
+struct lcs_ta_req;
+
+enum lcs_loc_req_fsm_event {
+ LCS_LOC_REQ_EV_RX_LB_PERFORM_LOCATION_RESPONSE,
+ LCS_LOC_REQ_EV_RX_A_PERFORM_LOCATION_ABORT,
+ LCS_LOC_REQ_EV_TA_REQ_START,
+ LCS_LOC_REQ_EV_TA_REQ_END,
+ LCS_LOC_REQ_EV_HANDOVER_PERFORMED,
+ LCS_LOC_REQ_EV_CONN_CLEAR,
+};
+
+struct lcs_loc_req {
+ struct osmo_fsm_inst *fi;
+ struct gsm_subscriber_connection *conn;
+
+ struct {
+ struct bssmap_le_location_type location_type;
+
+ bool cell_id_present;
+ struct gsm0808_cell_id cell_id;
+
+ bool client_type_present;
+ enum bssmap_le_lcs_client_type client_type;
+
+ bool priority_present;
+ uint8_t priority;
+
+ bool qos_present;
+ struct osmo_bssmap_le_lcs_qos qos;
+
+ struct osmo_mobile_identity imsi;
+ struct osmo_mobile_identity imei;
+ } req;
+
+ bool resp_present;
+ struct bssmap_le_perform_loc_resp resp;
+
+ struct lcs_cause_ie lcs_cause;
+
+ struct lcs_ta_req *ta_req;
+};
+
+void lcs_loc_req_start(struct gsm_subscriber_connection *conn, struct msgb *msg);
+int lcs_loc_req_rx_bssmap_le(struct gsm_subscriber_connection *conn, struct msgb *msg);
+void lcs_loc_req_reset(struct gsm_subscriber_connection *conn);
diff --git a/include/osmocom/bsc/lcs_ta_req.h b/include/osmocom/bsc/lcs_ta_req.h
new file mode 100644
index 000000000..bdfc14f60
--- /dev/null
+++ b/include/osmocom/bsc/lcs_ta_req.h
@@ -0,0 +1,29 @@
+/* Location Services (LCS): BSSLAP TA Request handling in OsmoBSC, API */
+#pragma once
+
+#include <osmocom/bsc/debug.h>
+#include <osmocom/bsc/gsm_data.h>
+#include <osmocom/core/fsm.h>
+#include <osmocom/gsm/bssmap_le.h>
+
+#define LOG_LCS_TA_REQ(TA_REQ, level, fmt, args...) do { \
+ if (TA_REQ) \
+ LOGPFSML((TA_REQ)->fi, level, fmt, ## args); \
+ else \
+ LOGP(DLCS, level, "LCS TA Req: " fmt, ## args); \
+ } while (0)
+
+enum lcs_ta_req_fsm_event {
+ LCS_TA_REQ_EV_GOT_TA,
+ LCS_TA_REQ_EV_ABORT,
+};
+
+struct lcs_ta_req {
+ struct osmo_fsm_inst *fi;
+ struct lcs_loc_req *loc_req;
+ enum lcs_cause failure_cause;
+ uint8_t failure_diagnostic_val;
+};
+int lcs_ta_req_start(struct lcs_loc_req *lcs_loc_req);
+
+void lcs_bsslap_rx(struct gsm_subscriber_connection *conn, struct msgb *msg);
diff --git a/include/osmocom/bsc/meas_feed.h b/include/osmocom/bsc/meas_feed.h
index 1849a8932..447eab8c5 100644
--- a/include/osmocom/bsc/meas_feed.h
+++ b/include/osmocom/bsc/meas_feed.h
@@ -20,7 +20,7 @@ struct meas_feed_meas {
uint8_t lchan_type;
/* The physical channel type, enum gsm_phys_chan_config */
uint8_t pchan_type;
- /* number of ths BTS in network */
+ /* number of this BTS in network */
uint8_t bts_nr;
/* number of this TRX in the BTS */
uint8_t trx_nr;
@@ -35,9 +35,12 @@ enum meas_feed_msgtype {
};
#define MEAS_FEED_VERSION 1
+#define MEAS_FEED_TXQUEUE_MAX_LEN_DEFAULT 100
int meas_feed_cfg_set(const char *dst_host, uint16_t dst_port);
void meas_feed_scenario_set(const char *name);
+void meas_feed_txqueue_max_length_set(unsigned int max_length);
void meas_feed_cfg_get(char **host, uint16_t *port);
const char *meas_feed_scenario_get(void);
+unsigned int meas_feed_txqueue_max_length_get(void);
diff --git a/include/osmocom/bsc/meas_rep.h b/include/osmocom/bsc/meas_rep.h
index b0c03f0bb..402a888b1 100644
--- a/include/osmocom/bsc/meas_rep.h
+++ b/include/osmocom/bsc/meas_rep.h
@@ -38,7 +38,7 @@ struct gsm_meas_rep {
struct gsm_meas_rep_unidir ul;
struct gsm_meas_rep_unidir dl;
- uint8_t bs_power;
+ uint8_t bs_power_db;
/* according to 3GPP TS 48.058 ยง MS Timing Offset [-63; 192] */
int16_t ms_timing_offset;
struct {
@@ -51,14 +51,38 @@ struct gsm_meas_rep {
struct gsm_meas_rep_cell cell[6];
};
+enum tdma_meas_field {
+ TDMA_MEAS_FIELD_RXLEV = 0,
+ TDMA_MEAS_FIELD_RXQUAL = 1,
+};
+
+enum tdma_meas_dir {
+ TDMA_MEAS_DIR_UL = 0,
+ TDMA_MEAS_DIR_DL = 1,
+};
+
+/* (function choose_meas_rep_field() depends on FULL and SUB being 0 and 1, but doesn't care about AUTO's value) */
+enum tdma_meas_set {
+ TDMA_MEAS_SET_FULL = 0,
+ TDMA_MEAS_SET_SUB = 1,
+ TDMA_MEAS_SET_AUTO,
+};
+
+extern const struct value_string tdma_meas_set_names[];
+static inline const char *tdma_meas_set_name(enum tdma_meas_set val)
+{ return get_value_string(tdma_meas_set_names, val); }
+static inline enum tdma_meas_set tdma_meas_set_from_str(const char *name)
+{ return get_string_value(tdma_meas_set_names, name); }
+
/* obtain an average over the last 'num' fields in the meas reps */
int get_meas_rep_avg(const struct gsm_lchan *lchan,
- enum meas_rep_field field, unsigned int num);
+ enum tdma_meas_field field, enum tdma_meas_dir dir, enum tdma_meas_set set,
+ unsigned int num);
/* Check if N out of M last values for FIELD are >= bd */
int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan,
- enum meas_rep_field field,
- unsigned int n, unsigned int m, int be);
+ enum tdma_meas_field field, enum tdma_meas_dir dir, enum tdma_meas_set set,
+ unsigned int n, unsigned int m, int be);
unsigned int calc_initial_idx(unsigned int array_size,
unsigned int meas_rep_idx,
diff --git a/include/osmocom/bsc/mgw_endpoint_fsm.h b/include/osmocom/bsc/mgw_endpoint_fsm.h
deleted file mode 100644
index e264a3c8b..000000000
--- a/include/osmocom/bsc/mgw_endpoint_fsm.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* osmo-bsc API to manage all sides of an MGW endpoint */
-#pragma once
-
-#include <osmocom/mgcp_client/mgcp_client_fsm.h>
-
-#include <osmocom/bsc/debug.h>
-
-/* This macro automatically includes a final \n, if omitted. */
-#define LOG_MGWEP(mgwep, level, fmt, args...) do { \
- LOGPFSML(mgwep->fi, level, "(%s) " fmt, \
- mgw_endpoint_name(mgwep), ## args); \
- } while(0)
-
-enum mgwep_fsm_state {
- MGWEP_ST_UNUSED,
- MGWEP_ST_WAIT_MGW_RESPONSE,
- MGWEP_ST_IN_USE,
-};
-
-enum mgwep_fsm_event {
- _MGWEP_EV_LAST,
- /* and MGW response events are allocated dynamically */
-};
-
-struct mgw_endpoint;
-struct mgwep_ci;
-struct T_def;
-
-void mgw_endpoint_fsm_init(struct T_def *T_defs);
-
-struct mgw_endpoint *mgw_endpoint_alloc(struct osmo_fsm_inst *parent, uint32_t parent_term_event,
- struct mgcp_client *mgcp_client,
- const char *fsm_id,
- const char *endpoint_str_fmt, ...);
-
-struct mgwep_ci *mgw_endpoint_ci_add(struct mgw_endpoint *mgwep,
- const char *label_fmt, ...);
-const struct mgcp_conn_peer *mgwep_ci_get_rtp_info(const struct mgwep_ci *ci);
-bool mgwep_ci_get_crcx_info_to_sockaddr(const struct mgwep_ci *ci, struct sockaddr_storage *dest);
-
-void mgw_endpoint_ci_request(struct mgwep_ci *ci,
- enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
- struct osmo_fsm_inst *notify,
- uint32_t event_success, uint32_t event_failure,
- void *notify_data);
-
-static inline void mgw_endpoint_ci_dlcx(struct mgwep_ci *ci)
-{
- mgw_endpoint_ci_request(ci, MGCP_VERB_DLCX, NULL, NULL, 0, 0, NULL);
-}
-
-void mgw_endpoint_clear(struct mgw_endpoint *mgwep);
-
-const char *mgw_endpoint_name(const struct mgw_endpoint *mgwep);
-const char *mgwep_ci_name(const struct mgwep_ci *ci);
-const char *mgcp_conn_peer_name(const struct mgcp_conn_peer *info);
-
-enum mgcp_codecs chan_mode_to_mgcp_codec(enum gsm48_chan_mode chan_mode, bool full_rate);
-void mgcp_pick_codec(struct mgcp_conn_peer *verb_info, const struct gsm_lchan *lchan, bool bss_side);
diff --git a/include/osmocom/bsc/neighbor_ident.h b/include/osmocom/bsc/neighbor_ident.h
index 17bffbc14..bd14bd409 100644
--- a/include/osmocom/bsc/neighbor_ident.h
+++ b/include/osmocom/bsc/neighbor_ident.h
@@ -5,54 +5,99 @@
#include <stdbool.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/ctrl/control_cmd.h>
+
+#include <osmocom/bsc/gsm_data.h>
struct vty;
struct gsm_network;
struct gsm_bts;
-struct neighbor_ident_list;
struct gsm0808_cell_id_list2;
#define NEIGHBOR_IDENT_KEY_ANY_BTS -1
#define BSIC_ANY 0xff
-struct neighbor_ident_key {
- int from_bts; /*< BTS nr 0..255 or NEIGHBOR_IDENT_KEY_ANY_BTS */
- uint16_t arfcn;
- uint8_t bsic;
+enum neighbor_type {
+ NEIGHBOR_TYPE_UNSET = 0,
+ NEIGHBOR_TYPE_BTS_NR = 1,
+ NEIGHBOR_TYPE_CELL_ID = 2,
+};
+
+/* One line of VTY neighbor configuration as entered by the user.
+ * One of three variants:
+ *
+ * - just the local-BSS neighbor BTS nr:
+ * neighbor bts 123
+ *
+ * - a neighbor cell identifier *without* ARFCN+BSIC:
+ * neighbor (lac|lac-ci|cgi|cgi-ps) 1 2 3...
+ * This is an elaborate / BTS-nr-agnostic way of indicating a local-BSS neighbor cell.
+ *
+ * - a neighbor cell identifier *with* ARFCN+BSIC:
+ * neighbor (lac|lac-ci|cgi|cgi-ps) 1 2 3... arfcn 456 bsic (23|any)
+ * This can either be
+ * - a remote-BSS neighbor cell, or
+ * - a super elaborate way of indicating a local-BSS neighbor, if this cell id exists in the local BSS.
+ */
+struct neighbor {
+ struct llist_head entry;
+
+ enum neighbor_type type;
+ union {
+ uint8_t bts_nr;
+ struct {
+ struct gsm0808_cell_id id;
+ bool ab_present;
+ struct cell_ab ab;
+ } cell_id;
+ };
};
-const char *neighbor_ident_key_name(const struct neighbor_ident_key *ni_key);
+int resolve_local_neighbor(struct gsm_bts **local_neighbor_p, const struct gsm_bts *from_bts,
+ const struct neighbor *neighbor);
+int resolve_remote_neighbors(struct gsm_bts *from_bts, const struct cell_ab *target_ab);
+
+int cell_ab_to_str_buf(char *buf, size_t buflen, const struct cell_ab *cell);
+char *cell_ab_to_str_c(void *ctx, const struct cell_ab *cell);
+
+bool cell_ab_match(const struct cell_ab *entry, const struct cell_ab *search_for, bool exact_match);
+bool cell_ab_valid(const struct cell_ab *cell);
-struct neighbor_ident_list *neighbor_ident_init(void *talloc_ctx);
-void neighbor_ident_free(struct neighbor_ident_list *nil);
+int neighbor_to_str_buf(char *buf, size_t buflen, const struct neighbor *n);
+char *neighbor_to_str_c(void *ctx, const struct neighbor *n);
+bool neighbor_same(const struct neighbor *a, const struct neighbor *b, bool check_cell_ab);
-bool neighbor_ident_key_match(const struct neighbor_ident_key *entry,
- const struct neighbor_ident_key *search_for,
- bool exact_match);
+void bts_cell_ab(struct cell_ab *arfcn_bsic, const struct gsm_bts *bts);
-int neighbor_ident_add(struct neighbor_ident_list *nil, const struct neighbor_ident_key *key,
- const struct gsm0808_cell_id_list2 *val);
-const struct gsm0808_cell_id_list2 *neighbor_ident_get(const struct neighbor_ident_list *nil,
- const struct neighbor_ident_key *key);
-bool neighbor_ident_del(struct neighbor_ident_list *nil, const struct neighbor_ident_key *key);
-void neighbor_ident_clear(struct neighbor_ident_list *nil);
+int resolve_neighbors(struct gsm_bts **local_neighbor_p, struct gsm0808_cell_id_list2 *remote_neighbors,
+ struct gsm_bts *from_bts, const struct cell_ab *target_ab, bool log_errors);
-void neighbor_ident_iter(const struct neighbor_ident_list *nil,
- bool (* iter_cb )(const struct neighbor_ident_key *key,
- const struct gsm0808_cell_id_list2 *val,
- void *cb_data),
- void *cb_data);
+void neighbor_ident_vty_init(void);
+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);
-void neighbor_ident_vty_init(struct gsm_network *net, struct neighbor_ident_list *nil);
-void neighbor_ident_vty_write(struct vty *vty, const char *indent, struct gsm_bts *bts);
+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);
-#define NEIGHBOR_IDENT_VTY_KEY_PARAMS "arfcn <0-1023> bsic (<0-63>|any)"
-#define NEIGHBOR_IDENT_VTY_KEY_DOC \
+int neighbors_check_cfg(void);
+
+#define CELL_AB_VTY_PARAMS "arfcn <0-1023> bsic (<0-63>|any)"
+#define CELL_AB_VTY_DOC \
"ARFCN of neighbor cell\n" "ARFCN value\n" \
"BSIC of neighbor cell\n" "BSIC value\n" \
"for all BSICs / use any BSIC in this ARFCN\n"
-bool neighbor_ident_vty_parse_key_params(struct vty *vty, const char **argv,
- struct neighbor_ident_key *key);
-bool neighbor_ident_bts_parse_key_params(struct vty *vty, struct gsm_bts *bts, const char **argv,
- struct neighbor_ident_key *key);
+void neighbor_ident_vty_parse_arfcn_bsic(struct cell_ab *ab, const char **argv);
+
+int neighbor_address_resolution(const struct gsm_network *net, const struct cell_ab *ab,
+ uint16_t lac, uint16_t cell_id,
+ struct osmo_cell_global_id_ps *res_cgi_ps);
+
+struct ctrl_handle *neighbor_controlif_setup(struct gsm_network *net);
+int neighbor_ctrl_cmds_install(struct gsm_network *net);
+
+enum neighbor_ctrl_node {
+ CTRL_NODE_NEIGH = _LAST_CTRL_NODE,
+ _LAST_CTRL_NODE_NEIGHBOR
+};
diff --git a/include/osmocom/bsc/nm_common_fsm.h b/include/osmocom/bsc/nm_common_fsm.h
new file mode 100644
index 000000000..91be64411
--- /dev/null
+++ b/include/osmocom/bsc/nm_common_fsm.h
@@ -0,0 +1,125 @@
+/* Header for all NM FSM. Following 3GPP TS 12.21 Figure 2/GSM 12.21:
+ GSM 12.21 Objects' Operational state and availability status behaviour during initialization */
+
+/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
+struct gsm_bts;
+
+/* Common */
+enum nm_fsm_events {
+ NM_EV_SW_ACT_REP,
+ NM_EV_STATE_CHG_REP,
+ NM_EV_GET_ATTR_REP,
+ NM_EV_SET_ATTR_ACK,
+ NM_EV_OPSTART_ACK,
+ NM_EV_OPSTART_NACK,
+ NM_EV_OML_DOWN,
+ NM_EV_SETUP_RAMP_READY, /* BTS setup ramp allow to continue to configure */
+ NM_EV_FORCE_LOCK, /* Only supported by RadioCarrier so far */
+ NM_EV_FEATURE_NEGOTIATED, /* Sent by BTS to NSVC MO */
+ NM_EV_RSL_CONNECT_ACK, /* Sent by BTS to BBTRANSC MO */
+ NM_EV_RSL_CONNECT_NACK, /* Sent by BTS to BBTRANSC MO */
+};
+extern const struct value_string nm_fsm_event_names[];
+
+/* BTS SiteManager */
+enum nm_bts_sm_op_fsm_states {
+ NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED,
+ NM_BTS_SM_ST_OP_DISABLED_DEPENDENCY,
+ NM_BTS_SM_ST_OP_DISABLED_OFFLINE,
+ NM_BTS_SM_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_bts_sm_fsm;
+
+/* BTS */
+enum nm_bts_op_fsm_states {
+ NM_BTS_ST_OP_DISABLED_NOTINSTALLED,
+ NM_BTS_ST_OP_DISABLED_DEPENDENCY,
+ NM_BTS_ST_OP_DISABLED_OFFLINE,
+ NM_BTS_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_bts_fsm;
+
+/* BaseBand Transceiver */
+enum nm_bb_transc_op_fsm_states {
+ NM_BB_TRANSC_ST_OP_DISABLED_NOTINSTALLED,
+ NM_BB_TRANSC_ST_OP_DISABLED_DEPENDENCY,
+ NM_BB_TRANSC_ST_OP_DISABLED_OFFLINE,
+ NM_BB_TRANSC_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_bb_transc_fsm;
+
+/* Radio Carrier */
+enum nm_rcarrier_op_fsm_states {
+ NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED,
+ NM_RCARRIER_ST_OP_DISABLED_DEPENDENCY,
+ NM_RCARRIER_ST_OP_DISABLED_OFFLINE,
+ NM_RCARRIER_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_rcarrier_fsm;
+
+/* Radio Channel */
+enum nm_chan_op_fsm_states {
+ NM_CHAN_ST_OP_DISABLED_NOTINSTALLED,
+ NM_CHAN_ST_OP_DISABLED_DEPENDENCY,
+ NM_CHAN_ST_OP_DISABLED_OFFLINE,
+ NM_CHAN_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_chan_fsm;
+
+/* GPRS NSE */
+enum nm_gprs_op_nse_states {
+ NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED,
+ NM_GPRS_NSE_ST_OP_DISABLED_DEPENDENCY,
+ NM_GPRS_NSE_ST_OP_DISABLED_OFFLINE,
+ NM_GPRS_NSE_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_gprs_nse_fsm;
+
+/* GPRS Cell */
+enum nm_gprs_op_cell_states {
+ NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED,
+ NM_GPRS_CELL_ST_OP_DISABLED_DEPENDENCY,
+ NM_GPRS_CELL_ST_OP_DISABLED_OFFLINE,
+ NM_GPRS_CELL_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_gprs_cell_fsm;
+
+/* GPRS NSVC */
+enum nm_gprs_op_nsvc_fsm_states {
+ NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED,
+ NM_GPRS_NSVC_ST_OP_DISABLED_DEPENDENCY,
+ NM_GPRS_NSVC_ST_OP_DISABLED_OFFLINE,
+ NM_GPRS_NSVC_ST_OP_ENABLED,
+};
+extern struct osmo_fsm nm_gprs_nsvc_fsm;
+
+void nm_obj_fsm_becomes_enabled_disabled(struct gsm_bts *bts, void *obj,
+ enum abis_nm_obj_class obj_class,
+ bool running);
+
+void nm_fsm_dispatch_all_configuring(struct gsm_bts *bts, uint32_t event, void *data);
diff --git a/include/osmocom/bsc/osmo_bsc.h b/include/osmocom/bsc/osmo_bsc.h
index bebfb2faa..ee8cc1312 100644
--- a/include/osmocom/bsc/osmo_bsc.h
+++ b/include/osmocom/bsc/osmo_bsc.h
@@ -2,10 +2,6 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
-#include <osmocom/bsc/bsc_msg_filter.h>
-
-#define BSS_SEND_USSD 1
-
enum bsc_con {
BSC_CON_SUCCESS,
BSC_CON_REJECT_NO_LINK,
@@ -13,6 +9,7 @@ enum bsc_con {
BSC_CON_NO_MEM,
};
+struct msgb;
struct bsc_msc_data;
struct gsm0808_channel_type;
struct gsm0808_speech_codec_list;
@@ -20,23 +17,16 @@ struct gsm_audio_support;
struct gsm_subscriber_connection;
struct gsm_bts;
-struct bsc_api *osmo_bsc_api();
-
-int bsc_queue_for_msc(struct gsm_subscriber_connection *conn, struct msgb *msg);
-int bsc_open_connection(struct gsm_subscriber_connection *sccp, struct msgb *msg);
-enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
- struct bsc_msc_data *msc, int send_ping);
-int bsc_delete_connection(struct gsm_subscriber_connection *sccp);
+struct bsc_api *osmo_bsc_api(void);
-struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn, struct msgb *);
int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
-int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn);
int bsc_handle_udt(struct bsc_msc_data *msc, struct msgb *msg, unsigned int length);
int bsc_handle_dt(struct gsm_subscriber_connection *conn, struct msgb *msg, unsigned int len);
-int bsc_ctrl_cmds_install();
+struct gsm_network;
+int bsc_ctrl_cmds_install(struct gsm_network *net);
void bsc_gen_location_state_trap(struct gsm_bts *bts);
diff --git a/include/osmocom/bsc/osmo_bsc_grace.h b/include/osmocom/bsc/osmo_bsc_grace.h
index d78e41c82..07dce8cd5 100644
--- a/include/osmocom/bsc/osmo_bsc_grace.h
+++ b/include/osmocom/bsc/osmo_bsc_grace.h
@@ -27,10 +27,5 @@
struct bsc_msc_data;
int bsc_grace_allow_new_connection(struct gsm_network *net, struct gsm_bts *bts);
-int bsc_grace_paging_request(enum signal_rf rf_policy,
- struct bsc_subscr *subscr,
- int chan_needed,
- struct bsc_msc_data *msc,
- struct gsm_bts *bts);
#endif
diff --git a/include/osmocom/bsc/osmo_bsc_lcls.h b/include/osmocom/bsc/osmo_bsc_lcls.h
index 3eaa5891a..8bbd55241 100644
--- a/include/osmocom/bsc/osmo_bsc_lcls.h
+++ b/include/osmocom/bsc/osmo_bsc_lcls.h
@@ -1,4 +1,7 @@
#pragma once
+
+#include "gsm_data.h"
+
#include <osmocom/core/fsm.h>
enum lcls_fsm_state {
@@ -29,7 +32,20 @@ enum lcls_event {
LCLS_EV_OTHER_DEAD,
};
-enum gsm0808_lcls_status lcls_get_status(struct gsm_subscriber_connection *conn);
+enum bsc_lcls_mode {
+ BSC_LCLS_MODE_DISABLED,
+ BSC_LCLS_MODE_MGW_LOOP,
+ BSC_LCLS_MODE_BTS_LOOP,
+};
+
+extern const struct value_string bsc_lcls_mode_names[];
+
+static inline const char *bsc_lcls_mode_name(enum bsc_lcls_mode m)
+{
+ return get_value_string(bsc_lcls_mode_names, m);
+}
+
+enum gsm0808_lcls_status lcls_get_status(const struct gsm_subscriber_connection *conn);
void lcls_update_config(struct gsm_subscriber_connection *conn,
const uint8_t *config, const uint8_t *control);
@@ -37,5 +53,3 @@ void lcls_update_config(struct gsm_subscriber_connection *conn,
void lcls_apply_config(struct gsm_subscriber_connection *conn);
extern struct osmo_fsm lcls_fsm;
-
-void bssmap_add_lcls_status_if_needed(struct gsm_subscriber_connection *conn, struct msgb *msg);
diff --git a/include/osmocom/bsc/osmo_bsc_reset.h b/include/osmocom/bsc/osmo_bsc_reset.h
deleted file mode 100644
index 578f763e6..000000000
--- a/include/osmocom/bsc/osmo_bsc_reset.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* (C) 2017 by sysmocom s.f.m.c. GmbH
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/* Create and start state machine which handles the reset/reset-ack procedure */
-void start_reset_fsm(struct bsc_msc_data *msc);
-
-/* Confirm that we sucessfully received a reset acknowlege message */
-void reset_ack_confirm(struct bsc_msc_data *msc);
-
-/* Report a failed connection */
-void report_conn_fail(struct bsc_msc_data *msc);
-
-/* Report a successful connection */
-void report_conn_success(struct bsc_msc_data *msc);
-
-/* Check if we have a connection to a specified msc */
-bool sccp_conn_ready(struct bsc_msc_data *msc);
diff --git a/include/osmocom/bsc/osmo_bsc_rf.h b/include/osmocom/bsc/osmo_bsc_rf.h
index 56ac980ca..f88ccbf6a 100644
--- a/include/osmocom/bsc/osmo_bsc_rf.h
+++ b/include/osmocom/bsc/osmo_bsc_rf.h
@@ -60,7 +60,12 @@ const char *osmo_bsc_rf_get_policy_name(enum osmo_bsc_rf_policy policy);
enum osmo_bsc_rf_opstate osmo_bsc_rf_get_opstate_by_bts(struct gsm_bts *bts);
enum osmo_bsc_rf_adminstate osmo_bsc_rf_get_adminstate_by_bts(struct gsm_bts *bts);
enum osmo_bsc_rf_policy osmo_bsc_rf_get_policy_by_bts(struct gsm_bts *bts);
+enum osmo_bsc_rf_opstate osmo_bsc_rf_get_opstate_by_trx(struct gsm_bts_trx *trx);
+enum osmo_bsc_rf_adminstate osmo_bsc_rf_get_adminstate_by_trx(struct gsm_bts_trx *trx);
struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net);
void osmo_bsc_rf_schedule_lock(struct osmo_bsc_rf *rf, char cmd);
+char *bsc_rf_states_of_bts_c(void *ctx, struct gsm_bts *bts);
+char *bsc_rf_states_c(void *ctx);
+
#endif
diff --git a/include/osmocom/bsc/osmo_bsc_sigtran.h b/include/osmocom/bsc/osmo_bsc_sigtran.h
index bd8b06398..2ee35e53c 100644
--- a/include/osmocom/bsc/osmo_bsc_sigtran.h
+++ b/include/osmocom/bsc/osmo_bsc_sigtran.h
@@ -33,14 +33,25 @@ int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_connection *conn, struct ms
/* Send data to MSC */
int osmo_bsc_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg);
-/* Initalize osmo sigtran backhaul */
+/* Initialize osmo sigtran backhaul */
int osmo_bsc_sigtran_init(struct llist_head *mscs);
/* Close all open sigtran connections and channels */
-void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc);
+void osmo_bsc_sigtran_reset(struct bsc_msc_data *msc);
+
+void osmo_bsc_sigtran_tx_reset(const struct bsc_msc_data *msc);
/* Send reset-ack to MSC */
void osmo_bsc_sigtran_tx_reset_ack(const struct bsc_msc_data *msc);
/* receive + process a CTRL command from the piggy-back on the IPA/SCCPlite link */
int bsc_sccplite_rx_ctrl(struct osmo_ss7_asp *asp, struct msgb *msg);
+
+/* receive + process a MGCP message from the piggy-back on the IPA/SCCPlite link */
+int bsc_sccplite_rx_mgcp(struct osmo_ss7_asp *asp, struct msgb *msg);
+
+/* send a message via SCCPLite to given MSC */
+int bsc_sccplite_msc_send(struct bsc_msc_data *msc, struct msgb *msg);
+
+/* we received some data on the UDP proxy socket from the MGW. Pass it to MSC via IPA */
+int bsc_sccplite_mgcp_proxy_cb(struct osmo_fd *ofd, unsigned int what);
diff --git a/include/osmocom/bsc/osmux.h b/include/osmocom/bsc/osmux.h
index f3ea72a85..aa3d1ab85 100644
--- a/include/osmocom/bsc/osmux.h
+++ b/include/osmocom/bsc/osmux.h
@@ -1,41 +1,7 @@
-#ifndef _OPENBSC_OSMUX_H_
-#define _OPENBSC_OSMUX_H_
-
-#include <osmocom/netif/osmux.h>
-
-#define OSMUX_PORT 1984
-
-enum {
- OSMUX_ROLE_BSC = 0,
- OSMUX_ROLE_BSC_NAT,
-};
-
-int osmux_init(int role, struct mgcp_config *cfg);
-int osmux_enable_endpoint(struct mgcp_endpoint *endp, struct in_addr *addr, uint16_t port);
-void osmux_disable_endpoint(struct mgcp_endpoint *endp);
-void osmux_allocate_cid(struct mgcp_endpoint *endp);
-void osmux_release_cid(struct mgcp_endpoint *endp);
-
-int osmux_xfrm_to_rtp(struct mgcp_endpoint *endp, int type, char *buf, int rc);
-int osmux_xfrm_to_osmux(int type, char *buf, int rc, struct mgcp_endpoint *endp);
-
-int osmux_send_dummy(struct mgcp_endpoint *endp);
-
-int osmux_get_cid(void);
-void osmux_put_cid(uint8_t osmux_cid);
-int osmux_used_cid(void);
-
-enum osmux_state {
- OSMUX_STATE_DISABLED = 0,
- OSMUX_STATE_NEGOTIATING,
- OSMUX_STATE_ACTIVATING,
- OSMUX_STATE_ENABLED,
-};
+#pragma once
enum osmux_usage {
OSMUX_USAGE_OFF = 0,
OSMUX_USAGE_ON = 1,
OSMUX_USAGE_ONLY = 2,
};
-
-#endif
diff --git a/include/osmocom/bsc/paging.h b/include/osmocom/bsc/paging.h
index 2be71c39f..054e5c78d 100644
--- a/include/osmocom/bsc/paging.h
+++ b/include/osmocom/bsc/paging.h
@@ -28,52 +28,135 @@
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/bsc_subscriber.h>
+#include <osmocom/bsc/bsc_msc_data.h>
struct bsc_msc_data;
+#define LOG_PAGING(PARAMS, SUBSYS, LEVEL, fmt, args...) \
+ LOGP(SUBSYS, LEVEL, "(msc=%d) Paging%s: %s: " fmt, \
+ (PARAMS)->msc ? (PARAMS)->msc->nr : -1, \
+ (PARAMS)->reason == BSC_PAGING_FOR_LCS ? " for LCS" : "", \
+ bsc_subscr_name((PARAMS)->bsub), \
+ ##args)
+
+#define LOG_PAGING_BTS(PARAMS, BTS, SUBSYS, LEVEL, fmt, args...) \
+ LOG_PAGING(PARAMS, SUBSYS, LEVEL, "(bts=%u) " fmt, (BTS) ? (BTS)->nr : 255, ##args)
+
+#define BSUB_USE_PAGING_START "paging-start"
+#define BSUB_USE_PAGING_REQUEST "paging-req"
+
+/* Bitmask of reasons for Paging. Each individual Paging via bsc_paging_start() typically has only one of these reasons
+ * set, but when a subscriber responds, we need to aggregate all pending Paging reasons (by bitwise-OR). */
+enum bsc_paging_reason {
+ BSC_PAGING_NONE = 0,
+ BSC_PAGING_FROM_CN = 0x1,
+ BSC_PAGING_FOR_LCS = 0x2,
+};
+
+/* OS#5552, OS#5553: Maximum allowed scheduling transmit delay in paging
+ * requests to be queued, in seconds. If calculated delay for requests to be
+ * queued goes over this threshold, they are discarded instead of inserted to
+ * the queue. This avoids keeping queueing requests which will be scheduled for
+ * transmission too late.
+ */
+#define PAGING_THRESHOLD_X3113_DEFAULT_SEC 60
+
+#define MAX_PAGING_BLOCKS_CCCH 9
+#define MAX_BS_PA_MFRMS 9
+
+struct bsc_paging_params {
+ enum bsc_paging_reason reason;
+ struct bsc_msc_data *msc;
+ struct bsc_subscr *bsub;
+ uint32_t tmsi;
+ struct osmo_mobile_identity imsi;
+ uint8_t chan_needed;
+ struct gsm0808_cell_id_list2 cil;
+};
+
/**
* A pending paging request
*/
struct gsm_paging_request {
/* list_head for list of all paging requests */
struct llist_head entry;
- /* the subscriber which we're paging. Later gsm_paging_request
- * should probably become a part of the bsc_subsrc struct? */
+ /* the subscriber which we're paging. This struct is included using
+ * bsub_entry field in list bsub->active_paging_requests */
struct bsc_subscr *bsub;
+ struct llist_head bsub_entry;
/* back-pointer to the BTS on which we are paging */
struct gsm_bts *bts;
/* what kind of channel type do we ask the MS to establish */
int chan_type;
+ /* paging group of the subscriber: */
+ uint8_t pgroup;
/* Timer 3113: how long do we try to page? */
struct osmo_timer_list T3113;
/* How often did we ask the BTS to page? */
int attempts;
+ /* Timestamp of last time the subscriber was paged */
+ struct timespec last_attempt_ts;
/* MSC that has issued this paging */
struct bsc_msc_data *msc;
+
+ enum bsc_paging_reason reason;
};
-/* schedule paging request */
-int paging_request_bts(struct gsm_bts *bts, struct bsc_subscr *bsub, int type,
- struct bsc_msc_data *msc);
+/*
+ * This keeps track of the paging status of one BTS. It
+ * includes a number of pending requests, a back pointer
+ * to the gsm_bts, a timer and some more state.
+ */
+struct gsm_bts_paging_state {
+ /* pending requests (initial paging request, no retransmits) */
+ struct llist_head initial_req_list;
+ /* Number of requests in initial_req_list */
+ unsigned int initial_req_list_len;
+ /* pending requests (already transmitted at least once) */
+ struct llist_head retrans_req_list;
+ /* Number of requests in pending_requests_len */
+ unsigned int retrans_req_list_len;
+
+ /* Number of requests in initial_req_list, indexed by pgroup. */
+ unsigned int initial_req_pgroup_counts[MAX_PAGING_BLOCKS_CCCH * MAX_BS_PA_MFRMS];
-/* stop paging requests */
-void paging_request_stop(struct llist_head *bts_list,
- struct gsm_bts *_bts, struct bsc_subscr *bsub,
- struct gsm_subscriber_connection *conn,
- struct msgb *msg);
+ struct gsm_bts *bts;
-/* update paging load */
-void paging_update_buffer_space(struct gsm_bts *bts, uint16_t);
+ struct osmo_timer_list work_timer;
+ struct osmo_timer_list credit_timer;
-/* pending paging requests */
-unsigned int paging_pending_requests_nr(struct gsm_bts *bts);
+ /* Last time paging worker was triggered */
+ struct timespec last_sched_ts;
+
+ /* free chans needed */
+ int free_chans_need;
+
+ /* load */
+ uint16_t available_slots;
+};
+
+void paging_global_init(void);
-struct bsc_msc_data *paging_get_msc(struct gsm_bts *bts, struct bsc_subscr *bsub);
+void paging_init(struct gsm_bts *bts);
+void paging_destructor(struct gsm_bts *bts);
+
+/* schedule paging request */
+int paging_request_bts(const struct bsc_paging_params *params, struct gsm_bts *bts);
+
+void paging_request_stop(struct bsc_msc_data **msc_p, enum bsc_paging_reason *reasons_p,
+ struct gsm_bts *bts, struct bsc_subscr *bsub);
+void paging_request_cancel(struct bsc_subscr *bsub, enum bsc_paging_reason reasons);
+
+/* pending paging requests */
+unsigned int paging_pending_requests_nr(const struct gsm_bts *bts);
void paging_flush_bts(struct gsm_bts *bts, struct bsc_msc_data *msc);
void paging_flush_network(struct gsm_network *net, struct bsc_msc_data *msc);
+uint16_t paging_estimate_available_slots(const struct gsm_bts *bts, unsigned int time_span_s);
+
+int bsc_paging_start(struct bsc_paging_params *params);
#endif
diff --git a/include/osmocom/bsc/pcu_if.h b/include/osmocom/bsc/pcu_if.h
index 1f398b4aa..f9aa9edbf 100644
--- a/include/osmocom/bsc/pcu_if.h
+++ b/include/osmocom/bsc/pcu_if.h
@@ -1,17 +1,24 @@
#ifndef _PCU_IF_H
#define _PCU_IF_H
+#include <osmocom/core/write_queue.h>
#include <osmocom/gsm/l1sap.h>
extern int pcu_direct;
+#define PCUIF_HDR_SIZE (sizeof(struct gsm_pcu_if) - sizeof(((struct gsm_pcu_if *)0)->u))
+
+#define BSC_PCU_SOCK_WQUEUE_LEN_DEFAULT 100
+
struct pcu_sock_state {
- struct gsm_network *net;
+ struct gsm_network *net; /* backpointer to GSM network */
struct osmo_fd listen_bfd; /* fd for listen socket */
- struct osmo_fd conn_bfd; /* fd for connection to lcr */
- struct llist_head upqueue; /* queue for sending messages */
+ struct osmo_wqueue upqueue; /* For sending messages; has fd for conn. to PCU */
};
+/* Check if BTS has a PCU connection */
+bool pcu_connected(const struct gsm_network *net);
+
/* PCU relevant information has changed; Inform PCU (if connected) */
void pcu_info_update(struct gsm_bts *bts);
@@ -19,17 +26,13 @@ void pcu_info_update(struct gsm_bts *bts);
int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn,
uint8_t is_11bit, enum ph_burst_type burst_type);
-/* Confirm the sending of an immediate assignment to the pcu */
-int pcu_tx_imm_ass_sent(struct gsm_bts *bts, uint32_t tlli);
-
-
-/* Confirm the sending of an immediate assignment to the pcu */
-int pcu_tx_imm_ass_sent(struct gsm_bts *bts, uint32_t tlli);
+/* Confirm the sending of an AGCH or PCH MAC block to the pcu */
+int pcu_tx_data_cnf(struct gsm_bts *bts, uint32_t msg_id, uint8_t sapi);
/* Open connection to PCU */
-int pcu_sock_init(const char *path, struct gsm_bts *bts);
+int pcu_sock_init(struct gsm_network *net);
/* Close connection to PCU */
-void pcu_sock_exit(struct gsm_bts *bts);
+void pcu_sock_exit(struct gsm_network *net);
#endif /* _PCU_IF_H */
diff --git a/include/osmocom/bsc/pcuif_proto.h b/include/osmocom/bsc/pcuif_proto.h
index b9f61b6f1..33036c330 100644
--- a/include/osmocom/bsc/pcuif_proto.h
+++ b/include/osmocom/bsc/pcuif_proto.h
@@ -2,36 +2,48 @@
#define _PCUIF_PROTO_H
#include <osmocom/gsm/l1sap.h>
+#include <arpa/inet.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/protocol/gsm_23_003.h>
-#define PCU_IF_VERSION 0x09
+#define PCU_SOCK_DEFAULT "/tmp/pcu_bts"
+
+#define PCU_IF_VERSION 0x0c
#define TXT_MAX_LEN 128
/* msg_type */
#define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */
-#define PCU_IF_MSG_DATA_CNF 0x01 /* confirm (e.g. transmission on PCH) */
#define PCU_IF_MSG_DATA_IND 0x02 /* receive data from given channel */
+#define PCU_IF_MSG_SUSP_REQ 0x03 /* BTS forwards GPRS SUSP REQ to PCU */
+#define PCU_IF_MSG_APP_INFO_REQ 0x04 /* BTS asks PCU to transmit APP INFO via PACCH */
#define PCU_IF_MSG_RTS_REQ 0x10 /* ready to send request */
-#define PCU_IF_MSG_DATA_CNF_DT 0x11 /* confirm (with direct tlli) */
+#define PCU_IF_MSG_DATA_CNF_2 0x11 /* confirm (using message id) */
#define PCU_IF_MSG_RACH_IND 0x22 /* receive RACH */
#define PCU_IF_MSG_INFO_IND 0x32 /* retrieve BTS info */
+#define PCU_IF_MSG_E1_CCU_IND 0x33 /* retrieve E1 CCU comm. parameters */
#define PCU_IF_MSG_ACT_REQ 0x40 /* activate/deactivate PDCH */
#define PCU_IF_MSG_TIME_IND 0x52 /* GSM time indication */
+#define PCU_IF_MSG_INTERF_IND 0x53 /* interference report */
#define PCU_IF_MSG_PAG_REQ 0x60 /* paging request */
#define PCU_IF_MSG_TXT_IND 0x70 /* Text indication for BTS */
+#define PCU_IF_MSG_CONTAINER 0x80 /* Transparent container message */
+
+/* msg_type coming from BSC (inside PCU_IF_MSG_CONTAINER) */
+#define PCU_IF_MSG_NEIGH_ADDR_REQ 0x81 /* Neighbor Address Resolution Request */
+#define PCU_IF_MSG_NEIGH_ADDR_CNF 0x82 /* Neighbor Address Resolution Confirmation */
/* sapi */
#define PCU_IF_SAPI_RACH 0x01 /* channel request on CCCH */
-#define PCU_IF_SAPI_AGCH 0x02 /* assignment on AGCH */
-#define PCU_IF_SAPI_PCH 0x03 /* paging/assignment on PCH */
#define PCU_IF_SAPI_BCCH 0x04 /* SI on BCCH */
#define PCU_IF_SAPI_PDTCH 0x05 /* packet data/control/ccch block */
#define PCU_IF_SAPI_PRACH 0x06 /* packet random access channel */
#define PCU_IF_SAPI_PTCCH 0x07 /* packet TA control channel */
-#define PCU_IF_SAPI_AGCH_DT 0x08 /* assignment on AGCH but with additional TLLI */
+#define PCU_IF_SAPI_PCH_2 0x08 /* assignment on PCH (confirmed using message id) */
+#define PCU_IF_SAPI_AGCH_2 0x09 /* assignment on AGCH (confirmed using message id) */
/* flags */
#define PCU_IF_FLAG_ACTIVE (1 << 0)/* BTS is active */
-#define PCU_IF_FLAG_SYSMO (1 << 1)/* access PDCH of sysmoBTS directly */
+#define PCU_IF_FLAG_DIRECT_PHY (1 << 1)/* access PHY directly via dedicated hardware support */
#define PCU_IF_FLAG_CS1 (1 << 16)
#define PCU_IF_FLAG_CS2 (1 << 17)
#define PCU_IF_FLAG_CS3 (1 << 18)
@@ -46,6 +58,25 @@
#define PCU_IF_FLAG_MCS8 (1 << 27)
#define PCU_IF_FLAG_MCS9 (1 << 28)
+/* NSVC address type */
+#define PCU_IF_ADDR_TYPE_UNSPEC 0x00 /* No address - empty entry */
+#define PCU_IF_ADDR_TYPE_IPV4 0x04 /* IPv4 address */
+#define PCU_IF_ADDR_TYPE_IPV6 0x29 /* IPv6 address */
+
+/* BTS model */
+enum gsm_pcuif_bts_model {
+ PCU_IF_BTS_MODEL_UNSPEC,
+ PCU_IF_BTS_MODEL_LC15,
+ PCU_IF_BTS_MODEL_OC2G,
+ PCU_IF_BTS_MODEL_OCTPHY,
+ PCU_IF_BTS_MODEL_SYSMO,
+ PCU_IF_BTS_MODEL_TRX,
+ PCU_IF_BTS_MODEL_RBS,
+};
+
+#define PCU_IF_NUM_NSVC 2
+#define PCU_IF_NUM_TRX 8
+
enum gsm_pcu_if_text_type {
PCU_VERSION,
PCU_OML_ALERT,
@@ -71,19 +102,10 @@ struct gsm_pcu_if_data {
int16_t lqual_cb; /* !< \brief Link quality in centiBel */
} __attribute__ ((packed));
-/* data confirmation with direct tlli (instead of raw mac block with tlli) */
-struct gsm_pcu_if_data_cnf_dt {
+/* data confirmation with message id (instead of raw mac block) */
+struct gsm_pcu_if_data_cnf {
uint8_t sapi;
- uint32_t tlli;
- uint32_t fn;
- uint16_t arfcn;
- uint8_t trx_nr;
- uint8_t ts_nr;
- uint8_t block_nr;
- int8_t rssi;
- uint16_t ber10k; /* !< \brief BER in units of 0.01% */
- int16_t ta_offs_qbits; /* !< \brief Burst TA Offset in quarter bits */
- int16_t lqual_cb; /* !< \brief Link quality in centiBel */
+ uint32_t msg_id;
} __attribute__ ((packed));
struct gsm_pcu_if_rts_req {
@@ -104,20 +126,31 @@ struct gsm_pcu_if_rach_ind {
uint16_t arfcn;
uint8_t is_11bit;
uint8_t burst_type;
+ uint8_t trx_nr;
+ uint8_t ts_nr;
+} __attribute__ ((packed));
+
+struct gsm_pcu_if_info_trx_ts {
+ uint8_t tsc;
+ uint8_t hopping;
+ uint8_t hsn;
+ uint8_t maio;
+ uint8_t ma_bit_len;
+ uint8_t ma[8];
} __attribute__ ((packed));
struct gsm_pcu_if_info_trx {
uint16_t arfcn;
- uint8_t pdch_mask; /* PDCH channels per TS */
+ uint8_t pdch_mask; /* PDCH timeslot mask */
uint8_t spare;
- uint8_t tsc[8]; /* TSC per channel */
uint32_t hlayer1;
+ struct gsm_pcu_if_info_trx_ts ts[8];
} __attribute__ ((packed));
struct gsm_pcu_if_info_ind {
uint32_t version;
uint32_t flags;
- struct gsm_pcu_if_info_trx trx[8]; /* TRX infos per BTS */
+ struct gsm_pcu_if_info_trx trx[PCU_IF_NUM_TRX]; /* TRX infos per BTS */
uint8_t bsic;
/* RAI */
uint16_t mcc, mnc;
@@ -146,10 +179,26 @@ struct gsm_pcu_if_info_ind {
uint8_t initial_cs;
uint8_t initial_mcs;
/* NSVC */
- uint16_t nsvci[2];
- uint16_t local_port[2];
- uint16_t remote_port[2];
- uint32_t remote_ip[2];
+ uint16_t nsvci[PCU_IF_NUM_NSVC];
+ uint16_t local_port[PCU_IF_NUM_NSVC];
+ uint16_t remote_port[PCU_IF_NUM_NSVC];
+ uint8_t address_type[PCU_IF_NUM_NSVC];
+ union {
+ struct in_addr v4;
+ struct in6_addr v6;
+ } remote_ip[PCU_IF_NUM_NSVC];
+ uint8_t bts_model; /* enum gsm_pcuif_bts_model */
+} __attribute__ ((packed));
+
+/* E1 CCU connection parameters */
+struct gsm_pcu_if_e1_ccu_ind {
+ /* GSM/GPRS air interface */
+ uint8_t trx_nr;
+ uint8_t ts_nr;
+ /* E1 line interface */
+ uint8_t e1_nr;
+ uint8_t e1_ts;
+ uint8_t e1_ts_ss;
} __attribute__ ((packed));
struct gsm_pcu_if_act_req {
@@ -169,6 +218,86 @@ struct gsm_pcu_if_pag_req {
uint8_t identity_lv[9];
} __attribute__ ((packed));
+/* BTS tells PCU to [once] send given application data via PACCH to all UE with active TBF */
+struct gsm_pcu_if_app_info_req {
+ uint8_t application_type; /* 4bit field, see TS 44.060 11.2.47 */
+ uint8_t len; /* length of data */
+ uint8_t data[162]; /* random size choice; ETWS needs 56 bytes */
+} __attribute__ ((packed));
+
+/* BTS tells PCU about a GPRS SUSPENSION REQUEST received on DCCH */
+struct gsm_pcu_if_susp_req {
+ uint32_t tlli;
+ uint8_t ra_id[6];
+ uint8_t cause;
+} __attribute__ ((packed));
+
+/* Interference measurements on PDCH timeslots */
+struct gsm_pcu_if_interf_ind {
+ uint8_t trx_nr;
+ uint8_t spare[3];
+ uint32_t fn;
+ uint8_t interf[8];
+} __attribute__ ((packed));
+
+/* Contains messages transmitted BSC<->PCU, potentially forwarded by BTS via IPA/PCU */
+struct gsm_pcu_if_container {
+ uint8_t msg_type;
+ uint8_t spare;
+ uint16_t length; /* network byte order */
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+/*** Used inside container: NOTE: values must be network byte order here! ***/
+/* Neighbor Address Resolution Request */
+struct gsm_pcu_if_neigh_addr_req {
+ uint16_t local_lac;
+ uint16_t local_ci;
+ uint16_t tgt_arfcn;
+ uint8_t tgt_bsic;
+} __attribute__ ((packed));
+
+/* Neighbor Address Resolution Confirmation */
+struct gsm_pcu_if_neigh_addr_cnf {
+ struct gsm_pcu_if_neigh_addr_req orig_req;
+ uint8_t err_code; /* 0 success, !0 failed & below unset */
+ /* RAI + CI (CGI-PS): */
+ struct __attribute__ ((packed)) {
+ uint16_t mcc;
+ uint16_t mnc;
+ uint8_t mnc_3_digits;
+ uint16_t lac;
+ uint8_t rac;
+ uint16_t cell_identity;
+ } cgi_ps;
+} __attribute__ ((packed));
+
+/* Struct to send a (confirmed) IMMEDIATE ASSIGNMENT message via PCH. The struct is sent as a data request
+ * (data_req) under SAPI PCU_IF_SAPI_PCH_2. */
+struct gsm_pcu_if_pch {
+ /* message id as reference for confirmation */
+ uint32_t msg_id;
+ /* IMSI (to derive paging group) */
+ char imsi[OSMO_IMSI_BUF_SIZE];
+ /* GSM mac-block (with immediate assignment message) */
+ uint8_t data[GSM_MACBLOCK_LEN];
+ /* Set to true in case the receiving end must send a confirmation
+ * when the MAC block (data) has been sent. */
+ bool confirm;
+} __attribute__((packed));
+
+/* Struct to send a (confirmed) IMMEDIATE ASSIGNMENT message via AGCH. The struct is sent as a data request
+ * (data_req) under SAPI PCU_IF_SAPI_AGCH_2. */
+struct gsm_pcu_if_agch {
+ /* message id as reference for confirmation */
+ uint32_t msg_id;
+ /* GSM mac-block (with immediate assignment message) */
+ uint8_t data[GSM_MACBLOCK_LEN];
+ /* Set to true in case the receiving end must send a confirmation
+ * when the MAC block (data) has been sent. */
+ bool confirm;
+} __attribute__((packed));
+
struct gsm_pcu_if {
/* context based information */
uint8_t msg_type; /* message type */
@@ -177,16 +306,20 @@ struct gsm_pcu_if {
union {
struct gsm_pcu_if_data data_req;
- struct gsm_pcu_if_data data_cnf;
- struct gsm_pcu_if_data_cnf_dt data_cnf_dt;
+ struct gsm_pcu_if_data_cnf data_cnf2;
struct gsm_pcu_if_data data_ind;
+ struct gsm_pcu_if_susp_req susp_req;
struct gsm_pcu_if_rts_req rts_req;
struct gsm_pcu_if_rach_ind rach_ind;
struct gsm_pcu_if_txt_ind txt_ind;
struct gsm_pcu_if_info_ind info_ind;
+ struct gsm_pcu_if_e1_ccu_ind e1_ccu_ind;
struct gsm_pcu_if_act_req act_req;
struct gsm_pcu_if_time_ind time_ind;
struct gsm_pcu_if_pag_req pag_req;
+ struct gsm_pcu_if_app_info_req app_info_req;
+ struct gsm_pcu_if_interf_ind interf_ind;
+ struct gsm_pcu_if_container container;
} u;
} __attribute__ ((packed));
diff --git a/include/osmocom/bsc/penalty_timers.h b/include/osmocom/bsc/penalty_timers.h
index 3aae8a0e5..d662b3c31 100644
--- a/include/osmocom/bsc/penalty_timers.h
+++ b/include/osmocom/bsc/penalty_timers.h
@@ -2,40 +2,23 @@
* initially used by handover algorithm 2 to keep per-BTS timers for each subscriber connection. */
#pragma once
-/* Opaque struct to manage penalty timers */
-struct penalty_timers;
+#include <osmocom/gsm/gsm0808_utils.h>
-/* Initialize a list of penalty timers.
- * param ctx: talloc context to allocate in.
- * returns an empty struct penalty_timers. */
-struct penalty_timers *penalty_timers_init(void *ctx);
+struct penalty_timer {
+ struct llist_head entry;
-/* Add a penalty timer for an arbitary object.
- * Note: the ownership of for_object remains with the caller; it is handled as a mere void* value, so
- * invalid pointers can be handled without problems, while common sense dictates that invalidated
- * pointers (freed objects) should probably be removed from this list. More importantly, the pointer must
- * match any pointers used to query penalty timers, so for_object should reference some global/singleton
- * object that tends to stay around longer than the penalty timers.
- * param pt: penalty timers list as from penalty_timers_init().
- * param for_object: arbitrary pointer reference to store a penalty timer for (passing NULL is possible,
- * but note that penalty_timers_clear() will clear all timers if given for_object=NULL).
- * param timeout: penalty time in seconds. */
-void penalty_timers_add(struct penalty_timers *pt, const void *for_object, int timeout);
+ struct gsm0808_cell_id for_target_cell;
+ unsigned int timeout;
+};
-/* Return the amount of penalty time remaining for an object.
- * param pt: penalty timers list as from penalty_timers_init().
- * param for_object: arbitrary pointer reference to query penalty timers for.
- * returns seconds remaining until all penalty time has expired. */
-unsigned int penalty_timers_remaining(struct penalty_timers *pt, const void *for_object);
+void penalty_timers_add(void *ctx, struct llist_head *penalty_timers,
+ const struct gsm0808_cell_id *for_target_cell, int timeout);
+void penalty_timers_add_list(void *ctx, struct llist_head *penalty_timers,
+ const struct gsm0808_cell_id_list2 *for_target_cells, int timeout);
-/* Clear penalty timers for one or all objects.
- * param pt: penalty timers list as from penalty_timers_init().
- * param for_object: arbitrary pointer reference to clear penalty time for,
- * or NULL to clear all timers. */
-void penalty_timers_clear(struct penalty_timers *pt, const void *for_object);
+unsigned int penalty_timers_remaining(struct llist_head *penalty_timers,
+ const struct gsm0808_cell_id *for_target_cell);
+unsigned int penalty_timers_remaining_list(struct llist_head *penalty_timers,
+ const struct gsm0808_cell_id_list2 *for_target_cells);
-/* Free a struct as returned from penalty_timers_init().
- * Clear all timers from the list, deallocate the list and set the pointer to NULL.
- * param pt: pointer-to-pointer which references a struct penalty_timers as returned by
- * penalty_timers_init(); *pt_p will be set to NULL. */
-void penalty_timers_free(struct penalty_timers **pt_p);
+void penalty_timers_clear(struct llist_head *penalty_timers, const struct gsm0808_cell_id *for_target_cell);
diff --git a/include/osmocom/bsc/power_control.h b/include/osmocom/bsc/power_control.h
new file mode 100644
index 000000000..2eb23e7e2
--- /dev/null
+++ b/include/osmocom/bsc/power_control.h
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <stdint.h>
+#include <osmocom/bsc/gsm_data.h>
+#include <osmocom/bsc/meas_rep.h>
+
+int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan, const struct gsm_meas_rep *mr);
+
+/* MS/BS Power related measurement averaging algo */
+enum gsm_power_ctrl_meas_avg_algo {
+ GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE = 0x00,
+ GSM_PWR_CTRL_MEAS_AVG_ALGO_UNWEIGHTED = 0x01,
+ GSM_PWR_CTRL_MEAS_AVG_ALGO_WEIGHTED = 0x02,
+ GSM_PWR_CTRL_MEAS_AVG_ALGO_MOD_MEDIAN = 0x03,
+ /* EWMA is an Osmocom specific algo */
+ GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA = 0x04,
+};
+
+/* MS/BS Power related measurement parameters */
+struct gsm_power_ctrl_meas_params {
+ /* Are these measurement paremeters to be taken into account by loop? */
+ bool enabled;
+
+ /* Thresholds (see 3GPP TS 45.008, section A.3.2.1) */
+ uint8_t lower_thresh; /* lower (decreasing) direction */
+ uint8_t upper_thresh; /* upper (increasing) direction */
+
+ /* Threshold Comparators for lower (decreasing) direction */
+ uint8_t lower_cmp_p; /* P1 for RxLev, P3 for RxQual */
+ uint8_t lower_cmp_n; /* N1 for RxLev, N3 for RxQual */
+ /* Threshold Comparators for upper (increasing) direction */
+ uint8_t upper_cmp_p; /* P2 for RxLev, P4 for RxQual */
+ uint8_t upper_cmp_n; /* N2 for RxLev, N4 for RxQual */
+
+ /* Hreqave and Hreqt (see 3GPP TS 45.008, Annex A) */
+ uint8_t h_reqave;
+ uint8_t h_reqt;
+
+ /* AVG algorithm and its specific parameters */
+ enum gsm_power_ctrl_meas_avg_algo algo;
+ union {
+ /* Exponentially Weighted Moving Average */
+ struct {
+ /* Smoothing factor: higher the value - less smoothing */
+ uint8_t alpha; /* 1 .. 99 (in %) */
+ } ewma;
+ };
+};
+
+enum gsm_power_ctrl_dir {
+ GSM_PWR_CTRL_DIR_UL, /* MS Power Control */
+ GSM_PWR_CTRL_DIR_DL, /* BS Power Control */
+};
+
+enum gsm_power_ctrl_mode {
+ /* Do not send MS/BS Power Control IEs */
+ GSM_PWR_CTRL_MODE_NONE = 0,
+ /* Send MS/BS Power IE only (with target level) */
+ GSM_PWR_CTRL_MODE_STATIC,
+ /* Send MS/BS Power [Parameters] IEs (dynamic mode) */
+ GSM_PWR_CTRL_MODE_DYN_BTS,
+ /* Do not send MS/BS Power IEs and use BSC Power Loop */
+ GSM_PWR_CTRL_MODE_DYN_BSC,
+
+};
+
+/* MS/BS Power Control Parameters */
+struct gsm_power_ctrl_params {
+ /* Power Control direction: Uplink or Downlink */
+ enum gsm_power_ctrl_dir dir;
+ /* Power Control mode to be used by the BTS */
+ enum gsm_power_ctrl_mode mode;
+
+ /* BS Power reduction value / maximum (in dB) */
+ uint8_t bs_power_val_db; /* for static mode */
+ uint8_t bs_power_max_db; /* for dynamic mode */
+
+ /* Power change step size (dynamic mode only) */
+ uint8_t inc_step_size_db; /* increasing direction */
+ uint8_t red_step_size_db; /* reducing direction */
+
+ /* Minimum interval between power level changes */
+ uint8_t ctrl_interval; /* 1 step is 2 SACCH periods */
+
+ /* Measurement averaging parameters for RxLev & RxQual */
+ struct gsm_power_ctrl_meas_params rxqual_meas;
+ struct gsm_power_ctrl_meas_params rxlev_meas;
+ /* Measurement averaging parameters for C/I: */
+ struct gsm_power_ctrl_meas_params ci_fr_meas;
+ struct gsm_power_ctrl_meas_params ci_hr_meas;
+ struct gsm_power_ctrl_meas_params ci_amr_fr_meas;
+ struct gsm_power_ctrl_meas_params ci_amr_hr_meas;
+ struct gsm_power_ctrl_meas_params ci_sdcch_meas;
+ struct gsm_power_ctrl_meas_params ci_gprs_meas;
+};
+
+extern const struct gsm_power_ctrl_params power_ctrl_params_def;
+void power_ctrl_params_def_reset(struct gsm_power_ctrl_params *params,
+ enum gsm_power_ctrl_dir dir);
diff --git a/include/osmocom/bsc/rest_octets.h b/include/osmocom/bsc/rest_octets.h
deleted file mode 100644
index f7ad682b7..000000000
--- a/include/osmocom/bsc/rest_octets.h
+++ /dev/null
@@ -1,122 +0,0 @@
-#ifndef _REST_OCTETS_H
-#define _REST_OCTETS_H
-
-#include <stdbool.h>
-#include <osmocom/gsm/sysinfo.h>
-
-struct gsm_bts;
-
-/* generate SI1 rest octets */
-int rest_octets_si1(uint8_t *data, uint8_t *nch_pos, int is1800_net);
-int rest_octets_si2quater(uint8_t *data, struct gsm_bts *bts);
-int rest_octets_si2ter(uint8_t *data);
-int rest_octets_si2bis(uint8_t *data);
-int rest_octets_si6(uint8_t *data, bool is1800_net);
-
-struct gsm48_si_selection_params {
- uint16_t penalty_time:5,
- temp_offs:3,
- cell_resel_off:6,
- cbq:1,
- present:1;
-};
-
-struct gsm48_si_power_offset {
- uint8_t power_offset:2,
- present:1;
-};
-
-struct gsm48_si3_gprs_ind {
- uint8_t si13_position:1,
- ra_colour:3,
- present:1;
-};
-
-struct gsm48_lsa_params {
- uint32_t prio_thr:3,
- lsa_offset:3,
- mcc:12,
- mnc:12;
- unsigned int present;
-};
-
-struct gsm48_si_ro_info {
- struct gsm48_si_selection_params selection_params;
- struct gsm48_si_power_offset power_offset;
- bool si2ter_indicator;
- bool early_cm_ctrl;
- struct {
- uint8_t where:3,
- present:1;
- } scheduling;
- struct gsm48_si3_gprs_ind gprs_ind;
- /* SI 3 specific */
- bool early_cm_restrict_3g;
- bool si2quater_indicator;
- /* SI 4 specific */
- struct gsm48_lsa_params lsa_params;
- uint16_t cell_id;
- uint8_t break_ind; /* do we have SI7 + SI8 ? */
-};
-
-
-/* Generate SI3 Rest Octests (Chapter 10.5.2.34 / Table 10.4.72) */
-int rest_octets_si3(uint8_t *data, const struct gsm48_si_ro_info *si3);
-
-/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */
-int rest_octets_si4(uint8_t *data, const struct gsm48_si_ro_info *si4, int len);
-
-/* TS 03.60 Chapter 6.3.3.1: Network Mode of Operation */
-enum gprs_nmo {
- GPRS_NMO_I = 0, /* CS pagin on GPRS paging or traffic channel */
- GPRS_NMO_II = 1, /* all paging on CCCH */
- GPRS_NMO_III = 2, /* no paging coordination */
-};
-
-/* TS 04.60 12.24 */
-struct gprs_cell_options {
- enum gprs_nmo nmo;
- /* T3168: wait for packet uplink assignment message */
- uint32_t t3168; /* in milliseconds */
- /* T3192: wait for release of the TBF after reception of the final block */
- uint32_t t3192; /* in milliseconds */
- uint32_t drx_timer_max;/* in seconds */
- uint32_t bs_cv_max;
- uint8_t supports_egprs_11bit_rach;
- bool ctrl_ack_type_use_block; /* use PACKET CONTROL ACKNOWLEDGMENT */
-
- uint8_t ext_info_present;
- struct {
- uint8_t egprs_supported;
- uint8_t use_egprs_p_ch_req;
- uint8_t bep_period;
- uint8_t pfc_supported;
- uint8_t dtm_supported;
- uint8_t bss_paging_coordination;
- } ext_info;
-};
-
-/* TS 04.60 Table 12.9.2 */
-struct gprs_power_ctrl_pars {
- uint8_t alpha;
- uint8_t t_avg_w;
- uint8_t t_avg_t;
- uint8_t pc_meas_chan;
- uint8_t n_avg_i;
-};
-
-struct gsm48_si13_info {
- struct gprs_cell_options cell_opts;
- struct gprs_power_ctrl_pars pwr_ctrl_pars;
- uint8_t bcch_change_mark;
- uint8_t si_change_field;
- uint8_t rac;
- uint8_t spgc_ccch_sup;
- uint8_t net_ctrl_ord;
- uint8_t prio_acc_thr;
-};
-
-/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */
-int rest_octets_si13(uint8_t *data, const struct gsm48_si13_info *si13);
-
-#endif /* _REST_OCTETS_H */
diff --git a/include/osmocom/bsc/signal.h b/include/osmocom/bsc/signal.h
index 62a3d2c88..4d5080da2 100644
--- a/include/osmocom/bsc/signal.h
+++ b/include/osmocom/bsc/signal.h
@@ -68,11 +68,15 @@ enum signal_nm {
S_NM_IPACC_RESTART_ACK, /* nanoBTS has send a restart ack */
S_NM_IPACC_RESTART_NACK,/* nanoBTS has send a restart ack */
S_NM_TEST_REP, /* GSM 12.21 Test Report */
- S_NM_STATECHG_OPER, /* Operational State changed*/
- S_NM_STATECHG_ADM, /* Administrative State changed */
+ S_NM_STATECHG, /* NM Oper/Admin/Avail State changed. arg is struct nm_statechg_signal_data*/
S_NM_OM2K_CONF_RES, /* OM2K Configuration Result */
S_NM_OPSTART_ACK, /* Received OPSTART ACK, arg is struct msgb *oml_msg */
+ S_NM_OPSTART_NACK, /* Received OPSTART NACK, arg is struct msgb *oml_msg */
S_NM_GET_ATTR_REP, /* Received Get Attributes Response, arg is struct msgb *oml_msg */
+ S_NM_SET_RADIO_ATTR_ACK, /* Received Set Radio Carrier Attributes Ack, arg is struct msgb *oml_msg */
+ S_NM_SET_CHAN_ATTR_ACK, /* Received Set Radio Channel Attributes Ack, arg is struct msgb *oml_msg */
+ S_NM_SET_BTS_ATTR_ACK, /* Received Set BTS Attributes Ack, arg is struct msgb *oml_msg */
+ S_NM_RUNNING_CHG, /* Object moves from/to NM running state (op=Enabled adm=Unlocked avail=OK) */
};
/* SS_LCHAN signals */
@@ -116,23 +120,34 @@ enum signal_rf {
};
struct ipacc_ack_signal_data {
- struct gsm_bts_trx *trx;
- uint8_t msg_type;
+ /* The BTS which sent the ACK/NACK to us: */
+ struct gsm_bts *bts;
+ /* messge header containing msg_type, obj_class, obj_inst: */
+ struct abis_om_fom_hdr *foh;
};
struct abis_om2k_mo;
+/* data for <SS_NM, S_NM_STATECHG>: */
struct nm_statechg_signal_data {
struct gsm_bts *bts;
uint8_t obj_class;
void *obj;
- struct gsm_nm_state *old_state;
- struct gsm_nm_state *new_state;
+ struct gsm_nm_state old_state;
+ struct gsm_nm_state new_state;
- /* This pointer is vaold for TS 12.21 MO */
+ /* This pointer is valid for TS 12.21 MO */
struct abis_om_obj_inst *obj_inst;
- /* This pointer is vaold for RBS2000 MO */
- struct abis_om2k_mo *om2k_mo;
+ /* This pointer is valid for RBS2000 MO */
+ const struct abis_om2k_mo *om2k_mo;
+};
+
+/* data for <SS_NM, S_NM_RUNNING_CHG>: */
+struct nm_running_chg_signal_data {
+ struct gsm_bts *bts;
+ uint8_t obj_class;
+ void *obj;
+ bool running;
};
struct nm_om2k_signal_data {
@@ -149,6 +164,20 @@ struct nm_nack_signal_data {
uint8_t mt;
};
+struct nm_fail_rep_signal_data {
+ struct gsm_bts *bts;
+ /* raw data */
+ struct msgb *msg;
+ struct tlv_parsed tp;
+ /* parsed data */
+ struct {
+ const char *event_type;
+ const char *severity;
+ const char *additional_text;
+ const uint8_t *probable_cause;
+ } parsed;
+};
+
struct challoc_signal_data {
struct gsm_bts *bts;
struct gsm_lchan *lchan;
diff --git a/include/osmocom/bsc/smscb.h b/include/osmocom/bsc/smscb.h
new file mode 100644
index 000000000..b4f2e196f
--- /dev/null
+++ b/include/osmocom/bsc/smscb.h
@@ -0,0 +1,73 @@
+#pragma once
+#include <osmocom/bsc/gsm_data.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/sockaddr_str.h>
+#include <osmocom/netif/stream.h>
+#include <osmocom/gsm/cbsp.h>
+
+struct bsc_cbc_link;
+
+/* smscb.c */
+void smscb_global_init(void);
+void bts_smscb_del(struct bts_smscb_message *smscb, struct bts_smscb_chan_state *cstate,
+ const char *reason);
+const char *bts_smscb_msg2str(const struct bts_smscb_message *smscb);
+struct bts_smscb_chan_state *bts_get_smscb_chan(struct gsm_bts *bts, bool extended);
+int cbsp_rx_decoded(struct bsc_cbc_link *cbc, const struct osmo_cbsp_decoded *dec);
+int cbsp_tx_restart(struct bsc_cbc_link *cbc, bool is_emerg);
+const char *bts_smscb_chan_state_name(const struct bts_smscb_chan_state *cstate);
+unsigned int bts_smscb_chan_load_percent(const struct bts_smscb_chan_state *cstate);
+unsigned int bts_smscb_chan_page_count(const struct bts_smscb_chan_state *cstate);
+
+/* cbch_scheduler.c */
+int bts_smscb_gen_sched_arr(struct bts_smscb_chan_state *cstate, struct bts_smscb_page ***arr_out);
+struct bts_smscb_page *bts_smscb_pull_page(struct bts_smscb_chan_state *cstate);
+void bts_smscb_page_done(struct bts_smscb_chan_state *cstate, struct bts_smscb_page *page);
+int bts_smscb_rx_cbch_load_ind(struct gsm_bts *bts, bool cbch_extended, bool is_overflow,
+ uint8_t slot_count);
+void bts_cbch_init(struct gsm_bts *bts);
+void bts_cbch_timer_schedule(struct gsm_bts *bts);
+void bts_cbch_timer_cb(void *data);
+
+enum bsc_cbc_link_mode {
+ BSC_CBC_LINK_MODE_DISABLED = 0,
+ BSC_CBC_LINK_MODE_SERVER,
+ BSC_CBC_LINK_MODE_CLIENT,
+};
+
+extern const struct value_string bsc_cbc_link_mode_names[];
+static inline const char *bsc_cbc_link_mode_name(enum bsc_cbc_link_mode val)
+{ return get_value_string(bsc_cbc_link_mode_names, val); }
+
+extern const struct osmo_sockaddr_str bsc_cbc_default_server_local_addr;
+
+/* cbsp_link.c */
+struct bsc_cbc_link {
+ struct gsm_network *net;
+ enum bsc_cbc_link_mode mode;
+ /* for handling inbound TCP connections */
+ struct {
+ struct osmo_sockaddr_str local_addr;
+ struct osmo_stream_srv *srv;
+ struct osmo_stream_srv_link *link;
+ char *sock_name;
+ struct msgb *msg;
+ } server;
+ /* for handling outbound TCP connections */
+ struct {
+ struct osmo_sockaddr_str remote_addr;
+ struct osmo_sockaddr_str local_addr;
+ struct osmo_stream_cli *cli;
+ char *sock_name;
+ struct msgb *msg;
+ } client;
+};
+int bsc_cbc_link_restart(void);
+int cbsp_tx_decoded(struct bsc_cbc_link *cbc, struct osmo_cbsp_decoded *decoded);
+
+void bts_etws_init(struct gsm_bts *bts);
+
+/* smscb_vty.c: */
+void smscb_vty_init(void);
+void cbc_vty_init(void);
diff --git a/include/osmocom/bsc/system_information.h b/include/osmocom/bsc/system_information.h
index 29f639dca..46213f619 100644
--- a/include/osmocom/bsc/system_information.h
+++ b/include/osmocom/bsc/system_information.h
@@ -3,17 +3,26 @@
#include <osmocom/gsm/sysinfo.h>
-#include <osmocom/bsc/arfcn_range_encode.h>
+#include <osmocom/gsm/gsm48_arfcn_range_encode.h>
+
+/* Complete length of SYSTEM INFORMATION 10 (SACCH) */
+#define SI10_LENGTH 21
struct gsm_bts;
+int band_compatible(const struct gsm_bts *bts, int arfcn);
+int generate_cell_chan_alloc(struct gsm_bts *bts);
+int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts);
int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type type);
+int gsm_generate_si10(struct gsm48_system_information_type_10 *si10, size_t len,
+ const struct gsm_subscriber_connection *conn);
size_t si2q_earfcn_count(const struct osmo_earfcn_si2q *e);
unsigned range1024_p(unsigned n);
unsigned range512_q(unsigned m);
-int range_encode(enum gsm48_range r, int *arfcns, int arfcns_used, int *w,
+int range_encode(enum osmo_gsm48_range r, int *arfcns, int arfcns_used, int *w,
int f0, uint8_t *chan_list);
uint8_t si2q_num(struct gsm_bts *bts);
+int bts_earfcn_del(struct gsm_bts *bts, uint16_t earfcn);
int bts_earfcn_add(struct gsm_bts *bts, uint16_t earfcn, uint8_t thresh_hi, uint8_t thresh_lo, uint8_t prio,
uint8_t qrx, uint8_t meas_bw);
int bts_uarfcn_del(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble);
diff --git a/include/osmocom/bsc/timeslot_fsm.h b/include/osmocom/bsc/timeslot_fsm.h
index d02e156df..c1b61b812 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,
@@ -36,18 +36,30 @@ enum ts_fsm_event {
TS_EV_RSL_DOWN,
TS_EV_LCHAN_REQUESTED,
TS_EV_LCHAN_UNUSED,
+
+ /* RSL responses received from the BTS: */
TS_EV_PDCH_ACT_ACK,
- TS_EV_PDCH_ACT_NACK,
- TS_EV_PDCH_DEACT_ACK,
- TS_EV_PDCH_DEACT_NACK,
-};
+ TS_EV_PDCH_ACT_NACK,
+ TS_EV_PDCH_DEACT_ACK,
+ TS_EV_PDCH_DEACT_NACK,
+
+ /* BSC co-located PCU disconnects from PCU socket, deactivate PDCH */
+ TS_EV_PDCH_DEACT,
-void ts_fsm_init();
+ /* BSC co-located PCU (re)connects to PCU socket, activate PDCH */
+ TS_EV_PDCH_ACT,
+};
void ts_fsm_alloc(struct gsm_bts_trx_ts *ts);
+void ts_fsm_free(struct gsm_bts_trx_ts *ts);
bool ts_is_capable_of_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan);
bool ts_is_capable_of_lchant(struct gsm_bts_trx_ts *ts, enum gsm_chan_t type);
bool ts_is_lchan_waiting_for_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config *target_pchan);
bool ts_is_pchan_switching(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config *target_pchan);
-bool ts_usable_as_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config as_pchan);
+bool ts_usable_as_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config as_pchan, bool allow_pchan_switch);
+
+void ts_set_pchan_is(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan_is);
+
+void ts_pdch_act(struct gsm_bts_trx_ts *ts);
+void ts_pdch_deact(struct gsm_bts_trx_ts *ts);
diff --git a/include/osmocom/bsc/ussd.h b/include/osmocom/bsc/ussd.h
deleted file mode 100644
index 266546811..000000000
--- a/include/osmocom/bsc/ussd.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _USSD_H
-#define _USSD_H
-
-/* Handler function for mobile-originated USSD messages */
-
-#include <osmocom/core/msgb.h>
-
-int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg);
-
-#endif
diff --git a/include/osmocom/bsc/vgcs_fsm.h b/include/osmocom/bsc/vgcs_fsm.h
new file mode 100644
index 000000000..80ea21fd0
--- /dev/null
+++ b/include/osmocom/bsc/vgcs_fsm.h
@@ -0,0 +1,121 @@
+/* Handle a call via VGCS/VBCS (Voice Group/Broadcast Call Service). */
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: AGPL-3.0+
+ *
+ * Author: Andreas Eversberg
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+/* Events for both VGCS/VBS state machines. */
+enum vgcs_fsm_event {
+ /* The BSC sets up a VGCS/VBS call. */
+ VGCS_EV_SETUP,
+ /* The BSC wants to assign a VGCS/VBS channel. */
+ VGCS_EV_ASSIGN_REQ,
+ /* The BTS detects a talker on a channel. */
+ VGCS_EV_TALKER_DET,
+ /* The BTS detects a listener on a channel. */
+ VGCS_EV_LISTENER_DET,
+ /* The MSC accepts a talker. */
+ VGCS_EV_MSC_ACK,
+ /* The MSC rejects a talker. */
+ VGCS_EV_MSC_REJECT,
+ /* The MSC seizes all channels. (blocking for calls) */
+ VGCS_EV_MSC_SEIZE,
+ /* The MSC releases all channels. (unblocking for calls) */
+ VGCS_EV_MSC_RELEASE,
+ /* The MSC sends message to talker. (E.g. CONNECT) */
+ VGCS_EV_MSC_DTAP,
+ /* Channel is now active. Waiting for Talker. */
+ VGCS_EV_LCHAN_ACTIVE,
+ /* Channel activation error. */
+ VGCS_EV_LCHAN_ERROR,
+ /* MGW connection is now active. Waiting for Talker. */
+ VGCS_EV_MGW_OK,
+ /* MGW connection error. */
+ VGCS_EV_MGW_FAIL,
+ /* Channel link established. (Talker establised.) */
+ VGCS_EV_TALKER_EST,
+ /* Channel link data. (Talker sends data.) */
+ VGCS_EV_TALKER_DATA,
+ /* Channel link released. (Talker released.) */
+ VGCS_EV_TALKER_REL,
+ /* Channel link failed. (Talker failed.) */
+ VGCS_EV_TALKER_FAIL,
+ /* Channel is blocked by BSC. */
+ VGCS_EV_BLOCK,
+ /* Channel is rejected by BSC. */
+ VGCS_EV_REJECT,
+ /* Channel is unblocked by BSC. */
+ VGCS_EV_UNBLOCK,
+ /* The connection will be destroyed. (free VGCS resources) */
+ VGCS_EV_CLEANUP,
+ /* The calling subscriber has been assigned to the group channel. */
+ VGCS_EV_CALLING_ASSIGNED,
+};
+
+
+/* States of the VGCS/VBS call state machine */
+enum vgcs_call_fsm_state {
+ /* Call is not setup. Initial state when instance is created. */
+ VGCS_CALL_ST_NULL = 0,
+ /* Call is idle. */
+ VGCS_CALL_ST_IDLE,
+ /* Call is busy, due to a talker in this BSC. */
+ VGCS_CALL_ST_BUSY,
+ /* Call is blocked, due to a talker in a different BSC. */
+ VGCS_CALL_ST_BLOCKED,
+};
+
+/* States of the VGCS/VBS channel state machine */
+enum vgcs_chan_fsm_state {
+ /* Channel not assigned. Initial state when instance is created. */
+ VGCS_CHAN_ST_NULL = 0,
+ /* Wait for establishment of VGCS/VBS channel at BTS. */
+ VGCS_CHAN_ST_WAIT_EST,
+ /* Channel active and idle. Channel is marked as uplink busy. */
+ VGCS_CHAN_ST_ACTIVE_BLOCKED,
+ /* Channel active and idle. Channel is marked as uplink free. */
+ VGCS_CHAN_ST_ACTIVE_FREE,
+ /* Channel active and talker was detected, L2 must be established. */
+ VGCS_CHAN_ST_ACTIVE_INIT,
+ /* Channel active and talker established L2. */
+ VGCS_CHAN_ST_ACTIVE_EST,
+ /* Channel active and wait for talker to release L2. */
+ VGCS_CHAN_ST_ACTIVE_REL,
+};
+
+int vgcs_vbs_chan_start(struct gsm_subscriber_connection *conn, struct msgb *msg);
+int vgcs_vbs_call_start(struct gsm_subscriber_connection *conn, struct msgb *msg);
+
+int bssmap_handle_ass_req_ct_speech(struct gsm_subscriber_connection *conn, struct gsm_bts *bts,
+ struct tlv_parsed *tp, struct gsm0808_channel_type *ct,
+ struct assignment_request *req, uint8_t *cause);
+void bsc_tx_setup_ack(struct gsm_subscriber_connection *conn, struct gsm0808_vgcs_feature_flags *ff);
+void bsc_tx_setup_refuse(struct gsm_subscriber_connection *conn, uint8_t cause);
+void bsc_tx_vgcs_vbs_assignment_result(struct gsm_subscriber_connection *conn, struct gsm0808_channel_type *ct,
+ struct gsm0808_cell_id *ci, uint32_t call_id);
+void bsc_tx_vgcs_vbs_assignment_fail(struct gsm_subscriber_connection *conn, uint8_t cause);
+void bsc_tx_uplink_req(struct gsm_subscriber_connection *conn);
+void bsc_tx_uplink_req_conf(struct gsm_subscriber_connection *conn, struct gsm0808_cell_id *ci, uint8_t *l3_info,
+ uint8_t length);
+void bsc_tx_uplink_app_data(struct gsm_subscriber_connection *conn, struct gsm0808_cell_id *ci, uint8_t *l3_info,
+ uint8_t length);
+void bsc_tx_uplink_release_ind(struct gsm_subscriber_connection *conn, uint8_t cause);
+struct gsm_lchan *vgcs_vbs_find_lchan(struct gsm_bts *bts, struct gsm0808_group_callref *gc);
diff --git a/include/osmocom/bsc/vty.h b/include/osmocom/bsc/vty.h
index e63275546..092bc20dd 100644
--- a/include/osmocom/bsc/vty.h
+++ b/include/osmocom/bsc/vty.h
@@ -6,33 +6,94 @@
#include <osmocom/vty/command.h>
struct gsm_network;
+struct gsm_bts;
+struct gsm_bts_trx;
+struct gsm_bts_trx_ts;
+struct gsm_nm_state;
+struct pchan_load;
+struct gsm_lchan;
+struct bsc_subscr;
+struct gsm_e1_subslot;
+struct e1inp_sign_link;
struct vty;
void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *);
struct buffer *vty_argv_to_buffer(int argc, const char *argv[], int base);
-extern struct cmd_element cfg_description_cmd;
-extern struct cmd_element cfg_no_description_cmd;
-
enum bsc_vty_node {
GSMNET_NODE = _LAST_OSMOVTY_NODE + 1,
+ MGW_NODE,
BTS_NODE,
TRX_NODE,
TS_NODE,
OML_NODE,
- NAT_NODE,
- NAT_BSC_NODE,
MSC_NODE,
OM2K_NODE,
OM2K_CON_GROUP_NODE,
BSC_NODE,
+ CBC_NODE,
+ CBC_SERVER_NODE,
+ CBC_CLIENT_NODE,
+ SMLC_NODE,
+ POWER_CTRL_NODE,
};
struct log_info;
int bsc_vty_init(struct gsm_network *network);
int bsc_vty_init_extra(void);
+void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms);
+int dummy_config_write(struct vty *v);
+void dump_pchan_load_vty(struct vty *vty, char *prefix, const struct pchan_load *pl);
+void bsc_subscr_dump_vty(struct vty *vty, struct bsc_subscr *bsub);
struct gsm_network *gsmnet_from_vty(struct vty *vty);
+int bts_vty_init(void);
+void bts_dump_vty(struct vty *vty, struct gsm_bts *bts);
+void bts_dump_vty_oml_link_state(struct vty *vty, struct gsm_bts *bts);
+void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx, bool print_rsl, bool show_connected);
+void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts);
+void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan);
+void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan);
+
+int bts_trx_vty_init(void);
+void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx);
+void config_write_e1_link(struct vty *vty, struct gsm_e1_subslot *e1_link,
+ const char *prefix);
+void e1isl_dump_vty_tcp(struct vty *vty, const struct e1inp_sign_link *e1l);
+void e1isl_dump_vty(struct vty *vty, struct e1inp_sign_link *e1l);
+void parse_e1_link(struct gsm_e1_subslot *e1_link, const char *line,
+ const char *ts, const char *ss);
+
+enum bsc_vty_cmd_attr {
+ BSC_VTY_ATTR_RESTART_ABIS_OML_LINK = 0,
+ BSC_VTY_ATTR_RESTART_ABIS_RSL_LINK,
+ BSC_VTY_ATTR_NEW_LCHAN,
+ BSC_VTY_ATTR_VENDOR_SPECIFIC,
+ /* NOTE: up to 32 entries */
+};
+
+#define BTS_NR_STR "BTS Number\n"
+#define TRX_NR_STR "TRX Number\n"
+#define TS_NR_STR "Timeslot Number\n"
+#define SS_NR_STR "Sub-slot Number\n"
+#define LCHAN_NR_STR "Logical Channel Number\n"
+#define BTS_TRX_STR BTS_NR_STR TRX_NR_STR
+#define BTS_TRX_TS_STR BTS_TRX_STR TS_NR_STR
+#define BTS_TRX_TS_LCHAN_STR BTS_TRX_TS_STR LCHAN_NR_STR
+#define BTS_NR_TRX_TS_STR2 \
+ "BTS for manual command\n" BTS_NR_STR \
+ "TRX for manual command\n" TRX_NR_STR \
+ "Timeslot for manual command\n" TS_NR_STR
+#define BTS_NR_TRX_TS_SS_STR2 \
+ BTS_NR_TRX_TS_STR2 \
+ "Sub-slot for manual command\n" SS_NR_STR
+
+#define TSC_ARGS_OPT "[tsc] [<1-4>] [<0-7>]"
+#define TSC_ARGS_DOC \
+ "Provide specific TSC Set and Training Sequence Code\n" \
+ "TSC Set\n" \
+ "Training Sequence Code\n"
+
#endif