summaryrefslogtreecommitdiffstats
path: root/src/host/virt_phy/src/l1ctl_sap.c
diff options
context:
space:
mode:
authorSebastian Stumpf <sebastian.stumpf87@googlemail.com>2017-01-09 17:05:31 +0100
committerHarald Welte <laforge@gnumonks.org>2017-07-12 23:26:26 +0200
commita4aaa14878f51bb61bd435a17ea95abe0e4a4e63 (patch)
treef66bdb276726c1f8beae51e4926490e1de6a359f /src/host/virt_phy/src/l1ctl_sap.c
parent064ffe6563cdf7105d97e3d45c2d14520cea8352 (diff)
VIRT-PHY: Initial commit of virt-phy to work with osmo-bts virt-phy.
This patch implements a virtual physical layer replacing the air interface. The purpose is to get rid of the hardware requirements and be able to start testing and implementing layer 2 communication functionality on one machine. Multicast sockets are used to enable bidirectional communication between the BTS and the MS process. The GSMTAP protocol designed for wireshark capturing is used to encapsulate the payload on the virtual physical layer. The virtual physical layer on the osmocom-bb side implements the L1CTL interface to the layer23 apps like mobile. * Working mcast socket communication and extraction of its functionality. * Basic handlers for file descriptor callbacks from incoming L1CTL messages and extraction of that functionality to a l1ctl socket class. * Multiplexing to different routines depending on incoming L1CTL message type. * Uses virt_um and osmocom_mcast_sock implementation from osmo-bts virt-phy. * Ecapsulation and parsing methods to and from GSMTAP messages. * Basic handlers for file descriptor callbacks from incoming mcast messages on the virtual um. * Multiplexing to different channel routines based on GSMTAP header channel type. * Example configuration for l23 app mobile using virtual test sim. Change-Id: I203c8ec58326e52a09603a37232fce7ae3641415
Diffstat (limited to 'src/host/virt_phy/src/l1ctl_sap.c')
-rw-r--r--src/host/virt_phy/src/l1ctl_sap.c833
1 files changed, 833 insertions, 0 deletions
diff --git a/src/host/virt_phy/src/l1ctl_sap.c b/src/host/virt_phy/src/l1ctl_sap.c
new file mode 100644
index 00000000..46121ed1
--- /dev/null
+++ b/src/host/virt_phy/src/l1ctl_sap.c
@@ -0,0 +1,833 @@
+/* L1CTL SAP implementation. */
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/utils.h>
+#include <stdio.h>
+#include <l1ctl_proto.h>
+#include <netinet/in.h>
+
+#include "virtual_um.h"
+#include "l1ctl_sock.h"
+#include "virt_l1_model.h"
+#include "l1ctl_sap.h"
+#include "logging.h"
+
+static struct l1_model_ms *l1_model_ms = NULL;
+
+/**
+ * @brief Init the SAP.
+ */
+void l1ctl_sap_init(struct l1_model_ms *model)
+{
+ l1_model_ms = model;
+}
+
+/**
+ * @brief L1CTL handler called for received messages from L23.
+ *
+ * Enqueues the message into the rx queue.
+ */
+void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_inst *lsi, struct msgb *msg)
+{
+ if (msg) {
+ DEBUGP(DL1C, "Message incoming from layer 2: %s\n",
+ osmo_hexdump(msg->data, msg->len));
+ l1ctl_sap_handler(msg);
+ }
+}
+/**
+ * @see l1ctl_sap_rx_from_l23_cb(struct l1ctl_sock_inst *lsi, struct msgb *msg).
+ */
+void l1ctl_sap_rx_from_l23(struct msgb *msg)
+{
+ l1ctl_sap_rx_from_l23_inst_cb(l1_model_ms->lsi, msg);
+}
+
+/**
+ * @brief Send a l1ctl message to layer 23.
+ *
+ * This will forward the message as it is to the upper layer.
+ */
+void l1ctl_sap_tx_to_l23_inst(struct l1ctl_sock_inst *lsi, struct msgb *msg)
+{
+ uint16_t *len;
+ /* prepend 16bit length before sending */
+ 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");
+ }
+}
+
+/**
+ * @see void l1ctl_sap_tx_to_l23(struct l1ctl_sock_inst *lsi, struct msgb *msg).
+ */
+void l1ctl_sap_tx_to_l23(struct msgb *msg)
+{
+ l1ctl_sap_tx_to_l23_inst(l1_model_ms->lsi, msg);
+}
+
+/**
+ * @brief Allocates a msgb with set l1ctl header and room for a l3 header.
+ *
+ * @param [in] msg_type L1CTL primitive message type set to l1ctl_hdr.
+ * @return the allocated message.
+ *
+ * The message looks as follows:
+ * # headers
+ * [l1ctl_hdr] : initialized. msgb->l1h points here
+ * [spare-bytes] : L3_MSG_HEAD bytes reserved for l3 header
+ * # data
+ * [spare-bytes] : L3_MSG_DATA bytes reserved for data. msgb->tail points here. msgb->data points here.
+ */
+struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
+{
+ struct msgb *msg;
+ struct l1ctl_hdr *l1h;
+ msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
+ if (!msg) {
+ while (1) {
+ puts("OOPS. Out of buffers...\n");
+ }
+
+ return NULL;
+ }
+ l1h = (struct l1ctl_hdr *)msgb_put(msg, sizeof(*l1h));
+ l1h->msg_type = msg_type;
+ l1h->flags = 0;
+
+ msg->l1h = (uint8_t *)l1h;
+
+ return msg;
+}
+
+/**
+ * @brief Allocates a msgb with set l1ctl header and room for a l3 header and puts l1ctl_info_dl to the msgb data.
+ *
+ * @param [in] msg_type L1CTL primitive message type set to l1ctl_hdr.
+ * @param [in] fn framenumber put into l1ctl_info_dl.
+ * @param [in] snr time slot number put into l1ctl_info_dl.
+ * @param [in] arfcn arfcn put into l1ctl_info_dl.
+ * @return the allocated message.
+ *
+ * The message looks as follows:
+ * # headers
+ * [l1ctl_hdr] : initialized. msgb->l1h points here
+ * [spare-bytes] : L3_MSG_HEAD bytes reserved for l3 header
+ * # data
+ * [l1ctl_info_dl] : initialized with params. msgb->data points here.
+ * [spare-bytes] : L3_MSG_DATA bytes reserved for data. msgb->tail points here.
+ */
+struct msgb *l1ctl_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
+ uint16_t arfcn)
+{
+ struct l1ctl_info_dl *dl;
+ struct msgb *msg = l1ctl_msgb_alloc(msg_type);
+
+ dl = (struct l1ctl_info_dl *)msgb_put(msg, sizeof(*dl));
+ dl->frame_nr = htonl(fn);
+ dl->snr = snr;
+ dl->band_arfcn = htons(arfcn);
+
+ return msg;
+}
+
+/**
+ * @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.
+ *
+ */
+void l1ctl_sap_handler(struct msgb *msg)
+{
+// struct msgb *msg;
+ struct l1ctl_hdr *l1h;
+ unsigned long flags;
+
+ if (!msg)
+ return;
+
+ l1h = (struct l1ctl_hdr *)msg->data;
+
+ if (sizeof(*l1h) > msg->len) {
+ LOGP(DL1C, LOGL_NOTICE, "Short message. %u\n", msg->len);
+ goto exit_msgbfree;
+ }
+
+ switch (l1h->msg_type) {
+ case L1CTL_FBSB_REQ:
+ l1ctl_rx_fbsb_req(msg);
+ break;
+ case L1CTL_DM_EST_REQ:
+ l1ctl_rx_dm_est_req(msg);
+ break;
+ case L1CTL_DM_REL_REQ:
+ l1ctl_rx_dm_rel_req(msg);
+ break;
+ case L1CTL_PARAM_REQ:
+ l1ctl_rx_param_req(msg);
+ break;
+ case L1CTL_DM_FREQ_REQ:
+ l1ctl_rx_dm_freq_req(msg);
+ break;
+ case L1CTL_CRYPTO_REQ:
+ l1ctl_rx_crypto_req(msg);
+ break;
+ case L1CTL_RACH_REQ:
+ l1ctl_rx_rach_req(msg);
+ break;
+ case L1CTL_DATA_REQ:
+ l1ctl_rx_data_req(msg);
+ /* we have to keep the msgb, not free it! */
+ goto exit_nofree;
+ case L1CTL_PM_REQ:
+ l1ctl_rx_pm_req(msg);
+ break;
+ case L1CTL_RESET_REQ:
+ l1ctl_rx_reset_req(msg);
+ break;
+ case L1CTL_CCCH_MODE_REQ:
+ l1ctl_rx_ccch_mode_req(msg);
+ break;
+ case L1CTL_TCH_MODE_REQ:
+ l1ctl_rx_tch_mode_req(msg);
+ break;
+ case L1CTL_NEIGH_PM_REQ:
+ l1ctl_rx_neigh_pm_req(msg);
+ break;
+ case L1CTL_TRAFFIC_REQ:
+ l1ctl_rx_traffic_req(msg);
+ /* we have to keep the msgb, not free it! */
+ goto exit_nofree;
+ case L1CTL_SIM_REQ:
+ l1ctl_rx_sim_req(msg);
+ break;
+ }
+
+ exit_msgbfree: msgb_free(msg);
+ exit_nofree: return;
+}
+
+/***************************************************************
+ * L1CTL RX ROUTINES *******************************************
+ ***************************************************************/
+
+/**
+ * @brief Handler for received L1CTL_FBSB_REQ from L23.
+ *
+ * -- frequency burst synchronisation burst request --
+ *
+ * @param [in] msg the received message.
+ *
+ * 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.
+ * TODO: Could be used to bind/connect to different virtual_bts sockets with a arfcn-socket mapping.
+ */
+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",
+ ntohs(sync_req->band_arfcn), sync_req->flags);
+
+ l1ctl_tx_fbsb_conf(0, ntohs(sync_req->band_arfcn));
+}
+
+/**
+ * @brief Handler for received L1CTL_DM_EST_REQ from L23.
+ *
+ * -- dedicated mode established request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Handle state change from idle to dedicated mode.
+ *
+ * TODO: Implement this handler routine!
+ */
+void l1ctl_rx_dm_est_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_dm_est_req *est_req =
+ (struct l1ctl_dm_est_req *)ul->payload;
+
+ 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);
+
+// /* 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));
+}
+
+/**
+ * @brief Handler for received L1CTL_DM_FREQ_REQ from L23.
+ *
+ * -- dedicated mode frequency request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Handle frequency change in dedicated mode. E.g. used for frequency hopping.
+ *
+ * Note: Not needed for virtual physical layer.
+ */
+void l1ctl_rx_dm_freq_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_dm_freq_req *freq_req =
+ (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);
+}
+
+/**
+ * @brief Handler for received L1CTL_CRYPTO_REQ from L23.
+ *
+ * -- cryptographic request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Configure the key and algorithm used for cryptographic operations in the DSP (Digital Signal Processor).
+ *
+ * Note: in the virtual physical layer the cryptographic operations are not handled in the DSP.
+ *
+ * TODO: Implement cryptographic operations for virtual um!
+ * TODO: Implement this handler routine!
+ */
+void l1ctl_rx_crypto_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_crypto_req *cr = (struct l1ctl_crypto_req *)ul->payload;
+ uint8_t key_len = msg->len - sizeof(*l1h) - sizeof(*ul) - sizeof(*cr);
+
+ DEBUGP(DL1C,
+ "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);
+}
+
+/**
+ * @brief Handler for received L1CTL_DM_REL_REQ from L23.
+ *
+ * -- dedicated mode release request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Handle state change from dedicated to idle mode. Flush message buffers of dedicated channel.
+ *
+ * TODO: Implement this handler routine!
+ */
+void l1ctl_rx_dm_rel_req(struct msgb *msg)
+{
+// struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+
+ 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;
+}
+
+/**
+ * @brief Handler for received L1CTL_PARAM_REQ from L23.
+ *
+ * -- parameter request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Configure transceiver parameters timing advance value and sending power.
+ *
+ * Note: Not needed for virtual physical layer.
+ */
+void l1ctl_rx_param_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_par_req *par_req = (struct l1ctl_par_req *)ul->payload;
+
+ DEBUGP(DL1C,
+ "Received and ignored from l23 - L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n",
+ par_req->ta, par_req->tx_power);
+}
+
+/**
+ * @brief Handler for received L1CTL_RACH_REQ from L23.
+ *
+ * -- random access channel request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Transmit RACH request on RACH.
+ *
+ * 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;
+
+ 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);
+
+// l1a_rach_req(ntohs(rach_req->offset), rach_req->combined,
+// rach_req->ra);
+}
+
+/**
+ * @brief Handler for received L1CTL_DATA_REQ from L23.
+ *
+ * -- data request --
+ *
+ * @param [in] msg the received message.
+ *
+ * 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!
+ */
+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;
+
+ DEBUGP(DL1C,
+ "Received and handled from l23 - L1CTL_DATA_REQ (link_id=0x%02x)\n",
+ ul->link_id);
+
+// 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);
+}
+
+/**
+ * @brief Handler for received L1CTL_PM_REQ from L23.
+ *
+ * -- power measurement request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Process power measurement for a given range of arfcns to calculate signal power and connection quality.
+ *
+ * Note: We do not need to calculate that for the virtual physical layer, but l23 apps can expect a response. So this response is mocked here.
+ */
+void l1ctl_rx_pm_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+ struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *)l1h->data;
+ struct msgb *resp_msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
+ uint16_t arfcn_next;
+ // convert to host order
+ 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);
+
+ 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 probably min and max
+ pm_conf->pm[0] = 63;
+ pm_conf->pm[1] = 63;
+ if(arfcn_next == pm_req->range.band_arfcn_to) {
+ struct l1ctl_hdr *resp_l1h = resp_msg->l1h;
+ resp_l1h->flags |= L1CTL_F_DONE;
+ }
+ // no more space in msgb, flush to l2
+ 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) {
+ l1ctl_sap_tx_to_l23(resp_msg);
+ }
+}
+
+/**
+ * @brief Handler for received L1CTL_RESET_REQ from L23.
+ *
+ * -- reset request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Reset layer 1 (state machine, scheduler, transceiver) depending on the reset type.
+ *
+ */
+void l1ctl_rx_reset_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+ struct l1ctl_reset *reset_req = (struct l1ctl_reset *)l1h->data;
+
+ switch (reset_req->type) {
+ case L1CTL_RES_T_FULL:
+ DEBUGP(DL1C,
+ "Received and handled from l23 - L1CTL_RESET_REQ (type=FULL)\n");
+// l1s_reset();
+// l1s_reset_hw();
+// audio_set_enabled(GSM48_CMODE_SIGN, 0);
+ 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");
+// sched_gsmtime_reset();
+ 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");
+ break;
+ }
+}
+
+/**
+ * @brief Handler for received L1CTL_CCCH_MODE_REQ from L23.
+ *
+ * -- common control channel mode request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Configure CCCH combined / non-combined mode.
+ *
+ * TODO: Implement this handler routine!
+ */
+void l1ctl_rx_ccch_mode_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+ struct l1ctl_ccch_mode_req *ccch_mode_req =
+ (struct l1ctl_ccch_mode_req *)l1h->data;
+ uint8_t ccch_mode = ccch_mode_req->ccch_mode;
+
+ DEBUGP(DL1C, "Received and handled from l23 - L1CTL_CCCH_MODE_REQ\n");
+
+ 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);
+}
+
+/**
+ * @brief Handler for received L1CTL_TCH_MODE_REQ from L23.
+ *
+ * -- traffic channel mode request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Configure TCH mode and audio mode.
+ *
+ * TODO: Implement this handler routine!
+ */
+void l1ctl_rx_tch_mode_req(struct msgb *msg)
+{
+ 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;
+
+ 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);
+}
+
+/**
+ * @brief Handler for received L1CTL_NEIGH_PM_REQ from L23.
+ *
+ * -- neighbor power measurement request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Update the maintained list of neighbor cells used in neighbor cell power measurement.
+ * 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.
+ */
+void l1ctl_rx_neigh_pm_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+ struct l1ctl_neigh_pm_req *pm_req =
+ (struct l1ctl_neigh_pm_req *)l1h->data;
+
+ DEBUGP(DL1C,
+ "Received and ignored from l23 - L1CTL_NEIGH_PM_REQ new list with %u entries\n",
+ pm_req->n);
+}
+
+/**
+ * @brief Handler for received L1CTL_TRAFFIC_REQ from L23.
+ *
+ * -- traffic request --
+ *
+ * @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.
+ *
+ * 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;
+
+ DEBUGP(DL1C, "Received and handled from l23 - L1CTL_TRAFFIC_REQ\n");
+
+// 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);
+}
+
+/**
+ * @brief Handler for received L1CTL_SIM_REQ from L23.
+ *
+ * -- sim request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Forward and a sim request to the SIM APDU.
+ *
+ * Note: Not needed for virtual layer. Please configure layer23 application to use test-sim implementation.
+ * ms <x>
+ * --------
+ * sim test
+ * test-sim
+ * imsi <xxxxxxxxxxxxxxx>
+ * ki comp128 <xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx>
+ * --------
+ */
+void l1ctl_rx_sim_req(struct msgb *msg)
+{
+ uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
+ uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
+
+ DEBUGP(DL1C,
+ "Received and ignored from l23 - SIM Request length: %u, data: %s: ",
+ len, osmo_hexdump(data, sizeof(data)));
+
+}
+
+/***************************************************************
+ * L1CTL TX ROUTINES *******************************************
+ ***************************************************************/
+
+/**
+ * @brief Transmit L1CTL_RESET_IND or L1CTL_RESET_CONF to layer 23.
+ *
+ * -- reset indication / confirm --
+ *
+ * @param [in] msg_type L1CTL primitive message type.
+ * @param [in] reset_type reset type (full, boot or just scheduler reset).
+ */
+void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
+{
+ struct msgb *msg = l1ctl_msgb_alloc(msg_type);
+ struct l1ctl_reset *reset_resp;
+ reset_resp = (struct l1ctl_reset *)msgb_put(msg, sizeof(*reset_resp));
+ reset_resp->type = reset_type;
+
+ DEBUGP(DL1C, "Sending to l23 - %s (reset_type: %u)\n",
+ getL1ctlPrimName(msg_type), reset_type);
+ l1ctl_sap_tx_to_l23(msg);
+}
+
+/**
+ * @brief Transmit L1CTL msg of a given type to layer 23.
+ *
+ * @param [in] msg_type L1CTL primitive message type.
+ */
+void l1ctl_tx_msg(uint8_t msg_type)
+{
+ struct msgb *msg = l1ctl_msgb_alloc(msg_type);
+ DEBUGP(DL1C, "Sending to l23 - %s\n", getL1ctlPrimName(msg_type));
+ l1ctl_sap_tx_to_l23(msg);
+}
+
+/**
+ * @brief Transmit L1CTL_FBSB_CONF to l23.
+ *
+ * -- frequency burst synchronisation burst confirm --
+ *
+ * @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.
+ */
+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;
+
+ msg = l1ctl_create_l2_msg(L1CTL_FBSB_CONF, fn,
+ snr,
+ arfcn);
+
+ resp = (struct l1ctl_fbsb_conf *) msgb_put(msg, sizeof(*resp));
+ resp->initial_freq_err = htons(initial_freq_err);
+ resp->result = res;
+ resp->bsic = bsic;
+
+ DEBUGP(DL1C, "Sending to l23 - %s (res: %u)\n",
+ getL1ctlPrimName(L1CTL_FBSB_CONF), res);
+
+ l1ctl_sap_tx_to_l23(msg);
+}
+
+/**
+ * @brief Transmit L1CTL_CCCH_MODE_CONF to layer 23.
+ *
+ * -- common control channel mode confirm --
+ *
+ * @param [in] ccch_mode the new configured ccch mode. Combined or non-combined, see l1ctl_proto.
+ *
+ * Called by layer 1 to inform layer 2 that the ccch mode was successfully changed.
+ */
+void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
+{
+ struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
+ struct l1ctl_ccch_mode_conf *mode_conf;
+ mode_conf = (struct l1ctl_ccch_mode_conf *)msgb_put(msg,
+ sizeof(*mode_conf));
+ mode_conf->ccch_mode = ccch_mode;
+
+ DEBUGP(DL1C, "Sending to l23 - L1CTL_CCCH_MODE_CONF (mode: %u)\n",
+ ccch_mode);
+ l1ctl_sap_tx_to_l23(msg);
+}
+
+/**
+ * @brief Transmit L1CTL_TCH_MODE_CONF to layer 23.
+ *
+ * -- traffic channel mode confirm --
+ *
+ * @param [in] tch_mode the new configured traffic channel mode, see gsm48_chan_mode in gsm_04_08.h.
+ * @param [in] audio_mode the new configured audio mode(s), see l1ctl_tch_mode_req in l1ctl_proto.h.
+ *
+ * Called by layer 1 to inform layer 23 that the traffic channel mode was successfully changed.
+ */
+void l1ctl_tx_tch_mode_conf(uint8_t tch_mode, uint8_t audio_mode)
+{
+ struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TCH_MODE_CONF);
+ struct l1ctl_tch_mode_conf *mode_conf;
+ mode_conf = (struct l1ctl_tch_mode_conf *)msgb_put(msg,
+ sizeof(*mode_conf));
+ mode_conf->tch_mode = tch_mode;
+ 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);
+ l1ctl_sap_tx_to_l23(msg);
+}
+
+