aboutsummaryrefslogtreecommitdiffstats
path: root/include/osmocom/bsc/gsm_data.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/osmocom/bsc/gsm_data.h')
-rw-r--r--include/osmocom/bsc/gsm_data.h334
1 files changed, 212 insertions, 122 deletions
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 1cba22e..a591af9 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -14,13 +14,13 @@
#include <osmocom/core/stat_item.h>
#include <osmocom/gsm/bts_features.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/core/fsm.h>
#include <osmocom/crypt/auth.h>
#include <osmocom/bsc/rest_octets.h>
-#include <osmocom/bsc/handover.h>
#include <osmocom/core/bitvec.h>
#include <osmocom/gsm/gsm_utils.h>
@@ -31,11 +31,16 @@
#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>
+
+#define GSM_T3122_DEFAULT 10
struct mgcp_client_conf;
struct mgcp_client;
struct mgcp_ctx;
struct gsm0808_cell_id;
+struct mgw_endpoint;
/** annotations for msgb ownership */
#define __uses
@@ -44,6 +49,7 @@ struct gsm0808_cell_id;
struct bsc_subscr;
struct gprs_ra_id;
+struct handover;
#define OBSC_LINKID_CB(__msgb) (__msgb)->cb[3]
@@ -93,6 +99,89 @@ enum subscr_sccp_state {
SUBSCR_SCCP_ST_CONNECTED
};
+struct assignment_request {
+ bool aoip;
+
+ char msc_rtp_addr[INET_ADDRSTRLEN];
+ uint16_t msc_rtp_port;
+
+ enum gsm48_chan_mode chan_mode;
+ bool full_rate;
+};
+
+struct assignment_fsm_data {
+ struct assignment_request req;
+ bool requires_voice_stream;
+
+ struct osmo_fsm_inst *fi;
+ struct gsm_lchan *new_lchan;
+
+ /* 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;
+
+ enum gsm0808_cause failure_cause;
+ enum gsm48_rr_cause rr_cause;
+};
+
+enum hodec_id {
+ HODEC_NONE,
+ HODEC1 = 1,
+ HODEC2 = 2,
+ HODEC_USER,
+ HODEC_REMOTE,
+};
+
+/* For example, to count specific kinds of ongoing handovers, it is useful to be able to OR-combine
+ * scopes. */
+enum handover_scope {
+ HO_NO_HANDOVER = 0,
+ HO_INTRA_CELL = 0x1,
+ HO_INTRA_BSC = 0x2,
+ HO_INTER_BSC_MO = 0x4,
+ HO_INTER_BSC_MT = 0x8,
+ HO_SCOPE_ALL = 0xffff,
+};
+
+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); }
+
+struct handover_mo_req {
+ enum hodec_id from_hodec_id;
+ struct gsm_lchan *old_lchan;
+ struct neighbor_ident_key target_nik;
+ enum gsm_chan_t new_lchan_type; /*< leave GSM_LCHAN_NONE to use same as old_lchan */
+};
+
+struct handover_mt_req {
+ struct gsm0808_channel_type ct;
+ struct gsm0808_speech_codec_list scl;
+ struct gsm0808_encrypt_info ei;
+ struct gsm_classmark classmark;
+ struct gsm0808_cell_id cell_id_serving;
+ struct gsm0808_cell_id cell_id_target;
+};
+
+
+struct handover {
+ struct osmo_fsm_inst *fi;
+
+ enum hodec_id from_hodec_id;
+ enum handover_scope scope;
+ enum gsm_chan_t new_lchan_type;
+ struct neighbor_ident_key target_cell;
+
+ struct {
+ uint8_t ho_ref;
+ struct gsm_bts *new_bts;
+ struct gsm_lchan *new_lchan;
+ bool async;
+ struct handover_mt_req inter_bsc;
+ } mt;
+};
+
/* active radio connection of a mobile subscriber */
struct gsm_subscriber_connection {
/* global linked list of subscriber_connections */
@@ -110,18 +199,17 @@ struct gsm_subscriber_connection {
/* the primary / currently active lchan to the BTS/subscriber */
struct gsm_lchan *lchan;
- /* handover information, if a handover is pending for this conn. */
- struct bsc_handover *ho;
+ struct assignment_fsm_data assignment;
- /* the future allocated but not yet used lchan during ASSIGNMENT */
- struct gsm_lchan *secondary_lchan;
+ /* handover information, if a handover is pending for this conn. */
+ struct handover ho;
/* buffer/cache for classmark of the ME of the subscriber */
struct gsm_classmark classmark;
/* Cache DTAP messages during handover/assignment (msgb_enqueue()/msgb_dequeue())*/
- struct llist_head ho_dtap_cache;
- unsigned int ho_dtap_cache_len;
+ struct llist_head gscon_dtap_cache;
+ unsigned int gscon_dtap_cache_len;
struct {
int failures;
@@ -135,7 +223,6 @@ struct gsm_subscriber_connection {
* i.e. by heeding the "Codec list (MSC Preferred)", we inherently heed the MS bearer
* capabilities, which the MSC is required to translate into the codec list. */
struct gsm0808_speech_codec_list codec_list;
- bool codec_list_present;
/* flag to prevent multiple simultaneous ciphering commands */
int ciphering_handled;
@@ -164,21 +251,12 @@ struct gsm_subscriber_connection {
uint16_t cic;
uint32_t rtp_ip;
int rtp_port;
- /* RTP address of the remote end (assigned by MSC through assignment request) */
- struct sockaddr_storage aoip_rtp_addr_remote;
-
- /* Local RTP address (reported back to the MSC by us with the
- * assignment complete message) */
- struct sockaddr_storage aoip_rtp_addr_local;
-
- /* FSM instance to control the BTS sided RTP connection */
- struct osmo_fsm_inst *fi_bts;
- /* FSM instance to control the MSC sided RTP connection */
- struct osmo_fsm_inst *fi_msc;
+ char msc_assigned_rtp_addr[INET_ADDRSTRLEN];
+ uint16_t msc_assigned_rtp_port;
- /* Endpoint identifier of the MGCP endpoint the connection uses */
- char *mgw_endpoint;
+ struct mgw_endpoint *mgw_endpoint;
+ struct mgwep_ci *mgw_endpoint_ci_msc;
/* Channel rate flag, FR=1, HR=0, Invalid=-1 */
int full_rate;
@@ -296,18 +374,6 @@ struct om2k_mo {
#define LCHAN_SAPI_UNUSED 0
#define LCHAN_SAPI_MS 1
#define LCHAN_SAPI_NET 2
-#define LCHAN_SAPI_REL 3
-
-/* state of a logical channel */
-enum gsm_lchan_state {
- LCHAN_S_NONE, /* channel is not active */
- LCHAN_S_ACT_REQ, /* channel activation requested */
- LCHAN_S_ACTIVE, /* channel is active and operational */
- LCHAN_S_REL_REQ, /* channel release has been requested */
- LCHAN_S_REL_ERR, /* channel is in an error state */
- LCHAN_S_BROKEN, /* channel is somehow unusable */
- LCHAN_S_INACTIVE, /* channel is set inactive */
-};
/* BTS ONLY */
#define MAX_NUM_UL_MEAS 104
@@ -384,11 +450,65 @@ struct gsm_encr {
bsc_subscr_name(lchan && lchan->conn ? lchan->conn->bsub : NULL), \
## args)
+/* 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");
+ * }
+ * Iterate only those lchans that have an FSM allocated. */
+#define ts_for_each_lchan(lchan, ts) ts_as_pchan_for_each_lchan(lchan, ts, ts->pchan_is)
+
+/* Same as ts_for_each_lchan() but with an explicit pchan kind (GSM_PCHAN_* constant).
+ * Iterate only those lchans that have an FSM allocated. */
+#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++)
+
+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 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;
+
+ struct osmo_fsm_inst *fi;
+ struct mgwep_ci *mgw_endpoint_ci_bts;
+
+ struct {
+ enum lchan_activate_mode activ_for;
+ bool concluded; /*< true as soon as LCHAN_ST_ACTIVE is reached */
+ bool requires_voice_stream;
+ bool mgw_endpoint_available;
+ enum gsm0808_cause gsm0808_error_cause;
+ } activate;
+
+ /* 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 release_requested;
+ bool deact_sacch;
+
+ char *last_error;
+
+ /* There is an RSL error cause of value 0, so we need a separate flag. */
+ bool release_in_error;
+ uint8_t error_cause;
+
/* The logical channel type */
enum gsm_chan_t type;
/* RSL channel mode */
@@ -396,9 +516,6 @@ struct gsm_lchan {
/* If TCH, traffic channel mode */
enum gsm48_chan_mode tch_mode;
enum lchan_csd_mode csd_mode;
- /* State */
- enum gsm_lchan_state state;
- const char *broken_reason;
/* Power levels for MS and BTS */
uint8_t bs_power;
uint8_t ms_power;
@@ -413,15 +530,14 @@ struct gsm_lchan {
uint8_t sapis[8];
struct {
- uint32_t bound_ip;
- uint32_t connect_ip;
+ 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;
- struct rtp_socket *rtp_socket;
/* info we need to postpone the AoIP
* assignment completed message */
@@ -433,15 +549,6 @@ struct gsm_lchan {
uint8_t rqd_ta;
- char *name;
-
- struct osmo_timer_list T3101;
- struct osmo_timer_list T3109;
- struct osmo_timer_list T3111;
- struct osmo_timer_list error_timer;
- struct osmo_timer_list act_timer;
- struct osmo_timer_list rel_work;
- uint8_t error_cause;
/* table of neighbor cell measurements */
struct neigh_meas_proc neigh_meas[MAX_NEIGH_MEAS];
@@ -453,43 +560,38 @@ struct gsm_lchan {
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;
-
- struct {
- /* channel activation type and handover ref */
- uint8_t act_type;
- uint8_t ho_ref;
- struct gsm48_req_ref *rqd_ref;
- uint8_t rqd_ta;
- } dyn;
};
-enum {
- TS_F_PDCH_ACTIVE = 0x1000,
- TS_F_PDCH_ACT_PENDING = 0x2000,
- TS_F_PDCH_DEACT_PENDING = 0x4000,
- TS_F_PDCH_PENDING_MASK = (TS_F_PDCH_ACT_PENDING | TS_F_PDCH_DEACT_PENDING),
-} gsm_bts_trx_ts_flags;
-
/* One Timeslot in a TRX */
struct gsm_bts_trx_ts {
struct gsm_bts_trx *trx;
- bool initialized;
-
/* number of this timeslot at the TRX */
uint8_t nr;
- enum gsm_phys_chan_config pchan;
-
- struct {
- enum gsm_phys_chan_config pchan_is;
- enum gsm_phys_chan_config pchan_want;
- struct msgb *pending_chan_activ;
- } dyn;
+ struct osmo_fsm_inst *fi;
+ char *last_errmsg;
+
+ /* vty phys_chan_config setting, not necessarily in effect in case it was changed in the telnet
+ * 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
+ * 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
+ * GSM_PCHAN_NONE or one of the standard GSM_PCHAN_TCH_F, GSM_PCHAN_TCH_H, GSM_PCHAN_PDCH.
+ * Callers can use this transparently without being aware of dyn ts. */
+ enum gsm_phys_chan_config pchan_is;
+
+ /* After a PDCH ACT NACK, we shall not infinitely loop to try and ACT again.
+ * Also marks a timeslot where PDCH was deactivated by VTY. This is cleared whenever a timeslot
+ * enters IN_USE state, i.e. after each TCH use we try to PDCH ACT once again. */
+ bool pdch_act_allowed;
- unsigned int flags;
struct gsm_abis_mo mo;
struct tlv_parsed nm_attr;
uint8_t nm_chan_comb;
@@ -1009,9 +1111,12 @@ struct gsm_bts {
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(struct gsm_network *net, int num);
-bool gsm_bts_matches_cell_id(struct gsm_bts *bts, const struct gsm0808_cell_id *ci);
-struct gsm_bts *gsm_bts_by_cell_id(struct gsm_network *net, const struct gsm0808_cell_id *ci);
+struct gsm_bts *gsm_bts_num(const struct gsm_network *net, int num);
+bool gsm_bts_matches_cell_id(const struct gsm_bts *bts, const struct gsm0808_cell_id *cell_id);
+bool gsm_bts_matches_lai(const struct gsm_bts *bts, const struct osmo_location_area_id *lai);
+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);
@@ -1028,9 +1133,12 @@ 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[];
-const struct value_string gsm_pchant_names[13];
-const struct value_string gsm_pchant_descs[13];
+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);
@@ -1038,7 +1146,6 @@ 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);
-const char *gsm_lchans_name(enum gsm_lchan_state s);
static inline char *gsm_lchan_name(const struct gsm_lchan *lchan)
{
@@ -1084,7 +1191,7 @@ struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
int *rc);
enum gsm_phys_chan_config ts_pchan(struct gsm_bts_trx_ts *ts);
-uint8_t ts_subslots(struct gsm_bts_trx_ts *ts);
+uint8_t pchan_subslots(enum gsm_phys_chan_config pchan);
bool ts_is_tch(struct gsm_bts_trx_ts *ts);
@@ -1241,23 +1348,6 @@ static const struct rate_ctr_group_desc bsc_ctrg_desc = {
bsc_ctr_description,
};
-#define GSM_T3101_DEFAULT 3 /* s */
-#define GSM_T3103_DEFAULT 5 /* s */
-#define GSM_T3105_DEFAULT 100 /* ms */
-#define GSM_T3107_DEFAULT 5 /* s */
-#define GSM_T3109_DEFAULT 5 /* s, must be 2s + radio_link_timeout*0.48 */
-#define GSM_T3111_DEFAULT 2 /* s */
-#define GSM_T3113_DEFAULT 10 /* s */
-#define GSM_T3115_DEFAULT 10
-#define GSM_T3117_DEFAULT 10
-#define GSM_T3119_DEFAULT 10
-#define GSM_T3122_DEFAULT 10
-#define GSM_T3141_DEFAULT 10
-#define GSM_T10_DEFAULT 6 /* RR Assignment timeout, in seconds */
-#define GSM_T7_DEFAULT 10 /* inter-BSC MO Handover first timeout, in seconds */
-#define GSM_T8_DEFAULT 10 /* inter-BSC MO Handover second timeout, in seconds */
-#define GSM_T101_DEFAULT 10 /* inter-BSC MT Handover timeout, in seconds */
-
struct gsm_tz {
int override; /* if 0, use system's time zone instead. */
int hr; /* hour */
@@ -1289,23 +1379,8 @@ struct gsm_network {
unsigned int num_bts;
struct llist_head bts_list;
- /* timer values */
- int T3101;
- int T3103; /*< Handover timeout */
- int T3105;
- int T3107;
- int T3109;
- int T3111;
- int T3113;
- int T3115;
- int T3117;
- int T3119;
- int T3122;
- int T3141;
- int T10; /*< RR Assignment timeout, in seconds */
- int T7; /*< inter-BSC handover MO timeout from Handover Required to Handover Command */
- int T8; /*< inter-BSC handover MO timeout from Handover Command to final Clear*/
- int T101; /*< inter-BSC handover MT timeout from Handover Request to Handover Accept */
+ /* shall reference gsm_network_T[] */
+ struct T_def *T_defs;
enum gsm_chan_t ctype_by_chreq[_NUM_CHREQ_T];
@@ -1339,9 +1414,6 @@ struct gsm_network {
* pointer is NULL to indicate absence of a bsc_subscribers list. */
struct llist_head *bsc_subscribers;
- /* Periodic location update default value */
- uint8_t t3212;
-
/* Timer for periodic channel load measurements to maintain each BTS's T3122. */
struct osmo_timer_list t3122_chan_load_timer;
@@ -1354,6 +1426,11 @@ struct gsm_network {
struct neighbor_ident_list *neighbor_bss_cells;
};
+struct gsm_audio_support {
+ uint8_t hr : 1,
+ ver : 7;
+};
+
static inline const struct osmo_location_area_id *bts_lai(struct gsm_bts *bts)
{
static struct osmo_location_area_id lai;
@@ -1489,12 +1566,25 @@ void gsm_bts_set_radio_link_timeout(struct gsm_bts *bts, int value);
bool classmark_is_r99(struct gsm_classmark *cm);
-void gsm_ts_check_init(struct gsm_bts_trx_ts *ts);
-void gsm_trx_mark_all_ts_uninitialized(struct gsm_bts_trx *trx);
-void gsm_bts_mark_all_ts_uninitialized(struct gsm_bts *bts);
-
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);
+
+int bts_count_free_ts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan);
+
+static inline const char *gsm48_chan_mode_name(enum gsm48_chan_mode val)
+{ return get_value_string(gsm48_chan_mode_names, val); }
-bool on_gsm_ts_init(struct gsm_bts_trx_ts *ts);
+int bsc_match_codec_pref(enum gsm48_chan_mode *chan_mode,
+ bool *full_rate,
+ const struct gsm0808_channel_type *ct,
+ const struct gsm0808_speech_codec_list *scl,
+ struct gsm_audio_support * const *audio_support,
+ int audio_length);
#endif /* _GSM_DATA_H */