summaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/gprs_sgsn.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/gprs/gprs_sgsn.c')
-rw-r--r--openbsc/src/gprs/gprs_sgsn.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index f3da0387a..6f706642d 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -403,10 +403,34 @@ uint32_t sgsn_alloc_ptmsi(void)
{
struct sgsn_mm_ctx *mm;
uint32_t ptmsi;
- int max_retries = 23;
+ int max_retries = 100;
restart:
- ptmsi = rand() | 0xC0000000;
+ ptmsi = rand();
+ /* Enforce that the 2 MSB are set without loosing the distance between
+ * identical values. Since rand() has no duplicate values within a
+ * period (because the size of the state is the same like the size of
+ * the random value), this leads to a distance of period/4 when the
+ * distribution of the 2 MSB is uniform. This approach fails with a
+ * probability of (3/4)^max_retries, only 1% of the approaches will
+ * need more than 16 numbers (even distribution assumed).
+ *
+ * Alternatively, a freeze list could be used if another PRNG is used
+ * or when this approach proves to be not sufficient.
+ */
+ if (ptmsi >= 0xC0000000) {
+ if (!max_retries--)
+ goto failed;
+ goto restart;
+ }
+ ptmsi |= 0xC0000000;
+
+ if (ptmsi == GSM_RESERVED_TMSI) {
+ if (!max_retries--)
+ goto failed;
+ goto restart;
+ }
+
llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
if (mm->p_tmsi == ptmsi) {
if (!max_retries--)