Use polling based LAPDm with frame numbers

Osmo-bts uses the new polling based LAPDm implementation.

The OML message NM_ATT_T200 is ignored, because T200 timeouts are set to
the minimal response time. Longer timeouts would cause lower throughput
in case of lost frames. Shorter timeouts would cause LAPDm to fail.

Related: OS#4074
Depends: libosmocore.git I6ebe83f829d7751ea9de1d90eb478c7a628db64c
Change-Id: Ic6d7902b13cf491daaa8752db78f9875387aeffd
This commit is contained in:
Andreas Eversberg 2023-11-13 14:51:39 +01:00
parent 1013ca3b8b
commit 17fe7d6841
6 changed files with 91 additions and 73 deletions

View File

@ -241,7 +241,7 @@ struct gsm_bts {
int16_t boundary[6];
uint8_t intave;
} interference;
unsigned int t200_ms[7];
uint32_t t200_fn[7];
unsigned int t3105_ms;
unsigned int t3115_ms; /* VGCS UPLINK GRANT repeat timer */
struct {

View File

@ -68,7 +68,7 @@ int oml_fom_ack_nack_copy_msg(const struct msgb *old_msg, uint8_t cause);
int oml_mo_fom_ack_nack(const struct gsm_abis_mo *mo, uint8_t orig_msg_type,
uint8_t cause);
extern const unsigned int oml_default_t200_ms[7];
extern const uint32_t oml_default_t200_fn[7];
/* Transmit failure event report */
int oml_tx_failure_event_rep(const struct gsm_abis_mo *mo, enum abis_nm_severity severity,

View File

@ -355,8 +355,8 @@ int bts_init(struct gsm_bts *bts)
bts->max_ber10k_rach = 1707; /* 7 of 41 bits is Eb/N0 of 0 dB = 0.1707 */
bts->pcu.sock_path = talloc_strdup(bts, PCU_SOCK_DEFAULT);
bts->pcu.sock_wqueue_len_max = BTS_PCU_SOCK_WQUEUE_LEN_DEFAULT;
for (i = 0; i < ARRAY_SIZE(bts->t200_ms); i++)
bts->t200_ms[i] = oml_default_t200_ms[i];
for (i = 0; i < ARRAY_SIZE(bts->t200_fn); i++)
bts->t200_fn[i] = oml_default_t200_fn[i];
/* default RADIO_LINK_TIMEOUT */
bts->radio_link_timeout.oml = 32;

View File

@ -957,10 +957,10 @@ static void l1sap_update_fnstats(struct gsm_bts *bts, uint32_t rts_fn)
}
/* Common dequeueing function */
static inline struct msgb *lapdm_phsap_dequeue_msg(struct lapdm_entity *le)
static inline struct msgb *lapdm_phsap_dequeue_msg(struct lapdm_entity *le, uint32_t fn)
{
struct osmo_phsap_prim pp;
if (lapdm_phsap_dequeue_prim(le, &pp) < 0)
if (lapdm_phsap_dequeue_prim_fn(le, &pp, fn) < 0)
return NULL;
return pp.oph.msg;
}
@ -983,7 +983,7 @@ static inline struct msgb *lapdm_phsap_dequeue_msg_facch(struct gsm_lchan *lchan
lchan->rep_acch.dl_facch[1].msg = NULL;
} else {
/* Fetch new FACCH from queue ... */
if (lapdm_phsap_dequeue_prim(le, &pp) < 0)
if (lapdm_phsap_dequeue_prim_fn(le, &pp, fn) < 0)
return NULL;
msg = pp.oph.msg;
@ -1013,7 +1013,7 @@ static inline struct msgb *lapdm_phsap_dequeue_msg_facch(struct gsm_lchan *lchan
}
/* Special dequeueing function with SACCH repetition (3GPP TS 44.006, section 11) */
static inline struct msgb *lapdm_phsap_dequeue_msg_sacch(struct gsm_lchan *lchan, struct lapdm_entity *le)
static inline struct msgb *lapdm_phsap_dequeue_msg_sacch(struct gsm_lchan *lchan, struct lapdm_entity *le, uint32_t fn)
{
struct osmo_phsap_prim pp;
struct msgb *msg;
@ -1037,7 +1037,7 @@ static inline struct msgb *lapdm_phsap_dequeue_msg_sacch(struct gsm_lchan *lchan
}
/* Fetch new repetition candidate from queue */
if (lapdm_phsap_dequeue_prim(le, &pp) < 0)
if (lapdm_phsap_dequeue_prim_fn(le, &pp, fn) < 0)
return NULL;
msg = pp.oph.msg;
sapi = (msg->data[0] >> 2) & 0x07;
@ -1148,9 +1148,9 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
LOGPLCHAN(lchan, DL1P, LOGL_DEBUG, "DL-SACCH repetition: active => inactive\n");
lchan->rep_acch.dl_sacch_active = false;
}
pp_msg = lapdm_phsap_dequeue_msg_sacch(lchan, le);
pp_msg = lapdm_phsap_dequeue_msg_sacch(lchan, le, fn);
} else {
pp_msg = lapdm_phsap_dequeue_msg(le);
pp_msg = lapdm_phsap_dequeue_msg(le, fn);
}
} else {
if (lchan->ts->trx->bts->dtxd)
@ -1159,7 +1159,7 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
if (lchan->rep_acch.dl_facch_active && lchan->rsl_cmode != RSL_CMOD_SPD_SIGN)
pp_msg = lapdm_phsap_dequeue_msg_facch(lchan, le, fn);
else
pp_msg = lapdm_phsap_dequeue_msg(le);
pp_msg = lapdm_phsap_dequeue_msg(le, fn);
lchan->tch.dtx_fr_hr_efr.dl_facch_stealing = (pp_msg != NULL);
}
if (!pp_msg) {
@ -1802,9 +1802,18 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
lchan_meas_handle_sacch(lchan, msg);
}
if (L1SAP_IS_LINK_SACCH(link_id))
le = &lchan->lapdm_ch.lapdm_acch;
else
le = &lchan->lapdm_ch.lapdm_dcch;
/* bad frame */
if (len == 0)
if (len == 0) {
/* Notify current receive FN to lapdm. */
lapdm_t200_fn(le, fn);
return -EINVAL;
}
/* report first valid received frame to handover process */
if (lchan->ho.active == HANDOVER_WAIT_FRAME)
@ -1825,11 +1834,6 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
return 0;
}
if (L1SAP_IS_LINK_SACCH(link_id))
le = &lchan->lapdm_ch.lapdm_acch;
else
le = &lchan->lapdm_ch.lapdm_dcch;
if (check_for_first_ciphrd(lchan, data, len))
l1sap_tx_ciph_req(lchan->ts->trx, chan_nr, 1, 0);
@ -1837,6 +1841,9 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
msgb_pull_to_l2(msg);
lapdm_phsap_up(&l1sap->oph, le);
/* Notify current receive FN to lapdm. */
lapdm_t200_fn(le, fn);
/* don't free, because we forwarded data */
return 1;
}
@ -1961,6 +1968,12 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
LOGPLCGT(lchan, &g_time, DL1P, LOGL_DEBUG, "Rx TCH.ind\n");
}
/* Notify current receive FN to lapdm.
* TCH frames may be indicated before FACCH frames are indicated. To prevent T200 timeout before FACCH is
* received, subtract one frame number, so that timeout is processed next time after FACCH is received.
*/
lapdm_t200_fn(&lchan->lapdm_ch.lapdm_dcch, GSM_TDMA_FN_SUB(fn, 1));
/* The ph_tch_param contained in the l1sap primitive may contain
* measurement data. If this data is present, forward it for
* processing */

