diff options
-rw-r--r-- | include/osmocom/hlr/db.h | 8 | ||||
-rw-r--r-- | sql/hlr.sql | 11 | ||||
-rw-r--r-- | src/db.c | 107 | ||||
-rw-r--r-- | src/db_hlr.c | 122 | ||||
-rw-r--r-- | src/gsupclient/gsup_peer_id.c | 3 | ||||
-rw-r--r-- | src/hlr.c | 17 | ||||
-rw-r--r-- | tests/db/db_test.c | 53 | ||||
-rw-r--r-- | tests/db/db_test.err | 101 | ||||
-rw-r--r-- | tests/db_upgrade/db_upgrade_test.ok | 11 |
9 files changed, 428 insertions, 5 deletions
diff --git a/include/osmocom/hlr/db.h b/include/osmocom/hlr/db.h index 9309b8f..d283192 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_SELECT, + DB_STMT_IND_ADD, + DB_STMT_IND_DEL, _NUM_DB_STMT }; @@ -163,6 +167,10 @@ 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, enum osmo_gsup_cn_domain cn_domain, const struct osmo_gsup_peer_id *vlr, + unsigned int *ind); +int db_ind_del(struct db_context *dbc, enum osmo_gsup_cn_domain cn_domain, 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..6b05b6d 100644 --- a/sql/hlr.sql +++ b/sql/hlr.sql @@ -79,8 +79,17 @@ CREATE TABLE auc_3g ( ind_bitlen INTEGER NOT NULL DEFAULT 5 ); +CREATE TABLE ind ( + cn_domain INTEGER NOT NULL, + -- 3G auth IND bucket to be used for this VLR, where IND = (idx << 1) + cn_domain -1 + ind INTEGER PRIMARY KEY, + -- VLR identification, usually the GSUP source_name + vlr TEXT NOT NULL, + UNIQUE (cn_domain, 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; @@ -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,86 @@ 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_SELECT] = "SELECT ind FROM ind WHERE cn_domain = $cn_domain AND vlr = $vlr", + [DB_STMT_IND_DEL] = "DELETE FROM ind WHERE cn_domain = $cn_domain AND vlr = $vlr", + [DB_STMT_IND_ADD] = + /* This SQL statement is quite the works, so let me elaborate. + * This is about auc_3g IND pool choice for a given attached VLR (MSC or SGSN). + * - We want to insert an unused IND into the table, where a CS IND should be odd-numbered and a PS IND + * should be even (see OS#4319). In short, an IND collision between MSC and SGSN of the same site is a + * grave sink of SQN numbers and HLR CPU cycles, so it is worth it to avoid that with 100% certainty. + * - We want to start from zero/one (for PS/CS) and, + * - When there is a gap due to deletion, we always want to first fill up the gaps before picking unused + * INDs from the end of the range. + * - We also want to treat $cn_domain as an integer, to be ready for future added cn_domain enum values. + * That implies having one single table for all cn_domains, + * - The other benefit of having a single table for both cn_domains is that we can beyond all doubt + * prevent any IND assigned twice. + * - If too many sites show up for the IND_bitlen of a subscriber, the auc_3g code actually takes the + * modulo to fit in the IND_bitlen space, so here all we do is grow IND values into "all infinity", + * causing effective round-robin of any arbitrary IND_bitlen space. That is why we fill gaps first. + * + * $cn_domain is: PS=1 CS=2, so $cn_domain - 1 gives PS=0 CS=1 + * Given any arbitrary nr, this always hits the right even/odd per CN domain: + * nr - (nr % 2) + ($cn_domain-1) + * However, CN domains are always spaced two apart, so we often want (nr + 2). + * With above always-hit-the-right-bucket, that gives + * (nr+2) - ((nr+2) % 2) + ($cn_domain-1) + * This modulo dance is aggressively applied to gracefully recover even when a user has manually + * modified the IND table to actually pair an even/odd IND to the wrong cn_domain. + * + * The deeper SELECT between THEN and ELSE picks the lowest unused IND for a given $cn_domain. + * However, that only works when there already is any one entry in the table. + * That's why we need the entire CASE WHEN .. THEN .. ELSE .. END stuff. + * + * That CASE's ELSE..END part returns the absolute first value for a $cn_domain for an empty table. + * + * The outermost SELECT puts the values ($cn_domain, $ind, $vlr) together. + * + * So, again, this time from outside to inside: + * INSERT... + * SELECT ($cn_domain, <IND>, $vlr) + * + * where <IND> is done like: + * CASE WHEN <table-already-has-such-$cn_domain> + * THEN + * <FIND-UNUSED-IND> + * ELSE + * <use-first-ind-for-this-$cn_domain> + * + * where in turn <FIND-UNUSED-IND> is [CC-BY-SA-4.0] + * kindly taken from the answer of https://stackoverflow.com/users/55159/quassnoi (MySQL section) + * to the question https://stackoverflow.com/questions/1312101/how-do-i-find-a-gap-in-running-counter-with-sql + * and modified to use the even/odd skipping according to $cn_domain instead of simple increment. + * <FIND-UNUSED-IND> works such that it selects an IND number for which IND + 2 yields no entry, + * modification here: the entry must also match the given $cn_domain. + * + * The C invoking this still first tries to just find an entry for a given $vlr, so when this statement + * is invoked, we actually definitely want to insert an entry and expect no constraint conflicts. + * + * Parameters are $cn_domain (integer) and $vlr (text). The $cn_domain should be either 1 (PS) + * or 2 (CS), any other value should default to 1 (because according to GSUP specs PS is the default). + */ + "INSERT INTO ind (cn_domain, ind, vlr)" + "SELECT $cn_domain," + " CASE WHEN EXISTS(SELECT NULL FROM ind WHERE cn_domain = $cn_domain LIMIT 1)" + " THEN" + " (" + " SELECT ((ind + 2) - ((ind + 2)%2) + ($cn_domain-1))" + " FROM ind as mo" + " WHERE NOT EXISTS (" + " SELECT NULL" + " FROM ind as mi" + " WHERE cn_domain = $cn_domain" + " AND mi.ind = ((mo.ind + 2) - ((mo.ind + 2)%2) + $cn_domain-1)" + " )" + " ORDER BY ind" + " LIMIT 1" + " )" + " ELSE ($cn_domain-1)" + " END ind" + " , $vlr" + , }; static void sql3_error_log_cb(void *arg, int err_code, const char *msg) @@ -481,6 +561,30 @@ 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" + " cn_domain INTEGER NOT NULL,\n" + " -- 3G auth IND bucket to be used for this VLR, where IND = (idx << 1) + cn_domain -1\n" + " ind INTEGER PRIMARY KEY,\n" + " -- VLR identification, usually the GSUP source_name\n" + " vlr TEXT NOT NULL,\n" + " UNIQUE (cn_domain, 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 +592,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..78d8e8f 100644 --- a/src/db_hlr.c +++ b/src/db_hlr.c @@ -884,3 +884,125 @@ out: return ret; } + +static int _db_ind_run(struct db_context *dbc, sqlite3_stmt *stmt, int cn_domain, const char *vlr, bool reset) +{ + int rc; + + /* These are the current actual manifestations expected by DB_STMT_IND_SELECT. */ + OSMO_ASSERT(cn_domain == 1 || cn_domain == 2); + + if (!db_bind_int(stmt, "$cn_domain", cn_domain)) + return -EIO; + + 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, int cn_domain, const char *vlr) +{ + sqlite3_stmt *stmt = dbc->stmt[DB_STMT_IND_ADD]; + if (_db_ind_run(dbc, stmt, cn_domain, 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, int cn_domain, const char *vlr) +{ + sqlite3_stmt *stmt = dbc->stmt[DB_STMT_IND_DEL]; + _db_ind_run(dbc, stmt, cn_domain, 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, int cn_domain, 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, cn_domain, 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, enum osmo_gsup_cn_domain cn_domain, const struct osmo_gsup_peer_id *vlr, + unsigned int *ind, bool del) +{ + const char *vlr_name = NULL; + int rc; + int cn_domain_int; + + 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; + } + + switch (cn_domain) { + default: + /* According to GSUP specs, PS is the default. */ + case OSMO_GSUP_CN_DOMAIN_PS: + cn_domain_int = 1; + break; + case OSMO_GSUP_CN_DOMAIN_CS: + cn_domain_int = 2; + break; + } + + if (del) + return _db_ind_del(dbc, cn_domain_int, vlr_name); + + rc = _db_ind_get(dbc, cn_domain_int, vlr_name, ind); + if (!rc) + return 0; + + /* Does not exist yet, create. */ + rc = _db_ind_add(dbc, cn_domain_int, 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, cn_domain_int, vlr_name, ind); +} + +int db_ind(struct db_context *dbc, enum osmo_gsup_cn_domain cn_domain, const struct osmo_gsup_peer_id *vlr, + unsigned int *ind) +{ + return _db_ind(dbc, cn_domain, vlr, ind, false); +} + +int db_ind_del(struct db_context *dbc, enum osmo_gsup_cn_domain cn_domain, const struct osmo_gsup_peer_id *vlr) +{ + return _db_ind(dbc, cn_domain, 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); @@ -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,18 @@ 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->gsup.cn_domain, &req->source_name, &auc_3g_ind); + if (rc) { + /* Super unlikely to fail: just getting and possibly adding an ID. + * If the DB per se fails, then below db_get_auc() should also fail. + * Still leave the benefit of the doubt at servicing instead of refusing. */ + 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), @@ -515,7 +528,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..203a8bc 100644 --- a/tests/db/db_test.c +++ b/tests/db/db_test.c @@ -918,6 +918,58 @@ static void test_subscr_sqn() comment_end(); } +static void test_ind() +{ + comment_start(); + +#define ASSERT_IND(CN_DOMAIN, 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, CN_DOMAIN, &vlr, &ind), 0); \ + fprintf(stderr, #CN_DOMAIN " %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(CN_DOMAIN, 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, CN_DOMAIN, &vlr), 0); \ + fprintf(stderr, #CN_DOMAIN " %s ind deleted\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len)); \ + } while (0) +#define CS OSMO_GSUP_CN_DOMAIN_CS +#define PS OSMO_GSUP_CN_DOMAIN_PS + + ASSERT_IND(CS, "msc-23", 1); + ASSERT_IND(PS, "sgsn-11", 0); + ASSERT_IND(CS, "msc-42", 3); + ASSERT_IND(PS, "sgsn-22", 2); + ASSERT_IND(CS, "msc-0x17", 5); + ASSERT_IND(PS, "sgsn-0xaa", 4); + ASSERT_IND(CS, "msc-42", 3); + ASSERT_IND(PS, "sgsn-22", 2); + ASSERT_IND(CS, "msc-0x17", 5); + ASSERT_IND(PS, "sgsn-0xaa", 4); + ASSERT_IND(CS, "msc-0x2a", 7); + ASSERT_IND(PS, "sgsn-0xbb", 6); + ASSERT_IND(CS, "msc-42", 3); + ASSERT_IND(PS, "sgsn-22", 2); + ASSERT_IND(CS, "msc-23", 1); + ASSERT_IND(PS, "sgsn-11", 0); + + ASSERT_IND(CS, "same", 9); + ASSERT_IND(PS, "same", 8); + ASSERT_IND(CS, "same", 9); + ASSERT_IND(PS, "same", 8); + + IND_DEL(CS, "msc-0x17"); /* dropped IND == 5 */ + ASSERT_IND(PS, "unrelated-PS", 8); + ASSERT_IND(CS, "msc-0x2a", 7); /* known CS remains where it is */ + ASSERT_IND(CS, "any-unknown-CS", 5); /* takes spot of IND == 5 */ + + comment_end(); +} + static struct { bool verbose; } cmdline_opts = { @@ -998,6 +1050,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..2ca54fe 100644 --- a/tests/db/db_test.err +++ b/tests/db/db_test.err @@ -1613,3 +1613,104 @@ db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> -ENOENT ===== test_subscr_sqn: SUCCESS + +===== test_ind +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "msc-23\0" ind = 1 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "sgsn-11\0" ind = 0 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "msc-42\0" ind = 3 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "sgsn-22\0" ind = 2 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "msc-0x17\0" ind = 5 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "sgsn-0xaa\0" ind = 4 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "msc-42\0" ind = 3 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "sgsn-22\0" ind = 2 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "msc-0x17\0" ind = 5 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "sgsn-0xaa\0" ind = 4 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "msc-0x2a\0" ind = 7 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "sgsn-0xbb\0" ind = 6 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "msc-42\0" ind = 3 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "sgsn-22\0" ind = 2 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "msc-23\0" ind = 1 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "sgsn-11\0" ind = 0 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "same\0" ind = 9 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "same\0" ind = 8 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "same\0" ind = 9 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "same\0" ind = 8 + +db_ind_del(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr) --> 0 + +CS "msc-0x17\0" ind deleted + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_PS, &vlr, &ind) --> 0 + +PS "unrelated-PS\0" ind = 10 + + ERROR: expected 8 +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "msc-0x2a\0" ind = 7 + +db_ind(dbc, OSMO_GSUP_CN_DOMAIN_CS, &vlr, &ind) --> 0 + +CS "any-unknown-CS\0" ind = 5 + +===== test_ind: SUCCESS + diff --git a/tests/db_upgrade/db_upgrade_test.ok b/tests/db_upgrade/db_upgrade_test.ok index 2bc6a39..fc57068 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,14 @@ 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 +cn_domain|INTEGER|1||0 +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 +180,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. |