L1CTL is sending PH-DATA.ind, not PH-DATA.req up to LAPDm
[osmocom-bb.git] / src / host / layer23 / src / common / l1ctl.c
index 993c7db..867f5c5 100644 (file)
 
 #include <arpa/inet.h>
 
-#include <l1a_l23_interface.h>
-
-#include <osmocore/signal.h>
-#include <osmocore/logging.h>
-#include <osmocore/timer.h>
-#include <osmocore/msgb.h>
-#include <osmocore/tlv.h>
-#include <osmocore/gsm_utils.h>
-#include <osmocore/gsmtap_util.h>
-#include <osmocore/protocol/gsm_04_08.h>
-#include <osmocore/protocol/gsm_08_58.h>
-#include <osmocore/rsl.h>
-
-#include <osmocom/l1ctl.h>
-#include <osmocom/osmocom_data.h>
-#include <osmocom/l1l2_interface.h>
-#include <osmocom/lapdm.h>
-#include <osmocom/logging.h>
+#include <l1ctl_proto.h>
+
+#include <osmocom/core/signal.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/gsmtap_util.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/gsm/rsl.h>
+
+#include <osmocom/bb/common/l1ctl.h>
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/l1l2_interface.h>
+#include <osmocom/bb/common/lapdm.h>
+#include <osmocom/bb/common/logging.h>
+
+extern struct gsmtap_inst *gsmtap_inst;
 
 static struct msgb *osmo_l1_alloc(uint8_t msg_type)
 {
@@ -76,6 +78,7 @@ static int rx_l1_fbsb_conf(struct osmocom_ms *ms, struct msgb *msg)
        struct l1ctl_info_dl *dl;
        struct l1ctl_fbsb_conf *sb;
        struct gsm_time tm;
+       struct osmobb_fbsb_res fr;
 
        if (msgb_l3len(msg) < sizeof(*dl) + sizeof(*sb)) {
                LOGP(DL1C, LOGL_ERROR, "FBSB RESP: MSG too short %u\n",
@@ -86,25 +89,30 @@ static int rx_l1_fbsb_conf(struct osmocom_ms *ms, struct msgb *msg)
        dl = (struct l1ctl_info_dl *) msg->l1h;
        sb = (struct l1ctl_fbsb_conf *) dl->payload;
 
-       printf("snr=%04x, arfcn=%u result=%u\n", dl->snr, ntohs(dl->band_arfcn),
-               sb->result);
+       LOGP(DL1C, LOGL_INFO, "snr=%04x, arfcn=%u result=%u\n", dl->snr,
+               ntohs(dl->band_arfcn), sb->result);
 
        if (sb->result != 0) {
                LOGP(DL1C, LOGL_ERROR, "FBSB RESP: result=%u\n", sb->result);
-               dispatch_signal(SS_L1CTL, S_L1CTL_FBSB_ERR, ms);
+               osmo_signal_dispatch(SS_L1CTL, S_L1CTL_FBSB_ERR, ms);
                return 0;
        }
 
        gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr));
        DEBUGP(DL1C, "SCH: SNR: %u TDMA: (%.4u/%.2u/%.2u) bsic: %d\n",
                dl->snr, tm.t1, tm.t2, tm.t3, sb->bsic);
-       dispatch_signal(SS_L1CTL, S_L1CTL_FBSB_RESP, ms);
+       fr.ms = ms;
+       fr.snr = dl->snr;
+       fr.bsic = sb->bsic;
+       osmo_signal_dispatch(SS_L1CTL, S_L1CTL_FBSB_RESP, &fr);
 
        return 0;
 }
 
 static int rx_l1_rach_conf(struct osmocom_ms *ms, struct msgb *msg)
 {
+       struct lapdm_entity *le = &ms->lapdm_channel.lapdm_dcch;
+       struct osmo_phsap_prim pp;
        struct l1ctl_info_dl *dl;
 
        if (msgb_l2len(msg) < sizeof(*dl)) {
@@ -116,42 +124,18 @@ static int rx_l1_rach_conf(struct osmocom_ms *ms, struct msgb *msg)
 
        dl = (struct l1ctl_info_dl *) msg->l1h;
 
-       l2_ph_chan_conf(msg, ms, dl);
+       osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_RACH,
+                       PRIM_OP_CONFIRM, msg);
+       pp.u.rach_ind.fn = ntohl(dl->frame_nr);
 
-       return 0;
-}
-
-char *chan_nr2string(uint8_t chan_nr)
-{
-       static char str[20];
-       uint8_t cbits = chan_nr >> 3;
-
-       str[0] = '\0';
-
-       if (cbits == 0x01)
-               sprintf(str, "TCH/F");
-       else if ((cbits & 0x1e) == 0x02)
-               sprintf(str, "TCH/H(%u)", cbits & 0x01);
-       else if ((cbits & 0x1c) == 0x04)
-               sprintf(str, "SDCCH/4(%u)", cbits & 0x03);
-       else if ((cbits & 0x18) == 0x08)
-               sprintf(str, "SDCCH/8(%u)", cbits & 0x07);
-       else if (cbits == 0x10)
-               sprintf(str, "BCCH");
-       else if (cbits == 0x11)
-               sprintf(str, "RACH");
-       else if (cbits == 0x12)
-               sprintf(str, "PCH/AGCH");
-       else
-               sprintf(str, "UNKNOWN");
-
-       return str;
+       return lapdm_phsap_up(&pp.oph, le);
 }
 
 /* Receive L1CTL_DATA_IND (Data Indication from L1) */
 static int rx_ph_data_ind(struct osmocom_ms *ms, struct msgb *msg)
 {
-       struct l1ctl_info_dl *dl, dl_cpy;
+       struct osmo_phsap_prim pp;
+       struct l1ctl_info_dl *dl;
        struct l1ctl_data_ind *ccch;
        struct lapdm_entity *le;
        struct rx_meas_stat *meas = &ms->meas;
@@ -172,76 +156,124 @@ static int rx_ph_data_ind(struct osmocom_ms *ms, struct msgb *msg)
 
        gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr));
        rsl_dec_chan_nr(dl->chan_nr, &chan_type, &chan_ss, &chan_ts);
