aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gtp/gtp.c104
-rw-r--r--gtp/gtp.h6
2 files changed, 73 insertions, 37 deletions
diff --git a/gtp/gtp.c b/gtp/gtp.c
index 1309cb5..95abbef 100644
--- a/gtp/gtp.c
+++ b/gtp/gtp.c
@@ -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;
}
diff --git a/gtp/gtp.h b/gtp/gtp.h
index 8f8e293..f185424 100644
--- a/gtp/gtp.h
+++ b/gtp/gtp.h
@@ -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);