aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2018-07-16 16:47:12 +0200
committerHarald Welte <laforge@gnumonks.org>2018-07-21 17:22:54 +0000
commit8e8c7ef3c7c2822737e7b74d299d520f0f4d94e0 (patch)
tree7b9a0b783d681ec9f33c735213ac1baba9018bf1
parent57238889ebf046cdf9381036d9bc1394a574ed57 (diff)
gtp: Add new API to avoid freeing pdp contexts during DEL CTX REQ
With this API, user is expectd to free the PDP ctx when the confirmation for the release has been received (cb_conf time). This way user can maintain the pdp ctx alive during all this time. Extra code is added to gtp_delete_pdp_resp() since it's now possible to match it and push it up to the user cb_conf. This way, cb_conf() can be used for locally-initiated DEL CTX REQ, while delete_context() cb is left for remotely-initiated DEL CTX REQ. In this later case, when the DEL CTX RESP is sent the ctx is deleted and the delete_context() is called, where the user can do related actions or trigger consequence events (in the case of SGSN, it will drop all related GGSN bits for that PDP ctx and forward the DEACT PDP CTX to the MS). Change-Id: I29d366253bb98dcba328c7ce8aa3e4daf8f75e6c
-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);