-       DEBUGP(DL1C, "%s (%.4u/%.2u/%.2u) %s\n",
-               chan_nr2string(dl->chan_nr), tm.t1, tm.t2, tm.t3,
-               hexdump(ccch->data, sizeof(ccch->data)));
+       DEBUGP(DL1C, "%s (%.4u/%.2u/%.2u) %d dBm: %s\n",
+               rsl_chan_nr_str(dl->chan_nr), tm.t1, tm.t2, tm.t3,
+               (int)dl->rx_level-110,
+               osmo_hexdump(ccch->data, sizeof(ccch->data)));
 
+       meas->last_fn = ntohl(dl->frame_nr);
        meas->frames++;
+       meas->snr += dl->snr;
        meas->berr += dl->num_biterr;
        meas->rxlev += dl->rx_level;
 
-       if (dl->num_biterr) {
-printf("dropping frame with %u bit errors\n", dl->num_biterr);
+       /* counting loss criteria */
+       if (!(dl->link_id & 0x40)) {
+               switch (chan_type) {
+               case RSL_CHAN_PCH_AGCH:
+                       if (!meas->ds_fail)
+                               break;
+                       if (dl->fire_crc >= 2)
+                               meas->dsc -= 4;
+                       else
+                               meas->dsc += 1;
+                       if (meas->dsc > meas->ds_fail)
+                               meas->dsc = meas->ds_fail;
+                       if (meas->dsc < meas->ds_fail)
+                               printf("LOSS counter for CCCH %d\n", meas->dsc);
+                       if (meas->dsc > 0)
+                               break;
+                       meas->ds_fail = 0;
+                       osmo_signal_dispatch(SS_L1CTL, S_L1CTL_LOSS_IND, ms);
+                       break;
+               }
+       } else {
+               switch (chan_type) {
+               case RSL_CHAN_Bm_ACCHs:
+               case RSL_CHAN_Lm_ACCHs:
+               case RSL_CHAN_SDCCH4_ACCH:
+               case RSL_CHAN_SDCCH8_ACCH:
+                       if (!meas->rl_fail)
+                               break;
+                       if (dl->fire_crc >= 2)
+                               meas->s -= 1;
+                       else
+                               meas->s += 2;
+                       if (meas->s > meas->rl_fail)
+                               meas->s = meas->rl_fail;
+                       if (meas->s < meas->rl_fail)
+                               printf("LOSS counter for ACCH %d\n", meas->s);
+                       if (meas->s > 0)
+                               break;
+                       meas->rl_fail = 0;
+                       osmo_signal_dispatch(SS_L1CTL, S_L1CTL_LOSS_IND, ms);
+                       break;
+               }
+       }
+
+       if (dl->fire_crc >= 2) {
+printf("Dropping frame with %u bit errors\n", dl->num_biterr);
                LOGP(DL1C, LOGL_NOTICE, "Dropping frame with %u bit errors\n",
                        dl->num_biterr);
+               msgb_free(msg);
                return 0;
        }
 
        /* send CCCH data via GSMTAP */
        gsmtap_chan_type = chantype_rsl2gsmtap(chan_type, dl->link_id);
-       gsmtap_sendmsg(ntohs(dl->band_arfcn), chan_ts, gsmtap_chan_type, chan_ss,
-                       tm.fn, dl->rx_level-110, dl->snr, ccch->data,
-                       sizeof(ccch->data));
+       gsmtap_send(gsmtap_inst, ntohs(dl->band_arfcn), chan_ts,
+                   gsmtap_chan_type, chan_ss, tm.fn, dl->rx_level-110,
+                   dl->snr, ccch->data, sizeof(ccch->data));
 
        /* determine LAPDm entity based on SACCH or not */
        if (dl->link_id & 0x40)
-               le = &ms->l2_entity.lapdm_acch;
+               le = &ms->lapdm_channel.lapdm_acch;
        else
-               le = &ms->l2_entity.lapdm_dcch;
-       /* make local stack copy of l1ctl_info_dl, as LAPDm will
-        * overwrite skb hdr */
-       memcpy(&dl_cpy, dl, sizeof(dl_cpy));
+               le = &ms->lapdm_channel.lapdm_dcch;
 
        /* pull the L1 header from the msgb */
        msgb_pull(msg, msg->l2h - (msg->l1h-sizeof(struct l1ctl_hdr)));
        msg->l1h = NULL;
 
-       /* send it up into LAPDm */
-       l2_ph_data_ind(msg, le, &dl_cpy);
+       osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_DATA,
+                       PRIM_OP_INDICATION, msg);
+       pp.u.data.chan_nr = dl->chan_nr;
+       pp.u.data.link_id = dl->link_id;
 
