aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2012-12-30 17:52:08 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2012-12-30 17:52:08 +0100
commit49e08e837a4ec90dbf14b7bf8bab19455e5de1f1 (patch)
tree1de8aec59fa6a6b0b22b56207a830bd7eaf2f92e
parent977cd13741e1e80879ea5b840206044fa1817aea (diff)
parentd85f6d54da2f45919f0ea4de0ad54562f05b0b20 (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.h1
-rw-r--r--openbsc/include/openbsc/gsm_data.h3
-rw-r--r--openbsc/include/openbsc/gsm_subscriber.h2
-rw-r--r--openbsc/src/libbsc/bsc_vty.c7
-rw-r--r--openbsc/src/libcommon/gsm_data.c1
-rw-r--r--openbsc/src/libmsc/db.c103
-rw-r--r--openbsc/src/libmsc/gsm_subscriber.c35
-rw-r--r--openbsc/src/osmo-nitb/bsc_hack.c12
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);