blob: e0d186ff4c6405d5b5d168f71a944e8a8cc0974c [file] [log] [blame]
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01001/*
Harald Welte632e8432017-09-05 18:12:14 +02002 * OsmoGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
Harald Welte632e8432017-09-05 18:12:14 +02004 * Copyright (C) 2010-2011, 2016-2017 Harald Welte <laforge@gnumonks.org>
5 * Copyright (C) 2015-2017 sysmocom - s.f.m.c. GmbH
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01006 *
jjako52c24142002-12-16 13:33:51 +00007 * 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.
Pau Espin Pedrol732131d2018-01-25 17:23:09 +010011 *
jjako52c24142002-12-16 13:33:51 +000012 */
13
14/*
15 * gtp.c: Contains all GTP functionality. Should be able to handle multiple
Pau Espin Pedrol732131d2018-01-25 17:23:09 +010016 * tunnels in the same program.
jjako52c24142002-12-16 13:33:51 +000017 *
18 * TODO:
19 * - Do we need to handle fragmentation?
20 */
21
jjako52c24142002-12-16 13:33:51 +000022#ifdef __linux__
23#define _GNU_SOURCE 1
24#endif
25
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +010026#include <osmocom/core/logging.h>
27#include <osmocom/core/utils.h>
Daniel Willmann65363762024-01-26 16:36:20 +010028#include <osmocom/gsm/gsm48.h>
29#include <osmocom/gsm/gsm23003.h>
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +010030
Holger Hans Peter Freyther5816bcf2014-04-04 11:43:09 +020031#if defined(__FreeBSD__)
32#include <sys/endian.h>
33#endif
34
jjako0fe0df02004-09-17 11:30:40 +000035#include "../config.h"
36#ifdef HAVE_STDINT_H
37#include <stdint.h>
38#endif
jjako52c24142002-12-16 13:33:51 +000039
jjako52c24142002-12-16 13:33:51 +000040#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>
Alexander Huemerdb852a12015-11-06 20:59:01 +010054#include <inttypes.h>
jjako52c24142002-12-16 13:33:51 +000055
56#include <arpa/inet.h>
57
jjakobae2cd42004-01-09 12:04:39 +000058/* #include <stdint.h> ISO C99 types */
jjako52c24142002-12-16 13:33:51 +000059
60#include "pdp.h"
61#include "gtp.h"
62#include "gtpie.h"
63#include "queue.h"
64
jjako1db1c812003-07-06 20:53:57 +000065/* Error reporting functions */
66
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +010067#define GTP_LOGPKG(pri, peer, pack, len, fmt, args...) \
68 logp2(DLGTP, pri, __FILE__, __LINE__, 0, \
69 "Packet from %s:%u, length: %d content: %s: " fmt, \
70 inet_ntoa((peer)->sin_addr), htons((peer)->sin_port), \
71 len, osmo_hexdump((const uint8_t *) pack, len), \
72 ##args);
jjako1db1c812003-07-06 20:53:57 +000073
Neels Hofmeyr9b097382015-10-12 14:00:19 +020074#define LOGP_WITH_ADDR(ss, level, addr, fmt, args...) \
75 LOGP(ss, level, "addr(%s:%d) " fmt, \
76 inet_ntoa((addr).sin_addr), htons((addr).sin_port), \
77 ##args);
78
jjako52c24142002-12-16 13:33:51 +000079/* API Functions */
80
Harald Weltebed35df2011-11-02 13:06:18 +010081const char *gtp_version()
jjako52c24142002-12-16 13:33:51 +000082{
Harald Weltebed35df2011-11-02 13:06:18 +010083 return VERSION;
jjako52c24142002-12-16 13:33:51 +000084}
85
Maxe6612772018-01-11 18:25:37 +010086const struct value_string gtp_type_names[] = {
87 { GTP_ECHO_REQ, "Echo Request" },
88 { GTP_ECHO_RSP, "Echo Response" },
89 { GTP_NOT_SUPPORTED, "Version Not Supported" },
90 { GTP_ALIVE_REQ, "Node Alive Request" },
91 { GTP_ALIVE_RSP, "Node Alive Response" },
92 { GTP_REDIR_REQ, "Redirection Request" },
93 { GTP_REDIR_RSP, "Redirection Response" },
94 { GTP_CREATE_PDP_REQ, "Create PDP Context Request" },
95 { GTP_CREATE_PDP_RSP, "Create PDP Context Response" },
96 { GTP_UPDATE_PDP_REQ, "Update PDP Context Request" },
97 { GTP_UPDATE_PDP_RSP, "Update PDP Context Response" },
98 { GTP_DELETE_PDP_REQ, "Delete PDP Context Request" },
99 { GTP_DELETE_PDP_RSP, "Delete PDP Context Response" },
100 { GTP_ERROR, "Error Indication" },
101 { GTP_PDU_NOT_REQ, "PDU Notification Request" },
102 { GTP_PDU_NOT_RSP, "PDU Notification Response" },
103 { GTP_PDU_NOT_REJ_REQ, "PDU Notification Reject Request" },
104 { GTP_PDU_NOT_REJ_RSP, "PDU Notification Reject Response" },
105 { GTP_SUPP_EXT_HEADER, "Supported Extension Headers Notification" },
106 { GTP_SND_ROUTE_REQ, "Send Routeing Information for GPRS Request" },
107 { GTP_SND_ROUTE_RSP, "Send Routeing Information for GPRS Response" },
108 { GTP_FAILURE_REQ, "Failure Report Request" },
109 { GTP_FAILURE_RSP, "Failure Report Response" },
110 { GTP_MS_PRESENT_REQ, "Note MS GPRS Present Request" },
111 { GTP_MS_PRESENT_RSP, "Note MS GPRS Present Response" },
112 { GTP_IDEN_REQ, "Identification Request" },
113 { GTP_IDEN_RSP, "Identification Response" },
114 { GTP_SGSN_CONTEXT_REQ,"SGSN Context Request" },
115 { GTP_SGSN_CONTEXT_RSP,"SGSN Context Response" },
116 { GTP_SGSN_CONTEXT_ACK,"SGSN Context Acknowledge" },
117 { GTP_FWD_RELOC_REQ, "Forward Relocation Request" },
118 { GTP_FWD_RELOC_RSP, "Forward Relocation Response" },
119 { GTP_FWD_RELOC_COMPL, "Forward Relocation Complete" },
120 { GTP_RELOC_CANCEL_REQ,"Relocation Cancel Request" },
121 { GTP_RELOC_CANCEL_RSP,"Relocation Cancel Response" },
122 { GTP_FWD_SRNS, "Forward SRNS Context" },
123 { GTP_FWD_RELOC_ACK, "Forward Relocation Complete Acknowledge" },
124 { GTP_FWD_SRNS_ACK, "Forward SRNS Context Acknowledge" },
125 { GTP_DATA_TRAN_REQ, "Data Record Transfer Request" },
126 { GTP_DATA_TRAN_RSP, "Data Record Transfer Response" },
127 { GTP_GPDU, "G-PDU" },
128 { 0, NULL }
129};
130
jjako52c24142002-12-16 13:33:51 +0000131
jjako52c24142002-12-16 13:33:51 +0000132
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +0200133static void emit_cb_recovery(struct gsn_t *gsn, struct sockaddr_in * peer,
134 struct pdp_t * pdp, uint8_t recovery)
135{
136 if (gsn->cb_recovery)
137 gsn->cb_recovery(peer, recovery);
138 if (gsn->cb_recovery2)
139 gsn->cb_recovery2(peer, pdp, recovery);
Pau Espin Pedrol5d8b2262019-08-22 15:00:00 +0200140 if (gsn->cb_recovery3)
141 gsn->cb_recovery3(gsn, peer, pdp, recovery);
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +0200142}
143
jjako08d331d2003-10-13 20:33:30 +0000144/**
145 * get_default_gtp()
146 * Generate a GPRS Tunneling Protocol signalling packet header, depending
147 * on GTP version and message type. pdp is used for teid/flow label.
148 * *packet must be allocated by the calling function, and be large enough
149 * to hold the packet header.
150 * returns the length of the header. 0 on error.
151 **/
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100152static unsigned int get_default_gtp(uint8_t version, uint8_t type, void *packet)
Harald Weltebed35df2011-11-02 13:06:18 +0100153{
154 struct gtp0_header *gtp0_default = (struct gtp0_header *)packet;
155 struct gtp1_header_long *gtp1_default =
156 (struct gtp1_header_long *)packet;
157 switch (version) {
158 case 0:
159 /* Initialise "standard" GTP0 header */
160 memset(gtp0_default, 0, sizeof(struct gtp0_header));
161 gtp0_default->flags = 0x1e;
162 gtp0_default->type = hton8(type);
163 gtp0_default->spare1 = 0xff;
164 gtp0_default->spare2 = 0xff;
165 gtp0_default->spare3 = 0xff;
166 gtp0_default->number = 0xff;
167 return GTP0_HEADER_SIZE;
168 case 1:
169 /* Initialise "standard" GTP1 header */
170 /* 29.060: 8.2: S=1 and PN=0 */
171 /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */
172 /* and Supported Extension Headers Notification, the S field shall be */
173 /* set to 1 */
174 /* Currently extension headers are not supported */
175 memset(gtp1_default, 0, sizeof(struct gtp1_header_long));
Harald Weltefed598f2017-09-24 16:39:22 +0800176 /* No extension, enable sequence, no N-PDU */
177 gtp1_default->flags = GTPHDR_F_VER(1) | GTP1HDR_F_GTP1 | GTP1HDR_F_SEQ;
Harald Weltebed35df2011-11-02 13:06:18 +0100178 gtp1_default->type = hton8(type);
179 return GTP1_HEADER_SIZE_LONG;
180 default:
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100181 LOGP(DLGTP, LOGL_ERROR,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +0100182 "Unknown GTP packet version: %d\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +0100183 return 0;
184 }
jjako52c24142002-12-16 13:33:51 +0000185}
186
jjako08d331d2003-10-13 20:33:30 +0000187/**
188 * get_seq()
189 * Get sequence number of a packet.
190 * Returns 0 on error
191 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100192static uint16_t get_seq(void *pack)
193{
194 union gtp_packet *packet = (union gtp_packet *)pack;
Harald Weltefed598f2017-09-24 16:39:22 +0800195 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
jjako08d331d2003-10-13 20:33:30 +0000196
Harald Weltefed598f2017-09-24 16:39:22 +0800197 if (ver == 0) {
Harald Weltebed35df2011-11-02 13:06:18 +0100198 return ntoh16(packet->gtp0.h.seq);
Harald Weltefed598f2017-09-24 16:39:22 +0800199 } else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
Harald Weltebed35df2011-11-02 13:06:18 +0100200 return ntoh16(packet->gtp1l.h.seq);
201 } else {
Harald Weltebed35df2011-11-02 13:06:18 +0100202 return 0;
203 }
jjako08d331d2003-10-13 20:33:30 +0000204}
205
206/**
207 * get_tid()
208 * Get tunnel identifier of a packet.
209 * Returns 0 on error
210 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100211static uint64_t get_tid(void *pack)
212{
213 union gtp_packet *packet = (union gtp_packet *)pack;
214
Harald Weltefed598f2017-09-24 16:39:22 +0800215 if (GTPHDR_F_GET_VER(packet->flags) == 0) { /* Version 0 */
Pablo Neira Ayuso1a1ba022014-03-20 12:35:26 +0100216 return be64toh(packet->gtp0.h.tid);
Harald Weltebed35df2011-11-02 13:06:18 +0100217 }
218 return 0;
jjako08d331d2003-10-13 20:33:30 +0000219}
220
221/**
222 * get_hlen()
223 * Get the header length of a packet.
224 * Returns 0 on error
225 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100226static uint16_t get_hlen(void *pack)
227{
228 union gtp_packet *packet = (union gtp_packet *)pack;
Harald Weltefed598f2017-09-24 16:39:22 +0800229 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
jjako08d331d2003-10-13 20:33:30 +0000230
Harald Weltefed598f2017-09-24 16:39:22 +0800231 if (ver == 0) { /* Version 0 */
Harald Weltebed35df2011-11-02 13:06:18 +0100232 return GTP0_HEADER_SIZE;
Harald Weltefed598f2017-09-24 16:39:22 +0800233 } else if (ver == 1 && (packet->flags & 0x07) == 0) { /* Short version 1 */
Harald Weltebed35df2011-11-02 13:06:18 +0100234 return GTP1_HEADER_SIZE_SHORT;
Harald Weltefed598f2017-09-24 16:39:22 +0800235 } else if (ver == 1) { /* Version 1 with seq/n-pdu/ext */
236 return GTP1_HEADER_SIZE_LONG;
Harald Weltebed35df2011-11-02 13:06:18 +0100237 } else {
Harald Welted37b80a2016-12-15 18:33:15 +0100238 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100239 return 0;
240 }
jjako08d331d2003-10-13 20:33:30 +0000241}
242
243/**
244 * get_tei()
245 * Get the tunnel endpoint identifier (flow label) of a packet.
246 * Returns 0xffffffff on error.
247 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100248static uint32_t get_tei(void *pack)
249{
250 union gtp_packet *packet = (union gtp_packet *)pack;
Harald Weltefed598f2017-09-24 16:39:22 +0800251 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
jjako08d331d2003-10-13 20:33:30 +0000252
Harald Weltefed598f2017-09-24 16:39:22 +0800253 if (ver == 0) { /* Version 0 */
Harald Weltebed35df2011-11-02 13:06:18 +0100254 return ntoh16(packet->gtp0.h.flow);
Harald Weltefed598f2017-09-24 16:39:22 +0800255 } else if (ver == 1) { /* Version 1 */
Harald Weltebed35df2011-11-02 13:06:18 +0100256 return ntoh32(packet->gtp1l.h.tei);
257 } else {
Harald Welted37b80a2016-12-15 18:33:15 +0100258 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100259 return 0xffffffff;
260 }
jjako08d331d2003-10-13 20:33:30 +0000261}
jjakoa7cd2492003-04-11 09:40:12 +0000262
jjako52c24142002-12-16 13:33:51 +0000263/* ***********************************************************
264 * Reliable delivery of signalling messages
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100265 *
jjako52c24142002-12-16 13:33:51 +0000266 * Sequence numbers are used for both signalling messages and
267 * data messages.
268 *
269 * For data messages each tunnel maintains a sequence counter,
270 * which is incremented by one each time a new data message
271 * is sent. The sequence number starts at (0) zero at tunnel
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100272 * establishment, and wraps around at 65535 (29.060 9.3.1.1
jjako52c24142002-12-16 13:33:51 +0000273 * and 09.60 8.1.1.1). The sequence numbers are either ignored,
274 * or can be used to check the validity of the message in the
275 * receiver, or for reordering af packets.
276 *
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100277 * For signalling messages the sequence number is used by
jjako52c24142002-12-16 13:33:51 +0000278 * signalling messages for which a response is defined. A response
279 * message should copy the sequence from the corresponding request
280 * message. The sequence number "unambiguously" identifies a request
281 * message within a given path, with a path being defined as a set of
282 * two endpoints (29.060 8.2, 29.060 7.6, 09.60 7.8). "All request
283 * messages shall be responded to, and all response messages associated
284 * with a certain request shall always include the same information"
285 *
286 * We take this to mean that the GSN transmitting a request is free to
287 * choose the sequence number, as long as it is unique within a given path.
288 * It means that we are allowed to count backwards, or roll over at 17
289 * if we prefer that. It also means that we can use the same counter for
290 * all paths. This has the advantage that the transmitted request sequence
291 * numbers are unique within each GSN, and also we dont have to mess around
292 * with path setup and teardown.
293 *
294 * If a response message is lost, the request will be retransmitted, and
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100295 * the receiving GSN will receive a "duplicated" request. The standard
jjako52c24142002-12-16 13:33:51 +0000296 * requires the receiving GSN to send a response, with the same information
297 * as in the original response. For most messages this happens automatically:
298 *
Pau Espin Pedrolde72d262019-05-29 18:17:05 +0200299 * Echo: Automatically duplicates the original response
jjako52c24142002-12-16 13:33:51 +0000300 * Create pdp context: The SGSN may send create context request even if
301 * a context allready exist (imsi+nsapi?). This means that the reply will
Pau Espin Pedrolde72d262019-05-29 18:17:05 +0200302 automatically duplicate the original response. It might however have
jjako08d331d2003-10-13 20:33:30 +0000303 * side effects in the application which is asked twice to validate
304 * the login.
Pau Espin Pedrolde72d262019-05-29 18:17:05 +0200305 * Update pdp context: Automatically duplicates the original response???
jjako52c24142002-12-16 13:33:51 +0000306 * Delete pdp context. Automatically in gtp0, but in gtp1 will generate
307 * a nonexist reply message.
308 *
309 * The correct solution will be to make a queue containing response messages.
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100310 * This queue should be checked whenever a request is received. If the
Pau Espin Pedrol0d3bd342022-11-02 13:22:17 +0100311 * response is already in the queue that response should be transmitted.
jjako52c24142002-12-16 13:33:51 +0000312 * It should be possible to find messages in this queue on the basis of
313 * the sequence number and peer GSN IP address (The sequense number is unique
314 * within each path). This need to be implemented by a hash table. Furthermore
315 * it should be possibly to delete messages based on a timeout. This can be
316 * achieved by means of a linked list. The timeout value need to be larger
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100317 * than T3-RESPONSE * N3-REQUESTS (recommended value 5). These timers are
jjako52c24142002-12-16 13:33:51 +0000318 * set in the peer GSN, so there is no way to know these parameters. On the
319 * other hand the timeout value need to be so small that we do not receive
320 * wraparound sequence numbere before the message is deleted. 60 seconds is
321 * probably not a bad choise.
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100322 *
jjako52c24142002-12-16 13:33:51 +0000323 * This queue however is first really needed from gtp1.
324 *
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100325 * gtp_req:
jjako52c24142002-12-16 13:33:51 +0000326 * Send off a signalling message with appropiate sequence
327 * number. Store packet in queue.
328 * gtp_conf:
329 * Remove an incoming confirmation from the queue
330 * gtp_resp:
jjako08d331d2003-10-13 20:33:30 +0000331 * Send off a response to a request. Use the same sequence
jjako52c24142002-12-16 13:33:51 +0000332 * number in the response as in the request.
jjako2c381332003-10-21 19:09:53 +0000333 * gtp_notification:
334 * Send off a notification message. This is neither a request nor
335 * a response. Both TEI and SEQ are zero.
jjako52c24142002-12-16 13:33:51 +0000336 * gtp_retrans:
337 * Retransmit any outstanding packets which have exceeded
338 * a predefined timeout.
339 *************************************************************/
340
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100341static int gtp_req(struct gsn_t *gsn, uint8_t version, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +0100342 union gtp_packet *packet, int len,
Daniel Willmanncd970ed2024-01-03 15:03:24 +0100343 const struct in_addr *inetaddr, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +0100344{
Harald Weltefed598f2017-09-24 16:39:22 +0800345 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100346 struct sockaddr_in addr;
347 struct qmsg_t *qmsg;
348 int fd;
jjako08d331d2003-10-13 20:33:30 +0000349
Harald Weltebed35df2011-11-02 13:06:18 +0100350 memset(&addr, 0, sizeof(addr));
351 addr.sin_family = AF_INET;
352 addr.sin_addr = *inetaddr;
jjako0fe0df02004-09-17 11:30:40 +0000353#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100354 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +0000355#endif
jjako52c24142002-12-16 13:33:51 +0000356
Harald Weltefed598f2017-09-24 16:39:22 +0800357 if (ver == 0) { /* Version 0 */
Harald Weltebed35df2011-11-02 13:06:18 +0100358 addr.sin_port = htons(GTP0_PORT);
359 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
360 packet->gtp0.h.seq = hton16(gsn->seq_next);
Pablo Neira Ayuso1a1ba022014-03-20 12:35:26 +0100361 if (pdp) {
Harald Weltebed35df2011-11-02 13:06:18 +0100362 packet->gtp0.h.tid =
Pablo Neira Ayuso746b9442014-03-24 17:58:27 +0100363 htobe64(pdp_gettid(pdp->imsi, pdp->nsapi));
Pablo Neira Ayuso1a1ba022014-03-20 12:35:26 +0100364 }
Harald Weltebed35df2011-11-02 13:06:18 +0100365 if (pdp && ((packet->gtp0.h.type == GTP_GPDU)
366 || (packet->gtp0.h.type == GTP_ERROR)))
367 packet->gtp0.h.flow = hton16(pdp->flru);
368 else if (pdp)
369 packet->gtp0.h.flow = hton16(pdp->flrc);
370 fd = gsn->fd0;
Harald Weltefed598f2017-09-24 16:39:22 +0800371 } else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
Harald Weltebed35df2011-11-02 13:06:18 +0100372 addr.sin_port = htons(GTP1C_PORT);
373 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
374 packet->gtp1l.h.seq = hton16(gsn->seq_next);
375 if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) ||
376 (packet->gtp1l.h.type == GTP_ERROR)))
377 packet->gtp1l.h.tei = hton32(pdp->teid_gn);
378 else if (pdp)
379 packet->gtp1l.h.tei = hton32(pdp->teic_gn);
380 fd = gsn->fd1c;
381 } else {
Harald Welted37b80a2016-12-15 18:33:15 +0100382 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100383 return -1;
384 }
jjako52c24142002-12-16 13:33:51 +0000385
Harald Weltebed35df2011-11-02 13:06:18 +0100386 if (sendto(fd, packet, len, 0,
387 (struct sockaddr *)&addr, sizeof(addr)) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100388 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Max14b1b632017-08-21 20:14:59 +0200389 LOGP(DLGTP, LOGL_ERROR, "Sendto(fd=%d, msg=%lx, len=%d, dst=%s) failed: Error = %s\n", fd,
390 (unsigned long)&packet, len, inet_ntoa(addr.sin_addr), strerror(errno));
Harald Weltebed35df2011-11-02 13:06:18 +0100391 return -1;
392 }
393
394 /* Use new queue structure */
395 if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100396 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_QUEUEFULL);
Pau Espin Pedrolbdf06972022-03-07 12:49:34 +0100397 LOGP(DLGTP, LOGL_ERROR, "Retransmit req queue is full (seq=%" PRIu16 ")\n",
398 gsn->seq_next);
Harald Weltebed35df2011-11-02 13:06:18 +0100399 } else {
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100400 unsigned int t3_response;
Pau Espin Pedrolf4718002022-03-07 12:55:51 +0100401 LOGP(DLGTP, LOGL_DEBUG, "Registering seq=%" PRIu16
402 " in restransmit req queue\n", gsn->seq_next);
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100403 t3_response = osmo_tdef_get(gsn->tdef, GTP_GSN_TIMER_T3_RESPONSE, OSMO_TDEF_S, -1);
Harald Weltebed35df2011-11-02 13:06:18 +0100404 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
405 qmsg->l = len;
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100406 qmsg->timeout = time(NULL) + t3_response; /* When to timeout */
Harald Weltebed35df2011-11-02 13:06:18 +0100407 qmsg->retrans = 0; /* No retransmissions so far */
408 qmsg->cbp = cbp;
409 qmsg->type = ntoh8(packet->gtp0.h.type);
410 qmsg->fd = fd;
Pau Espin Pedrol623c5b32019-08-16 13:20:09 +0200411 if (pdp) /* echo requests are not pdp-bound */
412 llist_add(&qmsg->entry, &pdp->qmsg_list_req);
Pau Espin Pedrolc94837c2019-08-28 19:44:20 +0200413
414 /* Rearm timer: Retrans time for qmsg just queued may be required
415 before an existing one (for instance a gtp echo req) */
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100416 gtp_queue_timer_start(gsn);
Harald Weltebed35df2011-11-02 13:06:18 +0100417 }
418 gsn->seq_next++; /* Count up this time */
419 return 0;
jjako52c24142002-12-16 13:33:51 +0000420}
421
422/* gtp_conf
423 * Remove signalling packet from retransmission queue.
424 * return 0 on success, EOF if packet was not found */
425
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100426static int gtp_conf(struct gsn_t *gsn, uint8_t version, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +0100427 union gtp_packet *packet, int len, uint8_t * type, void **cbp)
428{
Harald Weltefed598f2017-09-24 16:39:22 +0800429 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100430 uint16_t seq;
jjako08d331d2003-10-13 20:33:30 +0000431
Harald Weltefed598f2017-09-24 16:39:22 +0800432 if (ver == 0)
Harald Weltebed35df2011-11-02 13:06:18 +0100433 seq = ntoh16(packet->gtp0.h.seq);
Harald Weltefed598f2017-09-24 16:39:22 +0800434 else if (ver == 1 && (packet->gtp1l.h.flags & GTP1HDR_F_SEQ))
Harald Weltebed35df2011-11-02 13:06:18 +0100435 seq = ntoh16(packet->gtp1l.h.seq);
436 else {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100437 GTP_LOGPKG(LOGL_ERROR, peer, packet, len,
438 "Unknown GTP packet version\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100439 return EOF;
440 }
jjako08d331d2003-10-13 20:33:30 +0000441
Pau Espin Pedrolf4718002022-03-07 12:55:51 +0100442 GTP_LOGPKG(LOGL_DEBUG, peer, packet, len,
443 "Freeing seq=%" PRIu16 " from retransmit req queue\n",
444 seq);
Harald Weltebed35df2011-11-02 13:06:18 +0100445 if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100446 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SEQ);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100447 GTP_LOGPKG(LOGL_ERROR, peer, packet, len,
Pau Espin Pedrolf4718002022-03-07 12:55:51 +0100448 "Confirmation packet not found in retransmit req queue (seq=%"
449 PRIu16 ")\n", seq);
Harald Weltebed35df2011-11-02 13:06:18 +0100450 return EOF;
451 }
jjako52c24142002-12-16 13:33:51 +0000452
Harald Weltebed35df2011-11-02 13:06:18 +0100453 return 0;
jjako52c24142002-12-16 13:33:51 +0000454}
455
Daniel Willmann6d85d2a2024-01-26 16:24:50 +0100456static int gtp_resp2(struct gsn_t *gsn, union gtp_packet *packet, int len, struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid, uint16_t flow, uint32_t tei)
Harald Weltebed35df2011-11-02 13:06:18 +0100457{
Harald Weltefed598f2017-09-24 16:39:22 +0800458 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100459 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000460
Harald Weltefed598f2017-09-24 16:39:22 +0800461 if (ver == 0) { /* Version 0 */
Harald Weltebed35df2011-11-02 13:06:18 +0100462 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
463 packet->gtp0.h.seq = hton16(seq);
Pablo Neira Ayuso1a1ba022014-03-20 12:35:26 +0100464 packet->gtp0.h.tid = htobe64(tid);
Daniel Willmann6d85d2a2024-01-26 16:24:50 +0100465 packet->gtp0.h.flow = hton16(flow);
Harald Weltefed598f2017-09-24 16:39:22 +0800466 } else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
Harald Weltebed35df2011-11-02 13:06:18 +0100467 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
468 packet->gtp1l.h.seq = hton16(seq);
Daniel Willmann6d85d2a2024-01-26 16:24:50 +0100469 packet->gtp1l.h.tei = hton32(tei);
Harald Weltebed35df2011-11-02 13:06:18 +0100470 } else {
Harald Welted37b80a2016-12-15 18:33:15 +0100471 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100472 return -1;
473 }
jjako08d331d2003-10-13 20:33:30 +0000474
Harald Weltebed35df2011-11-02 13:06:18 +0100475 if (fcntl(fd, F_SETFL, 0)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100476 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100477 return -1;
478 }
jjako52c24142002-12-16 13:33:51 +0000479
Harald Weltebed35df2011-11-02 13:06:18 +0100480 if (sendto(fd, packet, len, 0,
Daniel Willmanncd970ed2024-01-03 15:03:24 +0100481 (const struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100482 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100483 LOGP(DLGTP, LOGL_ERROR,
484 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd,
Harald Weltebed35df2011-11-02 13:06:18 +0100485 (unsigned long)&packet, len, strerror(errno));
486 return -1;
487 }
488
489 /* Use new queue structure */
490 if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100491 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_QUEUEFULL);
Pau Espin Pedrolbdf06972022-03-07 12:49:34 +0100492 LOGP(DLGTP, LOGL_ERROR, "Retransmit resp queue is full (seq=%" PRIu16 ")\n",
493 seq);
Harald Weltebed35df2011-11-02 13:06:18 +0100494 } else {
Pau Espin Pedrol3a55b892022-11-04 11:21:23 +0100495 unsigned int t3_hold_resp;
Pau Espin Pedrolf4718002022-03-07 12:55:51 +0100496 LOGP(DLGTP, LOGL_DEBUG, "Registering seq=%" PRIu16
497 " in restransmit resp queue\n", seq);
Pau Espin Pedrol3a55b892022-11-04 11:21:23 +0100498 t3_hold_resp = osmo_tdef_get(gsn->tdef, GTP_GSN_TIMER_T3_HOLD_RESPONSE, OSMO_TDEF_S, -1);
Harald Weltebed35df2011-11-02 13:06:18 +0100499 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
500 qmsg->l = len;
Pau Espin Pedrol3a55b892022-11-04 11:21:23 +0100501 qmsg->timeout = time(NULL) + t3_hold_resp; /* When to timeout */
Harald Weltebed35df2011-11-02 13:06:18 +0100502 qmsg->retrans = 0; /* No retransmissions so far */
503 qmsg->cbp = NULL;
504 qmsg->type = 0;
505 qmsg->fd = fd;
Pau Espin Pedrol623c5b32019-08-16 13:20:09 +0200506 /* No need to add to pdp list here, because even on pdp ctx free
507 we want to leave messages in queue_resp until timeout to
508 detect duplicates */
Pau Espin Pedrolc94837c2019-08-28 19:44:20 +0200509
510 /* Rearm timer: Retrans time for qmsg just queued may be required
511 before an existing one (for instance a gtp echo req) */
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100512 gtp_queue_timer_start(gsn);
Harald Weltebed35df2011-11-02 13:06:18 +0100513 }
514 return 0;
jjako52c24142002-12-16 13:33:51 +0000515}
516
Daniel Willmann6d85d2a2024-01-26 16:24:50 +0100517static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
518 union gtp_packet *packet, int len,
519 struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
520{
521 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
522 uint16_t flow = 0, tei = 0;
523
524 if (ver == 0) { /* Version 0 */
525 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
526 (packet->gtp0.h.type == GTP_ERROR)))
527 flow = pdp->flru;
528 else if (pdp)
529 flow = pdp->flrc;
530 } else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
531 if (pdp && (fd == gsn->fd1u))
532 tei = pdp->teid_gn;
533 else if (pdp)
534 tei = pdp->teic_gn;
535 } else {
536 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
537 return -1;
538 }
539
Daniel Willmann54fcd642024-03-06 11:53:37 +0100540 return gtp_resp2(gsn, packet, len, peer, fd, seq, tid, flow, tei);
Daniel Willmann6d85d2a2024-01-26 16:24:50 +0100541}
Daniel Willmann54fcd642024-03-06 11:53:37 +0100542
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100543static int gtp_notification(struct gsn_t *gsn, uint8_t version,
jjako2c381332003-10-21 19:09:53 +0000544 union gtp_packet *packet, int len,
Pau Espin Pedrol2eed6ec2021-05-05 17:51:19 +0200545 const struct sockaddr_in *peer, int fd, uint16_t seq)
Harald Weltebed35df2011-11-02 13:06:18 +0100546{
jjako2c381332003-10-21 19:09:53 +0000547
Harald Weltefed598f2017-09-24 16:39:22 +0800548 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100549 struct sockaddr_in addr;
jjako2c381332003-10-21 19:09:53 +0000550
Harald Weltebed35df2011-11-02 13:06:18 +0100551 memcpy(&addr, peer, sizeof(addr));
jjako2c381332003-10-21 19:09:53 +0000552
Harald Weltebed35df2011-11-02 13:06:18 +0100553 /* In GTP0 notifications are treated as replies. In GTP1 they
554 are requests for which there is no reply */
jjako2c381332003-10-21 19:09:53 +0000555
Harald Weltebed35df2011-11-02 13:06:18 +0100556 if (fd == gsn->fd1c)
557 addr.sin_port = htons(GTP1C_PORT);
558 else if (fd == gsn->fd1u)
559 addr.sin_port = htons(GTP1C_PORT);
jjako2c381332003-10-21 19:09:53 +0000560
Harald Weltefed598f2017-09-24 16:39:22 +0800561 if (ver == 0) { /* Version 0 */
Harald Weltebed35df2011-11-02 13:06:18 +0100562 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
563 packet->gtp0.h.seq = hton16(seq);
Harald Weltefed598f2017-09-24 16:39:22 +0800564 } else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
Harald Weltebed35df2011-11-02 13:06:18 +0100565 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
566 packet->gtp1l.h.seq = hton16(seq);
567 } else {
Harald Welted37b80a2016-12-15 18:33:15 +0100568 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100569 return -1;
570 }
571
572 if (fcntl(fd, F_SETFL, 0)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100573 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100574 return -1;
575 }
576
577 if (sendto(fd, packet, len, 0,
578 (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100579 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100580 LOGP(DLGTP, LOGL_ERROR,
581 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd,
Harald Weltebed35df2011-11-02 13:06:18 +0100582 (unsigned long)&packet, len, strerror(errno));
583 return -1;
584 }
585 return 0;
jjako2c381332003-10-21 19:09:53 +0000586}
587
Pau Espin Pedrolde72d262019-05-29 18:17:05 +0200588static int gtp_duplicate(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +0100589 struct sockaddr_in *peer, uint16_t seq)
590{
591 struct qmsg_t *qmsg;
Pau Espin Pedrol1bf3b3d2022-03-07 12:19:24 +0100592 char buf[INET_ADDRSTRLEN];
jjako52c24142002-12-16 13:33:51 +0000593
Harald Weltebed35df2011-11-02 13:06:18 +0100594 if (queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) {
595 return EOF; /* Notfound */
596 }
jjakoa7cd2492003-04-11 09:40:12 +0000597
Pau Espin Pedrol1bf3b3d2022-03-07 12:19:24 +0100598
599 buf[0] = '\0';
600 inet_ntop(AF_INET, &peer->sin_addr, buf, sizeof(buf));
601 LOGP(DLGTP, LOGL_INFO,
602 "Rx duplicate seq=%" PRIu16 " from %s, retrans resp\n", seq, buf);
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100603 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_DUPLICATE);
Pau Espin Pedrol1bf3b3d2022-03-07 12:19:24 +0100604
Harald Weltebed35df2011-11-02 13:06:18 +0100605 if (fcntl(qmsg->fd, F_SETFL, 0)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100606 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100607 return -1;
608 }
609
610 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
611 (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100612 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100613 LOGP(DLGTP, LOGL_ERROR,
614 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n",
Harald Weltebed35df2011-11-02 13:06:18 +0100615 qmsg->fd, (unsigned long)&qmsg->p, qmsg->l,
616 strerror(errno));
617 }
618 return 0;
jjako52c24142002-12-16 13:33:51 +0000619}
620
jjako52c24142002-12-16 13:33:51 +0000621/* ***********************************************************
622 * Path management messages
623 * Messages: echo and version not supported.
624 * A path is connection between two UDP/IP endpoints
625 *
626 * A path is either using GTP0 or GTP1. A path can be
627 * established by any kind of GTP message??
628
629 * Which source port to use?
630 * GTP-C request destination port is 2123/3386
631 * GTP-U request destination port is 2152/3386
632 * T-PDU destination port is 2152/3386.
633 * For the above messages the source port is locally allocated.
634 * For response messages src=rx-dst and dst=rx-src.
635 * For simplicity we should probably use 2123+2152/3386 as
636 * src port even for the cases where src can be locally
637 * allocated. This also means that we have to listen only to
638 * the same ports.
639 * For response messages we need to be able to respond to
640 * the relevant src port even if it is locally allocated by
641 * the peer.
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100642 *
jjako52c24142002-12-16 13:33:51 +0000643 * The need for path management!
644 * We might need to keep a list of active paths. This might
645 * be in the form of remote IP address + UDP port numbers.
646 * (We will consider a path astablished if we have a context
647 * with the node in question)
648 *************************************************************/
649
650/* Send off an echo request */
jjako08d331d2003-10-13 20:33:30 +0000651int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
652 struct in_addr *inetaddr)
jjako52c24142002-12-16 13:33:51 +0000653{
Harald Weltebed35df2011-11-02 13:06:18 +0100654 union gtp_packet packet;
655 unsigned int length = get_default_gtp(version, GTP_ECHO_REQ, &packet);
656 return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp);
jjako52c24142002-12-16 13:33:51 +0000657}
658
jjako08d331d2003-10-13 20:33:30 +0000659/* Send off an echo reply */
660int gtp_echo_resp(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +0100661 struct sockaddr_in *peer, int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000662{
Harald Weltebed35df2011-11-02 13:06:18 +0100663 union gtp_packet packet;
664 unsigned int length = get_default_gtp(version, GTP_ECHO_RSP, &packet);
665 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
666 gsn->restart_counter);
667 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
668 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +0000669}
670
jjako52c24142002-12-16 13:33:51 +0000671/* Handle a received echo request */
Harald Weltebed35df2011-11-02 13:06:18 +0100672int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
673 int fd, void *pack, unsigned len)
674{
jjako52c24142002-12-16 13:33:51 +0000675
Pau Espin Pedrolde72d262019-05-29 18:17:05 +0200676 /* Check if it was a duplicate request */
677 if (!gtp_duplicate(gsn, 0, peer, get_seq(pack)))
Harald Weltebed35df2011-11-02 13:06:18 +0100678 return 0;
jjako52c24142002-12-16 13:33:51 +0000679
Harald Weltebed35df2011-11-02 13:06:18 +0100680 /* Send off reply to request */
681 return gtp_echo_resp(gsn, version, peer, fd, pack, len);
jjako52c24142002-12-16 13:33:51 +0000682}
683
684/* Handle a received echo reply */
jjako08d331d2003-10-13 20:33:30 +0000685int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +0100686 void *pack, unsigned len)
687{
688 union gtpie_member *ie[GTPIE_SIZE];
689 unsigned char recovery;
690 void *cbp = NULL;
691 uint8_t type = 0;
692 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +0000693
Harald Weltebed35df2011-11-02 13:06:18 +0100694 /* Remove packet from queue */
695 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
696 return EOF;
jjako52c24142002-12-16 13:33:51 +0000697
Harald Weltebed35df2011-11-02 13:06:18 +0100698 /* Extract information elements into a pointer array */
699 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100700 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100701 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
702 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100703 if (gsn->cb_conf)
704 gsn->cb_conf(type, EOF, NULL, cbp);
705 return EOF;
706 }
jjako52c24142002-12-16 13:33:51 +0000707
Harald Weltebed35df2011-11-02 13:06:18 +0100708 if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100709 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100710 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
711 "Missing mandatory field\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100712 if (gsn->cb_conf)
713 gsn->cb_conf(type, EOF, NULL, cbp);
714 return EOF;
715 }
jjako52c24142002-12-16 13:33:51 +0000716
Harald Weltebed35df2011-11-02 13:06:18 +0100717 /* Echo reply packages does not have a cause information element */
718 /* Instead we return the recovery number in the callback function */
719 if (gsn->cb_conf)
720 gsn->cb_conf(type, recovery, NULL, cbp);
Harald Welte629e9862010-12-24 20:58:09 +0100721
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +0200722 emit_cb_recovery(gsn, peer, NULL, recovery);
Harald Weltebed35df2011-11-02 13:06:18 +0100723
724 return 0;
jjako52c24142002-12-16 13:33:51 +0000725}
726
727/* Send off a Version Not Supported message */
728/* This message is somewhat special in that it actually is a
729 * response to some other message with unsupported GTP version
730 * For this reason it has parameters like a response, and does
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100731 * its own message transmission. No signalling queue is used
jjako52c24142002-12-16 13:33:51 +0000732 * The reply is sent to the peer IP and peer UDP. This means that
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100733 * the peer will be receiving a GTP0 message on a GTP1 port!
jjako52c24142002-12-16 13:33:51 +0000734 * In practice however this will never happen as a GTP0 GSN will
735 * only listen to the GTP0 port, and therefore will never receive
736 * anything else than GTP0 */
737
jjako08d331d2003-10-13 20:33:30 +0000738int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
739 int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000740{
Harald Weltebed35df2011-11-02 13:06:18 +0100741 union gtp_packet packet;
jjako52c24142002-12-16 13:33:51 +0000742
Harald Weltebed35df2011-11-02 13:06:18 +0100743 /* GTP 1 is the highest supported protocol */
744 unsigned int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet);
745 return gtp_notification(gsn, version, &packet, length, peer, fd, 0);
jjako52c24142002-12-16 13:33:51 +0000746}
747
748/* Handle a Version Not Supported message */
Harald Weltebed35df2011-11-02 13:06:18 +0100749int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
750 void *pack, unsigned len)
751{
jjako52c24142002-12-16 13:33:51 +0000752
Harald Weltebed35df2011-11-02 13:06:18 +0100753 if (gsn->cb_unsup_ind)
754 gsn->cb_unsup_ind(peer);
755
756 return 0;
jjako52c24142002-12-16 13:33:51 +0000757}
758
jjako2c381332003-10-21 19:09:53 +0000759/* Send off an Supported Extension Headers Notification */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100760static int gtp_extheader_req(struct gsn_t *gsn, uint8_t version, struct sockaddr_in *peer,
jjako2c381332003-10-21 19:09:53 +0000761 int fd, void *pack, unsigned len)
762{
Harald Weltebed35df2011-11-02 13:06:18 +0100763 union gtp_packet packet;
764 unsigned int length =
765 get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet);
jjako2c381332003-10-21 19:09:53 +0000766
Harald Weltebed35df2011-11-02 13:06:18 +0100767 uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU;
jjako2c381332003-10-21 19:09:53 +0000768
Harald Weltebed35df2011-11-02 13:06:18 +0100769 if (version < 1)
770 return 0;
jjako2c381332003-10-21 19:09:53 +0000771
Harald Weltebed35df2011-11-02 13:06:18 +0100772 /* We report back that we support only PDCP PDU headers */
773 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T,
774 sizeof(pdcp_pdu), &pdcp_pdu);
jjako2c381332003-10-21 19:09:53 +0000775
Harald Weltebed35df2011-11-02 13:06:18 +0100776 return gtp_notification(gsn, version, &packet, length,
777 peer, fd, get_seq(pack));
jjako2c381332003-10-21 19:09:53 +0000778}
779
780/* Handle a Supported Extension Headers Notification */
Pau Espin Pedrol7b38af52018-01-25 18:35:33 +0100781static int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +0100782 void *pack, unsigned len)
783{
jjako2c381332003-10-21 19:09:53 +0000784
Harald Weltebed35df2011-11-02 13:06:18 +0100785 if (gsn->cb_extheader_ind)
786 gsn->cb_extheader_ind(peer);
787
788 return 0;
jjako2c381332003-10-21 19:09:53 +0000789}
790
Pau Espin Pedrolf32c6a92021-05-03 17:58:55 +0200791/* Handle a RAN Information Relay message */
792static int gtp_ran_info_relay_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
793 void *pack, unsigned len)
794{
795 union gtpie_member *ie[GTPIE_SIZE];
796
797 if (version != 1) {
798 LOGP(DLGTP, LOGL_NOTICE,
799 "RAN Information Relay expected only on GTPCv1: %u\n", version);
800 return -EINVAL;
801 }
802
803 int hlen = get_hlen(pack);
804
805 /* Decode information elements */
806 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100807 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Pau Espin Pedrolf32c6a92021-05-03 17:58:55 +0200808 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
809 "Invalid message format (AN Information Relay)\n");
810 return -EINVAL;
811 }
812
813 if (gsn->cb_ran_info_relay_ind)
814 gsn->cb_ran_info_relay_ind(peer, ie);
815
816 return 0;
817}
818
819/* Send off a RAN Information Relay message */
820int gtp_ran_info_relay_req(struct gsn_t *gsn, const struct sockaddr_in *peer,
821 const uint8_t *ran_container, size_t ran_container_len,
822 const uint8_t *rim_route_addr, size_t rim_route_addr_len,
823 uint8_t rim_route_addr_discr)
824{
825 union gtp_packet packet;
826
827 /* GTP 1 is the highest supported protocol */
828 unsigned int length = get_default_gtp(1, GTP_RAN_INFO_RELAY, &packet);
829
830 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAN_T_CONTAIN, ran_container_len,
831 ran_container);
832 if (rim_route_addr) {
833 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RIM_ROUT_ADDR,
834 rim_route_addr_len, rim_route_addr);
835 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RIM_RA_DISCR, 1,
836 &rim_route_addr_discr);
837 }
838
839 return gtp_notification(gsn, 1, &packet, length, peer, gsn->fd1c, 0);
840}
841
Daniel Willmann65363762024-01-26 16:36:20 +0100842#define GSM_MI_TYPE_TLLI 0x05
843
Daniel Willmann54fcd642024-03-06 11:53:37 +0100844/* Send an SGSN Context Request for an MI */
Daniel Willmann65363762024-01-26 16:36:20 +0100845int gtp_sgsn_context_req(struct gsn_t *gsn, const struct in_addr *peer,
Daniel Willmann54fcd642024-03-06 11:53:37 +0100846 const struct osmo_mobile_identity *mi, uint16_t tlli, uint32_t teic,
Daniel Willmann65363762024-01-26 16:36:20 +0100847 const struct ul16_t *sgsn_addr, const struct ul255_t *rai, void *cbp)
848{
849 union gtp_packet packet;
850
851 /* GTP 1 is the highest supported protocol */
852 unsigned int length = get_default_gtp(1, GTP_SGSN_CONTEXT_REQ, &packet);
853
854 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI, rai->l, rai->v);
855 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, teic);
856 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, sgsn_addr->l, sgsn_addr->v);
857
858 switch (mi->type) {
859 case GSM_MI_TYPE_IMSI:
Daniel Willmann54fcd642024-03-06 11:53:37 +0100860 {
861 uint64_t imsi = gtp_imsi_str2gtp(mi->imsi);
862 imsi = ntoh64(imsi);
863 gtpie_tv8(&packet, &length, GTP_MAX, GTPIE_IMSI, imsi);
Daniel Willmann65363762024-01-26 16:36:20 +0100864 break;
Daniel Willmann54fcd642024-03-06 11:53:37 +0100865 }
Daniel Willmann65363762024-01-26 16:36:20 +0100866 case GSM_MI_TYPE_TLLI:
867 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TLLI, mi->tmsi);
868 break;
869 case GSM_MI_TYPE_TMSI:
870 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_P_TMSI, mi->tmsi);
871 break;
872 default:
Daniel Willmann54fcd642024-03-06 11:53:37 +0100873 return -1;
Daniel Willmann65363762024-01-26 16:36:20 +0100874 /* TODO: Error */
875 break;
876 }
877
878 return gtp_req(gsn, 1, NULL, &packet, length, peer, cbp);
879}
880
881/* Handle an SGSN Context Request */
882static int gtp_sgsn_context_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
883 void *pack, unsigned len)
884{
885 /* Check if we have a context with TLLI/P-TMSI/IMSI in the RAI */
886 struct osmo_mobile_identity mi = {0};
887 uint64_t imsi;
888
889 union gtpie_member *ie[GTPIE_SIZE];
890 uint32_t teic;
891 uint8_t seq = get_seq(pack);
892 struct ul16_t sgsn_addr;
893 struct ul255_t rai = { .l = 6 };
894 struct osmo_routing_area_id rai_parsed;
895
896 if (version != 1) {
897 LOGP(DLGTP, LOGL_NOTICE,
898 "SGSN Context Request expected only on GTPCv1: %u\n", version);
899 return -EINVAL;
900 }
901
902 int hlen = get_hlen(pack);
903
904 /* Decode information elements */
905 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
906 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
907 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
908 "Invalid message format\n");
909 return -EINVAL;
910 }
911
912 /* RAI */
913 if (gtpie_gettv0(ie, GTPIE_RAI, 0, &rai.v, 6)) {
914 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
915 "Missing RAI\n");
916 goto missing_ie;
917 }
918 if (osmo_routing_area_id_decode(&rai_parsed, rai.v, 6) < 0) {
919 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
920 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
921 "Invalid RAI\n");
922 }
923
924 /* TEI-C */
925 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &teic)) {
926 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
927 "Missing TEI-C\n");
928 goto missing_ie;
929 }
930
931 /* SGSN address for signalling (mandatory) */
932 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &sgsn_addr.l,
933 &sgsn_addr.v, sizeof(sgsn_addr.v))) {
934 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
935 "Missing GSN Addr\n");
936 goto missing_ie;
937 }
938
939 /* Get PTMSI, TLLI or IMSI - only one IE allowed */
940 if (!gtpie_gettv4(ie, GTPIE_TLLI, 0, &mi.tmsi)) {
941 mi.type = GSM_MI_TYPE_TLLI;
942 goto done;
943 }
944
945 if (!gtpie_gettv4(ie, GTPIE_P_TMSI, 0, &mi.tmsi)) {
946 mi.type = GSM_MI_TYPE_TMSI;
947 goto done;
948 }
949
950 if (!gtpie_gettv8(ie, GTPIE_IMSI, 0, &imsi)) {
Daniel Willmann65363762024-01-26 16:36:20 +0100951 mi.type = GSM_MI_TYPE_IMSI;
Daniel Willmann54fcd642024-03-06 11:53:37 +0100952 /* NOTE: gtpie_gettv8 already converts to host byte order, but imsi_gtp2str seems to prefer big endian */
953 imsi = ntoh64(imsi);
Daniel Willmann65363762024-01-26 16:36:20 +0100954 const char *imsi_str = imsi_gtp2str(&imsi);
955 memcpy(mi.imsi, imsi_str, sizeof(mi.imsi));
956 } else {
957 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
958 "Missing Identity information\n");
959 goto missing_ie;
960 }
961
962done:
963 if (gsn->cb_sgsn_context_request_ind)
Daniel Willmann54fcd642024-03-06 11:53:37 +0100964 gsn->cb_sgsn_context_request_ind(gsn, peer, seq, &rai_parsed, teic, &mi, ie);
Daniel Willmann65363762024-01-26 16:36:20 +0100965
966 return 0;
967
968missing_ie:
969 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
970 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
971 "Missing mandatory IE\n");
972 /* TODO: Send response with cause */
973 return -EINVAL;
974}
975
976static bool is_ext_ua(const struct pdp_t *pdp)
977{
978 return pdp->eua.l > 0 && pdp->eua.v[0] == PDP_EUA_TYPE_v4v6;
979}
980
981static int gtp_pdp_ctx(uint8_t *buf, unsigned int size, const struct pdp_t *pdp, uint16_t sapi)
982{
983 uint32_t tmp32;
984 uint16_t tmp16;
985 uint8_t *ptr = buf;
986#define CHECK_SPACE_ERR(bytes) \
987 if ((ptr - buf) + (bytes) > size) { \
988 printf("Failed size check: %lu + %lu > %lu\n", (ptr- buf), bytes, size); \
989 return -1; \
990 }
991#define MEMCPY_CHK(dst, src, len) \
992 CHECK_SPACE_ERR((len)) \
993 memcpy((dst), (uint8_t *)(src), (len)); \
994 (dst) += (len);
995
996 // Flags - FIXME: No ASI
997 *ptr++ = (is_ext_ua(pdp) << 7) | ((!!pdp->vplmn_allow) << 6) | ((!!pdp->reorder) << 4) | (pdp->nsapi & 0x0f);
998 // SAPI
999 *ptr++ = sapi & 0x0f;
1000
1001 // QoS Sub
1002 if (pdp->qos_sub.l < 4) {
1003 /* Work around qos_sub never being set */
1004 *ptr++ = 4;
1005 *ptr++ = 0;
1006 *ptr++ = 0x23;
1007 *ptr++ = 0x02;
1008 *ptr++ = 0x00;
1009 } else {
1010 *ptr++ = pdp->qos_sub.l;
1011 MEMCPY_CHK(ptr, pdp->qos_sub.v, pdp->qos_sub.l);
1012 }
1013 // QoS Req
1014 *ptr++ = pdp->qos_req.l;
1015 MEMCPY_CHK(ptr, pdp->qos_req.v, pdp->qos_req.l);
1016 // QoS Neg
1017 *ptr++ = pdp->qos_neg.l;
1018 MEMCPY_CHK(ptr, pdp->qos_neg.v, pdp->qos_neg.l);
1019
1020 // SND
1021 tmp16 = osmo_htons(pdp->pdcpsndd);
1022 MEMCPY_CHK(ptr, &tmp16, sizeof(tmp16));
1023 // SNU
1024 tmp16 = osmo_htons(pdp->pdcpsndu);
1025 MEMCPY_CHK(ptr, &tmp16, sizeof(tmp16));
1026 // Send N-PDU
1027 *ptr++ = pdp->gtpsntx;
1028 // Recv N-PDU
1029 *ptr++ = pdp->gtpsnrx;
1030 // Uplink TEIC
1031 tmp32 = osmo_htonl(pdp->teic_gn);
1032 MEMCPY_CHK(ptr, &tmp32, sizeof(tmp32));
1033 // Uplink TEIDI
1034 tmp32 = osmo_htonl(pdp->teid_gn);
1035 MEMCPY_CHK(ptr, &tmp32, sizeof(tmp32));
1036 // PDP Ctx Id
1037 *ptr++ = pdp->pdp_id;
1038 // PDP Type Org
1039 *ptr++ = PDP_EUA_ORG_IETF;
Daniel Willmann54fcd642024-03-06 11:53:37 +01001040
Daniel Willmann65363762024-01-26 16:36:20 +01001041 // PDP Type No.
1042 // PDP Address
Daniel Willmann65363762024-01-26 16:36:20 +01001043 switch (pdp->eua.v[1]) {
1044 case PDP_EUA_TYPE_v4:
1045 case PDP_EUA_TYPE_v4v6:
1046 /* v4v6 expects an IPv4 addr first followed by an IPv6 addr*/
1047 *ptr++ = PDP_EUA_TYPE_v4;
1048 if (pdp->eua.l < 6)
1049 return -1;
1050 *ptr++ = 4;
1051 MEMCPY_CHK(ptr, &pdp->eua.v[2], 4);
1052 break;
1053 case PDP_EUA_TYPE_v6:
1054 *ptr++ = PDP_EUA_TYPE_v6;
1055 if (pdp->eua.l < 18)
1056 return -1;
1057 *ptr++ = 16;
1058 MEMCPY_CHK(ptr, &pdp->eua.v[2], 16);
1059 break;
1060 default:
1061 return -EINVAL;
1062 //Panic
1063 }
1064 // GGSN Address Ctrl
1065 *ptr++ = pdp->gsnrc.l;
1066 MEMCPY_CHK(ptr, pdp->gsnrc.v, pdp->gsnrc.l);
1067 // GGSN Address User
1068 *ptr++ = pdp->gsnru.l;
1069 MEMCPY_CHK(ptr, pdp->gsnru.v, pdp->gsnru.l);
1070 // APN
1071 *ptr++ = pdp->apn_use.l;
1072 MEMCPY_CHK(ptr, pdp->apn_use.v, pdp->apn_use.l);
1073 // TransId
1074 *ptr++ = (pdp->ti >> 8) & 0x0f;
1075 *ptr++ = pdp->ti & 0xff;
1076
1077 if (is_ext_ua(pdp)) {
1078 *ptr++ = PDP_EUA_TYPE_v6;
1079 if (pdp->eua.l < 22)
1080 return -1;
1081 *ptr++ = 16;
1082 MEMCPY_CHK(ptr, &pdp->eua.v[6], 16);
1083 }
1084 return ptr - buf;
1085#undef CHECK_SPACE_ERR
1086#undef MEMCPY_CHK
1087}
1088
1089int gtp_sgsn_context_conf(struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq,
Daniel Willmann54fcd642024-03-06 11:53:37 +01001090 uint32_t teic, uint8_t cause, uint64_t imsi, const struct in_addr *sgsn_addr, struct pdp_t *pdpctx, uint16_t sapi, uint8_t *mmctx, int mm_len, void *cbp)
Daniel Willmann65363762024-01-26 16:36:20 +01001091{
1092 union gtp_packet packet;
1093 struct ul255_t pdp;
1094
1095 /* GTP 1 is the highest supported protocol */
1096 unsigned int length = get_default_gtp(1, GTP_SGSN_CONTEXT_RSP, &packet);
1097
1098 // Cause - TV1
1099 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
Daniel Willmann54fcd642024-03-06 11:53:37 +01001100
1101 if (cause != GTPCAUSE_ACC_REQ)
1102 return gtp_resp2(gsn, &packet, length, peer, gsn->fd1c, seq, 0, 0, teic);
1103
Daniel Willmann65363762024-01-26 16:36:20 +01001104 // IMSI - TV8
Daniel Willmann54fcd642024-03-06 11:53:37 +01001105 gtpie_tv8(&packet, &length, GTP_MAX, GTPIE_IMSI, imsi);
Daniel Willmann65363762024-01-26 16:36:20 +01001106
1107 // TEIC - TV4
1108 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, pdpctx->teic_own);
1109
1110 // MM Ctx - TLV
Daniel Willmann54fcd642024-03-06 11:53:37 +01001111 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MM_CONTEXT, mm_len, mmctx);
Daniel Willmann65363762024-01-26 16:36:20 +01001112
1113 // PDP Ctx - TLV
1114 if (pdpctx) {
1115 int rc = gtp_pdp_ctx(pdp.v, 255, pdpctx, sapi);
1116 if (rc > 0)
1117 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PDP_CONTEXT, rc, pdp.v);
1118 }
1119
1120 // SGSN Addr Ctrl - TLV
1121 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, 4, &sgsn_addr->s_addr);
1122
1123 // Alt GGSN Addr Ctrl (per PDP Ctx)
1124 // Alt GGSN Addr User (per PDP Ctx)
1125 /* The encoding for this is a bit insane */
1126
1127 return gtp_resp2(gsn, &packet, length, peer, gsn->fd1c, seq, 0, 0, teic);
1128}
1129
1130/* Handle an SGSN Context Response */
1131static int gtp_sgsn_context_conf_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
1132 void *pack, unsigned len)
1133{
1134 /** If cause is "Request accepted": Send ACK,
1135 else: Log and handle error */
1136
1137 /* Check if we have a context with TLLI/P-TMSI/IMSI in the RAI */
1138
1139 void *cbp = NULL;
1140 uint8_t type = 0;
1141 uint8_t cause;
1142 union gtpie_member *ie[GTPIE_SIZE];
1143 struct pdp_t *pdp = NULL;
Daniel Willmann65363762024-01-26 16:36:20 +01001144 uint32_t teic;
1145 struct ul16_t sgsn_addr;
1146
1147 if (version != 1) {
1148 LOGP(DLGTP, LOGL_NOTICE,
1149 "SGSN Context Request expected only on GTPCv1: %u\n", version);
1150 return -EINVAL;
1151 }
1152
1153 int hlen = get_hlen(pack);
1154
1155 /* Remove packet from queue */
1156 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
1157 return EOF;
1158
1159 /* Extract information elements into a pointer array */
1160 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
1161 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
1162 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1163 "Invalid message format\n");
1164 if (gsn->cb_conf)
1165 gsn->cb_conf(type, EOF, NULL, cbp);
1166 return EOF;
1167 }
1168
1169 /* Extract cause value (mandatory) */
1170 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
1171 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
1172 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1173 "Missing mandatory information field\n");
1174 if (gsn->cb_conf)
1175 gsn->cb_conf(type, EOF, NULL, cbp);
1176 return EOF;
1177 }
1178
1179 /* Check all conditional information elements */
1180 if (!gtp_cause_successful(cause)) {
1181 GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
1182 "SGSN Context response with cause (%u)\n", cause);
1183 if (gsn->cb_conf)
1184 gsn->cb_conf(type, cause, NULL, cbp);
1185 }
1186
1187 /* Gather UE context and PDP data, create pdp context */
1188 //gtp_pdp_newpdp(gsn, &pdp, imsi, nsapi, NULL)
1189 if (gsn->cb_conf)
1190 gsn->cb_conf(type, cause, pdp, cbp);
1191
1192 return 0;
1193}
1194
1195/* Handle an SGSN Context Acknowledge */
1196static int gtp_sgsn_context_ack(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
1197 void *pack, unsigned len)
1198{
1199 /* If cause is != Request accepted, log error */
1200 return -ENOTSUP;
1201}
1202
1203/* Handle an SGSN Context request */
1204int gtp_context_request(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
1205 void *pack, unsigned len)
1206{
1207 union gtpie_member *ie[GTPIE_SIZE];
1208
1209 if (version != 1) {
1210 LOGP(DLGTP, LOGL_NOTICE,
1211 "SGSN Context Request expected only on GTPCv1: %u\n", version);
1212 return -EINVAL;
1213 }
1214
1215 int hlen = get_hlen(pack);
1216
1217 /* Decode information elements */
1218 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
1219 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
1220 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1221 "Invalid message format (AN Information Relay)\n");
1222 return -EINVAL;
1223 }
1224
1225 if (gsn->cb_ran_info_relay_ind)
1226 gsn->cb_ran_info_relay_ind(peer, ie);
1227
1228 return 0;
1229}
1230
jjako52c24142002-12-16 13:33:51 +00001231/* ***********************************************************
1232 * Session management messages
1233 * Messages: create, update and delete PDP context
1234 *
1235 * Information storage
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01001236 * Information storage for each PDP context is defined in
jjako52c24142002-12-16 13:33:51 +00001237 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
1238 * PDP-address (IP address), sequence numbers, charging ID.
1239 * For the SGSN it also includes radio related mobility
1240 * information.
1241 *************************************************************/
1242
Harald Welte7b3347b2010-05-15 12:18:46 +02001243/* API: Send Create PDP Context Request (7.3.1) */
Pau Espin Pedrol7b38af52018-01-25 18:35:33 +01001244int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001245 void *cbp)
1246{
1247 union gtp_packet packet;
1248 unsigned int length =
1249 get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet);
1250 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001251
Harald Weltebed35df2011-11-02 13:06:18 +01001252 /* TODO: Secondary PDP Context Activation Procedure */
1253 /* In secondary activation procedure the PDP context is identified
1254 by tei in the header. The following fields are omitted: Selection
1255 mode, IMSI, MSISDN, End User Address, Access Point Name and
1256 Protocol Configuration Options */
jjako2c381332003-10-21 19:09:53 +00001257
Harald Weltebed35df2011-11-02 13:06:18 +01001258 if (pdp->secondary) {
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02001259 if (gtp_pdp_getgtp1(gsn, &linked_pdp, pdp->teic_own)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001260 LOGP(DLGTP, LOGL_ERROR,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01001261 "Unknown linked PDP context: %u\n", pdp->teic_own);
Harald Weltebed35df2011-11-02 13:06:18 +01001262 return EOF;
1263 }
1264 }
jjako2c381332003-10-21 19:09:53 +00001265
Harald Weltebed35df2011-11-02 13:06:18 +01001266 if (pdp->version == 0) {
1267 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1268 sizeof(pdp->qos_req0), pdp->qos_req0);
1269 }
jjako52c24142002-12-16 13:33:51 +00001270
Harald Weltebed35df2011-11-02 13:06:18 +01001271 /* Section 7.7.2 */
1272 if (pdp->version == 1) {
1273 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1274 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1275 sizeof(pdp->imsi), (uint8_t *) & pdp->imsi);
1276 }
jjako52c24142002-12-16 13:33:51 +00001277
Harald Weltebed35df2011-11-02 13:06:18 +01001278 /* Section 7.7.3 Routing Area Information */
1279 if (pdp->rai_given == 1)
1280 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI,
1281 pdp->rai.l, (uint8_t *) & pdp->rai.v);
Harald Welte41af5692011-10-07 18:42:34 +02001282
Harald Weltebed35df2011-11-02 13:06:18 +01001283 /* Section 7.7.11 */
1284 if (pdp->norecovery_given == 0)
1285 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1286 gsn->restart_counter);
Harald Welte41af5692011-10-07 18:42:34 +02001287
Harald Weltebed35df2011-11-02 13:06:18 +01001288 /* Section 7.7.12 */
1289 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1290 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE,
1291 pdp->selmode);
jjako2c381332003-10-21 19:09:53 +00001292
Harald Weltebed35df2011-11-02 13:06:18 +01001293 if (pdp->version == 0) {
1294 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu);
1295 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc);
1296 }
jjako08d331d2003-10-13 20:33:30 +00001297
Harald Weltebed35df2011-11-02 13:06:18 +01001298 /* Section 7.7.13 */
1299 if (pdp->version == 1) {
1300 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1301 pdp->teid_own);
jjako08d331d2003-10-13 20:33:30 +00001302
Harald Weltebed35df2011-11-02 13:06:18 +01001303 /* Section 7.7.14 */
1304 if (!pdp->teic_confirmed)
1305 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1306 pdp->teic_own);
jjako2c381332003-10-21 19:09:53 +00001307
Harald Weltebed35df2011-11-02 13:06:18 +01001308 /* Section 7.7.17 */
1309 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00001310
Harald Weltebed35df2011-11-02 13:06:18 +01001311 /* Section 7.7.17 */
1312 if (pdp->secondary) /* Secondary PDP Context Activation Procedure */
1313 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1314 linked_pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00001315
Harald Weltebed35df2011-11-02 13:06:18 +01001316 /* Section 7.7.23 */
1317 if (pdp->cch_pdp) /* Only include charging if flags are set */
1318 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C,
1319 pdp->cch_pdp);
1320 }
jjako9b4971d2004-05-27 20:30:19 +00001321
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01001322 /* TODO
Harald Weltebed35df2011-11-02 13:06:18 +01001323 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1324 pdp->traceref);
1325 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1326 pdp->tracetype); */
jjako08d331d2003-10-13 20:33:30 +00001327
Harald Weltebed35df2011-11-02 13:06:18 +01001328 /* Section 7.7.27 */
1329 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1330 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1331 pdp->eua.l, pdp->eua.v);
jjako08d331d2003-10-13 20:33:30 +00001332
Harald Weltebed35df2011-11-02 13:06:18 +01001333 /* Section 7.7.30 */
1334 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1335 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN,
1336 pdp->apn_use.l, pdp->apn_use.v);
jjako08d331d2003-10-13 20:33:30 +00001337
Harald Weltebed35df2011-11-02 13:06:18 +01001338 /* Section 7.7.31 */
1339 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1340 if (pdp->pco_req.l)
1341 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1342 pdp->pco_req.l, pdp->pco_req.v);
jjako2c381332003-10-21 19:09:53 +00001343
Harald Weltebed35df2011-11-02 13:06:18 +01001344 /* Section 7.7.32 */
1345 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1346 pdp->gsnlc.l, pdp->gsnlc.v);
1347 /* Section 7.7.32 */
1348 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1349 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001350
Harald Weltebed35df2011-11-02 13:06:18 +01001351 /* Section 7.7.33 */
1352 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1353 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN,
1354 pdp->msisdn.l, pdp->msisdn.v);
jjako08d331d2003-10-13 20:33:30 +00001355
Harald Weltebed35df2011-11-02 13:06:18 +01001356 /* Section 7.7.34 */
1357 if (pdp->version == 1)
1358 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1359 pdp->qos_req.l, pdp->qos_req.v);
jjako08d331d2003-10-13 20:33:30 +00001360
Harald Weltebed35df2011-11-02 13:06:18 +01001361 /* Section 7.7.36 */
1362 if ((pdp->version == 1) && pdp->tft.l)
1363 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1364 pdp->tft.l, pdp->tft.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001365
Harald Weltebed35df2011-11-02 13:06:18 +01001366 /* Section 7.7.41 */
1367 if ((pdp->version == 1) && pdp->triggerid.l)
1368 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1369 pdp->triggerid.l, pdp->triggerid.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001370
Harald Weltebed35df2011-11-02 13:06:18 +01001371 /* Section 7.7.42 */
1372 if ((pdp->version == 1) && pdp->omcid.l)
1373 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1374 pdp->omcid.l, pdp->omcid.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001375
Harald Weltebed35df2011-11-02 13:06:18 +01001376 /* new R7 fields */
1377 if (pdp->rattype_given == 1)
1378 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAT_TYPE,
1379 pdp->rattype.l, pdp->rattype.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001380
Harald Weltebed35df2011-11-02 13:06:18 +01001381 if (pdp->userloc_given == 1)
1382 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_USER_LOC,
1383 pdp->userloc.l, pdp->userloc.v);
jjako52c24142002-12-16 13:33:51 +00001384
Harald Weltebed35df2011-11-02 13:06:18 +01001385 if (pdp->mstz_given == 1)
1386 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MS_TZ,
1387 pdp->mstz.l, pdp->mstz.v);
1388
1389 if (pdp->imeisv_given == 1)
1390 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_IMEI_SV,
1391 pdp->imeisv.l, pdp->imeisv.v);
1392
1393 /* TODO hisaddr0 */
1394 gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
1395
1396 return 0;
jjako52c24142002-12-16 13:33:51 +00001397}
1398
jjako08d331d2003-10-13 20:33:30 +00001399/* API: Application response to context indication */
Harald Weltebed35df2011-11-02 13:06:18 +01001400int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause)
1401{
jjako08d331d2003-10-13 20:33:30 +00001402
Harald Weltebed35df2011-11-02 13:06:18 +01001403 /* Now send off a reply to the peer */
1404 gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
1405
Daniel Willmann6a2e8252023-11-23 18:41:59 +01001406 if (!gtp_cause_successful(cause))
Pau Espin Pedrold9501342019-08-21 15:24:29 +02001407 gtp_freepdp(gsn, pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01001408
1409 return 0;
jjako08d331d2003-10-13 20:33:30 +00001410}
1411
jjako08d331d2003-10-13 20:33:30 +00001412/* Send Create PDP Context Response */
Harald Weltebed35df2011-11-02 13:06:18 +01001413int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
1414 uint8_t cause)
1415{
1416 union gtp_packet packet;
1417 unsigned int length =
1418 get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
jjako52c24142002-12-16 13:33:51 +00001419
Harald Weltebed35df2011-11-02 13:06:18 +01001420 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00001421
Daniel Willmann6a2e8252023-11-23 18:41:59 +01001422 if (gtp_cause_successful(cause)) {
jjako08d331d2003-10-13 20:33:30 +00001423
Harald Weltebed35df2011-11-02 13:06:18 +01001424 if (version == 0)
1425 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1426 sizeof(pdp->qos_neg0), pdp->qos_neg0);
jjako08d331d2003-10-13 20:33:30 +00001427
Harald Weltebed35df2011-11-02 13:06:18 +01001428 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER,
1429 pdp->reorder);
1430 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1431 gsn->restart_counter);
jjako08d331d2003-10-13 20:33:30 +00001432
Harald Weltebed35df2011-11-02 13:06:18 +01001433 if (version == 0) {
1434 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1435 pdp->fllu);
1436 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1437 pdp->fllc);
1438 }
jjako08d331d2003-10-13 20:33:30 +00001439
Harald Weltebed35df2011-11-02 13:06:18 +01001440 if (version == 1) {
1441 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1442 pdp->teid_own);
1443 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1444 pdp->teic_own);
1445 }
jjako08d331d2003-10-13 20:33:30 +00001446
Harald Weltebed35df2011-11-02 13:06:18 +01001447 /* TODO: We use teic_own as charging ID */
1448 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
1449 pdp->teic_own);
jjako2c381332003-10-21 19:09:53 +00001450
Harald Weltebed35df2011-11-02 13:06:18 +01001451 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1452 pdp->eua.l, pdp->eua.v);
jjako52c24142002-12-16 13:33:51 +00001453
Harald Weltebed35df2011-11-02 13:06:18 +01001454 if (pdp->pco_neg.l) { /* Optional PCO */
1455 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1456 pdp->pco_neg.l, pdp->pco_neg.v);
1457 }
jjako52c24142002-12-16 13:33:51 +00001458
Harald Weltebed35df2011-11-02 13:06:18 +01001459 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1460 pdp->gsnlc.l, pdp->gsnlc.v);
1461 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1462 pdp->gsnlu.l, pdp->gsnlu.v);
jjako08d331d2003-10-13 20:33:30 +00001463
Harald Weltebed35df2011-11-02 13:06:18 +01001464 if (version == 1)
1465 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1466 pdp->qos_neg.l, pdp->qos_neg.v);
jjako08d331d2003-10-13 20:33:30 +00001467
Harald Weltebed35df2011-11-02 13:06:18 +01001468 /* TODO: Charging gateway address */
1469 }
jjako52c24142002-12-16 13:33:51 +00001470
Harald Weltebed35df2011-11-02 13:06:18 +01001471 return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer,
1472 pdp->fd, pdp->seq, pdp->tid);
jjako52c24142002-12-16 13:33:51 +00001473}
1474
1475/* Handle Create PDP Context Request */
1476int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01001477 struct sockaddr_in *peer, int fd,
1478 void *pack, unsigned len)
1479{
1480 struct pdp_t *pdp, *pdp_old;
1481 struct pdp_t pdp_buf;
1482 union gtpie_member *ie[GTPIE_SIZE];
1483 uint8_t recovery;
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001484 bool recovery_recvd = false;
1485 int rc;
jjako52c24142002-12-16 13:33:51 +00001486
Harald Weltebed35df2011-11-02 13:06:18 +01001487 uint16_t seq = get_seq(pack);
1488 int hlen = get_hlen(pack);
1489 uint8_t linked_nsapi = 0;
1490 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001491
Pau Espin Pedrolde72d262019-05-29 18:17:05 +02001492 if (!gtp_duplicate(gsn, version, peer, seq))
Harald Weltebed35df2011-11-02 13:06:18 +01001493 return 0;
jjako08d331d2003-10-13 20:33:30 +00001494
Harald Weltebed35df2011-11-02 13:06:18 +01001495 pdp = &pdp_buf;
1496 memset(pdp, 0, sizeof(struct pdp_t));
jjako08d331d2003-10-13 20:33:30 +00001497
Vadim Yanitskiy68c5a742019-08-30 21:04:19 +02001498 if (version == 0)
1499 pdp_set_imsi_nsapi(pdp, get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00001500
Harald Weltebed35df2011-11-02 13:06:18 +01001501 pdp->seq = seq;
1502 pdp->sa_peer = *peer;
1503 pdp->fd = fd;
1504 pdp->version = version;
jjako08d331d2003-10-13 20:33:30 +00001505
Harald Weltebed35df2011-11-02 13:06:18 +01001506 /* Decode information elements */
1507 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001508 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001509 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1510 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001511 if (0 == version)
1512 return EOF;
1513 else
1514 return gtp_create_pdp_resp(gsn, version, pdp,
1515 GTPCAUSE_INVALID_MESSAGE);
1516 }
jjako52c24142002-12-16 13:33:51 +00001517
Pau Espin Pedrolfb9303c2022-03-07 11:34:28 +01001518 switch (version) {
1519 case 1:
Harald Weltebed35df2011-11-02 13:06:18 +01001520 /* Linked NSAPI (conditional) */
1521 /* If included this is the Secondary PDP Context Activation Procedure */
1522 /* In secondary activation IMSI is not included, so the context must be */
1523 /* identified by the tei */
1524 if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) {
jjako2c381332003-10-21 19:09:53 +00001525
Harald Weltebed35df2011-11-02 13:06:18 +01001526 /* Find the primary PDP context */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02001527 if (gtp_pdp_getgtp1(gsn, &linked_pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001528 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INCORRECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001529 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001530 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001531 "Incorrect optional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001532 return gtp_create_pdp_resp(gsn, version, pdp,
1533 GTPCAUSE_OPT_IE_INCORRECT);
1534 }
jjako2c381332003-10-21 19:09:53 +00001535
Harald Weltebed35df2011-11-02 13:06:18 +01001536 /* Check that the primary PDP context matches linked nsapi */
1537 if (linked_pdp->nsapi != linked_nsapi) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001538 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INCORRECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001539 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001540 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001541 "Incorrect optional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001542 return gtp_create_pdp_resp(gsn, version, pdp,
1543 GTPCAUSE_OPT_IE_INCORRECT);
1544 }
jjako52c24142002-12-16 13:33:51 +00001545
Harald Weltebed35df2011-11-02 13:06:18 +01001546 /* Copy parameters from primary context */
1547 pdp->selmode = linked_pdp->selmode;
1548 pdp->imsi = linked_pdp->imsi;
1549 pdp->msisdn = linked_pdp->msisdn;
1550 pdp->eua = linked_pdp->eua;
1551 pdp->pco_req = linked_pdp->pco_req;
1552 pdp->apn_req = linked_pdp->apn_req;
1553 pdp->teic_gn = linked_pdp->teic_gn;
1554 pdp->secondary = 1;
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001555 } else {
1556 /* Not Secondary PDP Context Activation Procedure */
1557 /* IMSI (conditional): If the MS is emergency attached
1558 and the MS is UICCless, the IMSI cannot be included
1559 in the message and therefore IMSI shall not be
1560 included in the message. */
1561 if (gtpie_gettv0
1562 (ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001563 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001564 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1565 len, "Missing IMSI not supported\n");
1566 return gtp_create_pdp_resp(gsn, version, pdp,
1567 GTPCAUSE_MAN_IE_MISSING);
1568 }
1569 }
1570
1571 /* TEID (mandatory) */
1572 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001573 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001574 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1575 len, "Missing mandatory information field\n");
1576 return gtp_create_pdp_resp(gsn, version, pdp,
1577 GTPCAUSE_MAN_IE_MISSING);
1578 }
1579 /* TEIC (conditional) */
1580 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1581 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001582 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001583 GTP_LOGPKG(LOGL_ERROR, peer,
1584 pack, len,
1585 "Missing mandatory information field\n");
1586 return gtp_create_pdp_resp(gsn, version, pdp,
1587 GTPCAUSE_MAN_IE_MISSING);
1588 }
1589 }
1590 /* NSAPI (mandatory) */
1591 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001592 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001593 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1594 len, "Missing mandatory information field\n");
1595 return gtp_create_pdp_resp(gsn, version, pdp,
1596 GTPCAUSE_MAN_IE_MISSING);
1597 }
1598 /* QoS (mandatory) */
1599 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
1600 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001601 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001602 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1603 len, "Missing mandatory information field\n");
1604 return gtp_create_pdp_resp(gsn, version, pdp,
1605 GTPCAUSE_MAN_IE_MISSING);
1606 }
1607 /* TFT (conditional) */
1608 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
1609 &pdp->tft.v, sizeof(pdp->tft.v))) {
Harald Weltebed35df2011-11-02 13:06:18 +01001610 }
Pau Espin Pedrolfb9303c2022-03-07 11:34:28 +01001611 break; /* version 1 */
1612
1613 case 0:
Harald Weltebed35df2011-11-02 13:06:18 +01001614 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1615 pdp->qos_req0, sizeof(pdp->qos_req0))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001616 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001617 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1618 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001619 return gtp_create_pdp_resp(gsn, version, pdp,
1620 GTPCAUSE_MAN_IE_MISSING);
1621 }
Harald Weltebed35df2011-11-02 13:06:18 +01001622 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001623 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001624 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1625 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001626 return gtp_create_pdp_resp(gsn, version, pdp,
1627 GTPCAUSE_MAN_IE_MISSING);
1628 }
Harald Weltebed35df2011-11-02 13:06:18 +01001629 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001630 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001631 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1632 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001633 return gtp_create_pdp_resp(gsn, version, pdp,
1634 GTPCAUSE_MAN_IE_MISSING);
1635 }
Pau Espin Pedrolfb9303c2022-03-07 11:34:28 +01001636 break;
Harald Weltebed35df2011-11-02 13:06:18 +01001637 }
jjako08d331d2003-10-13 20:33:30 +00001638
Harald Weltebed35df2011-11-02 13:06:18 +01001639 /* SGSN address for signalling (mandatory) */
1640 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1641 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001642 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001643 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1644 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001645 return gtp_create_pdp_resp(gsn, version, pdp,
1646 GTPCAUSE_MAN_IE_MISSING);
1647 }
jjako2e840a32003-01-28 16:05:18 +00001648
Harald Weltebed35df2011-11-02 13:06:18 +01001649 /* SGSN address for user traffic (mandatory) */
1650 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1651 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001652 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001653 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1654 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001655 return gtp_create_pdp_resp(gsn, version, pdp,
1656 GTPCAUSE_MAN_IE_MISSING);
1657 }
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001658 /* Recovery (optional) */
1659 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1660 /* we use recovery futher down after announcing new pdp ctx to user */
1661 recovery_recvd = true;
1662 }
jjako52c24142002-12-16 13:33:51 +00001663
Harald Weltebed35df2011-11-02 13:06:18 +01001664 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001665 /* Selection mode (conditional) */
1666 if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0,
1667 &pdp->selmode, sizeof(pdp->selmode))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001668 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001669 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1670 len, "Missing mandatory information field\n");
1671 return gtp_create_pdp_resp(gsn, version, pdp,
1672 GTPCAUSE_MAN_IE_MISSING);
1673 }
1674 /* End User Address (conditional) */
1675 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1676 &pdp->eua.v, sizeof(pdp->eua.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001677 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001678 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1679 len, "Missing mandatory information field\n");
1680 return gtp_create_pdp_resp(gsn, version, pdp,
1681 GTPCAUSE_MAN_IE_MISSING);
1682 }
1683 /* APN */
1684 if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l,
1685 &pdp->apn_req.v, sizeof(pdp->apn_req.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001686 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001687 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1688 len, "Missing mandatory information field\n");
1689 return gtp_create_pdp_resp(gsn, version, pdp,
1690 GTPCAUSE_MAN_IE_MISSING);
1691 }
1692 /* Extract protocol configuration options (optional) */
1693 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1694 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1695 }
Harald Weltebed35df2011-11-02 13:06:18 +01001696 /* MSISDN (conditional) */
1697 if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l,
1698 &pdp->msisdn.v, sizeof(pdp->msisdn.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001699 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001700 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1701 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001702 return gtp_create_pdp_resp(gsn, version, pdp,
1703 GTPCAUSE_MAN_IE_MISSING);
1704 }
1705 }
jjako52c24142002-12-16 13:33:51 +00001706
Harald Weltebed35df2011-11-02 13:06:18 +01001707 /* Initialize our own IP addresses */
Oliver Smith9bd27112024-02-22 16:02:37 +01001708 in_addr2gsna(&pdp->gsnlc, &gsn->gsnc);
1709 in_addr2gsna(&pdp->gsnlu, &gsn->gsnu);
Harald Weltebed35df2011-11-02 13:06:18 +01001710
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02001711 if (!gtp_pdp_getimsi(gsn, &pdp_old, pdp->imsi, pdp->nsapi)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001712 /* Found old pdp with same tid. Now the voodoo begins! */
1713 /* 09.60 / 29.060 allows create on existing context to "steal" */
1714 /* the context which was allready established */
1715 /* We check that the APN, selection mode and MSISDN is the same */
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01001716 DEBUGP(DLGTP, "gtp_create_pdp_ind: Old context found\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001717 if ((pdp->apn_req.l == pdp_old->apn_req.l)
1718 &&
1719 (!memcmp
1720 (pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l))
1721 && (pdp->selmode == pdp_old->selmode)
1722 && (pdp->msisdn.l == pdp_old->msisdn.l)
1723 &&
1724 (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l)))
1725 {
1726 /* OK! We are dealing with the same APN. We will copy new
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01001727 * parameters to the old pdp and send off confirmation
Harald Weltebed35df2011-11-02 13:06:18 +01001728 * We ignore the following information elements:
1729 * QoS: MS will get originally negotiated QoS.
1730 * End user address (EUA). MS will get old EUA anyway.
1731 * Protocol configuration option (PCO): Only application can verify */
Pau Espin Pedrol674a9122022-03-07 12:44:11 +01001732 DEBUGP(DLGTP, "gtp_create_pdp_ind: Reusing old context\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001733
1734 /* Copy remote flow label */
1735 pdp_old->flru = pdp->flru;
1736 pdp_old->flrc = pdp->flrc;
1737
1738 /* Copy remote tei */
1739 pdp_old->teid_gn = pdp->teid_gn;
1740 pdp_old->teic_gn = pdp->teic_gn;
1741
1742 /* Copy peer GSN address */
1743 pdp_old->gsnrc.l = pdp->gsnrc.l;
1744 memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l);
1745 pdp_old->gsnru.l = pdp->gsnru.l;
1746 memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l);
1747
1748 /* Copy request parameters */
1749 pdp_old->seq = pdp->seq;
1750 pdp_old->sa_peer = pdp->sa_peer;
1751 pdp_old->fd = pdp->fd = fd;
1752 pdp_old->version = pdp->version = version;
1753
1754 /* Switch to using the old pdp context */
1755 pdp = pdp_old;
1756
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001757 if (recovery_recvd)
1758 emit_cb_recovery(gsn, peer, pdp, recovery);
1759
Harald Weltebed35df2011-11-02 13:06:18 +01001760 /* Confirm to peer that things were "successful" */
1761 return gtp_create_pdp_resp(gsn, version, pdp,
1762 GTPCAUSE_ACC_REQ);
1763 } else { /* This is not the same PDP context. Delete the old one. */
1764
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01001765 DEBUGP(DLGTP, "gtp_create_pdp_ind: Deleting old context\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001766
Pau Espin Pedrol0d0b0592019-05-29 20:42:09 +02001767 gtp_freepdp(gsn, pdp_old);
Harald Weltebed35df2011-11-02 13:06:18 +01001768
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01001769 DEBUGP(DLGTP, "gtp_create_pdp_ind: Deleted...\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001770 }
1771 }
1772
Pau Espin Pedrol9b288b72022-02-28 13:58:51 +01001773 rc = gtp_pdp_newpdp(gsn, &pdp, pdp->imsi, pdp->nsapi, pdp);
1774 if (rc != 0) {
1775 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1776 "Failed creating a new PDP context, array full (%u)\n", PDP_MAX);
1777 /* &pdp in gtp_pdp_newpdp is untouched if it failed: */
1778 rc = gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_NO_MEMORY);
1779 /* Don't pass it to emit_cb_recovery, since allocation failed and it was already rejected: */
1780 pdp = NULL;
1781 goto recover_ret;
1782 }
Harald Weltebed35df2011-11-02 13:06:18 +01001783
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001784 /* Callback function to validate login */
Harald Weltebed35df2011-11-02 13:06:18 +01001785 if (gsn->cb_create_context_ind != 0)
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001786 rc = gsn->cb_create_context_ind(pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01001787 else {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001788 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1789 "No create_context_ind callback defined\n");
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001790 rc = gtp_create_pdp_resp(gsn, version, pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001791 GTPCAUSE_NOT_SUPPORTED);
1792 }
Pau Espin Pedrol9b288b72022-02-28 13:58:51 +01001793
1794recover_ret:
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001795 if (recovery_recvd)
1796 emit_cb_recovery(gsn, peer, pdp, recovery);
1797 return rc;
jjako52c24142002-12-16 13:33:51 +00001798}
1799
jjako52c24142002-12-16 13:33:51 +00001800/* Handle Create PDP Context Response */
1801int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01001802 struct sockaddr_in *peer, void *pack, unsigned len)
1803{
1804 struct pdp_t *pdp;
1805 union gtpie_member *ie[GTPIE_SIZE];
1806 uint8_t cause, recovery;
1807 void *cbp = NULL;
1808 uint8_t type = 0;
1809 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001810
Harald Weltebed35df2011-11-02 13:06:18 +01001811 /* Remove packet from queue */
1812 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
1813 return EOF;
jjako52c24142002-12-16 13:33:51 +00001814
Harald Weltebed35df2011-11-02 13:06:18 +01001815 /* Find the context in question */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02001816 if (gtp_pdp_getgtp1(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001817 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001818 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01001819 "Unknown PDP context: %u\n", get_tei(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01001820 if (gsn->cb_conf)
1821 gsn->cb_conf(type, EOF, NULL, cbp);
1822 return EOF;
1823 }
jjako2c381332003-10-21 19:09:53 +00001824
Harald Weltebed35df2011-11-02 13:06:18 +01001825 /* Decode information elements */
1826 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001827 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001828 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1829 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001830 if (gsn->cb_conf)
1831 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001832 return EOF;
1833 }
jjako52c24142002-12-16 13:33:51 +00001834
Harald Weltebed35df2011-11-02 13:06:18 +01001835 /* Extract cause value (mandatory) */
1836 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001837 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001838 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1839 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001840 if (gsn->cb_conf)
1841 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001842 return EOF;
1843 }
jjako52c24142002-12-16 13:33:51 +00001844
Harald Weltebed35df2011-11-02 13:06:18 +01001845 /* Extract recovery (optional) */
1846 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001847 emit_cb_recovery(gsn, peer, pdp, recovery);
Harald Weltebed35df2011-11-02 13:06:18 +01001848 }
jjako52c24142002-12-16 13:33:51 +00001849
Harald Weltebed35df2011-11-02 13:06:18 +01001850 /* Extract protocol configuration options (optional) */
1851 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1852 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1853 }
jjako52c24142002-12-16 13:33:51 +00001854
Harald Weltebed35df2011-11-02 13:06:18 +01001855 /* Check all conditional information elements */
Daniel Willmann6a2e8252023-11-23 18:41:59 +01001856 if (gtp_cause_successful(cause)) {
jjako52c24142002-12-16 13:33:51 +00001857
Harald Weltebed35df2011-11-02 13:06:18 +01001858 if (version == 0) {
1859 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1860 &pdp->qos_neg0,
1861 sizeof(pdp->qos_neg0))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001862 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001863 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001864 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001865 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001866 if (gsn->cb_conf)
1867 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001868 return EOF;
1869 }
1870 }
jjako08d331d2003-10-13 20:33:30 +00001871
Harald Weltebed35df2011-11-02 13:06:18 +01001872 if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001873 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001874 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Harald Weltebed35df2011-11-02 13:06:18 +01001875 len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001876 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001877 if (gsn->cb_conf)
1878 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001879 return EOF;
1880 }
jjako52c24142002-12-16 13:33:51 +00001881
Harald Weltebed35df2011-11-02 13:06:18 +01001882 if (version == 0) {
1883 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001884 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001885 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001886 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001887 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001888 if (gsn->cb_conf)
1889 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001890 return EOF;
1891 }
jjako52c24142002-12-16 13:33:51 +00001892
Harald Weltebed35df2011-11-02 13:06:18 +01001893 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001894 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001895 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001896 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001897 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001898 if (gsn->cb_conf)
1899 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001900 return EOF;
1901 }
1902 }
1903
1904 if (version == 1) {
1905 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001906 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001907 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001908 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001909 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001910 if (gsn->cb_conf)
1911 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001912 return EOF;
1913 }
1914
1915 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001916 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001917 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001918 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001919 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001920 if (gsn->cb_conf)
1921 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001922 return EOF;
1923 }
Pau Espin Pedrol0b1d9db2021-04-21 19:45:23 +02001924 /* Register that we have received a valid teic from GGSN */
1925 pdp->teic_confirmed = 1;
Harald Weltebed35df2011-11-02 13:06:18 +01001926 }
1927
1928 if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001929 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001930 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Harald Weltebed35df2011-11-02 13:06:18 +01001931 len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001932 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001933 if (gsn->cb_conf)
1934 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001935 }
1936
1937 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1938 &pdp->eua.v, sizeof(pdp->eua.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001939 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001940 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Harald Weltebed35df2011-11-02 13:06:18 +01001941 len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001942 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001943 if (gsn->cb_conf)
1944 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001945 return EOF;
1946 }
1947
1948 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1949 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001950 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001951 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Harald Weltebed35df2011-11-02 13:06:18 +01001952 len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001953 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001954 if (gsn->cb_conf)
1955 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001956 return EOF;
1957 }
1958
1959 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1960 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001961 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001962 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Harald Weltebed35df2011-11-02 13:06:18 +01001963 len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001964 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001965 if (gsn->cb_conf)
1966 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001967 return EOF;
1968 }
1969
1970 if (version == 1) {
1971 if (gtpie_gettlv
1972 (ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
1973 &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001974 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001975 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001976 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001977 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001978 if (gsn->cb_conf)
1979 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001980 return EOF;
1981 }
1982 }
1983
1984 }
1985
1986 if (gsn->cb_conf)
1987 gsn->cb_conf(type, cause, pdp, cbp);
1988
1989 return 0;
jjako52c24142002-12-16 13:33:51 +00001990}
1991
jjako08d331d2003-10-13 20:33:30 +00001992/* API: Send Update PDP Context Request */
1993int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
Harald Weltebed35df2011-11-02 13:06:18 +01001994 struct in_addr *inetaddr)
1995{
1996 union gtp_packet packet;
1997 unsigned int length =
1998 get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet);
jjako52c24142002-12-16 13:33:51 +00001999
Harald Weltebed35df2011-11-02 13:06:18 +01002000 if (pdp->version == 0)
2001 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
2002 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako08d331d2003-10-13 20:33:30 +00002003
Harald Weltebed35df2011-11-02 13:06:18 +01002004 /* Include IMSI if updating with unknown teic_gn */
2005 if ((pdp->version == 1) && (!pdp->teic_gn))
2006 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
2007 sizeof(pdp->imsi), (uint8_t *) & pdp->imsi);
2008
2009 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
2010 gsn->restart_counter);
2011
2012 if (pdp->version == 0) {
2013 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu);
2014 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc);
2015 }
2016
2017 if (pdp->version == 1) {
2018 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
2019 pdp->teid_own);
2020
2021 if (!pdp->teic_confirmed)
2022 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
2023 pdp->teic_own);
2024 }
2025
2026 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
2027
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01002028 /* TODO
Harald Weltebed35df2011-11-02 13:06:18 +01002029 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
2030 pdp->traceref);
2031 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
2032 pdp->tracetype); */
2033
2034 /* TODO if ggsn update message
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01002035 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
Harald Weltebed35df2011-11-02 13:06:18 +01002036 pdp->eua.l, pdp->eua.v);
2037 */
2038
2039 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
2040 pdp->gsnlc.l, pdp->gsnlc.v);
2041 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
2042 pdp->gsnlu.l, pdp->gsnlu.v);
2043
2044 if (pdp->version == 1)
2045 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
2046 pdp->qos_req.l, pdp->qos_req.v);
2047
2048 if ((pdp->version == 1) && pdp->tft.l)
2049 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
2050 pdp->tft.l, pdp->tft.v);
2051
2052 if ((pdp->version == 1) && pdp->triggerid.l)
2053 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
2054 pdp->triggerid.l, pdp->triggerid.v);
2055
2056 if ((pdp->version == 1) && pdp->omcid.l)
2057 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
2058 pdp->omcid.l, pdp->omcid.v);
2059
Daniel Willmann134a7752016-02-03 18:53:29 +01002060 gtp_req(gsn, pdp->version, pdp, &packet, length, inetaddr, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01002061
2062 return 0;
jjako52c24142002-12-16 13:33:51 +00002063}
2064
jjako08d331d2003-10-13 20:33:30 +00002065/* Send Update PDP Context Response */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01002066static int gtp_update_pdp_resp(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +01002067 struct sockaddr_in *peer, int fd,
jjako08d331d2003-10-13 20:33:30 +00002068 void *pack, unsigned len,
Harald Weltebed35df2011-11-02 13:06:18 +01002069 struct pdp_t *pdp, uint8_t cause)
2070{
jjako08d331d2003-10-13 20:33:30 +00002071
Harald Weltebed35df2011-11-02 13:06:18 +01002072 union gtp_packet packet;
2073 unsigned int length =
2074 get_default_gtp(version, GTP_UPDATE_PDP_RSP, &packet);
jjako08d331d2003-10-13 20:33:30 +00002075
Harald Weltebed35df2011-11-02 13:06:18 +01002076 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako08d331d2003-10-13 20:33:30 +00002077
Daniel Willmann6a2e8252023-11-23 18:41:59 +01002078 if (gtp_cause_successful(cause)) {
Harald Weltebed35df2011-11-02 13:06:18 +01002079
2080 if (version == 0)
2081 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
2082 sizeof(pdp->qos_neg0), pdp->qos_neg0);
2083
2084 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
2085 gsn->restart_counter);
2086
2087 if (version == 0) {
2088 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
2089 pdp->fllu);
2090 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
2091 pdp->fllc);
2092 }
2093
2094 if (version == 1) {
2095 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
2096 pdp->teid_own);
2097
2098 if (!pdp->teic_confirmed)
2099 gtpie_tv4(&packet, &length, GTP_MAX,
2100 GTPIE_TEI_C, pdp->teic_own);
2101 }
2102
2103 /* TODO we use teid_own as charging ID address */
2104 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
2105 pdp->teid_own);
2106
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01002107 /* If ggsn
2108 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
Harald Weltebed35df2011-11-02 13:06:18 +01002109 pdp->eua.l, pdp->eua.v); */
2110
2111 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
2112 pdp->gsnlc.l, pdp->gsnlc.v);
2113 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
2114 pdp->gsnlu.l, pdp->gsnlu.v);
2115
2116 if (version == 1)
2117 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
2118 pdp->qos_neg.l, pdp->qos_neg.v);
2119
2120 /* TODO: Charging gateway address */
2121 }
2122
2123 return gtp_resp(version, gsn, pdp, &packet, length, peer,
2124 fd, get_seq(pack), get_tid(pack));
jjako08d331d2003-10-13 20:33:30 +00002125}
2126
jjako52c24142002-12-16 13:33:51 +00002127/* Handle Update PDP Context Request */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01002128static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +01002129 struct sockaddr_in *peer, int fd,
2130 void *pack, unsigned len)
2131{
2132 struct pdp_t *pdp;
2133 struct pdp_t pdp_backup;
2134 union gtpie_member *ie[GTPIE_SIZE];
2135 uint8_t recovery;
jjako52c24142002-12-16 13:33:51 +00002136
Harald Weltebed35df2011-11-02 13:06:18 +01002137 uint16_t seq = get_seq(pack);
2138 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002139
Harald Weltebed35df2011-11-02 13:06:18 +01002140 uint64_t imsi;
2141 uint8_t nsapi;
jjako52c24142002-12-16 13:33:51 +00002142
Pau Espin Pedrolde72d262019-05-29 18:17:05 +02002143 /* Is this a duplicate ? */
2144 if (!gtp_duplicate(gsn, version, peer, seq)) {
Harald Weltebed35df2011-11-02 13:06:18 +01002145 return 0; /* We allready send of response once */
2146 }
jjako08d331d2003-10-13 20:33:30 +00002147
Harald Weltebed35df2011-11-02 13:06:18 +01002148 /* Decode information elements */
2149 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002150 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002151 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2152 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002153 if (0 == version)
2154 return EOF;
2155 else
2156 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2157 len, NULL,
2158 GTPCAUSE_INVALID_MESSAGE);
2159 }
jjako08d331d2003-10-13 20:33:30 +00002160
Harald Weltebed35df2011-11-02 13:06:18 +01002161 /* Finding PDP: */
2162 /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
2163 /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
2164 /* we have to use the tunnel endpoint identifier */
2165 if (version == 0) {
Harald Weltebed35df2011-11-02 13:06:18 +01002166 /* Find the context in question */
Vadim Yanitskiy00a61712019-08-30 21:00:22 +02002167 if (gtp_pdp_tidget(gsn, &pdp, get_tid(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002168 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002169 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2170 "Unknown PDP context: TID=0x%" PRIx64 "\n",
2171 get_tid(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01002172 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2173 len, NULL,
2174 GTPCAUSE_NON_EXIST);
2175 }
Vadim Yanitskiy00a61712019-08-30 21:00:22 +02002176
2177 /* Update IMSI and NSAPI */
2178 pdp_set_imsi_nsapi(pdp, get_tid(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01002179 } else if (version == 1) {
2180 /* NSAPI (mandatory) */
2181 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002182 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002183 GTP_LOGPKG(LOGL_ERROR, peer, pack,
2184 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002185 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2186 len, NULL,
2187 GTPCAUSE_MAN_IE_MISSING);
2188 }
jjako08d331d2003-10-13 20:33:30 +00002189
Harald Weltebed35df2011-11-02 13:06:18 +01002190 /* IMSI (conditional) */
2191 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) {
2192 /* Find the context in question */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002193 if (gtp_pdp_getgtp1(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002194 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002195 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2196 "Unknown PDP context: TEI=0x%" PRIx32 "\n",
2197 get_tei(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01002198 return gtp_update_pdp_resp(gsn, version, peer,
2199 fd, pack, len, NULL,
2200 GTPCAUSE_NON_EXIST);
2201 }
2202 } else {
2203 /* Find the context in question */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002204 if (gtp_pdp_getimsi(gsn, &pdp, imsi, nsapi)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002205 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002206 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2207 "Unknown PDP context: IMSI=0x%" PRIx64
2208 " NSAPI=%" PRIu8 "\n", imsi, nsapi);
Harald Weltebed35df2011-11-02 13:06:18 +01002209 return gtp_update_pdp_resp(gsn, version, peer,
2210 fd, pack, len, NULL,
2211 GTPCAUSE_NON_EXIST);
2212 }
2213 }
2214 } else {
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01002215 LOGP(DLGTP, LOGL_ERROR, "Unknown version: %d\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01002216 return EOF;
2217 }
jjako08d331d2003-10-13 20:33:30 +00002218
Harald Weltebed35df2011-11-02 13:06:18 +01002219 /* Make a backup copy in case anything is wrong */
2220 memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
jjako08d331d2003-10-13 20:33:30 +00002221
Harald Weltebed35df2011-11-02 13:06:18 +01002222 if (version == 0) {
2223 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2224 pdp->qos_req0, sizeof(pdp->qos_req0))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002225 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002226 GTP_LOGPKG(LOGL_ERROR, peer, pack,
2227 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002228 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2229 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2230 len, pdp,
2231 GTPCAUSE_MAN_IE_MISSING);
2232 }
2233 }
jjako52c24142002-12-16 13:33:51 +00002234
Harald Weltebed35df2011-11-02 13:06:18 +01002235 /* Recovery (optional) */
2236 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02002237 emit_cb_recovery(gsn, peer, pdp, recovery);
Harald Weltebed35df2011-11-02 13:06:18 +01002238 }
jjako08d331d2003-10-13 20:33:30 +00002239
Harald Weltebed35df2011-11-02 13:06:18 +01002240 if (version == 0) {
2241 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002242 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002243 GTP_LOGPKG(LOGL_ERROR, peer, pack,
2244 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002245 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2246 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2247 len, pdp,
2248 GTPCAUSE_MAN_IE_MISSING);
2249 }
jjako52c24142002-12-16 13:33:51 +00002250
Harald Weltebed35df2011-11-02 13:06:18 +01002251 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002252 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002253 GTP_LOGPKG(LOGL_ERROR, peer, pack,
2254 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002255 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2256 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2257 len, pdp,
2258 GTPCAUSE_MAN_IE_MISSING);
2259 }
2260 }
jjako52c24142002-12-16 13:33:51 +00002261
Harald Weltebed35df2011-11-02 13:06:18 +01002262 if (version == 1) {
2263 /* TEID (mandatory) */
2264 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002265 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002266 GTP_LOGPKG(LOGL_ERROR, peer, pack,
2267 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002268 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2269 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2270 len, pdp,
2271 GTPCAUSE_MAN_IE_MISSING);
2272 }
jjako52c24142002-12-16 13:33:51 +00002273
Harald Weltebed35df2011-11-02 13:06:18 +01002274 /* TEIC (conditional) */
2275 /* If TEIC is not included it means that we have allready received it */
2276 /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
2277 /* all updated contexts, or only for one of the linked contexts */
2278 gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn);
2279
2280 /* NSAPI (mandatory) */
2281 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002282 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002283 GTP_LOGPKG(LOGL_ERROR, peer, pack,
2284 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002285 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2286 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2287 len, pdp,
2288 GTPCAUSE_MAN_IE_MISSING);
2289 }
2290 }
2291
2292 /* Trace reference (optional) */
2293 /* Trace type (optional) */
2294
2295 /* End User Address (conditional) TODO: GGSN Initiated
2296 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2297 &pdp->eua.v, sizeof(pdp->eua.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002298 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002299 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Harald Weltebed35df2011-11-02 13:06:18 +01002300 "Missing mandatory information field");
2301 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01002302 return gtp_update_pdp_resp(gsn, version, pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01002303 GTPCAUSE_MAN_IE_MISSING);
2304 } */
2305
2306 /* SGSN address for signalling (mandatory) */
2307 /* It is weird that this is mandatory when TEIC is conditional */
2308 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2309 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002310 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002311 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2312 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002313 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2314 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
2315 pdp, GTPCAUSE_MAN_IE_MISSING);
2316 }
2317
2318 /* SGSN address for user traffic (mandatory) */
2319 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2320 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002321 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002322 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2323 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002324 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2325 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
2326 pdp, GTPCAUSE_MAN_IE_MISSING);
2327 }
2328
2329 if (version == 1) {
2330 /* QoS (mandatory) */
2331 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
2332 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002333 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002334 GTP_LOGPKG(LOGL_ERROR, peer, pack,
2335 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002336 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2337 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2338 len, pdp,
2339 GTPCAUSE_MAN_IE_MISSING);
2340 }
2341
2342 /* TFT (conditional) */
2343 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
2344 &pdp->tft.v, sizeof(pdp->tft.v))) {
2345 }
2346
2347 /* OMC identity */
2348 }
2349
2350 /* Confirm to peer that things were "successful" */
2351 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2352 GTPCAUSE_ACC_REQ);
jjako52c24142002-12-16 13:33:51 +00002353}
2354
jjako52c24142002-12-16 13:33:51 +00002355/* Handle Update PDP Context Response */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01002356static int gtp_update_pdp_conf(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +01002357 struct sockaddr_in *peer, void *pack, unsigned len)
2358{
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002359 struct pdp_t *pdp = NULL;
Harald Weltebed35df2011-11-02 13:06:18 +01002360 union gtpie_member *ie[GTPIE_SIZE];
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002361 uint8_t cause = EOF;
2362 uint8_t recovery;
2363 int rc = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01002364 void *cbp = NULL;
2365 uint8_t type = 0;
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002366 bool trigger_recovery = false;
Daniel Willmann05f3ef32016-02-03 18:53:30 +01002367 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002368
Harald Weltebed35df2011-11-02 13:06:18 +01002369 /* Remove packet from queue */
2370 if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp))
2371 return EOF;
jjako52c24142002-12-16 13:33:51 +00002372
Harald Weltebed35df2011-11-02 13:06:18 +01002373 /* Decode information elements */
Daniel Willmann05f3ef32016-02-03 18:53:30 +01002374 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002375 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002376 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2377 "Invalid message format\n");
Daniel Willmannd9975522016-02-04 15:38:12 +01002378 goto err_out;
Harald Weltebed35df2011-11-02 13:06:18 +01002379 }
jjako52c24142002-12-16 13:33:51 +00002380
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002381 /* Extract recovery (optional) */
2382 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery))
2383 trigger_recovery = true;
2384
Harald Weltebed35df2011-11-02 13:06:18 +01002385 /* Extract cause value (mandatory) */
2386 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
Daniel Willmannd9975522016-02-04 15:38:12 +01002387 goto err_missing;
Harald Weltebed35df2011-11-02 13:06:18 +01002388 }
jjako52c24142002-12-16 13:33:51 +00002389
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002390 /* 3GPP TS 29.060 sec 8.2: "Receiving node shall send back to the source
2391 * of the message, a response with the appropriate cause value (either
2392 * "Non-existent" or "Context not found"). The Tunnel Endpoint
2393 * Identifier used in the response message shall be set to all zeroes."
2394 * Hence, TEID=0 in this scenario, it makes no sense to infer PDP ctx
2395 * from it. User is responsible to infer it from cbp */
2396 if (cause != GTPCAUSE_NON_EXIST && cause != GTPCAUSE_CONTEXT_NOT_FOUND) {
2397 /* Find the context in question */
2398 if (gtp_pdp_getgtp1(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002399 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002400 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002401 "Unknown PDP context: TEI=0x%" PRIx32 "\n", get_tei(pack));
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002402 goto err_out;
2403 }
Harald Weltebed35df2011-11-02 13:06:18 +01002404 }
2405
2406 /* Check all conditional information elements */
Daniel Willmannd9975522016-02-04 15:38:12 +01002407 /* TODO: This does not handle GGSN-initiated update responses */
Daniel Willmann6a2e8252023-11-23 18:41:59 +01002408 if (gtp_cause_successful(cause)) {
Daniel Willmannd9975522016-02-04 15:38:12 +01002409 if (version == 0) {
2410 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2411 &pdp->qos_neg0,
2412 sizeof(pdp->qos_neg0))) {
2413 goto err_missing;
2414 }
2415
2416 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
2417 goto err_missing;
2418 }
2419
2420 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
2421 goto err_missing;
2422 }
Harald Weltebed35df2011-11-02 13:06:18 +01002423 }
2424
Daniel Willmannd9975522016-02-04 15:38:12 +01002425 if (version == 1) {
2426 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
2427 goto err_missing;
2428 }
Harald Weltebed35df2011-11-02 13:06:18 +01002429
Daniel Willmannd9975522016-02-04 15:38:12 +01002430 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
2431 goto err_missing;
2432 }
Pau Espin Pedrol0b1d9db2021-04-21 19:45:23 +02002433 /* Register that we have received a valid teic from GGSN */
2434 pdp->teic_confirmed = 1;
Daniel Willmannd9975522016-02-04 15:38:12 +01002435 }
2436
2437 if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
2438 goto err_missing;
2439 }
2440
2441 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2442 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
2443 goto err_missing;
2444 }
2445
2446 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2447 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
2448 goto err_missing;
2449 }
2450
2451 if (version == 1) {
2452 if (gtpie_gettlv
2453 (ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
2454 &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
2455 goto err_missing;
2456 }
2457 }
Harald Weltebed35df2011-11-02 13:06:18 +01002458 }
Daniel Willmannd9975522016-02-04 15:38:12 +01002459
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002460generic_ret:
2461 if (trigger_recovery)
2462 emit_cb_recovery(gsn, peer, pdp, recovery);
Daniel Willmannd9975522016-02-04 15:38:12 +01002463 if (gsn->cb_conf)
2464 gsn->cb_conf(type, cause, pdp, cbp);
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002465 return rc; /* Succes */
Daniel Willmannd9975522016-02-04 15:38:12 +01002466
2467err_missing:
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002468 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Daniel Willmannd9975522016-02-04 15:38:12 +01002469 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2470 "Missing information field\n");
2471err_out:
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002472 rc = EOF;
2473 goto generic_ret;
jjako52c24142002-12-16 13:33:51 +00002474}
2475
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002476/* API: Deprecated. Send Delete PDP Context Request And free pdp ctx. */
jjako2c381332003-10-21 19:09:53 +00002477int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
Harald Weltebed35df2011-11-02 13:06:18 +01002478 int teardown)
2479{
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002480 struct pdp_t *linked_pdp;
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002481
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002482 if (gtp_pdp_getgtp1(gsn, &linked_pdp, pdp->teic_own)) {
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002483 LOGP(DLGTP, LOGL_ERROR,
2484 "Unknown linked PDP context: %u\n", pdp->teic_own);
2485 return EOF;
2486 }
2487
2488 if (gtp_delete_context_req2(gsn, pdp, cbp, teardown) == EOF)
2489 return EOF;
2490
2491 if (teardown) { /* Remove all contexts */
Pau Espin Pedrol0d0b0592019-05-29 20:42:09 +02002492 gtp_freepdp_teardown(gsn, linked_pdp);
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002493 } else {
Pau Espin Pedrol86515732019-05-31 16:40:37 +02002494 /* If we end up here (no teardown) it means we still
2495 have at least another pdp context active for this
2496 PDN connection (since last DeleteReq should come
2497 with teardown enabled). If the ctx to delete is a
2498 secondary ctx, simply free it. If it's the primary
2499 ctx, mark it as nodata but don't free it since we
2500 need it to hold data linked together and we'll
2501 require it later to tear down the entire tree. Still,
2502 we announce its deletion through cb_delete_context
2503 because we don't want user to release its related
2504 data and not use it anymore.
2505 */
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002506 if (pdp == linked_pdp) {
Pau Espin Pedrol93dd7982019-05-31 16:42:05 +02002507 if (gsn->cb_delete_context)
2508 gsn->cb_delete_context(pdp);
2509 pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2510 pdp->nodata = 1;
2511 } else {
2512 gtp_freepdp(gsn, pdp);
2513 }
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002514 }
2515
2516 return 0;
2517}
2518
Oliver Smith1cde2c12019-05-13 11:35:03 +02002519/* API: Send Delete PDP Context Request. PDP CTX shall be free'd by user at any
Pau Espin Pedrol4e605b32019-08-29 13:54:28 +02002520 point in time later than this function through a call to pdp_freepdp(pdp) (or
2521 through gtp_freepdp() if willing to receive cb_delete_context() callback),
2522 but it must be freed no later than during cb_conf(GTP_DELETE_PDP_REQ, pdp) */
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002523int gtp_delete_context_req2(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
2524 int teardown)
2525{
Harald Weltebed35df2011-11-02 13:06:18 +01002526 union gtp_packet packet;
2527 unsigned int length =
2528 get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
2529 struct in_addr addr;
2530 struct pdp_t *linked_pdp;
Pau Espin Pedrol9ee8d322019-05-30 14:11:22 +02002531 int count;
jjako2c381332003-10-21 19:09:53 +00002532
Harald Weltebed35df2011-11-02 13:06:18 +01002533 if (gsna2in_addr(&addr, &pdp->gsnrc)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002534 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_ADDRESS);
Max14b1b632017-08-21 20:14:59 +02002535 LOGP(DLGTP, LOGL_ERROR, "GSN address (len=%u) conversion failed\n", pdp->gsnrc.l);
Harald Weltebed35df2011-11-02 13:06:18 +01002536 return EOF;
jjako2c381332003-10-21 19:09:53 +00002537 }
jjako2c381332003-10-21 19:09:53 +00002538
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002539 if (gtp_pdp_getgtp1(gsn, &linked_pdp, pdp->teic_own)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002540 LOGP(DLGTP, LOGL_ERROR,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01002541 "Unknown linked PDP context: %u\n", pdp->teic_own);
Harald Weltebed35df2011-11-02 13:06:18 +01002542 return EOF;
2543 }
2544
2545 if (!teardown) {
Pau Espin Pedrol9ee8d322019-05-30 14:11:22 +02002546 count = pdp_count_secondary(linked_pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01002547 if (count <= 1) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002548 LOGP(DLGTP, LOGL_ERROR,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01002549 "Must use teardown for last context: %d\n", count);
Harald Weltebed35df2011-11-02 13:06:18 +01002550 return EOF;
2551 }
2552 }
2553
2554 if (pdp->version == 1) {
2555 if (teardown)
2556 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
2557 0xff);
2558
2559 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
2560 }
2561
2562 gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
2563
Harald Weltebed35df2011-11-02 13:06:18 +01002564 return 0;
jjako2c381332003-10-21 19:09:53 +00002565}
jjako08d331d2003-10-13 20:33:30 +00002566
jjako52c24142002-12-16 13:33:51 +00002567/* Send Delete PDP Context Response */
2568int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002569 struct sockaddr_in *peer, int fd,
Harald Weltebed35df2011-11-02 13:06:18 +01002570 void *pack, unsigned len,
2571 struct pdp_t *pdp, struct pdp_t *linked_pdp,
jjako2c381332003-10-21 19:09:53 +00002572 uint8_t cause, int teardown)
jjako52c24142002-12-16 13:33:51 +00002573{
Harald Weltebed35df2011-11-02 13:06:18 +01002574 union gtp_packet packet;
Harald Weltebed35df2011-11-02 13:06:18 +01002575 unsigned int length =
2576 get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet);
jjako52c24142002-12-16 13:33:51 +00002577
Harald Weltebed35df2011-11-02 13:06:18 +01002578 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00002579
Harald Weltebed35df2011-11-02 13:06:18 +01002580 gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
2581 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002582
Daniel Willmann6a2e8252023-11-23 18:41:59 +01002583 if (gtp_cause_successful(cause)) {
Harald Weltebed35df2011-11-02 13:06:18 +01002584 if ((teardown) || (version == 0)) { /* Remove all contexts */
Pau Espin Pedrol0d0b0592019-05-29 20:42:09 +02002585 gtp_freepdp_teardown(gsn, linked_pdp);
Pau Espin Pedrol86515732019-05-31 16:40:37 +02002586 } else {
2587 /* If we end up here (no teardown) it means we still
2588 have at least another pdp context active for this
2589 PDN connection (since last DeleteReq should come
2590 with teardown enabled). If the ctx to delete is a
2591 secondary ctx, simply free it. If it's the primary
2592 ctx, mark it as nodata but don't free it since we
2593 need it to hold data linked together and we'll
2594 require it later to tear down the entire tree. Still,
2595 we announce its deletion through cb_delete_context
2596 because we don't want user to release its related
2597 data and not use it anymore.
2598 */
Harald Weltebed35df2011-11-02 13:06:18 +01002599 if (pdp == linked_pdp) {
Pau Espin Pedrol93dd7982019-05-31 16:42:05 +02002600 if (gsn->cb_delete_context)
2601 gsn->cb_delete_context(pdp);
2602 pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2603 pdp->nodata = 1;
2604 } else {
2605 gtp_freepdp(gsn, pdp);
2606 }
Harald Weltebed35df2011-11-02 13:06:18 +01002607 }
jjako2c381332003-10-21 19:09:53 +00002608 }
Harald Weltebed35df2011-11-02 13:06:18 +01002609 return 0;
jjako52c24142002-12-16 13:33:51 +00002610}
2611
2612/* Handle Delete PDP Context Request */
2613int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002614 struct sockaddr_in *peer, int fd,
Harald Weltebed35df2011-11-02 13:06:18 +01002615 void *pack, unsigned len)
2616{
2617 struct pdp_t *pdp = NULL;
2618 struct pdp_t *linked_pdp = NULL;
2619 union gtpie_member *ie[GTPIE_SIZE];
jjako52c24142002-12-16 13:33:51 +00002620
Harald Weltebed35df2011-11-02 13:06:18 +01002621 uint16_t seq = get_seq(pack);
2622 int hlen = get_hlen(pack);
jjako2c381332003-10-21 19:09:53 +00002623
Harald Weltebed35df2011-11-02 13:06:18 +01002624 uint8_t nsapi;
2625 uint8_t teardown = 0;
Pau Espin Pedrol9ee8d322019-05-30 14:11:22 +02002626 int count;
jjako52c24142002-12-16 13:33:51 +00002627
Pau Espin Pedrolde72d262019-05-29 18:17:05 +02002628 /* Is this a duplicate ? */
2629 if (!gtp_duplicate(gsn, version, peer, seq)) {
Harald Weltebed35df2011-11-02 13:06:18 +01002630 return 0; /* We allready send off response once */
2631 }
jjako2c381332003-10-21 19:09:53 +00002632
Harald Weltebed35df2011-11-02 13:06:18 +01002633 /* Find the linked context in question */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002634 if (gtp_pdp_getgtp1(gsn, &linked_pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002635 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002636 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002637 "Unknown PDP context: TEI=0x%" PRIx32 "\n", get_tei(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01002638 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2639 NULL, NULL, GTPCAUSE_NON_EXIST,
2640 teardown);
2641 }
jjako2c381332003-10-21 19:09:53 +00002642
Harald Weltebed35df2011-11-02 13:06:18 +01002643 /* If version 0 this is also the secondary context */
2644 if (version == 0)
2645 pdp = linked_pdp;
jjako2c381332003-10-21 19:09:53 +00002646
Harald Weltebed35df2011-11-02 13:06:18 +01002647 /* Decode information elements */
2648 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002649 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002650 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2651 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002652 if (0 == version)
2653 return EOF;
2654 else
2655 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2656 len, NULL, NULL,
2657 GTPCAUSE_INVALID_MESSAGE,
2658 teardown);
2659 }
2660
2661 if (version == 1) {
2662 /* NSAPI (mandatory) */
2663 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002664 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002665 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002666 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002667 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2668 len, NULL, NULL,
2669 GTPCAUSE_MAN_IE_MISSING,
2670 teardown);
2671 }
2672
2673 /* Find the context in question */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002674 if (gtp_pdp_getgtp1(gsn, &pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002675 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002676 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2677 "Unknown PDP context: Secondary TEI=0x%" PRIx32 "\n",
2678 linked_pdp->secondary_tei[nsapi & 0x0f]);
Harald Weltebed35df2011-11-02 13:06:18 +01002679 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2680 len, NULL, NULL,
2681 GTPCAUSE_NON_EXIST,
2682 teardown);
2683 }
2684
2685 /* Teardown (conditional) */
2686 gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown);
2687
2688 if (!teardown) {
Pau Espin Pedrol742a6b52019-05-30 13:36:10 +02002689 /* TS 29.060 section 7.3.5: If a GSN receives a Delete PDP context
2690 * without a Teardown Indicator or with a Teardown Indicator with
2691 * value set to "0" and only that PDP context is active for a PDN
2692 * connection, then the GSN shall ignore the message. (Note:
2693 * This is symptom of a race condition. The reliable delivery of
2694 * signalling messages will eventually lead to a consistent
2695 * situation, allowing the teardown of the PDP context.)
2696 */
Pau Espin Pedrol9ee8d322019-05-30 14:11:22 +02002697 count = pdp_count_secondary(linked_pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01002698 if (count <= 1) {
Pau Espin Pedrold1bd6fc2018-07-13 19:11:45 +02002699 GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
2700 "Ignoring CTX DEL without teardown and count=%d\n",
2701 count);
Harald Weltebed35df2011-11-02 13:06:18 +01002702 return 0; /* 29.060 7.3.5 Ignore message */
2703 }
2704 }
2705 }
2706
2707 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2708 pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown);
jjako52c24142002-12-16 13:33:51 +00002709}
2710
jjako52c24142002-12-16 13:33:51 +00002711/* Handle Delete PDP Context Response */
2712int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002713 struct sockaddr_in *peer, void *pack, unsigned len)
2714{
2715 union gtpie_member *ie[GTPIE_SIZE];
2716 uint8_t cause;
2717 void *cbp = NULL;
2718 uint8_t type = 0;
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002719 struct pdp_t *pdp = NULL;
Harald Weltebed35df2011-11-02 13:06:18 +01002720 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002721
Harald Weltebed35df2011-11-02 13:06:18 +01002722 /* Remove packet from queue */
2723 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
2724 return EOF;
jjako52c24142002-12-16 13:33:51 +00002725
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002726 /* Find the context in question. It may not be available if gtp_delete_context_req
2727 * was used and as a result the PDP ctx was already freed */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002728 if (gtp_pdp_getgtp1(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002729 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002730 GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002731 "Unknown PDP context: TEI=0x%" PRIx32 " (expected if "
2732 "gtp_delete_context_req is used or pdp ctx was freed "
2733 "manually before response)\n", get_tei(pack));
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002734 if (gsn->cb_conf)
2735 gsn->cb_conf(type, EOF, NULL, cbp);
2736 return EOF;
2737 }
2738
Harald Weltebed35df2011-11-02 13:06:18 +01002739 /* Decode information elements */
2740 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002741 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002742 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2743 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002744 if (gsn->cb_conf)
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002745 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01002746 return EOF;
2747 }
2748
2749 /* Extract cause value (mandatory) */
2750 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002751 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002752 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2753 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002754 if (gsn->cb_conf)
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002755 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01002756 return EOF;
2757 }
2758
2759 /* Check the cause value (again) */
Daniel Willmann6a2e8252023-11-23 18:41:59 +01002760 if (!gtp_cause_successful(cause) && (GTPCAUSE_NON_EXIST != cause)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002761 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNEXPECTED_CAUSE);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002762 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2763 "Unexpected cause value received: %d\n", cause);
Harald Weltebed35df2011-11-02 13:06:18 +01002764 if (gsn->cb_conf)
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002765 gsn->cb_conf(type, cause, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01002766 return EOF;
2767 }
2768
2769 /* Callback function to notify application */
2770 if (gsn->cb_conf)
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002771 gsn->cb_conf(type, cause, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01002772
2773 return 0;
jjako52c24142002-12-16 13:33:51 +00002774}
2775
Harald Welte54d082e2017-08-12 22:43:21 +02002776/* Send Error Indication (response to a GPDU message) - 3GPP TS 29.060 7.3.7 */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01002777static int gtp_error_ind_resp(struct gsn_t *gsn, uint8_t version,
jjako08d331d2003-10-13 20:33:30 +00002778 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002779 void *pack, unsigned len)
2780{
Harald Weltebed35df2011-11-02 13:06:18 +01002781 union gtp_packet packet;
2782 unsigned int length = get_default_gtp(version, GTP_ERROR, &packet);
2783
Harald Welte54d082e2017-08-12 22:43:21 +02002784 if (version == 1) {
2785 /* Mandatory 7.7.13 TEI Data I */
2786 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
2787 ntoh32(((union gtp_packet *)pack)->gtp1l.h.tei));
2788
2789 /* Mandatory 7.7.32 GSN Address */
2790 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
2791 sizeof(gsn->gsnu), &gsn->gsnu);
2792 }
2793
Harald Weltebed35df2011-11-02 13:06:18 +01002794 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
2795 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002796}
2797
2798/* Handle Error Indication */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01002799static int gtp_error_ind_conf(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +01002800 struct sockaddr_in *peer, void *pack, unsigned len)
2801{
Harald Welte37d5b152017-08-12 23:58:29 +02002802 union gtpie_member *ie[GTPIE_SIZE];
Harald Weltebed35df2011-11-02 13:06:18 +01002803 struct pdp_t *pdp;
jjako52c24142002-12-16 13:33:51 +00002804
Harald Weltebed35df2011-11-02 13:06:18 +01002805 /* Find the context in question */
Harald Welte37d5b152017-08-12 23:58:29 +02002806 if (version == 0) {
Vadim Yanitskiy68c5a742019-08-30 21:04:19 +02002807 if (gtp_pdp_tidget(gsn, &pdp, get_tid(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002808 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Harald Welte37d5b152017-08-12 23:58:29 +02002809 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002810 "Unknown PDP context: TID=0x%" PRIx64 "\n",
2811 get_tid(pack));
Harald Welte37d5b152017-08-12 23:58:29 +02002812 return EOF;
2813 }
2814 } else if (version == 1) {
2815 /* we have to look-up based on the *peer* TEID */
2816 int hlen = get_hlen(pack);
2817 uint32_t teid_gn;
2818
2819 /* Decode information elements */
2820 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002821 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Harald Welte37d5b152017-08-12 23:58:29 +02002822 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2823 "Invalid message format\n");
2824 return EOF;
2825 }
2826
2827 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &teid_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002828 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Harald Welte37d5b152017-08-12 23:58:29 +02002829 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2830 "Missing mandatory information field\n");
2831 return EOF;
2832 }
2833
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002834 if (gtp_pdp_getgtp1_peer_d(gsn, &pdp, peer, teid_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002835 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002836 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2837 "Unknown PDP context: Peer TEID=0x%" PRIx32 "\n",
2838 teid_gn);
Harald Welte37d5b152017-08-12 23:58:29 +02002839 return EOF;
2840 }
Vadim Yanitskiybdf2cf92019-08-30 21:23:11 +02002841 } else {
2842 LOGP(DLGTP, LOGL_ERROR, "Unknown version: %d\n", version);
2843 return EOF;
Harald Weltebed35df2011-11-02 13:06:18 +01002844 }
jjako52c24142002-12-16 13:33:51 +00002845
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002846 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2847 "Received Error Indication\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002848
Harald Weltebd228242017-11-06 03:16:49 +09002849 /* This is obvious from above code, given the semantics of the
2850 * functions above, but Coverity doesn't figure this out, so
2851 * let's make it clear. It's good style anyway in case above
2852 * code should ever change. */
2853 OSMO_ASSERT(pdp);
2854
Pau Espin Pedrol0d0b0592019-05-29 20:42:09 +02002855 gtp_freepdp(gsn, pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01002856 return 0;
jjako52c24142002-12-16 13:33:51 +00002857}
2858
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01002859static int gtp_gpdu_ind(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +01002860 struct sockaddr_in *peer, int fd, void *pack, unsigned len)
2861{
jjako08d331d2003-10-13 20:33:30 +00002862
Pau Espin Pedrol282d4e32018-01-25 18:20:51 +01002863 int hlen;
jjako52c24142002-12-16 13:33:51 +00002864
Harald Weltebed35df2011-11-02 13:06:18 +01002865 struct pdp_t *pdp;
jjako1db1c812003-07-06 20:53:57 +00002866
Pau Espin Pedrol42d32502018-01-25 18:17:17 +01002867 switch (version) {
2868 case 0:
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002869 if (gtp_pdp_getgtp0(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002870 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002871 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2872 "Unknown PDP context: TEI=0x%" PRIx32 "\n",
2873 get_tei(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01002874 return gtp_error_ind_resp(gsn, version, peer, fd, pack,
2875 len);
2876 }
2877 hlen = GTP0_HEADER_SIZE;
Pau Espin Pedrol42d32502018-01-25 18:17:17 +01002878 break;
2879 case 1:
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002880 if (gtp_pdp_getgtp1(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002881 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002882 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2883 "Unknown PDP context: TEI=0x%" PRIx32 "\n",
2884 get_tei(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01002885 return gtp_error_ind_resp(gsn, version, peer, fd, pack,
2886 len);
2887 }
jjako08d331d2003-10-13 20:33:30 +00002888
Harald Weltebed35df2011-11-02 13:06:18 +01002889 /* Is this a long or a short header ? */
2890 if (((union gtp_packet *)pack)->gtp1l.h.flags & 0x07)
2891 hlen = GTP1_HEADER_SIZE_LONG;
2892 else
2893 hlen = GTP1_HEADER_SIZE_SHORT;
Pau Espin Pedrol42d32502018-01-25 18:17:17 +01002894 break;
2895 default:
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002896 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01002897 "Unknown version: %d\n", version);
Pau Espin Pedrol282d4e32018-01-25 18:20:51 +01002898 return EOF;
Harald Weltebed35df2011-11-02 13:06:18 +01002899 }
jjako08d331d2003-10-13 20:33:30 +00002900
Harald Weltebed35df2011-11-02 13:06:18 +01002901 /* If the GPDU was not from the peer GSN tell him to delete context */
2902 if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002903 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Max14b1b632017-08-21 20:14:59 +02002904 GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Unknown GSN peer %s\n", inet_ntoa(peer->sin_addr));
Harald Weltebed35df2011-11-02 13:06:18 +01002905 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2906 }
jjako52c24142002-12-16 13:33:51 +00002907
Harald Weltebed35df2011-11-02 13:06:18 +01002908 /* Callback function */
2909 if (gsn->cb_data_ind != 0)
2910 return gsn->cb_data_ind(pdp, pack + hlen, len - hlen);
2911
2912 return 0;
jjako52c24142002-12-16 13:33:51 +00002913}
2914
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01002915/* Receives GTP packet and sends off for further processing
jjako52c24142002-12-16 13:33:51 +00002916 * Function will check the validity of the header. If the header
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01002917 * is not valid the packet is either dropped or a version not
2918 * supported is returned to the peer.
jjako52c24142002-12-16 13:33:51 +00002919 * TODO: Need to decide on return values! */
jjako08d331d2003-10-13 20:33:30 +00002920int gtp_decaps0(struct gsn_t *gsn)
jjako52c24142002-12-16 13:33:51 +00002921{
Harald Weltebed35df2011-11-02 13:06:18 +01002922 unsigned char buffer[PACKET_MAX];
2923 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01002924 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01002925 int status;
2926 struct gtp0_header *pheader;
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002927 uint8_t version;
Harald Weltebed35df2011-11-02 13:06:18 +01002928 int fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00002929
Harald Weltebed35df2011-11-02 13:06:18 +01002930 /* TODO: Need strategy of userspace buffering and blocking */
2931 /* Currently read is non-blocking and send is blocking. */
2932 /* This means that the program have to wait for busy send calls... */
jjako52c24142002-12-16 13:33:51 +00002933
Harald Weltebed35df2011-11-02 13:06:18 +01002934 while (1) { /* Loop until no more to read */
2935 if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002936 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002937 return -1;
2938 }
2939 peerlen = sizeof(peer);
2940 if ((status =
2941 recvfrom(gsn->fd0, buffer, sizeof(buffer), 0,
2942 (struct sockaddr *)&peer, &peerlen)) < 0) {
2943 if (errno == EAGAIN)
2944 return 0;
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002945 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_READFROM);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002946 LOGP(DLGTP, LOGL_ERROR,
Alexander Huemerdb852a12015-11-06 20:59:01 +01002947 "recvfrom(fd0=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n",
Harald Weltebed35df2011-11-02 13:06:18 +01002948 gsn->fd0, (unsigned long)buffer, sizeof(buffer),
2949 status, status ? strerror(errno) : "No error");
2950 return -1;
2951 }
jjako1db1c812003-07-06 20:53:57 +00002952
Harald Weltebed35df2011-11-02 13:06:18 +01002953 /* Need at least 1 byte in order to check version */
2954 if (status < (1)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002955 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_EMPTY);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002956 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
2957 status, "Discarding packet - too small\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002958 continue;
2959 }
jjako08d331d2003-10-13 20:33:30 +00002960
Harald Weltebed35df2011-11-02 13:06:18 +01002961 pheader = (struct gtp0_header *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00002962
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002963 version = GTPHDR_F_GET_VER(pheader->flags);
2964
Harald Weltebed35df2011-11-02 13:06:18 +01002965 /* Version should be gtp0 (or earlier) */
2966 /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
2967 /* GTP 0 messages. If other version message is received we reply that we */
2968 /* only support version 0, implying that this is the only version */
2969 /* supported on this port */
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002970 if (version > 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002971 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Pau Espin Pedrola884a952018-01-25 17:28:11 +01002972 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
2973 "Unsupported GTP version %"PRIu8"\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01002974 gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */
2975 continue;
2976 }
2977
2978 /* Check length of gtp0 packet */
2979 if (status < GTP0_HEADER_SIZE) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002980 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002981 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
2982 status, "GTP0 packet too short\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002983 continue; /* Silently discard 29.60: 11.1.2 */
2984 }
2985
2986 /* Check packet length field versus length of packet */
2987 if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002988 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002989 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01002990 status,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002991 "GTP packet length field does not match actual length\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002992 continue; /* Silently discard */
2993 }
2994
2995 if ((gsn->mode == GTP_MODE_GGSN) &&
2996 ((pheader->type == GTP_CREATE_PDP_RSP) ||
Pau Espin Pedrola32e4c42018-07-13 19:05:00 +02002997 (pheader->type == GTP_UPDATE_PDP_RSP))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002998 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNEXPECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002999 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01003000 status,
Pau Espin Pedrol3b84e922018-07-13 18:32:35 +02003001 "Unexpected GTPv0 Signalling Message '%s'\n",
3002 get_value_string(gtp_type_names, pheader->type));
Harald Weltebed35df2011-11-02 13:06:18 +01003003 continue; /* Silently discard 29.60: 11.1.4 */
3004 }
3005
3006 if ((gsn->mode == GTP_MODE_SGSN) &&
3007 ((pheader->type == GTP_CREATE_PDP_REQ) ||
Pau Espin Pedrola32e4c42018-07-13 19:05:00 +02003008 (pheader->type == GTP_UPDATE_PDP_REQ))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003009 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNEXPECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003010 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01003011 status,
Pau Espin Pedrol3b84e922018-07-13 18:32:35 +02003012 "Unexpected GTPv0 Signalling Message '%s'\n",
3013 get_value_string(gtp_type_names, pheader->type));
Harald Weltebed35df2011-11-02 13:06:18 +01003014 continue; /* Silently discard 29.60: 11.1.4 */
3015 }
3016
3017 switch (pheader->type) {
3018 case GTP_ECHO_REQ:
3019 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
3020 break;
3021 case GTP_ECHO_RSP:
3022 gtp_echo_conf(gsn, version, &peer, buffer, status);
3023 break;
3024 case GTP_NOT_SUPPORTED:
3025 gtp_unsup_ind(gsn, &peer, buffer, status);
3026 break;
3027 case GTP_CREATE_PDP_REQ:
3028 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer,
3029 status);
3030 break;
3031 case GTP_CREATE_PDP_RSP:
3032 gtp_create_pdp_conf(gsn, version, &peer, buffer,
3033 status);
3034 break;
3035 case GTP_UPDATE_PDP_REQ:
3036 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer,
3037 status);
3038 break;
3039 case GTP_UPDATE_PDP_RSP:
3040 gtp_update_pdp_conf(gsn, version, &peer, buffer,
3041 status);
3042 break;
3043 case GTP_DELETE_PDP_REQ:
3044 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer,
3045 status);
3046 break;
3047 case GTP_DELETE_PDP_RSP:
3048 gtp_delete_pdp_conf(gsn, version, &peer, buffer,
3049 status);
3050 break;
3051 case GTP_ERROR:
3052 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
3053 break;
3054 case GTP_GPDU:
3055 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
3056 break;
3057 default:
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003058 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNKNOWN);
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01003059 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
3060 "Unknown GTP message type received: %d\n",
3061 pheader->type);
Harald Weltebed35df2011-11-02 13:06:18 +01003062 break;
3063 }
3064 }
jjako08d331d2003-10-13 20:33:30 +00003065}
3066
jjako08d331d2003-10-13 20:33:30 +00003067int gtp_decaps1c(struct gsn_t *gsn)
3068{
Harald Weltebed35df2011-11-02 13:06:18 +01003069 unsigned char buffer[PACKET_MAX];
3070 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01003071 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01003072 int status;
3073 struct gtp1_header_short *pheader;
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01003074 uint8_t version;
Harald Weltebed35df2011-11-02 13:06:18 +01003075 int fd = gsn->fd1c;
jjako08d331d2003-10-13 20:33:30 +00003076
Harald Weltebed35df2011-11-02 13:06:18 +01003077 /* TODO: Need strategy of userspace buffering and blocking */
3078 /* Currently read is non-blocking and send is blocking. */
3079 /* This means that the program have to wait for busy send calls... */
jjako08d331d2003-10-13 20:33:30 +00003080
Harald Weltebed35df2011-11-02 13:06:18 +01003081 while (1) { /* Loop until no more to read */
3082 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003083 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003084 return -1;
3085 }
3086 peerlen = sizeof(peer);
3087 if ((status =
3088 recvfrom(fd, buffer, sizeof(buffer), 0,
3089 (struct sockaddr *)&peer, &peerlen)) < 0) {
3090 if (errno == EAGAIN)
3091 return 0;
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003092 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_READFROM);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003093 LOGP(DLGTP, LOGL_ERROR,
Alexander Huemerdb852a12015-11-06 20:59:01 +01003094 "recvfrom(fd=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n",
Harald Weltebed35df2011-11-02 13:06:18 +01003095 fd, (unsigned long)buffer, sizeof(buffer),
3096 status, status ? strerror(errno) : "No error");
3097 return -1;
3098 }
jjako08d331d2003-10-13 20:33:30 +00003099
Harald Weltebed35df2011-11-02 13:06:18 +01003100 /* Need at least 1 byte in order to check version */
3101 if (status < (1)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003102 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_EMPTY);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003103 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
3104 status, "Discarding packet - too small\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003105 continue;
3106 }
jjako08d331d2003-10-13 20:33:30 +00003107
Harald Weltebed35df2011-11-02 13:06:18 +01003108 pheader = (struct gtp1_header_short *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00003109
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01003110 version = GTPHDR_F_GET_VER(pheader->flags);
3111
Harald Weltebed35df2011-11-02 13:06:18 +01003112 /* Version must be no larger than GTP 1 */
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01003113 if (version > 1) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003114 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Pau Espin Pedrola884a952018-01-25 17:28:11 +01003115 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
3116 "Unsupported GTP version %"PRIu8"\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01003117 gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
3118 /*29.60: 11.1.1 */
3119 continue;
3120 }
jjako08d331d2003-10-13 20:33:30 +00003121
Harald Weltebed35df2011-11-02 13:06:18 +01003122 /* Version must be at least GTP 1 */
3123 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
3124 /* GTP 1 messages. If GTP 0 message is received we silently discard */
3125 /* the message */
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01003126 if (version < 1) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003127 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Pau Espin Pedrola884a952018-01-25 17:28:11 +01003128 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
3129 "Unsupported GTP version %"PRIu8"\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01003130 continue;
3131 }
jjako08d331d2003-10-13 20:33:30 +00003132
Harald Weltebed35df2011-11-02 13:06:18 +01003133 /* Check packet flag field */
3134 if (((pheader->flags & 0xf7) != 0x32)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003135 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003136 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Welted37b80a2016-12-15 18:33:15 +01003137 status, "Unsupported packet flags: 0x%02x\n", pheader->flags);
Harald Weltebed35df2011-11-02 13:06:18 +01003138 continue;
3139 }
jjako2c381332003-10-21 19:09:53 +00003140
Harald Weltebed35df2011-11-02 13:06:18 +01003141 /* Check length of packet */
3142 if (status < GTP1_HEADER_SIZE_LONG) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003143 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003144 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
3145 status, "GTP packet too short\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003146 continue; /* Silently discard 29.60: 11.1.2 */
3147 }
jjako2c381332003-10-21 19:09:53 +00003148
Harald Weltebed35df2011-11-02 13:06:18 +01003149 /* Check packet length field versus length of packet */
3150 if (status !=
3151 (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003152 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003153 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01003154 status,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003155 "GTP packet length field does not match actual length\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003156 continue; /* Silently discard */
3157 }
jjako1db1c812003-07-06 20:53:57 +00003158
Harald Weltebed35df2011-11-02 13:06:18 +01003159 /* Check for extension headers */
3160 /* TODO: We really should cycle through the headers and determine */
3161 /* if any have the comprehension required flag set */
Harald Weltefed598f2017-09-24 16:39:22 +08003162 if (((pheader->flags & GTP1HDR_F_EXT) != 0x00)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003163 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003164 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
3165 status, "Unsupported extension header\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003166 gtp_extheader_req(gsn, version, &peer, fd, buffer,
3167 status);
jjako1db1c812003-07-06 20:53:57 +00003168
Harald Weltebed35df2011-11-02 13:06:18 +01003169 continue;
3170 }
3171
3172 if ((gsn->mode == GTP_MODE_GGSN) &&
3173 ((pheader->type == GTP_CREATE_PDP_RSP) ||
Pau Espin Pedrola32e4c42018-07-13 19:05:00 +02003174 (pheader->type == GTP_UPDATE_PDP_RSP))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003175 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNEXPECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003176 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01003177 status,
Pau Espin Pedrol3b84e922018-07-13 18:32:35 +02003178 "Unexpected GTPv1 Signalling Message '%s'\n",
3179 get_value_string(gtp_type_names, pheader->type));
Harald Weltebed35df2011-11-02 13:06:18 +01003180 continue; /* Silently discard 29.60: 11.1.4 */
3181 }
3182
3183 if ((gsn->mode == GTP_MODE_SGSN) &&
3184 ((pheader->type == GTP_CREATE_PDP_REQ) ||
Pau Espin Pedrola32e4c42018-07-13 19:05:00 +02003185 (pheader->type == GTP_UPDATE_PDP_REQ))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003186 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNEXPECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003187 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01003188 status,
Pau Espin Pedrol3b84e922018-07-13 18:32:35 +02003189 "Unexpected GTPv1 Signalling Message '%s'\n",
3190 get_value_string(gtp_type_names, pheader->type));
Harald Weltebed35df2011-11-02 13:06:18 +01003191 continue; /* Silently discard 29.60: 11.1.4 */
3192 }
3193
3194 switch (pheader->type) {
3195 case GTP_ECHO_REQ:
3196 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
3197 break;
3198 case GTP_ECHO_RSP:
3199 gtp_echo_conf(gsn, version, &peer, buffer, status);
3200 break;
3201 case GTP_NOT_SUPPORTED:
3202 gtp_unsup_ind(gsn, &peer, buffer, status);
3203 break;
3204 case GTP_SUPP_EXT_HEADER:
3205 gtp_extheader_ind(gsn, &peer, buffer, status);
3206 break;
3207 case GTP_CREATE_PDP_REQ:
3208 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer,
3209 status);
3210 break;
3211 case GTP_CREATE_PDP_RSP:
3212 gtp_create_pdp_conf(gsn, version, &peer, buffer,
3213 status);
3214 break;
3215 case GTP_UPDATE_PDP_REQ:
3216 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer,
3217 status);
3218 break;
3219 case GTP_UPDATE_PDP_RSP:
3220 gtp_update_pdp_conf(gsn, version, &peer, buffer,
3221 status);
3222 break;
3223 case GTP_DELETE_PDP_REQ:
3224 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer,
3225 status);
3226 break;
3227 case GTP_DELETE_PDP_RSP:
3228 gtp_delete_pdp_conf(gsn, version, &peer, buffer,
3229 status);
3230 break;
3231 case GTP_ERROR:
3232 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
3233 break;
Pau Espin Pedrolf32c6a92021-05-03 17:58:55 +02003234 case GTP_RAN_INFO_RELAY:
3235 gtp_ran_info_relay_ind(gsn, version, &peer, buffer, status);
3236 break;
Daniel Willmann65363762024-01-26 16:36:20 +01003237 case GTP_SGSN_CONTEXT_REQ:
3238 gtp_sgsn_context_ind(gsn, version, &peer, buffer, status);
3239 break;
3240 case GTP_SGSN_CONTEXT_RSP:
3241 gtp_sgsn_context_conf_ind(gsn, version, &peer, buffer, status);
3242 break;
3243 case GTP_SGSN_CONTEXT_ACK:
3244 gtp_sgsn_context_ack(gsn, version, &peer, buffer, status);
3245 break;
Harald Weltebed35df2011-11-02 13:06:18 +01003246 default:
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003247 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNKNOWN);
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01003248 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
3249 "Unknown GTP message type received: %u\n",
3250 pheader->type);
Harald Weltebed35df2011-11-02 13:06:18 +01003251 break;
3252 }
3253 }
jjako52c24142002-12-16 13:33:51 +00003254}
3255
jjako08d331d2003-10-13 20:33:30 +00003256int gtp_decaps1u(struct gsn_t *gsn)
3257{
Harald Weltebed35df2011-11-02 13:06:18 +01003258 unsigned char buffer[PACKET_MAX];
3259 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01003260 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01003261 int status;
3262 struct gtp1_header_short *pheader;
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01003263 uint8_t version;
Harald Weltebed35df2011-11-02 13:06:18 +01003264 int fd = gsn->fd1u;
jjako08d331d2003-10-13 20:33:30 +00003265
Harald Weltebed35df2011-11-02 13:06:18 +01003266 /* TODO: Need strategy of userspace buffering and blocking */
3267 /* Currently read is non-blocking and send is blocking. */
3268 /* This means that the program have to wait for busy send calls... */
jjako08d331d2003-10-13 20:33:30 +00003269
Harald Weltebed35df2011-11-02 13:06:18 +01003270 while (1) { /* Loop until no more to read */
3271 if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003272 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003273 return -1;
3274 }
3275 peerlen = sizeof(peer);
3276 if ((status =
3277 recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0,
3278 (struct sockaddr *)&peer, &peerlen)) < 0) {
3279 if (errno == EAGAIN)
3280 return 0;
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003281 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_READFROM);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003282 LOGP(DLGTP, LOGL_ERROR,
Alexander Huemerdb852a12015-11-06 20:59:01 +01003283 "recvfrom(fd1u=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n",
Harald Weltebed35df2011-11-02 13:06:18 +01003284 gsn->fd1u, (unsigned long)buffer,
3285 sizeof(buffer), status,
3286 status ? strerror(errno) : "No error");
3287 return -1;
3288 }
jjako08d331d2003-10-13 20:33:30 +00003289
Harald Weltebed35df2011-11-02 13:06:18 +01003290 /* Need at least 1 byte in order to check version */
3291 if (status < (1)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003292 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_EMPTY);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003293 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
3294 status, "Discarding packet - too small\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003295 continue;
3296 }
jjako08d331d2003-10-13 20:33:30 +00003297
Harald Weltebed35df2011-11-02 13:06:18 +01003298 pheader = (struct gtp1_header_short *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00003299
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01003300 version = GTPHDR_F_GET_VER(pheader->flags);
3301
Harald Weltebed35df2011-11-02 13:06:18 +01003302 /* Version must be no larger than GTP 1 */
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01003303 if (version > 1) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003304 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Pau Espin Pedrola884a952018-01-25 17:28:11 +01003305 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
3306 "Unsupported GTP version %"PRIu8"\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01003307 gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status); /*29.60: 11.1.1 */
3308 continue;
3309 }
jjako08d331d2003-10-13 20:33:30 +00003310
Harald Weltebed35df2011-11-02 13:06:18 +01003311 /* Version must be at least GTP 1 */
3312 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
3313 /* GTP 1 messages. If GTP 0 message is received we silently discard */
3314 /* the message */
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01003315 if (version < 1) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003316 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Pau Espin Pedrola884a952018-01-25 17:28:11 +01003317 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
3318 "Unsupported GTP version %"PRIu8"\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01003319 continue;
3320 }
jjako2c381332003-10-21 19:09:53 +00003321
Harald Weltebed35df2011-11-02 13:06:18 +01003322 /* Check packet flag field (allow both with and without sequence number) */
3323 if (((pheader->flags & 0xf5) != 0x30)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003324 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003325 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Welted37b80a2016-12-15 18:33:15 +01003326 status, "Unsupported packet flags 0x%02x\n", pheader->flags);
Harald Weltebed35df2011-11-02 13:06:18 +01003327 continue;
3328 }
jjako2c381332003-10-21 19:09:53 +00003329
Harald Weltebed35df2011-11-02 13:06:18 +01003330 /* Check length of packet */
3331 if (status < GTP1_HEADER_SIZE_SHORT) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003332 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003333 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
3334 status, "GTP packet too short\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003335 continue; /* Silently discard 29.60: 11.1.2 */
3336 }
3337
3338 /* Check packet length field versus length of packet */
3339 if (status !=
3340 (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003341 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003342 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01003343 status,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003344 "GTP packet length field does not match actual length\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003345 continue; /* Silently discard */
3346 }
3347
3348 /* Check for extension headers */
3349 /* TODO: We really should cycle through the headers and determine */
3350 /* if any have the comprehension required flag set */
Harald Weltefed598f2017-09-24 16:39:22 +08003351 if (((pheader->flags & GTP1HDR_F_EXT) != 0x00)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003352 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003353 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
3354 status, "Unsupported extension header\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003355 gtp_extheader_req(gsn, version, &peer, fd, buffer,
3356 status);
3357
3358 continue;
3359 }
3360
3361 switch (pheader->type) {
3362 case GTP_ECHO_REQ:
3363 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
3364 break;
3365 case GTP_ECHO_RSP:
3366 gtp_echo_conf(gsn, version, &peer, buffer, status);
3367 break;
3368 case GTP_SUPP_EXT_HEADER:
3369 gtp_extheader_ind(gsn, &peer, buffer, status);
3370 break;
3371 case GTP_ERROR:
3372 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
3373 break;
3374 /* Supported header extensions */
3375 case GTP_GPDU:
3376 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
3377 break;
3378 default:
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003379 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNKNOWN);
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01003380 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
3381 "Unknown GTP message type received: %u\n",
3382 pheader->type);
Harald Weltebed35df2011-11-02 13:06:18 +01003383 break;
3384 }
3385 }
jjako08d331d2003-10-13 20:33:30 +00003386}
3387
Harald Weltebed35df2011-11-02 13:06:18 +01003388int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +00003389{
Harald Weltebed35df2011-11-02 13:06:18 +01003390 union gtp_packet packet;
3391 struct sockaddr_in addr;
Harald Welte471e3492017-09-24 16:12:39 +08003392 struct msghdr msgh;
3393 struct iovec iov[2];
Harald Weltebed35df2011-11-02 13:06:18 +01003394 int fd;
jjako52c24142002-12-16 13:33:51 +00003395
Harald Welte471e3492017-09-24 16:12:39 +08003396 /* prepare destination address */
Harald Weltebed35df2011-11-02 13:06:18 +01003397 memset(&addr, 0, sizeof(addr));
3398 addr.sin_family = AF_INET;
jjako0fe0df02004-09-17 11:30:40 +00003399#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +01003400 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +00003401#endif
Harald Weltebed35df2011-11-02 13:06:18 +01003402 memcpy(&addr.sin_addr, pdp->gsnru.v, pdp->gsnru.l); /* TODO range check */
jjako52c24142002-12-16 13:33:51 +00003403
Harald Welte471e3492017-09-24 16:12:39 +08003404 /* prepare msghdr */
3405 memset(&msgh, 0, sizeof(msgh));
3406 msgh.msg_name = &addr;
3407 msgh.msg_namelen = sizeof(addr);
3408 msgh.msg_iov = iov;
3409 msgh.msg_iovlen = ARRAY_SIZE(iov);
3410
3411 /* prepare iovectors */
3412 iov[0].iov_base = &packet;
3413 /* iov[0].iov_len is not known here yet */
3414 iov[1].iov_base = pack;
3415 iov[1].iov_len = len;
3416
Harald Weltebed35df2011-11-02 13:06:18 +01003417 if (pdp->version == 0) {
jjako52c24142002-12-16 13:33:51 +00003418
Harald Welte471e3492017-09-24 16:12:39 +08003419 iov[0].iov_len = GTP0_HEADER_SIZE;
Harald Weltebed35df2011-11-02 13:06:18 +01003420 addr.sin_port = htons(GTP0_PORT);
3421 fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00003422
Harald Weltebed35df2011-11-02 13:06:18 +01003423 get_default_gtp(0, GTP_GPDU, &packet);
3424 packet.gtp0.h.length = hton16(len);
Harald Welte3c1cce22017-09-24 16:40:12 +08003425 if (pdp->tx_gpdu_seq)
3426 packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
3427 else
3428 packet.gtp0.h.seq = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01003429 packet.gtp0.h.flow = hton16(pdp->flru);
Pablo Neira Ayuso746b9442014-03-24 17:58:27 +01003430 packet.gtp0.h.tid = htobe64(pdp_gettid(pdp->imsi, pdp->nsapi));
Harald Weltebed35df2011-11-02 13:06:18 +01003431 } else if (pdp->version == 1) {
jjako08d331d2003-10-13 20:33:30 +00003432
Harald Weltebed35df2011-11-02 13:06:18 +01003433 addr.sin_port = htons(GTP1U_PORT);
3434 fd = gsn->fd1u;
jjakoa7cd2492003-04-11 09:40:12 +00003435
Harald Weltebed35df2011-11-02 13:06:18 +01003436 get_default_gtp(1, GTP_GPDU, &packet);
Harald Welte3c1cce22017-09-24 16:40:12 +08003437 if (pdp->tx_gpdu_seq) {
3438 packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
3439 packet.gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT +
3440 GTP1_HEADER_SIZE_LONG);
3441 packet.gtp1l.h.tei = hton32(pdp->teid_gn);
3442 iov[0].iov_len = GTP1_HEADER_SIZE_LONG;
3443 } else {
3444 packet.gtp1s.h.flags &= ~GTP1HDR_F_SEQ;
3445 packet.gtp1s.h.length = hton16(len);
3446 packet.gtp1s.h.tei = hton32(pdp->teid_gn);
3447 iov[0].iov_len = GTP1_HEADER_SIZE_SHORT;
3448 }
Harald Weltebed35df2011-11-02 13:06:18 +01003449 } else {
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01003450 LOGP(DLGTP, LOGL_ERROR, "Unknown version: %d\n", pdp->version);
Harald Weltebed35df2011-11-02 13:06:18 +01003451 return EOF;
3452 }
3453
3454 if (fcntl(fd, F_SETFL, 0)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003455 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003456 return -1;
3457 }
3458
Harald Welte471e3492017-09-24 16:12:39 +08003459 if (sendmsg(fd, &msgh, 0) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003460 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003461 LOGP(DLGTP, LOGL_ERROR,
Harald Welte471e3492017-09-24 16:12:39 +08003462 "sendmsg(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd,
Harald Weltebed35df2011-11-02 13:06:18 +01003463 (unsigned long)&packet, GTP0_HEADER_SIZE + len,
3464 strerror(errno));
3465 return EOF;
3466 }
3467 return 0;
jjako52c24142002-12-16 13:33:51 +00003468}
3469
jjako52c24142002-12-16 13:33:51 +00003470/* ***********************************************************
3471 * Conversion functions
3472 *************************************************************/
3473
jjako52c24142002-12-16 13:33:51 +00003474/* ***********************************************************
3475 * IP address conversion functions
3476 * There exist several types of address representations:
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01003477 * - eua: End User Address. (29.060, 7.7.27, message type 128)
jjako52c24142002-12-16 13:33:51 +00003478 * Used for signalling address to mobile station. Supports IPv4
3479 * IPv6 x.25 etc. etc.
3480 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
3481 * of GSN. If length is 4 it is IPv4. If length is 16 it is IPv6.
3482 * - in_addr: IPv4 address struct.
3483 * - sockaddr_in: Socket API representation of IP address and
3484 * port number.
3485 *************************************************************/
3486
Harald Weltebed35df2011-11-02 13:06:18 +01003487int ipv42eua(struct ul66_t *eua, struct in_addr *src)
3488{
Harald Weltecee75462017-09-24 17:45:05 +08003489 eua->v[0] = PDP_EUA_ORG_IETF;
3490 eua->v[1] = PDP_EUA_TYPE_v4;
Harald Weltebed35df2011-11-02 13:06:18 +01003491 if (src) {
3492 eua->l = 6;
3493 memcpy(&eua->v[2], src, 4);
3494 } else {
3495 eua->l = 2;
3496 }
3497 return 0;
jjako52c24142002-12-16 13:33:51 +00003498}
3499
Harald Weltebed35df2011-11-02 13:06:18 +01003500int eua2ipv4(struct in_addr *dst, struct ul66_t *eua)
3501{
Harald Weltecee75462017-09-24 17:45:05 +08003502 if ((eua->l != 6) || (eua->v[0] != PDP_EUA_ORG_IETF) || (eua->v[1] != PDP_EUA_TYPE_v4))
Harald Weltebed35df2011-11-02 13:06:18 +01003503 return -1; /* Not IPv4 address */
3504 memcpy(dst, &eua->v[2], 4);
3505 return 0;
jjako52c24142002-12-16 13:33:51 +00003506}
3507
Harald Weltebed35df2011-11-02 13:06:18 +01003508int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna)
3509{
3510 memset(dst, 0, sizeof(struct in_addr));
3511 if (gsna->l != 4)
3512 return EOF; /* Return if not IPv4 */
3513 memcpy(dst, gsna->v, gsna->l);
3514 return 0;
jjako52c24142002-12-16 13:33:51 +00003515}
3516
Harald Weltebed35df2011-11-02 13:06:18 +01003517int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src)
3518{
3519 memset(gsna, 0, sizeof(struct ul16_t));
3520 gsna->l = 4;
3521 memcpy(gsna->v, src, gsna->l);
3522 return 0;
jjako52c24142002-12-16 13:33:51 +00003523}
Harald Welteb10ee082017-08-12 19:29:16 +02003524
3525/* TS 29.060 has yet again a different encoding for IMSIs than
3526 * what we have in other places, so we cannot use the gsm48
3527 * decoding functions. Also, libgtp uses an uint64_t in
3528 * _network byte order_ to contain BCD digits ?!? */
3529const char *imsi_gtp2str(const uint64_t *imsi)
3530{
Harald Weltea06120d2017-11-06 03:12:54 +09003531 static char buf[sizeof(*imsi)*2+1];
Harald Welteb10ee082017-08-12 19:29:16 +02003532 const uint8_t *imsi8 = (const uint8_t *) imsi;
3533 unsigned int i, j = 0;
3534
3535 for (i = 0; i < sizeof(*imsi); i++) {
3536 uint8_t nibble;
3537
3538 nibble = imsi8[i] & 0xf;
3539 if (nibble == 0xf)
3540 break;
3541 buf[j++] = osmo_bcd2char(nibble);
3542
3543 nibble = imsi8[i] >> 4;
3544 if (nibble == 0xf)
3545 break;
3546 buf[j++] = osmo_bcd2char(nibble);
3547 }
3548
3549 buf[j++] = '\0';
3550 return buf;
3551}
Keithcbc07bd2020-10-10 12:17:26 +02003552
Keithfb2a7292020-10-12 15:32:07 +02003553/* Generate the GTP IMSI IE according to 09.60 Section 7.9.2 */
3554uint64_t gtp_imsi_str2gtp(const char *str)
Keithcbc07bd2020-10-10 12:17:26 +02003555{
Keithfb2a7292020-10-12 15:32:07 +02003556 uint64_t imsi64 = 0;
3557 unsigned int n;
3558 unsigned int imsi_len = strlen(str);
Keithcbc07bd2020-10-10 12:17:26 +02003559
Keithfb2a7292020-10-12 15:32:07 +02003560 if (imsi_len > 16) {
3561 LOGP(DLGTP, LOGL_NOTICE, "IMSI length > 16 not supported!\n");
3562 return 0;
3563 }
3564
3565 for (n = 0; n < 16; n++) {
3566 uint64_t val;
3567 if (n < imsi_len)
3568 val = (str[n]-'0') & 0xf;
3569 else
3570 val = 0xf;
3571 imsi64 |= (val << (n*4));
3572 }
3573 return imsi64;
3574}