-       return 0;
+       /* send it up into LAPDm */
+       return lapdm_phsap_up(&pp.oph, le);
 }
 
 /* Receive L1CTL_DATA_CONF (Data Confirm from L1) */
 static int rx_ph_data_conf(struct osmocom_ms *ms, struct msgb *msg)
 {
-       struct l1ctl_info_dl *dl;
+       struct osmo_phsap_prim pp;
+       struct l1ctl_info_dl *dl = (struct l1ctl_info_dl *) msg->l1h;
        struct lapdm_entity *le;
 
-       dl = (struct l1ctl_info_dl *) msg->l1h;
+       osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_RTS,
+                       PRIM_OP_INDICATION, msg);
 
        /* determine LAPDm entity based on SACCH or not */
        if (dl->link_id & 0x40)
-               le = &ms->l2_entity.lapdm_acch;
+               le = &ms->lapdm_channel.lapdm_acch;
        else
-               le = &ms->l2_entity.lapdm_dcch;
+               le = &ms->lapdm_channel.lapdm_dcch;
 
        /* send it up into LAPDm */
-       l2_ph_data_conf(msg, le);
-
-       return 0;
+       return lapdm_phsap_up(&pp.oph, le);
 }
 
 /* Transmit L1CTL_DATA_REQ */
