[MERGED] osmocom-bb[master]: VIRT-PHY: Add support for GPRS / TBF mode

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Sun Aug 20 20:23:41 UTC 2017


Harald Welte has submitted this change and it was merged.

Change subject: VIRT-PHY: Add support for GPRS / TBF mode
......................................................................


VIRT-PHY: Add support for GPRS / TBF mode

we add a new STATE_TBF to vthe MS model and add some L1CTL primitives
to configure that TBF mode as well as to enqueue transmissions for
blocks at a given USF+TS.

Change-Id: Ie6f37090bd45f463aa25d9e00bc06f563be5264a
---
M include/l1ctl_proto.h
M src/host/virt_phy/include/virtphy/virt_l1_model.h
M src/host/virt_phy/src/gsmtapl1_if.c
M src/host/virt_phy/src/l1ctl_sap.c
4 files changed, 293 insertions(+), 5 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/include/l1ctl_proto.h b/include/l1ctl_proto.h
index 771bf1c..37d3d87 100644
--- a/include/l1ctl_proto.h
+++ b/include/l1ctl_proto.h
@@ -56,6 +56,13 @@
 	L1CTL_TRAFFIC_REQ,
 	L1CTL_TRAFFIC_CONF,
 	L1CTL_TRAFFIC_IND,
+
+	/* configure TBF for uplink/downlink */
+	L1CTL_TBF_CFG_REQ,
+	L1CTL_TBF_CFG_CONF,
+
+	L1CTL_DATA_TBF_REQ,
+	L1CTL_DATA_TBF_CONF,
 };
 
 enum ccch_mode {
@@ -68,6 +75,23 @@
 	NEIGH_MODE_NONE = 0,
 	NEIGH_MODE_PM,
 	NEIGH_MODE_SB,
+};
+
+enum l1ctl_coding_scheme {
+	L1CTL_CS_NONE,
+	L1CTL_CS1,
+	L1CTL_CS2,
+	L1CTL_CS3,
+	L1CTL_CS4,
+	L1CTL_MCS1,
+	L1CTL_MCS2,
+	L1CTL_MCS3,
+	L1CTL_MCS4,
+	L1CTL_MCS5,
+	L1CTL_MCS6,
+	L1CTL_MCS7,
+	L1CTL_MCS8,
+	L1CTL_MCS9,
 };
 
 #define TRAFFIC_DATA_LEN	40
@@ -149,6 +173,15 @@
 	uint8_t link_id;
 	uint8_t padding[2];
 
+	uint8_t payload[0];
+} __attribute__((packed));
+
+struct l1ctl_info_ul_tbf {
+	/* references l1ctl_tbf_cfg_req.tbf_nr */
+	uint8_t tbf_nr;
+	uint8_t coding_scheme;
+	uint8_t padding[2];
+	/* RLC/MAC block, size determines CS */
 	uint8_t payload[0];
 } __attribute__((packed));
 
@@ -300,4 +333,15 @@
 	uint8_t data[TRAFFIC_DATA_LEN];
 } __attribute__((packed));
 
+struct l1ctl_tbf_cfg_req {
+	/* future support for multiple concurrent TBFs. 0 for now */
+	uint8_t tbf_nr;
+	/* is this about an UL TBF (1) or DL (0) */
+	uint8_t is_uplink;
+	uint8_t padding[2];
+
+	/* one USF for each TN, or 255 for invalid/unused */
+	uint8_t usf[8];
+} __attribute__((packed));
+
 #endif /* __L1CTL_PROTO_H__ */
diff --git a/src/host/virt_phy/include/virtphy/virt_l1_model.h b/src/host/virt_phy/include/virtphy/virt_l1_model.h
index fa79127..67c24bb 100644
--- a/src/host/virt_phy/include/virtphy/virt_l1_model.h
+++ b/src/host/virt_phy/include/virtphy/virt_l1_model.h
@@ -15,6 +15,7 @@
 	MS_STATE_IDLE_SYNCING,
 	MS_STATE_IDLE_CAMPING,
 	MS_STATE_DEDICATED,
+	MS_STATE_TBF
 };
 
 
@@ -74,6 +75,15 @@
 		uint8_t tsc; // training sequence code (ununsed in virtual um)
 		uint8_t h; // hopping enabled flag (ununsed in virtual um)
 	} dedicated;
