blob: dc3a05d5e228368462df8964c65b2c658ed9526c [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
jjako52c24142002-12-16 13:33:51 +00004 *
5 * The contents of this file may be used under the terms of the GNU
6 * General Public License Version 2, provided that the above copyright
7 * notice and this permission notice is included in all copies or
8 * substantial portions of the software.
9 *
jjako52c24142002-12-16 13:33:51 +000010 */
11
12/*
13 * gtp.c: Contains all GTP functionality. Should be able to handle multiple
14 * tunnels in the same program.
15 *
16 * TODO:
17 * - Do we need to handle fragmentation?
18 */
19
jjako52c24142002-12-16 13:33:51 +000020#ifdef __linux__
21#define _GNU_SOURCE 1
22#endif
23
jjako0fe0df02004-09-17 11:30:40 +000024#include "../config.h"
25#ifdef HAVE_STDINT_H
26#include <stdint.h>
27#endif
jjako52c24142002-12-16 13:33:51 +000028
29#include <syslog.h>
30#include <stdio.h>
31#include <stdarg.h>
32#include <stdlib.h>
33#include <sys/time.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38#include <sys/stat.h>
39#include <time.h>
40#include <unistd.h>
41#include <string.h>
42#include <errno.h>
43#include <fcntl.h>
44
45#include <arpa/inet.h>
46
jjakobae2cd42004-01-09 12:04:39 +000047/* #include <stdint.h> ISO C99 types */
jjako52c24142002-12-16 13:33:51 +000048
49#include "pdp.h"
50#include "gtp.h"
51#include "gtpie.h"
52#include "queue.h"
53
jjako1db1c812003-07-06 20:53:57 +000054/* Error reporting functions */
55
Harald Weltebed35df2011-11-02 13:06:18 +010056void gtp_err(int priority, char *filename, int linenum, char *fmt, ...)
57{
58 va_list args;
59 char buf[ERRMSG_SIZE];
jjako1db1c812003-07-06 20:53:57 +000060
Harald Weltebed35df2011-11-02 13:06:18 +010061 va_start(args, fmt);
62 vsnprintf(buf, ERRMSG_SIZE, fmt, args);
63 va_end(args);
64 buf[ERRMSG_SIZE - 1] = 0;
65 syslog(priority, "%s: %d: %s", filename, linenum, buf);
jjako1db1c812003-07-06 20:53:57 +000066}
67
68void gtp_errpack(int pri, char *fn, int ln, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +010069 void *pack, unsigned len, char *fmt, ...)
70{
jjako1db1c812003-07-06 20:53:57 +000071
Harald Weltebed35df2011-11-02 13:06:18 +010072 va_list args;
73 char buf[ERRMSG_SIZE];
74 char buf2[ERRMSG_SIZE];
75 unsigned int n;
76 int pos;
77
78 va_start(args, fmt);
79 vsnprintf(buf, ERRMSG_SIZE, fmt, args);
80 va_end(args);
81 buf[ERRMSG_SIZE - 1] = 0;
82
83 snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:",
84 inet_ntoa(peer->sin_addr), ntohs(peer->sin_port), len);
85 buf2[ERRMSG_SIZE - 1] = 0;
86 pos = strlen(buf2);
87 for (n = 0; n < len; n++) {
88 if ((pos + 4) < ERRMSG_SIZE) {
89 sprintf((buf2 + pos), " %02hhx",
90 ((unsigned char *)pack)[n]);
91 pos += 3;
92 }
93 }
94 buf2[pos] = 0;
95
96 syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
jjako1db1c812003-07-06 20:53:57 +000097
98}
99
jjako52c24142002-12-16 13:33:51 +0000100/* API Functions */
101
Harald Weltebed35df2011-11-02 13:06:18 +0100102const char *gtp_version()
jjako52c24142002-12-16 13:33:51 +0000103{
Harald Weltebed35df2011-11-02 13:06:18 +0100104 return VERSION;
jjako52c24142002-12-16 13:33:51 +0000105}
106
107/* gtp_new */
108/* gtp_free */
109
Harald Weltebed35df2011-11-02 13:06:18 +0100110int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
111 uint64_t imsi, uint8_t nsapi)
112{
113 return pdp_newpdp(pdp, imsi, nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +0000114}
115
Harald Weltebed35df2011-11-02 13:06:18 +0100116int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp)
117{
118 return pdp_freepdp(pdp);
jjako52c24142002-12-16 13:33:51 +0000119}
120
jjako52c24142002-12-16 13:33:51 +0000121/* gtp_gpdu */
122
Harald Weltebed35df2011-11-02 13:06:18 +0100123extern int gtp_fd(struct gsn_t *gsn)
124{
125 return gsn->fd0;
jjako52c24142002-12-16 13:33:51 +0000126}
127
128/* gtp_decaps */
129/* gtp_retrans */
130/* gtp_retranstimeout */
131
jjako08d331d2003-10-13 20:33:30 +0000132int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +0100133 int (*cb) (struct sockaddr_in * peer))
134{
135 gsn->cb_unsup_ind = cb;
136 return 0;
jjako08d331d2003-10-13 20:33:30 +0000137}
138
jjako2c381332003-10-21 19:09:53 +0000139int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +0100140 int (*cb) (struct sockaddr_in * peer))
141{
142 gsn->cb_extheader_ind = cb;
143 return 0;
jjako2c381332003-10-21 19:09:53 +0000144}
145
jjako08d331d2003-10-13 20:33:30 +0000146/* API: Initialise delete context callback */
147/* Called whenever a pdp context is deleted for any reason */
Harald Weltebed35df2011-11-02 13:06:18 +0100148int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb) (struct pdp_t * pdp))
jjako52c24142002-12-16 13:33:51 +0000149{
Harald Weltebed35df2011-11-02 13:06:18 +0100150 gsn->cb_delete_context = cb;
151 return 0;
jjako52c24142002-12-16 13:33:51 +0000152}
153
jjako52c24142002-12-16 13:33:51 +0000154int gtp_set_cb_conf(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +0100155 int (*cb) (int type, int cause,
156 struct pdp_t * pdp, void *cbp))
157{
158 gsn->cb_conf = cb;
159 return 0;
jjako52c24142002-12-16 13:33:51 +0000160}
161
Harald Welte629e9862010-12-24 20:58:09 +0100162int gtp_set_cb_recovery(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +0100163 int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
164{
165 gsn->cb_recovery = cb;
166 return 0;
Harald Welte629e9862010-12-24 20:58:09 +0100167}
168
jjako08d331d2003-10-13 20:33:30 +0000169extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +0100170 int (*cb_data_ind) (struct pdp_t * pdp,
171 void *pack, unsigned len))
jjako52c24142002-12-16 13:33:51 +0000172{
Harald Weltebed35df2011-11-02 13:06:18 +0100173 gsn->cb_data_ind = cb_data_ind;
174 return 0;
jjako52c24142002-12-16 13:33:51 +0000175}
176
jjako08d331d2003-10-13 20:33:30 +0000177/**
178 * get_default_gtp()
179 * Generate a GPRS Tunneling Protocol signalling packet header, depending
180 * on GTP version and message type. pdp is used for teid/flow label.
181 * *packet must be allocated by the calling function, and be large enough
182 * to hold the packet header.
183 * returns the length of the header. 0 on error.
184 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100185static unsigned int get_default_gtp(int version, uint8_t type, void *packet)
186{
187 struct gtp0_header *gtp0_default = (struct gtp0_header *)packet;
188 struct gtp1_header_long *gtp1_default =
189 (struct gtp1_header_long *)packet;
190 switch (version) {
191 case 0:
192 /* Initialise "standard" GTP0 header */
193 memset(gtp0_default, 0, sizeof(struct gtp0_header));
194 gtp0_default->flags = 0x1e;
195 gtp0_default->type = hton8(type);
196 gtp0_default->spare1 = 0xff;
197 gtp0_default->spare2 = 0xff;
198 gtp0_default->spare3 = 0xff;
199 gtp0_default->number = 0xff;
200 return GTP0_HEADER_SIZE;
201 case 1:
202 /* Initialise "standard" GTP1 header */
203 /* 29.060: 8.2: S=1 and PN=0 */
204 /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */
205 /* and Supported Extension Headers Notification, the S field shall be */
206 /* set to 1 */
207 /* Currently extension headers are not supported */
208 memset(gtp1_default, 0, sizeof(struct gtp1_header_long));
209 gtp1_default->flags = 0x32; /* No extension, enable sequence, no N-PDU */
210 gtp1_default->type = hton8(type);
211 return GTP1_HEADER_SIZE_LONG;
212 default:
213 gtp_err(LOG_ERR, __FILE__, __LINE__,
214 "Unknown GTP packet version");
215 return 0;
216 }
jjako52c24142002-12-16 13:33:51 +0000217}
218
jjako08d331d2003-10-13 20:33:30 +0000219/**
220 * get_seq()
221 * Get sequence number of a packet.
222 * Returns 0 on error
223 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100224static uint16_t get_seq(void *pack)
225{
226 union gtp_packet *packet = (union gtp_packet *)pack;
jjako08d331d2003-10-13 20:33:30 +0000227
Harald Weltebed35df2011-11-02 13:06:18 +0100228 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
229 return ntoh16(packet->gtp0.h.seq);
230 } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
231 return ntoh16(packet->gtp1l.h.seq);
232 } else {
233 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
234 return 0;
235 }
jjako08d331d2003-10-13 20:33:30 +0000236}
237
238/**
239 * get_tid()
240 * Get tunnel identifier of a packet.
241 * Returns 0 on error
242 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100243static uint64_t get_tid(void *pack)
244{
245 union gtp_packet *packet = (union gtp_packet *)pack;
246
247 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
248 return packet->gtp0.h.tid;
249 }
250 return 0;
jjako08d331d2003-10-13 20:33:30 +0000251}
252
253/**
254 * get_hlen()
255 * Get the header length of a packet.
256 * Returns 0 on error
257 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100258static uint16_t get_hlen(void *pack)
259{
260 union gtp_packet *packet = (union gtp_packet *)pack;
jjako08d331d2003-10-13 20:33:30 +0000261
Harald Weltebed35df2011-11-02 13:06:18 +0100262 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
263 return GTP0_HEADER_SIZE;
264 } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
265 return GTP1_HEADER_SIZE_LONG;
266 } else if ((packet->flags & 0xe7) == 0x20) { /* Short version 1 */
267 return GTP1_HEADER_SIZE_SHORT;
268 } else {
269 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
270 return 0;
271 }
jjako08d331d2003-10-13 20:33:30 +0000272}
273
274/**
275 * get_tei()
276 * Get the tunnel endpoint identifier (flow label) of a packet.
277 * Returns 0xffffffff on error.
278 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100279static uint32_t get_tei(void *pack)
280{
281 union gtp_packet *packet = (union gtp_packet *)pack;
jjako08d331d2003-10-13 20:33:30 +0000282
Harald Weltebed35df2011-11-02 13:06:18 +0100283 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
284 return ntoh16(packet->gtp0.h.flow);
285 } else if ((packet->flags & 0xe0) == 0x20) { /* Version 1 */
286 return ntoh32(packet->gtp1l.h.tei);
287 } else {
288 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
289 return 0xffffffff;
290 }
jjako08d331d2003-10-13 20:33:30 +0000291}
jjakoa7cd2492003-04-11 09:40:12 +0000292
jjako52c24142002-12-16 13:33:51 +0000293int print_packet(void *packet, unsigned len)
294{
Harald Weltebed35df2011-11-02 13:06:18 +0100295 unsigned int i;
296 printf("The packet looks like this (%d bytes):\n", len);
297 for (i = 0; i < len; i++) {
298 printf("%02x ", (unsigned char)*(char *)(packet + i));
299 if (!((i + 1) % 16))
300 printf("\n");
301 };
302 printf("\n");
303 return 0;
jjako52c24142002-12-16 13:33:51 +0000304}
305
Harald Weltebed35df2011-11-02 13:06:18 +0100306char *snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer,
307 void *pack, unsigned len, char *buf, int size)
308{
309 unsigned int n;
310 int pos;
311 snprintf(buf, size, "Packet from %s:%u, length: %d, content:",
312 inet_ntoa(peer->sin_addr), ntohs(peer->sin_port), len);
313 buf[size - 1] = 0;
314 pos = strlen(buf);
315 for (n = 0; n < len; n++) {
316 if ((pos + 4) < size) {
317 sprintf((buf + pos), " %02hhx",
318 ((unsigned char *)pack)[n]);
319 pos += 3;
320 }
321 }
322 buf[pos] = 0;
323 return buf;
jjako52c24142002-12-16 13:33:51 +0000324}
325
jjako52c24142002-12-16 13:33:51 +0000326/* ***********************************************************
327 * Reliable delivery of signalling messages
328 *
329 * Sequence numbers are used for both signalling messages and
330 * data messages.
331 *
332 * For data messages each tunnel maintains a sequence counter,
333 * which is incremented by one each time a new data message
334 * is sent. The sequence number starts at (0) zero at tunnel
335 * establishment, and wraps around at 65535 (29.060 9.3.1.1
336 * and 09.60 8.1.1.1). The sequence numbers are either ignored,
337 * or can be used to check the validity of the message in the
338 * receiver, or for reordering af packets.
339 *
340 * For signalling messages the sequence number is used by
341 * signalling messages for which a response is defined. A response
342 * message should copy the sequence from the corresponding request
343 * message. The sequence number "unambiguously" identifies a request
344 * message within a given path, with a path being defined as a set of
345 * two endpoints (29.060 8.2, 29.060 7.6, 09.60 7.8). "All request
346 * messages shall be responded to, and all response messages associated
347 * with a certain request shall always include the same information"
348 *
349 * We take this to mean that the GSN transmitting a request is free to
350 * choose the sequence number, as long as it is unique within a given path.
351 * It means that we are allowed to count backwards, or roll over at 17
352 * if we prefer that. It also means that we can use the same counter for
353 * all paths. This has the advantage that the transmitted request sequence
354 * numbers are unique within each GSN, and also we dont have to mess around
355 * with path setup and teardown.
356 *
357 * If a response message is lost, the request will be retransmitted, and
358 * the receiving GSN will receive a "duplicated" request. The standard
359 * requires the receiving GSN to send a response, with the same information
360 * as in the original response. For most messages this happens automatically:
361 *
362 * Echo: Automatically dublicates the original response
363 * Create pdp context: The SGSN may send create context request even if
364 * a context allready exist (imsi+nsapi?). This means that the reply will
365 automatically dublicate the original response. It might however have
jjako08d331d2003-10-13 20:33:30 +0000366 * side effects in the application which is asked twice to validate
367 * the login.
jjako52c24142002-12-16 13:33:51 +0000368 * Update pdp context: Automatically dublicates the original response???
369 * Delete pdp context. Automatically in gtp0, but in gtp1 will generate
370 * a nonexist reply message.
371 *
372 * The correct solution will be to make a queue containing response messages.
373 * This queue should be checked whenever a request is received. If the
374 * response is allready in the queue that response should be transmitted.
375 * It should be possible to find messages in this queue on the basis of
376 * the sequence number and peer GSN IP address (The sequense number is unique
377 * within each path). This need to be implemented by a hash table. Furthermore
378 * it should be possibly to delete messages based on a timeout. This can be
379 * achieved by means of a linked list. The timeout value need to be larger
380 * than T3-RESPONSE * N3-REQUESTS (recommended value 5). These timers are
381 * set in the peer GSN, so there is no way to know these parameters. On the
382 * other hand the timeout value need to be so small that we do not receive
383 * wraparound sequence numbere before the message is deleted. 60 seconds is
384 * probably not a bad choise.
385 *
386 * This queue however is first really needed from gtp1.
387 *
388 * gtp_req:
389 * Send off a signalling message with appropiate sequence
390 * number. Store packet in queue.
391 * gtp_conf:
392 * Remove an incoming confirmation from the queue
393 * gtp_resp:
jjako08d331d2003-10-13 20:33:30 +0000394 * Send off a response to a request. Use the same sequence
jjako52c24142002-12-16 13:33:51 +0000395 * number in the response as in the request.
jjako2c381332003-10-21 19:09:53 +0000396 * gtp_notification:
397 * Send off a notification message. This is neither a request nor
398 * a response. Both TEI and SEQ are zero.
jjako52c24142002-12-16 13:33:51 +0000399 * gtp_retrans:
400 * Retransmit any outstanding packets which have exceeded
401 * a predefined timeout.
402 *************************************************************/
403
jjako08d331d2003-10-13 20:33:30 +0000404int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +0100405 union gtp_packet *packet, int len,
406 struct in_addr *inetaddr, void *cbp)
407{
408 struct sockaddr_in addr;
409 struct qmsg_t *qmsg;
410 int fd;
jjako08d331d2003-10-13 20:33:30 +0000411
Harald Weltebed35df2011-11-02 13:06:18 +0100412 memset(&addr, 0, sizeof(addr));
413 addr.sin_family = AF_INET;
414 addr.sin_addr = *inetaddr;
jjako0fe0df02004-09-17 11:30:40 +0000415#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100416 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +0000417#endif
jjako52c24142002-12-16 13:33:51 +0000418
Harald Weltebed35df2011-11-02 13:06:18 +0100419 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
420 addr.sin_port = htons(GTP0_PORT);
421 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
422 packet->gtp0.h.seq = hton16(gsn->seq_next);
423 if (pdp)
424 packet->gtp0.h.tid =
425 (pdp->imsi & 0x0fffffffffffffffull) +
426 ((uint64_t) pdp->nsapi << 60);
427 if (pdp && ((packet->gtp0.h.type == GTP_GPDU)
428 || (packet->gtp0.h.type == GTP_ERROR)))
429 packet->gtp0.h.flow = hton16(pdp->flru);
430 else if (pdp)
431 packet->gtp0.h.flow = hton16(pdp->flrc);
432 fd = gsn->fd0;
433 } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
434 addr.sin_port = htons(GTP1C_PORT);
435 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
436 packet->gtp1l.h.seq = hton16(gsn->seq_next);
437 if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) ||
438 (packet->gtp1l.h.type == GTP_ERROR)))
439 packet->gtp1l.h.tei = hton32(pdp->teid_gn);
440 else if (pdp)
441 packet->gtp1l.h.tei = hton32(pdp->teic_gn);
442 fd = gsn->fd1c;
443 } else {
444 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
445 return -1;
446 }
jjako52c24142002-12-16 13:33:51 +0000447
Harald Weltebed35df2011-11-02 13:06:18 +0100448 if (sendto(fd, packet, len, 0,
449 (struct sockaddr *)&addr, sizeof(addr)) < 0) {
450 gsn->err_sendto++;
451 gtp_err(LOG_ERR, __FILE__, __LINE__,
452 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
453 (unsigned long)&packet, len, strerror(errno));
454 return -1;
455 }
456
457 /* Use new queue structure */
458 if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) {
459 gsn->err_queuefull++;
460 gtp_err(LOG_ERR, __FILE__, __LINE__,
461 "Retransmit queue is full");
462 } else {
463 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
464 qmsg->l = len;
465 qmsg->timeout = time(NULL) + 3; /* When to timeout */
466 qmsg->retrans = 0; /* No retransmissions so far */
467 qmsg->cbp = cbp;
468 qmsg->type = ntoh8(packet->gtp0.h.type);
469 qmsg->fd = fd;
470 }
471 gsn->seq_next++; /* Count up this time */
472 return 0;
jjako52c24142002-12-16 13:33:51 +0000473}
474
475/* gtp_conf
476 * Remove signalling packet from retransmission queue.
477 * return 0 on success, EOF if packet was not found */
478
479int gtp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +0100480 union gtp_packet *packet, int len, uint8_t * type, void **cbp)
481{
jjako52c24142002-12-16 13:33:51 +0000482
Harald Weltebed35df2011-11-02 13:06:18 +0100483 uint16_t seq;
jjako08d331d2003-10-13 20:33:30 +0000484
Harald Weltebed35df2011-11-02 13:06:18 +0100485 if ((packet->gtp0.h.flags & 0xe0) == 0x00)
486 seq = ntoh16(packet->gtp0.h.seq);
487 else if ((packet->gtp1l.h.flags & 0xe2) == 0x22)
488 seq = ntoh16(packet->gtp1l.h.seq);
489 else {
490 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
491 "Unknown GTP packet version");
492 return EOF;
493 }
jjako08d331d2003-10-13 20:33:30 +0000494
Harald Weltebed35df2011-11-02 13:06:18 +0100495 if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) {
496 gsn->err_seq++;
497 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
498 "Confirmation packet not found in queue");
499 return EOF;
500 }
jjako52c24142002-12-16 13:33:51 +0000501
Harald Weltebed35df2011-11-02 13:06:18 +0100502 return 0;
jjako52c24142002-12-16 13:33:51 +0000503}
504
Harald Weltebed35df2011-11-02 13:06:18 +0100505int gtp_retrans(struct gsn_t *gsn)
506{
507 /* Retransmit any outstanding packets */
508 /* Remove from queue if maxretrans exceeded */
509 time_t now;
510 struct qmsg_t *qmsg;
511 now = time(NULL);
512 /*printf("Retrans: New beginning %d\n", (int) now); */
jjako52c24142002-12-16 13:33:51 +0000513
Harald Weltebed35df2011-11-02 13:06:18 +0100514 while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
515 (qmsg->timeout <= now)) {
516 /*printf("Retrans timeout found: %d\n", (int) time(NULL)); */
517 if (qmsg->retrans > 3) { /* To many retrans */
518 if (gsn->cb_conf)
519 gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
520 queue_freemsg(gsn->queue_req, qmsg);
521 } else {
522 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
523 (struct sockaddr *)&qmsg->peer,
524 sizeof(struct sockaddr_in)) < 0) {
525 gsn->err_sendto++;
526 gtp_err(LOG_ERR, __FILE__, __LINE__,
527 "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s",
528 gsn->fd0, (unsigned long)&qmsg->p,
529 qmsg->l, strerror(errno));
530 }
531 queue_back(gsn->queue_req, qmsg);
532 qmsg->timeout = now + 3;
533 qmsg->retrans++;
534 }
535 }
jjako52c24142002-12-16 13:33:51 +0000536
Harald Weltebed35df2011-11-02 13:06:18 +0100537 /* Also clean up reply timeouts */
538 while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
539 (qmsg->timeout < now)) {
540 /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL)); */
541 queue_freemsg(gsn->queue_resp, qmsg);
542 }
jjako52c24142002-12-16 13:33:51 +0000543
Harald Weltebed35df2011-11-02 13:06:18 +0100544 return 0;
jjako52c24142002-12-16 13:33:51 +0000545}
546
Harald Weltebed35df2011-11-02 13:06:18 +0100547int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
548{
549 time_t now, later;
550 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000551
Harald Weltebed35df2011-11-02 13:06:18 +0100552 if (queue_getfirst(gsn->queue_req, &qmsg)) {
553 timeout->tv_sec = 10;
554 timeout->tv_usec = 0;
555 } else {
556 now = time(NULL);
557 later = qmsg->timeout;
558 timeout->tv_sec = later - now;
559 timeout->tv_usec = 0;
560 if (timeout->tv_sec < 0)
561 timeout->tv_sec = 0; /* No negative allowed */
562 if (timeout->tv_sec > 10)
563 timeout->tv_sec = 10; /* Max sleep for 10 sec */
564 }
565 return 0;
jjako52c24142002-12-16 13:33:51 +0000566}
567
Harald Weltebed35df2011-11-02 13:06:18 +0100568int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp,
jjako08d331d2003-10-13 20:33:30 +0000569 union gtp_packet *packet, int len,
Harald Weltebed35df2011-11-02 13:06:18 +0100570 struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
571{
572 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000573
Harald Weltebed35df2011-11-02 13:06:18 +0100574 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
575 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
576 packet->gtp0.h.seq = hton16(seq);
577 packet->gtp0.h.tid = tid;
578 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
579 (packet->gtp0.h.type == GTP_ERROR)))
580 packet->gtp0.h.flow = hton16(pdp->flru);
581 else if (pdp)
582 packet->gtp0.h.flow = hton16(pdp->flrc);
583 } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
584 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
585 packet->gtp1l.h.seq = hton16(seq);
586 if (pdp && (fd == gsn->fd1u))
587 packet->gtp1l.h.tei = hton32(pdp->teid_gn);
588 else if (pdp)
589 packet->gtp1l.h.tei = hton32(pdp->teic_gn);
590 } else {
591 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
592 return -1;
593 }
jjako08d331d2003-10-13 20:33:30 +0000594
Harald Weltebed35df2011-11-02 13:06:18 +0100595 if (fcntl(fd, F_SETFL, 0)) {
596 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
597 return -1;
598 }
jjako52c24142002-12-16 13:33:51 +0000599
Harald Weltebed35df2011-11-02 13:06:18 +0100600 if (sendto(fd, packet, len, 0,
601 (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
602 gsn->err_sendto++;
603 gtp_err(LOG_ERR, __FILE__, __LINE__,
604 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
605 (unsigned long)&packet, len, strerror(errno));
606 return -1;
607 }
608
609 /* Use new queue structure */
610 if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) {
611 gsn->err_queuefull++;
612 gtp_err(LOG_ERR, __FILE__, __LINE__,
613 "Retransmit queue is full");
614 } else {
615 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
616 qmsg->l = len;
617 qmsg->timeout = time(NULL) + 60; /* When to timeout */
618 qmsg->retrans = 0; /* No retransmissions so far */
619 qmsg->cbp = NULL;
620 qmsg->type = 0;
621 qmsg->fd = fd;
622 }
623 return 0;
jjako52c24142002-12-16 13:33:51 +0000624}
625
jjako2c381332003-10-21 19:09:53 +0000626int gtp_notification(struct gsn_t *gsn, int version,
627 union gtp_packet *packet, int len,
Harald Weltebed35df2011-11-02 13:06:18 +0100628 struct sockaddr_in *peer, int fd, uint16_t seq)
629{
jjako2c381332003-10-21 19:09:53 +0000630
Harald Weltebed35df2011-11-02 13:06:18 +0100631 struct sockaddr_in addr;
jjako2c381332003-10-21 19:09:53 +0000632
Harald Weltebed35df2011-11-02 13:06:18 +0100633 memcpy(&addr, peer, sizeof(addr));
jjako2c381332003-10-21 19:09:53 +0000634
Harald Weltebed35df2011-11-02 13:06:18 +0100635 /* In GTP0 notifications are treated as replies. In GTP1 they
636 are requests for which there is no reply */
jjako2c381332003-10-21 19:09:53 +0000637
Harald Weltebed35df2011-11-02 13:06:18 +0100638 if (fd == gsn->fd1c)
639 addr.sin_port = htons(GTP1C_PORT);
640 else if (fd == gsn->fd1u)
641 addr.sin_port = htons(GTP1C_PORT);
jjako2c381332003-10-21 19:09:53 +0000642
Harald Weltebed35df2011-11-02 13:06:18 +0100643 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
644 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
645 packet->gtp0.h.seq = hton16(seq);
646 } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
647 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
648 packet->gtp1l.h.seq = hton16(seq);
649 } else {
650 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
651 return -1;
652 }
653
654 if (fcntl(fd, F_SETFL, 0)) {
655 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
656 return -1;
657 }
658
659 if (sendto(fd, packet, len, 0,
660 (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
661 gsn->err_sendto++;
662 gtp_err(LOG_ERR, __FILE__, __LINE__,
663 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
664 (unsigned long)&packet, len, strerror(errno));
665 return -1;
666 }
667 return 0;
jjako2c381332003-10-21 19:09:53 +0000668}
669
Harald Weltebed35df2011-11-02 13:06:18 +0100670int gtp_dublicate(struct gsn_t *gsn, int version,
671 struct sockaddr_in *peer, uint16_t seq)
672{
673 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000674
Harald Weltebed35df2011-11-02 13:06:18 +0100675 if (queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) {
676 return EOF; /* Notfound */
677 }
jjakoa7cd2492003-04-11 09:40:12 +0000678
Harald Weltebed35df2011-11-02 13:06:18 +0100679 if (fcntl(qmsg->fd, F_SETFL, 0)) {
680 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
681 return -1;
682 }
683
684 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
685 (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
686 gsn->err_sendto++;
687 gtp_err(LOG_ERR, __FILE__, __LINE__,
688 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s",
689 qmsg->fd, (unsigned long)&qmsg->p, qmsg->l,
690 strerror(errno));
691 }
692 return 0;
jjako52c24142002-12-16 13:33:51 +0000693}
694
jjako52c24142002-12-16 13:33:51 +0000695/* Perform restoration and recovery error handling as described in 29.060 */
Harald Weltebed35df2011-11-02 13:06:18 +0100696static void log_restart(struct gsn_t *gsn)
697{
jjako52c24142002-12-16 13:33:51 +0000698 FILE *f;
Emmanuel Bretelle111e0542010-09-06 19:49:16 +0200699 int i, rc;
jjako52c24142002-12-16 13:33:51 +0000700 int counter = 0;
701 char filename[NAMESIZE];
702
Harald Weltebed35df2011-11-02 13:06:18 +0100703 filename[NAMESIZE - 1] = 0; /* No null term. guarantee by strncpy */
704 strncpy(filename, gsn->statedir, NAMESIZE - 1);
705 strncat(filename, RESTART_FILE, NAMESIZE - 1 - sizeof(RESTART_FILE));
jjako52c24142002-12-16 13:33:51 +0000706
707 i = umask(022);
708
709 /* We try to open file. On failure we will later try to create file */
710 if (!(f = fopen(filename, "r"))) {
jjako581c9f02003-10-22 11:28:20 +0000711
Harald Weltebed35df2011-11-02 13:06:18 +0100712 gtp_err(LOG_ERR, __FILE__, __LINE__,
713 "State information file (%s) not found. Creating new file.",
714 filename);
715 } else {
716 umask(i);
717 rc = fscanf(f, "%d", &counter);
718 if (rc != 1) {
719 gtp_err(LOG_ERR, __FILE__, __LINE__,
720 "fscanf failed to read counter value");
721 return;
722 }
723 if (fclose(f)) {
724 gtp_err(LOG_ERR, __FILE__, __LINE__,
725 "fclose failed: Error = %s", strerror(errno));
726 }
jjako52c24142002-12-16 13:33:51 +0000727 }
Harald Weltebed35df2011-11-02 13:06:18 +0100728
729 gsn->restart_counter = (unsigned char)counter;
jjako52c24142002-12-16 13:33:51 +0000730 gsn->restart_counter++;
Harald Weltebed35df2011-11-02 13:06:18 +0100731
jjako52c24142002-12-16 13:33:51 +0000732 if (!(f = fopen(filename, "w"))) {
Harald Weltebed35df2011-11-02 13:06:18 +0100733 gtp_err(LOG_ERR, __FILE__, __LINE__,
734 "fopen(path=%s, mode=%s) failed: Error = %s", filename,
735 "w", strerror(errno));
736 return;
jjako52c24142002-12-16 13:33:51 +0000737 }
738
739 umask(i);
740 fprintf(f, "%d\n", gsn->restart_counter);
741 if (fclose(f)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100742 gtp_err(LOG_ERR, __FILE__, __LINE__,
743 "fclose failed: Error = %s", strerror(errno));
744 return;
jjako52c24142002-12-16 13:33:51 +0000745 }
746}
747
jjako1db1c812003-07-06 20:53:57 +0000748int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
Harald Weltebed35df2011-11-02 13:06:18 +0100749 int mode)
jjako52c24142002-12-16 13:33:51 +0000750{
Harald Weltebed35df2011-11-02 13:06:18 +0100751 struct sockaddr_in addr;
jjako52c24142002-12-16 13:33:51 +0000752
Harald Weltebed35df2011-11-02 13:06:18 +0100753 syslog(LOG_ERR, "GTP: gtp_newgsn() started");
jjako52c24142002-12-16 13:33:51 +0000754
Harald Weltebed35df2011-11-02 13:06:18 +0100755 *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
jjakoa7cd2492003-04-11 09:40:12 +0000756
Harald Weltebed35df2011-11-02 13:06:18 +0100757 (*gsn)->statedir = statedir;
758 log_restart(*gsn);
jjako52c24142002-12-16 13:33:51 +0000759
Harald Weltebed35df2011-11-02 13:06:18 +0100760 /* Initialise sequence number */
761 (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
jjako52c24142002-12-16 13:33:51 +0000762
Harald Weltebed35df2011-11-02 13:06:18 +0100763 /* Initialise request retransmit queue */
764 queue_new(&(*gsn)->queue_req);
765 queue_new(&(*gsn)->queue_resp);
jjako08d331d2003-10-13 20:33:30 +0000766
Harald Weltebed35df2011-11-02 13:06:18 +0100767 /* Initialise pdp table */
768 pdp_init();
jjako08d331d2003-10-13 20:33:30 +0000769
Harald Weltebed35df2011-11-02 13:06:18 +0100770 /* Initialise call back functions */
771 (*gsn)->cb_create_context_ind = 0;
772 (*gsn)->cb_delete_context = 0;
773 (*gsn)->cb_unsup_ind = 0;
774 (*gsn)->cb_conf = 0;
775 (*gsn)->cb_data_ind = 0;
776
777 /* Store function parameters */
778 (*gsn)->gsnc = *listen;
779 (*gsn)->gsnu = *listen;
780 (*gsn)->mode = mode;
781
782 /* Create GTP version 0 socket */
783 if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
784 (*gsn)->err_socket++;
785 gtp_err(LOG_ERR, __FILE__, __LINE__,
786 "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s",
787 AF_INET, SOCK_DGRAM, 0, strerror(errno));
788 return -1;
789 }
790
791 memset(&addr, 0, sizeof(addr));
792 addr.sin_family = AF_INET;
793 addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
794 addr.sin_port = htons(GTP0_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000795#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100796 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +0000797#endif
jjako08d331d2003-10-13 20:33:30 +0000798
Harald Weltebed35df2011-11-02 13:06:18 +0100799 if (bind((*gsn)->fd0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
800 (*gsn)->err_socket++;
801 gtp_err(LOG_ERR, __FILE__, __LINE__,
802 "bind(fd0=%d, addr=%lx, len=%d) failed: Error = %s",
803 (*gsn)->fd0, (unsigned long)&addr, sizeof(addr),
804 strerror(errno));
805 return -1;
806 }
jjako08d331d2003-10-13 20:33:30 +0000807
Harald Weltebed35df2011-11-02 13:06:18 +0100808 /* Create GTP version 1 control plane socket */
809 if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
810 (*gsn)->err_socket++;
811 gtp_err(LOG_ERR, __FILE__, __LINE__,
812 "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s",
813 AF_INET, SOCK_DGRAM, 0, strerror(errno));
814 return -1;
815 }
816
817 memset(&addr, 0, sizeof(addr));
818 addr.sin_family = AF_INET;
819 addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
820 addr.sin_port = htons(GTP1C_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000821#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100822 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +0000823#endif
jjako08d331d2003-10-13 20:33:30 +0000824
Harald Weltebed35df2011-11-02 13:06:18 +0100825 if (bind((*gsn)->fd1c, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
826 (*gsn)->err_socket++;
827 gtp_err(LOG_ERR, __FILE__, __LINE__,
828 "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s",
829 (*gsn)->fd1c, (unsigned long)&addr, sizeof(addr),
830 strerror(errno));
831 return -1;
832 }
jjako08d331d2003-10-13 20:33:30 +0000833
Harald Weltebed35df2011-11-02 13:06:18 +0100834 /* Create GTP version 1 user plane socket */
835 if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
836 (*gsn)->err_socket++;
837 gtp_err(LOG_ERR, __FILE__, __LINE__,
838 "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s",
839 AF_INET, SOCK_DGRAM, 0, strerror(errno));
840 return -1;
841 }
842
843 memset(&addr, 0, sizeof(addr));
844 addr.sin_family = AF_INET;
845 addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
846 addr.sin_port = htons(GTP1U_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000847#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100848 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +0000849#endif
jjako52c24142002-12-16 13:33:51 +0000850
Harald Weltebed35df2011-11-02 13:06:18 +0100851 if (bind((*gsn)->fd1u, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
852 (*gsn)->err_socket++;
853 gtp_err(LOG_ERR, __FILE__, __LINE__,
854 "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s",
855 (*gsn)->fd1c, (unsigned long)&addr, sizeof(addr),
856 strerror(errno));
857 return -1;
858 }
859
860 return 0;
jjako52c24142002-12-16 13:33:51 +0000861}
862
Harald Weltebed35df2011-11-02 13:06:18 +0100863int gtp_free(struct gsn_t *gsn)
864{
jjako52c24142002-12-16 13:33:51 +0000865
Harald Weltebed35df2011-11-02 13:06:18 +0100866 /* Clean up retransmit queues */
867 queue_free(gsn->queue_req);
868 queue_free(gsn->queue_resp);
jjako52c24142002-12-16 13:33:51 +0000869
Harald Weltebed35df2011-11-02 13:06:18 +0100870 close(gsn->fd0);
871 close(gsn->fd1c);
872 close(gsn->fd1u);
873
874 free(gsn);
875 return 0;
jjako52c24142002-12-16 13:33:51 +0000876}
877
878/* ***********************************************************
879 * Path management messages
880 * Messages: echo and version not supported.
881 * A path is connection between two UDP/IP endpoints
882 *
883 * A path is either using GTP0 or GTP1. A path can be
884 * established by any kind of GTP message??
885
886 * Which source port to use?
887 * GTP-C request destination port is 2123/3386
888 * GTP-U request destination port is 2152/3386
889 * T-PDU destination port is 2152/3386.
890 * For the above messages the source port is locally allocated.
891 * For response messages src=rx-dst and dst=rx-src.
892 * For simplicity we should probably use 2123+2152/3386 as
893 * src port even for the cases where src can be locally
894 * allocated. This also means that we have to listen only to
895 * the same ports.
896 * For response messages we need to be able to respond to
897 * the relevant src port even if it is locally allocated by
898 * the peer.
899 *
900 * The need for path management!
901 * We might need to keep a list of active paths. This might
902 * be in the form of remote IP address + UDP port numbers.
903 * (We will consider a path astablished if we have a context
904 * with the node in question)
905 *************************************************************/
906
907/* Send off an echo request */
jjako08d331d2003-10-13 20:33:30 +0000908int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
909 struct in_addr *inetaddr)
jjako52c24142002-12-16 13:33:51 +0000910{
Harald Weltebed35df2011-11-02 13:06:18 +0100911 union gtp_packet packet;
912 unsigned int length = get_default_gtp(version, GTP_ECHO_REQ, &packet);
913 return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp);
jjako52c24142002-12-16 13:33:51 +0000914}
915
jjako08d331d2003-10-13 20:33:30 +0000916/* Send off an echo reply */
917int gtp_echo_resp(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +0100918 struct sockaddr_in *peer, int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000919{
Harald Weltebed35df2011-11-02 13:06:18 +0100920 union gtp_packet packet;
921 unsigned int length = get_default_gtp(version, GTP_ECHO_RSP, &packet);
922 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
923 gsn->restart_counter);
924 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
925 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +0000926}
927
jjako52c24142002-12-16 13:33:51 +0000928/* Handle a received echo request */
Harald Weltebed35df2011-11-02 13:06:18 +0100929int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
930 int fd, void *pack, unsigned len)
931{
jjako52c24142002-12-16 13:33:51 +0000932
Harald Weltebed35df2011-11-02 13:06:18 +0100933 /* Check if it was a dublicate request */
934 if (!gtp_dublicate(gsn, 0, peer, get_seq(pack)))
935 return 0;
jjako52c24142002-12-16 13:33:51 +0000936
Harald Weltebed35df2011-11-02 13:06:18 +0100937 /* Send off reply to request */
938 return gtp_echo_resp(gsn, version, peer, fd, pack, len);
jjako52c24142002-12-16 13:33:51 +0000939}
940
941/* Handle a received echo reply */
jjako08d331d2003-10-13 20:33:30 +0000942int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +0100943 void *pack, unsigned len)
944{
945 union gtpie_member *ie[GTPIE_SIZE];
946 unsigned char recovery;
947 void *cbp = NULL;
948 uint8_t type = 0;
949 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +0000950
Harald Weltebed35df2011-11-02 13:06:18 +0100951 /* Remove packet from queue */
952 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
953 return EOF;
jjako52c24142002-12-16 13:33:51 +0000954
Harald Weltebed35df2011-11-02 13:06:18 +0100955 /* Extract information elements into a pointer array */
956 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
957 gsn->invalid++;
958 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
959 "Invalid message format");
960 if (gsn->cb_conf)
961 gsn->cb_conf(type, EOF, NULL, cbp);
962 return EOF;
963 }
jjako52c24142002-12-16 13:33:51 +0000964
Harald Weltebed35df2011-11-02 13:06:18 +0100965 if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
966 gsn->missing++;
967 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
968 "Missing mandatory field");
969 if (gsn->cb_conf)
970 gsn->cb_conf(type, EOF, NULL, cbp);
971 return EOF;
972 }
jjako52c24142002-12-16 13:33:51 +0000973
Harald Weltebed35df2011-11-02 13:06:18 +0100974 /* Echo reply packages does not have a cause information element */
975 /* Instead we return the recovery number in the callback function */
976 if (gsn->cb_conf)
977 gsn->cb_conf(type, recovery, NULL, cbp);
Harald Welte629e9862010-12-24 20:58:09 +0100978
Harald Weltebed35df2011-11-02 13:06:18 +0100979 if (gsn->cb_recovery)
980 gsn->cb_recovery(peer, recovery);
981
982 return 0;
jjako52c24142002-12-16 13:33:51 +0000983}
984
985/* Send off a Version Not Supported message */
986/* This message is somewhat special in that it actually is a
987 * response to some other message with unsupported GTP version
988 * For this reason it has parameters like a response, and does
989 * its own message transmission. No signalling queue is used
990 * The reply is sent to the peer IP and peer UDP. This means that
991 * the peer will be receiving a GTP0 message on a GTP1 port!
992 * In practice however this will never happen as a GTP0 GSN will
993 * only listen to the GTP0 port, and therefore will never receive
994 * anything else than GTP0 */
995
jjako08d331d2003-10-13 20:33:30 +0000996int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
997 int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000998{
Harald Weltebed35df2011-11-02 13:06:18 +0100999 union gtp_packet packet;
jjako52c24142002-12-16 13:33:51 +00001000
Harald Weltebed35df2011-11-02 13:06:18 +01001001 /* GTP 1 is the highest supported protocol */
1002 unsigned int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet);
1003 return gtp_notification(gsn, version, &packet, length, peer, fd, 0);
jjako52c24142002-12-16 13:33:51 +00001004}
1005
1006/* Handle a Version Not Supported message */
Harald Weltebed35df2011-11-02 13:06:18 +01001007int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
1008 void *pack, unsigned len)
1009{
jjako52c24142002-12-16 13:33:51 +00001010
Harald Weltebed35df2011-11-02 13:06:18 +01001011 if (gsn->cb_unsup_ind)
1012 gsn->cb_unsup_ind(peer);
1013
1014 return 0;
jjako52c24142002-12-16 13:33:51 +00001015}
1016
jjako2c381332003-10-21 19:09:53 +00001017/* Send off an Supported Extension Headers Notification */
1018int gtp_extheader_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
1019 int fd, void *pack, unsigned len)
1020{
Harald Weltebed35df2011-11-02 13:06:18 +01001021 union gtp_packet packet;
1022 unsigned int length =
1023 get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet);
jjako2c381332003-10-21 19:09:53 +00001024
Harald Weltebed35df2011-11-02 13:06:18 +01001025 uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU;
jjako2c381332003-10-21 19:09:53 +00001026
Harald Weltebed35df2011-11-02 13:06:18 +01001027 if (version < 1)
1028 return 0;
jjako2c381332003-10-21 19:09:53 +00001029
Harald Weltebed35df2011-11-02 13:06:18 +01001030 /* We report back that we support only PDCP PDU headers */
1031 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T,
1032 sizeof(pdcp_pdu), &pdcp_pdu);
jjako2c381332003-10-21 19:09:53 +00001033
Harald Weltebed35df2011-11-02 13:06:18 +01001034 return gtp_notification(gsn, version, &packet, length,
1035 peer, fd, get_seq(pack));
jjako2c381332003-10-21 19:09:53 +00001036}
1037
1038/* Handle a Supported Extension Headers Notification */
Harald Weltebed35df2011-11-02 13:06:18 +01001039int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
1040 void *pack, unsigned len)
1041{
jjako2c381332003-10-21 19:09:53 +00001042
Harald Weltebed35df2011-11-02 13:06:18 +01001043 if (gsn->cb_extheader_ind)
1044 gsn->cb_extheader_ind(peer);
1045
1046 return 0;
jjako2c381332003-10-21 19:09:53 +00001047}
1048
jjako52c24142002-12-16 13:33:51 +00001049/* ***********************************************************
1050 * Session management messages
1051 * Messages: create, update and delete PDP context
1052 *
1053 * Information storage
1054 * Information storage for each PDP context is defined in
1055 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
1056 * PDP-address (IP address), sequence numbers, charging ID.
1057 * For the SGSN it also includes radio related mobility
1058 * information.
1059 *************************************************************/
1060
Harald Welte7b3347b2010-05-15 12:18:46 +02001061/* API: Send Create PDP Context Request (7.3.1) */
Harald Weltebed35df2011-11-02 13:06:18 +01001062extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
1063 void *cbp)
1064{
1065 union gtp_packet packet;
1066 unsigned int length =
1067 get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet);
1068 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001069
Harald Weltebed35df2011-11-02 13:06:18 +01001070 /* TODO: Secondary PDP Context Activation Procedure */
1071 /* In secondary activation procedure the PDP context is identified
1072 by tei in the header. The following fields are omitted: Selection
1073 mode, IMSI, MSISDN, End User Address, Access Point Name and
1074 Protocol Configuration Options */
jjako2c381332003-10-21 19:09:53 +00001075
Harald Weltebed35df2011-11-02 13:06:18 +01001076 if (pdp->secondary) {
1077 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
1078 gtp_err(LOG_ERR, __FILE__, __LINE__,
1079 "Unknown linked PDP context");
1080 return EOF;
1081 }
1082 }
jjako2c381332003-10-21 19:09:53 +00001083
Harald Weltebed35df2011-11-02 13:06:18 +01001084 if (pdp->version == 0) {
1085 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1086 sizeof(pdp->qos_req0), pdp->qos_req0);
1087 }
jjako52c24142002-12-16 13:33:51 +00001088
Harald Weltebed35df2011-11-02 13:06:18 +01001089 /* Section 7.7.2 */
1090 if (pdp->version == 1) {
1091 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1092 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1093 sizeof(pdp->imsi), (uint8_t *) & pdp->imsi);
1094 }
jjako52c24142002-12-16 13:33:51 +00001095
Harald Weltebed35df2011-11-02 13:06:18 +01001096 /* Section 7.7.3 Routing Area Information */
1097 if (pdp->rai_given == 1)
1098 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI,
1099 pdp->rai.l, (uint8_t *) & pdp->rai.v);
Harald Welte41af5692011-10-07 18:42:34 +02001100
Harald Weltebed35df2011-11-02 13:06:18 +01001101 /* Section 7.7.11 */
1102 if (pdp->norecovery_given == 0)
1103 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1104 gsn->restart_counter);
Harald Welte41af5692011-10-07 18:42:34 +02001105
Harald Weltebed35df2011-11-02 13:06:18 +01001106 /* Section 7.7.12 */
1107 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1108 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE,
1109 pdp->selmode);
jjako2c381332003-10-21 19:09:53 +00001110
Harald Weltebed35df2011-11-02 13:06:18 +01001111 if (pdp->version == 0) {
1112 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu);
1113 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc);
1114 }
jjako08d331d2003-10-13 20:33:30 +00001115
Harald Weltebed35df2011-11-02 13:06:18 +01001116 /* Section 7.7.13 */
1117 if (pdp->version == 1) {
1118 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1119 pdp->teid_own);
jjako08d331d2003-10-13 20:33:30 +00001120
Harald Weltebed35df2011-11-02 13:06:18 +01001121 /* Section 7.7.14 */
1122 if (!pdp->teic_confirmed)
1123 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1124 pdp->teic_own);
jjako2c381332003-10-21 19:09:53 +00001125
Harald Weltebed35df2011-11-02 13:06:18 +01001126 /* Section 7.7.17 */
1127 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00001128
Harald Weltebed35df2011-11-02 13:06:18 +01001129 /* Section 7.7.17 */
1130 if (pdp->secondary) /* Secondary PDP Context Activation Procedure */
1131 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1132 linked_pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00001133
Harald Weltebed35df2011-11-02 13:06:18 +01001134 /* Section 7.7.23 */
1135 if (pdp->cch_pdp) /* Only include charging if flags are set */
1136 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C,
1137 pdp->cch_pdp);
1138 }
jjako9b4971d2004-05-27 20:30:19 +00001139
Harald Weltebed35df2011-11-02 13:06:18 +01001140 /* TODO
1141 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1142 pdp->traceref);
1143 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1144 pdp->tracetype); */
jjako08d331d2003-10-13 20:33:30 +00001145
Harald Weltebed35df2011-11-02 13:06:18 +01001146 /* Section 7.7.27 */
1147 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1148 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1149 pdp->eua.l, pdp->eua.v);
jjako08d331d2003-10-13 20:33:30 +00001150
Harald Weltebed35df2011-11-02 13:06:18 +01001151 /* Section 7.7.30 */
1152 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1153 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN,
1154 pdp->apn_use.l, pdp->apn_use.v);
jjako08d331d2003-10-13 20:33:30 +00001155
Harald Weltebed35df2011-11-02 13:06:18 +01001156 /* Section 7.7.31 */
1157 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1158 if (pdp->pco_req.l)
1159 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1160 pdp->pco_req.l, pdp->pco_req.v);
jjako2c381332003-10-21 19:09:53 +00001161
Harald Weltebed35df2011-11-02 13:06:18 +01001162 /* Section 7.7.32 */
1163 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1164 pdp->gsnlc.l, pdp->gsnlc.v);
1165 /* Section 7.7.32 */
1166 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1167 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001168
Harald Weltebed35df2011-11-02 13:06:18 +01001169 /* Section 7.7.33 */
1170 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1171 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN,
1172 pdp->msisdn.l, pdp->msisdn.v);
jjako08d331d2003-10-13 20:33:30 +00001173
Harald Weltebed35df2011-11-02 13:06:18 +01001174 /* Section 7.7.34 */
1175 if (pdp->version == 1)
1176 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1177 pdp->qos_req.l, pdp->qos_req.v);
jjako08d331d2003-10-13 20:33:30 +00001178
Harald Weltebed35df2011-11-02 13:06:18 +01001179 /* Section 7.7.36 */
1180 if ((pdp->version == 1) && pdp->tft.l)
1181 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1182 pdp->tft.l, pdp->tft.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001183
Harald Weltebed35df2011-11-02 13:06:18 +01001184 /* Section 7.7.41 */
1185 if ((pdp->version == 1) && pdp->triggerid.l)
1186 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1187 pdp->triggerid.l, pdp->triggerid.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001188
Harald Weltebed35df2011-11-02 13:06:18 +01001189 /* Section 7.7.42 */
1190 if ((pdp->version == 1) && pdp->omcid.l)
1191 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1192 pdp->omcid.l, pdp->omcid.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001193
Harald Weltebed35df2011-11-02 13:06:18 +01001194 /* new R7 fields */
1195 if (pdp->rattype_given == 1)
1196 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAT_TYPE,
1197 pdp->rattype.l, pdp->rattype.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001198
Harald Weltebed35df2011-11-02 13:06:18 +01001199 if (pdp->userloc_given == 1)
1200 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_USER_LOC,
1201 pdp->userloc.l, pdp->userloc.v);
jjako52c24142002-12-16 13:33:51 +00001202
Harald Weltebed35df2011-11-02 13:06:18 +01001203 if (pdp->mstz_given == 1)
1204 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MS_TZ,
1205 pdp->mstz.l, pdp->mstz.v);
1206
1207 if (pdp->imeisv_given == 1)
1208 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_IMEI_SV,
1209 pdp->imeisv.l, pdp->imeisv.v);
1210
1211 /* TODO hisaddr0 */
1212 gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
1213
1214 return 0;
jjako52c24142002-12-16 13:33:51 +00001215}
1216
jjako08d331d2003-10-13 20:33:30 +00001217/* API: Application response to context indication */
Harald Weltebed35df2011-11-02 13:06:18 +01001218int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause)
1219{
jjako08d331d2003-10-13 20:33:30 +00001220
Harald Weltebed35df2011-11-02 13:06:18 +01001221 /* Now send off a reply to the peer */
1222 gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
1223
1224 if (cause != GTPCAUSE_ACC_REQ) {
1225 pdp_freepdp(pdp);
1226 }
1227
1228 return 0;
jjako08d331d2003-10-13 20:33:30 +00001229}
1230
1231/* API: Register create context indication callback */
1232int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +01001233 int (*cb_create_context_ind) (struct pdp_t *
1234 pdp))
jjako52c24142002-12-16 13:33:51 +00001235{
Harald Weltebed35df2011-11-02 13:06:18 +01001236 gsn->cb_create_context_ind = cb_create_context_ind;
1237 return 0;
jjako08d331d2003-10-13 20:33:30 +00001238}
1239
jjako08d331d2003-10-13 20:33:30 +00001240/* Send Create PDP Context Response */
Harald Weltebed35df2011-11-02 13:06:18 +01001241int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
1242 uint8_t cause)
1243{
1244 union gtp_packet packet;
1245 unsigned int length =
1246 get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
jjako52c24142002-12-16 13:33:51 +00001247
Harald Weltebed35df2011-11-02 13:06:18 +01001248 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00001249
Harald Weltebed35df2011-11-02 13:06:18 +01001250 if (cause == GTPCAUSE_ACC_REQ) {
jjako08d331d2003-10-13 20:33:30 +00001251
Harald Weltebed35df2011-11-02 13:06:18 +01001252 if (version == 0)
1253 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1254 sizeof(pdp->qos_neg0), pdp->qos_neg0);
jjako08d331d2003-10-13 20:33:30 +00001255
Harald Weltebed35df2011-11-02 13:06:18 +01001256 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER,
1257 pdp->reorder);
1258 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1259 gsn->restart_counter);
jjako08d331d2003-10-13 20:33:30 +00001260
Harald Weltebed35df2011-11-02 13:06:18 +01001261 if (version == 0) {
1262 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1263 pdp->fllu);
1264 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1265 pdp->fllc);
1266 }
jjako08d331d2003-10-13 20:33:30 +00001267
Harald Weltebed35df2011-11-02 13:06:18 +01001268 if (version == 1) {
1269 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1270 pdp->teid_own);
1271 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1272 pdp->teic_own);
1273 }
jjako08d331d2003-10-13 20:33:30 +00001274
Harald Weltebed35df2011-11-02 13:06:18 +01001275 /* TODO: We use teic_own as charging ID */
1276 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
1277 pdp->teic_own);
jjako2c381332003-10-21 19:09:53 +00001278
Harald Weltebed35df2011-11-02 13:06:18 +01001279 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1280 pdp->eua.l, pdp->eua.v);
jjako52c24142002-12-16 13:33:51 +00001281
Harald Weltebed35df2011-11-02 13:06:18 +01001282 if (pdp->pco_neg.l) { /* Optional PCO */
1283 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1284 pdp->pco_neg.l, pdp->pco_neg.v);
1285 }
jjako52c24142002-12-16 13:33:51 +00001286
Harald Weltebed35df2011-11-02 13:06:18 +01001287 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1288 pdp->gsnlc.l, pdp->gsnlc.v);
1289 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1290 pdp->gsnlu.l, pdp->gsnlu.v);
jjako08d331d2003-10-13 20:33:30 +00001291
Harald Weltebed35df2011-11-02 13:06:18 +01001292 if (version == 1)
1293 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1294 pdp->qos_neg.l, pdp->qos_neg.v);
jjako08d331d2003-10-13 20:33:30 +00001295
Harald Weltebed35df2011-11-02 13:06:18 +01001296 /* TODO: Charging gateway address */
1297 }
jjako52c24142002-12-16 13:33:51 +00001298
Harald Weltebed35df2011-11-02 13:06:18 +01001299 return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer,
1300 pdp->fd, pdp->seq, pdp->tid);
jjako52c24142002-12-16 13:33:51 +00001301}
1302
1303/* Handle Create PDP Context Request */
1304int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01001305 struct sockaddr_in *peer, int fd,
1306 void *pack, unsigned len)
1307{
1308 struct pdp_t *pdp, *pdp_old;
1309 struct pdp_t pdp_buf;
1310 union gtpie_member *ie[GTPIE_SIZE];
1311 uint8_t recovery;
jjako52c24142002-12-16 13:33:51 +00001312
Harald Weltebed35df2011-11-02 13:06:18 +01001313 uint16_t seq = get_seq(pack);
1314 int hlen = get_hlen(pack);
1315 uint8_t linked_nsapi = 0;
1316 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001317
Harald Weltebed35df2011-11-02 13:06:18 +01001318 if (!gtp_dublicate(gsn, version, peer, seq))
1319 return 0;
jjako08d331d2003-10-13 20:33:30 +00001320
Harald Weltebed35df2011-11-02 13:06:18 +01001321 pdp = &pdp_buf;
1322 memset(pdp, 0, sizeof(struct pdp_t));
jjako08d331d2003-10-13 20:33:30 +00001323
Harald Weltebed35df2011-11-02 13:06:18 +01001324 if (version == 0) {
1325 pdp->imsi =
1326 ((union gtp_packet *)pack)->gtp0.
1327 h.tid & 0x0fffffffffffffffull;
1328 pdp->nsapi =
1329 (((union gtp_packet *)pack)->gtp0.
1330 h.tid & 0xf000000000000000ull) >> 60;
1331 }
jjako52c24142002-12-16 13:33:51 +00001332
Harald Weltebed35df2011-11-02 13:06:18 +01001333 pdp->seq = seq;
1334 pdp->sa_peer = *peer;
1335 pdp->fd = fd;
1336 pdp->version = version;
jjako08d331d2003-10-13 20:33:30 +00001337
Harald Weltebed35df2011-11-02 13:06:18 +01001338 /* Decode information elements */
1339 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
1340 gsn->invalid++;
1341 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1342 "Invalid message format");
1343 if (0 == version)
1344 return EOF;
1345 else
1346 return gtp_create_pdp_resp(gsn, version, pdp,
1347 GTPCAUSE_INVALID_MESSAGE);
1348 }
jjako52c24142002-12-16 13:33:51 +00001349
Harald Weltebed35df2011-11-02 13:06:18 +01001350 if (version == 1) {
1351 /* Linked NSAPI (conditional) */
1352 /* If included this is the Secondary PDP Context Activation Procedure */
1353 /* In secondary activation IMSI is not included, so the context must be */
1354 /* identified by the tei */
1355 if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) {
jjako2c381332003-10-21 19:09:53 +00001356
Harald Weltebed35df2011-11-02 13:06:18 +01001357 /* Find the primary PDP context */
1358 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
1359 gsn->incorrect++;
1360 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1361 pack, len,
1362 "Incorrect optional information field");
1363 return gtp_create_pdp_resp(gsn, version, pdp,
1364 GTPCAUSE_OPT_IE_INCORRECT);
1365 }
jjako2c381332003-10-21 19:09:53 +00001366
Harald Weltebed35df2011-11-02 13:06:18 +01001367 /* Check that the primary PDP context matches linked nsapi */
1368 if (linked_pdp->nsapi != linked_nsapi) {
1369 gsn->incorrect++;
1370 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1371 pack, len,
1372 "Incorrect optional information field");
1373 return gtp_create_pdp_resp(gsn, version, pdp,
1374 GTPCAUSE_OPT_IE_INCORRECT);
1375 }
jjako52c24142002-12-16 13:33:51 +00001376
Harald Weltebed35df2011-11-02 13:06:18 +01001377 /* Copy parameters from primary context */
1378 pdp->selmode = linked_pdp->selmode;
1379 pdp->imsi = linked_pdp->imsi;
1380 pdp->msisdn = linked_pdp->msisdn;
1381 pdp->eua = linked_pdp->eua;
1382 pdp->pco_req = linked_pdp->pco_req;
1383 pdp->apn_req = linked_pdp->apn_req;
1384 pdp->teic_gn = linked_pdp->teic_gn;
1385 pdp->secondary = 1;
1386 }
1387 }
1388 /* if (version == 1) */
1389 if (version == 0) {
1390 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1391 pdp->qos_req0, sizeof(pdp->qos_req0))) {
1392 gsn->missing++;
1393 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1394 len, "Missing mandatory information field");
1395 return gtp_create_pdp_resp(gsn, version, pdp,
1396 GTPCAUSE_MAN_IE_MISSING);
1397 }
1398 }
jjako08d331d2003-10-13 20:33:30 +00001399
Harald Weltebed35df2011-11-02 13:06:18 +01001400 if ((version == 1) && (!linked_pdp)) {
1401 /* Not Secondary PDP Context Activation Procedure */
1402 /* IMSI (conditional) */
1403 if (gtpie_gettv0
1404 (ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) {
1405 gsn->missing++;
1406 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1407 len, "Missing mandatory information field");
1408 return gtp_create_pdp_resp(gsn, version, pdp,
1409 GTPCAUSE_MAN_IE_MISSING);
1410 }
1411 }
jjako52c24142002-12-16 13:33:51 +00001412
Harald Weltebed35df2011-11-02 13:06:18 +01001413 /* Recovery (optional) */
1414 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1415 if (gsn->cb_recovery)
1416 gsn->cb_recovery(peer, recovery);
1417 }
jjako52c24142002-12-16 13:33:51 +00001418
Harald Weltebed35df2011-11-02 13:06:18 +01001419 /* Selection mode (conditional) */
1420 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1421 if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0,
1422 &pdp->selmode, sizeof(pdp->selmode))) {
1423 gsn->missing++;
1424 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1425 len, "Missing mandatory information field");
1426 return gtp_create_pdp_resp(gsn, version, pdp,
1427 GTPCAUSE_MAN_IE_MISSING);
1428 }
1429 }
jjako52c24142002-12-16 13:33:51 +00001430
Harald Weltebed35df2011-11-02 13:06:18 +01001431 if (version == 0) {
1432 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1433 gsn->missing++;
1434 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1435 len, "Missing mandatory information field");
1436 return gtp_create_pdp_resp(gsn, version, pdp,
1437 GTPCAUSE_MAN_IE_MISSING);
1438 }
jjako52c24142002-12-16 13:33:51 +00001439
Harald Weltebed35df2011-11-02 13:06:18 +01001440 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1441 gsn->missing++;
1442 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1443 len, "Missing mandatory information field");
1444 return gtp_create_pdp_resp(gsn, version, pdp,
1445 GTPCAUSE_MAN_IE_MISSING);
1446 }
1447 }
jjako08d331d2003-10-13 20:33:30 +00001448
Harald Weltebed35df2011-11-02 13:06:18 +01001449 if (version == 1) {
1450 /* TEID (mandatory) */
1451 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1452 gsn->missing++;
1453 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1454 len, "Missing mandatory information field");
1455 return gtp_create_pdp_resp(gsn, version, pdp,
1456 GTPCAUSE_MAN_IE_MISSING);
1457 }
jjako2c381332003-10-21 19:09:53 +00001458
Harald Weltebed35df2011-11-02 13:06:18 +01001459 /* TEIC (conditional) */
1460 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1461 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1462 gsn->missing++;
1463 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1464 pack, len,
1465 "Missing mandatory information field");
1466 return gtp_create_pdp_resp(gsn, version, pdp,
1467 GTPCAUSE_MAN_IE_MISSING);
1468 }
1469 }
jjako08d331d2003-10-13 20:33:30 +00001470
Harald Weltebed35df2011-11-02 13:06:18 +01001471 /* NSAPI (mandatory) */
1472 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
1473 gsn->missing++;
1474 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1475 len, "Missing mandatory information field");
1476 return gtp_create_pdp_resp(gsn, version, pdp,
1477 GTPCAUSE_MAN_IE_MISSING);
1478 }
1479 }
jjako2e840a32003-01-28 16:05:18 +00001480
Harald Weltebed35df2011-11-02 13:06:18 +01001481 /* Charging Characteriatics (optional) */
1482 /* Trace reference (optional) */
1483 /* Trace type (optional) */
1484 /* Charging Characteriatics (optional) */
jjako52c24142002-12-16 13:33:51 +00001485
Harald Weltebed35df2011-11-02 13:06:18 +01001486 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1487 /* End User Address (conditional) */
1488 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1489 &pdp->eua.v, sizeof(pdp->eua.v))) {
1490 gsn->missing++;
1491 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1492 len, "Missing mandatory information field");
1493 return gtp_create_pdp_resp(gsn, version, pdp,
1494 GTPCAUSE_MAN_IE_MISSING);
1495 }
jjako08d331d2003-10-13 20:33:30 +00001496
Harald Weltebed35df2011-11-02 13:06:18 +01001497 /* APN */
1498 if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l,
1499 &pdp->apn_req.v, sizeof(pdp->apn_req.v))) {
1500 gsn->missing++;
1501 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1502 len, "Missing mandatory information field");
1503 return gtp_create_pdp_resp(gsn, version, pdp,
1504 GTPCAUSE_MAN_IE_MISSING);
1505 }
jjako2c381332003-10-21 19:09:53 +00001506
Harald Weltebed35df2011-11-02 13:06:18 +01001507 /* Extract protocol configuration options (optional) */
1508 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1509 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1510 }
1511 }
jjako2c381332003-10-21 19:09:53 +00001512
Harald Weltebed35df2011-11-02 13:06:18 +01001513 /* SGSN address for signalling (mandatory) */
1514 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1515 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1516 gsn->missing++;
1517 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1518 "Missing mandatory information field");
1519 return gtp_create_pdp_resp(gsn, version, pdp,
1520 GTPCAUSE_MAN_IE_MISSING);
1521 }
jjako2e840a32003-01-28 16:05:18 +00001522
Harald Weltebed35df2011-11-02 13:06:18 +01001523 /* SGSN address for user traffic (mandatory) */
1524 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1525 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1526 gsn->missing++;
1527 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1528 "Missing mandatory information field");
1529 return gtp_create_pdp_resp(gsn, version, pdp,
1530 GTPCAUSE_MAN_IE_MISSING);
1531 }
jjako52c24142002-12-16 13:33:51 +00001532
Harald Weltebed35df2011-11-02 13:06:18 +01001533 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1534 /* MSISDN (conditional) */
1535 if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l,
1536 &pdp->msisdn.v, sizeof(pdp->msisdn.v))) {
1537 gsn->missing++;
1538 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1539 len, "Missing mandatory information field");
1540 return gtp_create_pdp_resp(gsn, version, pdp,
1541 GTPCAUSE_MAN_IE_MISSING);
1542 }
1543 }
jjako52c24142002-12-16 13:33:51 +00001544
Harald Weltebed35df2011-11-02 13:06:18 +01001545 if (version == 1) {
1546 /* QoS (mandatory) */
1547 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
1548 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
1549 gsn->missing++;
1550 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1551 len, "Missing mandatory information field");
1552 return gtp_create_pdp_resp(gsn, version, pdp,
1553 GTPCAUSE_MAN_IE_MISSING);
1554 }
1555
1556 /* TFT (conditional) */
1557 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
1558 &pdp->tft.v, sizeof(pdp->tft.v))) {
1559 }
1560
1561 /* Trigger ID */
1562 /* OMC identity */
1563 }
1564
1565 /* Initialize our own IP addresses */
1566 in_addr2gsna(&pdp->gsnlc, &gsn->gsnc);
1567 in_addr2gsna(&pdp->gsnlu, &gsn->gsnu);
1568
1569 if (GTP_DEBUG)
1570 printf("gtp_create_pdp_ind: Before pdp_tidget\n");
1571
1572 if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) {
1573 /* Found old pdp with same tid. Now the voodoo begins! */
1574 /* 09.60 / 29.060 allows create on existing context to "steal" */
1575 /* the context which was allready established */
1576 /* We check that the APN, selection mode and MSISDN is the same */
1577 if (GTP_DEBUG)
1578 printf("gtp_create_pdp_ind: Old context found\n");
1579 if ((pdp->apn_req.l == pdp_old->apn_req.l)
1580 &&
1581 (!memcmp
1582 (pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l))
1583 && (pdp->selmode == pdp_old->selmode)
1584 && (pdp->msisdn.l == pdp_old->msisdn.l)
1585 &&
1586 (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l)))
1587 {
1588 /* OK! We are dealing with the same APN. We will copy new
1589 * parameters to the old pdp and send off confirmation
1590 * We ignore the following information elements:
1591 * QoS: MS will get originally negotiated QoS.
1592 * End user address (EUA). MS will get old EUA anyway.
1593 * Protocol configuration option (PCO): Only application can verify */
1594
1595 if (GTP_DEBUG)
1596 printf
1597 ("gtp_create_pdp_ind: Old context found\n");
1598
1599 /* Copy remote flow label */
1600 pdp_old->flru = pdp->flru;
1601 pdp_old->flrc = pdp->flrc;
1602
1603 /* Copy remote tei */
1604 pdp_old->teid_gn = pdp->teid_gn;
1605 pdp_old->teic_gn = pdp->teic_gn;
1606
1607 /* Copy peer GSN address */
1608 pdp_old->gsnrc.l = pdp->gsnrc.l;
1609 memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l);
1610 pdp_old->gsnru.l = pdp->gsnru.l;
1611 memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l);
1612
1613 /* Copy request parameters */
1614 pdp_old->seq = pdp->seq;
1615 pdp_old->sa_peer = pdp->sa_peer;
1616 pdp_old->fd = pdp->fd = fd;
1617 pdp_old->version = pdp->version = version;
1618
1619 /* Switch to using the old pdp context */
1620 pdp = pdp_old;
1621
1622 /* Confirm to peer that things were "successful" */
1623 return gtp_create_pdp_resp(gsn, version, pdp,
1624 GTPCAUSE_ACC_REQ);
1625 } else { /* This is not the same PDP context. Delete the old one. */
1626
1627 if (GTP_DEBUG)
1628 printf
1629 ("gtp_create_pdp_ind: Deleting old context\n");
1630
1631 if (gsn->cb_delete_context)
1632 gsn->cb_delete_context(pdp_old);
1633 pdp_freepdp(pdp_old);
1634
1635 if (GTP_DEBUG)
1636 printf("gtp_create_pdp_ind: Deleted...\n");
1637 }
1638 }
1639
1640 pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp);
1641
1642 /* Callback function to validata login */
1643 if (gsn->cb_create_context_ind != 0)
1644 return gsn->cb_create_context_ind(pdp);
1645 else {
1646 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1647 "No create_context_ind callback defined");
1648 return gtp_create_pdp_resp(gsn, version, pdp,
1649 GTPCAUSE_NOT_SUPPORTED);
1650 }
jjako52c24142002-12-16 13:33:51 +00001651}
1652
jjako52c24142002-12-16 13:33:51 +00001653/* Handle Create PDP Context Response */
1654int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01001655 struct sockaddr_in *peer, void *pack, unsigned len)
1656{
1657 struct pdp_t *pdp;
1658 union gtpie_member *ie[GTPIE_SIZE];
1659 uint8_t cause, recovery;
1660 void *cbp = NULL;
1661 uint8_t type = 0;
1662 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001663
Harald Weltebed35df2011-11-02 13:06:18 +01001664 /* Remove packet from queue */
1665 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
1666 return EOF;
jjako52c24142002-12-16 13:33:51 +00001667
Harald Weltebed35df2011-11-02 13:06:18 +01001668 /* Find the context in question */
1669 if (pdp_getgtp1(&pdp, get_tei(pack))) {
1670 gsn->err_unknownpdp++;
1671 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1672 "Unknown PDP context");
1673 if (gsn->cb_conf)
1674 gsn->cb_conf(type, EOF, NULL, cbp);
1675 return EOF;
1676 }
jjako2c381332003-10-21 19:09:53 +00001677
Harald Weltebed35df2011-11-02 13:06:18 +01001678 /* Register that we have received a valid teic from GGSN */
1679 pdp->teic_confirmed = 1;
jjako52c24142002-12-16 13:33:51 +00001680
Harald Weltebed35df2011-11-02 13:06:18 +01001681 /* Decode information elements */
1682 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
1683 gsn->invalid++;
1684 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1685 "Invalid message format");
1686 if (gsn->cb_conf)
1687 gsn->cb_conf(type, EOF, pdp, cbp);
1688 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1689 pdp_freepdp(pdp); */
1690 return EOF;
1691 }
jjako52c24142002-12-16 13:33:51 +00001692
Harald Weltebed35df2011-11-02 13:06:18 +01001693 /* Extract cause value (mandatory) */
1694 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
1695 gsn->missing++;
1696 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1697 "Missing mandatory information field");
1698 if (gsn->cb_conf)
1699 gsn->cb_conf(type, EOF, pdp, cbp);
1700 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1701 pdp_freepdp(pdp); */
1702 return EOF;
1703 }
jjako52c24142002-12-16 13:33:51 +00001704
Harald Weltebed35df2011-11-02 13:06:18 +01001705 /* Extract recovery (optional) */
1706 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1707 if (gsn->cb_recovery)
1708 gsn->cb_recovery(peer, recovery);
1709 }
jjako52c24142002-12-16 13:33:51 +00001710
Harald Weltebed35df2011-11-02 13:06:18 +01001711 /* Extract protocol configuration options (optional) */
1712 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1713 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1714 }
jjako52c24142002-12-16 13:33:51 +00001715
Harald Weltebed35df2011-11-02 13:06:18 +01001716 /* Check all conditional information elements */
1717 if (GTPCAUSE_ACC_REQ == cause) {
jjako52c24142002-12-16 13:33:51 +00001718
Harald Weltebed35df2011-11-02 13:06:18 +01001719 if (version == 0) {
1720 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1721 &pdp->qos_neg0,
1722 sizeof(pdp->qos_neg0))) {
1723 gsn->missing++;
1724 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1725 pack, len,
1726 "Missing conditional information field");
1727 if (gsn->cb_conf)
1728 gsn->cb_conf(type, EOF, pdp, cbp);
1729 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1730 pdp_freepdp(pdp); */
1731 return EOF;
1732 }
1733 }
jjako08d331d2003-10-13 20:33:30 +00001734
Harald Weltebed35df2011-11-02 13:06:18 +01001735 if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) {
1736 gsn->missing++;
1737 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1738 len,
1739 "Missing conditional information field");
1740 if (gsn->cb_conf)
1741 gsn->cb_conf(type, EOF, pdp, cbp);
1742 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1743 pdp_freepdp(pdp); */
1744 return EOF;
1745 }
jjako52c24142002-12-16 13:33:51 +00001746
Harald Weltebed35df2011-11-02 13:06:18 +01001747 if (version == 0) {
1748 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1749 gsn->missing++;
1750 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1751 pack, len,
1752 "Missing conditional information field");
1753 if (gsn->cb_conf)
1754 gsn->cb_conf(type, EOF, pdp, cbp);
1755 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1756 pdp_freepdp(pdp); */
1757 return EOF;
1758 }
jjako52c24142002-12-16 13:33:51 +00001759
Harald Weltebed35df2011-11-02 13:06:18 +01001760 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1761 gsn->missing++;
1762 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1763 pack, len,
1764 "Missing conditional information field");
1765 if (gsn->cb_conf)
1766 gsn->cb_conf(type, EOF, pdp, cbp);
1767 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1768 pdp_freepdp(pdp); */
1769 return EOF;
1770 }
1771 }
1772
1773 if (version == 1) {
1774 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1775 gsn->missing++;
1776 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1777 pack, len,
1778 "Missing conditional information field");
1779 if (gsn->cb_conf)
1780 gsn->cb_conf(type, EOF, pdp, cbp);
1781 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1782 pdp_freepdp(pdp); */
1783 return EOF;
1784 }
1785
1786 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1787 gsn->missing++;
1788 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1789 pack, len,
1790 "Missing conditional information field");
1791 if (gsn->cb_conf)
1792 gsn->cb_conf(type, EOF, pdp, cbp);
1793 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1794 pdp_freepdp(pdp); */
1795 return EOF;
1796 }
1797 }
1798
1799 if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
1800 gsn->missing++;
1801 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1802 len,
1803 "Missing conditional information field");
1804 if (gsn->cb_conf)
1805 gsn->cb_conf(type, EOF, pdp, cbp);
1806 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1807 pdp_freepdp(pdp); */
1808 }
1809
1810 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1811 &pdp->eua.v, sizeof(pdp->eua.v))) {
1812 gsn->missing++;
1813 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1814 len,
1815 "Missing conditional information field");
1816 if (gsn->cb_conf)
1817 gsn->cb_conf(type, EOF, pdp, cbp);
1818 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1819 pdp_freepdp(pdp); */
1820 return EOF;
1821 }
1822
1823 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1824 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1825 gsn->missing++;
1826 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1827 len,
1828 "Missing conditional information field");
1829 if (gsn->cb_conf)
1830 gsn->cb_conf(type, EOF, pdp, cbp);
1831 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1832 pdp_freepdp(pdp); */
1833 return EOF;
1834 }
1835
1836 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1837 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1838 gsn->missing++;
1839 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1840 len,
1841 "Missing conditional information field");
1842 if (gsn->cb_conf)
1843 gsn->cb_conf(type, EOF, pdp, cbp);
1844 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1845 pdp_freepdp(pdp); */
1846 return EOF;
1847 }
1848
1849 if (version == 1) {
1850 if (gtpie_gettlv
1851 (ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
1852 &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
1853 gsn->missing++;
1854 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1855 pack, len,
1856 "Missing conditional information field");
1857 if (gsn->cb_conf)
1858 gsn->cb_conf(type, EOF, pdp, cbp);
1859 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1860 pdp_freepdp(pdp); */
1861 return EOF;
1862 }
1863 }
1864
1865 }
1866
1867 if (gsn->cb_conf)
1868 gsn->cb_conf(type, cause, pdp, cbp);
1869
1870 return 0;
jjako52c24142002-12-16 13:33:51 +00001871}
1872
jjako08d331d2003-10-13 20:33:30 +00001873/* API: Send Update PDP Context Request */
1874int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
Harald Weltebed35df2011-11-02 13:06:18 +01001875 struct in_addr *inetaddr)
1876{
1877 union gtp_packet packet;
1878 unsigned int length =
1879 get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet);
jjako52c24142002-12-16 13:33:51 +00001880
Harald Weltebed35df2011-11-02 13:06:18 +01001881 if (pdp->version == 0)
1882 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1883 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako08d331d2003-10-13 20:33:30 +00001884
Harald Weltebed35df2011-11-02 13:06:18 +01001885 /* Include IMSI if updating with unknown teic_gn */
1886 if ((pdp->version == 1) && (!pdp->teic_gn))
1887 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1888 sizeof(pdp->imsi), (uint8_t *) & pdp->imsi);
1889
1890 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1891 gsn->restart_counter);
1892
1893 if (pdp->version == 0) {
1894 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu);
1895 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc);
1896 }
1897
1898 if (pdp->version == 1) {
1899 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1900 pdp->teid_own);
1901
1902 if (!pdp->teic_confirmed)
1903 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1904 pdp->teic_own);
1905 }
1906
1907 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
1908
1909 /* TODO
1910 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1911 pdp->traceref);
1912 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1913 pdp->tracetype); */
1914
1915 /* TODO if ggsn update message
1916 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1917 pdp->eua.l, pdp->eua.v);
1918 */
1919
1920 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1921 pdp->gsnlc.l, pdp->gsnlc.v);
1922 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1923 pdp->gsnlu.l, pdp->gsnlu.v);
1924
1925 if (pdp->version == 1)
1926 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1927 pdp->qos_req.l, pdp->qos_req.v);
1928
1929 if ((pdp->version == 1) && pdp->tft.l)
1930 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1931 pdp->tft.l, pdp->tft.v);
1932
1933 if ((pdp->version == 1) && pdp->triggerid.l)
1934 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1935 pdp->triggerid.l, pdp->triggerid.v);
1936
1937 if ((pdp->version == 1) && pdp->omcid.l)
1938 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1939 pdp->omcid.l, pdp->omcid.v);
1940
1941 gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp);
1942
1943 return 0;
jjako52c24142002-12-16 13:33:51 +00001944}
1945
jjako08d331d2003-10-13 20:33:30 +00001946/* Send Update PDP Context Response */
Harald Weltebed35df2011-11-02 13:06:18 +01001947int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
1948 struct sockaddr_in *peer, int fd,
jjako08d331d2003-10-13 20:33:30 +00001949 void *pack, unsigned len,
Harald Weltebed35df2011-11-02 13:06:18 +01001950 struct pdp_t *pdp, uint8_t cause)
1951{
jjako08d331d2003-10-13 20:33:30 +00001952
Harald Weltebed35df2011-11-02 13:06:18 +01001953 union gtp_packet packet;
1954 unsigned int length =
1955 get_default_gtp(version, GTP_UPDATE_PDP_RSP, &packet);
jjako08d331d2003-10-13 20:33:30 +00001956
Harald Weltebed35df2011-11-02 13:06:18 +01001957 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako08d331d2003-10-13 20:33:30 +00001958
Harald Weltebed35df2011-11-02 13:06:18 +01001959 if (cause == GTPCAUSE_ACC_REQ) {
1960
1961 if (version == 0)
1962 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1963 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1964
1965 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1966 gsn->restart_counter);
1967
1968 if (version == 0) {
1969 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1970 pdp->fllu);
1971 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1972 pdp->fllc);
1973 }
1974
1975 if (version == 1) {
1976 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1977 pdp->teid_own);
1978
1979 if (!pdp->teic_confirmed)
1980 gtpie_tv4(&packet, &length, GTP_MAX,
1981 GTPIE_TEI_C, pdp->teic_own);
1982 }
1983
1984 /* TODO we use teid_own as charging ID address */
1985 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
1986 pdp->teid_own);
1987
1988 /* If ggsn
1989 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1990 pdp->eua.l, pdp->eua.v); */
1991
1992 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1993 pdp->gsnlc.l, pdp->gsnlc.v);
1994 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1995 pdp->gsnlu.l, pdp->gsnlu.v);
1996
1997 if (version == 1)
1998 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1999 pdp->qos_neg.l, pdp->qos_neg.v);
2000
2001 /* TODO: Charging gateway address */
2002 }
2003
2004 return gtp_resp(version, gsn, pdp, &packet, length, peer,
2005 fd, get_seq(pack), get_tid(pack));
jjako08d331d2003-10-13 20:33:30 +00002006}
2007
jjako52c24142002-12-16 13:33:51 +00002008/* Handle Update PDP Context Request */
2009int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002010 struct sockaddr_in *peer, int fd,
2011 void *pack, unsigned len)
2012{
2013 struct pdp_t *pdp;
2014 struct pdp_t pdp_backup;
2015 union gtpie_member *ie[GTPIE_SIZE];
2016 uint8_t recovery;
jjako52c24142002-12-16 13:33:51 +00002017
Harald Weltebed35df2011-11-02 13:06:18 +01002018 uint16_t seq = get_seq(pack);
2019 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002020
Harald Weltebed35df2011-11-02 13:06:18 +01002021 uint64_t imsi;
2022 uint8_t nsapi;
jjako52c24142002-12-16 13:33:51 +00002023
Harald Weltebed35df2011-11-02 13:06:18 +01002024 /* Is this a dublicate ? */
2025 if (!gtp_dublicate(gsn, version, peer, seq)) {
2026 return 0; /* We allready send of response once */
2027 }
jjako08d331d2003-10-13 20:33:30 +00002028
Harald Weltebed35df2011-11-02 13:06:18 +01002029 /* Decode information elements */
2030 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
2031 gsn->invalid++;
2032 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2033 "Invalid message format");
2034 if (0 == version)
2035 return EOF;
2036 else
2037 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2038 len, NULL,
2039 GTPCAUSE_INVALID_MESSAGE);
2040 }
jjako08d331d2003-10-13 20:33:30 +00002041
Harald Weltebed35df2011-11-02 13:06:18 +01002042 /* Finding PDP: */
2043 /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
2044 /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
2045 /* we have to use the tunnel endpoint identifier */
2046 if (version == 0) {
2047 imsi =
2048 ((union gtp_packet *)pack)->gtp0.
2049 h.tid & 0x0fffffffffffffffull;
2050 nsapi =
2051 (((union gtp_packet *)pack)->gtp0.
2052 h.tid & 0xf000000000000000ull) >> 60;
jjako52c24142002-12-16 13:33:51 +00002053
Harald Weltebed35df2011-11-02 13:06:18 +01002054 /* Find the context in question */
2055 if (pdp_getimsi(&pdp, imsi, nsapi)) {
2056 gsn->err_unknownpdp++;
2057 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2058 len, "Unknown PDP context");
2059 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2060 len, NULL,
2061 GTPCAUSE_NON_EXIST);
2062 }
2063 } else if (version == 1) {
2064 /* NSAPI (mandatory) */
2065 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
2066 gsn->missing++;
2067 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2068 len, "Missing mandatory information field");
2069 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2070 len, NULL,
2071 GTPCAUSE_MAN_IE_MISSING);
2072 }
jjako08d331d2003-10-13 20:33:30 +00002073
Harald Weltebed35df2011-11-02 13:06:18 +01002074 /* IMSI (conditional) */
2075 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) {
2076 /* Find the context in question */
2077 if (pdp_getgtp1(&pdp, get_tei(pack))) {
2078 gsn->err_unknownpdp++;
2079 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
2080 pack, len, "Unknown PDP context");
2081 return gtp_update_pdp_resp(gsn, version, peer,
2082 fd, pack, len, NULL,
2083 GTPCAUSE_NON_EXIST);
2084 }
2085 } else {
2086 /* Find the context in question */
2087 if (pdp_getimsi(&pdp, imsi, nsapi)) {
2088 gsn->err_unknownpdp++;
2089 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
2090 pack, len, "Unknown PDP context");
2091 return gtp_update_pdp_resp(gsn, version, peer,
2092 fd, pack, len, NULL,
2093 GTPCAUSE_NON_EXIST);
2094 }
2095 }
2096 } else {
2097 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
2098 return EOF;
2099 }
jjako08d331d2003-10-13 20:33:30 +00002100
Harald Weltebed35df2011-11-02 13:06:18 +01002101 /* Make a backup copy in case anything is wrong */
2102 memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
jjako08d331d2003-10-13 20:33:30 +00002103
Harald Weltebed35df2011-11-02 13:06:18 +01002104 if (version == 0) {
2105 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2106 pdp->qos_req0, sizeof(pdp->qos_req0))) {
2107 gsn->missing++;
2108 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2109 len, "Missing mandatory information field");
2110 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2111 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2112 len, pdp,
2113 GTPCAUSE_MAN_IE_MISSING);
2114 }
2115 }
jjako52c24142002-12-16 13:33:51 +00002116
Harald Weltebed35df2011-11-02 13:06:18 +01002117 /* Recovery (optional) */
2118 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
2119 if (gsn->cb_recovery)
2120 gsn->cb_recovery(peer, recovery);
2121 }
jjako08d331d2003-10-13 20:33:30 +00002122
Harald Weltebed35df2011-11-02 13:06:18 +01002123 if (version == 0) {
2124 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
2125 gsn->missing++;
2126 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2127 len, "Missing mandatory information field");
2128 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2129 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2130 len, pdp,
2131 GTPCAUSE_MAN_IE_MISSING);
2132 }
jjako52c24142002-12-16 13:33:51 +00002133
Harald Weltebed35df2011-11-02 13:06:18 +01002134 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
2135 gsn->missing++;
2136 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2137 len, "Missing mandatory information field");
2138 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2139 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2140 len, pdp,
2141 GTPCAUSE_MAN_IE_MISSING);
2142 }
2143 }
jjako52c24142002-12-16 13:33:51 +00002144
Harald Weltebed35df2011-11-02 13:06:18 +01002145 if (version == 1) {
2146 /* TEID (mandatory) */
2147 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
2148 gsn->missing++;
2149 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2150 len, "Missing mandatory information field");
2151 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2152 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2153 len, pdp,
2154 GTPCAUSE_MAN_IE_MISSING);
2155 }
jjako52c24142002-12-16 13:33:51 +00002156
Harald Weltebed35df2011-11-02 13:06:18 +01002157 /* TEIC (conditional) */
2158 /* If TEIC is not included it means that we have allready received it */
2159 /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
2160 /* all updated contexts, or only for one of the linked contexts */
2161 gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn);
2162
2163 /* NSAPI (mandatory) */
2164 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
2165 gsn->missing++;
2166 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2167 len, "Missing mandatory information field");
2168 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2169 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2170 len, pdp,
2171 GTPCAUSE_MAN_IE_MISSING);
2172 }
2173 }
2174
2175 /* Trace reference (optional) */
2176 /* Trace type (optional) */
2177
2178 /* End User Address (conditional) TODO: GGSN Initiated
2179 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2180 &pdp->eua.v, sizeof(pdp->eua.v))) {
2181 gsn->missing++;
2182 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2183 "Missing mandatory information field");
2184 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2185 return gtp_update_pdp_resp(gsn, version, pdp,
2186 GTPCAUSE_MAN_IE_MISSING);
2187 } */
2188
2189 /* SGSN address for signalling (mandatory) */
2190 /* It is weird that this is mandatory when TEIC is conditional */
2191 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2192 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
2193 gsn->missing++;
2194 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2195 "Missing mandatory information field");
2196 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2197 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
2198 pdp, GTPCAUSE_MAN_IE_MISSING);
2199 }
2200
2201 /* SGSN address for user traffic (mandatory) */
2202 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2203 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
2204 gsn->missing++;
2205 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2206 "Missing mandatory information field");
2207 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2208 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
2209 pdp, GTPCAUSE_MAN_IE_MISSING);
2210 }
2211
2212 if (version == 1) {
2213 /* QoS (mandatory) */
2214 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
2215 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
2216 gsn->missing++;
2217 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2218 len, "Missing mandatory information field");
2219 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2220 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2221 len, pdp,
2222 GTPCAUSE_MAN_IE_MISSING);
2223 }
2224
2225 /* TFT (conditional) */
2226 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
2227 &pdp->tft.v, sizeof(pdp->tft.v))) {
2228 }
2229
2230 /* OMC identity */
2231 }
2232
2233 /* Confirm to peer that things were "successful" */
2234 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2235 GTPCAUSE_ACC_REQ);
jjako52c24142002-12-16 13:33:51 +00002236}
2237
jjako52c24142002-12-16 13:33:51 +00002238/* Handle Update PDP Context Response */
2239int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002240 struct sockaddr_in *peer, void *pack, unsigned len)
2241{
2242 struct pdp_t *pdp;
2243 union gtpie_member *ie[GTPIE_SIZE];
2244 uint8_t cause, recovery;
2245 void *cbp = NULL;
2246 uint8_t type = 0;
jjako52c24142002-12-16 13:33:51 +00002247
Harald Weltebed35df2011-11-02 13:06:18 +01002248 /* Remove packet from queue */
2249 if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp))
2250 return EOF;
jjako52c24142002-12-16 13:33:51 +00002251
Harald Weltebed35df2011-11-02 13:06:18 +01002252 /* Find the context in question */
2253 if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) {
2254 gsn->err_unknownpdp++;
2255 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2256 "Unknown PDP context");
2257 if (gsn->cb_conf)
2258 gsn->cb_conf(type, cause, NULL, cbp);
2259 return EOF;
2260 }
jjako2c381332003-10-21 19:09:53 +00002261
Harald Weltebed35df2011-11-02 13:06:18 +01002262 /* Register that we have received a valid teic from GGSN */
2263 pdp->teic_confirmed = 1;
jjako52c24142002-12-16 13:33:51 +00002264
Harald Weltebed35df2011-11-02 13:06:18 +01002265 /* Decode information elements */
2266 if (gtpie_decaps
2267 (ie, 0, pack + GTP0_HEADER_SIZE, len - GTP0_HEADER_SIZE)) {
2268 gsn->invalid++;
2269 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2270 "Invalid message format");
2271 if (gsn->cb_conf)
2272 gsn->cb_conf(type, EOF, pdp, cbp);
2273 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2274 pdp_freepdp(pdp); */
2275 return EOF;
2276 }
jjako52c24142002-12-16 13:33:51 +00002277
Harald Weltebed35df2011-11-02 13:06:18 +01002278 /* Extract cause value (mandatory) */
2279 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2280 gsn->missing++;
2281 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2282 "Missing mandatory information field");
2283 if (gsn->cb_conf)
2284 gsn->cb_conf(type, EOF, pdp, cbp);
2285 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2286 pdp_freepdp(pdp); */
2287 return EOF;
2288 }
jjako52c24142002-12-16 13:33:51 +00002289
Harald Weltebed35df2011-11-02 13:06:18 +01002290 /* Extract recovery (optional) */
2291 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
2292 if (gsn->cb_recovery)
2293 gsn->cb_recovery(peer, recovery);
2294 }
2295
2296 /* Check all conditional information elements */
2297 if (GTPCAUSE_ACC_REQ != cause) {
2298 if (gsn->cb_conf)
2299 gsn->cb_conf(type, cause, pdp, cbp);
2300 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2301 pdp_freepdp(pdp); */
2302 return 0;
2303 } else {
2304 /* Check for missing conditionary information elements */
2305 if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) &&
2306 gtpie_exist(ie, GTPIE_REORDER, 0) &&
2307 gtpie_exist(ie, GTPIE_FL_DI, 0) &&
2308 gtpie_exist(ie, GTPIE_FL_C, 0) &&
2309 gtpie_exist(ie, GTPIE_CHARGING_ID, 0) &&
2310 gtpie_exist(ie, GTPIE_EUA, 0) &&
2311 gtpie_exist(ie, GTPIE_GSN_ADDR, 0) &&
2312 gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) {
2313 gsn->missing++;
2314 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2315 len,
2316 "Missing conditional information field");
2317 if (gsn->cb_conf)
2318 gsn->cb_conf(type, EOF, pdp, cbp);
2319 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2320 pdp_freepdp(pdp); */
2321 return EOF;
2322 }
2323
2324 /* Update pdp with new values */
2325 gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2326 pdp->qos_neg0, sizeof(pdp->qos_neg0));
2327 gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder);
2328 gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru);
2329 gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc);
2330 gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid);
2331 gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2332 &pdp->eua.v, sizeof(pdp->eua.v));
2333 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2334 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v));
2335 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2336 &pdp->gsnru.v, sizeof(pdp->gsnru.v));
2337
2338 if (gsn->cb_conf)
2339 gsn->cb_conf(type, cause, pdp, cbp);
2340 return 0; /* Succes */
2341 }
jjako52c24142002-12-16 13:33:51 +00002342}
2343
jjako08d331d2003-10-13 20:33:30 +00002344/* API: Send Delete PDP Context Request */
jjako2c381332003-10-21 19:09:53 +00002345int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
Harald Weltebed35df2011-11-02 13:06:18 +01002346 int teardown)
2347{
2348 union gtp_packet packet;
2349 unsigned int length =
2350 get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
2351 struct in_addr addr;
2352 struct pdp_t *linked_pdp;
2353 struct pdp_t *secondary_pdp;
2354 int n;
2355 int count = 0;
jjako2c381332003-10-21 19:09:53 +00002356
Harald Weltebed35df2011-11-02 13:06:18 +01002357 if (gsna2in_addr(&addr, &pdp->gsnrc)) {
2358 gsn->err_address++;
2359 gtp_err(LOG_ERR, __FILE__, __LINE__,
2360 "GSN address conversion failed");
2361 return EOF;
jjako2c381332003-10-21 19:09:53 +00002362 }
jjako2c381332003-10-21 19:09:53 +00002363
Harald Weltebed35df2011-11-02 13:06:18 +01002364 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
2365 gtp_err(LOG_ERR, __FILE__, __LINE__,
2366 "Unknown linked PDP context");
2367 return EOF;
2368 }
2369
2370 if (!teardown) {
2371 for (n = 0; n < PDP_MAXNSAPI; n++)
2372 if (linked_pdp->secondary_tei[n])
2373 count++;
2374 if (count <= 1) {
2375 gtp_err(LOG_ERR, __FILE__, __LINE__,
2376 "Must use teardown for last context");
2377 return EOF;
2378 }
2379 }
2380
2381 if (pdp->version == 1) {
2382 if (teardown)
2383 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
2384 0xff);
2385
2386 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
2387 }
2388
2389 gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
2390
2391 if (teardown) { /* Remove all contexts */
2392 for (n = 0; n < PDP_MAXNSAPI; n++) {
2393 if (linked_pdp->secondary_tei[n]) {
2394 if (pdp_getgtp1
2395 (&secondary_pdp,
2396 linked_pdp->secondary_tei[n])) {
2397 gtp_err(LOG_ERR, __FILE__, __LINE__,
2398 "Unknown secondary PDP context");
2399 return EOF;
2400 }
2401 if (linked_pdp != secondary_pdp) {
2402 if (gsn->cb_delete_context)
2403 gsn->cb_delete_context
2404 (secondary_pdp);
2405 pdp_freepdp(secondary_pdp);
2406 }
2407 }
2408 }
2409 if (gsn->cb_delete_context)
2410 gsn->cb_delete_context(linked_pdp);
2411 pdp_freepdp(linked_pdp);
2412 } else {
2413 if (gsn->cb_delete_context)
2414 gsn->cb_delete_context(pdp);
2415 if (pdp == linked_pdp) {
2416 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2417 linked_pdp->nodata = 1;
2418 } else
2419 pdp_freepdp(pdp);
2420 }
2421
2422 return 0;
jjako2c381332003-10-21 19:09:53 +00002423}
jjako08d331d2003-10-13 20:33:30 +00002424
jjako52c24142002-12-16 13:33:51 +00002425/* Send Delete PDP Context Response */
2426int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002427 struct sockaddr_in *peer, int fd,
Harald Weltebed35df2011-11-02 13:06:18 +01002428 void *pack, unsigned len,
2429 struct pdp_t *pdp, struct pdp_t *linked_pdp,
jjako2c381332003-10-21 19:09:53 +00002430 uint8_t cause, int teardown)
jjako52c24142002-12-16 13:33:51 +00002431{
Harald Weltebed35df2011-11-02 13:06:18 +01002432 union gtp_packet packet;
2433 struct pdp_t *secondary_pdp;
2434 unsigned int length =
2435 get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet);
2436 int n;
jjako52c24142002-12-16 13:33:51 +00002437
Harald Weltebed35df2011-11-02 13:06:18 +01002438 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00002439
Harald Weltebed35df2011-11-02 13:06:18 +01002440 gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
2441 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002442
Harald Weltebed35df2011-11-02 13:06:18 +01002443 if (cause == GTPCAUSE_ACC_REQ) {
2444 if ((teardown) || (version == 0)) { /* Remove all contexts */
2445 for (n = 0; n < PDP_MAXNSAPI; n++) {
2446 if (linked_pdp->secondary_tei[n]) {
2447 if (pdp_getgtp1
2448 (&secondary_pdp,
2449 linked_pdp->secondary_tei[n])) {
2450 gtp_err(LOG_ERR, __FILE__,
2451 __LINE__,
2452 "Unknown secondary PDP context");
2453 return EOF;
2454 }
2455 if (linked_pdp != secondary_pdp) {
2456 if (gsn->cb_delete_context)
2457 gsn->cb_delete_context
2458 (secondary_pdp);
2459 pdp_freepdp(secondary_pdp);
2460 }
2461 }
2462 }
2463 if (gsn->cb_delete_context)
2464 gsn->cb_delete_context(linked_pdp);
2465 pdp_freepdp(linked_pdp);
2466 } else { /* Remove only current context */
2467 if (gsn->cb_delete_context)
2468 gsn->cb_delete_context(pdp);
2469 if (pdp == linked_pdp) {
2470 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] =
2471 0;
2472 linked_pdp->nodata = 1;
2473 } else
2474 pdp_freepdp(pdp);
2475 }
jjako2c381332003-10-21 19:09:53 +00002476 }
Harald Weltebed35df2011-11-02 13:06:18 +01002477 /* if (cause == GTPCAUSE_ACC_REQ) */
2478 return 0;
jjako52c24142002-12-16 13:33:51 +00002479}
2480
2481/* Handle Delete PDP Context Request */
2482int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002483 struct sockaddr_in *peer, int fd,
Harald Weltebed35df2011-11-02 13:06:18 +01002484 void *pack, unsigned len)
2485{
2486 struct pdp_t *pdp = NULL;
2487 struct pdp_t *linked_pdp = NULL;
2488 union gtpie_member *ie[GTPIE_SIZE];
jjako52c24142002-12-16 13:33:51 +00002489
Harald Weltebed35df2011-11-02 13:06:18 +01002490 uint16_t seq = get_seq(pack);
2491 int hlen = get_hlen(pack);
jjako2c381332003-10-21 19:09:53 +00002492
Harald Weltebed35df2011-11-02 13:06:18 +01002493 uint8_t nsapi;
2494 uint8_t teardown = 0;
2495 int n;
2496 int count = 0;
jjako52c24142002-12-16 13:33:51 +00002497
Harald Weltebed35df2011-11-02 13:06:18 +01002498 /* Is this a dublicate ? */
2499 if (!gtp_dublicate(gsn, version, peer, seq)) {
2500 return 0; /* We allready send off response once */
2501 }
jjako2c381332003-10-21 19:09:53 +00002502
Harald Weltebed35df2011-11-02 13:06:18 +01002503 /* Find the linked context in question */
2504 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
2505 gsn->err_unknownpdp++;
2506 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2507 "Unknown PDP context");
2508 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2509 NULL, NULL, GTPCAUSE_NON_EXIST,
2510 teardown);
2511 }
jjako2c381332003-10-21 19:09:53 +00002512
Harald Weltebed35df2011-11-02 13:06:18 +01002513 /* If version 0 this is also the secondary context */
2514 if (version == 0)
2515 pdp = linked_pdp;
jjako2c381332003-10-21 19:09:53 +00002516
Harald Weltebed35df2011-11-02 13:06:18 +01002517 /* Decode information elements */
2518 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
2519 gsn->invalid++;
2520 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2521 "Invalid message format");
2522 if (0 == version)
2523 return EOF;
2524 else
2525 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2526 len, NULL, NULL,
2527 GTPCAUSE_INVALID_MESSAGE,
2528 teardown);
2529 }
2530
2531 if (version == 1) {
2532 /* NSAPI (mandatory) */
2533 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
2534 gsn->missing++;
2535 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2536 len, "Missing mandatory information field");
2537 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2538 len, NULL, NULL,
2539 GTPCAUSE_MAN_IE_MISSING,
2540 teardown);
2541 }
2542
2543 /* Find the context in question */
2544 if (pdp_getgtp1(&pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) {
2545 gsn->err_unknownpdp++;
2546 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2547 len, "Unknown PDP context");
2548 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2549 len, NULL, NULL,
2550 GTPCAUSE_NON_EXIST,
2551 teardown);
2552 }
2553
2554 /* Teardown (conditional) */
2555 gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown);
2556
2557 if (!teardown) {
2558 for (n = 0; n < PDP_MAXNSAPI; n++)
2559 if (linked_pdp->secondary_tei[n])
2560 count++;
2561 if (count <= 1) {
2562 return 0; /* 29.060 7.3.5 Ignore message */
2563 }
2564 }
2565 }
2566
2567 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2568 pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown);
jjako52c24142002-12-16 13:33:51 +00002569}
2570
jjako52c24142002-12-16 13:33:51 +00002571/* Handle Delete PDP Context Response */
2572int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002573 struct sockaddr_in *peer, void *pack, unsigned len)
2574{
2575 union gtpie_member *ie[GTPIE_SIZE];
2576 uint8_t cause;
2577 void *cbp = NULL;
2578 uint8_t type = 0;
2579 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002580
Harald Weltebed35df2011-11-02 13:06:18 +01002581 /* Remove packet from queue */
2582 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
2583 return EOF;
jjako52c24142002-12-16 13:33:51 +00002584
Harald Weltebed35df2011-11-02 13:06:18 +01002585 /* Decode information elements */
2586 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
2587 gsn->invalid++;
2588 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2589 "Invalid message format");
2590 if (gsn->cb_conf)
2591 gsn->cb_conf(type, EOF, NULL, cbp);
2592 return EOF;
2593 }
2594
2595 /* Extract cause value (mandatory) */
2596 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2597 gsn->missing++;
2598 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2599 "Missing mandatory information field");
2600 if (gsn->cb_conf)
2601 gsn->cb_conf(type, EOF, NULL, cbp);
2602 return EOF;
2603 }
2604
2605 /* Check the cause value (again) */
2606 if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
2607 gsn->err_cause++;
2608 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2609 "Unexpected cause value received: %d", cause);
2610 if (gsn->cb_conf)
2611 gsn->cb_conf(type, cause, NULL, cbp);
2612 return EOF;
2613 }
2614
2615 /* Callback function to notify application */
2616 if (gsn->cb_conf)
2617 gsn->cb_conf(type, cause, NULL, cbp);
2618
2619 return 0;
jjako52c24142002-12-16 13:33:51 +00002620}
2621
2622/* Send Error Indication (response to a GPDU message */
2623int gtp_error_ind_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002624 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002625 void *pack, unsigned len)
2626{
Harald Weltebed35df2011-11-02 13:06:18 +01002627 union gtp_packet packet;
2628 unsigned int length = get_default_gtp(version, GTP_ERROR, &packet);
2629
2630 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
2631 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002632}
2633
2634/* Handle Error Indication */
2635int gtp_error_ind_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002636 struct sockaddr_in *peer, void *pack, unsigned len)
2637{
2638 struct pdp_t *pdp;
jjako52c24142002-12-16 13:33:51 +00002639
Harald Weltebed35df2011-11-02 13:06:18 +01002640 /* Find the context in question */
2641 if (pdp_tidget(&pdp, ((union gtp_packet *)pack)->gtp0.h.tid)) {
2642 gsn->err_unknownpdp++;
2643 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2644 "Unknown PDP context");
2645 return EOF;
2646 }
jjako52c24142002-12-16 13:33:51 +00002647
Harald Weltebed35df2011-11-02 13:06:18 +01002648 gsn->err_unknownpdp++; /* TODO: Change counter */
2649 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2650 "Received Error Indication");
2651
2652 if (gsn->cb_delete_context)
2653 gsn->cb_delete_context(pdp);
2654 pdp_freepdp(pdp);
2655 return 0;
jjako52c24142002-12-16 13:33:51 +00002656}
2657
2658int gtp_gpdu_ind(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002659 struct sockaddr_in *peer, int fd, void *pack, unsigned len)
2660{
jjako08d331d2003-10-13 20:33:30 +00002661
Harald Weltebed35df2011-11-02 13:06:18 +01002662 int hlen = GTP1_HEADER_SIZE_SHORT;
jjako52c24142002-12-16 13:33:51 +00002663
Harald Weltebed35df2011-11-02 13:06:18 +01002664 /* Need to include code to verify packet src and dest addresses */
2665 struct pdp_t *pdp;
jjako1db1c812003-07-06 20:53:57 +00002666
Harald Weltebed35df2011-11-02 13:06:18 +01002667 if (version == 0) {
2668 if (pdp_getgtp0
2669 (&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) {
2670 gsn->err_unknownpdp++;
2671 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2672 len, "Unknown PDP context");
2673 return gtp_error_ind_resp(gsn, version, peer, fd, pack,
2674 len);
2675 }
2676 hlen = GTP0_HEADER_SIZE;
2677 } else if (version == 1) {
2678 if (pdp_getgtp1
2679 (&pdp, ntoh32(((union gtp_packet *)pack)->gtp1l.h.tei))) {
2680 gsn->err_unknownpdp++;
2681 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2682 len, "Unknown PDP context");
2683 return gtp_error_ind_resp(gsn, version, peer, fd, pack,
2684 len);
2685 }
jjako08d331d2003-10-13 20:33:30 +00002686
Harald Weltebed35df2011-11-02 13:06:18 +01002687 /* Is this a long or a short header ? */
2688 if (((union gtp_packet *)pack)->gtp1l.h.flags & 0x07)
2689 hlen = GTP1_HEADER_SIZE_LONG;
2690 else
2691 hlen = GTP1_HEADER_SIZE_SHORT;
2692 } else {
2693 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2694 "Unknown version");
2695 }
jjako08d331d2003-10-13 20:33:30 +00002696
Harald Weltebed35df2011-11-02 13:06:18 +01002697 /* If the GPDU was not from the peer GSN tell him to delete context */
2698 if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
2699 gsn->err_unknownpdp++;
2700 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2701 "Unknown PDP context");
2702 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2703 }
jjako52c24142002-12-16 13:33:51 +00002704
Harald Weltebed35df2011-11-02 13:06:18 +01002705 /* Callback function */
2706 if (gsn->cb_data_ind != 0)
2707 return gsn->cb_data_ind(pdp, pack + hlen, len - hlen);
2708
2709 return 0;
jjako52c24142002-12-16 13:33:51 +00002710}
2711
jjako52c24142002-12-16 13:33:51 +00002712/* Receives GTP packet and sends off for further processing
2713 * Function will check the validity of the header. If the header
2714 * is not valid the packet is either dropped or a version not
2715 * supported is returned to the peer.
2716 * TODO: Need to decide on return values! */
jjako08d331d2003-10-13 20:33:30 +00002717int gtp_decaps0(struct gsn_t *gsn)
jjako52c24142002-12-16 13:33:51 +00002718{
Harald Weltebed35df2011-11-02 13:06:18 +01002719 unsigned char buffer[PACKET_MAX];
2720 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01002721 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01002722 int status;
2723 struct gtp0_header *pheader;
2724 int version = 0; /* GTP version should be determined from header! */
2725 int fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00002726
Harald Weltebed35df2011-11-02 13:06:18 +01002727 /* TODO: Need strategy of userspace buffering and blocking */
2728 /* Currently read is non-blocking and send is blocking. */
2729 /* This means that the program have to wait for busy send calls... */
jjako52c24142002-12-16 13:33:51 +00002730
Harald Weltebed35df2011-11-02 13:06:18 +01002731 while (1) { /* Loop until no more to read */
2732 if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) {
2733 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2734 return -1;
2735 }
2736 peerlen = sizeof(peer);
2737 if ((status =
2738 recvfrom(gsn->fd0, buffer, sizeof(buffer), 0,
2739 (struct sockaddr *)&peer, &peerlen)) < 0) {
2740 if (errno == EAGAIN)
2741 return 0;
2742 gsn->err_readfrom++;
2743 gtp_err(LOG_ERR, __FILE__, __LINE__,
2744 "recvfrom(fd0=%d, buffer=%lx, len=%d) failed: status = %d error = %s",
2745 gsn->fd0, (unsigned long)buffer, sizeof(buffer),
2746 status, status ? strerror(errno) : "No error");
2747 return -1;
2748 }
jjako1db1c812003-07-06 20:53:57 +00002749
Harald Weltebed35df2011-11-02 13:06:18 +01002750 /* Need at least 1 byte in order to check version */
2751 if (status < (1)) {
2752 gsn->empty++;
2753 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2754 status, "Discarding packet - too small");
2755 continue;
2756 }
jjako08d331d2003-10-13 20:33:30 +00002757
Harald Weltebed35df2011-11-02 13:06:18 +01002758 pheader = (struct gtp0_header *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00002759
Harald Weltebed35df2011-11-02 13:06:18 +01002760 /* Version should be gtp0 (or earlier) */
2761 /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
2762 /* GTP 0 messages. If other version message is received we reply that we */
2763 /* only support version 0, implying that this is the only version */
2764 /* supported on this port */
2765 if (((pheader->flags & 0xe0) > 0x00)) {
2766 gsn->unsup++;
2767 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2768 status, "Unsupported GTP version");
2769 gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */
2770 continue;
2771 }
2772
2773 /* Check length of gtp0 packet */
2774 if (status < GTP0_HEADER_SIZE) {
2775 gsn->tooshort++;
2776 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2777 status, "GTP0 packet too short");
2778 continue; /* Silently discard 29.60: 11.1.2 */
2779 }
2780
2781 /* Check packet length field versus length of packet */
2782 if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
2783 gsn->tooshort++;
2784 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2785 status,
2786 "GTP packet length field does not match actual length");
2787 continue; /* Silently discard */
2788 }
2789
2790 if ((gsn->mode == GTP_MODE_GGSN) &&
2791 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2792 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2793 (pheader->type == GTP_DELETE_PDP_RSP))) {
2794 gsn->unexpect++;
2795 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2796 status,
2797 "Unexpected GTP Signalling Message");
2798 continue; /* Silently discard 29.60: 11.1.4 */
2799 }
2800
2801 if ((gsn->mode == GTP_MODE_SGSN) &&
2802 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2803 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2804 (pheader->type == GTP_DELETE_PDP_REQ))) {
2805 gsn->unexpect++;
2806 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2807 status,
2808 "Unexpected GTP Signalling Message");
2809 continue; /* Silently discard 29.60: 11.1.4 */
2810 }
2811
2812 switch (pheader->type) {
2813 case GTP_ECHO_REQ:
2814 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2815 break;
2816 case GTP_ECHO_RSP:
2817 gtp_echo_conf(gsn, version, &peer, buffer, status);
2818 break;
2819 case GTP_NOT_SUPPORTED:
2820 gtp_unsup_ind(gsn, &peer, buffer, status);
2821 break;
2822 case GTP_CREATE_PDP_REQ:
2823 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer,
2824 status);
2825 break;
2826 case GTP_CREATE_PDP_RSP:
2827 gtp_create_pdp_conf(gsn, version, &peer, buffer,
2828 status);
2829 break;
2830 case GTP_UPDATE_PDP_REQ:
2831 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer,
2832 status);
2833 break;
2834 case GTP_UPDATE_PDP_RSP:
2835 gtp_update_pdp_conf(gsn, version, &peer, buffer,
2836 status);
2837 break;
2838 case GTP_DELETE_PDP_REQ:
2839 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer,
2840 status);
2841 break;
2842 case GTP_DELETE_PDP_RSP:
2843 gtp_delete_pdp_conf(gsn, version, &peer, buffer,
2844 status);
2845 break;
2846 case GTP_ERROR:
2847 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2848 break;
2849 case GTP_GPDU:
2850 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2851 break;
2852 default:
2853 gsn->unknown++;
2854 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2855 status,
2856 "Unknown GTP message type received");
2857 break;
2858 }
2859 }
jjako08d331d2003-10-13 20:33:30 +00002860}
2861
jjako08d331d2003-10-13 20:33:30 +00002862int gtp_decaps1c(struct gsn_t *gsn)
2863{
Harald Weltebed35df2011-11-02 13:06:18 +01002864 unsigned char buffer[PACKET_MAX];
2865 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01002866 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01002867 int status;
2868 struct gtp1_header_short *pheader;
2869 int version = 1; /* TODO GTP version should be determined from header! */
2870 int fd = gsn->fd1c;
jjako08d331d2003-10-13 20:33:30 +00002871
Harald Weltebed35df2011-11-02 13:06:18 +01002872 /* TODO: Need strategy of userspace buffering and blocking */
2873 /* Currently read is non-blocking and send is blocking. */
2874 /* This means that the program have to wait for busy send calls... */
jjako08d331d2003-10-13 20:33:30 +00002875
Harald Weltebed35df2011-11-02 13:06:18 +01002876 while (1) { /* Loop until no more to read */
2877 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
2878 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2879 return -1;
2880 }
2881 peerlen = sizeof(peer);
2882 if ((status =
2883 recvfrom(fd, buffer, sizeof(buffer), 0,
2884 (struct sockaddr *)&peer, &peerlen)) < 0) {
2885 if (errno == EAGAIN)
2886 return 0;
2887 gsn->err_readfrom++;
2888 gtp_err(LOG_ERR, __FILE__, __LINE__,
2889 "recvfrom(fd=%d, buffer=%lx, len=%d) failed: status = %d error = %s",
2890 fd, (unsigned long)buffer, sizeof(buffer),
2891 status, status ? strerror(errno) : "No error");
2892 return -1;
2893 }
jjako08d331d2003-10-13 20:33:30 +00002894
Harald Weltebed35df2011-11-02 13:06:18 +01002895 /* Need at least 1 byte in order to check version */
2896 if (status < (1)) {
2897 gsn->empty++;
2898 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2899 status, "Discarding packet - too small");
2900 continue;
2901 }
jjako08d331d2003-10-13 20:33:30 +00002902
Harald Weltebed35df2011-11-02 13:06:18 +01002903 pheader = (struct gtp1_header_short *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00002904
Harald Weltebed35df2011-11-02 13:06:18 +01002905 /* Version must be no larger than GTP 1 */
2906 if (((pheader->flags & 0xe0) > 0x20)) {
2907 gsn->unsup++;
2908 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2909 status, "Unsupported GTP version");
2910 gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
2911 /*29.60: 11.1.1 */
2912 continue;
2913 }
jjako08d331d2003-10-13 20:33:30 +00002914
Harald Weltebed35df2011-11-02 13:06:18 +01002915 /* Version must be at least GTP 1 */
2916 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2917 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2918 /* the message */
2919 if (((pheader->flags & 0xe0) < 0x20)) {
2920 gsn->unsup++;
2921 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2922 status, "Unsupported GTP version");
2923 continue;
2924 }
jjako08d331d2003-10-13 20:33:30 +00002925
Harald Weltebed35df2011-11-02 13:06:18 +01002926 /* Check packet flag field */
2927 if (((pheader->flags & 0xf7) != 0x32)) {
2928 gsn->unsup++;
2929 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2930 status, "Unsupported packet flag");
2931 continue;
2932 }
jjako2c381332003-10-21 19:09:53 +00002933
Harald Weltebed35df2011-11-02 13:06:18 +01002934 /* Check length of packet */
2935 if (status < GTP1_HEADER_SIZE_LONG) {
2936 gsn->tooshort++;
2937 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2938 status, "GTP packet too short");
2939 continue; /* Silently discard 29.60: 11.1.2 */
2940 }
jjako2c381332003-10-21 19:09:53 +00002941
Harald Weltebed35df2011-11-02 13:06:18 +01002942 /* Check packet length field versus length of packet */
2943 if (status !=
2944 (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
2945 gsn->tooshort++;
2946 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2947 status,
2948 "GTP packet length field does not match actual length");
2949 continue; /* Silently discard */
2950 }
jjako1db1c812003-07-06 20:53:57 +00002951
Harald Weltebed35df2011-11-02 13:06:18 +01002952 /* Check for extension headers */
2953 /* TODO: We really should cycle through the headers and determine */
2954 /* if any have the comprehension required flag set */
2955 if (((pheader->flags & 0x04) != 0x00)) {
2956 gsn->unsup++;
2957 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2958 status, "Unsupported extension header");
2959 gtp_extheader_req(gsn, version, &peer, fd, buffer,
2960 status);
jjako1db1c812003-07-06 20:53:57 +00002961
Harald Weltebed35df2011-11-02 13:06:18 +01002962 continue;
2963 }
2964
2965 if ((gsn->mode == GTP_MODE_GGSN) &&
2966 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2967 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2968 (pheader->type == GTP_DELETE_PDP_RSP))) {
2969 gsn->unexpect++;
2970 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2971 status,
2972 "Unexpected GTP Signalling Message");
2973 continue; /* Silently discard 29.60: 11.1.4 */
2974 }
2975
2976 if ((gsn->mode == GTP_MODE_SGSN) &&
2977 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2978 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2979 (pheader->type == GTP_DELETE_PDP_REQ))) {
2980 gsn->unexpect++;
2981 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2982 status,
2983 "Unexpected GTP Signalling Message");
2984 continue; /* Silently discard 29.60: 11.1.4 */
2985 }
2986
2987 switch (pheader->type) {
2988 case GTP_ECHO_REQ:
2989 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2990 break;
2991 case GTP_ECHO_RSP:
2992 gtp_echo_conf(gsn, version, &peer, buffer, status);
2993 break;
2994 case GTP_NOT_SUPPORTED:
2995 gtp_unsup_ind(gsn, &peer, buffer, status);
2996 break;
2997 case GTP_SUPP_EXT_HEADER:
2998 gtp_extheader_ind(gsn, &peer, buffer, status);
2999 break;
3000 case GTP_CREATE_PDP_REQ:
3001 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer,
3002 status);
3003 break;
3004 case GTP_CREATE_PDP_RSP:
3005 gtp_create_pdp_conf(gsn, version, &peer, buffer,
3006 status);
3007 break;
3008 case GTP_UPDATE_PDP_REQ:
3009 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer,
3010 status);
3011 break;
3012 case GTP_UPDATE_PDP_RSP:
3013 gtp_update_pdp_conf(gsn, version, &peer, buffer,
3014 status);
3015 break;
3016 case GTP_DELETE_PDP_REQ:
3017 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer,
3018 status);
3019 break;
3020 case GTP_DELETE_PDP_RSP:
3021 gtp_delete_pdp_conf(gsn, version, &peer, buffer,
3022 status);
3023 break;
3024 case GTP_ERROR:
3025 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
3026 break;
3027 default:
3028 gsn->unknown++;
3029 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3030 status,
3031 "Unknown GTP message type received");
3032 break;
3033 }
3034 }
jjako52c24142002-12-16 13:33:51 +00003035}
3036
jjako08d331d2003-10-13 20:33:30 +00003037int gtp_decaps1u(struct gsn_t *gsn)
3038{
Harald Weltebed35df2011-11-02 13:06:18 +01003039 unsigned char buffer[PACKET_MAX];
3040 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01003041 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01003042 int status;
3043 struct gtp1_header_short *pheader;
3044 int version = 1; /* GTP version should be determined from header! */
3045 int fd = gsn->fd1u;
jjako08d331d2003-10-13 20:33:30 +00003046
Harald Weltebed35df2011-11-02 13:06:18 +01003047 /* TODO: Need strategy of userspace buffering and blocking */
3048 /* Currently read is non-blocking and send is blocking. */
3049 /* This means that the program have to wait for busy send calls... */
jjako08d331d2003-10-13 20:33:30 +00003050
Harald Weltebed35df2011-11-02 13:06:18 +01003051 while (1) { /* Loop until no more to read */
3052 if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) {
3053 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
3054 return -1;
3055 }
3056 peerlen = sizeof(peer);
3057 if ((status =
3058 recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0,
3059 (struct sockaddr *)&peer, &peerlen)) < 0) {
3060 if (errno == EAGAIN)
3061 return 0;
3062 gsn->err_readfrom++;
3063 gtp_err(LOG_ERR, __FILE__, __LINE__,
3064 "recvfrom(fd1u=%d, buffer=%lx, len=%d) failed: status = %d error = %s",
3065 gsn->fd1u, (unsigned long)buffer,
3066 sizeof(buffer), status,
3067 status ? strerror(errno) : "No error");
3068 return -1;
3069 }
jjako08d331d2003-10-13 20:33:30 +00003070
Harald Weltebed35df2011-11-02 13:06:18 +01003071 /* Need at least 1 byte in order to check version */
3072 if (status < (1)) {
3073 gsn->empty++;
3074 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3075 status, "Discarding packet - too small");
3076 continue;
3077 }
jjako08d331d2003-10-13 20:33:30 +00003078
Harald Weltebed35df2011-11-02 13:06:18 +01003079 pheader = (struct gtp1_header_short *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00003080
Harald Weltebed35df2011-11-02 13:06:18 +01003081 /* Version must be no larger than GTP 1 */
3082 if (((pheader->flags & 0xe0) > 0x20)) {
3083 gsn->unsup++;
3084 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3085 status, "Unsupported GTP version");
3086 gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status); /*29.60: 11.1.1 */
3087 continue;
3088 }
jjako08d331d2003-10-13 20:33:30 +00003089
Harald Weltebed35df2011-11-02 13:06:18 +01003090 /* Version must be at least GTP 1 */
3091 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
3092 /* GTP 1 messages. If GTP 0 message is received we silently discard */
3093 /* the message */
3094 if (((pheader->flags & 0xe0) < 0x20)) {
3095 gsn->unsup++;
3096 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3097 status, "Unsupported GTP version");
3098 continue;
3099 }
jjako2c381332003-10-21 19:09:53 +00003100
Harald Weltebed35df2011-11-02 13:06:18 +01003101 /* Check packet flag field (allow both with and without sequence number) */
3102 if (((pheader->flags & 0xf5) != 0x30)) {
3103 gsn->unsup++;
3104 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3105 status, "Unsupported packet flag");
3106 continue;
3107 }
jjako2c381332003-10-21 19:09:53 +00003108
Harald Weltebed35df2011-11-02 13:06:18 +01003109 /* Check length of packet */
3110 if (status < GTP1_HEADER_SIZE_SHORT) {
3111 gsn->tooshort++;
3112 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3113 status, "GTP packet too short");
3114 continue; /* Silently discard 29.60: 11.1.2 */
3115 }
3116
3117 /* Check packet length field versus length of packet */
3118 if (status !=
3119 (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
3120 gsn->tooshort++;
3121 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3122 status,
3123 "GTP packet length field does not match actual length");
3124 continue; /* Silently discard */
3125 }
3126
3127 /* Check for extension headers */
3128 /* TODO: We really should cycle through the headers and determine */
3129 /* if any have the comprehension required flag set */
3130 if (((pheader->flags & 0x04) != 0x00)) {
3131 gsn->unsup++;
3132 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3133 status, "Unsupported extension header");
3134 gtp_extheader_req(gsn, version, &peer, fd, buffer,
3135 status);
3136
3137 continue;
3138 }
3139
3140 switch (pheader->type) {
3141 case GTP_ECHO_REQ:
3142 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
3143 break;
3144 case GTP_ECHO_RSP:
3145 gtp_echo_conf(gsn, version, &peer, buffer, status);
3146 break;
3147 case GTP_SUPP_EXT_HEADER:
3148 gtp_extheader_ind(gsn, &peer, buffer, status);
3149 break;
3150 case GTP_ERROR:
3151 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
3152 break;
3153 /* Supported header extensions */
3154 case GTP_GPDU:
3155 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
3156 break;
3157 default:
3158 gsn->unknown++;
3159 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3160 status,
3161 "Unknown GTP message type received");
3162 break;
3163 }
3164 }
jjako08d331d2003-10-13 20:33:30 +00003165}
3166
Harald Weltebed35df2011-11-02 13:06:18 +01003167int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +00003168{
Harald Weltebed35df2011-11-02 13:06:18 +01003169 union gtp_packet packet;
3170 struct sockaddr_in addr;
3171 int fd;
3172 int length;
jjako52c24142002-12-16 13:33:51 +00003173
Harald Weltebed35df2011-11-02 13:06:18 +01003174 memset(&addr, 0, sizeof(addr));
3175 addr.sin_family = AF_INET;
jjako0fe0df02004-09-17 11:30:40 +00003176#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +01003177 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +00003178#endif
3179
Harald Weltebed35df2011-11-02 13:06:18 +01003180 memcpy(&addr.sin_addr, pdp->gsnru.v, pdp->gsnru.l); /* TODO range check */
jjako52c24142002-12-16 13:33:51 +00003181
Harald Weltebed35df2011-11-02 13:06:18 +01003182 if (pdp->version == 0) {
jjako52c24142002-12-16 13:33:51 +00003183
Harald Weltebed35df2011-11-02 13:06:18 +01003184 length = GTP0_HEADER_SIZE + len;
3185 addr.sin_port = htons(GTP0_PORT);
3186 fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00003187
Harald Weltebed35df2011-11-02 13:06:18 +01003188 get_default_gtp(0, GTP_GPDU, &packet);
3189 packet.gtp0.h.length = hton16(len);
3190 packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
3191 packet.gtp0.h.flow = hton16(pdp->flru);
3192 packet.gtp0.h.tid =
3193 (pdp->imsi & 0x0fffffffffffffffull) +
3194 ((uint64_t) pdp->nsapi << 60);
jjako08d331d2003-10-13 20:33:30 +00003195
Harald Weltebed35df2011-11-02 13:06:18 +01003196 if (len > sizeof(union gtp_packet) - sizeof(struct gtp0_header)) {
3197 gsn->err_memcpy++;
3198 gtp_err(LOG_ERR, __FILE__, __LINE__,
3199 "Memcpy failed: %d > %d", len,
3200 sizeof(union gtp_packet) -
3201 sizeof(struct gtp0_header));
3202 return EOF;
3203 }
3204 memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */
3205 } else if (pdp->version == 1) {
jjako08d331d2003-10-13 20:33:30 +00003206
Harald Weltebed35df2011-11-02 13:06:18 +01003207 length = GTP1_HEADER_SIZE_LONG + len;
3208 addr.sin_port = htons(GTP1U_PORT);
3209 fd = gsn->fd1u;
jjakoa7cd2492003-04-11 09:40:12 +00003210
Harald Weltebed35df2011-11-02 13:06:18 +01003211 get_default_gtp(1, GTP_GPDU, &packet);
3212 packet.gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT +
3213 GTP1_HEADER_SIZE_LONG);
3214 packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
3215 packet.gtp1l.h.tei = hton32(pdp->teid_gn);
3216
3217 if (len >
3218 sizeof(union gtp_packet) -
3219 sizeof(struct gtp1_header_long)) {
3220 gsn->err_memcpy++;
3221 gtp_err(LOG_ERR, __FILE__, __LINE__,
3222 "Memcpy failed: %d > %d", len,
3223 sizeof(union gtp_packet) -
3224 sizeof(struct gtp0_header));
3225 return EOF;
3226 }
3227 memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */
3228 } else {
3229 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
3230 return EOF;
3231 }
3232
3233 if (fcntl(fd, F_SETFL, 0)) {
3234 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
3235 return -1;
3236 }
3237
3238 if (sendto(fd, &packet, length, 0,
3239 (struct sockaddr *)&addr, sizeof(addr)) < 0) {
3240 gsn->err_sendto++;
3241 gtp_err(LOG_ERR, __FILE__, __LINE__,
3242 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
3243 (unsigned long)&packet, GTP0_HEADER_SIZE + len,
3244 strerror(errno));
3245 return EOF;
3246 }
3247 return 0;
jjako52c24142002-12-16 13:33:51 +00003248}
3249
jjako52c24142002-12-16 13:33:51 +00003250/* ***********************************************************
3251 * Conversion functions
3252 *************************************************************/
3253
Harald Weltebed35df2011-11-02 13:06:18 +01003254int char2ul_t(char *src, struct ul_t dst)
3255{
3256 dst.l = strlen(src) + 1;
3257 dst.v = malloc(dst.l);
3258 dst.v[0] = dst.l - 1;
3259 memcpy(&dst.v[1], src, dst.v[0]);
3260 return 0;
jjako52c24142002-12-16 13:33:51 +00003261}
3262
3263/* ***********************************************************
3264 * IP address conversion functions
3265 * There exist several types of address representations:
3266 * - eua: End User Address. (29.060, 7.7.27, message type 128)
3267 * Used for signalling address to mobile station. Supports IPv4
3268 * IPv6 x.25 etc. etc.
3269 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
3270 * of GSN. If length is 4 it is IPv4. If length is 16 it is IPv6.
3271 * - in_addr: IPv4 address struct.
3272 * - sockaddr_in: Socket API representation of IP address and
3273 * port number.
3274 *************************************************************/
3275
Harald Weltebed35df2011-11-02 13:06:18 +01003276int ipv42eua(struct ul66_t *eua, struct in_addr *src)
3277{
3278 eua->v[0] = 0xf1; /* IETF */
3279 eua->v[1] = 0x21; /* IPv4 */
3280 if (src) {
3281 eua->l = 6;
3282 memcpy(&eua->v[2], src, 4);
3283 } else {
3284 eua->l = 2;
3285 }
3286 return 0;
jjako52c24142002-12-16 13:33:51 +00003287}
3288
Harald Weltebed35df2011-11-02 13:06:18 +01003289int eua2ipv4(struct in_addr *dst, struct ul66_t *eua)
3290{
3291 if ((eua->l != 6) || (eua->v[0] != 0xf1) || (eua->v[1] = 0x21))
3292 return -1; /* Not IPv4 address */
3293 memcpy(dst, &eua->v[2], 4);
3294 return 0;
jjako52c24142002-12-16 13:33:51 +00003295}
3296
Harald Weltebed35df2011-11-02 13:06:18 +01003297int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna)
3298{
3299 memset(dst, 0, sizeof(struct in_addr));
3300 if (gsna->l != 4)
3301 return EOF; /* Return if not IPv4 */
3302 memcpy(dst, gsna->v, gsna->l);
3303 return 0;
jjako52c24142002-12-16 13:33:51 +00003304}
3305
Harald Weltebed35df2011-11-02 13:06:18 +01003306int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src)
3307{
3308 memset(gsna, 0, sizeof(struct ul16_t));
3309 gsna->l = 4;
3310 memcpy(gsna->v, src, gsna->l);
3311 return 0;
jjako52c24142002-12-16 13:33:51 +00003312}