-int tx_ph_data_req(struct osmocom_ms *ms, struct msgb *msg, uint8_t chan_nr,
-       uint8_t link_id)
+int l1ctl_tx_data_req(struct osmocom_ms *ms, struct msgb *msg,
+                      uint8_t chan_nr, uint8_t link_id)
 {
        struct l1ctl_hdr *l1h;
        struct l1ctl_info_ul *l1i_ul;
        uint8_t chan_type, chan_ts, chan_ss;
        uint8_t gsmtap_chan_type;
 
-       DEBUGP(DL1C, "(%s)\n", hexdump(msg->l2h, msgb_l2len(msg)));
+       DEBUGP(DL1C, "(%s)\n", osmo_hexdump(msg->l2h, msgb_l2len(msg)));
 
        if (msgb_l2len(msg) > 23) {
                LOGP(DL1C, LOGL_ERROR, "L1 cannot handle message length "
@@ -255,8 +287,8 @@ int tx_ph_data_req(struct osmocom_ms *ms, struct msgb *msg, uint8_t chan_nr,
        /* send copy via GSMTAP */
        rsl_dec_chan_nr(chan_nr, &chan_type, &chan_ss, &chan_ts);
        gsmtap_chan_type = chantype_rsl2gsmtap(chan_type, link_id);
-       gsmtap_sendmsg(0|0x4000, chan_ts, gsmtap_chan_type, chan_ss,
-                       0, 127, 255, msg->l2h, msgb_l2len(msg));
+       gsmtap_send(gsmtap_inst, 0|0x4000, chan_ts, gsmtap_chan_type,
+                   chan_ss, 0, 127, 255, msg->l2h, msgb_l2len(msg));
 
        /* prepend uplink info header */
        l1i_ul = (struct l1ctl_info_ul *) msgb_push(msg, sizeof(*l1i_ul));
@@ -280,19 +312,17 @@ int l1ctl_tx_fbsb_req(struct osmocom_ms *ms, uint16_t arfcn,
        struct msgb *msg;
        struct l1ctl_fbsb_req *req;
 
-       printf("Sync Req\n");
+       LOGP(DL1C, LOGL_INFO, "Sync Req\n");
 
        msg = osmo_l1_alloc(L1CTL_FBSB_REQ);
        if (!msg)
                return -1;
 
-       memset(&ms->meas, 0, sizeof(ms->meas));
-
        req = (struct l1ctl_fbsb_req *) msgb_put(msg, sizeof(*req));
        req->band_arfcn = htons(osmo_make_band_arfcn(ms, arfcn));
        req->timeout = htons(timeout);
        /* Threshold when to consider FB_MODE1: 4kHz - 1kHz */
-       req->freq_err_thresh1 = htons(4000 - 1000);
+       req->freq_err_thresh1 = htons(11000 - 1000);
        /* Threshold when to consider SCH: 1kHz - 200Hz */
        req->freq_err_thresh2 = htons(1000 - 200);
        /* not used yet! */
@@ -310,7 +340,7 @@ int l1ctl_tx_ccch_mode_req(struct osmocom_ms *ms, uint8_t ccch_mode)
        struct msgb *msg;
        struct l1ctl_ccch_mode_req *req;
 
-       printf("CCCH Mode Req\n");
+       LOGP(DL1C, LOGL_INFO, "CCCH Mode Req\n");
 
        msg = osmo_l1_alloc(L1CTL_CCCH_MODE_REQ);
        if (!msg)
@@ -322,8 +352,26 @@ int l1ctl_tx_ccch_mode_req(struct osmocom_ms *ms, uint8_t ccch_mode)
        return osmo_send_l1(ms, msg);
 }
 
+/* Transmit L1CTL_TCH_MODE_REQ */
+int l1ctl_tx_tch_mode_req(struct osmocom_ms *ms, uint8_t tch_mode)
+{
+       struct msgb *msg;
+       struct l1ctl_tch_mode_req *req;
+
+       LOGP(DL1C, LOGL_INFO, "TCH Mode Req\n");
+
+       msg = osmo_l1_alloc(L1CTL_TCH_MODE_REQ);
+       if (!msg)
+               return -1;
+
+       req = (struct l1ctl_tch_mode_req *) msgb_put(msg, sizeof(*req));
+       req->tch_mode = tch_mode;
+
+       return osmo_send_l1(ms, msg);
+}
+
 /* Transmit L1CTL_PARAM_REQ */
-int l1ctl_tx_ph_param_req(struct osmocom_ms *ms, uint8_t ta, uint8_t tx_power)
+int l1ctl_tx_param_req(struct osmocom_ms *ms, uint8_t ta, uint8_t tx_power)
 {
        struct msgb *msg;
        struct l1ctl_info_ul *ul;
@@ -342,9 +390,31 @@ int l1ctl_tx_ph_param_req(struct osmocom_ms *ms, uint8_t ta, uint8_t tx_power)
        return osmo_send_l1(ms, msg);
 }
 
+/* Transmit L1CTL_CRYPTO_REQ */
+int l1ctl_tx_crypto_req(struct osmocom_ms *ms, uint8_t algo, uint8_t *key,
+       uint8_t len)
+{
+       struct msgb *msg;
+       struct l1ctl_info_ul *ul;
+       struct l1ctl_crypto_req *req;
+
+       msg = osmo_l1_alloc(L1CTL_CRYPTO_REQ);
+       if (!msg)
+               return -1;
+
+       DEBUGP(DL1C, "CRYPTO Req. algo=%d, len=%d\n", algo, len);
+       ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+       req = (struct l1ctl_crypto_req *) msgb_put(msg, sizeof(*req) + len);
+       req->algo = algo;
+       if (len)
+               memcpy(req->key, key, len);
+
+       return osmo_send_l1(ms, msg);
+}
+
 /* Transmit L1CTL_RACH_REQ */
-int tx_ph_rach_req(struct osmocom_ms *ms, uint8_t ra, uint8_t fn51,
-       uint8_t mf_off)
+int l1ctl_tx_rach_req(struct osmocom_ms *ms, uint8_t ra, uint16_t offset,
+       uint8_t combined)
 {
        struct msgb *msg;
        struct l1ctl_info_ul *ul;
@@ -354,19 +424,19 @@ int tx_ph_rach_req(struct osmocom_ms *ms, uint8_t ra, uint8_t fn51,
        if (!msg)
                return -1;
 
-       DEBUGP(DL1C, "RACH Req. fn51=%d, mf_off=%d\n", fn51, mf_off);
+       DEBUGP(DL1C, "RACH Req. offset=%d combined=%d\n", offset, combined);
        ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
        req = (struct l1ctl_rach_req *) msgb_put(msg, sizeof(*req));
        req->ra = ra;
-       req->fn51 = fn51;
-       req->mf_off = mf_off;
+       req->offset = htons(offset);
+       req->combined = combined;
 
        return osmo_send_l1(ms, msg);
 }
 
 /* Transmit L1CTL_DM_EST_REQ */
-int tx_ph_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
-       uint8_t chan_nr, uint8_t tsc)
+int l1ctl_tx_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
+                           uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode)
 {
        struct msgb *msg;
        struct l1ctl_info_ul *ul;
@@ -376,10 +446,8 @@ int tx_ph_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
        if (!msg)
                return -1;
 
-       printf("Tx Dedic.Mode Est Req (arfcn=%u, chan_nr=0x%02x)\n",
-               band_arfcn, chan_nr);
-
-       memset(&ms->meas, 0, sizeof(ms->meas));
+       LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Est Req (arfcn=%u, "
+               "chan_nr=0x%02x)\n", band_arfcn, chan_nr);
 
        ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
        ul->chan_nr = chan_nr;
@@ -389,12 +457,14 @@ int tx_ph_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
        req->tsc = tsc;
        req->h = 0;
        req->h0.band_arfcn = htons(band_arfcn);
+       req->tch_mode = tch_mode;
 
        return osmo_send_l1(ms, msg);
 }
 
-int tx_ph_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
-       uint16_t *ma, uint8_t ma_len, uint8_t chan_nr, uint8_t tsc)
+int l1ctl_tx_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
+                           uint16_t *ma, uint8_t ma_len,
+                           uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode)
 {
        struct msgb *msg;
        struct l1ctl_info_ul *ul;
@@ -405,11 +475,9 @@ int tx_ph_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
        if (!msg)
                return -1;
 
-       printf("Tx Dedic.Mode Est Req (maio=%u, hsn=%u, "
+       LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Est Req (maio=%u, hsn=%u, "
                "chan_nr=0x%02x)\n", maio, hsn, chan_nr);
 
-       memset(&ms->meas, 0, sizeof(ms->meas));
-
        ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
        ul->chan_nr = chan_nr;
        ul->link_id = 0;
@@ -420,6 +488,68 @@ int tx_ph_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
        req->h1.maio = maio;
        req->h1.hsn = hsn;
        req->h1.n = ma_len;
+       for (i = 0; i < ma_len; i++)
+               req->h1.ma[i] = htons(ma[i]);
+       req->tch_mode = tch_mode;
+
+       return osmo_send_l1(ms, msg);
+}
+
+/* Transmit L1CTL_DM_FREQ_REQ */
+int l1ctl_tx_dm_freq_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
+                            uint8_t tsc, uint16_t fn)
+{
+       struct msgb *msg;
+       struct l1ctl_info_ul *ul;
+       struct l1ctl_dm_freq_req *req;
+
+       msg = osmo_l1_alloc(L1CTL_DM_FREQ_REQ);
+       if (!msg)
+               return -1;
+
+       LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Freq Req (arfcn=%u, fn=%d)\n",
+               band_arfcn, fn);
+
+       ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+       ul->chan_nr = 0;
+       ul->link_id = 0;
+
+       req = (struct l1ctl_dm_freq_req *) msgb_put(msg, sizeof(*req));
+       req->fn = htons(fn);
+       req->tsc = tsc;
+       req->h = 0;
+       req->h0.band_arfcn = htons(band_arfcn);
+
+       return osmo_send_l1(ms, msg);
+}
+
+int l1ctl_tx_dm_freq_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
+                            uint16_t *ma, uint8_t ma_len,
+                            uint8_t tsc, uint16_t fn)
+{
+       struct msgb *msg;
+       struct l1ctl_info_ul *ul;
+       struct l1ctl_dm_freq_req *req;
+       int i;
+
+       msg = osmo_l1_alloc(L1CTL_DM_FREQ_REQ);
+       if (!msg)
+               return -1;
+
+       LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Freq Req (maio=%u, hsn=%u, "
+               "fn=%d)\n", maio, hsn, fn);
+
+       ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+       ul->chan_nr = 0;
+       ul->link_id = 0;
+
+       req = (struct l1ctl_dm_freq_req *) msgb_put(msg, sizeof(*req));
+       req->fn = htons(fn);
+       req->tsc = tsc;
+       req->h = 1;
+       req->h1.maio = maio;
+       req->h1.hsn = hsn;
+       req->h1.n = ma_len;
        for (i = 0; i < ma_len; i++)
                req->h1.ma[i] = htons(ma[i]);
 
@@ -427,7 +557,7 @@ int tx_ph_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
 }
 
 /* Transmit L1CTL_DM_REL_REQ */
