aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2014-11-06 15:43:10 +0100
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-11-14 10:19:29 +0100
commitf6e7d99d54cc75fdc19433011afb5eaaa8a2a002 (patch)
tree370d0bed4efcab87e3bb7ce734c5518f297e4487
parentc4f9bf3142f54b63174f653b07103dd6ab36b1ae (diff)
sgsn: Don't assign a new P-TMSI if one is pending
Currently every time an RA Update Req or an Attach Req is processed, a new P-TMSI is allocated. When an MS issues another of these messages before it has completed the first procedure, old_ptmsi is replaced by ptmsi (and thus lost) and ptmsi is replaced by the newly allocated P-TMSI. This can confuse the gbproxy, which can loose track of the logical link then. At least a Blackberry emits a double set of RA Upd Req messages from time to time which may be just 20ms apart. This patch adds a check whether mm->ptmsi or mm->old_ptmsi are set. If both are set, the P-TMSI is not re-allocated. This is only the case, when the Complete message has not been received yet, since that message will reset old_ptmsi. Sponsored-by: On-Waves ehf
-rw-r--r--openbsc/src/gprs/gprs_gmm.c14
-rw-r--r--openbsc/tests/sgsn/sgsn_test.c192
-rw-r--r--openbsc/tests/sgsn/sgsn_test.ok4
3 files changed, 206 insertions, 4 deletions
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
index ac063afa1..afd3bbb06 100644
--- a/openbsc/src/gprs/gprs_gmm.c
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -911,8 +911,11 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
#ifdef PTMSI_ALLOC
/* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */
- ctx->p_tmsi_old = ctx->p_tmsi;
- ctx->p_tmsi = sgsn_alloc_ptmsi();
+ /* Don't change the P-TMSI if a P-TMSI re-assignment is under way */
+ if (ctx->mm_state != GMM_COMMON_PROC_INIT) {
+ ctx->p_tmsi_old = ctx->p_tmsi;
+ ctx->p_tmsi = sgsn_alloc_ptmsi();
+ }
ctx->mm_state = GMM_COMMON_PROC_INIT;
#endif
/* Even if there is no P-TMSI allocated, the MS will switch from
@@ -1147,8 +1150,11 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]);
#ifdef PTMSI_ALLOC
- mmctx->p_tmsi_old = mmctx->p_tmsi;
- mmctx->p_tmsi = sgsn_alloc_ptmsi();
+ /* Don't change the P-TMSI if a P-TMSI re-assignment is under way */
+ if (mmctx->mm_state != GMM_COMMON_PROC_INIT) {
+ mmctx->p_tmsi_old = mmctx->p_tmsi;
+ mmctx->p_tmsi = sgsn_alloc_ptmsi();
+ }
/* Start T3350 and re-transmit up to 5 times until ATTACH COMPLETE */
mmctx->t3350_mode = GMM_T3350_MODE_RAU;
mmctx_timer_start(mmctx, 3350, GSM0408_T3350_SECS);
diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c
index 1756888fe..2c38a1275 100644
--- a/openbsc/tests/sgsn/sgsn_test.c
+++ b/openbsc/tests/sgsn/sgsn_test.c
@@ -546,6 +546,197 @@ static void test_gmm_reject(void)
}
}
+/*
+ * Test the dynamic allocation of P-TMSIs
+ */
+static void test_gmm_ptmsi_allocation(void)
+{
+ struct gprs_ra_id raid = { 0, };
+ struct sgsn_mm_ctx *ctx = NULL;
+ struct sgsn_mm_ctx *ictx;
+ uint32_t foreign_tlli;
+ uint32_t ptmsi1;
+ uint32_t ptmsi2;
+ uint32_t old_ptmsi;
+ uint32_t local_tlli = 0;
+ struct gprs_llc_lle *lle;
+ const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy;
+
+ /* DTAP - Attach Request (IMSI 12131415161718) */
+ static const unsigned char attach_req[] = {
+ 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02,
+ 0x08, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, 0x19,
+ 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00,
+ 0x60, 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60,
+ 0x80, 0xba, 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80,
+ 0x00,
+ };
+
+ /* DTAP - Identity Response IMEI */
+ static const unsigned char ident_resp_imei[] = {
+ 0x08, 0x16, 0x08, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78,
+ 0x56
+ };
+
+ /* DTAP - Attach Complete */
+ static const unsigned char attach_compl[] = {
+ 0x08, 0x03
+ };
+
+ /* DTAP - Routing Area Update Request */
+ static const unsigned char ra_upd_req[] = {
+ 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50,
+ 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b,
+ 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8,
+ 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02,
+ 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19,
+ 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04,
+ 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00
+ };
+
+ /* DTAP - Routing Area Update Complete */
+ static const unsigned char ra_upd_complete[] = {
+ 0x08, 0x0a
+ };
+
+ /* DTAP - Detach Request (MO) */
+ /* normal detach, power_off = 1 */
+ static const unsigned char detach_req[] = {
+ 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4, 0xef, 0xe2,
+ 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb
+ };
+
+ sgsn->cfg.auth_policy = SGSN_AUTH_POLICY_OPEN;
+
+ printf("Testing P-TMSI allocation\n");
+
+ printf(" - sgsn_alloc_ptmsi\n");
+
+ /* reset the PRNG used by sgsn_alloc_ptmsi */
+ srand(1);
+
+ ptmsi1 = sgsn_alloc_ptmsi();
+ OSMO_ASSERT(ptmsi1 != GSM_RESERVED_TMSI);
+
+ ptmsi2 = sgsn_alloc_ptmsi();
+ OSMO_ASSERT(ptmsi2 != GSM_RESERVED_TMSI);
+
+ OSMO_ASSERT(ptmsi1 != ptmsi2);
+
+ printf(" - Repeated Attach Request\n");
+
+ /* reset the PRNG, so that the same P-TMSI will be generated
+ * again */
+ srand(1);
+
+ foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN);
+
+ /* Create a LLE/LLME */
+ OSMO_ASSERT(count(gprs_llme_list()) == 0);
+ lle = gprs_lle_get_or_create(foreign_tlli, 3);
+ OSMO_ASSERT(count(gprs_llme_list()) == 1);
+
+ /* inject the attach request */
+ send_0408_message(lle->llme, foreign_tlli,
+ attach_req, ARRAY_SIZE(attach_req));
+
+ ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid);
+ OSMO_ASSERT(ctx != NULL);
+ OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT);
+ OSMO_ASSERT(ctx->p_tmsi == ptmsi1);
+
+ old_ptmsi = ctx->p_tmsi_old;
+
+ /* we expect an identity request (IMEI) */
+ OSMO_ASSERT(sgsn_tx_counter == 1);
+
+ /* inject the identity response (IMEI) */
+ send_0408_message(ctx->llme, foreign_tlli,
+ ident_resp_imei, ARRAY_SIZE(ident_resp_imei));
+
+ /* check that the MM context has not been removed due to a failed
+ * authorization */
+ OSMO_ASSERT(ctx == sgsn_mm_ctx_by_tlli(foreign_tlli, &raid));
+
+ OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT);
+ OSMO_ASSERT(ctx->p_tmsi == ptmsi1);
+
+ /* we expect an attach accept */
+ OSMO_ASSERT(sgsn_tx_counter == 1);
+
+ /* we ignore this and send the attach again */
+ send_0408_message(lle->llme, foreign_tlli,
+ attach_req, ARRAY_SIZE(attach_req));
+
+ /* the allocated P-TMSI should be the same */
+ ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid);
+ OSMO_ASSERT(ctx != NULL);
+ OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT);
+ OSMO_ASSERT(ctx->p_tmsi_old == old_ptmsi);
+ OSMO_ASSERT(ctx->p_tmsi == ptmsi1);
+
+ /* inject the attach complete */
+ local_tlli = gprs_tmsi2tlli(ptmsi1, TLLI_LOCAL);
+ send_0408_message(ctx->llme, local_tlli,
+ attach_compl, ARRAY_SIZE(attach_compl));
+
+ /* we don't expect a response */
+ OSMO_ASSERT(sgsn_tx_counter == 0);
+
+ OSMO_ASSERT(ctx->mm_state == GMM_REGISTERED_NORMAL);
+ OSMO_ASSERT(ctx->p_tmsi_old == 0);
+ OSMO_ASSERT(ctx->p_tmsi == ptmsi1);
+
+ printf(" - Repeated RA Update Request\n");
+
+ /* inject the RA update request */
+ send_0408_message(ctx->llme, local_tlli,
+ ra_upd_req, ARRAY_SIZE(ra_upd_req));
+
+ /* we expect an RA update accept */
+ OSMO_ASSERT(sgsn_tx_counter == 1);
+
+ OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT);
+ OSMO_ASSERT(ctx->p_tmsi_old == ptmsi1);
+ OSMO_ASSERT(ctx->p_tmsi == ptmsi2);
+
+ /* repeat the RA update request */
+ send_0408_message(ctx->llme, local_tlli,
+ ra_upd_req, ARRAY_SIZE(ra_upd_req));
+
+ /* we expect an RA update accept */
+ OSMO_ASSERT(sgsn_tx_counter == 1);
+
+ OSMO_ASSERT(ctx->mm_state == GMM_COMMON_PROC_INIT);
+ OSMO_ASSERT(ctx->p_tmsi_old == ptmsi1);
+ OSMO_ASSERT(ctx->p_tmsi == ptmsi2);
+
+ /* inject the RA update complete */
+ local_tlli = gprs_tmsi2tlli(ptmsi2, TLLI_LOCAL);
+ send_0408_message(ctx->llme, local_tlli,
+ ra_upd_complete, ARRAY_SIZE(ra_upd_complete));
+
+ /* we don't expect a response */
+ OSMO_ASSERT(sgsn_tx_counter == 0);
+
+ OSMO_ASSERT(ctx->mm_state == GMM_REGISTERED_NORMAL);
+ OSMO_ASSERT(ctx->p_tmsi_old == 0);
+ OSMO_ASSERT(ctx->p_tmsi == ptmsi2);
+
+ /* inject the detach */
+ send_0408_message(ctx->llme, local_tlli,
+ detach_req, ARRAY_SIZE(detach_req));
+
+ /* verify that things are gone */
+ OSMO_ASSERT(count(gprs_llme_list()) == 0);
+ ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid);
+ OSMO_ASSERT(!ictx);
+
+ sgsn->cfg.auth_policy = saved_auth_policy;
+}
+
+
static struct log_info_cat gprs_categories[] = {
[DMM] = {
.name = "DMM",
@@ -616,6 +807,7 @@ int main(int argc, char **argv)
test_gmm_status_no_mmctx();
test_gmm_attach();
test_gmm_reject();
+ test_gmm_ptmsi_allocation();
printf("Done\n");
return 0;
}
diff --git a/openbsc/tests/sgsn/sgsn_test.ok b/openbsc/tests/sgsn/sgsn_test.ok
index d3b333f8a..6f6204ff5 100644
--- a/openbsc/tests/sgsn/sgsn_test.ok
+++ b/openbsc/tests/sgsn/sgsn_test.ok
@@ -10,4 +10,8 @@ Testing GMM reject
- Routing Area Update Request (valid)
- Routing Area Update Request (invalid type)
- Routing Area Update Request (invalid CAP length)
+Testing P-TMSI allocation
+ - sgsn_alloc_ptmsi
+ - Repeated Attach Request
+ - Repeated RA Update Request
Done