[PATCH] osmocom-bb[master]: VIRT_PHY: Improved l1ctl-to-l23 interface + gsmtap header pa...

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
Wed Jul 12 21:20:45 UTC 2017


Review at  https://gerrit.osmocom.org/3199

VIRT_PHY: Improved l1ctl-to-l23 interface + gsmtap header parsing.

Fixed mapping from gsmtap msg type to rsl msg type and vice versa.
Proper chan_nr decoding instead of usage of dummy values for timeslot /
link_id / subslot.
Implemented missing l23 rx handler routines.

Change-Id: Ibad741d112643c55091b8ba00164b05d728ae1a1
---
M src/host/virt_phy/src/gsmtapl1_if.c
M src/host/virt_phy/src/gsmtapl1_if.h
M src/host/virt_phy/src/l1ctl_sap.c
M src/host/virt_phy/src/l1ctl_sap.h
M src/host/virt_phy/src/virt_l1_model.h
M src/host/virt_phy/src/virtphy.c
M src/host/virt_phy/src/virtual_um.c
7 files changed, 433 insertions(+), 342 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/99/3199/1

diff --git a/src/host/virt_phy/src/gsmtapl1_if.c b/src/host/virt_phy/src/gsmtapl1_if.c
index 53cc952..d46bb2f 100644
--- a/src/host/virt_phy/src/gsmtapl1_if.c
+++ b/src/host/virt_phy/src/gsmtapl1_if.c
@@ -91,25 +91,43 @@
 /**
  * Replace l11 header of given msgb by a gsmtap header and send it over the virt um.
  */
-void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, uint8_t tn, uint32_t fn, uint8_t gsmtap_chan, struct msgb *msg)
+void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, uint32_t fn,
+                                 struct msgb *msg)
 {
 	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
 	struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
-	uint8_t ss = 0;
-	uint8_t *data = msgb_l2(msg); // data bits to transmit (whole message without l1 header)
-	uint8_t data_len = msgb_l2len(msg);
-	struct msgb *outmsg;
+	struct gsmtap_hdr *gh;
+	struct msgb *outmsg; // msg to send with gsmtap header prepended
+	uint16_t arfcn = l1_model_ms->state->serving_cell.arfcn; // arfcn of the cell we currently camp on
+	uint8_t signal_dbm = 63; // signal strength, 63 is best
+	uint8_t snr = 63; // signal noise ratio, 63 is best
+	uint8_t *data = msgb_l2(msg); // data to transmit (whole message without l1 header)
+	uint8_t data_len = msgb_l2len(msg); // length of data
 
-	outmsg = gsmtap_makemsg(l1_model_ms->state->serving_cell.arfcn, ul->chan_nr, gsmtap_chan,
-	                ss, fn, 0, 0, data,
-	                data_len);
+	uint8_t rsl_chantype; // rsl chan type (8.58, 9.3.1)
+	uint8_t subslot; // multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51)
+	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);
+
+	outmsg = gsmtap_makemsg(arfcn, timeslot, gsmtap_chan, subslot, fn,
+	                signal_dbm, snr, data, data_len);
 	if (outmsg) {
-		struct gsmtap_hdr *gh = msgb_data(msg);
-		virt_um_write_msg(l1_model_ms->vui, outmsg);
-		DEBUGP(DVIRPHY,
-		                "Sending gsmtap msg to virt um - (arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
-		                gh->arfcn, gh->type, gh->sub_type, gh->timeslot,
-		                gh->sub_slot);
+		outmsg->l1h = msgb_data(outmsg);
+		gh = msgb_l1(outmsg);
+		if (virt_um_write_msg(l1_model_ms->vui, outmsg) == -1) {
+			LOGP(DVIRPHY, LOGL_ERROR,
+			                "Gsmtap msg could not send to virt um - (arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
+			                gh->arfcn, gh->type, gh->sub_type,
+			                gh->timeslot, gh->sub_slot);
+		} else {
+			DEBUGP(DVIRPHY,
+			                "Sending gsmtap msg to virt um - (arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
+			                gh->arfcn, gh->type, gh->sub_type,
+			                gh->timeslot, gh->sub_slot);
+		}
 	} else {
 		LOGP(DVIRPHY, LOGL_ERROR, "Gsmtap msg could not be created!\n");
 	}
@@ -119,29 +137,12 @@
 }
 
 /**
- * @see void gsmtapl1_tx_to_virt_um(struct virt_um_inst *vui, uint8_t tn, uint32_t fn, uint8_t gsmtap_chan, struct msgb *msg).
+ * @see void gsmtapl1_tx_to_virt_um(struct virt_um_inst *vui, uint32_t fn, struct msgb *msg).
  */
-void gsmtapl1_tx_to_virt_um(uint8_t tn, uint32_t fn, uint8_t gsmtap_chan, struct msgb *msg)
+void gsmtapl1_tx_to_virt_um(uint32_t fn, struct msgb *msg)
 {
-	gsmtapl1_tx_to_virt_um_inst(l1_model_ms->vui, tn, fn, gsmtap_chan, msg);
+	gsmtapl1_tx_to_virt_um_inst(l1_model_ms->vui, fn, msg);
 }
