diff options
-rw-r--r-- | include/osmocom/hlr/db.h | 7 | ||||
-rw-r--r-- | sql/hlr.sql | 10 | ||||
-rw-r--r-- | src/db.c | 29 | ||||
-rw-r--r-- | src/db_hlr.c | 103 | ||||
-rw-r--r-- | src/hlr.c | 13 | ||||
-rw-r--r-- | tests/db/db_test.c | 45 | ||||
-rw-r--r-- | tests/db/db_test.err | 80 | ||||
-rw-r--r-- | tests/db_upgrade/db_upgrade_test.ok | 10 |
8 files changed, 292 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; @@ -28,7 +28,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," \ @@ -85,6 +85,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) @@ -479,6 +482,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, @@ -486,6 +512,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); +} @@ -280,13 +280,14 @@ 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; int num_auth_vectors = OSMO_GSUP_MAX_NUM_AUTH_INFO; + unsigned int auc_3g_ind; int rc; subscr_create_on_demand(req->gsup.imsi); @@ -297,6 +298,14 @@ static int rx_send_auth_info(unsigned int auc_3g_ind, struct osmo_gsup_req *req) if (req->gsup.num_auth_vectors > 0 && req->gsup.num_auth_vectors <= OSMO_GSUP_MAX_NUM_AUTH_INFO) num_auth_vectors = req->gsup.num_auth_vectors; + 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, @@ -516,7 +525,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. |