summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Santos <jrsantos@jonathanrsantos.com>2011-06-22 12:13:59 -0400
committerHarald Welte <laforge@gnumonks.org>2011-10-16 21:36:26 +0200
commitfbdcc859c7404ef2a8d46dff5c345ac4a35cfc33 (patch)
tree437db3e6f9d065dffbd89922793d43882febdfe3
parent30754ddfa952059c6539d3382a6920eff7e91c1e (diff)
gprs: Reset LLC state when Timer 3350 expires
This works around a problem that occurs if a mobile loses packet data connectivity, e.g. moves out of coverage or switches over to a circuit-switched call, while a data transfer is occurring. The mobile would reset its LLC state, causing it to be unsynchronized with the SGSN. Therefore the SGSN would drop incoming frames until the sequence numbers matched. This workaround resets the LLC state in the SGSN if T3350 expires, indicating that Routing Area Updating Request, Attach Request, or P-TMSI Realloc Command has failed.
-rw-r--r--openbsc/include/openbsc/gprs_llc.h1
-rw-r--r--openbsc/src/gprs/gprs_gmm.c1
-rw-r--r--openbsc/src/gprs/gprs_llc.c24
3 files changed, 26 insertions, 0 deletions
diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h
index 908fccb35..0befa51cd 100644
--- a/openbsc/include/openbsc/gprs_llc.h
+++ b/openbsc/include/openbsc/gprs_llc.h
@@ -180,6 +180,7 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
int gprs_llgmm_suspend(struct gprs_llc_llme *llme);
int gprs_llgmm_resume(struct gprs_llc_llme *llme);
+void gprs_llgmm_reset_state(struct gprs_llc_llme *llme);
int gprs_llc_init(const char *cipher_plugin_path);
int gprs_llc_vty_init(void);
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
index d1858e9e5..411d99e08 100644
--- a/openbsc/src/gprs/gprs_gmm.c
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -1113,6 +1113,7 @@ static void mmctx_timer_cb(void *_mm)
if (mm->num_T_exp >= 5) {
LOGP(DMM, LOGL_NOTICE, "T3350 expired >= 5 times\n");
gprs_llgmm_resume(mm->llme);
+ gprs_llgmm_reset_state(mm->llme);
break;
}
/* re-transmit the respective msg and re-start timer */
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index be2e92a9c..322679d5b 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -920,6 +920,30 @@ int gprs_llgmm_resume(struct gprs_llc_llme* llme)
return 0;
}
+void gprs_llgmm_reset_state(struct gprs_llc_llme *llme)
+{
+ unsigned int i;
+
+ if (llme == 0)
+ {
+ LOGP(DLLC, LOGL_ERROR, "LLC TX: trying to reset LLC states "
+ "but passed null llme by gmm\n");
+ return;
+ }
+
+ LOGP(DLLC, LOGL_NOTICE, "LLC RX: reset state variable for TLLI 0x%08x",
+ llme->tlli);
+ /* 8.5.3.1 For all LLE's */
+ for (i = 0; i < ARRAY_SIZE(llme->lle); i++) {
+ struct gprs_llc_lle *l = &llme->lle[i];
+ l->vu_recv = 0; /* lets not mess with send state variable now */
+ /* l->vu_send = l->vu_recv = 0; */
+ l->retrans_ctr = 0;
+ l->state = GPRS_LLES_ASSIGNED_ADM;
+ /* FIXME Set parameters according to table 9 */
+ }
+}
+
int gprs_llc_init(const char *cipher_plugin_path)
{
return gprs_cipher_load(cipher_plugin_path);