aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/sgsn/gprs_sgsn.h2
-rw-r--r--src/gprs/gprs_sgsn.c8
-rw-r--r--src/gprs/sgsn_libgtp.c15
3 files changed, 16 insertions, 9 deletions
diff --git a/include/osmocom/sgsn/gprs_sgsn.h b/include/osmocom/sgsn/gprs_sgsn.h
index 8eba2d410..6f16dc75f 100644
--- a/include/osmocom/sgsn/gprs_sgsn.h
+++ b/include/osmocom/sgsn/gprs_sgsn.h
@@ -362,7 +362,7 @@ struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id);
void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx);
-int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn);
+int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except);
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
diff --git a/src/gprs/gprs_sgsn.c b/src/gprs/gprs_sgsn.c
index e6d88e3cb..904615764 100644
--- a/src/gprs/gprs_sgsn.c
+++ b/src/gprs/gprs_sgsn.c
@@ -714,13 +714,17 @@ void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx)
}
/* High-level function to be called in case a GGSN has disappeared or
- * otherwise lost state (recovery procedure) */
-int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn)
+ * otherwise lost state (recovery procedure). It will detach all related pdp ctx
+ * from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can
+ * be kept alive to allow handling later message which contained the Recovery IE. */
+int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except)
{
int num = 0;
struct sgsn_pdp_ctx *pdp, *pdp2;
llist_for_each_entry_safe(pdp, pdp2, &ggsn->pdp_list, ggsn_list) {
+ if (pdp == except)
+ continue;
sgsn_ggsn_ctx_drop_pdp(pdp);
num++;
}
diff --git a/src/gprs/sgsn_libgtp.c b/src/gprs/sgsn_libgtp.c
index 38133971b..782979677 100644
--- a/src/gprs/sgsn_libgtp.c
+++ b/src/gprs/sgsn_libgtp.c
@@ -591,9 +591,10 @@ static int echo_conf(struct pdp_t *pdp, void *cbp, int recovery)
}
/* Any message received by GGSN contains a recovery IE */
-static int cb_recovery(struct sockaddr_in *peer, uint8_t recovery)
+static int cb_recovery2(struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery)
{
struct sgsn_ggsn_ctx *ggsn;
+ struct sgsn_pdp_ctx *pctx = NULL;
ggsn = sgsn_ggsn_ctx_by_addr(&peer->sin_addr);
if (!ggsn) {
@@ -606,11 +607,13 @@ static int cb_recovery(struct sockaddr_in *peer, uint8_t recovery)
ggsn->remote_restart_ctr = recovery;
} else if (ggsn->remote_restart_ctr != recovery) {
/* counter has changed (GGSN restart): release all PDP */
- LOGP(DGPRS, LOGL_NOTICE, "GGSN recovery (%u->%u), "
- "releasing all PDP contexts\n",
- ggsn->remote_restart_ctr, recovery);
+ LOGP(DGPRS, LOGL_NOTICE, "GGSN recovery (%u->%u) pdp=%p, "
+ "releasing all%s PDP contexts\n",
+ ggsn->remote_restart_ctr, recovery, pdp, pdp ? " other" : "");
ggsn->remote_restart_ctr = recovery;
- sgsn_ggsn_ctx_drop_all_pdp(ggsn);
+ if (pdp)
+ pctx = pdp->priv;
+ sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, pctx);
}
return 0;
}
@@ -896,7 +899,7 @@ int sgsn_gtp_init(struct sgsn_instance *sgi)
/* Register callbackcs with libgtp */
gtp_set_cb_delete_context(gsn, cb_delete_context);
gtp_set_cb_conf(gsn, cb_conf);
- gtp_set_cb_recovery(gsn, cb_recovery);
+ gtp_set_cb_recovery2(gsn, cb_recovery2);
gtp_set_cb_data_ind(gsn, cb_data_ind);
gtp_set_cb_unsup_ind(gsn, cb_unsup_ind);
gtp_set_cb_extheader_ind(gsn, cb_extheader_ind);