aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/sgsn_libgtp.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-12-24 21:13:26 +0100
committerHarald Welte <laforge@gnumonks.org>2010-12-26 19:20:03 +0100
commita9b473a3c25d5b0f0993c3c53f6004b0e86fca5c (patch)
treed41b0f0bf4756737e0aa896b50c21f21e1fc7263 /openbsc/src/gprs/sgsn_libgtp.c
parent3357add225140a2e87a9d69150bf19cf578e24f7 (diff)
SGSN: Implement network-initiated PDP CTX DEACT when GGSN restarts
If the GGSN restarts, its restart counter will increase. We can detect that and accordingly release/delete all PDP contexts for that GGSN.
Diffstat (limited to 'openbsc/src/gprs/sgsn_libgtp.c')
-rw-r--r--openbsc/src/gprs/sgsn_libgtp.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c
index 5278e4d88..e5defe738 100644
--- a/openbsc/src/gprs/sgsn_libgtp.c
+++ b/openbsc/src/gprs/sgsn_libgtp.c
@@ -325,15 +325,38 @@ static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
}
/* Confirmation of an GTP ECHO request */
-static int echo_conf(int recovery)
+static int echo_conf(struct pdp_t *pdp, void *cbp, int recovery)
{
if (recovery < 0) {
DEBUGP(DGPRS, "GTP Echo Request timed out\n");
/* FIXME: if version == 1, retry with version 0 */
} else {
DEBUGP(DGPRS, "GTP Rx Echo Response\n");
- /* FIXME: check if recovery counter has incremented and
- * release all PDP context (if it has) */
+ }
+ return 0;
+}
+
+/* Any message received by GGSN contains a recovery IE */
+static int cb_recovery(struct sockaddr_in *peer, uint8_t recovery)
+{
+ struct sgsn_ggsn_ctx *ggsn;
+
+ ggsn = sgsn_ggsn_ctx_by_addr(&peer->sin_addr);
+ if (!ggsn) {
+ DEBUGP(DGPRS, "Received Recovery IE for unknown GGSN\n");
+ return -EINVAL;
+ }
+
+ if (ggsn->remote_restart_ctr == -1) {
+ /* First received ECHO RESPONSE, note the restart ctr */
+ 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);
+ ggsn->remote_restart_ctr = recovery;
+ drop_all_pdp_for_ggsn(ggsn);
}
return 0;
}
@@ -351,7 +374,7 @@ static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
switch (type) {
case GTP_ECHO_REQ:
/* libgtp hands us the RECOVERY number instead of a cause */
- return echo_conf(cause);
+ return echo_conf(pdp, cbp, cause);
case GTP_CREATE_PDP_REQ:
return create_pdp_conf(pdp, cbp, cause);
case GTP_DELETE_PDP_REQ:
@@ -579,6 +602,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_data_ind(gsn, cb_data_ind);
gtp_set_cb_unsup_ind(gsn, cb_unsup_ind);
gtp_set_cb_extheader_ind(gsn, cb_extheader_ind);