From 77289c202f1e0a748a31d473f7b64c6728377950 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 18 May 2010 14:32:29 +0200 Subject: [GPRS] SGSN: properly delete a PDP context after receiving PDP CTX DEACT REQ --- openbsc/include/openbsc/gprs_gmm.h | 3 ++- openbsc/include/openbsc/gprs_sgsn.h | 6 +++-- openbsc/include/openbsc/sgsn.h | 4 +++- openbsc/src/gprs/gprs_gmm.c | 46 ++++++++++++++++++++++--------------- openbsc/src/gprs/gprs_ns.c | 4 ++++ openbsc/src/gprs/gprs_sgsn.c | 32 ++++++++++++++++++-------- openbsc/src/gprs/sgsn_libgtp.c | 33 ++++++++++++++++---------- openbsc/src/gprs/sgsn_main.c | 6 +++++ openbsc/src/gprs/sgsn_vty.c | 8 +++---- 9 files changed, 95 insertions(+), 47 deletions(-) diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h index 44a28cf83..0d03dd91f 100644 --- a/openbsc/include/openbsc/gprs_gmm.h +++ b/openbsc/include/openbsc/gprs_gmm.h @@ -3,8 +3,9 @@ int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid, uint8_t cause, uint8_t pco_len, uint8_t *pco_v); - int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp); +int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp); + int gsm0408_gprs_rcvmsg(struct msgb *msg); #endif /* _GPRS_GMM_H */ diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 59bf5c097..b7e0a1b96 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -148,12 +148,14 @@ struct sgsn_pdp_ctx { struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm, uint8_t nsapi); +struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm, + uint8_t tid); struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm, uint8_t nsapi); void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp); -struct ggsn_ctx { +struct sgsn_ggsn_ctx { struct llist_head list; uint32_t id; unsigned int gtp_version; @@ -166,7 +168,7 @@ struct ggsn_ctx *ggsn_ctx_find_alloc(uint32_t id); struct apn_ctx { struct llist_head list; - struct ggsn_ctx *ggsn; + struct sgsn_ggsn_ctx *ggsn; char *name; char *description; }; diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 1633b834d..a90a8643c 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -46,8 +46,10 @@ int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg); int sgsn_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci); -struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct ggsn_ctx *ggsn, +struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn, struct sgsn_mm_ctx *mmctx, uint16_t nsapi, struct tlv_parsed *tp); +int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx); + #endif diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 474c7f238..3eddaff10 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -54,6 +54,7 @@ #include extern struct sgsn_instance *sgsn; +extern struct ggsn_ctx *dummy_ggsn; /* Protocol related stuff, should go into libosmocore */ @@ -530,8 +531,6 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) struct gprs_ra_id old_ra_id; uint8_t upd_type; - rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]); - /* Update Type 10.5.5.18 */ upd_type = *cur++ & 0x0f; @@ -572,6 +571,8 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) /* FIXME: Update the MM context with the MS radio acc capabilities */ /* FIXME: Update the MM context with the MS network capabilities */ + rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]); + DEBUGPC(DMM, " ACCEPT\n"); return gsm48_tx_gmm_ra_upd_ack(msg); } @@ -596,6 +597,7 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg) gh->msg_type != GSM48_MT_GMM_ATTACH_REQ && gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) { LOGP(DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n"); + /* FIXME: Send GMM_CAUSE_IMPL_DETACHED */ return -EINVAL; } @@ -683,8 +685,8 @@ int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp) /* PDP address */ msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, pdp->lib->eua.l, pdp->lib->eua.v); - /* Optional: Protocol configuration options */ - if (pdp->lib->pco_neg.l && pdp->lib->pco_neg.v) + /* Optional: Protocol configuration options (FIXME: why 'req') */ + if (pdp->lib->pco_req.l && pdp->lib->pco_req.v) msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT, pdp->lib->pco_neg.l, pdp->lib->pco_neg.v); /* Optional: Packet Flow Identifier */ @@ -701,7 +703,7 @@ int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid, struct gsm48_hdr *gh; uint8_t transaction_id = tid ^ 0x8; /* flip */ - DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT REJ\n"); + DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT REJ(cause=%u)\n", cause); mmctx2msgid(msg, mm); @@ -717,23 +719,22 @@ int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid, } /* Section 9.5.9: Deactivate PDP Context Accept */ -static int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mmctx, - struct msgb *old_msg) +int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp) { - struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg); struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; - uint8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ + uint8_t transaction_id = pdp->ti ^ 0x8; /* flip */ + int rc; DEBUGP(DMM, "<- DEACTIVATE PDP CONTEXT ACK\n"); - gmm_copy_id(msg, old_msg); + mmctx2msgid(msg, pdp->mm); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4); gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK; - return gsm48_gmm_sendmsg(msg, 0, mmctx); + return gsm48_gmm_sendmsg(msg, 0, pdp->mm); } /* Section 9.5.1: Activate PDP Context Request */ @@ -791,6 +792,8 @@ static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx, break; } + DEBUGPC(DMM, "\n"); + /* put the non-TLV elements in the TLV parser structure to * pass them on to the SGSN / GTP code */ tp.lv[OSMO_IE_GSM_REQ_QOS].len = req_qos_len; @@ -819,11 +822,7 @@ static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx, #if 1 { - struct ggsn_ctx ggsn; - ggsn.gtp_version = 1; - inet_aton("192.168.100.239", &ggsn.remote_addr); - ggsn.gsn = sgsn->gsn; - pdp = sgsn_create_pdp_ctx(&ggsn, mmctx, act_req->req_nsapi, &tp); + pdp = sgsn_create_pdp_ctx(dummy_ggsn, mmctx, act_req->req_nsapi, &tp); if (!pdp) return -1; pdp->sapi = act_req->req_llc_sapi; @@ -836,14 +835,24 @@ static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx, } /* Section 9.5.8: Deactivate PDP Context Request */ -static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) +static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t transaction_id = (gh->proto_discr >> 4); + struct sgsn_pdp_ctx *pdp; DEBUGP(DMM, "-> DEACTIVATE PDP CONTEXT REQ (cause: %s)\n", get_value_string(gsm_cause_names, gh->data[0])); - return gsm48_tx_gsm_deact_pdp_acc(ctx, msg); + pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id); + if (!pdp) { + LOGP(DMM, LOGL_NOTICE, "Deactivate PDP Context Request for " + "non-existing PDP Context (IMSI=%s, TI=%u)\n", + mm->imsi, transaction_id); + return -EINVAL; + } + + return sgsn_delete_pdp_ctx(pdp); } static int gsm48_rx_gsm_status(struct sgsn_mm_ctx *ctx, struct msgb *msg) @@ -873,6 +882,7 @@ static int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg) break; case GSM48_MT_GSM_DEACT_PDP_REQ: rc = gsm48_rx_gsm_deact_pdp_req(mmctx, msg); + break; case GSM48_MT_GSM_STATUS: rc = gsm48_rx_gsm_status(mmctx, msg); break; diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 7b1b13871..6d028aba1 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -667,9 +667,13 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, nsvc->nsvci = nsvc->nsei = 0xfffe; nsvc->ip.bts_addr = *saddr; nsvc->state = NSE_S_ALIVE; +#if 0 + return gprs_ns_tx_reset(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE); +#else return gprs_ns_tx_status(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE, 0, msg); +#endif } rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 38056f0e2..2671796ab 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -123,6 +123,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli, return ctx; } + struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm, uint8_t nsapi) { @@ -135,6 +136,19 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm, return NULL; } +struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm, + uint8_t tid) +{ + struct sgsn_pdp_ctx *pdp; + + llist_for_each_entry(pdp, &mm->pdp_list, list) { + if (pdp->ti == tid) + return pdp; + } + return NULL; +} + + struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm, uint8_t nsapi) { @@ -165,11 +179,11 @@ void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp) /* GGSN contexts */ -struct ggsn_ctx *ggsn_ctx_alloc(uint32_t id) +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id) { - struct ggsn_ctx *ggc; + struct sgsn_ggsn_ctx *ggc; - ggc = talloc_zero(tall_bsc_ctx, struct ggsn_ctx); + ggc = talloc_zero(tall_bsc_ctx, struct sgsn_ggsn_ctx); if (!ggc) return NULL; @@ -179,9 +193,9 @@ struct ggsn_ctx *ggsn_ctx_alloc(uint32_t id) return ggc; } -struct ggsn_ctx *ggsn_ctx_by_id(uint32_t id) +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id) { - struct ggsn_ctx *ggc; + struct sgsn_ggsn_ctx *ggc; llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) { if (id == ggc->id) @@ -190,13 +204,13 @@ struct ggsn_ctx *ggsn_ctx_by_id(uint32_t id) return NULL; } -struct ggsn_ctx *ggsn_ctx_find_alloc(uint32_t id) +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id) { - struct ggsn_ctx *ggc; + struct sgsn_ggsn_ctx *ggc; - ggc = ggsn_ctx_by_id(id); + ggc = sgsn_ggsn_ctx_by_id(id); if (!ggc) - ggc = ggsn_ctx_alloc(id); + ggc = sgsn_ggsn_ctx_alloc(id); return ggc; } diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index a034e7ae2..64786de8f 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -89,7 +89,7 @@ const struct value_string gtp_cause_strs[] = { /* generate a PDP context based on the IE's from the 04.08 message, * and send the GTP create pdp context request to the GGSN */ -struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct ggsn_ctx *ggsn, +struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn, struct sgsn_mm_ctx *mmctx, uint16_t nsapi, struct tlv_parsed *tp) @@ -99,6 +99,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct ggsn_ctx *ggsn, uint64_t imsi_ui64; int rc; + LOGP(DGPRS, LOGL_ERROR, "Create PDP Context\n"); pctx = sgsn_pdp_ctx_alloc(mmctx, nsapi); if (!pctx) { LOGP(DGPRS, LOGL_ERROR, "Couldn't allocate PDP Ctx\n"); @@ -178,6 +179,13 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct ggsn_ctx *ggsn, return pctx; } +int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx) +{ + LOGP(DGPRS, LOGL_ERROR, "Delete PDP Context\n"); + + /* FIXME: decide if we need teardown or not ! */ + return gtp_delete_context_req(pctx->ggsn->gsn, pctx->lib, pctx, 1); +} struct cause_map { uint8_t cause_in; @@ -261,20 +269,21 @@ reject: return EOF; } -/* If we receive a 04.08 DEACT PDP CTX REQ or GPRS DETACH, we need to - * look-up the PDP context and request its deletion from the SGSN */ -int sgsn_delete_pdp_ctx(struct ggsn_ctx *ggsn, struct sgsn_mm_ctx *mmctx, - struct tlv_parsed *tp) -{ - //return gtp_delete_context_req(gsn, pdp, cbp, teardown); -} - /* Confirmation of a PDP Context Delete */ -static int delete_pdp_conf(struct pdp_t *pdp, int cause) +static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) { + struct sgsn_pdp_ctx *pctx = cbp; + int rc; + DEBUGP(DGPRS, "Received DELETE PDP CTX CONF, cause=%d(%s)\n", cause, get_value_string(gtp_cause_strs, cause)); - return 0; + + /* Confirm deactivation of PDP context to MS */ + rc = gsm48_tx_gsm_deact_pdp_acc(pctx); + + sgsn_pdp_ctx_free(pctx); + + return rc; } /* Confirmation of an GTP ECHO request */ @@ -305,7 +314,7 @@ static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp) case GTP_CREATE_PDP_REQ: return create_pdp_conf(pdp, cbp, cause); case GTP_DELETE_PDP_REQ: - return delete_pdp_conf(pdp, cause); + return delete_pdp_conf(pdp, cbp, cause); default: break; } diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 2a119e3a8..e72d398a1 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -123,6 +123,8 @@ static void signal_handler(int signal) /* NSI that BSSGP uses when transmitting on NS */ extern struct gprs_ns_inst *bssgp_nsi; extern void *tall_msgb_ctx; +static struct sgsn_ggsn_ctx _ggsn; +struct sgsn_ggsn_ctx *dummy_ggsn = &_ggsn; int main(int argc, char **argv) { @@ -174,6 +176,10 @@ int main(int argc, char **argv) rc = sgsn_gtp_init(&sgsn_inst); nsip_listen(sgsn_nsi, sgsn_inst.cfg.nsip_listen_port); + _ggsn.gtp_version = 1; + inet_aton("192.168.100.239", &_ggsn.remote_addr); + _ggsn.gsn = sgsn_inst.gsn; + while (1) { rc = bsc_select_main(0); if (rc < 0) diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index 212f0e6e2..4fe3e9711 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -49,7 +49,7 @@ static struct cmd_node sgsn_node = { static int config_write_sgsn(struct vty *vty) { struct in_addr ia; - struct ggsn_ctx *gctx; + struct sgsn_ggsn_ctx *gctx; vty_out(vty, "sgsn%s", VTY_NEWLINE); @@ -111,7 +111,7 @@ DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd, "") { uint32_t id = atoi(argv[0]); - struct ggsn_ctx *ggc = ggsn_ctx_find_alloc(id); + struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id); inet_aton(argv[1], &ggc->remote_addr); @@ -124,7 +124,7 @@ DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd, "") { uint32_t id = atoi(argv[0]); - struct ggsn_ctx *ggc = ggsn_ctx_find_alloc(id); + struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id); uint16_t port = atoi(argv[1]); } @@ -135,7 +135,7 @@ DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd, "") { uint32_t id = atoi(argv[0]); - struct ggsn_ctx *ggc = ggsn_ctx_find_alloc(id); + struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id); uint16_t port = atoi(argv[1]); if (atoi(argv[1])) -- cgit v1.2.3