-int tx_ph_dm_rel_req(struct osmocom_ms *ms)
+int l1ctl_tx_dm_rel_req(struct osmocom_ms *ms)
 {
        struct msgb *msg;
        struct l1ctl_info_ul *ul;
@@ -436,9 +566,7 @@ int tx_ph_dm_rel_req(struct osmocom_ms *ms)
        if (!msg)
                return -1;
 
-       printf("Tx Dedic.Mode Rel Req\n");
-
-       memset(&ms->meas, 0, sizeof(ms->meas));
+       LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Rel Req\n");
 
        ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
 
@@ -462,6 +590,38 @@ int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len)
        return osmo_send_l1(ms, msg);
 }
 
+int l1ctl_tx_sim_req(struct osmocom_ms *ms, uint8_t *data, uint16_t length)
+{
+       struct msgb *msg;
+       uint8_t *dat;
+
+       msg = osmo_l1_alloc(L1CTL_SIM_REQ);
+       if (!msg)
+               return -1;
+
+       dat = msgb_put(msg, length);
+       memcpy(dat, data, length);
+
+       return osmo_send_l1(ms, msg);
+}
+
+/* just forward the SIM response to the SIM handler */
+static int rx_l1_sim_conf(struct osmocom_ms *ms, struct msgb *msg)
+{
+       uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
+       uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
+       
+       LOGP(DL1C, LOGL_INFO, "SIM %s\n", osmo_hexdump(data, len));
+       
+       /* pull the L1 header from the msgb */
+       msgb_pull(msg, sizeof(struct l1ctl_hdr));
+       msg->l1h = NULL;
+
+       sim_apdu_resp(ms, msg);
+       
+       return 0;
+}
+
 /* Transmit L1CTL_PM_REQ */
 int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
                          uint16_t arfcn_to)
