Files
osmo-ggsn/gtp/queue.h
Pau Espin Pedrol 05ec2b3fc8 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
2019-08-21 13:32:34 +02:00

76 lines
2.8 KiB
C

/*
* OsmoGGSN - Gateway GPRS Support Node
* Copyright (C) 2002 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
*/
/*
* Queue.c
* Reliable delivery of signalling messages
*/
#ifndef _QUEUE_H
#define _QUEUE_H
#include <osmocom/core/linuxlist.h>
#include "gtp.h"
#define QUEUE_DEBUG 0 /* Print debug information */
#define QUEUE_SIZE 1024 /* Size of retransmission queue */
#define QUEUE_HASH_SIZE 65536 /* Size of hash table (2^16) */
struct qmsg_t { /* Holder for queued packets */
int state; /* 0=empty, 1=full */
uint16_t seq; /* The sequence number */
uint8_t type; /* The type of packet */
void *cbp; /* Application specific pointer */
union gtp_packet p; /* The packet stored */
int l; /* Length of the packet */
int fd; /* Socket packet was sent to / received from */
struct sockaddr_in peer; /* Address packet was sent to / received from */
struct qmsg_t *seqnext; /* Pointer to next in sequence hash list */
int next; /* Pointer to the next in queue. -1: Last */
int prev; /* Pointer to the previous in queue. -1: First */
int this; /* Pointer to myself */
time_t timeout; /* When do we retransmit this packet? */
int retrans; /* How many times did we retransmit this? */
struct llist_head entry; /* Listed with other qmsg_t belonging to a pdp_t->qmsg_list_req */
};
struct queue_t {
struct qmsg_t qmsga[QUEUE_SIZE]; /* Array holding signalling messages */
void *hashseq[QUEUE_HASH_SIZE]; /* Hash array */
int next; /* Next location in queue to use */
int first; /* First packet in queue (oldest timeout) */
int last; /* Last packet in queue (youngest timeout) */
};
/* Allocates and initialises new queue structure */
int queue_new(struct queue_t **queue);
/* Deallocates queue structure */
int queue_free(struct queue_t *queue);
/* Find a new queue element. Return EOF if allready full */
int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg,
struct sockaddr_in *peer, uint16_t seq);
/* Remove an element from the queue. */
int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg);
/* Move an element to the back of the queue */
int queue_back(struct queue_t *queue, struct qmsg_t *qmsg);
/* Get the first element in the queue (oldest) */
int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg);
/* Get the element with a particular sequence number */
int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg,
struct sockaddr_in *peer, uint16_t seq);
/* Free message based on sequence number */
int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer,
uint16_t seq, uint8_t * type, void **cbp);
#endif /* !_QUEUE_H */