blob: 1ebc6dc5377444be065603024a4b3346bfb2d39e [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>
28
Holger Hans Peter Freyther5816bcf2014-04-04 11:43:09 +020029#if defined(__FreeBSD__)
30#include <sys/endian.h>
31#endif
32
jjako0fe0df02004-09-17 11:30:40 +000033#include "../config.h"
34#ifdef HAVE_STDINT_H
35#include <stdint.h>
36#endif
jjako52c24142002-12-16 13:33:51 +000037
jjako52c24142002-12-16 13:33:51 +000038#include <stdio.h>
39#include <stdarg.h>
40#include <stdlib.h>
41#include <sys/time.h>
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <netinet/in.h>
45#include <arpa/inet.h>
46#include <sys/stat.h>
47#include <time.h>
48#include <unistd.h>
49#include <string.h>
50#include <errno.h>
51#include <fcntl.h>
Alexander Huemerdb852a12015-11-06 20:59:01 +010052#include <inttypes.h>
jjako52c24142002-12-16 13:33:51 +000053
54#include <arpa/inet.h>
55
jjakobae2cd42004-01-09 12:04:39 +000056/* #include <stdint.h> ISO C99 types */
jjako52c24142002-12-16 13:33:51 +000057
58#include "pdp.h"
59#include "gtp.h"
60#include "gtpie.h"
61#include "queue.h"
62
jjako1db1c812003-07-06 20:53:57 +000063/* Error reporting functions */
64
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +010065#define GTP_LOGPKG(pri, peer, pack, len, fmt, args...) \
66 logp2(DLGTP, pri, __FILE__, __LINE__, 0, \
67 "Packet from %s:%u, length: %d content: %s: " fmt, \
68 inet_ntoa((peer)->sin_addr), htons((peer)->sin_port), \
69 len, osmo_hexdump((const uint8_t *) pack, len), \
70 ##args);
jjako1db1c812003-07-06 20:53:57 +000071
Neels Hofmeyr9b097382015-10-12 14:00:19 +020072#define LOGP_WITH_ADDR(ss, level, addr, fmt, args...) \
73 LOGP(ss, level, "addr(%s:%d) " fmt, \
74 inet_ntoa((addr).sin_addr), htons((addr).sin_port), \
75 ##args);
76
jjako52c24142002-12-16 13:33:51 +000077/* API Functions */
78
Harald Weltebed35df2011-11-02 13:06:18 +010079const char *gtp_version()
jjako52c24142002-12-16 13:33:51 +000080{
Harald Weltebed35df2011-11-02 13:06:18 +010081 return VERSION;
jjako52c24142002-12-16 13:33:51 +000082}
83
Maxe6612772018-01-11 18:25:37 +010084const struct value_string gtp_type_names[] = {
85 { GTP_ECHO_REQ, "Echo Request" },
86 { GTP_ECHO_RSP, "Echo Response" },
87 { GTP_NOT_SUPPORTED, "Version Not Supported" },
88 { GTP_ALIVE_REQ, "Node Alive Request" },
89 { GTP_ALIVE_RSP, "Node Alive Response" },
90 { GTP_REDIR_REQ, "Redirection Request" },
91 { GTP_REDIR_RSP, "Redirection Response" },
92 { GTP_CREATE_PDP_REQ, "Create PDP Context Request" },
93 { GTP_CREATE_PDP_RSP, "Create PDP Context Response" },
94 { GTP_UPDATE_PDP_REQ, "Update PDP Context Request" },
95 { GTP_UPDATE_PDP_RSP, "Update PDP Context Response" },
96 { GTP_DELETE_PDP_REQ, "Delete PDP Context Request" },
97 { GTP_DELETE_PDP_RSP, "Delete PDP Context Response" },
98 { GTP_ERROR, "Error Indication" },
99 { GTP_PDU_NOT_REQ, "PDU Notification Request" },
100 { GTP_PDU_NOT_RSP, "PDU Notification Response" },
101 { GTP_PDU_NOT_REJ_REQ, "PDU Notification Reject Request" },
102 { GTP_PDU_NOT_REJ_RSP, "PDU Notification Reject Response" },
103 { GTP_SUPP_EXT_HEADER, "Supported Extension Headers Notification" },
104 { GTP_SND_ROUTE_REQ, "Send Routeing Information for GPRS Request" },
105 { GTP_SND_ROUTE_RSP, "Send Routeing Information for GPRS Response" },
106 { GTP_FAILURE_REQ, "Failure Report Request" },
107 { GTP_FAILURE_RSP, "Failure Report Response" },
108 { GTP_MS_PRESENT_REQ, "Note MS GPRS Present Request" },
109 { GTP_MS_PRESENT_RSP, "Note MS GPRS Present Response" },
110 { GTP_IDEN_REQ, "Identification Request" },
111 { GTP_IDEN_RSP, "Identification Response" },
112 { GTP_SGSN_CONTEXT_REQ,"SGSN Context Request" },
113 { GTP_SGSN_CONTEXT_RSP,"SGSN Context Response" },
114 { GTP_SGSN_CONTEXT_ACK,"SGSN Context Acknowledge" },
115 { GTP_FWD_RELOC_REQ, "Forward Relocation Request" },
116 { GTP_FWD_RELOC_RSP, "Forward Relocation Response" },
117 { GTP_FWD_RELOC_COMPL, "Forward Relocation Complete" },
118 { GTP_RELOC_CANCEL_REQ,"Relocation Cancel Request" },
119 { GTP_RELOC_CANCEL_RSP,"Relocation Cancel Response" },
120 { GTP_FWD_SRNS, "Forward SRNS Context" },
121 { GTP_FWD_RELOC_ACK, "Forward Relocation Complete Acknowledge" },
122 { GTP_FWD_SRNS_ACK, "Forward SRNS Context Acknowledge" },
123 { GTP_DATA_TRAN_REQ, "Data Record Transfer Request" },
124 { GTP_DATA_TRAN_RSP, "Data Record Transfer Response" },
125 { GTP_GPDU, "G-PDU" },
126 { 0, NULL }
127};
128
jjako52c24142002-12-16 13:33:51 +0000129
jjako52c24142002-12-16 13:33:51 +0000130
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +0200131static void emit_cb_recovery(struct gsn_t *gsn, struct sockaddr_in * peer,
132 struct pdp_t * pdp, uint8_t recovery)
133{
134 if (gsn->cb_recovery)
135 gsn->cb_recovery(peer, recovery);
136 if (gsn->cb_recovery2)
137 gsn->cb_recovery2(peer, pdp, recovery);
Pau Espin Pedrol5d8b2262019-08-22 15:00:00 +0200138 if (gsn->cb_recovery3)
139 gsn->cb_recovery3(gsn, peer, pdp, recovery);
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +0200140}
141
jjako08d331d2003-10-13 20:33:30 +0000142/**
143 * get_default_gtp()
144 * Generate a GPRS Tunneling Protocol signalling packet header, depending
145 * on GTP version and message type. pdp is used for teid/flow label.
146 * *packet must be allocated by the calling function, and be large enough
147 * to hold the packet header.
148 * returns the length of the header. 0 on error.
149 **/
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100150static unsigned int get_default_gtp(uint8_t version, uint8_t type, void *packet)
Harald Weltebed35df2011-11-02 13:06:18 +0100151{
152 struct gtp0_header *gtp0_default = (struct gtp0_header *)packet;
153 struct gtp1_header_long *gtp1_default =
154 (struct gtp1_header_long *)packet;
155 switch (version) {
156 case 0:
157 /* Initialise "standard" GTP0 header */
158 memset(gtp0_default, 0, sizeof(struct gtp0_header));
159 gtp0_default->flags = 0x1e;
160 gtp0_default->type = hton8(type);
161 gtp0_default->spare1 = 0xff;
162 gtp0_default->spare2 = 0xff;
163 gtp0_default->spare3 = 0xff;
164 gtp0_default->number = 0xff;
165 return GTP0_HEADER_SIZE;
166 case 1:
167 /* Initialise "standard" GTP1 header */
168 /* 29.060: 8.2: S=1 and PN=0 */
169 /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */
170 /* and Supported Extension Headers Notification, the S field shall be */
171 /* set to 1 */
172 /* Currently extension headers are not supported */
173 memset(gtp1_default, 0, sizeof(struct gtp1_header_long));
Harald Weltefed598f2017-09-24 16:39:22 +0800174 /* No extension, enable sequence, no N-PDU */
175 gtp1_default->flags = GTPHDR_F_VER(1) | GTP1HDR_F_GTP1 | GTP1HDR_F_SEQ;
Harald Weltebed35df2011-11-02 13:06:18 +0100176 gtp1_default->type = hton8(type);
177 return GTP1_HEADER_SIZE_LONG;
178 default:
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100179 LOGP(DLGTP, LOGL_ERROR,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +0100180 "Unknown GTP packet version: %d\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +0100181 return 0;
182 }
jjako52c24142002-12-16 13:33:51 +0000183}
184
jjako08d331d2003-10-13 20:33:30 +0000185/**
186 * get_seq()
187 * Get sequence number of a packet.
188 * Returns 0 on error
189 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100190static uint16_t get_seq(void *pack)
191{
192 union gtp_packet *packet = (union gtp_packet *)pack;
Harald Weltefed598f2017-09-24 16:39:22 +0800193 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
jjako08d331d2003-10-13 20:33:30 +0000194
Harald Weltefed598f2017-09-24 16:39:22 +0800195 if (ver == 0) {
Harald Weltebed35df2011-11-02 13:06:18 +0100196 return ntoh16(packet->gtp0.h.seq);
Harald Weltefed598f2017-09-24 16:39:22 +0800197 } else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
Harald Weltebed35df2011-11-02 13:06:18 +0100198 return ntoh16(packet->gtp1l.h.seq);
199 } else {
Harald Weltebed35df2011-11-02 13:06:18 +0100200 return 0;
201 }
jjako08d331d2003-10-13 20:33:30 +0000202}
203
204/**
205 * get_tid()
206 * Get tunnel identifier of a packet.
207 * Returns 0 on error
208 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100209static uint64_t get_tid(void *pack)
210{
211 union gtp_packet *packet = (union gtp_packet *)pack;
212
Harald Weltefed598f2017-09-24 16:39:22 +0800213 if (GTPHDR_F_GET_VER(packet->flags) == 0) { /* Version 0 */
Pablo Neira Ayuso1a1ba022014-03-20 12:35:26 +0100214 return be64toh(packet->gtp0.h.tid);
Harald Weltebed35df2011-11-02 13:06:18 +0100215 }
216 return 0;
jjako08d331d2003-10-13 20:33:30 +0000217}
218
219/**
220 * get_hlen()
221 * Get the header length of a packet.
222 * Returns 0 on error
223 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100224static uint16_t get_hlen(void *pack)
225{
226 union gtp_packet *packet = (union gtp_packet *)pack;
Harald Weltefed598f2017-09-24 16:39:22 +0800227 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
jjako08d331d2003-10-13 20:33:30 +0000228
Harald Weltefed598f2017-09-24 16:39:22 +0800229 if (ver == 0) { /* Version 0 */
Harald Weltebed35df2011-11-02 13:06:18 +0100230 return GTP0_HEADER_SIZE;
Harald Weltefed598f2017-09-24 16:39:22 +0800231 } else if (ver == 1 && (packet->flags & 0x07) == 0) { /* Short version 1 */
Harald Weltebed35df2011-11-02 13:06:18 +0100232 return GTP1_HEADER_SIZE_SHORT;
Harald Weltefed598f2017-09-24 16:39:22 +0800233 } else if (ver == 1) { /* Version 1 with seq/n-pdu/ext */
234 return GTP1_HEADER_SIZE_LONG;
Harald Weltebed35df2011-11-02 13:06:18 +0100235 } else {
Harald Welted37b80a2016-12-15 18:33:15 +0100236 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100237 return 0;
238 }
jjako08d331d2003-10-13 20:33:30 +0000239}
240
241/**
242 * get_tei()
243 * Get the tunnel endpoint identifier (flow label) of a packet.
244 * Returns 0xffffffff on error.
245 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100246static uint32_t get_tei(void *pack)
247{
248 union gtp_packet *packet = (union gtp_packet *)pack;
Harald Weltefed598f2017-09-24 16:39:22 +0800249 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
jjako08d331d2003-10-13 20:33:30 +0000250
Harald Weltefed598f2017-09-24 16:39:22 +0800251 if (ver == 0) { /* Version 0 */
Harald Weltebed35df2011-11-02 13:06:18 +0100252 return ntoh16(packet->gtp0.h.flow);
Harald Weltefed598f2017-09-24 16:39:22 +0800253 } else if (ver == 1) { /* Version 1 */
Harald Weltebed35df2011-11-02 13:06:18 +0100254 return ntoh32(packet->gtp1l.h.tei);
255 } else {
Harald Welted37b80a2016-12-15 18:33:15 +0100256 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100257 return 0xffffffff;
258 }
jjako08d331d2003-10-13 20:33:30 +0000259}
jjakoa7cd2492003-04-11 09:40:12 +0000260
jjako52c24142002-12-16 13:33:51 +0000261/* ***********************************************************
262 * Reliable delivery of signalling messages
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100263 *
jjako52c24142002-12-16 13:33:51 +0000264 * Sequence numbers are used for both signalling messages and
265 * data messages.
266 *
267 * For data messages each tunnel maintains a sequence counter,
268 * which is incremented by one each time a new data message
269 * is sent. The sequence number starts at (0) zero at tunnel
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100270 * establishment, and wraps around at 65535 (29.060 9.3.1.1
jjako52c24142002-12-16 13:33:51 +0000271 * and 09.60 8.1.1.1). The sequence numbers are either ignored,
272 * or can be used to check the validity of the message in the
273 * receiver, or for reordering af packets.
274 *
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100275 * For signalling messages the sequence number is used by
jjako52c24142002-12-16 13:33:51 +0000276 * signalling messages for which a response is defined. A response
277 * message should copy the sequence from the corresponding request
278 * message. The sequence number "unambiguously" identifies a request
279 * message within a given path, with a path being defined as a set of
280 * two endpoints (29.060 8.2, 29.060 7.6, 09.60 7.8). "All request
281 * messages shall be responded to, and all response messages associated
282 * with a certain request shall always include the same information"
283 *
284 * We take this to mean that the GSN transmitting a request is free to
285 * choose the sequence number, as long as it is unique within a given path.
286 * It means that we are allowed to count backwards, or roll over at 17
287 * if we prefer that. It also means that we can use the same counter for
288 * all paths. This has the advantage that the transmitted request sequence
289 * numbers are unique within each GSN, and also we dont have to mess around
290 * with path setup and teardown.
291 *
292 * If a response message is lost, the request will be retransmitted, and
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100293 * the receiving GSN will receive a "duplicated" request. The standard
jjako52c24142002-12-16 13:33:51 +0000294 * requires the receiving GSN to send a response, with the same information
295 * as in the original response. For most messages this happens automatically:
296 *
Pau Espin Pedrolde72d262019-05-29 18:17:05 +0200297 * Echo: Automatically duplicates the original response
jjako52c24142002-12-16 13:33:51 +0000298 * Create pdp context: The SGSN may send create context request even if
299 * a context allready exist (imsi+nsapi?). This means that the reply will
Pau Espin Pedrolde72d262019-05-29 18:17:05 +0200300 automatically duplicate the original response. It might however have
jjako08d331d2003-10-13 20:33:30 +0000301 * side effects in the application which is asked twice to validate
302 * the login.
Pau Espin Pedrolde72d262019-05-29 18:17:05 +0200303 * Update pdp context: Automatically duplicates the original response???
jjako52c24142002-12-16 13:33:51 +0000304 * Delete pdp context. Automatically in gtp0, but in gtp1 will generate
305 * a nonexist reply message.
306 *
307 * The correct solution will be to make a queue containing response messages.
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100308 * This queue should be checked whenever a request is received. If the
Pau Espin Pedrol0d3bd342022-11-02 13:22:17 +0100309 * response is already in the queue that response should be transmitted.
jjako52c24142002-12-16 13:33:51 +0000310 * It should be possible to find messages in this queue on the basis of
311 * the sequence number and peer GSN IP address (The sequense number is unique
312 * within each path). This need to be implemented by a hash table. Furthermore
313 * it should be possibly to delete messages based on a timeout. This can be
314 * achieved by means of a linked list. The timeout value need to be larger
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100315 * than T3-RESPONSE * N3-REQUESTS (recommended value 5). These timers are
jjako52c24142002-12-16 13:33:51 +0000316 * set in the peer GSN, so there is no way to know these parameters. On the
317 * other hand the timeout value need to be so small that we do not receive
318 * wraparound sequence numbere before the message is deleted. 60 seconds is
319 * probably not a bad choise.
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100320 *
jjako52c24142002-12-16 13:33:51 +0000321 * This queue however is first really needed from gtp1.
322 *
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100323 * gtp_req:
jjako52c24142002-12-16 13:33:51 +0000324 * Send off a signalling message with appropiate sequence
325 * number. Store packet in queue.
326 * gtp_conf:
327 * Remove an incoming confirmation from the queue
328 * gtp_resp:
jjako08d331d2003-10-13 20:33:30 +0000329 * Send off a response to a request. Use the same sequence
jjako52c24142002-12-16 13:33:51 +0000330 * number in the response as in the request.
jjako2c381332003-10-21 19:09:53 +0000331 * gtp_notification:
332 * Send off a notification message. This is neither a request nor
333 * a response. Both TEI and SEQ are zero.
jjako52c24142002-12-16 13:33:51 +0000334 * gtp_retrans:
335 * Retransmit any outstanding packets which have exceeded
336 * a predefined timeout.
337 *************************************************************/
338
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100339static int gtp_req(struct gsn_t *gsn, uint8_t version, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +0100340 union gtp_packet *packet, int len,
341 struct in_addr *inetaddr, void *cbp)
342{
Harald Weltefed598f2017-09-24 16:39:22 +0800343 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100344 struct sockaddr_in addr;
345 struct qmsg_t *qmsg;
346 int fd;
jjako08d331d2003-10-13 20:33:30 +0000347
Harald Weltebed35df2011-11-02 13:06:18 +0100348 memset(&addr, 0, sizeof(addr));
349 addr.sin_family = AF_INET;
350 addr.sin_addr = *inetaddr;
jjako0fe0df02004-09-17 11:30:40 +0000351#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100352 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +0000353#endif
jjako52c24142002-12-16 13:33:51 +0000354
Harald Weltefed598f2017-09-24 16:39:22 +0800355 if (ver == 0) { /* Version 0 */
Harald Weltebed35df2011-11-02 13:06:18 +0100356 addr.sin_port = htons(GTP0_PORT);
357 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
358 packet->gtp0.h.seq = hton16(gsn->seq_next);
Pablo Neira Ayuso1a1ba022014-03-20 12:35:26 +0100359 if (pdp) {
Harald Weltebed35df2011-11-02 13:06:18 +0100360 packet->gtp0.h.tid =
Pablo Neira Ayuso746b9442014-03-24 17:58:27 +0100361 htobe64(pdp_gettid(pdp->imsi, pdp->nsapi));
Pablo Neira Ayuso1a1ba022014-03-20 12:35:26 +0100362 }
Harald Weltebed35df2011-11-02 13:06:18 +0100363 if (pdp && ((packet->gtp0.h.type == GTP_GPDU)
364 || (packet->gtp0.h.type == GTP_ERROR)))
365 packet->gtp0.h.flow = hton16(pdp->flru);
366 else if (pdp)
367 packet->gtp0.h.flow = hton16(pdp->flrc);
368 fd = gsn->fd0;
Harald Weltefed598f2017-09-24 16:39:22 +0800369 } else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
Harald Weltebed35df2011-11-02 13:06:18 +0100370 addr.sin_port = htons(GTP1C_PORT);
371 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
372 packet->gtp1l.h.seq = hton16(gsn->seq_next);
373 if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) ||
374 (packet->gtp1l.h.type == GTP_ERROR)))
375 packet->gtp1l.h.tei = hton32(pdp->teid_gn);
376 else if (pdp)
377 packet->gtp1l.h.tei = hton32(pdp->teic_gn);
378 fd = gsn->fd1c;
379 } else {
Harald Welted37b80a2016-12-15 18:33:15 +0100380 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100381 return -1;
382 }
jjako52c24142002-12-16 13:33:51 +0000383
Harald Weltebed35df2011-11-02 13:06:18 +0100384 if (sendto(fd, packet, len, 0,
385 (struct sockaddr *)&addr, sizeof(addr)) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100386 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Max14b1b632017-08-21 20:14:59 +0200387 LOGP(DLGTP, LOGL_ERROR, "Sendto(fd=%d, msg=%lx, len=%d, dst=%s) failed: Error = %s\n", fd,
388 (unsigned long)&packet, len, inet_ntoa(addr.sin_addr), strerror(errno));
Harald Weltebed35df2011-11-02 13:06:18 +0100389 return -1;
390 }
391
392 /* Use new queue structure */
393 if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100394 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_QUEUEFULL);
Pau Espin Pedrolbdf06972022-03-07 12:49:34 +0100395 LOGP(DLGTP, LOGL_ERROR, "Retransmit req queue is full (seq=%" PRIu16 ")\n",
396 gsn->seq_next);
Harald Weltebed35df2011-11-02 13:06:18 +0100397 } else {
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100398 unsigned int t3_response;
Pau Espin Pedrolf4718002022-03-07 12:55:51 +0100399 LOGP(DLGTP, LOGL_DEBUG, "Registering seq=%" PRIu16
400 " in restransmit req queue\n", gsn->seq_next);
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100401 t3_response = osmo_tdef_get(gsn->tdef, GTP_GSN_TIMER_T3_RESPONSE, OSMO_TDEF_S, -1);
Harald Weltebed35df2011-11-02 13:06:18 +0100402 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
403 qmsg->l = len;
Pau Espin Pedrol9f1f7472022-11-02 19:52:19 +0100404 qmsg->timeout = time(NULL) + t3_response; /* When to timeout */
Harald Weltebed35df2011-11-02 13:06:18 +0100405 qmsg->retrans = 0; /* No retransmissions so far */
406 qmsg->cbp = cbp;
407 qmsg->type = ntoh8(packet->gtp0.h.type);
408 qmsg->fd = fd;
Pau Espin Pedrol623c5b32019-08-16 13:20:09 +0200409 if (pdp) /* echo requests are not pdp-bound */
410 llist_add(&qmsg->entry, &pdp->qmsg_list_req);
Pau Espin Pedrolc94837c2019-08-28 19:44:20 +0200411
412 /* Rearm timer: Retrans time for qmsg just queued may be required
413 before an existing one (for instance a gtp echo req) */
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100414 gtp_queue_timer_start(gsn);
Harald Weltebed35df2011-11-02 13:06:18 +0100415 }
416 gsn->seq_next++; /* Count up this time */
417 return 0;
jjako52c24142002-12-16 13:33:51 +0000418}
419
420/* gtp_conf
421 * Remove signalling packet from retransmission queue.
422 * return 0 on success, EOF if packet was not found */
423
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100424static int gtp_conf(struct gsn_t *gsn, uint8_t version, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +0100425 union gtp_packet *packet, int len, uint8_t * type, void **cbp)
426{
Harald Weltefed598f2017-09-24 16:39:22 +0800427 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100428 uint16_t seq;
jjako08d331d2003-10-13 20:33:30 +0000429
Harald Weltefed598f2017-09-24 16:39:22 +0800430 if (ver == 0)
Harald Weltebed35df2011-11-02 13:06:18 +0100431 seq = ntoh16(packet->gtp0.h.seq);
Harald Weltefed598f2017-09-24 16:39:22 +0800432 else if (ver == 1 && (packet->gtp1l.h.flags & GTP1HDR_F_SEQ))
Harald Weltebed35df2011-11-02 13:06:18 +0100433 seq = ntoh16(packet->gtp1l.h.seq);
434 else {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100435 GTP_LOGPKG(LOGL_ERROR, peer, packet, len,
436 "Unknown GTP packet version\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100437 return EOF;
438 }
jjako08d331d2003-10-13 20:33:30 +0000439
Pau Espin Pedrolf4718002022-03-07 12:55:51 +0100440 GTP_LOGPKG(LOGL_DEBUG, peer, packet, len,
441 "Freeing seq=%" PRIu16 " from retransmit req queue\n",
442 seq);
Harald Weltebed35df2011-11-02 13:06:18 +0100443 if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100444 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SEQ);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100445 GTP_LOGPKG(LOGL_ERROR, peer, packet, len,
Pau Espin Pedrolf4718002022-03-07 12:55:51 +0100446 "Confirmation packet not found in retransmit req queue (seq=%"
447 PRIu16 ")\n", seq);
Harald Weltebed35df2011-11-02 13:06:18 +0100448 return EOF;
449 }
jjako52c24142002-12-16 13:33:51 +0000450
Harald Weltebed35df2011-11-02 13:06:18 +0100451 return 0;
jjako52c24142002-12-16 13:33:51 +0000452}
453
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100454static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
jjako08d331d2003-10-13 20:33:30 +0000455 union gtp_packet *packet, int len,
Harald Weltebed35df2011-11-02 13:06:18 +0100456 struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
457{
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);
Harald Weltebed35df2011-11-02 13:06:18 +0100465 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
466 (packet->gtp0.h.type == GTP_ERROR)))
467 packet->gtp0.h.flow = hton16(pdp->flru);
468 else if (pdp)
469 packet->gtp0.h.flow = hton16(pdp->flrc);
Harald Weltefed598f2017-09-24 16:39:22 +0800470 } else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
Harald Weltebed35df2011-11-02 13:06:18 +0100471 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
472 packet->gtp1l.h.seq = hton16(seq);
473 if (pdp && (fd == gsn->fd1u))
474 packet->gtp1l.h.tei = hton32(pdp->teid_gn);
475 else if (pdp)
476 packet->gtp1l.h.tei = hton32(pdp->teic_gn);
477 } else {
Harald Welted37b80a2016-12-15 18:33:15 +0100478 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100479 return -1;
480 }
jjako08d331d2003-10-13 20:33:30 +0000481
Harald Weltebed35df2011-11-02 13:06:18 +0100482 if (fcntl(fd, F_SETFL, 0)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100483 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100484 return -1;
485 }
jjako52c24142002-12-16 13:33:51 +0000486
Harald Weltebed35df2011-11-02 13:06:18 +0100487 if (sendto(fd, packet, len, 0,
488 (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100489 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100490 LOGP(DLGTP, LOGL_ERROR,
491 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd,
Harald Weltebed35df2011-11-02 13:06:18 +0100492 (unsigned long)&packet, len, strerror(errno));
493 return -1;
494 }
495
496 /* Use new queue structure */
497 if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100498 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_QUEUEFULL);
Pau Espin Pedrolbdf06972022-03-07 12:49:34 +0100499 LOGP(DLGTP, LOGL_ERROR, "Retransmit resp queue is full (seq=%" PRIu16 ")\n",
500 seq);
Harald Weltebed35df2011-11-02 13:06:18 +0100501 } else {
Pau Espin Pedrol3a55b892022-11-04 11:21:23 +0100502 unsigned int t3_hold_resp;
Pau Espin Pedrolf4718002022-03-07 12:55:51 +0100503 LOGP(DLGTP, LOGL_DEBUG, "Registering seq=%" PRIu16
504 " in restransmit resp queue\n", seq);
Pau Espin Pedrol3a55b892022-11-04 11:21:23 +0100505 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 +0100506 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
507 qmsg->l = len;
Pau Espin Pedrol3a55b892022-11-04 11:21:23 +0100508 qmsg->timeout = time(NULL) + t3_hold_resp; /* When to timeout */
Harald Weltebed35df2011-11-02 13:06:18 +0100509 qmsg->retrans = 0; /* No retransmissions so far */
510 qmsg->cbp = NULL;
511 qmsg->type = 0;
512 qmsg->fd = fd;
Pau Espin Pedrol623c5b32019-08-16 13:20:09 +0200513 /* No need to add to pdp list here, because even on pdp ctx free
514 we want to leave messages in queue_resp until timeout to
515 detect duplicates */
Pau Espin Pedrolc94837c2019-08-28 19:44:20 +0200516
517 /* Rearm timer: Retrans time for qmsg just queued may be required
518 before an existing one (for instance a gtp echo req) */
Pau Espin Pedrol724ecc62022-11-02 14:57:24 +0100519 gtp_queue_timer_start(gsn);
Harald Weltebed35df2011-11-02 13:06:18 +0100520 }
521 return 0;
jjako52c24142002-12-16 13:33:51 +0000522}
523
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100524static int gtp_notification(struct gsn_t *gsn, uint8_t version,
jjako2c381332003-10-21 19:09:53 +0000525 union gtp_packet *packet, int len,
Pau Espin Pedrol2eed6ec2021-05-05 17:51:19 +0200526 const struct sockaddr_in *peer, int fd, uint16_t seq)
Harald Weltebed35df2011-11-02 13:06:18 +0100527{
jjako2c381332003-10-21 19:09:53 +0000528
Harald Weltefed598f2017-09-24 16:39:22 +0800529 uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100530 struct sockaddr_in addr;
jjako2c381332003-10-21 19:09:53 +0000531
Harald Weltebed35df2011-11-02 13:06:18 +0100532 memcpy(&addr, peer, sizeof(addr));
jjako2c381332003-10-21 19:09:53 +0000533
Harald Weltebed35df2011-11-02 13:06:18 +0100534 /* In GTP0 notifications are treated as replies. In GTP1 they
535 are requests for which there is no reply */
jjako2c381332003-10-21 19:09:53 +0000536
Harald Weltebed35df2011-11-02 13:06:18 +0100537 if (fd == gsn->fd1c)
538 addr.sin_port = htons(GTP1C_PORT);
539 else if (fd == gsn->fd1u)
540 addr.sin_port = htons(GTP1C_PORT);
jjako2c381332003-10-21 19:09:53 +0000541
Harald Weltefed598f2017-09-24 16:39:22 +0800542 if (ver == 0) { /* Version 0 */
Harald Weltebed35df2011-11-02 13:06:18 +0100543 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
544 packet->gtp0.h.seq = hton16(seq);
Harald Weltefed598f2017-09-24 16:39:22 +0800545 } else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
Harald Weltebed35df2011-11-02 13:06:18 +0100546 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
547 packet->gtp1l.h.seq = hton16(seq);
548 } else {
Harald Welted37b80a2016-12-15 18:33:15 +0100549 LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
Harald Weltebed35df2011-11-02 13:06:18 +0100550 return -1;
551 }
552
553 if (fcntl(fd, F_SETFL, 0)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100554 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100555 return -1;
556 }
557
558 if (sendto(fd, packet, len, 0,
559 (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100560 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100561 LOGP(DLGTP, LOGL_ERROR,
562 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd,
Harald Weltebed35df2011-11-02 13:06:18 +0100563 (unsigned long)&packet, len, strerror(errno));
564 return -1;
565 }
566 return 0;
jjako2c381332003-10-21 19:09:53 +0000567}
568
Pau Espin Pedrolde72d262019-05-29 18:17:05 +0200569static int gtp_duplicate(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +0100570 struct sockaddr_in *peer, uint16_t seq)
571{
572 struct qmsg_t *qmsg;
Pau Espin Pedrol1bf3b3d2022-03-07 12:19:24 +0100573 char buf[INET_ADDRSTRLEN];
jjako52c24142002-12-16 13:33:51 +0000574
Harald Weltebed35df2011-11-02 13:06:18 +0100575 if (queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) {
576 return EOF; /* Notfound */
577 }
jjakoa7cd2492003-04-11 09:40:12 +0000578
Pau Espin Pedrol1bf3b3d2022-03-07 12:19:24 +0100579
580 buf[0] = '\0';
581 inet_ntop(AF_INET, &peer->sin_addr, buf, sizeof(buf));
582 LOGP(DLGTP, LOGL_INFO,
583 "Rx duplicate seq=%" PRIu16 " from %s, retrans resp\n", seq, buf);
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100584 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_DUPLICATE);
Pau Espin Pedrol1bf3b3d2022-03-07 12:19:24 +0100585
Harald Weltebed35df2011-11-02 13:06:18 +0100586 if (fcntl(qmsg->fd, F_SETFL, 0)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100587 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100588 return -1;
589 }
590
591 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
592 (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100593 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100594 LOGP(DLGTP, LOGL_ERROR,
595 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n",
Harald Weltebed35df2011-11-02 13:06:18 +0100596 qmsg->fd, (unsigned long)&qmsg->p, qmsg->l,
597 strerror(errno));
598 }
599 return 0;
jjako52c24142002-12-16 13:33:51 +0000600}
601
jjako52c24142002-12-16 13:33:51 +0000602/* ***********************************************************
603 * Path management messages
604 * Messages: echo and version not supported.
605 * A path is connection between two UDP/IP endpoints
606 *
607 * A path is either using GTP0 or GTP1. A path can be
608 * established by any kind of GTP message??
609
610 * Which source port to use?
611 * GTP-C request destination port is 2123/3386
612 * GTP-U request destination port is 2152/3386
613 * T-PDU destination port is 2152/3386.
614 * For the above messages the source port is locally allocated.
615 * For response messages src=rx-dst and dst=rx-src.
616 * For simplicity we should probably use 2123+2152/3386 as
617 * src port even for the cases where src can be locally
618 * allocated. This also means that we have to listen only to
619 * the same ports.
620 * For response messages we need to be able to respond to
621 * the relevant src port even if it is locally allocated by
622 * the peer.
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100623 *
jjako52c24142002-12-16 13:33:51 +0000624 * The need for path management!
625 * We might need to keep a list of active paths. This might
626 * be in the form of remote IP address + UDP port numbers.
627 * (We will consider a path astablished if we have a context
628 * with the node in question)
629 *************************************************************/
630
631/* Send off an echo request */
jjako08d331d2003-10-13 20:33:30 +0000632int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
633 struct in_addr *inetaddr)
jjako52c24142002-12-16 13:33:51 +0000634{
Harald Weltebed35df2011-11-02 13:06:18 +0100635 union gtp_packet packet;
636 unsigned int length = get_default_gtp(version, GTP_ECHO_REQ, &packet);
637 return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp);
jjako52c24142002-12-16 13:33:51 +0000638}
639
jjako08d331d2003-10-13 20:33:30 +0000640/* Send off an echo reply */
641int gtp_echo_resp(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +0100642 struct sockaddr_in *peer, int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000643{
Harald Weltebed35df2011-11-02 13:06:18 +0100644 union gtp_packet packet;
645 unsigned int length = get_default_gtp(version, GTP_ECHO_RSP, &packet);
646 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
647 gsn->restart_counter);
648 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
649 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +0000650}
651
jjako52c24142002-12-16 13:33:51 +0000652/* Handle a received echo request */
Harald Weltebed35df2011-11-02 13:06:18 +0100653int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
654 int fd, void *pack, unsigned len)
655{
jjako52c24142002-12-16 13:33:51 +0000656
Pau Espin Pedrolde72d262019-05-29 18:17:05 +0200657 /* Check if it was a duplicate request */
658 if (!gtp_duplicate(gsn, 0, peer, get_seq(pack)))
Harald Weltebed35df2011-11-02 13:06:18 +0100659 return 0;
jjako52c24142002-12-16 13:33:51 +0000660
Harald Weltebed35df2011-11-02 13:06:18 +0100661 /* Send off reply to request */
662 return gtp_echo_resp(gsn, version, peer, fd, pack, len);
jjako52c24142002-12-16 13:33:51 +0000663}
664
665/* Handle a received echo reply */
jjako08d331d2003-10-13 20:33:30 +0000666int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +0100667 void *pack, unsigned len)
668{
669 union gtpie_member *ie[GTPIE_SIZE];
670 unsigned char recovery;
671 void *cbp = NULL;
672 uint8_t type = 0;
673 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +0000674
Harald Weltebed35df2011-11-02 13:06:18 +0100675 /* Remove packet from queue */
676 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
677 return EOF;
jjako52c24142002-12-16 13:33:51 +0000678
Harald Weltebed35df2011-11-02 13:06:18 +0100679 /* Extract information elements into a pointer array */
680 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100681 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100682 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
683 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100684 if (gsn->cb_conf)
685 gsn->cb_conf(type, EOF, NULL, cbp);
686 return EOF;
687 }
jjako52c24142002-12-16 13:33:51 +0000688
Harald Weltebed35df2011-11-02 13:06:18 +0100689 if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100690 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100691 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
692 "Missing mandatory field\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100693 if (gsn->cb_conf)
694 gsn->cb_conf(type, EOF, NULL, cbp);
695 return EOF;
696 }
jjako52c24142002-12-16 13:33:51 +0000697
Harald Weltebed35df2011-11-02 13:06:18 +0100698 /* Echo reply packages does not have a cause information element */
699 /* Instead we return the recovery number in the callback function */
700 if (gsn->cb_conf)
701 gsn->cb_conf(type, recovery, NULL, cbp);
Harald Welte629e9862010-12-24 20:58:09 +0100702
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +0200703 emit_cb_recovery(gsn, peer, NULL, recovery);
Harald Weltebed35df2011-11-02 13:06:18 +0100704
705 return 0;
jjako52c24142002-12-16 13:33:51 +0000706}
707
708/* Send off a Version Not Supported message */
709/* This message is somewhat special in that it actually is a
710 * response to some other message with unsupported GTP version
711 * For this reason it has parameters like a response, and does
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100712 * its own message transmission. No signalling queue is used
jjako52c24142002-12-16 13:33:51 +0000713 * The reply is sent to the peer IP and peer UDP. This means that
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100714 * the peer will be receiving a GTP0 message on a GTP1 port!
jjako52c24142002-12-16 13:33:51 +0000715 * In practice however this will never happen as a GTP0 GSN will
716 * only listen to the GTP0 port, and therefore will never receive
717 * anything else than GTP0 */
718
jjako08d331d2003-10-13 20:33:30 +0000719int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
720 int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000721{
Harald Weltebed35df2011-11-02 13:06:18 +0100722 union gtp_packet packet;
jjako52c24142002-12-16 13:33:51 +0000723
Harald Weltebed35df2011-11-02 13:06:18 +0100724 /* GTP 1 is the highest supported protocol */
725 unsigned int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet);
726 return gtp_notification(gsn, version, &packet, length, peer, fd, 0);
jjako52c24142002-12-16 13:33:51 +0000727}
728
729/* Handle a Version Not Supported message */
Harald Weltebed35df2011-11-02 13:06:18 +0100730int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
731 void *pack, unsigned len)
732{
jjako52c24142002-12-16 13:33:51 +0000733
Harald Weltebed35df2011-11-02 13:06:18 +0100734 if (gsn->cb_unsup_ind)
735 gsn->cb_unsup_ind(peer);
736
737 return 0;
jjako52c24142002-12-16 13:33:51 +0000738}
739
jjako2c381332003-10-21 19:09:53 +0000740/* Send off an Supported Extension Headers Notification */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +0100741static int gtp_extheader_req(struct gsn_t *gsn, uint8_t version, struct sockaddr_in *peer,
jjako2c381332003-10-21 19:09:53 +0000742 int fd, void *pack, unsigned len)
743{
Harald Weltebed35df2011-11-02 13:06:18 +0100744 union gtp_packet packet;
745 unsigned int length =
746 get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet);
jjako2c381332003-10-21 19:09:53 +0000747
Harald Weltebed35df2011-11-02 13:06:18 +0100748 uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU;
jjako2c381332003-10-21 19:09:53 +0000749
Harald Weltebed35df2011-11-02 13:06:18 +0100750 if (version < 1)
751 return 0;
jjako2c381332003-10-21 19:09:53 +0000752
Harald Weltebed35df2011-11-02 13:06:18 +0100753 /* We report back that we support only PDCP PDU headers */
754 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T,
755 sizeof(pdcp_pdu), &pdcp_pdu);
jjako2c381332003-10-21 19:09:53 +0000756
Harald Weltebed35df2011-11-02 13:06:18 +0100757 return gtp_notification(gsn, version, &packet, length,
758 peer, fd, get_seq(pack));
jjako2c381332003-10-21 19:09:53 +0000759}
760
761/* Handle a Supported Extension Headers Notification */
Pau Espin Pedrol7b38af52018-01-25 18:35:33 +0100762static int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +0100763 void *pack, unsigned len)
764{
jjako2c381332003-10-21 19:09:53 +0000765
Harald Weltebed35df2011-11-02 13:06:18 +0100766 if (gsn->cb_extheader_ind)
767 gsn->cb_extheader_ind(peer);
768
769 return 0;
jjako2c381332003-10-21 19:09:53 +0000770}
771
Pau Espin Pedrolf32c6a92021-05-03 17:58:55 +0200772/* Handle a RAN Information Relay message */
773static int gtp_ran_info_relay_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
774 void *pack, unsigned len)
775{
776 union gtpie_member *ie[GTPIE_SIZE];
777
778 if (version != 1) {
779 LOGP(DLGTP, LOGL_NOTICE,
780 "RAN Information Relay expected only on GTPCv1: %u\n", version);
781 return -EINVAL;
782 }
783
784 int hlen = get_hlen(pack);
785
786 /* Decode information elements */
787 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +0100788 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Pau Espin Pedrolf32c6a92021-05-03 17:58:55 +0200789 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
790 "Invalid message format (AN Information Relay)\n");
791 return -EINVAL;
792 }
793
794 if (gsn->cb_ran_info_relay_ind)
795 gsn->cb_ran_info_relay_ind(peer, ie);
796
797 return 0;
798}
799
800/* Send off a RAN Information Relay message */
801int gtp_ran_info_relay_req(struct gsn_t *gsn, const struct sockaddr_in *peer,
802 const uint8_t *ran_container, size_t ran_container_len,
803 const uint8_t *rim_route_addr, size_t rim_route_addr_len,
804 uint8_t rim_route_addr_discr)
805{
806 union gtp_packet packet;
807
808 /* GTP 1 is the highest supported protocol */
809 unsigned int length = get_default_gtp(1, GTP_RAN_INFO_RELAY, &packet);
810
811 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAN_T_CONTAIN, ran_container_len,
812 ran_container);
813 if (rim_route_addr) {
814 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RIM_ROUT_ADDR,
815 rim_route_addr_len, rim_route_addr);
816 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RIM_RA_DISCR, 1,
817 &rim_route_addr_discr);
818 }
819
820 return gtp_notification(gsn, 1, &packet, length, peer, gsn->fd1c, 0);
821}
822
jjako52c24142002-12-16 13:33:51 +0000823/* ***********************************************************
824 * Session management messages
825 * Messages: create, update and delete PDP context
826 *
827 * Information storage
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100828 * Information storage for each PDP context is defined in
jjako52c24142002-12-16 13:33:51 +0000829 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
830 * PDP-address (IP address), sequence numbers, charging ID.
831 * For the SGSN it also includes radio related mobility
832 * information.
833 *************************************************************/
834
Harald Welte7b3347b2010-05-15 12:18:46 +0200835/* API: Send Create PDP Context Request (7.3.1) */
Pau Espin Pedrol7b38af52018-01-25 18:35:33 +0100836int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +0100837 void *cbp)
838{
839 union gtp_packet packet;
840 unsigned int length =
841 get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet);
842 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +0000843
Harald Weltebed35df2011-11-02 13:06:18 +0100844 /* TODO: Secondary PDP Context Activation Procedure */
845 /* In secondary activation procedure the PDP context is identified
846 by tei in the header. The following fields are omitted: Selection
847 mode, IMSI, MSISDN, End User Address, Access Point Name and
848 Protocol Configuration Options */
jjako2c381332003-10-21 19:09:53 +0000849
Harald Weltebed35df2011-11-02 13:06:18 +0100850 if (pdp->secondary) {
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +0200851 if (gtp_pdp_getgtp1(gsn, &linked_pdp, pdp->teic_own)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +0100852 LOGP(DLGTP, LOGL_ERROR,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +0100853 "Unknown linked PDP context: %u\n", pdp->teic_own);
Harald Weltebed35df2011-11-02 13:06:18 +0100854 return EOF;
855 }
856 }
jjako2c381332003-10-21 19:09:53 +0000857
Harald Weltebed35df2011-11-02 13:06:18 +0100858 if (pdp->version == 0) {
859 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
860 sizeof(pdp->qos_req0), pdp->qos_req0);
861 }
jjako52c24142002-12-16 13:33:51 +0000862
Harald Weltebed35df2011-11-02 13:06:18 +0100863 /* Section 7.7.2 */
864 if (pdp->version == 1) {
865 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
866 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
867 sizeof(pdp->imsi), (uint8_t *) & pdp->imsi);
868 }
jjako52c24142002-12-16 13:33:51 +0000869
Harald Weltebed35df2011-11-02 13:06:18 +0100870 /* Section 7.7.3 Routing Area Information */
871 if (pdp->rai_given == 1)
872 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI,
873 pdp->rai.l, (uint8_t *) & pdp->rai.v);
Harald Welte41af5692011-10-07 18:42:34 +0200874
Harald Weltebed35df2011-11-02 13:06:18 +0100875 /* Section 7.7.11 */
876 if (pdp->norecovery_given == 0)
877 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
878 gsn->restart_counter);
Harald Welte41af5692011-10-07 18:42:34 +0200879
Harald Weltebed35df2011-11-02 13:06:18 +0100880 /* Section 7.7.12 */
881 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
882 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE,
883 pdp->selmode);
jjako2c381332003-10-21 19:09:53 +0000884
Harald Weltebed35df2011-11-02 13:06:18 +0100885 if (pdp->version == 0) {
886 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu);
887 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc);
888 }
jjako08d331d2003-10-13 20:33:30 +0000889
Harald Weltebed35df2011-11-02 13:06:18 +0100890 /* Section 7.7.13 */
891 if (pdp->version == 1) {
892 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
893 pdp->teid_own);
jjako08d331d2003-10-13 20:33:30 +0000894
Harald Weltebed35df2011-11-02 13:06:18 +0100895 /* Section 7.7.14 */
896 if (!pdp->teic_confirmed)
897 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
898 pdp->teic_own);
jjako2c381332003-10-21 19:09:53 +0000899
Harald Weltebed35df2011-11-02 13:06:18 +0100900 /* Section 7.7.17 */
901 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +0000902
Harald Weltebed35df2011-11-02 13:06:18 +0100903 /* Section 7.7.17 */
904 if (pdp->secondary) /* Secondary PDP Context Activation Procedure */
905 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
906 linked_pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +0000907
Harald Weltebed35df2011-11-02 13:06:18 +0100908 /* Section 7.7.23 */
909 if (pdp->cch_pdp) /* Only include charging if flags are set */
910 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C,
911 pdp->cch_pdp);
912 }
jjako9b4971d2004-05-27 20:30:19 +0000913
Pau Espin Pedrol732131d2018-01-25 17:23:09 +0100914 /* TODO
Harald Weltebed35df2011-11-02 13:06:18 +0100915 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
916 pdp->traceref);
917 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
918 pdp->tracetype); */
jjako08d331d2003-10-13 20:33:30 +0000919
Harald Weltebed35df2011-11-02 13:06:18 +0100920 /* Section 7.7.27 */
921 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
922 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
923 pdp->eua.l, pdp->eua.v);
jjako08d331d2003-10-13 20:33:30 +0000924
Harald Weltebed35df2011-11-02 13:06:18 +0100925 /* Section 7.7.30 */
926 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
927 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN,
928 pdp->apn_use.l, pdp->apn_use.v);
jjako08d331d2003-10-13 20:33:30 +0000929
Harald Weltebed35df2011-11-02 13:06:18 +0100930 /* Section 7.7.31 */
931 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
932 if (pdp->pco_req.l)
933 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
934 pdp->pco_req.l, pdp->pco_req.v);
jjako2c381332003-10-21 19:09:53 +0000935
Harald Weltebed35df2011-11-02 13:06:18 +0100936 /* Section 7.7.32 */
937 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
938 pdp->gsnlc.l, pdp->gsnlc.v);
939 /* Section 7.7.32 */
940 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
941 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +0000942
Harald Weltebed35df2011-11-02 13:06:18 +0100943 /* Section 7.7.33 */
944 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
945 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN,
946 pdp->msisdn.l, pdp->msisdn.v);
jjako08d331d2003-10-13 20:33:30 +0000947
Harald Weltebed35df2011-11-02 13:06:18 +0100948 /* Section 7.7.34 */
949 if (pdp->version == 1)
950 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
951 pdp->qos_req.l, pdp->qos_req.v);
jjako08d331d2003-10-13 20:33:30 +0000952
Harald Weltebed35df2011-11-02 13:06:18 +0100953 /* Section 7.7.36 */
954 if ((pdp->version == 1) && pdp->tft.l)
955 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
956 pdp->tft.l, pdp->tft.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200957
Harald Weltebed35df2011-11-02 13:06:18 +0100958 /* Section 7.7.41 */
959 if ((pdp->version == 1) && pdp->triggerid.l)
960 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
961 pdp->triggerid.l, pdp->triggerid.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200962
Harald Weltebed35df2011-11-02 13:06:18 +0100963 /* Section 7.7.42 */
964 if ((pdp->version == 1) && pdp->omcid.l)
965 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
966 pdp->omcid.l, pdp->omcid.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200967
Harald Weltebed35df2011-11-02 13:06:18 +0100968 /* new R7 fields */
969 if (pdp->rattype_given == 1)
970 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAT_TYPE,
971 pdp->rattype.l, pdp->rattype.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200972
Harald Weltebed35df2011-11-02 13:06:18 +0100973 if (pdp->userloc_given == 1)
974 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_USER_LOC,
975 pdp->userloc.l, pdp->userloc.v);
jjako52c24142002-12-16 13:33:51 +0000976
Harald Weltebed35df2011-11-02 13:06:18 +0100977 if (pdp->mstz_given == 1)
978 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MS_TZ,
979 pdp->mstz.l, pdp->mstz.v);
980
981 if (pdp->imeisv_given == 1)
982 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_IMEI_SV,
983 pdp->imeisv.l, pdp->imeisv.v);
984
985 /* TODO hisaddr0 */
986 gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
987
988 return 0;
jjako52c24142002-12-16 13:33:51 +0000989}
990
jjako08d331d2003-10-13 20:33:30 +0000991/* API: Application response to context indication */
Harald Weltebed35df2011-11-02 13:06:18 +0100992int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause)
993{
jjako08d331d2003-10-13 20:33:30 +0000994
Harald Weltebed35df2011-11-02 13:06:18 +0100995 /* Now send off a reply to the peer */
996 gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
997
Pau Espin Pedrold9501342019-08-21 15:24:29 +0200998 if (cause != GTPCAUSE_ACC_REQ)
999 gtp_freepdp(gsn, pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01001000
1001 return 0;
jjako08d331d2003-10-13 20:33:30 +00001002}
1003
jjako08d331d2003-10-13 20:33:30 +00001004/* Send Create PDP Context Response */
Harald Weltebed35df2011-11-02 13:06:18 +01001005int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
1006 uint8_t cause)
1007{
1008 union gtp_packet packet;
1009 unsigned int length =
1010 get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
jjako52c24142002-12-16 13:33:51 +00001011
Harald Weltebed35df2011-11-02 13:06:18 +01001012 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00001013
Harald Weltebed35df2011-11-02 13:06:18 +01001014 if (cause == GTPCAUSE_ACC_REQ) {
jjako08d331d2003-10-13 20:33:30 +00001015
Harald Weltebed35df2011-11-02 13:06:18 +01001016 if (version == 0)
1017 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1018 sizeof(pdp->qos_neg0), pdp->qos_neg0);
jjako08d331d2003-10-13 20:33:30 +00001019
Harald Weltebed35df2011-11-02 13:06:18 +01001020 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER,
1021 pdp->reorder);
1022 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1023 gsn->restart_counter);
jjako08d331d2003-10-13 20:33:30 +00001024
Harald Weltebed35df2011-11-02 13:06:18 +01001025 if (version == 0) {
1026 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1027 pdp->fllu);
1028 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1029 pdp->fllc);
1030 }
jjako08d331d2003-10-13 20:33:30 +00001031
Harald Weltebed35df2011-11-02 13:06:18 +01001032 if (version == 1) {
1033 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1034 pdp->teid_own);
1035 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1036 pdp->teic_own);
1037 }
jjako08d331d2003-10-13 20:33:30 +00001038
Harald Weltebed35df2011-11-02 13:06:18 +01001039 /* TODO: We use teic_own as charging ID */
1040 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
1041 pdp->teic_own);
jjako2c381332003-10-21 19:09:53 +00001042
Harald Weltebed35df2011-11-02 13:06:18 +01001043 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1044 pdp->eua.l, pdp->eua.v);
jjako52c24142002-12-16 13:33:51 +00001045
Harald Weltebed35df2011-11-02 13:06:18 +01001046 if (pdp->pco_neg.l) { /* Optional PCO */
1047 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1048 pdp->pco_neg.l, pdp->pco_neg.v);
1049 }
jjako52c24142002-12-16 13:33:51 +00001050
Harald Weltebed35df2011-11-02 13:06:18 +01001051 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1052 pdp->gsnlc.l, pdp->gsnlc.v);
1053 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1054 pdp->gsnlu.l, pdp->gsnlu.v);
jjako08d331d2003-10-13 20:33:30 +00001055
Harald Weltebed35df2011-11-02 13:06:18 +01001056 if (version == 1)
1057 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1058 pdp->qos_neg.l, pdp->qos_neg.v);
jjako08d331d2003-10-13 20:33:30 +00001059
Harald Weltebed35df2011-11-02 13:06:18 +01001060 /* TODO: Charging gateway address */
1061 }
jjako52c24142002-12-16 13:33:51 +00001062
Harald Weltebed35df2011-11-02 13:06:18 +01001063 return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer,
1064 pdp->fd, pdp->seq, pdp->tid);
jjako52c24142002-12-16 13:33:51 +00001065}
1066
1067/* Handle Create PDP Context Request */
1068int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01001069 struct sockaddr_in *peer, int fd,
1070 void *pack, unsigned len)
1071{
1072 struct pdp_t *pdp, *pdp_old;
1073 struct pdp_t pdp_buf;
1074 union gtpie_member *ie[GTPIE_SIZE];
1075 uint8_t recovery;
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001076 bool recovery_recvd = false;
1077 int rc;
jjako52c24142002-12-16 13:33:51 +00001078
Harald Weltebed35df2011-11-02 13:06:18 +01001079 uint16_t seq = get_seq(pack);
1080 int hlen = get_hlen(pack);
1081 uint8_t linked_nsapi = 0;
1082 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001083
Pau Espin Pedrolde72d262019-05-29 18:17:05 +02001084 if (!gtp_duplicate(gsn, version, peer, seq))
Harald Weltebed35df2011-11-02 13:06:18 +01001085 return 0;
jjako08d331d2003-10-13 20:33:30 +00001086
Harald Weltebed35df2011-11-02 13:06:18 +01001087 pdp = &pdp_buf;
1088 memset(pdp, 0, sizeof(struct pdp_t));
jjako08d331d2003-10-13 20:33:30 +00001089
Vadim Yanitskiy68c5a742019-08-30 21:04:19 +02001090 if (version == 0)
1091 pdp_set_imsi_nsapi(pdp, get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00001092
Harald Weltebed35df2011-11-02 13:06:18 +01001093 pdp->seq = seq;
1094 pdp->sa_peer = *peer;
1095 pdp->fd = fd;
1096 pdp->version = version;
jjako08d331d2003-10-13 20:33:30 +00001097
Harald Weltebed35df2011-11-02 13:06:18 +01001098 /* Decode information elements */
1099 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001100 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001101 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1102 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001103 if (0 == version)
1104 return EOF;
1105 else
1106 return gtp_create_pdp_resp(gsn, version, pdp,
1107 GTPCAUSE_INVALID_MESSAGE);
1108 }
jjako52c24142002-12-16 13:33:51 +00001109
Pau Espin Pedrolfb9303c2022-03-07 11:34:28 +01001110 switch (version) {
1111 case 1:
Harald Weltebed35df2011-11-02 13:06:18 +01001112 /* Linked NSAPI (conditional) */
1113 /* If included this is the Secondary PDP Context Activation Procedure */
1114 /* In secondary activation IMSI is not included, so the context must be */
1115 /* identified by the tei */
1116 if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) {
jjako2c381332003-10-21 19:09:53 +00001117
Harald Weltebed35df2011-11-02 13:06:18 +01001118 /* Find the primary PDP context */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02001119 if (gtp_pdp_getgtp1(gsn, &linked_pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001120 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INCORRECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001121 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001122 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001123 "Incorrect optional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001124 return gtp_create_pdp_resp(gsn, version, pdp,
1125 GTPCAUSE_OPT_IE_INCORRECT);
1126 }
jjako2c381332003-10-21 19:09:53 +00001127
Harald Weltebed35df2011-11-02 13:06:18 +01001128 /* Check that the primary PDP context matches linked nsapi */
1129 if (linked_pdp->nsapi != linked_nsapi) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001130 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INCORRECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001131 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001132 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001133 "Incorrect optional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001134 return gtp_create_pdp_resp(gsn, version, pdp,
1135 GTPCAUSE_OPT_IE_INCORRECT);
1136 }
jjako52c24142002-12-16 13:33:51 +00001137
Harald Weltebed35df2011-11-02 13:06:18 +01001138 /* Copy parameters from primary context */
1139 pdp->selmode = linked_pdp->selmode;
1140 pdp->imsi = linked_pdp->imsi;
1141 pdp->msisdn = linked_pdp->msisdn;
1142 pdp->eua = linked_pdp->eua;
1143 pdp->pco_req = linked_pdp->pco_req;
1144 pdp->apn_req = linked_pdp->apn_req;
1145 pdp->teic_gn = linked_pdp->teic_gn;
1146 pdp->secondary = 1;
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001147 } else {
1148 /* Not Secondary PDP Context Activation Procedure */
1149 /* IMSI (conditional): If the MS is emergency attached
1150 and the MS is UICCless, the IMSI cannot be included
1151 in the message and therefore IMSI shall not be
1152 included in the message. */
1153 if (gtpie_gettv0
1154 (ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001155 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001156 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1157 len, "Missing IMSI not supported\n");
1158 return gtp_create_pdp_resp(gsn, version, pdp,
1159 GTPCAUSE_MAN_IE_MISSING);
1160 }
1161 }
1162
1163 /* TEID (mandatory) */
1164 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001165 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001166 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1167 len, "Missing mandatory information field\n");
1168 return gtp_create_pdp_resp(gsn, version, pdp,
1169 GTPCAUSE_MAN_IE_MISSING);
1170 }
1171 /* TEIC (conditional) */
1172 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1173 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001174 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001175 GTP_LOGPKG(LOGL_ERROR, peer,
1176 pack, len,
1177 "Missing mandatory information field\n");
1178 return gtp_create_pdp_resp(gsn, version, pdp,
1179 GTPCAUSE_MAN_IE_MISSING);
1180 }
1181 }
1182 /* NSAPI (mandatory) */
1183 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001184 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001185 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1186 len, "Missing mandatory information field\n");
1187 return gtp_create_pdp_resp(gsn, version, pdp,
1188 GTPCAUSE_MAN_IE_MISSING);
1189 }
1190 /* QoS (mandatory) */
1191 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
1192 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001193 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001194 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1195 len, "Missing mandatory information field\n");
1196 return gtp_create_pdp_resp(gsn, version, pdp,
1197 GTPCAUSE_MAN_IE_MISSING);
1198 }
1199 /* TFT (conditional) */
1200 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
1201 &pdp->tft.v, sizeof(pdp->tft.v))) {
Harald Weltebed35df2011-11-02 13:06:18 +01001202 }
Pau Espin Pedrolfb9303c2022-03-07 11:34:28 +01001203 break; /* version 1 */
1204
1205 case 0:
Harald Weltebed35df2011-11-02 13:06:18 +01001206 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1207 pdp->qos_req0, sizeof(pdp->qos_req0))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001208 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001209 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1210 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001211 return gtp_create_pdp_resp(gsn, version, pdp,
1212 GTPCAUSE_MAN_IE_MISSING);
1213 }
Harald Weltebed35df2011-11-02 13:06:18 +01001214 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001215 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001216 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1217 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001218 return gtp_create_pdp_resp(gsn, version, pdp,
1219 GTPCAUSE_MAN_IE_MISSING);
1220 }
Harald Weltebed35df2011-11-02 13:06:18 +01001221 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001222 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001223 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1224 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001225 return gtp_create_pdp_resp(gsn, version, pdp,
1226 GTPCAUSE_MAN_IE_MISSING);
1227 }
Pau Espin Pedrolfb9303c2022-03-07 11:34:28 +01001228 break;
Harald Weltebed35df2011-11-02 13:06:18 +01001229 }
jjako08d331d2003-10-13 20:33:30 +00001230
Harald Weltebed35df2011-11-02 13:06:18 +01001231 /* SGSN address for signalling (mandatory) */
1232 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1233 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001234 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001235 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1236 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001237 return gtp_create_pdp_resp(gsn, version, pdp,
1238 GTPCAUSE_MAN_IE_MISSING);
1239 }
jjako2e840a32003-01-28 16:05:18 +00001240
Harald Weltebed35df2011-11-02 13:06:18 +01001241 /* SGSN address for user traffic (mandatory) */
1242 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1243 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001244 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001245 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1246 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001247 return gtp_create_pdp_resp(gsn, version, pdp,
1248 GTPCAUSE_MAN_IE_MISSING);
1249 }
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001250 /* Recovery (optional) */
1251 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1252 /* we use recovery futher down after announcing new pdp ctx to user */
1253 recovery_recvd = true;
1254 }
jjako52c24142002-12-16 13:33:51 +00001255
Harald Weltebed35df2011-11-02 13:06:18 +01001256 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001257 /* Selection mode (conditional) */
1258 if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0,
1259 &pdp->selmode, sizeof(pdp->selmode))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001260 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001261 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1262 len, "Missing mandatory information field\n");
1263 return gtp_create_pdp_resp(gsn, version, pdp,
1264 GTPCAUSE_MAN_IE_MISSING);
1265 }
1266 /* End User Address (conditional) */
1267 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1268 &pdp->eua.v, sizeof(pdp->eua.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001269 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001270 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1271 len, "Missing mandatory information field\n");
1272 return gtp_create_pdp_resp(gsn, version, pdp,
1273 GTPCAUSE_MAN_IE_MISSING);
1274 }
1275 /* APN */
1276 if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l,
1277 &pdp->apn_req.v, sizeof(pdp->apn_req.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001278 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001279 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1280 len, "Missing mandatory information field\n");
1281 return gtp_create_pdp_resp(gsn, version, pdp,
1282 GTPCAUSE_MAN_IE_MISSING);
1283 }
1284 /* Extract protocol configuration options (optional) */
1285 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1286 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1287 }
Harald Weltebed35df2011-11-02 13:06:18 +01001288 /* MSISDN (conditional) */
1289 if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l,
1290 &pdp->msisdn.v, sizeof(pdp->msisdn.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001291 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001292 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1293 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001294 return gtp_create_pdp_resp(gsn, version, pdp,
1295 GTPCAUSE_MAN_IE_MISSING);
1296 }
1297 }
jjako52c24142002-12-16 13:33:51 +00001298
Harald Weltebed35df2011-11-02 13:06:18 +01001299 /* Initialize our own IP addresses */
1300 in_addr2gsna(&pdp->gsnlc, &gsn->gsnc);
1301 in_addr2gsna(&pdp->gsnlu, &gsn->gsnu);
1302
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02001303 if (!gtp_pdp_getimsi(gsn, &pdp_old, pdp->imsi, pdp->nsapi)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001304 /* Found old pdp with same tid. Now the voodoo begins! */
1305 /* 09.60 / 29.060 allows create on existing context to "steal" */
1306 /* the context which was allready established */
1307 /* We check that the APN, selection mode and MSISDN is the same */
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01001308 DEBUGP(DLGTP, "gtp_create_pdp_ind: Old context found\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001309 if ((pdp->apn_req.l == pdp_old->apn_req.l)
1310 &&
1311 (!memcmp
1312 (pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l))
1313 && (pdp->selmode == pdp_old->selmode)
1314 && (pdp->msisdn.l == pdp_old->msisdn.l)
1315 &&
1316 (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l)))
1317 {
1318 /* OK! We are dealing with the same APN. We will copy new
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01001319 * parameters to the old pdp and send off confirmation
Harald Weltebed35df2011-11-02 13:06:18 +01001320 * We ignore the following information elements:
1321 * QoS: MS will get originally negotiated QoS.
1322 * End user address (EUA). MS will get old EUA anyway.
1323 * Protocol configuration option (PCO): Only application can verify */
Pau Espin Pedrol674a9122022-03-07 12:44:11 +01001324 DEBUGP(DLGTP, "gtp_create_pdp_ind: Reusing old context\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001325
1326 /* Copy remote flow label */
1327 pdp_old->flru = pdp->flru;
1328 pdp_old->flrc = pdp->flrc;
1329
1330 /* Copy remote tei */
1331 pdp_old->teid_gn = pdp->teid_gn;
1332 pdp_old->teic_gn = pdp->teic_gn;
1333
1334 /* Copy peer GSN address */
1335 pdp_old->gsnrc.l = pdp->gsnrc.l;
1336 memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l);
1337 pdp_old->gsnru.l = pdp->gsnru.l;
1338 memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l);
1339
1340 /* Copy request parameters */
1341 pdp_old->seq = pdp->seq;
1342 pdp_old->sa_peer = pdp->sa_peer;
1343 pdp_old->fd = pdp->fd = fd;
1344 pdp_old->version = pdp->version = version;
1345
1346 /* Switch to using the old pdp context */
1347 pdp = pdp_old;
1348
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001349 if (recovery_recvd)
1350 emit_cb_recovery(gsn, peer, pdp, recovery);
1351
Harald Weltebed35df2011-11-02 13:06:18 +01001352 /* Confirm to peer that things were "successful" */
1353 return gtp_create_pdp_resp(gsn, version, pdp,
1354 GTPCAUSE_ACC_REQ);
1355 } else { /* This is not the same PDP context. Delete the old one. */
1356
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01001357 DEBUGP(DLGTP, "gtp_create_pdp_ind: Deleting old context\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001358
Pau Espin Pedrol0d0b0592019-05-29 20:42:09 +02001359 gtp_freepdp(gsn, pdp_old);
Harald Weltebed35df2011-11-02 13:06:18 +01001360
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01001361 DEBUGP(DLGTP, "gtp_create_pdp_ind: Deleted...\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001362 }
1363 }
1364
Pau Espin Pedrol9b288b72022-02-28 13:58:51 +01001365 rc = gtp_pdp_newpdp(gsn, &pdp, pdp->imsi, pdp->nsapi, pdp);
1366 if (rc != 0) {
1367 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1368 "Failed creating a new PDP context, array full (%u)\n", PDP_MAX);
1369 /* &pdp in gtp_pdp_newpdp is untouched if it failed: */
1370 rc = gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_NO_MEMORY);
1371 /* Don't pass it to emit_cb_recovery, since allocation failed and it was already rejected: */
1372 pdp = NULL;
1373 goto recover_ret;
1374 }
Harald Weltebed35df2011-11-02 13:06:18 +01001375
Pau Espin Pedrolaad77a02019-05-30 12:44:20 +02001376 /* Callback function to validate login */
Harald Weltebed35df2011-11-02 13:06:18 +01001377 if (gsn->cb_create_context_ind != 0)
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001378 rc = gsn->cb_create_context_ind(pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01001379 else {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001380 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1381 "No create_context_ind callback defined\n");
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001382 rc = gtp_create_pdp_resp(gsn, version, pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001383 GTPCAUSE_NOT_SUPPORTED);
1384 }
Pau Espin Pedrol9b288b72022-02-28 13:58:51 +01001385
1386recover_ret:
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001387 if (recovery_recvd)
1388 emit_cb_recovery(gsn, peer, pdp, recovery);
1389 return rc;
jjako52c24142002-12-16 13:33:51 +00001390}
1391
jjako52c24142002-12-16 13:33:51 +00001392/* Handle Create PDP Context Response */
1393int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01001394 struct sockaddr_in *peer, void *pack, unsigned len)
1395{
1396 struct pdp_t *pdp;
1397 union gtpie_member *ie[GTPIE_SIZE];
1398 uint8_t cause, recovery;
1399 void *cbp = NULL;
1400 uint8_t type = 0;
1401 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001402
Harald Weltebed35df2011-11-02 13:06:18 +01001403 /* Remove packet from queue */
1404 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
1405 return EOF;
jjako52c24142002-12-16 13:33:51 +00001406
Harald Weltebed35df2011-11-02 13:06:18 +01001407 /* Find the context in question */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02001408 if (gtp_pdp_getgtp1(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001409 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001410 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01001411 "Unknown PDP context: %u\n", get_tei(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01001412 if (gsn->cb_conf)
1413 gsn->cb_conf(type, EOF, NULL, cbp);
1414 return EOF;
1415 }
jjako2c381332003-10-21 19:09:53 +00001416
Harald Weltebed35df2011-11-02 13:06:18 +01001417 /* Decode information elements */
1418 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001419 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001420 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1421 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001422 if (gsn->cb_conf)
1423 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001424 return EOF;
1425 }
jjako52c24142002-12-16 13:33:51 +00001426
Harald Weltebed35df2011-11-02 13:06:18 +01001427 /* Extract cause value (mandatory) */
1428 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001429 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001430 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1431 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001432 if (gsn->cb_conf)
1433 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001434 return EOF;
1435 }
jjako52c24142002-12-16 13:33:51 +00001436
Harald Weltebed35df2011-11-02 13:06:18 +01001437 /* Extract recovery (optional) */
1438 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001439 emit_cb_recovery(gsn, peer, pdp, recovery);
Harald Weltebed35df2011-11-02 13:06:18 +01001440 }
jjako52c24142002-12-16 13:33:51 +00001441
Harald Weltebed35df2011-11-02 13:06:18 +01001442 /* Extract protocol configuration options (optional) */
1443 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1444 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1445 }
jjako52c24142002-12-16 13:33:51 +00001446
Harald Weltebed35df2011-11-02 13:06:18 +01001447 /* Check all conditional information elements */
1448 if (GTPCAUSE_ACC_REQ == cause) {
jjako52c24142002-12-16 13:33:51 +00001449
Harald Weltebed35df2011-11-02 13:06:18 +01001450 if (version == 0) {
1451 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1452 &pdp->qos_neg0,
1453 sizeof(pdp->qos_neg0))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001454 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001455 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001456 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001457 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001458 if (gsn->cb_conf)
1459 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001460 return EOF;
1461 }
1462 }
jjako08d331d2003-10-13 20:33:30 +00001463
Harald Weltebed35df2011-11-02 13:06:18 +01001464 if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001465 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001466 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Harald Weltebed35df2011-11-02 13:06:18 +01001467 len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001468 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001469 if (gsn->cb_conf)
1470 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001471 return EOF;
1472 }
jjako52c24142002-12-16 13:33:51 +00001473
Harald Weltebed35df2011-11-02 13:06:18 +01001474 if (version == 0) {
1475 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001476 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001477 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001478 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001479 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001480 if (gsn->cb_conf)
1481 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001482 return EOF;
1483 }
jjako52c24142002-12-16 13:33:51 +00001484
Harald Weltebed35df2011-11-02 13:06:18 +01001485 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001486 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001487 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001488 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001489 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001490 if (gsn->cb_conf)
1491 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001492 return EOF;
1493 }
1494 }
1495
1496 if (version == 1) {
1497 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001498 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001499 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001500 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001501 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001502 if (gsn->cb_conf)
1503 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001504 return EOF;
1505 }
1506
1507 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001508 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001509 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001510 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001511 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001512 if (gsn->cb_conf)
1513 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001514 return EOF;
1515 }
Pau Espin Pedrol0b1d9db2021-04-21 19:45:23 +02001516 /* Register that we have received a valid teic from GGSN */
1517 pdp->teic_confirmed = 1;
Harald Weltebed35df2011-11-02 13:06:18 +01001518 }
1519
1520 if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001521 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001522 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Harald Weltebed35df2011-11-02 13:06:18 +01001523 len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001524 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001525 if (gsn->cb_conf)
1526 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001527 }
1528
1529 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1530 &pdp->eua.v, sizeof(pdp->eua.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001531 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001532 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Harald Weltebed35df2011-11-02 13:06:18 +01001533 len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001534 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001535 if (gsn->cb_conf)
1536 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001537 return EOF;
1538 }
1539
1540 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1541 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001542 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001543 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Harald Weltebed35df2011-11-02 13:06:18 +01001544 len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001545 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001546 if (gsn->cb_conf)
1547 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001548 return EOF;
1549 }
1550
1551 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1552 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001553 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001554 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Harald Weltebed35df2011-11-02 13:06:18 +01001555 len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001556 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001557 if (gsn->cb_conf)
1558 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001559 return EOF;
1560 }
1561
1562 if (version == 1) {
1563 if (gtpie_gettlv
1564 (ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
1565 &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001566 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001567 GTP_LOGPKG(LOGL_ERROR, peer,
Harald Weltebed35df2011-11-02 13:06:18 +01001568 pack, len,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001569 "Missing conditional information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001570 if (gsn->cb_conf)
1571 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001572 return EOF;
1573 }
1574 }
1575
1576 }
1577
1578 if (gsn->cb_conf)
1579 gsn->cb_conf(type, cause, pdp, cbp);
1580
1581 return 0;
jjako52c24142002-12-16 13:33:51 +00001582}
1583
jjako08d331d2003-10-13 20:33:30 +00001584/* API: Send Update PDP Context Request */
1585int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
Harald Weltebed35df2011-11-02 13:06:18 +01001586 struct in_addr *inetaddr)
1587{
1588 union gtp_packet packet;
1589 unsigned int length =
1590 get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet);
jjako52c24142002-12-16 13:33:51 +00001591
Harald Weltebed35df2011-11-02 13:06:18 +01001592 if (pdp->version == 0)
1593 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1594 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako08d331d2003-10-13 20:33:30 +00001595
Harald Weltebed35df2011-11-02 13:06:18 +01001596 /* Include IMSI if updating with unknown teic_gn */
1597 if ((pdp->version == 1) && (!pdp->teic_gn))
1598 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1599 sizeof(pdp->imsi), (uint8_t *) & pdp->imsi);
1600
1601 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1602 gsn->restart_counter);
1603
1604 if (pdp->version == 0) {
1605 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu);
1606 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc);
1607 }
1608
1609 if (pdp->version == 1) {
1610 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1611 pdp->teid_own);
1612
1613 if (!pdp->teic_confirmed)
1614 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1615 pdp->teic_own);
1616 }
1617
1618 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
1619
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01001620 /* TODO
Harald Weltebed35df2011-11-02 13:06:18 +01001621 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1622 pdp->traceref);
1623 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1624 pdp->tracetype); */
1625
1626 /* TODO if ggsn update message
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01001627 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
Harald Weltebed35df2011-11-02 13:06:18 +01001628 pdp->eua.l, pdp->eua.v);
1629 */
1630
1631 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1632 pdp->gsnlc.l, pdp->gsnlc.v);
1633 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1634 pdp->gsnlu.l, pdp->gsnlu.v);
1635
1636 if (pdp->version == 1)
1637 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1638 pdp->qos_req.l, pdp->qos_req.v);
1639
1640 if ((pdp->version == 1) && pdp->tft.l)
1641 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1642 pdp->tft.l, pdp->tft.v);
1643
1644 if ((pdp->version == 1) && pdp->triggerid.l)
1645 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1646 pdp->triggerid.l, pdp->triggerid.v);
1647
1648 if ((pdp->version == 1) && pdp->omcid.l)
1649 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1650 pdp->omcid.l, pdp->omcid.v);
1651
Daniel Willmann134a7752016-02-03 18:53:29 +01001652 gtp_req(gsn, pdp->version, pdp, &packet, length, inetaddr, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01001653
1654 return 0;
jjako52c24142002-12-16 13:33:51 +00001655}
1656
jjako08d331d2003-10-13 20:33:30 +00001657/* Send Update PDP Context Response */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01001658static int gtp_update_pdp_resp(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +01001659 struct sockaddr_in *peer, int fd,
jjako08d331d2003-10-13 20:33:30 +00001660 void *pack, unsigned len,
Harald Weltebed35df2011-11-02 13:06:18 +01001661 struct pdp_t *pdp, uint8_t cause)
1662{
jjako08d331d2003-10-13 20:33:30 +00001663
Harald Weltebed35df2011-11-02 13:06:18 +01001664 union gtp_packet packet;
1665 unsigned int length =
1666 get_default_gtp(version, GTP_UPDATE_PDP_RSP, &packet);
jjako08d331d2003-10-13 20:33:30 +00001667
Harald Weltebed35df2011-11-02 13:06:18 +01001668 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako08d331d2003-10-13 20:33:30 +00001669
Harald Weltebed35df2011-11-02 13:06:18 +01001670 if (cause == GTPCAUSE_ACC_REQ) {
1671
1672 if (version == 0)
1673 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1674 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1675
1676 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1677 gsn->restart_counter);
1678
1679 if (version == 0) {
1680 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1681 pdp->fllu);
1682 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1683 pdp->fllc);
1684 }
1685
1686 if (version == 1) {
1687 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1688 pdp->teid_own);
1689
1690 if (!pdp->teic_confirmed)
1691 gtpie_tv4(&packet, &length, GTP_MAX,
1692 GTPIE_TEI_C, pdp->teic_own);
1693 }
1694
1695 /* TODO we use teid_own as charging ID address */
1696 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
1697 pdp->teid_own);
1698
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01001699 /* If ggsn
1700 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
Harald Weltebed35df2011-11-02 13:06:18 +01001701 pdp->eua.l, pdp->eua.v); */
1702
1703 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1704 pdp->gsnlc.l, pdp->gsnlc.v);
1705 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1706 pdp->gsnlu.l, pdp->gsnlu.v);
1707
1708 if (version == 1)
1709 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1710 pdp->qos_neg.l, pdp->qos_neg.v);
1711
1712 /* TODO: Charging gateway address */
1713 }
1714
1715 return gtp_resp(version, gsn, pdp, &packet, length, peer,
1716 fd, get_seq(pack), get_tid(pack));
jjako08d331d2003-10-13 20:33:30 +00001717}
1718
jjako52c24142002-12-16 13:33:51 +00001719/* Handle Update PDP Context Request */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01001720static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +01001721 struct sockaddr_in *peer, int fd,
1722 void *pack, unsigned len)
1723{
1724 struct pdp_t *pdp;
1725 struct pdp_t pdp_backup;
1726 union gtpie_member *ie[GTPIE_SIZE];
1727 uint8_t recovery;
jjako52c24142002-12-16 13:33:51 +00001728
Harald Weltebed35df2011-11-02 13:06:18 +01001729 uint16_t seq = get_seq(pack);
1730 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001731
Harald Weltebed35df2011-11-02 13:06:18 +01001732 uint64_t imsi;
1733 uint8_t nsapi;
jjako52c24142002-12-16 13:33:51 +00001734
Pau Espin Pedrolde72d262019-05-29 18:17:05 +02001735 /* Is this a duplicate ? */
1736 if (!gtp_duplicate(gsn, version, peer, seq)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001737 return 0; /* We allready send of response once */
1738 }
jjako08d331d2003-10-13 20:33:30 +00001739
Harald Weltebed35df2011-11-02 13:06:18 +01001740 /* Decode information elements */
1741 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001742 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001743 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1744 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001745 if (0 == version)
1746 return EOF;
1747 else
1748 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
1749 len, NULL,
1750 GTPCAUSE_INVALID_MESSAGE);
1751 }
jjako08d331d2003-10-13 20:33:30 +00001752
Harald Weltebed35df2011-11-02 13:06:18 +01001753 /* Finding PDP: */
1754 /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
1755 /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
1756 /* we have to use the tunnel endpoint identifier */
1757 if (version == 0) {
Harald Weltebed35df2011-11-02 13:06:18 +01001758 /* Find the context in question */
Vadim Yanitskiy00a61712019-08-30 21:00:22 +02001759 if (gtp_pdp_tidget(gsn, &pdp, get_tid(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001760 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02001761 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1762 "Unknown PDP context: TID=0x%" PRIx64 "\n",
1763 get_tid(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01001764 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
1765 len, NULL,
1766 GTPCAUSE_NON_EXIST);
1767 }
Vadim Yanitskiy00a61712019-08-30 21:00:22 +02001768
1769 /* Update IMSI and NSAPI */
1770 pdp_set_imsi_nsapi(pdp, get_tid(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01001771 } else if (version == 1) {
1772 /* NSAPI (mandatory) */
1773 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001774 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001775 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1776 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001777 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
1778 len, NULL,
1779 GTPCAUSE_MAN_IE_MISSING);
1780 }
jjako08d331d2003-10-13 20:33:30 +00001781
Harald Weltebed35df2011-11-02 13:06:18 +01001782 /* IMSI (conditional) */
1783 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) {
1784 /* Find the context in question */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02001785 if (gtp_pdp_getgtp1(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001786 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02001787 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1788 "Unknown PDP context: TEI=0x%" PRIx32 "\n",
1789 get_tei(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01001790 return gtp_update_pdp_resp(gsn, version, peer,
1791 fd, pack, len, NULL,
1792 GTPCAUSE_NON_EXIST);
1793 }
1794 } else {
1795 /* Find the context in question */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02001796 if (gtp_pdp_getimsi(gsn, &pdp, imsi, nsapi)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001797 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02001798 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1799 "Unknown PDP context: IMSI=0x%" PRIx64
1800 " NSAPI=%" PRIu8 "\n", imsi, nsapi);
Harald Weltebed35df2011-11-02 13:06:18 +01001801 return gtp_update_pdp_resp(gsn, version, peer,
1802 fd, pack, len, NULL,
1803 GTPCAUSE_NON_EXIST);
1804 }
1805 }
1806 } else {
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01001807 LOGP(DLGTP, LOGL_ERROR, "Unknown version: %d\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01001808 return EOF;
1809 }
jjako08d331d2003-10-13 20:33:30 +00001810
Harald Weltebed35df2011-11-02 13:06:18 +01001811 /* Make a backup copy in case anything is wrong */
1812 memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
jjako08d331d2003-10-13 20:33:30 +00001813
Harald Weltebed35df2011-11-02 13:06:18 +01001814 if (version == 0) {
1815 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1816 pdp->qos_req0, sizeof(pdp->qos_req0))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001817 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001818 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1819 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001820 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1821 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
1822 len, pdp,
1823 GTPCAUSE_MAN_IE_MISSING);
1824 }
1825 }
jjako52c24142002-12-16 13:33:51 +00001826
Harald Weltebed35df2011-11-02 13:06:18 +01001827 /* Recovery (optional) */
1828 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
Pau Espin Pedrolb5f93342018-07-23 11:24:07 +02001829 emit_cb_recovery(gsn, peer, pdp, recovery);
Harald Weltebed35df2011-11-02 13:06:18 +01001830 }
jjako08d331d2003-10-13 20:33:30 +00001831
Harald Weltebed35df2011-11-02 13:06:18 +01001832 if (version == 0) {
1833 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001834 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001835 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1836 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001837 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1838 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
1839 len, pdp,
1840 GTPCAUSE_MAN_IE_MISSING);
1841 }
jjako52c24142002-12-16 13:33:51 +00001842
Harald Weltebed35df2011-11-02 13:06:18 +01001843 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001844 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001845 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1846 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001847 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1848 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
1849 len, pdp,
1850 GTPCAUSE_MAN_IE_MISSING);
1851 }
1852 }
jjako52c24142002-12-16 13:33:51 +00001853
Harald Weltebed35df2011-11-02 13:06:18 +01001854 if (version == 1) {
1855 /* TEID (mandatory) */
1856 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001857 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001858 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1859 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001860 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1861 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
1862 len, pdp,
1863 GTPCAUSE_MAN_IE_MISSING);
1864 }
jjako52c24142002-12-16 13:33:51 +00001865
Harald Weltebed35df2011-11-02 13:06:18 +01001866 /* TEIC (conditional) */
1867 /* If TEIC is not included it means that we have allready received it */
1868 /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
1869 /* all updated contexts, or only for one of the linked contexts */
1870 gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn);
1871
1872 /* NSAPI (mandatory) */
1873 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001874 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001875 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1876 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001877 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1878 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
1879 len, pdp,
1880 GTPCAUSE_MAN_IE_MISSING);
1881 }
1882 }
1883
1884 /* Trace reference (optional) */
1885 /* Trace type (optional) */
1886
1887 /* End User Address (conditional) TODO: GGSN Initiated
1888 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1889 &pdp->eua.v, sizeof(pdp->eua.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001890 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001891 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Harald Weltebed35df2011-11-02 13:06:18 +01001892 "Missing mandatory information field");
1893 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01001894 return gtp_update_pdp_resp(gsn, version, pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001895 GTPCAUSE_MAN_IE_MISSING);
1896 } */
1897
1898 /* SGSN address for signalling (mandatory) */
1899 /* It is weird that this is mandatory when TEIC is conditional */
1900 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1901 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001902 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001903 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1904 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001905 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1906 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1907 pdp, GTPCAUSE_MAN_IE_MISSING);
1908 }
1909
1910 /* SGSN address for user traffic (mandatory) */
1911 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1912 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001913 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001914 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1915 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001916 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1917 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1918 pdp, GTPCAUSE_MAN_IE_MISSING);
1919 }
1920
1921 if (version == 1) {
1922 /* QoS (mandatory) */
1923 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
1924 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001925 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001926 GTP_LOGPKG(LOGL_ERROR, peer, pack,
1927 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01001928 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1929 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
1930 len, pdp,
1931 GTPCAUSE_MAN_IE_MISSING);
1932 }
1933
1934 /* TFT (conditional) */
1935 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
1936 &pdp->tft.v, sizeof(pdp->tft.v))) {
1937 }
1938
1939 /* OMC identity */
1940 }
1941
1942 /* Confirm to peer that things were "successful" */
1943 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
1944 GTPCAUSE_ACC_REQ);
jjako52c24142002-12-16 13:33:51 +00001945}
1946
jjako52c24142002-12-16 13:33:51 +00001947/* Handle Update PDP Context Response */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01001948static int gtp_update_pdp_conf(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +01001949 struct sockaddr_in *peer, void *pack, unsigned len)
1950{
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02001951 struct pdp_t *pdp = NULL;
Harald Weltebed35df2011-11-02 13:06:18 +01001952 union gtpie_member *ie[GTPIE_SIZE];
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02001953 uint8_t cause = EOF;
1954 uint8_t recovery;
1955 int rc = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001956 void *cbp = NULL;
1957 uint8_t type = 0;
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02001958 bool trigger_recovery = false;
Daniel Willmann05f3ef32016-02-03 18:53:30 +01001959 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001960
Harald Weltebed35df2011-11-02 13:06:18 +01001961 /* Remove packet from queue */
1962 if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp))
1963 return EOF;
jjako52c24142002-12-16 13:33:51 +00001964
Harald Weltebed35df2011-11-02 13:06:18 +01001965 /* Decode information elements */
Daniel Willmann05f3ef32016-02-03 18:53:30 +01001966 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001967 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01001968 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
1969 "Invalid message format\n");
Daniel Willmannd9975522016-02-04 15:38:12 +01001970 goto err_out;
Harald Weltebed35df2011-11-02 13:06:18 +01001971 }
jjako52c24142002-12-16 13:33:51 +00001972
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02001973 /* Extract recovery (optional) */
1974 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery))
1975 trigger_recovery = true;
1976
Harald Weltebed35df2011-11-02 13:06:18 +01001977 /* Extract cause value (mandatory) */
1978 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
Daniel Willmannd9975522016-02-04 15:38:12 +01001979 goto err_missing;
Harald Weltebed35df2011-11-02 13:06:18 +01001980 }
jjako52c24142002-12-16 13:33:51 +00001981
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02001982 /* 3GPP TS 29.060 sec 8.2: "Receiving node shall send back to the source
1983 * of the message, a response with the appropriate cause value (either
1984 * "Non-existent" or "Context not found"). The Tunnel Endpoint
1985 * Identifier used in the response message shall be set to all zeroes."
1986 * Hence, TEID=0 in this scenario, it makes no sense to infer PDP ctx
1987 * from it. User is responsible to infer it from cbp */
1988 if (cause != GTPCAUSE_NON_EXIST && cause != GTPCAUSE_CONTEXT_NOT_FOUND) {
1989 /* Find the context in question */
1990 if (gtp_pdp_getgtp1(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01001991 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02001992 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02001993 "Unknown PDP context: TEI=0x%" PRIx32 "\n", get_tei(pack));
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02001994 goto err_out;
1995 }
Harald Weltebed35df2011-11-02 13:06:18 +01001996 }
1997
1998 /* Check all conditional information elements */
Daniel Willmannd9975522016-02-04 15:38:12 +01001999 /* TODO: This does not handle GGSN-initiated update responses */
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002000 if (cause == GTPCAUSE_ACC_REQ) {
Daniel Willmannd9975522016-02-04 15:38:12 +01002001 if (version == 0) {
2002 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2003 &pdp->qos_neg0,
2004 sizeof(pdp->qos_neg0))) {
2005 goto err_missing;
2006 }
2007
2008 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
2009 goto err_missing;
2010 }
2011
2012 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
2013 goto err_missing;
2014 }
Harald Weltebed35df2011-11-02 13:06:18 +01002015 }
2016
Daniel Willmannd9975522016-02-04 15:38:12 +01002017 if (version == 1) {
2018 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
2019 goto err_missing;
2020 }
Harald Weltebed35df2011-11-02 13:06:18 +01002021
Daniel Willmannd9975522016-02-04 15:38:12 +01002022 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
2023 goto err_missing;
2024 }
Pau Espin Pedrol0b1d9db2021-04-21 19:45:23 +02002025 /* Register that we have received a valid teic from GGSN */
2026 pdp->teic_confirmed = 1;
Daniel Willmannd9975522016-02-04 15:38:12 +01002027 }
2028
2029 if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
2030 goto err_missing;
2031 }
2032
2033 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2034 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
2035 goto err_missing;
2036 }
2037
2038 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2039 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
2040 goto err_missing;
2041 }
2042
2043 if (version == 1) {
2044 if (gtpie_gettlv
2045 (ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
2046 &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
2047 goto err_missing;
2048 }
2049 }
Harald Weltebed35df2011-11-02 13:06:18 +01002050 }
Daniel Willmannd9975522016-02-04 15:38:12 +01002051
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002052generic_ret:
2053 if (trigger_recovery)
2054 emit_cb_recovery(gsn, peer, pdp, recovery);
Daniel Willmannd9975522016-02-04 15:38:12 +01002055 if (gsn->cb_conf)
2056 gsn->cb_conf(type, cause, pdp, cbp);
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002057 return rc; /* Succes */
Daniel Willmannd9975522016-02-04 15:38:12 +01002058
2059err_missing:
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002060 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Daniel Willmannd9975522016-02-04 15:38:12 +01002061 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2062 "Missing information field\n");
2063err_out:
Pau Espin Pedrol00e05592021-04-22 13:47:57 +02002064 rc = EOF;
2065 goto generic_ret;
jjako52c24142002-12-16 13:33:51 +00002066}
2067
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002068/* API: Deprecated. Send Delete PDP Context Request And free pdp ctx. */
jjako2c381332003-10-21 19:09:53 +00002069int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
Harald Weltebed35df2011-11-02 13:06:18 +01002070 int teardown)
2071{
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002072 struct pdp_t *linked_pdp;
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002073
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002074 if (gtp_pdp_getgtp1(gsn, &linked_pdp, pdp->teic_own)) {
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002075 LOGP(DLGTP, LOGL_ERROR,
2076 "Unknown linked PDP context: %u\n", pdp->teic_own);
2077 return EOF;
2078 }
2079
2080 if (gtp_delete_context_req2(gsn, pdp, cbp, teardown) == EOF)
2081 return EOF;
2082
2083 if (teardown) { /* Remove all contexts */
Pau Espin Pedrol0d0b0592019-05-29 20:42:09 +02002084 gtp_freepdp_teardown(gsn, linked_pdp);
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002085 } else {
Pau Espin Pedrol86515732019-05-31 16:40:37 +02002086 /* If we end up here (no teardown) it means we still
2087 have at least another pdp context active for this
2088 PDN connection (since last DeleteReq should come
2089 with teardown enabled). If the ctx to delete is a
2090 secondary ctx, simply free it. If it's the primary
2091 ctx, mark it as nodata but don't free it since we
2092 need it to hold data linked together and we'll
2093 require it later to tear down the entire tree. Still,
2094 we announce its deletion through cb_delete_context
2095 because we don't want user to release its related
2096 data and not use it anymore.
2097 */
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002098 if (pdp == linked_pdp) {
Pau Espin Pedrol93dd7982019-05-31 16:42:05 +02002099 if (gsn->cb_delete_context)
2100 gsn->cb_delete_context(pdp);
2101 pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2102 pdp->nodata = 1;
2103 } else {
2104 gtp_freepdp(gsn, pdp);
2105 }
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002106 }
2107
2108 return 0;
2109}
2110
Oliver Smith1cde2c12019-05-13 11:35:03 +02002111/* API: Send Delete PDP Context Request. PDP CTX shall be free'd by user at any
Pau Espin Pedrol4e605b32019-08-29 13:54:28 +02002112 point in time later than this function through a call to pdp_freepdp(pdp) (or
2113 through gtp_freepdp() if willing to receive cb_delete_context() callback),
2114 but it must be freed no later than during cb_conf(GTP_DELETE_PDP_REQ, pdp) */
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002115int gtp_delete_context_req2(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
2116 int teardown)
2117{
Harald Weltebed35df2011-11-02 13:06:18 +01002118 union gtp_packet packet;
2119 unsigned int length =
2120 get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
2121 struct in_addr addr;
2122 struct pdp_t *linked_pdp;
Pau Espin Pedrol9ee8d322019-05-30 14:11:22 +02002123 int count;
jjako2c381332003-10-21 19:09:53 +00002124
Harald Weltebed35df2011-11-02 13:06:18 +01002125 if (gsna2in_addr(&addr, &pdp->gsnrc)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002126 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_ADDRESS);
Max14b1b632017-08-21 20:14:59 +02002127 LOGP(DLGTP, LOGL_ERROR, "GSN address (len=%u) conversion failed\n", pdp->gsnrc.l);
Harald Weltebed35df2011-11-02 13:06:18 +01002128 return EOF;
jjako2c381332003-10-21 19:09:53 +00002129 }
jjako2c381332003-10-21 19:09:53 +00002130
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002131 if (gtp_pdp_getgtp1(gsn, &linked_pdp, pdp->teic_own)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002132 LOGP(DLGTP, LOGL_ERROR,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01002133 "Unknown linked PDP context: %u\n", pdp->teic_own);
Harald Weltebed35df2011-11-02 13:06:18 +01002134 return EOF;
2135 }
2136
2137 if (!teardown) {
Pau Espin Pedrol9ee8d322019-05-30 14:11:22 +02002138 count = pdp_count_secondary(linked_pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01002139 if (count <= 1) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002140 LOGP(DLGTP, LOGL_ERROR,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01002141 "Must use teardown for last context: %d\n", count);
Harald Weltebed35df2011-11-02 13:06:18 +01002142 return EOF;
2143 }
2144 }
2145
2146 if (pdp->version == 1) {
2147 if (teardown)
2148 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
2149 0xff);
2150
2151 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
2152 }
2153
2154 gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
2155
Harald Weltebed35df2011-11-02 13:06:18 +01002156 return 0;
jjako2c381332003-10-21 19:09:53 +00002157}
jjako08d331d2003-10-13 20:33:30 +00002158
jjako52c24142002-12-16 13:33:51 +00002159/* Send Delete PDP Context Response */
2160int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002161 struct sockaddr_in *peer, int fd,
Harald Weltebed35df2011-11-02 13:06:18 +01002162 void *pack, unsigned len,
2163 struct pdp_t *pdp, struct pdp_t *linked_pdp,
jjako2c381332003-10-21 19:09:53 +00002164 uint8_t cause, int teardown)
jjako52c24142002-12-16 13:33:51 +00002165{
Harald Weltebed35df2011-11-02 13:06:18 +01002166 union gtp_packet packet;
Harald Weltebed35df2011-11-02 13:06:18 +01002167 unsigned int length =
2168 get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet);
jjako52c24142002-12-16 13:33:51 +00002169
Harald Weltebed35df2011-11-02 13:06:18 +01002170 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00002171
Harald Weltebed35df2011-11-02 13:06:18 +01002172 gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
2173 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002174
Harald Weltebed35df2011-11-02 13:06:18 +01002175 if (cause == GTPCAUSE_ACC_REQ) {
2176 if ((teardown) || (version == 0)) { /* Remove all contexts */
Pau Espin Pedrol0d0b0592019-05-29 20:42:09 +02002177 gtp_freepdp_teardown(gsn, linked_pdp);
Pau Espin Pedrol86515732019-05-31 16:40:37 +02002178 } else {
2179 /* If we end up here (no teardown) it means we still
2180 have at least another pdp context active for this
2181 PDN connection (since last DeleteReq should come
2182 with teardown enabled). If the ctx to delete is a
2183 secondary ctx, simply free it. If it's the primary
2184 ctx, mark it as nodata but don't free it since we
2185 need it to hold data linked together and we'll
2186 require it later to tear down the entire tree. Still,
2187 we announce its deletion through cb_delete_context
2188 because we don't want user to release its related
2189 data and not use it anymore.
2190 */
Harald Weltebed35df2011-11-02 13:06:18 +01002191 if (pdp == linked_pdp) {
Pau Espin Pedrol93dd7982019-05-31 16:42:05 +02002192 if (gsn->cb_delete_context)
2193 gsn->cb_delete_context(pdp);
2194 pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2195 pdp->nodata = 1;
2196 } else {
2197 gtp_freepdp(gsn, pdp);
2198 }
Harald Weltebed35df2011-11-02 13:06:18 +01002199 }
jjako2c381332003-10-21 19:09:53 +00002200 }
Harald Weltebed35df2011-11-02 13:06:18 +01002201 /* if (cause == GTPCAUSE_ACC_REQ) */
2202 return 0;
jjako52c24142002-12-16 13:33:51 +00002203}
2204
2205/* Handle Delete PDP Context Request */
2206int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002207 struct sockaddr_in *peer, int fd,
Harald Weltebed35df2011-11-02 13:06:18 +01002208 void *pack, unsigned len)
2209{
2210 struct pdp_t *pdp = NULL;
2211 struct pdp_t *linked_pdp = NULL;
2212 union gtpie_member *ie[GTPIE_SIZE];
jjako52c24142002-12-16 13:33:51 +00002213
Harald Weltebed35df2011-11-02 13:06:18 +01002214 uint16_t seq = get_seq(pack);
2215 int hlen = get_hlen(pack);
jjako2c381332003-10-21 19:09:53 +00002216
Harald Weltebed35df2011-11-02 13:06:18 +01002217 uint8_t nsapi;
2218 uint8_t teardown = 0;
Pau Espin Pedrol9ee8d322019-05-30 14:11:22 +02002219 int count;
jjako52c24142002-12-16 13:33:51 +00002220
Pau Espin Pedrolde72d262019-05-29 18:17:05 +02002221 /* Is this a duplicate ? */
2222 if (!gtp_duplicate(gsn, version, peer, seq)) {
Harald Weltebed35df2011-11-02 13:06:18 +01002223 return 0; /* We allready send off response once */
2224 }
jjako2c381332003-10-21 19:09:53 +00002225
Harald Weltebed35df2011-11-02 13:06:18 +01002226 /* Find the linked context in question */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002227 if (gtp_pdp_getgtp1(gsn, &linked_pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002228 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002229 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002230 "Unknown PDP context: TEI=0x%" PRIx32 "\n", get_tei(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01002231 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2232 NULL, NULL, GTPCAUSE_NON_EXIST,
2233 teardown);
2234 }
jjako2c381332003-10-21 19:09:53 +00002235
Harald Weltebed35df2011-11-02 13:06:18 +01002236 /* If version 0 this is also the secondary context */
2237 if (version == 0)
2238 pdp = linked_pdp;
jjako2c381332003-10-21 19:09:53 +00002239
Harald Weltebed35df2011-11-02 13:06:18 +01002240 /* Decode information elements */
2241 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002242 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002243 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2244 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002245 if (0 == version)
2246 return EOF;
2247 else
2248 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2249 len, NULL, NULL,
2250 GTPCAUSE_INVALID_MESSAGE,
2251 teardown);
2252 }
2253
2254 if (version == 1) {
2255 /* NSAPI (mandatory) */
2256 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002257 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002258 GTP_LOGPKG(LOGL_ERROR, peer, pack,
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002259 len, "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002260 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2261 len, NULL, NULL,
2262 GTPCAUSE_MAN_IE_MISSING,
2263 teardown);
2264 }
2265
2266 /* Find the context in question */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002267 if (gtp_pdp_getgtp1(gsn, &pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002268 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002269 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2270 "Unknown PDP context: Secondary TEI=0x%" PRIx32 "\n",
2271 linked_pdp->secondary_tei[nsapi & 0x0f]);
Harald Weltebed35df2011-11-02 13:06:18 +01002272 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2273 len, NULL, NULL,
2274 GTPCAUSE_NON_EXIST,
2275 teardown);
2276 }
2277
2278 /* Teardown (conditional) */
2279 gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown);
2280
2281 if (!teardown) {
Pau Espin Pedrol742a6b52019-05-30 13:36:10 +02002282 /* TS 29.060 section 7.3.5: If a GSN receives a Delete PDP context
2283 * without a Teardown Indicator or with a Teardown Indicator with
2284 * value set to "0" and only that PDP context is active for a PDN
2285 * connection, then the GSN shall ignore the message. (Note:
2286 * This is symptom of a race condition. The reliable delivery of
2287 * signalling messages will eventually lead to a consistent
2288 * situation, allowing the teardown of the PDP context.)
2289 */
Pau Espin Pedrol9ee8d322019-05-30 14:11:22 +02002290 count = pdp_count_secondary(linked_pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01002291 if (count <= 1) {
Pau Espin Pedrold1bd6fc2018-07-13 19:11:45 +02002292 GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
2293 "Ignoring CTX DEL without teardown and count=%d\n",
2294 count);
Harald Weltebed35df2011-11-02 13:06:18 +01002295 return 0; /* 29.060 7.3.5 Ignore message */
2296 }
2297 }
2298 }
2299
2300 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2301 pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown);
jjako52c24142002-12-16 13:33:51 +00002302}
2303
jjako52c24142002-12-16 13:33:51 +00002304/* Handle Delete PDP Context Response */
2305int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002306 struct sockaddr_in *peer, void *pack, unsigned len)
2307{
2308 union gtpie_member *ie[GTPIE_SIZE];
2309 uint8_t cause;
2310 void *cbp = NULL;
2311 uint8_t type = 0;
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002312 struct pdp_t *pdp = NULL;
Harald Weltebed35df2011-11-02 13:06:18 +01002313 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002314
Harald Weltebed35df2011-11-02 13:06:18 +01002315 /* Remove packet from queue */
2316 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
2317 return EOF;
jjako52c24142002-12-16 13:33:51 +00002318
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002319 /* Find the context in question. It may not be available if gtp_delete_context_req
2320 * was used and as a result the PDP ctx was already freed */
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002321 if (gtp_pdp_getgtp1(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002322 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002323 GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002324 "Unknown PDP context: TEI=0x%" PRIx32 " (expected if "
2325 "gtp_delete_context_req is used or pdp ctx was freed "
2326 "manually before response)\n", get_tei(pack));
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002327 if (gsn->cb_conf)
2328 gsn->cb_conf(type, EOF, NULL, cbp);
2329 return EOF;
2330 }
2331
Harald Weltebed35df2011-11-02 13:06:18 +01002332 /* Decode information elements */
2333 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002334 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002335 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2336 "Invalid message format\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002337 if (gsn->cb_conf)
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002338 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01002339 return EOF;
2340 }
2341
2342 /* Extract cause value (mandatory) */
2343 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002344 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002345 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2346 "Missing mandatory information field\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002347 if (gsn->cb_conf)
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002348 gsn->cb_conf(type, EOF, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01002349 return EOF;
2350 }
2351
2352 /* Check the cause value (again) */
2353 if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002354 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNEXPECTED_CAUSE);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002355 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2356 "Unexpected cause value received: %d\n", cause);
Harald Weltebed35df2011-11-02 13:06:18 +01002357 if (gsn->cb_conf)
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002358 gsn->cb_conf(type, cause, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01002359 return EOF;
2360 }
2361
2362 /* Callback function to notify application */
2363 if (gsn->cb_conf)
Pau Espin Pedrol8e8c7ef2018-07-16 16:47:12 +02002364 gsn->cb_conf(type, cause, pdp, cbp);
Harald Weltebed35df2011-11-02 13:06:18 +01002365
2366 return 0;
jjako52c24142002-12-16 13:33:51 +00002367}
2368
Harald Welte54d082e2017-08-12 22:43:21 +02002369/* Send Error Indication (response to a GPDU message) - 3GPP TS 29.060 7.3.7 */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01002370static int gtp_error_ind_resp(struct gsn_t *gsn, uint8_t version,
jjako08d331d2003-10-13 20:33:30 +00002371 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002372 void *pack, unsigned len)
2373{
Harald Weltebed35df2011-11-02 13:06:18 +01002374 union gtp_packet packet;
2375 unsigned int length = get_default_gtp(version, GTP_ERROR, &packet);
2376
Harald Welte54d082e2017-08-12 22:43:21 +02002377 if (version == 1) {
2378 /* Mandatory 7.7.13 TEI Data I */
2379 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
2380 ntoh32(((union gtp_packet *)pack)->gtp1l.h.tei));
2381
2382 /* Mandatory 7.7.32 GSN Address */
2383 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
2384 sizeof(gsn->gsnu), &gsn->gsnu);
2385 }
2386
Harald Weltebed35df2011-11-02 13:06:18 +01002387 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
2388 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002389}
2390
2391/* Handle Error Indication */
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01002392static int gtp_error_ind_conf(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +01002393 struct sockaddr_in *peer, void *pack, unsigned len)
2394{
Harald Welte37d5b152017-08-12 23:58:29 +02002395 union gtpie_member *ie[GTPIE_SIZE];
Harald Weltebed35df2011-11-02 13:06:18 +01002396 struct pdp_t *pdp;
jjako52c24142002-12-16 13:33:51 +00002397
Harald Weltebed35df2011-11-02 13:06:18 +01002398 /* Find the context in question */
Harald Welte37d5b152017-08-12 23:58:29 +02002399 if (version == 0) {
Vadim Yanitskiy68c5a742019-08-30 21:04:19 +02002400 if (gtp_pdp_tidget(gsn, &pdp, get_tid(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002401 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Harald Welte37d5b152017-08-12 23:58:29 +02002402 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002403 "Unknown PDP context: TID=0x%" PRIx64 "\n",
2404 get_tid(pack));
Harald Welte37d5b152017-08-12 23:58:29 +02002405 return EOF;
2406 }
2407 } else if (version == 1) {
2408 /* we have to look-up based on the *peer* TEID */
2409 int hlen = get_hlen(pack);
2410 uint32_t teid_gn;
2411
2412 /* Decode information elements */
2413 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002414 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
Harald Welte37d5b152017-08-12 23:58:29 +02002415 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2416 "Invalid message format\n");
2417 return EOF;
2418 }
2419
2420 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &teid_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002421 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
Harald Welte37d5b152017-08-12 23:58:29 +02002422 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2423 "Missing mandatory information field\n");
2424 return EOF;
2425 }
2426
Pau Espin Pedrol9fbcb102019-05-31 16:29:32 +02002427 if (gtp_pdp_getgtp1_peer_d(gsn, &pdp, peer, teid_gn)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002428 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002429 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2430 "Unknown PDP context: Peer TEID=0x%" PRIx32 "\n",
2431 teid_gn);
Harald Welte37d5b152017-08-12 23:58:29 +02002432 return EOF;
2433 }
Vadim Yanitskiybdf2cf92019-08-30 21:23:11 +02002434 } else {
2435 LOGP(DLGTP, LOGL_ERROR, "Unknown version: %d\n", version);
2436 return EOF;
Harald Weltebed35df2011-11-02 13:06:18 +01002437 }
jjako52c24142002-12-16 13:33:51 +00002438
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002439 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2440 "Received Error Indication\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002441
Harald Weltebd228242017-11-06 03:16:49 +09002442 /* This is obvious from above code, given the semantics of the
2443 * functions above, but Coverity doesn't figure this out, so
2444 * let's make it clear. It's good style anyway in case above
2445 * code should ever change. */
2446 OSMO_ASSERT(pdp);
2447
Pau Espin Pedrol0d0b0592019-05-29 20:42:09 +02002448 gtp_freepdp(gsn, pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01002449 return 0;
jjako52c24142002-12-16 13:33:51 +00002450}
2451
Pau Espin Pedrol07730bb2018-01-25 18:43:38 +01002452static int gtp_gpdu_ind(struct gsn_t *gsn, uint8_t version,
Harald Weltebed35df2011-11-02 13:06:18 +01002453 struct sockaddr_in *peer, int fd, void *pack, unsigned len)
2454{
jjako08d331d2003-10-13 20:33:30 +00002455
Pau Espin Pedrol282d4e32018-01-25 18:20:51 +01002456 int hlen;
jjako52c24142002-12-16 13:33:51 +00002457
Harald Weltebed35df2011-11-02 13:06:18 +01002458 struct pdp_t *pdp;
jjako1db1c812003-07-06 20:53:57 +00002459
Pau Espin Pedrol42d32502018-01-25 18:17:17 +01002460 switch (version) {
2461 case 0:
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002462 if (gtp_pdp_getgtp0(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002463 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002464 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2465 "Unknown PDP context: TEI=0x%" PRIx32 "\n",
2466 get_tei(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01002467 return gtp_error_ind_resp(gsn, version, peer, fd, pack,
2468 len);
2469 }
2470 hlen = GTP0_HEADER_SIZE;
Pau Espin Pedrol42d32502018-01-25 18:17:17 +01002471 break;
2472 case 1:
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002473 if (gtp_pdp_getgtp1(gsn, &pdp, get_tei(pack))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002474 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Pau Espin Pedrolbfd31192021-04-22 15:01:23 +02002475 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2476 "Unknown PDP context: TEI=0x%" PRIx32 "\n",
2477 get_tei(pack));
Harald Weltebed35df2011-11-02 13:06:18 +01002478 return gtp_error_ind_resp(gsn, version, peer, fd, pack,
2479 len);
2480 }
jjako08d331d2003-10-13 20:33:30 +00002481
Harald Weltebed35df2011-11-02 13:06:18 +01002482 /* Is this a long or a short header ? */
2483 if (((union gtp_packet *)pack)->gtp1l.h.flags & 0x07)
2484 hlen = GTP1_HEADER_SIZE_LONG;
2485 else
2486 hlen = GTP1_HEADER_SIZE_SHORT;
Pau Espin Pedrol42d32502018-01-25 18:17:17 +01002487 break;
2488 default:
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002489 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01002490 "Unknown version: %d\n", version);
Pau Espin Pedrol282d4e32018-01-25 18:20:51 +01002491 return EOF;
Harald Weltebed35df2011-11-02 13:06:18 +01002492 }
jjako08d331d2003-10-13 20:33:30 +00002493
Harald Weltebed35df2011-11-02 13:06:18 +01002494 /* If the GPDU was not from the peer GSN tell him to delete context */
2495 if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002496 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNKNOWN_PDP);
Max14b1b632017-08-21 20:14:59 +02002497 GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Unknown GSN peer %s\n", inet_ntoa(peer->sin_addr));
Harald Weltebed35df2011-11-02 13:06:18 +01002498 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2499 }
jjako52c24142002-12-16 13:33:51 +00002500
Harald Weltebed35df2011-11-02 13:06:18 +01002501 /* Callback function */
2502 if (gsn->cb_data_ind != 0)
2503 return gsn->cb_data_ind(pdp, pack + hlen, len - hlen);
2504
2505 return 0;
jjako52c24142002-12-16 13:33:51 +00002506}
2507
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01002508/* Receives GTP packet and sends off for further processing
jjako52c24142002-12-16 13:33:51 +00002509 * Function will check the validity of the header. If the header
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01002510 * is not valid the packet is either dropped or a version not
2511 * supported is returned to the peer.
jjako52c24142002-12-16 13:33:51 +00002512 * TODO: Need to decide on return values! */
jjako08d331d2003-10-13 20:33:30 +00002513int gtp_decaps0(struct gsn_t *gsn)
jjako52c24142002-12-16 13:33:51 +00002514{
Harald Weltebed35df2011-11-02 13:06:18 +01002515 unsigned char buffer[PACKET_MAX];
2516 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01002517 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01002518 int status;
2519 struct gtp0_header *pheader;
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002520 uint8_t version;
Harald Weltebed35df2011-11-02 13:06:18 +01002521 int fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00002522
Harald Weltebed35df2011-11-02 13:06:18 +01002523 /* TODO: Need strategy of userspace buffering and blocking */
2524 /* Currently read is non-blocking and send is blocking. */
2525 /* This means that the program have to wait for busy send calls... */
jjako52c24142002-12-16 13:33:51 +00002526
Harald Weltebed35df2011-11-02 13:06:18 +01002527 while (1) { /* Loop until no more to read */
2528 if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002529 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002530 return -1;
2531 }
2532 peerlen = sizeof(peer);
2533 if ((status =
2534 recvfrom(gsn->fd0, buffer, sizeof(buffer), 0,
2535 (struct sockaddr *)&peer, &peerlen)) < 0) {
2536 if (errno == EAGAIN)
2537 return 0;
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002538 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_READFROM);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002539 LOGP(DLGTP, LOGL_ERROR,
Alexander Huemerdb852a12015-11-06 20:59:01 +01002540 "recvfrom(fd0=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n",
Harald Weltebed35df2011-11-02 13:06:18 +01002541 gsn->fd0, (unsigned long)buffer, sizeof(buffer),
2542 status, status ? strerror(errno) : "No error");
2543 return -1;
2544 }
jjako1db1c812003-07-06 20:53:57 +00002545
Harald Weltebed35df2011-11-02 13:06:18 +01002546 /* Need at least 1 byte in order to check version */
2547 if (status < (1)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002548 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_EMPTY);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002549 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
2550 status, "Discarding packet - too small\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002551 continue;
2552 }
jjako08d331d2003-10-13 20:33:30 +00002553
Harald Weltebed35df2011-11-02 13:06:18 +01002554 pheader = (struct gtp0_header *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00002555
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002556 version = GTPHDR_F_GET_VER(pheader->flags);
2557
Harald Weltebed35df2011-11-02 13:06:18 +01002558 /* Version should be gtp0 (or earlier) */
2559 /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
2560 /* GTP 0 messages. If other version message is received we reply that we */
2561 /* only support version 0, implying that this is the only version */
2562 /* supported on this port */
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002563 if (version > 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002564 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Pau Espin Pedrola884a952018-01-25 17:28:11 +01002565 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
2566 "Unsupported GTP version %"PRIu8"\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01002567 gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */
2568 continue;
2569 }
2570
2571 /* Check length of gtp0 packet */
2572 if (status < GTP0_HEADER_SIZE) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002573 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002574 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
2575 status, "GTP0 packet too short\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002576 continue; /* Silently discard 29.60: 11.1.2 */
2577 }
2578
2579 /* Check packet length field versus length of packet */
2580 if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002581 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002582 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01002583 status,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002584 "GTP packet length field does not match actual length\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002585 continue; /* Silently discard */
2586 }
2587
2588 if ((gsn->mode == GTP_MODE_GGSN) &&
2589 ((pheader->type == GTP_CREATE_PDP_RSP) ||
Pau Espin Pedrola32e4c42018-07-13 19:05:00 +02002590 (pheader->type == GTP_UPDATE_PDP_RSP))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002591 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNEXPECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002592 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01002593 status,
Pau Espin Pedrol3b84e922018-07-13 18:32:35 +02002594 "Unexpected GTPv0 Signalling Message '%s'\n",
2595 get_value_string(gtp_type_names, pheader->type));
Harald Weltebed35df2011-11-02 13:06:18 +01002596 continue; /* Silently discard 29.60: 11.1.4 */
2597 }
2598
2599 if ((gsn->mode == GTP_MODE_SGSN) &&
2600 ((pheader->type == GTP_CREATE_PDP_REQ) ||
Pau Espin Pedrola32e4c42018-07-13 19:05:00 +02002601 (pheader->type == GTP_UPDATE_PDP_REQ))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002602 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNEXPECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002603 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01002604 status,
Pau Espin Pedrol3b84e922018-07-13 18:32:35 +02002605 "Unexpected GTPv0 Signalling Message '%s'\n",
2606 get_value_string(gtp_type_names, pheader->type));
Harald Weltebed35df2011-11-02 13:06:18 +01002607 continue; /* Silently discard 29.60: 11.1.4 */
2608 }
2609
2610 switch (pheader->type) {
2611 case GTP_ECHO_REQ:
2612 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2613 break;
2614 case GTP_ECHO_RSP:
2615 gtp_echo_conf(gsn, version, &peer, buffer, status);
2616 break;
2617 case GTP_NOT_SUPPORTED:
2618 gtp_unsup_ind(gsn, &peer, buffer, status);
2619 break;
2620 case GTP_CREATE_PDP_REQ:
2621 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer,
2622 status);
2623 break;
2624 case GTP_CREATE_PDP_RSP:
2625 gtp_create_pdp_conf(gsn, version, &peer, buffer,
2626 status);
2627 break;
2628 case GTP_UPDATE_PDP_REQ:
2629 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer,
2630 status);
2631 break;
2632 case GTP_UPDATE_PDP_RSP:
2633 gtp_update_pdp_conf(gsn, version, &peer, buffer,
2634 status);
2635 break;
2636 case GTP_DELETE_PDP_REQ:
2637 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer,
2638 status);
2639 break;
2640 case GTP_DELETE_PDP_RSP:
2641 gtp_delete_pdp_conf(gsn, version, &peer, buffer,
2642 status);
2643 break;
2644 case GTP_ERROR:
2645 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2646 break;
2647 case GTP_GPDU:
2648 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2649 break;
2650 default:
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002651 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNKNOWN);
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01002652 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
2653 "Unknown GTP message type received: %d\n",
2654 pheader->type);
Harald Weltebed35df2011-11-02 13:06:18 +01002655 break;
2656 }
2657 }
jjako08d331d2003-10-13 20:33:30 +00002658}
2659
jjako08d331d2003-10-13 20:33:30 +00002660int gtp_decaps1c(struct gsn_t *gsn)
2661{
Harald Weltebed35df2011-11-02 13:06:18 +01002662 unsigned char buffer[PACKET_MAX];
2663 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01002664 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01002665 int status;
2666 struct gtp1_header_short *pheader;
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002667 uint8_t version;
Harald Weltebed35df2011-11-02 13:06:18 +01002668 int fd = gsn->fd1c;
jjako08d331d2003-10-13 20:33:30 +00002669
Harald Weltebed35df2011-11-02 13:06:18 +01002670 /* TODO: Need strategy of userspace buffering and blocking */
2671 /* Currently read is non-blocking and send is blocking. */
2672 /* This means that the program have to wait for busy send calls... */
jjako08d331d2003-10-13 20:33:30 +00002673
Harald Weltebed35df2011-11-02 13:06:18 +01002674 while (1) { /* Loop until no more to read */
2675 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002676 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002677 return -1;
2678 }
2679 peerlen = sizeof(peer);
2680 if ((status =
2681 recvfrom(fd, buffer, sizeof(buffer), 0,
2682 (struct sockaddr *)&peer, &peerlen)) < 0) {
2683 if (errno == EAGAIN)
2684 return 0;
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002685 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_READFROM);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002686 LOGP(DLGTP, LOGL_ERROR,
Alexander Huemerdb852a12015-11-06 20:59:01 +01002687 "recvfrom(fd=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n",
Harald Weltebed35df2011-11-02 13:06:18 +01002688 fd, (unsigned long)buffer, sizeof(buffer),
2689 status, status ? strerror(errno) : "No error");
2690 return -1;
2691 }
jjako08d331d2003-10-13 20:33:30 +00002692
Harald Weltebed35df2011-11-02 13:06:18 +01002693 /* Need at least 1 byte in order to check version */
2694 if (status < (1)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002695 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_EMPTY);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002696 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
2697 status, "Discarding packet - too small\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002698 continue;
2699 }
jjako08d331d2003-10-13 20:33:30 +00002700
Harald Weltebed35df2011-11-02 13:06:18 +01002701 pheader = (struct gtp1_header_short *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00002702
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002703 version = GTPHDR_F_GET_VER(pheader->flags);
2704
Harald Weltebed35df2011-11-02 13:06:18 +01002705 /* Version must be no larger than GTP 1 */
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002706 if (version > 1) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002707 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Pau Espin Pedrola884a952018-01-25 17:28:11 +01002708 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
2709 "Unsupported GTP version %"PRIu8"\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01002710 gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
2711 /*29.60: 11.1.1 */
2712 continue;
2713 }
jjako08d331d2003-10-13 20:33:30 +00002714
Harald Weltebed35df2011-11-02 13:06:18 +01002715 /* Version must be at least GTP 1 */
2716 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2717 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2718 /* the message */
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002719 if (version < 1) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002720 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Pau Espin Pedrola884a952018-01-25 17:28:11 +01002721 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
2722 "Unsupported GTP version %"PRIu8"\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01002723 continue;
2724 }
jjako08d331d2003-10-13 20:33:30 +00002725
Harald Weltebed35df2011-11-02 13:06:18 +01002726 /* Check packet flag field */
2727 if (((pheader->flags & 0xf7) != 0x32)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002728 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002729 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Welted37b80a2016-12-15 18:33:15 +01002730 status, "Unsupported packet flags: 0x%02x\n", pheader->flags);
Harald Weltebed35df2011-11-02 13:06:18 +01002731 continue;
2732 }
jjako2c381332003-10-21 19:09:53 +00002733
Harald Weltebed35df2011-11-02 13:06:18 +01002734 /* Check length of packet */
2735 if (status < GTP1_HEADER_SIZE_LONG) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002736 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002737 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
2738 status, "GTP packet too short\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002739 continue; /* Silently discard 29.60: 11.1.2 */
2740 }
jjako2c381332003-10-21 19:09:53 +00002741
Harald Weltebed35df2011-11-02 13:06:18 +01002742 /* Check packet length field versus length of packet */
2743 if (status !=
2744 (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002745 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002746 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01002747 status,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002748 "GTP packet length field does not match actual length\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002749 continue; /* Silently discard */
2750 }
jjako1db1c812003-07-06 20:53:57 +00002751
Harald Weltebed35df2011-11-02 13:06:18 +01002752 /* Check for extension headers */
2753 /* TODO: We really should cycle through the headers and determine */
2754 /* if any have the comprehension required flag set */
Harald Weltefed598f2017-09-24 16:39:22 +08002755 if (((pheader->flags & GTP1HDR_F_EXT) != 0x00)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002756 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002757 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
2758 status, "Unsupported extension header\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002759 gtp_extheader_req(gsn, version, &peer, fd, buffer,
2760 status);
jjako1db1c812003-07-06 20:53:57 +00002761
Harald Weltebed35df2011-11-02 13:06:18 +01002762 continue;
2763 }
2764
2765 if ((gsn->mode == GTP_MODE_GGSN) &&
2766 ((pheader->type == GTP_CREATE_PDP_RSP) ||
Pau Espin Pedrola32e4c42018-07-13 19:05:00 +02002767 (pheader->type == GTP_UPDATE_PDP_RSP))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002768 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNEXPECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002769 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01002770 status,
Pau Espin Pedrol3b84e922018-07-13 18:32:35 +02002771 "Unexpected GTPv1 Signalling Message '%s'\n",
2772 get_value_string(gtp_type_names, pheader->type));
Harald Weltebed35df2011-11-02 13:06:18 +01002773 continue; /* Silently discard 29.60: 11.1.4 */
2774 }
2775
2776 if ((gsn->mode == GTP_MODE_SGSN) &&
2777 ((pheader->type == GTP_CREATE_PDP_REQ) ||
Pau Espin Pedrola32e4c42018-07-13 19:05:00 +02002778 (pheader->type == GTP_UPDATE_PDP_REQ))) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002779 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNEXPECT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002780 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01002781 status,
Pau Espin Pedrol3b84e922018-07-13 18:32:35 +02002782 "Unexpected GTPv1 Signalling Message '%s'\n",
2783 get_value_string(gtp_type_names, pheader->type));
Harald Weltebed35df2011-11-02 13:06:18 +01002784 continue; /* Silently discard 29.60: 11.1.4 */
2785 }
2786
2787 switch (pheader->type) {
2788 case GTP_ECHO_REQ:
2789 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2790 break;
2791 case GTP_ECHO_RSP:
2792 gtp_echo_conf(gsn, version, &peer, buffer, status);
2793 break;
2794 case GTP_NOT_SUPPORTED:
2795 gtp_unsup_ind(gsn, &peer, buffer, status);
2796 break;
2797 case GTP_SUPP_EXT_HEADER:
2798 gtp_extheader_ind(gsn, &peer, buffer, status);
2799 break;
2800 case GTP_CREATE_PDP_REQ:
2801 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer,
2802 status);
2803 break;
2804 case GTP_CREATE_PDP_RSP:
2805 gtp_create_pdp_conf(gsn, version, &peer, buffer,
2806 status);
2807 break;
2808 case GTP_UPDATE_PDP_REQ:
2809 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer,
2810 status);
2811 break;
2812 case GTP_UPDATE_PDP_RSP:
2813 gtp_update_pdp_conf(gsn, version, &peer, buffer,
2814 status);
2815 break;
2816 case GTP_DELETE_PDP_REQ:
2817 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer,
2818 status);
2819 break;
2820 case GTP_DELETE_PDP_RSP:
2821 gtp_delete_pdp_conf(gsn, version, &peer, buffer,
2822 status);
2823 break;
2824 case GTP_ERROR:
2825 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2826 break;
Pau Espin Pedrolf32c6a92021-05-03 17:58:55 +02002827 case GTP_RAN_INFO_RELAY:
2828 gtp_ran_info_relay_ind(gsn, version, &peer, buffer, status);
2829 break;
Harald Weltebed35df2011-11-02 13:06:18 +01002830 default:
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002831 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNKNOWN);
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01002832 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
2833 "Unknown GTP message type received: %u\n",
2834 pheader->type);
Harald Weltebed35df2011-11-02 13:06:18 +01002835 break;
2836 }
2837 }
jjako52c24142002-12-16 13:33:51 +00002838}
2839
jjako08d331d2003-10-13 20:33:30 +00002840int gtp_decaps1u(struct gsn_t *gsn)
2841{
Harald Weltebed35df2011-11-02 13:06:18 +01002842 unsigned char buffer[PACKET_MAX];
2843 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01002844 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01002845 int status;
2846 struct gtp1_header_short *pheader;
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002847 uint8_t version;
Harald Weltebed35df2011-11-02 13:06:18 +01002848 int fd = gsn->fd1u;
jjako08d331d2003-10-13 20:33:30 +00002849
Harald Weltebed35df2011-11-02 13:06:18 +01002850 /* TODO: Need strategy of userspace buffering and blocking */
2851 /* Currently read is non-blocking and send is blocking. */
2852 /* This means that the program have to wait for busy send calls... */
jjako08d331d2003-10-13 20:33:30 +00002853
Harald Weltebed35df2011-11-02 13:06:18 +01002854 while (1) { /* Loop until no more to read */
2855 if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002856 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002857 return -1;
2858 }
2859 peerlen = sizeof(peer);
2860 if ((status =
2861 recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0,
2862 (struct sockaddr *)&peer, &peerlen)) < 0) {
2863 if (errno == EAGAIN)
2864 return 0;
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002865 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_READFROM);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002866 LOGP(DLGTP, LOGL_ERROR,
Alexander Huemerdb852a12015-11-06 20:59:01 +01002867 "recvfrom(fd1u=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n",
Harald Weltebed35df2011-11-02 13:06:18 +01002868 gsn->fd1u, (unsigned long)buffer,
2869 sizeof(buffer), status,
2870 status ? strerror(errno) : "No error");
2871 return -1;
2872 }
jjako08d331d2003-10-13 20:33:30 +00002873
Harald Weltebed35df2011-11-02 13:06:18 +01002874 /* Need at least 1 byte in order to check version */
2875 if (status < (1)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002876 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_EMPTY);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002877 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
2878 status, "Discarding packet - too small\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002879 continue;
2880 }
jjako08d331d2003-10-13 20:33:30 +00002881
Harald Weltebed35df2011-11-02 13:06:18 +01002882 pheader = (struct gtp1_header_short *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00002883
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002884 version = GTPHDR_F_GET_VER(pheader->flags);
2885
Harald Weltebed35df2011-11-02 13:06:18 +01002886 /* Version must be no larger than GTP 1 */
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002887 if (version > 1) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002888 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Pau Espin Pedrola884a952018-01-25 17:28:11 +01002889 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
2890 "Unsupported GTP version %"PRIu8"\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01002891 gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status); /*29.60: 11.1.1 */
2892 continue;
2893 }
jjako08d331d2003-10-13 20:33:30 +00002894
Harald Weltebed35df2011-11-02 13:06:18 +01002895 /* Version must be at least GTP 1 */
2896 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2897 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2898 /* the message */
Pau Espin Pedrola4aada02018-01-25 17:24:38 +01002899 if (version < 1) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002900 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Pau Espin Pedrola884a952018-01-25 17:28:11 +01002901 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
2902 "Unsupported GTP version %"PRIu8"\n", version);
Harald Weltebed35df2011-11-02 13:06:18 +01002903 continue;
2904 }
jjako2c381332003-10-21 19:09:53 +00002905
Harald Weltebed35df2011-11-02 13:06:18 +01002906 /* Check packet flag field (allow both with and without sequence number) */
2907 if (((pheader->flags & 0xf5) != 0x30)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002908 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002909 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Welted37b80a2016-12-15 18:33:15 +01002910 status, "Unsupported packet flags 0x%02x\n", pheader->flags);
Harald Weltebed35df2011-11-02 13:06:18 +01002911 continue;
2912 }
jjako2c381332003-10-21 19:09:53 +00002913
Harald Weltebed35df2011-11-02 13:06:18 +01002914 /* Check length of packet */
2915 if (status < GTP1_HEADER_SIZE_SHORT) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002916 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002917 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
2918 status, "GTP packet too short\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002919 continue; /* Silently discard 29.60: 11.1.2 */
2920 }
2921
2922 /* Check packet length field versus length of packet */
2923 if (status !=
2924 (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002925 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_TOOSHORT);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002926 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
Harald Weltebed35df2011-11-02 13:06:18 +01002927 status,
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002928 "GTP packet length field does not match actual length\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002929 continue; /* Silently discard */
2930 }
2931
2932 /* Check for extension headers */
2933 /* TODO: We really should cycle through the headers and determine */
2934 /* if any have the comprehension required flag set */
Harald Weltefed598f2017-09-24 16:39:22 +08002935 if (((pheader->flags & GTP1HDR_F_EXT) != 0x00)) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002936 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNSUP);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01002937 GTP_LOGPKG(LOGL_ERROR, &peer, buffer,
2938 status, "Unsupported extension header\n");
Harald Weltebed35df2011-11-02 13:06:18 +01002939 gtp_extheader_req(gsn, version, &peer, fd, buffer,
2940 status);
2941
2942 continue;
2943 }
2944
2945 switch (pheader->type) {
2946 case GTP_ECHO_REQ:
2947 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2948 break;
2949 case GTP_ECHO_RSP:
2950 gtp_echo_conf(gsn, version, &peer, buffer, status);
2951 break;
2952 case GTP_SUPP_EXT_HEADER:
2953 gtp_extheader_ind(gsn, &peer, buffer, status);
2954 break;
2955 case GTP_ERROR:
2956 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2957 break;
2958 /* Supported header extensions */
2959 case GTP_GPDU:
2960 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2961 break;
2962 default:
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01002963 rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNKNOWN);
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01002964 GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
2965 "Unknown GTP message type received: %u\n",
2966 pheader->type);
Harald Weltebed35df2011-11-02 13:06:18 +01002967 break;
2968 }
2969 }
jjako08d331d2003-10-13 20:33:30 +00002970}
2971
Harald Weltebed35df2011-11-02 13:06:18 +01002972int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +00002973{
Harald Weltebed35df2011-11-02 13:06:18 +01002974 union gtp_packet packet;
2975 struct sockaddr_in addr;
Harald Welte471e3492017-09-24 16:12:39 +08002976 struct msghdr msgh;
2977 struct iovec iov[2];
Harald Weltebed35df2011-11-02 13:06:18 +01002978 int fd;
jjako52c24142002-12-16 13:33:51 +00002979
Harald Welte471e3492017-09-24 16:12:39 +08002980 /* prepare destination address */
Harald Weltebed35df2011-11-02 13:06:18 +01002981 memset(&addr, 0, sizeof(addr));
2982 addr.sin_family = AF_INET;
jjako0fe0df02004-09-17 11:30:40 +00002983#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +01002984 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +00002985#endif
Harald Weltebed35df2011-11-02 13:06:18 +01002986 memcpy(&addr.sin_addr, pdp->gsnru.v, pdp->gsnru.l); /* TODO range check */
jjako52c24142002-12-16 13:33:51 +00002987
Harald Welte471e3492017-09-24 16:12:39 +08002988 /* prepare msghdr */
2989 memset(&msgh, 0, sizeof(msgh));
2990 msgh.msg_name = &addr;
2991 msgh.msg_namelen = sizeof(addr);
2992 msgh.msg_iov = iov;
2993 msgh.msg_iovlen = ARRAY_SIZE(iov);
2994
2995 /* prepare iovectors */
2996 iov[0].iov_base = &packet;
2997 /* iov[0].iov_len is not known here yet */
2998 iov[1].iov_base = pack;
2999 iov[1].iov_len = len;
3000
Harald Weltebed35df2011-11-02 13:06:18 +01003001 if (pdp->version == 0) {
jjako52c24142002-12-16 13:33:51 +00003002
Harald Welte471e3492017-09-24 16:12:39 +08003003 iov[0].iov_len = GTP0_HEADER_SIZE;
Harald Weltebed35df2011-11-02 13:06:18 +01003004 addr.sin_port = htons(GTP0_PORT);
3005 fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00003006
Harald Weltebed35df2011-11-02 13:06:18 +01003007 get_default_gtp(0, GTP_GPDU, &packet);
3008 packet.gtp0.h.length = hton16(len);
Harald Welte3c1cce22017-09-24 16:40:12 +08003009 if (pdp->tx_gpdu_seq)
3010 packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
3011 else
3012 packet.gtp0.h.seq = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01003013 packet.gtp0.h.flow = hton16(pdp->flru);
Pablo Neira Ayuso746b9442014-03-24 17:58:27 +01003014 packet.gtp0.h.tid = htobe64(pdp_gettid(pdp->imsi, pdp->nsapi));
Harald Weltebed35df2011-11-02 13:06:18 +01003015 } else if (pdp->version == 1) {
jjako08d331d2003-10-13 20:33:30 +00003016
Harald Weltebed35df2011-11-02 13:06:18 +01003017 addr.sin_port = htons(GTP1U_PORT);
3018 fd = gsn->fd1u;
jjakoa7cd2492003-04-11 09:40:12 +00003019
Harald Weltebed35df2011-11-02 13:06:18 +01003020 get_default_gtp(1, GTP_GPDU, &packet);
Harald Welte3c1cce22017-09-24 16:40:12 +08003021 if (pdp->tx_gpdu_seq) {
3022 packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
3023 packet.gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT +
3024 GTP1_HEADER_SIZE_LONG);
3025 packet.gtp1l.h.tei = hton32(pdp->teid_gn);
3026 iov[0].iov_len = GTP1_HEADER_SIZE_LONG;
3027 } else {
3028 packet.gtp1s.h.flags &= ~GTP1HDR_F_SEQ;
3029 packet.gtp1s.h.length = hton16(len);
3030 packet.gtp1s.h.tei = hton32(pdp->teid_gn);
3031 iov[0].iov_len = GTP1_HEADER_SIZE_SHORT;
3032 }
Harald Weltebed35df2011-11-02 13:06:18 +01003033 } else {
Holger Hans Peter Freyther01b40d02014-12-04 15:01:53 +01003034 LOGP(DLGTP, LOGL_ERROR, "Unknown version: %d\n", pdp->version);
Harald Weltebed35df2011-11-02 13:06:18 +01003035 return EOF;
3036 }
3037
3038 if (fcntl(fd, F_SETFL, 0)) {
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003039 LOGP(DLGTP, LOGL_ERROR, "fnctl()\n");
Harald Weltebed35df2011-11-02 13:06:18 +01003040 return -1;
3041 }
3042
Harald Welte471e3492017-09-24 16:12:39 +08003043 if (sendmsg(fd, &msgh, 0) < 0) {
Pau Espin Pedrolb9036af2022-11-02 18:17:56 +01003044 rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
Holger Hans Peter Freyther42ca1d12014-12-03 20:18:43 +01003045 LOGP(DLGTP, LOGL_ERROR,
Harald Welte471e3492017-09-24 16:12:39 +08003046 "sendmsg(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd,
Harald Weltebed35df2011-11-02 13:06:18 +01003047 (unsigned long)&packet, GTP0_HEADER_SIZE + len,
3048 strerror(errno));
3049 return EOF;
3050 }
3051 return 0;
jjako52c24142002-12-16 13:33:51 +00003052}
3053
jjako52c24142002-12-16 13:33:51 +00003054/* ***********************************************************
3055 * Conversion functions
3056 *************************************************************/
3057
jjako52c24142002-12-16 13:33:51 +00003058/* ***********************************************************
3059 * IP address conversion functions
3060 * There exist several types of address representations:
Pau Espin Pedrol732131d2018-01-25 17:23:09 +01003061 * - eua: End User Address. (29.060, 7.7.27, message type 128)
jjako52c24142002-12-16 13:33:51 +00003062 * Used for signalling address to mobile station. Supports IPv4
3063 * IPv6 x.25 etc. etc.
3064 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
3065 * of GSN. If length is 4 it is IPv4. If length is 16 it is IPv6.
3066 * - in_addr: IPv4 address struct.
3067 * - sockaddr_in: Socket API representation of IP address and
3068 * port number.
3069 *************************************************************/
3070
Harald Weltebed35df2011-11-02 13:06:18 +01003071int ipv42eua(struct ul66_t *eua, struct in_addr *src)
3072{
Harald Weltecee75462017-09-24 17:45:05 +08003073 eua->v[0] = PDP_EUA_ORG_IETF;
3074 eua->v[1] = PDP_EUA_TYPE_v4;
Harald Weltebed35df2011-11-02 13:06:18 +01003075 if (src) {
3076 eua->l = 6;
3077 memcpy(&eua->v[2], src, 4);
3078 } else {
3079 eua->l = 2;
3080 }
3081 return 0;
jjako52c24142002-12-16 13:33:51 +00003082}
3083
Harald Weltebed35df2011-11-02 13:06:18 +01003084int eua2ipv4(struct in_addr *dst, struct ul66_t *eua)
3085{
Harald Weltecee75462017-09-24 17:45:05 +08003086 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 +01003087 return -1; /* Not IPv4 address */
3088 memcpy(dst, &eua->v[2], 4);
3089 return 0;
jjako52c24142002-12-16 13:33:51 +00003090}
3091
Harald Weltebed35df2011-11-02 13:06:18 +01003092int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna)
3093{
3094 memset(dst, 0, sizeof(struct in_addr));
3095 if (gsna->l != 4)
3096 return EOF; /* Return if not IPv4 */
3097 memcpy(dst, gsna->v, gsna->l);
3098 return 0;
jjako52c24142002-12-16 13:33:51 +00003099}
3100
Harald Weltebed35df2011-11-02 13:06:18 +01003101int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src)
3102{
3103 memset(gsna, 0, sizeof(struct ul16_t));
3104 gsna->l = 4;
3105 memcpy(gsna->v, src, gsna->l);
3106 return 0;
jjako52c24142002-12-16 13:33:51 +00003107}
Harald Welteb10ee082017-08-12 19:29:16 +02003108
3109/* TS 29.060 has yet again a different encoding for IMSIs than
3110 * what we have in other places, so we cannot use the gsm48
3111 * decoding functions. Also, libgtp uses an uint64_t in
3112 * _network byte order_ to contain BCD digits ?!? */
3113const char *imsi_gtp2str(const uint64_t *imsi)
3114{
Harald Weltea06120d2017-11-06 03:12:54 +09003115 static char buf[sizeof(*imsi)*2+1];
Harald Welteb10ee082017-08-12 19:29:16 +02003116 const uint8_t *imsi8 = (const uint8_t *) imsi;
3117 unsigned int i, j = 0;
3118
3119 for (i = 0; i < sizeof(*imsi); i++) {
3120 uint8_t nibble;
3121
3122 nibble = imsi8[i] & 0xf;
3123 if (nibble == 0xf)
3124 break;
3125 buf[j++] = osmo_bcd2char(nibble);
3126
3127 nibble = imsi8[i] >> 4;
3128 if (nibble == 0xf)
3129 break;
3130 buf[j++] = osmo_bcd2char(nibble);
3131 }
3132
3133 buf[j++] = '\0';
3134 return buf;
3135}
Keithcbc07bd2020-10-10 12:17:26 +02003136
Keithfb2a7292020-10-12 15:32:07 +02003137/* Generate the GTP IMSI IE according to 09.60 Section 7.9.2 */
3138uint64_t gtp_imsi_str2gtp(const char *str)
Keithcbc07bd2020-10-10 12:17:26 +02003139{
Keithfb2a7292020-10-12 15:32:07 +02003140 uint64_t imsi64 = 0;
3141 unsigned int n;
3142 unsigned int imsi_len = strlen(str);
Keithcbc07bd2020-10-10 12:17:26 +02003143
Keithfb2a7292020-10-12 15:32:07 +02003144 if (imsi_len > 16) {
3145 LOGP(DLGTP, LOGL_NOTICE, "IMSI length > 16 not supported!\n");
3146 return 0;
3147 }
3148
3149 for (n = 0; n < 16; n++) {
3150 uint64_t val;
3151 if (n < imsi_len)
3152 val = (str[n]-'0') & 0xf;
3153 else
3154 val = 0xf;
3155 imsi64 |= (val << (n*4));
3156 }
3157 return imsi64;
3158}