-
-/* This is the header as it is used by gsmtap peer virtual layer 1.
-struct gsmtap_hdr {
-	guint8 version;		// version, set to 0x01 currently
-	guint8 hdr_len;		// length in number of 32bit words
-	guint8 type;		// see GSMTAP_TYPE_*
-	guint8 timeslot;	// timeslot (0..7 on Um)
-	guint16 arfcn;		// ARFCN (frequency)
-	gint8 signal_dbm;	// signal level in dBm
-	gint8 snr_db;		// signal/noise ratio in dB
-	guint32 frame_number;	// GSM Frame Number (FN)
-	guint8 sub_type;	// Type of burst/channel, see above
-	guint8 antenna_nr;	// Antenna Number
-	guint8 sub_slot;	// sub-slot within timeslot
-	guint8 res;		// reserved for future use (RFU)
-}
- */
 
 /**
  * Receive a gsmtap message from the virt um.
@@ -149,81 +150,117 @@
 void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
                                       struct msgb *msg)
 {
-	if (msg) {
-		// we assume we only receive msgs if we actually camp on a cell
-		if (l1_model_ms->state->camping) {
-			struct gsmtap_hdr *gh;
-			struct l1ctl_info_dl *l1dl;
-			struct msgb *l1ctl_msg = NULL;
-			struct l1ctl_data_ind * l1di;
-
-			msg->l1h = msgb_data(msg);
-			msg->l2h = msgb_pull(msg, sizeof(*gh));
-			gh = msgb_l1(msg);
-
-			DEBUGP(DVIRPHY,
-					"Receiving gsmtap msg from virt um - (arfcn=%u, framenumber=%u, type=%s, subtype=%s, timeslot=%u, subslot=%u)\n",
-					ntohs(gh->arfcn), ntohl(gh->frame_number), get_value_string(gsmtap_types, gh->type), get_value_string(gsmtap_channels, gh->sub_type), gh->timeslot,
-					gh->sub_slot);
-
-			// compose the l1ctl message for layer 2
-			switch (gh->sub_type) {
-			case GSMTAP_CHANNEL_RACH:
-				LOGP(DL1C, LOGL_NOTICE,
-						"Ignoring gsmtap msg from virt um - channel type is uplink only!\n");
-				break;
-			case GSMTAP_CHANNEL_TCH_F:
-				l1ctl_msg = l1ctl_msgb_alloc(L1CTL_TRAFFIC_IND);
-				// TODO: implement channel handling
-				break;
-			case GSMTAP_CHANNEL_SDCCH:
-			case GSMTAP_CHANNEL_SDCCH4:
-			case GSMTAP_CHANNEL_SDCCH8:
-				// TODO: we might need to implement own channel handling for standalone dedicated channels
-			case GSMTAP_CHANNEL_AGCH:
-			case GSMTAP_CHANNEL_PCH:
-			case GSMTAP_CHANNEL_BCCH:
-				l1ctl_msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
-				l1dl = (struct l1ctl_info_dl *) msgb_put(l1ctl_msg, sizeof(struct l1ctl_info_dl));
-				l1di = (struct l1ctl_data_ind *) msgb_put(l1ctl_msg, sizeof(struct l1ctl_data_ind));
-
-				l1dl->band_arfcn = htons(ntohs(gh->arfcn));
-				l1dl->link_id = gh->timeslot;
-				// see GSM 8.58 -> 9.3.1 for channel number encoding
-				l1dl->chan_nr = rsl_enc_chan_nr(chantype_gsmtap2rsl(gh->sub_type), gh->sub_slot, gh->timeslot);
-				l1dl->frame_nr = htonl(ntohl(gh->frame_number));
-				l1dl->snr = gh->snr_db;
-				l1dl->rx_level = gh->signal_dbm;
-				l1dl->num_biterr = 0;
-				l1dl->fire_crc = 0;
-
-				memcpy(l1di->data, msgb_data(msg), msgb_length(msg));
-
-				break;
-			case GSMTAP_CHANNEL_CCCH:
-			case GSMTAP_CHANNEL_TCH_H:
-			case GSMTAP_CHANNEL_PACCH:
-			case GSMTAP_CHANNEL_PDCH:
-			case GSMTAP_CHANNEL_PTCCH:
-			case GSMTAP_CHANNEL_CBCH51:
-			case GSMTAP_CHANNEL_CBCH52:
-				LOGP(DL1C, LOGL_NOTICE,
-						"Ignoring gsmtap msg from virt um - channel type not supported!\n");
-				break;
-			default:
-				LOGP(DL1C, LOGL_NOTICE,
-						"Ignoring gsmtap msg from virt um - channel type unknown.\n");
-				break;
-			}
-
-			/* forward l1ctl message to l2 */
-			if(l1ctl_msg) {
-				l1ctl_sap_tx_to_l23(l1ctl_msg);
-			}
-		}
-		// handle memory deallocation
-		talloc_free(msg);
+	if (!msg) {
+		return;
 	}
+	// we assume we only receive msgs if we actually camp on a cell
+	if (!l1_model_ms->state->camping) {
+		talloc_free(msg);
+		return;
+	}
+
+	struct gsmtap_hdr *gh = msgb_l1(msg);
+	struct msgb *l1ctl_msg = NULL;
+	struct l1ctl_info_dl *l1dl;
+	uint32_t fn = ntohl(gh->frame_number); // frame number of the rcv msg
+	uint16_t arfcn = ntohs(gh->arfcn); // arfcn of the cell we currently camp on
+	uint8_t gsmtap_chantype = gh->sub_type; // gsmtap channel type
+	uint8_t signal_dbm = gh->signal_dbm; // signal strength, 63 is best
+	uint8_t snr = gh->snr_db; // signal noise ratio, 63 is best
+	uint8_t subslot = gh->sub_slot; // multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51)
+	uint8_t timeslot = gh->timeslot; // tdma timeslot to send in (0-7)
+	uint8_t rsl_chantype; // rsl chan type (8.58, 9.3.1)
+	uint8_t link_id; // rsl link id tells if this is an ssociated or dedicated link
+	uint8_t chan_nr; // encoded rsl channel type, timeslot and mf subslot
+
+	msg->l2h = msgb_pull(msg, sizeof(*gh));
+	chantype_gsmtap2rsl(gsmtap_chantype, &rsl_chantype, &link_id);
+	// see GSM 8.58 -> 9.3.1 for channel number encoding
+	chan_nr = rsl_enc_chan_nr(rsl_chantype, subslot, timeslot);
+
+	DEBUGP(DVIRPHY,
+	                "Receiving gsmtap msg from virt um - (arfcn=%u, framenumber=%u, type=%s, subtype=%s, timeslot=%u, subslot=%u, rsl_chan_type=0x%2x, link_id=0x%2x, chan_nr=0x%2x)\n",
+	                arfcn, fn, get_value_string(gsmtap_types, gh->type),
+	                get_value_string(gsmtap_channels, gsmtap_chantype),
+	                timeslot, subslot, rsl_chantype, link_id, chan_nr);
+
+	// switch case with removed acch flag
+	switch (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) {
+	case GSMTAP_CHANNEL_TCH_H:
+	case GSMTAP_CHANNEL_TCH_F:
+		struct l1ctl_traffic_ind * l1ti;
+		l1ctl_msg = l1ctl_msgb_alloc(L1CTL_TRAFFIC_IND);
+		l1dl = (struct l1ctl_info_dl *)msgb_put(l1ctl_msg,
+		                sizeof(struct l1ctl_info_dl));
+		l1ti = (struct l1ctl_traffic_ind *)msgb_put(l1ctl_msg,
+		                sizeof(struct l1ctl_traffic_ind));
+
+		l1dl->band_arfcn = htons(arfcn);
+		l1dl->link_id = link_id;
+		l1dl->chan_nr = chan_nr;
+		l1dl->frame_nr = htonl(fn);
+		l1dl->snr = snr;
+		l1dl->rx_level = signal_dbm;
+		l1dl->num_biterr = 0; // no biterrors
+		l1dl->fire_crc = 0;
+
+		// TODO: traffic decoding and decryption
+
+		memcpy(l1ti->data, msgb_data(msg), msgb_length(msg));
+		break;
+	case GSMTAP_CHANNEL_SDCCH4:
+	case GSMTAP_CHANNEL_SDCCH8:
+		// TODO: we might need to implement own channel handling for standalone dedicated channels
+	case GSMTAP_CHANNEL_AGCH:
+	case GSMTAP_CHANNEL_PCH:
+	case GSMTAP_CHANNEL_BCCH:
+		struct l1ctl_data_ind * l1di;
+		l1ctl_msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
+		l1dl = (struct l1ctl_info_dl *)msgb_put(l1ctl_msg,
+		                sizeof(struct l1ctl_info_dl));
+		l1di = (struct l1ctl_data_ind *)msgb_put(l1ctl_msg,
+		                sizeof(struct l1ctl_data_ind));
+
+		l1dl->band_arfcn = htons(arfcn);
+		l1dl->link_id = link_id;
+		l1dl->chan_nr = chan_nr;
+		l1dl->frame_nr = htonl(fn);
+		l1dl->snr = snr;
+		l1dl->rx_level = signal_dbm;
+		l1dl->num_biterr = 0; // no biterrors
+		l1dl->fire_crc = 0; // TODO: check if this means fire crc is not used or crc produced no error
+
+		// TODO: data decoding and decryption
+
+		memcpy(l1di->data, msgb_data(msg), msgb_length(msg));
+
+		break;
+	case GSMTAP_CHANNEL_RACH:
+		LOGP(DVIRPHY, LOGL_NOTICE,
+		                "Ignoring gsmtap msg from virt um - channel type is uplink only!\n");
+		break;
+	case GSMTAP_CHANNEL_SDCCH:
+	case GSMTAP_CHANNEL_CCCH:
+	case GSMTAP_CHANNEL_PACCH:
+	case GSMTAP_CHANNEL_PDCH:
+	case GSMTAP_CHANNEL_PTCCH:
+	case GSMTAP_CHANNEL_CBCH51:
+	case GSMTAP_CHANNEL_CBCH52:
+		LOGP(DVIRPHY, LOGL_NOTICE,
+		                "Ignoring gsmtap msg from virt um - channel type not supported!\n");
+		break;
+	default:
+		LOGP(DVIRPHY, LOGL_NOTICE,
+		                "Ignoring gsmtap msg from virt um - channel type unknown.\n");
+		break;
+	}
+
+	/* forward l1ctl message to l2 */
+	if (l1ctl_msg) {
+		l1ctl_sap_tx_to_l23(l1ctl_msg);
+	}
+	// handle memory deallocation
+	talloc_free(msg);
 }
 
 /**
@@ -236,41 +273,77 @@
 
 /*! \brief convert GSMTAP channel type to RSL channel number
  *  \param[in] gsmtap_chantype GSMTAP channel type
- *  \returns RSL channel type
+ *  \param[out] rsl_chantype rsl channel type
+ *  \param[out] rsl_chantype rsl link id
+ *
+ *  Mapping from gsmtap channel:
+ *  GSMTAP_CHANNEL_UNKNOWN *  0x00
+ *  GSMTAP_CHANNEL_BCCH *  0x01
+ *  GSMTAP_CHANNEL_CCCH *  0x02
+ *  GSMTAP_CHANNEL_RACH *  0x03
+ *  GSMTAP_CHANNEL_AGCH *  0x04
+ *  GSMTAP_CHANNEL_PCH *  0x05
+ *  GSMTAP_CHANNEL_SDCCH *  0x06
+ *  GSMTAP_CHANNEL_SDCCH4 *  0x07
+ *  GSMTAP_CHANNEL_SDCCH8 *  0x08
+ *  GSMTAP_CHANNEL_TCH_F *  0x09
+ *  GSMTAP_CHANNEL_TCH_H *  0x0a
+ *  GSMTAP_CHANNEL_PACCH *  0x0b
+ *  GSMTAP_CHANNEL_CBCH52 *  0x0c
+ *  GSMTAP_CHANNEL_PDCH *  0x0d
+ *  GSMTAP_CHANNEL_PTCCH *  0x0e
+ *  GSMTAP_CHANNEL_CBCH51 *  0x0f
+ *  to rsl channel type:
+ *  RSL_CHAN_NR_MASK *  0xf8
+ *  RSL_CHAN_NR_1 *   *  0x08
+ *  RSL_CHAN_Bm_ACCHs *  0x08
+ *  RSL_CHAN_Lm_ACCHs *  0x10
+ *  RSL_CHAN_SDCCH4_ACCH *  0x20
+ *  RSL_CHAN_SDCCH8_ACCH *  0x40
+ *  RSL_CHAN_BCCH *   *  0x80
+ *  RSL_CHAN_RACH *   *  0x88
+ *  RSL_CHAN_PCH_AGCH *  0x90
+ *  RSL_CHAN_OSMO_PDCH *  0xc0
+ *  and logical channel link id:
+ *  LID_SACCH  *   *  0x40
+ *  LID_DEDIC  *   *  0x00
+ *
+ *  TODO: move this to a library used by both ms and bts virt um
  */