View File

@ -57,41 +57,40 @@ const struct value_string lchan_ciph_state_names[] = {
};
/* prepare the per-SAPI T200 arrays for a given lchan */
static int t200_by_lchan(int *t200_ms_dcch, int *t200_ms_acch, struct gsm_lchan *lchan)
static int t200_by_lchan(uint32_t *t200_fn_dcch, uint32_t *t200_fn_acch, struct gsm_lchan *lchan)
{
struct gsm_bts *bts = lchan->ts->trx->bts;
/* we have to compensate for the "RTS advance" due to the asynchronous interface between
* the BTS (LAPDm) and the PHY/L1 (OsmoTRX or DSP in case of osmo-bts-{sysmo,lc15,oc2g,octphy} */
int32_t fn_advance = bts_get_avg_fn_advance(bts);
int32_t fn_advance_us = fn_advance * 4615;
int fn_advance_ms = fn_advance_us / 1000;
t200_ms_acch[DL_SAPI0] = bts->t200_ms[T200_SACCH_SDCCH] + fn_advance_ms;
t200_ms_acch[DL_SAPI3] = bts->t200_ms[T200_SACCH_SDCCH] + fn_advance_ms;
if (lchan->rep_acch_cap.dl_facch_all && lchan_is_tch(lchan)) {
t200_ms_acch[DL_SAPI0] *= 2;
t200_ms_acch[DL_SAPI3] *= 2;
}
switch (lchan->type) {
case GSM_LCHAN_SDCCH:
t200_ms_dcch[DL_SAPI0] = bts->t200_ms[T200_SDCCH] + fn_advance_ms;
t200_ms_dcch[DL_SAPI3] = bts->t200_ms[T200_SDCCH_SAPI3] + fn_advance_ms;
t200_fn_dcch[DL_SAPI0] = bts->t200_fn[T200_SDCCH];
t200_fn_dcch[DL_SAPI3] = bts->t200_fn[T200_SDCCH_SAPI3];
t200_fn_acch[DL_SAPI0] = bts->t200_fn[T200_SACCH_SDCCH];
t200_fn_acch[DL_SAPI3] = bts->t200_fn[T200_SACCH_SDCCH];
break;
case GSM_LCHAN_TCH_F:
t200_ms_dcch[DL_SAPI0] = bts->t200_ms[T200_FACCH_F] + fn_advance_ms;
t200_ms_dcch[DL_SAPI3] = bts->t200_ms[T200_FACCH_F] + fn_advance_ms;
t200_fn_dcch[DL_SAPI0] = bts->t200_fn[T200_FACCH_F];
t200_fn_dcch[DL_SAPI3] = bts->t200_fn[T200_FACCH_F];
t200_fn_acch[DL_SAPI0] = bts->t200_fn[T200_SACCH_TCH_SAPI0];
t200_fn_acch[DL_SAPI3] = bts->t200_fn[T200_SACCH_TCH_SAPI3];
break;
case GSM_LCHAN_TCH_H:
t200_ms_dcch[DL_SAPI0] = bts->t200_ms[T200_FACCH_H] + fn_advance_ms;
t200_ms_dcch[DL_SAPI3] = bts->t200_ms[T200_FACCH_H] + fn_advance_ms;
t200_fn_dcch[DL_SAPI0] = bts->t200_fn[T200_FACCH_H];
t200_fn_dcch[DL_SAPI3] = bts->t200_fn[T200_FACCH_H];
t200_fn_acch[DL_SAPI0] = bts->t200_fn[T200_SACCH_TCH_SAPI0];
t200_fn_acch[DL_SAPI3] = bts->t200_fn[T200_SACCH_TCH_SAPI3];
break;
default:
/* Channels such as CCCH don't use lapdm DL, and hence no T200 is needed */
return -1;
}
/* Add time of two extra messages frames. */
if (lchan->rep_acch_cap.dl_facch_all && lchan_is_tch(lchan)) {
t200_fn_acch[DL_SAPI0] += 104 * 2;
t200_fn_acch[DL_SAPI3] += 104 * 2;
}
return 0;
}
@ -152,17 +151,17 @@ void gsm_lchan_name_update(struct gsm_lchan *lchan)
int lchan_init_lapdm(struct gsm_lchan *lchan)
{
struct lapdm_channel *lc = &lchan->lapdm_ch;
int t200_ms_dcch[_NR_DL_SAPI], t200_ms_acch[_NR_DL_SAPI];
uint32_t t200_fn_dcch[_NR_DL_SAPI], t200_fn_acch[_NR_DL_SAPI];
if (t200_by_lchan(t200_ms_dcch, t200_ms_acch, lchan) == 0) {
if (t200_by_lchan(t200_fn_dcch, t200_fn_acch, lchan) == 0) {
LOGPLCHAN(lchan, DLLAPD, LOGL_DEBUG,
"Setting T200 D0=%u, D3=%u, S0=%u, S3=%u (all in ms)\n",
t200_ms_dcch[DL_SAPI0], t200_ms_dcch[DL_SAPI3],
t200_ms_acch[DL_SAPI0], t200_ms_acch[DL_SAPI3]);
lapdm_channel_init3(lc, LAPDM_MODE_BTS, t200_ms_dcch, t200_ms_acch, lchan->type,
gsm_lchan_name(lchan));
lapdm_channel_set_flags(lc, LAPDM_ENT_F_POLLING_ONLY);
"Setting T200 D0=%u, D3=%u, S0=%u, S3=%u (all in frames)\n",
t200_fn_dcch[DL_SAPI0], t200_fn_dcch[DL_SAPI3],
t200_fn_acch[DL_SAPI0], t200_fn_acch[DL_SAPI3]);
lapdm_channel_init3(lc, LAPDM_MODE_BTS, NULL, NULL, lchan->type, gsm_lchan_name(lchan));
lapdm_channel_set_flags(lc, LAPDM_ENT_F_POLLING_ONLY | LAPDM_ENT_F_RTS);
lapdm_channel_set_l1(lc, NULL, lchan);
lapdm_channel_set_t200_fn(lc, t200_fn_dcch, t200_fn_acch);
}
/* We still need to set Rx callback to receive RACH requests: */
lapdm_channel_set_l3(lc, lapdm_rll_tx_cb, lchan);

View File

@ -525,16 +525,21 @@ int oml_mo_tx_sw_act_rep(const struct gsm_abis_mo *mo)
return oml_mo_send_msg(mo, nmsg, NM_MT_SW_ACTIVATED_REP);
}
/* The defaults below correspond to various sources/recommendations that could be found online.
* The BSC should override this via OML anyway. */
const unsigned int oml_default_t200_ms[7] = {
[T200_SDCCH] = 1000,
[T200_FACCH_F] = 1000,
[T200_FACCH_H] = 1000,
[T200_SACCH_TCH_SAPI0] = 2000,
[T200_SACCH_SDCCH] = 2000,
[T200_SDCCH_SAPI3] = 1000,
[T200_SACCH_TCH_SAPI3] = 2000,
/* The defaults below correspond to the number of frames until a response from the MS is expected.
* It defines the FN distance between the frame number when a message is sent (first frame) and when the response is
* received (first frame). On SACCH the duration is two frames, because SAPI0 and SAPI3 are are transmitted in
* alternating order. On DCCH with SAPI3 the duration is two seconds, because SAPI0 has priority over SAPI3.
*
* See Table 8 if 3GPP TS 44.006. Note that the table only shows the FN distance between frames.
*/
const uint32_t oml_default_t200_fn[7] = {
[T200_SDCCH] = 4+32,
[T200_FACCH_F] = 8+9,
[T200_FACCH_H] = 6+10,
[T200_SACCH_TCH_SAPI0] = 79+25+104,
[T200_SACCH_SDCCH] = 4+32+51,
[T200_SDCCH_SAPI3] = 4+32+408, /* two seconds */
[T200_SACCH_TCH_SAPI3] = 79+25+104,
};
/* 3GPP TS 52.021 §8.11.1 Get Attributes has been received */
@ -677,25 +682,26 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
}
/* 9.4.53 T200 */
if (TLVP_PRES_LEN(&tp, NM_ATT_T200, ARRAY_SIZE(bts->t200_ms))) {
payload = TLVP_VAL(&tp, NM_ATT_T200);
for (i = 0; i < ARRAY_SIZE(bts->t200_ms); i++) {
uint32_t t200_ms = payload[i] * abis_nm_t200_ms[i];
if (TLVP_PRES_LEN(&tp, NM_ATT_T200, ARRAY_SIZE(bts->t200_fn))) {
/* The OML message NM_ATT_T200 is ignored, because T200 timeouts are set to
* the minimal response time. Longer timeouts would cause lower throughput
* in case of lost frames. Shorter timeouts would cause LAPDm to fail. */
DEBUGPFOH(DOML, foh, "Ignoring T200 BTS attribute.\n");
#if 0
bts->t200_ms[i] = t200_ms;
DEBUGPFOH(DOML, foh, "T200[%u]: OML=%u, mult=%u => %u ms\n",
payload = TLVP_VAL(&tp, NM_ATT_T200);
for (i = 0; i < ARRAY_SIZE(bts->t200_fn); i++) {
uint32_t t200_ms = payload[i] * abis_nm_t200_ms[i];
uint32_t t200_fn = t200_ms * 1000 + (GSM_TDMA_FN_DURATION_uS - 1) / GSM_TDMA_FN_DURATION_uS;
/* Values must not be less than absolute minimum. */
if (oml_default_t200_fn[i] <= t200_fn)
bts->t200_fn[i] = t200_fn;
else
bts->t200_fn[i] = oml_default_t200_fn[i];
DEBUGPFOH(DOML, foh, "T200[%u]: OML=%u, mult=%u => %u ms -> %u fn\n",
i, payload[i], abis_nm_t200_ms[i],
bts->t200_ms[i]);
#else
/* we'd rather use the 1s/2s (long) defaults by
* libosmocore, as we appear to have some bug(s)
* related to handling T200 expiration in
* libosmogsm lapd(m) code? */
LOGPFOH(DOML, LOGL_NOTICE, foh, "Ignoring T200[%u] (%u ms) "
"as sent by BSC due to suspected LAPDm bug!\n",
i, t200_ms);
#endif
t200_ms, bts->t200_fn[i]);
}
#endif
}
/* 9.4.31 Maximum Timing Advance */