gbproxy: Use different TLLI/P-TMSI for BSS and SGSN

This patch modifies gbprox_make_bss_ptmsi() to generate a new P-TMSI
when patch_ptmsi is set in the configuration instead of using the
P-TMSI assigned by the SGSN. It modifies gbprox_make_sgsn_tlli() to
either use a foreign TLLI based on the SGSN side P-TMSI or (if there
is none) generate a random TLLI if patch_ptmsi is set. Otherwise, the
TLLI used by the BSS is used.

The seeds for the pseudo-random sequences sre set based on time
initially. Note that these are neither cryptographically safe nor
protected against collisions.

Ticket: OW#1259
Sponsored-by: On-Waves ehf
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index 8bad721..86ae0e8 100644
--- a/openbsc/src/gprs/gb_proxy.c
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -446,6 +446,20 @@
 	return NULL;
 }
 
+static struct gbproxy_tlli_info *gbprox_find_tlli_by_ptmsi(
+	struct gbproxy_peer *peer,
+	uint32_t ptmsi)
+{
+	struct gbproxy_tlli_info *tlli_info;
+	struct gbproxy_patch_state *state = &peer->patch_state;
+
+	llist_for_each_entry(tlli_info, &state->enabled_tllis, list)
+		if (tlli_info->tlli.ptmsi == ptmsi)
+			return tlli_info;
+
+	return NULL;
+}
+
 struct gbproxy_tlli_info *gbprox_find_tlli_by_sgsn_tlli(
 	struct gbproxy_peer *peer,
 	uint32_t tlli)
@@ -1605,14 +1619,43 @@
 static uint32_t gbprox_make_bss_ptmsi(struct gbproxy_peer *peer,
 				      uint32_t sgsn_ptmsi)
 {
-	return sgsn_ptmsi;
+	uint32_t bss_ptmsi;
+	if (!peer->cfg->patch_ptmsi) {
+		bss_ptmsi = sgsn_ptmsi;
+	} else {
+		do {
+			bss_ptmsi = rand_r(&peer->cfg->bss_ptmsi_state);
+			bss_ptmsi = bss_ptmsi | 0xC0000000;
+
+			if (gbprox_find_tlli_by_ptmsi(peer, bss_ptmsi))
+				bss_ptmsi = GSM_RESERVED_TMSI;
+		} while (bss_ptmsi == GSM_RESERVED_TMSI);
+	}
+
+	return bss_ptmsi;
 }
 
 static uint32_t gbprox_make_sgsn_tlli(struct gbproxy_peer *peer,
 				      struct gbproxy_tlli_info *tlli_info,
 				      uint32_t bss_tlli)
 {
-	return bss_tlli;
+	uint32_t sgsn_tlli;
+	if (!peer->cfg->patch_ptmsi) {
+		sgsn_tlli = bss_tlli;
+	} else if (tlli_info->sgsn_tlli.ptmsi != GSM_RESERVED_TMSI) {
+		sgsn_tlli = gprs_tmsi2tlli(tlli_info->sgsn_tlli.ptmsi,
+					   TLLI_FOREIGN);
+	} else {
+		do {
+			/* create random TLLI, 0b01111xxx... */
+			sgsn_tlli = rand_r(&peer->cfg->sgsn_tlli_state);
+			sgsn_tlli = (sgsn_tlli & 0x7fffffff) | 0x78000000;
+
+			if (gbprox_find_tlli_by_sgsn_tlli(peer, sgsn_tlli))
+				sgsn_tlli = 0;
+		} while (!sgsn_tlli);
+	}
+	return sgsn_tlli;
 }
 
 static struct gbproxy_tlli_info *gbprox_update_state_ul(
@@ -2698,7 +2741,11 @@
 
 int gbproxy_init_config(struct gbproxy_config *cfg)
 {
+	struct timespec tp;
 	INIT_LLIST_HEAD(&cfg->bts_peers);
 	cfg->ctrg = rate_ctr_group_alloc(tall_bsc_ctx, &global_ctrg_desc, 0);
+	clock_gettime(CLOCK_REALTIME, &tp);
+	cfg->bss_ptmsi_state = tp.tv_sec + tp.tv_nsec;
+	cfg->sgsn_tlli_state = tp.tv_sec - tp.tv_nsec;
 	return 0;
 }