-uint8_t chantype_gsmtap2rsl(uint8_t gsmtap_chantype)
+void chantype_gsmtap2rsl(uint8_t gsmtap_chantype, uint8_t *rsl_chantype,
+                         uint8_t *link_id)
 {
-	// TODO: proper retval for unknown channel
-	uint8_t ret = 0;
-
-	switch (gsmtap_chantype) {
-	case GSMTAP_CHANNEL_TCH_F:
-		ret = RSL_CHAN_Bm_ACCHs;
+	// switch case with removed acch flag
+	switch (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) {
+	case GSMTAP_CHANNEL_TCH_F: // TCH/F, FACCH/F
+		*rsl_chantype = RSL_CHAN_Bm_ACCHs;
 		break;
-	case GSMTAP_CHANNEL_TCH_H:
-		ret = RSL_CHAN_Lm_ACCHs;
+	case GSMTAP_CHANNEL_TCH_H: // TCH/H, FACCH/H
+		*rsl_chantype = RSL_CHAN_Lm_ACCHs;
 		break;
-	case GSMTAP_CHANNEL_SDCCH4:
-		ret = RSL_CHAN_SDCCH4_ACCH;
+	case GSMTAP_CHANNEL_SDCCH4: // SDCCH/4
+		*rsl_chantype = RSL_CHAN_SDCCH4_ACCH;
 		break;
-	case GSMTAP_CHANNEL_SDCCH8:
-		ret = RSL_CHAN_SDCCH8_ACCH;
+	case GSMTAP_CHANNEL_SDCCH8: // SDCCH/8
+		*rsl_chantype = RSL_CHAN_SDCCH8_ACCH;
 		break;
-	case GSMTAP_CHANNEL_BCCH:
-		ret = RSL_CHAN_BCCH;
+	case GSMTAP_CHANNEL_BCCH: // BCCH
+		*rsl_chantype = RSL_CHAN_BCCH;
 		break;
-	case GSMTAP_CHANNEL_RACH:
-		ret = RSL_CHAN_RACH;
+	case GSMTAP_CHANNEL_RACH: // RACH
+		*rsl_chantype = RSL_CHAN_RACH;
 		break;
-	case GSMTAP_CHANNEL_PCH:
-	case GSMTAP_CHANNEL_AGCH:
-		ret = RSL_CHAN_PCH_AGCH;
+	case GSMTAP_CHANNEL_PCH: // PCH
+	case GSMTAP_CHANNEL_AGCH: // AGCH
+		*rsl_chantype = RSL_CHAN_PCH_AGCH;
+		break;
+	case GSMTAP_CHANNEL_PDCH:
+		*rsl_chantype = GSMTAP_CHANNEL_PDCH;
 		break;
 	}
 
-	// TODO: check how to handle this...
-//	if (link_id & 0x40)
-//		ret |= GSMTAP_CHANNEL_ACCH;
+	*link_id = gsmtap_chantype & GSMTAP_CHANNEL_ACCH ?
+	LID_SACCH :
+	                                                   LID_DEDIC;
 
-	return ret;
 }
diff --git a/src/host/virt_phy/src/gsmtapl1_if.h b/src/host/virt_phy/src/gsmtapl1_if.h
index 09d34f4..6311e07 100644
--- a/src/host/virt_phy/src/gsmtapl1_if.h
+++ b/src/host/virt_phy/src/gsmtapl1_if.h
@@ -8,11 +8,11 @@
 #include "virt_l1_model.h"
 
 void gsmtapl1_init(struct l1_model_ms *model);
-
-void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui, struct msgb *msg);
+void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
+                                      struct msgb *msg);
 void gsmtapl1_rx_from_virt_um(struct msgb *msg);
