[GPRS] SGSN: properly delete a PDP context after receiving PDP CTX DEACT REQ

This commit is contained in:
Harald Welte 2010-05-18 14:32:29 +02:00
parent 55e0df7c43
commit 77289c202f
9 changed files with 95 additions and 47 deletions

View File

@ -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 */

View File

@ -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;
};

View File

@ -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

View File

@ -54,6 +54,7 @@
#include <pdp.h>
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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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]))