Major update; Code now supports SAI, LU and ISD transactions

We also introduce a 'gsup_router' which enables us to route
a transaction to a given VLR.  It works based on the SERIAL attribute
communicated at time of the IPA multiplex setup as part of the CCM
sub-protocol.
diff --git a/src/db_hlr.c b/src/db_hlr.c
new file mode 100644
index 0000000..5d22717
--- /dev/null
+++ b/src/db_hlr.c
@@ -0,0 +1,136 @@
+/* (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"
+
+#define LOGHLR(imsi, level, fmt, args ...)	LOGP(DAUC, level, "%s: " fmt, imsi, ## args)
+
+#define SL3_TXT(x, stmt, idx)					do {	\
+		const char *_txt = (const char *) sqlite3_column_text(stmt, idx);	\
+		if (_txt)						\
+			strncpy(x, _txt, sizeof(x));			\
+			x[sizeof(x)-1] = '\0';				\
+		} while (0)
+
+int db_subscr_get(struct db_context *dbc, const char *imsi,
+		  struct hlr_subscriber *subscr)
+{
+	sqlite3_stmt *stmt = dbc->stmt[SEL_BY_IMSI];
+	int rc, ret = 0;
+
+	rc = sqlite3_bind_text(stmt, 1, imsi, -1, SQLITE_STATIC);
+	if (rc != SQLITE_OK) {
+		LOGHLR(imsi, LOGL_ERROR, "Error binding IMSI: %d\n", rc);
+		return -1;
+	}
+
+	/* execute the statement */
+	rc = sqlite3_step(stmt);
+	if (rc != SQLITE_ROW) {
+		LOGHLR(imsi, LOGL_ERROR, "Error executing SQL: %d\n", rc);
+		ret = -2;
+		goto out;
+	}
+
+	/* obtain the various columns */
+	subscr->id = sqlite3_column_int64(stmt, 0);
+	SL3_TXT(subscr->imsi, stmt, 1);
+	SL3_TXT(subscr->msisdn, stmt, 2);
+	SL3_TXT(subscr->vlr_number, stmt, 3);
+	SL3_TXT(subscr->sgsn_number, stmt, 4);
+	SL3_TXT(subscr->sgsn_address, stmt, 5);
+	subscr->periodic_lu_timer = sqlite3_column_int(stmt, 6);
+	subscr->periodic_rau_tau_timer = sqlite3_column_int(stmt, 7);
+	subscr->nam_cs = sqlite3_column_int(stmt, 8);
+	subscr->nam_ps = sqlite3_column_int(stmt, 9);
+	subscr->lmsi = sqlite3_column_int(stmt, 10);
+	subscr->ms_purged_cs = sqlite3_column_int(stmt, 11);
+	subscr->ms_purged_ps = sqlite3_column_int(stmt, 12);
+
+out:
+	/* 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 ret;
+}
+
+int db_subscr_lu(struct db_context *dbc,
+		 const struct hlr_subscriber *subscr,
+		 const char *vlr_or_sgsn_number, bool lu_is_ps)
+{
+	sqlite3_stmt *stmt = dbc->stmt[UPD_VLR_BY_ID];
+	const char *txt;
+	int rc, ret = 0;
+
+	if (lu_is_ps) {
+		stmt = dbc->stmt[UPD_SGSN_BY_ID];
+		txt = subscr->sgsn_number;
+	} else {
+		stmt = dbc->stmt[UPD_VLR_BY_ID];
+		txt = subscr->vlr_number;
+	}
+
+	rc = sqlite3_bind_int64(stmt, 1, subscr->id);
+	if (rc != SQLITE_OK) {
+		LOGP(DAUC, LOGL_ERROR, "Error binding ID: %d\n", rc);
+		return -1;
+	}
+
+	rc = sqlite3_bind_text(stmt, 2, txt, -1, SQLITE_STATIC);
+	if (rc != SQLITE_OK) {
+		LOGP(DAUC, LOGL_ERROR, "Error binding VLR/SGSN Number: %d\n", rc);
+		ret = -2;
+		goto out;
+	}
+
+	/* execute the statement */
+	rc = sqlite3_step(stmt);
+	if (rc != SQLITE_DONE) {
+		LOGP(DAUC, LOGL_ERROR, "Error updating SQN: %d\n", rc);
+		ret = -3;
+		goto out;
+	}
+out:
+	/* 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 ret;
+}