-
-void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, uint8_t tn, uint32_t fn, uint8_t gsmtap_chan, struct msgb *msg);
-void gsmtapl1_tx_to_virt_um(uint8_t tn, uint32_t fn, uint8_t gsmtap_chan, struct msgb *msg);
-
-uint8_t chantype_gsmtap2rsl(uint8_t gsmtap_chantype);
+void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, uint32_t fn,
+                                 struct msgb *msg);
+void gsmtapl1_tx_to_virt_um(uint32_t fn, struct msgb *msg);
+void chantype_gsmtap2rsl(uint8_t gsmtap_chantype, uint8_t *rsl_chantype,
+                         uint8_t *link_id);
diff --git a/src/host/virt_phy/src/l1ctl_sap.c b/src/host/virt_phy/src/l1ctl_sap.c
index b5fb0f0..91f1d10 100644
--- a/src/host/virt_phy/src/l1ctl_sap.c
+++ b/src/host/virt_phy/src/l1ctl_sap.c
@@ -4,9 +4,13 @@
 #include <osmocom/core/msgb.h>
 #include <osmocom/core/utils.h>
 #include <osmocom/core/gsmtap.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/rsl.h>
 #include <stdio.h>
 #include <l1ctl_proto.h>
 #include <netinet/in.h>
+#include <string.h>
 
 #include "virtual_um.h"
 #include "l1ctl_sock.h"
@@ -16,6 +20,18 @@
 #include "gsmtapl1_if.h"
 
 static struct l1_model_ms *l1_model_ms = NULL;
+
+static void l1_model_tch_mode_set(uint8_t tch_mode)
+{
+	if (tch_mode == GSM48_CMODE_SPEECH_V1
+	                || tch_mode == GSM48_CMODE_SPEECH_EFR) {
+		l1_model_ms->state->tch_mode = tch_mode;
+
+	} else {
+		// set default value if no proper mode was assigned by l23
+		l1_model_ms->state->tch_mode = GSM48_CMODE_SIGN;
+	}
+}
 
 /**
  * @brief Init the SAP.
@@ -30,7 +46,8 @@
  *
  * Enqueues the message into the rx queue.
  */
