diff options
Diffstat (limited to 'src/db_hlr.c')
-rw-r--r-- | src/db_hlr.c | 122 |
1 files changed, 116 insertions, 6 deletions
diff --git a/src/db_hlr.c b/src/db_hlr.c index a4c467e..aa2e365 100644 --- a/src/db_hlr.c +++ b/src/db_hlr.c @@ -1,4 +1,4 @@ -/* (C) 2015 by Harald Welte <laforge@gnumonks.org> +/* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org> * * All Rights Reserved * @@ -45,7 +45,8 @@ * \param[in,out] dbc database context. * \param[in] imsi ASCII string of IMSI digits, is validated. * \param[in] flags Bitmask of DB_SUBSCR_FLAG_*. - * \returns 0 on success, -EINVAL on invalid IMSI, -EIO on database error. + * \returns 0 on success, -EINVAL on invalid IMSI, -EEXIST if subscriber with + * provided imsi already exists, -EIO on other database errors. */ int db_subscr_create(struct db_context *dbc, const char *imsi, uint8_t flags) { @@ -73,6 +74,8 @@ int db_subscr_create(struct db_context *dbc, const char *imsi, uint8_t flags) if (rc != SQLITE_DONE) { LOGHLR(imsi, LOGL_ERROR, "Cannot create subscriber: SQL error: (%d) %s\n", rc, sqlite3_errmsg(dbc->db)); + if (rc == SQLITE_CONSTRAINT_UNIQUE) + return -EEXIST; return -EIO; } @@ -235,8 +238,9 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id, case OSMO_AUTH_ALG_COMP128v1: case OSMO_AUTH_ALG_COMP128v2: case OSMO_AUTH_ALG_COMP128v3: - case OSMO_AUTH_ALG_XOR: + case OSMO_AUTH_ALG_XOR_2G: break; + case OSMO_AUTH_ALG_XOR_3G: case OSMO_AUTH_ALG_MILENAGE: LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:" " auth algo not suited for 2G: %s\n", @@ -264,11 +268,12 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id, switch (aud->algo) { case OSMO_AUTH_ALG_NONE: case OSMO_AUTH_ALG_MILENAGE: - case OSMO_AUTH_ALG_XOR: + case OSMO_AUTH_ALG_XOR_3G: break; case OSMO_AUTH_ALG_COMP128v1: case OSMO_AUTH_ALG_COMP128v2: case OSMO_AUTH_ALG_COMP128v3: + case OSMO_AUTH_ALG_XOR_2G: LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:" " auth algo not suited for 3G: %s\n", osmo_auth_alg_name(aud->algo)); @@ -281,12 +286,12 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id, if (aud->algo == OSMO_AUTH_ALG_NONE) break; - if (!osmo_is_hexstr(aud->u.umts.k, 32, 32, true)) { + if (!osmo_is_hexstr(aud->u.umts.k, 32, 64, true)) { LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:" " Invalid K: '%s'\n", aud->u.umts.k); return -EINVAL; } - if (!osmo_is_hexstr(aud->u.umts.opc, 32, 32, true)) { + if (!osmo_is_hexstr(aud->u.umts.opc, 32, 64, true)) { LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:" " Invalid OP/OPC: '%s'\n", aud->u.umts.opc); return -EINVAL; @@ -648,6 +653,8 @@ int db_subscrs_get(struct db_context *dbc, const char *filter_type, const char * if (!filter_type) { stmt = dbc->stmt[DB_STMT_SEL_ALL]; + } else if (strcmp(filter_type, "imei") == 0) { + stmt = dbc->stmt[DB_STMT_SEL_FILTER_IMEI]; } else if (strcmp(filter_type, "imsi") == 0) { stmt = dbc->stmt[DB_STMT_SEL_FILTER_IMSI]; } else if (strcmp(filter_type, "msisdn") == 0) { @@ -970,3 +977,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_cni_peer_id *vlr, + unsigned int *ind, bool del) +{ + const char *vlr_name = NULL; + int rc; + + switch (vlr->type) { + case OSMO_CNI_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_cni_peer_id type: %s\n", + osmo_cni_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_cni_peer_id *vlr, unsigned int *ind) +{ + return _db_ind(dbc, vlr, ind, false); +} + +int db_ind_del(struct db_context *dbc, const struct osmo_cni_peer_id *vlr) +{ + return _db_ind(dbc, vlr, NULL, true); +} |