blob: 3cc0c0bd48bcb03407763f77d870436a5218efe5 [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
Harald Welte95848ba2011-11-02 18:17:50 +010054/* According to section 14.2 of 3GPP TS 29.006 version 6.9.0 */
55#define N3_REQUESTS 5
56
57#define T3_REQUEST 3
58
jjako1db1c812003-07-06 20:53:57 +000059/* Error reporting functions */
60
Harald Weltebed35df2011-11-02 13:06:18 +010061void gtp_err(int priority, char *filename, int linenum, char *fmt, ...)
62{
63 va_list args;
64 char buf[ERRMSG_SIZE];
jjako1db1c812003-07-06 20:53:57 +000065
Harald Weltebed35df2011-11-02 13:06:18 +010066 va_start(args, fmt);
67 vsnprintf(buf, ERRMSG_SIZE, fmt, args);
68 va_end(args);
69 buf[ERRMSG_SIZE - 1] = 0;
70 syslog(priority, "%s: %d: %s", filename, linenum, buf);
jjako1db1c812003-07-06 20:53:57 +000071}
72
73void gtp_errpack(int pri, char *fn, int ln, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +010074 void *pack, unsigned len, char *fmt, ...)
75{
jjako1db1c812003-07-06 20:53:57 +000076
Harald Weltebed35df2011-11-02 13:06:18 +010077 va_list args;
78 char buf[ERRMSG_SIZE];
79 char buf2[ERRMSG_SIZE];
80 unsigned int n;
81 int pos;
82
83 va_start(args, fmt);
84 vsnprintf(buf, ERRMSG_SIZE, fmt, args);
85 va_end(args);
86 buf[ERRMSG_SIZE - 1] = 0;
87
88 snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:",
89 inet_ntoa(peer->sin_addr), ntohs(peer->sin_port), len);
90 buf2[ERRMSG_SIZE - 1] = 0;
91 pos = strlen(buf2);
92 for (n = 0; n < len; n++) {
93 if ((pos + 4) < ERRMSG_SIZE) {
94 sprintf((buf2 + pos), " %02hhx",
95 ((unsigned char *)pack)[n]);
96 pos += 3;
97 }
98 }
99 buf2[pos] = 0;
100
101 syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
jjako1db1c812003-07-06 20:53:57 +0000102
103}
104
jjako52c24142002-12-16 13:33:51 +0000105/* API Functions */
106
Harald Weltebed35df2011-11-02 13:06:18 +0100107const char *gtp_version()
jjako52c24142002-12-16 13:33:51 +0000108{
Harald Weltebed35df2011-11-02 13:06:18 +0100109 return VERSION;
jjako52c24142002-12-16 13:33:51 +0000110}
111
112/* gtp_new */
113/* gtp_free */
114
Harald Weltebed35df2011-11-02 13:06:18 +0100115int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
116 uint64_t imsi, uint8_t nsapi)
117{
118 return pdp_newpdp(pdp, imsi, nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +0000119}
120
Harald Weltebed35df2011-11-02 13:06:18 +0100121int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp)
122{
123 return pdp_freepdp(pdp);
jjako52c24142002-12-16 13:33:51 +0000124}
125
jjako52c24142002-12-16 13:33:51 +0000126/* gtp_gpdu */
127
Harald Weltebed35df2011-11-02 13:06:18 +0100128extern int gtp_fd(struct gsn_t *gsn)
129{
130 return gsn->fd0;
jjako52c24142002-12-16 13:33:51 +0000131}
132
133/* gtp_decaps */
134/* gtp_retrans */
135/* gtp_retranstimeout */
136
jjako08d331d2003-10-13 20:33:30 +0000137int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +0100138 int (*cb) (struct sockaddr_in * peer))
139{
140 gsn->cb_unsup_ind = cb;
141 return 0;
jjako08d331d2003-10-13 20:33:30 +0000142}
143
jjako2c381332003-10-21 19:09:53 +0000144int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +0100145 int (*cb) (struct sockaddr_in * peer))
146{
147 gsn->cb_extheader_ind = cb;
148 return 0;
jjako2c381332003-10-21 19:09:53 +0000149}
150
jjako08d331d2003-10-13 20:33:30 +0000151/* API: Initialise delete context callback */
152/* Called whenever a pdp context is deleted for any reason */
Harald Weltebed35df2011-11-02 13:06:18 +0100153int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb) (struct pdp_t * pdp))
jjako52c24142002-12-16 13:33:51 +0000154{
Harald Weltebed35df2011-11-02 13:06:18 +0100155 gsn->cb_delete_context = cb;
156 return 0;
jjako52c24142002-12-16 13:33:51 +0000157}
158
jjako52c24142002-12-16 13:33:51 +0000159int gtp_set_cb_conf(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +0100160 int (*cb) (int type, int cause,
161 struct pdp_t * pdp, void *cbp))
162{
163 gsn->cb_conf = cb;
164 return 0;
jjako52c24142002-12-16 13:33:51 +0000165}
166
Harald Welte629e9862010-12-24 20:58:09 +0100167int gtp_set_cb_recovery(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +0100168 int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
169{
170 gsn->cb_recovery = cb;
171 return 0;
Harald Welte629e9862010-12-24 20:58:09 +0100172}
173
jjako08d331d2003-10-13 20:33:30 +0000174extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +0100175 int (*cb_data_ind) (struct pdp_t * pdp,
176 void *pack, unsigned len))
jjako52c24142002-12-16 13:33:51 +0000177{
Harald Weltebed35df2011-11-02 13:06:18 +0100178 gsn->cb_data_ind = cb_data_ind;
179 return 0;
jjako52c24142002-12-16 13:33:51 +0000180}
181
jjako08d331d2003-10-13 20:33:30 +0000182/**
183 * get_default_gtp()
184 * Generate a GPRS Tunneling Protocol signalling packet header, depending
185 * on GTP version and message type. pdp is used for teid/flow label.
186 * *packet must be allocated by the calling function, and be large enough
187 * to hold the packet header.
188 * returns the length of the header. 0 on error.
189 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100190static unsigned int get_default_gtp(int version, uint8_t type, void *packet)
191{
192 struct gtp0_header *gtp0_default = (struct gtp0_header *)packet;
193 struct gtp1_header_long *gtp1_default =
194 (struct gtp1_header_long *)packet;
195 switch (version) {
196 case 0:
197 /* Initialise "standard" GTP0 header */
198 memset(gtp0_default, 0, sizeof(struct gtp0_header));
199 gtp0_default->flags = 0x1e;
200 gtp0_default->type = hton8(type);
201 gtp0_default->spare1 = 0xff;
202 gtp0_default->spare2 = 0xff;
203 gtp0_default->spare3 = 0xff;
204 gtp0_default->number = 0xff;
205 return GTP0_HEADER_SIZE;
206 case 1:
207 /* Initialise "standard" GTP1 header */
208 /* 29.060: 8.2: S=1 and PN=0 */
209 /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */
210 /* and Supported Extension Headers Notification, the S field shall be */
211 /* set to 1 */
212 /* Currently extension headers are not supported */
213 memset(gtp1_default, 0, sizeof(struct gtp1_header_long));
214 gtp1_default->flags = 0x32; /* No extension, enable sequence, no N-PDU */
215 gtp1_default->type = hton8(type);
216 return GTP1_HEADER_SIZE_LONG;
217 default:
218 gtp_err(LOG_ERR, __FILE__, __LINE__,
219 "Unknown GTP packet version");
220 return 0;
221 }
jjako52c24142002-12-16 13:33:51 +0000222}
223
jjako08d331d2003-10-13 20:33:30 +0000224/**
225 * get_seq()
226 * Get sequence number of a packet.
227 * Returns 0 on error
228 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100229static uint16_t get_seq(void *pack)
230{
231 union gtp_packet *packet = (union gtp_packet *)pack;
jjako08d331d2003-10-13 20:33:30 +0000232
Harald Weltebed35df2011-11-02 13:06:18 +0100233 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
234 return ntoh16(packet->gtp0.h.seq);
235 } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
236 return ntoh16(packet->gtp1l.h.seq);
237 } else {
238 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
239 return 0;
240 }
jjako08d331d2003-10-13 20:33:30 +0000241}
242
243/**
244 * get_tid()
245 * Get tunnel identifier of a packet.
246 * Returns 0 on error
247 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100248static uint64_t get_tid(void *pack)
249{
250 union gtp_packet *packet = (union gtp_packet *)pack;
251
252 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
253 return packet->gtp0.h.tid;
254 }
255 return 0;
jjako08d331d2003-10-13 20:33:30 +0000256}
257
258/**
259 * get_hlen()
260 * Get the header length of a packet.
261 * Returns 0 on error
262 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100263static uint16_t get_hlen(void *pack)
264{
265 union gtp_packet *packet = (union gtp_packet *)pack;
jjako08d331d2003-10-13 20:33:30 +0000266
Harald Weltebed35df2011-11-02 13:06:18 +0100267 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
268 return GTP0_HEADER_SIZE;
269 } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
270 return GTP1_HEADER_SIZE_LONG;
271 } else if ((packet->flags & 0xe7) == 0x20) { /* Short version 1 */
272 return GTP1_HEADER_SIZE_SHORT;
273 } else {
274 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
275 return 0;
276 }
jjako08d331d2003-10-13 20:33:30 +0000277}
278
279/**
280 * get_tei()
281 * Get the tunnel endpoint identifier (flow label) of a packet.
282 * Returns 0xffffffff on error.
283 **/
Harald Weltebed35df2011-11-02 13:06:18 +0100284static uint32_t get_tei(void *pack)
285{
286 union gtp_packet *packet = (union gtp_packet *)pack;
jjako08d331d2003-10-13 20:33:30 +0000287
Harald Weltebed35df2011-11-02 13:06:18 +0100288 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
289 return ntoh16(packet->gtp0.h.flow);
290 } else if ((packet->flags & 0xe0) == 0x20) { /* Version 1 */
291 return ntoh32(packet->gtp1l.h.tei);
292 } else {
293 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
294 return 0xffffffff;
295 }
jjako08d331d2003-10-13 20:33:30 +0000296}
jjakoa7cd2492003-04-11 09:40:12 +0000297
jjako52c24142002-12-16 13:33:51 +0000298int print_packet(void *packet, unsigned len)
299{
Harald Weltebed35df2011-11-02 13:06:18 +0100300 unsigned int i;
301 printf("The packet looks like this (%d bytes):\n", len);
302 for (i = 0; i < len; i++) {
303 printf("%02x ", (unsigned char)*(char *)(packet + i));
304 if (!((i + 1) % 16))
305 printf("\n");
306 };
307 printf("\n");
308 return 0;
jjako52c24142002-12-16 13:33:51 +0000309}
310
Harald Weltebed35df2011-11-02 13:06:18 +0100311char *snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer,
312 void *pack, unsigned len, char *buf, int size)
313{
314 unsigned int n;
315 int pos;
316 snprintf(buf, size, "Packet from %s:%u, length: %d, content:",
317 inet_ntoa(peer->sin_addr), ntohs(peer->sin_port), len);
318 buf[size - 1] = 0;
319 pos = strlen(buf);
320 for (n = 0; n < len; n++) {
321 if ((pos + 4) < size) {
322 sprintf((buf + pos), " %02hhx",
323 ((unsigned char *)pack)[n]);
324 pos += 3;
325 }
326 }
327 buf[pos] = 0;
328 return buf;
jjako52c24142002-12-16 13:33:51 +0000329}
330
jjako52c24142002-12-16 13:33:51 +0000331/* ***********************************************************
332 * Reliable delivery of signalling messages
333 *
334 * Sequence numbers are used for both signalling messages and
335 * data messages.
336 *
337 * For data messages each tunnel maintains a sequence counter,
338 * which is incremented by one each time a new data message
339 * is sent. The sequence number starts at (0) zero at tunnel
340 * establishment, and wraps around at 65535 (29.060 9.3.1.1
341 * and 09.60 8.1.1.1). The sequence numbers are either ignored,
342 * or can be used to check the validity of the message in the
343 * receiver, or for reordering af packets.
344 *
345 * For signalling messages the sequence number is used by
346 * signalling messages for which a response is defined. A response
347 * message should copy the sequence from the corresponding request
348 * message. The sequence number "unambiguously" identifies a request
349 * message within a given path, with a path being defined as a set of
350 * two endpoints (29.060 8.2, 29.060 7.6, 09.60 7.8). "All request
351 * messages shall be responded to, and all response messages associated
352 * with a certain request shall always include the same information"
353 *
354 * We take this to mean that the GSN transmitting a request is free to
355 * choose the sequence number, as long as it is unique within a given path.
356 * It means that we are allowed to count backwards, or roll over at 17
357 * if we prefer that. It also means that we can use the same counter for
358 * all paths. This has the advantage that the transmitted request sequence
359 * numbers are unique within each GSN, and also we dont have to mess around
360 * with path setup and teardown.
361 *
362 * If a response message is lost, the request will be retransmitted, and
363 * the receiving GSN will receive a "duplicated" request. The standard
364 * requires the receiving GSN to send a response, with the same information
365 * as in the original response. For most messages this happens automatically:
366 *
367 * Echo: Automatically dublicates the original response
368 * Create pdp context: The SGSN may send create context request even if
369 * a context allready exist (imsi+nsapi?). This means that the reply will
370 automatically dublicate the original response. It might however have
jjako08d331d2003-10-13 20:33:30 +0000371 * side effects in the application which is asked twice to validate
372 * the login.
jjako52c24142002-12-16 13:33:51 +0000373 * Update pdp context: Automatically dublicates the original response???
374 * Delete pdp context. Automatically in gtp0, but in gtp1 will generate
375 * a nonexist reply message.
376 *
377 * The correct solution will be to make a queue containing response messages.
378 * This queue should be checked whenever a request is received. If the
379 * response is allready in the queue that response should be transmitted.
380 * It should be possible to find messages in this queue on the basis of
381 * the sequence number and peer GSN IP address (The sequense number is unique
382 * within each path). This need to be implemented by a hash table. Furthermore
383 * it should be possibly to delete messages based on a timeout. This can be
384 * achieved by means of a linked list. The timeout value need to be larger
385 * than T3-RESPONSE * N3-REQUESTS (recommended value 5). These timers are
386 * set in the peer GSN, so there is no way to know these parameters. On the
387 * other hand the timeout value need to be so small that we do not receive
388 * wraparound sequence numbere before the message is deleted. 60 seconds is
389 * probably not a bad choise.
390 *
391 * This queue however is first really needed from gtp1.
392 *
393 * gtp_req:
394 * Send off a signalling message with appropiate sequence
395 * number. Store packet in queue.
396 * gtp_conf:
397 * Remove an incoming confirmation from the queue
398 * gtp_resp:
jjako08d331d2003-10-13 20:33:30 +0000399 * Send off a response to a request. Use the same sequence
jjako52c24142002-12-16 13:33:51 +0000400 * number in the response as in the request.
jjako2c381332003-10-21 19:09:53 +0000401 * gtp_notification:
402 * Send off a notification message. This is neither a request nor
403 * a response. Both TEI and SEQ are zero.
jjako52c24142002-12-16 13:33:51 +0000404 * gtp_retrans:
405 * Retransmit any outstanding packets which have exceeded
406 * a predefined timeout.
407 *************************************************************/
408
jjako08d331d2003-10-13 20:33:30 +0000409int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +0100410 union gtp_packet *packet, int len,
411 struct in_addr *inetaddr, void *cbp)
412{
413 struct sockaddr_in addr;
414 struct qmsg_t *qmsg;
415 int fd;
jjako08d331d2003-10-13 20:33:30 +0000416
Harald Weltebed35df2011-11-02 13:06:18 +0100417 memset(&addr, 0, sizeof(addr));
418 addr.sin_family = AF_INET;
419 addr.sin_addr = *inetaddr;
jjako0fe0df02004-09-17 11:30:40 +0000420#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100421 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +0000422#endif
jjako52c24142002-12-16 13:33:51 +0000423
Harald Weltebed35df2011-11-02 13:06:18 +0100424 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
425 addr.sin_port = htons(GTP0_PORT);
426 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
427 packet->gtp0.h.seq = hton16(gsn->seq_next);
428 if (pdp)
429 packet->gtp0.h.tid =
430 (pdp->imsi & 0x0fffffffffffffffull) +
431 ((uint64_t) pdp->nsapi << 60);
432 if (pdp && ((packet->gtp0.h.type == GTP_GPDU)
433 || (packet->gtp0.h.type == GTP_ERROR)))
434 packet->gtp0.h.flow = hton16(pdp->flru);
435 else if (pdp)
436 packet->gtp0.h.flow = hton16(pdp->flrc);
437 fd = gsn->fd0;
438 } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
439 addr.sin_port = htons(GTP1C_PORT);
440 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
441 packet->gtp1l.h.seq = hton16(gsn->seq_next);
442 if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) ||
443 (packet->gtp1l.h.type == GTP_ERROR)))
444 packet->gtp1l.h.tei = hton32(pdp->teid_gn);
445 else if (pdp)
446 packet->gtp1l.h.tei = hton32(pdp->teic_gn);
447 fd = gsn->fd1c;
448 } else {
449 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
450 return -1;
451 }
jjako52c24142002-12-16 13:33:51 +0000452
Harald Weltebed35df2011-11-02 13:06:18 +0100453 if (sendto(fd, packet, len, 0,
454 (struct sockaddr *)&addr, sizeof(addr)) < 0) {
455 gsn->err_sendto++;
456 gtp_err(LOG_ERR, __FILE__, __LINE__,
457 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
458 (unsigned long)&packet, len, strerror(errno));
459 return -1;
460 }
461
462 /* Use new queue structure */
463 if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) {
464 gsn->err_queuefull++;
465 gtp_err(LOG_ERR, __FILE__, __LINE__,
466 "Retransmit queue is full");
467 } else {
468 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
469 qmsg->l = len;
Harald Welte95848ba2011-11-02 18:17:50 +0100470 qmsg->timeout = time(NULL) + T3_REQUEST; /* When to timeout */
Harald Weltebed35df2011-11-02 13:06:18 +0100471 qmsg->retrans = 0; /* No retransmissions so far */
472 qmsg->cbp = cbp;
473 qmsg->type = ntoh8(packet->gtp0.h.type);
474 qmsg->fd = fd;
475 }
476 gsn->seq_next++; /* Count up this time */
477 return 0;
jjako52c24142002-12-16 13:33:51 +0000478}
479
480/* gtp_conf
481 * Remove signalling packet from retransmission queue.
482 * return 0 on success, EOF if packet was not found */
483
484int gtp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +0100485 union gtp_packet *packet, int len, uint8_t * type, void **cbp)
486{
jjako52c24142002-12-16 13:33:51 +0000487
Harald Weltebed35df2011-11-02 13:06:18 +0100488 uint16_t seq;
jjako08d331d2003-10-13 20:33:30 +0000489
Harald Weltebed35df2011-11-02 13:06:18 +0100490 if ((packet->gtp0.h.flags & 0xe0) == 0x00)
491 seq = ntoh16(packet->gtp0.h.seq);
492 else if ((packet->gtp1l.h.flags & 0xe2) == 0x22)
493 seq = ntoh16(packet->gtp1l.h.seq);
494 else {
495 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
496 "Unknown GTP packet version");
497 return EOF;
498 }
jjako08d331d2003-10-13 20:33:30 +0000499
Harald Weltebed35df2011-11-02 13:06:18 +0100500 if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) {
501 gsn->err_seq++;
502 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
503 "Confirmation packet not found in queue");
504 return EOF;
505 }
jjako52c24142002-12-16 13:33:51 +0000506
Harald Weltebed35df2011-11-02 13:06:18 +0100507 return 0;
jjako52c24142002-12-16 13:33:51 +0000508}
509
Harald Weltebed35df2011-11-02 13:06:18 +0100510int gtp_retrans(struct gsn_t *gsn)
511{
512 /* Retransmit any outstanding packets */
513 /* Remove from queue if maxretrans exceeded */
514 time_t now;
515 struct qmsg_t *qmsg;
516 now = time(NULL);
517 /*printf("Retrans: New beginning %d\n", (int) now); */
jjako52c24142002-12-16 13:33:51 +0000518
Harald Welte95848ba2011-11-02 18:17:50 +0100519 /* get first element in queue, as long as the timeout of that
520 * element has expired */
Harald Weltebed35df2011-11-02 13:06:18 +0100521 while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
522 (qmsg->timeout <= now)) {
523 /*printf("Retrans timeout found: %d\n", (int) time(NULL)); */
Harald Welte95848ba2011-11-02 18:17:50 +0100524 if (qmsg->retrans > N3_REQUESTS) { /* To many retrans */
Harald Weltebed35df2011-11-02 13:06:18 +0100525 if (gsn->cb_conf)
526 gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
527 queue_freemsg(gsn->queue_req, qmsg);
528 } else {
529 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
530 (struct sockaddr *)&qmsg->peer,
531 sizeof(struct sockaddr_in)) < 0) {
532 gsn->err_sendto++;
533 gtp_err(LOG_ERR, __FILE__, __LINE__,
534 "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s",
535 gsn->fd0, (unsigned long)&qmsg->p,
536 qmsg->l, strerror(errno));
537 }
538 queue_back(gsn->queue_req, qmsg);
Harald Welte95848ba2011-11-02 18:17:50 +0100539 qmsg->timeout = now + T3_REQUEST;
Harald Weltebed35df2011-11-02 13:06:18 +0100540 qmsg->retrans++;
541 }
542 }
jjako52c24142002-12-16 13:33:51 +0000543
Harald Weltebed35df2011-11-02 13:06:18 +0100544 /* Also clean up reply timeouts */
545 while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
546 (qmsg->timeout < now)) {
547 /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL)); */
548 queue_freemsg(gsn->queue_resp, qmsg);
549 }
jjako52c24142002-12-16 13:33:51 +0000550
Harald Weltebed35df2011-11-02 13:06:18 +0100551 return 0;
jjako52c24142002-12-16 13:33:51 +0000552}
553
Harald Weltebed35df2011-11-02 13:06:18 +0100554int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
555{
556 time_t now, later;
557 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000558
Harald Weltebed35df2011-11-02 13:06:18 +0100559 if (queue_getfirst(gsn->queue_req, &qmsg)) {
560 timeout->tv_sec = 10;
561 timeout->tv_usec = 0;
562 } else {
563 now = time(NULL);
564 later = qmsg->timeout;
565 timeout->tv_sec = later - now;
566 timeout->tv_usec = 0;
567 if (timeout->tv_sec < 0)
568 timeout->tv_sec = 0; /* No negative allowed */
569 if (timeout->tv_sec > 10)
570 timeout->tv_sec = 10; /* Max sleep for 10 sec */
571 }
572 return 0;
jjako52c24142002-12-16 13:33:51 +0000573}
574
Harald Weltebed35df2011-11-02 13:06:18 +0100575int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp,
jjako08d331d2003-10-13 20:33:30 +0000576 union gtp_packet *packet, int len,
Harald Weltebed35df2011-11-02 13:06:18 +0100577 struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
578{
579 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000580
Harald Weltebed35df2011-11-02 13:06:18 +0100581 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
582 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
583 packet->gtp0.h.seq = hton16(seq);
584 packet->gtp0.h.tid = tid;
585 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
586 (packet->gtp0.h.type == GTP_ERROR)))
587 packet->gtp0.h.flow = hton16(pdp->flru);
588 else if (pdp)
589 packet->gtp0.h.flow = hton16(pdp->flrc);
590 } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
591 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
592 packet->gtp1l.h.seq = hton16(seq);
593 if (pdp && (fd == gsn->fd1u))
594 packet->gtp1l.h.tei = hton32(pdp->teid_gn);
595 else if (pdp)
596 packet->gtp1l.h.tei = hton32(pdp->teic_gn);
597 } else {
598 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
599 return -1;
600 }
jjako08d331d2003-10-13 20:33:30 +0000601
Harald Weltebed35df2011-11-02 13:06:18 +0100602 if (fcntl(fd, F_SETFL, 0)) {
603 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
604 return -1;
605 }
jjako52c24142002-12-16 13:33:51 +0000606
Harald Weltebed35df2011-11-02 13:06:18 +0100607 if (sendto(fd, packet, len, 0,
608 (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
609 gsn->err_sendto++;
610 gtp_err(LOG_ERR, __FILE__, __LINE__,
611 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
612 (unsigned long)&packet, len, strerror(errno));
613 return -1;
614 }
615
616 /* Use new queue structure */
617 if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) {
618 gsn->err_queuefull++;
619 gtp_err(LOG_ERR, __FILE__, __LINE__,
620 "Retransmit queue is full");
621 } else {
622 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
623 qmsg->l = len;
624 qmsg->timeout = time(NULL) + 60; /* When to timeout */
625 qmsg->retrans = 0; /* No retransmissions so far */
626 qmsg->cbp = NULL;
627 qmsg->type = 0;
628 qmsg->fd = fd;
629 }
630 return 0;
jjako52c24142002-12-16 13:33:51 +0000631}
632
jjako2c381332003-10-21 19:09:53 +0000633int gtp_notification(struct gsn_t *gsn, int version,
634 union gtp_packet *packet, int len,
Harald Weltebed35df2011-11-02 13:06:18 +0100635 struct sockaddr_in *peer, int fd, uint16_t seq)
636{
jjako2c381332003-10-21 19:09:53 +0000637
Harald Weltebed35df2011-11-02 13:06:18 +0100638 struct sockaddr_in addr;
jjako2c381332003-10-21 19:09:53 +0000639
Harald Weltebed35df2011-11-02 13:06:18 +0100640 memcpy(&addr, peer, sizeof(addr));
jjako2c381332003-10-21 19:09:53 +0000641
Harald Weltebed35df2011-11-02 13:06:18 +0100642 /* In GTP0 notifications are treated as replies. In GTP1 they
643 are requests for which there is no reply */
jjako2c381332003-10-21 19:09:53 +0000644
Harald Weltebed35df2011-11-02 13:06:18 +0100645 if (fd == gsn->fd1c)
646 addr.sin_port = htons(GTP1C_PORT);
647 else if (fd == gsn->fd1u)
648 addr.sin_port = htons(GTP1C_PORT);
jjako2c381332003-10-21 19:09:53 +0000649
Harald Weltebed35df2011-11-02 13:06:18 +0100650 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
651 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
652 packet->gtp0.h.seq = hton16(seq);
653 } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
654 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
655 packet->gtp1l.h.seq = hton16(seq);
656 } else {
657 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
658 return -1;
659 }
660
661 if (fcntl(fd, F_SETFL, 0)) {
662 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
663 return -1;
664 }
665
666 if (sendto(fd, packet, len, 0,
667 (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
668 gsn->err_sendto++;
669 gtp_err(LOG_ERR, __FILE__, __LINE__,
670 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
671 (unsigned long)&packet, len, strerror(errno));
672 return -1;
673 }
674 return 0;
jjako2c381332003-10-21 19:09:53 +0000675}
676
Harald Weltebed35df2011-11-02 13:06:18 +0100677int gtp_dublicate(struct gsn_t *gsn, int version,
678 struct sockaddr_in *peer, uint16_t seq)
679{
680 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000681
Harald Weltebed35df2011-11-02 13:06:18 +0100682 if (queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) {
683 return EOF; /* Notfound */
684 }
jjakoa7cd2492003-04-11 09:40:12 +0000685
Harald Weltebed35df2011-11-02 13:06:18 +0100686 if (fcntl(qmsg->fd, F_SETFL, 0)) {
687 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
688 return -1;
689 }
690
691 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
692 (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
693 gsn->err_sendto++;
694 gtp_err(LOG_ERR, __FILE__, __LINE__,
695 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s",
696 qmsg->fd, (unsigned long)&qmsg->p, qmsg->l,
697 strerror(errno));
698 }
699 return 0;
jjako52c24142002-12-16 13:33:51 +0000700}
701
jjako52c24142002-12-16 13:33:51 +0000702/* Perform restoration and recovery error handling as described in 29.060 */
Harald Weltebed35df2011-11-02 13:06:18 +0100703static void log_restart(struct gsn_t *gsn)
704{
jjako52c24142002-12-16 13:33:51 +0000705 FILE *f;
Emmanuel Bretelle111e0542010-09-06 19:49:16 +0200706 int i, rc;
jjako52c24142002-12-16 13:33:51 +0000707 int counter = 0;
708 char filename[NAMESIZE];
709
Harald Weltebed35df2011-11-02 13:06:18 +0100710 filename[NAMESIZE - 1] = 0; /* No null term. guarantee by strncpy */
711 strncpy(filename, gsn->statedir, NAMESIZE - 1);
712 strncat(filename, RESTART_FILE, NAMESIZE - 1 - sizeof(RESTART_FILE));
jjako52c24142002-12-16 13:33:51 +0000713
714 i = umask(022);
715
716 /* We try to open file. On failure we will later try to create file */
717 if (!(f = fopen(filename, "r"))) {
jjako581c9f02003-10-22 11:28:20 +0000718
Harald Weltebed35df2011-11-02 13:06:18 +0100719 gtp_err(LOG_ERR, __FILE__, __LINE__,
720 "State information file (%s) not found. Creating new file.",
721 filename);
722 } else {
723 umask(i);
724 rc = fscanf(f, "%d", &counter);
725 if (rc != 1) {
726 gtp_err(LOG_ERR, __FILE__, __LINE__,
727 "fscanf failed to read counter value");
728 return;
729 }
730 if (fclose(f)) {
731 gtp_err(LOG_ERR, __FILE__, __LINE__,
732 "fclose failed: Error = %s", strerror(errno));
733 }
jjako52c24142002-12-16 13:33:51 +0000734 }
Harald Weltebed35df2011-11-02 13:06:18 +0100735
736 gsn->restart_counter = (unsigned char)counter;
jjako52c24142002-12-16 13:33:51 +0000737 gsn->restart_counter++;
Harald Weltebed35df2011-11-02 13:06:18 +0100738
jjako52c24142002-12-16 13:33:51 +0000739 if (!(f = fopen(filename, "w"))) {
Harald Weltebed35df2011-11-02 13:06:18 +0100740 gtp_err(LOG_ERR, __FILE__, __LINE__,
741 "fopen(path=%s, mode=%s) failed: Error = %s", filename,
742 "w", strerror(errno));
743 return;
jjako52c24142002-12-16 13:33:51 +0000744 }
745
746 umask(i);
747 fprintf(f, "%d\n", gsn->restart_counter);
748 if (fclose(f)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100749 gtp_err(LOG_ERR, __FILE__, __LINE__,
750 "fclose failed: Error = %s", strerror(errno));
751 return;
jjako52c24142002-12-16 13:33:51 +0000752 }
753}
754
jjako1db1c812003-07-06 20:53:57 +0000755int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
Harald Weltebed35df2011-11-02 13:06:18 +0100756 int mode)
jjako52c24142002-12-16 13:33:51 +0000757{
Harald Weltebed35df2011-11-02 13:06:18 +0100758 struct sockaddr_in addr;
jjako52c24142002-12-16 13:33:51 +0000759
Harald Weltebed35df2011-11-02 13:06:18 +0100760 syslog(LOG_ERR, "GTP: gtp_newgsn() started");
jjako52c24142002-12-16 13:33:51 +0000761
Harald Weltebed35df2011-11-02 13:06:18 +0100762 *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
jjakoa7cd2492003-04-11 09:40:12 +0000763
Harald Weltebed35df2011-11-02 13:06:18 +0100764 (*gsn)->statedir = statedir;
765 log_restart(*gsn);
jjako52c24142002-12-16 13:33:51 +0000766
Harald Weltebed35df2011-11-02 13:06:18 +0100767 /* Initialise sequence number */
768 (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
jjako52c24142002-12-16 13:33:51 +0000769
Harald Weltebed35df2011-11-02 13:06:18 +0100770 /* Initialise request retransmit queue */
771 queue_new(&(*gsn)->queue_req);
772 queue_new(&(*gsn)->queue_resp);
jjako08d331d2003-10-13 20:33:30 +0000773
Harald Weltebed35df2011-11-02 13:06:18 +0100774 /* Initialise pdp table */
775 pdp_init();
jjako08d331d2003-10-13 20:33:30 +0000776
Harald Weltebed35df2011-11-02 13:06:18 +0100777 /* Initialise call back functions */
778 (*gsn)->cb_create_context_ind = 0;
779 (*gsn)->cb_delete_context = 0;
780 (*gsn)->cb_unsup_ind = 0;
781 (*gsn)->cb_conf = 0;
782 (*gsn)->cb_data_ind = 0;
783
784 /* Store function parameters */
785 (*gsn)->gsnc = *listen;
786 (*gsn)->gsnu = *listen;
787 (*gsn)->mode = mode;
788
789 /* Create GTP version 0 socket */
790 if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
791 (*gsn)->err_socket++;
792 gtp_err(LOG_ERR, __FILE__, __LINE__,
793 "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s",
794 AF_INET, SOCK_DGRAM, 0, strerror(errno));
795 return -1;
796 }
797
798 memset(&addr, 0, sizeof(addr));
799 addr.sin_family = AF_INET;
800 addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
801 addr.sin_port = htons(GTP0_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000802#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100803 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +0000804#endif
jjako08d331d2003-10-13 20:33:30 +0000805
Harald Weltebed35df2011-11-02 13:06:18 +0100806 if (bind((*gsn)->fd0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
807 (*gsn)->err_socket++;
808 gtp_err(LOG_ERR, __FILE__, __LINE__,
809 "bind(fd0=%d, addr=%lx, len=%d) failed: Error = %s",
810 (*gsn)->fd0, (unsigned long)&addr, sizeof(addr),
811 strerror(errno));
812 return -1;
813 }
jjako08d331d2003-10-13 20:33:30 +0000814
Harald Weltebed35df2011-11-02 13:06:18 +0100815 /* Create GTP version 1 control plane socket */
816 if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
817 (*gsn)->err_socket++;
818 gtp_err(LOG_ERR, __FILE__, __LINE__,
819 "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s",
820 AF_INET, SOCK_DGRAM, 0, strerror(errno));
821 return -1;
822 }
823
824 memset(&addr, 0, sizeof(addr));
825 addr.sin_family = AF_INET;
826 addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
827 addr.sin_port = htons(GTP1C_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000828#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100829 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +0000830#endif
jjako08d331d2003-10-13 20:33:30 +0000831
Harald Weltebed35df2011-11-02 13:06:18 +0100832 if (bind((*gsn)->fd1c, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
833 (*gsn)->err_socket++;
834 gtp_err(LOG_ERR, __FILE__, __LINE__,
835 "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s",
836 (*gsn)->fd1c, (unsigned long)&addr, sizeof(addr),
837 strerror(errno));
838 return -1;
839 }
jjako08d331d2003-10-13 20:33:30 +0000840
Harald Weltebed35df2011-11-02 13:06:18 +0100841 /* Create GTP version 1 user plane socket */
842 if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
843 (*gsn)->err_socket++;
844 gtp_err(LOG_ERR, __FILE__, __LINE__,
845 "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s",
846 AF_INET, SOCK_DGRAM, 0, strerror(errno));
847 return -1;
848 }
849
850 memset(&addr, 0, sizeof(addr));
851 addr.sin_family = AF_INET;
852 addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
853 addr.sin_port = htons(GTP1U_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000854#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100855 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +0000856#endif
jjako52c24142002-12-16 13:33:51 +0000857
Harald Weltebed35df2011-11-02 13:06:18 +0100858 if (bind((*gsn)->fd1u, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
859 (*gsn)->err_socket++;
860 gtp_err(LOG_ERR, __FILE__, __LINE__,
861 "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s",
862 (*gsn)->fd1c, (unsigned long)&addr, sizeof(addr),
863 strerror(errno));
864 return -1;
865 }
866
867 return 0;
jjako52c24142002-12-16 13:33:51 +0000868}
869
Harald Weltebed35df2011-11-02 13:06:18 +0100870int gtp_free(struct gsn_t *gsn)
871{
jjako52c24142002-12-16 13:33:51 +0000872
Harald Weltebed35df2011-11-02 13:06:18 +0100873 /* Clean up retransmit queues */
874 queue_free(gsn->queue_req);
875 queue_free(gsn->queue_resp);
jjako52c24142002-12-16 13:33:51 +0000876
Harald Weltebed35df2011-11-02 13:06:18 +0100877 close(gsn->fd0);
878 close(gsn->fd1c);
879 close(gsn->fd1u);
880
881 free(gsn);
882 return 0;
jjako52c24142002-12-16 13:33:51 +0000883}
884
885/* ***********************************************************
886 * Path management messages
887 * Messages: echo and version not supported.
888 * A path is connection between two UDP/IP endpoints
889 *
890 * A path is either using GTP0 or GTP1. A path can be
891 * established by any kind of GTP message??
892
893 * Which source port to use?
894 * GTP-C request destination port is 2123/3386
895 * GTP-U request destination port is 2152/3386
896 * T-PDU destination port is 2152/3386.
897 * For the above messages the source port is locally allocated.
898 * For response messages src=rx-dst and dst=rx-src.
899 * For simplicity we should probably use 2123+2152/3386 as
900 * src port even for the cases where src can be locally
901 * allocated. This also means that we have to listen only to
902 * the same ports.
903 * For response messages we need to be able to respond to
904 * the relevant src port even if it is locally allocated by
905 * the peer.
906 *
907 * The need for path management!
908 * We might need to keep a list of active paths. This might
909 * be in the form of remote IP address + UDP port numbers.
910 * (We will consider a path astablished if we have a context
911 * with the node in question)
912 *************************************************************/
913
914/* Send off an echo request */
jjako08d331d2003-10-13 20:33:30 +0000915int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
916 struct in_addr *inetaddr)
jjako52c24142002-12-16 13:33:51 +0000917{
Harald Weltebed35df2011-11-02 13:06:18 +0100918 union gtp_packet packet;
919 unsigned int length = get_default_gtp(version, GTP_ECHO_REQ, &packet);
920 return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp);
jjako52c24142002-12-16 13:33:51 +0000921}
922
jjako08d331d2003-10-13 20:33:30 +0000923/* Send off an echo reply */
924int gtp_echo_resp(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +0100925 struct sockaddr_in *peer, int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000926{
Harald Weltebed35df2011-11-02 13:06:18 +0100927 union gtp_packet packet;
928 unsigned int length = get_default_gtp(version, GTP_ECHO_RSP, &packet);
929 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
930 gsn->restart_counter);
931 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
932 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +0000933}
934
jjako52c24142002-12-16 13:33:51 +0000935/* Handle a received echo request */
Harald Weltebed35df2011-11-02 13:06:18 +0100936int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
937 int fd, void *pack, unsigned len)
938{
jjako52c24142002-12-16 13:33:51 +0000939
Harald Weltebed35df2011-11-02 13:06:18 +0100940 /* Check if it was a dublicate request */
941 if (!gtp_dublicate(gsn, 0, peer, get_seq(pack)))
942 return 0;
jjako52c24142002-12-16 13:33:51 +0000943
Harald Weltebed35df2011-11-02 13:06:18 +0100944 /* Send off reply to request */
945 return gtp_echo_resp(gsn, version, peer, fd, pack, len);
jjako52c24142002-12-16 13:33:51 +0000946}
947
948/* Handle a received echo reply */
jjako08d331d2003-10-13 20:33:30 +0000949int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
Harald Weltebed35df2011-11-02 13:06:18 +0100950 void *pack, unsigned len)
951{
952 union gtpie_member *ie[GTPIE_SIZE];
953 unsigned char recovery;
954 void *cbp = NULL;
955 uint8_t type = 0;
956 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +0000957
Harald Weltebed35df2011-11-02 13:06:18 +0100958 /* Remove packet from queue */
959 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
960 return EOF;
jjako52c24142002-12-16 13:33:51 +0000961
Harald Weltebed35df2011-11-02 13:06:18 +0100962 /* Extract information elements into a pointer array */
963 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
964 gsn->invalid++;
965 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
966 "Invalid message format");
967 if (gsn->cb_conf)
968 gsn->cb_conf(type, EOF, NULL, cbp);
969 return EOF;
970 }
jjako52c24142002-12-16 13:33:51 +0000971
Harald Weltebed35df2011-11-02 13:06:18 +0100972 if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
973 gsn->missing++;
974 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
975 "Missing mandatory field");
976 if (gsn->cb_conf)
977 gsn->cb_conf(type, EOF, NULL, cbp);
978 return EOF;
979 }
jjako52c24142002-12-16 13:33:51 +0000980
Harald Weltebed35df2011-11-02 13:06:18 +0100981 /* Echo reply packages does not have a cause information element */
982 /* Instead we return the recovery number in the callback function */
983 if (gsn->cb_conf)
984 gsn->cb_conf(type, recovery, NULL, cbp);
Harald Welte629e9862010-12-24 20:58:09 +0100985
Harald Weltebed35df2011-11-02 13:06:18 +0100986 if (gsn->cb_recovery)
987 gsn->cb_recovery(peer, recovery);
988
989 return 0;
jjako52c24142002-12-16 13:33:51 +0000990}
991
992/* Send off a Version Not Supported message */
993/* This message is somewhat special in that it actually is a
994 * response to some other message with unsupported GTP version
995 * For this reason it has parameters like a response, and does
996 * its own message transmission. No signalling queue is used
997 * The reply is sent to the peer IP and peer UDP. This means that
998 * the peer will be receiving a GTP0 message on a GTP1 port!
999 * In practice however this will never happen as a GTP0 GSN will
1000 * only listen to the GTP0 port, and therefore will never receive
1001 * anything else than GTP0 */
1002
jjako08d331d2003-10-13 20:33:30 +00001003int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
1004 int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +00001005{
Harald Weltebed35df2011-11-02 13:06:18 +01001006 union gtp_packet packet;
jjako52c24142002-12-16 13:33:51 +00001007
Harald Weltebed35df2011-11-02 13:06:18 +01001008 /* GTP 1 is the highest supported protocol */
1009 unsigned int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet);
1010 return gtp_notification(gsn, version, &packet, length, peer, fd, 0);
jjako52c24142002-12-16 13:33:51 +00001011}
1012
1013/* Handle a Version Not Supported message */
Harald Weltebed35df2011-11-02 13:06:18 +01001014int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
1015 void *pack, unsigned len)
1016{
jjako52c24142002-12-16 13:33:51 +00001017
Harald Weltebed35df2011-11-02 13:06:18 +01001018 if (gsn->cb_unsup_ind)
1019 gsn->cb_unsup_ind(peer);
1020
1021 return 0;
jjako52c24142002-12-16 13:33:51 +00001022}
1023
jjako2c381332003-10-21 19:09:53 +00001024/* Send off an Supported Extension Headers Notification */
1025int gtp_extheader_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
1026 int fd, void *pack, unsigned len)
1027{
Harald Weltebed35df2011-11-02 13:06:18 +01001028 union gtp_packet packet;
1029 unsigned int length =
1030 get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet);
jjako2c381332003-10-21 19:09:53 +00001031
Harald Weltebed35df2011-11-02 13:06:18 +01001032 uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU;
jjako2c381332003-10-21 19:09:53 +00001033
Harald Weltebed35df2011-11-02 13:06:18 +01001034 if (version < 1)
1035 return 0;
jjako2c381332003-10-21 19:09:53 +00001036
Harald Weltebed35df2011-11-02 13:06:18 +01001037 /* We report back that we support only PDCP PDU headers */
1038 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T,
1039 sizeof(pdcp_pdu), &pdcp_pdu);
jjako2c381332003-10-21 19:09:53 +00001040
Harald Weltebed35df2011-11-02 13:06:18 +01001041 return gtp_notification(gsn, version, &packet, length,
1042 peer, fd, get_seq(pack));
jjako2c381332003-10-21 19:09:53 +00001043}
1044
1045/* Handle a Supported Extension Headers Notification */
Harald Weltebed35df2011-11-02 13:06:18 +01001046int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
1047 void *pack, unsigned len)
1048{
jjako2c381332003-10-21 19:09:53 +00001049
Harald Weltebed35df2011-11-02 13:06:18 +01001050 if (gsn->cb_extheader_ind)
1051 gsn->cb_extheader_ind(peer);
1052
1053 return 0;
jjako2c381332003-10-21 19:09:53 +00001054}
1055
jjako52c24142002-12-16 13:33:51 +00001056/* ***********************************************************
1057 * Session management messages
1058 * Messages: create, update and delete PDP context
1059 *
1060 * Information storage
1061 * Information storage for each PDP context is defined in
1062 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
1063 * PDP-address (IP address), sequence numbers, charging ID.
1064 * For the SGSN it also includes radio related mobility
1065 * information.
1066 *************************************************************/
1067
Harald Welte7b3347b2010-05-15 12:18:46 +02001068/* API: Send Create PDP Context Request (7.3.1) */
Harald Weltebed35df2011-11-02 13:06:18 +01001069extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
1070 void *cbp)
1071{
1072 union gtp_packet packet;
1073 unsigned int length =
1074 get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet);
1075 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001076
Harald Weltebed35df2011-11-02 13:06:18 +01001077 /* TODO: Secondary PDP Context Activation Procedure */
1078 /* In secondary activation procedure the PDP context is identified
1079 by tei in the header. The following fields are omitted: Selection
1080 mode, IMSI, MSISDN, End User Address, Access Point Name and
1081 Protocol Configuration Options */
jjako2c381332003-10-21 19:09:53 +00001082
Harald Weltebed35df2011-11-02 13:06:18 +01001083 if (pdp->secondary) {
1084 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
1085 gtp_err(LOG_ERR, __FILE__, __LINE__,
1086 "Unknown linked PDP context");
1087 return EOF;
1088 }
1089 }
jjako2c381332003-10-21 19:09:53 +00001090
Harald Weltebed35df2011-11-02 13:06:18 +01001091 if (pdp->version == 0) {
1092 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1093 sizeof(pdp->qos_req0), pdp->qos_req0);
1094 }
jjako52c24142002-12-16 13:33:51 +00001095
Harald Weltebed35df2011-11-02 13:06:18 +01001096 /* Section 7.7.2 */
1097 if (pdp->version == 1) {
1098 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1099 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1100 sizeof(pdp->imsi), (uint8_t *) & pdp->imsi);
1101 }
jjako52c24142002-12-16 13:33:51 +00001102
Harald Weltebed35df2011-11-02 13:06:18 +01001103 /* Section 7.7.3 Routing Area Information */
1104 if (pdp->rai_given == 1)
1105 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI,
1106 pdp->rai.l, (uint8_t *) & pdp->rai.v);
Harald Welte41af5692011-10-07 18:42:34 +02001107
Harald Weltebed35df2011-11-02 13:06:18 +01001108 /* Section 7.7.11 */
1109 if (pdp->norecovery_given == 0)
1110 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1111 gsn->restart_counter);
Harald Welte41af5692011-10-07 18:42:34 +02001112
Harald Weltebed35df2011-11-02 13:06:18 +01001113 /* Section 7.7.12 */
1114 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1115 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE,
1116 pdp->selmode);
jjako2c381332003-10-21 19:09:53 +00001117
Harald Weltebed35df2011-11-02 13:06:18 +01001118 if (pdp->version == 0) {
1119 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu);
1120 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc);
1121 }
jjako08d331d2003-10-13 20:33:30 +00001122
Harald Weltebed35df2011-11-02 13:06:18 +01001123 /* Section 7.7.13 */
1124 if (pdp->version == 1) {
1125 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1126 pdp->teid_own);
jjako08d331d2003-10-13 20:33:30 +00001127
Harald Weltebed35df2011-11-02 13:06:18 +01001128 /* Section 7.7.14 */
1129 if (!pdp->teic_confirmed)
1130 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1131 pdp->teic_own);
jjako2c381332003-10-21 19:09:53 +00001132
Harald Weltebed35df2011-11-02 13:06:18 +01001133 /* Section 7.7.17 */
1134 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00001135
Harald Weltebed35df2011-11-02 13:06:18 +01001136 /* Section 7.7.17 */
1137 if (pdp->secondary) /* Secondary PDP Context Activation Procedure */
1138 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1139 linked_pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00001140
Harald Weltebed35df2011-11-02 13:06:18 +01001141 /* Section 7.7.23 */
1142 if (pdp->cch_pdp) /* Only include charging if flags are set */
1143 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C,
1144 pdp->cch_pdp);
1145 }
jjako9b4971d2004-05-27 20:30:19 +00001146
Harald Weltebed35df2011-11-02 13:06:18 +01001147 /* TODO
1148 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1149 pdp->traceref);
1150 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1151 pdp->tracetype); */
jjako08d331d2003-10-13 20:33:30 +00001152
Harald Weltebed35df2011-11-02 13:06:18 +01001153 /* Section 7.7.27 */
1154 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1155 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1156 pdp->eua.l, pdp->eua.v);
jjako08d331d2003-10-13 20:33:30 +00001157
Harald Weltebed35df2011-11-02 13:06:18 +01001158 /* Section 7.7.30 */
1159 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1160 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN,
1161 pdp->apn_use.l, pdp->apn_use.v);
jjako08d331d2003-10-13 20:33:30 +00001162
Harald Weltebed35df2011-11-02 13:06:18 +01001163 /* Section 7.7.31 */
1164 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1165 if (pdp->pco_req.l)
1166 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1167 pdp->pco_req.l, pdp->pco_req.v);
jjako2c381332003-10-21 19:09:53 +00001168
Harald Weltebed35df2011-11-02 13:06:18 +01001169 /* Section 7.7.32 */
1170 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1171 pdp->gsnlc.l, pdp->gsnlc.v);
1172 /* Section 7.7.32 */
1173 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1174 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001175
Harald Weltebed35df2011-11-02 13:06:18 +01001176 /* Section 7.7.33 */
1177 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1178 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN,
1179 pdp->msisdn.l, pdp->msisdn.v);
jjako08d331d2003-10-13 20:33:30 +00001180
Harald Weltebed35df2011-11-02 13:06:18 +01001181 /* Section 7.7.34 */
1182 if (pdp->version == 1)
1183 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1184 pdp->qos_req.l, pdp->qos_req.v);
jjako08d331d2003-10-13 20:33:30 +00001185
Harald Weltebed35df2011-11-02 13:06:18 +01001186 /* Section 7.7.36 */
1187 if ((pdp->version == 1) && pdp->tft.l)
1188 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1189 pdp->tft.l, pdp->tft.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001190
Harald Weltebed35df2011-11-02 13:06:18 +01001191 /* Section 7.7.41 */
1192 if ((pdp->version == 1) && pdp->triggerid.l)
1193 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1194 pdp->triggerid.l, pdp->triggerid.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001195
Harald Weltebed35df2011-11-02 13:06:18 +01001196 /* Section 7.7.42 */
1197 if ((pdp->version == 1) && pdp->omcid.l)
1198 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1199 pdp->omcid.l, pdp->omcid.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001200
Harald Weltebed35df2011-11-02 13:06:18 +01001201 /* new R7 fields */
1202 if (pdp->rattype_given == 1)
1203 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAT_TYPE,
1204 pdp->rattype.l, pdp->rattype.v);
Yann BONNAMY944dce32010-10-29 17:07:44 +02001205
Harald Weltebed35df2011-11-02 13:06:18 +01001206 if (pdp->userloc_given == 1)
1207 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_USER_LOC,
1208 pdp->userloc.l, pdp->userloc.v);
jjako52c24142002-12-16 13:33:51 +00001209
Harald Weltebed35df2011-11-02 13:06:18 +01001210 if (pdp->mstz_given == 1)
1211 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MS_TZ,
1212 pdp->mstz.l, pdp->mstz.v);
1213
1214 if (pdp->imeisv_given == 1)
1215 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_IMEI_SV,
1216 pdp->imeisv.l, pdp->imeisv.v);
1217
1218 /* TODO hisaddr0 */
1219 gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
1220
1221 return 0;
jjako52c24142002-12-16 13:33:51 +00001222}
1223
jjako08d331d2003-10-13 20:33:30 +00001224/* API: Application response to context indication */
Harald Weltebed35df2011-11-02 13:06:18 +01001225int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause)
1226{
jjako08d331d2003-10-13 20:33:30 +00001227
Harald Weltebed35df2011-11-02 13:06:18 +01001228 /* Now send off a reply to the peer */
1229 gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
1230
1231 if (cause != GTPCAUSE_ACC_REQ) {
1232 pdp_freepdp(pdp);
1233 }
1234
1235 return 0;
jjako08d331d2003-10-13 20:33:30 +00001236}
1237
1238/* API: Register create context indication callback */
1239int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
Harald Weltebed35df2011-11-02 13:06:18 +01001240 int (*cb_create_context_ind) (struct pdp_t *
1241 pdp))
jjako52c24142002-12-16 13:33:51 +00001242{
Harald Weltebed35df2011-11-02 13:06:18 +01001243 gsn->cb_create_context_ind = cb_create_context_ind;
1244 return 0;
jjako08d331d2003-10-13 20:33:30 +00001245}
1246
jjako08d331d2003-10-13 20:33:30 +00001247/* Send Create PDP Context Response */
Harald Weltebed35df2011-11-02 13:06:18 +01001248int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
1249 uint8_t cause)
1250{
1251 union gtp_packet packet;
1252 unsigned int length =
1253 get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
jjako52c24142002-12-16 13:33:51 +00001254
Harald Weltebed35df2011-11-02 13:06:18 +01001255 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00001256
Harald Weltebed35df2011-11-02 13:06:18 +01001257 if (cause == GTPCAUSE_ACC_REQ) {
jjako08d331d2003-10-13 20:33:30 +00001258
Harald Weltebed35df2011-11-02 13:06:18 +01001259 if (version == 0)
1260 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1261 sizeof(pdp->qos_neg0), pdp->qos_neg0);
jjako08d331d2003-10-13 20:33:30 +00001262
Harald Weltebed35df2011-11-02 13:06:18 +01001263 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER,
1264 pdp->reorder);
1265 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1266 gsn->restart_counter);
jjako08d331d2003-10-13 20:33:30 +00001267
Harald Weltebed35df2011-11-02 13:06:18 +01001268 if (version == 0) {
1269 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1270 pdp->fllu);
1271 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1272 pdp->fllc);
1273 }
jjako08d331d2003-10-13 20:33:30 +00001274
Harald Weltebed35df2011-11-02 13:06:18 +01001275 if (version == 1) {
1276 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1277 pdp->teid_own);
1278 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1279 pdp->teic_own);
1280 }
jjako08d331d2003-10-13 20:33:30 +00001281
Harald Weltebed35df2011-11-02 13:06:18 +01001282 /* TODO: We use teic_own as charging ID */
1283 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
1284 pdp->teic_own);
jjako2c381332003-10-21 19:09:53 +00001285
Harald Weltebed35df2011-11-02 13:06:18 +01001286 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1287 pdp->eua.l, pdp->eua.v);
jjako52c24142002-12-16 13:33:51 +00001288
Harald Weltebed35df2011-11-02 13:06:18 +01001289 if (pdp->pco_neg.l) { /* Optional PCO */
1290 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1291 pdp->pco_neg.l, pdp->pco_neg.v);
1292 }
jjako52c24142002-12-16 13:33:51 +00001293
Harald Weltebed35df2011-11-02 13:06:18 +01001294 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1295 pdp->gsnlc.l, pdp->gsnlc.v);
1296 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1297 pdp->gsnlu.l, pdp->gsnlu.v);
jjako08d331d2003-10-13 20:33:30 +00001298
Harald Weltebed35df2011-11-02 13:06:18 +01001299 if (version == 1)
1300 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1301 pdp->qos_neg.l, pdp->qos_neg.v);
jjako08d331d2003-10-13 20:33:30 +00001302
Harald Weltebed35df2011-11-02 13:06:18 +01001303 /* TODO: Charging gateway address */
1304 }
jjako52c24142002-12-16 13:33:51 +00001305
Harald Weltebed35df2011-11-02 13:06:18 +01001306 return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer,
1307 pdp->fd, pdp->seq, pdp->tid);
jjako52c24142002-12-16 13:33:51 +00001308}
1309
1310/* Handle Create PDP Context Request */
1311int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01001312 struct sockaddr_in *peer, int fd,
1313 void *pack, unsigned len)
1314{
1315 struct pdp_t *pdp, *pdp_old;
1316 struct pdp_t pdp_buf;
1317 union gtpie_member *ie[GTPIE_SIZE];
1318 uint8_t recovery;
jjako52c24142002-12-16 13:33:51 +00001319
Harald Weltebed35df2011-11-02 13:06:18 +01001320 uint16_t seq = get_seq(pack);
1321 int hlen = get_hlen(pack);
1322 uint8_t linked_nsapi = 0;
1323 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001324
Harald Weltebed35df2011-11-02 13:06:18 +01001325 if (!gtp_dublicate(gsn, version, peer, seq))
1326 return 0;
jjako08d331d2003-10-13 20:33:30 +00001327
Harald Weltebed35df2011-11-02 13:06:18 +01001328 pdp = &pdp_buf;
1329 memset(pdp, 0, sizeof(struct pdp_t));
jjako08d331d2003-10-13 20:33:30 +00001330
Harald Weltebed35df2011-11-02 13:06:18 +01001331 if (version == 0) {
1332 pdp->imsi =
1333 ((union gtp_packet *)pack)->gtp0.
1334 h.tid & 0x0fffffffffffffffull;
1335 pdp->nsapi =
1336 (((union gtp_packet *)pack)->gtp0.
1337 h.tid & 0xf000000000000000ull) >> 60;
1338 }
jjako52c24142002-12-16 13:33:51 +00001339
Harald Weltebed35df2011-11-02 13:06:18 +01001340 pdp->seq = seq;
1341 pdp->sa_peer = *peer;
1342 pdp->fd = fd;
1343 pdp->version = version;
jjako08d331d2003-10-13 20:33:30 +00001344
Harald Weltebed35df2011-11-02 13:06:18 +01001345 /* Decode information elements */
1346 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
1347 gsn->invalid++;
1348 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1349 "Invalid message format");
1350 if (0 == version)
1351 return EOF;
1352 else
1353 return gtp_create_pdp_resp(gsn, version, pdp,
1354 GTPCAUSE_INVALID_MESSAGE);
1355 }
jjako52c24142002-12-16 13:33:51 +00001356
Harald Weltebed35df2011-11-02 13:06:18 +01001357 if (version == 1) {
1358 /* Linked NSAPI (conditional) */
1359 /* If included this is the Secondary PDP Context Activation Procedure */
1360 /* In secondary activation IMSI is not included, so the context must be */
1361 /* identified by the tei */
1362 if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) {
jjako2c381332003-10-21 19:09:53 +00001363
Harald Weltebed35df2011-11-02 13:06:18 +01001364 /* Find the primary PDP context */
1365 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
1366 gsn->incorrect++;
1367 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1368 pack, len,
1369 "Incorrect optional information field");
1370 return gtp_create_pdp_resp(gsn, version, pdp,
1371 GTPCAUSE_OPT_IE_INCORRECT);
1372 }
jjako2c381332003-10-21 19:09:53 +00001373
Harald Weltebed35df2011-11-02 13:06:18 +01001374 /* Check that the primary PDP context matches linked nsapi */
1375 if (linked_pdp->nsapi != linked_nsapi) {
1376 gsn->incorrect++;
1377 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1378 pack, len,
1379 "Incorrect optional information field");
1380 return gtp_create_pdp_resp(gsn, version, pdp,
1381 GTPCAUSE_OPT_IE_INCORRECT);
1382 }
jjako52c24142002-12-16 13:33:51 +00001383
Harald Weltebed35df2011-11-02 13:06:18 +01001384 /* Copy parameters from primary context */
1385 pdp->selmode = linked_pdp->selmode;
1386 pdp->imsi = linked_pdp->imsi;
1387 pdp->msisdn = linked_pdp->msisdn;
1388 pdp->eua = linked_pdp->eua;
1389 pdp->pco_req = linked_pdp->pco_req;
1390 pdp->apn_req = linked_pdp->apn_req;
1391 pdp->teic_gn = linked_pdp->teic_gn;
1392 pdp->secondary = 1;
1393 }
1394 }
1395 /* if (version == 1) */
1396 if (version == 0) {
1397 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1398 pdp->qos_req0, sizeof(pdp->qos_req0))) {
1399 gsn->missing++;
1400 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1401 len, "Missing mandatory information field");
1402 return gtp_create_pdp_resp(gsn, version, pdp,
1403 GTPCAUSE_MAN_IE_MISSING);
1404 }
1405 }
jjako08d331d2003-10-13 20:33:30 +00001406
Harald Weltebed35df2011-11-02 13:06:18 +01001407 if ((version == 1) && (!linked_pdp)) {
1408 /* Not Secondary PDP Context Activation Procedure */
1409 /* IMSI (conditional) */
1410 if (gtpie_gettv0
1411 (ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) {
1412 gsn->missing++;
1413 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1414 len, "Missing mandatory information field");
1415 return gtp_create_pdp_resp(gsn, version, pdp,
1416 GTPCAUSE_MAN_IE_MISSING);
1417 }
1418 }
jjako52c24142002-12-16 13:33:51 +00001419
Harald Weltebed35df2011-11-02 13:06:18 +01001420 /* Recovery (optional) */
1421 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1422 if (gsn->cb_recovery)
1423 gsn->cb_recovery(peer, recovery);
1424 }
jjako52c24142002-12-16 13:33:51 +00001425
Harald Weltebed35df2011-11-02 13:06:18 +01001426 /* Selection mode (conditional) */
1427 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1428 if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0,
1429 &pdp->selmode, sizeof(pdp->selmode))) {
1430 gsn->missing++;
1431 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1432 len, "Missing mandatory information field");
1433 return gtp_create_pdp_resp(gsn, version, pdp,
1434 GTPCAUSE_MAN_IE_MISSING);
1435 }
1436 }
jjako52c24142002-12-16 13:33:51 +00001437
Harald Weltebed35df2011-11-02 13:06:18 +01001438 if (version == 0) {
1439 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1440 gsn->missing++;
1441 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1442 len, "Missing mandatory information field");
1443 return gtp_create_pdp_resp(gsn, version, pdp,
1444 GTPCAUSE_MAN_IE_MISSING);
1445 }
jjako52c24142002-12-16 13:33:51 +00001446
Harald Weltebed35df2011-11-02 13:06:18 +01001447 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1448 gsn->missing++;
1449 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1450 len, "Missing mandatory information field");
1451 return gtp_create_pdp_resp(gsn, version, pdp,
1452 GTPCAUSE_MAN_IE_MISSING);
1453 }
1454 }
jjako08d331d2003-10-13 20:33:30 +00001455
Harald Weltebed35df2011-11-02 13:06:18 +01001456 if (version == 1) {
1457 /* TEID (mandatory) */
1458 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1459 gsn->missing++;
1460 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1461 len, "Missing mandatory information field");
1462 return gtp_create_pdp_resp(gsn, version, pdp,
1463 GTPCAUSE_MAN_IE_MISSING);
1464 }
jjako2c381332003-10-21 19:09:53 +00001465
Harald Weltebed35df2011-11-02 13:06:18 +01001466 /* TEIC (conditional) */
1467 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1468 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1469 gsn->missing++;
1470 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1471 pack, len,
1472 "Missing mandatory information field");
1473 return gtp_create_pdp_resp(gsn, version, pdp,
1474 GTPCAUSE_MAN_IE_MISSING);
1475 }
1476 }
jjako08d331d2003-10-13 20:33:30 +00001477
Harald Weltebed35df2011-11-02 13:06:18 +01001478 /* NSAPI (mandatory) */
1479 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
1480 gsn->missing++;
1481 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1482 len, "Missing mandatory information field");
1483 return gtp_create_pdp_resp(gsn, version, pdp,
1484 GTPCAUSE_MAN_IE_MISSING);
1485 }
1486 }
jjako2e840a32003-01-28 16:05:18 +00001487
Harald Weltebed35df2011-11-02 13:06:18 +01001488 /* Charging Characteriatics (optional) */
1489 /* Trace reference (optional) */
1490 /* Trace type (optional) */
1491 /* Charging Characteriatics (optional) */
jjako52c24142002-12-16 13:33:51 +00001492
Harald Weltebed35df2011-11-02 13:06:18 +01001493 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1494 /* End User Address (conditional) */
1495 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1496 &pdp->eua.v, sizeof(pdp->eua.v))) {
1497 gsn->missing++;
1498 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1499 len, "Missing mandatory information field");
1500 return gtp_create_pdp_resp(gsn, version, pdp,
1501 GTPCAUSE_MAN_IE_MISSING);
1502 }
jjako08d331d2003-10-13 20:33:30 +00001503
Harald Weltebed35df2011-11-02 13:06:18 +01001504 /* APN */
1505 if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l,
1506 &pdp->apn_req.v, sizeof(pdp->apn_req.v))) {
1507 gsn->missing++;
1508 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1509 len, "Missing mandatory information field");
1510 return gtp_create_pdp_resp(gsn, version, pdp,
1511 GTPCAUSE_MAN_IE_MISSING);
1512 }
jjako2c381332003-10-21 19:09:53 +00001513
Harald Weltebed35df2011-11-02 13:06:18 +01001514 /* Extract protocol configuration options (optional) */
1515 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1516 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1517 }
1518 }
jjako2c381332003-10-21 19:09:53 +00001519
Harald Weltebed35df2011-11-02 13:06:18 +01001520 /* SGSN address for signalling (mandatory) */
1521 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1522 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1523 gsn->missing++;
1524 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1525 "Missing mandatory information field");
1526 return gtp_create_pdp_resp(gsn, version, pdp,
1527 GTPCAUSE_MAN_IE_MISSING);
1528 }
jjako2e840a32003-01-28 16:05:18 +00001529
Harald Weltebed35df2011-11-02 13:06:18 +01001530 /* SGSN address for user traffic (mandatory) */
1531 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1532 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1533 gsn->missing++;
1534 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1535 "Missing mandatory information field");
1536 return gtp_create_pdp_resp(gsn, version, pdp,
1537 GTPCAUSE_MAN_IE_MISSING);
1538 }
jjako52c24142002-12-16 13:33:51 +00001539
Harald Weltebed35df2011-11-02 13:06:18 +01001540 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1541 /* MSISDN (conditional) */
1542 if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l,
1543 &pdp->msisdn.v, sizeof(pdp->msisdn.v))) {
1544 gsn->missing++;
1545 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1546 len, "Missing mandatory information field");
1547 return gtp_create_pdp_resp(gsn, version, pdp,
1548 GTPCAUSE_MAN_IE_MISSING);
1549 }
1550 }
jjako52c24142002-12-16 13:33:51 +00001551
Harald Weltebed35df2011-11-02 13:06:18 +01001552 if (version == 1) {
1553 /* QoS (mandatory) */
1554 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
1555 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
1556 gsn->missing++;
1557 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1558 len, "Missing mandatory information field");
1559 return gtp_create_pdp_resp(gsn, version, pdp,
1560 GTPCAUSE_MAN_IE_MISSING);
1561 }
1562
1563 /* TFT (conditional) */
1564 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
1565 &pdp->tft.v, sizeof(pdp->tft.v))) {
1566 }
1567
1568 /* Trigger ID */
1569 /* OMC identity */
1570 }
1571
1572 /* Initialize our own IP addresses */
1573 in_addr2gsna(&pdp->gsnlc, &gsn->gsnc);
1574 in_addr2gsna(&pdp->gsnlu, &gsn->gsnu);
1575
1576 if (GTP_DEBUG)
1577 printf("gtp_create_pdp_ind: Before pdp_tidget\n");
1578
1579 if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) {
1580 /* Found old pdp with same tid. Now the voodoo begins! */
1581 /* 09.60 / 29.060 allows create on existing context to "steal" */
1582 /* the context which was allready established */
1583 /* We check that the APN, selection mode and MSISDN is the same */
1584 if (GTP_DEBUG)
1585 printf("gtp_create_pdp_ind: Old context found\n");
1586 if ((pdp->apn_req.l == pdp_old->apn_req.l)
1587 &&
1588 (!memcmp
1589 (pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l))
1590 && (pdp->selmode == pdp_old->selmode)
1591 && (pdp->msisdn.l == pdp_old->msisdn.l)
1592 &&
1593 (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l)))
1594 {
1595 /* OK! We are dealing with the same APN. We will copy new
1596 * parameters to the old pdp and send off confirmation
1597 * We ignore the following information elements:
1598 * QoS: MS will get originally negotiated QoS.
1599 * End user address (EUA). MS will get old EUA anyway.
1600 * Protocol configuration option (PCO): Only application can verify */
1601
1602 if (GTP_DEBUG)
1603 printf
1604 ("gtp_create_pdp_ind: Old context found\n");
1605
1606 /* Copy remote flow label */
1607 pdp_old->flru = pdp->flru;
1608 pdp_old->flrc = pdp->flrc;
1609
1610 /* Copy remote tei */
1611 pdp_old->teid_gn = pdp->teid_gn;
1612 pdp_old->teic_gn = pdp->teic_gn;
1613
1614 /* Copy peer GSN address */
1615 pdp_old->gsnrc.l = pdp->gsnrc.l;
1616 memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l);
1617 pdp_old->gsnru.l = pdp->gsnru.l;
1618 memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l);
1619
1620 /* Copy request parameters */
1621 pdp_old->seq = pdp->seq;
1622 pdp_old->sa_peer = pdp->sa_peer;
1623 pdp_old->fd = pdp->fd = fd;
1624 pdp_old->version = pdp->version = version;
1625
1626 /* Switch to using the old pdp context */
1627 pdp = pdp_old;
1628
1629 /* Confirm to peer that things were "successful" */
1630 return gtp_create_pdp_resp(gsn, version, pdp,
1631 GTPCAUSE_ACC_REQ);
1632 } else { /* This is not the same PDP context. Delete the old one. */
1633
1634 if (GTP_DEBUG)
1635 printf
1636 ("gtp_create_pdp_ind: Deleting old context\n");
1637
1638 if (gsn->cb_delete_context)
1639 gsn->cb_delete_context(pdp_old);
1640 pdp_freepdp(pdp_old);
1641
1642 if (GTP_DEBUG)
1643 printf("gtp_create_pdp_ind: Deleted...\n");
1644 }
1645 }
1646
1647 pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp);
1648
1649 /* Callback function to validata login */
1650 if (gsn->cb_create_context_ind != 0)
1651 return gsn->cb_create_context_ind(pdp);
1652 else {
1653 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1654 "No create_context_ind callback defined");
1655 return gtp_create_pdp_resp(gsn, version, pdp,
1656 GTPCAUSE_NOT_SUPPORTED);
1657 }
jjako52c24142002-12-16 13:33:51 +00001658}
1659
jjako52c24142002-12-16 13:33:51 +00001660/* Handle Create PDP Context Response */
1661int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01001662 struct sockaddr_in *peer, void *pack, unsigned len)
1663{
1664 struct pdp_t *pdp;
1665 union gtpie_member *ie[GTPIE_SIZE];
1666 uint8_t cause, recovery;
1667 void *cbp = NULL;
1668 uint8_t type = 0;
1669 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001670
Harald Weltebed35df2011-11-02 13:06:18 +01001671 /* Remove packet from queue */
1672 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
1673 return EOF;
jjako52c24142002-12-16 13:33:51 +00001674
Harald Weltebed35df2011-11-02 13:06:18 +01001675 /* Find the context in question */
1676 if (pdp_getgtp1(&pdp, get_tei(pack))) {
1677 gsn->err_unknownpdp++;
1678 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1679 "Unknown PDP context");
1680 if (gsn->cb_conf)
1681 gsn->cb_conf(type, EOF, NULL, cbp);
1682 return EOF;
1683 }
jjako2c381332003-10-21 19:09:53 +00001684
Harald Weltebed35df2011-11-02 13:06:18 +01001685 /* Register that we have received a valid teic from GGSN */
1686 pdp->teic_confirmed = 1;
jjako52c24142002-12-16 13:33:51 +00001687
Harald Weltebed35df2011-11-02 13:06:18 +01001688 /* Decode information elements */
1689 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
1690 gsn->invalid++;
1691 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1692 "Invalid message format");
1693 if (gsn->cb_conf)
1694 gsn->cb_conf(type, EOF, pdp, cbp);
1695 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1696 pdp_freepdp(pdp); */
1697 return EOF;
1698 }
jjako52c24142002-12-16 13:33:51 +00001699
Harald Weltebed35df2011-11-02 13:06:18 +01001700 /* Extract cause value (mandatory) */
1701 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
1702 gsn->missing++;
1703 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1704 "Missing mandatory information field");
1705 if (gsn->cb_conf)
1706 gsn->cb_conf(type, EOF, pdp, cbp);
1707 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1708 pdp_freepdp(pdp); */
1709 return EOF;
1710 }
jjako52c24142002-12-16 13:33:51 +00001711
Harald Weltebed35df2011-11-02 13:06:18 +01001712 /* Extract recovery (optional) */
1713 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1714 if (gsn->cb_recovery)
1715 gsn->cb_recovery(peer, recovery);
1716 }
jjako52c24142002-12-16 13:33:51 +00001717
Harald Weltebed35df2011-11-02 13:06:18 +01001718 /* Extract protocol configuration options (optional) */
1719 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1720 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1721 }
jjako52c24142002-12-16 13:33:51 +00001722
Harald Weltebed35df2011-11-02 13:06:18 +01001723 /* Check all conditional information elements */
1724 if (GTPCAUSE_ACC_REQ == cause) {
jjako52c24142002-12-16 13:33:51 +00001725
Harald Weltebed35df2011-11-02 13:06:18 +01001726 if (version == 0) {
1727 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1728 &pdp->qos_neg0,
1729 sizeof(pdp->qos_neg0))) {
1730 gsn->missing++;
1731 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1732 pack, len,
1733 "Missing conditional information field");
1734 if (gsn->cb_conf)
1735 gsn->cb_conf(type, EOF, pdp, cbp);
1736 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1737 pdp_freepdp(pdp); */
1738 return EOF;
1739 }
1740 }
jjako08d331d2003-10-13 20:33:30 +00001741
Harald Weltebed35df2011-11-02 13:06:18 +01001742 if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) {
1743 gsn->missing++;
1744 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1745 len,
1746 "Missing conditional information field");
1747 if (gsn->cb_conf)
1748 gsn->cb_conf(type, EOF, pdp, cbp);
1749 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1750 pdp_freepdp(pdp); */
1751 return EOF;
1752 }
jjako52c24142002-12-16 13:33:51 +00001753
Harald Weltebed35df2011-11-02 13:06:18 +01001754 if (version == 0) {
1755 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1756 gsn->missing++;
1757 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1758 pack, len,
1759 "Missing conditional information field");
1760 if (gsn->cb_conf)
1761 gsn->cb_conf(type, EOF, pdp, cbp);
1762 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1763 pdp_freepdp(pdp); */
1764 return EOF;
1765 }
jjako52c24142002-12-16 13:33:51 +00001766
Harald Weltebed35df2011-11-02 13:06:18 +01001767 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1768 gsn->missing++;
1769 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1770 pack, len,
1771 "Missing conditional information field");
1772 if (gsn->cb_conf)
1773 gsn->cb_conf(type, EOF, pdp, cbp);
1774 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1775 pdp_freepdp(pdp); */
1776 return EOF;
1777 }
1778 }
1779
1780 if (version == 1) {
1781 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1782 gsn->missing++;
1783 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1784 pack, len,
1785 "Missing conditional information field");
1786 if (gsn->cb_conf)
1787 gsn->cb_conf(type, EOF, pdp, cbp);
1788 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1789 pdp_freepdp(pdp); */
1790 return EOF;
1791 }
1792
1793 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1794 gsn->missing++;
1795 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1796 pack, len,
1797 "Missing conditional information field");
1798 if (gsn->cb_conf)
1799 gsn->cb_conf(type, EOF, pdp, cbp);
1800 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1801 pdp_freepdp(pdp); */
1802 return EOF;
1803 }
1804 }
1805
1806 if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
1807 gsn->missing++;
1808 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1809 len,
1810 "Missing conditional information field");
1811 if (gsn->cb_conf)
1812 gsn->cb_conf(type, EOF, pdp, cbp);
1813 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1814 pdp_freepdp(pdp); */
1815 }
1816
1817 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1818 &pdp->eua.v, sizeof(pdp->eua.v))) {
1819 gsn->missing++;
1820 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1821 len,
1822 "Missing conditional information field");
1823 if (gsn->cb_conf)
1824 gsn->cb_conf(type, EOF, pdp, cbp);
1825 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1826 pdp_freepdp(pdp); */
1827 return EOF;
1828 }
1829
1830 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1831 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1832 gsn->missing++;
1833 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1834 len,
1835 "Missing conditional information field");
1836 if (gsn->cb_conf)
1837 gsn->cb_conf(type, EOF, pdp, cbp);
1838 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1839 pdp_freepdp(pdp); */
1840 return EOF;
1841 }
1842
1843 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1844 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1845 gsn->missing++;
1846 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
1847 len,
1848 "Missing conditional information field");
1849 if (gsn->cb_conf)
1850 gsn->cb_conf(type, EOF, pdp, cbp);
1851 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1852 pdp_freepdp(pdp); */
1853 return EOF;
1854 }
1855
1856 if (version == 1) {
1857 if (gtpie_gettlv
1858 (ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
1859 &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
1860 gsn->missing++;
1861 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
1862 pack, len,
1863 "Missing conditional information field");
1864 if (gsn->cb_conf)
1865 gsn->cb_conf(type, EOF, pdp, cbp);
1866 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1867 pdp_freepdp(pdp); */
1868 return EOF;
1869 }
1870 }
1871
1872 }
1873
1874 if (gsn->cb_conf)
1875 gsn->cb_conf(type, cause, pdp, cbp);
1876
1877 return 0;
jjako52c24142002-12-16 13:33:51 +00001878}
1879
jjako08d331d2003-10-13 20:33:30 +00001880/* API: Send Update PDP Context Request */
1881int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
Harald Weltebed35df2011-11-02 13:06:18 +01001882 struct in_addr *inetaddr)
1883{
1884 union gtp_packet packet;
1885 unsigned int length =
1886 get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet);
jjako52c24142002-12-16 13:33:51 +00001887
Harald Weltebed35df2011-11-02 13:06:18 +01001888 if (pdp->version == 0)
1889 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1890 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako08d331d2003-10-13 20:33:30 +00001891
Harald Weltebed35df2011-11-02 13:06:18 +01001892 /* Include IMSI if updating with unknown teic_gn */
1893 if ((pdp->version == 1) && (!pdp->teic_gn))
1894 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1895 sizeof(pdp->imsi), (uint8_t *) & pdp->imsi);
1896
1897 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1898 gsn->restart_counter);
1899
1900 if (pdp->version == 0) {
1901 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu);
1902 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc);
1903 }
1904
1905 if (pdp->version == 1) {
1906 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1907 pdp->teid_own);
1908
1909 if (!pdp->teic_confirmed)
1910 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1911 pdp->teic_own);
1912 }
1913
1914 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
1915
1916 /* TODO
1917 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1918 pdp->traceref);
1919 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1920 pdp->tracetype); */
1921
1922 /* TODO if ggsn update message
1923 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1924 pdp->eua.l, pdp->eua.v);
1925 */
1926
1927 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1928 pdp->gsnlc.l, pdp->gsnlc.v);
1929 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1930 pdp->gsnlu.l, pdp->gsnlu.v);
1931
1932 if (pdp->version == 1)
1933 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1934 pdp->qos_req.l, pdp->qos_req.v);
1935
1936 if ((pdp->version == 1) && pdp->tft.l)
1937 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1938 pdp->tft.l, pdp->tft.v);
1939
1940 if ((pdp->version == 1) && pdp->triggerid.l)
1941 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1942 pdp->triggerid.l, pdp->triggerid.v);
1943
1944 if ((pdp->version == 1) && pdp->omcid.l)
1945 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1946 pdp->omcid.l, pdp->omcid.v);
1947
1948 gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp);
1949
1950 return 0;
jjako52c24142002-12-16 13:33:51 +00001951}
1952
jjako08d331d2003-10-13 20:33:30 +00001953/* Send Update PDP Context Response */
Harald Weltebed35df2011-11-02 13:06:18 +01001954int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
1955 struct sockaddr_in *peer, int fd,
jjako08d331d2003-10-13 20:33:30 +00001956 void *pack, unsigned len,
Harald Weltebed35df2011-11-02 13:06:18 +01001957 struct pdp_t *pdp, uint8_t cause)
1958{
jjako08d331d2003-10-13 20:33:30 +00001959
Harald Weltebed35df2011-11-02 13:06:18 +01001960 union gtp_packet packet;
1961 unsigned int length =
1962 get_default_gtp(version, GTP_UPDATE_PDP_RSP, &packet);
jjako08d331d2003-10-13 20:33:30 +00001963
Harald Weltebed35df2011-11-02 13:06:18 +01001964 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako08d331d2003-10-13 20:33:30 +00001965
Harald Weltebed35df2011-11-02 13:06:18 +01001966 if (cause == GTPCAUSE_ACC_REQ) {
1967
1968 if (version == 0)
1969 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1970 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1971
1972 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1973 gsn->restart_counter);
1974
1975 if (version == 0) {
1976 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1977 pdp->fllu);
1978 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1979 pdp->fllc);
1980 }
1981
1982 if (version == 1) {
1983 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1984 pdp->teid_own);
1985
1986 if (!pdp->teic_confirmed)
1987 gtpie_tv4(&packet, &length, GTP_MAX,
1988 GTPIE_TEI_C, pdp->teic_own);
1989 }
1990
1991 /* TODO we use teid_own as charging ID address */
1992 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
1993 pdp->teid_own);
1994
1995 /* If ggsn
1996 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1997 pdp->eua.l, pdp->eua.v); */
1998
1999 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
2000 pdp->gsnlc.l, pdp->gsnlc.v);
2001 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
2002 pdp->gsnlu.l, pdp->gsnlu.v);
2003
2004 if (version == 1)
2005 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
2006 pdp->qos_neg.l, pdp->qos_neg.v);
2007
2008 /* TODO: Charging gateway address */
2009 }
2010
2011 return gtp_resp(version, gsn, pdp, &packet, length, peer,
2012 fd, get_seq(pack), get_tid(pack));
jjako08d331d2003-10-13 20:33:30 +00002013}
2014
jjako52c24142002-12-16 13:33:51 +00002015/* Handle Update PDP Context Request */
2016int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002017 struct sockaddr_in *peer, int fd,
2018 void *pack, unsigned len)
2019{
2020 struct pdp_t *pdp;
2021 struct pdp_t pdp_backup;
2022 union gtpie_member *ie[GTPIE_SIZE];
2023 uint8_t recovery;
jjako52c24142002-12-16 13:33:51 +00002024
Harald Weltebed35df2011-11-02 13:06:18 +01002025 uint16_t seq = get_seq(pack);
2026 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002027
Harald Weltebed35df2011-11-02 13:06:18 +01002028 uint64_t imsi;
2029 uint8_t nsapi;
jjako52c24142002-12-16 13:33:51 +00002030
Harald Weltebed35df2011-11-02 13:06:18 +01002031 /* Is this a dublicate ? */
2032 if (!gtp_dublicate(gsn, version, peer, seq)) {
2033 return 0; /* We allready send of response once */
2034 }
jjako08d331d2003-10-13 20:33:30 +00002035
Harald Weltebed35df2011-11-02 13:06:18 +01002036 /* Decode information elements */
2037 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
2038 gsn->invalid++;
2039 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2040 "Invalid message format");
2041 if (0 == version)
2042 return EOF;
2043 else
2044 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2045 len, NULL,
2046 GTPCAUSE_INVALID_MESSAGE);
2047 }
jjako08d331d2003-10-13 20:33:30 +00002048
Harald Weltebed35df2011-11-02 13:06:18 +01002049 /* Finding PDP: */
2050 /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
2051 /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
2052 /* we have to use the tunnel endpoint identifier */
2053 if (version == 0) {
2054 imsi =
2055 ((union gtp_packet *)pack)->gtp0.
2056 h.tid & 0x0fffffffffffffffull;
2057 nsapi =
2058 (((union gtp_packet *)pack)->gtp0.
2059 h.tid & 0xf000000000000000ull) >> 60;
jjako52c24142002-12-16 13:33:51 +00002060
Harald Weltebed35df2011-11-02 13:06:18 +01002061 /* Find the context in question */
2062 if (pdp_getimsi(&pdp, imsi, nsapi)) {
2063 gsn->err_unknownpdp++;
2064 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2065 len, "Unknown PDP context");
2066 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2067 len, NULL,
2068 GTPCAUSE_NON_EXIST);
2069 }
2070 } else if (version == 1) {
2071 /* NSAPI (mandatory) */
2072 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
2073 gsn->missing++;
2074 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2075 len, "Missing mandatory information field");
2076 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2077 len, NULL,
2078 GTPCAUSE_MAN_IE_MISSING);
2079 }
jjako08d331d2003-10-13 20:33:30 +00002080
Harald Weltebed35df2011-11-02 13:06:18 +01002081 /* IMSI (conditional) */
2082 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) {
2083 /* Find the context in question */
2084 if (pdp_getgtp1(&pdp, get_tei(pack))) {
2085 gsn->err_unknownpdp++;
2086 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
2087 pack, len, "Unknown PDP context");
2088 return gtp_update_pdp_resp(gsn, version, peer,
2089 fd, pack, len, NULL,
2090 GTPCAUSE_NON_EXIST);
2091 }
2092 } else {
2093 /* Find the context in question */
2094 if (pdp_getimsi(&pdp, imsi, nsapi)) {
2095 gsn->err_unknownpdp++;
2096 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
2097 pack, len, "Unknown PDP context");
2098 return gtp_update_pdp_resp(gsn, version, peer,
2099 fd, pack, len, NULL,
2100 GTPCAUSE_NON_EXIST);
2101 }
2102 }
2103 } else {
2104 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
2105 return EOF;
2106 }
jjako08d331d2003-10-13 20:33:30 +00002107
Harald Weltebed35df2011-11-02 13:06:18 +01002108 /* Make a backup copy in case anything is wrong */
2109 memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
jjako08d331d2003-10-13 20:33:30 +00002110
Harald Weltebed35df2011-11-02 13:06:18 +01002111 if (version == 0) {
2112 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2113 pdp->qos_req0, sizeof(pdp->qos_req0))) {
2114 gsn->missing++;
2115 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2116 len, "Missing mandatory information field");
2117 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2118 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2119 len, pdp,
2120 GTPCAUSE_MAN_IE_MISSING);
2121 }
2122 }
jjako52c24142002-12-16 13:33:51 +00002123
Harald Weltebed35df2011-11-02 13:06:18 +01002124 /* Recovery (optional) */
2125 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
2126 if (gsn->cb_recovery)
2127 gsn->cb_recovery(peer, recovery);
2128 }
jjako08d331d2003-10-13 20:33:30 +00002129
Harald Weltebed35df2011-11-02 13:06:18 +01002130 if (version == 0) {
2131 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
2132 gsn->missing++;
2133 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2134 len, "Missing mandatory information field");
2135 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2136 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2137 len, pdp,
2138 GTPCAUSE_MAN_IE_MISSING);
2139 }
jjako52c24142002-12-16 13:33:51 +00002140
Harald Weltebed35df2011-11-02 13:06:18 +01002141 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
2142 gsn->missing++;
2143 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2144 len, "Missing mandatory information field");
2145 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2146 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2147 len, pdp,
2148 GTPCAUSE_MAN_IE_MISSING);
2149 }
2150 }
jjako52c24142002-12-16 13:33:51 +00002151
Harald Weltebed35df2011-11-02 13:06:18 +01002152 if (version == 1) {
2153 /* TEID (mandatory) */
2154 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
2155 gsn->missing++;
2156 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2157 len, "Missing mandatory information field");
2158 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2159 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2160 len, pdp,
2161 GTPCAUSE_MAN_IE_MISSING);
2162 }
jjako52c24142002-12-16 13:33:51 +00002163
Harald Weltebed35df2011-11-02 13:06:18 +01002164 /* TEIC (conditional) */
2165 /* If TEIC is not included it means that we have allready received it */
2166 /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
2167 /* all updated contexts, or only for one of the linked contexts */
2168 gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn);
2169
2170 /* NSAPI (mandatory) */
2171 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
2172 gsn->missing++;
2173 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2174 len, "Missing mandatory information field");
2175 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2176 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2177 len, pdp,
2178 GTPCAUSE_MAN_IE_MISSING);
2179 }
2180 }
2181
2182 /* Trace reference (optional) */
2183 /* Trace type (optional) */
2184
2185 /* End User Address (conditional) TODO: GGSN Initiated
2186 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2187 &pdp->eua.v, sizeof(pdp->eua.v))) {
2188 gsn->missing++;
2189 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2190 "Missing mandatory information field");
2191 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2192 return gtp_update_pdp_resp(gsn, version, pdp,
2193 GTPCAUSE_MAN_IE_MISSING);
2194 } */
2195
2196 /* SGSN address for signalling (mandatory) */
2197 /* It is weird that this is mandatory when TEIC is conditional */
2198 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2199 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
2200 gsn->missing++;
2201 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2202 "Missing mandatory information field");
2203 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2204 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
2205 pdp, GTPCAUSE_MAN_IE_MISSING);
2206 }
2207
2208 /* SGSN address for user traffic (mandatory) */
2209 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2210 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
2211 gsn->missing++;
2212 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2213 "Missing mandatory information field");
2214 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2215 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
2216 pdp, GTPCAUSE_MAN_IE_MISSING);
2217 }
2218
2219 if (version == 1) {
2220 /* QoS (mandatory) */
2221 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
2222 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
2223 gsn->missing++;
2224 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2225 len, "Missing mandatory information field");
2226 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2227 return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
2228 len, pdp,
2229 GTPCAUSE_MAN_IE_MISSING);
2230 }
2231
2232 /* TFT (conditional) */
2233 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
2234 &pdp->tft.v, sizeof(pdp->tft.v))) {
2235 }
2236
2237 /* OMC identity */
2238 }
2239
2240 /* Confirm to peer that things were "successful" */
2241 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2242 GTPCAUSE_ACC_REQ);
jjako52c24142002-12-16 13:33:51 +00002243}
2244
jjako52c24142002-12-16 13:33:51 +00002245/* Handle Update PDP Context Response */
2246int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002247 struct sockaddr_in *peer, void *pack, unsigned len)
2248{
2249 struct pdp_t *pdp;
2250 union gtpie_member *ie[GTPIE_SIZE];
2251 uint8_t cause, recovery;
2252 void *cbp = NULL;
2253 uint8_t type = 0;
jjako52c24142002-12-16 13:33:51 +00002254
Harald Weltebed35df2011-11-02 13:06:18 +01002255 /* Remove packet from queue */
2256 if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp))
2257 return EOF;
jjako52c24142002-12-16 13:33:51 +00002258
Harald Weltebed35df2011-11-02 13:06:18 +01002259 /* Find the context in question */
2260 if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) {
2261 gsn->err_unknownpdp++;
2262 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2263 "Unknown PDP context");
2264 if (gsn->cb_conf)
2265 gsn->cb_conf(type, cause, NULL, cbp);
2266 return EOF;
2267 }
jjako2c381332003-10-21 19:09:53 +00002268
Harald Weltebed35df2011-11-02 13:06:18 +01002269 /* Register that we have received a valid teic from GGSN */
2270 pdp->teic_confirmed = 1;
jjako52c24142002-12-16 13:33:51 +00002271
Harald Weltebed35df2011-11-02 13:06:18 +01002272 /* Decode information elements */
2273 if (gtpie_decaps
2274 (ie, 0, pack + GTP0_HEADER_SIZE, len - GTP0_HEADER_SIZE)) {
2275 gsn->invalid++;
2276 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2277 "Invalid message format");
2278 if (gsn->cb_conf)
2279 gsn->cb_conf(type, EOF, pdp, cbp);
2280 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2281 pdp_freepdp(pdp); */
2282 return EOF;
2283 }
jjako52c24142002-12-16 13:33:51 +00002284
Harald Weltebed35df2011-11-02 13:06:18 +01002285 /* Extract cause value (mandatory) */
2286 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2287 gsn->missing++;
2288 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2289 "Missing mandatory information field");
2290 if (gsn->cb_conf)
2291 gsn->cb_conf(type, EOF, pdp, cbp);
2292 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2293 pdp_freepdp(pdp); */
2294 return EOF;
2295 }
jjako52c24142002-12-16 13:33:51 +00002296
Harald Weltebed35df2011-11-02 13:06:18 +01002297 /* Extract recovery (optional) */
2298 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
2299 if (gsn->cb_recovery)
2300 gsn->cb_recovery(peer, recovery);
2301 }
2302
2303 /* Check all conditional information elements */
2304 if (GTPCAUSE_ACC_REQ != cause) {
2305 if (gsn->cb_conf)
2306 gsn->cb_conf(type, cause, pdp, cbp);
2307 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2308 pdp_freepdp(pdp); */
2309 return 0;
2310 } else {
2311 /* Check for missing conditionary information elements */
2312 if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) &&
2313 gtpie_exist(ie, GTPIE_REORDER, 0) &&
2314 gtpie_exist(ie, GTPIE_FL_DI, 0) &&
2315 gtpie_exist(ie, GTPIE_FL_C, 0) &&
2316 gtpie_exist(ie, GTPIE_CHARGING_ID, 0) &&
2317 gtpie_exist(ie, GTPIE_EUA, 0) &&
2318 gtpie_exist(ie, GTPIE_GSN_ADDR, 0) &&
2319 gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) {
2320 gsn->missing++;
2321 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2322 len,
2323 "Missing conditional information field");
2324 if (gsn->cb_conf)
2325 gsn->cb_conf(type, EOF, pdp, cbp);
2326 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2327 pdp_freepdp(pdp); */
2328 return EOF;
2329 }
2330
2331 /* Update pdp with new values */
2332 gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2333 pdp->qos_neg0, sizeof(pdp->qos_neg0));
2334 gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder);
2335 gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru);
2336 gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc);
2337 gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid);
2338 gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2339 &pdp->eua.v, sizeof(pdp->eua.v));
2340 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2341 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v));
2342 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2343 &pdp->gsnru.v, sizeof(pdp->gsnru.v));
2344
2345 if (gsn->cb_conf)
2346 gsn->cb_conf(type, cause, pdp, cbp);
2347 return 0; /* Succes */
2348 }
jjako52c24142002-12-16 13:33:51 +00002349}
2350
jjako08d331d2003-10-13 20:33:30 +00002351/* API: Send Delete PDP Context Request */
jjako2c381332003-10-21 19:09:53 +00002352int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
Harald Weltebed35df2011-11-02 13:06:18 +01002353 int teardown)
2354{
2355 union gtp_packet packet;
2356 unsigned int length =
2357 get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
2358 struct in_addr addr;
2359 struct pdp_t *linked_pdp;
2360 struct pdp_t *secondary_pdp;
2361 int n;
2362 int count = 0;
jjako2c381332003-10-21 19:09:53 +00002363
Harald Weltebed35df2011-11-02 13:06:18 +01002364 if (gsna2in_addr(&addr, &pdp->gsnrc)) {
2365 gsn->err_address++;
2366 gtp_err(LOG_ERR, __FILE__, __LINE__,
2367 "GSN address conversion failed");
2368 return EOF;
jjako2c381332003-10-21 19:09:53 +00002369 }
jjako2c381332003-10-21 19:09:53 +00002370
Harald Weltebed35df2011-11-02 13:06:18 +01002371 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
2372 gtp_err(LOG_ERR, __FILE__, __LINE__,
2373 "Unknown linked PDP context");
2374 return EOF;
2375 }
2376
2377 if (!teardown) {
2378 for (n = 0; n < PDP_MAXNSAPI; n++)
2379 if (linked_pdp->secondary_tei[n])
2380 count++;
2381 if (count <= 1) {
2382 gtp_err(LOG_ERR, __FILE__, __LINE__,
2383 "Must use teardown for last context");
2384 return EOF;
2385 }
2386 }
2387
2388 if (pdp->version == 1) {
2389 if (teardown)
2390 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
2391 0xff);
2392
2393 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
2394 }
2395
2396 gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
2397
2398 if (teardown) { /* Remove all contexts */
2399 for (n = 0; n < PDP_MAXNSAPI; n++) {
2400 if (linked_pdp->secondary_tei[n]) {
2401 if (pdp_getgtp1
2402 (&secondary_pdp,
2403 linked_pdp->secondary_tei[n])) {
2404 gtp_err(LOG_ERR, __FILE__, __LINE__,
2405 "Unknown secondary PDP context");
2406 return EOF;
2407 }
2408 if (linked_pdp != secondary_pdp) {
2409 if (gsn->cb_delete_context)
2410 gsn->cb_delete_context
2411 (secondary_pdp);
2412 pdp_freepdp(secondary_pdp);
2413 }
2414 }
2415 }
2416 if (gsn->cb_delete_context)
2417 gsn->cb_delete_context(linked_pdp);
2418 pdp_freepdp(linked_pdp);
2419 } else {
2420 if (gsn->cb_delete_context)
2421 gsn->cb_delete_context(pdp);
2422 if (pdp == linked_pdp) {
2423 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2424 linked_pdp->nodata = 1;
2425 } else
2426 pdp_freepdp(pdp);
2427 }
2428
2429 return 0;
jjako2c381332003-10-21 19:09:53 +00002430}
jjako08d331d2003-10-13 20:33:30 +00002431
jjako52c24142002-12-16 13:33:51 +00002432/* Send Delete PDP Context Response */
2433int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002434 struct sockaddr_in *peer, int fd,
Harald Weltebed35df2011-11-02 13:06:18 +01002435 void *pack, unsigned len,
2436 struct pdp_t *pdp, struct pdp_t *linked_pdp,
jjako2c381332003-10-21 19:09:53 +00002437 uint8_t cause, int teardown)
jjako52c24142002-12-16 13:33:51 +00002438{
Harald Weltebed35df2011-11-02 13:06:18 +01002439 union gtp_packet packet;
2440 struct pdp_t *secondary_pdp;
2441 unsigned int length =
2442 get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet);
2443 int n;
jjako52c24142002-12-16 13:33:51 +00002444
Harald Weltebed35df2011-11-02 13:06:18 +01002445 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00002446
Harald Weltebed35df2011-11-02 13:06:18 +01002447 gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
2448 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002449
Harald Weltebed35df2011-11-02 13:06:18 +01002450 if (cause == GTPCAUSE_ACC_REQ) {
2451 if ((teardown) || (version == 0)) { /* Remove all contexts */
2452 for (n = 0; n < PDP_MAXNSAPI; n++) {
2453 if (linked_pdp->secondary_tei[n]) {
2454 if (pdp_getgtp1
2455 (&secondary_pdp,
2456 linked_pdp->secondary_tei[n])) {
2457 gtp_err(LOG_ERR, __FILE__,
2458 __LINE__,
2459 "Unknown secondary PDP context");
2460 return EOF;
2461 }
2462 if (linked_pdp != secondary_pdp) {
2463 if (gsn->cb_delete_context)
2464 gsn->cb_delete_context
2465 (secondary_pdp);
2466 pdp_freepdp(secondary_pdp);
2467 }
2468 }
2469 }
2470 if (gsn->cb_delete_context)
2471 gsn->cb_delete_context(linked_pdp);
2472 pdp_freepdp(linked_pdp);
2473 } else { /* Remove only current context */
2474 if (gsn->cb_delete_context)
2475 gsn->cb_delete_context(pdp);
2476 if (pdp == linked_pdp) {
2477 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] =
2478 0;
2479 linked_pdp->nodata = 1;
2480 } else
2481 pdp_freepdp(pdp);
2482 }
jjako2c381332003-10-21 19:09:53 +00002483 }
Harald Weltebed35df2011-11-02 13:06:18 +01002484 /* if (cause == GTPCAUSE_ACC_REQ) */
2485 return 0;
jjako52c24142002-12-16 13:33:51 +00002486}
2487
2488/* Handle Delete PDP Context Request */
2489int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002490 struct sockaddr_in *peer, int fd,
Harald Weltebed35df2011-11-02 13:06:18 +01002491 void *pack, unsigned len)
2492{
2493 struct pdp_t *pdp = NULL;
2494 struct pdp_t *linked_pdp = NULL;
2495 union gtpie_member *ie[GTPIE_SIZE];
jjako52c24142002-12-16 13:33:51 +00002496
Harald Weltebed35df2011-11-02 13:06:18 +01002497 uint16_t seq = get_seq(pack);
2498 int hlen = get_hlen(pack);
jjako2c381332003-10-21 19:09:53 +00002499
Harald Weltebed35df2011-11-02 13:06:18 +01002500 uint8_t nsapi;
2501 uint8_t teardown = 0;
2502 int n;
2503 int count = 0;
jjako52c24142002-12-16 13:33:51 +00002504
Harald Weltebed35df2011-11-02 13:06:18 +01002505 /* Is this a dublicate ? */
2506 if (!gtp_dublicate(gsn, version, peer, seq)) {
2507 return 0; /* We allready send off response once */
2508 }
jjako2c381332003-10-21 19:09:53 +00002509
Harald Weltebed35df2011-11-02 13:06:18 +01002510 /* Find the linked context in question */
2511 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
2512 gsn->err_unknownpdp++;
2513 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2514 "Unknown PDP context");
2515 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2516 NULL, NULL, GTPCAUSE_NON_EXIST,
2517 teardown);
2518 }
jjako2c381332003-10-21 19:09:53 +00002519
Harald Weltebed35df2011-11-02 13:06:18 +01002520 /* If version 0 this is also the secondary context */
2521 if (version == 0)
2522 pdp = linked_pdp;
jjako2c381332003-10-21 19:09:53 +00002523
Harald Weltebed35df2011-11-02 13:06:18 +01002524 /* Decode information elements */
2525 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
2526 gsn->invalid++;
2527 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2528 "Invalid message format");
2529 if (0 == version)
2530 return EOF;
2531 else
2532 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2533 len, NULL, NULL,
2534 GTPCAUSE_INVALID_MESSAGE,
2535 teardown);
2536 }
2537
2538 if (version == 1) {
2539 /* NSAPI (mandatory) */
2540 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
2541 gsn->missing++;
2542 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2543 len, "Missing mandatory information field");
2544 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2545 len, NULL, NULL,
2546 GTPCAUSE_MAN_IE_MISSING,
2547 teardown);
2548 }
2549
2550 /* Find the context in question */
2551 if (pdp_getgtp1(&pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) {
2552 gsn->err_unknownpdp++;
2553 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2554 len, "Unknown PDP context");
2555 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
2556 len, NULL, NULL,
2557 GTPCAUSE_NON_EXIST,
2558 teardown);
2559 }
2560
2561 /* Teardown (conditional) */
2562 gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown);
2563
2564 if (!teardown) {
2565 for (n = 0; n < PDP_MAXNSAPI; n++)
2566 if (linked_pdp->secondary_tei[n])
2567 count++;
2568 if (count <= 1) {
2569 return 0; /* 29.060 7.3.5 Ignore message */
2570 }
2571 }
2572 }
2573
2574 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2575 pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown);
jjako52c24142002-12-16 13:33:51 +00002576}
2577
jjako52c24142002-12-16 13:33:51 +00002578/* Handle Delete PDP Context Response */
2579int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002580 struct sockaddr_in *peer, void *pack, unsigned len)
2581{
2582 union gtpie_member *ie[GTPIE_SIZE];
2583 uint8_t cause;
2584 void *cbp = NULL;
2585 uint8_t type = 0;
2586 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002587
Harald Weltebed35df2011-11-02 13:06:18 +01002588 /* Remove packet from queue */
2589 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
2590 return EOF;
jjako52c24142002-12-16 13:33:51 +00002591
Harald Weltebed35df2011-11-02 13:06:18 +01002592 /* Decode information elements */
2593 if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
2594 gsn->invalid++;
2595 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2596 "Invalid message format");
2597 if (gsn->cb_conf)
2598 gsn->cb_conf(type, EOF, NULL, cbp);
2599 return EOF;
2600 }
2601
2602 /* Extract cause value (mandatory) */
2603 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2604 gsn->missing++;
2605 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2606 "Missing mandatory information field");
2607 if (gsn->cb_conf)
2608 gsn->cb_conf(type, EOF, NULL, cbp);
2609 return EOF;
2610 }
2611
2612 /* Check the cause value (again) */
2613 if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
2614 gsn->err_cause++;
2615 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2616 "Unexpected cause value received: %d", cause);
2617 if (gsn->cb_conf)
2618 gsn->cb_conf(type, cause, NULL, cbp);
2619 return EOF;
2620 }
2621
2622 /* Callback function to notify application */
2623 if (gsn->cb_conf)
2624 gsn->cb_conf(type, cause, NULL, cbp);
2625
2626 return 0;
jjako52c24142002-12-16 13:33:51 +00002627}
2628
2629/* Send Error Indication (response to a GPDU message */
2630int gtp_error_ind_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002631 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002632 void *pack, unsigned len)
2633{
Harald Weltebed35df2011-11-02 13:06:18 +01002634 union gtp_packet packet;
2635 unsigned int length = get_default_gtp(version, GTP_ERROR, &packet);
2636
2637 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
2638 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002639}
2640
2641/* Handle Error Indication */
2642int gtp_error_ind_conf(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002643 struct sockaddr_in *peer, void *pack, unsigned len)
2644{
2645 struct pdp_t *pdp;
jjako52c24142002-12-16 13:33:51 +00002646
Harald Weltebed35df2011-11-02 13:06:18 +01002647 /* Find the context in question */
2648 if (pdp_tidget(&pdp, ((union gtp_packet *)pack)->gtp0.h.tid)) {
2649 gsn->err_unknownpdp++;
2650 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2651 "Unknown PDP context");
2652 return EOF;
2653 }
jjako52c24142002-12-16 13:33:51 +00002654
Harald Weltebed35df2011-11-02 13:06:18 +01002655 gsn->err_unknownpdp++; /* TODO: Change counter */
2656 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2657 "Received Error Indication");
2658
2659 if (gsn->cb_delete_context)
2660 gsn->cb_delete_context(pdp);
2661 pdp_freepdp(pdp);
2662 return 0;
jjako52c24142002-12-16 13:33:51 +00002663}
2664
2665int gtp_gpdu_ind(struct gsn_t *gsn, int version,
Harald Weltebed35df2011-11-02 13:06:18 +01002666 struct sockaddr_in *peer, int fd, void *pack, unsigned len)
2667{
jjako08d331d2003-10-13 20:33:30 +00002668
Harald Weltebed35df2011-11-02 13:06:18 +01002669 int hlen = GTP1_HEADER_SIZE_SHORT;
jjako52c24142002-12-16 13:33:51 +00002670
Harald Weltebed35df2011-11-02 13:06:18 +01002671 /* Need to include code to verify packet src and dest addresses */
2672 struct pdp_t *pdp;
jjako1db1c812003-07-06 20:53:57 +00002673
Harald Weltebed35df2011-11-02 13:06:18 +01002674 if (version == 0) {
2675 if (pdp_getgtp0
2676 (&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) {
2677 gsn->err_unknownpdp++;
2678 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2679 len, "Unknown PDP context");
2680 return gtp_error_ind_resp(gsn, version, peer, fd, pack,
2681 len);
2682 }
2683 hlen = GTP0_HEADER_SIZE;
2684 } else if (version == 1) {
2685 if (pdp_getgtp1
2686 (&pdp, ntoh32(((union gtp_packet *)pack)->gtp1l.h.tei))) {
2687 gsn->err_unknownpdp++;
2688 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
2689 len, "Unknown PDP context");
2690 return gtp_error_ind_resp(gsn, version, peer, fd, pack,
2691 len);
2692 }
jjako08d331d2003-10-13 20:33:30 +00002693
Harald Weltebed35df2011-11-02 13:06:18 +01002694 /* Is this a long or a short header ? */
2695 if (((union gtp_packet *)pack)->gtp1l.h.flags & 0x07)
2696 hlen = GTP1_HEADER_SIZE_LONG;
2697 else
2698 hlen = GTP1_HEADER_SIZE_SHORT;
2699 } else {
2700 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2701 "Unknown version");
2702 }
jjako08d331d2003-10-13 20:33:30 +00002703
Harald Weltebed35df2011-11-02 13:06:18 +01002704 /* If the GPDU was not from the peer GSN tell him to delete context */
2705 if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
2706 gsn->err_unknownpdp++;
2707 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2708 "Unknown PDP context");
2709 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2710 }
jjako52c24142002-12-16 13:33:51 +00002711
Harald Weltebed35df2011-11-02 13:06:18 +01002712 /* Callback function */
2713 if (gsn->cb_data_ind != 0)
2714 return gsn->cb_data_ind(pdp, pack + hlen, len - hlen);
2715
2716 return 0;
jjako52c24142002-12-16 13:33:51 +00002717}
2718
jjako52c24142002-12-16 13:33:51 +00002719/* Receives GTP packet and sends off for further processing
2720 * Function will check the validity of the header. If the header
2721 * is not valid the packet is either dropped or a version not
2722 * supported is returned to the peer.
2723 * TODO: Need to decide on return values! */
jjako08d331d2003-10-13 20:33:30 +00002724int gtp_decaps0(struct gsn_t *gsn)
jjako52c24142002-12-16 13:33:51 +00002725{
Harald Weltebed35df2011-11-02 13:06:18 +01002726 unsigned char buffer[PACKET_MAX];
2727 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01002728 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01002729 int status;
2730 struct gtp0_header *pheader;
2731 int version = 0; /* GTP version should be determined from header! */
2732 int fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00002733
Harald Weltebed35df2011-11-02 13:06:18 +01002734 /* TODO: Need strategy of userspace buffering and blocking */
2735 /* Currently read is non-blocking and send is blocking. */
2736 /* This means that the program have to wait for busy send calls... */
jjako52c24142002-12-16 13:33:51 +00002737
Harald Weltebed35df2011-11-02 13:06:18 +01002738 while (1) { /* Loop until no more to read */
2739 if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) {
2740 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2741 return -1;
2742 }
2743 peerlen = sizeof(peer);
2744 if ((status =
2745 recvfrom(gsn->fd0, buffer, sizeof(buffer), 0,
2746 (struct sockaddr *)&peer, &peerlen)) < 0) {
2747 if (errno == EAGAIN)
2748 return 0;
2749 gsn->err_readfrom++;
2750 gtp_err(LOG_ERR, __FILE__, __LINE__,
2751 "recvfrom(fd0=%d, buffer=%lx, len=%d) failed: status = %d error = %s",
2752 gsn->fd0, (unsigned long)buffer, sizeof(buffer),
2753 status, status ? strerror(errno) : "No error");
2754 return -1;
2755 }
jjako1db1c812003-07-06 20:53:57 +00002756
Harald Weltebed35df2011-11-02 13:06:18 +01002757 /* Need at least 1 byte in order to check version */
2758 if (status < (1)) {
2759 gsn->empty++;
2760 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2761 status, "Discarding packet - too small");
2762 continue;
2763 }
jjako08d331d2003-10-13 20:33:30 +00002764
Harald Weltebed35df2011-11-02 13:06:18 +01002765 pheader = (struct gtp0_header *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00002766
Harald Weltebed35df2011-11-02 13:06:18 +01002767 /* Version should be gtp0 (or earlier) */
2768 /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
2769 /* GTP 0 messages. If other version message is received we reply that we */
2770 /* only support version 0, implying that this is the only version */
2771 /* supported on this port */
2772 if (((pheader->flags & 0xe0) > 0x00)) {
2773 gsn->unsup++;
2774 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2775 status, "Unsupported GTP version");
2776 gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */
2777 continue;
2778 }
2779
2780 /* Check length of gtp0 packet */
2781 if (status < GTP0_HEADER_SIZE) {
2782 gsn->tooshort++;
2783 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2784 status, "GTP0 packet too short");
2785 continue; /* Silently discard 29.60: 11.1.2 */
2786 }
2787
2788 /* Check packet length field versus length of packet */
2789 if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
2790 gsn->tooshort++;
2791 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2792 status,
2793 "GTP packet length field does not match actual length");
2794 continue; /* Silently discard */
2795 }
2796
2797 if ((gsn->mode == GTP_MODE_GGSN) &&
2798 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2799 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2800 (pheader->type == GTP_DELETE_PDP_RSP))) {
2801 gsn->unexpect++;
2802 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2803 status,
2804 "Unexpected GTP Signalling Message");
2805 continue; /* Silently discard 29.60: 11.1.4 */
2806 }
2807
2808 if ((gsn->mode == GTP_MODE_SGSN) &&
2809 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2810 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2811 (pheader->type == GTP_DELETE_PDP_REQ))) {
2812 gsn->unexpect++;
2813 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2814 status,
2815 "Unexpected GTP Signalling Message");
2816 continue; /* Silently discard 29.60: 11.1.4 */
2817 }
2818
2819 switch (pheader->type) {
2820 case GTP_ECHO_REQ:
2821 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2822 break;
2823 case GTP_ECHO_RSP:
2824 gtp_echo_conf(gsn, version, &peer, buffer, status);
2825 break;
2826 case GTP_NOT_SUPPORTED:
2827 gtp_unsup_ind(gsn, &peer, buffer, status);
2828 break;
2829 case GTP_CREATE_PDP_REQ:
2830 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer,
2831 status);
2832 break;
2833 case GTP_CREATE_PDP_RSP:
2834 gtp_create_pdp_conf(gsn, version, &peer, buffer,
2835 status);
2836 break;
2837 case GTP_UPDATE_PDP_REQ:
2838 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer,
2839 status);
2840 break;
2841 case GTP_UPDATE_PDP_RSP:
2842 gtp_update_pdp_conf(gsn, version, &peer, buffer,
2843 status);
2844 break;
2845 case GTP_DELETE_PDP_REQ:
2846 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer,
2847 status);
2848 break;
2849 case GTP_DELETE_PDP_RSP:
2850 gtp_delete_pdp_conf(gsn, version, &peer, buffer,
2851 status);
2852 break;
2853 case GTP_ERROR:
2854 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2855 break;
2856 case GTP_GPDU:
2857 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2858 break;
2859 default:
2860 gsn->unknown++;
2861 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2862 status,
2863 "Unknown GTP message type received");
2864 break;
2865 }
2866 }
jjako08d331d2003-10-13 20:33:30 +00002867}
2868
jjako08d331d2003-10-13 20:33:30 +00002869int gtp_decaps1c(struct gsn_t *gsn)
2870{
Harald Weltebed35df2011-11-02 13:06:18 +01002871 unsigned char buffer[PACKET_MAX];
2872 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01002873 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01002874 int status;
2875 struct gtp1_header_short *pheader;
2876 int version = 1; /* TODO GTP version should be determined from header! */
2877 int fd = gsn->fd1c;
jjako08d331d2003-10-13 20:33:30 +00002878
Harald Weltebed35df2011-11-02 13:06:18 +01002879 /* TODO: Need strategy of userspace buffering and blocking */
2880 /* Currently read is non-blocking and send is blocking. */
2881 /* This means that the program have to wait for busy send calls... */
jjako08d331d2003-10-13 20:33:30 +00002882
Harald Weltebed35df2011-11-02 13:06:18 +01002883 while (1) { /* Loop until no more to read */
2884 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
2885 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2886 return -1;
2887 }
2888 peerlen = sizeof(peer);
2889 if ((status =
2890 recvfrom(fd, buffer, sizeof(buffer), 0,
2891 (struct sockaddr *)&peer, &peerlen)) < 0) {
2892 if (errno == EAGAIN)
2893 return 0;
2894 gsn->err_readfrom++;
2895 gtp_err(LOG_ERR, __FILE__, __LINE__,
2896 "recvfrom(fd=%d, buffer=%lx, len=%d) failed: status = %d error = %s",
2897 fd, (unsigned long)buffer, sizeof(buffer),
2898 status, status ? strerror(errno) : "No error");
2899 return -1;
2900 }
jjako08d331d2003-10-13 20:33:30 +00002901
Harald Weltebed35df2011-11-02 13:06:18 +01002902 /* Need at least 1 byte in order to check version */
2903 if (status < (1)) {
2904 gsn->empty++;
2905 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2906 status, "Discarding packet - too small");
2907 continue;
2908 }
jjako08d331d2003-10-13 20:33:30 +00002909
Harald Weltebed35df2011-11-02 13:06:18 +01002910 pheader = (struct gtp1_header_short *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00002911
Harald Weltebed35df2011-11-02 13:06:18 +01002912 /* Version must be no larger than GTP 1 */
2913 if (((pheader->flags & 0xe0) > 0x20)) {
2914 gsn->unsup++;
2915 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2916 status, "Unsupported GTP version");
2917 gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
2918 /*29.60: 11.1.1 */
2919 continue;
2920 }
jjako08d331d2003-10-13 20:33:30 +00002921
Harald Weltebed35df2011-11-02 13:06:18 +01002922 /* Version must be at least GTP 1 */
2923 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2924 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2925 /* the message */
2926 if (((pheader->flags & 0xe0) < 0x20)) {
2927 gsn->unsup++;
2928 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2929 status, "Unsupported GTP version");
2930 continue;
2931 }
jjako08d331d2003-10-13 20:33:30 +00002932
Harald Weltebed35df2011-11-02 13:06:18 +01002933 /* Check packet flag field */
2934 if (((pheader->flags & 0xf7) != 0x32)) {
2935 gsn->unsup++;
2936 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2937 status, "Unsupported packet flag");
2938 continue;
2939 }
jjako2c381332003-10-21 19:09:53 +00002940
Harald Weltebed35df2011-11-02 13:06:18 +01002941 /* Check length of packet */
2942 if (status < GTP1_HEADER_SIZE_LONG) {
2943 gsn->tooshort++;
2944 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2945 status, "GTP packet too short");
2946 continue; /* Silently discard 29.60: 11.1.2 */
2947 }
jjako2c381332003-10-21 19:09:53 +00002948
Harald Weltebed35df2011-11-02 13:06:18 +01002949 /* Check packet length field versus length of packet */
2950 if (status !=
2951 (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
2952 gsn->tooshort++;
2953 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2954 status,
2955 "GTP packet length field does not match actual length");
2956 continue; /* Silently discard */
2957 }
jjako1db1c812003-07-06 20:53:57 +00002958
Harald Weltebed35df2011-11-02 13:06:18 +01002959 /* Check for extension headers */
2960 /* TODO: We really should cycle through the headers and determine */
2961 /* if any have the comprehension required flag set */
2962 if (((pheader->flags & 0x04) != 0x00)) {
2963 gsn->unsup++;
2964 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2965 status, "Unsupported extension header");
2966 gtp_extheader_req(gsn, version, &peer, fd, buffer,
2967 status);
jjako1db1c812003-07-06 20:53:57 +00002968
Harald Weltebed35df2011-11-02 13:06:18 +01002969 continue;
2970 }
2971
2972 if ((gsn->mode == GTP_MODE_GGSN) &&
2973 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2974 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2975 (pheader->type == GTP_DELETE_PDP_RSP))) {
2976 gsn->unexpect++;
2977 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2978 status,
2979 "Unexpected GTP Signalling Message");
2980 continue; /* Silently discard 29.60: 11.1.4 */
2981 }
2982
2983 if ((gsn->mode == GTP_MODE_SGSN) &&
2984 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2985 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2986 (pheader->type == GTP_DELETE_PDP_REQ))) {
2987 gsn->unexpect++;
2988 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
2989 status,
2990 "Unexpected GTP Signalling Message");
2991 continue; /* Silently discard 29.60: 11.1.4 */
2992 }
2993
2994 switch (pheader->type) {
2995 case GTP_ECHO_REQ:
2996 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2997 break;
2998 case GTP_ECHO_RSP:
2999 gtp_echo_conf(gsn, version, &peer, buffer, status);
3000 break;
3001 case GTP_NOT_SUPPORTED:
3002 gtp_unsup_ind(gsn, &peer, buffer, status);
3003 break;
3004 case GTP_SUPP_EXT_HEADER:
3005 gtp_extheader_ind(gsn, &peer, buffer, status);
3006 break;
3007 case GTP_CREATE_PDP_REQ:
3008 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer,
3009 status);
3010 break;
3011 case GTP_CREATE_PDP_RSP:
3012 gtp_create_pdp_conf(gsn, version, &peer, buffer,
3013 status);
3014 break;
3015 case GTP_UPDATE_PDP_REQ:
3016 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer,
3017 status);
3018 break;
3019 case GTP_UPDATE_PDP_RSP:
3020 gtp_update_pdp_conf(gsn, version, &peer, buffer,
3021 status);
3022 break;
3023 case GTP_DELETE_PDP_REQ:
3024 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer,
3025 status);
3026 break;
3027 case GTP_DELETE_PDP_RSP:
3028 gtp_delete_pdp_conf(gsn, version, &peer, buffer,
3029 status);
3030 break;
3031 case GTP_ERROR:
3032 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
3033 break;
3034 default:
3035 gsn->unknown++;
3036 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3037 status,
3038 "Unknown GTP message type received");
3039 break;
3040 }
3041 }
jjako52c24142002-12-16 13:33:51 +00003042}
3043
jjako08d331d2003-10-13 20:33:30 +00003044int gtp_decaps1u(struct gsn_t *gsn)
3045{
Harald Weltebed35df2011-11-02 13:06:18 +01003046 unsigned char buffer[PACKET_MAX];
3047 struct sockaddr_in peer;
Harald Welted88e11d2011-11-02 13:09:43 +01003048 socklen_t peerlen;
Harald Weltebed35df2011-11-02 13:06:18 +01003049 int status;
3050 struct gtp1_header_short *pheader;
3051 int version = 1; /* GTP version should be determined from header! */
3052 int fd = gsn->fd1u;
jjako08d331d2003-10-13 20:33:30 +00003053
Harald Weltebed35df2011-11-02 13:06:18 +01003054 /* TODO: Need strategy of userspace buffering and blocking */
3055 /* Currently read is non-blocking and send is blocking. */
3056 /* This means that the program have to wait for busy send calls... */
jjako08d331d2003-10-13 20:33:30 +00003057
Harald Weltebed35df2011-11-02 13:06:18 +01003058 while (1) { /* Loop until no more to read */
3059 if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) {
3060 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
3061 return -1;
3062 }
3063 peerlen = sizeof(peer);
3064 if ((status =
3065 recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0,
3066 (struct sockaddr *)&peer, &peerlen)) < 0) {
3067 if (errno == EAGAIN)
3068 return 0;
3069 gsn->err_readfrom++;
3070 gtp_err(LOG_ERR, __FILE__, __LINE__,
3071 "recvfrom(fd1u=%d, buffer=%lx, len=%d) failed: status = %d error = %s",
3072 gsn->fd1u, (unsigned long)buffer,
3073 sizeof(buffer), status,
3074 status ? strerror(errno) : "No error");
3075 return -1;
3076 }
jjako08d331d2003-10-13 20:33:30 +00003077
Harald Weltebed35df2011-11-02 13:06:18 +01003078 /* Need at least 1 byte in order to check version */
3079 if (status < (1)) {
3080 gsn->empty++;
3081 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3082 status, "Discarding packet - too small");
3083 continue;
3084 }
jjako08d331d2003-10-13 20:33:30 +00003085
Harald Weltebed35df2011-11-02 13:06:18 +01003086 pheader = (struct gtp1_header_short *)(buffer);
jjako08d331d2003-10-13 20:33:30 +00003087
Harald Weltebed35df2011-11-02 13:06:18 +01003088 /* Version must be no larger than GTP 1 */
3089 if (((pheader->flags & 0xe0) > 0x20)) {
3090 gsn->unsup++;
3091 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3092 status, "Unsupported GTP version");
3093 gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status); /*29.60: 11.1.1 */
3094 continue;
3095 }
jjako08d331d2003-10-13 20:33:30 +00003096
Harald Weltebed35df2011-11-02 13:06:18 +01003097 /* Version must be at least GTP 1 */
3098 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
3099 /* GTP 1 messages. If GTP 0 message is received we silently discard */
3100 /* the message */
3101 if (((pheader->flags & 0xe0) < 0x20)) {
3102 gsn->unsup++;
3103 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3104 status, "Unsupported GTP version");
3105 continue;
3106 }
jjako2c381332003-10-21 19:09:53 +00003107
Harald Weltebed35df2011-11-02 13:06:18 +01003108 /* Check packet flag field (allow both with and without sequence number) */
3109 if (((pheader->flags & 0xf5) != 0x30)) {
3110 gsn->unsup++;
3111 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3112 status, "Unsupported packet flag");
3113 continue;
3114 }
jjako2c381332003-10-21 19:09:53 +00003115
Harald Weltebed35df2011-11-02 13:06:18 +01003116 /* Check length of packet */
3117 if (status < GTP1_HEADER_SIZE_SHORT) {
3118 gsn->tooshort++;
3119 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3120 status, "GTP packet too short");
3121 continue; /* Silently discard 29.60: 11.1.2 */
3122 }
3123
3124 /* Check packet length field versus length of packet */
3125 if (status !=
3126 (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
3127 gsn->tooshort++;
3128 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3129 status,
3130 "GTP packet length field does not match actual length");
3131 continue; /* Silently discard */
3132 }
3133
3134 /* Check for extension headers */
3135 /* TODO: We really should cycle through the headers and determine */
3136 /* if any have the comprehension required flag set */
3137 if (((pheader->flags & 0x04) != 0x00)) {
3138 gsn->unsup++;
3139 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3140 status, "Unsupported extension header");
3141 gtp_extheader_req(gsn, version, &peer, fd, buffer,
3142 status);
3143
3144 continue;
3145 }
3146
3147 switch (pheader->type) {
3148 case GTP_ECHO_REQ:
3149 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
3150 break;
3151 case GTP_ECHO_RSP:
3152 gtp_echo_conf(gsn, version, &peer, buffer, status);
3153 break;
3154 case GTP_SUPP_EXT_HEADER:
3155 gtp_extheader_ind(gsn, &peer, buffer, status);
3156 break;
3157 case GTP_ERROR:
3158 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
3159 break;
3160 /* Supported header extensions */
3161 case GTP_GPDU:
3162 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
3163 break;
3164 default:
3165 gsn->unknown++;
3166 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
3167 status,
3168 "Unknown GTP message type received");
3169 break;
3170 }
3171 }
jjako08d331d2003-10-13 20:33:30 +00003172}
3173
Harald Weltebed35df2011-11-02 13:06:18 +01003174int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +00003175{
Harald Weltebed35df2011-11-02 13:06:18 +01003176 union gtp_packet packet;
3177 struct sockaddr_in addr;
3178 int fd;
3179 int length;
jjako52c24142002-12-16 13:33:51 +00003180
Harald Weltebed35df2011-11-02 13:06:18 +01003181 memset(&addr, 0, sizeof(addr));
3182 addr.sin_family = AF_INET;
jjako0fe0df02004-09-17 11:30:40 +00003183#if defined(__FreeBSD__) || defined(__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +01003184 addr.sin_len = sizeof(addr);
jjako06e9f122004-01-19 18:37:58 +00003185#endif
3186
Harald Weltebed35df2011-11-02 13:06:18 +01003187 memcpy(&addr.sin_addr, pdp->gsnru.v, pdp->gsnru.l); /* TODO range check */
jjako52c24142002-12-16 13:33:51 +00003188
Harald Weltebed35df2011-11-02 13:06:18 +01003189 if (pdp->version == 0) {
jjako52c24142002-12-16 13:33:51 +00003190
Harald Weltebed35df2011-11-02 13:06:18 +01003191 length = GTP0_HEADER_SIZE + len;
3192 addr.sin_port = htons(GTP0_PORT);
3193 fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00003194
Harald Weltebed35df2011-11-02 13:06:18 +01003195 get_default_gtp(0, GTP_GPDU, &packet);
3196 packet.gtp0.h.length = hton16(len);
3197 packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
3198 packet.gtp0.h.flow = hton16(pdp->flru);
3199 packet.gtp0.h.tid =
3200 (pdp->imsi & 0x0fffffffffffffffull) +
3201 ((uint64_t) pdp->nsapi << 60);
jjako08d331d2003-10-13 20:33:30 +00003202
Harald Weltebed35df2011-11-02 13:06:18 +01003203 if (len > sizeof(union gtp_packet) - sizeof(struct gtp0_header)) {
3204 gsn->err_memcpy++;
3205 gtp_err(LOG_ERR, __FILE__, __LINE__,
3206 "Memcpy failed: %d > %d", len,
3207 sizeof(union gtp_packet) -
3208 sizeof(struct gtp0_header));
3209 return EOF;
3210 }
3211 memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */
3212 } else if (pdp->version == 1) {
jjako08d331d2003-10-13 20:33:30 +00003213
Harald Weltebed35df2011-11-02 13:06:18 +01003214 length = GTP1_HEADER_SIZE_LONG + len;
3215 addr.sin_port = htons(GTP1U_PORT);
3216 fd = gsn->fd1u;
jjakoa7cd2492003-04-11 09:40:12 +00003217
Harald Weltebed35df2011-11-02 13:06:18 +01003218 get_default_gtp(1, GTP_GPDU, &packet);
3219 packet.gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT +
3220 GTP1_HEADER_SIZE_LONG);
3221 packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
3222 packet.gtp1l.h.tei = hton32(pdp->teid_gn);
3223
3224 if (len >
3225 sizeof(union gtp_packet) -
3226 sizeof(struct gtp1_header_long)) {
3227 gsn->err_memcpy++;
3228 gtp_err(LOG_ERR, __FILE__, __LINE__,
3229 "Memcpy failed: %d > %d", len,
3230 sizeof(union gtp_packet) -
3231 sizeof(struct gtp0_header));
3232 return EOF;
3233 }
3234 memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */
3235 } else {
3236 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
3237 return EOF;
3238 }
3239
3240 if (fcntl(fd, F_SETFL, 0)) {
3241 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
3242 return -1;
3243 }
3244
3245 if (sendto(fd, &packet, length, 0,
3246 (struct sockaddr *)&addr, sizeof(addr)) < 0) {
3247 gsn->err_sendto++;
3248 gtp_err(LOG_ERR, __FILE__, __LINE__,
3249 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
3250 (unsigned long)&packet, GTP0_HEADER_SIZE + len,
3251 strerror(errno));
3252 return EOF;
3253 }
3254 return 0;
jjako52c24142002-12-16 13:33:51 +00003255}
3256
jjako52c24142002-12-16 13:33:51 +00003257/* ***********************************************************
3258 * Conversion functions
3259 *************************************************************/
3260
Harald Weltebed35df2011-11-02 13:06:18 +01003261int char2ul_t(char *src, struct ul_t dst)
3262{
3263 dst.l = strlen(src) + 1;
3264 dst.v = malloc(dst.l);
3265 dst.v[0] = dst.l - 1;
3266 memcpy(&dst.v[1], src, dst.v[0]);
3267 return 0;
jjako52c24142002-12-16 13:33:51 +00003268}
3269
3270/* ***********************************************************
3271 * IP address conversion functions
3272 * There exist several types of address representations:
3273 * - eua: End User Address. (29.060, 7.7.27, message type 128)
3274 * Used for signalling address to mobile station. Supports IPv4
3275 * IPv6 x.25 etc. etc.
3276 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
3277 * of GSN. If length is 4 it is IPv4. If length is 16 it is IPv6.
3278 * - in_addr: IPv4 address struct.
3279 * - sockaddr_in: Socket API representation of IP address and
3280 * port number.
3281 *************************************************************/
3282
Harald Weltebed35df2011-11-02 13:06:18 +01003283int ipv42eua(struct ul66_t *eua, struct in_addr *src)
3284{
3285 eua->v[0] = 0xf1; /* IETF */
3286 eua->v[1] = 0x21; /* IPv4 */
3287 if (src) {
3288 eua->l = 6;
3289 memcpy(&eua->v[2], src, 4);
3290 } else {
3291 eua->l = 2;
3292 }
3293 return 0;
jjako52c24142002-12-16 13:33:51 +00003294}
3295
Harald Weltebed35df2011-11-02 13:06:18 +01003296int eua2ipv4(struct in_addr *dst, struct ul66_t *eua)
3297{
3298 if ((eua->l != 6) || (eua->v[0] != 0xf1) || (eua->v[1] = 0x21))
3299 return -1; /* Not IPv4 address */
3300 memcpy(dst, &eua->v[2], 4);
3301 return 0;
jjako52c24142002-12-16 13:33:51 +00003302}
3303
Harald Weltebed35df2011-11-02 13:06:18 +01003304int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna)
3305{
3306 memset(dst, 0, sizeof(struct in_addr));
3307 if (gsna->l != 4)
3308 return EOF; /* Return if not IPv4 */
3309 memcpy(dst, gsna->v, gsna->l);
3310 return 0;
jjako52c24142002-12-16 13:33:51 +00003311}
3312
Harald Weltebed35df2011-11-02 13:06:18 +01003313int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src)
3314{
3315 memset(gsna, 0, sizeof(struct ul16_t));
3316 gsna->l = 4;
3317 memcpy(gsna->v, src, gsna->l);
3318 return 0;
jjako52c24142002-12-16 13:33:51 +00003319}