-void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_inst *lsi, struct msgb *msg)
+void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_inst *lsi,
+                                   struct msgb *msg)
 {
 	// check if the received msg is not empty
 	if (msg) {
@@ -56,11 +73,11 @@
 {
 	uint16_t *len;
 	/* prepend 16bit length before sending */
-	len = (uint16_t *) msgb_push(msg, sizeof(*len));
+	len = (uint16_t *)msgb_push(msg, sizeof(*len));
 	*len = htons(msg->len - sizeof(*len));
 
-	if(l1ctl_sock_write_msg(lsi, msg) == -1 ) {
-		//DEBUGP(DL1C, "Error writing to layer2 socket");
+	if (l1ctl_sock_write_msg(lsi, msg) == -1) {
+		DEBUGP(DL1C, "Error writing to layer2 socket");
 	}
 }
 
@@ -140,22 +157,22 @@
 /**
  * @brief General handler for incoming L1CTL messages from layer 2/3.
  *
- * This handler will dequeue the rx queue (if !empty) and call the specific routine for the dequeued l1ctl message.
+ * This handler will call the specific routine dependent on the L1CTL message type.
  *
  */
 void l1ctl_sap_handler(struct msgb *msg)
 {
-//	struct msgb *msg;
 	struct l1ctl_hdr *l1h;
-	unsigned long flags;
 
-	if (!msg)
+	if (!msg) {
 		return;
+	}
 
 	l1h = (struct l1ctl_hdr *)msg->data;
 
 	if (sizeof(*l1h) > msg->len) {
-		LOGP(DL1C, LOGL_NOTICE, "Short message. %u\n", msg->len);
+		LOGP(DL1C, LOGL_NOTICE, "Malformed message: too short. %u\n",
+		                msg->len);
 		goto exit_msgbfree;
 	}
 
@@ -182,7 +199,6 @@
 		l1ctl_rx_rach_req(msg);
 		// msg is freed by rx routine
 		goto exit_nofree;
-		break;
 	case L1CTL_DATA_REQ:
 		l1ctl_rx_data_req(msg);
 		/* we have to keep the msgb, not free it! */
@@ -229,24 +245,29 @@
  * Transmit frequency control and synchronisation bursts on FCCH and SCH to calibrate transceiver and search for base stations.
  * Sync to a given arfcn.
  *
- * Note: Not needed for virtual physical layer.
+ * Note: ms will start receiving msgs on virtual um only after this req was received.
+ * Note: virt bts does not broadcast freq and sync bursts.
+ *
  * TODO: Could be used to bind/connect to different virtual_bts sockets with a arfcn-socket mapping.
+ * TODO: Check flags if this is a sync or freq request and handle it accordingly.
  */
 void l1ctl_rx_fbsb_req(struct msgb *msg)
 {
 	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
 	struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *)l1h->data;
 
-	DEBUGP(DL1C, "Received and handled from l23 - L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
+	DEBUGP(DL1C,
+	                "Received and handled from l23 - L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
 	                ntohs(sync_req->band_arfcn), sync_req->flags);
 
 	l1_model_ms->state->camping = 1;
-	l1_model_ms->state->serving_cell.arfcn = ntohs(sync_req->band_arfcn);
-	l1_model_ms->state->serving_cell.ccch_mode = sync_req->ccch_mode;
-	l1_model_ms->state->serving_cell.fn_offset = 0;
-	l1_model_ms->state->serving_cell.bsic = 0;
-	l1_model_ms->state->serving_cell.time_alignment = 0;
-	// TODO: reset and synchronize the ms uplink schedulers with bts multiframe structure.
+	l1_model_ms->state->serving_cell.arfcn = ntohs(sync_req->band_arfcn); // freq req
+
+	// not needed in virt um
+	l1_model_ms->state->serving_cell.ccch_mode = sync_req->ccch_mode; // sync req
+	l1_model_ms->state->serving_cell.fn_offset = 0; // sync req
+	l1_model_ms->state->serving_cell.bsic = 0; // sync req
+	l1_model_ms->state->serving_cell.time_alignment = 0; // sync req
 
 	l1ctl_tx_fbsb_conf(0, l1_model_ms->state->serving_cell.arfcn);
 }
@@ -268,47 +289,25 @@
 	struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
 	struct l1ctl_dm_est_req *est_req =
 	                (struct l1ctl_dm_est_req *)ul->payload;
+	uint8_t rsl_chantype, subslot, timeslot;
+
+	rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, &timeslot);
 
 	DEBUGP(DL1C,
-	                "Received and handled from l23 - L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n",
-	                ntohs(est_req->h0.band_arfcn), ul->chan_nr,
-	                est_req->tsc);
+	                "Received and handled from l23 - L1CTL_DM_EST_REQ (chan_nr=0x%02x, tn=%u)\n",
+	                ul->chan_nr, timeslot);
 
-//	/* disable neighbour cell measurement of C0 TS 0 */
-//	mframe_disable(MF_TASK_NEIGH_PM51_C0T0);
-//
-//	/* configure dedicated channel state */
-//	l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
-//	l1s.dedicated.tsc  = est_req->tsc;
-//	l1s.dedicated.tn   = ul->chan_nr & 0x7;
-//	l1s.dedicated.h    = est_req->h;
-//
-//	if (est_req->h) {
-//		int i;
-//		l1s.dedicated.h1.hsn  = est_req->h1.hsn;
-//		l1s.dedicated.h1.maio = est_req->h1.maio;
-//		l1s.dedicated.h1.n    = est_req->h1.n;
-//		for (i=0; i<est_req->h1.n; i++)
-//			l1s.dedicated.h1.ma[i] = ntohs(est_req->h1.ma[i]);
-//	} else {
-//		l1s.dedicated.h0.arfcn = ntohs(est_req->h0.band_arfcn);
-//	}
-//
-//	/* TCH config */
-//	if (chan_nr_is_tch(ul->chan_nr)) {
-//		/* Mode */
-//		l1a_tch_mode_set(est_req->tch_mode);
-//		l1a_audio_mode_set(est_req->audio_mode);
-//
-//		/* Sync */
-//		l1s.tch_sync = 1;	/* can be set without locking */
-//
-//		/* Audio path */
-//		audio_set_enabled(est_req->tch_mode, est_req->audio_mode);
-//	}
-//
-//	/* figure out which MF tasks to enable */
-//	l1a_mftask_set(chan_nr2mf_task_mask(ul->chan_nr, NEIGH_MODE_PM));
+	l1_model_ms->state->dedicated.chan_type = rsl_chantype;
+	l1_model_ms->state->dedicated.tn = timeslot;
+
+	/* TCH config */
+	if (rsl_chantype == RSL_CHAN_Bm_ACCHs
+	                || rsl_chantype == RSL_CHAN_Lm_ACCHs) {
+		l1_model_ms->state->tch_mode = est_req->tch_mode;
+		l1_model_tch_mode_set(est_req->tch_mode);
+		l1_model_ms->state->audio_mode = est_req->audio_mode;
+		// TODO: configure audio hardware for encoding / decoding / recording / playing voice
+	}
 }
 
 /**
@@ -320,7 +319,7 @@
  *
  * Handle frequency change in dedicated mode. E.g. used for frequency hopping.
  *
- * Note: Not needed for virtual physical layer.
+ * Note: Not needed for virtual physical layer as freqency hopping is generally disabled.
  */
 void l1ctl_rx_dm_freq_req(struct msgb *msg)
 {
@@ -330,8 +329,9 @@
 	                (struct l1ctl_dm_freq_req *)ul->payload;
 
 	DEBUGP(DL1C,
-	                "Received and ignored from l23 - L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n",
-	                ntohs(freq_req->h0.band_arfcn), freq_req->tsc);
+	                "Received and ignored from l23 - L1CTL_DM_FREQ_REQ (arfcn0=%u, hsn=%u, maio=%u)\n",
+	                ntohs(freq_req->h0.band_arfcn), freq_req->h1.hsn,
+	                freq_req->h1.maio);
 }
 
 /**
@@ -359,12 +359,14 @@
 	                "Received and handled from l23 - L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n",
 	                cr->algo, key_len);
 
-//	if (cr->algo && key_len != 8) {
-//		DEBUGP(DL1C, "L1CTL_CRYPTO_REQ -> Invalid key\n");
-//		return;
-//	}
-//
-//	dsp_load_ciph_param(cr->algo, cr->key);
+	if (cr->algo && key_len != A5_KEY_LEN) {
+		DEBUGP(DL1C, "L1CTL_CRYPTO_REQ -> Invalid key\n");
+		return;
+	}
+
+	l1_model_ms->crypto_inf->algo = cr->algo;
+	memcpy(l1_model_ms->crypto_inf->key, cr->key,
+	                sizeof(uint8_t) * A5_KEY_LEN);
 }
 
 /**
@@ -380,19 +382,13 @@
  */
 void l1ctl_rx_dm_rel_req(struct msgb *msg)
 {
-//	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+	DEBUGP(DL1C, "Received and handled from l23 - L1CTL_DM_REL_REQ\n");
 
-	DEBUGP(DL1C, "Received and ignored from l23 - L1CTL_DM_REL_REQ\n");
-//	l1a_mftask_set(0);
-//	l1s.dedicated.type = GSM_DCHAN_NONE;
-//	l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_MAIN]);
-//	l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_SACCH]);
-//	l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_TRAFFIC]);
-//	l1a_meas_msgb_set(NULL);
-//	dsp_load_ciph_param(0, NULL);
-//	l1a_tch_mode_set(GSM48_CMODE_SIGN);
-//	audio_set_enabled(GSM48_CMODE_SIGN, 0);
-//	l1s.neigh_pm.n = 0;
+	l1_model_ms->state->dedicated.chan_type = 0;
+	l1_model_ms->state->tch_mode = GSM48_CMODE_SIGN;
+
+	// TODO: disable ciphering
+	// TODO: disable audio recording / playing
 }
 
 /**
@@ -424,44 +420,38 @@
  *
  * @param [in] msg the received message.
  *
- * Transmit RACH request on RACH.
+ * Transmit RACH request on RACH. Refer to 04.08 - 9.1.8 - Channel request.
  *
- * TODO: Implement this handler routine!
  */
 void l1ctl_rx_rach_req(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_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
-
-	uint32_t fn_sched;
-	uint8_t ts;
+	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+	struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
+	struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *)ul->payload;
+	// FIXME: proper frame number
+	uint32_t fn_sched = 42;
 
 	DEBUGP(DL1C,
 	                "Received and handled from l23 - L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
 	                rach_req->ra, ntohs(rach_req->offset),
 	                rach_req->combined);
 
-	// TODO: calculate correct fn/ts for a RACH (if needed by bts)
-	// TODO: implement scheduler for uplink!
-	fn_sched = 42;
-	ts = 0;
 	// for the rach channel request, there is no layer2 header, but only the one bit ra content to submit
-	// see 4.18-9.1.8 CHannel Request
-	// that means we have to set l2h of msgb to the ra content
-	msg->l2h = &rach_req->ra;
-	// avoid all data after ra to also be submitted
-	msgb_trim(msg, sizeof(rach_req->ra));
-	// TODO: check if we need to submit more data than the ra content to the bts
+	// replace l1ctl_rach_req with ra data that rly shall be submitted
+	// ra on peer side is decoded as uint16_t, but we do not use the 11bit option and thus 8bits must be sufficient
+	msg->l2h = msgb_put(msg, sizeof(uint8_t));
+	*msg->l2h = rach_req->ra;
+
+	// chan_nr is not specified in info_ul for rach request coming from l23, but needed in gsmtapl1_tx_to_virt_um()
+	ul->chan_nr = rsl_enc_chan_nr(RSL_CHAN_RACH, 0, 0);
+	ul->link_id = LID_DEDIC;
 
 	// send rach over virt um
-	gsmtapl1_tx_to_virt_um(ts, fn_sched, GSMTAP_CHANNEL_RACH, msg);
+	gsmtapl1_tx_to_virt_um(fn_sched, msg);
 
 	// send confirm to layer23
 	l1ctl_tx_rach_conf(fn_sched, l1_model_ms->state->serving_cell.arfcn);
 
