#include <osmocom/file.h>
#include <osmocom/osmocom_data.h>
#include <osmocom/networks.h>
+#include <osmocom/vty.h>
extern void *l23_ctx;
static void gsm322_cs_timeout(void *arg);
+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);
-
-//#define SINGLE
-
-#ifdef SINGLE
-#warning HACK to stay on one channel
-static int already = 0;
-int l1ctl_tx_ccch_req_(struct osmocom_ms *ms, uint16_t arfcn)
-{
-
- if (!already) {
- already = 1;
- return l1ctl_tx_ccch_req(ms, arfcn);
- }
- ms->cellsel.ccch_sync = 1;
- return 0;
-}
-#else
-#define l1ctl_tx_ccch_req_ l1ctl_tx_ccch_req
-#endif
+#warning HACKING!!!
+int hack;
/*
* notes
* - cs->selected and cs->sel_* states of the current / last selected cell.
*
*
- * There is a special state: GSM322_HPLMN_SEARCH
+ * There is a special state: GSM322_PLMN_SEARCH
* It is used to search for all cells, to find the HPLMN. This is triggered
- * by a timer.
+ * by a timer. Also it is used before selecting PLMN from list.
*
*/
{ GSM322_EVENT_REG_SUCCESS, "EVENT_REG_SUCCESS" },
{ GSM322_EVENT_NEW_PLMN, "EVENT_NEW_PLMN" },
{ GSM322_EVENT_ON_PLMN, "EVENT_ON_PLMN" },
- { GSM322_EVENT_HPLMN_SEARCH, "EVENT_HPLMN_SEARCH" },
- { GSM322_EVENT_HPLMN_FOUND, "EVENT_HPLMN_FOUND" },
- { GSM322_EVENT_HPLMN_NOT_FOUND, "EVENT_HPLMN_NOT_FOUND" },
+ { GSM322_EVENT_PLMN_SEARCH_START,"EVENT_PLMN_SEARCH_START" },
+ { GSM322_EVENT_PLMN_SEARCH_END, "EVENT_PLMN_SEARCH_END" },
{ GSM322_EVENT_USER_RESEL, "EVENT_USER_RESEL" },
{ GSM322_EVENT_PLMN_AVAIL, "EVENT_PLMN_AVAIL" },
{ GSM322_EVENT_CHOSE_PLMN, "EVENT_CHOSE_PLMN" },
{ GSM322_EVENT_RET_IDLE, "EVENT_RET_IDLE" },
{ GSM322_EVENT_CELL_RESEL, "EVENT_CELL_RESEL" },
{ GSM322_EVENT_SYSINFO, "EVENT_SYSINFO" },
+ { GSM322_EVENT_HPLMN_SEARCH, "EVENT_HPLMN_SEARCH" },
{ 0, NULL }
};
* support
*/
-/* del forbidden PLMN */
-int gsm322_del_forbidden_plmn(struct osmocom_ms *ms, uint16_t mcc,
- uint16_t mnc)
+static int gsm322_sync_to_cell(struct gsm322_cellsel *cs)
{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm_sub_plmn_na *na;
+ struct osmocom_ms *ms = cs->ms;
+ struct gsm48_sysinfo *s = cs->si;
- llist_for_each_entry(na, &subscr->plmn_na, entry) {
- if (na->mcc == mcc && na->mnc == mnc) {
- LOGP(DPLMN, LOGL_INFO, "Delete from list of forbidden "
- "PLMNs (mcc=%03d, mnc=%02d)\n", mcc, mnc);
- llist_del(&na->entry);
- talloc_free(na);
-#ifdef TODO
- update plmn not allowed list on sim
-#endif
- return 0;
+ 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);
- return -EINVAL;
+ 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);
}
-/* add forbidden PLMN */
-int gsm322_add_forbidden_plmn(struct osmocom_ms *ms, uint16_t mcc,
- uint16_t mnc, uint8_t cause)
+static void gsm322_unselect_cell(struct gsm322_cellsel *cs)
{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm_sub_plmn_na *na;
-
- /* don't add Home PLMN */
- if (subscr->sim_valid && mcc == subscr->mcc && mnc == subscr->mnc)
- return -EINVAL;
-
- LOGP(DPLMN, LOGL_INFO, "Add to list of forbidden PLMNs "
- "(mcc=%03d, mnc=%02d)\n", mcc, mnc);
- na = talloc_zero(l23_ctx, struct gsm_sub_plmn_na);
- if (!na)
- return -ENOMEM;
- na->mcc = mcc;
- na->mnc = mnc;
- na->cause = cause;
- llist_add_tail(&na->entry, &subscr->plmn_na);
-
-#ifdef TODO
- update plmn not allowed list on sim
-#endif
-
- return 0;
+ 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;
}
-/* search forbidden PLMN */
-int gsm322_is_forbidden_plmn(struct osmocom_ms *ms, uint16_t mcc, uint16_t mnc)
+/* print to DCS logging */
+static void print_dcs(void *priv, const char *fmt, ...)
{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm_sub_plmn_na *na;
+ char buffer[1000];
+ va_list args;
- llist_for_each_entry(na, &subscr->plmn_na, entry) {
- if (na->mcc == mcc && na->mnc == mnc)
- return 1;
- }
+ va_start(args, fmt);
+ vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
+ buffer[sizeof(buffer) - 1] = '\0';
+ va_end(args);
- return 0;
+ if (buffer[0])
+// LOGP(DCS, LOGL_INFO, "%s", buffer);
+ printf("%s", buffer);
}
/* del forbidden LA */
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;
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;
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
}
/* start cell selection timer */
-static void start_cs_timer(struct gsm322_cellsel *cs, int sec, int micro)
+void start_cs_timer(struct gsm322_cellsel *cs, int sec, int micro)
{
LOGP(DCS, LOGL_INFO, "Starting CS timer with %d seconds.\n", sec);
cs->timer.cb = gsm322_cs_timeout;
bsc_schedule_timer(&cs->timer, sec, micro);
}
+/* start loss timer */
+void start_loss_timer(struct gsm322_cellsel *cs, int sec, int micro)
+{
+ /* update timer */
+ cs->timer.cb = gsm322_cs_loss;
+ cs->timer.data = cs;
+ if (bsc_timer_pending(&cs->timer)) {
+ struct timeval current_time;
+ unsigned long long currentTime;
+
+ gettimeofday(¤t_time, NULL);
+ currentTime = current_time.tv_sec * 1000000LL
+ + current_time.tv_usec;
+ currentTime += sec * 1000000LL + micro;
+ cs->timer.timeout.tv_sec = currentTime / 1000000LL;
+ cs->timer.timeout.tv_usec = currentTime % 1000000LL;
+
+ return;
+ }
+
+ LOGP(DCS, LOGL_INFO, "Starting loss CS timer with %d seconds.\n", sec);
+ bsc_schedule_timer(&cs->timer, sec, micro);
+}
+
/* stop cell selection timer */
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[] = {
- "M1_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",
- "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;
}
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;
/* 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;
}
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;
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 */
found = NULL;
llist_for_each_entry(temp, &temp_list, entry) {
if (temp->mcc == cs->list[i].sysinfo->mcc
- && temp->mnc == cs->list[i].sysinfo->mnc)
+ && temp->mnc == cs->list[i].sysinfo->mnc) {
found = temp;
break;
+ }
}
/* update or create */
if (found) {
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;
}
/* move */
llist_del(&found->entry);
llist_add_tail(&found->entry, &plmn->sorted_plmn);
- } 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);
}
}
break;
}
}
- LOGP(DPLMN, LOGL_INFO, "Crating Sorted PLMN list. "
- "(%02d: mcc=%03d mnc=%02d allowed=%s rx-lev=%d)\n",
- i, temp->mcc, temp->mnc, (temp->cause) ? "no ":"yes",
+ LOGP(DPLMN, LOGL_INFO, "Creating Sorted PLMN list. "
+ "(%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++;
}
struct gsm322_plmn *plmn = &ms->plmn;
struct gsm_subscriber *subscr = &ms->subscr;
- /* set last registered PLMN */
- subscr->plmn_valid = 1;
- subscr->plmn_mcc = plmn->mcc;
- subscr->plmn_mnc = plmn->mnc;
-#ifdef TODO
- store on sim
-#endif
-
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
/* indicate selected PLMN */
static int gsm322_a_indicate_selected(struct osmocom_ms *ms, struct msgb *msg)
{
-#ifdef TODO
- indicate selected plmn to user
-#endif
+ 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));
return gsm322_a_go_on_plmn(ms, msg);
}
{
struct gsm322_plmn *plmn = &ms->plmn;
struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm_subscriber *subscr = &ms->subscr;
struct msgb *nmsg;
int found;
/* 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);
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 */
static int gsm322_a_sel_first_plmn(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm322_plmn *plmn = &ms->plmn;
+ struct gsm_subscriber *subscr = &ms->subscr;
struct msgb *nmsg;
struct gsm322_plmn_list *plmn_entry;
struct gsm322_plmn_list *plmn_first = NULL;
/* select first entry */
i = 0;
llist_for_each_entry(plmn_entry, &plmn->sorted_plmn, entry) {
- /* if RPLMN is HPLMN, we skip that */
- if (plmn->state == GSM322_A1_TRYING_RPLMN
+ /* if last selected PLMN was HPLMN, we skip that */
+ 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 "
+ "previously selected.\n");
i++;
continue;
}
plmn_first = plmn_entry;
break;
}
+ LOGP(DPLMN, LOGL_INFO, "Skip PLMN (%02d: mcc=%03d), because it "
+ "not allowed (cause %d).\n", plmn_entry->mcc,
+ plmn_entry->mnc, plmn_entry->cause);
i++;
}
plmn->plmn_curr = i;
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 */
plmn_next = plmn_entry;
break;
}
+ LOGP(DPLMN, LOGL_INFO, "Skip PLMN (%02d: mcc=%03d), because it "
+ "not allowed (cause %d).\n", plmn_entry->mcc,
+ plmn_entry->mnc, plmn_entry->cause);
i++;
}
plmn->plmn_curr = i;
}
- 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 */
}
/* User re-selection event */
-static int gsm322_a_user_reselection(struct osmocom_ms *ms, struct msgb *msg)
+static int gsm322_a_user_resel(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm322_plmn *plmn = &ms->plmn;
+ struct gsm_subscriber *subscr = &ms->subscr;
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm322_plmn_list *plmn_entry;
struct gsm322_plmn_list *plmn_found = NULL;
+ if (!subscr->sim_valid) {
+ return 0;
+ }
+
+ /* try again later, if not idle */
+ if (rr->state != GSM48_RR_ST_IDLE) {
+ LOGP(DPLMN, LOGL_INFO, "Not idle, rejecting.\n");
+
+ return 0;
+ }
+
/* search current PLMN in list */
llist_for_each_entry(plmn_entry, &plmn->sorted_plmn, entry) {
if (plmn_entry->mcc == plmn->mcc
/* 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 */
/* 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));
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);
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);
return 0;
}
- /* select first PLMN in list */
- return gsm322_a_sel_first_plmn(ms, 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);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_cs_sendmsg(ms, nmsg);
+
+ return 0;
}
/* MS is switched off */
}
/* On VPLMN of home country and timeout occurs */
-static int gsm322_a_hplmn_search(struct osmocom_ms *ms, struct msgb *msg)
+static int gsm322_a_hplmn_search_start(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm322_plmn *plmn = &ms->plmn;
new_a_state(plmn, GSM322_A5_HPLMN_SEARCH);
/* initiate search at cell selection */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_HPLMN_SEARCH);
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_PLMN_SEARCH_START);
if (!nmsg)
return -ENOMEM;
gsm322_cs_sendmsg(ms, nmsg);
/* 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);
* handler for manual search
*/
-/* go Not on PLMN state */
-static int gsm322_m_go_not_on_plmn(struct osmocom_ms *ms, struct msgb *msg)
+/* 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, 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;
+ }
+
+ 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 */
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)
+/* user starts reselection */
+static int gsm322_m_user_resel(struct osmocom_ms *ms, struct msgb *msg)
{
- /* generate list */
- gsm322_sort_list(ms);
+ struct gsm_subscriber *subscr = &ms->subscr;
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct msgb *nmsg;
-#ifdef TODO
- display PLMNs to user
-#endif
-
- /* go Not on PLMN state */
- return gsm322_m_go_not_on_plmn(ms, msg);
+ if (!subscr->sim_valid) {
+ return 0;
+ }
+
+ /* try again later, if not idle */
+ if (rr->state != GSM48_RR_ST_IDLE) {
+ LOGP(DPLMN, LOGL_INFO, "Not idle, rejecting.\n");
+
+ return 0;
+ }
+
+ /* 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");
+
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_PLMN_SEARCH_START);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_cs_sendmsg(ms, nmsg);
+
+ return 0;
}
/* MS is switched on OR SIM is inserted OR removed */
{
struct gsm_subscriber *subscr = &ms->subscr;
struct gsm322_plmn *plmn = &ms->plmn;
+ 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);
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);
return 0;
}
- /* display PLMNs */
- return gsm322_m_display_plmns(ms, 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);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_cs_sendmsg(ms, nmsg);
+
+ return 0;
}
/* MS is switched off */
struct gsm_subscriber *subscr = &ms->subscr;
/* if selected PLMN is in list of forbidden PLMNs */
- gsm322_del_forbidden_plmn(ms, plmn->mcc, plmn->mnc);
+ gsm_subscr_del_forbidden_plmn(subscr, plmn->mcc, plmn->mnc);
/* set last registered PLMN */
subscr->plmn_valid = 1;
/* indicate selected PLMN */
static int gsm322_m_indicate_selected(struct osmocom_ms *ms, struct msgb *msg)
{
-#ifdef TODO
- indicate selected plmn to user
-#endif
+ 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));
return gsm322_m_go_on_plmn(ms, msg);
}
plmn->mcc = gm->mcc;
plmn->mnc = gm->mnc;
- LOGP(DPLMN, LOGL_INFO, "User selects PLMN. (mcc=%03d mnc=%02d "
- "%s, %s)\n", plmn->mcc, plmn->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=%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);
/* 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);
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 */
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;
}
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 */
/* 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++) {
cs->scan_state = weight;
if (!weight)
- gsm322_dump_cs_list(ms, GSM322_CS_FLAG_SYSINFO);
+ gsm322_dump_cs_list(cs, GSM322_CS_FLAG_SYSINFO, print_dcs,
+ NULL);
- /* special negative case for HPLMN search */
+ /* special case for PLMN search */
+ if (cs->state == GSM322_PLMN_SEARCH && !weight) {
+ struct msgb *nmsg;
+
+ /* create AA flag */
+ cs->mcc = cs->mnc = 0;
+ gsm322_cs_select(ms, 0);
+
+ new_c_state(cs, GSM322_C0_NULL);
+
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_PLMN_SEARCH_END);
+ LOGP(DCS, LOGL_INFO, "PLMN search finished.\n");
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_plmn_sendmsg(ms, nmsg);
+
+ return 0;
+ }
+
+ /* special case for HPLMN search */
if (cs->state == GSM322_HPLMN_SEARCH && !weight) {
struct msgb *nmsg;
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_HPLMN_NOT_FOUND);
- LOGP(DCS, LOGL_INFO, "No HPLMN cell available.\n");
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_NO_CELL_FOUND);
+ LOGP(DCS, LOGL_INFO, "HPLMN search finished, no cell.\n");
if (!nmsg)
return -ENOMEM;
gsm322_plmn_sendmsg(ms, nmsg);
- /* re-tune back to current VPLMN */
- cs->ccch_sync = 0;
- l1ctl_tx_ccch_req_(ms, cs->arfcn);
+ new_c_state(cs, GSM322_C3_CAMPED_NORMALLY);
+
+ 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);
+ hack = 5;
+ gsm322_sync_to_cell(cs);
+// start_cs_timer(cs, ms->support.sync_to, 0);
return 0;
}
/* tune */
cs->arfcn = found;
cs->si = cs->list[cs->arfcn].sysinfo;
- cs->ccch_sync = 0;
- 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 */
} 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");
cs->arfcn = weight & 1023;
LOGP(DCS, LOGL_INFO, "Scanning frequency %d (rxlev %d).\n", cs->arfcn,
cs->list[cs->arfcn].rxlev_db);
- cs->ccch_sync = 0;
- l1ctl_tx_ccch_req_(ms, cs->arfcn);
-// cs->tune_retry = 0;
- 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;
if (cs->list[cs->arfcn].sysinfo)
memset(cs->list[cs->arfcn].sysinfo, 0,
sizeof(struct gsm48_sysinfo));
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;
}
static int gsm322_cs_store(struct osmocom_ms *ms)
{
struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm_subscriber *subscr = &ms->subscr;
struct gsm48_sysinfo *s = cs->si;
struct gsm322_plmn *plmn = &ms->plmn;
struct msgb *nmsg;
&& cs->state != GSM322_C8_ANY_CELL_RESEL
&& cs->state != GSM322_C5_CHOOSE_CELL
&& cs->state != GSM322_C9_CHOOSE_ANY_CELL
+ && cs->state != GSM322_PLMN_SEARCH
&& cs->state != GSM322_HPLMN_SEARCH) {
LOGP(DCS, LOGL_FATAL, "This must only happen during cell "
"(re-)selection, please fix!\n");
/* store sysinfo */
cs->list[cs->arfcn].flags |= GSM322_CS_FLAG_SYSINFO;
- if (s->cell_barr)
+ if (s->cell_barr
+ && !(cs->list[cs->arfcn].sysinfo && cs->list[cs->arfcn].sysinfo->sp &&
+ cs->list[cs->arfcn].sysinfo->sp_cbq))
cs->list[cs->arfcn].flags |= GSM322_CS_FLAG_BARRED;
else
cs->list[cs->arfcn].flags &= ~GSM322_CS_FLAG_BARRED;
}
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);
-
- /* special prositive case for HPLMN search */
- if (cs->state == GSM322_HPLMN_SEARCH && s->mcc == subscr->mcc
- && s->mnc == subscr->mnc) {
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_HPLMN_FOUND);
- LOGP(DCS, LOGL_INFO, "HPLMN cell available.\n");
+ "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)
+ /* tune to next cell */
+ return gsm322_cs_scan(ms);
+
+ /* special case for HPLMN search */
+ if (cs->state == GSM322_HPLMN_SEARCH) {
+ struct gsm_subscriber *subscr = &ms->subscr;
+ struct msgb *nmsg;
+
+ if (!gsm322_is_hplmn_avail(cs, subscr->imsi))
+ /* tune to next cell */
+ return gsm322_cs_scan(ms);
+
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_CELL_FOUND);
+ LOGP(DCS, LOGL_INFO, "HPLMN search finished, cell found.\n");
if (!nmsg)
return -ENOMEM;
gsm322_plmn_sendmsg(ms, nmsg);
/* tune */
cs->arfcn = found;
cs->si = cs->list[cs->arfcn].sysinfo;
- cs->ccch_sync = 0;
- 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);
&& 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);
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));
}
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));
}
/* 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,
LOGP(DCS, LOGL_INFO, "Sysinfo of selected cell is "
"updated.\n");
memcpy(&cs->sel_si, s, sizeof(cs->sel_si));
- gsm48_sysinfo_dump(ms, s);
+ //gsm48_sysinfo_dump(s, print_dcs, NULL);
}
}
/* check for barred cell */
if (gm->sysinfo == GSM48_MT_RR_SYSINFO_1) {
/* check if cell becomes barred */
- if (!subscr->acc_barr && s->cell_barr) {
+ if (!subscr->acc_barr && s->cell_barr
+ && !(cs->list[cs->arfcn].sysinfo
+ && cs->list[cs->arfcn].sysinfo->sp
+ && cs->list[cs->arfcn].sysinfo->sp_cbq)) {
LOGP(DCS, LOGL_INFO, "Cell becomes barred.\n");
trigger_resel:
/* mark cell as unscanned */
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
/* stop timer */
stop_cs_timer(cs);
- gsm48_sysinfo_dump(ms, s);
+ //gsm48_sysinfo_dump(s, print_dcs, NULL);
/* store sysinfo and continue scan */
return gsm322_cs_store(ms);
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_sync) {
-#if 0
- if (++cs->tune_retry < 4) {
- LOGP(DCS, LOGL_INFO, "No lock, retrying frequency %d.\n", cs->arfcn);
- start_cs_timer(cs, ms->support.sync_to, 0);
- l1ctl_tx_ccch_req_(ms, cs->arfcn);
- return;
- }
- LOGP(DCS, LOGL_INFO, "No lock, after trying %d times.\n", cs->tune_retry);
-#else
+ if (cs->ccch_state != GSM322_CCCH_ST_SYNC)
LOGP(DCS, LOGL_INFO, "Sync timeout.\n");
-#endif
- } else
+ else
LOGP(DCS, LOGL_INFO, "Read timeout.\n");
LOGP(DCS, LOGL_INFO, "Scan frequency %d: Cell not found. (rxlev=%d)\n",
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 */
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;
+ }
}
}
-#ifdef SINGLE
-#warning testing
-if (already) s = -1;
-#endif
-#if 0
-cs->list[ms->test_arfcn].rxlev_db = -50;
-cs->list[ms->test_arfcn].flags |= GSM322_CS_FLAG_POWER;
-cs->list[ms->test_arfcn].flags |= GSM322_CS_FLAG_SIGNAL;
-s = -1;
-#endif
-
/* if there is no more frequency, we can tune to that cell */
if (s < 0) {
int found = 0;
cs->list[i].sysinfo = NULL;
}
}
+ /* no cell selected */
+ gsm322_unselect_cell(cs);
goto again;
}
/* on other cell selection, indicate "no cell found" */
* If we would continue to process CS, then we might get
* our list of scanned cells disturbed.
*/
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_NO_CELL_FOUND);
+ if (cs->state == GSM322_PLMN_SEARCH)
+ nmsg = gsm322_msgb_alloc(
+ GSM322_EVENT_PLMN_SEARCH_END);
+ else
+ nmsg = gsm322_msgb_alloc(
+ GSM322_EVENT_NO_CELL_FOUND);
if (!nmsg)
return -ENOMEM;
gsm322_plmn_sendmsg(ms, nmsg);
+ /* if HPLMN search, select last frequency */
+ if (cs->state == GSM322_HPLMN_SEARCH) {
+ new_c_state(cs, GSM322_C3_CAMPED_NORMALLY);
+
+ 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);
+ hack = 5;
+ gsm322_sync_to_cell(cs);
+// start_cs_timer(cs, ms->support.sync_to, 0);
+
+ } else
+ new_c_state(cs, GSM322_C0_NULL);
+
return 0;
}
LOGP(DCS, LOGL_INFO, "Found %d frequencies.\n", found);
/* 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);
}
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);
return -EINVAL;
gsm322_cs_powerscan(ms);
break;
- case S_L1CTL_CCCH_RESP:
+ case S_L1CTL_FBSB_RESP:
ms = signal_data;
cs = &ms->cellsel;
- if (!cs->ccch_sync) {
- LOGP(DCS, LOGL_INFO, "Channel activated.\n");
+ if (cs->ccch_state == GSM322_CCCH_ST_INIT) {
+ LOGP(DCS, LOGL_INFO, "Channel synched.\n");
+ cs->ccch_state = GSM322_CCCH_ST_SYNC;
+#if 0
stop_cs_timer(cs);
- cs->ccch_sync = 1;
/* 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
|| cs->state == GSM322_C8_ANY_CELL_RESEL
|| cs->state == GSM322_C5_CHOOSE_CELL
|| cs->state == GSM322_C9_CHOOSE_ANY_CELL
+ || cs->state == GSM322_PLMN_SEARCH
|| cs->state == GSM322_HPLMN_SEARCH)
start_cs_timer(cs, ms->support.scan_to, 0);
// TODO: timer depends on BCCH config
}
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;
}
+static void gsm322_cs_loss(void *arg)
+{
+ struct gsm322_cellsel *cs = arg;
+ struct osmocom_ms *ms = cs->ms;
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+
+ 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) {
+ struct msgb *nmsg;
+
+ LOGP(DCS, LOGL_INFO, "Trigger re-selection.\n");
+
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_CELL_RESEL);
+ if (!nmsg)
+ return;
+ gsm322_c_event(ms, nmsg);
+ 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.
+ */
+ }
+ }
+
+ return;
+}
+
/*
* handler for cell selection process
*/
+/* start PLMN search */
+static int gsm322_c_plmn_search(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm322_cellsel *cs = &ms->cellsel;
+ int i;
+
+ new_c_state(cs, GSM322_PLMN_SEARCH);
+
+ /* mark all frequencies except our own BA to be scanned */
+ for (i = 0; i <= 1023; i++) {
+ cs->list[i].flags &= ~(GSM322_CS_FLAG_POWER
+ | GSM322_CS_FLAG_SIGNAL
+ | GSM322_CS_FLAG_SYSINFO);
+ if (cs->list[i].sysinfo) {
+ 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 */
+ gsm322_unselect_cell(cs);
+
+ /* start power scan */
+ return gsm322_cs_powerscan(ms);
+}
+
/* start HPLMN search */
static int gsm322_c_hplmn_search(struct osmocom_ms *ms, struct msgb *msg)
{
/* mark all frequencies except our own BA to be scanned */
for (i = 0; i <= 1023; i++) {
- if ((cs->list[i].flags & GSM322_CS_FLAG_SYSINFO)
+ if (i != cs->sel_arfcn
+ && (cs->list[i].flags & GSM322_CS_FLAG_SYSINFO)
&& !(cs->list[i].flags & GSM322_CS_FLAG_BA)) {
cs->list[i].flags &= ~(GSM322_CS_FLAG_POWER
| GSM322_CS_FLAG_SIGNAL
}
}
- /* 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;
+ /* no cell selected */
+ gsm322_unselect_cell(cs);
/* start power scan */
return gsm322_cs_powerscan(ms);
}
/* 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);
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);
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 selection, power scan again */
- if (cs->state == GSM322_C6_ANY_CELL_SEL) {
- 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);
+ /* in case we already tried any cell (re-)selection, power scan again */
+ if (cs->state == GSM322_C0_NULL
+ || cs->state == GSM322_C6_ANY_CELL_SEL
+ || cs->state == GSM322_C8_ANY_CELL_RESEL) {
+ int i;
for (i = 0; i <= 1023; i++) {
cs->list[i].flags &= ~(GSM322_CS_FLAG_POWER
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);
}
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);
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;
/* 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
}
/* 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);
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);
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)
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)
/* be sure to go to current camping frequency on return */
LOGP(DCS, LOGL_INFO, "Going to camping frequency %d.\n", cs->arfcn);
- cs->ccch_sync = 0;
- 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;
}
/* be sure to go to current camping frequency on return */
LOGP(DCS, LOGL_INFO, "Going to camping frequency %d.\n", cs->arfcn);
- cs->ccch_sync = 0;
- l1ctl_tx_ccch_req_(ms, cs->arfcn);
+ hack = 5;
+ gsm322_sync_to_cell(cs);
cs->si = cs->list[cs->arfcn].sysinfo;
return 0;
} 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},
+ 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_reselection},
+ 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_HPLMN_FOUND, gsm322_a_sel_first_plmn},
+ GSM322_EVENT_CELL_FOUND, gsm322_a_sel_first_plmn},
+
{SBIT(GSM322_A5_HPLMN_SEARCH),
- GSM322_EVENT_HPLMN_NOT_FOUND, gsm322_a_go_on_plmn},
+ 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},
};
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++)
} 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_M2_ON_PLMN),
- GSM322_EVENT_USER_RESEL, gsm322_m_display_plmns},
+
+ {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_go_not_on_plmn},
+ GSM322_EVENT_REG_FAILED, gsm322_m_display_plmns},
+
{SBIT(GSM322_M4_TRYING_PLMN),
- GSM322_EVENT_NO_CELL_FOUND, 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_display_plmns},
+
{ALL_STATES,
GSM322_EVENT_SEL_AUTO, gsm322_m_sel_auto},
+
{ALL_STATES,
GSM322_EVENT_NO_CELL_FOUND, gsm322_am_no_cell_found},
};
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++)
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);
} 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_HPLMN_SEARCH),
+ 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}
+ GSM322_EVENT_HPLMN_SEARCH, gsm322_c_hplmn_search},
};
#define CELLSELSLLEN \
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++)
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);
}
return 0;
}
-int gsm322_dump_cs_list(struct osmocom_ms *ms, uint8_t flags)
+int gsm322_dump_cs_list(struct gsm322_cellsel *cs, uint8_t flags,
+ void (*print)(void *, const char *, ...), void *priv)
{
- struct gsm322_cellsel *cs = &ms->cellsel;
- int i, j;
+ int i;
struct gsm48_sysinfo *s;
- printf("rx-lev |MCC |MNC |forb.LA|barred,0123456789abcdef|"
- "min-db |max-pwr\n"
- "-------+-------+-------+-------+-----------------------+"
- "-------+-------\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;
- printf("%4d |", cs->list[i].rxlev_db);
+ print(priv, "%4d |%4d |", i, cs->list[i].rxlev_db);
if ((cs->list[i].flags & GSM322_CS_FLAG_SYSINFO)) {
- printf("%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))
- printf("yes |");
+ print(priv, "yes |");
else
- printf("no |");
+ print(priv, "no |");
if ((cs->list[i].flags & GSM322_CS_FLAG_BARRED))
- printf("yes ");
- else
- printf("no ");
- for (j = 0; j < 16; j++) {
- if ((s->class_barr & (1 << j)))
- printf("*");
+ print(priv, "barred |");
+ else {
+ if (cs->list[i].sysinfo->cell_barr)
+ print(priv, "low |");
else
- printf(" ");
+ print(priv, "normal |");
}
- printf("|%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
- printf("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_sim_plmn(struct osmocom_ms *ms)
+int gsm322_dump_forbidden_la(struct osmocom_ms *ms,
+ void (*print)(void *, const char *, ...), void *priv)
{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm_sub_plmn_list *temp;
-
- printf("MCC |MNC\n");
- printf("-------+-------\n");
- llist_for_each_entry(temp, &subscr->plmn_list, entry)
- printf("%03d |%02d\n", temp->mcc, temp->mnc);
-
- return 0;
-}
-
-int gsm322_dump_forbidden_plmn(struct osmocom_ms *ms)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm_sub_plmn_na *temp;
+ struct gsm322_plmn *plmn = &ms->plmn;
+ struct gsm322_la_list *temp;
- printf("MCC |MNC |cause\n");
- printf("-------+-------+-------\n");
- llist_for_each_entry(temp, &subscr->plmn_na, entry)
- printf("%03d |%02d |#%d\n", temp->mcc, temp->mnc,
- temp->cause);
+ print(priv, "MCC |MNC |LAC |cause\n");
+ print(priv, "-------+-------+-------+-------\n");
+ llist_for_each_entry(temp, &plmn->forbidden_la, entry)
+ 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;
}
-int gsm322_dump_forbidden_la(struct osmocom_ms *ms)
+int gsm322_dump_ba_list(struct gsm322_cellsel *cs, uint16_t mcc, uint16_t mnc,
+ void (*print)(void *, const char *, ...), void *priv)
{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm322_la_list *temp;
+ struct gsm322_ba_list *ba;
+ int i;
- printf("MCC |MNC |LAC |cause\n");
- printf("-------+-------+-------+-------\n");
- llist_for_each_entry(temp, &plmn->forbidden_la, entry)
- printf("%03d |%02d |0x%04x |#%d\n", temp->mcc, temp->mnc,
- temp->lac, temp->cause);
+ llist_for_each_entry(ba, &cs->ba_list, entry) {
+ if (mcc && mnc && (mcc != ba->mcc || mnc != ba->mnc))
+ continue;
+ print(priv, "Band Allocation of network: MCC %03d MNC %02d "
+ "(%s, %s)\n", ba->mcc, ba->mnc, gsm_get_mcc(ba->mcc),
+ gsm_get_mnc(ba->mcc, ba->mnc));
+ for (i = 0; i <= 1023; i++) {
+ if ((ba->freq[i >> 3] & (1 << (i & 7))))
+ print(priv, " %d", i);
+ }
+ print(priv, "\n");
+ }
return 0;
}
/* 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);
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);
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);