diff options
-rw-r--r-- | include/osmocom/sgsn/gprs_sgsn.h | 2 | ||||
-rw-r--r-- | src/gprs/gprs_sgsn.c | 8 | ||||
-rw-r--r-- | src/gprs/sgsn_libgtp.c | 15 |
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); |