@@ -473,7 +633,7 @@ int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
        if (!msg)
                return -1;
 
-       printf("Tx PM Req (%u-%u)\n", arfcn_from, arfcn_to);
+       LOGP(DL1C, LOGL_INFO, "Tx PM Req (%u-%u)\n", arfcn_from, arfcn_to);
        pm = (struct l1ctl_pm_req *) msgb_put(msg, sizeof(*pm));
        pm->type = 1;
        pm->range.band_arfcn_from = htons(arfcn_from);
@@ -492,7 +652,7 @@ int l1ctl_tx_reset_req(struct osmocom_ms *ms, uint8_t type)
        if (!msg)
                return -1;
 
-       printf("Tx Reset Req (%u)\n", type);
+       LOGP(DL1C, LOGL_INFO, "Tx Reset Req (%u)\n", type);
        res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
        res->type = type;
 
@@ -502,8 +662,8 @@ int l1ctl_tx_reset_req(struct osmocom_ms *ms, uint8_t type)
 /* Receive L1CTL_RESET_IND */
 static int rx_l1_reset(struct osmocom_ms *ms)
 {
-       printf("Layer1 Reset indication\n");
-       dispatch_signal(SS_L1CTL, S_L1CTL_RESET, ms);
+       LOGP(DL1C, LOGL_INFO, "Layer1 Reset indication\n");
+       osmo_signal_dispatch(SS_L1CTL, S_L1CTL_RESET, ms);
 
        return 0;
 }
