diff options
-rw-r--r-- | include/openbsc/gsm_data.h | 20 | ||||
-rw-r--r-- | src/gsm_04_08.c | 89 |
2 files changed, 78 insertions, 31 deletions
diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h index 986f33127..30e8b4617 100644 --- a/include/openbsc/gsm_data.h +++ b/include/openbsc/gsm_data.h @@ -82,6 +82,19 @@ enum gsm_chreq_reason_t { GSM_CHREQ_REASON_OTHER, }; +/* + * LOCATION UPDATING REQUEST state + * + * Our current operation is: + * - Get imei/tmsi + * - Accept/Reject according to global policy + */ +struct gsm_loc_updating_operation { + struct timer_list updating_timer; + int waiting_for_imsi : 1; + int waiting_for_imei : 1; +}; + struct gsm_lchan { /* The TS that we're part of */ struct gsm_bts_trx_ts *ts; @@ -94,7 +107,6 @@ struct gsm_lchan { /* Timer started to release the channel */ struct timer_list release_timer; - struct timer_list updating_timer; /* local end of a call, if any */ struct gsm_call call; @@ -102,9 +114,13 @@ struct gsm_lchan { /* temporary user data, to be removed... and merged into gsm_call */ void *user_data; + /* + * Operations that have a state and might be pending + */ + struct gsm_loc_updating_operation *loc_operation; + /* use count. how many users use this channel */ unsigned int use_count; - unsigned int pending_update_request : 1; }; #define BTS_TRX_F_ACTIVATED 0x0001 diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c index 65d2f647a..82fd52389 100644 --- a/src/gsm_04_08.c +++ b/src/gsm_04_08.c @@ -65,17 +65,44 @@ void gsm0408_set_reject_cause(int cause) 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 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) 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 @@ static int mm_rx_id_resp(struct msgb *msg) 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 @@ static void loc_upd_rej_cb(void *data) { 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 @@ static int mm_rx_loc_upd_req(struct msgb *msg) 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 @@ static int mm_rx_loc_upd_req(struct msgb *msg) /* 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 @@ static int mm_rx_loc_upd_req(struct msgb *msg) /* 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 @@ static int mm_rx_loc_upd_req(struct msgb *msg) 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); } |