diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 05e04906e..874150535 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -104,6 +104,9 @@ struct gsm_subscriber_connection { /* To whom we are allocated at the moment */ struct gsm_subscriber *subscr; + /* LU expiration handling */ + uint8_t expire_timer_stopped; + /* * Operations that have a state and might be pending */ diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index 78f9710c5..32e0a4e96 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -100,6 +100,7 @@ char *subscr_name(struct gsm_subscriber *subscr); int subscr_purge_inactive(struct gsm_network *net); void subscr_update_from_db(struct gsm_subscriber *subscr); void subscr_expire(struct gsm_network *net); +int subscr_update_expire_lu(struct gsm_subscriber *subscr, struct gsm_bts *bts); /* internal */ struct gsm_subscriber *subscr_alloc(void); diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 7f38be28e..eea073614 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -829,6 +829,9 @@ static int _gsm48_rx_mm_serv_req_sec_cb( struct gsm_subscriber_connection *conn = data; int rc = 0; + /* auth failed or succeeded, the timer was stopped */ + conn->expire_timer_stopped = 1; + switch (event) { case GSM_SECURITY_AUTH_FAILED: /* Nothing to do */ @@ -930,6 +933,9 @@ static int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct m memcpy(subscr->equipment.classmark2, classmark2, classmark2_len); db_sync_equipment(&subscr->equipment); + /* we will send a MM message soon */ + conn->expire_timer_stopped = 1; + return gsm48_secure_channel(conn, req->cipher_key_seq, _gsm48_rx_mm_serv_req_sec_cb, NULL); } @@ -1123,6 +1129,9 @@ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct m memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv); db_sync_equipment(&subscr->equipment); + /* We received a paging */ + conn->expire_timer_stopped = 1; + rc = gsm48_handle_paging_resp(conn, msg, subscr); return rc; } diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index 7ff44075c..6abb0d832 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -1,7 +1,7 @@ /* The concept of a subscriber for the MSC, roughly HLR/VLR functionality */ /* (C) 2008 by Harald Welte - * (C) 2009 by Holger Hans Peter Freyther + * (C) 2009,2013 by Holger Hans Peter Freyther * * All Rights Reserved * @@ -37,6 +37,7 @@ #include #include #include +#include void *tall_sub_req_ctx; @@ -323,6 +324,21 @@ struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net, return db_get_subscriber(net, GSM_SUBSCRIBER_ID, buf); } +int subscr_update_expire_lu(struct gsm_subscriber *s, struct gsm_bts *bts) +{ + int rc; + + /* Table 10.5.33: The T3212 timeout value field is coded as the + * binary representation of the timeout value for + * periodic updating in decihours. Mark the subscriber as + * inactive if it missed two consecutive location updates. + * Timeout is twice the t3212 value plus one minute */ + s->expire_lu = time(NULL) + + (bts->si_common.chan_desc.t3212 * 60 * 6 * 2) + 60; + rc = db_sync_subscriber(s); + db_subscriber_update(s); + return rc; +} int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason) { @@ -335,24 +351,19 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason) /* Indicate "attached to LAC" */ s->lac = bts->location_area_code; + LOGP(DMM, LOGL_INFO, "Subscriber %s ATTACHED LAC=%u\n", + subscr_name(s), s->lac); + /* FIXME: We should allow 0 for T3212 as well to disable the * location update period. In that case we will need a way to * indicate that in the database and then reenable that value in * VTY. */ - - /* Table 10.5.33: The T3212 timeout value field is coded as the - * binary representation of the timeout value for - * periodic updating in decihours. Mark the subscriber as - * inactive if it missed two consecutive location updates. - * Timeout is twice the t3212 value plus one minute */ - s->expire_lu = time(NULL) + - (bts->si_common.chan_desc.t3212 * 60 * 6 * 2) + 60; - - LOGP(DMM, LOGL_INFO, "Subscriber %s ATTACHED LAC=%u\n", - subscr_name(s), s->lac); - rc = db_sync_subscriber(s); - db_subscriber_update(s); + /* + * The below will set a new expire_lu but as a side-effect + * the new lac will be saved in the database. + */ + rc = subscr_update_expire_lu(s, bts); osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_ATTACHED, s); break; case GSM_SUBSCRIBER_UPDATE_DETACHED: @@ -383,8 +394,23 @@ void subscr_update_from_db(struct gsm_subscriber *sub) static void subscr_expire_callback(void *data, long long unsigned int id) { struct gsm_network *net = data; - struct gsm_subscriber *s = - subscr_get_by_id(net, id); + struct gsm_subscriber *s = subscr_get_by_id(net, id); + struct gsm_subscriber_connection *conn = connection_for_subscr(s); + + /* + * The subscriber is active and the phone stopped the timer. As + * we don't want to periodically update the database for active + * subscribers we will just do it when the subscriber was selected + * for expiration. This way on the next around another subscriber + * will be selected. + */ + if (conn && conn->expire_timer_stopped) { + LOGP(DMM, LOGL_DEBUG, "Not expiring subscriber %s (ID %llu)\n", + subscr_name(s), id); + subscr_update_expire_lu(s, conn->bts); + return; + } + LOGP(DMM, LOGL_NOTICE, "Expiring inactive subscriber %s (ID %llu)\n", subscr_name(s), id); diff --git a/openbsc/src/libmsc/osmo_msc.c b/openbsc/src/libmsc/osmo_msc.c index 452de62d5..31b72b925 100644 --- a/openbsc/src/libmsc/osmo_msc.c +++ b/openbsc/src/libmsc/osmo_msc.c @@ -1,7 +1,7 @@ /* main MSC management code... */ /* - * (C) 2010 by Holger Hans Peter Freyther + * (C) 2010,2013 by Holger Hans Peter Freyther * (C) 2010 by On-Waves * * All Rights Reserved @@ -158,6 +158,15 @@ void msc_release_connection(struct gsm_subscriber_connection *conn) return; /* no more connections, asking to release the channel */ + + /* + * We had stopped the LU expire timer T3212. Now we are about + * to send the MS back to the idle state and this should lead + * to restarting the timer. Set the new expiration time. + */ + if (conn->expire_timer_stopped) + subscr_update_expire_lu(conn->subscr, conn->bts); + conn->in_release = 1; gsm0808_clear(conn); if (conn->put_channel) { diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c index 440e1803c..ab0d9eb0b 100644 --- a/openbsc/tests/channel/channel_test.c +++ b/openbsc/tests/channel/channel_test.c @@ -89,6 +89,7 @@ void gsm_net_update_ctype(struct gsm_network *network) {} void gsm48_secure_channel() {} void paging_request_stop() {} void vty_out() {} +void* connection_for_subscr(void) { abort(); return NULL; } struct tlv_definition nm_att_tlvdef;