#include <osmocom/file.h>
#include <osmocom/osmocom_data.h>
#include <osmocom/networks.h>
+#include <osmocom/telnet_interface.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);
+#warning HACKING!!!
+int hack;
+
/*
* notes
*/
* if the cell is 'suitable' and 'allowable' to 'camp' on.
*
* This list is also used to generate a list of available networks.
+ *
+ * The states are:
+ *
+ * - cs->list[0..1023].xxx for each cell, where
+ * - flags and rxlev_db are used to store outcome of cell scanning process
+ * - sysinfo pointing to sysinfo memory, allocated temporarily
+ * - cs->selected and cs->sel_* states of the current / last selected cell.
+ *
+ *
+ * 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. Also it is used before selecting PLMN from list.
+ *
*/
/* PLMN selection process
{ 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 osmocom_ms *ms, struct gsm322_cellsel *cs)
{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm_sub_plmn_na *na;
-
- 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;
- }
- }
-
- return -EINVAL;
+ return l1ctl_tx_fbsb_req(ms, cs->arfcn,
+ L1CTL_FBSB_F_FB01SB, 100, 0,
+ CCCH_MODE_COMBINED);
}
-/* 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 ba_found;
}
+/* search available PLMN */
+int gsm322_is_plmn_avail(struct gsm322_cellsel *cs, uint16_t mcc, uint16_t mnc)
+{
+ int i;
+
+ for (i = 0; i <= 1023; i++) {
+ if (cs->list[i].sysinfo
+ && cs->list[i].sysinfo->mcc == mcc
+ && cs->list[i].sysinfo->mnc == mnc)
+ return 1;
+ }
+
+ 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 */
/* Create a temporary list of all networks */
INIT_LLIST_HEAD(&temp_list);
for (i = 0; i <= 1023; i++) {
- if (!(cs->list[i].flags & GSM322_CS_FLAG_TEMP_AA))
+ if (!(cs->list[i].flags & GSM322_CS_FLAG_TEMP_AA)
+ || !cs->list[i].sysinfo)
continue;
/* search if network has multiple cells */
found = NULL;
llist_for_each_entry(temp, &temp_list, entry) {
- if (temp->mcc == cs->list[i].mcc
- && temp->mnc == cs->list[i].mnc)
+ if (temp->mcc == cs->list[i].sysinfo->mcc
+ && temp->mnc == cs->list[i].sysinfo->mnc) {
found = temp;
break;
+ }
}
/* update or create */
if (found) {
temp = talloc_zero(l23_ctx, struct gsm322_plmn_list);
if (!temp)
return -ENOMEM;
- temp->mcc = cs->list[i].mcc;
- temp->mnc = cs->list[i].mnc;
+ temp->mcc = cs->list[i].sysinfo->mcc;
+ temp->mnc = cs->list[i].sysinfo->mnc;
temp->rxlev_db = cs->list[i].rxlev_db;
llist_add_tail(&temp->entry, &temp_list);
}
}
- /* move Home PLMN, if in list */
+ /* move Home PLMN, if in list, else add it */
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;
}
}
if (found) {
+ /* move */
llist_del(&found->entry);
llist_add_tail(&found->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++;
}
+ gsm322_dump_sorted_plmn(ms);
+
return 0;
}
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;
- /* any PLMN available */
+ /* any allowable PLMN available? */
+ plmn->mcc = plmn->mnc = 0;
found = gsm322_cs_select(ms, 0);
/* 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);
}
/* select first PLMN in list */
- plmn->mcc = cs->list[found].mcc;
- plmn->mnc = cs->list[found].mnc;
+ 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 */
struct gsm322_plmn *plmn = &ms->plmn;
struct gsm322_cellsel *cs = &ms->cellsel;
int found;
+ struct msgb *nmsg;
/* any PLMN available */
found = gsm322_cs_select(ms, 0);
/* if PLMN in list */
if (found >= 0) {
- LOGP(DPLMN, LOGL_INFO, "PLMN available (mcc=%03d mnc=%02d "
- "%s, %s)\n", cs->list[found].mcc, cs->list[found].mnc,
- gsm_get_mcc(cs->list[found].mcc),
- gsm_get_mnc(cs->list[found].mcc, cs->list[found].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));
return gsm322_a_sel_first_plmn(ms, msg);
}
new_a_state(plmn, GSM322_A4_WAIT_FOR_PLMN);
+ /* Tell cell selection process to handle "no cell found". */
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_NO_CELL_FOUND);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_cs_sendmsg(ms, nmsg);
+
return 0;
}
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 */
return 0;
}
+static int gsm322_a_sim_insert(struct osmocom_ms *ms, struct msgb *msg)
+{
+ LOGP(DPLMN, LOGL_INFO, "SIM already inserted when switched on.\n");
+ return 0;
+}
+
/* SIM is removed */
static int gsm322_a_sim_removed(struct osmocom_ms *ms, struct msgb *msg)
{
}
/* 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;
struct gsm322_cellsel *cs = &ms->cellsel;
struct msgb *nmsg;
- /* try again later, if not idle */
- if (cs->state != GSM322_C3_CAMPED_NORMALLY) {
- LOGP(DPLMN, LOGL_INFO, "Not camping normal, wait some more.\n");
+ /* try again later, if not idle and not camping */
+ if (rr->state != GSM48_RR_ST_IDLE
+ || cs->state != GSM322_C3_CAMPED_NORMALLY) {
+ LOGP(DPLMN, LOGL_INFO, "Not camping, wait some more.\n");
start_plmn_timer(plmn, 60);
return 0;
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);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm48_mmevent_msg(ms, nmsg);
+
return 0;
}
* 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);
/* if there is a registered PLMN */
if (subscr->plmn_valid) {
+ struct msgb *nmsg;
+
/* select the registered PLMN */
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);
+ /* indicate New PLMN */
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_NEW_PLMN);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_cs_sendmsg(ms, nmsg);
+
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 */
return 0;
}
+static int gsm322_m_sim_insert(struct osmocom_ms *ms, struct msgb *msg)
+{
+ LOGP(DPLMN, LOGL_INFO, "SIM already inserted when switched on.\n");
+ return 0;
+}
+
/* SIM is removed */
static int gsm322_m_sim_removed(struct osmocom_ms *ms, struct msgb *msg)
{
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);
}
static int gsm322_m_plmn_avail(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm322_plmn *plmn = &ms->plmn;
+ struct gsm322_cellsel *cs = &ms->cellsel;
new_m_state(plmn, GSM322_M1_TRYING_RPLMN);
+ if (cs->mcc != plmn->mcc || cs->mnc != plmn->mnc) {
+ struct msgb *nmsg;
+
+ LOGP(DPLMN, LOGL_INFO, "PLMN available, but currently not "
+ "selected, so start selection.\n");
+
+ /* indicate New PLMN */
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_NEW_PLMN);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_cs_sendmsg(ms, nmsg);
+ }
+
return 0;
}
{
struct gsm322_plmn *plmn = &ms->plmn;
struct gsm322_msg *gm = (struct gsm322_msg *) msg->data;
+ struct msgb *nmsg;
/* use user selection */
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);
+ /* indicate New PLMN */
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_NEW_PLMN);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_cs_sendmsg(ms, nmsg);
+
return 0;
}
/* 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);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm48_mmevent_msg(ms, nmsg);
+
return 0;
}
{
struct gsm322_cellsel *cs = &ms->cellsel;
struct gsm_subscriber *subscr = &ms->subscr;
+ struct gsm48_sysinfo *s;
int i, found = -1, power = 0;
uint8_t flags, mask;
uint16_t acc_class;
/* set out access class depending on the cell selection type */
if (any) {
acc_class = subscr->acc_class | 0x0400; /* add emergency */
- LOGP(DCS, LOGL_INFO, "Using access class with Emergency "
+ 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, "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 */
/* loop through all scanned frequencies and select cell */
for (i = 0; i <= 1023; i++) {
cs->list[i].flags &= ~GSM322_CS_FLAG_TEMP_AA;
+ s = cs->list[i].sysinfo;
/* channel has no informations for us */
- if ((cs->list[i].flags & mask) != flags) {
+ if (!s || (cs->list[i].flags & mask) != flags) {
continue;
}
/* check C1 criteria not fullfilled */
// TODO: C1 is also dependant on power class and max power
- if (cs->list[i].rxlev_db < cs->list[i].min_db) {
+ if (cs->list[i].rxlev_db < s->rxlev_acc_min_db) {
LOGP(DCS, LOGL_INFO, "Skip frequency %d: C1 criteria "
"not met. (rxlev=%d < min=%d)\n", i,
- cs->list[i].rxlev_db, cs->list[i].min_db);
+ cs->list[i].rxlev_db, s->rxlev_acc_min_db);
continue;
}
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, cs->list[i].mcc,
- cs->list[i].mnc, cs->list[i].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 we have no access to the cell and we don't override */
if (!subscr->acc_barr
- && !(acc_class & (cs->list[i].class_barr ^ 0xffff))) {
+ && !(acc_class & (s->class_barr ^ 0xffff))) {
LOGP(DCS, LOGL_INFO, "Skip frequency %d: Class is "
"barred for out access. (access=%04x "
- "barred=%04x)\n", i, acc_class,
- cs->list[i].class_barr);
+ "barred=%04x)\n", i, acc_class, s->class_barr);
continue;
}
cs->list[i].flags |= GSM322_CS_FLAG_TEMP_AA;
/* if we search a specific PLMN, but it does not match */
- if (!any && (cs->mcc != cs->list[i].mcc
- || cs->mnc != cs->list[i].mnc)) {
+ 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, cs->list[i].mcc,
- cs->list[i].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, cs->list[i].mcc, cs->list[i].mnc,
- cs->list[i].lac, gsm_get_mcc(cs->list[i].mcc),
- gsm_get_mnc(cs->list[i].mcc, cs->list[i].mnc));
+ "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 */
if (found < 0 || cs->list[i].rxlev_db > power) {
}
}
- gsm322_dump_sorted_plmn(ms);
-
if (found >= 0)
LOGP(DCS, LOGL_INFO, "Cell frequency %d selected.\n", found);
static int gsm322_cs_scan(struct osmocom_ms *ms)
{
struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm48_sysinfo *s = &ms->sysinfo;
- struct gsm48_rrlayer *rr = &ms->rrlayer;
int i, j;
uint8_t mask, flags;
uint32_t weight = 0, test = cs->scan_state;
- if (rr->state != GSM48_RR_ST_IDLE) {
- LOGP(DCS, LOGL_FATAL, "This must only happen in IDLE mode, "
- "please fix!\n");
- return -EINVAL;
- }
-
- /* special prositive case for HPLMN search */
- if (cs->state == GSM322_HPLMN_SEARCH && s->mcc == subscr->mcc
- && s->mnc == subscr->mnc) {
- struct msgb *nmsg;
-
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_HPLMN_FOUND);
- LOGP(DCS, LOGL_INFO, "HPLMN cell available.\n");
- if (!nmsg)
- return -ENOMEM;
- gsm322_plmn_sendmsg(ms, nmsg);
-
- return 0;
- }
-
/* 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_dump_cs_list(cs, GSM322_CS_FLAG_SYSINFO, print_dcs,
+ NULL);
- /* special negative case for HPLMN search */
- if (cs->state == GSM322_HPLMN_SEARCH && !weight) {
+ /* special case for PLMN search */
+ if (cs->state == GSM322_PLMN_SEARCH && !weight) {
struct msgb *nmsg;
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_HPLMN_NOT_FOUND);
- LOGP(DCS, LOGL_INFO, "No HPLMN cell available.\n");
+ /* 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);
- /* re-tune back to current VPLMN */
- l1ctl_tx_ccch_req(ms, cs->arfcn);
- cs->ccch_active = 0;
-
return 0;
}
- /* if all frequencies have been searched */
- if (!weight) {
+ /* special case for HPLMN search */
+ if (cs->state == GSM322_HPLMN_SEARCH && !weight) {
struct msgb *nmsg;
- int found, any;
+
+ 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);
+
+ 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);
+ cs->ccch_state = GSM322_CCCH_ST_INIT;
+ hack = 5;
+ gsm322_sync_to_cell(ms, cs);
+// start_cs_timer(cs, ms->support.sync_to, 0);
+
+ return 0;
+ }
+
+ /* if all frequencies have been searched */
+ if (!weight) {
+ struct msgb *nmsg;
+#if 0
+ int found, any = 0;
LOGP(DCS, LOGL_INFO, "All frequencies scanned.\n");
/* if found */
if (found >= 0) {
+ struct gsm322_plmn *plmn = &ms->plmn;
+
LOGP(DCS, LOGL_INFO, "Tune to frequency %d.\n", found);
/* tune */
cs->arfcn = found;
- l1ctl_tx_ccch_req(ms, cs->arfcn);
- cs->ccch_active = 0;
-
- /* Clear system information. */
- gsm48_sysinfo_init(ms);
-
- /* tell PLMN process about available PLMNs */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_PLMN_AVAIL);
- if (!nmsg)
- return -ENOMEM;
- gsm322_plmn_sendmsg(ms, nmsg);
+ cs->si = cs->list[cs->arfcn].sysinfo;
+ cs->ccch_state = GSM322_CCCH_ST_INIT;
+ hack = 5;
+ gsm322_sync_to_cell(ms, cs);
+
+ /* selected PLMN (manual) or any PLMN (auto) */
+ 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);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_plmn_sendmsg(ms, nmsg);
+ }
+ break;
+ case PLMN_MODE_MANUAL:
+ if (plmn->state == GSM322_M3_NOT_ON_PLMN
+ && gsm322_is_plmn_avail(cs, plmn->mcc,
+ plmn->mnc)) {
+ /* PLMN becomes available */
+ nmsg = gsm322_msgb_alloc(
+ GSM322_EVENT_PLMN_AVAIL);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_plmn_sendmsg(ms, nmsg);
+ }
+ break;
+ }
+ /* set selected cell */
+ cs->selected = 1;
+ cs->sel_arfcn = cs->arfcn;
+ memcpy(&cs->sel_si, cs->si, sizeof(cs->sel_si));
+ cs->sel_mcc = cs->si->mcc;
+ cs->sel_mnc = cs->si->mnc;
+ cs->sel_lac = cs->si->lac;
+ cs->sel_id = cs->si->cell_id;
+
+ /* tell CS process about available cell */
+ LOGP(DCS, LOGL_INFO, "Cell available.\n");
nmsg = gsm322_msgb_alloc(GSM322_EVENT_CELL_FOUND);
} else {
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_NO_CELL_FOUND);
+#endif
+ /* unset selected cell */
+ gsm322_unselect_cell(cs);
+
+ /* tell CS process about no cell available */
LOGP(DCS, LOGL_INFO, "No cell available.\n");
- }
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_NO_CELL_FOUND);
+// }
if (!nmsg)
return -ENOMEM;
- gsm322_cs_sendmsg(ms, nmsg);
+ gsm322_c_event(ms, nmsg);
+ msgb_free(nmsg);
return 0;
}
/* Tune to frequency for a while, to receive broadcasts. */
cs->arfcn = weight & 1023;
- LOGP(DCS, LOGL_INFO, "Scanning frequency %d.\n", cs->arfcn);
- l1ctl_tx_ccch_req(ms, cs->arfcn);
- cs->ccch_active = 0;
-
- /* Clear system information. */
- gsm48_sysinfo_init(ms);
+ 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;
+ hack = 5;
+ gsm322_sync_to_cell(ms, 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));
+ else
+ cs->list[cs->arfcn].sysinfo = talloc_zero(l23_ctx,
+ struct gsm48_sysinfo);
+ if (!cs->list[cs->arfcn].sysinfo)
+ exit(-ENOMEM);
+ 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 gsm48_sysinfo *s = &ms->sysinfo;
- int i = cs->scan_state & 1023;
+ struct gsm48_sysinfo *s = cs->si;
+ struct gsm322_plmn *plmn = &ms->plmn;
+ struct msgb *nmsg;
+ int found, any = 0;
if (cs->state != GSM322_C2_STORED_CELL_SEL
&& cs->state != GSM322_C1_NORMAL_CELL_SEL
&& cs->state != GSM322_C4_NORMAL_CELL_RESEL
&& cs->state != GSM322_C8_ANY_CELL_RESEL
&& cs->state != GSM322_C5_CHOOSE_CELL
- && cs->state != GSM322_C9_CHOOSE_ANY_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");
return -EINVAL;
}
/* store sysinfo */
- cs->list[i].flags |= GSM322_CS_FLAG_SYSINFO;
- if (s->cell_barr)
- cs->list[i].flags |= GSM322_CS_FLAG_BARRED;
+ cs->list[cs->arfcn].flags |= GSM322_CS_FLAG_SYSINFO;
+ 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[i].flags &= ~GSM322_CS_FLAG_BARRED;
- cs->list[i].min_db = s->rxlev_acc_min_db;
- cs->list[i].class_barr = s->class_barr;
- cs->list[i].max_pwr = s->ms_txpwr_max_ccch;
+ cs->list[cs->arfcn].flags &= ~GSM322_CS_FLAG_BARRED;
+
+#if 0
+ cs->list[cs->arfcn].min_db = s->rxlev_acc_min_db;
+ cs->list[cs->arfcn].class_barr = s->class_barr;
+ cs->list[cs->arfcn].max_pwr = s->ms_txpwr_max_ccch;
+#endif
/* store selected network */
if (s->mcc) {
- cs->list[i].mcc = s->mcc;
- cs->list[i].mnc = s->mnc;
- cs->list[i].lac = s->lac;
+#if 0
+ cs->list[cs->arfcn].mcc = s->mcc;
+ cs->list[cs->arfcn].mnc = s->mnc;
+ cs->list[cs->arfcn].lac = s->lac;
+#endif
if (gsm322_is_forbidden_la(ms, s->mcc, s->mnc, s->lac))
- cs->list[i].flags |= GSM322_CS_FLAG_FORBIDD;
+ cs->list[cs->arfcn].flags |= GSM322_CS_FLAG_FORBIDD;
else
- cs->list[i].flags &= ~GSM322_CS_FLAG_FORBIDD;
+ cs->list[cs->arfcn].flags &= ~GSM322_CS_FLAG_FORBIDD;
}
LOGP(DCS, LOGL_INFO, "Scan frequency %d: Cell found. (rxlev=%d "
- "mcc=%03d mnc=%02d lac=%04x)\n", i, cs->list[i].rxlev_db,
- cs->list[i].mcc, cs->list[i].mnc, cs->list[i].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);
- /* tune to next cell */
- return gsm322_cs_scan(ms);
+ /* 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);
+
+ return 0;
+ }
+
+ /* just see, if we search for any cell */
+ if (cs->state == GSM322_C6_ANY_CELL_SEL
+ || cs->state == GSM322_C8_ANY_CELL_RESEL
+ || cs->state == GSM322_C9_CHOOSE_ANY_CELL)
+ any = 1;
+
+ found = gsm322_cs_select(ms, any);
+
+ /* if not found */
+ if (found < 0) {
+ LOGP(DCS, LOGL_INFO, "Cell not suitable and allowable.\n");
+ /* tune to next cell */
+ return gsm322_cs_scan(ms);
+ }
+
+ LOGP(DCS, LOGL_INFO, "Tune to frequency %d.\n", found);
+ /* tune */
+ cs->arfcn = found;
+ cs->si = cs->list[cs->arfcn].sysinfo;
+ cs->ccch_state = GSM322_CCCH_ST_INIT;
+ hack = 5;
+ gsm322_sync_to_cell(ms, cs);
+
+ /* selected PLMN (manual) or any PLMN (auto) */
+ 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);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_plmn_sendmsg(ms, nmsg);
+ }
+ break;
+ case PLMN_MODE_MANUAL:
+ if (plmn->state == GSM322_M3_NOT_ON_PLMN
+ && gsm322_is_plmn_avail(cs, plmn->mcc,
+ plmn->mnc)) {
+ /* PLMN becomes available */
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_PLMN_AVAIL);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_plmn_sendmsg(ms, nmsg);
+ }
+ break;
+ }
+
+ /* set selected cell */
+ cs->selected = 1;
+ cs->sel_arfcn = cs->arfcn;
+ memcpy(&cs->sel_si, cs->si, sizeof(cs->sel_si));
+ cs->sel_mcc = cs->si->mcc;
+ cs->sel_mnc = cs->si->mnc;
+ cs->sel_lac = cs->si->lac;
+ cs->sel_id = cs->si->cell_id;
+
+ /* tell CS process about available cell */
+ LOGP(DCS, LOGL_INFO, "Cell available.\n");
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_CELL_FOUND);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_c_event(ms, nmsg);
+ msgb_free(nmsg);
+
+ return 0;
}
/* process system information when returing to idle mode */
struct gsm322_ba_list *gsm322_cs_sysinfo_sacch(struct osmocom_ms *ms)
{
struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = cs->si;
struct gsm322_ba_list *ba = NULL;
int i;
uint8_t freq[128];
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));
}
return ba;
}
+/* store BA whenever a system informations changes */
+static int gsm322_store_ba_list(struct gsm322_cellsel *cs,
+ struct gsm48_sysinfo *s)
+{
+ struct gsm322_ba_list *ba;
+ int i;
+ uint8_t freq[128];
+
+ /* find or create ba list */
+ ba = gsm322_find_ba_list(cs, s->mcc, s->mnc);
+ if (!ba) {
+ ba = talloc_zero(l23_ctx, struct gsm322_ba_list);
+ if (!ba)
+ return -ENOMEM;
+ ba->mcc = s->mcc;
+ ba->mnc = s->mnc;
+ llist_add_tail(&ba->entry, &cs->ba_list);
+ }
+ /* update ba list */
+ memset(freq, 0, sizeof(freq));
+ freq[cs->arfcn >> 3] |= (1 << (cs->arfcn & 7));
+ for (i = 0; i <= 1023; i++) {
+ if ((s->freq[i].mask &
+ (FREQ_TYPE_SERV | FREQ_TYPE_NCELL)))
+ freq[i >> 3] |= (1 << (i & 7));
+ }
+ if (!!memcmp(freq, ba->freq, sizeof(freq))) {
+ 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));
+ }
+
+ return 0;
+}
+
/* 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 gsm322_cellsel *cs = &ms->cellsel;
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ 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 (rr->state != GSM48_RR_ST_IDLE) {
+ LOGP(DCS, LOGL_INFO, "Ignoring in dedicated mode.\n");
+ return -EBUSY;
+ }
+
+ /* Store BA if we have full system info about cells and neigbor cells.
+ * Depending on the extended bit in the channel description,
+ * we require more or less system informations about neighbor cells
+ */
+ if (s->mcc
+ && s->mnc
+ && (gm->sysinfo == GSM48_MT_RR_SYSINFO_1
+ || gm->sysinfo == GSM48_MT_RR_SYSINFO_2
+ || gm->sysinfo == GSM48_MT_RR_SYSINFO_2bis
+ || gm->sysinfo == GSM48_MT_RR_SYSINFO_2ter)
+ && s->si1
+ && s->si2
+ && (!s->nb_ext_ind_si2
+ || (s->si2bis && s->nb_ext_ind_si2 && !s->nb_ext_ind_si2bis)
+ || (s->si2bis && s->si2ter && s->nb_ext_ind_si2
+ && s->nb_ext_ind_si2bis)))
+ gsm322_store_ba_list(cs, s);
+
+ /* update sel_si, if all relevant system informations received */
+ if (s->si1 && s->si2 && s->si3
+ && (!s->nb_ext_ind_si2
+ || (s->si2bis && s->nb_ext_ind_si2 && !s->nb_ext_ind_si2bis)
+ || (s->si2bis && s->si2ter && s->nb_ext_ind_si2
+ && s->nb_ext_ind_si2bis))) {
+ if (cs->selected) {
+ 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);
+ }
+ }
+
+ /* 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->list[cs->arfcn].flags &= ~GSM322_CS_FLAG_SYSINFO;
- /* trigger reselection event */
+ if (cs->list[cs->arfcn].sysinfo) {
+ 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);
+ }
+ /* trigger reselection without queueing,
+ * because other sysinfo message may be queued
+ * before
+ */
nmsg = gsm322_msgb_alloc(GSM322_EVENT_CELL_RESEL);
if (!nmsg)
return -ENOMEM;
- gsm322_cs_sendmsg(ms, nmsg);
+ gsm322_c_event(ms, nmsg);
+ msgb_free(nmsg);
return 0;
}
/* check if cell access becomes barred */
if (!((subscr->acc_class & 0xfbff)
- & (cs->list[cs->arfcn].class_barr ^ 0xffff))) {
+ & (s->class_barr ^ 0xffff))) {
LOGP(DCS, LOGL_INFO, "Cell access becomes barred.\n");
goto trigger_resel;
}
}
+ /* check if MCC, MNC, LAC, cell ID changes */
+ if (cs->sel_mcc != s->mcc || cs->sel_mnc != s->mnc
+ || cs->sel_lac != s->lac) {
+ LOGP(DCS, LOGL_NOTICE, "Cell changes location area. "
+ "This is not good!\n");
+ goto trigger_resel;
+ }
+ if (cs->sel_id != s->cell_id) {
+ LOGP(DCS, LOGL_NOTICE, "Cell changes cell ID. "
+ "This is not good!\n");
+ goto trigger_resel;
+ }
+
return 0;
}
static int gsm322_c_scan_sysinfo_bcch(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm48_rrlayer *rr = &ms->rrlayer;
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = cs->si;
struct gsm322_msg *gm = (struct gsm322_msg *) msg->data;
- struct gsm322_ba_list *ba;
- int i;
- uint8_t freq[128];
-
- if (rr->state != GSM48_RR_ST_IDLE) {
- LOGP(DCS, LOGL_FATAL, "This must only happen in IDLE mode, "
- "please fix!\n");
- return -EINVAL;
- }
/* no sysinfo if we are not done with power scan */
if (cs->powerscan) {
&& (!s->nb_ext_ind_si2
|| (s->si2bis && s->nb_ext_ind_si2 && !s->nb_ext_ind_si2bis)
|| (s->si2bis && s->si2ter && s->nb_ext_ind_si2
- && s->nb_ext_ind_si2bis))) {
- /* find or create ba list */
- ba = gsm322_find_ba_list(cs, s->mcc, s->mnc);
- if (!ba) {
- ba = talloc_zero(l23_ctx, struct gsm322_ba_list);
- if (!ba)
- return -ENOMEM;
- ba->mcc = s->mcc;
- ba->mnc = s->mnc;
- llist_add_tail(&ba->entry, &cs->ba_list);
- }
- /* update ba list */
- memset(freq, 0, sizeof(freq));
- freq[cs->arfcn >> 3] |= (1 << (cs->arfcn & 7));
- for (i = 0; i <= 1023; i++) {
- if ((s->freq[i].mask &
- (FREQ_TYPE_SERV | FREQ_TYPE_NCELL)))
- 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),
- gsm_get_mnc(ba->mcc, ba->mnc));
- memcpy(ba->freq, freq, sizeof(freq));
- }
- }
+ && s->nb_ext_ind_si2bis)))
+ gsm322_store_ba_list(cs, s);
-#warning testing
-printf("%d %d %d\n", s->si1, s->si2, s->si3);
/* all relevant system informations received */
if (s->si1 && s->si2 && s->si3
&& (!s->nb_ext_ind_si2
|| (s->si2bis && s->nb_ext_ind_si2 && !s->nb_ext_ind_si2bis)
|| (s->si2bis && s->si2ter && s->nb_ext_ind_si2
&& s->nb_ext_ind_si2bis))) {
+ LOGP(DCS, LOGL_INFO, "Received relevant sysinfo.\n");
/* stop timer */
stop_cs_timer(cs);
- gsm48_sysinfo_dump(ms);
+ //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;
- int i = cs->scan_state & 1023;
- 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)
+ LOGP(DCS, LOGL_INFO, "Sync timeout.\n");
+ else
+ LOGP(DCS, LOGL_INFO, "Read timeout.\n");
+
LOGP(DCS, LOGL_INFO, "Scan frequency %d: Cell not found. (rxlev=%d)\n",
- i, cs->list[i].rxlev_db);
+ cs->arfcn, cs->list[cs->arfcn].rxlev_db);
/* remove system information */
- cs->list[i].flags &= ~GSM322_CS_FLAG_SYSINFO;
+ cs->list[cs->arfcn].flags &= ~GSM322_CS_FLAG_SYSINFO;
+ if (cs->list[cs->arfcn].sysinfo) {
+ 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 */
gsm322_cs_scan(ms);
* power scan process
*/
-/* search for block of unscanned freqeuncies and start scanning */
+/* search for block of unscanned frequencies and start scanning */
static int gsm322_cs_powerscan(struct osmocom_ms *ms)
{
struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm48_rrlayer *rr = &ms->rrlayer;
int i, s = -1, e;
uint8_t mask, flags;
- if (rr->state != GSM48_RR_ST_IDLE) {
- LOGP(DCS, LOGL_FATAL, "This must only happen in IDLE mode, "
- "please fix!\n");
- return -EINVAL;
- }
-
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) {
+ 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;
~(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;
+ }
}
+ /* 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);
+ cs->ccch_state = GSM322_CCCH_ST_INIT;
+ hack = 5;
+ gsm322_sync_to_cell(ms, 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);
break;
}
- LOGP(DCS, LOGL_INFO, "Scanning frequecies. (%d..%d)\n", s, e);
+ 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);
}
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_active) {
- LOGP(DCS, LOGL_INFO, "Channel activated.\n");
- cs->ccch_active = 1;
+ 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);
+
+ /* 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_C1_NORMAL_CELL_SEL
|| cs->state == GSM322_C4_NORMAL_CELL_RESEL
|| cs->state == GSM322_C8_ANY_CELL_RESEL
|| cs->state == GSM322_C5_CHOOSE_CELL
- || cs->state == GSM322_C9_CHOOSE_ANY_CELL)
- start_cs_timer(cs, 4, 0);
+ || 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(ms, 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;
}
+
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)
- && !(cs->list[i].flags & GSM322_CS_FLAG_BA))
+ 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
| 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;
+ }
+ }
}
+ /* no cell selected */
+ gsm322_unselect_cell(cs);
+
/* start power scan */
return gsm322_cs_powerscan(ms);
}
cs->list[i].flags &= ~GSM322_CS_FLAG_BA;
}
+ /* unset selected cell */
+ gsm322_unselect_cell(cs);
+
/* start power scan */
return gsm322_cs_powerscan(ms);
}
/* except for stored cell selection state, we weed to rescan ?? */
if (cs->state != GSM322_C2_STORED_CELL_SEL) {
- for (i = 0; i <= 1023; i++)
+ 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;
+ }
+ }
}
new_c_state(cs, GSM322_C1_NORMAL_CELL_SEL);
+ /* unset selected cell */
+ 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) {
- for (i = 0; i <= 1023; i++)
+ /* 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
| 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;
+ }
+ }
+ }
+ /* 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 */
+ 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
- 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);
-#ifdef TODO
+ 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);
+ }
}
-#endif
if (!ba) {
struct msgb *nmsg;
- LOGP(DCS, LOGL_INFO, "No BA list.\n");
+ LOGP(DCS, LOGL_INFO, "No BA list to use.\n");
/* tell CS to start over */
nmsg = gsm322_msgb_alloc(GSM322_EVENT_NO_CELL_FOUND);
if (!nmsg)
return -ENOMEM;
- gsm322_cs_sendmsg(ms, nmsg);
+ gsm322_c_event(ms, nmsg);
+ msgb_free(nmsg);
+
+ return 0;
}
/* 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
| 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;
+ }
}
-#ifdef TODO
- remove this:
-#else
- /* use hacked frequency */
- cs->list[ms->test_arfcn].flags |= GSM322_CS_FLAG_POWER;
- cs->list[ms->test_arfcn].flags |= GSM322_CS_FLAG_SIGNAL;
- cs->list[ms->test_arfcn].rxlev_db = -40;
-#endif
+
+ /* unset selected cell */
+ 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;
- nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_NEW_LAI);
+ 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)
return -ENOMEM;
gsm48_mmevent_msg(ms, nmsg);
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)
+ return -ENOMEM;
+ gsm48_mmevent_msg(ms, nmsg);
new_c_state(cs, GSM322_C7_CAMPED_ANY_CELL);
{
struct gsm322_cellsel *cs = &ms->cellsel;
- /* stop camping process */
+ /* check for error */
+ if (!cs->selected)
+ return -EINVAL;
+ cs->arfcn = cs->sel_arfcn;
/* be sure to go to current camping frequency on return */
LOGP(DCS, LOGL_INFO, "Going to camping frequency %d.\n", cs->arfcn);
- l1ctl_tx_ccch_req(ms, cs->arfcn);
- cs->ccch_active = 0;
+ cs->ccch_state = GSM322_CCCH_ST_INIT;
+ hack = 5;
+ gsm322_sync_to_cell(ms, cs);
+ cs->si = cs->list[cs->arfcn].sysinfo;
+#warning TESTING: laforge must fix the sync error when sending fbsb request too close to each other. also we must get a response with arfcn or a confirm, so we know where the response belongs to.
+usleep(300000);
return 0;
}
{
struct gsm322_cellsel *cs = &ms->cellsel;
- /* stop camping process */
+ /* check for error */
+ if (!cs->selected)
+ return -EINVAL;
+ cs->arfcn = cs->sel_arfcn;
/* be sure to go to current camping frequency on return */
LOGP(DCS, LOGL_INFO, "Going to camping frequency %d.\n", cs->arfcn);
- l1ctl_tx_ccch_req(ms, cs->arfcn);
- cs->ccch_active = 0;
+ cs->ccch_state = GSM322_CCCH_ST_INIT;
+ hack = 5;
+ gsm322_sync_to_cell(ms, 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_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},
};
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_C4_NORMAL_CELL_RESEL),
+ 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_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)
+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++) {
- if (!(cs->list[i].flags & GSM322_CS_FLAG_SIGNAL))
+ 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 |", cs->list[i].mcc,
- cs->list[i].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 ((cs->list[i].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", cs->list[i].min_db,
- cs->list[i].max_pwr);
+ print(priv, "%4d |%4d\n", s->rxlev_acc_min_db,
+ s->ms_txpwr_max_ccch);
} 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)
-{
- 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)
+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_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);
} else
- LOGP(DCS, LOGL_NOTICE, "No stored BA list\n");
+ LOGP(DCS, LOGL_INFO, "No stored BA list\n");
register_signal_handler(SS_L1CTL, &gsm322_l1_signal, NULL);
char filename[sizeof(ms->name) + strlen(suffix) + 1];
struct gsm322_ba_list *ba;
uint8_t buf[4];
+ int i;
LOGP(DPLMN, LOGL_INFO, "exit PLMN process\n");
LOGP(DCS, LOGL_INFO, "exit Cell Selection process\n");
stop_cs_timer(cs);
stop_plmn_timer(plmn);
+ /* flush sysinfo */
+ for (i = 0; i <= 1023; i++) {
+ 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;
+ }
+ cs->list[i].flags = 0;
+ }
+
/* store BA list */
strcpy(filename, ms->name);
strcat(filename, suffix);
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);