[layer23] Rework of channel request process and control of TA and TX-power
authorAndreas.Eversberg <jolly@eversberg.eu>
Tue, 13 Jul 2010 14:21:52 +0000 (14:21 +0000)
committerAndreas.Eversberg <jolly@eversberg.eu>
Tue, 13 Jul 2010 14:21:52 +0000 (14:21 +0000)
The radio ressource layer uses RSL messages to perform RACH requests now.

TX power and timing advance is controlled before RACH request, after IMM.ASS,
and during dedicated mode. (Note that TX power control is not yet supported
by layer 1.)

src/host/layer23/include/osmocom/gsm48_rr.h
src/host/layer23/include/osmocom/lapdm.h
src/host/layer23/include/osmocom/osmocom_data.h
src/host/layer23/include/osmocom/settings.h
src/host/layer23/include/osmocom/support.h
src/host/layer23/src/gsm322.c
src/host/layer23/src/gsm48_rr.c
src/host/layer23/src/lapdm.c

index 74ccb27..16ba2fe 100644 (file)
@@ -42,6 +42,9 @@
 #define L3_ALLOC_SIZE                  256
 #define L3_ALLOC_HEADROOM              64
 
+#define RSL_ALLOC_SIZE                 256
+#define RSL_ALLOC_HEADROOM             64
+
 #define RR_ALLOC_SIZE                  256
 #define RR_ALLOC_HEADROOM              64
 
@@ -88,9 +91,8 @@ struct gsm48_rr_meas {
 };
 
 struct gsm48_cr_hist {
-       uint32_t        fn;
-       uint8_t         chan_req;
-       uint8_t         valid;
+       uint8_t                 valid;
+       struct gsm48_req_ref    ref;
 };
 
 /* RR sublayer instance */
