initial import of osmo-gsup-hlr code so far
diff --git a/src/db_auc.c b/src/db_auc.c
new file mode 100644
index 0000000..fa5f3e5
--- /dev/null
+++ b/src/db_auc.c
@@ -0,0 +1,208 @@
+/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/crypt/auth.h>
+
+#include <sqlite3.h>
+
+#include "logging.h"
+#include "db.h"
+#include "auc.h"
+#include "rand.h"
+
+#define LOGAUC(imsi, level, fmt, args ...)	LOGP(DAUC, level, "%s: " fmt, imsi, ## args)
+
+/* update the SQN for a given subscriber ID */
+int db_update_sqn(struct db_context *dbc, uint64_t id,
+		      uint64_t new_sqn)
+{
+	sqlite3_stmt *stmt = dbc->stmt[AUC_UPD_SQN];
+	int rc;
+
+	/* bind new SQN and subscriber ID */
+	rc = sqlite3_bind_int64(stmt, 1, new_sqn);
+	if (rc != SQLITE_OK) {
+		LOGP(DAUC, LOGL_ERROR, "Error binding SQN: %d\n", rc);
+		return -1;
+	}
+
+	rc = sqlite3_bind_int64(stmt, 2, id);
+	if (rc != SQLITE_OK) {
+		LOGP(DAUC, LOGL_ERROR, "Error binding Subscrber ID: %d\n", rc);
+		return -1;
+	}
+
+	/* execute the statement */
+	rc = sqlite3_step(stmt);
+	if (rc != SQLITE_DONE) {
+		LOGP(DAUC, LOGL_ERROR, "Error updating SQN: %d\n", rc);
+		return -2;
+	}
+
+	/* remove bindings and reset statement to be re-executed */
+	rc = sqlite3_clear_bindings(stmt);
+	if (rc != SQLITE_OK) {
+		LOGP(DAUC, LOGL_ERROR, "Error clerearing bindings: %d\n", rc);
+	}
+	rc = sqlite3_reset(stmt);
+	if (rc != SQLITE_OK) {
+		LOGP(DAUC, LOGL_ERROR, "Error in sqlite3_reset: %d\n", rc);
+	}
+
+	return 0;
+}
+
+/* obtain the authentication data for a given imsi */
+int db_get_auth_data(struct db_context *dbc, const char *imsi,
+		     struct osmo_sub_auth_data *aud2g,
+		     struct osmo_sub_auth_data *aud3g,
+		     uint64_t *subscr_id)
+{
+	sqlite3_stmt *stmt = dbc->stmt[AUC_BY_IMSI];
+	int rc;
+
+	memset(aud2g, 0, sizeof(*aud2g));
+	memset(aud3g, 0, sizeof(*aud3g));
+
+	/* bind the IMSI value */
+	rc = sqlite3_bind_text(stmt, 1, imsi, -1,
+				SQLITE_STATIC);
+	if (rc != SQLITE_OK) {
+		LOGAUC(imsi, LOGL_ERROR, "Error binding IMSI: %d\n", rc);
+	}
+
+	/* execute the statement */
+	rc = sqlite3_step(stmt);
+	if (rc != SQLITE_ROW) {
+		LOGAUC(imsi, LOGL_ERROR, "Error executing SQL: %d\n", rc);
+		goto out;
+	}
+
+	/* as an optimization, we retrieve the subscriber ID, to ensure we can
+	 * update the SQN later without having to go back via a JOIN with the
+	 * subscriber table. */
+	if (subscr_id)
+		*subscr_id = sqlite3_column_int64(stmt, 0);
+
+	for (int i = 0; i < 10; i++)
+		LOGAUC(imsi, LOGL_DEBUG, "col_type(%d)=%d\n", i,
+				sqlite3_column_type(stmt, i));
+
+	/* obtain result values using sqlite3_column_*() */
+	if (sqlite3_column_type(stmt, 1) == SQLITE_INTEGER) {
+		/* we do have some 2G authentication data */
+		const uint8_t *ki;
+
+		aud2g->algo = sqlite3_column_int(stmt, 1);
+		ki = sqlite3_column_text(stmt, 2);
+#if 0
+		if (sqlite3_column_bytes(stmt, 2) != sizeof(aud2g->u.gsm.ki)) {
+			LOGAUC(imsi, LOGL_ERROR, "Error reading Ki: %d\n", rc);
+			goto end_2g;
+		}
+#endif
+		memcpy(&aud2g->u.gsm.ki, ki, sizeof(aud2g->u.gsm.ki));
+		aud2g->type = OSMO_AUTH_TYPE_GSM;
+	} else
+		LOGAUC(imsi, LOGL_DEBUG, "No 2G Auth Data\n");
+//end_2g:
+	if (sqlite3_column_type(stmt, 3) == SQLITE_INTEGER) {
+		/* we do have some 3G authentication data */
+		const uint8_t *k, *op, *opc;
+
+		aud3g->algo = sqlite3_column_int(stmt, 3);
+		k = sqlite3_column_text(stmt, 4);
+		if (!k) {
+			LOGAUC(imsi, LOGL_ERROR, "Error reading K: %d\n", rc);
+			goto out;
+		}
+		memcpy(&aud3g->u.umts.k, k, sizeof(aud3g->u.umts.k));
+		/* UMTS Subscribers can have either OP or OPC */
+		op = sqlite3_column_text(stmt, 5);
+		if (!op) {
+			opc = sqlite3_column_text(stmt, 6);
+			if (!opc) {
+				LOGAUC(imsi, LOGL_ERROR, "Error reading OPC: %d\n", rc);
+				goto out;
+			}
+			memcpy(&aud3g->u.umts.opc, opc, sizeof(aud3g->u.umts.opc));
+			aud3g->u.umts.opc_is_op = 0;
+		} else {
+			memcpy(&aud3g->u.umts.opc, op, sizeof(aud3g->u.umts.opc));
+			aud3g->u.umts.opc_is_op = 1;
+		}
+		aud3g->u.umts.sqn = sqlite3_column_int64(stmt, 7);
+		/* FIXME: amf? */
+		aud3g->type = OSMO_AUTH_TYPE_UMTS;
+	} else
+		LOGAUC(imsi, LOGL_DEBUG, "No 3G Auth Data\n");
+out:
+	/* remove bindings and reset statement to be re-executed */
+	rc = sqlite3_clear_bindings(stmt);
+	if (rc != SQLITE_OK) {
+		LOGAUC(imsi, LOGL_ERROR, "Error in sqlite3_clear_bindings(): %d\n", rc);
+	}
+	rc = sqlite3_reset(stmt);
+	if (rc != SQLITE_OK) {
+		LOGAUC(imsi, LOGL_ERROR, "Error in sqlite3_reset(): %d\n", rc);
+	}
+
+	if (aud2g->type == 0 && aud3g->type == 0)
+		return -1;
+
+	return 0;
+}
+
+int db_get_auc(struct db_context *dbc, const char *imsi,
+	    struct osmo_auth_vector *vec, unsigned int num_vec,
+	    const uint8_t *rand_auts, const uint8_t *auts)
+{
+	struct osmo_sub_auth_data aud2g, aud3g;
+	uint64_t subscr_id;
+	int rc;
+
+	rc = db_get_auth_data(dbc, imsi, &aud2g, &aud3g, &subscr_id);
+	if (rc < 0)
+		return rc;
+
+	LOGAUC(imsi, LOGL_INFO, "Calling to generate %u vectors\n", num_vec);
+	rc = auc_compute_vectors(vec, num_vec, &aud2g, &aud3g, rand_auts, auts);
+	if (rc < 0)
+		num_vec = 0;
+	else
+		num_vec = rc;
+	LOGAUC(imsi, LOGL_INFO, "Generated %u vectors\n", num_vec);
+
+	/* Update SQN in database, as needed */
+	if (aud3g.algo) {
+		LOGAUC(imsi, LOGL_DEBUG, "Updating SQN in DB\n");
+		rc = db_update_sqn(dbc, subscr_id, aud3g.u.umts.sqn);
+		/* don't tell caller we generated any triplets in case of
+		 * update error */
+		if (rc < 0) {
+			LOGAUC(imsi, LOGL_ERROR, "Error updating SQN: %d\n", rc);
+			num_vec = 0;
+		}
+	}
+
+	return num_vec;
+}