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 + * 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 +#include + +#if defined(__FreeBSD__) +#include +#endif + +#include "../config.h" +#ifdef HAVE_STDINT_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* #include 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 +#include +#include + +#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 -#include -#include #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);