aboutsummaryrefslogtreecommitdiffstats
path: root/gtp/pdp.c
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2019-08-16 13:20:09 +0200
committerPau Espin Pedrol <pespin@sysmocom.de>2019-08-23 14:38:56 +0200
commit623c5b36e9453f1623bc443e04627c2c31cb2619 (patch)
tree7010a41ae11c45dfc4a3683d2b34c44aa385345f /gtp/pdp.c
parentaab47afe58124981f7391a4df43821cf2f95725f (diff)
libgtp: Remove packets in tx queue belonging pdp being freed
Doing so should avoid the crash seen in OS#3956, where a message is received in osmo-sgsn gtp iface after having received a DeleteCtxAccept message where pdp and associated cbp is freed. As a result, when new confirmation arrives, it can still be matched against an old request and be sent to upper layers providing an already freed cbp. With this patch, since all queued messages belonging to that pdp are dropped, confirmation won't find a match and be discarded in libgtp. In order to be able to drop all req messages belonging to a pdp, a new list is added to pdp_t and qmsg_t are added to that list when inserted into the per-gsn req transmit queue. This way upon pdp free time it's simply a matter of iterating over that list to remove all messages. There's no need to do same for resp queue, and it'd be actually counter-productive, because it wouldn't be possible to detect and discard duplicates anymore after pdp ctx has been freed. Related: OS#3956 Change-Id: Id86d0b241454d3ad49c64c28087fd2710fa2d17a
Diffstat (limited to 'gtp/pdp.c')
-rw-r--r--gtp/pdp.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/gtp/pdp.c b/gtp/pdp.c
index d745916..eaef545 100644
--- a/gtp/pdp.c
+++ b/gtp/pdp.c
@@ -31,6 +31,7 @@
#include "pdp.h"
#include "gtp.h"
#include "lookupa.h"
+#include "queue.h"
/* ***********************************************************
* Functions related to PDP storage
@@ -156,7 +157,7 @@ int gtp_pdp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t
}
/* Default: Generate G-PDU sequence numbers on Tx */
(*pdp)->tx_gpdu_seq = true;
-
+ INIT_LLIST_HEAD(&(*pdp)->qmsg_list_req);
return 0;
}
}
@@ -165,7 +166,17 @@ int gtp_pdp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t
int pdp_freepdp(struct pdp_t *pdp)
{
+ struct qmsg_t *qmsg, *qmsg2;
struct pdp_t *pdpa = pdp->gsn->pdpa;
+ int rc;
+
+ /* Remove all enqueued messages belonging to this pdp from req tx transmit
+ queue. queue_freemsg will call llist_del(). */
+ llist_for_each_entry_safe(qmsg, qmsg2, &pdp->qmsg_list_req, entry) {
+ if ((rc = queue_freemsg(pdp->gsn->queue_req, qmsg)))
+ LOGP(DLGTP, LOGL_ERROR,
+ "Failed freeing qmsg from qmsg_list_req during pdp_freepdp()! %d\n", rc);
+ }
pdp_tiddel(pdp);