aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2023-06-28 19:56:39 +0200
committerHarald Welte <laforge@osmocom.org>2023-06-28 21:43:58 +0200
commitdfffd5c17ffc6b4affbebe38941cadd306a5c311 (patch)
tree66750a48259e6edc5de3ce6d3b7135fe93ff6f50
parent4c3b4e2868dba83f1450b2bf9d0e48b93a0e2d6f (diff)
osmo-bts-trx: add ability to send raw burst data via GSMTAPlaforge/gsmtap-burst
-rw-r--r--include/osmo-bts/phy_link.h5
-rw-r--r--src/osmo-bts-trx/sched_lchan_tchf.c6
-rw-r--r--src/osmo-bts-trx/sched_lchan_tchh.c5
-rw-r--r--src/osmo-bts-trx/sched_lchan_xcch.c15
-rw-r--r--src/osmo-bts-trx/trx_if.c34
-rw-r--r--src/osmo-bts-trx/trx_if.h7
-rw-r--r--src/osmo-bts-trx/trx_vty.c51
7 files changed, 121 insertions, 2 deletions
diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h
index 862ed48f..82a32629 100644
--- a/include/osmo-bts/phy_link.h
+++ b/include/osmo-bts/phy_link.h
@@ -52,6 +52,11 @@ struct phy_link {
bool powered; /* last POWERON (true) or POWEROFF (false) confirmed */
bool poweron_sent; /* is there a POWERON in transit? */
bool poweroff_sent; /* is there a POWEROFF in transit? */
+ struct {
+ char *remote_host;
+ bool all;
+ struct gsmtap_inst *gti;
+ } gsmtap_burst;
} osmotrx;
struct {
char *mcast_dev; /* Network device for multicast */
diff --git a/src/osmo-bts-trx/sched_lchan_tchf.c b/src/osmo-bts-trx/sched_lchan_tchf.c
index 9acbf31c..bf011eac 100644
--- a/src/osmo-bts-trx/sched_lchan_tchf.c
+++ b/src/osmo-bts-trx/sched_lchan_tchf.c
@@ -42,9 +42,11 @@
#include <osmo-bts/scheduler.h>
#include <osmo-bts/scheduler_backend.h>
#include <osmo-bts/msg_utils.h>
+#include <osmo-bts/phy_link.h>
#include <sched_utils.h>
#include <amr_loop.h>
+#include <trx_if.h>
/* 3GPP TS 45.009, table 3.2.1.3-{1,3}: AMR on Uplink TCH/F.
*
@@ -74,6 +76,7 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
{
struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
struct gsm_lchan *lchan = chan_state->lchan;
+ struct phy_link *plink = lchan->ts->trx->pinst->phy_link;
sbit_t *burst, *bursts_p = chan_state->ul_bursts;
uint8_t *mask = &chan_state->ul_mask;
uint8_t rsl_cmode = chan_state->rsl_cmode;
@@ -267,6 +270,9 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
* Doing so tells l1sap.c to ignore the measurement result. */
meas_avg.rssi = 0;
rc = 0;
+
+ if (bfi_flag || OSMO_UNLIKELY(plink->u.osmotrx.gsmtap_burst.all))
+ gsmtap_bursts_tx(plink, bi->fn, lchan, bursts_p, 464, n_errors, n_bits_total, &meas_avg);
}
if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
diff --git a/src/osmo-bts-trx/sched_lchan_tchh.c b/src/osmo-bts-trx/sched_lchan_tchh.c
index 8d1aab39..ec8bdbc9 100644
--- a/src/osmo-bts-trx/sched_lchan_tchh.c
+++ b/src/osmo-bts-trx/sched_lchan_tchh.c
@@ -42,9 +42,11 @@
#include <osmo-bts/scheduler.h>
#include <osmo-bts/scheduler_backend.h>
#include <osmo-bts/msg_utils.h>
+#include <osmo-bts/phy_link.h>
#include <sched_utils.h>
#include <amr_loop.h>
+#include <trx_if.h>
/* 3GPP TS 45.009, table 3.2.1.3-{2,4}: AMR on Uplink TCH/H.
*
@@ -96,6 +98,7 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
{
struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
struct gsm_lchan *lchan = chan_state->lchan;
+ struct phy_link *plink = lchan->ts->trx->pinst->phy_link;
sbit_t *burst, *bursts_p = chan_state->ul_bursts;
uint8_t *mask = &chan_state->ul_mask;
uint8_t rsl_cmode = chan_state->rsl_cmode;
@@ -301,6 +304,8 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
PRES_INFO_UNKNOWN);
ber10k = 0;
bfi:
+ if (bfi_flag || OSMO_UNLIKELY(plink->u.osmotrx.gsmtap_burst.all))
+ gsmtap_bursts_tx(plink, bi->fn, lchan, bursts_p, 464, n_errors, n_bits_total, &meas_avg);
/* A FACCH/H frame replaces two speech frames, so we need to send two BFIs.
* One is sent here, another will be sent two bursts later (see above). */
rc = 0;
diff --git a/src/osmo-bts-trx/sched_lchan_xcch.c b/src/osmo-bts-trx/sched_lchan_xcch.c
index 0fccf3ec..59002666 100644
--- a/src/osmo-bts-trx/sched_lchan_xcch.c
+++ b/src/osmo-bts-trx/sched_lchan_xcch.c
@@ -32,8 +32,10 @@
#include <osmo-bts/logging.h>
#include <osmo-bts/scheduler.h>
#include <osmo-bts/scheduler_backend.h>
+#include <osmo-bts/phy_link.h>
#include <sched_utils.h>
+#include <trx_if.h>
/* Add two arrays of sbits */
static void add_sbits(sbit_t * current, const sbit_t * previous)
@@ -61,6 +63,7 @@ int rx_data_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
int rc;
struct gsm_lchan *lchan = chan_state->lchan;
bool rep_sacch = L1SAP_IS_LINK_SACCH(trx_chan_desc[bi->chan].link_id) && lchan->rep_acch.ul_sacch_active;
+ struct phy_link *plink = lchan->ts->trx->pinst->phy_link;
/* If handover RACH detection is turned on, treat this burst as an Access Burst.
* Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */
@@ -128,15 +131,23 @@ int rx_data_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
"Combining current SACCH block with previous SACCH block also yields bad data (%u/%u)\n",
bi->fn % l1ts->mf_period, l1ts->mf_period);
+
+ gsmtap_bursts_tx(plink, bi->fn, lchan, bursts_p, 464, n_errors, n_bits_total, &meas_avg);
} else {
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
"Combining current SACCH block with previous SACCH block yields good data (%u/%u)\n",
bi->fn % l1ts->mf_period, l1ts->mf_period);
l2_len = GSM_MACBLOCK_LEN;
+ if (OSMO_UNLIKELY(plink->u.osmotrx.gsmtap_burst.all))
+ gsmtap_bursts_tx(plink, bi->fn, lchan, bursts_p, 464, n_errors, n_bits_total, &meas_avg);
}
- }
- } else
+ } else
+ gsmtap_bursts_tx(plink, bi->fn, lchan, bursts_p, 464, n_errors, n_bits_total, &meas_avg);
+ } else {
l2_len = GSM_MACBLOCK_LEN;
+ if (OSMO_UNLIKELY(plink->u.osmotrx.gsmtap_burst.all))
+ gsmtap_bursts_tx(plink, bi->fn, lchan, bursts_p, 464, n_errors, n_bits_total, &meas_avg);
+ }
ber10k = compute_ber10k(n_bits_total, n_errors);
diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c
index fef8c22f..0a660d80 100644
--- a/src/osmo-bts-trx/trx_if.c
+++ b/src/osmo-bts-trx/trx_if.c
@@ -41,6 +41,8 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/fsm.h>
+#include <osmocom/core/gsmtap.h>
+#include <osmocom/core/gsmtap_util.h>
#include <osmo-bts/phy_link.h>
#include <osmo-bts/logging.h>
@@ -1339,6 +1341,14 @@ int bts_model_phy_link_open(struct phy_link *plink)
return -1;
}
+ if (plink->u.osmotrx.gsmtap_burst.remote_host) {
+ LOGPPHL(plink, DL1C, LOGL_NOTICE, "Opening burst-gsmtap to remote host %s\n",
+ plink->u.osmotrx.gsmtap_burst.remote_host);
+ plink->u.osmotrx.gsmtap_burst.gti = gsmtap_source_init2(NULL, 0,
+ plink->u.osmotrx.gsmtap_burst.remote_host,
+ GSMTAP_UDP_PORT, 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;
@@ -1375,6 +1385,11 @@ int bts_model_phy_link_close(struct phy_link *plink)
}
trx_udp_close(&plink->u.osmotrx.trx_ofd_clk);
phy_link_state_set(plink, PHY_LINK_SHUTDOWN);
+
+ if (plink->u.osmotrx.gsmtap_burst.gti) {
+ gsmtap_source_free(plink->u.osmotrx.gsmtap_burst.gti);
+ plink->u.osmotrx.gsmtap_burst.gti = NULL;
+ }
return 0;
}
@@ -1385,3 +1400,22 @@ int trx_if_powered(struct trx_l1h *l1h)
struct phy_link *plink = pinst->phy_link;
return plink->u.osmotrx.powered;
}
+
+void gsmtap_bursts_tx(const struct phy_link *plink, uint32_t fn, const struct gsm_lchan *lchan,
+ const sbit_t *sbits, size_t n_sbits, int n_errors, int n_bits_total,
+ const struct l1sched_meas_set *meas_avg)
+{
+ struct msgb *msg;
+ int rc;
+
+ if (!plink->u.osmotrx.gsmtap_burst.gti)
+ return;
+
+ msg = gsmtap_makemsg_ex(GSMTAP_TYPE_UM_BURST, lchan->ts->trx->arfcn | GSMTAP_ARFCN_F_UPLINK, lchan->ts->nr,
+ GSMTAP_BURST_NORMAL, lchan->nr, fn, meas_avg->rssi, 0/*snr*/, (const uint8_t *) sbits, n_sbits);
+ if (msg) {
+ rc = gsmtap_sendmsg(plink->u.osmotrx.gsmtap_burst.gti, msg);
+ if (rc < 0)
+ msgb_free(msg);
+ }
+}
diff --git a/src/osmo-bts-trx/trx_if.h b/src/osmo-bts-trx/trx_if.h
index b838b76a..738e7499 100644
--- a/src/osmo-bts-trx/trx_if.h
+++ b/src/osmo-bts-trx/trx_if.h
@@ -48,3 +48,10 @@ int trx_if_powered(struct trx_l1h *l1h);
/* Format negotiation command */
int trx_if_cmd_setformat(struct trx_l1h *l1h, uint8_t ver, trx_if_cmd_generic_cb *cb);
+
+struct l1sched_meas_avg;
+struct phy_link;
+
+void gsmtap_bursts_tx(const struct phy_link *plink, uint32_t fn, const struct gsm_lchan *lchan,
+ const sbit_t *sbits, size_t n_sbits, int n_errors, int n_bits_total,
+ const struct l1sched_meas_set *meas_avg);
diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c
index 9cc98052..acf88921 100644
--- a/src/osmo-bts-trx/trx_vty.c
+++ b/src/osmo-bts-trx/trx_vty.c
@@ -504,6 +504,48 @@ DEFUN(cfg_phy_base_port, cfg_phy_base_port_cmd,
return CMD_SUCCESS;
}
+#define GSMTAP_BURSTS_STR "Configure GSMTAP for raw bursts\n"
+
+DEFUN_USRATTR(cfg_phy_gsmtap_bursts_host, cfg_phy_gsmtap_bursts_host_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "osmotrx gsmtap-bursts remote-host " VTY_IPV46_CMD,
+ OSMOTRX_STR GSMTAP_BURSTS_STR
+ "Set remote IP address to which send raw bursts in GSMTAP format\n"
+ "Remote IPv4 address\n"
+ "Remote IPv6 address\n")
+{
+ struct phy_link *plink = vty->index;
+ osmo_talloc_replace_string(plink, &plink->u.osmotrx.gsmtap_burst.remote_host, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN_USRATTR(cfg_phy_no_gsmtap_bursts_host, cfg_phy_no_gsmtap_bursts_host_cmd,
+ X(BTS_VTY_TRX_POWERCYCLE),
+ "no osmotrx gsmtap-bursts remote-host",
+ NO_STR OSMOTRX_STR GSMTAP_BURSTS_STR
+ "Disable sending GSMTAP bust data\n")
+{
+ struct phy_link *plink = vty->index;
+ talloc_free(plink->u.osmotrx.gsmtap_burst.remote_host);
+ plink->u.osmotrx.gsmtap_burst.remote_host = NULL;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_phy_gsmtap_bursts_type, cfg_phy_gsmtap_bursts_type_cmd,
+ "osmotrx gsmtap-bursts type (all|crc-error)",
+ OSMOTRX_STR GSMTAP_BURSTS_STR
+ "Configure which bursts to send via GSMTAP\n"
+ "Send all burst as GSMTAP burstss\n"
+ "Send only bursts with CRC failures as GSMTAP bursts\n")
+{
+ struct phy_link *plink = vty->index;
+ if (!strcmp(argv[0], "all"))
+ plink->u.osmotrx.gsmtap_burst.all = true;
+ else
+ plink->u.osmotrx.gsmtap_burst.all = false;
+ return CMD_SUCCESS;
+}
+
DEFUN_USRATTR(cfg_phy_setbsic, cfg_phy_setbsic_cmd,
X(BTS_VTY_TRX_POWERCYCLE),
"osmotrx legacy-setbsic", OSMOTRX_STR
@@ -580,6 +622,12 @@ void bts_model_config_write_phy(struct vty *vty, const struct phy_link *plink)
if (plink->u.osmotrx.trxd_pdu_ver_max != TRX_DATA_PDU_VER)
vty_out(vty, " osmotrx trxd-max-version %d%s", plink->u.osmotrx.trxd_pdu_ver_max, VTY_NEWLINE);
+
+ if (plink->u.osmotrx.gsmtap_burst.remote_host) {
+ vty_out(vty, " osmotrx gsmtap-bursts remote-host %s%s", plink->u.osmotrx.gsmtap_burst.remote_host, VTY_NEWLINE);
+ vty_out(vty, " osmotrx gsmtap-bursts type %s%s",
+ plink->u.osmotrx.gsmtap_burst.all ? "all" : "crc-error", VTY_NEWLINE);
+ }
}
void bts_model_config_write_phy_inst(struct vty *vty, const struct phy_instance *pinst)
@@ -645,6 +693,9 @@ int bts_model_vty_init(void *ctx)
install_element(PHY_NODE, &cfg_phy_setbsic_cmd);
install_element(PHY_NODE, &cfg_phy_no_setbsic_cmd);
install_element(PHY_NODE, &cfg_phy_trxd_max_version_cmd);
+ install_element(PHY_NODE, &cfg_phy_gsmtap_bursts_host_cmd);
+ install_element(PHY_NODE, &cfg_phy_no_gsmtap_bursts_host_cmd);
+ install_element(PHY_NODE, &cfg_phy_gsmtap_bursts_type_cmd);
install_element(PHY_INST_NODE, &cfg_phyinst_rxgain_cmd);
install_element(PHY_INST_NODE, &cfg_phyinst_tx_atten_cmd);