diff options
-rw-r--r-- | gtp/gtp.c | 104 | ||||
-rw-r--r-- | gtp/gtp.h | 6 |
2 files changed, 73 insertions, 37 deletions
@@ -2337,24 +2337,13 @@ err_out: return EOF; } -/* API: Send Delete PDP Context Request */ +/* API: Deprecated. Send Delete PDP Context Request And free pdp ctx. */ int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, int teardown) { - union gtp_packet packet; - unsigned int length = - get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet); - struct in_addr addr; struct pdp_t *linked_pdp; struct pdp_t *secondary_pdp; int n; - int count = 0; - - if (gsna2in_addr(&addr, &pdp->gsnrc)) { - gsn->err_address++; - LOGP(DLGTP, LOGL_ERROR, "GSN address (len=%u) conversion failed\n", pdp->gsnrc.l); - return EOF; - } if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) { LOGP(DLGTP, LOGL_ERROR, @@ -2362,26 +2351,8 @@ int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, return EOF; } - if (!teardown) { - for (n = 0; n < PDP_MAXNSAPI; n++) - if (linked_pdp->secondary_tei[n]) - count++; - if (count <= 1) { - LOGP(DLGTP, LOGL_ERROR, - "Must use teardown for last context: %d\n", count); - return EOF; - } - } - - if (pdp->version == 1) { - if (teardown) - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN, - 0xff); - - gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi); - } - - gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp); + if (gtp_delete_context_req2(gsn, pdp, cbp, teardown) == EOF) + return EOF; if (teardown) { /* Remove all contexts */ for (n = 0; n < PDP_MAXNSAPI; n++) { @@ -2417,6 +2388,54 @@ int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, return 0; } +/* API: Send Delete PDP Context Request. PDP CTX shall be free'd by user at cb_conf(GTP_DELETE_PDP_RSP) */ +int gtp_delete_context_req2(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, + int teardown) +{ + union gtp_packet packet; + unsigned int length = + get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet); + struct in_addr addr; + struct pdp_t *linked_pdp; + int n; + int count = 0; + + if (gsna2in_addr(&addr, &pdp->gsnrc)) { + gsn->err_address++; + LOGP(DLGTP, LOGL_ERROR, "GSN address (len=%u) conversion failed\n", pdp->gsnrc.l); + return EOF; + } + + if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) { + LOGP(DLGTP, LOGL_ERROR, + "Unknown linked PDP context: %u\n", pdp->teic_own); + return EOF; + } + + if (!teardown) { + for (n = 0; n < PDP_MAXNSAPI; n++) + if (linked_pdp->secondary_tei[n]) + count++; + if (count <= 1) { + LOGP(DLGTP, LOGL_ERROR, + "Must use teardown for last context: %d\n", count); + return EOF; + } + } + + if (pdp->version == 1) { + if (teardown) + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN, + 0xff); + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi); + } + + gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp); + + return 0; +} + /* Send Delete PDP Context Response */ int gtp_delete_pdp_resp(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, @@ -2573,19 +2592,32 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version, uint8_t cause; void *cbp = NULL; uint8_t type = 0; + struct pdp_t *pdp = NULL; int hlen = get_hlen(pack); /* Remove packet from queue */ if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF; + /* Find the context in question. It may not be available if gtp_delete_context_req + * was used and as a result the PDP ctx was already freed */ + if (pdp_getgtp1(&pdp, get_tei(pack))) { + gsn->err_unknownpdp++; + GTP_LOGPKG(LOGL_NOTICE, peer, pack, len, + "Unknown PDP context: %u (expected if gtp_delete_context_req is used)\n", + get_tei(pack)); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, NULL, cbp); + return EOF; + } + /* Decode information elements */ if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) { gsn->invalid++; GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Invalid message format\n"); if (gsn->cb_conf) - gsn->cb_conf(type, EOF, NULL, cbp); + gsn->cb_conf(type, EOF, pdp, cbp); return EOF; } @@ -2595,7 +2627,7 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version, GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Missing mandatory information field\n"); if (gsn->cb_conf) - gsn->cb_conf(type, EOF, NULL, cbp); + gsn->cb_conf(type, EOF, pdp, cbp); return EOF; } @@ -2605,13 +2637,13 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version, GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Unexpected cause value received: %d\n", cause); if (gsn->cb_conf) - gsn->cb_conf(type, cause, NULL, cbp); + gsn->cb_conf(type, cause, pdp, cbp); return EOF; } /* Callback function to notify application */ if (gsn->cb_conf) - gsn->cb_conf(type, cause, NULL, cbp); + gsn->cb_conf(type, cause, pdp, cbp); return 0; } @@ -13,6 +13,7 @@ #define _GTP_H #include <osmocom/core/utils.h> +#include <osmocom/core/defs.h> #define GTP_MODE_GGSN 1 #define GTP_MODE_SGSN 2 @@ -323,7 +324,10 @@ extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, struct in_addr *inetaddr); extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, - void *cbp, int teardown); + void *cbp, int teardown) + OSMO_DEPRECATED("Use gtp_delete_context_req2() instead, to avoid freeing pdp ctx before reply"); +extern int gtp_delete_context_req2(struct gsn_t *gsn, struct pdp_t *pdp, + void *cbp, int teardown); extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len); |