Introduce logical updating request operation on the gsm_lchan
We are going to have logical operations like Phone Call, SMS,
Paging, Updating Request on a logical channel and for each of
these operations we might need to store state. For now pointers
in gsm_lchan look like the best way of doing this and we start
by introducing an operation for the location updating request.
The new flow of things are:
- We get the location updating request and update/create
the subscriber and maybe send the identity requests to
the mobile station
- We start the updating timer, if it times out we will
reject the mobile station.
- Once we get the Identity Responses we have asked for
and the reject timer did not fire yet we might accept
the user.
diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c
index 65d2f64..82fd523 100644
--- a/src/gsm_04_08.c
+++ b/src/gsm_04_08.c
@@ -65,17 +65,44 @@
reject_cause = cause;
}
-static int authorize_subscriber(struct gsm_subscriber *subscriber)
+static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
+ struct gsm_subscriber *subscriber)
{
if (!subscriber)
return 0;
+ /*
+ * Do not send accept yet as more information should arrive. Some
+ * phones will not send us the information and we will have to check
+ * what we want to do with that.
+ */
+ if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei))
+ return 0;
+
if (authorize_everonye)
return 1;
return subscriber->authorized;
}
+static void release_loc_updating_req(struct gsm_lchan *lchan)
+{
+ if (lchan->loc_operation)
+ return;
+
+ del_timer(&lchan->loc_operation->updating_timer);
+ free(lchan->loc_operation);
+ lchan->loc_operation = 0;
+}
+
+static void allocate_loc_updating_req(struct gsm_lchan *lchan)
+{
+ release_loc_updating_req(lchan);
+
+ lchan->loc_operation = (struct gsm_loc_updating_operation *)
+ malloc(sizeof(*lchan->loc_operation));
+ memset(lchan->loc_operation, 0, sizeof(*lchan->loc_operation));
+}
static void parse_lai(struct gsm_lai *lai, const struct gsm48_loc_area_id *lai48)
{
@@ -231,7 +258,6 @@
mid = msgb_put(msg, MID_TMSI_LEN);
generate_mid_from_tmsi(mid, tmsi);
- lchan->pending_update_request = 0;
DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
/* inform the upper layer on the progress */
@@ -338,26 +364,27 @@
case GSM_MI_TYPE_IMSI:
if (!lchan->subscr)
lchan->subscr = db_create_subscriber(mi_string);
-
- /* We have a pending UPDATING REQUEST handle it now */
- if (lchan->pending_update_request) {
- if (authorize_subscriber(lchan->subscr)) {
- db_subscriber_alloc_tmsi(lchan->subscr);
- tmsi = strtoul(lchan->subscr->tmsi, NULL, 10);
- del_timer(&lchan->updating_timer);
- return gsm0408_loc_upd_acc(msg->lchan, tmsi);
- } else {
- schedule_reject(lchan);
- }
- }
+ if (lchan->loc_operation)
+ lchan->loc_operation->waiting_for_imsi = 0;
break;
case GSM_MI_TYPE_IMEI:
case GSM_MI_TYPE_IMEISV:
/* update subscribe <-> IMEI mapping */
if (lchan->subscr)
db_subscriber_assoc_imei(lchan->subscr, mi_string);
+ if (lchan->loc_operation)
+ lchan->loc_operation->waiting_for_imei = 0;
break;
}
+
+ /* Check if we can let the mobile station enter */
+ if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) {
+ db_subscriber_alloc_tmsi(lchan->subscr);
+ tmsi = strtoul(lchan->subscr->tmsi, NULL, 10);
+ release_loc_updating_req(lchan);
+ return gsm0408_loc_upd_acc(msg->lchan, tmsi);
+ }
+
return 0;
}
@@ -366,16 +393,16 @@
{
struct gsm_lchan *lchan = data;
+ release_loc_updating_req(lchan);
gsm0408_loc_upd_rej(lchan, reject_cause);
rsl_chan_release(lchan);
}
static void schedule_reject(struct gsm_lchan *lchan)
{
- lchan->updating_timer.cb = loc_upd_rej_cb;
- lchan->updating_timer.data = lchan;
- lchan->pending_update_request = 0;
- schedule_timer(&lchan->updating_timer, 1, 0);
+ lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
+ lchan->loc_operation->updating_timer.data = lchan;
+ schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
}
#define MI_SIZE 32
@@ -399,11 +426,15 @@
mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
DEBUGP(DMM, "LUPDREQ: mi_type=0x%02x MI(%s)\n", mi_type, mi_string);
+
+ allocate_loc_updating_req(lchan);
+
switch (mi_type) {
case GSM_MI_TYPE_IMSI:
/* we always want the IMEI, too */
use_lchan(lchan);
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEISV);
+ lchan->loc_operation->waiting_for_imei = 1;
/* look up subscriber based on IMSI */
subscr = db_create_subscriber(mi_string);
@@ -412,6 +443,7 @@
/* we always want the IMEI, too */
use_lchan(lchan);
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEISV);
+ lchan->loc_operation->waiting_for_imei = 1;
/* look up the subscriber based on TMSI, request IMSI if it fails */
subscr = subscr_get_by_tmsi(lu->mi);
@@ -419,6 +451,7 @@
/* send IDENTITY REQUEST message to get IMSI */
use_lchan(lchan);
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
+ lchan->loc_operation->waiting_for_imsi = 1;
}
break;
case GSM_MI_TYPE_IMEI:
@@ -433,23 +466,21 @@
lchan->subscr = subscr;
- /* we know who we deal with and don't want him */
- if (subscr && !authorize_subscriber(subscr)) {
- schedule_reject(lchan);
- return 0;
- } else if (!subscr) {
- /* we have asked for the imsi and should get a
- * IDENTITY RESPONSE */
- lchan->pending_update_request = 1;
- return 0;
- }
+ /*
+ * Schedule the reject timer and check if we can let the
+ * subscriber into our network immediately or if we need to wait
+ * for identity responses.
+ */
+ schedule_reject(lchan);
+ if (!authorize_subscriber(lchan->loc_operation, subscr))
+ return;
db_subscriber_alloc_tmsi(subscr);
subscr_update(subscr, bts);
tmsi = strtoul(subscr->tmsi, NULL, 10);
- del_timer(&lchan->updating_timer);
+ release_loc_updating_req(lchan);
return gsm0408_loc_upd_acc(lchan, tmsi);
}