aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2022-11-02 14:57:24 +0100
committerPau Espin Pedrol <pespin@sysmocom.de>2022-11-02 18:41:34 +0100
commit724ecc66801c713ba8234ae7e94b74052e6ef024 (patch)
tree352b5d568be7157892904c4e8b0f2dac92fd14ea
parent0d3bd3435ff8057251742fb6d5e3566248ac3172 (diff)
Split gsn_t related APIs out of gtp.{c,h}
This way we split the gsn_t object API/logic from the protocol (message handling) code. Change-Id: I47cebb51bf08b9fcf7f115fc8dbea5f3493d4388
-rw-r--r--gtp/Makefile.am4
-rw-r--r--gtp/gsn.c536
-rw-r--r--gtp/gsn.h167
-rw-r--r--gtp/gtp.c467
-rw-r--r--gtp/gtp.h147
5 files changed, 710 insertions, 611 deletions
diff --git a/gtp/Makefile.am b/gtp/Makefile.am
index 50c582c..77f81cf 100644
--- a/gtp/Makefile.am
+++ b/gtp/Makefile.am
@@ -6,10 +6,10 @@ LIBVERSION=8:1:2
lib_LTLIBRARIES = libgtp.la
-include_HEADERS = gtp.h pdp.h gtpie.h
+include_HEADERS = gtp.h gsn.h pdp.h gtpie.h
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
-libgtp_la_SOURCES = gtp.c gtp.h gtpie.c gtpie.h pdp.c pdp.h lookupa.c lookupa.h queue.c queue.h
+libgtp_la_SOURCES = gtp.c gtp.h gsn.c gsn.h gtpie.c gtpie.h pdp.c pdp.h lookupa.c lookupa.h queue.c queue.h
libgtp_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined
libgtp_la_LIBADD = $(LIBOSMOCORE_LIBS)
diff --git a/gtp/gsn.c b/gtp/gsn.c
new file mode 100644
index 0000000..8fb0fdb
--- /dev/null
+++ b/gtp/gsn.c
@@ -0,0 +1,536 @@
+/*
+ * OsmoGGSN - Gateway GPRS Support Node
+ * Copyright (C) 2002, 2003, 2004 Mondru AB.
+ * Copyright (C) 2010-2011, 2016-2017 Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2015-2017 sysmocom - s.f.m.c. GmbH
+ *
+ * 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.
+ *
+ */
+
+/*
+ * gtp.c: Contains all GTP functionality. Should be able to handle multiple
+ * tunnels in the same program.
+ *
+ * TODO:
+ * - Do we need to handle fragmentation?
+ */
+
+#ifdef __linux__
+#define _GNU_SOURCE 1
+#endif
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+
+#if defined(__FreeBSD__)
+#include <sys/endian.h>
+#endif
+
+#include "../config.h"
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <arpa/inet.h>
+
+/* #include <stdint.h> ISO C99 types */
+
+#include "pdp.h"
+#include "gtp.h"
+#include "gtpie.h"
+#include "queue.h"
+
+/* According to section 14.2 of 3GPP TS 29.006 version 6.9.0 */
+#define N3_REQUESTS 5
+
+#define T3_REQUEST 3
+
+/* Error reporting functions */
+
+#define LOGP_WITH_ADDR(ss, level, addr, fmt, args...) \
+ LOGP(ss, level, "addr(%s:%d) " fmt, \
+ inet_ntoa((addr).sin_addr), htons((addr).sin_port), \
+ ##args);
+
+/* API Functions */
+
+/* Deprecated, use gtp_pdp_newpdp() instead */
+int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
+ uint64_t imsi, uint8_t nsapi)
+{
+ int rc;
+ rc = gtp_pdp_newpdp(gsn, pdp, imsi, nsapi, NULL);
+ return rc;
+}
+
+int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp)
+{
+ if (gsn->cb_delete_context)
+ gsn->cb_delete_context(pdp);
+ return pdp_freepdp(pdp);
+}
+
+/* Free pdp and all its secondary PDP contexts. Must be called on the primary PDP context. */
+int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp)
+{
+ int n;
+ struct pdp_t *secondary_pdp;
+ OSMO_ASSERT(!pdp->secondary);
+
+ for (n = 0; n < PDP_MAXNSAPI; n++) {
+ if (pdp->secondary_tei[n]) {
+ if (gtp_pdp_getgtp1(gsn, &secondary_pdp,
+ pdp->secondary_tei[n])) {
+ LOGP(DLGTP, LOGL_ERROR,
+ "Unknown secondary PDP context\n");
+ continue;
+ }
+ if (pdp != secondary_pdp) {
+ gtp_freepdp(gsn, secondary_pdp);
+ }
+ }
+ }
+
+ return gtp_freepdp(gsn, pdp);
+}
+
+/* gtp_gpdu */
+
+extern int gtp_fd(struct gsn_t *gsn)
+{
+ return gsn->fd0;
+}
+
+int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer))
+{
+ gsn->cb_unsup_ind = cb;
+ return 0;
+}
+
+int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer))
+{
+ gsn->cb_extheader_ind = cb;
+ return 0;
+}
+
+int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie))
+{
+ gsn->cb_ran_info_relay_ind = cb;
+ return 0;
+}
+
+/* API: Initialise delete context callback */
+/* Called whenever a pdp context is deleted for any reason */
+int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb) (struct pdp_t * pdp))
+{
+ gsn->cb_delete_context = cb;
+ return 0;
+}
+
+int gtp_set_cb_conf(struct gsn_t *gsn,
+ int (*cb) (int type, int cause,
+ struct pdp_t * pdp, void *cbp))
+{
+ gsn->cb_conf = cb;
+ return 0;
+}
+
+int gtp_set_cb_recovery(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
+{
+ gsn->cb_recovery = cb;
+ return 0;
+}
+
+/* cb_recovery()
+ * pdp may be NULL if Recovery IE was received from a message independent
+ * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
+ * local setup. In case pdp is known, caller may want to keep that pdp alive to
+ * handle subsequent msg cb as this specific pdp ctx is still valid according to
+ * specs.
+ */
+int gtp_set_cb_recovery2(struct gsn_t *gsn,
+ int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery))
+{
+ gsn->cb_recovery2 = cb_recovery2;
+ return 0;
+}
+
+/* cb_recovery()
+ * pdp may be NULL if Recovery IE was received from a message independent
+ * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
+ * local setup. In case pdp is known, caller may want to keep that pdp alive to
+ * handle subsequent msg cb as this specific pdp ctx is still valid according to
+ * specs.
+ */
+int gtp_set_cb_recovery3(struct gsn_t *gsn,
+ int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer,
+ struct pdp_t *pdp, uint8_t recovery))
+{
+ gsn->cb_recovery3 = cb_recovery3;
+ return 0;
+}
+
+int gtp_set_cb_data_ind(struct gsn_t *gsn,
+ int (*cb_data_ind) (struct pdp_t * pdp,
+ void *pack, unsigned len))
+{
+ gsn->cb_data_ind = cb_data_ind;
+ return 0;
+}
+
+static int queue_timer_retrans(struct gsn_t *gsn)
+{
+ /* Retransmit any outstanding packets */
+ /* Remove from queue if maxretrans exceeded */
+ time_t now;
+ struct qmsg_t *qmsg;
+ now = time(NULL);
+
+ /* get first element in queue, as long as the timeout of that
+ * element has expired */
+ while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
+ (qmsg->timeout <= now)) {
+ if (qmsg->retrans > N3_REQUESTS) { /* Too many retrans */
+ LOGP(DLGTP, LOGL_NOTICE, "Retransmit req queue timeout of seq %" PRIu16 "\n",
+ qmsg->seq);
+ if (gsn->cb_conf)
+ gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
+ queue_freemsg(gsn->queue_req, qmsg);
+ } else {
+ LOGP(DLGTP, LOGL_INFO, "Retransmit (%d) of seq %" PRIu16 "\n",
+ qmsg->retrans, qmsg->seq);
+ if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
+ (struct sockaddr *)&qmsg->peer,
+ sizeof(struct sockaddr_in)) < 0) {
+ gsn->err_sendto++;
+ LOGP(DLGTP, LOGL_ERROR,
+ "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s\n",
+ gsn->fd0, (unsigned long)&qmsg->p,
+ qmsg->l, strerror(errno));
+ }
+ queue_back(gsn->queue_req, qmsg);
+ qmsg->timeout = now + T3_REQUEST;
+ qmsg->retrans++;
+ }
+ }
+
+ /* Also clean up reply timeouts */
+ while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
+ (qmsg->timeout < now)) {
+ LOGP(DLGTP, LOGL_DEBUG, "Retransmit resp queue seq %"
+ PRIu16 " expired, removing from queue\n", qmsg->seq);
+ queue_freemsg(gsn->queue_resp, qmsg);
+ }
+
+ return 0;
+}
+
+static int queue_timer_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
+{
+ time_t now, later, diff;
+ struct qmsg_t *qmsg;
+ timeout->tv_usec = 0;
+
+ if (queue_getfirst(gsn->queue_req, &qmsg)) {
+ timeout->tv_sec = 10;
+ } else {
+ now = time(NULL);
+ later = qmsg->timeout;
+ timeout->tv_sec = later - now;
+ if (timeout->tv_sec < 0)
+ timeout->tv_sec = 0; /* No negative allowed */
+ if (timeout->tv_sec > 10)
+ timeout->tv_sec = 10; /* Max sleep for 10 sec */
+ }
+
+ if (queue_getfirst(gsn->queue_resp, &qmsg)) {
+ /* already set by queue_req, do nothing */
+ } else { /* trigger faster if earlier timeout exists in queue_resp */
+ now = time(NULL);
+ later = qmsg->timeout;
+ diff = later - now;
+ if (diff < 0)
+ diff = 0;
+ if (diff < timeout->tv_sec)
+ timeout->tv_sec = diff;
+ }
+
+ return 0;
+}
+
+void gtp_queue_timer_start(struct gsn_t *gsn)
+{
+ struct timeval next;
+
+ /* Retrieve next retransmission as timeval */
+ queue_timer_retranstimeout(gsn, &next);
+
+ /* re-schedule the timer */
+ osmo_timer_schedule(&gsn->queue_timer, next.tv_sec, next.tv_usec/1000);
+}
+
+/* timer callback for libgtp retransmission and ping */
+static void queue_timer_cb(void *data)
+{
+ struct gsn_t *gsn = data;
+
+ /* do all the retransmissions as needed */
+ queue_timer_retrans(gsn);
+
+ gtp_queue_timer_start(gsn);
+}
+
+
+/**
+ * @brief clear the request and response queue. Useful for debugging to reset "some" state.
+ * @param gsn The GGSN instance
+ */
+void gtp_clear_queues(struct gsn_t *gsn)
+{
+ struct qmsg_t *qmsg;
+
+ LOGP(DLGTP, LOGL_INFO, "Clearing req & resp retransmit queues\n");
+ while (!queue_getfirst(gsn->queue_req, &qmsg)) {
+ queue_freemsg(gsn->queue_req, qmsg);
+ }
+
+ while (!queue_getfirst(gsn->queue_resp, &qmsg)) {
+ queue_freemsg(gsn->queue_resp, qmsg);
+ }
+}
+
+/* Perform restoration and recovery error handling as described in 29.060 */
+static void log_restart(struct gsn_t *gsn)
+{
+ FILE *f;
+ int i, rc;
+ int counter = 0;
+ char *filename;
+
+ filename = talloc_asprintf(NULL, "%s/%s", gsn->statedir, RESTART_FILE);
+ OSMO_ASSERT(filename);
+
+ /* We try to open file. On failure we will later try to create file */
+ if (!(f = fopen(filename, "r"))) {
+ LOGP(DLGTP, LOGL_NOTICE,
+ "State information file (%s) not found. Creating new file.\n",
+ filename);
+ } else {
+ rc = fscanf(f, "%d", &counter);
+ if (rc != 1) {
+ LOGP(DLGTP, LOGL_ERROR,
+ "fscanf failed to read counter value\n");
+ goto close_file;
+ }
+ if (fclose(f)) {
+ LOGP(DLGTP, LOGL_ERROR,
+ "fclose failed: Error = %s\n", strerror(errno));
+ }
+ }
+
+ gsn->restart_counter = (unsigned char)counter;
+ gsn->restart_counter++;
+
+ /* Keep the umask closely wrapped around our fopen() call in case the
+ * log outputs cause file creation. */
+ i = umask(022);
+ f = fopen(filename, "w");
+ umask(i);
+ if (!f) {
+ LOGP(DLGTP, LOGL_ERROR,
+ "fopen(path=%s, mode=%s) failed: Error = %s\n", filename,
+ "w", strerror(errno));
+ goto free_filename;
+ }
+
+ fprintf(f, "%d\n", gsn->restart_counter);
+close_file:
+ if (fclose(f))
+ LOGP(DLGTP, LOGL_ERROR,
+ "fclose failed: Error = %s\n", strerror(errno));
+free_filename:
+ talloc_free(filename);
+}
+
+int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
+ int mode)
+{
+ struct sockaddr_in addr;
+
+ LOGP(DLGTP, LOGL_NOTICE, "GTP: gtp_newgsn() started at %s\n", inet_ntoa(*listen));
+
+ *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
+
+ (*gsn)->statedir = statedir;
+ log_restart(*gsn);
+
+ /* Initialise sequence number */
+ (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
+
+ /* Initialise request retransmit queue */
+ queue_new(&(*gsn)->queue_req);
+ queue_new(&(*gsn)->queue_resp);
+
+ /* Initialise pdp table */
+ pdp_init(*gsn);
+
+ /* Initialize internal queue timer */
+ osmo_timer_setup(&(*gsn)->queue_timer, queue_timer_cb, *gsn);
+
+ /* Initialise call back functions */
+ (*gsn)->cb_create_context_ind = 0;
+ (*gsn)->cb_delete_context = 0;
+ (*gsn)->cb_unsup_ind = 0;
+ (*gsn)->cb_conf = 0;
+ (*gsn)->cb_data_ind = 0;
+
+ /* Store function parameters */
+ (*gsn)->gsnc = *listen;
+ (*gsn)->gsnu = *listen;
+ (*gsn)->mode = mode;
+
+ /* Create GTP version 0 socket */
+ if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ (*gsn)->err_socket++;
+ LOGP(DLGTP, LOGL_ERROR,
+ "GTPv0 socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
+ AF_INET, SOCK_DGRAM, 0, strerror(errno));
+ return -errno;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
+ addr.sin_port = htons(GTP0_PORT);
+#if defined(__FreeBSD__) || defined(__APPLE__)
+ addr.sin_len = sizeof(addr);
+#endif
+
+ if (bind((*gsn)->fd0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ (*gsn)->err_socket++;
+ LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
+ "bind(fd0=%d) failed: Error = %s\n",
+ (*gsn)->fd0, strerror(errno));
+ return -errno;
+ }
+
+ /* Create GTP version 1 control plane socket */
+ if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ (*gsn)->err_socket++;
+ LOGP(DLGTP, LOGL_ERROR,
+ "GTPv1 control plane socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
+ AF_INET, SOCK_DGRAM, 0, strerror(errno));
+ return -errno;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
+ addr.sin_port = htons(GTP1C_PORT);
+#if defined(__FreeBSD__) || defined(__APPLE__)
+ addr.sin_len = sizeof(addr);
+#endif
+
+ if (bind((*gsn)->fd1c, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ (*gsn)->err_socket++;
+ LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
+ "bind(fd1c=%d) failed: Error = %s\n",
+ (*gsn)->fd1c, strerror(errno));
+ return -errno;
+ }
+
+ /* Create GTP version 1 user plane socket */
+ if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ (*gsn)->err_socket++;
+ LOGP(DLGTP, LOGL_ERROR,
+ "GTPv1 user plane socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
+ AF_INET, SOCK_DGRAM, 0, strerror(errno));
+ return -errno;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
+ addr.sin_port = htons(GTP1U_PORT);
+#if defined(__FreeBSD__) || defined(__APPLE__)
+ addr.sin_len = sizeof(addr);
+#endif
+
+ if (bind((*gsn)->fd1u, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ (*gsn)->err_socket++;
+ LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
+ "bind(fd1u=%d) failed: Error = %s\n",
+ (*gsn)->fd1u, strerror(errno));
+ return -errno;
+ }
+
+ /* Start internal queue timer */
+ gtp_queue_timer_start(*gsn);
+
+ return 0;
+}
+
+int gtp_free(struct gsn_t *gsn)
+{
+
+ /* Cleanup internal queue timer */
+ osmo_timer_del(&gsn->queue_timer);
+
+ /* Clean up retransmit queues */
+ queue_free(gsn->queue_req);
+ queue_free(gsn->queue_resp);
+
+ close(gsn->fd0);
+ close(gsn->fd1c);
+ close(gsn->fd1u);
+
+ free(gsn);
+ return 0;
+}
+
+/* API: Register create context indication callback */
+int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
+ int (*cb_create_context_ind) (struct pdp_t *
+ pdp))
+{
+ gsn->cb_create_context_ind = cb_create_context_ind;
+ return 0;
+}
+
+int gtp_retrans(struct gsn_t *gsn)
+{
+ /* dummy API, deprecated. */
+ return 0;
+}
+
+int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
+{
+ timeout->tv_sec = 24*60*60;
+ timeout->tv_usec = 0;
+ /* dummy API, deprecated. Return a huge timer to do nothing */
+ return 0;
+} \ No newline at end of file
diff --git a/gtp/gsn.h b/gtp/gsn.h
new file mode 100644
index 0000000..18a6d58
--- /dev/null
+++ b/gtp/gsn.h
@@ -0,0 +1,167 @@
+/*
+ * OsmoGGSN - Gateway GPRS Support Node
+ * Copyright (C) 2002, 2003, 2004 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.
+ *
+ */
+
+#ifndef _GSN_H
+#define _GSN_H
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/defs.h>
+#include <osmocom/core/timer.h>
+
+#include "pdp.h"
+
+#define GTP_MODE_GGSN 1
+#define GTP_MODE_SGSN 2
+
+#define RESTART_FILE "gsn_restart"
+
+/* ***********************************************************
+ * Information storage for each gsn instance
+ *
+ * Normally each instance of the application corresponds to
+ * one instance of a gsn.
+ *
+ * In order to avoid global variables in the application, and
+ * also in order to allow several instances of a gsn in the same
+ * application this struct is provided in order to store all
+ * relevant information related to the gsn.
+ *
+ * Note that this does not include information storage for '
+ * each pdp context. This is stored in another struct.
+ *************************************************************/
+
+struct gsn_t {
+ /* Parameters related to the network interface */
+
+ int fd0; /* GTP0 file descriptor */
+ int fd1c; /* GTP1 control plane file descriptor */
+ int fd1u; /* GTP0 user plane file descriptor */
+ int mode; /* Mode of operation: GGSN or SGSN */
+ struct in_addr gsnc; /* IP address of this gsn for signalling */
+ struct in_addr gsnu; /* IP address of this gsn for user traffic */
+
+ /* Parameters related to signalling messages */
+ uint16_t seq_next; /* Next sequence number to use */
+ int seq_first; /* First packet in queue (oldest timeout) */
+ int seq_last; /* Last packet in queue (youngest timeout) */
+
+ unsigned char restart_counter; /* Increment on restart. Stored on disk */
+ char *statedir; /* Disk location for permanent storage */
+ void *priv; /* used by libgtp users to attach their own state) */
+ struct queue_t *queue_req; /* Request queue */
+ struct queue_t *queue_resp; /* Response queue */
+
+ struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
+ struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
+
+ struct osmo_timer_list queue_timer; /* internal queue_{req,resp} timer */
+
+ /* Call back functions */
+ int (*cb_delete_context) (struct pdp_t *);
+ int (*cb_create_context_ind) (struct pdp_t *);
+ int (*cb_unsup_ind) (struct sockaddr_in * peer);
+ int (*cb_extheader_ind) (struct sockaddr_in * peer);
+ int (*cb_ran_info_relay_ind) (struct sockaddr_in *peer, union gtpie_member **ie);
+ int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp);
+ int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len);
+ int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery);
+ int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery);
+ int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery);
+
+ /* Counters */
+
+ uint64_t err_socket; /* Number of socket errors */
+ uint64_t err_readfrom; /* Number of readfrom errors */
+ uint64_t err_sendto; /* Number of sendto errors */
+ uint64_t err_memcpy; /* Number of memcpy */
+ uint64_t err_queuefull; /* Number of times queue was full */
+ uint64_t err_seq; /* Number of seq out of range */
+ uint64_t err_address; /* GSN address conversion failed */
+ uint64_t err_unknownpdp; /* GSN address conversion failed */
+ uint64_t err_unknowntid; /* Application supplied unknown imsi+nsapi */
+ uint64_t err_cause; /* Unexpected cause value received */
+ uint64_t err_outofpdp; /* Out of storage for PDP contexts */
+
+ uint64_t empty; /* Number of empty packets */
+ uint64_t unsup; /* Number of unsupported version 29.60 11.1.1 */
+ uint64_t tooshort; /* Number of too short headers 29.60 11.1.2 */
+ uint64_t unknown; /* Number of unknown messages 29.60 11.1.3 */
+ uint64_t unexpect; /* Number of unexpected messages 29.60 11.1.4 */
+ uint64_t duplicate; /* Number of duplicate or unsolicited replies */
+ uint64_t missing; /* Number of missing information field messages */
+ uint64_t incorrect; /* Number of incorrect information field messages */
+ uint64_t invalid; /* Number of invalid message format messages */
+};
+
+/* External API functions */
+
+extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
+ int mode);
+
+extern int gtp_free(struct gsn_t *gsn);
+
+extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
+ uint64_t imsi, uint8_t nsapi) OSMO_DEPRECATED("Use gtp_pdp_newpdp() instead");
+extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp);
+extern int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp);
+
+extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
+ void *cbp);
+
+extern int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
+ int (*cb_create_context_ind) (struct
+ pdp_t *
+ pdp));
+extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
+ int (*cb_data_ind) (struct pdp_t * pdp,
+ void *pack, unsigned len));
+extern int gtp_set_cb_delete_context(struct gsn_t *gsn,
+ int (*cb_delete_context) (struct pdp_t *
+ pdp));
+/*extern int gtp_set_cb_create_context(struct gsn_t *gsn,
+ int (*cb_create_context) (struct pdp_t* pdp)); */
+
+extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer));
+
+extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer));
+
+extern int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie));
+
+extern int gtp_set_cb_conf(struct gsn_t *gsn,
+ int (*cb) (int type, int cause, struct pdp_t * pdp,
+ void *cbp));
+
+int gtp_set_cb_recovery(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer,
+ uint8_t recovery))
+ OSMO_DEPRECATED("Use gtp_set_cb_recovery2() instead, to obtain pdp ctx originating the recovery");
+int gtp_set_cb_recovery2(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer,
+ struct pdp_t * pdp,
+ uint8_t recovery))
+ OSMO_DEPRECATED("Use gtp_set_cb_recovery3() instead, to obtain gsn handling the recovery");
+int gtp_set_cb_recovery3(struct gsn_t *gsn,
+ int (*cb) (struct gsn_t * gsn, struct sockaddr_in * peer,
+ struct pdp_t * pdp,
+ uint8_t recovery));
+void gtp_clear_queues(struct gsn_t *gsn);
+extern int gtp_fd(struct gsn_t *gsn);
+
+extern int gtp_retrans(struct gsn_t *gsn) OSMO_DEPRECATED("This API is a no-op, libgtp already does the job internally");
+extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) OSMO_DEPRECATED("This API is a no-op and will return a 1 day timeout");
+
+/* Internal APIs: */
+void gtp_queue_timer_start(struct gsn_t *gsn);
+
+#endif /* !_GSN_H */
diff --git a/gtp/gtp.c b/gtp/gtp.c
index d2f2219..5585256 100644
--- a/gtp/gtp.c
+++ b/gtp/gtp.c
@@ -131,93 +131,7 @@ const struct value_string gtp_type_names[] = {
{ 0, NULL }
};
-/* Deprecated, use gtp_pdp_newpdp() instead */
-int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
- uint64_t imsi, uint8_t nsapi)
-{
- int rc;
- rc = gtp_pdp_newpdp(gsn, pdp, imsi, nsapi, NULL);
- return rc;
-}
-
-int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp)
-{
- if (gsn->cb_delete_context)
- gsn->cb_delete_context(pdp);
- return pdp_freepdp(pdp);
-}
-
-/* Free pdp and all its secondary PDP contexts. Must be called on the primary PDP context. */
-int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp)
-{
- int n;
- struct pdp_t *secondary_pdp;
- OSMO_ASSERT(!pdp->secondary);
-
- for (n = 0; n < PDP_MAXNSAPI; n++) {
- if (pdp->secondary_tei[n]) {
- if (gtp_pdp_getgtp1(gsn, &secondary_pdp,
- pdp->secondary_tei[n])) {
- LOGP(DLGTP, LOGL_ERROR,
- "Unknown secondary PDP context\n");
- continue;
- }
- if (pdp != secondary_pdp) {
- gtp_freepdp(gsn, secondary_pdp);
- }
- }
- }
-
- return gtp_freepdp(gsn, pdp);
-}
-
-/* gtp_gpdu */
-
-extern int gtp_fd(struct gsn_t *gsn)
-{
- return gsn->fd0;
-}
-
-/* gtp_decaps */
-/* gtp_retrans */
-/* gtp_retranstimeout */
-int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in * peer))
-{
- gsn->cb_unsup_ind = cb;
- return 0;
-}
-
-int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in * peer))
-{
- gsn->cb_extheader_ind = cb;
- return 0;
-}
-
-int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie))
-{
- gsn->cb_ran_info_relay_ind = cb;
- return 0;
-}
-
-/* API: Initialise delete context callback */
-/* Called whenever a pdp context is deleted for any reason */
-int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb) (struct pdp_t * pdp))
-{
- gsn->cb_delete_context = cb;
- return 0;
-}
-
-int gtp_set_cb_conf(struct gsn_t *gsn,
- int (*cb) (int type, int cause,
- struct pdp_t * pdp, void *cbp))
-{
- gsn->cb_conf = cb;
- return 0;
-}
static void emit_cb_recovery(struct gsn_t *gsn, struct sockaddr_in * peer,
struct pdp_t * pdp, uint8_t recovery)
@@ -230,50 +144,6 @@ static void emit_cb_recovery(struct gsn_t *gsn, struct sockaddr_in * peer,
gsn->cb_recovery3(gsn, peer, pdp, recovery);
}
-int gtp_set_cb_recovery(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
-{
- gsn->cb_recovery = cb;
- return 0;
-}
-
-/* cb_recovery()
- * pdp may be NULL if Recovery IE was received from a message independent
- * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
- * local setup. In case pdp is known, caller may want to keep that pdp alive to
- * handle subsequent msg cb as this specific pdp ctx is still valid according to
- * specs.
- */
-int gtp_set_cb_recovery2(struct gsn_t *gsn,
- int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery))
-{
- gsn->cb_recovery2 = cb_recovery2;
- return 0;
-}
-
-/* cb_recovery()
- * pdp may be NULL if Recovery IE was received from a message independent
- * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
- * local setup. In case pdp is known, caller may want to keep that pdp alive to
- * handle subsequent msg cb as this specific pdp ctx is still valid according to
- * specs.
- */
-int gtp_set_cb_recovery3(struct gsn_t *gsn,
- int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer,
- struct pdp_t *pdp, uint8_t recovery))
-{
- gsn->cb_recovery3 = cb_recovery3;
- return 0;
-}
-
-int gtp_set_cb_data_ind(struct gsn_t *gsn,
- int (*cb_data_ind) (struct pdp_t * pdp,
- void *pack, unsigned len))
-{
- gsn->cb_data_ind = cb_data_ind;
- return 0;
-}
-
/**
* get_default_gtp()
* Generate a GPRS Tunneling Protocol signalling packet header, depending
@@ -393,108 +263,6 @@ static uint32_t get_tei(void *pack)
}
}
-static int queue_timer_retrans(struct gsn_t *gsn)
-{
- /* Retransmit any outstanding packets */
- /* Remove from queue if maxretrans exceeded */
- time_t now;
- struct qmsg_t *qmsg;
- now = time(NULL);
-
- /* get first element in queue, as long as the timeout of that
- * element has expired */
- while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
- (qmsg->timeout <= now)) {
- if (qmsg->retrans > N3_REQUESTS) { /* Too many retrans */
- LOGP(DLGTP, LOGL_NOTICE, "Retransmit req queue timeout of seq %" PRIu16 "\n",
- qmsg->seq);
- if (gsn->cb_conf)
- gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
- queue_freemsg(gsn->queue_req, qmsg);
- } else {
- LOGP(DLGTP, LOGL_INFO, "Retransmit (%d) of seq %" PRIu16 "\n",
- qmsg->retrans, qmsg->seq);
- if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
- (struct sockaddr *)&qmsg->peer,
- sizeof(struct sockaddr_in)) < 0) {
- gsn->err_sendto++;
- LOGP(DLGTP, LOGL_ERROR,
- "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s\n",
- gsn->fd0, (unsigned long)&qmsg->p,
- qmsg->l, strerror(errno));
- }
- queue_back(gsn->queue_req, qmsg);
- qmsg->timeout = now + T3_REQUEST;
- qmsg->retrans++;
- }
- }
-
- /* Also clean up reply timeouts */
- while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
- (qmsg->timeout < now)) {
- LOGP(DLGTP, LOGL_DEBUG, "Retransmit resp queue seq %"
- PRIu16 " expired, removing from queue\n", qmsg->seq);
- queue_freemsg(gsn->queue_resp, qmsg);
- }
-
- return 0;
-}
-
-static int queue_timer_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
-{
- time_t now, later, diff;
- struct qmsg_t *qmsg;
- timeout->tv_usec = 0;
-
- if (queue_getfirst(gsn->queue_req, &qmsg)) {
- timeout->tv_sec = 10;
- } else {
- now = time(NULL);
- later = qmsg->timeout;
- timeout->tv_sec = later - now;
- if (timeout->tv_sec < 0)
- timeout->tv_sec = 0; /* No negative allowed */
- if (timeout->tv_sec > 10)
- timeout->tv_sec = 10; /* Max sleep for 10 sec */
- }
-
- if (queue_getfirst(gsn->queue_resp, &qmsg)) {
- /* already set by queue_req, do nothing */
- } else { /* trigger faster if earlier timeout exists in queue_resp */
- now = time(NULL);
- later = qmsg->timeout;
- diff = later - now;
- if (diff < 0)
- diff = 0;
- if (diff < timeout->tv_sec)
- timeout->tv_sec = diff;
- }
-
- return 0;
-}
-
-static void queue_timer_start(struct gsn_t *gsn)
-{
- struct timeval next;
-
- /* Retrieve next retransmission as timeval */
- queue_timer_retranstimeout(gsn, &next);
-
- /* re-schedule the timer */
- osmo_timer_schedule(&gsn->queue_timer, next.tv_sec, next.tv_usec/1000);
-}
-
-/* timer callback for libgtp retransmission and ping */
-static void queue_timer_cb(void *data)
-{
- struct gsn_t *gsn = data;
-
- /* do all the retransmissions as needed */
- queue_timer_retrans(gsn);
-
- queue_timer_start(gsn);
-}
-
/* ***********************************************************
* Reliable delivery of signalling messages
*
@@ -646,31 +414,12 @@ static int gtp_req(struct gsn_t *gsn, uint8_t version, struct pdp_t *pdp,
/* Rearm timer: Retrans time for qmsg just queued may be required
before an existing one (for instance a gtp echo req) */
- queue_timer_start(gsn);
+ gtp_queue_timer_start(gsn);
}
gsn->seq_next++; /* Count up this time */
return 0;
}
-
-/**
- * @brief clear the request and response queue. Useful for debugging to reset "some" state.
- * @param gsn The GGSN instance
- */
-void gtp_clear_queues(struct gsn_t *gsn)
-{
- struct qmsg_t *qmsg;
-
- LOGP(DLGTP, LOGL_INFO, "Clearing req & resp retransmit queues\n");
- while (!queue_getfirst(gsn->queue_req, &qmsg)) {
- queue_freemsg(gsn->queue_req, qmsg);
- }
-
- while (!queue_getfirst(gsn->queue_resp, &qmsg)) {
- queue_freemsg(gsn->queue_resp, qmsg);
- }
-}
-
/* gtp_conf
* Remove signalling packet from retransmission queue.
* return 0 on success, EOF if packet was not found */
@@ -705,20 +454,6 @@ static int gtp_conf(struct gsn_t *gsn, uint8_t version, struct sockaddr_in *peer
return 0;
}
-int gtp_retrans(struct gsn_t *gsn)
-{
- /* dummy API, deprecated. */
- return 0;
-}
-
-int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
-{
- timeout->tv_sec = 24*60*60;
- timeout->tv_usec = 0;
- /* dummy API, deprecated. Return a huge timer to do nothing */
- return 0;
-}
-
static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
union gtp_packet *packet, int len,
struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
@@ -782,7 +517,7 @@ static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
/* Rearm timer: Retrans time for qmsg just queued may be required
before an existing one (for instance a gtp echo req) */
- queue_timer_start(gsn);
+ gtp_queue_timer_start(gsn);
}
return 0;
}
@@ -864,195 +599,6 @@ static int gtp_duplicate(struct gsn_t *gsn, uint8_t version,
return 0;
}
-/* Perform restoration and recovery error handling as described in 29.060 */
-static void log_restart(struct gsn_t *gsn)
-{
- FILE *f;
- int i, rc;
- int counter = 0;
- char *filename;
-
- filename = talloc_asprintf(NULL, "%s/%s", gsn->statedir, RESTART_FILE);
- OSMO_ASSERT(filename);
-
- /* We try to open file. On failure we will later try to create file */
- if (!(f = fopen(filename, "r"))) {
- LOGP(DLGTP, LOGL_NOTICE,
- "State information file (%s) not found. Creating new file.\n",
- filename);
- } else {
- rc = fscanf(f, "%d", &counter);
- if (rc != 1) {
- LOGP(DLGTP, LOGL_ERROR,
- "fscanf failed to read counter value\n");
- goto close_file;
- }
- if (fclose(f)) {
- LOGP(DLGTP, LOGL_ERROR,
- "fclose failed: Error = %s\n", strerror(errno));
- }
- }
-
- gsn->restart_counter = (unsigned char)counter;
- gsn->restart_counter++;
-
- /* Keep the umask closely wrapped around our fopen() call in case the
- * log outputs cause file creation. */
- i = umask(022);
- f = fopen(filename, "w");
- umask(i);
- if (!f) {
- LOGP(DLGTP, LOGL_ERROR,
- "fopen(path=%s, mode=%s) failed: Error = %s\n", filename,
- "w", strerror(errno));
- goto free_filename;
- }
-
- fprintf(f, "%d\n", gsn->restart_counter);
-close_file:
- if (fclose(f))
- LOGP(DLGTP, LOGL_ERROR,
- "fclose failed: Error = %s\n", strerror(errno));
-free_filename:
- talloc_free(filename);
-}
-
-int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
- int mode)
-{
- struct sockaddr_in addr;
-
- LOGP(DLGTP, LOGL_NOTICE, "GTP: gtp_newgsn() started at %s\n", inet_ntoa(*listen));
-
- *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
-
- (*gsn)->statedir = statedir;
- log_restart(*gsn);
-
- /* Initialise sequence number */
- (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
-
- /* Initialise request retransmit queue */
- queue_new(&(*gsn)->queue_req);
- queue_new(&(*gsn)->queue_resp);
-
- /* Initialise pdp table */
- pdp_init(*gsn);
-
- /* Initialize internal queue timer */
- osmo_timer_setup(&(*gsn)->queue_timer, queue_timer_cb, *gsn);
-
- /* Initialise call back functions */
- (*gsn)->cb_create_context_ind = 0;
- (*gsn)->cb_delete_context = 0;
- (*gsn)->cb_unsup_ind = 0;
- (*gsn)->cb_conf = 0;
- (*gsn)->cb_data_ind = 0;
-
- /* Store function parameters */
- (*gsn)->gsnc = *listen;
- (*gsn)->gsnu = *listen;
- (*gsn)->mode = mode;
-
- /* Create GTP version 0 socket */
- if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- (*gsn)->err_socket++;
- LOGP(DLGTP, LOGL_ERROR,
- "GTPv0 socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
- AF_INET, SOCK_DGRAM, 0, strerror(errno));
- return -errno;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
- addr.sin_port = htons(GTP0_PORT);
-#if defined(__FreeBSD__) || defined(__APPLE__)
- addr.sin_len = sizeof(addr);
-#endif
-
- if (bind((*gsn)->fd0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- (*gsn)->err_socket++;
- LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
- "bind(fd0=%d) failed: Error = %s\n",
- (*gsn)->fd0, strerror(errno));
- return -errno;
- }
-
- /* Create GTP version 1 control plane socket */
- if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- (*gsn)->err_socket++;
- LOGP(DLGTP, LOGL_ERROR,
- "GTPv1 control plane socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
- AF_INET, SOCK_DGRAM, 0, strerror(errno));
- return -errno;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
- addr.sin_port = htons(GTP1C_PORT);
-#if defined(__FreeBSD__) || defined(__APPLE__)
- addr.sin_len = sizeof(addr);
-#endif
-
- if (bind((*gsn)->fd1c, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- (*gsn)->err_socket++;
- LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
- "bind(fd1c=%d) failed: Error = %s\n",
- (*gsn)->fd1c, strerror(errno));
- return -errno;
- }
-
- /* Create GTP version 1 user plane socket */
- if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- (*gsn)->err_socket++;
- LOGP(DLGTP, LOGL_ERROR,
- "GTPv1 user plane socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
- AF_INET, SOCK_DGRAM, 0, strerror(errno));
- return -errno;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
- addr.sin_port = htons(GTP1U_PORT);
-#if defined(__FreeBSD__) || defined(__APPLE__)
- addr.sin_len = sizeof(addr);
-#endif
-
- if (bind((*gsn)->fd1u, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- (*gsn)->err_socket++;
- LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
- "bind(fd1u=%d) failed: Error = %s\n",
- (*gsn)->fd1u, strerror(errno));
- return -errno;
- }
-
- /* Start internal queue timer */
- queue_timer_start(*gsn);
-
- return 0;
-}
-
-int gtp_free(struct gsn_t *gsn)
-{
-
- /* Cleanup internal queue timer */
- osmo_timer_del(&gsn->queue_timer);
-
- /* Clean up retransmit queues */
- queue_free(gsn->queue_req);
- queue_free(gsn->queue_resp);
-
- close(gsn->fd0);
- close(gsn->fd1c);
- close(gsn->fd1u);
-
- free(gsn);
- return 0;
-}
-
/* ***********************************************************
* Path management messages
* Messages: echo and version not supported.
@@ -1455,15 +1001,6 @@ int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause)
return 0;
}
-/* API: Register create context indication callback */
-int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
- int (*cb_create_context_ind) (struct pdp_t *
- pdp))
-{
- gsn->cb_create_context_ind = cb_create_context_ind;
- return 0;
-}
-
/* Send Create PDP Context Response */
int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
uint8_t cause)
diff --git a/gtp/gtp.h b/gtp/gtp.h
index 0583025..ede6f73 100644
--- a/gtp/gtp.h
+++ b/gtp/gtp.h
@@ -13,14 +13,10 @@
#define _GTP_H
#include <osmocom/core/utils.h>
-#include <osmocom/core/defs.h>
-#include <osmocom/core/timer.h>
#include "gtpie.h"
#include "pdp.h"
-
-#define GTP_MODE_GGSN 1
-#define GTP_MODE_SGSN 2
+#include "gsn.h"
#define GTP0_PORT 3386
#define GTP1C_PORT 2123
@@ -32,12 +28,10 @@
#define GTP1_HEADER_SIZE_SHORT 8
#define GTP1_HEADER_SIZE_LONG 12
+#define NAMESIZE 1024
#define SYSLOG_PRINTSIZE 255
#define ERRMSG_SIZE 255
-#define RESTART_FILE "gsn_restart"
-#define NAMESIZE 1024
-
/* GTP version 1 extension header type definitions. */
#define GTP_EXT_PDCP_PDU 0xC0 /* PDCP PDU Number */
@@ -232,105 +226,13 @@ union gtp_packet {
struct gtp1_packet_long gtp1l;
} __attribute__ ((packed));
-/* ***********************************************************
- * Information storage for each gsn instance
- *
- * Normally each instance of the application corresponds to
- * one instance of a gsn.
- *
- * In order to avoid global variables in the application, and
- * also in order to allow several instances of a gsn in the same
- * application this struct is provided in order to store all
- * relevant information related to the gsn.
- *
- * Note that this does not include information storage for '
- * each pdp context. This is stored in another struct.
- *************************************************************/
-
-struct gsn_t {
- /* Parameters related to the network interface */
-
- int fd0; /* GTP0 file descriptor */
- int fd1c; /* GTP1 control plane file descriptor */
- int fd1u; /* GTP0 user plane file descriptor */
- int mode; /* Mode of operation: GGSN or SGSN */
- struct in_addr gsnc; /* IP address of this gsn for signalling */
- struct in_addr gsnu; /* IP address of this gsn for user traffic */
-
- /* Parameters related to signalling messages */
- uint16_t seq_next; /* Next sequence number to use */
- int seq_first; /* First packet in queue (oldest timeout) */
- int seq_last; /* Last packet in queue (youngest timeout) */
-
- unsigned char restart_counter; /* Increment on restart. Stored on disk */
- char *statedir; /* Disk location for permanent storage */
- void *priv; /* used by libgtp users to attach their own state) */
- struct queue_t *queue_req; /* Request queue */
- struct queue_t *queue_resp; /* Response queue */
-
- struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
- struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
-
- struct osmo_timer_list queue_timer; /* internal queue_{req,resp} timer */
-
- /* Call back functions */
- int (*cb_delete_context) (struct pdp_t *);
- int (*cb_create_context_ind) (struct pdp_t *);
- int (*cb_unsup_ind) (struct sockaddr_in * peer);
- int (*cb_extheader_ind) (struct sockaddr_in * peer);
- int (*cb_ran_info_relay_ind) (struct sockaddr_in *peer, union gtpie_member **ie);
- int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp);
- int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len);
- int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery);
- int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery);
- int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery);
-
- /* Counters */
-
- uint64_t err_socket; /* Number of socket errors */
- uint64_t err_readfrom; /* Number of readfrom errors */
- uint64_t err_sendto; /* Number of sendto errors */
- uint64_t err_memcpy; /* Number of memcpy */
- uint64_t err_queuefull; /* Number of times queue was full */
- uint64_t err_seq; /* Number of seq out of range */
- uint64_t err_address; /* GSN address conversion failed */
- uint64_t err_unknownpdp; /* GSN address conversion failed */
- uint64_t err_unknowntid; /* Application supplied unknown imsi+nsapi */
- uint64_t err_cause; /* Unexpected cause value received */
- uint64_t err_outofpdp; /* Out of storage for PDP contexts */
-
- uint64_t empty; /* Number of empty packets */
- uint64_t unsup; /* Number of unsupported version 29.60 11.1.1 */
- uint64_t tooshort; /* Number of too short headers 29.60 11.1.2 */
- uint64_t unknown; /* Number of unknown messages 29.60 11.1.3 */
- uint64_t unexpect; /* Number of unexpected messages 29.60 11.1.4 */
- uint64_t duplicate; /* Number of duplicate or unsolicited replies */
- uint64_t missing; /* Number of missing information field messages */
- uint64_t incorrect; /* Number of incorrect information field messages */
- uint64_t invalid; /* Number of invalid message format messages */
-};
-
/* External API functions */
extern const char *gtp_version();
-extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
- int mode);
-
-extern int gtp_free(struct gsn_t *gsn);
-
-extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
- uint64_t imsi, uint8_t nsapi) OSMO_DEPRECATED("Use gtp_pdp_newpdp() instead");
-extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp);
-extern int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp);
extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
void *cbp);
-extern int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
- int (*cb_create_context_ind) (struct
- pdp_t *
- pdp));
-
extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp,
int cause);
@@ -351,53 +253,10 @@ extern int gtp_ran_info_relay_req(struct gsn_t *gsn, const struct sockaddr_in *p
const uint8_t *rim_route_addr, size_t rim_route_addr_len,
uint8_t rim_route_addr_discr);
-extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
- int (*cb_data_ind) (struct pdp_t * pdp,
- void *pack, unsigned len));
-
-extern int gtp_fd(struct gsn_t *gsn);
extern int gtp_decaps0(struct gsn_t *gsn);
extern int gtp_decaps1c(struct gsn_t *gsn);
extern int gtp_decaps1u(struct gsn_t *gsn);
-extern int gtp_retrans(struct gsn_t *gsn) OSMO_DEPRECATED("This API is a no-op, libgtp already does the job internally");
-extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) OSMO_DEPRECATED("This API is a no-op and will return a 1 day timeout");
-
-extern int gtp_set_cb_delete_context(struct gsn_t *gsn,
- int (*cb_delete_context) (struct pdp_t *
- pdp));
-/*extern int gtp_set_cb_create_context(struct gsn_t *gsn,
- int (*cb_create_context) (struct pdp_t* pdp)); */
-
-extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in * peer));
-
-extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in * peer));
-
-extern int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie));
-
-extern int gtp_set_cb_conf(struct gsn_t *gsn,
- int (*cb) (int type, int cause, struct pdp_t * pdp,
- void *cbp));
-
-int gtp_set_cb_recovery(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in * peer,
- uint8_t recovery))
- OSMO_DEPRECATED("Use gtp_set_cb_recovery2() instead, to obtain pdp ctx originating the recovery");
-int gtp_set_cb_recovery2(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in * peer,
- struct pdp_t * pdp,
- uint8_t recovery))
- OSMO_DEPRECATED("Use gtp_set_cb_recovery3() instead, to obtain gsn handling the recovery");;
-int gtp_set_cb_recovery3(struct gsn_t *gsn,
- int (*cb) (struct gsn_t * gsn, struct sockaddr_in * peer,
- struct pdp_t * pdp,
- uint8_t recovery));
-
-void gtp_clear_queues(struct gsn_t *gsn);
-
-/* Internal functions (not part of the API */
+/* Internal functions (not part of the API) */
extern int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
struct in_addr *inetaddrs);