@@ -521,30 +681,53 @@ static int rx_l1_pm_conf(struct osmocom_ms *ms, struct msgb *msg)
                mr.band_arfcn = ntohs(pmr->band_arfcn);
                mr.rx_lev = pmr->pm[0];
                mr.ms = ms;
-               dispatch_signal(SS_L1CTL, S_L1CTL_PM_RES, &mr);
+               osmo_signal_dispatch(SS_L1CTL, S_L1CTL_PM_RES, &mr);
        }
        return 0;
 }
 
-/* Receive L1CTL_MODE_CONF */
+/* Receive L1CTL_CCCH_MODE_CONF */
 static int rx_l1_ccch_mode_conf(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct osmobb_ccch_mode_conf mc;
        struct l1ctl_ccch_mode_conf *conf;
 
        if (msgb_l3len(msg) < sizeof(*conf)) {
-               LOGP(DL1C, LOGL_ERROR, "MODE CONF: MSG too short %u\n",
+               LOGP(DL1C, LOGL_ERROR, "CCCH MODE CONF: MSG too short %u\n",
                        msgb_l3len(msg));
                return -1;
        }
 
        conf = (struct l1ctl_ccch_mode_conf *) msg->l1h;
 
-       printf("mode=%u\n", conf->ccch_mode);
+       LOGP(DL1C, LOGL_INFO, "CCCH MODE CONF: mode=%u\n", conf->ccch_mode);
 
        mc.ccch_mode = conf->ccch_mode;
        mc.ms = ms;
-       dispatch_signal(SS_L1CTL, S_L1CTL_CCCH_MODE_CONF, &mc);
+       osmo_signal_dispatch(SS_L1CTL, S_L1CTL_CCCH_MODE_CONF, &mc);
+
+       return 0;
+}
+
+/* Receive L1CTL_TCH_MODE_CONF */
+static int rx_l1_tch_mode_conf(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct osmobb_tch_mode_conf mc;
+       struct l1ctl_tch_mode_conf *conf;
+
+       if (msgb_l3len(msg) < sizeof(*conf)) {
+               LOGP(DL1C, LOGL_ERROR, "TCH MODE CONF: MSG too short %u\n",
+                       msgb_l3len(msg));
+               return -1;
+       }
+
+       conf = (struct l1ctl_tch_mode_conf *) msg->l1h;
+
+       LOGP(DL1C, LOGL_INFO, "TCH MODE CONF: mode=%u\n", conf->tch_mode);
+
+       mc.tch_mode = conf->tch_mode;
+       mc.ms = ms;
+       osmo_signal_dispatch(SS_L1CTL, S_L1CTL_TCH_MODE_CONF, &mc);
 
        return 0;
 }
@@ -587,9 +770,9 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
                break;
        case L1CTL_PM_CONF:
                rc = rx_l1_pm_conf(ms, msg);
-               msgb_free(msg);
                if (l1h->flags & L1CTL_F_DONE)
-                       dispatch_signal(SS_L1CTL, S_L1CTL_PM_DONE, ms);
+                       osmo_signal_dispatch(SS_L1CTL, S_L1CTL_PM_DONE, ms);
+               msgb_free(msg);
                break;
        case L1CTL_RACH_CONF:
                rc = rx_l1_rach_conf(ms, msg);
@@ -598,8 +781,15 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
                rc = rx_l1_ccch_mode_conf(ms, msg);
                msgb_free(msg);
                break;
+       case L1CTL_TCH_MODE_CONF:
+               rc = rx_l1_tch_mode_conf(ms, msg);
+               msgb_free(msg);
+               break;
+       case L1CTL_SIM_CONF:
+               rc = rx_l1_sim_conf(ms, msg);
+               break;
        default:
-               fprintf(stderr, "Unknown MSG: %u\n", l1h->msg_type);
+               LOGP(DL1C, LOGL_ERROR, "Unknown MSG: %u\n", l1h->msg_type);
                msgb_free(msg);
                break;
        }