@@ -123,9 +125,10 @@ struct gsm48_rrlayer {
        uint8_t                 wait_assign; /* waiting for assignment state */
        uint8_t                 n_chan_req; /* number left, incl. current */
        uint8_t                 chan_req_val; /* current request value */ 
-       uint8_t                 chan_req_mask; /* mask of random bits */ 
+       uint8_t                 chan_req_mask; /* mask of random bits */
 
-       /* cr_hist must be signed and greater 8 bit, -1 = no value */
+       /* cr_hist */
+       uint8_t                 cr_ra; /* stores requested ra until confirmed */
        struct gsm48_cr_hist    cr_hist[3];
 
        /* current channel descriptions */
@@ -143,6 +146,8 @@ struct gsm48_rrlayer {
 
        /* measurements */
        struct gsm48_rr_meas    meas;
+       uint8_t                 ind_tx_power; /* last indicated power */
+       uint8_t                 ind_ta; /* last indicated ta */
 
        /* BA range */
        uint8_t                 ba_ranges;
index 06ac5f8..ab048b8 100644 (file)
@@ -28,6 +28,8 @@ struct lapdm_msg_ctx {
        uint8_t link_id;
        uint8_t addr;
        uint8_t ctrl;
+       uint8_t ta_ind;
+       uint8_t tx_power_ind;
 };
 
 /* TS 04.06 / Section 3.5.2 */
@@ -80,6 +82,10 @@ void lapdm_exit(struct lapdm_entity *le);
 int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le, struct l1ctl_info_dl *l1i);
 int l2_ph_data_conf(struct msgb *msg, struct lapdm_entity *le);
 
+/* L1 confirms channel request */
+int l2_ph_chan_conf(struct msgb *msg, struct osmocom_ms *ms,
+                       struct l1ctl_info_dl *dl);
+
 /* input into layer2 (from layer 3) */
 int rslms_recvmsg(struct msgb *msg, struct osmocom_ms *ms);
 
index e4430fc..1be19a3 100644 (file)
@@ -57,7 +57,6 @@ enum osmobb_meas_sig {
        S_L1CTL_RESET,
        S_L1CTL_PM_RES,
        S_L1CTL_PM_DONE,
-       S_L1CTL_RACH_CONF,
        S_L1CTL_CCCH_MODE_CONF,
 };
 
@@ -67,11 +66,6 @@ struct osmobb_meas_res {
        uint8_t rx_lev;
 };
 
-struct osmobb_rach_conf {
-       struct osmocom_ms *ms;
-       uint32_t fn;
-};
-
 struct osmobb_ccch_mode_conf {
        struct osmocom_ms *ms;
        uint8_t ccch_mode;
index 95c53a8..e44ee3f 100644 (file)
@@ -24,6 +24,13 @@ struct gsm_settings {
        /* call related settings */
        uint8_t                 cw; /* set if call-waiting is allowed */
        uint8_t                 clip, clir;
+
+       /* changing default behavior */
+       uint8_t                 alter_tx_power;
+       uint8_t                 alter_tx_power_value;
+       int8_t                  alter_delay;
+       uint8_t                 stick;
+       uint16_t                stick_arfcn;
 };
 
 int gsm_settings_init(struct osmocom_ms *ms);
index ad1ccd7..9af4d1b 100644 (file)
@@ -86,6 +86,7 @@ struct gsm_support_scan_max {
 extern struct gsm_support_scan_max gsm_sup_smax[];
 
 void gsm_support_init(struct osmocom_ms *ms);
+int gsm_support_txpwr(uint8_t tx_power, uint16_t arfcn);
 void gsm_support_dump(struct gsm_support *sup,
                        void (*print)(void *, const char *, ...), void *priv);
 
index 6cbba03..fcc85a7 100644 (file)
@@ -239,7 +239,7 @@ static int gsm322_sync_to_cell(struct gsm322_cellsel *cs)
        }
 //     printf("s->ccch_conf %d\n", cs->si->ccch_conf);
 
-//     l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
+       l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
        return l1ctl_tx_fbsb_req(ms, cs->arfcn,
                                 L1CTL_FBSB_F_FB01SB, 100, 0,
                                 cs->ccch_mode);
@@ -2022,17 +2022,19 @@ static int gsm322_store_ba_list(struct gsm322_cellsel *cs,
 /* process system information during camping on a cell */
 static int gsm322_c_camp_sysinfo_bcch(struct osmocom_ms *ms, struct msgb *msg)
 {
-       struct gsm48_rrlayer *rr = &ms->rrlayer;
+//     struct gsm48_rrlayer *rr = &ms->rrlayer;
        struct gsm322_cellsel *cs = &ms->cellsel;
        struct gsm48_sysinfo *s = cs->si;
        struct gsm_subscriber *subscr = &ms->subscr;
        struct gsm322_msg *gm = (struct gsm322_msg *) msg->data;
        struct msgb *nmsg;
 
+#if 0
        if (rr->state != GSM48_RR_ST_IDLE) {
                LOGP(DCS, LOGL_INFO, "Ignoring in dedicated mode.\n");
                return -EBUSY;
        }
+#endif
 
        /* Store BA if we have full system info about cells and neigbor cells.
         * Depending on the extended bit in the channel description,
@@ -2210,25 +2212,37 @@ static void gsm322_cs_timeout(void *arg)
 static int gsm322_cs_powerscan(struct osmocom_ms *ms)
 {
        struct gsm322_cellsel *cs = &ms->cellsel;
+       struct gsm_settings *set = &ms->settings;
        int i, s = -1, e;
        uint8_t mask, flags;
 
        again:
 
-       /* search for first frequency to scan */
        mask = GSM322_CS_FLAG_SUPPORT | GSM322_CS_FLAG_POWER;
        flags = GSM322_CS_FLAG_SUPPORT;
-       if (cs->state == GSM322_C2_STORED_CELL_SEL
-        || cs->state == GSM322_C5_CHOOSE_CELL) {
-               LOGP(DCS, LOGL_FATAL, "Scanning power for stored BA list.\n");
-               mask |= GSM322_CS_FLAG_BA;
-               flags |= GSM322_CS_FLAG_BA;
-       } else
-               LOGP(DCS, LOGL_FATAL, "Scanning power for all frequencies.\n");
-       for (i = 0; i <= 1023; i++) {
-               if ((cs->list[i].flags & mask) == flags) {
+
+       /* in case of sticking to a cell, we only select it */
+       if (set->stick) {
+               LOGP(DCS, LOGL_FATAL, "Scanning power for sticked cell.\n");
+               i = set->stick_arfcn;
+               if ((cs->list[i].flags & mask) == flags)
                        s = e = i;
-                       break;
+       } else {
+               /* search for first frequency to scan */
+               if (cs->state == GSM322_C2_STORED_CELL_SEL
+                || cs->state == GSM322_C5_CHOOSE_CELL) {
+                       LOGP(DCS, LOGL_FATAL, "Scanning power for stored BA "
+                               "list.\n");
+                       mask |= GSM322_CS_FLAG_BA;
+                       flags |= GSM322_CS_FLAG_BA;
+               } else
+                       LOGP(DCS, LOGL_FATAL, "Scanning power for all "
+                               "frequencies.\n");
+               for (i = 0; i <= 1023; i++) {
+                       if ((cs->list[i].flags & mask) == flags) {
+                               s = e = i;
+                               break;
+                       }
                }
        }
 
@@ -2312,11 +2326,13 @@ static int gsm322_cs_powerscan(struct osmocom_ms *ms)
 
        /* search last frequency to scan (en block) */
        e = i;
-       for (i = s + 1; i <= 1023; i++) {
-               if ((cs->list[i].flags & mask) == flags)
-                       e = i;
-               else
-                       break;
+       if (!set->stick) {
+               for (i = s + 1; i <= 1023; i++) {
+                       if ((cs->list[i].flags & mask) == flags)
+                               e = i;
+                       else
+                               break;
+               }
        }
 
        LOGP(DCS, LOGL_INFO, "Scanning frequencies. (%d..%d)\n", s, e);
@@ -2334,7 +2350,6 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
        struct osmocom_ms *ms;
        struct gsm322_cellsel *cs;
        struct osmobb_meas_res *mr;
-       struct osmobb_rach_conf *rc;
        int i;
        int8_t rxlev_db;
 
@@ -2352,7 +2367,9 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
                rxlev_db = mr->rx_lev - 110;
                cs->list[i].rxlev_db = rxlev_db;
                cs->list[i].flags |= GSM322_CS_FLAG_POWER;
-               if (rxlev_db >= ms->support.min_rxlev_db) {
+               /* if minimum level is reached or if we stick to a cell */
+               if (rxlev_db >= ms->support.min_rxlev_db
+                || ms->settings.stick) {
                        cs->list[i].flags |= GSM322_CS_FLAG_SIGNAL;
                        LOGP(DCS, LOGL_INFO, "Found signal (frequency %d "
                                "rxlev %d)\n", i, cs->list[i].rxlev_db);
@@ -2413,13 +2430,7 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
                else
                        gsm322_cs_timeout(cs);
                break;
-       case S_L1CTL_RACH_CONF:
-               rc = signal_data;
-               ms = rc->ms;
-               gsm48_rr_rach_conf(ms, rc->fn);
-               break;
        case S_L1CTL_RESET:
-               LOGP(DCS, LOGL_INFO, "Reset\n");
                break;
        }
 
index 2faf38a..92bd2ec 100644 (file)
@@ -206,6 +206,13 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state)
                (sizeof(gsm48_rr_state_names) / sizeof(char *)))
                return;
 
+       /* must check against equal state */
+       if (rr->state == state) {
+               LOGP(DRR, LOGL_INFO, "equal state ? %s\n",
+                       gsm48_rr_state_names[rr->state]);
+               return;
+       }
+
        LOGP(DRR, LOGL_INFO, "new state %s -> %s\n",
                gsm48_rr_state_names[rr->state], gsm48_rr_state_names[state]);
 
@@ -215,7 +222,7 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state)
                struct msgb *msg, *nmsg;
 
                /* release dedicated mode, if any */
-//             tx_ph_dm_rel_req(rr->ms);
+               tx_ph_dm_rel_req(rr->ms);
                l1ctl_tx_reset_req(rr->ms, L1CTL_RES_T_FULL);
                /* free establish message, if any */
                rr->rr_est_req = 0;
@@ -286,6 +293,20 @@ struct msgb *gsm48_l3_msgb_alloc(void)
        return msg;
 }
 
+/* allocate GSM 04.06 layer 2 RSL message */
+struct msgb *gsm48_rsl_msgb_alloc(void)
+{
+       struct msgb *msg;
+
+       msg = msgb_alloc_headroom(RSL_ALLOC_SIZE+RSL_ALLOC_HEADROOM,
+               RSL_ALLOC_HEADROOM, "GSM 04.06 RSL");
+       if (!msg)
+               return NULL;
+       msg->l2h = msg->data;
+
+       return msg;
+}
+
 /* allocate GSM 04.08 message (RR-SAP) */
 struct msgb *gsm48_rr_msgb_alloc(int msg_type)
 {
@@ -330,7 +351,7 @@ static int gsm48_send_rsl(struct osmocom_ms *ms, uint8_t msg_type,
 }
 
 /* enqueue messages (RSL-SAP) */
-static int gsm48_rx_rll(struct msgb *msg, struct osmocom_ms *ms)
+static int gsm48_rx_rsl(struct msgb *msg, struct osmocom_ms *ms)
 {
        struct gsm48_rrlayer *rr = &ms->rrlayer;
 
@@ -339,28 +360,6 @@ static int gsm48_rx_rll(struct msgb *msg, struct osmocom_ms *ms)
        return 0;
 }
 
-/* input function that L2 calls when sending messages up to L3 */
-static int gsm48_rx_rsl(struct msgb *msg, struct osmocom_ms *ms)
-{
-       struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
-       int rc = 0;
-
-       switch (rslh->msg_discr & 0xfe) {
-       case ABIS_RSL_MDISC_RLL:
-               rc = gsm48_rx_rll(msg, ms);
-               break;
-       default:
-               /* FIXME: implement this */
-               LOGP(DRSL, LOGL_NOTICE, "unknown RSLms msg_discr 0x%02x\n",
-                       rslh->msg_discr);
-               msgb_free(msg);
-               rc = -EINVAL;
-               break;
-       }
-
-       return rc;
-}
-
 /* dequeue messages (RSL-SAP) */
 int gsm48_rsl_dequeue(struct osmocom_ms *ms)
 {
@@ -821,33 +820,6 @@ static int gsm48_rr_rx_cm_enq(struct osmocom_ms *ms, struct msgb *msg)
  * random access
  */
 
-/* temporary timer until we have time control over channnel request */
-/* TODO: turn this into a channel activation timeout, later */
-#define RSL_MT_CHAN_CNF 0x19
-#include <osmocom/l1ctl.h>
-int gsm48_rr_rach_conf(struct osmocom_ms *ms, uint32_t fn)
-{
-       struct gsm48_rrlayer *rr = &ms->rrlayer;
-       struct msgb *msg = msgb_alloc_headroom(23+10, 10, "LAPDm RR");
-       struct abis_rsl_rll_hdr *rllh =
-               (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rllh));
-
-       if (!rr->wait_assign) {
-               LOGP(DRR, LOGL_INFO, "RACH confirm ignored, not waiting for "
-                       "assignment.\n");
-               return 0;
-       }
-       LOGP(DRR, LOGL_INFO, "RACH confirm framenr=%u\n", fn);
-       rr->cr_hist[0].valid = 2;
-       rr->cr_hist[0].fn = fn;
-
-       rllh->c.msg_type = RSL_MT_CHAN_CNF;
-       msg->l2h = (unsigned char *)rllh;
-       gsm48_rcv_rsl(ms, msg);
-
-       return 0;
-}
-
 /* start random access */
 static int gsm48_rr_chan_req(struct osmocom_ms *ms, int cause, int paging)
 {
@@ -889,6 +861,9 @@ static int gsm48_rr_chan_req(struct osmocom_ms *ms, int cause, int paging)
        /* 3.3.1.1.2 */
        new_rr_state(rr, GSM48_RR_ST_CONN_PEND);
 
+       /* set assignment state */
+       rr->wait_assign = 0;
+
        /* number of retransmissions (with first transmission) */
        rr->n_chan_req = s->max_retrans + 1;
 
@@ -1036,11 +1011,40 @@ int gsm48_rr_tx_rand_acc(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_rrlayer *rr = &ms->rrlayer;
        struct gsm322_cellsel *cs = &ms->cellsel;
        struct gsm48_sysinfo *s = &ms->cellsel.sel_si;
+       struct gsm_settings *set = &ms->settings;
        struct msgb *nmsg;
-       struct l1ctl_info_ul *nul;
-       struct l1ctl_rach_req *nra;
+       struct abis_rsl_cchan_hdr *ncch;
        int slots;
        uint8_t chan_req;
+       uint8_t tx_power;
+
+       /* already assigned */
+       if (rr->wait_assign == 2)
+               return 0;
+
+       /* store frame number */
+       if (msg) {
+               struct abis_rsl_cchan_hdr *ch = msgb_l2(msg);
+               struct gsm48_req_ref *ref =
+                               (struct gsm48_req_ref *) (ch->data + 1);
+
+               if (msgb_l2len(msg) < sizeof(*ch) + sizeof(*ref)) {
+                       LOGP(DRR, LOGL_ERROR, "CHAN_CNF too slort\n");
+                       return -EINVAL;
+               }
+
+               /* shift history and store */
+               memcpy(&(rr->cr_hist[2]), &(rr->cr_hist[1]),
+                       sizeof(struct gsm48_cr_hist));
+               memcpy(&(rr->cr_hist[1]), &(rr->cr_hist[0]),
+                       sizeof(struct gsm48_cr_hist));
+               rr->cr_hist[0].valid = 1;
+               rr->cr_hist[0].ref.ra = rr->cr_ra;
+               rr->cr_hist[0].ref.t1 = ref->t1;
+               rr->cr_hist[0].ref.t2 = ref->t2;
+               rr->cr_hist[0].ref.t3_low = ref->t3_low;
+               rr->cr_hist[0].ref.t3_high = ref->t3_high;
+       }
 
        if (cs->ccch_state != GSM322_CCCH_ST_DATA) {
                LOGP(DRR, LOGL_INFO, "CCCH channel activation failed.\n");
@@ -1081,7 +1085,7 @@ int gsm48_rr_tx_rand_acc(struct osmocom_ms *ms, struct msgb *msg)
        }
        rr->n_chan_req--;
 
-       if (!rr->wait_assign) {
+       if (rr->wait_assign == 0) {
                /* first random acces, without delay of slots */
                slots = 0;
                rr->wait_assign = 1;
@@ -1121,47 +1125,62 @@ int gsm48_rr_tx_rand_acc(struct osmocom_ms *ms, struct msgb *msg)
                }
        }
 
-       /* resend chan_req with new randiom */
-#ifdef TODO
-       nmsg = gsm48_rsl_msgb_alloc();
-#else
-       nmsg = msgb_alloc_headroom(64, 48, "RAND_ACC");
-       struct l1ctl_hdr *l1h;
-       nmsg->l1h = msgb_put(nmsg, sizeof(*l1h));
-       l1h = (struct l1ctl_hdr *) nmsg->l1h;
-       l1h->msg_type = L1CTL_RACH_REQ;
-       if (!nmsg)
-               return -ENOMEM;
-       nul = (struct l1ctl_info_ul *) msgb_put(nmsg, sizeof(*nul));
-#endif
-       nra = (struct l1ctl_rach_req *) msgb_put(nmsg, sizeof(*nra));
        chan_req = random();
        chan_req &= rr->chan_req_mask;
        chan_req |= rr->chan_req_val;
-       nra->ra = chan_req;
-#warning TODO
-       nra->mf_off = 1; // (random() % s->tx_integer) + slots;
-       nra->fn51 = (s->ccch_conf == 1) ? 27 : 50;
 
        LOGP(DRR, LOGL_INFO, "RANDOM ACCESS (Tx-integer %d combined %s "
-               "S(lots) %d ra 0x%02x offset %d)\n", s->tx_integer,
-               (s->ccch_conf == 1) ? "yes": "no", slots, nra->ra, nra->mf_off);
+               "S(lots) %d ra 0x%02x)\n", s->tx_integer,
+               (s->ccch_conf == 1) ? "yes": "no", slots, chan_req);
 
-       /* shift history and store */
-       memcpy(&(rr->cr_hist[2]), &(rr->cr_hist[1]),
-               sizeof(struct gsm48_cr_hist));
-       memcpy(&(rr->cr_hist[1]), &(rr->cr_hist[0]),
-               sizeof(struct gsm48_cr_hist));
-       rr->cr_hist[0].valid = 1;
-       rr->cr_hist[0].chan_req = chan_req;
+       /* (re)send CHANNEL RQD with new randiom */
+       nmsg = gsm48_rsl_msgb_alloc();
+       if (!nmsg)
+               return -ENOMEM;
+       ncch = (struct abis_rsl_cchan_hdr *) msgb_put(nmsg, sizeof(*ncch)
+                                                       + 4 + 2 + 2);
+       rsl_init_cchan_hdr(ncch, RSL_MT_CHAN_RQD);
+       ncch->chan_nr = RSL_CHAN_RACH;
+       ncch->data[0] = RSL_IE_REQ_REFERENCE;
+       ncch->data[1] = chan_req;
+#warning HACK: fn51 and fn_off
+       ncch->data[2] = (s->ccch_conf == 1) ? 27 : 50;
+       ncch->data[3] = 1 + ((random() % s->tx_integer) + slots) / 51;
+printf("%d\n", ncch->data[3]);
+       ncch->data[4] = RSL_IE_ACCESS_DELAY;
+       ncch->data[5] = set->alter_delay; /* (-)=earlier (+)=later */
+       ncch->data[6] = RSL_IE_MS_POWER;
+       if (set->alter_tx_power) {
+               tx_power = set->alter_tx_power_value;
+               LOGP(DRR, LOGL_INFO, "Use alternative tx-power %d (%d dBm)\n",
+                       tx_power,
+                       ms_pwr_dbm(gsm_arfcn2band(cs->arfcn), tx_power));
+       } else {
+               tx_power = s->ms_txpwr_max_cch;
+               /* power offset in case of DCS1800 */
+               if (s->po && cs->arfcn >= 512 && cs->arfcn <= 885) {
+                       LOGP(DRR, LOGL_INFO, "Use MS-TXPWR-MAX-CCH power value "
+                               "%d (%d dBm) with offset %d dBm\n", tx_power,
+                               ms_pwr_dbm(gsm_arfcn2band(cs->arfcn), tx_power),
+                               s->po_value * 2);
+                       /* use reserved bits 7,8 for offset (+ X * 2dB) */
+                       tx_power |= s->po_value << 6;
+               } else
+                       LOGP(DRR, LOGL_INFO, "Use MS-TXPWR-MAX-CCH power value "
+                               "%d (%d dBm)\n", tx_power,
+                               ms_pwr_dbm(gsm_arfcn2band(cs->arfcn),
+                                                       tx_power));
+       }
+       ncch->data[7] = tx_power;
 
-#ifdef TODO
-       add layer 1 conrols to RSL...
-       return gsm48_send_rsl(ms, RSL_MT_CHAN_REQ, nmsg);
-#else
-//#warning disabled!
-       return osmo_send_l1(ms, nmsg);
-#endif
+       /* set initial indications */
+       rr->ind_tx_power = s->ms_txpwr_max_cch;
+       rr->ind_ta = set->alter_delay;
+
+       /* store ra until confirmed, then copy it with time into cr_hist */
+       rr->cr_ra = chan_req;
+
+       return rslms_recvmsg(nmsg, ms);
 }
 
 /*
@@ -2273,8 +2292,8 @@ static int gsm48_rr_rx_sysinfo6(struct osmocom_ms *ms, struct msgb *msg)
                gsm48_decode_si6_rest(s, si->rest_octets, payload_len);
 
        LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 6 (mcc %s mnc %s "
-               "lac 0x%04x)\n", gsm_print_mcc(s->mcc),
-               gsm_print_mnc(s->mnc), s->lac);
+               "lac 0x%04x SACCH-timeout %d)\n", gsm_print_mcc(s->mcc),
+               gsm_print_mnc(s->mnc), s->lac, s->sacch_radio_link_timeout);
 
        s->si6 = 1;
 
@@ -2529,19 +2548,21 @@ static int gsm48_match_ra(struct osmocom_ms *ms, struct gsm48_req_ref *ref)
 {
        struct gsm48_rrlayer *rr = &ms->rrlayer;
        int i;
-       struct gsm_time tm;
        uint8_t ia_t1, ia_t2, ia_t3;
+       uint8_t cr_t1, cr_t2, cr_t3;
 
        for (i = 0; i < 3; i++) {
                /* filter confirmed RACH requests only */
-               if (rr->cr_hist[i].valid == 2
-                && ref->ra == rr->cr_hist[i].chan_req) {
+               if (rr->cr_hist[i].valid && ref->ra == rr->cr_hist[i].ref.ra) {
                        ia_t1 = ref->t1;
                        ia_t2 = ref->t2;
                        ia_t3 = (ref->t3_high << 3) | ref->t3_low;
-                       gsm_fn2gsmtime(&tm, rr->cr_hist[i].fn);
-                       if (ia_t1 == (tm.t1 & 0x1f) && ia_t2 == tm.t2
-                        && ia_t3 == tm.t3) {
+                       ref = &rr->cr_hist[i].ref;
+                       cr_t1 = ref->t1;
+                       cr_t2 = ref->t2;
+                       cr_t3 = (ref->t3_high << 3) | ref->t3_low;
+                       if (ia_t1 == cr_t1 && ia_t2 == cr_t2
+                        && ia_t3 == cr_t3) {
                                LOGP(DRR, LOGL_INFO, "request %02x matches "
                                        "(fn=%d,%d,%d)\n", ref->ra, ia_t1,
                                        ia_t2, ia_t3);
@@ -2551,7 +2572,7 @@ static int gsm48_match_ra(struct osmocom_ms *ms, struct gsm48_req_ref *ref)
                                        "but not frame number (IMM.ASS "
                                        "fn=%d,%d,%d != RACH fn=%d,%d,%d)\n",
                                        ref->ra, ia_t1, ia_t2, ia_t3,
-                                       tm.t1 & 0x1f, tm.t2, tm.t3);
+                                       cr_t1, cr_t2, cr_t3);
                }
        }
 
@@ -2614,11 +2635,16 @@ static int gsm48_rr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
        }
 
        /* 3.3.1.1.2: ignore assignment while idle */
-       if (rr->state != GSM48_RR_ST_CONN_PEND || !rr->wait_assign) {
+       if (rr->state != GSM48_RR_ST_CONN_PEND || rr->wait_assign == 0) {
                LOGP(DRR, LOGL_INFO, "Not for us, no request.\n");
                return 0;
        }
 
+       if (rr->wait_assign == 2) {
+               LOGP(DRR, LOGL_INFO, "Ignoring, channel already assigned.\n");
+               return 0;
+       }
+
        /* request ref */
        if (gsm48_match_ra(ms, &ia->req_ref)) {
                /* channel description */
@@ -2628,7 +2654,7 @@ static int gsm48_rr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
                /* mobile allocation */
                memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len, 
                        ia->mob_alloc_len + 1);
-               rr->wait_assign = 0;
+               rr->wait_assign = 2;
                return gsm48_rr_dl_est(ms);
        }
        LOGP(DRR, LOGL_INFO, "Request, but not for us.\n");
@@ -2718,11 +2744,16 @@ static int gsm48_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg)
        }
 
        /* 3.3.1.1.2: ignore assignment while idle */
-       if (rr->state != GSM48_RR_ST_CONN_PEND || !rr->wait_assign) {
+       if (rr->state != GSM48_RR_ST_CONN_PEND || rr->wait_assign == 0) {
                LOGP(DRR, LOGL_INFO, "Not for us, no request.\n");
                return 0;
        }
 
+       if (rr->wait_assign == 2) {
+               LOGP(DRR, LOGL_INFO, "Ignoring, channel already assigned.\n");
+               return 0;
+       }
+
        /* request ref 1 */
        if (gsm48_match_ra(ms, &ia->req_ref1)) {
                /* channel description */
@@ -2732,7 +2763,7 @@ static int gsm48_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg)
                /* mobile allocation */
                memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len,
                        ia->mob_alloc_len + 1);
-               rr->wait_assign = 0;
+               rr->wait_assign = 2;
                return gsm48_rr_dl_est(ms);
        }
        /* request ref 1 */
@@ -2744,7 +2775,7 @@ static int gsm48_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg)
                /* mobile allocation */
                memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len,
                        ia->mob_alloc_len + 1);
