aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/rsl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/rsl.c')
-rw-r--r--src/common/rsl.c384
1 files changed, 213 insertions, 171 deletions
diff --git a/src/common/rsl.c b/src/common/rsl.c
index 18c03491..145cc8a9 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -440,29 +440,32 @@ int rsl_tx_rf_res(struct gsm_bts_trx *trx)
uint8_t *len = msgb_tl_put(nmsg, RSL_IE_RESOURCE_INFO);
for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ const struct gsm_bts_trx_ts *ts = &trx->ts[tn];
for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++) {
- struct gsm_lchan *lchan = &ts->lchan[ln];
+ const struct gsm_lchan *lchan = &ts->lchan[ln];
- /* We're not interested in active lchans */
- if (lchan->state == LCHAN_S_ACTIVE) {
- /* Avoid potential buffer overflow */
- lchan->meas.interf_meas_num = 0;
- continue;
- }
-
- /* Only for GSM_LCHAN_{SDCCH,TCH_F,TCH_H} */
- if (!lchan_is_dcch(lchan))
+ /* No average interference value => no band */
+ if (lchan->meas.interf_meas_avg_dbm == 0)
continue;
- /* Average all collected samples */
- int band = gsm_lchan_interf_meas_calc_band(lchan);
- if (band < 0)
+ /* Only for GSM_LCHAN_{SDCCH,TCH_F,TCH_H,PDTCH} */
+ switch (lchan->type) {
+ case GSM_LCHAN_SDCCH:
+ case GSM_LCHAN_TCH_F:
+ case GSM_LCHAN_TCH_H:
+ /* We're not interested in active CS lchans */
+ if (lchan->state == LCHAN_S_ACTIVE)
+ continue;
+ break;
+ case GSM_LCHAN_PDTCH:
+ break;
+ default:
continue;
+ }
- msgb_v_put(nmsg, gsm_lchan2chan_nr(lchan));
- msgb_v_put(nmsg, (band & 0x07) << 5);
+ msgb_v_put(nmsg, gsm_lchan2chan_nr_rsl(lchan));
+ msgb_v_put(nmsg, (lchan->meas.interf_band & 0x07) << 5);
}
}
@@ -909,7 +912,7 @@ static int parse_power_ctrl_params(struct gsm_power_ctrl_params *params,
const uint8_t *data, size_t data_len)
{
const struct tlv_p_entry *ie;
- struct tlv_parsed tp[2];
+ struct tlv_parsed tp[3];
unsigned int i;
int rc;
@@ -938,6 +941,30 @@ static int parse_power_ctrl_params(struct gsm_power_ctrl_params *params,
params->rxqual_meas.upper_thresh = thresh->u_rxqual;
}
+ /* Osmocom extension, C/I related thresholds: */
+ if (TLVP_PRES_LEN(&tp[0], RSL_IPAC_EIE_OSMO_MS_PWR_CTL, sizeof(struct osmo_preproc_pc_thresh))) {
+ const struct osmo_preproc_pc_thresh *osmo_thresh;
+ ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_OSMO_MS_PWR_CTL);
+ osmo_thresh = (const struct osmo_preproc_pc_thresh *) ie->val;
+ params->ci_fr_meas.lower_thresh = osmo_thresh->l_ci_fr;
+ params->ci_fr_meas.upper_thresh = osmo_thresh->u_ci_fr;
+
+ params->ci_hr_meas.lower_thresh = osmo_thresh->l_ci_hr;
+ params->ci_hr_meas.upper_thresh = osmo_thresh->u_ci_hr;
+
+ params->ci_amr_fr_meas.lower_thresh = osmo_thresh->l_ci_amr_fr;
+ params->ci_amr_fr_meas.upper_thresh = osmo_thresh->u_ci_amr_fr;
+
+ params->ci_amr_hr_meas.lower_thresh = osmo_thresh->l_ci_amr_hr;
+ params->ci_amr_hr_meas.upper_thresh = osmo_thresh->u_ci_amr_hr;
+
+ params->ci_sdcch_meas.lower_thresh = osmo_thresh->l_ci_sdcch;
+ params->ci_sdcch_meas.upper_thresh = osmo_thresh->u_ci_sdcch;
+
+ params->ci_gprs_meas.lower_thresh = osmo_thresh->l_ci_gprs;
+ params->ci_gprs_meas.upper_thresh = osmo_thresh->u_ci_gprs;
+ }
+
/* (TV) PC Threshold Comparators */
if ((ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_PC_THRESH_COMP)) != NULL) {
const struct ipac_preproc_pc_comp *thresh_comp;
@@ -964,12 +991,31 @@ static int parse_power_ctrl_params(struct gsm_power_ctrl_params *params,
params->red_step_size_db = thresh_comp->red_step_size;
}
+ /* Osmocom extension, C/I related thresholds: */
+ if (TLVP_PRES_LEN(&tp[0], RSL_IPAC_EIE_OSMO_PC_THRESH_COMP, sizeof(struct osmo_preproc_pc_thresh))) {
+ const struct osmo_preproc_pc_comp *osmo_thresh_comp;
+ ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_OSMO_PC_THRESH_COMP);
+ osmo_thresh_comp = (const struct osmo_preproc_pc_comp *) ie->val;
+ #define SET_PREPROC_PC(PARAMS, FROM, TYPE) \
+ (PARAMS)->TYPE##_meas.lower_cmp_p = (FROM)->TYPE.lower_p; \
+ (PARAMS)->TYPE##_meas.lower_cmp_n = (FROM)->TYPE.lower_n; \
+ (PARAMS)->TYPE##_meas.upper_cmp_p = (FROM)->TYPE.upper_p; \
+ (PARAMS)->TYPE##_meas.upper_cmp_n = (FROM)->TYPE.upper_n
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_fr);
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_hr);
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_amr_fr);
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_amr_hr);
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_sdcch);
+ SET_PREPROC_PC(params, osmo_thresh_comp, ci_gprs);
+ #undef SET_PREPROC_PC
+ }
+
/* (TLV) Measurement Averaging parameters for RxLev/RxQual */
for (i = 0; i < ARRAY_SIZE(tp); i++) {
const struct ipac_preproc_ave_cfg *ave_cfg;
struct gsm_power_ctrl_meas_params *mp;
- ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_MEAS_AVG_CFG);
+ ie = TLVP_GET(&tp[i], RSL_IPAC_EIE_MEAS_AVG_CFG);
if (ie == NULL)
break;
@@ -1008,6 +1054,42 @@ static int parse_power_ctrl_params(struct gsm_power_ctrl_params *params,
}
}
+ /* (TLV) Measurement Averaging parameters for C/I (Osmocom extension)*/
+ if (TLVP_PRES_LEN(&tp[0], RSL_IPAC_EIE_OSMO_MEAS_AVG_CFG, sizeof(struct osmo_preproc_ave_cfg))) {
+ ie = TLVP_GET(&tp[0], RSL_IPAC_EIE_OSMO_MEAS_AVG_CFG);
+ const struct osmo_preproc_ave_cfg *cfg = (const struct osmo_preproc_ave_cfg *) ie->val;
+ unsigned params_offset = 0;
+ #define SET_AVE_CFG(PARAMS, FROM, TYPE, PARAM_OFFSET) do {\
+ if ((FROM)->TYPE.ave_enabled) { \
+ (PARAMS)->TYPE##_meas.h_reqave = (FROM)->TYPE.h_reqave; \
+ (PARAMS)->TYPE##_meas.h_reqt = (FROM)->TYPE.h_reqt; \
+ (PARAMS)->TYPE##_meas.algo = (FROM)->TYPE.ave_method + 1; \
+ switch ((FROM)->TYPE.ave_method) { \
+ case IPAC_OSMO_EWMA_AVE: \
+ if (ie->len > sizeof(*cfg) + (PARAM_OFFSET)) { \
+ (PARAMS)->TYPE##_meas.ewma.alpha = (FROM)->params[PARAM_OFFSET]; \
+ (PARAM_OFFSET)++; \
+ } \
+ break; \
+ /* FIXME: not implemented */ \
+ case IPAC_UNWEIGHTED_AVE: \
+ case IPAC_WEIGHTED_AVE: \
+ case IPAC_MEDIAN_AVE: \
+ break; \
+ } \
+ } else { \
+ (PARAMS)->TYPE##_meas.algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE; \
+ } \
+ } while(0)
+ SET_AVE_CFG(params, cfg, ci_fr, params_offset);
+ SET_AVE_CFG(params, cfg, ci_hr, params_offset);
+ SET_AVE_CFG(params, cfg, ci_amr_fr, params_offset);
+ SET_AVE_CFG(params, cfg, ci_amr_hr, params_offset);
+ SET_AVE_CFG(params, cfg, ci_sdcch, params_offset);
+ SET_AVE_CFG(params, cfg, ci_gprs, params_offset);
+ #undef SET_AVE_CFG
+ }
+
return 0;
}
@@ -1032,7 +1114,8 @@ static int rsl_rx_meas_preproc_dft(struct gsm_bts_trx *trx, struct msgb *msg)
/* TLV (O) BS Power Parameters IE */
if ((ie = TLVP_GET(&tp, RSL_IE_BS_POWER_PARAM)) != NULL) {
/* Allocate a new chunk and initialize with default values */
- params = talloc_memdup(trx, &power_ctrl_params_def, sizeof(*params));
+ params = talloc(trx, struct gsm_power_ctrl_params);
+ power_ctrl_params_def_reset(params, true);
if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) == 0) {
/* Initially it points to the global defaults */
@@ -1049,7 +1132,8 @@ static int rsl_rx_meas_preproc_dft(struct gsm_bts_trx *trx, struct msgb *msg)
/* TLV (O) MS Power Parameters IE */
if ((ie = TLVP_GET(&tp, RSL_IE_MS_POWER_PARAM)) != NULL) {
/* Allocate a new chunk and initialize with default values */
- params = talloc_memdup(trx, &power_ctrl_params_def, sizeof(*params));
+ params = talloc(trx, struct gsm_power_ctrl_params);
+ power_ctrl_params_def_reset(params, false);
if (ie->len && parse_power_ctrl_params(params, ie->val, ie->len) == 0) {
/* Initially it points to the global defaults */
@@ -1085,6 +1169,30 @@ static int rsl_rx_imm_ass(struct gsm_bts_trx *trx, struct msgb *msg)
msg->l2h = NULL;
msg->len = TLVP_LEN(&tp, RSL_IE_FULL_IMM_ASS_INFO);
+ /* Early Immediate Assignment: when there is a lot of latency on Abis, the Abis roundtrip of Chan Activ -> Chan
+ * Activ ACK -> Immediate Assignment may take so long that each MS sends a second RACH for Chan Rqd, reserving
+ * two SDCCH for each request but using only one. To help with that, the Early IA feature in osmo-bsc sends the
+ * Immediate Assignment without waiting for the Channel Activation ACK. This may then be too early, and the MS
+ * may not be able to establish a channel. So to help with Early IA, look up whether the target lchan is already
+ * active. If not, then hold back the RR Immediate Assignment message, and send it once L1 has confirmed that
+ * the channel is active. Hence we still wait for the activation, but don't need the Abis roundtrip of Activ ACK
+ * -> Immediate Assignment via the BSC.
+ * If anything is wrong with the sizes or the lchan lookup, behave normally, i.e. do not do the RR IA caching,
+ * but just send the RR message to the MS as-is. */
+ if (msg->len >= sizeof(struct gsm48_imm_ass)) {
+ struct gsm48_imm_ass *rr_ia = (void*)msg->data;
+ struct gsm_lchan *ia_target_lchan = lchan_lookup(trx, rr_ia->chan_desc.chan_nr, "Early IA check: ");
+ if (ia_target_lchan && ia_target_lchan->state != LCHAN_S_ACTIVE) {
+ /* Target lchan is not yet active. Cache the IA.
+ * If a previous IA is still lingering, free it. */
+ msgb_free(ia_target_lchan->early_rr_ia);
+ ia_target_lchan->early_rr_ia = msg;
+
+ /* return 1 means: don't msgb_free() the msg */
+ return 1;
+ }
+ }
+
/* put into the AGCH queue of the BTS */
if (bts_agch_enqueue(trx->bts, msg) < 0) {
/* if there is no space in the queue: send DELETE IND */
@@ -1122,7 +1230,7 @@ static int tx_rf_rel_ack(struct gsm_lchan *lchan, uint8_t chan_nr)
/* 8.4.19 sending RF CHANnel RELease ACKnowledge */
int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan)
{
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
bool send_rel_ack;
switch (lchan->rel_act_kind) {
@@ -1188,21 +1296,6 @@ int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan)
gsm_ts_and_pchan_name(lchan->ts), lchan->nr,
gsm_lchant_name(lchan->type));
- /*
- * Free the LAPDm resources now that the BTS
- * has released all the resources.
- */
- lapdm_channel_exit(&lchan->lapdm_ch);
-
- /* Also ensure that there are no leftovers from repeated FACCH or
- * repeated SACCH that might cause memory leakage. */
- msgb_free(lchan->tch.rep_facch[0].msg);
- msgb_free(lchan->tch.rep_facch[1].msg);
- lchan->tch.rep_facch[0].msg = NULL;
- lchan->tch.rep_facch[1].msg = NULL;
- msgb_free(lchan->rep_sacch);
- lchan->rep_sacch = NULL;
-
return tx_rf_rel_ack(lchan, chan_nr);
}
@@ -1211,7 +1304,7 @@ static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan)
{
struct gsm_time *gtime = get_time(lchan->ts->trx->bts);
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
uint8_t ie[2];
LOGP(DRSL, LOGL_NOTICE, "%s (ss=%d) %s Tx CHAN ACT ACK\n",
@@ -1237,7 +1330,7 @@ static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan)
int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending HANDOver DETect\n");
@@ -1279,7 +1372,7 @@ static int _rsl_tx_chan_act_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uint8
return abis_bts_rsl_sendmsg(msg);
}
static int rsl_tx_chan_act_nack(struct gsm_lchan *lchan, uint8_t cause) {
- return _rsl_tx_chan_act_nack(lchan->ts->trx, gsm_lchan2chan_nr(lchan), cause, lchan);
+ return _rsl_tx_chan_act_nack(lchan->ts->trx, gsm_lchan2chan_nr_rsl(lchan), cause, lchan);
}
/* Send an RSL Channel Activation Ack if cause is zero, a Nack otherwise. */
@@ -1300,7 +1393,7 @@ int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause)
int rsl_tx_conn_fail(const struct gsm_lchan *lchan, uint8_t cause)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "Sending Connection Failure: cause = 0x%02x\n", cause);
@@ -1409,7 +1502,7 @@ static void clear_lchan_for_pdch_activ(struct gsm_lchan *lchan)
memset(&lchan->ho, 0, sizeof(lchan->ho));
memset(&lchan->ms_power_ctrl, 0, sizeof(lchan->ms_power_ctrl));
memset(&lchan->bs_power_ctrl, 0, sizeof(lchan->bs_power_ctrl));
- lchan->rqd_ta = 0;
+ lchan->ta_ctrl.current = 0;
copy_sacch_si_to_lchan(lchan);
memset(&lchan->tch, 0, sizeof(lchan->tch));
}
@@ -1418,7 +1511,7 @@ static void clear_lchan_for_pdch_activ(struct gsm_lchan *lchan)
* Store the CHAN_ACTIV msg, connect the L1 timeslot in the proper type and
* then invoke rsl_rx_chan_activ() with msg.
*/
-static int dyn_ts_l1_reconnect(struct gsm_bts_trx_ts *ts, struct msgb *msg)
+static int dyn_ts_l1_reconnect(struct gsm_bts_trx_ts *ts)
{
DEBUGP(DRSL, "%s dyn_ts_l1_reconnect\n", gsm_ts_and_pchan_name(ts));
@@ -1439,9 +1532,6 @@ static int dyn_ts_l1_reconnect(struct gsm_bts_trx_ts *ts, struct msgb *msg)
return -EINVAL;
}
- /* We will feed this back to rsl_rx_chan_activ() later */
- ts->dyn.pending_chan_activ = msg;
-
/* Disconnect, continue connecting from cb_ts_disconnected(). */
DEBUGP(DRSL, "%s Disconnect\n", gsm_ts_and_pchan_name(ts));
return bts_model_ts_disconnect(ts);
@@ -1486,21 +1576,40 @@ static void parse_repeated_acch_capability(struct gsm_lchan *lchan, struct tlv_p
memset(&lchan->repeated_acch_capability, 0, sizeof(lchan->repeated_acch_capability));
- if (!TLVP_PRESENT(tp, RSL_IE_OSMO_REP_ACCH_CAP))
- return;
- if (TLVP_LEN(tp, RSL_IE_OSMO_REP_ACCH_CAP) != sizeof(lchan->repeated_acch_capability))
+ if (!TLVP_PRES_LEN(tp, RSL_IE_OSMO_REP_ACCH_CAP, sizeof(lchan->repeated_acch_capability)))
return;
memcpy(&lchan->repeated_acch_capability, TLVP_VAL(tp, RSL_IE_OSMO_REP_ACCH_CAP),
sizeof(lchan->repeated_acch_capability));
}
+/* Parse RSL_IE_OSMO_TOP_ACCH_CAP */
+static int parse_temporary_overpower_acch_capability(struct gsm_lchan *lchan,
+ const struct tlv_parsed *tp)
+{
+ struct abis_rsl_osmo_temp_ovp_acch_cap *top;
+
+ lchan->bs_acch_overpower_db = 0;
+
+ if (!TLVP_PRES_LEN(tp, RSL_IE_OSMO_TEMP_OVP_ACCH_CAP, sizeof(*top)))
+ return 0;
+
+ if (!osmo_bts_has_feature(lchan->ts->trx->bts->features, BTS_FEAT_ACCH_TEMP_OVP))
+ return -RSL_ERR_OPT_IE_ERROR;
+
+ top = (struct abis_rsl_osmo_temp_ovp_acch_cap *)TLVP_VAL(tp, RSL_IE_OSMO_TEMP_OVP_ACCH_CAP);
+ lchan->bs_acch_overpower_db = top->overpower_db;
+
+ return 0;
+}
+
/* 8.4.1 CHANnel ACTIVation is received */
static int rsl_rx_chan_activ(struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct gsm_lchan *lchan = msg->lchan;
struct gsm_bts_trx_ts *ts = lchan->ts;
+ struct gsm_bts_trx_ts *primary_ts;
struct tlv_parsed tp;
const struct tlv_p_entry *ie;
uint8_t type, cause;
@@ -1512,6 +1621,15 @@ static int rsl_rx_chan_activ(struct msgb *msg)
return rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL);
}
+ /* We need to pick the real TS here to check NM state: */
+ primary_ts = ts->vamos.is_shadow ? ts->vamos.peer : ts;
+ if (primary_ts->mo.nm_state.operational != NM_OPSTATE_ENABLED ||
+ primary_ts->mo.nm_state.availability != NM_AVSTATE_OK) {
+ LOGP(DRSL, LOGL_ERROR, "%s rx chan activ but TS not in nm_state oper=ENABLED avail=OK, nack!\n",
+ gsm_ts_and_pchan_name(ts));
+ return rsl_tx_chan_act_nack(lchan, RSL_ERR_RR_UNAVAIL);
+ }
+
if (ts->pchan == GSM_PCHAN_OSMO_DYN) {
ts->dyn.pchan_want = dyn_pchan_from_chan_nr(dch->chan_nr);
DEBUGP(DRSL, "%s rx chan activ\n", gsm_ts_and_pchan_name(ts));
@@ -1522,17 +1640,17 @@ static int rsl_rx_chan_activ(struct msgb *msg)
* mode than this activation needs it to be.
* Re-connect, then come back to rsl_rx_chan_activ().
*/
- rc = dyn_ts_l1_reconnect(ts, msg);
+ rc = dyn_ts_l1_reconnect(ts);
if (rc)
return rsl_tx_chan_act_nack(lchan, RSL_ERR_NORMAL_UNSPEC);
+ /* will be fed back to rsl_rx_chan_activ() later */
+ OSMO_ASSERT(lchan->pending_chan_activ == NULL);
+ lchan->pending_chan_activ = msg;
/* indicate that the msgb should not be freed. */
return 1;
}
}
- LOGPLCHAN(lchan, DRSL, LOGL_DEBUG, "rx Channel Activation in state: %s.\n",
- gsm_lchans_name(lchan->state));
-
/* Initialize MS Power Control defaults */
lchan->ms_power_ctrl = (struct lchan_power_ctrl_state) {
.max = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, 0),
@@ -1618,7 +1736,7 @@ static int rsl_rx_chan_activ(struct msgb *msg)
}
/* 9.3.24 Timing Advance */
if (TLVP_PRES_LEN(&tp, RSL_IE_TIMING_ADVANCE, 1))
- lchan->rqd_ta = *TLVP_VAL(&tp, RSL_IE_TIMING_ADVANCE);
+ lchan->ta_ctrl.current = *TLVP_VAL(&tp, RSL_IE_TIMING_ADVANCE);
/* 9.3.31 (TLV) MS Power Parameters IE (vendor specific) */
if ((ie = TLVP_GET(&tp, RSL_IE_MS_POWER_PARAM)) != NULL) {
@@ -1795,6 +1913,9 @@ static int rsl_rx_chan_activ(struct msgb *msg)
lchan->rel_act_kind = LCHAN_REL_ACT_RSL;
parse_repeated_acch_capability(lchan, &tp);
+ rc = parse_temporary_overpower_acch_capability(lchan, &tp);
+ if (rc < 0)
+ return rsl_tx_chan_act_acknack(lchan, -rc);
/* actually activate the channel in the BTS */
rc = l1sap_chan_act(lchan->ts->trx, dch->chan_nr, &tp);
@@ -1804,37 +1925,9 @@ static int rsl_rx_chan_activ(struct msgb *msg)
return 0;
}
-static int dyn_ts_pdch_release(struct gsm_lchan *lchan)
-{
- struct gsm_bts_trx_ts *ts = lchan->ts;
-
- if (ts->dyn.pchan_is != ts->dyn.pchan_want) {
- LOGP(DRSL, LOGL_ERROR, "%s: PDCH release requested but already"
- " in switchover\n", gsm_ts_and_pchan_name(ts));
- return -EINVAL;
- }
-
- /*
- * Indicate PDCH Disconnect in dyn_pdch.want, let pcu_tx_info_ind()
- * pick it up and wait for PCU to disable the channel.
- */
- ts->dyn.pchan_want = GSM_PCHAN_NONE;
-
- if (!pcu_connected()) {
- /* PCU not connected yet. Just record the new type and done,
- * the PCU will pick it up once connected. */
- ts->dyn.pchan_is = GSM_PCHAN_NONE;
- return 1;
- }
-
- return pcu_tx_info_ind();
-}
-
/* 8.4.14 RF CHANnel RELease is received */
static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan, uint8_t chan_nr)
{
- int rc;
-
if (lchan->state == LCHAN_S_NONE) {
LOGP(DRSL, LOGL_ERROR,
"%s ss=%d state=%s Rx RSL RF Channel Release, but is already inactive;"
@@ -1845,38 +1938,7 @@ static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan, uint8_t chan_nr)
* not necessarily reflecting the current lchan state. */
return tx_rf_rel_ack(lchan, chan_nr);
}
-
- if (lchan->abis_ip.rtp_socket) {
- rsl_tx_ipac_dlcx_ind(lchan, RSL_ERR_NORMAL_UNSPEC);
- osmo_rtp_socket_log_stats(lchan->abis_ip.rtp_socket, DRTP, LOGL_INFO,
- "Closing RTP socket on Channel Release ");
- osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
- lchan->abis_ip.rtp_socket = NULL;
- msgb_queue_flush(&lchan->dl_tch_queue);
- }
-
- /* release handover state */
- handover_reset(lchan);
-
- lchan->rel_act_kind = LCHAN_REL_ACT_RSL;
-
- /* Dynamic channel in PDCH mode is released via PCU */
- if (lchan->ts->pchan == GSM_PCHAN_OSMO_DYN
- && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH) {
- rc = dyn_ts_pdch_release(lchan);
- if (rc == 1) {
- /* If the PCU is not connected, continue to rel ack right away. */
- lchan->rel_act_kind = LCHAN_REL_ACT_PCU;
- return rsl_tx_rf_rel_ack(lchan);
- }
- /* Waiting for PDCH release */
- return rc;
- }
-
- l1sap_chan_rel(lchan->ts->trx, chan_nr);
-
- lapdm_channel_exit(&lchan->lapdm_ch);
-
+ gsm_lchan_release(lchan, LCHAN_REL_ACT_RSL);
return 0;
}
@@ -1910,7 +1972,7 @@ static int tx_ciph_mod_compl_hack(struct gsm_lchan *lchan, uint8_t link_id,
}
}
- rsl_rll_push_l3(fake_msg, RSL_MT_DATA_IND, gsm_lchan2chan_nr(lchan),
+ rsl_rll_push_l3(fake_msg, RSL_MT_DATA_IND, gsm_lchan2chan_nr_rsl(lchan),
link_id, 1);
fake_msg->lchan = lchan;
@@ -2045,7 +2107,7 @@ static int _rsl_tx_mode_modif_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uin
}
static int rsl_tx_mode_modif_nack(struct gsm_lchan *lchan, uint8_t cause)
{
- return _rsl_tx_mode_modif_nack(lchan->ts->trx, gsm_lchan2chan_nr(lchan), cause, lchan);
+ return _rsl_tx_mode_modif_nack(lchan->ts->trx, gsm_lchan2chan_nr_rsl(lchan), cause, lchan);
}
@@ -2053,7 +2115,7 @@ static int rsl_tx_mode_modif_nack(struct gsm_lchan *lchan, uint8_t cause)
static int rsl_tx_mode_modif_ack(struct gsm_lchan *lchan)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Tx MODE MODIF ACK\n");
@@ -2119,6 +2181,9 @@ static int rsl_rx_mode_modif(struct msgb *msg)
/* 9.3.54 Supported Codec Types */
parse_repeated_acch_capability(lchan, &tp);
+ rc = parse_temporary_overpower_acch_capability(lchan, &tp);
+ if (rc < 0)
+ return rsl_tx_mode_modif_nack(lchan, -rc);
l1sap_chan_modify(lchan->ts->trx, dch->chan_nr);
@@ -2331,7 +2396,7 @@ int rsl_tx_cbch_load_indication(struct gsm_bts *bts, bool ext_cbch, bool overflo
return -ENOMEM;
/* 9.3.1 Channel Number */
- rsl_cch_push_hdr(msg, RSL_MT_CBCH_LOAD_IND, gsm_lchan2chan_nr(lchan));
+ rsl_cch_push_hdr(msg, RSL_MT_CBCH_LOAD_IND, gsm_lchan2chan_nr_rsl(lchan));
/* 9.3.43 CBCH Load Information */
load_info = ((overflow & 1) << 7) | (amount & 0x0F);
@@ -2393,7 +2458,7 @@ int rsl_tx_ipac_dlcx_ind(struct gsm_lchan *lchan, uint8_t cause)
msgb_tv16_put(nmsg, RSL_IE_IPAC_CONN_ID, htons(lchan->abis_ip.conn_id));
rsl_add_rtp_stats(lchan, nmsg);
msgb_tlv_put(nmsg, RSL_IE_CAUSE, 1, &cause);
- rsl_ipa_push_hdr(nmsg, RSL_MT_IPAC_DLCX_IND, gsm_lchan2chan_nr(lchan));
+ rsl_ipa_push_hdr(nmsg, RSL_MT_IPAC_DLCX_IND, gsm_lchan2chan_nr_rsl(lchan));
nmsg->trx = lchan->ts->trx;
@@ -2405,7 +2470,7 @@ static int rsl_tx_ipac_XXcx_ack(struct gsm_lchan *lchan, int inc_pt2,
uint8_t orig_msgt)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
const char *name;
struct in_addr ia;
@@ -2453,7 +2518,7 @@ static int rsl_tx_ipac_XXcx_ack(struct gsm_lchan *lchan, int inc_pt2,
static int rsl_tx_ipac_dlcx_ack(struct gsm_lchan *lchan, int inc_conn_id)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "RSL Tx IPAC_DLCX_ACK\n");
@@ -2476,7 +2541,7 @@ static int rsl_tx_ipac_dlcx_nack(struct gsm_lchan *lchan, int inc_conn_id,
uint8_t cause)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "RSL Tx IPAC_DLCX_NACK\n");
@@ -2502,7 +2567,7 @@ static int tx_ipac_XXcx_nack(struct gsm_lchan *lchan, uint8_t cause,
int inc_ipport, uint8_t orig_msgtype)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
/* FIXME: allocate new msgb and copy old over */
LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "RSL Tx IPAC_BIND_NACK\n");
@@ -2817,7 +2882,7 @@ static int rsl_rx_ipac_dlcx(struct msgb *msg)
static int rsl_tx_dyn_pdch_ack(struct gsm_lchan *lchan, bool pdch_act)
{
struct gsm_time *gtime = get_time(lchan->ts->trx->bts);
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
struct msgb *msg;
uint8_t ie[2];
@@ -2846,7 +2911,7 @@ static int rsl_tx_dyn_pdch_nack(struct gsm_lchan *lchan, bool pdch_act,
uint8_t cause)
{
struct msgb *msg;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "Tx PDCH %s NACK (cause = 0x%02x)\n",
pdch_act ? "ACT" : "DEACT", cause);
@@ -3107,8 +3172,7 @@ static void ipacc_dyn_pdch_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
static void osmo_dyn_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
{
- struct msgb *msg = ts->dyn.pending_chan_activ;
- ts->dyn.pending_chan_activ = NULL;
+ unsigned int ln;
if (rc) {
LOGP(DRSL, LOGL_NOTICE, "%s PDCH ACT OSMO operation failed (%d) in bts model\n",
@@ -3117,20 +3181,23 @@ static void osmo_dyn_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
return;
}
- if (!msg) {
- LOGP(DRSL, LOGL_ERROR,
- "%s TS re-connected, but no chan activ msg pending\n",
- gsm_ts_and_pchan_name(ts));
- return;
- }
-
ts->dyn.pchan_is = ts->dyn.pchan_want;
DEBUGP(DRSL, "%s Connected\n", gsm_ts_and_pchan_name(ts));
- /* continue where we left off before re-connecting the TS. */
- rc = rsl_rx_chan_activ(msg);
- if (rc != 1)
- msgb_free(msg);
+ /* Handle postponed RSL CHANnel ACTIVation messages (if any) */
+ for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++) {
+ struct gsm_lchan *lchan = &ts->lchan[ln];
+
+ if (lchan->pending_chan_activ == NULL)
+ continue;
+
+ struct msgb *msg = lchan->pending_chan_activ;
+ lchan->pending_chan_activ = NULL;
+
+ /* Continue where we left off before re-connecting the TS */
+ if (rsl_rx_chan_activ(msg) != 1)
+ msgb_free(msg);
+ }
}
void cb_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
@@ -3389,16 +3456,6 @@ static int handle_gprs_susp_req(struct msgb *msg)
return rc;
}
-static inline uint8_t ms_to2rsl(const struct gsm_lchan *lchan, const struct lapdm_entity *le)
-{
- return (lchan->ms_t_offs >= 0) ? lchan->ms_t_offs : (lchan->p_offs - le->ta);
-}
-
-static inline bool ms_to_valid(const struct gsm_lchan *lchan)
-{
- return (lchan->ms_t_offs >= 0) || (lchan->p_offs >= 0);
-}
-
struct osmo_bts_supp_meas_info {
int16_t toa256_mean;
int16_t toa256_min;
@@ -3406,12 +3463,12 @@ struct osmo_bts_supp_meas_info {
uint16_t toa256_std_dev;
} __attribute__((packed));
-/* Compose and send 8.4.8 MEASUREMENT RESult via RSL */
-int rsl_tx_meas_res(struct gsm_lchan *lchan, uint8_t *l3, int l3_len, const struct lapdm_entity *le)
+/* Compose and send 8.4.8 MEASUREMENT RESult via RSL. (timing_offset=-1 -> not present) */
+int rsl_tx_meas_res(struct gsm_lchan *lchan, uint8_t *l3, int l3_len, int timing_offset)
{
struct msgb *msg;
uint8_t meas_res[16];
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
int res_valid = lchan->meas.flags & LC_UL_M_F_RES_VALID;
struct gsm_bts *bts = lchan->ts->trx->bts;
@@ -3433,13 +3490,12 @@ int rsl_tx_meas_res(struct gsm_lchan *lchan, uint8_t *l3, int l3_len, const stru
lchan->meas.ul_res.full.rx_qual,
lchan->meas.ul_res.sub.rx_qual,
lchan->meas.l1_info.ms_pwr,
- lchan->meas.l1_info.ta, l3_len, ms_to2rsl(lchan, le) - MEAS_MAX_TIMING_ADVANCE);
+ lchan->meas.l1_info.ta, l3_len, timing_offset - MEAS_MAX_TIMING_ADVANCE);
- msgb_tv_put(msg, RSL_IE_MEAS_RES_NR, lchan->meas.res_nr++);
+ msgb_tv_put(msg, RSL_IE_MEAS_RES_NR, lchan->meas.res_nr);
size_t ie_len = gsm0858_rsl_ul_meas_enc(&lchan->meas.ul_res,
lchan->tch.dtx.dl_active,
meas_res);
- lchan->tch.dtx.dl_active = false;
if (ie_len >= 3) {
if (bts->supp_meas_toa256 && lchan->meas.flags & LC_UL_M_F_OSMO_EXT_VALID) {
struct osmo_bts_supp_meas_info *smi;
@@ -3457,24 +3513,18 @@ int rsl_tx_meas_res(struct gsm_lchan *lchan, uint8_t *l3, int l3_len, const stru
smi->toa256_min = htons(ta256 + lchan->meas.ext.toa256_min);
smi->toa256_max = htons(ta256 + lchan->meas.ext.toa256_max);
smi->toa256_std_dev = htons(lchan->meas.ext.toa256_std_dev);
- lchan->meas.flags &= ~LC_UL_M_F_OSMO_EXT_VALID;
}
msgb_tlv_put(msg, RSL_IE_UPLINK_MEAS, ie_len, meas_res);
- lchan->meas.flags &= ~LC_UL_M_F_RES_VALID;
}
msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power_ctrl.current / 2);
if (lchan->meas.flags & LC_UL_M_F_L1_VALID) {
msgb_tv_fixed_put(msg, RSL_IE_L1_INFO, sizeof(lchan->meas.l1_info), (uint8_t*)&lchan->meas.l1_info);
- lchan->meas.flags &= ~LC_UL_M_F_L1_VALID;
}
- if (l3 && l3_len > 0)
+ if (l3 && l3_len > 0) {
msgb_tl16v_put(msg, RSL_IE_L3_INFO, l3_len, l3);
- if (ms_to_valid(lchan)) {
- if (l3 && l3_len > 0)
- msgb_tv_put(msg, RSL_IE_MS_TIMING_OFFSET, ms_to2rsl(lchan, le));
- lchan->ms_t_offs = -1;
- lchan->p_offs = -1;
+ if (timing_offset != -1)
+ msgb_tv_put(msg, RSL_IE_MS_TIMING_OFFSET, timing_offset);
}
rsl_dch_push_hdr(msg, RSL_MT_MEAS_RES, chan_nr);
@@ -3528,7 +3578,7 @@ int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
}
repeated_dl_facch_active_decision(lchan, msgb_l3(msg), msgb_l3len(msg));
- rc = rsl_tx_meas_res(lchan, msgb_l3(msg), msgb_l3len(msg), le);
+ rc = handle_ms_meas_report(lchan, (struct gsm48_hdr *)msgb_l3(msg), msgb_l3len(msg));
msgb_free(msg);
return rc;
} else if (rslms_is_gprs_susp_req(msg)) {
@@ -3767,14 +3817,6 @@ static int rsl_rx_ipaccess(struct gsm_bts_trx *trx, struct msgb *msg)
return ret;
}
-int lchan_deactivate(struct gsm_lchan *lchan)
-{
- OSMO_ASSERT(lchan);
-
- lchan->ciph_state = 0;
- return bts_model_lchan_deactivate(lchan);
-}
-
int down_rsl(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_common_hdr *rslh;