osmo-bts/src/osmo-bts-trx/trx_if.c

1384 lines
38 KiB
C
Raw Normal View History

/*
* OpenBTS-style TRX interface/protocol handling
*
* This file contains the BTS-side implementation of the OpenBTS-style
* UDP TRX protocol. It manages the clock, control + burst-data UDP
* sockets and their respective protocol encoding/parsing.
*
* Copyright (C) 2013 Andreas Eversberg <jolly@eversberg.eu>
* Copyright (C) 2016-2017 Harald Welte <laforge@gnumonks.org>
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
2019-06-25 11:23:14 +00:00
* Copyright (C) 2019 Vadim Yanitskiy <axilirator@gmail.com>
* Copyright (C) 2021 sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/fsm.h>
#include <osmo-bts/phy_link.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/scheduler.h>
#include "l1_if.h"
#include "trx_if.h"
#include "trx_provision_fsm.h"
#include "btsconfig.h"
#ifdef HAVE_SYSTEMTAP
/* include the generated probes header and put markers in code */
#include "probes.h"
#define TRACE(probe) probe
#define TRACE_ENABLED(probe) probe ## _ENABLED()
#else
/* Wrap the probe to allow it to be removed when no systemtap available */
#define TRACE(probe)
#define TRACE_ENABLED(probe) (0)
#endif /* HAVE_SYSTEMTAP */
/*
* socket helper functions
*/
/*! convenience wrapper to open socket + fill in osmo_fd */
static int trx_udp_open(void *priv, struct osmo_fd *ofd, const char *host_local,
uint16_t port_local, const char *host_remote, uint16_t port_remote,
int (*cb)(struct osmo_fd *fd, unsigned int what))
{
int rc;
/* Init */
ofd->fd = -1;
ofd->cb = cb;
ofd->data = priv;
/* Listen / Binds + Connect */
rc = osmo_sock_init2_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, host_local, port_local,
host_remote, port_remote, OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
if (rc < 0)
return rc;
return 0;
}
/* close socket + unregister osmo_fd */
static void trx_udp_close(struct osmo_fd *ofd)
{
if (ofd->fd >= 0) {
osmo_fd_unregister(ofd);
close(ofd->fd);
ofd->fd = -1;
}
}
/*
* TRX clock socket
*/
/* get clock from clock socket */
static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what)
{
struct phy_link *plink = ofd->data;
struct phy_instance *pinst = phy_instance_by_num(plink, 0);
char buf[TRXC_MSG_BUF_SIZE];
ssize_t len;
uint32_t fn;
OSMO_ASSERT(pinst);
len = recv(ofd->fd, buf, sizeof(buf) - 1, 0);
if (len <= 0) {
strerror_r(errno, (char *)buf, sizeof(buf));
LOGPPHI(pinst, DTRX, LOGL_ERROR,
"recv() failed on TRXD with rc=%zd (%s)\n", len, buf);
return len;
}
buf[len] = '\0';
if (!!strncmp(buf, "IND CLOCK ", 10)) {
LOGPPHI(pinst, DTRX, LOGL_NOTICE,
"Unknown message on clock port: %s\n", buf);
return 0;
}
if (sscanf(buf, "IND CLOCK %u", &fn) != 1) {
LOGPPHI(pinst, DTRX, LOGL_ERROR, "Unable to parse '%s'\n", buf);
return 0;
}
LOGPPHI(pinst, DTRX, LOGL_INFO, "Clock indication: fn=%u\n", fn);
if (fn >= GSM_TDMA_HYPERFRAME) {
fn %= GSM_TDMA_HYPERFRAME;
LOGPPHI(pinst, DTRX, LOGL_ERROR, "Indicated clock's FN is not "
"wrapping correctly, correcting to fn=%u\n", fn);
}
bts-trx: Get rid of messy transceiver_available state handler This variable meaning has been changing its exact meaning over time until finally not being really clear which kind of state it holds. Initially it seemed to be used to identfy whether CLOCK IND were being received. However, over time both osmo-bts and osmo-trx have evolved and were fixed so that clock indications are only sent by osmo-trx after POWERON command is sent. As a result, this state can be checked simply by looking at the "powered" phy_link variable, which is only set to true once the TRX has confirmed the POWERON command, and hence it is sending CLOCK IND. On the other hand, at some point in time "available" started to be set to 1 in bts_model_phy_link_open(), which means available is nowadays almost always 1 from startup until the end (only dropped during bts_shutdown(), when we are already exiting the process anyway). As a result, !available condition in scheduler_trx.c:trx_fn_timer_cb can almost never happen, because available is set to true already. Only possibility would be if an old process of osmo-trx (not set up by this BTS process) is still sending CLOCK INDs, but in that case we for sure don't want to configure the BTS based on that, but ignore them until this BTS process has again configured the TRX. So that whole check can be dropped. We are better checking for "powered" state, which is far more accurate, and we better do that in trx_if.c before calling trx_fn_timer_cb(). Other uses of "transceiver_available" being used can be changed to use plink->state!= PHY_LINK_SHUTDOWN, since available was already being set to 1 at the same time the plink->state was being set to PHY_LINK_CONNECTING. As a result of this state handling re-arrangement, OS#4215 is fixed since trx_if_powered() is used instead of previous state condition to check whether data frames should be sent. Related: OS#4215 Change-Id: I35f4697bd33dbe8a4c76c9500b82c16589c701d4
2019-09-27 15:21:31 +00:00
if (!plink->u.osmotrx.powered) {
LOGPPHI(pinst, DTRX, LOGL_NOTICE, "Ignoring CLOCK IND %u, TRX not yet powered on\n", fn);
return 0;
}
/* inform core TRX clock handling code that a FN has been received */
trx_sched_clock(pinst->trx->bts, fn);
return 0;
}
/*
* TRX ctrl socket
*/
/* send first ctrl message and start timer */
static void trx_ctrl_send(struct trx_l1h *l1h)
{
struct trx_ctrl_msg *tcm;
char buf[TRXC_MSG_BUF_SIZE];
int len;
ssize_t snd_len;
/* get first command */
if (llist_empty(&l1h->trx_ctrl_list))
return;
tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg, list);
len = snprintf(buf, sizeof(buf), "CMD %s%s%s", tcm->cmd, tcm->params_len ? " ":"", tcm->params);
OSMO_ASSERT(len < sizeof(buf));
LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG, "Sending control '%s'\n", buf);
/* send command */
snd_len = send(l1h->trx_ofd_ctrl.fd, buf, len+1, 0);
if (snd_len <= 0) {
strerror_r(errno, (char *)buf, sizeof(buf));
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"send() failed on TRXC with rc=%zd (%s)\n", snd_len, buf);
}
/* start timer */
osmo_timer_schedule(&l1h->trx_ctrl_timer, 2, 0);
}
/* send first ctrl message and start timer */
static void trx_ctrl_timer_cb(void *data)
{
struct trx_l1h *l1h = data;
struct trx_ctrl_msg *tcm = NULL;
/* get first command */
OSMO_ASSERT(!llist_empty(&l1h->trx_ctrl_list));
tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg, list);
LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE, "No satisfactory response from transceiver(CMD %s%s%s)\n",
tcm->cmd, tcm->params_len ? " ":"", tcm->params);
trx_ctrl_send(l1h);
}
void trx_if_init(struct trx_l1h *l1h)
{
l1h->trx_ctrl_timer.cb = trx_ctrl_timer_cb;
l1h->trx_ctrl_timer.data = l1h;
/* initialize ctrl queue */
INIT_LLIST_HEAD(&l1h->trx_ctrl_list);
l1h->trx_ofd_ctrl.fd = -1;
l1h->trx_ofd_data.fd = -1;
}
/*! Send a new TRX control command.
* \param[inout] l1h TRX Layer1 handle to which to send command
* \param[in] critical
bts-trx: (n)ack PDCH DEACT only after TRX answered SETSLOT Before this patch, PDCH DEACT was (n)acked to the BSC without taking into account if TRX succeeded or failed to set the TS: 20181123044720655 DRLL rsl.c:2523 (bts=0,trx=0,ts=0,ss=0) Rx RLL DATA_REQ Abis -> LAPDm 20181123044720700 DRSL rsl.c:2805 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) ss=0 Rx RSL IPAC_PDCH_DEACT 20181123044720700 DRSL rsl.c:2205 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) Request to PDCH DEACT, but lchan is still active 20181123044720700 DRSL rsl.c:2131 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT NACK (cause = 0x0f) 20181123044720700 DPCU pcu_sock.c:124 Sending info 20181123044720700 DPCU pcu_sock.c:139 BTS is up 20181123044720700 DPCU pcu_sock.c:232 trx=0 ts=7: available (tsc=7 arfcn=868) 20181123044720703 DPCU pcu_sock.c:608 Deactivate request received: TRX=0 TX=6 20181123044720703 DL1C l1sap.c:1519 deactivating channel chan_nr=TCH/F on TS6 trx=0 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD NOHANDOVER 6 0' 20181123044720703 DL1C l1sap.c:648 deactivate confirm chan_nr=TCH/F on TS6 trx=0 20181123044720703 DRSL rsl.c:714 (bts=0,trx=0,ts=6,ss=0) not sending REL ACK 20181123044720703 DRSL rsl.c:2264 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: channel disconnected, will reconnect as TCH 20181123044720703 DL1C scheduler.c:593 Configuring multiframe with TCH/F+SACCH trx=0 ts=6 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD SETSLOT 6 1' 20181123044720703 DL1C l1_if.c:780 (bts=0,trx=0,ts=6) bts_model_ts_connect(as_pchan=TCH/F) success, calling cb_ts_connected() 20181123044720703 DRSL rsl.c:2339 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: timeslot connected as TCH/F 20181123044720703 DRSL rsl.c:2440 (bts=0,trx=0,ts=6,ss=0) TCH/F_PDCH switched to TCH/F mode (ts->flags == 0) 20181123044720703 DRSL rsl.c:2103 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT ACK 20181123044720704 DTRX trx_if.c:492 Response message: 'RSP NOHANDOVER 0 6' 20181123044720705 DTRX trx_if.c:492 Response message: 'RSP SETSLOT 0 6 1' Change-Id: I888de761b65c3ea8bfe623fcf009f3b2b57c926c
2018-11-26 12:59:52 +00:00
* \param[in] cb callback function to be called when valid response is
* received. Type of cb depends on type of message.
* \param[in] cmd zero-terminated string containing command
* \param[in] fmt Format string (+ variable list of arguments)
* \returns 0 on success; negative on error
*
* The new command will be added to the end of the control command
* queue.
*/
bts-trx: (n)ack PDCH DEACT only after TRX answered SETSLOT Before this patch, PDCH DEACT was (n)acked to the BSC without taking into account if TRX succeeded or failed to set the TS: 20181123044720655 DRLL rsl.c:2523 (bts=0,trx=0,ts=0,ss=0) Rx RLL DATA_REQ Abis -> LAPDm 20181123044720700 DRSL rsl.c:2805 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) ss=0 Rx RSL IPAC_PDCH_DEACT 20181123044720700 DRSL rsl.c:2205 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) Request to PDCH DEACT, but lchan is still active 20181123044720700 DRSL rsl.c:2131 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT NACK (cause = 0x0f) 20181123044720700 DPCU pcu_sock.c:124 Sending info 20181123044720700 DPCU pcu_sock.c:139 BTS is up 20181123044720700 DPCU pcu_sock.c:232 trx=0 ts=7: available (tsc=7 arfcn=868) 20181123044720703 DPCU pcu_sock.c:608 Deactivate request received: TRX=0 TX=6 20181123044720703 DL1C l1sap.c:1519 deactivating channel chan_nr=TCH/F on TS6 trx=0 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD NOHANDOVER 6 0' 20181123044720703 DL1C l1sap.c:648 deactivate confirm chan_nr=TCH/F on TS6 trx=0 20181123044720703 DRSL rsl.c:714 (bts=0,trx=0,ts=6,ss=0) not sending REL ACK 20181123044720703 DRSL rsl.c:2264 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: channel disconnected, will reconnect as TCH 20181123044720703 DL1C scheduler.c:593 Configuring multiframe with TCH/F+SACCH trx=0 ts=6 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD SETSLOT 6 1' 20181123044720703 DL1C l1_if.c:780 (bts=0,trx=0,ts=6) bts_model_ts_connect(as_pchan=TCH/F) success, calling cb_ts_connected() 20181123044720703 DRSL rsl.c:2339 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: timeslot connected as TCH/F 20181123044720703 DRSL rsl.c:2440 (bts=0,trx=0,ts=6,ss=0) TCH/F_PDCH switched to TCH/F mode (ts->flags == 0) 20181123044720703 DRSL rsl.c:2103 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT ACK 20181123044720704 DTRX trx_if.c:492 Response message: 'RSP NOHANDOVER 0 6' 20181123044720705 DTRX trx_if.c:492 Response message: 'RSP SETSLOT 0 6 1' Change-Id: I888de761b65c3ea8bfe623fcf009f3b2b57c926c
2018-11-26 12:59:52 +00:00
static int trx_ctrl_cmd_cb(struct trx_l1h *l1h, int critical, void *cb, const char *cmd,
const char *fmt, ...)
{
struct trx_ctrl_msg *tcm;
struct trx_ctrl_msg *prev = NULL;
va_list ap;
/* create message */
tcm = talloc_zero(tall_bts_ctx, struct trx_ctrl_msg);
if (!tcm)
return -ENOMEM;
snprintf(tcm->cmd, sizeof(tcm->cmd)-1, "%s", cmd);
tcm->cmd[sizeof(tcm->cmd)-1] = '\0';
tcm->cmd_len = strlen(tcm->cmd);
if (fmt && fmt[0]) {
va_start(ap, fmt);
vsnprintf(tcm->params, sizeof(tcm->params) - 1, fmt, ap);
va_end(ap);
tcm->params[sizeof(tcm->params)-1] = '\0';
tcm->params_len = strlen(tcm->params);
} else {
tcm->params[0] ='\0';
tcm->params_len = 0;
}
tcm->critical = critical;
bts-trx: (n)ack PDCH DEACT only after TRX answered SETSLOT Before this patch, PDCH DEACT was (n)acked to the BSC without taking into account if TRX succeeded or failed to set the TS: 20181123044720655 DRLL rsl.c:2523 (bts=0,trx=0,ts=0,ss=0) Rx RLL DATA_REQ Abis -> LAPDm 20181123044720700 DRSL rsl.c:2805 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) ss=0 Rx RSL IPAC_PDCH_DEACT 20181123044720700 DRSL rsl.c:2205 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) Request to PDCH DEACT, but lchan is still active 20181123044720700 DRSL rsl.c:2131 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT NACK (cause = 0x0f) 20181123044720700 DPCU pcu_sock.c:124 Sending info 20181123044720700 DPCU pcu_sock.c:139 BTS is up 20181123044720700 DPCU pcu_sock.c:232 trx=0 ts=7: available (tsc=7 arfcn=868) 20181123044720703 DPCU pcu_sock.c:608 Deactivate request received: TRX=0 TX=6 20181123044720703 DL1C l1sap.c:1519 deactivating channel chan_nr=TCH/F on TS6 trx=0 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD NOHANDOVER 6 0' 20181123044720703 DL1C l1sap.c:648 deactivate confirm chan_nr=TCH/F on TS6 trx=0 20181123044720703 DRSL rsl.c:714 (bts=0,trx=0,ts=6,ss=0) not sending REL ACK 20181123044720703 DRSL rsl.c:2264 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: channel disconnected, will reconnect as TCH 20181123044720703 DL1C scheduler.c:593 Configuring multiframe with TCH/F+SACCH trx=0 ts=6 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD SETSLOT 6 1' 20181123044720703 DL1C l1_if.c:780 (bts=0,trx=0,ts=6) bts_model_ts_connect(as_pchan=TCH/F) success, calling cb_ts_connected() 20181123044720703 DRSL rsl.c:2339 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: timeslot connected as TCH/F 20181123044720703 DRSL rsl.c:2440 (bts=0,trx=0,ts=6,ss=0) TCH/F_PDCH switched to TCH/F mode (ts->flags == 0) 20181123044720703 DRSL rsl.c:2103 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT ACK 20181123044720704 DTRX trx_if.c:492 Response message: 'RSP NOHANDOVER 0 6' 20181123044720705 DTRX trx_if.c:492 Response message: 'RSP SETSLOT 0 6 1' Change-Id: I888de761b65c3ea8bfe623fcf009f3b2b57c926c
2018-11-26 12:59:52 +00:00
tcm->cb = cb;
/* Avoid adding consecutive duplicate messages, eg: two consecutive POWEROFF */
if (!llist_empty(&l1h->trx_ctrl_list))
prev = llist_entry(l1h->trx_ctrl_list.prev, struct trx_ctrl_msg, list);
if (prev != NULL && !strcmp(tcm->cmd, prev->cmd)
&& !strcmp(tcm->params, prev->params)) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
"Not sending duplicate command '%s'\n", tcm->cmd);
talloc_free(tcm);
return 0;
}
LOGPPHI(l1h->phy_inst, DTRX, LOGL_INFO, "Enqueuing TRX control command 'CMD %s%s%s'\n",
tcm->cmd, tcm->params_len ? " " : "", tcm->params);
llist_add_tail(&tcm->list, &l1h->trx_ctrl_list);
/* send message, if we didn't already have pending messages */
if (prev == NULL)
trx_ctrl_send(l1h);
return 0;
}
bts-trx: (n)ack PDCH DEACT only after TRX answered SETSLOT Before this patch, PDCH DEACT was (n)acked to the BSC without taking into account if TRX succeeded or failed to set the TS: 20181123044720655 DRLL rsl.c:2523 (bts=0,trx=0,ts=0,ss=0) Rx RLL DATA_REQ Abis -> LAPDm 20181123044720700 DRSL rsl.c:2805 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) ss=0 Rx RSL IPAC_PDCH_DEACT 20181123044720700 DRSL rsl.c:2205 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) Request to PDCH DEACT, but lchan is still active 20181123044720700 DRSL rsl.c:2131 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT NACK (cause = 0x0f) 20181123044720700 DPCU pcu_sock.c:124 Sending info 20181123044720700 DPCU pcu_sock.c:139 BTS is up 20181123044720700 DPCU pcu_sock.c:232 trx=0 ts=7: available (tsc=7 arfcn=868) 20181123044720703 DPCU pcu_sock.c:608 Deactivate request received: TRX=0 TX=6 20181123044720703 DL1C l1sap.c:1519 deactivating channel chan_nr=TCH/F on TS6 trx=0 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD NOHANDOVER 6 0' 20181123044720703 DL1C l1sap.c:648 deactivate confirm chan_nr=TCH/F on TS6 trx=0 20181123044720703 DRSL rsl.c:714 (bts=0,trx=0,ts=6,ss=0) not sending REL ACK 20181123044720703 DRSL rsl.c:2264 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: channel disconnected, will reconnect as TCH 20181123044720703 DL1C scheduler.c:593 Configuring multiframe with TCH/F+SACCH trx=0 ts=6 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD SETSLOT 6 1' 20181123044720703 DL1C l1_if.c:780 (bts=0,trx=0,ts=6) bts_model_ts_connect(as_pchan=TCH/F) success, calling cb_ts_connected() 20181123044720703 DRSL rsl.c:2339 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: timeslot connected as TCH/F 20181123044720703 DRSL rsl.c:2440 (bts=0,trx=0,ts=6,ss=0) TCH/F_PDCH switched to TCH/F mode (ts->flags == 0) 20181123044720703 DRSL rsl.c:2103 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT ACK 20181123044720704 DTRX trx_if.c:492 Response message: 'RSP NOHANDOVER 0 6' 20181123044720705 DTRX trx_if.c:492 Response message: 'RSP SETSLOT 0 6 1' Change-Id: I888de761b65c3ea8bfe623fcf009f3b2b57c926c
2018-11-26 12:59:52 +00:00
#define trx_ctrl_cmd(l1h, critical, cmd, fmt, ...) trx_ctrl_cmd_cb(l1h, critical, NULL, cmd, fmt, ##__VA_ARGS__)
/*! Send "POWEROFF" command to TRX */
int trx_if_cmd_poweroff(struct trx_l1h *l1h, trx_if_cmd_poweronoff_cb *cb)
{
return trx_ctrl_cmd_cb(l1h, 1, cb, "POWEROFF", "");
}
/*! Send "POWERON" command to TRX */
int trx_if_cmd_poweron(struct trx_l1h *l1h, trx_if_cmd_poweronoff_cb *cb)
{
return trx_ctrl_cmd_cb(l1h, 1, cb, "POWERON", "");
}
/*! Send "SETFORMAT" command to TRX: change TRXD PDU version */
int trx_if_cmd_setformat(struct trx_l1h *l1h, uint8_t ver, trx_if_cmd_generic_cb *cb)
{
LOGPPHI(l1h->phy_inst, DTRX, LOGL_INFO,
"Requesting TRXD PDU version %u\n", ver);
return trx_ctrl_cmd_cb(l1h, 0, cb, "SETFORMAT", "%u", ver);
}
/*! Send "SETTSC" command to TRX */
int trx_if_cmd_settsc(struct trx_l1h *l1h, uint8_t tsc, trx_if_cmd_generic_cb *cb)
{
return trx_ctrl_cmd_cb(l1h, 1, cb, "SETTSC", "%d", tsc);
}
/*! Send "SETBSIC" command to TRX */
int trx_if_cmd_setbsic(struct trx_l1h *l1h, uint8_t bsic, trx_if_cmd_generic_cb *cb)
{
return trx_ctrl_cmd_cb(l1h, 1, cb, "SETBSIC", "%d", bsic);
}
/*! Send "SETRXGAIN" command to TRX */
int trx_if_cmd_setrxgain(struct trx_l1h *l1h, int db)
{
return trx_ctrl_cmd(l1h, 0, "SETRXGAIN", "%d", db);
}
/*! Send "NOMTXPOWER" command to TRX */
int trx_if_cmd_getnompower(struct trx_l1h *l1h, trx_if_cmd_getnompower_cb *cb)
{
return trx_ctrl_cmd_cb(l1h, 1, cb, "NOMTXPOWER", "");
}
/*! Send "SETPOWER" command to TRX */
int trx_if_cmd_setpower_att(struct trx_l1h *l1h, int power_att_db, trx_if_cmd_setpower_att_cb *cb)
{
return trx_ctrl_cmd_cb(l1h, 0, cb, "SETPOWER", "%d", power_att_db);
}
/*! Send "SETMAXDLY" command to TRX, i.e. maximum delay for RACH bursts */
int trx_if_cmd_setmaxdly(struct trx_l1h *l1h, int dly)
{
return trx_ctrl_cmd(l1h, 0, "SETMAXDLY", "%d", dly);
}
/*! Send "SETMAXDLYNB" command to TRX, i.e. maximum delay for normal bursts */
int trx_if_cmd_setmaxdlynb(struct trx_l1h *l1h, int dly)
{
return trx_ctrl_cmd(l1h, 0, "SETMAXDLYNB", "%d", dly);
}
/*! Send "SETSLOT" command to TRX: Configure Channel Combination and TSC for TS */
int trx_if_cmd_setslot(struct trx_l1h *l1h, uint8_t tn,
trx_if_cmd_setslot_cb *cb)
{
const struct trx_config *cfg = &l1h->config;
const struct phy_instance *pinst = l1h->phy_inst;
if (cfg->setslot[tn].tsc_valid && cfg->setslot[tn].tsc_val != BTS_TSC(pinst->trx->bts)) {
/* PHY is instructed to use a custom TSC */
return trx_ctrl_cmd_cb(l1h, 1, cb, "SETSLOT", "%u %u C%u/S%u",
tn, cfg->setslot[tn].slottype,
cfg->setslot[tn].tsc_val,
cfg->setslot[tn].tsc_set);
} else { /* PHY is instructed to use the default TSC from 'SETTSC' */
return trx_ctrl_cmd_cb(l1h, 1, cb, "SETSLOT", "%u %u",
tn, cfg->setslot[tn].slottype);
}
}
/*! Send "RXTUNE" command to TRX: Tune Receiver to given ARFCN */
int trx_if_cmd_rxtune(struct trx_l1h *l1h, uint16_t arfcn, trx_if_cmd_generic_cb *cb)
{
struct phy_instance *pinst = l1h->phy_inst;
uint16_t freq10;
if (pinst->trx->bts->band == GSM_BAND_1900)
arfcn |= ARFCN_PCS;
freq10 = gsm_arfcn2freq10(arfcn, 1); /* RX = uplink */
if (freq10 == 0xffff) {
LOGPPHI(pinst, DTRX, LOGL_ERROR, "Arfcn %d not defined.\n",
arfcn & ~ARFCN_FLAG_MASK);
return -ENOTSUP;
}
return trx_ctrl_cmd_cb(l1h, 1, cb, "RXTUNE", "%d", freq10 * 100);
}
/*! Send "TXTUNE" command to TRX: Tune Transmitter to given ARFCN */
int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn, trx_if_cmd_generic_cb *cb)
{
struct phy_instance *pinst = l1h->phy_inst;
uint16_t freq10;
if (pinst->trx->bts->band == GSM_BAND_1900)
arfcn |= ARFCN_PCS;
freq10 = gsm_arfcn2freq10(arfcn, 0); /* TX = downlink */
if (freq10 == 0xffff) {
LOGPPHI(pinst, DTRX, LOGL_ERROR, "Arfcn %d not defined.\n",
arfcn & ~ARFCN_FLAG_MASK);
return -ENOTSUP;
}
return trx_ctrl_cmd_cb(l1h, 1, cb, "TXTUNE", "%d", freq10 * 100);
}
/*! Send "HANDOVER" command to TRX: Enable handover RACH Detection on timeslot/sub-slot */
2013-06-12 07:12:04 +00:00
int trx_if_cmd_handover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss)
{
return trx_ctrl_cmd(l1h, 1, "HANDOVER", "%d %d", tn, ss);
}
/*! Send "NOHANDOVER" command to TRX: Disable handover RACH Detection on timeslot/sub-slot */
2013-06-12 07:12:04 +00:00
int trx_if_cmd_nohandover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss)
{
return trx_ctrl_cmd(l1h, 1, "NOHANDOVER", "%d %d", tn, ss);
}
/*! Send "RFMUTE" command to TRX: Mute or Unmute RF transmission */
int trx_if_cmd_rfmute(struct trx_l1h *l1h, bool mute)
{
return trx_ctrl_cmd(l1h, 0, "RFMUTE", mute ? "1" : "0");
}
struct trx_ctrl_rsp {
char cmd[50];
char params[100];
int status;
bts-trx: (n)ack PDCH DEACT only after TRX answered SETSLOT Before this patch, PDCH DEACT was (n)acked to the BSC without taking into account if TRX succeeded or failed to set the TS: 20181123044720655 DRLL rsl.c:2523 (bts=0,trx=0,ts=0,ss=0) Rx RLL DATA_REQ Abis -> LAPDm 20181123044720700 DRSL rsl.c:2805 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) ss=0 Rx RSL IPAC_PDCH_DEACT 20181123044720700 DRSL rsl.c:2205 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) Request to PDCH DEACT, but lchan is still active 20181123044720700 DRSL rsl.c:2131 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT NACK (cause = 0x0f) 20181123044720700 DPCU pcu_sock.c:124 Sending info 20181123044720700 DPCU pcu_sock.c:139 BTS is up 20181123044720700 DPCU pcu_sock.c:232 trx=0 ts=7: available (tsc=7 arfcn=868) 20181123044720703 DPCU pcu_sock.c:608 Deactivate request received: TRX=0 TX=6 20181123044720703 DL1C l1sap.c:1519 deactivating channel chan_nr=TCH/F on TS6 trx=0 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD NOHANDOVER 6 0' 20181123044720703 DL1C l1sap.c:648 deactivate confirm chan_nr=TCH/F on TS6 trx=0 20181123044720703 DRSL rsl.c:714 (bts=0,trx=0,ts=6,ss=0) not sending REL ACK 20181123044720703 DRSL rsl.c:2264 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: channel disconnected, will reconnect as TCH 20181123044720703 DL1C scheduler.c:593 Configuring multiframe with TCH/F+SACCH trx=0 ts=6 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD SETSLOT 6 1' 20181123044720703 DL1C l1_if.c:780 (bts=0,trx=0,ts=6) bts_model_ts_connect(as_pchan=TCH/F) success, calling cb_ts_connected() 20181123044720703 DRSL rsl.c:2339 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: timeslot connected as TCH/F 20181123044720703 DRSL rsl.c:2440 (bts=0,trx=0,ts=6,ss=0) TCH/F_PDCH switched to TCH/F mode (ts->flags == 0) 20181123044720703 DRSL rsl.c:2103 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT ACK 20181123044720704 DTRX trx_if.c:492 Response message: 'RSP NOHANDOVER 0 6' 20181123044720705 DTRX trx_if.c:492 Response message: 'RSP SETSLOT 0 6 1' Change-Id: I888de761b65c3ea8bfe623fcf009f3b2b57c926c
2018-11-26 12:59:52 +00:00
void *cb;
};
static int parse_rsp(const char *buf_in, size_t len_in, struct trx_ctrl_rsp *rsp)
{
size_t nlen, plen;
char *p, *k;
if (strncmp(buf_in, "RSP ", 4))
goto parse_err;
/* Get the RSP cmd name */
if (!(p = strchr(buf_in + 4, ' ')))
goto parse_err;
/* Calculate length of the name part */
nlen = p - (buf_in + 4);
if (nlen >= sizeof(rsp->cmd)) {
LOGP(DTRX, LOGL_ERROR, "TRXC command name part is too long: "
"%zu >= %zu\n", nlen, sizeof(rsp->cmd));
goto parse_err;
}
memcpy(&rsp->cmd[0], buf_in + 4, nlen);
rsp->cmd[nlen] = '\0';
/* Now comes the status code of the response */
p++;
if (sscanf(p, "%d", &rsp->status) != 1)
goto parse_err;
/* Now copy back the parameters */
k = strchr(p, ' ');
if (k)
k++;
else
k = p + strlen(p);
/* Calculate length of the parameters part */
plen = strlen(k);
if (plen >= sizeof(rsp->params)) {
LOGP(DTRX, LOGL_ERROR, "TRXC command parameters part is too long: "
"%zu >= %zu\n", plen, sizeof(rsp->params));
goto parse_err;
}
memcpy(&rsp->params[0], k, plen);
rsp->params[plen] = '\0';
return 0;
parse_err:
LOGP(DTRX, LOGL_NOTICE, "Unknown TRXC message: %s\n", buf_in);
return -1;
}
static bool cmd_matches_rsp(struct trx_ctrl_msg *tcm, struct trx_ctrl_rsp *rsp)
{
if (strcmp(tcm->cmd, rsp->cmd))
return false;
/* For SETSLOT we also need to check if it's the response for the
specific timeslot. For other commands such as SETRXGAIN, it is
expected that they can return different values */
if (strcmp(tcm->cmd, "SETSLOT") == 0 && strcmp(tcm->params, rsp->params))
return false;
else if (strcmp(tcm->cmd, "SETFORMAT") == 0 && strcmp(tcm->params, rsp->params))
return false;
return true;
}
static int trx_ctrl_rx_rsp_poweron(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp)
{
trx_if_cmd_poweronoff_cb *cb = (trx_if_cmd_poweronoff_cb*) rsp->cb;
if (rsp->status != 0)
LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
"transceiver rejected POWERON command (%d), re-trying in a few seconds\n",
rsp->status);
if (cb)
cb(l1h, true, rsp->status);
/* If TRX fails, try again after 5 sec */
return rsp->status == 0 ? 0 : 5;
}
static int trx_ctrl_rx_rsp_poweroff(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp)
{
trx_if_cmd_poweronoff_cb *cb = (trx_if_cmd_poweronoff_cb*) rsp->cb;
if (rsp->status == 0) {
if (cb)
cb(l1h, false, rsp->status);
return 0;
}
return -EINVAL;
}
bts-trx: (n)ack PDCH DEACT only after TRX answered SETSLOT Before this patch, PDCH DEACT was (n)acked to the BSC without taking into account if TRX succeeded or failed to set the TS: 20181123044720655 DRLL rsl.c:2523 (bts=0,trx=0,ts=0,ss=0) Rx RLL DATA_REQ Abis -> LAPDm 20181123044720700 DRSL rsl.c:2805 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) ss=0 Rx RSL IPAC_PDCH_DEACT 20181123044720700 DRSL rsl.c:2205 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) Request to PDCH DEACT, but lchan is still active 20181123044720700 DRSL rsl.c:2131 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT NACK (cause = 0x0f) 20181123044720700 DPCU pcu_sock.c:124 Sending info 20181123044720700 DPCU pcu_sock.c:139 BTS is up 20181123044720700 DPCU pcu_sock.c:232 trx=0 ts=7: available (tsc=7 arfcn=868) 20181123044720703 DPCU pcu_sock.c:608 Deactivate request received: TRX=0 TX=6 20181123044720703 DL1C l1sap.c:1519 deactivating channel chan_nr=TCH/F on TS6 trx=0 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD NOHANDOVER 6 0' 20181123044720703 DL1C l1sap.c:648 deactivate confirm chan_nr=TCH/F on TS6 trx=0 20181123044720703 DRSL rsl.c:714 (bts=0,trx=0,ts=6,ss=0) not sending REL ACK 20181123044720703 DRSL rsl.c:2264 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: channel disconnected, will reconnect as TCH 20181123044720703 DL1C scheduler.c:593 Configuring multiframe with TCH/F+SACCH trx=0 ts=6 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD SETSLOT 6 1' 20181123044720703 DL1C l1_if.c:780 (bts=0,trx=0,ts=6) bts_model_ts_connect(as_pchan=TCH/F) success, calling cb_ts_connected() 20181123044720703 DRSL rsl.c:2339 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: timeslot connected as TCH/F 20181123044720703 DRSL rsl.c:2440 (bts=0,trx=0,ts=6,ss=0) TCH/F_PDCH switched to TCH/F mode (ts->flags == 0) 20181123044720703 DRSL rsl.c:2103 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT ACK 20181123044720704 DTRX trx_if.c:492 Response message: 'RSP NOHANDOVER 0 6' 20181123044720705 DTRX trx_if.c:492 Response message: 'RSP SETSLOT 0 6 1' Change-Id: I888de761b65c3ea8bfe623fcf009f3b2b57c926c
2018-11-26 12:59:52 +00:00
static int trx_ctrl_rx_rsp_setslot(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp)
{
trx_if_cmd_setslot_cb *cb = (trx_if_cmd_setslot_cb*) rsp->cb;
struct phy_instance *pinst = l1h->phy_inst;
unsigned int tn, ts_type;
if (rsp->status)
LOGPPHI(pinst, DTRX, LOGL_ERROR, "transceiver SETSLOT failed with status %d\n",
rsp->status);
bts-trx: (n)ack PDCH DEACT only after TRX answered SETSLOT Before this patch, PDCH DEACT was (n)acked to the BSC without taking into account if TRX succeeded or failed to set the TS: 20181123044720655 DRLL rsl.c:2523 (bts=0,trx=0,ts=0,ss=0) Rx RLL DATA_REQ Abis -> LAPDm 20181123044720700 DRSL rsl.c:2805 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) ss=0 Rx RSL IPAC_PDCH_DEACT 20181123044720700 DRSL rsl.c:2205 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) Request to PDCH DEACT, but lchan is still active 20181123044720700 DRSL rsl.c:2131 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT NACK (cause = 0x0f) 20181123044720700 DPCU pcu_sock.c:124 Sending info 20181123044720700 DPCU pcu_sock.c:139 BTS is up 20181123044720700 DPCU pcu_sock.c:232 trx=0 ts=7: available (tsc=7 arfcn=868) 20181123044720703 DPCU pcu_sock.c:608 Deactivate request received: TRX=0 TX=6 20181123044720703 DL1C l1sap.c:1519 deactivating channel chan_nr=TCH/F on TS6 trx=0 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD NOHANDOVER 6 0' 20181123044720703 DL1C l1sap.c:648 deactivate confirm chan_nr=TCH/F on TS6 trx=0 20181123044720703 DRSL rsl.c:714 (bts=0,trx=0,ts=6,ss=0) not sending REL ACK 20181123044720703 DRSL rsl.c:2264 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: channel disconnected, will reconnect as TCH 20181123044720703 DL1C scheduler.c:593 Configuring multiframe with TCH/F+SACCH trx=0 ts=6 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD SETSLOT 6 1' 20181123044720703 DL1C l1_if.c:780 (bts=0,trx=0,ts=6) bts_model_ts_connect(as_pchan=TCH/F) success, calling cb_ts_connected() 20181123044720703 DRSL rsl.c:2339 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: timeslot connected as TCH/F 20181123044720703 DRSL rsl.c:2440 (bts=0,trx=0,ts=6,ss=0) TCH/F_PDCH switched to TCH/F mode (ts->flags == 0) 20181123044720703 DRSL rsl.c:2103 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT ACK 20181123044720704 DTRX trx_if.c:492 Response message: 'RSP NOHANDOVER 0 6' 20181123044720705 DTRX trx_if.c:492 Response message: 'RSP SETSLOT 0 6 1' Change-Id: I888de761b65c3ea8bfe623fcf009f3b2b57c926c
2018-11-26 12:59:52 +00:00
/* Since message was already validated against CMD we sent, we know format
* of params is: "<TN> <TS_TYPE>" */
if (sscanf(rsp->params, "%u %u", &tn, &ts_type) < 2) {
LOGPPHI(pinst, DTRX, LOGL_ERROR, "transceiver SETSLOT unable to parse params\n");
bts-trx: (n)ack PDCH DEACT only after TRX answered SETSLOT Before this patch, PDCH DEACT was (n)acked to the BSC without taking into account if TRX succeeded or failed to set the TS: 20181123044720655 DRLL rsl.c:2523 (bts=0,trx=0,ts=0,ss=0) Rx RLL DATA_REQ Abis -> LAPDm 20181123044720700 DRSL rsl.c:2805 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) ss=0 Rx RSL IPAC_PDCH_DEACT 20181123044720700 DRSL rsl.c:2205 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) Request to PDCH DEACT, but lchan is still active 20181123044720700 DRSL rsl.c:2131 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT NACK (cause = 0x0f) 20181123044720700 DPCU pcu_sock.c:124 Sending info 20181123044720700 DPCU pcu_sock.c:139 BTS is up 20181123044720700 DPCU pcu_sock.c:232 trx=0 ts=7: available (tsc=7 arfcn=868) 20181123044720703 DPCU pcu_sock.c:608 Deactivate request received: TRX=0 TX=6 20181123044720703 DL1C l1sap.c:1519 deactivating channel chan_nr=TCH/F on TS6 trx=0 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD NOHANDOVER 6 0' 20181123044720703 DL1C l1sap.c:648 deactivate confirm chan_nr=TCH/F on TS6 trx=0 20181123044720703 DRSL rsl.c:714 (bts=0,trx=0,ts=6,ss=0) not sending REL ACK 20181123044720703 DRSL rsl.c:2264 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: channel disconnected, will reconnect as TCH 20181123044720703 DL1C scheduler.c:593 Configuring multiframe with TCH/F+SACCH trx=0 ts=6 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD SETSLOT 6 1' 20181123044720703 DL1C l1_if.c:780 (bts=0,trx=0,ts=6) bts_model_ts_connect(as_pchan=TCH/F) success, calling cb_ts_connected() 20181123044720703 DRSL rsl.c:2339 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: timeslot connected as TCH/F 20181123044720703 DRSL rsl.c:2440 (bts=0,trx=0,ts=6,ss=0) TCH/F_PDCH switched to TCH/F mode (ts->flags == 0) 20181123044720703 DRSL rsl.c:2103 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT ACK 20181123044720704 DTRX trx_if.c:492 Response message: 'RSP NOHANDOVER 0 6' 20181123044720705 DTRX trx_if.c:492 Response message: 'RSP SETSLOT 0 6 1' Change-Id: I888de761b65c3ea8bfe623fcf009f3b2b57c926c
2018-11-26 12:59:52 +00:00
return -EINVAL;
}
if (cb)
cb(l1h, tn, ts_type, rsp->status);
return rsp->status == 0 ? 0 : -EINVAL;
}
/* TRXD PDU format negotiation handler.
*
* If the transceiver does not support the format negotiation, it would
* reject SETFORMAT with 'RSP ERR 1'. If the requested version is not
* supported by the transceiver, status code of the response message
* should indicate a preferred (basically, the latest) version.
*/
static int trx_ctrl_rx_rsp_setformat(struct trx_l1h *l1h,
struct trx_ctrl_rsp *rsp)
{
trx_if_cmd_generic_cb *cb;
/* Old transceivers reject 'SETFORMAT' with 'RSP ERR 1' */
if (strcmp(rsp->cmd, "SETFORMAT") != 0) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
"Transceiver rejected the format negotiation command, "
"using legacy TRXD PDU version (0)\n");
if (rsp->cb) {
cb = (trx_if_cmd_generic_cb*) rsp->cb;
cb(l1h, 0);
}
return 0;
}
/* Status shall indicate a proper version supported by the transceiver */
if (rsp->status < 0 || rsp->status > l1h->config.trxd_pdu_ver_req) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"Transceiver indicated an out of range "
"PDU version %d (requested %u)\n",
rsp->status, l1h->config.trxd_pdu_ver_req);
return -EINVAL;
}
if (rsp->cb) {
cb = (trx_if_cmd_generic_cb*) rsp->cb;
cb(l1h, rsp->status);
}
return 0;
}
static int trx_ctrl_rx_rsp_nomtxpower(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp)
{
trx_if_cmd_getnompower_cb *cb = (trx_if_cmd_getnompower_cb*) rsp->cb;
struct phy_instance *pinst = l1h->phy_inst;
int nominal_power;
if (rsp->status)
LOGPPHI(pinst, DTRX, LOGL_ERROR, "transceiver NOMTXPOWER failed "
"with status %d. If your transceiver doesn't support this "
"command, then please set the nominal transmit power manually "
"through VTY cmd 'nominal-tx-power'.\n",
rsp->status);
if (cb) {
sscanf(rsp->params, "%d", &nominal_power);
cb(l1h, nominal_power, rsp->status);
}
return 0;
}
static int trx_ctrl_rx_rsp_setpower(struct trx_l1h *l1h, struct trx_ctrl_rsp *rsp)
{
trx_if_cmd_setpower_att_cb *cb = (trx_if_cmd_setpower_att_cb*) rsp->cb;
struct phy_instance *pinst = l1h->phy_inst;
int power_att;
if (rsp->status)
LOGPPHI(pinst, DTRX, LOGL_ERROR, "transceiver SETPOWER failed with status %d\n",
rsp->status);
if (cb) {
sscanf(rsp->params, "%d", &power_att);
cb(l1h, power_att, rsp->status);
}
return 0;
}
/* -EINVAL: unrecoverable error, exit BTS
* N > 0: try sending originating command again after N seconds
* 0: Done with response, get originating command out from send queue
*/
static int trx_ctrl_rx_rsp(struct trx_l1h *l1h,
struct trx_ctrl_rsp *rsp,
struct trx_ctrl_msg *tcm)
{
trx_if_cmd_generic_cb *cb;
if (strcmp(rsp->cmd, "POWERON") == 0) {
return trx_ctrl_rx_rsp_poweron(l1h, rsp);
} else if (strcmp(rsp->cmd, "POWEROFF") == 0) {
return trx_ctrl_rx_rsp_poweroff(l1h, rsp);
bts-trx: (n)ack PDCH DEACT only after TRX answered SETSLOT Before this patch, PDCH DEACT was (n)acked to the BSC without taking into account if TRX succeeded or failed to set the TS: 20181123044720655 DRLL rsl.c:2523 (bts=0,trx=0,ts=0,ss=0) Rx RLL DATA_REQ Abis -> LAPDm 20181123044720700 DRSL rsl.c:2805 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) ss=0 Rx RSL IPAC_PDCH_DEACT 20181123044720700 DRSL rsl.c:2205 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) Request to PDCH DEACT, but lchan is still active 20181123044720700 DRSL rsl.c:2131 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT NACK (cause = 0x0f) 20181123044720700 DPCU pcu_sock.c:124 Sending info 20181123044720700 DPCU pcu_sock.c:139 BTS is up 20181123044720700 DPCU pcu_sock.c:232 trx=0 ts=7: available (tsc=7 arfcn=868) 20181123044720703 DPCU pcu_sock.c:608 Deactivate request received: TRX=0 TX=6 20181123044720703 DL1C l1sap.c:1519 deactivating channel chan_nr=TCH/F on TS6 trx=0 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD NOHANDOVER 6 0' 20181123044720703 DL1C l1sap.c:648 deactivate confirm chan_nr=TCH/F on TS6 trx=0 20181123044720703 DRSL rsl.c:714 (bts=0,trx=0,ts=6,ss=0) not sending REL ACK 20181123044720703 DRSL rsl.c:2264 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: channel disconnected, will reconnect as TCH 20181123044720703 DL1C scheduler.c:593 Configuring multiframe with TCH/F+SACCH trx=0 ts=6 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD SETSLOT 6 1' 20181123044720703 DL1C l1_if.c:780 (bts=0,trx=0,ts=6) bts_model_ts_connect(as_pchan=TCH/F) success, calling cb_ts_connected() 20181123044720703 DRSL rsl.c:2339 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: timeslot connected as TCH/F 20181123044720703 DRSL rsl.c:2440 (bts=0,trx=0,ts=6,ss=0) TCH/F_PDCH switched to TCH/F mode (ts->flags == 0) 20181123044720703 DRSL rsl.c:2103 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT ACK 20181123044720704 DTRX trx_if.c:492 Response message: 'RSP NOHANDOVER 0 6' 20181123044720705 DTRX trx_if.c:492 Response message: 'RSP SETSLOT 0 6 1' Change-Id: I888de761b65c3ea8bfe623fcf009f3b2b57c926c
2018-11-26 12:59:52 +00:00
} else if (strcmp(rsp->cmd, "SETSLOT") == 0) {
return trx_ctrl_rx_rsp_setslot(l1h, rsp);
/* We may get 'RSP ERR 1' if 'SETFORMAT' is not supported,
* so that's why we should use tcm instead of rsp. */
} else if (strcmp(tcm->cmd, "SETFORMAT") == 0) {
return trx_ctrl_rx_rsp_setformat(l1h, rsp);
} else if (strcmp(tcm->cmd, "NOMTXPOWER") == 0) {
return trx_ctrl_rx_rsp_nomtxpower(l1h, rsp);
} else if (strcmp(tcm->cmd, "SETPOWER") == 0) {
return trx_ctrl_rx_rsp_setpower(l1h, rsp);
}
/* Generic callback if available */
if (rsp->cb) {
cb = (trx_if_cmd_generic_cb*) rsp->cb;
cb(l1h, rsp->status);
}
if (rsp->status) {
LOGPPHI(l1h->phy_inst, DTRX, tcm->critical ? LOGL_FATAL : LOGL_NOTICE,
"transceiver rejected TRX command with response: '%s%s%s %d'\n",
rsp->cmd, rsp->params[0] != '\0' ? " ":"",
rsp->params, rsp->status);
if (tcm->critical)
return -EINVAL;
}
return 0;
}
/*! Get + parse response from TRX ctrl socket */
static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
{
struct trx_l1h *l1h = ofd->data;
struct phy_instance *pinst = l1h->phy_inst;
char buf[TRXC_MSG_BUF_SIZE];
struct trx_ctrl_rsp rsp;
int len, rc;
struct trx_ctrl_msg *tcm;
len = recv(ofd->fd, buf, sizeof(buf) - 1, 0);
if (len <= 0)
return len;
buf[len] = '\0';
if (parse_rsp(buf, len, &rsp) < 0)
return 0;
LOGPPHI(l1h->phy_inst, DTRX, LOGL_INFO, "Response message: '%s'\n", buf);
/* abort timer and send next message, if any */
if (osmo_timer_pending(&l1h->trx_ctrl_timer))
osmo_timer_del(&l1h->trx_ctrl_timer);
/* get command for response message */
if (llist_empty(&l1h->trx_ctrl_list)) {
bts-trx: Detect duplicated responses for retransmitted commands It was detected that under some conditions, osmo-trx (with limesdr) may take a long time to answer to CMDs, which means trx_ctrl_timer will trigger re-transmitting the last sent but yet unacked CMD. Due to the high latency in osmo-trx, the original AND the rentrasnmited CMD are handled after a while and RSP messages are sent for both. When osmo-bts-trx receives the first RSP, it was marking the CMD as acked and carried on with next one. Then, when the RSP from the retransmited CMD arrives, it already lost state and doesn't know where does that come from. As a result, osmo-bts-trx shutdowns. The issue can be seen in the following truncated log from osmo-bts-trx with TRX category enabled: 20180117135228175 Enqueuing TRX control command 'CMD RXTUNE 1782000' 20180117135228175 Enqueuing TRX control command 'CMD TXTUNE 1877000' 20180117135228175 Enqueuing TRX control command 'CMD SETTSC 7' 20180117135228175 Enqueuing TRX control command 'CMD POWERON' 20180117135228175 Enqueuing TRX control command 'CMD SETRXGAIN 1' 20180117135228175 Enqueuing TRX control command 'CMD SETPOWER 20' 20180117135228175 Enqueuing TRX control command 'CMD SETSLOT 0 5' ... 20180117135249829 Response message: 'RSP POWEROFF 0' 20180117135249855 Response message: 'RSP RXTUNE 0 1782000' 20180117135249876 Response message: 'RSP TXTUNE 0 1877000' 20180117135249876 Response message: 'RSP SETTSC 0 7' 20180117135250648 Response message: 'RSP POWERON 0' 20180117135251150 Response message: 'RSP SETRXGAIN 0 0' 20180117135253151 No response from transceiver for phy0.0 (CMD SETPOWER 20) 20180117135253777 Response message: 'RSP SETPOWER 0 20' 20180117135254535 Clock indication: fn=2018878 20180117135255777 No response from transceiver for phy0.0 (CMD SETSLOT 0 5) ... 20180117135256858 Response message: 'RSP SETPOWER 0 20' 20180117135256858 Discarding duplicated RSP from old CMD 'RSP SETPOWER 0 20' 20180117135256858 Response message: 'RSP SETSLOT 0 0 5' 20180117135256858 Response message: 'RSP SETSLOT 0 0 5' 20180117135256858 Discarding duplicated RSP from old CMD 'RSP SETSLOT 0 0 5' Change-Id: I3633cba212edde878f83ed36aef922aaca6f503a
2018-01-17 12:45:40 +00:00
/* RSP from a retransmission, skip it */
if (l1h->last_acked && cmd_matches_rsp(l1h->last_acked, &rsp)) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE, "Discarding duplicated RSP "
bts-trx: Detect duplicated responses for retransmitted commands It was detected that under some conditions, osmo-trx (with limesdr) may take a long time to answer to CMDs, which means trx_ctrl_timer will trigger re-transmitting the last sent but yet unacked CMD. Due to the high latency in osmo-trx, the original AND the rentrasnmited CMD are handled after a while and RSP messages are sent for both. When osmo-bts-trx receives the first RSP, it was marking the CMD as acked and carried on with next one. Then, when the RSP from the retransmited CMD arrives, it already lost state and doesn't know where does that come from. As a result, osmo-bts-trx shutdowns. The issue can be seen in the following truncated log from osmo-bts-trx with TRX category enabled: 20180117135228175 Enqueuing TRX control command 'CMD RXTUNE 1782000' 20180117135228175 Enqueuing TRX control command 'CMD TXTUNE 1877000' 20180117135228175 Enqueuing TRX control command 'CMD SETTSC 7' 20180117135228175 Enqueuing TRX control command 'CMD POWERON' 20180117135228175 Enqueuing TRX control command 'CMD SETRXGAIN 1' 20180117135228175 Enqueuing TRX control command 'CMD SETPOWER 20' 20180117135228175 Enqueuing TRX control command 'CMD SETSLOT 0 5' ... 20180117135249829 Response message: 'RSP POWEROFF 0' 20180117135249855 Response message: 'RSP RXTUNE 0 1782000' 20180117135249876 Response message: 'RSP TXTUNE 0 1877000' 20180117135249876 Response message: 'RSP SETTSC 0 7' 20180117135250648 Response message: 'RSP POWERON 0' 20180117135251150 Response message: 'RSP SETRXGAIN 0 0' 20180117135253151 No response from transceiver for phy0.0 (CMD SETPOWER 20) 20180117135253777 Response message: 'RSP SETPOWER 0 20' 20180117135254535 Clock indication: fn=2018878 20180117135255777 No response from transceiver for phy0.0 (CMD SETSLOT 0 5) ... 20180117135256858 Response message: 'RSP SETPOWER 0 20' 20180117135256858 Discarding duplicated RSP from old CMD 'RSP SETPOWER 0 20' 20180117135256858 Response message: 'RSP SETSLOT 0 0 5' 20180117135256858 Response message: 'RSP SETSLOT 0 0 5' 20180117135256858 Discarding duplicated RSP from old CMD 'RSP SETSLOT 0 0 5' Change-Id: I3633cba212edde878f83ed36aef922aaca6f503a
2018-01-17 12:45:40 +00:00
"from old CMD '%s'\n", buf);
return 0;
}
LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE, "Response message without command\n");
return -EINVAL;
}
tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg,
list);
/* check if response matches command */
if (!cmd_matches_rsp(tcm, &rsp)) {
bts-trx: Detect duplicated responses for retransmitted commands It was detected that under some conditions, osmo-trx (with limesdr) may take a long time to answer to CMDs, which means trx_ctrl_timer will trigger re-transmitting the last sent but yet unacked CMD. Due to the high latency in osmo-trx, the original AND the rentrasnmited CMD are handled after a while and RSP messages are sent for both. When osmo-bts-trx receives the first RSP, it was marking the CMD as acked and carried on with next one. Then, when the RSP from the retransmited CMD arrives, it already lost state and doesn't know where does that come from. As a result, osmo-bts-trx shutdowns. The issue can be seen in the following truncated log from osmo-bts-trx with TRX category enabled: 20180117135228175 Enqueuing TRX control command 'CMD RXTUNE 1782000' 20180117135228175 Enqueuing TRX control command 'CMD TXTUNE 1877000' 20180117135228175 Enqueuing TRX control command 'CMD SETTSC 7' 20180117135228175 Enqueuing TRX control command 'CMD POWERON' 20180117135228175 Enqueuing TRX control command 'CMD SETRXGAIN 1' 20180117135228175 Enqueuing TRX control command 'CMD SETPOWER 20' 20180117135228175 Enqueuing TRX control command 'CMD SETSLOT 0 5' ... 20180117135249829 Response message: 'RSP POWEROFF 0' 20180117135249855 Response message: 'RSP RXTUNE 0 1782000' 20180117135249876 Response message: 'RSP TXTUNE 0 1877000' 20180117135249876 Response message: 'RSP SETTSC 0 7' 20180117135250648 Response message: 'RSP POWERON 0' 20180117135251150 Response message: 'RSP SETRXGAIN 0 0' 20180117135253151 No response from transceiver for phy0.0 (CMD SETPOWER 20) 20180117135253777 Response message: 'RSP SETPOWER 0 20' 20180117135254535 Clock indication: fn=2018878 20180117135255777 No response from transceiver for phy0.0 (CMD SETSLOT 0 5) ... 20180117135256858 Response message: 'RSP SETPOWER 0 20' 20180117135256858 Discarding duplicated RSP from old CMD 'RSP SETPOWER 0 20' 20180117135256858 Response message: 'RSP SETSLOT 0 0 5' 20180117135256858 Response message: 'RSP SETSLOT 0 0 5' 20180117135256858 Discarding duplicated RSP from old CMD 'RSP SETSLOT 0 0 5' Change-Id: I3633cba212edde878f83ed36aef922aaca6f503a
2018-01-17 12:45:40 +00:00
/* RSP from a retransmission, skip it */
if (l1h->last_acked && cmd_matches_rsp(l1h->last_acked, &rsp)) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE, "Discarding duplicated RSP "
bts-trx: Detect duplicated responses for retransmitted commands It was detected that under some conditions, osmo-trx (with limesdr) may take a long time to answer to CMDs, which means trx_ctrl_timer will trigger re-transmitting the last sent but yet unacked CMD. Due to the high latency in osmo-trx, the original AND the rentrasnmited CMD are handled after a while and RSP messages are sent for both. When osmo-bts-trx receives the first RSP, it was marking the CMD as acked and carried on with next one. Then, when the RSP from the retransmited CMD arrives, it already lost state and doesn't know where does that come from. As a result, osmo-bts-trx shutdowns. The issue can be seen in the following truncated log from osmo-bts-trx with TRX category enabled: 20180117135228175 Enqueuing TRX control command 'CMD RXTUNE 1782000' 20180117135228175 Enqueuing TRX control command 'CMD TXTUNE 1877000' 20180117135228175 Enqueuing TRX control command 'CMD SETTSC 7' 20180117135228175 Enqueuing TRX control command 'CMD POWERON' 20180117135228175 Enqueuing TRX control command 'CMD SETRXGAIN 1' 20180117135228175 Enqueuing TRX control command 'CMD SETPOWER 20' 20180117135228175 Enqueuing TRX control command 'CMD SETSLOT 0 5' ... 20180117135249829 Response message: 'RSP POWEROFF 0' 20180117135249855 Response message: 'RSP RXTUNE 0 1782000' 20180117135249876 Response message: 'RSP TXTUNE 0 1877000' 20180117135249876 Response message: 'RSP SETTSC 0 7' 20180117135250648 Response message: 'RSP POWERON 0' 20180117135251150 Response message: 'RSP SETRXGAIN 0 0' 20180117135253151 No response from transceiver for phy0.0 (CMD SETPOWER 20) 20180117135253777 Response message: 'RSP SETPOWER 0 20' 20180117135254535 Clock indication: fn=2018878 20180117135255777 No response from transceiver for phy0.0 (CMD SETSLOT 0 5) ... 20180117135256858 Response message: 'RSP SETPOWER 0 20' 20180117135256858 Discarding duplicated RSP from old CMD 'RSP SETPOWER 0 20' 20180117135256858 Response message: 'RSP SETSLOT 0 0 5' 20180117135256858 Response message: 'RSP SETSLOT 0 0 5' 20180117135256858 Discarding duplicated RSP from old CMD 'RSP SETSLOT 0 0 5' Change-Id: I3633cba212edde878f83ed36aef922aaca6f503a
2018-01-17 12:45:40 +00:00
"from old CMD '%s'\n", buf);
return 0;
}
LOGPPHI(l1h->phy_inst, DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE,
"Response message '%s' does not match command "
"message 'CMD %s%s%s'\n",
buf, tcm->cmd, tcm->params_len ? " ":"", tcm->params);
/* We may get 'RSP ERR 1' for non-critical commands */
if (tcm->critical)
goto rsp_error;
}
bts-trx: (n)ack PDCH DEACT only after TRX answered SETSLOT Before this patch, PDCH DEACT was (n)acked to the BSC without taking into account if TRX succeeded or failed to set the TS: 20181123044720655 DRLL rsl.c:2523 (bts=0,trx=0,ts=0,ss=0) Rx RLL DATA_REQ Abis -> LAPDm 20181123044720700 DRSL rsl.c:2805 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) ss=0 Rx RSL IPAC_PDCH_DEACT 20181123044720700 DRSL rsl.c:2205 (bts=0,trx=0,ts=6,pchan=TCH/F_PDCH as PDCH) Request to PDCH DEACT, but lchan is still active 20181123044720700 DRSL rsl.c:2131 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT NACK (cause = 0x0f) 20181123044720700 DPCU pcu_sock.c:124 Sending info 20181123044720700 DPCU pcu_sock.c:139 BTS is up 20181123044720700 DPCU pcu_sock.c:232 trx=0 ts=7: available (tsc=7 arfcn=868) 20181123044720703 DPCU pcu_sock.c:608 Deactivate request received: TRX=0 TX=6 20181123044720703 DL1C l1sap.c:1519 deactivating channel chan_nr=TCH/F on TS6 trx=0 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD NOHANDOVER 6 0' 20181123044720703 DL1C l1sap.c:648 deactivate confirm chan_nr=TCH/F on TS6 trx=0 20181123044720703 DRSL rsl.c:714 (bts=0,trx=0,ts=6,ss=0) not sending REL ACK 20181123044720703 DRSL rsl.c:2264 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: channel disconnected, will reconnect as TCH 20181123044720703 DL1C scheduler.c:593 Configuring multiframe with TCH/F+SACCH trx=0 ts=6 20181123044720703 DTRX trx_if.c:242 Enqueuing TRX control command 'CMD SETSLOT 6 1' 20181123044720703 DL1C l1_if.c:780 (bts=0,trx=0,ts=6) bts_model_ts_connect(as_pchan=TCH/F) success, calling cb_ts_connected() 20181123044720703 DRSL rsl.c:2339 (bts=0,trx=0,ts=6,ss=0) PDCH DEACT operation: timeslot connected as TCH/F 20181123044720703 DRSL rsl.c:2440 (bts=0,trx=0,ts=6,ss=0) TCH/F_PDCH switched to TCH/F mode (ts->flags == 0) 20181123044720703 DRSL rsl.c:2103 (bts=0,trx=0,ts=6,ss=0) Tx PDCH DEACT ACK 20181123044720704 DTRX trx_if.c:492 Response message: 'RSP NOHANDOVER 0 6' 20181123044720705 DTRX trx_if.c:492 Response message: 'RSP SETSLOT 0 6 1' Change-Id: I888de761b65c3ea8bfe623fcf009f3b2b57c926c
2018-11-26 12:59:52 +00:00
rsp.cb = tcm->cb;
/* Remove command from list, save it to last_acked and remove previous
* last_acked. Do it before calling callback to avoid user freeing tcm
* pointer if flushing/closing the iface. */
llist_del(&tcm->list);
talloc_free(l1h->last_acked);
l1h->last_acked = tcm;
/* check for response code */
rc = trx_ctrl_rx_rsp(l1h, &rsp, tcm);
if (rc == -EINVAL)
goto rsp_error;
/* re-schedule last cmd in rc seconds time */
if (rc > 0) {
if (!llist_empty(&l1h->trx_ctrl_list))
osmo_timer_schedule(&l1h->trx_ctrl_timer, rc, 0);
return 0;
}
trx_ctrl_send(l1h);
return 0;
rsp_error:
bts_shutdown(pinst->trx->bts, "TRX-CTRL-MSG: CRITICAL");
/* keep tcm list, so process is stopped */
return -EIO;
}
/*
* TRX burst data socket
*/
/* Uplink TRXDv0 header length: TDMA TN + FN + RSSI + ToA256 */
#define TRX_UL_V0HDR_LEN (1 + 4 + 1 + 2)
/* Uplink TRXDv1 header length: additional MTS + C/I */
osmo-bts-trx/trx_if.c: introduce TRXD header version 0x01 support The new version adds the following fields to the TRX2L1 message, keeping the L12TRX message unchanged: +------+-----+-----+-----+--------------------+ | RSSI | ToA | MTS | C/I | soft-bits (254..0) | +------+-----+-----+-----+--------------------+ - MTS (1 octet) - Modulation and Training Sequence info, and - C/I (2 octets) - Carrier-to-Interference ratio (big endian). == Coding of MTS: Modulation and Training Sequence info 3GPP TS 45.002 version 15.1.0 defines several modulation types, and a few sets of training sequences for each type. The most common are GMSK and 8-PSK (which is used in EDGE). +-----------------+---------------------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------------------+ | . . . . . X X X | Training Sequence Code (0..7) | +-----------------+---------------------------------------+ | . X X X X . . . | Modulation, TS set number (see below) | +-----------------+---------------------------------------+ | X . . . . . . . | IDLE / nope frame indication (0 or 1) | +-----------------+---------------------------------------+ The bit number 7 (MSB) is set to high when either nothing has been detected, or during IDLE frames, so we can deliver noise levels, and avoid clock gaps on the L1 side. Other bits are ignored, and should be set to low (0) in this case. == Coding of modulation and TS set number GMSK has 4 sets of training sequences (see tables 5.2.3a-d), while 8-PSK (see tables 5.2.3f-g) and the others have 2 sets. Access and Synchronization bursts also have several synch. sequences. +-----------------+---------------------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------------------+ | . 0 0 X X . . . | GMSK, 4 TS sets (0..3) | +-----------------+---------------------------------------+ | . 0 1 0 X . . . | 8-PSK, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 0 1 1 X . . . | AQPSK, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 0 0 X . . . | 16QAM, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 0 1 X . . . | 32QAM, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 1 1 X . . . | RESERVED (0) | +-----------------+---------------------------------------+ == C/I: Carrier-to-Interference ratio The C/I value is computed from the training sequence of each burst, where we can compare the "ideal" training sequence with the actual training sequence, and then express that difference in centiBels. == Limitations - The only supported modulation types are GMSK and 8-PSK. Messages with other modulation types will be rejected. - IDLE / NOPE indications are not (yet) handled. - The logical channel handlers do not (yet) handle optional fields, such as TSC and C/I. This will be implemented in the follow-up changes. Change-Id: If61c71d20d590bf07bfd019afb33000a0b6135bd Related: OS#4006
2019-07-03 18:08:48 +00:00
#define TRX_UL_V1HDR_LEN (TRX_UL_V0HDR_LEN + 1 + 2)
/* Uplink TRXDv2 header length: TDMA TN + TRXN + MTS + RSSI + ToA256 + C/I */
#define TRX_UL_V2HDR_LEN (1 + 1 + 1 + 1 + 2 + 2)
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
2019-06-25 11:23:14 +00:00
/* Minimum Uplink TRXD header length for all PDU versions */
static const uint8_t trx_data_rx_hdr_len[] = {
TRX_UL_V0HDR_LEN, /* TRXDv0 */
TRX_UL_V1HDR_LEN, /* TRXDv1 */
TRX_UL_V2HDR_LEN, /* TRXDv2 */
};
static const uint8_t trx_data_mod_val[] = {
[TRX_MOD_T_GMSK] = 0x00, /* .00xx... */
[TRX_MOD_T_8PSK] = 0x20, /* .010x... */
[TRX_MOD_T_AQPSK] = 0x60, /* .11xx... */
};
/* Header dissector for TRXDv0 (and part of TRXDv1) */
static inline void trx_data_handle_hdr_v0_part(struct trx_ul_burst_ind *bi,
const uint8_t *buf)
{
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
2019-06-25 11:23:14 +00:00
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);
}
/* TRXD header dissector for version 0x00 */
static int trx_data_handle_hdr_v0(struct phy_instance *phy_inst,
struct trx_ul_burst_ind *bi,
const uint8_t *buf, size_t buf_len)
{
/* Parse TRXDv0 specific header part */
trx_data_handle_hdr_v0_part(bi, buf);
buf_len -= TRX_UL_V0HDR_LEN;
/* Guess modulation and burst length by the rest octets.
* NOTE: a legacy transceiver may append two garbage bytes. */
switch (buf_len) {
case EGPRS_BURST_LEN + 2:
case EGPRS_BURST_LEN:
bi->mod = TRX_MOD_T_8PSK;
break;
case GSM_BURST_LEN + 2:
case GSM_BURST_LEN:
bi->mod = TRX_MOD_T_GMSK;
break;
default:
LOGPPHI(phy_inst, DTRX, LOGL_NOTICE,
"Rx TRXD PDU with odd burst length %zu\n", buf_len);
return -EINVAL;
}
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
2019-06-25 11:23:14 +00:00
return TRX_UL_V0HDR_LEN;
}
/* Parser for MTS (Modulation and Training Sequence) */
static inline int trx_data_parse_mts(struct phy_instance *phy_inst,
struct trx_ul_burst_ind *bi,
const uint8_t mts)
{
if (mts & (1 << 7)) {
bi->flags |= TRX_BI_F_NOPE_IND;
return 0;
}
/* | 7 6 5 4 3 2 1 0 | Bitmask / description
* | . 0 0 X X . . . | GMSK, 4 TSC sets (0..3)
* | . 0 1 0 X . . . | 8-PSK, 2 TSC sets (0..1) */
if ((mts >> 5) == 0x00) {
bi->mod = TRX_MOD_T_GMSK;
bi->tsc_set = (mts >> 3) & 0x03;
} else if ((mts >> 4) == 0x02) {
bi->mod = TRX_MOD_T_8PSK;
bi->tsc_set = (mts >> 3) & 0x01;
} else {
LOGPPHI(phy_inst, DTRX, LOGL_ERROR,
"Rx TRXD PDU with unknown or not supported "
"modulation (MTS=0x%02x)\n", mts);
return -ENOTSUP;
}
/* Training Sequence Code */
bi->tsc = mts & 0x07;
bi->flags |= (TRX_BI_F_MOD_TYPE | TRX_BI_F_TS_INFO);
return 0;
}
osmo-bts-trx/trx_if.c: introduce TRXD header version 0x01 support The new version adds the following fields to the TRX2L1 message, keeping the L12TRX message unchanged: +------+-----+-----+-----+--------------------+ | RSSI | ToA | MTS | C/I | soft-bits (254..0) | +------+-----+-----+-----+--------------------+ - MTS (1 octet) - Modulation and Training Sequence info, and - C/I (2 octets) - Carrier-to-Interference ratio (big endian). == Coding of MTS: Modulation and Training Sequence info 3GPP TS 45.002 version 15.1.0 defines several modulation types, and a few sets of training sequences for each type. The most common are GMSK and 8-PSK (which is used in EDGE). +-----------------+---------------------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------------------+ | . . . . . X X X | Training Sequence Code (0..7) | +-----------------+---------------------------------------+ | . X X X X . . . | Modulation, TS set number (see below) | +-----------------+---------------------------------------+ | X . . . . . . . | IDLE / nope frame indication (0 or 1) | +-----------------+---------------------------------------+ The bit number 7 (MSB) is set to high when either nothing has been detected, or during IDLE frames, so we can deliver noise levels, and avoid clock gaps on the L1 side. Other bits are ignored, and should be set to low (0) in this case. == Coding of modulation and TS set number GMSK has 4 sets of training sequences (see tables 5.2.3a-d), while 8-PSK (see tables 5.2.3f-g) and the others have 2 sets. Access and Synchronization bursts also have several synch. sequences. +-----------------+---------------------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------------------+ | . 0 0 X X . . . | GMSK, 4 TS sets (0..3) | +-----------------+---------------------------------------+ | . 0 1 0 X . . . | 8-PSK, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 0 1 1 X . . . | AQPSK, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 0 0 X . . . | 16QAM, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 0 1 X . . . | 32QAM, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 1 1 X . . . | RESERVED (0) | +-----------------+---------------------------------------+ == C/I: Carrier-to-Interference ratio The C/I value is computed from the training sequence of each burst, where we can compare the "ideal" training sequence with the actual training sequence, and then express that difference in centiBels. == Limitations - The only supported modulation types are GMSK and 8-PSK. Messages with other modulation types will be rejected. - IDLE / NOPE indications are not (yet) handled. - The logical channel handlers do not (yet) handle optional fields, such as TSC and C/I. This will be implemented in the follow-up changes. Change-Id: If61c71d20d590bf07bfd019afb33000a0b6135bd Related: OS#4006
2019-07-03 18:08:48 +00:00
/* TRXD header dissector for version 0x01 */
static int trx_data_handle_hdr_v1(struct phy_instance *phy_inst,
osmo-bts-trx/trx_if.c: introduce TRXD header version 0x01 support The new version adds the following fields to the TRX2L1 message, keeping the L12TRX message unchanged: +------+-----+-----+-----+--------------------+ | RSSI | ToA | MTS | C/I | soft-bits (254..0) | +------+-----+-----+-----+--------------------+ - MTS (1 octet) - Modulation and Training Sequence info, and - C/I (2 octets) - Carrier-to-Interference ratio (big endian). == Coding of MTS: Modulation and Training Sequence info 3GPP TS 45.002 version 15.1.0 defines several modulation types, and a few sets of training sequences for each type. The most common are GMSK and 8-PSK (which is used in EDGE). +-----------------+---------------------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------------------+ | . . . . . X X X | Training Sequence Code (0..7) | +-----------------+---------------------------------------+ | . X X X X . . . | Modulation, TS set number (see below) | +-----------------+---------------------------------------+ | X . . . . . . . | IDLE / nope frame indication (0 or 1) | +-----------------+---------------------------------------+ The bit number 7 (MSB) is set to high when either nothing has been detected, or during IDLE frames, so we can deliver noise levels, and avoid clock gaps on the L1 side. Other bits are ignored, and should be set to low (0) in this case. == Coding of modulation and TS set number GMSK has 4 sets of training sequences (see tables 5.2.3a-d), while 8-PSK (see tables 5.2.3f-g) and the others have 2 sets. Access and Synchronization bursts also have several synch. sequences. +-----------------+---------------------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------------------+ | . 0 0 X X . . . | GMSK, 4 TS sets (0..3) | +-----------------+---------------------------------------+ | . 0 1 0 X . . . | 8-PSK, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 0 1 1 X . . . | AQPSK, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 0 0 X . . . | 16QAM, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 0 1 X . . . | 32QAM, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 1 1 X . . . | RESERVED (0) | +-----------------+---------------------------------------+ == C/I: Carrier-to-Interference ratio The C/I value is computed from the training sequence of each burst, where we can compare the "ideal" training sequence with the actual training sequence, and then express that difference in centiBels. == Limitations - The only supported modulation types are GMSK and 8-PSK. Messages with other modulation types will be rejected. - IDLE / NOPE indications are not (yet) handled. - The logical channel handlers do not (yet) handle optional fields, such as TSC and C/I. This will be implemented in the follow-up changes. Change-Id: If61c71d20d590bf07bfd019afb33000a0b6135bd Related: OS#4006
2019-07-03 18:08:48 +00:00
struct trx_ul_burst_ind *bi,
const uint8_t *buf, size_t buf_len)
{
int rc;
/* Parse TRXDv0 specific header part */
trx_data_handle_hdr_v0_part(bi, buf);
buf += TRX_UL_V0HDR_LEN;
osmo-bts-trx/trx_if.c: introduce TRXD header version 0x01 support The new version adds the following fields to the TRX2L1 message, keeping the L12TRX message unchanged: +------+-----+-----+-----+--------------------+ | RSSI | ToA | MTS | C/I | soft-bits (254..0) | +------+-----+-----+-----+--------------------+ - MTS (1 octet) - Modulation and Training Sequence info, and - C/I (2 octets) - Carrier-to-Interference ratio (big endian). == Coding of MTS: Modulation and Training Sequence info 3GPP TS 45.002 version 15.1.0 defines several modulation types, and a few sets of training sequences for each type. The most common are GMSK and 8-PSK (which is used in EDGE). +-----------------+---------------------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------------------+ | . . . . . X X X | Training Sequence Code (0..7) | +-----------------+---------------------------------------+ | . X X X X . . . | Modulation, TS set number (see below) | +-----------------+---------------------------------------+ | X . . . . . . . | IDLE / nope frame indication (0 or 1) | +-----------------+---------------------------------------+ The bit number 7 (MSB) is set to high when either nothing has been detected, or during IDLE frames, so we can deliver noise levels, and avoid clock gaps on the L1 side. Other bits are ignored, and should be set to low (0) in this case. == Coding of modulation and TS set number GMSK has 4 sets of training sequences (see tables 5.2.3a-d), while 8-PSK (see tables 5.2.3f-g) and the others have 2 sets. Access and Synchronization bursts also have several synch. sequences. +-----------------+---------------------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------------------+ | . 0 0 X X . . . | GMSK, 4 TS sets (0..3) | +-----------------+---------------------------------------+ | . 0 1 0 X . . . | 8-PSK, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 0 1 1 X . . . | AQPSK, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 0 0 X . . . | 16QAM, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 0 1 X . . . | 32QAM, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 1 1 X . . . | RESERVED (0) | +-----------------+---------------------------------------+ == C/I: Carrier-to-Interference ratio The C/I value is computed from the training sequence of each burst, where we can compare the "ideal" training sequence with the actual training sequence, and then express that difference in centiBels. == Limitations - The only supported modulation types are GMSK and 8-PSK. Messages with other modulation types will be rejected. - IDLE / NOPE indications are not (yet) handled. - The logical channel handlers do not (yet) handle optional fields, such as TSC and C/I. This will be implemented in the follow-up changes. Change-Id: If61c71d20d590bf07bfd019afb33000a0b6135bd Related: OS#4006
2019-07-03 18:08:48 +00:00
/* MTS (Modulation and Training Sequence) */
rc = trx_data_parse_mts(phy_inst, bi, buf[0]);
if (rc < 0)
return rc;
osmo-bts-trx/trx_if.c: introduce TRXD header version 0x01 support The new version adds the following fields to the TRX2L1 message, keeping the L12TRX message unchanged: +------+-----+-----+-----+--------------------+ | RSSI | ToA | MTS | C/I | soft-bits (254..0) | +------+-----+-----+-----+--------------------+ - MTS (1 octet) - Modulation and Training Sequence info, and - C/I (2 octets) - Carrier-to-Interference ratio (big endian). == Coding of MTS: Modulation and Training Sequence info 3GPP TS 45.002 version 15.1.0 defines several modulation types, and a few sets of training sequences for each type. The most common are GMSK and 8-PSK (which is used in EDGE). +-----------------+---------------------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------------------+ | . . . . . X X X | Training Sequence Code (0..7) | +-----------------+---------------------------------------+ | . X X X X . . . | Modulation, TS set number (see below) | +-----------------+---------------------------------------+ | X . . . . . . . | IDLE / nope frame indication (0 or 1) | +-----------------+---------------------------------------+ The bit number 7 (MSB) is set to high when either nothing has been detected, or during IDLE frames, so we can deliver noise levels, and avoid clock gaps on the L1 side. Other bits are ignored, and should be set to low (0) in this case. == Coding of modulation and TS set number GMSK has 4 sets of training sequences (see tables 5.2.3a-d), while 8-PSK (see tables 5.2.3f-g) and the others have 2 sets. Access and Synchronization bursts also have several synch. sequences. +-----------------+---------------------------------------+ | 7 6 5 4 3 2 1 0 | bit numbers (value range) | +-----------------+---------------------------------------+ | . 0 0 X X . . . | GMSK, 4 TS sets (0..3) | +-----------------+---------------------------------------+ | . 0 1 0 X . . . | 8-PSK, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 0 1 1 X . . . | AQPSK, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 0 0 X . . . | 16QAM, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 0 1 X . . . | 32QAM, 2 TS sets (0..1) | +-----------------+---------------------------------------+ | . 1 1 1 X . . . | RESERVED (0) | +-----------------+---------------------------------------+ == C/I: Carrier-to-Interference ratio The C/I value is computed from the training sequence of each burst, where we can compare the "ideal" training sequence with the actual training sequence, and then express that difference in centiBels. == Limitations - The only supported modulation types are GMSK and 8-PSK. Messages with other modulation types will be rejected. - IDLE / NOPE indications are not (yet) handled. - The logical channel handlers do not (yet) handle optional fields, such as TSC and C/I. This will be implemented in the follow-up changes. Change-Id: If61c71d20d590bf07bfd019afb33000a0b6135bd Related: OS#4006
2019-07-03 18:08:48 +00:00
/* C/I: Carrier-to-Interference ratio (in centiBels) */
bi->ci_cb = (int16_t) osmo_load16be(buf + 1);
bi->flags |= TRX_BI_F_CI_CB;
return TRX_UL_V1HDR_LEN;
}
/* TRXD header dissector for version 0x01 */
static int trx_data_handle_pdu_v2(struct phy_instance *phy_inst,
struct trx_ul_burst_ind *bi,
const uint8_t *buf, size_t buf_len)
{
int rc;
/* TDMA timeslot number (other bits are RFU) */
bi->tn = buf[0] & 0x07;
if (buf[1] & (1 << 7)) /* BATCH.ind */
bi->flags |= TRX_BI_F_BATCH_IND;
if (buf[1] & (1 << 6)) /* VAMOS.ind */
bi->flags |= TRX_BI_F_SHADOW_IND;
/* TRX (RF channel) number */
bi->trx_num = buf[1] & 0x3f;
bi->flags |= TRX_BI_F_TRX_NUM;
/* MTS (Modulation and Training Sequence) */
rc = trx_data_parse_mts(phy_inst, bi, buf[2]);
if (rc < 0)
return rc;
bi->rssi = -(int8_t)buf[3];
bi->toa256 = (int16_t) osmo_load16be(&buf[4]);
bi->ci_cb = (int16_t) osmo_load16be(&buf[6]);
bi->flags |= TRX_BI_F_CI_CB;
/* TDMA frame number is absent in batched PDUs */
if (bi->_num_pdus == 0) {
if (buf_len < sizeof(bi->fn) + TRX_UL_V2HDR_LEN) {
LOGPPHI(phy_inst, DTRX, LOGL_ERROR,
"Rx malformed TRXDv2 PDU: not enough bytes "
"to parse TDMA frame number\n");
return -EINVAL;
}
bi->fn = osmo_load32be(buf + TRX_UL_V2HDR_LEN);
return TRX_UL_V2HDR_LEN + sizeof(bi->fn);
}
return TRX_UL_V2HDR_LEN;
}
/* TRXD burst handler (version independent) */
static int trx_data_handle_burst(struct trx_ul_burst_ind *bi,
const uint8_t *buf, size_t buf_len)
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
2019-06-25 11:23:14 +00:00
{
size_t i;
/* NOPE.ind contains no burst */
if (bi->flags & TRX_BI_F_NOPE_IND) {
bi->burst_len = 0;
return 0;
}
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
2019-06-25 11:23:14 +00:00
/* Modulation types defined in 3GPP TS 45.002 */
static const size_t bl[] = {
[TRX_MOD_T_GMSK] = 148, /* 1 bit per symbol */
[TRX_MOD_T_8PSK] = 444, /* 3 bits per symbol */
};
bi->burst_len = bl[bi->mod];
if (buf_len < bi->burst_len)
return -EINVAL;
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
2019-06-25 11:23:14 +00:00
/* 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
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
2019-06-25 11:23:14 +00:00
bi->burst[i] = 127 - buf[i];
}
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
2019-06-25 11:23:14 +00:00
return 0;
}
static const char *trx_data_desc_msg(const struct trx_ul_burst_ind *bi)
{
struct osmo_strbuf sb;
static char buf[256];
/* Modulation types defined in 3GPP TS 45.002 */
static const char *mod_names[] = {
[TRX_MOD_T_GMSK] = "GMSK",
[TRX_MOD_T_8PSK] = "8-PSK",
};
/* Initialize the string buffer */
sb = (struct osmo_strbuf) { .buf = buf, .len = sizeof(buf) };
/* Common TDMA parameters */
OSMO_STRBUF_PRINTF(sb, "tn=%u fn=%u", bi->tn, bi->fn);
/* TRX (RF channel number) */
if (bi->flags & TRX_BI_F_TRX_NUM)
OSMO_STRBUF_PRINTF(sb, " trx_num=%u", bi->trx_num);
/* RSSI and ToA256 */
OSMO_STRBUF_PRINTF(sb, " rssi=%d toa256=%d", bi->rssi, bi->toa256);
/* C/I: Carrier-to-Interference ratio (in centiBels) */
if (bi->flags & TRX_BI_F_CI_CB)
OSMO_STRBUF_PRINTF(sb, " C/I=%d cB", bi->ci_cb);
/* Nothing else to print for NOPE.ind */
if (bi->flags & TRX_BI_F_NOPE_IND)
return buf;
/* Modulation and TSC set */
if (bi->flags & TRX_BI_F_MOD_TYPE)
OSMO_STRBUF_PRINTF(sb, " mod=%s", mod_names[bi->mod]);
/* Training Sequence Code */
if (bi->flags & TRX_BI_F_TS_INFO)
OSMO_STRBUF_PRINTF(sb, " set=%u tsc=%u", bi->tsc_set, bi->tsc);
/* Burst length */
OSMO_STRBUF_PRINTF(sb, " burst_len=%zu", bi->burst_len);
return buf;
}
/* TRXD buffer used by Rx/Tx handlers */
static uint8_t trx_data_buf[TRXD_MSG_BUF_SIZE];
/* Parse TRXD message from transceiver, compose an UL burst indication. */
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
2019-06-25 11:23:14 +00:00
static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
{
const uint8_t *buf = &trx_data_buf[0];
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
2019-06-25 11:23:14 +00:00
struct trx_l1h *l1h = ofd->data;
struct trx_ul_burst_ind bi;
ssize_t hdr_len, buf_len;
uint8_t pdu_ver;
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
2019-06-25 11:23:14 +00:00
buf_len = recv(ofd->fd, trx_data_buf, sizeof(trx_data_buf), 0);
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
2019-06-25 11:23:14 +00:00
if (buf_len <= 0) {
strerror_r(errno, (char *) trx_data_buf, sizeof(trx_data_buf));
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
2019-06-25 11:23:14 +00:00
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"recv() failed on TRXD with rc=%zd (%s)\n",
buf_len, trx_data_buf);
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
2019-06-25 11:23:14 +00:00
return buf_len;
}
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
2019-06-25 11:23:14 +00:00
/* Parse PDU version first */
pdu_ver = buf[0] >> 4;
/* Make sure that PDU version matches our expectations */
if (pdu_ver != l1h->config.trxd_pdu_ver_use) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"Rx TRXD PDU with unexpected version %u (expected %u)\n",
pdu_ver, l1h->config.trxd_pdu_ver_use);
return -EIO;
}
/* We're about to parse the first PDU */
bi._num_pdus = 0;
/* Starting from TRXDv2, there can be batched PDUs */
do {
/* (Re)initialize the flags */
bi.flags = 0x00;
/* Make sure that we have enough bytes to parse the header */
if (buf_len < trx_data_rx_hdr_len[pdu_ver]) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"Rx malformed TRXDv%u PDU: len=%zd < expected %u\n",
pdu_ver, buf_len, trx_data_rx_hdr_len[pdu_ver]);
return -EINVAL;
}
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
2019-06-25 11:23:14 +00:00
/* Parse header depending on the PDU version */
switch (pdu_ver) {
case 0: /* TRXDv0 */
hdr_len = trx_data_handle_hdr_v0(l1h->phy_inst, &bi, buf, buf_len);
break;
case 1: /* TRXDv1 */
hdr_len = trx_data_handle_hdr_v1(l1h->phy_inst, &bi, buf, buf_len);
break;
case 2: /* TRXDv2 */
hdr_len = trx_data_handle_pdu_v2(l1h->phy_inst, &bi, buf, buf_len);
break;
default:
/* Shall not happen */
OSMO_ASSERT(0);
}
/* Header parsing error */
if (hdr_len < 0)
return hdr_len;
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
2019-06-25 11:23:14 +00:00
if (bi.fn >= GSM_TDMA_HYPERFRAME) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"Rx malformed TRXDv%u PDU: illegal TDMA fn=%u\n",
pdu_ver, bi.fn);
return -EINVAL;
}
/* We're done with the header now */
buf_len -= hdr_len;
buf += hdr_len;
/* Calculate burst length and parse it (if present) */
if (trx_data_handle_burst(&bi, buf, buf_len) != 0) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"Rx malformed TRXDv%u PDU: odd burst length=%zd\n",
pdu_ver, buf_len);
return -EINVAL;
}
/* We're done with the burst bits now */
buf_len -= bi.burst_len;
buf += bi.burst_len;
/* Print header & burst info */
LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG, "Rx %s (pdu_ver=%u): %s\n",
(bi.flags & TRX_BI_F_NOPE_IND) ? "NOPE.ind" : "UL burst",
pdu_ver, trx_data_desc_msg(&bi));
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
2019-06-25 11:23:14 +00:00
/* Number of processed PDUs */
bi._num_pdus++;
/* feed received burst into scheduler code */
TRACE(OSMO_BTS_TRX_UL_DATA_START(l1h->phy_inst->trx->nr, bi.tn, bi.fn));
[VAMOS] Re-organize osmo-bts-trx specific structures Together with the 'generic' structures which used to be shared between osmo-bsc and osmo-bts some time ago, we also have the following osmo-bts-trx specific structures (in hierarchical order): - struct l1sched_trx (struct gsm_bts_trx), - struct l1sched_ts (struct gsm_bts_trx_ts), - struct l1sched_chan_state (struct gsm_lchan). These structures are not integrated into the tree of the generic structures, but maintained in a _separate tree_ instead. Until recently, only the 'l1sched_trx' had a pointer to generic 'gsm_bts_trx', so in order to find the corresponding 'gsm_lchan' for 'l1sched_chan_state' one would need to traverse all the way up to 'l1sched_trx' and then tracerse another three backwards. + gsm_network | --+ gsm_bts (0..255) | --+ l1sched_trx --------------------> gsm_bts_trx (0..255) | | --+ l1sched_trx_ts --+ gsm_bts_trx_ts (8) | | --+ l1sched_chan_state --+ gsm_lchan (up to 8) I find this architecture a bit over-complicated, especially given that 'l1sched_trx' is kind of a dummy node containing nothing else than a pointer to 'gsm_bts_trx' and the list of 'l1sched_trx_ts'. In this path I slightly change the architecture as follows: + gsm_network | --+ gsm_bts (0..255) | --+ gsm_bts_trx (0..255) | --+ l1sched_trx_ts <----------------> gsm_bts_trx_ts (8) | | --+ l1sched_chan_state --+ gsm_lchan (up to 8) Note that unfortunately we cannot 1:1 map 'l1sched_chan_state' to 'gsm_lchan' (like we do for 'l1sched_trx_ts' and 'gsm_bts_trx_ts') because there is no direct mapping. The former is a higl-level representation of a logical channel, while the later represents one specific logical channel type like FCCH, SDCCH/0 or SACCH/0. osmo-bts-virtual re-uses the osmo-bts-trx hierarchy, so it's also affected by this change. Change-Id: I7c4379e43a25e9d858d582a99bf6c4b65c9af481
2021-05-07 13:47:57 +00:00
trx_sched_route_burst_ind(l1h->phy_inst->trx, &bi);
TRACE(OSMO_BTS_TRX_UL_DATA_DONE(l1h->phy_inst->trx->nr, bi.tn, bi.fn));
} while (bi.flags & TRX_BI_F_BATCH_IND);
return 0;
}
/*! Send burst data for given FN/timeslot to TRX
* \param[inout] l1h TRX Layer1 handle referring to TX
* \param[in] br Downlink burst request structure
* \returns 0 on success; negative on error */
int trx_if_send_burst(struct trx_l1h *l1h, const struct trx_dl_burst_req *br)
{
uint8_t pdu_ver = l1h->config.trxd_pdu_ver_use;
static uint8_t *buf = &trx_data_buf[0];
static uint8_t *last_pdu = NULL;
static unsigned int pdu_num = 0;
ssize_t snd_len, buf_len;
/* Make sure that the PHY is powered on */
if (!trx_if_powered(l1h)) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"Ignoring Tx data, transceiver is powered off\n");
return -ENODEV;
}
/* Burst batching breaker */
if (br == NULL) {
if (pdu_num > 0)
goto sendall;
return -ENOMSG;
}
/* Pointer to the last encoded PDU */
last_pdu = &buf[0];
switch (pdu_ver) {
/* Both versions have the same PDU format */
case 0: /* TRXDv0 */
case 1: /* TRXDv1 */
buf[0] = ((pdu_ver & 0x0f) << 4) | br->tn;
osmo_store32be(br->fn, buf + 1);
buf[5] = br->att;
buf += 6;
break;
case 2: /* TRXDv2 */
buf[0] = br->tn;
/* BATCH.ind will be unset in the last PDU */
buf[1] = (br->trx_num & 0x3f) | (1 << 7);
buf[2] = trx_data_mod_val[br->mod]
| (br->tsc_set << 3)
| (br->tsc & 0x07);
buf[3] = br->att;
buf[4] = (uint8_t) br->scpir;
buf[5] = buf[6] = buf[7] = 0x00; /* Spare */
/* Some fields are not present in batched PDUs */
if (pdu_num == 0) {
buf[0] |= (pdu_ver & 0x0f) << 4;
osmo_store32be(br->fn, buf + 8);
buf += 4;
}
buf += 8;
break;
default:
/* Shall not happen */
OSMO_ASSERT(0);
}
/* copy ubits {0,1} */
memcpy(buf, br->burst, br->burst_len);
buf += br->burst_len;
/* One more PDU in the buffer */
pdu_num++;
/* TRXDv2: wait for the batching breaker */
if (pdu_ver >= 2)
return 0;
sendall:
LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
"Tx TRXDv%u datagram with %u PDU(s)\n",
pdu_ver, pdu_num);
/* TRXDv2: unset BATCH.ind in the last PDU */
if (pdu_ver >= 2)
last_pdu[1] &= ~(1 << 7);
buf_len = buf - &trx_data_buf[0];
buf = &trx_data_buf[0];
pdu_num = 0;
snd_len = send(l1h->trx_ofd_data.fd, trx_data_buf, buf_len, 0);
if (snd_len <= 0) {
strerror_r(errno, (char *) trx_data_buf, sizeof(trx_data_buf));
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"send() failed on TRXD with rc=%zd (%s)\n",
snd_len, trx_data_buf);
return -2;
}
return 0;
}
/*
* open/close
*/
/*! flush (delete) all pending control messages */
void trx_if_flush(struct trx_l1h *l1h)
{
struct trx_ctrl_msg *tcm;
/* free ctrl message list */
while (!llist_empty(&l1h->trx_ctrl_list)) {
tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg,
list);
llist_del(&tcm->list);
talloc_free(tcm);
}
bts-trx: Detect duplicated responses for retransmitted commands It was detected that under some conditions, osmo-trx (with limesdr) may take a long time to answer to CMDs, which means trx_ctrl_timer will trigger re-transmitting the last sent but yet unacked CMD. Due to the high latency in osmo-trx, the original AND the rentrasnmited CMD are handled after a while and RSP messages are sent for both. When osmo-bts-trx receives the first RSP, it was marking the CMD as acked and carried on with next one. Then, when the RSP from the retransmited CMD arrives, it already lost state and doesn't know where does that come from. As a result, osmo-bts-trx shutdowns. The issue can be seen in the following truncated log from osmo-bts-trx with TRX category enabled: 20180117135228175 Enqueuing TRX control command 'CMD RXTUNE 1782000' 20180117135228175 Enqueuing TRX control command 'CMD TXTUNE 1877000' 20180117135228175 Enqueuing TRX control command 'CMD SETTSC 7' 20180117135228175 Enqueuing TRX control command 'CMD POWERON' 20180117135228175 Enqueuing TRX control command 'CMD SETRXGAIN 1' 20180117135228175 Enqueuing TRX control command 'CMD SETPOWER 20' 20180117135228175 Enqueuing TRX control command 'CMD SETSLOT 0 5' ... 20180117135249829 Response message: 'RSP POWEROFF 0' 20180117135249855 Response message: 'RSP RXTUNE 0 1782000' 20180117135249876 Response message: 'RSP TXTUNE 0 1877000' 20180117135249876 Response message: 'RSP SETTSC 0 7' 20180117135250648 Response message: 'RSP POWERON 0' 20180117135251150 Response message: 'RSP SETRXGAIN 0 0' 20180117135253151 No response from transceiver for phy0.0 (CMD SETPOWER 20) 20180117135253777 Response message: 'RSP SETPOWER 0 20' 20180117135254535 Clock indication: fn=2018878 20180117135255777 No response from transceiver for phy0.0 (CMD SETSLOT 0 5) ... 20180117135256858 Response message: 'RSP SETPOWER 0 20' 20180117135256858 Discarding duplicated RSP from old CMD 'RSP SETPOWER 0 20' 20180117135256858 Response message: 'RSP SETSLOT 0 0 5' 20180117135256858 Response message: 'RSP SETSLOT 0 0 5' 20180117135256858 Discarding duplicated RSP from old CMD 'RSP SETSLOT 0 0 5' Change-Id: I3633cba212edde878f83ed36aef922aaca6f503a
2018-01-17 12:45:40 +00:00
talloc_free(l1h->last_acked);
l1h->last_acked = NULL;
/* Tx queue is now empty, so there's no point in keeping the retrans timer armed: */
if (osmo_timer_pending(&l1h->trx_ctrl_timer))
osmo_timer_del(&l1h->trx_ctrl_timer);
}
/*! close the TRX for given handle (data + control socket) */
void trx_if_close(struct trx_l1h *l1h)
{
LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE, "Closing TRXC/TRXD connections\n");
trx_if_flush(l1h);
/* close sockets */
trx_udp_close(&l1h->trx_ofd_ctrl);
trx_udp_close(&l1h->trx_ofd_data);
}
/*! compute UDP port number used for TRX protocol */
static uint16_t compute_port(struct phy_instance *pinst, int remote, int is_data)
{
struct phy_link *plink = pinst->phy_link;
uint16_t inc = 1;
if (is_data)
inc = 2;
if (remote)
return plink->u.osmotrx.base_port_remote + (pinst->num << 1) + inc;
else
return plink->u.osmotrx.base_port_local + (pinst->num << 1) + inc;
}
/*! open a TRX interface. creates control + data sockets */
static int trx_if_open(struct trx_l1h *l1h)
{
struct phy_instance *pinst = l1h->phy_inst;
struct phy_link *plink = pinst->phy_link;
int rc;
LOGPPHI(pinst, DTRX, LOGL_NOTICE, "Opening TRXC/TRXD connections\n");
/* open sockets */
rc = trx_udp_open(l1h, &l1h->trx_ofd_ctrl,
plink->u.osmotrx.local_ip,
compute_port(pinst, 0, 0),
plink->u.osmotrx.remote_ip,
compute_port(pinst, 1, 0), trx_ctrl_read_cb);
if (rc < 0)
return rc;
rc = trx_udp_open(l1h, &l1h->trx_ofd_data,
plink->u.osmotrx.local_ip,
compute_port(pinst, 0, 1),
plink->u.osmotrx.remote_ip,
compute_port(pinst, 1, 1), trx_data_read_cb);
if (rc < 0)
return rc;
return 0;
}
/*! close the control + burst data sockets for one phy_instance */
static void trx_phy_inst_close(struct phy_instance *pinst)
{
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
trx_if_close(l1h);
if (pinst->trx)
trx_sched_clean(pinst->trx);
}
/*! open the control + burst data sockets for one phy_instance */
static int trx_phy_inst_open(struct phy_instance *pinst)
{
struct trx_l1h *l1h;
int rc;
l1h = pinst->u.osmotrx.hdl;
if (!l1h)
return -EINVAL;
/* PHY instance may be not associated with a TRX instance */
if (pinst->trx != NULL)
trx_sched_init(pinst->trx);
rc = trx_if_open(l1h);
if (rc < 0) {
LOGPPHI(l1h->phy_inst, DL1C, LOGL_FATAL, "Cannot open TRX interface\n");
trx_phy_inst_close(pinst);
return -EIO;
}
return 0;
}
/*! open the PHY link using TRX protocol */
int bts_model_phy_link_open(struct phy_link *plink)
{
struct phy_instance *pinst;
int rc;
phy_link_state_set(plink, PHY_LINK_CONNECTING);
/* open the shared/common clock socket */
rc = trx_udp_open(plink, &plink->u.osmotrx.trx_ofd_clk,
plink->u.osmotrx.local_ip,
plink->u.osmotrx.base_port_local,
plink->u.osmotrx.remote_ip,
plink->u.osmotrx.base_port_remote,
trx_clk_read_cb);
if (rc < 0) {
phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
return -1;
}
/* open the individual instances with their ctrl+data sockets */
llist_for_each_entry(pinst, &plink->instances, list) {
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
if (trx_phy_inst_open(pinst) < 0)
goto cleanup;
osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_OPEN, NULL);
}
bts-trx: Get rid of messy transceiver_available state handler This variable meaning has been changing its exact meaning over time until finally not being really clear which kind of state it holds. Initially it seemed to be used to identfy whether CLOCK IND were being received. However, over time both osmo-bts and osmo-trx have evolved and were fixed so that clock indications are only sent by osmo-trx after POWERON command is sent. As a result, this state can be checked simply by looking at the "powered" phy_link variable, which is only set to true once the TRX has confirmed the POWERON command, and hence it is sending CLOCK IND. On the other hand, at some point in time "available" started to be set to 1 in bts_model_phy_link_open(), which means available is nowadays almost always 1 from startup until the end (only dropped during bts_shutdown(), when we are already exiting the process anyway). As a result, !available condition in scheduler_trx.c:trx_fn_timer_cb can almost never happen, because available is set to true already. Only possibility would be if an old process of osmo-trx (not set up by this BTS process) is still sending CLOCK INDs, but in that case we for sure don't want to configure the BTS based on that, but ignore them until this BTS process has again configured the TRX. So that whole check can be dropped. We are better checking for "powered" state, which is far more accurate, and we better do that in trx_if.c before calling trx_fn_timer_cb(). Other uses of "transceiver_available" being used can be changed to use plink->state!= PHY_LINK_SHUTDOWN, since available was already being set to 1 at the same time the plink->state was being set to PHY_LINK_CONNECTING. As a result of this state handling re-arrangement, OS#4215 is fixed since trx_if_powered() is used instead of previous state condition to check whether data frames should be sent. Related: OS#4215 Change-Id: I35f4697bd33dbe8a4c76c9500b82c16589c701d4
2019-09-27 15:21:31 +00:00
return 0;
cleanup:
phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
llist_for_each_entry(pinst, &plink->instances, list) {
if (pinst->u.osmotrx.hdl) {
trx_if_close(pinst->u.osmotrx.hdl);
pinst->u.osmotrx.hdl = NULL;
}
}
trx_udp_close(&plink->u.osmotrx.trx_ofd_clk);
return -1;
}
/*! close the PHY link using TRX protocol */
int bts_model_phy_link_close(struct phy_link *plink)
{
bool clock_stopped = false;
struct phy_instance *pinst;
llist_for_each_entry(pinst, &plink->instances, list) {
if (!clock_stopped) {
clock_stopped = true;
trx_sched_clock_stopped(pinst->trx->bts);
}
trx_phy_inst_close(pinst);
}
trx_udp_close(&plink->u.osmotrx.trx_ofd_clk);
phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
return 0;
}
/*! determine if the TRX for given handle is powered up */
int trx_if_powered(struct trx_l1h *l1h)
{
struct phy_instance *pinst = l1h->phy_inst;
struct phy_link *plink = pinst->phy_link;
return plink->u.osmotrx.powered;
}