-               rr->wait_assign = 0;
+               rr->wait_assign = 2;
                return gsm48_rr_dl_est(ms);
        }
        LOGP(DRR, LOGL_INFO, "Request, but not for us.\n");
@@ -2763,8 +2794,12 @@ static int gsm48_rr_rx_imm_ass_rej(struct osmocom_ms *ms, struct msgb *msg)
        uint8_t t3122_value;
 
        /* 3.3.1.1.2: ignore assignment while idle */
-       if (rr->state != GSM48_RR_ST_CONN_PEND || !rr->wait_assign)
+       if (rr->state != GSM48_RR_ST_CONN_PEND || rr->wait_assign == 0)
+               return 0;
+
+       if (rr->wait_assign == 2) {
                return 0;
+       }
 
        if (payload_len < 0) {
                LOGP(DRR, LOGL_NOTICE, "Short read of IMMEDIATE ASSIGNMENT "
@@ -2961,6 +2996,7 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms)
        struct gsm_subscriber *subscr = &ms->subscr;
        struct gsm322_cellsel *cs = &ms->cellsel;
        struct gsm48_sysinfo *s = cs->si;
+       struct gsm_settings *set = &ms->settings;
        struct msgb *nmsg;
        struct gsm48_hdr *gh;
        struct gsm48_pag_rsp *pr;
@@ -3018,23 +3054,36 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms)
                memcpy(pr->data, mi + 1, 1 + mi[1]);
        }
 
