diff options
Diffstat (limited to 'include/osmocom/bsc')
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 |