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 <lafo...@gnumonks.org>
Gerrit-Reviewer: BastusIII <sebastian.stump...@googlemail.com>

Reply via email to