+       /* reset scheduler */
+       LOGP(DRR, LOGL_INFO, "resetting scheduler\n");
+       l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED);
+
+       /* setting (new) timing advance */
+       rr->ind_ta = rr->cd_now.ta;
+       LOGP(DRR, LOGL_INFO, "setting indicated ta %d (actual ta %d)\n",
+               rr->ind_ta, rr->ind_ta - set->alter_delay);
+       l1ctl_tx_ph_param_req(ms, rr->ind_ta - set->alter_delay,
+                       (set->alter_tx_power) ? set->alter_tx_power_value
+                                               : rr->ind_tx_power);
+
        /* activate channel */
+       LOGP(DRR, LOGL_INFO, "activating channel\n");
 #ifdef TODO
        RSL_MT_ to activate channel with all the cd_now informations
 #else
        rsl_dec_chan_nr(rr->cd_now.chan_nr, &ch_type, &ch_subch, &ch_ts);
        if ((ch_type != RSL_CHAN_SDCCH8_ACCH
-         && ch_type != RSL_CHAN_SDCCH4_ACCH) || ch_ts > 4) {
+         && ch_type != RSL_CHAN_SDCCH4_ACCH) || ch_ts > 4 || ch_subch >= 4) {
                printf("Channel type %d, subch %d, ts %d not supported, "
                        "exitting.\n", ch_type, ch_subch, ch_ts);
                exit(-ENOTSUP);
        }
        if (rr->cd_now.h)
                tx_ph_dm_est_req_h1(ms, rr->cd_now.maio, rr->cd_now.hsn,
-                       ma, ma_len, rr->cd_now.chan_nr, rr->cd_now.tsc, 0);
+                       ma, ma_len, rr->cd_now.chan_nr, rr->cd_now.tsc);
        else
                tx_ph_dm_est_req_h0(ms, rr->cd_now.arfcn, rr->cd_now.chan_nr,
-                       rr->cd_now.tsc, 0);
+                       rr->cd_now.tsc);
 #endif
 
        /* start establishmnet */