-// l1a_rach_req(ntohs(rach_req->offset), rach_req->combined,
-//		rach_req->ra);
 }
 
 /**
@@ -473,36 +463,29 @@
  *
  * Transmit message on a signalling channel. FACCH/SDCCH or SACCH depending on the headers set link id (TS 8.58 - 9.3.2).
  *
- * TODO: Implement this handler routine!
+ * TODO: Check if a msg on FACCH is coming in here and needs special handling.
  */
 void l1ctl_rx_data_req(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_data_ind *data_ind = (struct l1ctl_data_ind *)ul->payload;
-	struct llist_head *tx_queue;
+	// FIXME: proper frame number
+	uint32_t fn_sched = 42;
 
 	DEBUGP(DL1C,
-	                "Received and handled from l23 - L1CTL_DATA_REQ (link_id=0x%02x)\n",
-	                ul->link_id);
+	                "Received and handled from l23 - L1CTL_DATA_REQ (link_id=0x%02x, ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p)\n",
+	                ul->link_id, ul, ul->payload, data_ind, data_ind->data,
+	                msg->l3h);
 
-//	msg->l3h = data_ind->data;
-//	if (ul->link_id & 0x40) {
-//		struct gsm48_hdr *gh = (struct gsm48_hdr *)(data_ind->data + 5);
-//		if (gh->proto_discr == GSM48_PDISC_RR
-//		 && gh->msg_type == GSM48_MT_RR_MEAS_REP) {
-//			DEBUGP(DL1C, "updating measurement report\n");
-//			l1a_meas_msgb_set(msg);
-//			return;
-//		}
-//		tx_queue = &l1s.tx_queue[L1S_CHAN_SACCH];
-//	} else
-//		tx_queue = &l1s.tx_queue[L1S_CHAN_MAIN];
-//
-//	DEBUGP(DL1C, "ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p\n",
-//		ul, ul->payload, data_ind, data_ind->data, msg->l3h);
-//
-//	l1a_txq_msgb_enq(tx_queue, msg);
+	msg->l2h = data_ind->data;
+
+	// send msg over virt um
+	gsmtapl1_tx_to_virt_um(fn_sched, msg);
+
+	// send confirm to layer23
+	msg = l1ctl_create_l2_msg(L1CTL_DATA_CONF, fn_sched, 0, 0);
+	l1ctl_sap_tx_to_l23(msg);
 }
 
 /**
@@ -528,26 +511,33 @@
 	pm_req->range.band_arfcn_from = ntohs(pm_req->range.band_arfcn_from);
 	pm_req->range.band_arfcn_to = ntohs(pm_req->range.band_arfcn_to);
 
-	DEBUGP(DL1C, "Received from l23 - L1CTL_PM_REQ TYPE=%u, FROM=%d, TO=%d\n",
-	                pm_req->type, pm_req->range.band_arfcn_from, pm_req->range.band_arfcn_to);
+	DEBUGP(DL1C,
+	                "Received from l23 - L1CTL_PM_REQ TYPE=%u, FROM=%d, TO=%d\n",
+	                pm_req->type, pm_req->range.band_arfcn_from,
+	                pm_req->range.band_arfcn_to);
 
-	for(arfcn_next = pm_req->range.band_arfcn_from; arfcn_next <= pm_req->range.band_arfcn_to; ++arfcn_next) {
-		struct l1ctl_pm_conf *pm_conf = (struct l1ctl_pm_conf *)msgb_put(resp_msg, sizeof(*pm_conf));
+	for (arfcn_next = pm_req->range.band_arfcn_from;
+	                arfcn_next <= pm_req->range.band_arfcn_to;
+	                ++arfcn_next) {
+		struct l1ctl_pm_conf *pm_conf =
+		                (struct l1ctl_pm_conf *)msgb_put(resp_msg,
+		                                sizeof(*pm_conf));
 		pm_conf->band_arfcn = htons(arfcn_next);
 		// rxlev 63 is great, 0 is bad the two values are min and max
 		pm_conf->pm[0] = 63;
 		pm_conf->pm[1] = 63;
-		if(arfcn_next == pm_req->range.band_arfcn_to) {
+		if (arfcn_next == pm_req->range.band_arfcn_to) {
 			struct l1ctl_hdr *resp_l1h = msgb_l1(resp_msg);
 			resp_l1h->flags |= L1CTL_F_DONE;
 		}
-		// no more space in msgb, flush to l2
-		if(msgb_tailroom(resp_msg) < sizeof(*pm_conf)) {
+		// no more space to hold mor pm info in msgb, flush to l23
+		if (msgb_tailroom(resp_msg) < sizeof(*pm_conf)) {
 			l1ctl_sap_tx_to_l23(resp_msg);
 			resp_msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
 		}
 	}
-	if(resp_msg) {
+	// transmit the remaining part of pm response to l23
+	if (resp_msg) {
 		l1ctl_sap_tx_to_l23(resp_msg);
 	}
 }
@@ -563,7 +553,6 @@
  *
  * Note: Currently we do not perform anything else than response with a reset confirm
  * to just tell l2 that we are rdy.
- * TODO: Validate if an action has to be done here.
  *
  */
 void l1ctl_rx_reset_req(struct msgb *msg)
@@ -573,16 +562,20 @@
 
 	switch (reset_req->type) {
 	case L1CTL_RES_T_FULL:
-		DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RESET_REQ (type=FULL)\n");
+		DEBUGP(DL1C,
+		                "Received and handled from l23 - L1CTL_RESET_REQ (type=FULL)\n");
 		l1_model_ms->state->camping = 0;
+		// TODO: check if we also need to reset the dedicated channel state
 		l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
 		break;
 	case L1CTL_RES_T_SCHED:
-		DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RESET_REQ (type=SCHED)\n");
+		DEBUGP(DL1C,
+		                "Received and handled from l23 - L1CTL_RESET_REQ (type=SCHED)\n");
 		l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
 		break;
 	default:
-		LOGP(DL1C, LOGL_ERROR, "Received and ignored from l23 - L1CTL_RESET_REQ (type=unknown)\n");
+		LOGP(DL1C, LOGL_ERROR,
+		                "Received and ignored from l23 - L1CTL_RESET_REQ (type=unknown)\n");
 		break;
 	}
 }
@@ -595,6 +588,8 @@
  * @param [in] msg the received message.
  *
  * Configure CCCH combined / non-combined mode.
+ *
+ * @see l1ctl_proto.h -- enum ccch_mode
  *
  * TODO: Implement this handler routine!
  */
@@ -610,22 +605,7 @@
 	l1_model_ms->state->serving_cell.ccch_mode = ccch_mode;
 
 	// check if more has to be done here
-
 	l1ctl_tx_ccch_mode_conf(ccch_mode);
