Work on various L3 processes.
[osmocom-bb.git] / src / host / gsm48-andreas / gsm48_rr.c
index f1dfc18..bb11856 100644 (file)
  *
  */
 
+/* Very short description of some of the procedures:
+ *
+ * A radio ressource request causes sendig a channel request on RACH.
+ * After receiving of an immediate assignment the link will be establised.
+ * After the link is established, the dedicated mode is entered and confirmed.
+ *
+ * A Paging request also triggers the channel request as above...
+ * After the link is established, the dedicated mode is entered and indicated.
+ *
+ * During dedicated mode, messages are transferred.
+ *
+ * When an assignment command or a handover command is received, the current
+ * link is released. After release, the new channel is activated and the
+ * link is established again. After link is establised, pending messages from
+ * radio ressource are sent.
+ *
+ * When the assignment or handover fails, the old channel is activate and the
+ * link is established again. Also pending messages are sent.
+ *
+ */
+
 /*
  * state transition
  */
@@ -54,6 +75,31 @@ static void new_rr_state(struct gsm_rrlayer *rr, int state)
        rr->state = state;
 }
 
+/*
+ * messages
+ */
+
+/* allocate GSM 04.08 radio ressource message (RR to L2) */
+static struct msgb *gsm48_rr_msgb_alloc(void)
+{
+       struct msgb *msg;
+
+       msg = msgb_alloc_headroom(GSM48_RR_ALLOC_SIZE, GSM48_RR_ALLOC_HEADROOM,
+               "GSM 04.08 RR");
+       if (!msg)
+               return NULL;
+
+       return msg;
+}
+
+/* queue message L2 -> RR */
+int gsm48_rr_upmsg(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct gsm_rrlayer *rr = ms->rrlayer;
+
+       msgb_enqueue(&rr->up_queue, msg);
+}
+
 /*
  * timers handling
  */
@@ -108,7 +154,7 @@ static void timeout_rr_t3126(void *arg)
                mmh = (struct gsm_mm_hdr *)msg->data;
                mmh->msg_type RR_REL_IND;
                mmh->cause = GSM_MM_CAUSE_RA_FAILURE;
-               rr_rcvmsg(ms, msg);
+               gsm48_mm_upmsg(ms, msg);
        }
 
        new_rr_state(rr, GSM_RRSTATE_IDLE);
