pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/28979 )
Change subject: split lchan specific defines and code to its own file
......................................................................
split lchan specific defines and code to its own file
It is really difficult right now to find out where all the different
stuff relative to operation and lifecycle of an lchan is. Let's move
everything to its own file to have all the related defines and logic
together.
Change-Id: Idd855d126c43ac6576c5f3ba7e0b8014127a65e1
---
M include/osmocom/bsc/Makefile.am
M include/osmocom/bsc/assignment_fsm.h
M include/osmocom/bsc/gsm_data.h
A include/osmocom/bsc/lchan.h
M include/osmocom/bsc/lchan_rtp_fsm.h
M src/osmo-bsc/Makefile.am
M src/osmo-bsc/abis_rsl.c
M src/osmo-bsc/assignment_fsm.c
M src/osmo-bsc/bsc_subscr_conn_fsm.c
M src/osmo-bsc/bsc_vty.c
M src/osmo-bsc/bts_trx.c
M src/osmo-bsc/bts_trx_vty.c
M src/osmo-bsc/gsm_04_08_rr.c
M src/osmo-bsc/gsm_data.c
M src/osmo-bsc/handover_fsm.c
A src/osmo-bsc/lchan.c
M src/osmo-bsc/lchan_fsm.c
M src/osmo-bsc/lchan_rtp_fsm.c
M src/osmo-bsc/meas_feed.c
M src/osmo-bsc/osmo_bsc_lcls.c
M src/osmo-bsc/timeslot_fsm.c
M tests/handover/handover_test.c
22 files changed, 541 insertions(+), 476 deletions(-)
Approvals:
laforge: Looks good to me, but someone else must approve
fixeria: Looks good to me, but someone else must approve
pespin: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am
index 3ddad45..115c92b 100644
--- a/include/osmocom/bsc/Makefile.am
+++ b/include/osmocom/bsc/Makefile.am
@@ -32,6 +32,7 @@
handover_vty.h \
ipaccess.h \
lb.h \
+ lchan.h \
lchan_fsm.h \
lchan_rtp_fsm.h \
lchan_select.h \
diff --git a/include/osmocom/bsc/assignment_fsm.h b/include/osmocom/bsc/assignment_fsm.h
index 6c429e4..98bec42 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 { \
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 91c78d1..cb64c4c 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -35,6 +35,7 @@
#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
@@ -91,22 +92,6 @@
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;
@@ -122,34 +107,6 @@
SUBSCR_SCCP_ST_CONNECTED
};
-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);
-
-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,
-};
-
-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_* */
- enum lchan_csd_mode csd_mode;
-};
-
enum assign_for {
ASSIGN_FOR_NONE,
ASSIGN_FOR_BSSMAP_REQ,
@@ -161,14 +118,6 @@
static inline const char *assign_for_name(enum assign_for assign_for)
{ return get_value_string(assign_for_names, assign_for); }
-/* 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;
-};
-
/* 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. */
@@ -444,21 +393,6 @@
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,
-};
-
-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;
-}
-
/* 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
@@ -556,11 +490,6 @@
* rest octets elements, so to really fit 48 EARFCNs most other SI2quater elements need to be omitted. */
#define MAX_EARFCN_LIST (3*16)
-/* is the data link established? who established it? */
-#define LCHAN_SAPI_UNUSED 0
-#define LCHAN_SAPI_MS 1
-#define LCHAN_SAPI_NET 2
-
/* BTS ONLY */
#define MAX_NUM_UL_MEAS 104
#define LC_UL_M_F_L1_VALID (1 << 0)
@@ -599,33 +528,6 @@
};
/* /BTS ONLY */
-/* 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_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];
-};
-
-#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)
-
/* Iterate at most N lchans of the given timeslot.
* usage:
* struct gsm_lchan *lchan;
@@ -641,260 +543,9 @@
&& ((lchan - (ts)->lchan) < (N)); \
lchan++)
-enum lchan_activate_for {
- ACTIVATE_FOR_NONE,
- ACTIVATE_FOR_MS_CHANNEL_REQUEST,
- ACTIVATE_FOR_ASSIGNMENT,
- ACTIVATE_FOR_HANDOVER,
- ACTIVATE_FOR_VTY,
- ACTIVATE_FOR_MODE_MODIFY_RTP,
-};
-
-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;
- bool requires_voice_stream;
- 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;
-
- bool vamos;
-
- /* 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;
- bool requires_voice_stream;
- 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;
-
- bool vamos;
-};
-
#define INTERF_DBM_UNKNOWN 0
#define INTERF_BAND_UNKNOWN 0xff
-/* 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;
- 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;
- /* 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 speech_mode;
-
- /* info we need to postpone the AoIP
- * assignment completed message */
- struct {
- uint8_t rr_cause;
- bool valid;
- } ass_compl;
- } 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;
-
- /* 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;
-};
-
/* One Timeslot in a TRX */
struct gsm_bts_trx_ts {
struct gsm_bts_trx *trx;
@@ -967,8 +618,6 @@
struct chan_counts chan_counts;
};
-#define GSM_LCHAN_SI(lchan, i) (void *)((lchan)->si.buf[i][0])
-
struct gsm_envabtse {
struct gsm_abis_mo mo;
};
@@ -1151,14 +800,6 @@
const char *gsm_chreq_name(enum gsm_chreq_reason_t c);
char *gsm_ts_name(const struct gsm_bts_trx_ts *ts);
char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts);
-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;
-}
void gsm_abis_mo_reset(struct gsm_abis_mo *mo);
void gsm_mo_init(struct gsm_abis_mo *mo, struct gsm_bts *bts,
@@ -1190,13 +831,9 @@
uint8_t pchan_subslots_vamos(enum gsm_phys_chan_config pchan);
bool ts_is_tch(struct gsm_bts_trx_ts *ts);
-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);
-
struct gsm_bts *conn_get_bts(struct gsm_subscriber_connection *conn);
void conn_update_ms_power_class(struct gsm_subscriber_connection *conn, uint8_t power_class);
-void lchan_update_ms_power_ctrl_level(struct gsm_lchan *lchan, int ms_power_dbm);
struct gsm_tz {
int override; /* if 0, use system's time zone instead. */
diff --git a/include/osmocom/bsc/lchan.h b/include/osmocom/bsc/lchan.h
new file mode 100644
index 0000000..4a4634c
--- /dev/null
+++ b/include/osmocom/bsc/lchan.h
@@ -0,0 +1,379 @@
+#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/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);
+
+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,
+};
+
+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_* */
+ enum lchan_csd_mode csd_mode;
+};
+
+/* 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_VTY,
+ ACTIVATE_FOR_MODE_MODIFY_RTP,
+};
+
+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;
+ bool requires_voice_stream;
+ 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;
+
+ bool vamos;
+
+ /* 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;
+ bool requires_voice_stream;
+ 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;
+
+ bool vamos;
+};
+
+/* 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;
+ 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;
+ /* 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 speech_mode;
+
+ /* info we need to postpone the AoIP
+ * assignment completed message */
+ struct {
+ uint8_t rr_cause;
+ bool valid;
+ } ass_compl;
+ } 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;
+
+ /* 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_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_rtp_fsm.h b/include/osmocom/bsc/lchan_rtp_fsm.h
index 18ab348..5dbdb0a 100644
--- a/include/osmocom/bsc/lchan_rtp_fsm.h
+++ b/include/osmocom/bsc/lchan_rtp_fsm.h
@@ -1,6 +1,8 @@
/* 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); \
diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am
index f075580..c242e36 100644
--- a/src/osmo-bsc/Makefile.am
+++ b/src/osmo-bsc/Makefile.am
@@ -70,6 +70,7 @@
handover_logic.c \
handover_vty.c \
lb.c \
+ lchan.c \
lchan_fsm.c \
lchan_rtp_fsm.c \
lchan_select.c \
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index c650c36..8ec94a9 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -57,6 +57,7 @@
#include <osmocom/bsc/bts.h>
#include <osmocom/bsc/power_control.h>
#include <osmocom/bsc/chan_counts.h>
+#include <osmocom/bsc/lchan.h>
static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan,
struct gsm_meas_rep *resp)
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index 1918252..7ca17c6 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -37,7 +37,7 @@
#include <osmocom/bsc/abis_rsl.h>
#include <osmocom/bsc/bts.h>
#include <osmocom/bsc/bsc_stats.h>
-
+#include <osmocom/bsc/lchan.h>
#include <osmocom/bsc/assignment_fsm.h>
static struct osmo_fsm assignment_fsm;
diff --git a/src/osmo-bsc/bsc_subscr_conn_fsm.c b/src/osmo-bsc/bsc_subscr_conn_fsm.c
index 7c0c7c3..21988ce 100644
--- a/src/osmo-bsc/bsc_subscr_conn_fsm.c
+++ b/src/osmo-bsc/bsc_subscr_conn_fsm.c
@@ -32,6 +32,7 @@
#include <osmocom/bsc/handover_fsm.h>
#include <osmocom/bsc/lchan_fsm.h>
#include <osmocom/bsc/lchan_rtp_fsm.h>
+#include <osmocom/bsc/lchan.h>
#include <osmocom/bsc/bsc_subscriber.h>
#include <osmocom/bsc/osmo_bsc_sigtran.h>
#include <osmocom/bsc/osmo_bsc_lcls.h>
diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c
index 8f0618a..61a1559 100644
--- a/src/osmo-bsc/bsc_vty.c
+++ b/src/osmo-bsc/bsc_vty.c
@@ -65,6 +65,7 @@
#include <osmocom/bsc/assignment_fsm.h>
#include <osmocom/bsc/bssmap_reset.h>
#include <osmocom/bsc/bsc_msc_data.h>
+#include <osmocom/bsc/lchan.h>
#include <inttypes.h>
diff --git a/src/osmo-bsc/bts_trx.c b/src/osmo-bsc/bts_trx.c
index 71d9fbf..2202347 100644
--- a/src/osmo-bsc/bts_trx.c
+++ b/src/osmo-bsc/bts_trx.c
@@ -31,6 +31,7 @@
#include <osmocom/bsc/pcu_if.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/nm_common_fsm.h>
+#include <osmocom/bsc/lchan.h>
static int gsm_bts_trx_talloc_destructor(struct gsm_bts_trx *trx)
{
diff --git a/src/osmo-bsc/bts_trx_vty.c b/src/osmo-bsc/bts_trx_vty.c
index d8c633a..b5275ac 100644
--- a/src/osmo-bsc/bts_trx_vty.c
+++ b/src/osmo-bsc/bts_trx_vty.c
@@ -39,6 +39,7 @@
#include <osmocom/bsc/system_information.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/timeslot_fsm.h>
+#include <osmocom/bsc/lchan.h>
#include <osmocom/bsc/lchan_fsm.h>
#include <osmocom/bsc/lchan_select.h>
#include <osmocom/bsc/bts.h>
diff --git a/src/osmo-bsc/gsm_04_08_rr.c b/src/osmo-bsc/gsm_04_08_rr.c
index 13b00da..3321a0e 100644
--- a/src/osmo-bsc/gsm_04_08_rr.c
+++ b/src/osmo-bsc/gsm_04_08_rr.c
@@ -46,7 +46,7 @@
#include <osmocom/bsc/bsc_msc_data.h>
#include <osmocom/bsc/system_information.h>
#include <osmocom/bsc/bts.h>
-
+#include <osmocom/bsc/lchan.h>
int gsm48_sendmsg(struct msgb *msg)
{
diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c
index 174ff2a..1562ea8 100644
--- a/src/osmo-bsc/gsm_data.c
+++ b/src/osmo-bsc/gsm_data.c
@@ -325,32 +325,6 @@
return ts2str;
}
-void lchan_update_name(struct gsm_lchan *lchan)
-{
- struct gsm_bts_trx_ts *ts = lchan->ts;
- if (lchan->name)
- talloc_free(lchan->name);
- lchan->name = talloc_asprintf(ts->trx, "(bts=%d,trx=%d,ts=%d,ss=%s%d)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
- lchan->vamos.is_secondary ? "shadow" : "",
- lchan->nr - (lchan->vamos.is_secondary ? ts->max_primary_lchans : 0));
-}
-
-/* If the lchan is currently active, return the duration since activation in milliseconds.
- * Otherwise return 0. */
-uint64_t gsm_lchan_active_duration_ms(const struct gsm_lchan *lchan)
-{
- struct timespec now, elapsed;
-
- if (lchan->active_start.tv_sec == 0 && lchan->active_start.tv_nsec == 0)
- return 0;
-
- osmo_clock_gettime(CLOCK_MONOTONIC, &now);
- timespecsub(&now, &lchan->active_start, &elapsed);
-
- return elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000;
-}
-
/* obtain the MO structure for a given object instance */
static inline struct gsm_abis_mo *
gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
@@ -668,36 +642,6 @@
return pchan_is_tch(ts->pchan_is);
}
-/* For a VAMOS secondary shadow lchan, return its primary lchan. If the lchan is not a secondary lchan, return NULL. */
-struct gsm_lchan *gsm_lchan_vamos_to_primary(const struct gsm_lchan *lchan_vamos)
-{
- struct gsm_lchan *lchan_primary;
- if (!lchan_vamos || !lchan_vamos->vamos.is_secondary)
- return NULL;
- /* OsmoBSC currently does not support mixed TCH/F + TCH/H VAMOS multiplexes. Hence the primary <-> secondary
- * relation is a simple index shift in the lchan array. If mixed multiplexes were allowed, a TCH/F primary might
- * have two TCH/H VAMOS secondary lchans, etc. Fortunately, we don't need to care about that. */
- lchan_primary = (struct gsm_lchan*)lchan_vamos - lchan_vamos->ts->max_primary_lchans;
- if (!lchan_primary->fi)
- return NULL;
- return lchan_primary;
-}
-
-/* For a primary lchan, return its VAMOS secondary shadow lchan. If the lchan is not a primary lchan, return NULL. */
-struct gsm_lchan *gsm_lchan_primary_to_vamos(const struct gsm_lchan *lchan_primary)
-{
- struct gsm_lchan *lchan_vamos;
- if (!lchan_primary || lchan_primary->vamos.is_secondary)
- return NULL;
- /* OsmoBSC currently does not support mixed TCH/F + TCH/H VAMOS multiplexes. Hence the primary <-> secondary
- * relation is a simple index shift in the lchan array. If mixed multiplexes were allowed, a TCH/F primary might
- * have two TCH/H VAMOS secondary lchans, etc. Fortunately, we don't need to care about that. */
- lchan_vamos = (struct gsm_lchan*)lchan_primary + lchan_primary->ts->max_primary_lchans;
- if (!lchan_vamos->fi)
- return NULL;
- return lchan_vamos;
-}
-
struct gsm_bts *conn_get_bts(struct gsm_subscriber_connection *conn) {
if (!conn || !conn->lchan)
return NULL;
@@ -990,59 +934,6 @@
lchan_update_ms_power_ctrl_level(conn->lchan, bts->ms_max_power);
}
-void lchan_update_ms_power_ctrl_level(struct gsm_lchan *lchan, int ms_power_dbm)
-{
- struct gsm_bts *bts = lchan->ts->trx->bts;
- struct gsm_subscriber_connection *conn = lchan->conn;
- int max_pwr_dbm_pwclass, new_pwr;
- bool send_pwr_ctrl_msg = false;
-
- LOG_LCHAN(lchan, LOGL_DEBUG,
- "MS Power level update requested: %d dBm\n", ms_power_dbm);
-
- if (!conn)
- goto ms_power_default;
-
- if (conn->ms_power_class == 0)
- goto ms_power_default;
-
- if ((max_pwr_dbm_pwclass = (int)ms_class_gmsk_dbm(bts->band, conn->ms_power_class)) < 0) {
- LOG_LCHAN(lchan, LOGL_INFO,
- "Failed getting max ms power for power class %" PRIu8
- " on band %s, providing default max ms power\n",
- conn->ms_power_class, gsm_band_name(bts->band));
- goto ms_power_default;
- }
-
- /* Current configured max pwr is above maximum one allowed on
- current band + ms power class, so use that one. */
- if (ms_power_dbm > max_pwr_dbm_pwclass)
- ms_power_dbm = max_pwr_dbm_pwclass;
-
-ms_power_default:
- if ((new_pwr = ms_pwr_ctl_lvl(bts->band, ms_power_dbm)) < 0) {
- LOG_LCHAN(lchan, LOGL_INFO,
- "Failed getting max ms power level %d on band %s,"
- " providing default max ms power\n",
- ms_power_dbm, gsm_band_name(bts->band));
- return;
- }
-
- LOG_LCHAN(lchan, LOGL_DEBUG,
- "MS Power level update (power class %" PRIu8 "): %" PRIu8 " -> %d\n",
- conn ? conn->ms_power_class : 0, lchan->ms_power, new_pwr);
-
- /* If chan was already activated and max ms_power changes (due to power
- classmark received), send an MS Power Control message */
- if (lchan->activate.activ_ack && new_pwr != lchan->ms_power)
- send_pwr_ctrl_msg = true;
-
- lchan->ms_power = new_pwr;
-
- if (send_pwr_ctrl_msg)
- rsl_chan_ms_power_ctrl(lchan);
-}
-
const struct value_string lchan_activate_mode_names[] = {
OSMO_VALUE_STRING(ACTIVATE_FOR_NONE),
OSMO_VALUE_STRING(ACTIVATE_FOR_MS_CHANNEL_REQUEST),
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c
index 5ba8c17..92e8c6e 100644
--- a/src/osmo-bsc/handover_fsm.c
+++ b/src/osmo-bsc/handover_fsm.c
@@ -46,6 +46,7 @@
#include <osmocom/bsc/bts.h>
#include <osmocom/bsc/lcs_loc_req.h>
#include <osmocom/bsc/bsc_stats.h>
+#include <osmocom/bsc/lchan.h>
#define LOG_FMT_BTS "bts %u lac-ci %u-%u arfcn-bsic %d-%d"
#define LOG_ARGS_BTS(bts) \
diff --git a/src/osmo-bsc/lchan.c b/src/osmo-bsc/lchan.c
new file mode 100644
index 0000000..84fc97a
--- /dev/null
+++ b/src/osmo-bsc/lchan.c
@@ -0,0 +1,141 @@
+/* (C) 2022 by sysmocom - s.m.f.c. GmbH <info(a)sysmocom.de>
+ * (C) 2008-2018 by Harald Welte <laforge(a)gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <osmocom/bsc/lchan.h>
+#include <osmocom/bsc/lchan_fsm.h>
+#include <osmocom/bsc/gsm_data.h>
+#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/bts_trx.h>
+#include <osmocom/bsc/abis_rsl.h>
+
+void lchan_update_name(struct gsm_lchan *lchan)
+{
+ struct gsm_bts_trx_ts *ts = lchan->ts;
+ if (lchan->name)
+ talloc_free(lchan->name);
+ lchan->name = talloc_asprintf(ts->trx, "(bts=%d,trx=%d,ts=%d,ss=%s%d)",
+ ts->trx->bts->nr, ts->trx->nr, ts->nr,
+ lchan->vamos.is_secondary ? "shadow" : "",
+ lchan->nr - (lchan->vamos.is_secondary ? ts->max_primary_lchans : 0));
+}
+
+/* If the lchan is currently active, return the duration since activation in milliseconds.
+ * Otherwise return 0. */
+uint64_t gsm_lchan_active_duration_ms(const struct gsm_lchan *lchan)
+{
+ struct timespec now, elapsed;
+
+ if (lchan->active_start.tv_sec == 0 && lchan->active_start.tv_nsec == 0)
+ return 0;
+
+ osmo_clock_gettime(CLOCK_MONOTONIC, &now);
+ timespecsub(&now, &lchan->active_start, &elapsed);
+
+ return elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000;
+}
+
+/* For a VAMOS secondary shadow lchan, return its primary lchan. If the lchan is not a secondary lchan, return NULL. */
+struct gsm_lchan *gsm_lchan_vamos_to_primary(const struct gsm_lchan *lchan_vamos)
+{
+ struct gsm_lchan *lchan_primary;
+ if (!lchan_vamos || !lchan_vamos->vamos.is_secondary)
+ return NULL;
+ /* OsmoBSC currently does not support mixed TCH/F + TCH/H VAMOS multiplexes. Hence the primary <-> secondary
+ * relation is a simple index shift in the lchan array. If mixed multiplexes were allowed, a TCH/F primary might
+ * have two TCH/H VAMOS secondary lchans, etc. Fortunately, we don't need to care about that. */
+ lchan_primary = (struct gsm_lchan *)lchan_vamos - lchan_vamos->ts->max_primary_lchans;
+ if (!lchan_primary->fi)
+ return NULL;
+ return lchan_primary;
+}
+
+/* For a primary lchan, return its VAMOS secondary shadow lchan. If the lchan is not a primary lchan, return NULL. */
+struct gsm_lchan *gsm_lchan_primary_to_vamos(const struct gsm_lchan *lchan_primary)
+{
+ struct gsm_lchan *lchan_vamos;
+ if (!lchan_primary || lchan_primary->vamos.is_secondary)
+ return NULL;
+ /* OsmoBSC currently does not support mixed TCH/F + TCH/H VAMOS multiplexes. Hence the primary <-> secondary
+ * relation is a simple index shift in the lchan array. If mixed multiplexes were allowed, a TCH/F primary might
+ * have two TCH/H VAMOS secondary lchans, etc. Fortunately, we don't need to care about that. */
+ lchan_vamos = (struct gsm_lchan *)lchan_primary + lchan_primary->ts->max_primary_lchans;
+ if (!lchan_vamos->fi)
+ return NULL;
+ return lchan_vamos;
+}
+
+void lchan_update_ms_power_ctrl_level(struct gsm_lchan *lchan, int ms_power_dbm)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ struct gsm_subscriber_connection *conn = lchan->conn;
+ int max_pwr_dbm_pwclass, new_pwr;
+ bool send_pwr_ctrl_msg = false;
+
+ LOG_LCHAN(lchan, LOGL_DEBUG,
+ "MS Power level update requested: %d dBm\n", ms_power_dbm);
+
+ if (!conn)
+ goto ms_power_default;
+
+ if (conn->ms_power_class == 0)
+ goto ms_power_default;
+
+ if ((max_pwr_dbm_pwclass = (int)ms_class_gmsk_dbm(bts->band, conn->ms_power_class)) < 0) {
+ LOG_LCHAN(lchan, LOGL_INFO,
+ "Failed getting max ms power for power class %" PRIu8
+ " on band %s, providing default max ms power\n",
+ conn->ms_power_class, gsm_band_name(bts->band));
+ goto ms_power_default;
+ }
+
+ /* Current configured max pwr is above maximum one allowed on
+ current band + ms power class, so use that one. */
+ if (ms_power_dbm > max_pwr_dbm_pwclass)
+ ms_power_dbm = max_pwr_dbm_pwclass;
+
+ms_power_default:
+ if ((new_pwr = ms_pwr_ctl_lvl(bts->band, ms_power_dbm)) < 0) {
+ LOG_LCHAN(lchan, LOGL_INFO,
+ "Failed getting max ms power level %d on band %s,"
+ " providing default max ms power\n",
+ ms_power_dbm, gsm_band_name(bts->band));
+ return;
+ }
+
+ LOG_LCHAN(lchan, LOGL_DEBUG,
+ "MS Power level update (power class %" PRIu8 "): %" PRIu8 " -> %d\n",
+ conn ? conn->ms_power_class : 0, lchan->ms_power, new_pwr);
+
+ /* If chan was already activated and max ms_power changes (due to power
+ classmark received), send an MS Power Control message */
+ if (lchan->activate.activ_ack && new_pwr != lchan->ms_power)
+ send_pwr_ctrl_msg = true;
+
+ lchan->ms_power = new_pwr;
+
+ if (send_pwr_ctrl_msg)
+ rsl_chan_ms_power_ctrl(lchan);
+}
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index be3be7b..21e145b 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -41,6 +41,7 @@
#include <osmocom/bsc/codec_pref.h>
#include <osmocom/bsc/bts.h>
#include <osmocom/bsc/bsc_stats.h>
+#include <osmocom/bsc/lchan.h>
static struct osmo_fsm lchan_fsm;
diff --git a/src/osmo-bsc/lchan_rtp_fsm.c b/src/osmo-bsc/lchan_rtp_fsm.c
index 14d8e07..f5da930 100644
--- a/src/osmo-bsc/lchan_rtp_fsm.c
+++ b/src/osmo-bsc/lchan_rtp_fsm.c
@@ -31,6 +31,7 @@
#include <osmocom/bsc/abis_rsl.h>
#include <osmocom/bsc/bsc_msc_data.h>
#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/lchan.h>
static struct osmo_fsm lchan_rtp_fsm;
diff --git a/src/osmo-bsc/meas_feed.c b/src/osmo-bsc/meas_feed.c
index 881f409..afd96e1 100644
--- a/src/osmo-bsc/meas_feed.c
+++ b/src/osmo-bsc/meas_feed.c
@@ -20,6 +20,7 @@
#include <osmocom/bsc/vty.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/lchan.h>
struct meas_feed_state {
struct osmo_wqueue wqueue;
diff --git a/src/osmo-bsc/osmo_bsc_lcls.c b/src/osmo-bsc/osmo_bsc_lcls.c
index 542bbf5..eab0be4 100644
--- a/src/osmo-bsc/osmo_bsc_lcls.c
+++ b/src/osmo-bsc/osmo_bsc_lcls.c
@@ -30,6 +30,7 @@
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/osmo_bsc_lcls.h>
#include <osmocom/bsc/lchan_rtp_fsm.h>
+#include <osmocom/bsc/lchan.h>
#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
struct value_string lcls_event_names[] = {
@@ -561,7 +562,7 @@
case LCLS_EV_UPDATE_CFG_CSC:
if (lcls_handle_cfg_update(conn, data) != 0)
return;
- //FIXME osmo_fsm_inst_state_chg(fi,
+ //FIXME osmo_fsm_inst_state_chg(fi,
return;
case LCLS_EV_APPLY_CFG_CSC:
if (lcls_perform_correlation(conn) != 0) {
diff --git a/src/osmo-bsc/timeslot_fsm.c b/src/osmo-bsc/timeslot_fsm.c
index 3a25fc9..72db0fa 100644
--- a/src/osmo-bsc/timeslot_fsm.c
+++ b/src/osmo-bsc/timeslot_fsm.c
@@ -29,6 +29,7 @@
#include <osmocom/bsc/abis_rsl.h>
#include <osmocom/bsc/pcu_if.h>
#include <osmocom/bsc/bts.h>
+#include <osmocom/bsc/lchan.h>
static struct osmo_fsm ts_fsm;
diff --git a/tests/handover/handover_test.c b/tests/handover/handover_test.c
index 26c72ab..d237ab7 100644
--- a/tests/handover/handover_test.c
+++ b/tests/handover/handover_test.c
@@ -52,6 +52,7 @@
#include <osmocom/bsc/bts.h>
#include <osmocom/bsc/paging.h>
#include <osmocom/bsc/vty.h>
+#include <osmocom/bsc/lchan.h>
#include <osmocom/mgcp_client/mgcp_client_pool.h>
#include "../../bscconfig.h"
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/28979
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Idd855d126c43ac6576c5f3ba7e0b8014127a65e1
Gerrit-Change-Number: 28979
Gerrit-PatchSet: 3
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
pespin has posted comments on this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/28980 )
Change subject: lchan: Move init logic to a specific function
......................................................................
Patch Set 1: Code-Review+2
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/28980
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I043d1c2ee75d4d2a8b323b7960ee490e567f3865
Gerrit-Change-Number: 28980
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-Comment-Date: Tue, 09 Aug 2022 08:38:45 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
Gerrit-MessageType: comment
Attention is currently required from: laforge.
pespin has posted comments on this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/28979 )
Change subject: split lchan specific defines and code to its own file
......................................................................
Patch Set 2: Code-Review+2
(1 comment)
Patchset:
PS2:
> I'm not sure I buy the argument "it's difficult to find" (juts one git grep away), but I certainly w […]
You need to first know exactly what you want to find before start using grep, so first step is opening the file where the APIs are :)
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/28979
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Idd855d126c43ac6576c5f3ba7e0b8014127a65e1
Gerrit-Change-Number: 28979
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-Comment-Date: Tue, 09 Aug 2022 08:38:40 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Comment-In-Reply-To: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: comment
Attention is currently required from: neels, laforge.
fixeria has posted comments on this change. ( https://gerrit.osmocom.org/c/osmo-ci/+/28998 )
Change subject: coverity: add missing libosmo-pfcp, dependency of osmo-upf
......................................................................
Patch Set 1:
(1 comment)
File coverity/prepare_source_Osmocom.sh:
https://gerrit.osmocom.org/c/osmo-ci/+/28998/comment/7dbc50ca_81da165a
PS1, Line 7: add it as component here
I need somebody to help me with this step, I have no permissions to access this page.
--
To view, visit https://gerrit.osmocom.org/c/osmo-ci/+/28998
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-ci
Gerrit-Branch: master
Gerrit-Change-Id: Ic4fe7b40cf9a57e0462b2c0806f8810fcc04a10c
Gerrit-Change-Number: 28998
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Attention: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-Comment-Date: Tue, 09 Aug 2022 08:25:29 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ci/+/28998 )
Change subject: coverity: add missing libosmo-pfcp, dependency of osmo-upf
......................................................................
coverity: add missing libosmo-pfcp, dependency of osmo-upf
Since recently [1] osmo-upf depends on libosmo-{gtlv,pfcp}.so, which
are provided by libosmo-pfcp.git. We need to build libosmo-pfcp
before attempting to build osmo-upf, otherwise it fails:
configure: error: Package requirements (libosmo-gtlv >= 0.1.0) were not met:
Package libosmo-gtlv was not found in the pkg-config search path.
Perhaps you should add the directory containing `libosmo-gtlv.pc'
to the PKG_CONFIG_PATH environment variable
Package 'libosmo-gtlv', required by 'world', not found
Change-Id: Ic4fe7b40cf9a57e0462b2c0806f8810fcc04a10c
---
M coverity/build_Osmocom.sh
M coverity/prepare_source_Osmocom.sh
2 files changed, 2 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ci refs/changes/98/28998/1
diff --git a/coverity/build_Osmocom.sh b/coverity/build_Osmocom.sh
index a7f8cdd..4291558 100755
--- a/coverity/build_Osmocom.sh
+++ b/coverity/build_Osmocom.sh
@@ -75,6 +75,7 @@
build_libusrp
build_default libosmo-abis
build_default libosmo-netif
+build_default libosmo-pfcp
build_default libosmo-sccp
build_default libsmpp34
build_default osmo-ggsn
diff --git a/coverity/prepare_source_Osmocom.sh b/coverity/prepare_source_Osmocom.sh
index 31d6714..73baf2c 100755
--- a/coverity/prepare_source_Osmocom.sh
+++ b/coverity/prepare_source_Osmocom.sh
@@ -13,6 +13,7 @@
libosmocore
libosmo-dsp
libosmo-netif
+ libosmo-pfcp
libosmo-sccp
libsmpp34
libusrp
--
To view, visit https://gerrit.osmocom.org/c/osmo-ci/+/28998
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-ci
Gerrit-Branch: master
Gerrit-Change-Id: Ic4fe7b40cf9a57e0462b2c0806f8810fcc04a10c
Gerrit-Change-Number: 28998
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange