diff options
author | Harald Welte <laforge@gnumonks.org> | 2010-12-24 21:13:26 +0100 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2010-12-26 19:20:03 +0100 |
commit | a9b473a3c25d5b0f0993c3c53f6004b0e86fca5c (patch) | |
tree | d41b0f0bf4756737e0aa896b50c21f21e1fc7263 /openbsc/src/gprs/sgsn_libgtp.c | |
parent | 3357add225140a2e87a9d69150bf19cf578e24f7 (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.c | 32 |
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); |