@@ -122,10 +168,11 @@ static void timeout_rr_t3126(void *arg)
 static int gsm_rr_tx_rr_status(struct osmocom_ms *ms, uint8_t cause)
 {
        struct gsm_rrlayer *rr = ms->rrlayer;
-       struct msgb *msg = gsm48_rr_msgb_alloc();
+       struct msgb *msg;
        struct gsm48_hdr *gh;
        struct gsm48_rr_status *st;
 
+       msg = gsm48_rr_msgb_alloc();
        if (!msg)
                return -ENOMEM;
        gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
@@ -149,10 +196,11 @@ static int gsm_rr_tx_cip_mode_cpl(struct osmocom_ms *ms, uint8_t cr)
 {
        struct gsm_rrlayer *rr = ms->rrlayer;
        struct gsm_subscriber *subcr = ms->subscr;
-       struct msgb *msg = gsm48_rr_msgb_alloc();
+       struct msgb *msg;
        struct gsm48_hdr *gh;
        u_int8_t buf[11], *ie;
 
+       msg = gsm48_rr_msgb_alloc();
        if (!msg)
                return -ENOMEM;
        gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
@@ -346,12 +394,13 @@ static int gsm_rr_tx_cm_change(struct osmocom_ms *ms)
 {
        struct gsm_rrlayer *rr = ms->rrlayer;
        struct gsm_support *sup = ms->support;
-       struct msgb *msg = gsm48_rr_msgb_alloc();
+       struct msgb *msg;
        struct gsm48_hdr *gh;
        struct gsm48_cm_change *cc;
        int len;
        uint8_t buf[14];
 
+       msg = gsm48_rr_msgb_alloc();
        if (!msg)
                return -ENOMEM;
        gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
@@ -505,7 +554,7 @@ static int gsm_rr_tx_chan_req(struct osmocom_ms *ms, int cause)
                mmh = (struct gsm_mm_hdr *)msg->data;
                mmh->msg_type RR_REL_IND;
                mmh->cause = GSM_MM_CAUSE_UNDEFINED;
-               rr_rcvmsg(ms, msg);
+               gsm48_mm_upmsg(ms, msg);
                new_rr_state(rr, GSM_RRSTATE_IDLE);
                return -EINVAL;
        }
@@ -533,7 +582,7 @@ static int gsm_rr_tx_chan_req(struct osmocom_ms *ms, int cause)
 static int gsm_rr_rand_acc_cnf(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct gsm_rrlayer *rr = ms->rrlayer;
-       struct msgb *newmsg;
+       struct msgb *nmsg;
        int s;
 
        if (!rr->n_chan_req) {
@@ -572,15 +621,15 @@ static int gsm_rr_rand_acc_cnf(struct osmocom_ms *ms, struct msgb *msg)
                        s = 115;
 
        /* resend chan_req */
-       newmsg = msgb_alloc_headroom(20, 16, "CHAN_REQ");
-       if (!newmsg)
+       nmsg = msgb_alloc_headroom(20, 16, "CHAN_REQ");
+       if (!nmsg)
                return -ENOMEM;
-       *msgb_put(newmsg, 1) = rr->chan_req;
-       *msgb_put(newmsg, 1) = (random() % ms->si.tx_integer) + s; /* delay */
+       *msgb_put(nmsg, 1) = rr->chan_req;
+       *msgb_put(nmsg, 1) = (random() % ms->si.tx_integer) + s; /* delay */
        rr->cr_hist[3] = rr->cr_hist[2];
        rr->cr_hist[2] = rr->cr_hist[1];
        rr->cr_hist[1] = chan_req;
-       return rslms_tx_rll_req_l3(ms, RSL_MT_RAND_ACC_REQ, chan_nr, 0, newmsg);
+       return rslms_tx_rll_req_l3(ms, RSL_MT_RAND_ACC_REQ, chan_nr, 0, nmsg);
 }
 
 /*
@@ -1177,6 +1226,7 @@ static int gsm_rr_rx_sysinfo1(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_system_information_type_1 *si = msgb_l3(msg);
        struct gsm48_sysinfo *s = ms->sysinfo;
        int payload_len = msgb_l3len(msg) - sizeof(*si);
+       struct msgb *nmsg;
 
        if (payload_len < 0) {
                DEBUGP(DRR, "Short read of SYSTEM INFORMATION 1 message.\n");
@@ -1191,6 +1241,13 @@ static int gsm_rr_rx_sysinfo1(struct osmocom_ms *ms, struct msgb *msg)
        if (payload_len)
                gsm48_decode_si1_rest(si->rest_octets, payload_len);
 
+       si->si1 = 1;
+
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
        return 0;
 }
 
@@ -1200,6 +1257,7 @@ static int gsm_rr_rx_sysinfo2(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_system_information_type_2 *si = msgb_l3(msg);
        struct gsm48_sysinfo *s = ms->sysinfo;
        int payload_len = msgb_l3len(msg) - sizeof(*si);
+       struct msgb *nmsg;
 
        if (payload_len < 0) {
                DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2 message.\n");
@@ -1213,6 +1271,13 @@ static int gsm_rr_rx_sysinfo2(struct osmocom_ms *ms, struct msgb *msg)
        /* RACH Control Parameter */
        gsm48_decode_rach_ctl_neigh(s, si->rach_control);
 
+       si->si2 = 1;
+
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
        return 0;
 }
 
@@ -1222,6 +1287,7 @@ static int gsm_rr_rx_sysinfo2bis(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_system_information_type_2bis *si = msgb_l3(msg);
        struct gsm48_sysinfo *s = ms->sysinfo;
        int payload_len = msgb_l3len(msg) - sizeof(*si);
+       struct msgb *nmsg;
 
        if (payload_len < 0) {
                DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2bis message.\n");
@@ -1235,6 +1301,13 @@ static int gsm_rr_rx_sysinfo2bis(struct osmocom_ms *ms, struct msgb *msg)
        /* RACH Control Parameter */
        gsm48_decode_rach_ctl_neigh(s, si->rach_control);
 
+       si->si2bis = 1;
+
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
        return 0;
 }
 
@@ -1244,6 +1317,7 @@ static int gsm_rr_rx_sysinfo2ter(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_system_information_type_2ter *si = msgb_l3(msg);
        struct gsm48_sysinfo *s = ms->sysinfo;
        int payload_len = msgb_l3len(msg) - sizeof(*si);
+       struct msgb *nmsg;
 
        if (payload_len < 0) {
                DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2ter message.\n");
@@ -1254,6 +1328,13 @@ static int gsm_rr_rx_sysinfo2ter(struct osmocom_ms *ms, struct msgb *msg)
        gsm48_decode_freq_list(s->freq, si->ext_bcch_frequency_list,
                sizeof(si->ext_bcch_frequency_list), 0x8e, FREQ_TYPE_NCELL_2ter);
 
+       si->si2ter = 1;
+
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
        return 0;
 }
 
@@ -1263,6 +1344,7 @@ static int gsm_rr_rx_sysinfo3(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_system_information_type_3 *si = msgb_l3(msg);
        struct gsm48_sysinfo *s = ms->sysinfo;
        int payload_len = msgb_l3len(msg) - sizeof(*si);
+       struct msgb *nmsg;
 
        if (payload_len < 0) {
                DEBUGP(DRR, "Short read of SYSTEM INFORMATION 3 message.\n");
@@ -1271,7 +1353,7 @@ static int gsm_rr_rx_sysinfo3(struct osmocom_ms *ms, struct msgb *msg)
        /* Cell Identity */
        s->cell_identity = ntohl(si->cell_identity);
        /* LAI */
-       gsm48_decode_lai(si->lai, s->mcc, s->mnc, s->lac);
+       gsm48_decode_lai(si->lai, &s->mcc, &s->mnc, &s->lac);
        /* Control Channel Description */
        gsm48_decode_ccd(s, si->control_channel_desc);
        /* Cell Options (BCCH) */
@@ -1284,6 +1366,13 @@ static int gsm_rr_rx_sysinfo3(struct osmocom_ms *ms, struct msgb *msg)
        if (payload_len >= 4)
                gsm48_decode_si3_rest(si->rest_octets, payload_len);
 
+       si->si3 = 1;
+
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
        return 0;
 }
 
@@ -1294,6 +1383,7 @@ static int gsm_rr_rx_sysinfo4(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_sysinfo *s = ms->sysinfo;
        int payload_len = msgb_l3len(msg) - sizeof(*si);
        uint8_t *data = si->data;
+       struct msgb *nmsg;
 todo: si has different header in structures
 
        if (payload_len < 0) {
@@ -1302,7 +1392,7 @@ todo: si has different header in structures
                return -EINVAL;
        }
        /* LAI */
-       gsm48_decode_lai(si->lai, s->mcc, s->mnc, s->lac);
+       gsm48_decode_lai(si->lai, &s->mcc, &s->mnc, &s->lac);
        /* Cell Selection Parameters */
        gsm48_decode_cell_sel_param(s, si->cell_sel_par);
        /* RACH Control Parameter */
@@ -1327,6 +1417,13 @@ todo: si has different header in structures
        if (payload_len > 0)
                gsm48_decode_si3_rest(data, payload_len);
 
+       si->si4 = 1;
+
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
        return 0;
 }
 
@@ -1336,6 +1433,7 @@ static int gsm_rr_rx_sysinfo5(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_system_information_type_5 *si = msgb_l3(msg);
        struct gsm48_sysinfo *s = ms->sysinfo;
        int payload_len = msgb_l3len(msg) - sizeof(*si);
+       struct msgb *nmsg;
 
        if (payload_len < 0) {
                DEBUGP(DRR, "Short read of SYSTEM INFORMATION 5 message.\n");
@@ -1345,6 +1443,13 @@ static int gsm_rr_rx_sysinfo5(struct osmocom_ms *ms, struct msgb *msg)
        gsm48_decode_freq_list(s->freq, si->bcch_frequency_list,
                sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5);
 
+       si->si5 = 1;
+
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
        return 0;
 }
 
@@ -1354,6 +1459,7 @@ static int gsm_rr_rx_sysinfo5bis(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_system_information_type_5bis *si = msgb_l3(msg);
        struct gsm48_sysinfo *s = ms->sysinfo;
        int payload_len = msgb_l3len(msg) - sizeof(*si);
+       struct msgb *nmsg;
 
        if (payload_len < 0) {
                DEBUGP(DRR, "Short read of SYSTEM INFORMATION 5bis message.\n");
@@ -1363,6 +1469,13 @@ static int gsm_rr_rx_sysinfo5bis(struct osmocom_ms *ms, struct msgb *msg)
        gsm48_decode_freq_list(s->freq, si->bcch_frequency_list,
                sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5bis);
 
+       si->si5bis = 1;
+
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
        return 0;
 }
 
@@ -1372,6 +1485,7 @@ static int gsm_rr_rx_sysinfo5ter(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_system_information_type_5ter *si = msgb_l3(msg);
        struct gsm48_sysinfo *s = ms->sysinfo;
        int payload_len = msgb_l3len(msg) - sizeof(*si);
+       struct msgb *nmsg;
 
        if (payload_len < 0) {
                DEBUGP(DRR, "Short read of SYSTEM INFORMATION 5ter message.\n");
@@ -1381,6 +1495,13 @@ static int gsm_rr_rx_sysinfo5ter(struct osmocom_ms *ms, struct msgb *msg)
        gsm48_decode_freq_list(s->freq, si->bcch_frequency_list,
                sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5ter);
 
+       si->si5ter = 1;
+
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
        return 0;
 }
 
@@ -1390,6 +1511,7 @@ static int gsm_rr_rx_sysinfo6(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm48_system_information_type_6 *si = msgb_l3(msg);
        struct gsm48_sysinfo *s = ms->sysinfo;
        int payload_len = msgb_l3len(msg) - sizeof(*si);
+       struct msgb *nmsg;
 
        if (payload_len < 0) {
                DEBUGP(DRR, "Short read of SYSTEM INFORMATION 6 message.\n");
@@ -1398,7 +1520,7 @@ static int gsm_rr_rx_sysinfo6(struct osmocom_ms *ms, struct msgb *msg)
        /* Cell Identity */
        s->cell_identity = ntohl(si->cell_identity);
        /* LAI */
-       gsm48_decode_lai(si->lai, s->mcc, s->mnc, s->lac);
+       gsm48_decode_lai(si->lai, &s->mcc, &s->mnc, &s->lac);
        /* Cell Options (SACCH) */
        gsm48_decode_cellopt_sacch(s, si->control_channel_desc);
        /* NCC Permitted */
@@ -1407,6 +1529,13 @@ static int gsm_rr_rx_sysinfo6(struct osmocom_ms *ms, struct msgb *msg)
        if (payload_len >= 4)
                gsm48_decode_si6_rest(si->rest_octets, payload_len);
 
+       si->si6 = 1;
+
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
        return 0;
 }
 
@@ -1426,7 +1555,7 @@ static int gsm_rr_chan2cause[4] = {
 static int gsm_match_mi(struct osmocom_ms *ms, u_int8_t mi)
 {
        char imsi[16];
-       u_int32_t tmsi;
+       uint32_t tmsi;
 
        if (mi[0] < 1)
                return 0;
@@ -1501,7 +1630,7 @@ static int gsm_rr_rx_pag_req_2(struct osmocom_ms *ms, struct gsm_msgb *msg)
        struct gsm_rrlayer *rr = ms->rrlayer;
        struct gsm48_rr_paging2 *pa = msgb_l3(msg);
        int payload_len = msgb_l3len(msg) - sizeof(*pa);
-       u_int32_t tmsi;
+       uint32_t tmsi;
        int chan_first, chan_second, chan_third;
 
        /* 3.3.1.1.2: ignore paging while establishing */
@@ -1546,7 +1675,7 @@ static int gsm_rr_rx_pag_req_3(struct osmocom_ms *ms, struct gsm_msgb *msg)
        struct gsm_rrlayer *rr = ms->rrlayer;
        struct gsm48_rr_paging3 *pa = msgb_l3(msg);
        int payload_len = msgb_l3len(msg) - sizeof(*pa);
-       u_int32_t tmsi;
+       uint32_t tmsi;
        int chan_first, chan_second, chan_third, chan_fourth;
 
        /* 3.3.1.1.2: ignore paging while establishing */
@@ -1609,10 +1738,11 @@ static int gsm_match_ra(struct osmocom_ms *ms, struct gsm48_req_ref *req)
 static int gsm_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause)
 {
        struct gsm_rrlayer *rr = ms->rrlayer;
-       struct msgb *msg = gsm48_rr_msgb_alloc();
+       struct msgb *msg;
        struct gsm48_hdr *gh;
        struct gsm48_ass_cpl *ac;
 
+       msg = gsm48_rr_msgb_alloc();
        if (!msg)
                return -ENOMEM;
        gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
@@ -1631,10 +1761,11 @@ static int gsm_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause)
 static int gsm_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause)
 {
        struct gsm_rrlayer *rr = ms->rrlayer;
-       struct msgb *msg = gsm48_rr_msgb_alloc();
+       struct msgb *msg;
        struct gsm48_hdr *gh;
        struct gsm48_ass_fail *ac;
 
+       msg = gsm48_rr_msgb_alloc();
        if (!msg)
                return -ENOMEM;
        gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
@@ -1673,8 +1804,8 @@ static int gsm_rr_rx_imm_ass(struct osmocom_ms *ms, struct gsm_msgb *msg)
        /* request ref */
        if (gsm_match_ra(ms, ia->req_ref)) {
                /* channel description */
+todo channel structure and right management of channel IEs
                memset(&rr->chan_desc, 0, sizeof(cd));
-               memcpy(rr->chan_desc.chan_desc, ia->chan_desc, 3);
                /* timing advance */
                rr->timing_advance = ia->timing_advance;
                /* mobile allocation */
@@ -1803,10 +1934,11 @@ static int gsm_rr_tx_meas_rep(struct osmocom_ms *ms)
 {
        struct gsm_rrlayer *rr = ms->rrlayer;
        struct gsm_rr_meas *meas = &rr->meas;
-       struct msgb *msg = gsm48_rr_msgb_alloc();
+       struct msgb *msg;
        struct gsm48_hdr *gh;
        struct gsm48_meas_res *mr;
 
+       msg = gsm48_rr_msgb_alloc();
        if (!msg)
                return -ENOMEM;
        gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
@@ -1931,29 +2063,29 @@ static int gsm_rr_dl_est(struct osmocom_ms *ms)
 /* the link is established */
 static int gsm_rr_estab_cnf(struct osmocom_ms *ms, struct msgb *msg)
 {
-       struct msgb *newmsg;
-       struct gsm_mm_hdr *newmmh;
+       struct msgb *nmsg;
+       struct gsm_mm_hdr *nmmh;
 
        /* if MM has releases before confirm, we start release */
        if (rr->state == GSM_RRSTATE_IDLE) {
                /* release message */
-               newmsg = gsm48_rr_msgb_alloc();
-               if (!newmsg)
+               nmsg = gsm48_rr_msgb_alloc();
+               if (!nmsg)
                        return -ENOMEM;
                /* start release */
-               return rslms_tx_rll_req_l3(ms, RSL_MT_REL_REQ, 0, 0, newmsg);
+               return rslms_tx_rll_req_l3(ms, RSL_MT_REL_REQ, 0, 0, nmsg);
        }
 
        /* 3.3.1.1.4 */
        new_rr_state(rr, GSM_RRSTATE_DEDICATED);
 
        /* send confirm to upper layer */
-       newmsg = gsm48_mm_msgb_alloc();
-       if (!newmsg)
+       nmsg = gsm48_mm_msgb_alloc();
+       if (!nmsg)
                return -ENOMEM;
-       newmmh = (struct gsm_mm_hdr *)newmsg->data;
-       newmmh->msg_type = (rr->rr_est_req) ? RR_EST_CNF : RR_EST_IND;
-       return rr_rcvmsg(ms, newmsg);
+       nmmh = (struct gsm_mm_hdr *)nmsg->data;
+       nmmh->msg_type = (rr->rr_est_req) ? RR_EST_CNF : RR_EST_IND;
+       return gsm48_mm_upmsg(ms, nmsg);
 }
 
 /* the link is released */
@@ -1984,16 +2116,16 @@ static int gsm_rr_est_req(struct osmocom_ms *ms, struct msgb *msg)
        /* 3.3.1.1.3.2 */
        if (timer_pending(rr->t3122)) {
                if (rrmsg->cause != RR_EST_CAUSE_EMERGENCY) {
-                       struct msgb *newmsg;
-                       struct gsm_mm_hdr *newmmh;
+                       struct msgb *nmsg;
+                       struct gsm_mm_hdr *nmmh;
 
-                       newmsg = gsm48_mm_msgb_alloc();
-                       if (!newmsg)
+                       nmsg = gsm48_mm_msgb_alloc();
+                       if (!nmsg)
                                return -ENOMEM;
-                       newmmh = (struct gsm_mm_hdr *)newmsg->data;
-                       newmmh->msg_type RR_REL_IND;
-                       newmmh->cause = GSM_MM_CAUSE_T3122_PEND;
-                       return rr_rcvmsg(ms, newmsg);
+                       nmmh = (struct gsm_mm_hdr *)nmsg->data;
+                       nmmh->msg_type RR_REL_IND;
+                       nmmh->cause = GSM_MM_CAUSE_T3122_PEND;
+                       return gsm48_mm_upmsg(ms, nmsg);
                } else
                        stop_rr_t3122(rr);
        }
@@ -2003,16 +2135,16 @@ static int gsm_rr_est_req(struct osmocom_ms *ms, struct msgb *msg)
                if (!(ms->access_class & ms->si.access_class)) {
                        reject:
                        if (!ms->opt.access_class_override) {
-                               struct msgb *newmsg;
-                               struct gsm_mm_hdr *newmmh;
+                               struct msgb *nmsg;
+                               struct gsm_mm_hdr *nmmh;
 
-                               newmsg = gsm48_mm_msgb_alloc();
-                               if (!newmsg)
+                               nmsg = gsm48_mm_msgb_alloc();
+                               if (!nmsg)
                                        return -ENOMEM;
-                               newmmh = (struct gsm_mm_hdr *)newmsg->data;
-                               newmmh->msg_type RR_REL_IND;
-                               newmmh->cause = GSM_MM_CAUSE_NOT_AUTHORIZED;
-                               return rr_rcvmsg(ms, newmsg);
+                               nmmh = (struct gsm_mm_hdr *)nmsg->data;
+                               nmmh->msg_type RR_REL_IND;
+                               nmmh->cause = GSM_MM_CAUSE_NOT_AUTHORIZED;
+                               return gsm48_mm_upmsg(ms, nmsg);
                        }
                }
        } else {
@@ -2116,11 +2248,11 @@ static int gsm_rr_data_ind(struct osmocom_ms *ms, struct msbg *msg)
        }
 
        /* push header */
-       msgb_push(msg, sizeof(struct gsm_mm_hdr));
-       mmh = (struct gsm_mm_hdr *)msg->data;
+       msgb_push(msg, sizeof(struct gsm48_mm_hdr));
+       mmh = (struct gsm48_mm_hdr *)msg->data;
        mmh->msg_type = RR_DATA_IND;
-       /* forward message */
-       return rr_rcvmsg(ms, msg);
+
+       return gsm48_mm_upmsg(ms, msg);
 }
 
 /* unit data from layer 2 to RR layer */
@@ -2169,10 +2301,9 @@ static int gsm_rr_unit_data_ind(struct osmocom_ms *ms, struct msgb *msg)
 
 
 
-complete
--------------------------------------------------------------------------------
-uncomplete
-
+the process above is complete
+------------------------------------------------------------------------------
+incomplete
 
 
 
@@ -2214,46 +2345,39 @@ they queue must be flushed when rr fails
 
 #include <osmocore/protocol/gsm_04_08.h>
 #include <osmocore/msgb.h>
+#include <osmocore/utils.h>
 #include <osmocore/gsm48.h>
 
-static struct rr_names {
-       char *name;
-       int value;
-} rr_names[] = {
-       { "RR_EST_REQ",         RR_EST_REQ },
-       { "RR_EST_IND",         RR_EST_IND },
-       { "RR_EST_CNF",         RR_EST_CNF },
-       { "RR_REL_IND",         RR_REL_IND },
-       { "RR_SYNC_IND",        RR_SYNC_IND },
-       { "RR_DATA_REQ",        RR_DATA_REQ },
-       { "RR_DATA_IND",        RR_DATA_IND },
-       { "RR_UNIT_DATA_IND",   RR_UNIT_DATA_IND },
-       { "RR_ABORT_REQ",       RR_ABORT_REQ },
-       { "RR_ABORT_IND",       RR_ABORT_IND },
-       { "RR_ACT_REQ",         RR_ACT_REQ },
-
-       {NULL, 0}
+static const struct value_string rr_names[] = {
+       { RR_EST_REQ,           "RR_EST_REQ" },
+       { RR_EST_IND,           "RR_EST_IND" },
+       { RR_EST_CNF,           "RR_EST_CNF" },
+       { RR_REL_IND,           "RR_REL_IND" },
+       { RR_SYNC_IND,          "RR_SYNC_IND" },
+       { RR_DATA_REQ,          "RR_DATA_REQ" },
+       { RR_DATA_IND,          "RR_DATA_IND" },
+       { RR_UNIT_DATA_IND,     "RR_UNIT_DATA_IND" },
+       { RR_ABORT_REQ,         "RR_ABORT_REQ" },
+       { RR_ABORT_IND,         "RR_ABORT_IND" },
+       { RR_ACT_REQ,           "RR_ACT_REQ" },
+       { 0,                    NULL }
 };
 
-char *get_rr_name(int value)
+const char *get_rr_name(int value)
 {
-       int i;
-
-       for (i = 0; rr_names[i].name; i++) {
-               if (rr_names[i].value == value)
-                       return rr_names[i].name;
-       }
-
-       return "RR_Unknown";
+       return get_value_string(rr_names, value);
 }
 
-static int rr_rcvmsg(struct osmocom_ms *ms,
+move to mm
+static int gsm48_mm_upmsg(struct osmocom_ms *ms,
                        int msg_type, struct gsm_mncc *rrmsg)
 {
        struct msgb *msg;
 
+#if 0
        DEBUGP(DRR, "(MS %s) Sending '%s' to MM.\n", ms->name,
                get_rr_name(msg_type));
+#endif
 
        rrmsg->msg_type = msg_type;
        
@@ -2285,7 +2409,7 @@ static int gsm_rr_act_req(struct osmocom_ms *ms, struct gsm_rr *rrmsg)
 
 /* state trasitions for radio ressource messages (upper layer) */
 static struct rrdownstate {
-       u_int32_t       states;
+       uint32_t        states;
        int             type;
        int             (*rout) (struct osmocom_ms *ms, struct gsm_dl *rrmsg);
 } rrdownstatelist[] = {
@@ -2302,13 +2426,13 @@ static struct rrdownstate {
 #define RRDOWNSLLEN \
        (sizeof(rrdownstatelist) / sizeof(struct rrdownstate))
 
-static int gsm_send_rr(struct osmocom_ms *ms, struct gsm_rr *msg)
+static int gsm48_rr_sendmsg(struct osmocom_ms *ms, struct gsm_rr *msg)
 {
        struct gsm_mm_hdr *mmh = msgb->data;
        int msg_type = mmh->msg_type;
 
        DEBUGP(DRR, "(ms %s) Sending '%s' to DL in state %s\n", ms->name,
-               gsm0408_rr_msg_names[msg_type], mm_state_names[mm->state]);
+               gsm48_rr_msg_name(msg_type), mm_state_names[mm->state]);
 
        /* find function for current state and message */
        for (i = 0; i < RRDOWNSLLEN; i++)
@@ -2317,6 +2441,8 @@ static int gsm_send_rr(struct osmocom_ms *ms, struct gsm_rr *msg)
                        break;
        if (i == RRDOWNSLLEN) {
                DEBUGP(DRR, "Message unhandled at this state.\n");
+               free_msgb(msg);
+todo: in all functions of this type: free_msgb must be called if unhandled.
                return 0;
        }
 
@@ -2443,8 +2569,8 @@ static int gsm_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
        memcpy(&rr->chan_desc, cd, sizeof(cd));
 
        /* start suspension of current link */
-       newmsg = gsm48_rr_msgb_alloc();
-       if (!newmsg)
+       nmsg = gsm48_rr_msgb_alloc();
+       if (!nmsg)
                return -ENOMEM;
        rslms_tx_rll_req_l3(ms, RSL_MT_SUSP_REQ, rr->chan_desc.chan_nr, 0, msg);
 
@@ -2455,6 +2581,30 @@ static int gsm_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
        return 0;
 }
 
+/* decode "Cell Description" (10.5.2.2) */
+static int gsm48_decode_cell_desc(struct gsm48_cell_desc *cd, uint16_t *arfcn, uint8_t *ncc uint8_t *bcc)
+{
+       *arfcn = (cd->bcch_hi << 8) + cd->bcch_lo;
+       *ncc = cd->ncc;
+       *bcc = cd->bcc;
+}
+
+/* decode "Power Command" (10.5.2.28) and (10.5.2.28a) */
+static int gsm48_decode_power_cmd_acc(struct gsm48_power_cmd *pc, uint8_t *power_level uint8_t *atc)
+{
+       *power_level = pc->power_level;
+       if (atc) /* only in case of 10.5.2.28a */
+               *atc = pc->atc;
+}
+
+/* decode "Synchronization Indication" (10.5.2.39) */
+static int gsm48_decode_power_cmd_acc(struct gsm_rrlayer *rr, struct gsm_rr_sync_ind *si)
+{
+       rr->ho_sync_ind = si->si;
+       rr->ho_rot = si->rot;
+       rr->ho_nci = si->nci;
+}
+
 /* receiving HANDOVER COMMAND message (9.1.15) */
 static int gsm_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
 {
@@ -2473,8 +2623,25 @@ static int gsm_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
        }
        tlv_parse(&tp, &rsl_att_tlvdef, ho->data, payload_len, 0, 0);
 
-
-
+       /* decode Cell Description */
+       gsm_decode_cell_desc(&ho->cell_desc, &cd.bcch_arfcn, &cd.ncc, &cd.bcc);
+       /* Channel Description */
+       memcpy(&rr->chan_desc.chan_desc, ho->chan_desc, 3);
+       /* Handover Reference */
+       rr->hando_ref = ho->ho_ref;
+       /* Power Command and access type */
+       gsm_decode_power_cmd_acc((struct gsm48_power_cmd *)&ho->power_command,
+               &cd.power_level, cd.atc);
+       /* Synchronization Indication */
+       if (TLVP_PRESENT(&tp, GSM48_IE_SYNC_IND))
+               gsm48_decode_sync_ind(rr,
+                       TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC)-1, &cd);
+       /* Frequency Sort List */
+       if (TLVP_PRESENT(&tp, GSM48_IE_FREQ_SHORT_LIST))
+               gsm48_decode_freq_list(s->freq,
+                       TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC),
+                       *(TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC)-1),
+                               0xce, FREQ_TYPE_SERV);
 
 
 today: more IE parsing
@@ -2485,8 +2652,8 @@ today: more IE parsing
        memcpy(&rr->chan_desc, cd, sizeof(cd));
 
        /* start suspension of current link */
-       newmsg = gsm48_rr_msgb_alloc();
-       if (!newmsg)
+       nmsg = gsm48_rr_msgb_alloc();
+       if (!nmsg)
                return -ENOMEM;
        rslms_tx_rll_req_l3(ms, RSL_MT_SUSP_REQ, rr->chan_desc.chan_nr, 0, msg);
 
@@ -2537,11 +2704,11 @@ static int gsm_rr_rel_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
                /* change radio to new channel */
                tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
 
-               newmsg = gsm48_rr_msgb_alloc();
-               if (!newmsg)
+               nmsg = gsm48_rr_msgb_alloc();
+               if (!nmsg)
                        return -ENOMEM;
                /* send DL-ESTABLISH REQUEST */
-               rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_desc.chan_nr, 0, newmsg);
+               rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_desc.chan_nr, 0, nmsg);
 
        }
        if (rr->hando_susp_state) {
@@ -2554,8 +2721,8 @@ static int gsm_rr_rel_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
 static int gsm_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct gsm_rrlayer *rr = ms->rrlayer;
-       struct msgb *newmsg;
-       struct gsm_mm_hdr *newmmh;
+       struct msgb *nmsg;
+       struct gsm_mm_hdr *nmmh;
 
        if (rr->hando_susp_state || rr->assign_susp_state) {
                if (!rr->resume_last_state) {
@@ -2568,10 +2735,10 @@ static int gsm_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
                        tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
 
                        /* re-establish old link */
-                       newmsg = gsm48_rr_msgb_alloc();
-                       if (!newmsg)
+                       nmsg = gsm48_rr_msgb_alloc();
+                       if (!nmsg)
                                return -ENOMEM;
-                       return rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_desc.chan_nr, 0, newmsg);
+                       return rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_desc.chan_nr, 0, nmsg);
                }
                rr->resume_last_state = 0;
        }
@@ -2580,19 +2747,19 @@ static int gsm_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
        tx_ph_dm_rel_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
 
        /* send abort ind to upper layer */
-       newmsg = gsm48_mm_msgb_alloc();
+       nmsg = gsm48_mm_msgb_alloc();
 
        if (!msg)
                return -ENOMEM;
-       newmmh = (struct gsm_mm_hdr *)newmsg->data;
-       newmmh->msg_type = RR_ABORT_IND;
-       newmmh->cause = GSM_MM_CAUSE_LINK_FAILURE;
-       return rr_rcvmsg(ms, msg);
+       nmmh = (struct gsm_mm_hdr *)nmsg->data;
+       nmmh->msg_type = RR_ABORT_IND;
+       nmmh->cause = GSM_MM_CAUSE_LINK_FAILURE;
+       return gsm48_mm_upmsg(ms, msg);
 }
 
 /* state trasitions for link layer messages (lower layer) */
 static struct dldatastate {
-       u_int32_t       states;
+       uint32_t        states;
        int             type;
        int             (*rout) (struct osmocom_ms *ms, struct gsm_dl *dlmsg);
 } dldatastatelist[] = {
@@ -2623,12 +2790,12 @@ static struct dldatastate {
 #define DLDATASLLEN \
        (sizeof(dldatastatelist) / sizeof(struct dldatastate))
 
-static int gsm_rcv_dl(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
+static int gsm48_rcv_dl(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
 {
        int msg_type = dlmsg->msg_type;
 
        DEBUGP(DRR, "(ms %s) Received '%s' from DL in state %s\n", ms->name,
-               gsm0408_dl_msg_names[msg_type], mm_state_names[mm->state]);
+               gsm48_dl_msg_name(msg_type), mm_state_names[mm->state]);
 
        /* find function for current state and message */
        for (i = 0; i < DLDATASLLEN; i++)
@@ -2637,6 +2804,7 @@ static int gsm_rcv_dl(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
                        break;
        if (i == DLDATASLLEN) {
                DEBUGP(DRR, "Message unhandled at this state.\n");
+               free_msgb(msg);
                return 0;
        }
 
@@ -2649,6 +2817,22 @@ static int gsm_rcv_dl(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
        return rc;
 }
 
+/* dequeue messages from dl */
+int gsm48_rr_queue(struct osmocom_ms *ms)
+{
+       struct gsm_rrlayer *rr = ms->rrlayer;
+       struct msgb *msg;
+       int work = 0;
+       
+       while ((msg = msgb_dequeue(&rr->up_queue))) {
+               /* msg is freed there */
+               gsm48_rcv_dl(ms, msg);
+               work = 1; /* work done */
+       }
+       
+       return work;
+}
+
 static void timeout_rr_t3124(void *arg)
 {
        struct gsm_rrlayer *rr = arg;
@@ -2680,9 +2864,7 @@ struct gsm_rrlayer *gsm_new_rr(struct osmocom_ms *ms)
                return NULL;
        rr->ms = ms;
 
-       init queues
-
-       init timers
+       INIT_LLIST_HEAD(&rr->up_queue);
 
        return;
 }
@@ -2705,17 +2887,18 @@ todo stop t3122 when cell change
 /* send HANDOVER ACCESS burst (9.1.14) */
 static int gsm_rr_tx_hando_access(struct osmocom_ms *ms)
 {
-       newmsg = msgb_alloc_headroom(20, 16, "HAND_ACCESS");
-       if (!newmsg)
+       nmsg = msgb_alloc_headroom(20, 16, "HAND_ACCESS");
+       if (!nmsg)
                return -ENOMEM;
-       *msgb_put(newmsg, 1) = rr->hando_ref;
-       return rslms_tx_rll_req_l3(ms, RSL_MT_RAND_ACC_REQ, chan_nr, 0, newmsg);
+       *msgb_put(nmsg, 1) = rr->hando_ref;
+       return rslms_tx_rll_req_l3(ms, RSL_MT_RAND_ACC_REQ, chan_nr, 0, nmsg);
 }
+
 /* send next channel request in dedicated state */
 static int gsm_rr_rand_acc_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct gsm_rrlayer *rr = ms->rrlayer;
-       struct msgb *newmsg;
+       struct msgb *nmsg;
        int s;
 
        if (!rr->hando_susp_state) {