gbproxy: Implement TLLI cache and use it for SUSPEND/RESUME

When routing a SUSPEND/RESUME we need to keep track of where it came
from so we can send the (N)ACK back to the correct BSS. Use the TLLI
which is present in both messages to cache and retrieve the correct BSS.

A timer runs every two seconds and expires entries that are older than
the timeout (hardcoded to 5 seconds for now).

Related: SYS#4865, OS#4472
Change-Id: I42adf70f560d2bb358a9e1c7614281e8d2967568
diff --git a/include/osmocom/sgsn/gb_proxy.h b/include/osmocom/sgsn/gb_proxy.h
index ad5bb27..04a3c4b 100644
--- a/include/osmocom/sgsn/gb_proxy.h
+++ b/include/osmocom/sgsn/gb_proxy.h
@@ -75,6 +75,14 @@
 	/* hash table of all gbproxy_cell */
 	DECLARE_HASHTABLE(cells, 8);
 
+	/* tlli<->nse cache used to map SUSPEND/RESUME (N)ACKS */
+	struct {
+		DECLARE_HASHTABLE(entries, 10);
+		struct osmo_timer_list timer;
+		/* Time in seconds that the entries should be valid */
+		uint8_t timeout;
+	} tlli_cache;
+
 	/* List of all SGSNs */
 	struct llist_head sgsns;
 
@@ -163,6 +171,19 @@
 	} pool;
 };
 
+/* TLLI cache */
+struct gbproxy_tlli_cache_entry {
+	/* linked to gbproxy_config.tlli_cache */
+	struct hlist_node list;
+
+	/* TLLI of the entry */
+	uint32_t tlli;
+	/* When was this entry last seen */
+	time_t tstamp;
+	/* The Cell this TLLI was last seen */
+	struct gbproxy_nse *nse;
+};
+
 /* Convenience logging macros for NSE/BVC */
 #define LOGPNSE_CAT(NSE, SUBSYS, LEVEL, FMT, ARGS...) \
 	LOGP(SUBSYS, LEVEL, "NSE(%05u/%s) " FMT, (NSE)->nsei, \
@@ -229,6 +250,12 @@
 void gbproxy_nse_free(struct gbproxy_nse *nse);
 struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags);
 struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing);
+struct gbproxy_nse *gbproxy_nse_by_tlli(struct gbproxy_config *cfg, uint32_t tlli);
+
+/* TLLI cache */
+void gbproxy_tlli_cache_update(struct gbproxy_nse *nse, uint32_t tlli);
+void gbproxy_tlli_cache_remove(struct gbproxy_config *cfg, uint32_t tlli);
+int gbproxy_tlli_cache_cleanup(struct gbproxy_config *cfg);
 
 /* SGSN handling */
 struct gbproxy_sgsn *gbproxy_sgsn_alloc(struct gbproxy_config *cfg, uint16_t nsei, const char *name);