aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/hlr/db.h7
-rw-r--r--sql/hlr.sql10
-rw-r--r--src/db.c29
-rw-r--r--src/db_hlr.c103
-rw-r--r--src/gsupclient/gsup_peer_id.c3
-rw-r--r--src/hlr.c14
-rw-r--r--tests/db/db_test.c45
-rw-r--r--tests/db/db_test.err80
-rw-r--r--tests/db_upgrade/db_upgrade_test.ok10
9 files changed, 296 insertions, 5 deletions
diff --git a/include/osmocom/hlr/db.h b/include/osmocom/hlr/db.h
index 9309b8f..1f1bacb 100644
--- a/include/osmocom/hlr/db.h
+++ b/include/osmocom/hlr/db.h
@@ -4,6 +4,7 @@
#include <sqlite3.h>
#include <osmocom/gsupclient/gsup_peer_id.h>
+#include <osmocom/gsm/gsup.h>
struct hlr;
@@ -33,6 +34,9 @@ enum stmt_idx {
DB_STMT_SET_LAST_LU_SEEN_PS,
DB_STMT_EXISTS_BY_IMSI,
DB_STMT_EXISTS_BY_MSISDN,
+ DB_STMT_IND_ADD,
+ DB_STMT_IND_SELECT,
+ DB_STMT_IND_DEL,
_NUM_DB_STMT
};
@@ -163,6 +167,9 @@ int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
bool purge_val, bool is_ps);
+int db_ind(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr, unsigned int *ind);
+int db_ind_del(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr);
+
/*! Call sqlite3_column_text() and copy result to a char[].
* \param[out] buf A char[] used as sizeof() arg(!) and osmo_strlcpy() target.
* \param[in] stmt An sqlite3_stmt*.
diff --git a/sql/hlr.sql b/sql/hlr.sql
index 98e586d..e855a6c 100644
--- a/sql/hlr.sql
+++ b/sql/hlr.sql
@@ -79,8 +79,16 @@ CREATE TABLE auc_3g (
ind_bitlen INTEGER NOT NULL DEFAULT 5
);
+CREATE TABLE ind (
+ -- 3G auth IND pool to be used for this VLR
+ ind INTEGER PRIMARY KEY,
+ -- VLR identification, usually the GSUP source_name
+ vlr TEXT NOT NULL,
+ UNIQUE (vlr)
+);
+
CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi);
-- Set HLR database schema version number
-- Note: This constant is currently duplicated in src/db.c and must be kept in sync!
-PRAGMA user_version = 5;
+PRAGMA user_version = 6;
diff --git a/src/db.c b/src/db.c
index 3cbd9c9..c265ffa 100644
--- a/src/db.c
+++ b/src/db.c
@@ -30,7 +30,7 @@
#include "db_bootstrap.h"
/* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */
-#define CURRENT_SCHEMA_VERSION 5
+#define CURRENT_SCHEMA_VERSION 6
#define SEL_COLUMNS \
"id," \
@@ -87,6 +87,9 @@ static const char *stmt_sql[] = {
[DB_STMT_SET_LAST_LU_SEEN_PS] = "UPDATE subscriber SET last_lu_seen_ps = datetime($val, 'unixepoch') WHERE id = $subscriber_id",
[DB_STMT_EXISTS_BY_IMSI] = "SELECT 1 FROM subscriber WHERE imsi = $imsi",
[DB_STMT_EXISTS_BY_MSISDN] = "SELECT 1 FROM subscriber WHERE msisdn = $msisdn",
+ [DB_STMT_IND_ADD] = "INSERT INTO ind (vlr) VALUES ($vlr)",
+ [DB_STMT_IND_SELECT] = "SELECT ind FROM ind WHERE vlr = $vlr",
+ [DB_STMT_IND_DEL] = "DELETE FROM ind WHERE vlr = $vlr",
};
static void sql3_error_log_cb(void *arg, int err_code, const char *msg)
@@ -481,6 +484,29 @@ static int db_upgrade_v5(struct db_context *dbc)
return rc;
}
+static int db_upgrade_v6(struct db_context *dbc)
+{
+ int rc;
+ const char *statements[] = {
+ "CREATE TABLE ind (\n"
+ " -- 3G auth IND pool to be used for this VLR\n"
+ " ind INTEGER PRIMARY KEY,\n"
+ " -- VLR identification, usually the GSUP source_name\n"
+ " vlr TEXT NOT NULL,\n"
+ " UNIQUE (vlr)\n"
+ ")"
+ ,
+ "PRAGMA user_version = 6",
+ };
+
+ rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
+ if (rc != SQLITE_DONE) {
+ LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 6\n");
+ return rc;
+ }
+ return rc;
+}
+
typedef int (*db_upgrade_func_t)(struct db_context *dbc);
static db_upgrade_func_t db_upgrade_path[] = {
db_upgrade_v1,
@@ -488,6 +514,7 @@ static db_upgrade_func_t db_upgrade_path[] = {
db_upgrade_v3,
db_upgrade_v4,
db_upgrade_v5,
+ db_upgrade_v6,
};
static int db_get_user_version(struct db_context *dbc)
diff --git a/src/db_hlr.c b/src/db_hlr.c
index 030a6a7..b13763a 100644
--- a/src/db_hlr.c
+++ b/src/db_hlr.c
@@ -884,3 +884,106 @@ out:
return ret;
}
+
+static int _db_ind_run(struct db_context *dbc, sqlite3_stmt *stmt, const char *vlr, bool reset)
+{
+ int rc;
+
+ if (!db_bind_text(stmt, "$vlr", vlr))
+ return -EIO;
+
+ /* execute the statement */
+ rc = sqlite3_step(stmt);
+ if (reset)
+ db_remove_reset(stmt);
+ return rc;
+}
+
+static int _db_ind_add(struct db_context *dbc, const char *vlr)
+{
+ sqlite3_stmt *stmt = dbc->stmt[DB_STMT_IND_ADD];
+ if (_db_ind_run(dbc, stmt, vlr, true) != SQLITE_DONE) {
+ LOGP(DDB, LOGL_ERROR, "Cannot create IND entry for %s\n", osmo_quote_str_c(OTC_SELECT, vlr, -1));
+ return -EIO;
+ }
+ return 0;
+}
+
+static int _db_ind_del(struct db_context *dbc, const char *vlr)
+{
+ sqlite3_stmt *stmt = dbc->stmt[DB_STMT_IND_DEL];
+ _db_ind_run(dbc, stmt, vlr, true);
+ /* We don't really care about the result. If it didn't exist, then that was the goal anyway. */
+ return 0;
+}
+
+static int _db_ind_get(struct db_context *dbc, const char *vlr, unsigned int *ind)
+{
+ int ret = 0;
+ sqlite3_stmt *stmt = dbc->stmt[DB_STMT_IND_SELECT];
+ int rc = _db_ind_run(dbc, stmt, vlr, false);
+ if (rc == SQLITE_DONE) {
+ /* Does not exist yet */
+ ret = -ENOENT;
+ goto out;
+ } else if (rc != SQLITE_ROW) {
+ LOGP(DDB, LOGL_ERROR, "Error executing SQL: %d\n", rc);
+ ret = -EIO;
+ goto out;
+ }
+
+ OSMO_ASSERT(ind);
+ *ind = sqlite3_column_int64(stmt, 0);
+out:
+ db_remove_reset(stmt);
+ return ret;
+}
+
+int _db_ind(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr,
+ unsigned int *ind, bool del)
+{
+ const char *vlr_name = NULL;
+ int rc;
+
+ switch (vlr->type) {
+ case OSMO_GSUP_PEER_ID_IPA_NAME:
+ if (vlr->ipa_name.len < 2 || vlr->ipa_name.val[vlr->ipa_name.len - 1] != '\0') {
+ LOGP(DDB, LOGL_ERROR, "Expecting VLR ipa_name to be zero terminated; found %s\n",
+ osmo_ipa_name_to_str(&vlr->ipa_name));
+ return -ENOTSUP;
+ }
+ vlr_name = (const char*)vlr->ipa_name.val;
+ break;
+ default:
+ LOGP(DDB, LOGL_ERROR, "Unsupported osmo_gsup_peer_id type: %s\n",
+ osmo_gsup_peer_id_type_name(vlr->type));
+ return -ENOTSUP;
+ }
+
+ if (del)
+ return _db_ind_del(dbc, vlr_name);
+
+ rc = _db_ind_get(dbc, vlr_name, ind);
+ if (!rc)
+ return 0;
+
+ /* Does not exist yet, create. */
+ rc = _db_ind_add(dbc, vlr_name);
+ if (rc) {
+ LOGP(DDB, LOGL_ERROR, "Error creating IND entry for %s\n", osmo_quote_str_c(OTC_SELECT, vlr_name, -1));
+ return rc;
+ }
+
+ /* To be sure, query again from scratch. */
+ return _db_ind_get(dbc, vlr_name, ind);
+}
+
+int db_ind(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr, unsigned int *ind)
+{
+ return _db_ind(dbc, vlr, ind, false);
+}
+
+int db_ind_del(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr)
+{
+ return _db_ind(dbc, vlr, NULL, true);
+}
diff --git a/src/gsupclient/gsup_peer_id.c b/src/gsupclient/gsup_peer_id.c
index 9ac3af9..0a7bd73 100644
--- a/src/gsupclient/gsup_peer_id.c
+++ b/src/gsupclient/gsup_peer_id.c
@@ -132,8 +132,11 @@ int osmo_gsup_peer_id_set_str(struct osmo_gsup_peer_id *gsup_peer_id, enum osmo_
va_list ap;
int rc;
+ *gsup_peer_id = (struct osmo_gsup_peer_id){};
+
switch (type) {
case OSMO_GSUP_PEER_ID_IPA_NAME:
+ gsup_peer_id->type = OSMO_GSUP_PEER_ID_IPA_NAME;
va_start(ap, str_fmt);
rc = osmo_ipa_name_set_str_va(&gsup_peer_id->ipa_name, str_fmt, ap);
va_end(ap);
diff --git a/src/hlr.c b/src/hlr.c
index 79b50c2..215c0e8 100644
--- a/src/hlr.c
+++ b/src/hlr.c
@@ -280,12 +280,13 @@ int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val,
***********************************************************************/
/* process an incoming SAI request */
-static int rx_send_auth_info(unsigned int auc_3g_ind, struct osmo_gsup_req *req)
+static int rx_send_auth_info(struct osmo_gsup_req *req)
{
struct osmo_gsup_message gsup_out = {
.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT,
};
bool separation_bit = false;
+ unsigned int auc_3g_ind;
int rc;
subscr_create_on_demand(req->gsup.imsi);
@@ -293,6 +294,15 @@ static int rx_send_auth_info(unsigned int auc_3g_ind, struct osmo_gsup_req *req)
if (req->gsup.current_rat_type == OSMO_RAT_EUTRAN_SGS)
separation_bit = true;
+ rc = db_ind(g_hlr->dbc, &req->source_name, &auc_3g_ind);
+ if (rc) {
+ LOG_GSUP_REQ(req, LOGL_ERROR,
+ "Unable to determine 3G auth IND for source %s (rc=%d),"
+ " generating tuples with IND = 0\n",
+ osmo_gsup_peer_id_to_str(&req->source_name), rc);
+ auc_3g_ind = 0;
+ }
+
rc = db_get_auc(g_hlr->dbc, req->gsup.imsi, auc_3g_ind,
gsup_out.auth_vectors,
ARRAY_SIZE(gsup_out.auth_vectors),
@@ -511,7 +521,7 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
switch (req->gsup.message_type) {
/* requests sent to us */
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:
- rx_send_auth_info(conn->auc_3g_ind, req);
+ rx_send_auth_info(req);
break;
case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST:
rx_upd_loc_req(conn, req);
diff --git a/tests/db/db_test.c b/tests/db/db_test.c
index 4a0f3e8..bbc728e 100644
--- a/tests/db/db_test.c
+++ b/tests/db/db_test.c
@@ -918,6 +918,50 @@ static void test_subscr_sqn()
comment_end();
}
+static void test_ind()
+{
+ comment_start();
+
+#define ASSERT_IND(VLR, IND) do { \
+ unsigned int ind; \
+ struct osmo_gsup_peer_id vlr; \
+ OSMO_ASSERT(!osmo_gsup_peer_id_set_str(&vlr, OSMO_GSUP_PEER_ID_IPA_NAME, VLR)); \
+ ASSERT_RC(db_ind(dbc, &vlr, &ind), 0); \
+ fprintf(stderr, "%s ind = %u\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len), ind); \
+ if (ind != (IND)) \
+ fprintf(stderr, " ERROR: expected " #IND "\n"); \
+ } while (0)
+#define IND_DEL(VLR) do { \
+ struct osmo_gsup_peer_id vlr; \
+ OSMO_ASSERT(!osmo_gsup_peer_id_set_str(&vlr, OSMO_GSUP_PEER_ID_IPA_NAME, VLR)); \
+ ASSERT_RC(db_ind_del(dbc, &vlr), 0); \
+ fprintf(stderr, "%s ind deleted\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len)); \
+ } while (0)
+
+ ASSERT_IND("msc-23", 1);
+ ASSERT_IND("sgsn-11", 2);
+ ASSERT_IND("msc-42", 3);
+ ASSERT_IND("sgsn-22", 4);
+ ASSERT_IND("msc-0x17", 5);
+ ASSERT_IND("sgsn-0xaa", 6);
+ ASSERT_IND("msc-42", 3);
+ ASSERT_IND("sgsn-22", 4);
+ ASSERT_IND("msc-0x17", 5);
+ ASSERT_IND("sgsn-0xaa", 6);
+ ASSERT_IND("sgsn-0xbb", 7);
+ ASSERT_IND("msc-0x2a", 8);
+ ASSERT_IND("msc-42", 3);
+ ASSERT_IND("sgsn-22", 4);
+ ASSERT_IND("msc-23", 1);
+ ASSERT_IND("sgsn-11", 2);
+
+ IND_DEL("msc-0x17"); /* dropped IND == 5 */
+ ASSERT_IND("msc-0x2a", 8); /* known CS remains where it is */
+ ASSERT_IND("any-unknown", 9); /* new VLR takes a new IND from the end */
+
+ comment_end();
+}
+
static struct {
bool verbose;
} cmdline_opts = {
@@ -998,6 +1042,7 @@ int main(int argc, char **argv)
test_subscr_aud();
test_subscr_aud_invalid_len();
test_subscr_sqn();
+ test_ind();
printf("Done\n");
db_close(dbc);
diff --git a/tests/db/db_test.err b/tests/db/db_test.err
index 871e722..ddf6d00 100644
--- a/tests/db/db_test.err
+++ b/tests/db/db_test.err
@@ -1613,3 +1613,83 @@ db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> -ENOENT
===== test_subscr_sqn: SUCCESS
+
+===== test_ind
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-23\0" ind = 1
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-11\0" ind = 2
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-42\0" ind = 3
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-22\0" ind = 4
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-0x17\0" ind = 5
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-0xaa\0" ind = 6
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-42\0" ind = 3
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-22\0" ind = 4
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-0x17\0" ind = 5
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-0xaa\0" ind = 6
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-0xbb\0" ind = 7
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-0x2a\0" ind = 8
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-42\0" ind = 3
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-22\0" ind = 4
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-23\0" ind = 1
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"sgsn-11\0" ind = 2
+
+db_ind_del(dbc, &vlr) --> 0
+
+"msc-0x17\0" ind deleted
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"msc-0x2a\0" ind = 8
+
+db_ind(dbc, &vlr, &ind) --> 0
+
+"any-unknown\0" ind = 9
+
+===== test_ind: SUCCESS
+
diff --git a/tests/db_upgrade/db_upgrade_test.ok b/tests/db_upgrade/db_upgrade_test.ok
index 2bc6a39..0a45f7c 100644
--- a/tests/db_upgrade/db_upgrade_test.ok
+++ b/tests/db_upgrade/db_upgrade_test.ok
@@ -85,6 +85,7 @@ DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 2
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 3
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 4
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 5
+DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 6
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
Resulting db:
@@ -117,6 +118,13 @@ algo_id_3g|ind_bitlen|k|op|opc|sqn|subscriber_id
5|5|44444444444444444444444444444444|44444444444444444444444444444444||0|5
5|5|55555555555555555555555555555555||55555555555555555555555555555555|0|6
+Table: ind
+name|type|notnull|dflt_value|pk
+ind|INTEGER|0||1
+vlr|TEXT|1||0
+
+Table ind contents:
+
Table: subscriber
name|type|notnull|dflt_value|pk
ggsn_number|VARCHAR(15)|0||0
@@ -171,5 +179,5 @@ osmo-hlr --database $db --db-check --config-file $srcdir/osmo-hlr.cfg
rc = 0
DMAIN hlr starting
DDB using database: <PATH>test.db
-DDB Database <PATH>test.db' has HLR DB schema version 5
+DDB Database <PATH>test.db' has HLR DB schema version 6
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.