move headers to include/osmocom/hlr

Apply the same headers structure that we keep in most Osmocom source trees:
Keep noinst_HEADERS in include/osmocom/hlr and include them using
  #include <osmocom/hlr/*.h>

The only header kept in src/ is db_bootstrap.h, because it is generated during
build time. If it was built in include/osmocom/hlr, we would need db.o to
depend on db_bootstrap.h in a different subdir, which automake can't do well.

Change-Id: Ic912fe27f545b85443c5fb713d8c3c8aac23c9ad
diff --git a/include/Makefile.am b/include/Makefile.am
index dac7011..d8eb1ec 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,2 +1,3 @@
-nobase_include_HEADERS = osmocom/gsupclient/gsup_client.h
+SUBDIRS = osmocom
 
+nobase_include_HEADERS = osmocom/gsupclient/gsup_client.h
diff --git a/include/osmocom/Makefile.am b/include/osmocom/Makefile.am
new file mode 100644
index 0000000..dbc2344
--- /dev/null
+++ b/include/osmocom/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = \
+	hlr \
+	$(NULL)
diff --git a/include/osmocom/hlr/Makefile.am b/include/osmocom/hlr/Makefile.am
new file mode 100644
index 0000000..77a8764
--- /dev/null
+++ b/include/osmocom/hlr/Makefile.am
@@ -0,0 +1,14 @@
+noinst_HEADERS = \
+	auc.h \
+	ctrl.h \
+	db.h \
+	gsup_router.h \
+	gsup_server.h \
+	hlr.h \
+	hlr_ussd.h \
+	hlr_vty.h \
+	hlr_vty_subscr.h \
+	logging.h \
+	luop.h \
+	rand.h \
+	$(NULL)
diff --git a/include/osmocom/hlr/auc.h b/include/osmocom/hlr/auc.h
new file mode 100644
index 0000000..f5b6765
--- /dev/null
+++ b/include/osmocom/hlr/auc.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <osmocom/crypt/auth.h>
+
+int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
+			struct osmo_sub_auth_data *aud2g,
+			struct osmo_sub_auth_data *aud3g,
+			const uint8_t *rand_auts, const uint8_t *auts);
diff --git a/include/osmocom/hlr/ctrl.h b/include/osmocom/hlr/ctrl.h
new file mode 100644
index 0000000..3f9ba3f
--- /dev/null
+++ b/include/osmocom/hlr/ctrl.h
@@ -0,0 +1,34 @@
+/* OsmoHLR Control Interface implementation */
+
+/* (C) 2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Max Suraev <msuraev@sysmocom.de>
+ *
+ * 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/>.
+ *
+ */
+
+#pragma once
+
+#include <osmocom/ctrl/control_if.h>
+
+enum hlr_ctrl_node {
+	CTRL_NODE_SUBSCR = _LAST_CTRL_NODE,
+	CTRL_NODE_SUBSCR_BY,
+	_LAST_CTRL_NODE_HLR
+};
+
+int hlr_ctrl_cmds_install();
+struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr);
diff --git a/include/osmocom/hlr/db.h b/include/osmocom/hlr/db.h
new file mode 100644
index 0000000..15d83de
--- /dev/null
+++ b/include/osmocom/hlr/db.h
@@ -0,0 +1,168 @@
+#pragma once
+
+#include <stdbool.h>
+#include <sqlite3.h>
+
+struct hlr;
+
+enum stmt_idx {
+	DB_STMT_SEL_BY_IMSI,
+	DB_STMT_SEL_BY_MSISDN,
+	DB_STMT_SEL_BY_ID,
+	DB_STMT_SEL_BY_IMEI,
+	DB_STMT_UPD_VLR_BY_ID,
+	DB_STMT_UPD_SGSN_BY_ID,
+	DB_STMT_UPD_IMEI_BY_IMSI,
+	DB_STMT_AUC_BY_IMSI,
+	DB_STMT_AUC_UPD_SQN,
+	DB_STMT_UPD_PURGE_CS_BY_IMSI,
+	DB_STMT_UPD_PURGE_PS_BY_IMSI,
+	DB_STMT_UPD_NAM_PS_BY_IMSI,
+	DB_STMT_UPD_NAM_CS_BY_IMSI,
+	DB_STMT_SUBSCR_CREATE,
+	DB_STMT_DEL_BY_ID,
+	DB_STMT_SET_MSISDN_BY_IMSI,
+	DB_STMT_DELETE_MSISDN_BY_IMSI,
+	DB_STMT_AUC_2G_INSERT,
+	DB_STMT_AUC_2G_DELETE,
+	DB_STMT_AUC_3G_INSERT,
+	DB_STMT_AUC_3G_DELETE,
+	DB_STMT_SET_LAST_LU_SEEN,
+	DB_STMT_EXISTS_BY_IMSI,
+	DB_STMT_EXISTS_BY_MSISDN,
+	_NUM_DB_STMT
+};
+
+struct db_context {
+	char *fname;
+	sqlite3 *db;
+	sqlite3_stmt *stmt[_NUM_DB_STMT];
+};
+
+/* Optional feature to make SQLite3 using talloc */
+#ifdef SQLITE_USE_TALLOC
+int db_sqlite3_use_talloc(void *ctx);
+#endif
+
+void db_remove_reset(sqlite3_stmt *stmt);
+bool db_bind_text(sqlite3_stmt *stmt, const char *param_name, const char *text);
+bool db_bind_int(sqlite3_stmt *stmt, const char *param_name, int nr);
+bool db_bind_int64(sqlite3_stmt *stmt, const char *param_name, int64_t nr);
+void db_close(struct db_context *dbc);
+struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite3_logging, bool allow_upgrades);
+
+#include <osmocom/crypt/auth.h>
+
+/* 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,
+		     int64_t *subscr_id);
+
+int db_update_sqn(struct db_context *dbc, int64_t id,
+		      uint64_t new_sqn);
+
+int db_get_auc(struct db_context *dbc, const char *imsi,
+	       unsigned int auc_3g_ind, struct osmo_auth_vector *vec,
+	       unsigned int num_vec, const uint8_t *rand_auts,
+	       const uint8_t *auts);
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/protocol/gsm_23_003.h>
+
+/* TODO: Get this from somewhere? */
+#define GT_MAX_DIGITS	15
+
+struct hlr_subscriber {
+	struct llist_head list;
+
+	int64_t		id;
+	char		imsi[GSM23003_IMSI_MAX_DIGITS+1];
+	char		msisdn[GSM23003_MSISDN_MAX_DIGITS+1];
+	/* imeisv? */
+	char		imei[GSM23003_IMEI_NUM_DIGITS+1];
+	char		vlr_number[32];
+	char		sgsn_number[32];
+	char		sgsn_address[GT_MAX_DIGITS+1];
+	/* ggsn number + address */
+	/* gmlc number */
+	/* smsc number */
+	uint32_t	periodic_lu_timer;
+	uint32_t	periodic_rau_tau_timer;
+	bool		nam_cs;
+	bool		nam_ps;
+	uint32_t	lmsi;
+	bool		ms_purged_cs;
+	bool		ms_purged_ps;
+	time_t		last_lu_seen;
+};
+
+/* A format string for use with strptime(3). This format string is
+ * used to parse the last_lu_seen column stored in the HLR database.
+ * See https://sqlite.org/lang_datefunc.html, function datetime(). */
+#define DB_LAST_LU_SEEN_FMT "%Y-%m-%d %H:%M:%S"
+
+/* Like struct osmo_sub_auth_data, but the keys are in hexdump representation.
+ * This is useful because SQLite requires them in hexdump format, and callers
+ * like the VTY and CTRL interface also have them available as hexdump to begin
+ * with. In the binary format, a VTY command would first need to hexparse,
+ * after which the db function would again hexdump, copying to separate
+ * buffers. The roundtrip can be saved by providing char* to begin with. */
+struct sub_auth_data_str {
+	enum osmo_sub_auth_type type;
+	enum osmo_auth_algo algo;
+	union {
+		struct {
+			const char *opc;
+			const char *k;
+			uint64_t sqn;
+			int opc_is_op;
+			unsigned int ind_bitlen;
+		} umts;
+		struct {
+			const char *ki;
+		} gsm;
+	} u;
+};
+
+#define DB_SUBSCR_FLAG_NAM_CS	(1 << 1)
+#define DB_SUBSCR_FLAG_NAM_PS	(1 << 2)
+
+int db_subscr_create(struct db_context *dbc, const char *imsi, uint8_t flags);
+int db_subscr_delete_by_id(struct db_context *dbc, int64_t subscr_id);
+
+int db_subscr_update_msisdn_by_imsi(struct db_context *dbc, const char *imsi,
+				    const char *msisdn);
+int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
+			       const struct sub_auth_data_str *aud);
+int db_subscr_update_imei_by_imsi(struct db_context *dbc, const char* imsi, const char *imei);
+
+int db_subscr_exists_by_imsi(struct db_context *dbc, const char *imsi);
+int db_subscr_exists_by_msisdn(struct db_context *dbc, const char *msisdn);
+
+int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
+			  struct hlr_subscriber *subscr);
+int db_subscr_get_by_msisdn(struct db_context *dbc, const char *msisdn,
+			    struct hlr_subscriber *subscr);
+int db_subscr_get_by_id(struct db_context *dbc, int64_t id,
+			struct hlr_subscriber *subscr);
+int db_subscr_get_by_imei(struct db_context *dbc, const char *imei, struct hlr_subscriber *subscr);
+int db_subscr_nam(struct db_context *dbc, const char *imsi, bool nam_val, bool is_ps);
+int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
+		 const char *vlr_or_sgsn_number, bool is_ps);
+
+int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
+		    bool purge_val, bool is_ps);
+
+int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val, bool is_ps);
+
+/*! 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*.
+ * \param[in] idx   Index in stmt's returned columns.
+ */
+#define copy_sqlite3_text_to_buf(buf, stmt, idx) \
+	do { \
+		const char *_txt = (const char *) sqlite3_column_text(stmt, idx); \
+		osmo_strlcpy(buf, _txt, sizeof(buf)); \
+	} while (0)
diff --git a/include/osmocom/hlr/gsup_router.h b/include/osmocom/hlr/gsup_router.h
new file mode 100644
index 0000000..0fc10d0
--- /dev/null
+++ b/include/osmocom/hlr/gsup_router.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <stdint.h>
+#include <osmocom/hlr/gsup_server.h>
+
+struct gsup_route {
+	struct llist_head list;
+
+	uint8_t *addr;
+	struct osmo_gsup_conn *conn;
+};
+
+struct osmo_gsup_conn *gsup_route_find(struct osmo_gsup_server *gs,
+					const uint8_t *addr, size_t addrlen);
+
+struct gsup_route *gsup_route_find_by_conn(const struct osmo_gsup_conn *conn);
+
+/* add a new route for the given address to the given conn */
+int gsup_route_add(struct osmo_gsup_conn *conn, const uint8_t *addr, size_t addrlen);
+
+/* delete all routes for the given connection */
+int gsup_route_del_conn(struct osmo_gsup_conn *conn);
+
+int osmo_gsup_addr_send(struct osmo_gsup_server *gs,
+			const uint8_t *addr, size_t addrlen,
+			struct msgb *msg);
diff --git a/include/osmocom/hlr/gsup_server.h b/include/osmocom/hlr/gsup_server.h
new file mode 100644
index 0000000..9c4d483
--- /dev/null
+++ b/include/osmocom/hlr/gsup_server.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/abis/ipa.h>
+#include <osmocom/abis/ipaccess.h>
+#include <osmocom/gsm/gsup.h>
+
+#ifndef OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN
+#define OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN	43 /* TS 24.008 10.5.4.7 */
+#endif
+
+struct osmo_gsup_conn;
+
+/* Expects message in msg->l2h */
+typedef int (*osmo_gsup_read_cb_t)(struct osmo_gsup_conn *conn, struct msgb *msg);
+
+struct osmo_gsup_server {
+	/* private data of the application/user */
+	void *priv;
+
+	/* list of osmo_gsup_conn */
+	struct llist_head clients;
+
+	/* lu_operations list */
+	struct llist_head *luop;
+
+	struct ipa_server_link *link;
+	osmo_gsup_read_cb_t read_cb;
+	struct llist_head routes;
+};
+
+
+/* a single connection to a given client (SGSN, MSC) */
+struct osmo_gsup_conn {
+	struct llist_head list;
+
+	struct osmo_gsup_server *server;
+	struct ipa_server_conn *conn;
+	//struct oap_state oap_state;
+	struct tlv_parsed ccm;
+
+	unsigned int auc_3g_ind; /*!< IND index used for UMTS AKA SQN */
+
+	/* Set when Location Update is received: */
+	bool supports_cs; /* client supports OSMO_GSUP_CN_DOMAIN_CS */
+	bool supports_ps; /* client supports OSMO_GSUP_CN_DOMAIN_PS */
+};
+
+
+int osmo_gsup_conn_send(struct osmo_gsup_conn *conn, struct msgb *msg);
+int osmo_gsup_conn_ccm_get(const struct osmo_gsup_conn *clnt, uint8_t **addr,
+			   uint8_t tag);
+
+struct osmo_gsup_server *osmo_gsup_server_create(void *ctx,
+						 const char *ip_addr,
+						 uint16_t tcp_port,
+						 osmo_gsup_read_cb_t read_cb,
+						 struct llist_head *lu_op_lst,
+						 void *priv);
+
+void osmo_gsup_server_destroy(struct osmo_gsup_server *gsups);
+
+int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
+				     uint8_t *apn_buf, size_t apn_buf_size);
+int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
+					    uint8_t *msisdn_enc, size_t msisdn_enc_size,
+				            uint8_t *apn_buf, size_t apn_buf_size,
+					    enum osmo_gsup_cn_domain cn_domain);
diff --git a/include/osmocom/hlr/hlr.h b/include/osmocom/hlr/hlr.h
new file mode 100644
index 0000000..18c4a1d
--- /dev/null
+++ b/include/osmocom/hlr/hlr.h
@@ -0,0 +1,70 @@
+/* OsmoHLR generic header */
+
+/* (C) 2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Max Suraev <msuraev@sysmocom.de>
+ *
+ * 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/>.
+ *
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <osmocom/core/linuxlist.h>
+
+#define HLR_DEFAULT_DB_FILE_PATH "hlr.db"
+
+struct hlr_euse;
+
+struct hlr {
+	/* GSUP server pointer */
+	struct osmo_gsup_server *gs;
+
+	/* DB context */
+	char *db_file_path;
+	struct db_context *dbc;
+
+	/* Control Interface */
+	struct ctrl_handle *ctrl;
+	const char *ctrl_bind_addr;
+
+	/* Local bind addr */
+	char *gsup_bind_addr;
+
+	struct llist_head euse_list;
+	struct hlr_euse *euse_default;
+	struct llist_head iuse_list;
+
+	/* NCSS (call independent) session guard timeout value */
+	int ncss_guard_timeout;
+
+	struct llist_head ussd_routes;
+
+	struct llist_head ss_sessions;
+
+	bool store_imei;
+
+	bool subscr_create_on_demand;
+	/* Bitmask of DB_SUBSCR_FLAG_* */
+	uint8_t subscr_create_on_demand_flags;
+	unsigned int subscr_create_on_demand_rand_msisdn_len;
+};
+
+extern struct hlr *g_hlr;
+
+struct hlr_subscriber;
+
+void osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr);
diff --git a/include/osmocom/hlr/hlr_ussd.h b/include/osmocom/hlr/hlr_ussd.h
new file mode 100644
index 0000000..08e810e
--- /dev/null
+++ b/include/osmocom/hlr/hlr_ussd.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <stdbool.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/gsup.h>
+
+#include <osmocom/hlr/gsup_server.h>
+
+#define NCSS_GUARD_TIMEOUT_DEFAULT 30
+
+struct hlr_ussd_route {
+	/* g_hlr.routes */
+	struct llist_head list;
+	const char *prefix;
+	bool is_external;
+	union {
+		struct hlr_euse *euse;
+		const struct hlr_iuse *iuse;
+	} u;
+};
+
+struct hlr_euse {
+	/* list in the per-hlr list of EUSEs */
+	struct llist_head list;
+	struct hlr *hlr;
+	/* name (must match the IPA ID tag) */
+	const char *name;
+	/* human-readable description */
+	const char *description;
+
+	/* GSUP connection to the EUSE, if any */
+	struct osmo_gsup_conn *conn;
+};
+
+struct hlr_euse *euse_find(struct hlr *hlr, const char *name);
+struct hlr_euse *euse_alloc(struct hlr *hlr, const char *name);
+void euse_del(struct hlr_euse *euse);
+
+const struct hlr_iuse *iuse_find(const char *name);
+
+struct hlr_ussd_route *ussd_route_find_prefix(struct hlr *hlr, const char *prefix);
+struct hlr_ussd_route *ussd_route_prefix_alloc_int(struct hlr *hlr, const char *prefix,
+						   const struct hlr_iuse *iuse);
+struct hlr_ussd_route *ussd_route_prefix_alloc_ext(struct hlr *hlr, const char *prefix,
+						   struct hlr_euse *euse);
+void ussd_route_del(struct hlr_ussd_route *rt);
+
+int rx_proc_ss_req(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup);
+int rx_proc_ss_error(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup);
+
+struct ss_session;
+struct ss_request;
+
+/* Internal USSD Handler */
+struct hlr_iuse {
+	const char *name;
+	/* call-back to be called for any incoming USSD messages for this IUSE */
+	int (*handle_ussd)(struct osmo_gsup_conn *conn, struct ss_session *ss,
+			   const struct osmo_gsup_message *gsup, const struct ss_request *req);
+};
diff --git a/include/osmocom/hlr/hlr_vty.h b/include/osmocom/hlr/hlr_vty.h
new file mode 100644
index 0000000..acd6510
--- /dev/null
+++ b/include/osmocom/hlr/hlr_vty.h
@@ -0,0 +1,38 @@
+/* OsmoHLR VTY implementation */
+
+/* (C) 2016 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
+ *
+ * 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/>.
+ *
+ */
+
+#pragma once
+
+#include <osmocom/core/logging.h>
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/hlr/hlr.h>
+
+enum hlr_vty_node {
+	HLR_NODE = _LAST_OSMOVTY_NODE + 1,
+	GSUP_NODE,
+	EUSE_NODE,
+};
+
+int hlr_vty_is_config_node(struct vty *vty, int node);
+int hlr_vty_go_parent(struct vty *vty);
+void hlr_vty_init(void);
diff --git a/include/osmocom/hlr/hlr_vty_subscr.h b/include/osmocom/hlr/hlr_vty_subscr.h
new file mode 100644
index 0000000..5dd0772
--- /dev/null
+++ b/include/osmocom/hlr/hlr_vty_subscr.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void hlr_vty_subscriber_init(void);
diff --git a/include/osmocom/hlr/logging.h b/include/osmocom/hlr/logging.h
new file mode 100644
index 0000000..ed24075
--- /dev/null
+++ b/include/osmocom/hlr/logging.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <osmocom/core/logging.h>
+
+enum {
+	DMAIN,
+	DDB,
+	DGSUP,
+	DAUC,
+	DSS,
+};
+
+extern const struct log_info hlr_log_info;
diff --git a/include/osmocom/hlr/luop.h b/include/osmocom/hlr/luop.h
new file mode 100644
index 0000000..77a1dec
--- /dev/null
+++ b/include/osmocom/hlr/luop.h
@@ -0,0 +1,81 @@
+/* OsmoHLR TX/RX lu operations */
+
+/* (C) 2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Harald Welte <laforge@gnumonks.org>
+ *
+ * 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/>.
+ *
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include <osmocom/core/timer.h>
+#include <osmocom/gsm/gsup.h>
+
+#include <osmocom/hlr/db.h>
+#include <osmocom/hlr/gsup_server.h>
+
+#define CANCEL_TIMEOUT_SECS	30
+#define ISD_TIMEOUT_SECS	30
+
+enum lu_state {
+	LU_S_NULL,
+	LU_S_LU_RECEIVED,
+	LU_S_CANCEL_SENT,
+	LU_S_CANCEL_ACK_RECEIVED,
+	LU_S_ISD_SENT,
+	LU_S_ISD_ACK_RECEIVED,
+	LU_S_COMPLETE,
+};
+
+extern const struct value_string lu_state_names[];
+
+struct lu_operation {
+	/*! entry in global list of location update operations */
+	struct llist_head list;
+	/*! to which gsup_server do we belong */
+	struct osmo_gsup_server *gsup_server;
+	/*! state of the location update */
+	enum lu_state state;
+	/*! CS (false) or PS (true) Location Update? */
+	bool is_ps;
+	/*! currently running timer */
+	struct osmo_timer_list timer;
+
+	/*! subscriber related to this operation */
+	struct hlr_subscriber subscr;
+	/*! peer VLR/SGSN starting the request */
+	uint8_t *peer;
+};
+
+
+struct lu_operation *lu_op_alloc(struct osmo_gsup_server *srv);
+struct lu_operation *lu_op_alloc_conn(struct osmo_gsup_conn *conn);
+void lu_op_statechg(struct lu_operation *luop, enum lu_state new_state);
+bool lu_op_fill_subscr(struct lu_operation *luop, struct db_context *dbc,
+		       const char *imsi);
+struct lu_operation *lu_op_by_imsi(const char *imsi,
+				   const struct llist_head *lst);
+
+void lu_op_tx_error(struct lu_operation *luop, enum gsm48_gmm_cause cause);
+void lu_op_tx_ack(struct lu_operation *luop);
+void lu_op_tx_cancel_old(struct lu_operation *luop);
+void lu_op_tx_insert_subscr_data(struct lu_operation *luop);
+void lu_op_tx_del_subscr_data(struct lu_operation *luop);
+
+void lu_op_free(struct lu_operation *luop);
diff --git a/include/osmocom/hlr/rand.h b/include/osmocom/hlr/rand.h
new file mode 100644
index 0000000..9c5aedf
--- /dev/null
+++ b/include/osmocom/hlr/rand.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <stdint.h>
+
+int rand_init(void);
+
+int rand_get(uint8_t *rand, unsigned int len);