diff options
author | Holger Hans Peter Freyther <zecke@selfish.org> | 2012-12-30 17:52:08 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <zecke@selfish.org> | 2012-12-30 17:52:08 +0100 |
commit | 49e08e837a4ec90dbf14b7bf8bab19455e5de1f1 (patch) | |
tree | 1de8aec59fa6a6b0b22b56207a830bd7eaf2f92e | |
parent | 977cd13741e1e80879ea5b840206044fa1817aea (diff) | |
parent | d85f6d54da2f45919f0ea4de0ad54562f05b0b20 (diff) |
Merge remote-tracking branch 'origin/daniel/t3212-work'
This implements http://openbsc.osmocom.org/trac/wiki/Tasks/NITBPeriodicDetach.
-rw-r--r-- | openbsc/include/openbsc/db.h | 1 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_data.h | 3 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_subscriber.h | 2 | ||||
-rw-r--r-- | openbsc/src/libbsc/bsc_vty.c | 7 | ||||
-rw-r--r-- | openbsc/src/libcommon/gsm_data.c | 1 | ||||
-rw-r--r-- | openbsc/src/libmsc/db.c | 103 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_subscriber.c | 35 | ||||
-rw-r--r-- | openbsc/src/osmo-nitb/bsc_hack.c | 12 |
8 files changed, 154 insertions, 10 deletions
diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index d0c85ea30..25c2aea70 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -41,6 +41,7 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, enum gsm_subscriber_field field, const char *subscr); int db_sync_subscriber(struct gsm_subscriber *subscriber); +int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsigned int id)); int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber); int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber); int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t* token); diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index ea9f601ea..feb692f7c 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -247,6 +247,9 @@ struct gsm_network { int T3122; int T3141; + /* timer to expire old location updates */ + struct osmo_timer_list subscr_expire_timer; + /* Radio Resource Location Protocol (TS 04.31) */ struct { enum rrlp_mode mode; diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index 6cf85731b..78f9710c5 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -38,6 +38,7 @@ struct gsm_subscriber { char name[GSM_NAME_LENGTH]; char extension[GSM_EXTENSION_LENGTH]; int authorized; + time_t expire_lu; /* Temporary field which is not stored in the DB/HLR */ uint32_t flags; @@ -98,6 +99,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); /* internal */ struct gsm_subscriber *subscr_alloc(void); diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index dfe80c9e7..70263dd6b 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -490,9 +490,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) (sp->penalty_time*20)+20, VTY_NEWLINE); } - if (bts->si_common.chan_desc.t3212) - vty_out(vty, " periodic location update %u%s", - bts->si_common.chan_desc.t3212 * 6, VTY_NEWLINE); + vty_out(vty, " periodic location update %u%s", + bts->si_common.chan_desc.t3212 * 6, VTY_NEWLINE); vty_out(vty, " channel allocator %s%s", bts->chan_alloc_reverse ? "descending" : "ascending", VTY_NEWLINE); @@ -2018,7 +2017,7 @@ DEFUN(cfg_bts_penalty_time_rsvd, cfg_bts_penalty_time_rsvd_cmd, } DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd, - "periodic location update <0-1530>", + "periodic location update <6-1530>", "Periodic Location Updating Interval\n" "Periodic Location Updating Interval\n" "Periodic Location Updating Interval\n" diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c index 352700adf..4ccb82004 100644 --- a/openbsc/src/libcommon/gsm_data.c +++ b/openbsc/src/libcommon/gsm_data.c @@ -408,6 +408,7 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ bts->si_common.chan_desc.att = 1; /* attachment required */ bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; /* paging frames */ bts->si_common.chan_desc.bs_ag_blks_res = 1; /* reserved AGCH blocks */ + bts->si_common.chan_desc.t3212 = 5; /* Use 30 min periodic update interval as sane default */ llist_add_tail(&bts->list, &net->bts_list); diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c index 9a5f18db7..4e20e2318 100644 --- a/openbsc/src/libmsc/db.c +++ b/openbsc/src/libmsc/db.c @@ -42,6 +42,8 @@ static char *db_basename = NULL; static char *db_dirname = NULL; static dbi_conn conn; +#define SCHEMA_REVISION "3" + static char *create_stmts[] = { "CREATE TABLE IF NOT EXISTS Meta (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " @@ -51,7 +53,7 @@ static char *create_stmts[] = { "INSERT OR IGNORE INTO Meta " "(key, value) " "VALUES " - "('revision', '2')", + "('revision', " SCHEMA_REVISION ")", "CREATE TABLE IF NOT EXISTS Subscriber (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "created TIMESTAMP NOT NULL, " @@ -61,7 +63,8 @@ static char *create_stmts[] = { "extension TEXT UNIQUE, " "authorized INTEGER NOT NULL DEFAULT 0, " "tmsi TEXT UNIQUE, " - "lac INTEGER NOT NULL DEFAULT 0" + "lac INTEGER NOT NULL DEFAULT 0, " + "expire_lu TIMESTAMP DEFAULT NULL" ")", "CREATE TABLE IF NOT EXISTS AuthToken (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " @@ -158,10 +161,39 @@ void db_error_func(dbi_conn conn, void *data) LOGP(DDB, LOGL_ERROR, "DBI: %s\n", msg); } +static int update_db_revision_2(void) +{ + dbi_result result; + + result = dbi_conn_query(conn, + "ALTER TABLE Subscriber " + "ADD COLUMN expire_lu " + "TIMESTAMP DEFAULT NULL"); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed to alter table Subscriber (upgrade vom rev 2).\n"); + return -EINVAL; + } + dbi_result_free(result); + + result = dbi_conn_query(conn, + "UPDATE Meta " + "SET value = '3' " + "WHERE key = 'revision'"); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed set new revision (upgrade vom rev 2).\n"); + return -EINVAL; + } + dbi_result_free(result); + + return 0; +} + static int check_db_revision(void) { dbi_result result; - const char *rev; + const char *rev_s; result = dbi_conn_query(conn, "SELECT value FROM Meta WHERE key='revision'"); @@ -172,11 +204,37 @@ static int check_db_revision(void) dbi_result_free(result); return -EINVAL; } - rev = dbi_result_get_string(result, "value"); - if (!rev || atoi(rev) != 2) { + rev_s = dbi_result_get_string(result, "value"); + if (!rev_s) { dbi_result_free(result); return -EINVAL; } + if (!strcmp(rev_s, "2")) { + if (update_db_revision_2()) { + LOGP(DDB, LOGL_FATAL, "Failed to update database from schema revision '%s'.\n", rev_s); + dbi_result_free(result); + return -EINVAL; + } + } else if (!strcmp(rev_s, SCHEMA_REVISION)) { + /* everything is fine */ + } else { + LOGP(DDB, LOGL_FATAL, "Invalid database schema revision '%s'.\n", rev_s); + dbi_result_free(result); + return -EINVAL; + } + + dbi_result_free(result); + return 0; +} + +static int db_configure(void) +{ + dbi_result result; + + result = dbi_conn_query(conn, + "PRAGMA synchronous = FULL"); + if (!result) + return -EINVAL; dbi_result_free(result); return 0; @@ -242,6 +300,8 @@ int db_prepare(void) return -1; } + db_configure(); + return 0; } @@ -575,6 +635,12 @@ static void db_set_from_query(struct gsm_subscriber *subscr, dbi_conn result) strncpy(subscr->extension, string, GSM_EXTENSION_LENGTH); subscr->lac = dbi_result_get_uint(result, "lac"); + + if (!dbi_result_field_is_null(result, "expire_lu")) + subscr->expire_lu = dbi_result_get_datetime(result, "expire_lu"); + else + subscr->expire_lu = 0; + subscr->authorized = dbi_result_get_uint(result, "authorized"); } @@ -707,13 +773,15 @@ int db_sync_subscriber(struct gsm_subscriber *subscriber) "extension = %s, " "authorized = %i, " "tmsi = %s, " - "lac = %i " + "lac = %i, " + "expire_lu = datetime(%i, 'unixepoch') " "WHERE imsi = %s ", q_name, q_extension, subscriber->authorized, q_tmsi, subscriber->lac, + subscriber->expire_lu, subscriber->imsi); free(q_tmsi); @@ -776,6 +844,29 @@ int db_sync_equipment(struct gsm_equipment *equip) return 0; } +int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsigned int id)) +{ + dbi_result result; + + result = dbi_conn_query(conn, + "SELECT id " + "FROM Subscriber " + "WHERE lac != 0 AND " + "( expire_lu is NULL " + "OR expire_lu < datetime('now') ) " + "LIMIT 1"); + if (!result) { + LOGP(DDB, LOGL_ERROR, "Failed to get expired subscribers\n"); + return -EIO; + } + + while (dbi_result_next_row(result)) + callback(priv, dbi_result_get_ulonglong(result, "id")); + + dbi_result_free(result); + return 0; +} + int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber) { dbi_result result = NULL; diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index 0889400b8..3e65176b1 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -25,6 +25,7 @@ #include <stdio.h> #include <string.h> #include <assert.h> +#include <time.h> #include <osmocom/core/talloc.h> @@ -333,6 +334,21 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason) s->net = bts->network; /* Indicate "attached to LAC" */ s->lac = bts->location_area_code; + + /* 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); @@ -364,6 +380,25 @@ void subscr_update_from_db(struct gsm_subscriber *sub) db_subscriber_update(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); + + LOGP(DMM, LOGL_NOTICE, "Expiring inactive subscriber %s (ID %i)\n", + subscr_name(s), id); + s->lac = GSM_LAC_RESERVED_DETACHED; + db_sync_subscriber(s); + + subscr_put(s); +} + +void subscr_expire(struct gsm_network *net) +{ + db_subscriber_expire(net, subscr_expire_callback); +} + int subscr_pending_requests(struct gsm_subscriber *sub) { struct subscr_request *req; diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index 40c6f4337..93630ae6a 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -63,6 +63,8 @@ static int use_db_counter = 1; /* timer to store statistics */ #define DB_SYNC_INTERVAL 60, 0 +#define EXPIRE_INTERVAL 10, 0 + static struct osmo_timer_list db_sync_timer; static void create_pcap_file(char *file) @@ -223,6 +225,12 @@ static void db_sync_timer_cb(void *data) osmo_timer_schedule(&db_sync_timer, DB_SYNC_INTERVAL); } +static void subscr_expire_cb(void *data) +{ + subscr_expire(bsc_gsmnet); + osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL); +} + void talloc_ctx_init(void); extern enum node_type bsc_vty_go_parent(struct vty *vty); @@ -308,6 +316,10 @@ int main(int argc, char **argv) if (use_db_counter) osmo_timer_schedule(&db_sync_timer, DB_SYNC_INTERVAL); + bsc_gsmnet->subscr_expire_timer.cb = subscr_expire_cb; + bsc_gsmnet->subscr_expire_timer.data = NULL; + osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL); + signal(SIGINT, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); |