-
-//	/* pre-set the CCCH mode */
-//	l1s.serving_cell.ccch_mode = ccch_mode;
-//
-//	/* Update task */
-//	mframe_disable(MF_TASK_CCCH_COMB);
-//	mframe_disable(MF_TASK_CCCH);
-//
-//	if (ccch_mode == CCCH_MODE_COMBINED)
-//		mframe_enable(MF_TASK_CCCH_COMB);
-//	else if (ccch_mode == CCCH_MODE_NON_COMBINED)
-//		mframe_enable(MF_TASK_CCCH);
-//
-//	l1ctl_tx_ccch_mode_conf(ccch_mode);
 }
 
 /**
@@ -644,20 +624,18 @@
 	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
 	struct l1ctl_tch_mode_req *tch_mode_req =
 	                (struct l1ctl_tch_mode_req *)l1h->data;
-	uint8_t tch_mode = tch_mode_req->tch_mode;
-	uint8_t audio_mode = tch_mode_req->audio_mode;
+
+	l1_model_tch_mode_set(tch_mode_req->tch_mode);
+	l1_model_ms->state->audio_mode = tch_mode_req->audio_mode;
 
 	DEBUGP(DL1C,
 	                "Received and handled from l23 - L1CTL_TCH_MODE_REQ (tch_mode=0x%02x audio_mode=0x%02x)\n",
-	                tch_mode, audio_mode);
-//	tch_mode = l1a_tch_mode_set(tch_mode);
-//	audio_mode = l1a_audio_mode_set(audio_mode);
-//
-//	audio_set_enabled(tch_mode, audio_mode);
-//
-//	l1s.tch_sync = 1; /* Needed for audio to work */
-//
-//	l1ctl_tx_tch_mode_conf(tch_mode, audio_mode);
+	                tch_mode_req->tch_mode, tch_mode_req->audio_mode);
+
+	// TODO: configure audio hardware for encoding / decoding / recording / playing voice
+
+	l1ctl_tx_tch_mode_conf(l1_model_ms->state->tch_mode,
+	                l1_model_ms->state->audio_mode);
 }
 
 /**
@@ -671,7 +649,7 @@
  * The neighbor cell description is one of the info messages sent by the BTS on BCCH.
  * This method will also enable neighbor measurement in the multiframe scheduler.
  *
- * Note: Not needed for virtual physical layer.
+ * Note: Not needed for virtual physical layer as we dont maintain neigbors.
  */
 void l1ctl_rx_neigh_pm_req(struct msgb *msg)
 {
@@ -691,30 +669,26 @@
  *
  * @param [in] msg the received message.
  *
- * Enqueue the message (traffic frame) to the L1 state machine's transmit queue.
- * Will drop the traffic frame at queue sizes >= 4.
+ * Enqueue the message (traffic frame) to the L1 state machine's transmit queue. In virtual layer1 just submit it to the virt um.
  *
- * TODO: Implement this handler routine!
  */
 void l1ctl_rx_traffic_req(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_traffic_req *tr = (struct l1ctl_traffic_req *)ul->payload;
-	int num = 0;
+	uint32_t fn_sched = 42;
 
 	DEBUGP(DL1C, "Received and handled from l23 - L1CTL_TRAFFIC_REQ\n");
 
-//	msg->l2h = tr->data;
+	msg->l2h = tr->data;
 
-//	num = l1a_txq_msgb_count(&l1s.tx_queue[L1S_CHAN_TRAFFIC]);
-//	if (num >= 4) {
-//		DEBUGP(DL1C, "dropping traffic frame\n");
-//		msgb_free(msg);
-//		return;
-//	}
-//
-//	l1a_txq_msgb_enq(&l1s.tx_queue[L1S_CHAN_TRAFFIC], msg);
+	// send msg over virt um
+	gsmtapl1_tx_to_virt_um(fn_sched, msg);
+
+	// send confirm to layer23
+	msg = l1ctl_create_l2_msg(L1CTL_TRAFFIC_CONF, fn_sched, 0, 0);
+	l1ctl_sap_tx_to_l23(msg);
 }
 
 /**
@@ -727,6 +701,7 @@
  * Forward and a sim request to the SIM APDU.
  *
  * Note: Not needed for virtual layer. Please configure layer23 application to use test-sim implementation.
+ * In this case layer1 wont need to handle sim logic.
  * ms <x>
  * --------
  * sim test
@@ -766,7 +741,7 @@
 	reset_resp->type = reset_type;
 
 	DEBUGP(DL1C, "Sending to l23 - %s (reset_type: %u)\n",
-	       	       getL1ctlPrimName(msg_type), reset_type);
+	                getL1ctlPrimName(msg_type), reset_type);
 	l1ctl_sap_tx_to_l23(msg);
 }
 
@@ -783,7 +758,7 @@
 	struct msgb * msg = l1ctl_create_l2_msg(L1CTL_RACH_CONF, fn, 0, arfcn);
 
 	DEBUGP(DL1C, "Sending to l23 - %s (fn: %u, arfcn: %u)\n",
-	       	       getL1ctlPrimName(L1CTL_RACH_CONF), fn, arfcn);
+	                getL1ctlPrimName(L1CTL_RACH_CONF), fn, arfcn);
 	l1ctl_sap_tx_to_l23(msg);
 }
 
@@ -807,22 +782,20 @@
  * @param [in] res 0 -> success, 255 -> error.
  * @param [in] arfcn the arfcn we are synced to.
  *
- * No calculation needed for virtual pyh -> uses default values for a good link quality.
+ * No calculation needed for virtual pyh -> uses dummy values for a good link quality.
  */
 void l1ctl_tx_fbsb_conf(uint8_t res, uint16_t arfcn)
 {
 	struct msgb *msg;
 	struct l1ctl_fbsb_conf *resp;
 	uint32_t fn = 0; // 0 should be okay here
-	uint16_t snr = 40; // signal noise ratio > 40db is best signal.
-	int16_t initial_freq_err = 0; // 0 means no error.
-	uint8_t bsic = 0;
+	uint16_t snr = 40; // signal noise ratio > 40db is best signal (unused in virt)
+	int16_t initial_freq_err = 0; // 0 means no error (unused in virt)
+	uint8_t bsic = 0; // bsci can be read from sync burst (unused in virt)
 
-	msg = l1ctl_create_l2_msg(L1CTL_FBSB_CONF, fn,
-			snr,
-			arfcn);
+	msg = l1ctl_create_l2_msg(L1CTL_FBSB_CONF, fn, snr, arfcn);
 
-	resp = (struct l1ctl_fbsb_conf *) msgb_put(msg, sizeof(*resp));
+	resp = (struct l1ctl_fbsb_conf *)msgb_put(msg, sizeof(*resp));
 	resp->initial_freq_err = htons(initial_freq_err);
 	resp->result = res;
 	resp->bsic = bsic;
@@ -875,9 +848,8 @@
 	mode_conf->audio_mode = audio_mode;
 
 	DEBUGP(DL1C,
-	                "Sending to l23 - L1CTL_TCH_MODE_CONF (tch_mode: %u, audio_mode: %u)\n", tch_mode,
-	                audio_mode);
+	                "Sending to l23 - L1CTL_TCH_MODE_CONF (tch_mode: %u, audio_mode: %u)\n",
+	                tch_mode, audio_mode);
 	l1ctl_sap_tx_to_l23(msg);
 }
-
 
diff --git a/src/host/virt_phy/src/l1ctl_sap.h b/src/host/virt_phy/src/l1ctl_sap.h
index f540197..9472013 100644
--- a/src/host/virt_phy/src/l1ctl_sap.h
+++ b/src/host/virt_phy/src/l1ctl_sap.h
@@ -15,6 +15,10 @@
 #define L3_MSG_DATA 200
 #define L3_MSG_SIZE (sizeof(struct l1ctl_hdr) + L3_MSG_HEAD + L3_MSG_DATA)
 
+/* lchan link ID */
+#define LID_SACCH 		0x40
+#define LID_DEDIC 		0x00
+
 void l1ctl_sap_init(struct l1_model_ms *model);
 void l1ctl_sap_tx_to_l23_inst(struct l1ctl_sock_inst *lsi, struct msgb *msg);
 void l1ctl_sap_tx_to_l23(struct msgb *msg);
