[layer23] Rework of channel request process and control of TA and TX-power
[osmocom-bb.git] / src / host / layer23 / src / gsm322.c
index 0480037..fcc85a7 100644 (file)
@@ -36,7 +36,7 @@
 #include <osmocom/file.h>
 #include <osmocom/osmocom_data.h>
 #include <osmocom/networks.h>
-#include <osmocom/telnet_interface.h>
+#include <osmocom/vty.h>
 
 extern void *l23_ctx;
 
@@ -45,6 +45,9 @@ static void gsm322_cs_loss(void *arg);
 static int gsm322_cs_select(struct osmocom_ms *ms, int any);
 static int gsm322_m_switch_on(struct osmocom_ms *ms, struct msgb *msg);
 
+#warning HACKING!!!
+int hack;
+
 /*
  * notes
  */
@@ -216,6 +219,40 @@ int gsm322_cs_sendmsg(struct osmocom_ms *ms, struct msgb *msg)
  * support
  */
 
+static int gsm322_sync_to_cell(struct gsm322_cellsel *cs)
+{
+       struct osmocom_ms *ms = cs->ms;
+       struct gsm48_sysinfo *s = cs->si;
+
+       cs->ccch_state = GSM322_CCCH_ST_INIT;
+       if (s) {
+               if (s->ccch_conf == 1) {
+                       LOGP(DCS, LOGL_INFO, "Sysinfo, ccch mode COMB\n");
+                       cs->ccch_mode = CCCH_MODE_COMBINED;
+               } else {
+                       LOGP(DCS, LOGL_INFO, "Sysinfo, ccch mode NON-COMB\n");
+                       cs->ccch_mode = CCCH_MODE_NON_COMBINED;
+               }
+       } else {
+               LOGP(DCS, LOGL_INFO, "No sysinfo, ccch mode NONE\n");
+               cs->ccch_mode = CCCH_MODE_NONE;
+       }
+//     printf("s->ccch_conf %d\n", cs->si->ccch_conf);
+
+       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);
+}
+
+static void gsm322_unselect_cell(struct gsm322_cellsel *cs)
+{
+       cs->selected = 0;
+       cs->si = NULL;
+       memset(&cs->sel_si, 0, sizeof(cs->sel_si));
+       cs->sel_mcc = cs->sel_mnc = cs->sel_lac = cs->sel_id = 0;
+}
+
 /* print to DCS logging */
 static void print_dcs(void *priv, const char *fmt, ...)
 {
@@ -242,8 +279,8 @@ int gsm322_del_forbidden_la(struct osmocom_ms *ms, uint16_t mcc,
        llist_for_each_entry(la, &plmn->forbidden_la, entry) {
                if (la->mcc == mcc && la->mnc == mnc && la->lac == lac) {
                        LOGP(DPLMN, LOGL_INFO, "Delete from list of forbidden "
-                               "LAs (mcc=%03d, mnc=%02d, lac=%04x)\n",
-                               mcc, mnc, lac);
+                               "LAs (mcc=%s, mnc=%s, lac=%04x)\n",
+                               gsm_print_mcc(mcc), gsm_print_mnc(mnc), lac);
                        llist_del(&la->entry);
                        talloc_free(la);
                        return 0;
@@ -261,7 +298,8 @@ int gsm322_add_forbidden_la(struct osmocom_ms *ms, uint16_t mcc,
        struct gsm322_la_list *la;
 
        LOGP(DPLMN, LOGL_INFO, "Add to list of forbidden LAs "
-               "(mcc=%03d, mnc=%02d, lac=%04x)\n", mcc, mnc, lac);
+               "(mcc=%s, mnc=%s, lac=%04x)\n", gsm_print_mcc(mcc),
+               gsm_print_mnc(mnc), lac);
        la = talloc_zero(l23_ctx, struct gsm322_la_list);
        if (!la)
                return -ENOMEM;
@@ -322,6 +360,21 @@ int gsm322_is_plmn_avail(struct gsm322_cellsel *cs, uint16_t mcc, uint16_t mnc)
        return 0;
 }
 
+/* search available HPLMN */
+int gsm322_is_hplmn_avail(struct gsm322_cellsel *cs, char *imsi)
+{
+       int i;
+
+       for (i = 0; i <= 1023; i++) {
+               if (cs->list[i].sysinfo
+                && gsm_match_mnc(cs->list[i].sysinfo->mcc,
+                       cs->list[i].sysinfo->mnc, imsi))
+                       return 1;
+       }
+
+       return 0;
+}
+
 /* del forbidden LA */
 /*
  * timer
@@ -407,45 +460,45 @@ static void stop_cs_timer(struct gsm322_cellsel *cs)
  * state change
  */
 
-static const char *plmn_a_state_names[] = {
-       "A0_NULL",
-       "A1_TRYING_RPLMN",
-       "A2_ON_PLMN",
-       "A3_TRYING_PLMN",
-       "A4_WAIT_FOR_PLMN",
-       "A5_HPLMN",
-       "A6_NO_SIM"
+const char *plmn_a_state_names[] = {
+       "A0 null",
+       "A1 trying RPLMN",
+       "A2 on PLMN",
+       "A3 trying PLMN",
+       "A4 wait for PLMN to appear",
+       "A5 HPLMN search",
+       "A6 no SIM inserted"
 };
 
-static const char *plmn_m_state_names[] = {
-       "M0_NULL",
-       "M1_TRYING_RPLMN",
-       "M2_ON_PLMN",
-       "M3_NOT_ON_PLMN",
-       "M4_TRYING_PLMN",
-       "M5_NO_SIM"
+const char *plmn_m_state_names[] = {
+       "M0 null",
+       "M1 trying RPLMN",
+       "M2 on PLMN",
+       "M3 not on PLMN",
+       "M4 trying PLMN",
+       "M5 no SIM inserted"
 };
 
-static const char *cs_state_names[] = {
-       "C0_NULL",
-       "C1_NORMAL_CELL_SEL",
-       "C2_STORED_CELL_SEL",
-       "C3_CAMPED_NORMALLY",
-       "C4_NORMAL_CELL_RESEL",
-       "C5_CHOOSE_CELL",
-       "C6_ANY_CELL_SEL",
-       "C7_CAMPED_ANY_CELL",
-       "C8_ANY_CELL_RESEL",
-       "C9_CHOOSE_ANY_CELL",
-       "PLMN_SEARCH",
-       "HPLMN_SEARCH"
+const char *cs_state_names[] = {
+       "C0 null",
+       "C1 normal cell selection",
+       "C2 stored cell selection",
+       "C3 camped normally",
+       "C4 normal cell re-selection",
+       "C5 choose cell",
+       "C6 any cell selection",
+       "C7 camped on any cell",
+       "C8 any cell re-selection",
+       "C9 choose any cell",
+       "PLMN search",
+       "HPLMN search"
 };
 
 
 /* new automatic PLMN search state */
 static void new_a_state(struct gsm322_plmn *plmn, int state)
 {
-       if (plmn->mode != PLMN_MODE_AUTO) {
+       if (plmn->ms->settings.plmn_mode != PLMN_MODE_AUTO) {
                LOGP(DPLMN, LOGL_FATAL, "not in auto mode, please fix!\n");
                return;
        }
@@ -455,7 +508,7 @@ static void new_a_state(struct gsm322_plmn *plmn, int state)
        if (state < 0 || state >= (sizeof(plmn_a_state_names) / sizeof(char *)))
                return;
 
-       LOGP(DPLMN, LOGL_INFO, "new state %s -> %s\n",
+       LOGP(DPLMN, LOGL_INFO, "new state '%s' -> '%s'\n",
                plmn_a_state_names[plmn->state], plmn_a_state_names[state]);
 
        plmn->state = state;
@@ -464,7 +517,7 @@ static void new_a_state(struct gsm322_plmn *plmn, int state)
 /* new manual PLMN search state */
 static void new_m_state(struct gsm322_plmn *plmn, int state)
 {
-       if (plmn->mode != PLMN_MODE_MANUAL) {
+       if (plmn->ms->settings.plmn_mode != PLMN_MODE_MANUAL) {
                LOGP(DPLMN, LOGL_FATAL, "not in manual mode, please fix!\n");
                return;
        }
@@ -472,7 +525,7 @@ static void new_m_state(struct gsm322_plmn *plmn, int state)
        if (state < 0 || state >= (sizeof(plmn_m_state_names) / sizeof(char *)))
                return;
 
-       LOGP(DPLMN, LOGL_INFO, "new state %s -> %s\n",
+       LOGP(DPLMN, LOGL_INFO, "new state '%s' -> '%s'\n",
                plmn_m_state_names[plmn->state], plmn_m_state_names[state]);
 
        plmn->state = state;
@@ -484,7 +537,7 @@ static void new_c_state(struct gsm322_cellsel *cs, int state)
        if (state < 0 || state >= (sizeof(cs_state_names) / sizeof(char *)))
                return;
 
-       LOGP(DCS, LOGL_INFO, "new state %s -> %s\n",
+       LOGP(DCS, LOGL_INFO, "new state '%s' -> '%s'\n",
                cs_state_names[cs->state], cs_state_names[state]);
 
        /* stop cell selection timer, if running */
@@ -579,8 +632,7 @@ static int gsm322_sort_list(struct osmocom_ms *ms)
        if (subscr->sim_valid) {
                found = NULL;
                llist_for_each_entry(temp, &temp_list, entry) {
-                       if (temp->mcc == subscr->mcc
-                        && temp->mnc == subscr->mnc) {
+                       if (gsm_match_mnc(temp->mcc, temp->mnc, subscr->imsi)) {
                                found = temp;
                                break;
                        }
@@ -590,18 +642,6 @@ static int gsm322_sort_list(struct osmocom_ms *ms)
                        llist_del(&found->entry);
                        llist_add_tail(&found->entry, &plmn->sorted_plmn);
                }
-#if 0
-               else {
-                       /* add */
-                       temp = talloc_zero(l23_ctx, struct gsm322_plmn_list);
-                       if (!temp)
-                               return -ENOMEM;
-                       temp->mcc = subscr->mcc;
-                       temp->mnc = subscr->mnc;
-                       temp->rxlev_db = 0; /* unknown */
-                       llist_add_tail(&temp->entry, &plmn->sorted_plmn);
-               }
-#endif
        }
 
        /* move entries if in SIM's PLMN Selector list */
@@ -670,8 +710,9 @@ static int gsm322_sort_list(struct osmocom_ms *ms)
                        }
                }
                LOGP(DPLMN, LOGL_INFO, "Creating Sorted PLMN list. "
-                       "(%02d: mcc=%03d mnc=%02d allowed=%s rx-lev=%d)\n",
-                       i, temp->mcc, temp->mnc, (temp->cause) ? "no ":"yes",
+                       "(%02d: mcc=%s mnc=%s allowed=%s rx-lev=%d)\n",
+                       i, gsm_print_mcc(temp->mcc),
+                       gsm_print_mnc(temp->mnc), (temp->cause) ? "no ":"yes",
                        temp->rxlev_db);
                i++;
        }
@@ -694,9 +735,9 @@ static int gsm322_a_go_on_plmn(struct osmocom_ms *ms, struct msgb *msg)
        new_a_state(plmn, GSM322_A2_ON_PLMN);
 
        /* start timer, if on VPLMN of home country OR special case */
-       if ((plmn->mcc == subscr->mcc && plmn->mcc != subscr->mnc)
-        || (subscr->always_search_hplmn && (plmn->mcc != subscr->mnc
-               || plmn->mcc != subscr->mnc))) {
+       if (!gsm_match_mnc(plmn->mcc, plmn->mnc, subscr->imsi)
+        && (subscr->always_search_hplmn
+         || gsm_match_mcc(plmn->mcc, subscr->imsi))) {
                if (subscr->sim_valid && subscr->t6m_hplmn)
                        start_plmn_timer(plmn, subscr->t6m_hplmn * 360);
                else
@@ -712,6 +753,7 @@ static int gsm322_a_indicate_selected(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct gsm322_plmn *plmn = &ms->plmn;
 
+       vty_notify(ms, NULL);
        vty_notify(ms, "Selected Network: %s, %s\n",
                gsm_get_mcc(plmn->mcc), gsm_get_mnc(plmn->mcc, plmn->mnc));
 
@@ -723,7 +765,6 @@ static int gsm322_a_no_more_plmn(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct gsm322_plmn *plmn = &ms->plmn;
        struct gsm322_cellsel *cs = &ms->cellsel;
-       struct gsm_subscriber *subscr = &ms->subscr;
        struct msgb *nmsg;
        int found;
 
@@ -733,15 +774,7 @@ static int gsm322_a_no_more_plmn(struct osmocom_ms *ms, struct msgb *msg)
 
        /* if no PLMN in list */
        if (found < 0) {
-               if (subscr->plmn_valid) {
-                       LOGP(DPLMN, LOGL_INFO, "Select RPLMN.\n");
-                       plmn->mcc = subscr->plmn_mcc;
-                       plmn->mnc = subscr->plmn_mnc;
-               } else {
-                       LOGP(DPLMN, LOGL_INFO, "Select HPLMN.\n");
-                       plmn->mcc = subscr->mcc;
-                       plmn->mnc = subscr->mnc;
-               }
+               LOGP(DPLMN, LOGL_INFO, "Not any PLNs allowable.\n");
 
                new_a_state(plmn, GSM322_A4_WAIT_FOR_PLMN);
 
@@ -760,8 +793,8 @@ static int gsm322_a_no_more_plmn(struct osmocom_ms *ms, struct msgb *msg)
        plmn->mcc = cs->list[found].sysinfo->mcc;
        plmn->mnc = cs->list[found].sysinfo->mnc;
 
-       LOGP(DPLMN, LOGL_INFO, "PLMN available (mcc=%03d mnc=%02d  %s, %s)\n",
-               plmn->mcc, plmn->mnc,
+       LOGP(DPLMN, LOGL_INFO, "PLMN available (mcc=%s mnc=%s  %s, %s)\n",
+               gsm_print_mcc(plmn->mcc), gsm_print_mnc(plmn->mnc),
                gsm_get_mcc(plmn->mcc), gsm_get_mnc(plmn->mcc, plmn->mnc));
 
        /* indicate New PLMN */
@@ -791,8 +824,8 @@ static int gsm322_a_sel_first_plmn(struct osmocom_ms *ms, struct msgb *msg)
        i = 0;
        llist_for_each_entry(plmn_entry, &plmn->sorted_plmn, entry) {
                /* if last selected PLMN was HPLMN, we skip that */
-               if (plmn_entry->mcc == subscr->mcc
-                && plmn_entry->mnc == subscr->mnc
+               if (gsm_match_mnc(plmn_entry->mcc, plmn_entry->mnc,
+                                       subscr->imsi)
                 && plmn_entry->mcc == plmn->mcc
                 && plmn_entry->mnc == plmn->mnc) {
                        LOGP(DPLMN, LOGL_INFO, "Skip HPLMN, because it was "
@@ -820,9 +853,10 @@ static int gsm322_a_sel_first_plmn(struct osmocom_ms *ms, struct msgb *msg)
                return 0;
        }
 
-       LOGP(DPLMN, LOGL_INFO, "Selecting PLMN from list. (%02d: mcc=%03d "
-               "mnc=%02d  %s, %s)\n", plmn->plmn_curr, plmn_first->mcc,
-               plmn_first->mnc, gsm_get_mcc(plmn_first->mcc),
+       LOGP(DPLMN, LOGL_INFO, "Selecting PLMN from list. (%02d: mcc=%s "
+               "mnc=%s  %s, %s)\n", plmn->plmn_curr,
+               gsm_print_mcc(plmn_first->mcc), gsm_print_mnc(plmn_first->mnc),
+               gsm_get_mcc(plmn_first->mcc),
                gsm_get_mnc(plmn_first->mcc, plmn_first->mnc));
 
        /* set current network */
@@ -878,9 +912,9 @@ static int gsm322_a_sel_next_plmn(struct osmocom_ms *ms, struct msgb *msg)
        }
 
 
-       LOGP(DPLMN, LOGL_INFO, "Selecting PLMN from list. (%02d: mcc=%03d "
-               "mnc=%02d  %s, %s)\n", plmn->plmn_curr, plmn_next->mcc,
-               plmn_next->mnc,
+       LOGP(DPLMN, LOGL_INFO, "Selecting PLMN from list. (%02d: mcc=%s "
+               "mnc=%s  %s, %s)\n", plmn->plmn_curr,
+               gsm_print_mcc(plmn_next->mcc), gsm_print_mnc(plmn_next->mnc),
                gsm_get_mcc(plmn->mcc), gsm_get_mnc(plmn->mcc, plmn->mnc));
 
        /* set next network */
@@ -955,7 +989,7 @@ static int gsm322_a_plmn_avail(struct osmocom_ms *ms, struct msgb *msg)
                /* go On PLMN */
                plmn->mcc = gm->mcc;
                plmn->mnc = gm->mnc;
-               LOGP(DPLMN, LOGL_INFO, "HPLMN became available.\n");
+               LOGP(DPLMN, LOGL_INFO, "RPLMN became available.\n");
                return gsm322_a_go_on_plmn(ms, msg);
        } else {
                /* select first PLMN in list */
@@ -978,9 +1012,10 @@ static int gsm322_a_loss_of_radio(struct osmocom_ms *ms, struct msgb *msg)
 
        /* if PLMN in list */
        if (found >= 0) {
-               LOGP(DPLMN, LOGL_INFO, "PLMN available (mcc=%03d mnc=%02d  "
-                       "%s, %s)\n", cs->list[found].sysinfo->mcc,
-                       cs->list[found].sysinfo->mnc,
+               LOGP(DPLMN, LOGL_INFO, "PLMN available (mcc=%s mnc=%s  "
+                       "%s, %s)\n", gsm_print_mcc(
+                       cs->list[found].sysinfo->mcc),
+                       gsm_print_mnc(cs->list[found].sysinfo->mnc),
                        gsm_get_mcc(cs->list[found].sysinfo->mcc),
                        gsm_get_mnc(cs->list[found].sysinfo->mcc,
                                cs->list[found].sysinfo->mnc));
@@ -1010,6 +1045,7 @@ static int gsm322_a_switch_on(struct osmocom_ms *ms, struct msgb *msg)
        struct msgb *nmsg;
 
        if (!subscr->sim_valid) {
+               LOGP(DSUM, LOGL_INFO, "SIM is removed\n");
                LOGP(DPLMN, LOGL_INFO, "Switch on without SIM.\n");
                new_a_state(plmn, GSM322_A6_NO_SIM);
 
@@ -1022,9 +1058,13 @@ static int gsm322_a_switch_on(struct osmocom_ms *ms, struct msgb *msg)
                plmn->mcc = subscr->plmn_mcc;
                plmn->mnc = subscr->plmn_mnc;
 
-               LOGP(DPLMN, LOGL_INFO, "Use RPLMN (mcc=%03d mnc=%02d  "
-                       "%s, %s)\n", plmn->mcc, plmn->mnc,
-                       gsm_get_mcc(plmn->mcc),
+               LOGP(DSUM, LOGL_INFO, "Start search of last registered PLMN "
+                       "(mcc=%s mnc=%s  %s, %s)\n", gsm_print_mcc(plmn->mcc),
+                       gsm_print_mnc(plmn->mnc), gsm_get_mcc(plmn->mcc),
+                       gsm_get_mnc(plmn->mcc, plmn->mnc));
+               LOGP(DPLMN, LOGL_INFO, "Use RPLMN (mcc=%s mnc=%s  "
+                       "%s, %s)\n", gsm_print_mcc(plmn->mcc),
+                       gsm_print_mnc(plmn->mnc), gsm_get_mcc(plmn->mcc),
                        gsm_get_mnc(plmn->mcc, plmn->mnc));
 
                new_a_state(plmn, GSM322_A1_TRYING_RPLMN);
@@ -1039,6 +1079,7 @@ static int gsm322_a_switch_on(struct osmocom_ms *ms, struct msgb *msg)
        }
 
        /* initiate search at cell selection */
+       LOGP(DSUM, LOGL_INFO, "Search for network\n");
        LOGP(DPLMN, LOGL_INFO, "Switch on, start PLMN search first.\n");
 
        nmsg = gsm322_msgb_alloc(GSM322_EVENT_PLMN_SEARCH_START);
@@ -1118,12 +1159,11 @@ static int gsm322_a_hplmn_search_start(struct osmocom_ms *ms, struct msgb *msg)
 /* manual mode selected */
 static int gsm322_a_sel_manual(struct osmocom_ms *ms, struct msgb *msg)
 {
-       struct gsm322_plmn *plmn = &ms->plmn;
        struct msgb *nmsg;
 
        /* restart state machine */
        gsm322_a_switch_off(ms, msg);
-       plmn->mode = PLMN_MODE_MANUAL;
+       ms->settings.plmn_mode = PLMN_MODE_MANUAL;
        gsm322_m_switch_on(ms, msg);
 
        nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_USER_PLMN_SEL);
@@ -1138,34 +1178,58 @@ static int gsm322_a_sel_manual(struct osmocom_ms *ms, struct msgb *msg)
  * handler for manual search
  */
 
-/* go Not on PLMN state */
-static int gsm322_m_go_not_on_plmn(struct osmocom_ms *ms, struct msgb *msg)
-{
-       struct gsm322_plmn *plmn = &ms->plmn;
-
-       new_m_state(plmn, GSM322_M3_NOT_ON_PLMN);
-
-       return 0;
-}
-
 /* display PLMNs and to Not on PLMN */
 static int gsm322_m_display_plmns(struct osmocom_ms *ms, struct msgb *msg)
 {
+       struct gsm322_msg *gm = (struct gsm322_msg *) msg->data;
+       int msg_type = gm->msg_type;
        struct gsm322_plmn *plmn = &ms->plmn;
        struct gsm_sub_plmn_list *temp;
 
        /* generate list */
        gsm322_sort_list(ms);
 
-       vty_notify(ms, "Select from Network:\n");
+       vty_notify(ms, NULL);
+       switch (msg_type) {
+       case GSM322_EVENT_REG_FAILED:
+               vty_notify(ms, "Failed to register to network %s, %s "
+                       "(%s, %s)\n",
+                       gsm_print_mcc(plmn->mcc), gsm_print_mnc(plmn->mnc),
+                       gsm_get_mcc(plmn->mcc),
+                       gsm_get_mnc(plmn->mcc, plmn->mnc));
+               break;
+       case GSM322_EVENT_NO_CELL_FOUND:
+               vty_notify(ms, "No cell found for network %s, %s "
+                       "(%s, %s)\n",
+                       gsm_print_mcc(plmn->mcc), gsm_print_mnc(plmn->mnc),
+                       gsm_get_mcc(plmn->mcc),
+                       gsm_get_mnc(plmn->mcc, plmn->mnc));
+               break;
+       case GSM322_EVENT_ROAMING_NA:
+               vty_notify(ms, "Roaming not allowed to network %s, %s "
+                       "(%s, %s)\n",
+                       gsm_print_mcc(plmn->mcc), gsm_print_mnc(plmn->mnc),
+                       gsm_get_mcc(plmn->mcc),
+                       gsm_get_mnc(plmn->mcc, plmn->mnc));
+               break;
+       }
 
-       llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
-               vty_notify(ms, " Network %03d, %02d (%s, %s)\n", temp->mcc,
-                       temp->mnc, gsm_get_mcc(temp->mcc),
-                       gsm_get_mnc(temp->mcc, temp->mnc));
+       if (llist_empty(&plmn->sorted_plmn))
+               vty_notify(ms, "Search network!\n");
+       else {
+               vty_notify(ms, "Search or select from network:\n");
+               llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
+                       vty_notify(ms, " Network %s, %s (%s, %s)\n",
+                               gsm_print_mcc(temp->mcc),
+                               gsm_print_mnc(temp->mnc),
+                               gsm_get_mcc(temp->mcc),
+                               gsm_get_mnc(temp->mcc, temp->mnc));
+       }
        
        /* go Not on PLMN state */
-       return gsm322_m_go_not_on_plmn(ms, msg);
+       new_m_state(plmn, GSM322_M3_NOT_ON_PLMN);
+
+       return 0;
 }
 
 /* user starts reselection */
@@ -1187,6 +1251,7 @@ static int gsm322_m_user_resel(struct osmocom_ms *ms, struct msgb *msg)
        }
 
        /* initiate search at cell selection */
+       vty_notify(ms, NULL);
        vty_notify(ms, "Searching Network, please wait...\n");
        LOGP(DPLMN, LOGL_INFO, "User re-select, start PLMN search first.\n");
 
@@ -1206,6 +1271,7 @@ static int gsm322_m_switch_on(struct osmocom_ms *ms, struct msgb *msg)
        struct msgb *nmsg;
 
        if (!subscr->sim_valid) {
+               LOGP(DSUM, LOGL_INFO, "SIM is removed\n");
                LOGP(DPLMN, LOGL_INFO, "Switch on without SIM.\n");
                new_m_state(plmn, GSM322_M5_NO_SIM);
 
@@ -1220,9 +1286,13 @@ static int gsm322_m_switch_on(struct osmocom_ms *ms, struct msgb *msg)
                plmn->mcc = subscr->plmn_mcc;
                plmn->mnc = subscr->plmn_mnc;
 
-               LOGP(DPLMN, LOGL_INFO, "Use RPLMN (mcc=%03d mnc=%02d  "
-                       "%s, %s)\n", plmn->mcc, plmn->mnc,
-                       gsm_get_mcc(plmn->mcc),
+               LOGP(DSUM, LOGL_INFO, "Start search of last registered PLMN "
+                       "(mcc=%s mnc=%s  %s, %s)\n", gsm_print_mcc(plmn->mcc),
+                       gsm_print_mnc(plmn->mnc), gsm_get_mcc(plmn->mcc),
+                       gsm_get_mnc(plmn->mcc, plmn->mnc));
+               LOGP(DPLMN, LOGL_INFO, "Use RPLMN (mcc=%s mnc=%s  "
+                       "%s, %s)\n", gsm_print_mcc(plmn->mcc),
+                       gsm_print_mnc(plmn->mnc), gsm_get_mcc(plmn->mcc),
                        gsm_get_mnc(plmn->mcc, plmn->mnc));
 
                new_m_state(plmn, GSM322_M1_TRYING_RPLMN);
@@ -1237,7 +1307,9 @@ static int gsm322_m_switch_on(struct osmocom_ms *ms, struct msgb *msg)
        }
 
        /* initiate search at cell selection */
+       LOGP(DSUM, LOGL_INFO, "Search for network\n");
        LOGP(DPLMN, LOGL_INFO, "Switch on, start PLMN search first.\n");
+       vty_notify(ms, NULL);
        vty_notify(ms, "Searching Network, please wait...\n");
 
        nmsg = gsm322_msgb_alloc(GSM322_EVENT_PLMN_SEARCH_START);
@@ -1310,6 +1382,7 @@ static int gsm322_m_indicate_selected(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct gsm322_plmn *plmn = &ms->plmn;
 
+       vty_notify(ms, NULL);
        vty_notify(ms, "Selected Network: %s, %s\n",
                gsm_get_mcc(plmn->mcc), gsm_get_mnc(plmn->mcc, plmn->mnc));
 
@@ -1351,10 +1424,11 @@ static int gsm322_m_choose_plmn(struct osmocom_ms *ms, struct msgb *msg)
        plmn->mcc = gm->mcc;
        plmn->mnc = gm->mnc;
 
+       vty_notify(ms, NULL);
        vty_notify(ms, "Selected Network: %s, %s\n",
                gsm_get_mcc(plmn->mcc), gsm_get_mnc(plmn->mcc, plmn->mnc));
-       LOGP(DPLMN, LOGL_INFO, "User selects PLMN. (mcc=%03d mnc=%02d  "
-               "%s, %s)\n", plmn->mcc, plmn->mnc,
+       LOGP(DPLMN, LOGL_INFO, "User selects PLMN. (mcc=%s mnc=%s  "
+               "%s, %s)\n", gsm_print_mcc(plmn->mcc), gsm_print_mnc(plmn->mnc),
                gsm_get_mcc(plmn->mcc), gsm_get_mnc(plmn->mcc, plmn->mnc));
 
        new_m_state(plmn, GSM322_M4_TRYING_PLMN);
@@ -1371,12 +1445,11 @@ static int gsm322_m_choose_plmn(struct osmocom_ms *ms, struct msgb *msg)
 /* auto mode selected */
 static int gsm322_m_sel_auto(struct osmocom_ms *ms, struct msgb *msg)
 {
-       struct gsm322_plmn *plmn = &ms->plmn;
        struct msgb *nmsg;
 
        /* restart state machine */
        gsm322_m_switch_off(ms, msg);
-       plmn->mode = PLMN_MODE_AUTO;
+       ms->settings.plmn_mode = PLMN_MODE_AUTO;
        gsm322_a_switch_on(ms, msg);
 
        nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_USER_PLMN_SEL);
@@ -1421,15 +1494,15 @@ static int gsm322_cs_select(struct osmocom_ms *ms, int any)
                LOGP(DCS, LOGL_INFO, "Select using access class with Emergency "
                        "class.\n");
        } else {
-               acc_class = subscr->acc_class & 0xfbff; /* remove emergency */
-               LOGP(DCS, LOGL_INFO, "Select using access class without "
-                       "Emergency class\n");
+               acc_class = subscr->acc_class;
+               LOGP(DCS, LOGL_INFO, "Select using access class \n");
        }
 
        /* flags to match */
        mask = GSM322_CS_FLAG_SUPPORT | GSM322_CS_FLAG_POWER
                | GSM322_CS_FLAG_SIGNAL | GSM322_CS_FLAG_SYSINFO;
-       if (cs->state == GSM322_C2_STORED_CELL_SEL)
+       if (cs->state == GSM322_C2_STORED_CELL_SEL
+        || cs->state == GSM322_C5_CHOOSE_CELL)
                mask |= GSM322_CS_FLAG_BA;
        flags = mask; /* all masked flags are requied */
 
@@ -1464,8 +1537,9 @@ static int gsm322_cs_select(struct osmocom_ms *ms, int any)
                if (!subscr->acc_barr
                 && (cs->list[i].flags & GSM322_CS_FLAG_FORBIDD)) {
                        LOGP(DCS, LOGL_INFO, "Skip frequency %d: Cell is in "
-                               "list of forbidden LAs. (mcc=%03d mnc=%02d "
-                               "lai=%04x)\n", i, s->mcc, s->mnc, s->lac);
+                               "list of forbidden LAs. (mcc=%s mnc=%s "
+                               "lai=%04x)\n", i, gsm_print_mcc(s->mcc),
+                               gsm_print_mnc(s->mnc), s->lac);
                        continue;
                }
 
@@ -1485,15 +1559,16 @@ static int gsm322_cs_select(struct osmocom_ms *ms, int any)
                if (!any && cs->mcc && (cs->mcc != s->mcc
                                || cs->mnc != s->mnc)) {
                        LOGP(DCS, LOGL_INFO, "Skip frequency %d: PLMN of cell "
-                               "does not match target PLMN. (mcc=%03d "
-                               "mnc=%02d)\n", i, s->mcc, s->mnc);
+                               "does not match target PLMN. (mcc=%s "
+                               "mnc=%s)\n", i, gsm_print_mcc(s->mcc),
+                               gsm_print_mnc(s->mnc));
                        continue;
                }
 
                LOGP(DCS, LOGL_INFO, "Cell frequency %d: Cell found, (rxlev=%d "
-                       "mcc=%03d mnc=%02d lac=%04x  %s, %s)\n", i,
-                       cs->list[i].rxlev_db, s->mcc, s->mnc,
-                       s->lac, gsm_get_mcc(s->mcc),
+                       "mcc=%s mnc=%s lac=%04x  %s, %s)\n", i,
+                       cs->list[i].rxlev_db, gsm_print_mcc(s->mcc),
+                       gsm_print_mnc(s->mnc), s->lac, gsm_get_mcc(s->mcc),
                        gsm_get_mnc(s->mcc, s->mnc));
 
                /* find highest power cell */
@@ -1520,7 +1595,8 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
        /* search for strongest unscanned cell */
        mask = GSM322_CS_FLAG_SUPPORT | GSM322_CS_FLAG_POWER
                | GSM322_CS_FLAG_SIGNAL;
-       if (cs->state == GSM322_C2_STORED_CELL_SEL)
+       if (cs->state == GSM322_C2_STORED_CELL_SEL
+        || cs->state == GSM322_C5_CHOOSE_CELL)
                mask |= GSM322_CS_FLAG_BA;
        flags = mask; /* all masked flags are requied */
        for (i = 0; i <= 1023; i++) {
@@ -1593,9 +1669,9 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
                cs->arfcn = cs->sel_arfcn;
                LOGP(DCS, LOGL_INFO, "Tuning back to frequency %d (rxlev "
                        "%d).\n", cs->arfcn, cs->list[cs->arfcn].rxlev_db);
-               cs->ccch_state = GSM322_CCCH_ST_INIT;
-               l1ctl_tx_ccch_req(ms, cs->arfcn);
-               start_cs_timer(cs, ms->support.sync_to, 0);
+               hack = 5;
+               gsm322_sync_to_cell(cs);
+//             start_cs_timer(cs, ms->support.sync_to, 0);
 
                return 0;
        }
@@ -1624,11 +1700,11 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
                        /* tune */
                        cs->arfcn = found;
                        cs->si = cs->list[cs->arfcn].sysinfo;
-                       cs->ccch_state = GSM322_CCCH_ST_INIT;
-                       l1ctl_tx_ccch_req(ms, cs->arfcn);
+                       hack = 5;
+                       gsm322_sync_to_cell(cs);
 
                        /* selected PLMN (manual) or any PLMN (auto) */
-                       switch (plmn->mode) {
+                       switch (ms->settings.plmn_mode) {
                        case PLMN_MODE_AUTO:
                                if (plmn->state == GSM322_A4_WAIT_FOR_PLMN) {
                                        /* PLMN becomes available */
@@ -1668,10 +1744,7 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
                } else {
 #endif
                        /* unset selected cell */
-                       cs->selected = 0;
-                       memset(&cs->sel_si, 0, sizeof(cs->sel_si));
-                       cs->sel_mcc = cs->sel_mnc = cs->sel_lac = cs->sel_id
-                               = 0;
+                       gsm322_unselect_cell(cs);
 
                        /* tell CS process about no cell available */
                        LOGP(DCS, LOGL_INFO, "No cell available.\n");
@@ -1693,9 +1766,9 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
        cs->arfcn = weight & 1023;
        LOGP(DCS, LOGL_INFO, "Scanning frequency %d (rxlev %d).\n", cs->arfcn,
                cs->list[cs->arfcn].rxlev_db);
-       cs->ccch_state = GSM322_CCCH_ST_INIT;
-       l1ctl_tx_ccch_req(ms, cs->arfcn);
-       start_cs_timer(cs, ms->support.sync_to, 0);
+       hack = 5;
+       gsm322_sync_to_cell(cs);
+//     start_cs_timer(cs, ms->support.sync_to, 0);
 
        /* Allocate/clean system information. */
        cs->list[cs->arfcn].flags &= ~GSM322_CS_FLAG_SYSINFO;
@@ -1710,8 +1783,12 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
        cs->si = cs->list[cs->arfcn].sysinfo;
 
        /* increase scan counter for each maximum scan range */
-       if (gsm_sup_smax[j].max)
+       if (gsm_sup_smax[j].max) {
+               LOGP(DCS, LOGL_INFO, "%d frequencies left in band %d..%d\n",
+                       gsm_sup_smax[j].max - gsm_sup_smax[j].temp,
+                       gsm_sup_smax[j].start, gsm_sup_smax[j].end);
                gsm_sup_smax[j].temp++;
+       }
 
        return 0;
 }
@@ -1769,8 +1846,9 @@ static int gsm322_cs_store(struct osmocom_ms *ms)
        }
 
        LOGP(DCS, LOGL_INFO, "Scan frequency %d: Cell found. (rxlev=%d "
-               "mcc=%03d mnc=%02d lac=%04x)\n", cs->arfcn,
-               cs->list[cs->arfcn].rxlev_db, s->mcc, s->mnc, s->lac);
+               "mcc=%s mnc=%s lac=%04x)\n", cs->arfcn,
+               cs->list[cs->arfcn].rxlev_db, gsm_print_mcc(s->mcc),
+               gsm_print_mnc(s->mnc), s->lac);
 
        /* special case for PLMN search */
        if (cs->state == GSM322_PLMN_SEARCH)
@@ -1782,7 +1860,7 @@ static int gsm322_cs_store(struct osmocom_ms *ms)
                struct gsm_subscriber *subscr = &ms->subscr;
                struct msgb *nmsg;
 
-               if (!gsm322_is_plmn_avail(cs, subscr->mcc, subscr->mnc))
+               if (!gsm322_is_hplmn_avail(cs, subscr->imsi))
                        /* tune to next cell */
                        return gsm322_cs_scan(ms);
 
@@ -1814,15 +1892,15 @@ static int gsm322_cs_store(struct osmocom_ms *ms)
        /* tune */
        cs->arfcn = found;
        cs->si = cs->list[cs->arfcn].sysinfo;
-       cs->ccch_state = GSM322_CCCH_ST_INIT;
-       l1ctl_tx_ccch_req(ms, cs->arfcn);
+       hack = 5;
+       gsm322_sync_to_cell(cs);
 
        /* selected PLMN (manual) or any PLMN (auto) */
-       switch (plmn->mode) {
+       switch (ms->settings.plmn_mode) {
        case PLMN_MODE_AUTO:
                if (plmn->state == GSM322_A4_WAIT_FOR_PLMN) {
                        /* PLMN becomes available */
-                       nmsg = gsm322_msgb_alloc( GSM322_EVENT_PLMN_AVAIL);
+                       nmsg = gsm322_msgb_alloc(GSM322_EVENT_PLMN_AVAIL);
                        if (!nmsg)
                                return -ENOMEM;
                        gsm322_plmn_sendmsg(ms, nmsg);
@@ -1833,7 +1911,7 @@ static int gsm322_cs_store(struct osmocom_ms *ms)
                  && gsm322_is_plmn_avail(cs, plmn->mcc,
                        plmn->mnc)) {
                        /* PLMN becomes available */
-                       nmsg = gsm322_msgb_alloc( GSM322_EVENT_PLMN_AVAIL);
+                       nmsg = gsm322_msgb_alloc(GSM322_EVENT_PLMN_AVAIL);
                        if (!nmsg)
                                return -ENOMEM;
                        gsm322_plmn_sendmsg(ms, nmsg);
@@ -1893,9 +1971,9 @@ struct gsm322_ba_list *gsm322_cs_sysinfo_sacch(struct osmocom_ms *ms)
                                freq[i >> 3] |= (1 << (i & 7));
                }
                if (!!memcmp(freq, ba->freq, sizeof(freq))) {
-                       LOGP(DCS, LOGL_INFO, "New BA list (mcc=%d mnc=%d  "
-                               "%s, %s).\n", ba->mcc, ba->mnc,
-                               gsm_get_mcc(ba->mcc),
+                       LOGP(DCS, LOGL_INFO, "New BA list (mcc=%s mnc=%s  "
+                               "%s, %s).\n", gsm_print_mcc(ba->mcc),
+                               gsm_print_mnc(ba->mnc), gsm_get_mcc(ba->mcc),
                                gsm_get_mnc(ba->mcc, ba->mnc));
                        memcpy(ba->freq, freq, sizeof(freq));
                }
@@ -1931,9 +2009,9 @@ static int gsm322_store_ba_list(struct gsm322_cellsel *cs,
                        freq[i >> 3] |= (1 << (i & 7));
        }
        if (!!memcmp(freq, ba->freq, sizeof(freq))) {
-               LOGP(DCS, LOGL_INFO, "New BA list (mcc=%d mnc=%d  "
-                       "%s, %s).\n", ba->mcc, ba->mnc,
-                       gsm_get_mcc(ba->mcc),
+               LOGP(DCS, LOGL_INFO, "New BA list (mcc=%s mnc=%s  "
+                       "%s, %s).\n", gsm_print_mcc(ba->mcc),
+                       gsm_print_mnc(ba->mnc), gsm_get_mcc(ba->mcc),
                        gsm_get_mnc(ba->mcc, ba->mnc));
                memcpy(ba->freq, freq, sizeof(freq));
        }
@@ -1944,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,
@@ -1984,7 +2064,7 @@ static int gsm322_c_camp_sysinfo_bcch(struct osmocom_ms *ms, struct msgb *msg)
                        LOGP(DCS, LOGL_INFO, "Sysinfo of selected cell is "
                                "updated.\n");
                        memcpy(&cs->sel_si, s, sizeof(cs->sel_si));
-                       gsm48_sysinfo_dump(s, print_dcs, NULL);
+                       //gsm48_sysinfo_dump(s, print_dcs, NULL);
                }
        }
 
@@ -2004,6 +2084,7 @@ static int gsm322_c_camp_sysinfo_bcch(struct osmocom_ms *ms, struct msgb *msg)
                                        cs->arfcn);
                                talloc_free(cs->list[cs->arfcn].sysinfo);
                                cs->list[cs->arfcn].sysinfo = NULL;
+                               gsm322_unselect_cell(cs);
                        }
                        /* trigger reselection without queueing,
                         * because other sysinfo message may be queued
@@ -2082,7 +2163,7 @@ static int gsm322_c_scan_sysinfo_bcch(struct osmocom_ms *ms, struct msgb *msg)
                /* stop timer */
                stop_cs_timer(cs);
 
-               gsm48_sysinfo_dump(s, print_dcs, NULL);
+               //gsm48_sysinfo_dump(s, print_dcs, NULL);
 
                /* store sysinfo and continue scan */
                return gsm322_cs_store(ms);
@@ -2097,7 +2178,7 @@ static void gsm322_cs_timeout(void *arg)
        struct gsm322_cellsel *cs = arg;
        struct osmocom_ms *ms = cs->ms;
 
-       LOGP(DCS, LOGL_INFO, "Cell selection timer has fired.\n");
+       LOGP(DCS, LOGL_INFO, "Cell selection failed.\n");
 
        /* if we have no lock, we retry */
        if (cs->ccch_state != GSM322_CCCH_ST_SYNC)
@@ -2114,6 +2195,7 @@ static void gsm322_cs_timeout(void *arg)
                LOGP(DCS, LOGL_INFO, "free sysinfo arfcn=%d\n", cs->arfcn);
                talloc_free(cs->list[cs->arfcn].sysinfo);
                cs->list[cs->arfcn].sysinfo = NULL;
+               gsm322_unselect_cell(cs);
        }
 
        /* tune to next cell */
@@ -2130,24 +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) {
-               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;
+                       }
                }
        }
 
@@ -2184,6 +2279,8 @@ static int gsm322_cs_powerscan(struct osmocom_ms *ms)
                                                cs->list[i].sysinfo = NULL;
                                        }
                                }
+                               /* no cell selected */
+                               gsm322_unselect_cell(cs);
                                goto again;
                        }
                        /* on other cell selection, indicate "no cell found" */
@@ -2210,9 +2307,9 @@ static int gsm322_cs_powerscan(struct osmocom_ms *ms)
                                LOGP(DCS, LOGL_INFO, "Tuning back to frequency "
                                        "%d (rxlev %d).\n", cs->arfcn,
                                        cs->list[cs->arfcn].rxlev_db);
-                               cs->ccch_state = GSM322_CCCH_ST_INIT;
-                               l1ctl_tx_ccch_req(ms, cs->arfcn);
-                               start_cs_timer(cs, ms->support.sync_to, 0);
+                               hack = 5;
+                               gsm322_sync_to_cell(cs);
+//                             start_cs_timer(cs, ms->support.sync_to, 0);
 
                        } else
                                new_c_state(cs, GSM322_C0_NULL);
@@ -2229,17 +2326,21 @@ 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);
 
        /* start scan on radio interface */
        cs->powerscan = 1;
+//#warning TESTING!!!!
+//usleep(300000);
        return l1ctl_tx_pm_req_range(ms, s, e);
 }
 
@@ -2266,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);
@@ -2292,6 +2395,7 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
                        /* in dedicated mode */
                        if (ms->rrlayer.state == GSM48_RR_ST_CONN_PEND)
                                return gsm48_rr_tx_rand_acc(ms, NULL);
+#endif
 
                        /* set timer for reading BCCH */
                        if (cs->state == GSM322_C2_STORED_CELL_SEL
@@ -2305,10 +2409,31 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
                         || cs->state == GSM322_HPLMN_SEARCH)
                                start_cs_timer(cs, ms->support.scan_to, 0);
                                        // TODO: timer depends on BCCH config
-#endif
                }
                break;
+       case S_L1CTL_FBSB_ERR:
+               if (hack) {
+                       ms = signal_data;
+                       cs = &ms->cellsel;
+                       gsm322_sync_to_cell(cs);
+                       hack--;
+                       LOGP(DCS, LOGL_INFO, "Channel sync error, try again.\n");
+                       break;
+               }
+               LOGP(DCS, LOGL_INFO, "Channel sync error.\n");
+               ms = signal_data;
+               cs = &ms->cellsel;
+
+               stop_cs_timer(cs);
+               if (cs->selected)
+                       gsm322_cs_loss(cs);
+               else
+                       gsm322_cs_timeout(cs);
+               break;
+       case S_L1CTL_RESET:
+               break;
        }
+
        return 0;
 }
 
@@ -2318,7 +2443,7 @@ static void gsm322_cs_loss(void *arg)
        struct osmocom_ms *ms = cs->ms;
        struct gsm48_rrlayer *rr = &ms->rrlayer;
 
-       LOGP(DCS, LOGL_INFO, "Loss of CCCH timer fired.\n");
+       LOGP(DCS, LOGL_INFO, "Loss of CCCH.\n");
        if (cs->state == GSM322_C3_CAMPED_NORMALLY
         || cs->state == GSM322_C7_CAMPED_ANY_CELL) {
                if (rr->state == GSM48_RR_ST_IDLE) {
@@ -2333,6 +2458,11 @@ static void gsm322_cs_loss(void *arg)
                        msgb_free(nmsg);
                } else {
                        LOGP(DCS, LOGL_INFO, "Trigger RR abort.\n");
+                       gsm48_rr_los(ms);
+                       /* be shure that nothing else is done after here
+                        * because the function call above may cause
+                        * to return from idle state and trigger cell re-sel.
+                        */
                }
        }
 
@@ -2360,13 +2490,12 @@ static int gsm322_c_plmn_search(struct osmocom_ms *ms, struct msgb *msg)
                        LOGP(DCS, LOGL_INFO, "free sysinfo arfcn=%d\n", i);
                        talloc_free(cs->list[i].sysinfo);
                        cs->list[i].sysinfo = NULL;
+                       gsm322_unselect_cell(cs);
                }
        }
 
        /* unset selected cell */
-       cs->selected = 0;
-       memset(&cs->sel_si, 0, sizeof(cs->sel_si));
-       cs->sel_mcc = cs->sel_mnc = cs->sel_lac = cs->sel_id = 0;
+       gsm322_unselect_cell(cs);
 
        /* start power scan */
        return gsm322_cs_powerscan(ms);
@@ -2397,6 +2526,9 @@ static int gsm322_c_hplmn_search(struct osmocom_ms *ms, struct msgb *msg)
                }
        }
 
+       /* no cell selected */
+       gsm322_unselect_cell(cs);
+
        /* start power scan */
        return gsm322_cs_powerscan(ms);
 }
@@ -2418,9 +2550,7 @@ static int gsm322_c_stored_cell_sel(struct osmocom_ms *ms, struct gsm322_ba_list
        }
 
        /* unset selected cell */
-       cs->selected = 0;
-       memset(&cs->sel_si, 0, sizeof(cs->sel_si));
-       cs->sel_mcc = cs->sel_mnc = cs->sel_lac = cs->sel_id = 0;
+       gsm322_unselect_cell(cs);
 
        /* start power scan */
        return gsm322_cs_powerscan(ms);
@@ -2450,9 +2580,7 @@ static int gsm322_c_normal_cell_sel(struct osmocom_ms *ms, struct msgb *msg)
        new_c_state(cs, GSM322_C1_NORMAL_CELL_SEL);
 
        /* unset selected cell */
-       cs->selected = 0;
-       memset(&cs->sel_si, 0, sizeof(cs->sel_si));
-       cs->sel_mcc = cs->sel_mnc = cs->sel_lac = cs->sel_id = 0;
+       gsm322_unselect_cell(cs);
 
        /* start power scan */
        return gsm322_cs_powerscan(ms);
@@ -2462,18 +2590,12 @@ static int gsm322_c_normal_cell_sel(struct osmocom_ms *ms, struct msgb *msg)
 static int gsm322_c_any_cell_sel(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct gsm322_cellsel *cs = &ms->cellsel;
-       int i;
 
        /* in case we already tried any cell (re-)selection, power scan again */
-       if (cs->state == GSM322_C6_ANY_CELL_SEL
+       if (cs->state == GSM322_C0_NULL
+        || cs->state == GSM322_C6_ANY_CELL_SEL
         || cs->state == GSM322_C8_ANY_CELL_RESEL) {
-               struct msgb *nmsg;
-
-               /* tell that we have no cell found */
-               nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_NO_CELL_FOUND);
-               if (!nmsg)
-                       return -ENOMEM;
-               gsm48_mmevent_msg(ms, nmsg);
+               int i;
 
                for (i = 0; i <= 1023; i++) {
                        cs->list[i].flags &= ~(GSM322_CS_FLAG_POWER
@@ -2486,6 +2608,18 @@ static int gsm322_c_any_cell_sel(struct osmocom_ms *ms, struct msgb *msg)
                                cs->list[i].sysinfo = NULL;
                        }
                }
+       }
+       /* after re-selection, indicate no cell found */
+       if (cs->state == GSM322_C6_ANY_CELL_SEL
+        || cs->state == GSM322_C8_ANY_CELL_RESEL) {
+               struct msgb *nmsg;
+
+               /* tell that we have no cell found */
+               nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_NO_CELL_FOUND);
+               if (!nmsg)
+                       return -ENOMEM;
+               gsm48_mmevent_msg(ms, nmsg);
+
        } else { 
                new_c_state(cs, GSM322_C6_ANY_CELL_SEL);
        }
@@ -2493,9 +2627,7 @@ static int gsm322_c_any_cell_sel(struct osmocom_ms *ms, struct msgb *msg)
        cs->mcc = cs->mnc = 0;
 
        /* unset selected cell */
-       cs->selected = 0;
-       memset(&cs->sel_si, 0, sizeof(cs->sel_si));
-       cs->sel_mcc = cs->sel_mnc = cs->sel_lac = cs->sel_id = 0;
+       gsm322_unselect_cell(cs);
 
        /* start power scan */
        return gsm322_cs_powerscan(ms);
@@ -2559,25 +2691,26 @@ struct gsm322_ba_list *gsm322_cs_ba_range(struct osmocom_ms *ms,
 static int gsm322_cs_choose(struct osmocom_ms *ms)
 {
        struct gsm322_cellsel *cs = &ms->cellsel;
+       struct gsm48_rrlayer *rr = &ms->rrlayer;
        struct gsm322_ba_list *ba = NULL;
        int i;
 
-#ifdef TODO
-what we have todo here:
-if we return from dedicated mode and we have a ba range, we can use that for cell reselection
-       if (message->ranges)
-               ba = gsm322_cs_ba_range(ms, message->range, message->ranges);
+       /* NOTE: The call to this function is synchron to RR layer, so
+        * we may access the BA range there.
+        */
+       if (rr->ba_ranges)
+               ba = gsm322_cs_ba_range(ms, rr->ba_range, rr->ba_ranges);
        else {
                LOGP(DCS, LOGL_INFO, "No BA range(s), try sysinfo.\n");
-#endif
                /* get and update BA of last received sysinfo 5* */
                ba = gsm322_cs_sysinfo_sacch(ms);
-               if (!ba)
+               if (!ba) {
+                       LOGP(DCS, LOGL_INFO, "No BA on sysinfo, try stored "
+                               "BA list.\n");
                        ba = gsm322_find_ba_list(cs, cs->sel_si.mcc,
                                cs->sel_si.mnc);
-#ifdef TODO
+               }
        }
-#endif
 
        if (!ba) {
                struct msgb *nmsg;
@@ -2597,10 +2730,11 @@ if we return from dedicated mode and we have a ba range, we can use that for cel
        /* flag all frequencies that are in current band allocation */
        for (i = 0; i <= 1023; i++) {
                if (cs->state == GSM322_C5_CHOOSE_CELL) {
-                       if ((ba->freq[i >> 3] & (1 << (i & 7))))
+                       if ((ba->freq[i >> 3] & (1 << (i & 7)))) {
                                cs->list[i].flags |= GSM322_CS_FLAG_BA;
-                       else
+                       } else {
                                cs->list[i].flags &= ~GSM322_CS_FLAG_BA;
+                       }
                }
                cs->list[i].flags &= ~(GSM322_CS_FLAG_POWER
                                        | GSM322_CS_FLAG_SIGNAL
@@ -2613,9 +2747,7 @@ if we return from dedicated mode and we have a ba range, we can use that for cel
        }
 
        /* unset selected cell */
-       cs->selected = 0;
-       memset(&cs->sel_si, 0, sizeof(cs->sel_si));
-       cs->sel_mcc = cs->sel_mnc = cs->sel_lac = cs->sel_id = 0;
+       gsm322_unselect_cell(cs);
 
        /* start power scan */
        return gsm322_cs_powerscan(ms);
@@ -2651,6 +2783,11 @@ static int gsm322_c_new_plmn(struct osmocom_ms *ms, struct msgb *msg)
        cs->mcc = plmn->mcc;
        cs->mnc = plmn->mnc;
 
+       LOGP(DSUM, LOGL_INFO, "Selecting network (mcc=%s "
+               "mnc=%s  %s, %s)\n", gsm_print_mcc(cs->mcc),
+               gsm_print_mnc(cs->mnc), gsm_get_mcc(cs->mcc),
+               gsm_get_mnc(cs->mcc, cs->mnc));
+
        /* search for BA list */
        ba = gsm322_find_ba_list(cs, plmn->mcc, plmn->mnc);
 
@@ -2669,6 +2806,11 @@ static int gsm322_c_camp_normally(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm322_cellsel *cs = &ms->cellsel;
        struct msgb *nmsg;
 
+       LOGP(DSUM, LOGL_INFO, "Camping normally on cell (arfcn=%d mcc=%s "
+               "mnc=%s  %s, %s)\n", cs->sel_arfcn, gsm_print_mcc(cs->sel_mcc),
+               gsm_print_mnc(cs->sel_mnc), gsm_get_mcc(cs->sel_mcc),
+               gsm_get_mnc(cs->sel_mcc, cs->sel_mnc));
+
        /* tell that we have selected a (new) cell */
        nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_CELL_SELECTED);
        if (!nmsg)
@@ -2686,6 +2828,12 @@ static int gsm322_c_camp_any_cell(struct osmocom_ms *ms, struct msgb *msg)
        struct gsm322_cellsel *cs = &ms->cellsel;
        struct msgb *nmsg;
 
+       LOGP(DSUM, LOGL_INFO, "Camping on any cell (arfcn=%d mcc=%s "
+               "mnc=%s  %s, %s)\n", cs->sel_arfcn, gsm_print_mcc(cs->sel_mcc),
+               gsm_print_mnc(cs->sel_mnc), gsm_get_mcc(cs->sel_mcc),
+               gsm_get_mnc(cs->sel_mcc, cs->sel_mnc));
+
+
        /* tell that we have selected a (new) cell */
        nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_CELL_SELECTED);
        if (!nmsg)
@@ -2709,9 +2857,11 @@ static int gsm322_c_conn_mode_1(struct osmocom_ms *ms, struct msgb *msg)
 
        /* be sure to go to current camping frequency on return */
        LOGP(DCS, LOGL_INFO, "Going to camping frequency %d.\n", cs->arfcn);
-       cs->ccch_state = GSM322_CCCH_ST_INIT;
-       l1ctl_tx_ccch_req(ms, cs->arfcn);
+       hack = 5;
+       gsm322_sync_to_cell(cs);
        cs->si = cs->list[cs->arfcn].sysinfo;
+//#warning TESTING!!!!
+//usleep(300000);
 
        return 0;
 }
@@ -2727,8 +2877,8 @@ static int gsm322_c_conn_mode_2(struct osmocom_ms *ms, struct msgb *msg)
 
        /* be sure to go to current camping frequency on return */
        LOGP(DCS, LOGL_INFO, "Going to camping frequency %d.\n", cs->arfcn);
-       cs->ccch_state = GSM322_CCCH_ST_INIT;
-       l1ctl_tx_ccch_req(ms, cs->arfcn);
+       hack = 5;
+       gsm322_sync_to_cell(cs);
        cs->si = cs->list[cs->arfcn].sysinfo;
 
        return 0;
@@ -2763,44 +2913,70 @@ static struct plmnastatelist {
 } plmnastatelist[] = {
        {SBIT(GSM322_A0_NULL),
         GSM322_EVENT_SWITCH_ON, gsm322_a_switch_on},
+
        {SBIT(GSM322_A0_NULL),
         GSM322_EVENT_PLMN_SEARCH_END, gsm322_a_sel_first_plmn},
+
        {ALL_STATES,
         GSM322_EVENT_SWITCH_OFF, gsm322_a_switch_off},
+
        {SBIT(GSM322_A6_NO_SIM),
         GSM322_EVENT_SIM_INSERT, gsm322_a_switch_on},
+
        {ALL_STATES,
         GSM322_EVENT_SIM_INSERT, gsm322_a_sim_insert},
+
        {ALL_STATES,
         GSM322_EVENT_SIM_REMOVE, gsm322_a_sim_removed},
+
        {ALL_STATES,
         GSM322_EVENT_INVALID_SIM, gsm322_a_sim_removed},
+
        {SBIT(GSM322_A1_TRYING_RPLMN),
         GSM322_EVENT_REG_FAILED, gsm322_a_sel_first_plmn},
+
+       {SBIT(GSM322_A1_TRYING_RPLMN),
+        GSM322_EVENT_ROAMING_NA, gsm322_a_sel_first_plmn},
+
        {SBIT(GSM322_A1_TRYING_RPLMN),
         GSM322_EVENT_NO_CELL_FOUND, gsm322_a_sel_first_plmn},
+
        {SBIT(GSM322_A1_TRYING_RPLMN) | SBIT(GSM322_A3_TRYING_PLMN),
         GSM322_EVENT_REG_SUCCESS, gsm322_a_indicate_selected},
+
        {SBIT(GSM322_A2_ON_PLMN),
         GSM322_EVENT_ROAMING_NA, gsm322_a_roaming_na},
+
        {SBIT(GSM322_A2_ON_PLMN),
         GSM322_EVENT_HPLMN_SEARCH, gsm322_a_hplmn_search_start},
+
        {SBIT(GSM322_A2_ON_PLMN),
         GSM322_EVENT_NO_CELL_FOUND, gsm322_a_loss_of_radio},
+
        {SBIT(GSM322_A2_ON_PLMN),
         GSM322_EVENT_USER_RESEL, gsm322_a_user_resel},
+
        {SBIT(GSM322_A3_TRYING_PLMN),
         GSM322_EVENT_REG_FAILED, gsm322_a_sel_next_plmn},
+
+       {SBIT(GSM322_A3_TRYING_PLMN),
+        GSM322_EVENT_ROAMING_NA, gsm322_a_sel_next_plmn},
+
        {SBIT(GSM322_A3_TRYING_PLMN),
         GSM322_EVENT_NO_CELL_FOUND, gsm322_a_sel_next_plmn},
+
        {SBIT(GSM322_A5_HPLMN_SEARCH),
         GSM322_EVENT_CELL_FOUND, gsm322_a_sel_first_plmn},
+
        {SBIT(GSM322_A5_HPLMN_SEARCH),
         GSM322_EVENT_NO_CELL_FOUND, gsm322_a_go_on_plmn},
+
        {SBIT(GSM322_A4_WAIT_FOR_PLMN),
         GSM322_EVENT_PLMN_AVAIL, gsm322_a_plmn_avail},
+
        {ALL_STATES,
         GSM322_EVENT_SEL_MANUAL, gsm322_a_sel_manual},
+
        {ALL_STATES,
         GSM322_EVENT_NO_CELL_FOUND, gsm322_am_no_cell_found},
 };
@@ -2817,7 +2993,7 @@ static int gsm322_a_event(struct osmocom_ms *ms, struct msgb *msg)
        int i;
 
        LOGP(DPLMN, LOGL_INFO, "(ms %s) Event '%s' for automatic PLMN "
-               "selection in state %s\n", ms->name, get_event_name(msg_type),
+               "selection in state '%s'\n", ms->name, get_event_name(msg_type),
                plmn_a_state_names[plmn->state]);
        /* find function for current state and message */
        for (i = 0; i < PLMNASLLEN; i++)
@@ -2842,42 +3018,66 @@ static struct plmnmstatelist {
 } plmnmstatelist[] = {
        {SBIT(GSM322_M0_NULL),
         GSM322_EVENT_SWITCH_ON, gsm322_m_switch_on},
+
        {SBIT(GSM322_M0_NULL) | SBIT(GSM322_M3_NOT_ON_PLMN) |
         SBIT(GSM322_M2_ON_PLMN),
         GSM322_EVENT_PLMN_SEARCH_END, gsm322_m_display_plmns},
+
        {ALL_STATES,
         GSM322_EVENT_SWITCH_OFF, gsm322_m_switch_off},
+
        {SBIT(GSM322_M5_NO_SIM),
         GSM322_EVENT_SIM_INSERT, gsm322_m_switch_on},
+
        {ALL_STATES,
         GSM322_EVENT_SIM_INSERT, gsm322_m_sim_insert},
+
        {ALL_STATES,
         GSM322_EVENT_SIM_REMOVE, gsm322_m_sim_removed},
+
        {SBIT(GSM322_M1_TRYING_RPLMN),
         GSM322_EVENT_REG_FAILED, gsm322_m_display_plmns},
+
+       {SBIT(GSM322_M1_TRYING_RPLMN),
+        GSM322_EVENT_ROAMING_NA, gsm322_m_display_plmns},
+
        {SBIT(GSM322_M1_TRYING_RPLMN),
         GSM322_EVENT_NO_CELL_FOUND, gsm322_m_display_plmns},
+
        {SBIT(GSM322_M1_TRYING_RPLMN),
         GSM322_EVENT_REG_SUCCESS, gsm322_m_indicate_selected},
+
        {SBIT(GSM322_M2_ON_PLMN),
         GSM322_EVENT_ROAMING_NA, gsm322_m_display_plmns},
+
        {SBIT(GSM322_M1_TRYING_RPLMN) | SBIT(GSM322_M2_ON_PLMN) |
         SBIT(GSM322_M4_TRYING_PLMN),
         GSM322_EVENT_INVALID_SIM, gsm322_m_sim_removed},
+
        {SBIT(GSM322_M3_NOT_ON_PLMN) | SBIT(GSM322_M2_ON_PLMN),
         GSM322_EVENT_USER_RESEL, gsm322_m_user_resel},
+
        {SBIT(GSM322_M3_NOT_ON_PLMN),
         GSM322_EVENT_PLMN_AVAIL, gsm322_m_plmn_avail},
+
        {SBIT(GSM322_M3_NOT_ON_PLMN),
         GSM322_EVENT_CHOSE_PLMN, gsm322_m_choose_plmn},
+
        {SBIT(GSM322_M4_TRYING_PLMN),
         GSM322_EVENT_REG_SUCCESS, gsm322_m_go_on_plmn},
+
+       {SBIT(GSM322_M4_TRYING_PLMN),
+        GSM322_EVENT_REG_FAILED, gsm322_m_display_plmns},
+
        {SBIT(GSM322_M4_TRYING_PLMN),
-        GSM322_EVENT_REG_FAILED, gsm322_m_go_not_on_plmn},
+        GSM322_EVENT_ROAMING_NA, gsm322_m_display_plmns},
+
        {SBIT(GSM322_M4_TRYING_PLMN),
-        GSM322_EVENT_NO_CELL_FOUND, gsm322_m_go_not_on_plmn},
+        GSM322_EVENT_NO_CELL_FOUND, gsm322_m_display_plmns},
+
        {ALL_STATES,
         GSM322_EVENT_SEL_AUTO, gsm322_m_sel_auto},
+
        {ALL_STATES,
         GSM322_EVENT_NO_CELL_FOUND, gsm322_am_no_cell_found},
 };
@@ -2894,7 +3094,7 @@ static int gsm322_m_event(struct osmocom_ms *ms, struct msgb *msg)
        int i;
 
        LOGP(DPLMN, LOGL_INFO, "(ms %s) Event '%s' for manual PLMN selection "
-               "in state %s\n", ms->name, get_event_name(msg_type),
+               "in state '%s'\n", ms->name, get_event_name(msg_type),
                plmn_m_state_names[plmn->state]);
        /* find function for current state and message */
        for (i = 0; i < PLMNMSLLEN; i++)
@@ -2920,7 +3120,7 @@ int gsm322_plmn_dequeue(struct osmocom_ms *ms)
        
        while ((msg = msgb_dequeue(&plmn->event_queue))) {
                /* send event to PLMN select process */
-               if (plmn->mode == PLMN_MODE_AUTO)
+               if (ms->settings.plmn_mode == PLMN_MODE_AUTO)
                        gsm322_a_event(ms, msg);
                else
                        gsm322_m_event(ms, msg);
@@ -2939,46 +3139,63 @@ static struct cellselstatelist {
 } cellselstatelist[] = {
        {ALL_STATES,
         GSM322_EVENT_SWITCH_ON, gsm322_c_switch_on},
+
        {ALL_STATES,
         GSM322_EVENT_SIM_REMOVE, gsm322_c_any_cell_sel},
+
        {ALL_STATES,
         GSM322_EVENT_NEW_PLMN, gsm322_c_new_plmn},
+
        {ALL_STATES,
         GSM322_EVENT_PLMN_SEARCH_START, gsm322_c_plmn_search},
+
        {SBIT(GSM322_C1_NORMAL_CELL_SEL) | SBIT(GSM322_C2_STORED_CELL_SEL) |
         SBIT(GSM322_C4_NORMAL_CELL_RESEL) | SBIT(GSM322_C5_CHOOSE_CELL),
         GSM322_EVENT_CELL_FOUND, gsm322_c_camp_normally},
+
        {SBIT(GSM322_C9_CHOOSE_ANY_CELL) | SBIT(GSM322_C6_ANY_CELL_SEL) |
         SBIT(GSM322_C8_ANY_CELL_RESEL),
         GSM322_EVENT_CELL_FOUND, gsm322_c_camp_any_cell},
+
        {SBIT(GSM322_C1_NORMAL_CELL_SEL) | SBIT(GSM322_C6_ANY_CELL_SEL) |
         SBIT(GSM322_C9_CHOOSE_ANY_CELL) | SBIT(GSM322_C8_ANY_CELL_RESEL) |
         SBIT(GSM322_C0_NULL),
         GSM322_EVENT_NO_CELL_FOUND, gsm322_c_any_cell_sel},
+
        {SBIT(GSM322_C2_STORED_CELL_SEL) | SBIT(GSM322_C5_CHOOSE_CELL) |
         SBIT(GSM322_C4_NORMAL_CELL_RESEL),
         GSM322_EVENT_NO_CELL_FOUND, gsm322_c_normal_cell_sel},
+
        {SBIT(GSM322_C3_CAMPED_NORMALLY),
         GSM322_EVENT_LEAVE_IDLE, gsm322_c_conn_mode_1},
+
        {SBIT(GSM322_C7_CAMPED_ANY_CELL),
         GSM322_EVENT_LEAVE_IDLE, gsm322_c_conn_mode_2},
+
        {SBIT(GSM322_C3_CAMPED_NORMALLY),
         GSM322_EVENT_RET_IDLE, gsm322_c_choose_cell},
+
        {SBIT(GSM322_C7_CAMPED_ANY_CELL),
         GSM322_EVENT_RET_IDLE, gsm322_c_choose_any_cell},
+
        {SBIT(GSM322_C3_CAMPED_NORMALLY),
         GSM322_EVENT_CELL_RESEL, gsm322_c_normal_cell_resel},
+
        {SBIT(GSM322_C7_CAMPED_ANY_CELL),
         GSM322_EVENT_CELL_RESEL, gsm322_c_any_cell_resel},
+
        {SBIT(GSM322_C7_CAMPED_ANY_CELL),
         GSM322_EVENT_CELL_FOUND, gsm322_c_normal_cell_sel},
+
        {SBIT(GSM322_C1_NORMAL_CELL_SEL) | SBIT(GSM322_C2_STORED_CELL_SEL) |
         SBIT(GSM322_C4_NORMAL_CELL_RESEL) | SBIT(GSM322_C5_CHOOSE_CELL) |
         SBIT(GSM322_C9_CHOOSE_ANY_CELL) | SBIT(GSM322_C8_ANY_CELL_RESEL) |
         SBIT(GSM322_C6_ANY_CELL_SEL) | SBIT(GSM322_PLMN_SEARCH),
         GSM322_EVENT_SYSINFO, gsm322_c_scan_sysinfo_bcch},
+
        {SBIT(GSM322_C3_CAMPED_NORMALLY) | SBIT(GSM322_C7_CAMPED_ANY_CELL),
         GSM322_EVENT_SYSINFO, gsm322_c_camp_sysinfo_bcch},
+
        {SBIT(GSM322_C3_CAMPED_NORMALLY),
         GSM322_EVENT_HPLMN_SEARCH, gsm322_c_hplmn_search},
 };
@@ -2995,7 +3212,7 @@ int gsm322_c_event(struct osmocom_ms *ms, struct msgb *msg)
        int i;
 
        LOGP(DCS, LOGL_INFO, "(ms %s) Event '%s' for Cell selection in state "
-               "%s\n", ms->name, get_event_name(msg_type),
+               "'%s'\n", ms->name, get_event_name(msg_type),
                cs_state_names[cs->state]);
        /* find function for current state and message */
        for (i = 0; i < CELLSELSLLEN; i++)
@@ -3041,7 +3258,9 @@ int gsm322_dump_sorted_plmn(struct osmocom_ms *ms)
        printf("MCC    |MNC    |allowed|rx-lev\n");
        printf("-------+-------+-------+-------\n");
        llist_for_each_entry(temp, &plmn->sorted_plmn, entry) {
-               printf("%03d    |%02d     |%s    |%d\n", temp->mcc, temp->mnc,
+               printf("%s    |%s%s    |%s    |%d\n", gsm_print_mcc(temp->mcc),
+                       gsm_print_mnc(temp->mnc),
+                       ((temp->mnc & 0x00f) == 0x00f) ? " ":"",
                        (temp->cause) ? "no ":"yes", temp->rxlev_db);
        }
 
@@ -3051,58 +3270,58 @@ int gsm322_dump_sorted_plmn(struct osmocom_ms *ms)
 int gsm322_dump_cs_list(struct gsm322_cellsel *cs, uint8_t flags,
                        void (*print)(void *, const char *, ...), void *priv)
 {
-       int i, j;
+       int i;
        struct gsm48_sysinfo *s;
 
-       print(priv, "arfcn  |rx-lev |MCC    |MNC    |forb.LA|"
-               "prio  ,0123456789abcdef|min-db |max-pwr\n");
-       print(priv, "-------+-------+-------+-------+-------+"
-               "-----------------------+-------+-------\n");
+       print(priv, "arfcn  |rx-lev |MCC    |MNC    |LAC    |cell ID|forb.LA|"
+               "prio   |min-db |max-pwr\n");
+       print(priv, "-------+-------+-------+-------+-------+-------+-------+"
+               "-------+-------+-------\n");
        for (i = 0; i <= 1023; i++) {
                s = cs->list[i].sysinfo;
                if (!s || !(cs->list[i].flags & flags))
                        continue;
                print(priv, "%4d   |%4d   |", i, cs->list[i].rxlev_db);
                if ((cs->list[i].flags & GSM322_CS_FLAG_SYSINFO)) {
-                       print(priv, "%03d    |%02d     |", s->mcc, s->mnc);
+                       print(priv, "%s    |%s%s    |", gsm_print_mcc(s->mcc),
+                               gsm_print_mnc(s->mnc),
+                               ((s->mnc & 0x00f) == 0x00f) ? " ":"");
+                       print(priv, "0x%04x |0x%04x |", s->lac, s->cell_id);
                        if ((cs->list[i].flags & GSM322_CS_FLAG_FORBIDD))
                                print(priv, "yes    |");
                        else
                                print(priv, "no     |");
                        if ((cs->list[i].flags & GSM322_CS_FLAG_BARRED))
-                               print(priv, "barred ");
+                               print(priv, "barred |");
                        else {
                                if (cs->list[i].sysinfo->cell_barr)
-                                       print(priv, "low    ");
+                                       print(priv, "low    |");
                                else
-                                       print(priv, "normal ");
+                                       print(priv, "normal |");
                        }
-                       for (j = 0; j < 16; j++) {
-                               if ((s->class_barr & (1 << j)))
-                                       print(priv, "*");
-                               else
-                                       print(priv, " ");
-                       }
-                       print(priv, "|%4d   |%4d\n", s->rxlev_acc_min_db,
-                               s->ms_txpwr_max_ccch);
+                       print(priv, "%4d   |%4d\n", s->rxlev_acc_min_db,
+                               s->ms_txpwr_max_cch);
                } else
-                       print(priv, "n/a    |n/a    |       |                       "
-                               "|n/a    |n/a\n");
+                       print(priv, "n/a    |n/a    |n/a    |n/a    |n/a    |"
+                               "n/a    |n/a    |n/a\n");
        }
        print(priv, "\n");
 
        return 0;
 }
 
-int gsm322_dump_forbidden_la(struct osmocom_ms *ms)
+int gsm322_dump_forbidden_la(struct osmocom_ms *ms,
+                       void (*print)(void *, const char *, ...), void *priv)
 {
        struct gsm322_plmn *plmn = &ms->plmn;
        struct gsm322_la_list *temp;
 
-       printf("MCC    |MNC    |LAC    |cause\n");
-       printf("-------+-------+-------+-------\n");
+       print(priv, "MCC    |MNC    |LAC    |cause\n");
+       print(priv, "-------+-------+-------+-------\n");
        llist_for_each_entry(temp, &plmn->forbidden_la, entry)
-               printf("%03d    |%02d     |0x%04x |#%d\n", temp->mcc, temp->mnc,
+               print(priv, "%s    |%s%s    |0x%04x |#%d\n",
+                       gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
+                       ((temp->mnc & 0x00f) == 0x00f) ? " ":"",
                        temp->lac, temp->cause);
 
        return 0;
@@ -3156,7 +3375,7 @@ int gsm322_init(struct osmocom_ms *ms)
        /* set initial state */
        plmn->state = 0;
        cs->state = 0;
-       plmn->mode = PLMN_MODE_AUTO;
+       ms->settings.plmn_mode = PLMN_MODE_AUTO;
 
        /* init lists */
        INIT_LLIST_HEAD(&plmn->event_queue);
@@ -3194,9 +3413,9 @@ int gsm322_init(struct osmocom_ms *ms)
                                break;
                        }
                        llist_add_tail(&ba->entry, &cs->ba_list);
-                       LOGP(DCS, LOGL_INFO, "Read stored BA list (mcc=%d "
-                               "mnc=%d  %s, %s)\n", ba->mcc, ba->mnc,
-                               gsm_get_mcc(ba->mcc),
+                       LOGP(DCS, LOGL_INFO, "Read stored BA list (mcc=%s "
+                               "mnc=%s  %s, %s)\n", gsm_print_mcc(ba->mcc),
+                               gsm_print_mnc(ba->mnc), gsm_get_mcc(ba->mcc),
                                gsm_get_mnc(ba->mcc, ba->mnc));
                }
                osmocom_fclose(fp);
@@ -3257,9 +3476,9 @@ int gsm322_exit(struct osmocom_ms *ms)
                        buf[3] = ba->mnc & 0xff;
                        rc = osmocom_fwrite(buf, 4, 1, fp);
                        rc = osmocom_fwrite(ba->freq, sizeof(ba->freq), 1, fp);
-                       LOGP(DCS, LOGL_INFO, "Write stored BA list (mcc=%d "
-                               "mnc=%d  %s, %s)\n", ba->mcc, ba->mnc,
-                               gsm_get_mcc(ba->mcc),
+                       LOGP(DCS, LOGL_INFO, "Write stored BA list (mcc=%s "
+                               "mnc=%s  %s, %s)\n", gsm_print_mcc(ba->mcc),
+                               gsm_print_mnc(ba->mnc), gsm_get_mcc(ba->mcc),
                                gsm_get_mnc(ba->mcc, ba->mnc));
                }
                osmocom_fclose(fp);