blob: 5c63c1738545ba575bc5ded37daf122bcb588bbb [file] [log] [blame]
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +01001/*
2 * OsmoGGSN - Gateway GPRS Support Node
3 * Copyright (C) 2002, 2003, 2004 Mondru AB.
4 * Copyright (C) 2010-2011, 2016-2017 Harald Welte <laforge@gnumonks.org>
5 * Copyright (C) 2015-2017 sysmocom - s.f.m.c. GmbH
6 *
7 * The contents of this file may be used under the terms of the GNU
8 * General Public License Version 2, provided that the above copyright
9 * notice and this permission notice is included in all copies or
10 * substantial portions of the software.
11 *
12 */
13
14/*
15 * gtp.c: Contains all GTP functionality. Should be able to handle multiple
16 * tunnels in the same program.
17 *
18 * TODO:
19 * - Do we need to handle fragmentation?
20 */
21
22#ifdef __linux__
23#define _GNU_SOURCE 1
24#endif
25
26#include <osmocom/core/logging.h>
27#include <osmocom/core/utils.h>
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +010028#include <osmocom/core/stats.h>
29#include <osmocom/core/rate_ctr.h>
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +010030
31#if defined(__FreeBSD__)
32#include <sys/endian.h>
33#endif
34
35#include "../config.h"
36#ifdef HAVE_STDINT_H
37#include <stdint.h>
38#endif
39
40#include <stdio.h>
41#include <stdarg.h>
42#include <stdlib.h>
43#include <sys/time.h>
44#include <sys/types.h>
45#include <sys/socket.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <sys/stat.h>
49#include <time.h>
50#include <unistd.h>
51#include <string.h>
52#include <errno.h>
53#include <fcntl.h>
54#include <inttypes.h>
55
56#include <arpa/inet.h>
57
58/* #include <stdint.h> ISO C99 types */
59
60#include "pdp.h"
61#include "gtp.h"
62#include "gtpie.h"
63#include "queue.h"
64
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +010065/* Error reporting functions */
66
Oliver Smith9bd27112024-02-22 16:02:37 +010067#define LOGP_WITH_ADDR(ss, level, addr, fmt, args...) \
68 LOGP(ss, level, "addr(%s:%d) " fmt, \
69 inet_ntoa((addr).sin_addr), htons((addr).sin_port), \
70 ##args)
71
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +010072static const struct rate_ctr_desc gsn_ctr_description[] = {
73 [GSN_CTR_ERR_SOCKET] = { "err:socket", "Socket error" },
74 [GSN_CTR_ERR_READFROM] = { "err:readfrom", "readfrom() errors" },
75 [GSN_CTR_ERR_SENDTO] = { "err:sendto", "sendto() errors" },
76 [GSN_CTR_ERR_QUEUEFULL] = { "err:queuefull", "Failed to queue message because queue is full" },
77 [GSN_CTR_ERR_SEQ] = { "err:seq", "Sequence number out of range" },
78 [GSN_CTR_ERR_ADDRESS] = { "err:address", "GSN address conversion failed" },
79 [GSN_CTR_ERR_UNKNOWN_PDP] = { "err:unknown_pdp", "Failed looking up PDP context" },
80 [GSN_CTR_ERR_UNEXPECTED_CAUSE] = { "err:unexpected_cause", "Unexpected cause value received" },
81 [GSN_CTR_ERR_OUT_OF_PDP] = { "err:out_of_pdp", "Out of storage for PDP contexts" },
82 [GSN_CTR_PKT_EMPTY] = { "pkt:empty", "Empty packet received" },
83 [GSN_CTR_PKT_UNSUP] = { "pkt:unsupported", "Unsupported GTP version received" },
84 [GSN_CTR_PKT_TOOSHORT] = { "pkt:too_short", "Packet too short received" },
85 [GSN_CTR_PKT_UNKNOWN] = { "pkt:unknown", "Unknown packet type received" },
86 [GSN_CTR_PKT_UNEXPECT] = { "pkt:unexpected", "Unexpected packet type received" },
87 [GSN_CTR_PKT_DUPLICATE] = { "pkt:duplicate", "Duplicate or unsolicited packet received" },
88 [GSN_CTR_PKT_MISSING] = { "pkt:missing", "Missing IE in packet received" },
89 [GSN_CTR_PKT_INCORRECT] = { "pkt:incorrect", "Incorrect IE in packet received" },
90 [GSN_CTR_PKT_INVALID] = { "pkt:invalid", "Invalid format in packet received" },
91};
92
93static const struct rate_ctr_group_desc gsn_ctrg_desc = {
94 "gsn",
95 "GSN Statistics",
96 OSMO_STATS_CLASS_PEER,
97 ARRAY_SIZE(gsn_ctr_description),
98 gsn_ctr_description,
99};
100static unsigned int gsn_ctr_next_idx = 0;
101
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100102/* Global timer definitions for GTP operation, provided for convenience. To make these user configurable, it is convenient to add
103 * gtp_gsn_tdefs as one of your program's osmo_tdef_group entries and call osmo_tdef_vty_init(). */
104struct osmo_tdef gtp_T_defs[] = {
105 { .T = GTP_GSN_TIMER_T3_RESPONSE, .default_val = 5, .unit = OSMO_TDEF_S,
106 .desc = "Timer T3-RESPONSE holds the maximum wait time for a response of a request message"
107 },
108 { .T = GTP_GSN_TIMER_N3_REQUESTS, .default_val = 3, .unit = OSMO_TDEF_CUSTOM,
109 .desc = "Counter N3-REQUESTS holds the maximum number of attempts made by GTP to send a request message"
110 },
Pau Espin Pedrol3a55b892022-11-04 11:21:23 +0100111 { .T = GTP_GSN_TIMER_T3_HOLD_RESPONSE, .default_val = 5 * 3 /* (GTP_GSN_TIMER_T3_RESPONSE * GTP_GSN_TIMER_N3_REQUESTS) */, .unit = OSMO_TDEF_S,
112 .desc = "Time a GTP respoonse message is kept cached to re-transmit it when a duplicate request is received. Value is generally equal to (T3-RESPONSE * N3-REQUESTS) set at the peer"
113 },
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100114 {}
115};
116
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100117
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100118/* API Functions */
119
120/* Deprecated, use gtp_pdp_newpdp() instead */
121int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
122 uint64_t imsi, uint8_t nsapi)
123{
124 int rc;
125 rc = gtp_pdp_newpdp(gsn, pdp, imsi, nsapi, NULL);
126 return rc;
127}
128
129int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp)
130{
131 if (gsn->cb_delete_context)
132 gsn->cb_delete_context(pdp);
133 return pdp_freepdp(pdp);
134}
135
136/* Free pdp and all its secondary PDP contexts. Must be called on the primary PDP context. */
137int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp)
138{
139 int n;
140 struct pdp_t *secondary_pdp;
141 OSMO_ASSERT(!pdp->secondary);
142
143 for (n = 0; n < PDP_MAXNSAPI; n++) {
144 if (pdp->secondary_tei[n]) {
145 if (gtp_pdp_getgtp1(gsn, &secondary_pdp,
146 pdp->secondary_tei[n])) {
147 LOGP(DLGTP, LOGL_ERROR,
148 "Unknown secondary PDP context\n");
149 continue;
150 }
151 if (pdp != secondary_pdp) {
152 gtp_freepdp(gsn, secondary_pdp);
153 }
154 }
155 }
156
157 return gtp_freepdp(gsn, pdp);
158}
159
160/* gtp_gpdu */
161
162extern int gtp_fd(struct gsn_t *gsn)
163{
164 return gsn->fd0;
165}
166
167int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
168 int (*cb) (struct sockaddr_in * peer))
169{
170 gsn->cb_unsup_ind = cb;
171 return 0;
172}
173
174int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
175 int (*cb) (struct sockaddr_in * peer))
176{
177 gsn->cb_extheader_ind = cb;
178 return 0;
179}
180
181int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn,
182 int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie))
183{
184 gsn->cb_ran_info_relay_ind = cb;
185 return 0;
186}
187
188/* API: Initialise delete context callback */
189/* Called whenever a pdp context is deleted for any reason */
190int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb) (struct pdp_t * pdp))
191{
192 gsn->cb_delete_context = cb;
193 return 0;
194}
195
196int gtp_set_cb_conf(struct gsn_t *gsn,
197 int (*cb) (int type, int cause,
198 struct pdp_t * pdp, void *cbp))
199{
200 gsn->cb_conf = cb;
201 return 0;
202}
203
204int gtp_set_cb_recovery(struct gsn_t *gsn,
205 int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
206{
207 gsn->cb_recovery = cb;
208 return 0;
209}
210
211/* cb_recovery()
212 * pdp may be NULL if Recovery IE was received from a message independent
213 * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
214 * local setup. In case pdp is known, caller may want to keep that pdp alive to
215 * handle subsequent msg cb as this specific pdp ctx is still valid according to
216 * specs.
217 */
218int gtp_set_cb_recovery2(struct gsn_t *gsn,
219 int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery))
220{
221 gsn->cb_recovery2 = cb_recovery2;
222 return 0;
223}
224
225/* cb_recovery()
226 * pdp may be NULL if Recovery IE was received from a message independent
227 * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
228 * local setup. In case pdp is known, caller may want to keep that pdp alive to
229 * handle subsequent msg cb as this specific pdp ctx is still valid according to
230 * specs.
231 */
232int gtp_set_cb_recovery3(struct gsn_t *gsn,
233 int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer,
234 struct pdp_t *pdp, uint8_t recovery))
235{
236 gsn->cb_recovery3 = cb_recovery3;
237 return 0;
238}
239
240int gtp_set_cb_data_ind(struct gsn_t *gsn,
241 int (*cb_data_ind) (struct pdp_t * pdp,
242 void *pack, unsigned len))
243{
244 gsn->cb_data_ind = cb_data_ind;
245 return 0;
246}
Daniel Willmann65363762024-01-26 16:36:20 +0100247int gtp_set_cb_sgsn_context_request_ind(struct gsn_t *gsn,
Daniel Willmann54fcd642024-03-06 11:53:37 +0100248 int (*cb) (struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie))
Daniel Willmann65363762024-01-26 16:36:20 +0100249{
250 gsn->cb_sgsn_context_request_ind = cb;
251 return 0;
252}
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100253
254static int queue_timer_retrans(struct gsn_t *gsn)
255{
256 /* Retransmit any outstanding packets */
257 /* Remove from queue if maxretrans exceeded */
258 time_t now;
259 struct qmsg_t *qmsg;
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100260 unsigned int t3_response, n3_requests;
261
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100262 now = time(NULL);
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100263 t3_response = osmo_tdef_get(gsn->tdef, GTP_GSN_TIMER_T3_RESPONSE, OSMO_TDEF_S, -1);
264 n3_requests = osmo_tdef_get(gsn->tdef, GTP_GSN_TIMER_N3_REQUESTS, OSMO_TDEF_CUSTOM, -1);
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100265
266 /* get first element in queue, as long as the timeout of that
267 * element has expired */
268 while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
269 (qmsg->timeout <= now)) {
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100270 if (qmsg->retrans > n3_requests) { /* Too many retrans */
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100271 LOGP(DLGTP, LOGL_NOTICE, "Retransmit req queue timeout of seq %" PRIu16 "\n",
272 qmsg->seq);
273 if (gsn->cb_conf)
274 gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
275 queue_freemsg(gsn->queue_req, qmsg);
276 } else {
277 LOGP(DLGTP, LOGL_INFO, "Retransmit (%d) of seq %" PRIu16 "\n",
278 qmsg->retrans, qmsg->seq);
279 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
280 (struct sockaddr *)&qmsg->peer,
281 sizeof(struct sockaddr_in)) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100282 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100283 LOGP(DLGTP, LOGL_ERROR,
284 "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s\n",
285 gsn->fd0, (unsigned long)&qmsg->p,
286 qmsg->l, strerror(errno));
287 }
288 queue_back(gsn->queue_req, qmsg);
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100289 qmsg->timeout = now + t3_response;
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100290 qmsg->retrans++;
291 }
292 }
293
294 /* Also clean up reply timeouts */
295 while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
296 (qmsg->timeout < now)) {
297 LOGP(DLGTP, LOGL_DEBUG, "Retransmit resp queue seq %"
298 PRIu16 " expired, removing from queue\n", qmsg->seq);
299 queue_freemsg(gsn->queue_resp, qmsg);
300 }
301
302 return 0;
303}
304
305static int queue_timer_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
306{
307 time_t now, later, diff;
308 struct qmsg_t *qmsg;
309 timeout->tv_usec = 0;
310
311 if (queue_getfirst(gsn->queue_req, &qmsg)) {
312 timeout->tv_sec = 10;
313 } else {
314 now = time(NULL);
315 later = qmsg->timeout;
316 timeout->tv_sec = later - now;
317 if (timeout->tv_sec < 0)
318 timeout->tv_sec = 0; /* No negative allowed */
319 if (timeout->tv_sec > 10)
320 timeout->tv_sec = 10; /* Max sleep for 10 sec */
321 }
322
323 if (queue_getfirst(gsn->queue_resp, &qmsg)) {
324 /* already set by queue_req, do nothing */
325 } else { /* trigger faster if earlier timeout exists in queue_resp */
326 now = time(NULL);
327 later = qmsg->timeout;
328 diff = later - now;
329 if (diff < 0)
330 diff = 0;
331 if (diff < timeout->tv_sec)
332 timeout->tv_sec = diff;
333 }
334
335 return 0;
336}
337
338void gtp_queue_timer_start(struct gsn_t *gsn)
339{
340 struct timeval next;
341
342 /* Retrieve next retransmission as timeval */
343 queue_timer_retranstimeout(gsn, &next);
344
345 /* re-schedule the timer */
346 osmo_timer_schedule(&gsn->queue_timer, next.tv_sec, next.tv_usec/1000);
347}
348
349/* timer callback for libgtp retransmission and ping */
350static void queue_timer_cb(void *data)
351{
352 struct gsn_t *gsn = data;
353
354 /* do all the retransmissions as needed */
355 queue_timer_retrans(gsn);
356
357 gtp_queue_timer_start(gsn);
358}
359
360
361/**
362 * @brief clear the request and response queue. Useful for debugging to reset "some" state.
363 * @param gsn The GGSN instance
364 */
365void gtp_clear_queues(struct gsn_t *gsn)
366{
367 struct qmsg_t *qmsg;
368
369 LOGP(DLGTP, LOGL_INFO, "Clearing req & resp retransmit queues\n");
370 while (!queue_getfirst(gsn->queue_req, &qmsg)) {
371 queue_freemsg(gsn->queue_req, qmsg);
372 }
373
374 while (!queue_getfirst(gsn->queue_resp, &qmsg)) {
375 queue_freemsg(gsn->queue_resp, qmsg);
376 }
377}
378
379/* Perform restoration and recovery error handling as described in 29.060 */
380static void log_restart(struct gsn_t *gsn)
381{
382 FILE *f;
383 int i, rc;
384 int counter = 0;
385 char *filename;
386
387 filename = talloc_asprintf(NULL, "%s/%s", gsn->statedir, RESTART_FILE);
388 OSMO_ASSERT(filename);
389
390 /* We try to open file. On failure we will later try to create file */
391 if (!(f = fopen(filename, "r"))) {
392 LOGP(DLGTP, LOGL_NOTICE,
393 "State information file (%s) not found. Creating new file.\n",
394 filename);
395 } else {
396 rc = fscanf(f, "%d", &counter);
397 if (rc != 1) {
398 LOGP(DLGTP, LOGL_ERROR,
399 "fscanf failed to read counter value\n");
400 goto close_file;
401 }
402 if (fclose(f)) {
403 LOGP(DLGTP, LOGL_ERROR,
404 "fclose failed: Error = %s\n", strerror(errno));
405 }
406 }
407
408 gsn->restart_counter = (unsigned char)counter;
409 gsn->restart_counter++;
410
411 /* Keep the umask closely wrapped around our fopen() call in case the
412 * log outputs cause file creation. */
413 i = umask(022);
414 f = fopen(filename, "w");
415 umask(i);
416 if (!f) {
417 LOGP(DLGTP, LOGL_ERROR,
418 "fopen(path=%s, mode=%s) failed: Error = %s\n", filename,
419 "w", strerror(errno));
420 goto free_filename;
421 }
422
423 fprintf(f, "%d\n", gsn->restart_counter);
424close_file:
425 if (fclose(f))
426 LOGP(DLGTP, LOGL_ERROR,
427 "fclose failed: Error = %s\n", strerror(errno));
428free_filename:
429 talloc_free(filename);
430}
431
Oliver Smith9bd27112024-02-22 16:02:37 +0100432static int create_and_bind_socket(const char *name, struct gsn_t *gsn, int *fd, int domain,
433 const struct in_addr *listen, int port)
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100434{
Oliver Smith9bd27112024-02-22 16:02:37 +0100435 struct sockaddr_in addr;
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100436 int type = SOCK_DGRAM;
437 int protocol = 0;
438
Oliver Smith9bd27112024-02-22 16:02:37 +0100439 *fd = socket(domain, type, protocol);
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100440
441 if (*fd < 0) {
442 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SOCKET);
443 LOGP(DLGTP, LOGL_ERROR,
444 "%s socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
Oliver Smith9bd27112024-02-22 16:02:37 +0100445 name, domain, type, protocol, strerror(errno));
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100446 return -errno;
447 }
448
Oliver Smith9bd27112024-02-22 16:02:37 +0100449 memset(&addr, 0, sizeof(addr));
450 addr.sin_family = domain;
451 addr.sin_addr = *listen;
452 addr.sin_port = htons(port);
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100453#if defined(__FreeBSD__) || defined(__APPLE__)
Oliver Smith9bd27112024-02-22 16:02:37 +0100454 addr.sin_len = sizeof(addr);
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100455#endif
456
Oliver Smith9bd27112024-02-22 16:02:37 +0100457 if (bind(*fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100458 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SOCKET);
Oliver Smith9bd27112024-02-22 16:02:37 +0100459 LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
460 "%s bind(fd=%d) failed: Error = %s\n",
461 name, *fd, strerror(errno));
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100462 return -errno;
463 }
464
465 return 0;
466}
467
Oliver Smith9bd27112024-02-22 16:02:37 +0100468int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
469 int mode)
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100470{
Oliver Smith9bd27112024-02-22 16:02:37 +0100471 LOGP(DLGTP, LOGL_NOTICE, "GTP: gtp_newgsn() started at %s\n", inet_ntoa(*listen));
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100472
473 *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
474
475 (*gsn)->statedir = statedir;
476 log_restart(*gsn);
477
478 /* Initialise sequence number */
479 (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
480
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100481 /* Initialize timers: */
482 (*gsn)->tdef = gtp_T_defs;
483 /* Small hack to properly reset tdef for old clients not using the tdef_group: */
Vadim Yanitskiybf69ddb2023-02-25 18:04:45 +0700484 OSMO_ASSERT(gtp_T_defs[0].default_val != 0);
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100485 if (gtp_T_defs[0].val == 0)
486 osmo_tdefs_reset((*gsn)->tdef);
487
488
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100489 /* Initialise request retransmit queue */
490 queue_new(&(*gsn)->queue_req);
491 queue_new(&(*gsn)->queue_resp);
492
493 /* Initialise pdp table */
494 pdp_init(*gsn);
495
496 /* Initialize internal queue timer */
497 osmo_timer_setup(&(*gsn)->queue_timer, queue_timer_cb, *gsn);
498
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100499 /* Initialize counter group: */
500 (*gsn)->ctrg = rate_ctr_group_alloc(NULL, &gsn_ctrg_desc, gsn_ctr_next_idx++);
501
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100502 /* Initialise call back functions */
503 (*gsn)->cb_create_context_ind = 0;
504 (*gsn)->cb_delete_context = 0;
505 (*gsn)->cb_unsup_ind = 0;
506 (*gsn)->cb_conf = 0;
507 (*gsn)->cb_data_ind = 0;
508
509 /* Store function parameters */
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100510 /* Same IP for user traffic and signalling */
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100511 (*gsn)->gsnc = *listen;
512 (*gsn)->gsnu = *listen;
513 (*gsn)->mode = mode;
514
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100515 (*gsn)->fd0 = -1;
516 (*gsn)->fd1c = -1;
517 (*gsn)->fd1u = -1;
518
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100519 /* Create GTP version 0 socket */
Oliver Smith9bd27112024-02-22 16:02:37 +0100520 if (create_and_bind_socket("GTPv0", *gsn, &(*gsn)->fd0, AF_INET, listen, GTP0_PORT) < 0)
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100521 goto error;
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100522
523 /* Create GTP version 1 control plane socket */
Oliver Smith9bd27112024-02-22 16:02:37 +0100524 if (create_and_bind_socket("GTPv1 control plane", *gsn, &(*gsn)->fd1c, AF_INET, listen, GTP1C_PORT) < 0)
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100525 goto error;
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100526
527 /* Create GTP version 1 user plane socket */
Oliver Smith9bd27112024-02-22 16:02:37 +0100528 if (create_and_bind_socket("GTPv1 user plane", *gsn, &(*gsn)->fd1u, AF_INET, listen, GTP1U_PORT) < 0)
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100529 goto error;
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100530
531 /* Start internal queue timer */
532 gtp_queue_timer_start(*gsn);
533
534 return 0;
Oliver Smith2a0d37c2024-02-20 12:06:53 +0100535error:
536 gtp_free(*gsn);
537 *gsn = NULL;
538 return -1;
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100539}
540
541int gtp_free(struct gsn_t *gsn)
542{
543
544 /* Cleanup internal queue timer */
545 osmo_timer_del(&gsn->queue_timer);
546
547 /* Clean up retransmit queues */
548 queue_free(gsn->queue_req);
549 queue_free(gsn->queue_resp);
550
551 close(gsn->fd0);
552 close(gsn->fd1c);
553 close(gsn->fd1u);
554
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100555 rate_ctr_group_free(gsn->ctrg);
556
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100557 free(gsn);
558 return 0;
559}
560
561/* API: Register create context indication callback */
562int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
563 int (*cb_create_context_ind) (struct pdp_t *
564 pdp))
565{
566 gsn->cb_create_context_ind = cb_create_context_ind;
567 return 0;
568}
569
570int gtp_retrans(struct gsn_t *gsn)
571{
572 /* dummy API, deprecated. */
573 return 0;
574}
575
576int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
577{
578 timeout->tv_sec = 24*60*60;
579 timeout->tv_usec = 0;
580 /* dummy API, deprecated. Return a huge timer to do nothing */
581 return 0;
Vadim Yanitskiy70a4e2e2023-02-25 18:02:01 +0700582}