diff --git a/include/osmocom/sgsn/gprs_ranap.h b/include/osmocom/sgsn/gprs_ranap.h index b300130ac..62fdf6f2d 100644 --- a/include/osmocom/sgsn/gprs_ranap.h +++ b/include/osmocom/sgsn/gprs_ranap.h @@ -12,8 +12,19 @@ void activate_pdp_rabs(struct sgsn_mm_ctx *ctx); int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data); int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp); +/* free the Iu UE context */ +void sgsn_ranap_iu_free(struct sgsn_mm_ctx *ctx); + +/* send a Iu Release Command and free afterwards the UE context */ +void sgsn_ranap_iu_release_free(struct sgsn_mm_ctx *ctx, + const struct RANAP_Cause *cause); + int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id, uint16_t *sai); -#endif + +#else /* ifndef BUILD_IU */ +inline static void sgsn_ranap_iu_free(void *ctx) {}; +inline static void sgsn_ranap_iu_release_free(void *ctx, void *cause) {}; +#endif /* BUILD_IU*/ struct ranap_ue_conn_ctx; /* On RANAP, Returns pointer to he associated ranap_ue_conn_ctx in msg, filled diff --git a/src/sgsn/gprs_mm_state_iu_fsm.c b/src/sgsn/gprs_mm_state_iu_fsm.c index 1ed5f56f1..b098f2018 100644 --- a/src/sgsn/gprs_mm_state_iu_fsm.c +++ b/src/sgsn/gprs_mm_state_iu_fsm.c @@ -6,6 +6,7 @@ #include #include +#include #define X(s) (1 << (s)) @@ -45,11 +46,15 @@ static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data static void st_pmm_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data) { + struct sgsn_mm_ctx *ctx = fi->priv; + switch(event) { case E_PMM_PS_CONN_RELEASE: + sgsn_ranap_iu_free(ctx); mm_state_iu_fsm_state_chg(fi, ST_PMM_IDLE); break; case E_PMM_IMPLICIT_DETACH: + sgsn_ranap_iu_release_free(ctx, NULL); mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED); break; case E_PMM_RA_UPDATE: diff --git a/src/sgsn/gprs_ranap.c b/src/sgsn/gprs_ranap.c index d2b345546..8f4565045 100644 --- a/src/sgsn/gprs_ranap.c +++ b/src/sgsn/gprs_ranap.c @@ -119,6 +119,7 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type mm = sgsn_mm_ctx_by_ue_ctx(ctx); if (!mm) { LOGIUP(ctx, LOGL_NOTICE, "Cannot find mm ctx for IU event %d\n", type); + ranap_iu_free_ue(ctx); return rc; } @@ -131,7 +132,11 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type case RANAP_IU_EVENT_LINK_INVALIDATED: /* Clean up ranap_ue_conn_ctx here */ LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi); - osmo_fsm_inst_dispatch(mm->iu.mm_state_fsm, E_PMM_PS_CONN_RELEASE, NULL); + if (mm->iu.mm_state_fsm->state == ST_PMM_CONNECTED) + osmo_fsm_inst_dispatch(mm->iu.mm_state_fsm, E_PMM_PS_CONN_RELEASE, NULL); + else + sgsn_ranap_iu_free(mm); + rc = 0; break; case RANAP_IU_EVENT_SECURITY_MODE_COMPLETE: @@ -153,6 +158,35 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type return rc; } +/* TODO: use timers */ +#define TIMEOUT_RANAP_RELEASE_SEC 5 +void sgsn_ranap_iu_free(struct sgsn_mm_ctx *ctx) +{ + if (!ctx) + return; + + if (!ctx->iu.ue_ctx) + return; + + ranap_iu_free_ue(ctx->iu.ue_ctx); + ctx->iu.ue_ctx = NULL; +} + +void sgsn_ranap_iu_release_free(struct sgsn_mm_ctx *ctx, + const struct RANAP_Cause *cause) +{ + if (!ctx) + return; + + if (!ctx->iu.ue_ctx) + return; + + ranap_iu_tx_release_free(ctx->iu.ue_ctx, + cause, + TIMEOUT_RANAP_RELEASE_SEC); + ctx->iu.ue_ctx = NULL; +} + int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp) { struct msgb *msg;