diff options
author | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2023-05-22 16:54:21 +0700 |
---|---|---|
committer | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2023-07-12 03:52:34 +0700 |
commit | fd8962e89144fb0af4b99199589d9f9768804640 (patch) | |
tree | a1b2974be609f0f669a2ee08395d7ae7c111277e | |
parent | 44282c0fe8957ef43853ab982e9bf4a30e54efde (diff) |
trxcon/l1sched: do not craft artificial BFI frames on TCH
Whenever decoding fails or a FACCH setaling happens, simply send an
empty DATA.ind to the upper layers. On the Uplink path, use a dummy
LAPDm func=UI frame (with random padding) whenever possible.
Crafting TCH frames with zeroes is not really needed and moreover makes
it hard to distinguish between valid speech frames and BFIs. This also
used to be the case for osmo-bts-trx, but not anymore (see the related
patch).
Change-Id: I20391b860fbc2ce8f0f03d7ba95ef7a098c0f9db
Related: osmo-bts.git I8f9fb5b8c5b2cad4b92ac693c0040779f811981a
-rw-r--r-- | src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h | 2 | ||||
-rw-r--r-- | src/host/trxcon/include/osmocom/bb/l1sched/prim.h | 3 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_common.c | 49 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_tchf.c | 45 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_tchh.c | 119 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_xcch.c | 2 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_prim.c | 83 |
7 files changed, 53 insertions, 250 deletions
diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h index cee26600..5385c00d 100644 --- a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h +++ b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h @@ -389,8 +389,6 @@ int l1sched_handle_burst_req(struct l1sched_state *sched, extern const uint8_t l1sched_nb_training_bits[8][26]; const char *l1sched_burst_mask2str(const uint8_t *mask, int bits); -size_t l1sched_bad_frame_ind(uint8_t *l2, struct l1sched_lchan_state *lchan); -bool l1sched_lchan_amr_prim_is_valid(struct l1sched_lchan_state *lchan, bool is_cmr); /* Interleaved TCH/H block TDMA frame mapping */ bool l1sched_tchh_block_map_fn(enum l1sched_lchan_type chan, diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/prim.h b/src/host/trxcon/include/osmocom/bb/l1sched/prim.h index c0e6af60..af3ac3b6 100644 --- a/src/host/trxcon/include/osmocom/bb/l1sched/prim.h +++ b/src/host/trxcon/include/osmocom/bb/l1sched/prim.h @@ -116,9 +116,10 @@ void l1sched_prim_init(struct msgb *msg, struct msgb *l1sched_prim_alloc(enum l1sched_prim_type type, enum osmo_prim_operation op); +bool l1sched_lchan_amr_prim_is_valid(struct l1sched_lchan_state *lchan, bool is_cmr); struct msgb *l1sched_lchan_prim_dequeue_sacch(struct l1sched_lchan_state *lchan); struct msgb *l1sched_lchan_prim_dequeue_tch(struct l1sched_lchan_state *lchan, bool facch); -struct msgb *l1sched_lchan_prim_dummy(struct l1sched_lchan_state *lchan); +struct msgb *l1sched_lchan_prim_dummy_lapdm(const struct l1sched_lchan_state *lchan); void l1sched_lchan_prim_drop(struct l1sched_lchan_state *lchan); int l1sched_lchan_emit_data_ind(struct l1sched_lchan_state *lchan, diff --git a/src/host/trxcon/src/sched_lchan_common.c b/src/host/trxcon/src/sched_lchan_common.c index ad42d9e8..bf318316 100644 --- a/src/host/trxcon/src/sched_lchan_common.c +++ b/src/host/trxcon/src/sched_lchan_common.c @@ -93,55 +93,6 @@ const char *l1sched_burst_mask2str(const uint8_t *mask, int bits) return buf; } -/** - * Composes a bad frame indication message - * according to the current tch_mode. - * - * @param l2 Caller-allocated byte array - * @param lchan Logical channel to generate BFI for - * @return How much bytes were written - */ -size_t l1sched_bad_frame_ind(uint8_t *l2, struct l1sched_lchan_state *lchan) -{ - int rc; - - switch (lchan->tch_mode) { - case GSM48_CMODE_SPEECH_V1: - if (lchan->type == L1SCHED_TCHF) { /* Full Rate */ - memset(l2, 0x00, GSM_FR_BYTES); - l2[0] = 0xd0; - return GSM_FR_BYTES; - } else { /* Half Rate */ - memset(l2 + 1, 0x00, GSM_HR_BYTES); - l2[0] = 0x70; /* F = 0, FT = 111 */ - return GSM_HR_BYTES + 1; - } - case GSM48_CMODE_SPEECH_EFR: /* Enhanced Full Rate */ - memset(l2, 0x00, GSM_EFR_BYTES); - l2[0] = 0xc0; - return GSM_EFR_BYTES; - case GSM48_CMODE_SPEECH_AMR: /* Adaptive Multi Rate */ - rc = osmo_amr_rtp_enc(l2, - lchan->amr.codec[lchan->amr.dl_cmr], - lchan->amr.codec[lchan->amr.dl_ft], - AMR_BAD); - if (rc < 2) { - LOGP_LCHAND(lchan, LOGL_ERROR, - "Failed to encode AMR_BAD frame (rc=%d), " - "not sending BFI\n", rc); - return 0; - } - memset(l2 + 2, 0, rc - 2); - return rc; - case GSM48_CMODE_SIGN: - LOGP_LCHAND(lchan, LOGL_ERROR, "BFI is not allowed in signalling mode\n"); - return 0; - default: - LOGP_LCHAND(lchan, LOGL_ERROR, "Invalid TCH mode: %u\n", lchan->tch_mode); - return 0; - } -} - bool l1sched_lchan_amr_prim_is_valid(struct l1sched_lchan_state *lchan, bool is_cmr) { enum osmo_amr_type ft_codec; diff --git a/src/host/trxcon/src/sched_lchan_tchf.c b/src/host/trxcon/src/sched_lchan_tchf.c index a87efafe..cd53c46f 100644 --- a/src/host/trxcon/src/sched_lchan_tchf.c +++ b/src/host/trxcon/src/sched_lchan_tchf.c @@ -167,16 +167,17 @@ int rx_tchf_fn(struct l1sched_lchan_state *lchan, "Received bad frame (rc=%d, ber=%d/%d) at fn=%u\n", rc, n_errors, n_bits_total, lchan->meas_avg.fn); - /* Send BFI */ - goto bfi; + /* Send BFI (DATA.ind without payload) */ + tch_data_len = 0; } else if (rc == GSM_MACBLOCK_LEN) { /* FACCH received, forward it to the higher layers */ l1sched_lchan_emit_data_ind(lchan, &tch_data[amr], GSM_MACBLOCK_LEN, n_errors, n_bits_total, false); - /* Send BFI substituting a stolen TCH frame */ - n_errors = -1; /* ensure fake measurements */ - goto bfi; + /* Send BFI (DATA.ind without payload) */ + if (lchan->tch_mode == GSM48_CMODE_SIGN) + return 0; + tch_data_len = 0; } else { /* A good TCH frame received */ tch_data_len = rc; @@ -185,32 +186,6 @@ int rx_tchf_fn(struct l1sched_lchan_state *lchan, /* Send a traffic frame to the higher layers */ return l1sched_lchan_emit_data_ind(lchan, &tch_data[0], tch_data_len, n_errors, n_bits_total, true); - -bfi: - /* Didn't try to decode, fake measurements */ - if (n_errors < 0) { - lchan->meas_avg = (struct l1sched_meas_set) { - .fn = lchan->meas_avg.fn, - .toa256 = 0, - .rssi = -110, - }; - - /* No bursts => no errors */ - n_errors = 0; - } - - /* BFI is not applicable in signalling mode */ - if (lchan->tch_mode == GSM48_CMODE_SIGN) { - return l1sched_lchan_emit_data_ind(lchan, NULL, 0, - n_errors, n_bits_total, false); - } - - /* Bad frame indication */ - tch_data_len = l1sched_bad_frame_ind(&tch_data[0], lchan); - - /* Send a BFI frame to the higher layers */ - return l1sched_lchan_emit_data_ind(lchan, &tch_data[0], tch_data_len, - n_errors, n_bits_total, true); } static struct msgb *prim_dequeue_tchf(struct l1sched_lchan_state *lchan) @@ -255,11 +230,9 @@ int tx_tchf_fn(struct l1sched_lchan_state *lchan, *mask = *mask << 4; lchan->prim = prim_dequeue_tchf(lchan); - if (lchan->prim == NULL) { - lchan->prim = l1sched_lchan_prim_dummy(lchan); - if (lchan->prim == NULL) - return -ENOENT; - } + if (lchan->prim == NULL) + lchan->prim = l1sched_lchan_prim_dummy_lapdm(lchan); + OSMO_ASSERT(lchan->prim != NULL); /* populate the buffer with bursts */ switch (lchan->tch_mode) { diff --git a/src/host/trxcon/src/sched_lchan_tchh.c b/src/host/trxcon/src/sched_lchan_tchh.c index 67e21320..3fa823ba 100644 --- a/src/host/trxcon/src/sched_lchan_tchh.c +++ b/src/host/trxcon/src/sched_lchan_tchh.c @@ -180,60 +180,6 @@ bool l1sched_tchh_block_map_fn(enum l1sched_lchan_type chan, return false; } -/** - * Calculates a frame number of the first burst - * using given frame number of the last burst. - * - * See GSM 05.02, clause 7, table 1 - * - * @param chan channel type (L1SCHED_TCHH_0 or L1SCHED_TCHH_1) - * @param last_fn frame number of the last burst - * @param facch FACCH/H or traffic? - * @return either frame number of the first burst, - * or fn=last_fn if calculation failed - */ -static uint32_t tchh_block_dl_first_fn(const struct l1sched_lchan_state *lchan, - uint32_t last_fn, bool facch) -{ - enum l1sched_lchan_type chan = lchan->type; - uint8_t fn_mf, fn_diff; - int i = 0; - - /* Just to be sure */ - OSMO_ASSERT(chan == L1SCHED_TCHH_0 || chan == L1SCHED_TCHH_1); - - /* Calculate a modulo */ - fn_mf = facch ? (last_fn % 26) : (last_fn % 13); - -#define BLOCK_FIRST_FN(map) \ - do { \ - if (map[i][ARRAY_SIZE(map[i]) - 1] == fn_mf) { \ - fn_diff = GSM_TDMA_FN_DIFF(fn_mf, map[i][0]); \ - return GSM_TDMA_FN_SUB(last_fn, fn_diff); \ - } \ - } while (++i < ARRAY_SIZE(map)) - - /* Choose a proper block map */ - if (facch) { - if (chan == L1SCHED_TCHH_0) - BLOCK_FIRST_FN(tch_h0_dl_facch_block_map); - else - BLOCK_FIRST_FN(tch_h1_dl_facch_block_map); - } else { - if (chan == L1SCHED_TCHH_0) - BLOCK_FIRST_FN(tch_h0_traffic_block_map); - else - BLOCK_FIRST_FN(tch_h1_traffic_block_map); - } - - LOGP_LCHAND(lchan, LOGL_ERROR, - "Failed to calculate TDMA frame number of the first burst of %s block, " - "using the current fn=%u\n", facch ? "FACCH/H" : "TCH/H", last_fn); - - /* Couldn't calculate the first fn, return the last */ - return last_fn; -} - int rx_tchh_fn(struct l1sched_lchan_state *lchan, const struct l1sched_burst_ind *bi) { @@ -290,21 +236,13 @@ int rx_tchh_fn(struct l1sched_lchan_state *lchan, if (bi->bid != 1) return 0; - /* Wait for complete set of bursts */ - if (lchan->tch_mode == GSM48_CMODE_SIGN) { - /* FACCH/H is interleaved over 6 bursts */ - if ((*mask & 0x3f) != 0x3f) - goto bfi; - } else { - /* Traffic is interleaved over 4 bursts */ - if ((*mask & 0x0f) != 0x0f) - goto bfi; - } - /* Skip decoding attempt in case of FACCH/H */ if (lchan->dl_ongoing_facch) { + /* Send BFI (DATA.ind without payload) for the 2nd stolen TCH frame */ + l1sched_lchan_meas_avg(lchan, 4); + l1sched_lchan_emit_data_ind(lchan, NULL, 0, 0, 0, true); lchan->dl_ongoing_facch = false; - goto bfi; /* 2/2 BFI */ + return 0; } switch (lchan->tch_mode) { @@ -350,15 +288,12 @@ int rx_tchh_fn(struct l1sched_lchan_state *lchan, /* Check decoding result */ if (rc < 4) { - /* Calculate AVG of the measurements (assuming 4 bursts) */ - l1sched_lchan_meas_avg(lchan, 4); - LOGP_LCHAND(lchan, LOGL_ERROR, "Received bad frame (rc=%d, ber=%d/%d) at fn=%u\n", rc, n_errors, n_bits_total, lchan->meas_avg.fn); - /* Send BFI */ - goto bfi; + /* Send BFI (DATA.ind without payload) */ + tch_data_len = 0; } else if (rc == GSM_MACBLOCK_LEN) { /* Skip decoding of the next 2 stolen bursts */ lchan->dl_ongoing_facch = true; @@ -370,44 +305,19 @@ int rx_tchh_fn(struct l1sched_lchan_state *lchan, l1sched_lchan_emit_data_ind(lchan, &tch_data[amr], GSM_MACBLOCK_LEN, n_errors, n_bits_total, false); - /* Send BFI substituting 1/2 stolen TCH frames */ - n_errors = -1; /* ensure fake measurements */ - goto bfi; + /* Send BFI (DATA.ind without payload) for the 1st stolen TCH frame */ + if (lchan->tch_mode == GSM48_CMODE_SIGN) + return 0; + tch_data_len = 0; } else { /* A good TCH frame received */ tch_data_len = rc; - - /* Calculate AVG of the measurements (traffic takes 4 bursts) */ - l1sched_lchan_meas_avg(lchan, 4); - } - - /* Send a traffic frame to the higher layers */ - return l1sched_lchan_emit_data_ind(lchan, &tch_data[0], tch_data_len, - n_errors, n_bits_total, true); - -bfi: - /* Didn't try to decode, fake measurements */ - if (n_errors < 0) { - lchan->meas_avg = (struct l1sched_meas_set) { - .fn = tchh_block_dl_first_fn(lchan, bi->fn, false), - .toa256 = 0, - .rssi = -110, - }; - - /* No bursts => no errors */ - n_errors = 0; } - /* BFI is not applicable in signalling mode */ - if (lchan->tch_mode == GSM48_CMODE_SIGN) { - return l1sched_lchan_emit_data_ind(lchan, NULL, 0, - n_errors, n_bits_total, false); - } - - /* Bad frame indication */ - tch_data_len = l1sched_bad_frame_ind(&tch_data[0], lchan); + /* Calculate AVG of the measurements (traffic takes 4 bursts) */ + l1sched_lchan_meas_avg(lchan, 4); - /* Send a BFI frame to the higher layers */ + /* Send a traffic frame to the higher layers */ return l1sched_lchan_emit_data_ind(lchan, &tch_data[0], tch_data_len, n_errors, n_bits_total, true); } @@ -473,7 +383,8 @@ int tx_tchh_fn(struct l1sched_lchan_state *lchan, lchan->prim = prim_dequeue_tchh(lchan, br->fn); if (lchan->prim == NULL) { - lchan->prim = l1sched_lchan_prim_dummy(lchan); + if (l1sched_tchh_facch_start(lchan->type, br->fn, 1)) + lchan->prim = l1sched_lchan_prim_dummy_lapdm(lchan); if (lchan->prim == NULL) return -ENOENT; } diff --git a/src/host/trxcon/src/sched_lchan_xcch.c b/src/host/trxcon/src/sched_lchan_xcch.c index 7f1dd11a..e2638362 100644 --- a/src/host/trxcon/src/sched_lchan_xcch.c +++ b/src/host/trxcon/src/sched_lchan_xcch.c @@ -141,7 +141,7 @@ int tx_data_fn(struct l1sched_lchan_state *lchan, lchan->prim = prim_dequeue_xcch(lchan); if (lchan->prim == NULL) - lchan->prim = l1sched_lchan_prim_dummy(lchan); + lchan->prim = l1sched_lchan_prim_dummy_lapdm(lchan); OSMO_ASSERT(lchan->prim != NULL); /* Encode payload */ diff --git a/src/host/trxcon/src/sched_prim.c b/src/host/trxcon/src/sched_prim.c index 3301df4d..46756750 100644 --- a/src/host/trxcon/src/sched_prim.c +++ b/src/host/trxcon/src/sched_prim.c @@ -260,81 +260,50 @@ void l1sched_lchan_prim_drop(struct l1sched_lchan_state *lchan) } /** - * Allocate a dummy DATA.req for the given logical channel. + * Allocate a DATA.req with dummy LAPDm func=UI frame for the given logical channel. * To be used when no suitable DATA.req is present in the Tx queue. * * @param lchan lchan to allocate a dummy primitive for * @return an msgb with DATA.req primitive, or NULL */ -struct msgb *l1sched_lchan_prim_dummy(struct l1sched_lchan_state *lchan) +struct msgb *l1sched_lchan_prim_dummy_lapdm(const struct l1sched_lchan_state *lchan) { - const struct l1sched_lchan_desc *lchan_desc; - enum l1sched_lchan_type chan = lchan->type; - uint8_t tch_mode = lchan->tch_mode; struct l1sched_prim *prim; struct msgb *msg; - uint8_t prim_buffer[40]; - size_t prim_len = 0; - int i; + uint8_t *ptr; - /** - * TS 144.006, section 8.4.2.3 "Fill frames" - * A fill frame is a UI command frame for SAPI 0, P=0 - * and with an information field of 0 octet length. - */ - static const uint8_t lapdm_fill_frame[] = { - 0x01, 0x03, 0x01, 0x2b, - /* Pending part is to be randomized */ - }; - - /* Not applicable for SACCH! */ + /* LAPDm func=UI is not applicable for SACCH */ OSMO_ASSERT(!L1SCHED_CHAN_IS_SACCH(lchan->type)); - lchan_desc = &l1sched_lchan_desc[lchan->type]; - - /** - * Determine what actually should be generated: - * TCH in GSM48_CMODE_SIGN: LAPDm fill frame; - * TCH in other modes: silence frame; - * other channels: LAPDm fill frame. - */ - if (L1SCHED_CHAN_IS_TCH(chan) && L1SCHED_TCH_MODE_IS_SPEECH(tch_mode)) { - /* Bad frame indication */ - prim_len = l1sched_bad_frame_ind(prim_buffer, lchan); - } else if (L1SCHED_CHAN_IS_TCH(chan) && L1SCHED_TCH_MODE_IS_DATA(tch_mode)) { - /* FIXME: should we do anything for CSD? */ - return NULL; - } else { - /* Copy LAPDm fill frame's header */ - memcpy(prim_buffer, lapdm_fill_frame, sizeof(lapdm_fill_frame)); - - /** - * TS 144.006, section 5.2 "Frame delimitation and fill bits" - * Except for the first octet containing fill bits which shall - * be set to the binary value "00101011", each fill bit should - * be set to a random value when sent by the network. - */ - for (i = sizeof(lapdm_fill_frame); i < GSM_MACBLOCK_LEN; i++) - prim_buffer[i] = (uint8_t) rand(); - - /* Define a prim length */ - prim_len = GSM_MACBLOCK_LEN; - } - - /* Nothing to allocate / assign */ - if (!prim_len) - return NULL; - msg = l1sched_prim_alloc(L1SCHED_PRIM_T_DATA, PRIM_OP_REQUEST); OSMO_ASSERT(msg != NULL); prim = l1sched_prim_from_msgb(msg); prim->data_req = (struct l1sched_prim_chdr) { - .chan_nr = lchan_desc->chan_nr | lchan->ts->index, - .link_id = lchan_desc->link_id, + .chan_nr = l1sched_lchan_desc[lchan->type].chan_nr | lchan->ts->index, + .link_id = l1sched_lchan_desc[lchan->type].link_id, }; - memcpy(msgb_put(msg, prim_len), &prim_buffer[0], prim_len); + ptr = msgb_put(msg, GSM_MACBLOCK_LEN); + + /** + * TS 144.006, section 8.4.2.3 "Fill frames" + * A fill frame is a UI command frame for SAPI 0, P=0 + * and with an information field of 0 octet length. + */ + *(ptr++) = 0x01; + *(ptr++) = 0x03; + *(ptr++) = 0x01; + + /** + * TS 144.006, section 5.2 "Frame delimitation and fill bits" + * Except for the first octet containing fill bits which shall + * be set to the binary value "00101011", each fill bit should + * be set to a random value when sent by the network. + */ + *(ptr++) = 0x2b; + while (ptr < msg->tail) + *(ptr++) = (uint8_t)rand(); return msg; } |