@@ -3546,8 +3595,10 @@ static int gsm48_rr_rx_pch_agch(struct osmocom_ms *ms, struct msgb *msg)
        case GSM48_MT_RR_IMM_ASS_REJ:
                return gsm48_rr_rx_imm_ass_rej(ms, msg);
        default:
+#if 0
                LOGP(DRR, LOGL_NOTICE, "CCCH message type 0x%02x unknown.\n",
                        sih->system_information);
+#endif
                return -EINVAL;
        }
 }
@@ -3555,7 +3606,31 @@ static int gsm48_rr_rx_pch_agch(struct osmocom_ms *ms, struct msgb *msg)
 /* receive ACCH at RR layer */
 static int gsm48_rr_rx_acch(struct osmocom_ms *ms, struct msgb *msg)
 {
+       struct gsm48_rrlayer *rr = &ms->rrlayer;
+       struct gsm_settings *set = &ms->settings;
+       struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
        struct gsm48_system_information_type_header *sih = msgb_l3(msg);
+       uint8_t ind_ta, ind_tx_power;
+
+       if (msgb_l2len(msg) < sizeof(*rllh) + 2 + 2) {
+               LOGP(DRR, LOGL_ERROR, "Missing TA and TX_POWER IEs\n");
+               return -EINVAL;
+       }
+
+       ind_ta = rllh->data[1];
+       ind_tx_power = rllh->data[3];
+       LOGP(DRR, LOGL_INFO, "Indicated ta %d (actual ta %d)\n",
+               ind_ta, ind_ta - set->alter_delay);
+       LOGP(DRR, LOGL_INFO, "Indicated tx_power %d\n",
+               ind_tx_power);
+       if (ind_ta != rr->ind_ta || ind_tx_power != rr->ind_tx_power) {
+               LOGP(DRR, LOGL_INFO, "setting new ta and tx_power\n");
+               l1ctl_tx_ph_param_req(ms, ind_ta - set->alter_delay,
+                       (set->alter_tx_power) ? set->alter_tx_power_value
+                                               : ind_tx_power);
+               rr->ind_ta = ind_ta;
+               rr->ind_tx_power = ind_tx_power;
+       }
 
        switch (sih->system_information) {
        case GSM48_MT_RR_SYSINFO_5:
@@ -3576,6 +3651,7 @@ static int gsm48_rr_rx_acch(struct osmocom_ms *ms, struct msgb *msg)
 /* unit data from layer 2 to RR layer */
 static int gsm48_rr_unit_data_ind(struct osmocom_ms *ms, struct msgb *msg)
 {
+       struct gsm48_rrlayer *rr = &ms->rrlayer;
        struct gsm322_cellsel *cs = &ms->cellsel;
        struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
        struct tlv_parsed tv;
@@ -3603,7 +3679,10 @@ static int gsm48_rr_unit_data_ind(struct osmocom_ms *ms, struct msgb *msg)
        set radio link timeout on layer 1
        it is the number of subsequent BCCH blocks. (about 1/4 seconds)
 #else
-               start_loss_timer(cs, s->bcch_radio_link_timeout / 4, 0);
+               /* use maximu loss timer, if to value is not available yet */
+               start_loss_timer(cs, ((rr->state == GSM48_RR_ST_DEDICATED)
+                       ? ((s->sacch_radio_link_timeout) ? : 64)
+                       : s->bcch_radio_link_timeout) / 4, 0);
 #endif
        }
 
@@ -3758,9 +3837,6 @@ static struct dldatastate {
         RSL_MT_DATA_IND, gsm48_rr_data_ind},
 
        /* esablish */
-       {SBIT(GSM48_RR_ST_CONN_PEND), /* 3.3.1.1.2 */
-        RSL_MT_CHAN_CNF, gsm48_rr_tx_rand_acc},
-
        {SBIT(GSM48_RR_ST_IDLE) |
         SBIT(GSM48_RR_ST_CONN_PEND) |
         SBIT(GSM48_RR_ST_REL_PEND),
@@ -3799,7 +3875,7 @@ static struct dldatastate {
 #define DLDATASLLEN \
        (sizeof(dldatastatelist) / sizeof(struct dldatastate))
 
-static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg)
+static int gsm48_rcv_rll(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct gsm48_rrlayer *rr = &ms->rrlayer;
        struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
@@ -3833,6 +3909,55 @@ static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg)
        return rc;
 }
 
+static int gsm48_rcv_cch(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct gsm48_rrlayer *rr = &ms->rrlayer;
+       struct abis_rsl_cchan_hdr *ch = msgb_l2(msg);
+       int msg_type = ch->c.msg_type;
+       int rc;
+
+       LOGP(DRSL, LOGL_INFO, "(ms %s) Received '%s' from L2 in state "
+               "%s\n", ms->name, get_rsl_name(msg_type),
+               gsm48_rr_state_names[rr->state]);
+
+       if (rr->state == GSM48_RR_ST_CONN_PEND
+        && msg_type == RSL_MT_CHAN_CONF) {
+               rc = gsm48_rr_tx_rand_acc(ms, msg);
+               msgb_free(msg);
+               return rc;
+       }
+
+       LOGP(DRSL, LOGL_NOTICE, "RSLms message unhandled\n");
+       msgb_free(msg);
+       return 0;
+}
+
+
+/* input function for L2 messags up to L3 */
+static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
+       int rc = 0;
+
+       switch (rslh->msg_discr & 0xfe) {
+       case ABIS_RSL_MDISC_RLL:
+               rc = gsm48_rcv_rll(ms, msg);
+               break;
+       case ABIS_RSL_MDISC_COM_CHAN:
+               rc = gsm48_rcv_cch(ms, msg);
+               break;
+       default:
+               /* FIXME: implement this */
+               LOGP(DRSL, LOGL_NOTICE, "unknown RSLms msg_discr 0x%02x\n",
+                       rslh->msg_discr);
+               msgb_free(msg);
+               rc = -EINVAL;
+               break;
+       }
+
+       return rc;
+}
+
 /* state trasitions for RR-SAP messages from up */
 static struct rrdownstate {
        uint32_t        states;
@@ -4110,12 +4235,13 @@ static int gsm48_rr_connect_cnf(struct osmocom_ms *ms, struct msgbl *msg)
 static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct gsm48_rrlayer *rr = ms->rrlayer;
+       struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
        struct msgb *nmsg;
-       struct gsm_rr_hdr *nrrh;
+       uint8_t cause = rllh->data[2];
 
        printing of the cause
 
-       switch (msg->l3h[0]) {
+       switch (cause) {
        case RLL_CAUSE_SEQ_ERR:
        case RLL_CAUSE_UNSOL_DM_RESP_MF:
        einige muessen ignoriert werden
index eff7aab..9e4b4a1 100644 (file)
@@ -54,6 +54,7 @@
 #include <stdint.h>
 #include <string.h>
 #include <errno.h>
+#include <arpa/inet.h>
 
 #include <osmocore/logging.h>
 #include <osmocore/timer.h>
@@ -364,7 +365,7 @@ printf("\n");
        return tx_ph_data_req(ms, msg, chan_nr, link_id);
 }
 
-/* Take a Bbis format message from L1 and create RSLms UNIT DATA IND */
+/* Create RSLms various RSLms messages */
 static int send_rslms_rll_l3(uint8_t msg_type, struct lapdm_msg_ctx *mctx,
                             struct msgb *msg)
 {
@@ -375,6 +376,28 @@ static int send_rslms_rll_l3(uint8_t msg_type, struct lapdm_msg_ctx *mctx,
        return rslms_sendmsg(msg, mctx->dl->entity->ms);
 }
 
+/* Take a B4 format message from L1 and create RSLms UNIT DATA IND */
+static int send_rslms_rll_l3_ui(struct lapdm_msg_ctx *mctx, struct msgb *msg)
+{
+       uint8_t l3_len = msg->tail - (uint8_t *)msgb_l3(msg);
+       struct abis_rsl_rll_hdr *rllh;
+
+       /* Add the RSL + RLL header */
+       msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
+       msgb_push(msg, 2 + 2);
+       rsl_rll_push_hdr(msg, RSL_MT_UNIT_DATA_IND, mctx->chan_nr,
+               mctx->link_id, 1);
+       rllh = (struct abis_rsl_rll_hdr *)msgb_l2(msg);
+
+       rllh->data[0] = RSL_IE_ACCESS_DELAY;
+       rllh->data[1] = mctx->ta_ind;
+
+       rllh->data[2] = RSL_IE_MS_POWER;
+       rllh->data[3] = mctx->tx_power_ind;
+       
+       return rslms_sendmsg(msg, mctx->dl->entity->ms);
+}
+
 static int send_rll_simple(uint8_t msg_type, struct lapdm_msg_ctx *mctx)
 {
        struct msgb *msg;
@@ -388,11 +411,15 @@ static int send_rll_simple(uint8_t msg_type, struct lapdm_msg_ctx *mctx)
 static int rsl_rll_error(uint8_t cause, struct lapdm_msg_ctx *mctx)
 {
        struct msgb *msg;
+       uint8_t *tlv;
 
        LOGP(DLAPDM, LOGL_NOTICE, "sending MDL-ERROR-IND %d\n", cause);
        msg = rsl_rll_simple(RSL_MT_ERROR_IND, mctx->chan_nr, mctx->link_id, 1);
-       msg->l2h = msgb_put(msg, sizeof(struct abis_rsl_rll_hdr) + 1);
-       msg->l2h[0] = cause;
+       msg->l2h = msgb_put(msg, sizeof(struct abis_rsl_rll_hdr) + 3);
+       tlv = msg->l2h + sizeof(struct abis_rsl_rll_hdr);
+       tlv[0] = RSL_IE_RLM_CAUSE;
+       tlv[1] = 1;
+       tlv[2] = cause;
        return rslms_sendmsg(msg, mctx->dl->entity->ms);
 }
 
@@ -874,7 +901,7 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
                        return 0;
                }
                msgb_pull_l2h(msg);
-               rc = send_rslms_rll_l3(RSL_MT_UNIT_DATA_IND, mctx, msg);
+               rc = send_rslms_rll_l3_ui(mctx, msg);
                break;
        case LAPDm_U_DISC:
                rsl_msg = RSL_MT_REL_IND;
@@ -1502,6 +1529,8 @@ int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le, struct l1ctl_info_
                        LOGP(DLAPDM, LOGL_INFO, "fmt=B4\n");
                        /* SACCH frames have a two-byte L1 header that
                         * OsmocomBB L1 doesn't strip */
+                       mctx.tx_power_ind = msg->l2h[0] & 0x1f;
+                       mctx.ta_ind = msg->l2h[1];
                        msgb_pull(msg, 2);
                        msg->l2h += 2;
                } else {
@@ -1948,6 +1977,64 @@ static int rslms_rx_rll_rel_req_idle(struct msgb *msg, struct lapdm_datalink *dl
        return send_rll_simple(RSL_MT_REL_CONF, &dl->mctx);
 }
 
+/* L3 requests channel in idle state */
+static int rslms_rx_chan_rqd(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct abis_rsl_cchan_hdr *cch = msgb_l2(msg);
+       int rc;
+
+       if (msgb_l2len(msg) < sizeof(*cch) + 4 + 2 + 2) {
+               LOGP(DRSL, LOGL_ERROR, "Message too short for CHAN RQD!\n");
+               return -EINVAL;
+       }
+       if (cch->data[0] != RSL_IE_REQ_REFERENCE) {
+               LOGP(DRSL, LOGL_ERROR, "Missing REQ REFERENCE IE\n");
+               return -EINVAL;
+       }
+       if (cch->data[4] != RSL_IE_ACCESS_DELAY) {
+               LOGP(DRSL, LOGL_ERROR, "Missing ACCESS_DELAY IE\n");
+               return -EINVAL;
+       }
+       if (cch->data[6] != RSL_IE_MS_POWER) {
+               LOGP(DRSL, LOGL_ERROR, "Missing MS POWER IE\n");
+               return -EINVAL;
+       }
+
+       /* TA = 0 - delay */
+       rc = l1ctl_tx_ph_param_req(ms, 0 - cch->data[5], cch->data[7]);
+
+       rc = tx_ph_rach_req(ms, cch->data[1], cch->data[2], cch->data[3]);
+
+       msgb_free(msg);
+
+       return rc;
+}
+
+/* L1 confirms channel request */
+int l2_ph_chan_conf(struct msgb *msg, struct osmocom_ms *ms,
+                       struct l1ctl_info_dl *dl)
+{
+       struct abis_rsl_cchan_hdr *ch;
+       struct gsm_time tm;
+       struct gsm48_req_ref *ref;
+
+       gsm_fn2gsmtime(&tm, htonl(dl->frame_nr));
+
+       msgb_pull_l2h(msg);
+       msg->l2h = msgb_push(msg, sizeof(*ch) + sizeof(*ref));
+       ch = (struct abis_rsl_cchan_hdr *)msg->l2h;
+       rsl_init_cchan_hdr(ch, RSL_MT_CHAN_CONF);
+       ch->chan_nr = RSL_CHAN_RACH;
+       ch->data[0] = RSL_IE_REQ_REFERENCE;
+       ref = (struct gsm48_req_ref *) (ch->data + 1);
+       ref->t1 = tm.t1;
+       ref->t2 = tm.t2;
+       ref->t3_low = tm.t3 & 0x3;
+       ref->t3_high = tm.t3 >> 3;
+       
+       return rslms_sendmsg(msg, ms);
+}
+
 /* Names for Radio Link Layer Management */
 static const struct value_string rsl_msg_names[] = {
        { RSL_MT_DATA_REQ,              "RSL_MT_DATA_REQ" },
@@ -1966,6 +2053,8 @@ static const struct value_string rsl_msg_names[] = {
        { RSL_MT_SUSP_CONF,             "RSL_MT_SUSP_CONF" },
        { RSL_MT_RES_REQ,               "RSL_MT_RES_REQ" },
        { RSL_MT_RECON_REQ,             "RSL_MT_RECON_REQ" },
+       { RSL_MT_CHAN_RQD,              "RSL_MT_CHAN_RQD" },
+       { RSL_MT_CHAN_CONF,             "RSL_MT_CHAN_CONF" },
        { 0,                            NULL }
 };
 
@@ -2026,8 +2115,6 @@ static struct l2downstate {
        /* release in idle state */
        {SBIT(LAPDm_STATE_IDLE),
         RSL_MT_REL_REQ, rslms_rx_rll_rel_req_idle},
-
-       /* FIXME: create and send DISC command */
 };
 
 #define L2DOWNSLLEN \
@@ -2044,6 +2131,11 @@ static int rslms_rx_rll(struct msgb *msg, struct osmocom_ms *ms)
        int i, supported = 0;
        int rc = 0;
 
+       if (msgb_l2len(msg) < sizeof(*rllh)) {
+               LOGP(DRSL, LOGL_ERROR, "Message too short for RLL hdr!\n");
+               return -EINVAL;
+       }
+
        if (rllh->link_id & 0x40)
                le = &ms->l2_entity.lapdm_acch;
        else
@@ -2085,16 +2177,51 @@ static int rslms_rx_rll(struct msgb *msg, struct osmocom_ms *ms)
        return rc;
 }
 
+/* incoming RSLms COMMON CHANNEL message from L3 */
+static int rslms_rx_com_chan(struct msgb *msg, struct osmocom_ms *ms)
+{
+       struct abis_rsl_cchan_hdr *cch = msgb_l2(msg);
+       int msg_type = cch->c.msg_type;
+       int rc = 0;
+
+       if (msgb_l2len(msg) < sizeof(*cch)) {
+               LOGP(DRSL, LOGL_ERROR, "Message too short for COM CHAN hdr!\n");
+               return -EINVAL;
+       }
+
+       switch (msg_type) {
+       case RSL_MT_CHAN_RQD:
+               /* create and send RACH request */
+               rc = rslms_rx_chan_rqd(ms, msg);
+               break;
+       default:
+               LOGP(DRSL, LOGL_NOTICE, "Unknown COMMON CHANNEL msg %d!\n",
+                       msg_type);
+               msgb_free(msg);
+               return 0;
+       }
+
+       return rc;
+}
+
 /* input into layer2 (from layer 3) */
 int rslms_recvmsg(struct msgb *msg, struct osmocom_ms *ms)
 {
        struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
        int rc = 0;
 
+       if (msgb_l2len(msg) < sizeof(*rslh)) {
+               LOGP(DRSL, LOGL_ERROR, "Message too short RSL hdr!\n");
+               return -EINVAL;
+       }
+
        switch (rslh->msg_discr & 0xfe) {
        case ABIS_RSL_MDISC_RLL:
                rc = rslms_rx_rll(msg, ms);
                break;
+       case ABIS_RSL_MDISC_COM_CHAN:
+               rc = rslms_rx_com_chan(msg, ms);
+               break;
        default:
                LOGP(DRSL, LOGL_ERROR, "unknown RSLms message "
                        "discriminator 0x%02x", rslh->msg_discr);