diff --git a/src/host/virt_phy/src/virt_l1_model.h b/src/host/virt_phy/src/virt_l1_model.h
index f0619ab..38d9efe 100644
--- a/src/host/virt_phy/src/virt_l1_model.h
+++ b/src/host/virt_phy/src/virt_l1_model.h
@@ -1,29 +1,65 @@
 #pragma once
 
-#include <layer1/sync.h>
 #include "l1ctl_sock.h"
 #include "virtual_um.h"
+
+#define L1S_NUM_NEIGH_CELL	6
+#define A5_KEY_LEN		8
 
 struct l1_model_ms {
 	struct l1ctl_sock_inst *lsi;
 	struct virt_um_inst *vui;
 	struct l1_state_ms *state;
+	struct crypto_info_ms *crypto_inf;
 };
 
-//TODO: must contain logical channel information (fram number, ciphering mode, ...)
+/* structure representing L1 sync information about a cell */
+struct l1_cell_info {
+	/* on which ARFCN (+band) is the cell? */
+	uint16_t	arfcn;
+	/* what's the BSIC of the cell (from SCH burst decoding) */
+	uint8_t		bsic;
+	/* Combined or non-combined CCCH */
+	uint8_t		ccch_mode; /* enum ccch_mode */
+	/* whats the delta of the cells current GSM frame number
+	 * compared to our current local frame number */
+	int32_t		fn_offset;
+	/* how much does the TPU need adjustment (delta) to synchronize
+	 * with the cells burst */
+	uint32_t	time_alignment;
+};
+
+struct crypto_info_ms {
+	/* key is expected in the same format as in RSL
+	 * Encryption information IE. */
+	uint8_t key[A5_KEY_LEN];
+	uint8_t algo;
+};
+
 struct l1_state_ms {
 
-	uint8_t camping;
+	uint8_t camping; // are we currently camping on a cell
+
 	/* the cell on which we are camping right now */
 	struct l1_cell_info serving_cell;
-
 	/* neighbor cell sync info */
 	struct l1_cell_info neigh_cell[L1S_NUM_NEIGH_CELL];
 
-	/* TCH */
-	uint8_t tch_mode;
-	uint8_t tch_sync;
-	uint8_t audio_mode;
+	/* TCH info */
+	uint8_t tch_mode; // see enum gsm48_chan_mode in gsm_04_08.h
+	uint8_t tch_sync; // needed for audio synchronization
+	uint8_t audio_mode; // see l1ctl_proto.h, e.g. AUDIO_TX_MICROPHONE
+
+	/* dedicated channel info */
+	struct {
+		uint8_t chan_type; // like rsl chantype 08.58 -> Chapter 9.3.1 */
+
+		uint8_t tn; // timeslot number 1-7
+
+		uint8_t scn; // single-hop cellular network? (ununsed in virtual um)
+		uint8_t tsc; // training sequence code (ununsed in virtual um)
+		uint8_t h; // hopping enabled flag (ununsed in virtual um)
+	} dedicated;
 };
 
 struct l1_model_ms *l1_model_ms_init(void *ctx);
diff --git a/src/host/virt_phy/src/virtphy.c b/src/host/virt_phy/src/virtphy.c
index 94f6fa5..b2a2d4f 100644
--- a/src/host/virt_phy/src/virtphy.c
+++ b/src/host/virt_phy/src/virtphy.c
@@ -17,10 +17,10 @@
 
 int main(void)
 {
-
 	// init loginfo
 	static struct l1_model_ms *model;
-	ms_log_init("DL1C,1:DVIRPHY,1");
+	//ms_log_init("DL1C,1:DVIRPHY,1");
+	ms_log_init("DL1C,1");
 	//ms_log_init("DL1C,8:DVIRPHY,8");
 
 	LOGP(DVIRPHY, LOGL_INFO, "Virtual physical layer starting up...\n");
@@ -28,7 +28,10 @@
 	model = l1_model_ms_init(NULL);
 
 	// TODO: make this configurable
-	model->vui = virt_um_init(NULL, DEFAULT_BTS_MCAST_GROUP, DEFAULT_BTS_MCAST_PORT, DEFAULT_MS_MCAST_GROUP, DEFAULT_MS_MCAST_PORT, gsmtapl1_rx_from_virt_um_inst_cb);
+	model->vui = virt_um_init(NULL, DEFAULT_BTS_MCAST_GROUP,
+	                DEFAULT_BTS_MCAST_PORT, DEFAULT_MS_MCAST_GROUP,
+	                DEFAULT_MS_MCAST_PORT,
+	                gsmtapl1_rx_from_virt_um_inst_cb);
 	model->lsi = l1ctl_sock_init(NULL, l1ctl_sap_rx_from_l23_inst_cb, NULL);
 
 	gsmtapl1_init(model);
diff --git a/src/host/virt_phy/src/virtual_um.c b/src/host/virt_phy/src/virtual_um.c
index 2b15509..e2e86e4 100644
--- a/src/host/virt_phy/src/virtual_um.c
+++ b/src/host/virt_phy/src/virtual_um.c
@@ -19,7 +19,6 @@
  *
  */
 
-#include <unistd.h>
 #include <osmocom/core/select.h>
 #include <osmocom/core/utils.h>
 #include <osmocom/core/socket.h>
@@ -46,10 +45,12 @@
 		int rc;
 
 		// read message from fd in message buffer
-		rc = mcast_bidir_sock_rx(vui->mcast_sock, msgb_data(msg), msgb_tailroom(msg));
+		rc = mcast_bidir_sock_rx(vui->mcast_sock, msgb_data(msg),
+		                msgb_tailroom(msg));
 		// rc is number of bytes actually read
 		if (rc > 0) {
 			msgb_put(msg, rc);
+			msg->l1h = msgb_data(msg);
 			// call the l1 callback function for a received msg
 			vui->recv_cb(vui, msg);
 		} else {
@@ -68,12 +69,13 @@
 
 struct virt_um_inst *virt_um_init(
                 void *ctx, const char *tx_mcast_group, uint16_t tx_mcast_port,
-                const char *rx_mcast_group, uint16_t rx_mcast_port, void (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg))
+                const char *rx_mcast_group, uint16_t rx_mcast_port,
+                void (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg))
 {
-
 	struct virt_um_inst *vui = talloc_zero(ctx, struct virt_um_inst);
-	vui->mcast_sock = mcast_bidir_sock_setup(ctx, tx_mcast_group, tx_mcast_port,
-	                rx_mcast_group, rx_mcast_port, 1, virt_um_fd_cb, vui);
+	vui->mcast_sock = mcast_bidir_sock_setup(ctx, tx_mcast_group,
+	                tx_mcast_port, rx_mcast_group, rx_mcast_port, 1,
+	                virt_um_fd_cb, vui);
 	vui->recv_cb = recv_cb;
 
 	return vui;
@@ -93,7 +95,8 @@
 {
 	int rc;
 
-	rc = mcast_bidir_sock_tx(vui->mcast_sock, msgb_data(msg), msgb_length(msg));
+	rc = mcast_bidir_sock_tx(vui->mcast_sock, msgb_data(msg),
+	                msgb_length(msg));
 	msgb_free(msg);
 
 	return rc;

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibad741d112643c55091b8ba00164b05d728ae1a1
Gerrit-PatchSet: 1
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: BastusIII <sebastian.stumpf87 at googlemail.com>



More information about the gerrit-log mailing list