gbproxy: Don't remove stale TLLI automatically

This patches removes the call to gbprox_remove_stale_tllis()
from gbprox_register_tlli(), so it must be called explicitly now.
The call is now done from within gbprox_update_state_after().

In addition, the TLLI cache size counter is also kept in sync when
gbprox_remove_stale_tllis is called manually. The call to
gbproxy_peer_free() in gbproxy_peer_free() is moved behind the TLLI
to allow for counter updates in gbprox_delete_tlli().

Sponsored-by: On-Waves ehf
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index 32e56c0..7550e3f 100644
--- a/openbsc/src/gprs/gb_proxy.c
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -217,11 +217,13 @@
 
 void gbproxy_peer_free(struct gbproxy_peer *peer)
 {
-	rate_ctr_group_free(peer->ctrg);
 	llist_del(&peer->list);
 
 	gbprox_delete_tllis(peer);
 
+	rate_ctr_group_free(peer->ctrg);
+	peer->ctrg = NULL;
+
 	talloc_free(peer);
 }
 
@@ -462,6 +464,9 @@
 	llist_del(&tlli_info->list);
 	talloc_free(tlli_info);
 	state->enabled_tllis_count -= 1;
+
+	peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
+		state->enabled_tllis_count;
 }
 
 static void gbprox_delete_tllis(struct gbproxy_peer *peer)
@@ -546,6 +551,9 @@
 	tlli_info->timestamp = now;
 	llist_add(&tlli_info->list, &state->enabled_tllis);
 	state->enabled_tllis_count += 1;
+
+	peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
+		state->enabled_tllis_count;
 }
 
 int gbprox_remove_stale_tllis(struct gbproxy_peer *peer, time_t now)
@@ -597,6 +605,9 @@
 		llist_del(&tlli_info->list);
 		OSMO_ASSERT(state->enabled_tllis_count > 0);
 		state->enabled_tllis_count -= 1;
+
+		peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
+			state->enabled_tllis_count;
 	}
 
 	return tlli_info;
@@ -632,7 +643,6 @@
 void gbprox_register_tlli(struct gbproxy_peer *peer, uint32_t tlli,
 				 const uint8_t *imsi, size_t imsi_len)
 {
-	struct gbproxy_patch_state *state = &peer->patch_state;
 	struct gbproxy_tlli_info *tlli_info;
 	int enable_patching = -1;
 	time_t now = 0;
@@ -673,20 +683,11 @@
 	gbprox_update_tlli_info(tlli_info, imsi, imsi_len);
 	if (enable_patching >= 0)
 		tlli_info->enable_patching = enable_patching;
-
-	gbprox_remove_stale_tllis(peer, now);
-	/* Be on the safe side, currently the new tlli_info won't be
-	 * removed, but this not enforced explicitely */
-	tlli_info = NULL;
-
-	peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
-		state->enabled_tllis_count;
 }
 
 static void gbprox_unregister_tlli(struct gbproxy_peer *peer, uint32_t tlli)
 {
 	struct gbproxy_tlli_info *tlli_info;
-	struct gbproxy_patch_state *state = &peer->patch_state;
 
 	tlli_info = gbprox_find_tlli(peer, tlli);
 	if (tlli_info) {
@@ -695,9 +696,6 @@
 		     tlli);
 		gbprox_delete_tlli(peer, tlli_info);
 	}
-
-	peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
-		state->enabled_tllis_count;
 }
 
 static int gbprox_check_tlli(struct gbproxy_peer *peer, uint32_t tlli)
@@ -1363,8 +1361,12 @@
 static void gbprox_update_state_after(struct gbproxy_peer *peer,
 				      struct gbproxy_parse_context *parse_ctx)
 {
+	time_t now = time(NULL);
+
 	if (parse_ctx->invalidate_tlli)
 		gbprox_unregister_tlli(peer, parse_ctx->tlli);
+
+	gbprox_remove_stale_tllis(peer, now);
 }
 
 static int gbprox_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c
index bb2b1aa..beade6e 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.c
+++ b/openbsc/tests/gbproxy/gbproxy_test.c
@@ -1412,6 +1412,7 @@
 
 	{
 		struct gbproxy_tlli_info *tlli_info;
+		int num_removed;
 
 		printf("Test TLLI expiry, max_len == 1:\n");
 
@@ -1427,6 +1428,10 @@
 		/* replace the old entry */
 		printf("  Add TLLI 2, IMSI 2 (should replace IMSI 1)\n");
 		gbprox_register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2));
+		OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 2);
+
+		num_removed = gbprox_remove_stale_tllis(peer, time(NULL) + 2);
+		OSMO_ASSERT(num_removed == 1);
 		OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 1);
 
 		dump_peers(stdout, 2, &cfg);
@@ -1444,7 +1449,7 @@
 	}
 
 	{
-		int ret;
+		int num_removed;
 
 		printf("Test TLLI expiry, max_age == 1:\n");
 
@@ -1462,8 +1467,8 @@
 		gbprox_register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2));
 		OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 2);
 
-		ret = gbprox_remove_stale_tllis(peer, time(NULL) + 2);
-		OSMO_ASSERT(ret == 2);
+		num_removed = gbprox_remove_stale_tllis(peer, time(NULL) + 2);
+		OSMO_ASSERT(num_removed == 2);
 		OSMO_ASSERT(peer->patch_state.enabled_tllis_count == 0);
 
 		dump_peers(stdout, 2, &cfg);
diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok
index c893ff3..aea4de3 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.ok
+++ b/openbsc/tests/gbproxy/gbproxy_test.ok
@@ -1922,7 +1922,6 @@
   Add TLLI 2, IMSI 2 (should expire after timeout)
   Peers:
     NSEI 0, BVCI 20, not blocked, RAI 0-0-0-0
-      TLLI cache size                 : 2
       TLLI-Cache: 0
 
 ===== GbProxy test END