+	struct {
+		struct {
+			uint8_t usf[8];
+			struct llist_head tx_queue;
+		} ul;
+		struct {
+			uint8_t tfi[8];
+		} dl;
+	} tbf;
 
 	/* fbsb state */
 	struct {
diff --git a/src/host/virt_phy/src/gsmtapl1_if.c b/src/host/virt_phy/src/gsmtapl1_if.c
index 8202046..2cf9d2d 100644
--- a/src/host/virt_phy/src/gsmtapl1_if.c
+++ b/src/host/virt_phy/src/gsmtapl1_if.c
@@ -54,7 +54,7 @@
 void gsmtapl1_tx_to_virt_um_inst(struct l1_model_ms *ms, uint32_t fn, uint8_t tn, struct msgb *msg)
 {
 	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
-	struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
+	struct l1ctl_info_ul *ul;
 	struct gsmtap_hdr *gh;
 	struct msgb *outmsg;	/* msg to send with gsmtap header prepended */
 	uint16_t arfcn = ms->state.serving_cell.arfcn;	/* arfcn of the cell we currently camp on */
@@ -68,8 +68,20 @@
 	uint8_t timeslot;	/* tdma timeslot to send in (0-7) */
 	uint8_t gsmtap_chan;	/* the gsmtap channel */
 
-	rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, &timeslot);
-	gsmtap_chan = chantype_rsl2gsmtap(rsl_chantype, ul->link_id);
+	switch (l1h->msg_type) {
+	case L1CTL_DATA_TBF_REQ:
+		ul = NULL;
+		rsl_chantype = RSL_CHAN_OSMO_PDCH;
+		timeslot = tn;
+		subslot = 0;
+		gsmtap_chan = chantype_rsl2gsmtap(rsl_chantype, 0);
+		break;
+	default:
+		ul = (struct l1ctl_info_ul *)l1h->data;
+		rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, &timeslot);
+		gsmtap_chan = chantype_rsl2gsmtap(rsl_chantype, ul->link_id);
+		break;
+	}
 
 	/* arfcn needs to be flagged to be able to distinguish between uplink and downlink */
 	outmsg = gsmtap_makemsg(arfcn | GSMTAP_ARFCN_F_UPLINK, timeslot,
@@ -104,6 +116,77 @@
  */
 extern uint16_t prim_pm_set_sig_strength(struct l1_model_ms *ms, uint16_t arfcn, int16_t sig_lev);
 
+/* determine if a received Downlink RLC/MAC block matches the current MS configuration */
+static bool gprs_dl_block_matches_ms(struct l1_model_ms *ms, struct msgb *msg, uint8_t timeslot)
+{
+	uint8_t payload_type;
+	uint8_t tfi;
+
+	if (msgb_length(msg) < 1)
+		return false;
+
+	/* FIXME: Ensure this will also work for EGPRS!  */
+	payload_type = msg->data[0] >> 6;
+	switch (payload_type) {
+	case 0: /* RLC Data Block */
+		/* forward all RLD Data Blocks destined for TFI of MS */
+		tfi = (msg->data[1] >> 1) & 0x1f;
+		if (ms->state.state == MS_STATE_TBF && ms->state.tbf.dl.tfi[timeslot] == tfi)
+			return true;
+		break;
+	case 1: /* RLC/MAC Control without optional octets */
+		/* forward all RLC/MAC control blocks without optional octets, i.e. not adressed
+		 * to a specific TFI */
+		return true;
+	case 2: /* RLC/MAC with optional control octets */
+		/* forward all RLD Control Blocks destined for TFI of MS */
+		tfi = (msg->data[2] >> 1) & 0x1f;
+		if (ms->state.state == MS_STATE_TBF && ms->state.tbf.dl.tfi[timeslot] == tfi)
+			return true;
+		break;
+	default:
+		break;
+	}
+	return false;
+}
+
+/* determine if given USF at given timeslot is relevant to given MS or not */
+static bool usf_matches_ms(struct l1_model_ms *ms, uint8_t usf, uint8_t timeslot)
+{
+	if (ms->state.state == MS_STATE_TBF && ms->state.tbf.ul.usf[timeslot] == usf)
+		return true;
+
+	return false;
+}
+
+/* extract USF from (E)GPRS RLC/MAC block */
+static uint8_t get_usf_from_block(struct msgb *msg)
+{
+	/* FIXME: Ensure this will also work for EGPRS!  */
+	return msg->data[0] & 0x7;
+}
+
+/* MS is authorized to transmit a block in uplink for given USF on timeslot+arfcn at FN */
+static void ms_ul_tbf_may_transmit(struct l1_model_ms *ms, uint16_t arfcn, uint8_t timeslot,
+				   uint32_t fn, uint8_t usf)
+{
+	struct msgb *msg;
+
+	/* If USF is not for us, bail out */
+	if (!usf_matches_ms(ms, usf, timeslot))
+		return;
+
+	/* attempt to de-queue pending msgb for this UL TBF and transmit it */
+	msg = msgb_dequeue(&ms->state.tbf.ul.tx_queue);
+	if (!msg) {
+		printf("FN=%u, TN=%u, USF=%u: empty tx_queue, not transmitting\n", fn, timeslot, usf);
+		/* FIXME: send some dummy control frame? */
+	} else {
+		printf("FN=%u, TN=%u, USF=%u: transmitting queued msg\n", fn, timeslot, usf);
+		gsmtapl1_tx_to_virt_um_inst(ms, fn, timeslot, msg);
+	}
+}
+
 static void l1ctl_from_virt_um(struct l1ctl_sock_client *lsc, struct msgb *msg, uint32_t fn,
 				uint16_t arfcn, uint8_t timeslot, uint8_t subslot,
 				uint8_t gsmtap_chantype, uint8_t chan_nr, uint8_t link_id,
@@ -111,6 +194,7 @@
 {
 	struct l1_model_ms *ms = lsc->priv;
 	uint8_t signal_dbm = dbm2rxlev(prim_pm_set_sig_strength(ms, arfcn & GSMTAP_ARFCN_MASK, MAX_SIG_LEV_DBM));	/* Power measurement with each received massage */
+	uint8_t usf;
 
 	gsm_fn2gsmtime(&ms->state.downlink_time, fn);
 
@@ -163,10 +247,15 @@
 	case GSMTAP_CHANNEL_RACH:
 		LOGPMS(DVIRPHY, LOGL_NOTICE, ms, "Ignoring unexpected RACH in downlink ?!?\n");
 		break;
-	case GSMTAP_CHANNEL_SDCCH:
-	case GSMTAP_CHANNEL_CCCH:
 	case GSMTAP_CHANNEL_PACCH:
 	case GSMTAP_CHANNEL_PDCH:
+		if (gprs_dl_block_matches_ms(ms, msg, timeslot))
+			l1ctl_tx_data_ind(ms, msg, arfcn, link_id, chan_nr, fn, snr_db, signal_dbm, 0, 0);
+		usf = get_usf_from_block(msg);
+		ms_ul_tbf_may_transmit(ms, arfcn, timeslot, fn, usf);
+		break;
+	case GSMTAP_CHANNEL_SDCCH:
+	case GSMTAP_CHANNEL_CCCH:
 	case GSMTAP_CHANNEL_PTCCH:
 		LOGPMS(DVIRPHY, LOGL_NOTICE, ms, "Ignoring unsupported channel type %s\n",
 			get_value_string(gsmtap_gsm_channel_names, gsmtap_chantype));
diff --git a/src/host/virt_phy/src/l1ctl_sap.c b/src/host/virt_phy/src/l1ctl_sap.c
index d4b33f1..aac49bf 100644
--- a/src/host/virt_phy/src/l1ctl_sap.c
+++ b/src/host/virt_phy/src/l1ctl_sap.c
@@ -27,6 +27,7 @@
 #include <osmocom/gsm/protocol/gsm_08_58.h>
 #include <osmocom/gsm/protocol/gsm_04_08.h>
 #include <osmocom/gsm/rsl.h>
+#include <osmocom/gprs/gprs_rlc.h>
 #include <stdio.h>
 #include <l1ctl_proto.h>
 #include <netinet/in.h>
@@ -38,6 +39,9 @@
 #include <virtphy/gsmtapl1_if.h>
 #include <virtphy/logging.h>
 #include <virtphy/virt_l1_sched.h>
+
+static void l1ctl_rx_tbf_cfg_req(struct l1_model_ms *ms, struct msgb *msg);
+static void l1ctl_rx_data_tbf_req(struct l1_model_ms *ms, struct msgb *msg);
 
 static void l1_model_tch_mode_set(struct l1_model_ms *ms, uint8_t tch_mode)
 {
@@ -55,6 +59,8 @@
 void l1ctl_sap_init(struct l1_model_ms *model)
 {
 	INIT_LLIST_HEAD(&model->state.sched.mframe_items);
+	INIT_LLIST_HEAD(&model->state.tbf.ul.tx_queue);
+
 	prim_pm_init(model);
 }
 
@@ -156,6 +162,8 @@
 	switch (msg_type) {
 	case L1CTL_DATA_REQ:
 	case L1CTL_DATA_CONF:
+	case L1CTL_DATA_TBF_REQ:
+	case L1CTL_DATA_TBF_CONF:
 	case L1CTL_TRAFFIC_REQ:
 	case L1CTL_TRAFFIC_CONF:
 	case L1CTL_TRAFFIC_IND:
@@ -238,6 +246,12 @@
 	case L1CTL_SIM_REQ:
 		l1ctl_rx_sim_req(ms, msg);
 		break;
+	case L1CTL_TBF_CFG_REQ:
+		l1ctl_rx_tbf_cfg_req(ms, msg);
+		break;
+	case L1CTL_DATA_TBF_REQ:
+		l1ctl_rx_data_tbf_req(ms, msg);
+		goto exit_nofree;
 	}
 
 exit_msgbfree:
@@ -529,12 +543,143 @@
 
 }
 
+static void l1ctl_tx_tbf_cfg_conf(struct l1_model_ms *ms, const struct l1ctl_tbf_cfg_req *in);
+
+static void l1ctl_rx_tbf_cfg_req(struct l1_model_ms *ms, struct msgb *msg)
+{
+	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+	struct l1ctl_tbf_cfg_req *cfg_req = (struct l1ctl_tbf_cfg_req *) l1h->data;
+	unsigned int i;
+
+	LOGPMS(DL1C, LOGL_INFO, ms, "Rx L1CTL_TBF_CFG_REQ (tbf_id=%u, dir=%s, "
+		"usf=[%d,%d,%d,%d,%d,%d,%d,%d]\n", cfg_req->tbf_nr,
+		cfg_req->is_uplink ? "UL" : "DL", cfg_req->usf[0], cfg_req->usf[1],
+		cfg_req->usf[2], cfg_req->usf[3], cfg_req->usf[4], cfg_req->usf[5],
+		cfg_req->usf[6], cfg_req->usf[7]);
+
+	if (cfg_req->tbf_nr != 0) {
+		LOGPMS(DL1C, LOGL_ERROR, ms, "TBF_NR != 0 not supported yet!\n");
+		return;
+	}
+
+	if (ms->state.state == MS_STATE_DEDICATED)
+		LOGPMS(DL1C, LOGL_NOTICE, ms, "Harrd termiation of DEDICATED mode, fix L23!\n");
+
+	if (cfg_req->is_uplink) {
+		for (i = 0; i < 8; i++)
+			ms->state.tbf.ul.usf[i] = cfg_req->usf[i];
+	} else {
+		for (i = 0; i < 8; i++)
+			ms->state.tbf.dl.tfi[i] = cfg_req->usf[i];
+	}
+	ms->state.state = MS_STATE_TBF;
+
+	l1ctl_tx_tbf_cfg_conf(ms, cfg_req);
+}
+
+static const enum osmo_gprs_cs osmo_cs_by_l1ctl[] = {
+	[L1CTL_CS_NONE]	= OSMO_GPRS_CS_NONE,
+	[L1CTL_CS1]	= OSMO_GPRS_CS1,
+	[L1CTL_CS2]	= OSMO_GPRS_CS2,
+	[L1CTL_CS3]	= OSMO_GPRS_CS3,
+	[L1CTL_CS4]	= OSMO_GPRS_CS4,
+	[L1CTL_MCS1]	= OSMO_GPRS_MCS1,
+	[L1CTL_MCS2]	= OSMO_GPRS_MCS2,
+	[L1CTL_MCS3]	= OSMO_GPRS_MCS3,
+	[L1CTL_MCS4]	= OSMO_GPRS_MCS4,
+	[L1CTL_MCS5]	= OSMO_GPRS_MCS5,
+	[L1CTL_MCS6]	= OSMO_GPRS_MCS6,
+	[L1CTL_MCS7]	= OSMO_GPRS_MCS7,
+	[L1CTL_MCS8]	= OSMO_GPRS_MCS8,
+	[L1CTL_MCS9]	= OSMO_GPRS_MCS9,
+};
+
+static int get_osmo_cs_by_l1ctl(enum l1ctl_coding_scheme l1)
+{
+	if (l1 >= ARRAY_SIZE(osmo_cs_by_l1ctl))
+		return -1;
+	return osmo_cs_by_l1ctl[l1];
+}
+
+static const enum l1ctl_coding_scheme l1ctl_cs_by_osmo[] = {
+	[OSMO_GPRS_CS_NONE]	= L1CTL_CS_NONE,
+	[OSMO_GPRS_CS1]		= L1CTL_CS1,
+	[OSMO_GPRS_CS2]		= L1CTL_CS2,
+	[OSMO_GPRS_CS3]		= L1CTL_CS3,
+	[OSMO_GPRS_CS4]		= L1CTL_CS4,
+	[OSMO_GPRS_MCS1]	= L1CTL_MCS1,
+	[OSMO_GPRS_MCS2]	= L1CTL_MCS2,
+	[OSMO_GPRS_MCS3]	= L1CTL_MCS3,
+	[OSMO_GPRS_MCS4]	= L1CTL_MCS4,
+	[OSMO_GPRS_MCS5]	= L1CTL_MCS5,
+	[OSMO_GPRS_MCS6]	= L1CTL_MCS6,
+	[OSMO_GPRS_MCS7]	= L1CTL_MCS7,
+	[OSMO_GPRS_MCS8]	= L1CTL_MCS8,
+	[OSMO_GPRS_MCS9]	= L1CTL_MCS9,
+};
+
+static int get_l1ctl_cs_by_osmo(enum osmo_gprs_cs in)
+{
+	if (in >= ARRAY_SIZE(l1ctl_cs_by_osmo))
+		return -1;
+	return l1ctl_cs_by_osmo[in];
+}
+
+static void l1ctl_rx_data_tbf_req(struct l1_model_ms *ms, struct msgb *msg)
+{
+	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+	struct l1ctl_info_ul_tbf *udt = (struct l1ctl_info_ul_tbf *) l1h->data;
+	enum osmo_gprs_cs osmo_cs;
+	int block_size;
+
+	msg->l2h = udt->payload;
+
+	LOGPMS(DL1P, LOGL_ERROR, ms, "Rx L1CTL_DATA_TBF_REQ (tbf_id=%d, data=%s)\n",
+		udt->tbf_nr, osmo_hexdump(msg->l2h, msgb_l2len(msg)));
+	if (udt->tbf_nr != 0) {
+		LOGPMS(DL1C, LOGL_ERROR, ms, "TBF_NR != 0 not supported yet!\n");
+		return;
+	}
+
+	if (ms->state.state != MS_STATE_TBF) {
+		LOGPMS(DL1P, LOGL_ERROR, ms, "DATA_TBF_REQ in state != TBF\n");
+		return;
+	}
+
+	osmo_cs = get_l1ctl_cs_by_osmo(udt->coding_scheme);
+	if (osmo_cs < 0) {
+		LOGPMS(DL1P, LOGL_ERROR, ms, "DATA_RBF_REQ with invalid CS\n");
+		return;
+	}
+	block_size = osmo_gprs_ul_block_size_bytes(osmo_cs);
+
+	if (msgb_l2len(msg) < block_size) {
+		int pad_len = block_size - msgb_l2len(msg);
+		uint8_t *pad = msgb_put(msg, pad_len);
+		memset(pad, GSM_MACBLOCK_PADDING, pad_len);
+	}
+
+	msgb_enqueue(&ms->state.tbf.ul.tx_queue, msg);
+}
+
 /***************************************************************
  * L1CTL TX ROUTINES *******************************************
  * For more routines check the respective handler classes ******
  * like virt_prim_rach.c ***************************************
  ***************************************************************/
 
+static void l1ctl_tx_tbf_cfg_conf(struct l1_model_ms *ms, const struct l1ctl_tbf_cfg_req *in)
+{
+	struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TBF_CFG_CONF);
+	struct l1ctl_tbf_cfg_req *out;
+
+	/* copy over the data from the request */
+	out = (struct l1ctl_tbf_cfg_req *) msgb_put(msg, sizeof(*out));
+	*out = *in;
+
+	l1ctl_sap_tx_to_l23_inst(ms, msg);
+}
+
 /**
  * @brief Transmit L1CTL_RESET_IND or L1CTL_RESET_CONF to layer 23.
  *

-- 
To view, visit https://gerrit.osmocom.org/3569
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ie6f37090bd45f463aa25d9e00bc06f563be5264a
Gerrit-PatchSet: 1
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder



More information about the gerrit-log mailing list