aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVadim Yanitskiy <axilirator@gmail.com>2019-06-25 18:23:14 +0700
committerVadim Yanitskiy <axilirator@gmail.com>2019-06-27 12:51:02 +0700
commitb06cd9f439200869c96ed5d82113c3eba0453229 (patch)
tree4c25c2cd29ae55e0d64b17f19398b8d390314d5e
parentd1e7d0dafa93220ffb657661b3a1c9bc2b7a700a (diff)
osmo-bts-trx/trx_if.c: introduce TRXD header version handling
It may be necessary to extend the message specific header with more information. Since this is not a TLV-based protocol, we need to include the header format version. +-----------------+---------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------+ | X X X X . . . . | header version (0..15) | +-----------------+---------------------------+ | . . . . . X X X | TDMA TN (0..7) | +-----------------+---------------------------+ | . . . . X . . . | RESERVED (0) | +-----------------+---------------------------+ Instead of prepending an additional byte, it was decided to use 4 MSB bits of the first octet, which used to be zero-initialized due to the value range of TDMA TN (0..7). Therefore the current header format has implicit version 0. Otherwise Wireshark (or trx_sniff.py) would have to guess the header version, or alternatively follow the control channel looking for the version setting command. This change introduces a new structure 'trx_ul_burst_ind', which represents an Uplink burst and the corresponding meta info. The purpose of this structure is to avoid overloading the existing functions, such as trx_sched_ul_burst(), with more and more arguments every time we bump the version. On receipt of a TRXD message, trx_data_read_cb() now parses the header version, and calls the corresponding dissector functions, e.g. trx_data_handle_(hdr|burst)_v0(). Change-Id: I171c18229ca3e5cab70de0064a31e47c78602c0c Related: OS#4006
-rw-r--r--include/osmo-bts/scheduler.h20
-rw-r--r--src/common/scheduler.c26
-rw-r--r--src/osmo-bts-trx/trx_if.c210
3 files changed, 199 insertions, 57 deletions
diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h
index c8623079..9748d45c 100644
--- a/include/osmo-bts/scheduler.h
+++ b/include/osmo-bts/scheduler.h
@@ -173,10 +173,6 @@ int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap);
/*! \brief PHY informs us of new (current) GSM frame number */
int trx_sched_clock(struct gsm_bts *bts, uint32_t fn);
-/*! \brief handle an UL burst received by PHY */
-int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- sbit_t *bits, uint16_t nbits, int8_t rssi, int16_t toa);
-
/*! \brief set multiframe scheduler to given physical channel config */
int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn,
enum gsm_phys_chan_config pchan);
@@ -231,4 +227,20 @@ int find_sched_mframe_idx(enum gsm_phys_chan_config pchan, uint8_t tn);
bool trx_sched_is_sacch_fn(struct gsm_bts_trx_ts *ts, uint32_t fn, bool uplink);
extern const struct trx_sched_multiframe trx_sched_multiframes[];
+/*! UL burst indication with the corresponding meta info */
+struct trx_ul_burst_ind {
+ /* Mandatory fields */
+ uint32_t fn; /*!< TDMA frame number */
+ uint8_t tn; /*!< TDMA time-slot number */
+ int16_t toa256; /*!< Timing of Arrival in units of 1/256 of symbol */
+ int8_t rssi; /*!< Received Signal Strength Indication */
+
+ /*! Burst soft-bits buffer */
+ sbit_t burst[EGPRS_BURST_LEN];
+ size_t burst_len;
+};
+
+/*! Handle an UL burst received by PHY */
+int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi);
+
#endif /* TRX_SCHEDULER_H */
diff --git a/src/common/scheduler.c b/src/common/scheduler.c
index 3f804a90..83779d79 100644
--- a/src/common/scheduler.c
+++ b/src/common/scheduler.c
@@ -1313,11 +1313,10 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
return 0;
}
-/* process uplink burst */
-int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- sbit_t *bits, uint16_t nbits, int8_t rssi, int16_t toa256)
+/* Process an Uplink burst indication */
+int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi)
{
- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
struct l1sched_chan_state *l1cs;
const struct trx_sched_frame *frame;
uint8_t offset, period, bid;
@@ -1329,7 +1328,7 @@ int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
/* get frame from multiframe */
period = l1ts->mf_period;
- offset = fn % period;
+ offset = bi->fn % period;
frame = l1ts->mf_frames + offset;
chan = frame->ul_chan;
@@ -1346,28 +1345,29 @@ int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
return -EINVAL;
/* calculate how many TDMA frames were potentially lost */
- trx_sched_calc_frame_loss(l1t, l1cs, tn, fn);
+ trx_sched_calc_frame_loss(l1t, l1cs, bi->tn, bi->fn);
/* update TDMA frame counters */
- l1cs->last_tdma_fn = fn;
+ l1cs->last_tdma_fn = bi->fn;
l1cs->proc_tdma_fs++;
/* decrypt */
- if (bits && l1cs->ul_encr_algo) {
+ if (bi->burst_len && l1cs->ul_encr_algo) {
ubit_t ks[114];
int i;
- osmo_a5(l1cs->ul_encr_algo, l1cs->ul_encr_key, fn, NULL, ks);
+ osmo_a5(l1cs->ul_encr_algo, l1cs->ul_encr_key, bi->fn, NULL, ks);
for (i = 0; i < 57; i++) {
if (ks[i])
- bits[i + 3] = - bits[i + 3];
+ bi->burst[i + 3] = - bi->burst[i + 3];
if (ks[i + 57])
- bits[i + 88] = - bits[i + 88];
+ bi->burst[i + 88] = - bi->burst[i + 88];
}
}
- /* put burst to function */
- func(l1t, tn, fn, chan, bid, bits, nbits, rssi, toa256);
+ /* put burst to function
+ * TODO: rather pass a pointer to trx_ul_burst_ind */
+ func(l1t, bi->tn, bi->fn, chan, bid, bi->burst, bi->burst_len, bi->rssi, bi->toa256);
return 0;
}
diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c
index 9b1604c2..a164f173 100644
--- a/src/osmo-bts-trx/trx_if.c
+++ b/src/osmo-bts-trx/trx_if.c
@@ -7,6 +7,7 @@
*
* Copyright (C) 2013 Andreas Eversberg <jolly@eversberg.eu>
* Copyright (C) 2016-2017 Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2019 Vadim Yanitskiy <axilirator@gmail.com>
*
* All Rights Reserved
*
@@ -588,65 +589,194 @@ rsp_error:
/* Maximum DATA message length (header + burst) */
#define TRX_DATA_MSG_MAX_LEN 512
-static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
+/* Common header length: 1/2 VER + 1/2 TDMA TN + 4 TDMA FN */
+#define TRX_CHDR_LEN (1 + 4)
+/* Uplink v0 header length: 1 RSSI + 2 ToA256 */
+#define TRX_UL_V0HDR_LEN (TRX_CHDR_LEN + 1 + 2)
+
+/* TRXD header dissector for version 0 */
+static int trx_data_handle_hdr_v0(struct trx_l1h *l1h,
+ struct trx_ul_burst_ind *bi,
+ const uint8_t *buf, size_t buf_len)
+{
+ /* Make sure we have enough data */
+ if (buf_len < TRX_UL_V0HDR_LEN) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "Short read on TRXD, missing version 0 header "
+ "(len=%zu vs expected %d)\n", buf_len, TRX_UL_V0HDR_LEN);
+ return -EIO;
+ }
+
+ bi->tn = buf[0] & 0b111;
+ bi->fn = osmo_load32be(buf + 1);
+ bi->rssi = -(int8_t)buf[5];
+ bi->toa256 = (int16_t) osmo_load16be(buf + 6);
+
+ if (bi->fn >= GSM_HYPERFRAME) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "Illegal TDMA fn=%u\n", bi->fn);
+ return -EINVAL;
+ }
+
+ return TRX_UL_V0HDR_LEN;
+}
+
+/* TRXD burst handler for header version 0 */
+static int trx_data_handle_burst_v0(struct trx_l1h *l1h,
+ struct trx_ul_burst_ind *bi,
+ const uint8_t *buf, size_t buf_len)
{
- struct trx_l1h *l1h = ofd->data;
- uint8_t buf[TRX_DATA_MSG_MAX_LEN];
- int len;
- uint8_t tn;
- int8_t rssi;
- int16_t toa256 = 0;
- uint32_t fn;
- sbit_t bits[EGPRS_BURST_LEN];
- int i, burst_len = GSM_BURST_LEN;
+ size_t i;
- len = recv(ofd->fd, buf, sizeof(buf), 0);
- if (len <= 0) {
- return len;
- } else if (len == EGPRS_BURST_LEN + 10) {
- burst_len = EGPRS_BURST_LEN;
- /* Accept bursts ending with 2 bytes of padding (OpenBTS compatible trx) or without them: */
- } else if (len != GSM_BURST_LEN + 10 && len != GSM_BURST_LEN + 8) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE, "Got data message with invalid lenght "
- "'%d'\n", len);
+ /* Verify burst length */
+ switch (buf_len) {
+ /* Legacy transceivers append two padding bytes */
+ case EGPRS_BURST_LEN + 2:
+ case GSM_BURST_LEN + 2:
+ bi->burst_len = buf_len - 2;
+ break;
+ case EGPRS_BURST_LEN:
+ case GSM_BURST_LEN:
+ bi->burst_len = buf_len;
+ break;
+
+ default:
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
+ "Rx TRXD message with odd burst length %zu\n", buf_len);
return -EINVAL;
}
- tn = buf[0];
- fn = osmo_load32be(buf + 1);
- rssi = -(int8_t)buf[5];
- toa256 = (int16_t) osmo_load16be(buf + 6);
-
- /* copy and convert bits {254..0} to sbits {-127..127} */
- for (i = 0; i < burst_len; i++) {
- if (buf[8 + i] == 255)
- bits[i] = -127;
+
+ /* Convert unsigned soft-bits [254..0] to soft-bits [-127..127] */
+ for (i = 0; i < bi->burst_len; i++) {
+ if (buf[i] == 255)
+ bi->burst[i] = -127;
else
- bits[i] = 127 - buf[8 + i];
+ bi->burst[i] = 127 - buf[i];
}
- if (tn >= 8) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR, "Illegal TS %d\n", tn);
- return -EINVAL;
+ return 0;
+}
+
+/* Parse TRXD message from transceiver, compose an UL burst indication.
+ *
+ * This message contains a demodulated Uplink burst with fixed-size
+ * header preceding the burst bits. The header consists of the common
+ * and message specific part.
+ *
+ * +---------------+-----------------+------------+
+ * | common header | specific header | burst bits |
+ * +---------------+-----------------+------------+
+ *
+ * Common header is the same as for Downlink message:
+ *
+ * +-----------------+----------------+-------------------+
+ * | VER (1/2 octet) | TN (1/2 octet) | FN (4 octets, BE) |
+ * +-----------------+----------------+-------------------+
+ *
+ * and among with TDMA parameters, contains the version indicator:
+ *
+ * +-----------------+------------------------+
+ * | 7 6 5 4 3 2 1 0 | bit numbers |
+ * +-----------------+------------------------+
+ * | X X X X . . . . | header version (0..15) |
+ * +-----------------+------------------------+
+ * | . . . . . X X X | TDMA TN (0..7) |
+ * +-----------------+------------------------+
+ * | . . . . X . . . | RESERVED (0) |
+ * +-----------------+------------------------+
+ *
+ * which is encoded in 4 MSB bits of the first octet, which used to be
+ * zero-initialized due to the value range of TDMA TN. Therefore, the
+ * old header format has implicit version 0x00.
+ *
+ * The message specific header has the following structure:
+ *
+ * == Version 0x00
+ *
+ * +------+-----+--------------------+
+ * | RSSI | ToA | soft-bits (254..0) |
+ * +------+-----+--------------------+
+ *
+ * where:
+ *
+ * - RSSI (1 octet) - Received Signal Strength Indication
+ * encoded without the negative sign.
+ * - ToA (2 octets) - Timing of Arrival in units of 1/256
+ * of symbol (big endian).
+ *
+ * == Coding of the burst bits
+ *
+ * Unlike to be transmitted bursts, the received bursts are designated
+ * using the soft-bits notation, so the receiver can indicate its
+ * assurance from 0 to -127 that a given bit is 1, and from 0 to +127
+ * that a given bit is 0.
+ *
+ * Each soft-bit (-127..127) of the burst is encoded as an unsigned
+ * value in range (254..0) respectively using the constant shift.
+ *
+ */
+static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
+{
+ struct trx_l1h *l1h = ofd->data;
+ uint8_t buf[TRX_DATA_MSG_MAX_LEN];
+ struct trx_ul_burst_ind bi;
+ ssize_t hdr_len, buf_len;
+ uint8_t hdr_ver;
+ int rc;
+
+ buf_len = recv(ofd->fd, buf, sizeof(buf), 0);
+ if (buf_len <= 0) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "recv() failed on TRXD with rc=%zd\n", buf_len);
+ return buf_len;
}
- if (fn >= GSM_HYPERFRAME) {
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR, "Illegal FN %u\n", fn);
- return -EINVAL;
+
+ /* Parse the header depending on its version */
+ hdr_ver = buf[0] >> 4;
+ switch (hdr_ver) {
+ case 0:
+ /* Legacy protocol has no version indicator */
+ hdr_len = trx_data_handle_hdr_v0(l1h, &bi, buf, buf_len);
+ break;
+ default:
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "TRXD header version %u is not supported\n", hdr_ver);
+ return -ENOTSUP;
}
- LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG, "RX burst tn=%u fn=%u rssi=%d toa256=%d\n",
- tn, fn, rssi, toa256);
+ /* Header parsing error */
+ if (hdr_len < 0)
+ return hdr_len;
+
+ /* We're done with the header now */
+ buf_len -= hdr_len;
+
+ switch (hdr_ver) {
+ case 0:
+ rc = trx_data_handle_burst_v0(l1h, &bi, buf + hdr_len, buf_len);
+ break;
+ }
+
+ /* Burst parsing error */
+ if (rc < 0)
+ return rc;
+
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
+ "Rx UL burst (hdr_ver=%u) tn=%u fn=%u rssi=%d toa256=%d\n",
+ hdr_ver, bi.tn, bi.fn, bi.rssi, bi.toa256);
#ifdef TOA_RSSI_DEBUG
char deb[128];
sprintf(deb, "| 0 "
- " | rssi=%4d toa=%5d fn=%u", rssi, toa256, fn);
- deb[1 + (128 + rssi) / 4] = '*';
+ " | rssi=%4d toa=%5d fn=%u",
+ bi.rssi, bi.toa256, bi.fn);
+ deb[1 + (128 + bi.rssi) / 4] = '*';
fprintf(stderr, "%s\n", deb);
#endif
/* feed received burst into scheduler code */
- trx_sched_ul_burst(&l1h->l1s, tn, fn, bits, burst_len, rssi, toa256);
+ trx_sched_ul_burst(&l1h->l1s, &bi);
return 0;
}