l1sap: rework handling of DATA.ind on SACCH
Currently an Uplink SACCH block is being passed to LAPDm first, and then gets forwareded to the BSC in handle_ms_meas_report(), together with the Uplink measurements collected so far. This approach has a serious flaw: handle_ms_meas_report() won't be called if an Uplink block contains SAPI=3 data (SMS) or was not decoded at all (len=0) fow whatever reason. Therefore, no RSL MEASurement RESult message will be sent to the BSC. Rename handle_ms_meas_report() to lchan_meas_handle_sacch(), and call it from l1sap_ph_data_ind(). This way perioduc RSL MEASurement RESult messages will be sent regardless of what happens on Uplink SACCH. Change-Id: Ifed91f87fd653debc87a09da3fd31ad64a13f330 Fixes: TC_meas_res_speech_{tchf,tchh}_sapi3 Related: SYS#5319
This commit is contained in:
parent
5c705a676d
commit
c13b325877
|
@ -20,8 +20,6 @@ bool ts45008_83_is_sub(struct gsm_lchan *lchan, uint32_t fn);
|
||||||
|
|
||||||
int is_meas_complete(struct gsm_lchan *lchan, uint32_t fn);
|
int is_meas_complete(struct gsm_lchan *lchan, uint32_t fn);
|
||||||
|
|
||||||
int handle_ms_meas_report(struct gsm_lchan *lchan,
|
void lchan_meas_handle_sacch(struct gsm_lchan *lchan, struct msgb *msg);
|
||||||
const struct gsm48_hdr *gh,
|
|
||||||
unsigned int len);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include <osmocom/gsm/l1sap.h>
|
#include <osmocom/gsm/l1sap.h>
|
||||||
#include <osmocom/gsm/gsm_utils.h>
|
#include <osmocom/gsm/gsm_utils.h>
|
||||||
#include <osmocom/gsm/rsl.h>
|
#include <osmocom/gsm/rsl.h>
|
||||||
#include <osmocom/gsm/protocol/gsm_44_004.h>
|
|
||||||
#include <osmocom/core/gsmtap.h>
|
#include <osmocom/core/gsmtap.h>
|
||||||
#include <osmocom/core/gsmtap_util.h>
|
#include <osmocom/core/gsmtap_util.h>
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
|
@ -1470,7 +1469,6 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
|
||||||
uint8_t tn;
|
uint8_t tn;
|
||||||
uint32_t fn;
|
uint32_t fn;
|
||||||
enum osmo_ph_pres_info_type pr_info = data_ind->pdch_presence_info;
|
enum osmo_ph_pres_info_type pr_info = data_ind->pdch_presence_info;
|
||||||
struct gsm_sacch_l1_hdr *l1_hdr;
|
|
||||||
|
|
||||||
chan_nr = data_ind->chan_nr;
|
chan_nr = data_ind->chan_nr;
|
||||||
link_id = data_ind->link_id;
|
link_id = data_ind->link_id;
|
||||||
|
@ -1529,48 +1527,33 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
|
||||||
if (bts_internal_flag_get(trx->bts, BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB))
|
if (bts_internal_flag_get(trx->bts, BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB))
|
||||||
process_l1sap_meas_data(lchan, l1sap, PRIM_PH_DATA);
|
process_l1sap_meas_data(lchan, l1sap, PRIM_PH_DATA);
|
||||||
|
|
||||||
if (L1SAP_IS_LINK_SACCH(link_id))
|
if (L1SAP_IS_LINK_SACCH(link_id)) {
|
||||||
repeated_ul_sacch_active_decision(lchan, data_ind->ber10k);
|
repeated_ul_sacch_active_decision(lchan, data_ind->ber10k);
|
||||||
|
|
||||||
/* bad frame */
|
/* Radio Link Timeout counter */
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
if (L1SAP_IS_LINK_SACCH(link_id)) {
|
LOGPGT(DL1P, LOGL_INFO, &g_time, "%s Lost SACCH block\n",
|
||||||
/* In case we loose a SACCH block, we must take care
|
gsm_lchan_name(lchan));
|
||||||
* that the related measurement report is sent via RSL.
|
|
||||||
* This is a fallback method. The report will also
|
|
||||||
* lack the measurement report from the MS side. See
|
|
||||||
* also rsl.c:lapdm_rll_tx_cb() */
|
|
||||||
LOGPGT(DL1P, LOGL_INFO, &g_time, "Lost SACCH block, faking meas reports and ms pwr\n");
|
|
||||||
handle_ms_meas_report(lchan, NULL, 0);
|
|
||||||
|
|
||||||
radio_link_timeout(lchan, true);
|
radio_link_timeout(lchan, true);
|
||||||
|
} else {
|
||||||
|
radio_link_timeout(lchan, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Trigger the measurement reporting/processing logic */
|
||||||
|
lchan_meas_handle_sacch(lchan, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bad frame */
|
||||||
|
if (len == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
/* report first valid received frame to handover process */
|
/* report first valid received frame to handover process */
|
||||||
if (lchan->ho.active == HANDOVER_WAIT_FRAME)
|
if (lchan->ho.active == HANDOVER_WAIT_FRAME)
|
||||||
handover_frame(lchan);
|
handover_frame(lchan);
|
||||||
|
|
||||||
if (L1SAP_IS_LINK_SACCH(link_id)) {
|
if (L1SAP_IS_LINK_SACCH(link_id))
|
||||||
radio_link_timeout(lchan, false);
|
|
||||||
le = &lchan->lapdm_ch.lapdm_acch;
|
le = &lchan->lapdm_ch.lapdm_acch;
|
||||||
/* save the SACCH L1 header in the lchan struct for RSL MEAS RES */
|
else
|
||||||
if (len != GSM_MACBLOCK_LEN) {
|
|
||||||
LOGPGT(DL1P, LOGL_NOTICE, &g_time, "SACCH with odd len=%u!?!\n", len);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
/* Some brilliant engineer decided that the ordering of
|
|
||||||
* fields on the Um interface is different from the
|
|
||||||
* order of fields in RSL. See 3GPP TS 44.004 (section 7.2)
|
|
||||||
* vs. 3GPP TS 48.058 (section 9.3.10). */
|
|
||||||
l1_hdr = (struct gsm_sacch_l1_hdr*)data;
|
|
||||||
lchan->meas.l1_info.ms_pwr = l1_hdr->ms_pwr;
|
|
||||||
lchan->meas.l1_info.fpc_epc = l1_hdr->fpc_epc;
|
|
||||||
lchan->meas.l1_info.srr_sro = l1_hdr->srr_sro;
|
|
||||||
lchan->meas.l1_info.ta = l1_hdr->ta;
|
|
||||||
lchan->meas.flags |= LC_UL_M_F_L1_VALID;
|
|
||||||
} else
|
|
||||||
le = &lchan->lapdm_ch.lapdm_dcch;
|
le = &lchan->lapdm_ch.lapdm_dcch;
|
||||||
|
|
||||||
if (check_for_first_ciphrd(lchan, data, len))
|
if (check_for_first_ciphrd(lchan, data, len))
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <osmocom/gsm/gsm_utils.h>
|
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/endian.h>
|
||||||
|
|
||||||
|
#include <osmocom/gsm/gsm_utils.h>
|
||||||
|
#include <osmocom/gsm/protocol/gsm_44_004.h>
|
||||||
|
|
||||||
#include <osmo-bts/gsm_data.h>
|
#include <osmo-bts/gsm_data.h>
|
||||||
#include <osmo-bts/logging.h>
|
#include <osmo-bts/logging.h>
|
||||||
|
@ -865,24 +868,74 @@ out:
|
||||||
LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "DL-FACCH repetition: active => inactive\n");
|
LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "DL-FACCH repetition: active => inactive\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called every time a Measurement Result (TS 08.58 8.4.8) is received from
|
static bool data_is_rr_meas_rep(const uint8_t *data)
|
||||||
* lower layers and has to be forwarded to BSC */
|
|
||||||
int handle_ms_meas_report(struct gsm_lchan *lchan,
|
|
||||||
const struct gsm48_hdr *gh,
|
|
||||||
unsigned int len)
|
|
||||||
{
|
{
|
||||||
|
const struct gsm48_hdr *gh = (void *)(data + 5);
|
||||||
|
const uint8_t *lapdm_hdr = (void *)(data + 2);
|
||||||
|
|
||||||
|
/* LAPDm address field: SAPI=0, C/R=0, EA=1 */
|
||||||
|
if (lapdm_hdr[0] != 0x01)
|
||||||
|
return false;
|
||||||
|
/* LAPDm control field: U, func=UI */
|
||||||
|
if (lapdm_hdr[1] != 0x03)
|
||||||
|
return false;
|
||||||
|
/* Protocol discriminator: RR */
|
||||||
|
if (gh->proto_discr != GSM48_PDISC_RR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (gh->msg_type) {
|
||||||
|
case GSM48_MT_RR_EXT_MEAS_REP:
|
||||||
|
case GSM48_MT_RR_MEAS_REP:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called every time a SACCH block is received from lower layers */
|
||||||
|
void lchan_meas_handle_sacch(struct gsm_lchan *lchan, struct msgb *msg)
|
||||||
|
{
|
||||||
|
const struct gsm48_meas_res *mr = NULL;
|
||||||
|
const struct gsm48_hdr *gh = NULL;
|
||||||
int timing_offset, rc;
|
int timing_offset, rc;
|
||||||
struct lapdm_entity *le;
|
struct lapdm_entity *le;
|
||||||
bool dtxu_used;
|
bool dtxu_used = true; /* safe default assumption */
|
||||||
uint8_t ms_pwr;
|
uint8_t ms_pwr;
|
||||||
uint8_t ms_ta;
|
uint8_t ms_ta;
|
||||||
int8_t ul_rssi;
|
int8_t ul_rssi;
|
||||||
int16_t ul_ci_cb;
|
int16_t ul_ci_cb;
|
||||||
|
|
||||||
|
if (msgb_l2len(msg) == GSM_MACBLOCK_LEN) {
|
||||||
|
/* Some brilliant engineer decided that the ordering of
|
||||||
|
* fields on the Um interface is different from the
|
||||||
|
* order of fields in RSL. See 3GPP TS 44.004 (section 7.2)
|
||||||
|
* vs. 3GPP TS 48.058 (section 9.3.10). */
|
||||||
|
const struct gsm_sacch_l1_hdr *l1h = msgb_l2(msg);
|
||||||
|
lchan->meas.l1_info.ms_pwr = l1h->ms_pwr;
|
||||||
|
lchan->meas.l1_info.fpc_epc = l1h->fpc_epc;
|
||||||
|
lchan->meas.l1_info.srr_sro = l1h->srr_sro;
|
||||||
|
lchan->meas.l1_info.ta = l1h->ta;
|
||||||
|
lchan->meas.flags |= LC_UL_M_F_L1_VALID;
|
||||||
|
|
||||||
|
/* Check if this is a Measurement Report */
|
||||||
|
if (data_is_rr_meas_rep(msgb_l2(msg))) {
|
||||||
|
/* Skip both L1 SACCH and LAPDm headers */
|
||||||
|
msg->l3h = (void *)(msg->l2h + 2 + 3);
|
||||||
|
gh = msgb_l3(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
ms_pwr = lchan->meas.l1_info.ms_pwr;
|
||||||
|
ms_ta = lchan->meas.l1_info.ta;
|
||||||
|
} else {
|
||||||
|
lchan->meas.flags &= ~LC_UL_M_F_L1_VALID;
|
||||||
|
ms_pwr = lchan->ms_power_ctrl.current;
|
||||||
|
ms_ta = lchan->ta_ctrl.current;
|
||||||
|
}
|
||||||
|
|
||||||
le = &lchan->lapdm_ch.lapdm_acch;
|
le = &lchan->lapdm_ch.lapdm_acch;
|
||||||
|
|
||||||
timing_offset = ms_to_valid(lchan) ? ms_to2rsl(lchan, le) : -1;
|
timing_offset = ms_to_valid(lchan) ? ms_to2rsl(lchan, le) : -1;
|
||||||
rc = rsl_tx_meas_res(lchan, (const uint8_t *)gh, len, timing_offset);
|
rc = rsl_tx_meas_res(lchan, msgb_l3(msg), msgb_l3len(msg), timing_offset);
|
||||||
if (rc == 0) /* Count successful transmissions */
|
if (rc == 0) /* Count successful transmissions */
|
||||||
lchan->meas.res_nr++;
|
lchan->meas.res_nr++;
|
||||||
|
|
||||||
|
@ -896,25 +949,9 @@ int handle_ms_meas_report(struct gsm_lchan *lchan,
|
||||||
* feed the Control Loop with the measurements for the same
|
* feed the Control Loop with the measurements for the same
|
||||||
* period (the previous one), which is stored in lchan->meas(.ul_res):
|
* period (the previous one), which is stored in lchan->meas(.ul_res):
|
||||||
*/
|
*/
|
||||||
if (len == 0) {
|
if (gh && gh->msg_type == GSM48_MT_RR_MEAS_REP) {
|
||||||
dtxu_used = true;
|
mr = (const struct gsm48_meas_res *)gh->data;
|
||||||
ms_ta = lchan->ta_ctrl.current;
|
dtxu_used = mr->dtx_used;
|
||||||
ms_pwr = lchan->ms_power_ctrl.current;
|
|
||||||
} else {
|
|
||||||
/* if len!=0, it means we were able to parse L1Header in UL SACCH: */
|
|
||||||
OSMO_ASSERT(lchan->meas.flags & LC_UL_M_F_L1_VALID);
|
|
||||||
|
|
||||||
ms_ta = lchan->meas.l1_info.ta;
|
|
||||||
ms_pwr = lchan->meas.l1_info.ms_pwr;
|
|
||||||
switch (gh->msg_type) {
|
|
||||||
case GSM48_MT_RR_MEAS_REP:
|
|
||||||
dtxu_used = (len > sizeof(*gh) + 1) && !!(gh->data[0] & 0x40);
|
|
||||||
break;
|
|
||||||
case GSM48_MT_RR_EXT_MEAS_REP:
|
|
||||||
default:
|
|
||||||
dtxu_used = true; /* FIXME: not implemented */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dtxu_used) {
|
if (dtxu_used) {
|
||||||
|
@ -934,8 +971,6 @@ int handle_ms_meas_report(struct gsm_lchan *lchan,
|
||||||
/* Reset state for next iteration */
|
/* Reset state for next iteration */
|
||||||
lchan->tch.dtx.dl_active = false;
|
lchan->tch.dtx.dl_active = false;
|
||||||
lchan->meas.flags &= ~LC_UL_M_F_OSMO_EXT_VALID;
|
lchan->meas.flags &= ~LC_UL_M_F_OSMO_EXT_VALID;
|
||||||
lchan->meas.flags &= ~LC_UL_M_F_L1_VALID;
|
|
||||||
lchan->ms_t_offs = -1;
|
lchan->ms_t_offs = -1;
|
||||||
lchan->p_offs = -1;
|
lchan->p_offs = -1;
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3566,17 +3566,11 @@ int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
|
||||||
msg->trx = lchan->ts->trx;
|
msg->trx = lchan->ts->trx;
|
||||||
msg->lchan = lchan;
|
msg->lchan = lchan;
|
||||||
|
|
||||||
/* check if this is a measurement report from SACCH which needs special
|
/* If this is a Measurement Report, then we simply ignore it,
|
||||||
* processing before forwarding */
|
* because it has already been processed in l1sap_ph_data_ind(). */
|
||||||
if (rslms_is_meas_rep(msg)) {
|
if (rslms_is_meas_rep(msg)) {
|
||||||
int rc;
|
|
||||||
|
|
||||||
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Handing RLL msg %s from LAPDm to MEAS REP\n",
|
|
||||||
rsl_msg_name(rh->msg_type));
|
|
||||||
|
|
||||||
rc = handle_ms_meas_report(lchan, (struct gsm48_hdr *)msgb_l3(msg), msgb_l3len(msg));
|
|
||||||
msgb_free(msg);
|
msgb_free(msg);
|
||||||
return rc;
|
return 0;
|
||||||
} else if (rslms_is_gprs_susp_req(msg)) {
|
} else if (rslms_is_gprs_susp_req(msg)) {
|
||||||
return handle_gprs_susp_req(msg);
|
return handle_gprs_susp_req(msg);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue