aboutsummaryrefslogtreecommitdiffstats
path: root/src/db_hlr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/db_hlr.c')
-rw-r--r--src/db_hlr.c122
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);
+}