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/gprs_sgsn.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/gprs_sgsn.c')
-rw-r--r-- | openbsc/src/gprs/gprs_sgsn.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 48a00b822..f5580037e 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -32,6 +32,8 @@ #include <openbsc/gprs_ns.h> #include <openbsc/gprs_bssgp.h> #include <openbsc/sgsn.h> +#include <openbsc/gsm_04_08_gprs.h> +#include <openbsc/gprs_gmm.h> extern struct sgsn_instance *sgsn; @@ -240,6 +242,7 @@ struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id) ggc->id = id; ggc->gtp_version = 1; + ggc->remote_restart_ctr = -1; /* if we are called from config file parse, this gsn doesn't exist yet */ ggc->gsn = sgsn->gsn; llist_add(&ggc->list, &sgsn_ggsn_ctxts); @@ -258,6 +261,18 @@ struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id) return NULL; } +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr) +{ + struct sgsn_ggsn_ctx *ggc; + + llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) { + if (!memcmp(addr, &ggc->remote_addr, sizeof(*addr))) + return ggc; + } + return NULL; +} + + struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id) { struct sgsn_ggsn_ctx *ggc; @@ -320,3 +335,35 @@ restart: return ptmsi; } + +static void drop_one_pdp(struct sgsn_pdp_ctx *pdp) +{ + if (pdp->mm->mm_state == GMM_REGISTERED_NORMAL) + gsm48_tx_gsm_deact_pdp_req(pdp, GSM_CAUSE_NET_FAIL); + else { + /* FIXME: GPRS paging in case MS is SUSPENDED */ + LOGP(DGPRS, LOGL_NOTICE, "Hard-dropping PDP ctx due to GGSN " + "recovery\n"); + sgsn_pdp_ctx_free(pdp); + } +} + +/* High-level function to be called in case a GGSN has disappeared or + * ottherwise lost state (recovery procedure) */ +int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn) +{ + struct sgsn_mm_ctx *mm; + int num = 0; + + llist_for_each_entry(mm, &sgsn_mm_ctxts, list) { + struct sgsn_pdp_ctx *pdp; + llist_for_each_entry(pdp, &mm->pdp_list, list) { + if (pdp->ggsn == ggsn) { + drop_one_pdp(pdp); + num++; + } + } + } + + return num; +} |