blob: 111168b178c6763ae8ed9a1ea1ad3f7707331eb6 [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
20
21#ifdef __linux__
22#define _GNU_SOURCE 1
23#endif
24
jjako0fe0df02004-09-17 11:30:40 +000025#include "../config.h"
26#ifdef HAVE_STDINT_H
27#include <stdint.h>
28#endif
jjako52c24142002-12-16 13:33:51 +000029
30#include <syslog.h>
31#include <stdio.h>
32#include <stdarg.h>
33#include <stdlib.h>
34#include <sys/time.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#include <sys/stat.h>
40#include <time.h>
41#include <unistd.h>
42#include <string.h>
43#include <errno.h>
44#include <fcntl.h>
45
46#include <arpa/inet.h>
47
jjakobae2cd42004-01-09 12:04:39 +000048/* #include <stdint.h> ISO C99 types */
jjako52c24142002-12-16 13:33:51 +000049
50#include "pdp.h"
51#include "gtp.h"
52#include "gtpie.h"
53#include "queue.h"
54
jjako1db1c812003-07-06 20:53:57 +000055
56/* Error reporting functions */
57
58void gtp_err(int priority, char *filename, int linenum, char *fmt, ...) {
59 va_list args;
60 char buf[ERRMSG_SIZE];
61
62 va_start(args, fmt);
63 vsnprintf(buf, ERRMSG_SIZE, fmt, args);
64 va_end(args);
65 buf[ERRMSG_SIZE-1] = 0;
66 syslog(priority, "%s: %d: %s", filename, linenum, buf);
67}
68
69void gtp_errpack(int pri, char *fn, int ln, struct sockaddr_in *peer,
70 void *pack, unsigned len, char *fmt, ...) {
71
72 va_list args;
73 char buf[ERRMSG_SIZE];
74 char buf2[ERRMSG_SIZE];
Harald Weltef54a1f42010-05-04 11:08:38 +020075 unsigned int n;
jjako1db1c812003-07-06 20:53:57 +000076 int pos;
77
78 va_start(args, fmt);
79 vsnprintf(buf, ERRMSG_SIZE, fmt, args);
80 va_end(args);
81 buf[ERRMSG_SIZE-1] = 0;
82
83 snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:",
84 inet_ntoa(peer->sin_addr),
85 ntohs(peer->sin_port),
86 len);
87 buf2[ERRMSG_SIZE-1] = 0;
88 pos = strlen(buf2);
89 for(n=0; n<len; n++) {
90 if ((pos+4)<ERRMSG_SIZE) {
91 sprintf((buf2+pos), " %02hhx", ((unsigned char*)pack)[n]);
92 pos += 3;
93 }
94 }
95 buf2[pos] = 0;
96
97 syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
98
99}
100
101
102
103
jjako52c24142002-12-16 13:33:51 +0000104/* API Functions */
105
106const char* gtp_version()
107{
108 return VERSION;
109}
110
111/* gtp_new */
112/* gtp_free */
113
114int gtp_newpdp(struct gsn_t* gsn, struct pdp_t **pdp,
115 uint64_t imsi, uint8_t nsapi) {
116 return pdp_newpdp(pdp, imsi, nsapi, NULL);
117}
118
119int gtp_freepdp(struct gsn_t* gsn, struct pdp_t *pdp) {
120 return pdp_freepdp(pdp);
121}
122
jjako52c24142002-12-16 13:33:51 +0000123/* gtp_gpdu */
124
125extern int gtp_fd(struct gsn_t *gsn) {
jjako08d331d2003-10-13 20:33:30 +0000126 return gsn->fd0;
jjako52c24142002-12-16 13:33:51 +0000127}
128
129/* gtp_decaps */
130/* gtp_retrans */
131/* gtp_retranstimeout */
132
jjako08d331d2003-10-13 20:33:30 +0000133
134int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
135 int (*cb) (struct sockaddr_in *peer)) {
136 gsn->cb_unsup_ind = cb;
137 return 0;
138}
139
jjako2c381332003-10-21 19:09:53 +0000140int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
141 int (*cb) (struct sockaddr_in *peer)) {
142 gsn->cb_extheader_ind = cb;
143 return 0;
144}
145
jjako08d331d2003-10-13 20:33:30 +0000146
147/* API: Initialise delete context callback */
148/* Called whenever a pdp context is deleted for any reason */
jjako52c24142002-12-16 13:33:51 +0000149int gtp_set_cb_delete_context(struct gsn_t *gsn,
jjako08d331d2003-10-13 20:33:30 +0000150 int (*cb) (struct pdp_t* pdp))
jjako52c24142002-12-16 13:33:51 +0000151{
jjako08d331d2003-10-13 20:33:30 +0000152 gsn->cb_delete_context = cb;
jjako52c24142002-12-16 13:33:51 +0000153 return 0;
154}
155
jjako52c24142002-12-16 13:33:51 +0000156int gtp_set_cb_conf(struct gsn_t *gsn,
157 int (*cb) (int type, int cause,
jjako08d331d2003-10-13 20:33:30 +0000158 struct pdp_t* pdp, void *cbp)) {
jjako52c24142002-12-16 13:33:51 +0000159 gsn->cb_conf = cb;
160 return 0;
161}
162
Harald Welte629e9862010-12-24 20:58:09 +0100163int gtp_set_cb_recovery(struct gsn_t *gsn,
164 int (*cb) (struct sockaddr_in *peer,
165 uint8_t recovery)) {
166 gsn->cb_recovery = cb;
167 return 0;
168}
169
jjako08d331d2003-10-13 20:33:30 +0000170extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
171 int (*cb_data_ind) (struct pdp_t* pdp,
jjako52c24142002-12-16 13:33:51 +0000172 void* pack,
173 unsigned len))
174{
jjako08d331d2003-10-13 20:33:30 +0000175 gsn->cb_data_ind = cb_data_ind;
jjako52c24142002-12-16 13:33:51 +0000176 return 0;
177}
178
jjako08d331d2003-10-13 20:33:30 +0000179/**
180 * get_default_gtp()
181 * Generate a GPRS Tunneling Protocol signalling packet header, depending
182 * on GTP version and message type. pdp is used for teid/flow label.
183 * *packet must be allocated by the calling function, and be large enough
184 * to hold the packet header.
185 * returns the length of the header. 0 on error.
186 **/
Harald Weltef54a1f42010-05-04 11:08:38 +0200187static unsigned int get_default_gtp(int version, uint8_t type, void *packet) {
jjakoa7cd2492003-04-11 09:40:12 +0000188 struct gtp0_header *gtp0_default = (struct gtp0_header*) packet;
189 struct gtp1_header_long *gtp1_default = (struct gtp1_header_long*) packet;
jjako52c24142002-12-16 13:33:51 +0000190 switch (version) {
191 case 0:
jjakoa7cd2492003-04-11 09:40:12 +0000192 /* Initialise "standard" GTP0 header */
jjako08d331d2003-10-13 20:33:30 +0000193 memset(gtp0_default, 0, sizeof(struct gtp0_header));
jjakoa7cd2492003-04-11 09:40:12 +0000194 gtp0_default->flags=0x1e;
jjako08d331d2003-10-13 20:33:30 +0000195 gtp0_default->type=hton8(type);
jjakoa7cd2492003-04-11 09:40:12 +0000196 gtp0_default->spare1=0xff;
197 gtp0_default->spare2=0xff;
198 gtp0_default->spare3=0xff;
199 gtp0_default->number=0xff;
jjako08d331d2003-10-13 20:33:30 +0000200 return GTP0_HEADER_SIZE;
jjako52c24142002-12-16 13:33:51 +0000201 case 1:
jjakoa7cd2492003-04-11 09:40:12 +0000202 /* Initialise "standard" GTP1 header */
jjako08d331d2003-10-13 20:33:30 +0000203 /* 29.060: 8.2: S=1 and PN=0 */
204 /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */
205 /* and Supported Extension Headers Notification, the S field shall be */
206 /* set to 1 */
207 /* Currently extension headers are not supported */
208 memset(gtp1_default, 0, sizeof(struct gtp1_header_long));
209 gtp1_default->flags=0x32; /* No extension, enable sequence, no N-PDU */
210 gtp1_default->type=hton8(type);
211 return GTP1_HEADER_SIZE_LONG;
212 default:
213 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown GTP packet version");
214 return 0;
jjako52c24142002-12-16 13:33:51 +0000215 }
216}
217
jjako08d331d2003-10-13 20:33:30 +0000218/**
219 * get_seq()
220 * Get sequence number of a packet.
221 * Returns 0 on error
222 **/
223static uint16_t get_seq(void *pack) {
224 union gtp_packet *packet = (union gtp_packet *) pack;
225
226 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
227 return ntoh16(packet->gtp0.h.seq);
228 }
229 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
230 return ntoh16(packet->gtp1l.h.seq);
231 } else {
232 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
233 return 0;
234 }
235}
236
237/**
238 * get_tid()
239 * Get tunnel identifier of a packet.
240 * Returns 0 on error
241 **/
242static uint64_t get_tid(void *pack) {
243 union gtp_packet *packet = (union gtp_packet *) pack;
244
245 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
246 return packet->gtp0.h.tid;
247 }
248 return 0;
249}
250
251/**
252 * get_hlen()
253 * Get the header length of a packet.
254 * Returns 0 on error
255 **/
256static uint16_t get_hlen(void *pack) {
257 union gtp_packet *packet = (union gtp_packet *) pack;
258
259 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
260 return GTP0_HEADER_SIZE;
261 }
262 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
263 return GTP1_HEADER_SIZE_LONG;
264 }
265 else if ((packet->flags & 0xe7) == 0x20) { /* Short version 1 */
266 return GTP1_HEADER_SIZE_SHORT;
267 } else {
268 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
269 return 0;
270 }
271}
272
273/**
274 * get_tei()
275 * Get the tunnel endpoint identifier (flow label) of a packet.
276 * Returns 0xffffffff on error.
277 **/
278static uint32_t get_tei(void *pack) {
279 union gtp_packet *packet = (union gtp_packet *) pack;
280
281 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
282 return ntoh16(packet->gtp0.h.flow);
283 }
284 else if ((packet->flags & 0xe0) == 0x20) { /* Version 1 */
285 return ntoh32(packet->gtp1l.h.tei);
286 }
287 else {
288 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
289 return 0xffffffff;
290 }
291}
jjakoa7cd2492003-04-11 09:40:12 +0000292
293
jjako52c24142002-12-16 13:33:51 +0000294int print_packet(void *packet, unsigned len)
295{
Harald Weltef54a1f42010-05-04 11:08:38 +0200296 unsigned int i;
jjako52c24142002-12-16 13:33:51 +0000297 printf("The packet looks like this (%d bytes):\n", len);
298 for( i=0; i<len; i++) {
299 printf("%02x ", (unsigned char)*(char *)(packet+i));
300 if (!((i+1)%16)) printf("\n");
301 };
302 printf("\n");
303 return 0;
304}
305
306char* snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer,
307 void *pack, unsigned len, char *buf, int size) {
Harald Weltef54a1f42010-05-04 11:08:38 +0200308 unsigned int n;
jjako52c24142002-12-16 13:33:51 +0000309 int pos;
310 snprintf(buf, size, "Packet from %s:%u, length: %d, content:",
311 inet_ntoa(peer->sin_addr),
312 ntohs(peer->sin_port),
313 len);
jjako2e840a32003-01-28 16:05:18 +0000314 buf[size-1] = 0;
jjako52c24142002-12-16 13:33:51 +0000315 pos = strlen(buf);
316 for(n=0; n<len; n++) {
317 if ((pos+4)<size) {
318 sprintf((buf+pos), " %02hhx", ((unsigned char*)pack)[n]);
319 pos += 3;
320 }
321 }
322 buf[pos] = 0;
323 return buf;
324}
325
jjako52c24142002-12-16 13:33:51 +0000326
327/* ***********************************************************
328 * Reliable delivery of signalling messages
329 *
330 * Sequence numbers are used for both signalling messages and
331 * data messages.
332 *
333 * For data messages each tunnel maintains a sequence counter,
334 * which is incremented by one each time a new data message
335 * is sent. The sequence number starts at (0) zero at tunnel
336 * establishment, and wraps around at 65535 (29.060 9.3.1.1
337 * and 09.60 8.1.1.1). The sequence numbers are either ignored,
338 * or can be used to check the validity of the message in the
339 * receiver, or for reordering af packets.
340 *
341 * For signalling messages the sequence number is used by
342 * signalling messages for which a response is defined. A response
343 * message should copy the sequence from the corresponding request
344 * message. The sequence number "unambiguously" identifies a request
345 * message within a given path, with a path being defined as a set of
346 * two endpoints (29.060 8.2, 29.060 7.6, 09.60 7.8). "All request
347 * messages shall be responded to, and all response messages associated
348 * with a certain request shall always include the same information"
349 *
350 * We take this to mean that the GSN transmitting a request is free to
351 * choose the sequence number, as long as it is unique within a given path.
352 * It means that we are allowed to count backwards, or roll over at 17
353 * if we prefer that. It also means that we can use the same counter for
354 * all paths. This has the advantage that the transmitted request sequence
355 * numbers are unique within each GSN, and also we dont have to mess around
356 * with path setup and teardown.
357 *
358 * If a response message is lost, the request will be retransmitted, and
359 * the receiving GSN will receive a "duplicated" request. The standard
360 * requires the receiving GSN to send a response, with the same information
361 * as in the original response. For most messages this happens automatically:
362 *
363 * Echo: Automatically dublicates the original response
364 * Create pdp context: The SGSN may send create context request even if
365 * a context allready exist (imsi+nsapi?). This means that the reply will
366 automatically dublicate the original response. It might however have
jjako08d331d2003-10-13 20:33:30 +0000367 * side effects in the application which is asked twice to validate
368 * the login.
jjako52c24142002-12-16 13:33:51 +0000369 * Update pdp context: Automatically dublicates the original response???
370 * Delete pdp context. Automatically in gtp0, but in gtp1 will generate
371 * a nonexist reply message.
372 *
373 * The correct solution will be to make a queue containing response messages.
374 * This queue should be checked whenever a request is received. If the
375 * response is allready in the queue that response should be transmitted.
376 * It should be possible to find messages in this queue on the basis of
377 * the sequence number and peer GSN IP address (The sequense number is unique
378 * within each path). This need to be implemented by a hash table. Furthermore
379 * it should be possibly to delete messages based on a timeout. This can be
380 * achieved by means of a linked list. The timeout value need to be larger
381 * than T3-RESPONSE * N3-REQUESTS (recommended value 5). These timers are
382 * set in the peer GSN, so there is no way to know these parameters. On the
383 * other hand the timeout value need to be so small that we do not receive
384 * wraparound sequence numbere before the message is deleted. 60 seconds is
385 * probably not a bad choise.
386 *
387 * This queue however is first really needed from gtp1.
388 *
389 * gtp_req:
390 * Send off a signalling message with appropiate sequence
391 * number. Store packet in queue.
392 * gtp_conf:
393 * Remove an incoming confirmation from the queue
394 * gtp_resp:
jjako08d331d2003-10-13 20:33:30 +0000395 * Send off a response to a request. Use the same sequence
jjako52c24142002-12-16 13:33:51 +0000396 * number in the response as in the request.
jjako2c381332003-10-21 19:09:53 +0000397 * gtp_notification:
398 * Send off a notification message. This is neither a request nor
399 * a response. Both TEI and SEQ are zero.
jjako52c24142002-12-16 13:33:51 +0000400 * gtp_retrans:
401 * Retransmit any outstanding packets which have exceeded
402 * a predefined timeout.
403 *************************************************************/
404
jjako08d331d2003-10-13 20:33:30 +0000405int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp,
406 union gtp_packet *packet, int len,
407 struct in_addr *inetaddr, void *cbp) {
jjako52c24142002-12-16 13:33:51 +0000408 struct sockaddr_in addr;
409 struct qmsg_t *qmsg;
jjako08d331d2003-10-13 20:33:30 +0000410 int fd;
411
jjako52c24142002-12-16 13:33:51 +0000412 memset(&addr, 0, sizeof(addr));
413 addr.sin_family = AF_INET;
414 addr.sin_addr = *inetaddr;
jjako0fe0df02004-09-17 11:30:40 +0000415#if defined(__FreeBSD__) || defined(__APPLE__)
jjako06e9f122004-01-19 18:37:58 +0000416 addr.sin_len = sizeof(addr);
417#endif
jjako52c24142002-12-16 13:33:51 +0000418
jjako08d331d2003-10-13 20:33:30 +0000419 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
420 addr.sin_port = htons(GTP0_PORT);
421 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
422 packet->gtp0.h.seq = hton16(gsn->seq_next);
423 if (pdp)
jjakod48c5ff2004-01-26 22:25:40 +0000424 packet->gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffffull) +
jjako08d331d2003-10-13 20:33:30 +0000425 ((uint64_t)pdp->nsapi << 60);
426 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
427 (packet->gtp0.h.type == GTP_ERROR)))
428 packet->gtp0.h.flow=hton16(pdp->flru);
429 else if (pdp)
430 packet->gtp0.h.flow=hton16(pdp->flrc);
431 fd = gsn->fd0;
432 }
433 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
434 addr.sin_port = htons(GTP1C_PORT);
435 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
436 packet->gtp1l.h.seq = hton16(gsn->seq_next);
437 if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) ||
438 (packet->gtp1l.h.type == GTP_ERROR)))
439 packet->gtp1l.h.tei=hton32(pdp->teid_gn);
440 else if (pdp)
441 packet->gtp1l.h.tei=hton32(pdp->teic_gn);
442 fd = gsn->fd1c;
443 } else {
444 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
445 return -1;
446 }
jjako52c24142002-12-16 13:33:51 +0000447
jjako08d331d2003-10-13 20:33:30 +0000448 if (sendto(fd, packet, len, 0,
jjako52c24142002-12-16 13:33:51 +0000449 (struct sockaddr *) &addr, sizeof(addr)) < 0) {
450 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000451 gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno));
jjako52c24142002-12-16 13:33:51 +0000452 return -1;
453 }
454
455 /* Use new queue structure */
456 if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) {
457 gsn->err_queuefull++;
458 gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full");
459 }
460 else {
461 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
462 qmsg->l = len;
463 qmsg->timeout = time(NULL) + 3; /* When to timeout */
464 qmsg->retrans = 0; /* No retransmissions so far */
jjako08d331d2003-10-13 20:33:30 +0000465 qmsg->cbp = cbp;
jjako52c24142002-12-16 13:33:51 +0000466 qmsg->type = ntoh8(packet->gtp0.h.type);
jjako08d331d2003-10-13 20:33:30 +0000467 qmsg->fd = fd;
jjako52c24142002-12-16 13:33:51 +0000468 }
469 gsn->seq_next++; /* Count up this time */
470 return 0;
471}
472
473/* gtp_conf
474 * Remove signalling packet from retransmission queue.
475 * return 0 on success, EOF if packet was not found */
476
477int gtp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
jjako08d331d2003-10-13 20:33:30 +0000478 union gtp_packet *packet, int len, uint8_t *type, void **cbp) {
jjako52c24142002-12-16 13:33:51 +0000479
jjako08d331d2003-10-13 20:33:30 +0000480 uint16_t seq;
481
482 if ((packet->gtp0.h.flags & 0xe0) == 0x00)
483 seq = ntoh16(packet->gtp0.h.seq);
484 else if ((packet->gtp1l.h.flags & 0xe2) == 0x22)
485 seq = ntoh16(packet->gtp1l.h.seq);
486 else {
487 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
488 "Unknown GTP packet version");
489 return EOF;
490 }
491
492 if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) {
jjako52c24142002-12-16 13:33:51 +0000493 gsn->err_seq++;
494 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
495 "Confirmation packet not found in queue");
496 return EOF;
497 }
498
499 return 0;
500}
501
502int gtp_retrans(struct gsn_t *gsn) {
503 /* Retransmit any outstanding packets */
504 /* Remove from queue if maxretrans exceeded */
505 time_t now;
506 struct qmsg_t *qmsg;
507 now = time(NULL);
508 /*printf("Retrans: New beginning %d\n", (int) now);*/
509
510 while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
511 (qmsg->timeout <= now)) {
512 /*printf("Retrans timeout found: %d\n", (int) time(NULL));*/
513 if (qmsg->retrans > 3) { /* To many retrans */
jjako08d331d2003-10-13 20:33:30 +0000514 if (gsn->cb_conf) gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
jjako52c24142002-12-16 13:33:51 +0000515 queue_freemsg(gsn->queue_req, qmsg);
516 }
517 else {
jjako08d331d2003-10-13 20:33:30 +0000518 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
jjako52c24142002-12-16 13:33:51 +0000519 (struct sockaddr *) &qmsg->peer, sizeof(struct sockaddr_in)) < 0) {
520 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000521 gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s", gsn->fd0, (unsigned long) &qmsg->p, qmsg->l, strerror(errno));
jjako52c24142002-12-16 13:33:51 +0000522 }
523 queue_back(gsn->queue_req, qmsg);
524 qmsg->timeout = now + 3;
525 qmsg->retrans++;
526 }
527 }
528
529 /* Also clean up reply timeouts */
530 while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
531 (qmsg->timeout < now)) {
532 /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL));*/
533 queue_freemsg(gsn->queue_resp, qmsg);
534 }
535
536 return 0;
537}
538
539int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) {
540 time_t now, later;
541 struct qmsg_t *qmsg;
542
543 if (queue_getfirst(gsn->queue_req, &qmsg)) {
544 timeout->tv_sec = 10;
545 timeout->tv_usec = 0;
546 }
547 else {
548 now = time(NULL);
549 later = qmsg->timeout;
550 timeout->tv_sec = later - now;
551 timeout->tv_usec = 0;
552 if (timeout->tv_sec < 0) timeout->tv_sec = 0; /* No negative allowed */
553 if (timeout->tv_sec > 10) timeout->tv_sec = 10; /* Max sleep for 10 sec*/
554 }
555 return 0;
556}
557
jjako08d331d2003-10-13 20:33:30 +0000558int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp,
559 union gtp_packet *packet, int len,
560 struct sockaddr_in *peer, int fd,
561 uint16_t seq, uint64_t tid) {
jjako52c24142002-12-16 13:33:51 +0000562 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000563
jjako08d331d2003-10-13 20:33:30 +0000564 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
565 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
566 packet->gtp0.h.seq = hton16(seq);
567 packet->gtp0.h.tid = tid;
568 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
569 (packet->gtp0.h.type == GTP_ERROR)))
570 packet->gtp0.h.flow=hton16(pdp->flru);
571 else if (pdp)
572 packet->gtp0.h.flow=hton16(pdp->flrc);
573 }
574 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
575 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
576 packet->gtp1l.h.seq = hton16(seq);
577 if (pdp && (fd == gsn->fd1u))
578 packet->gtp1l.h.tei=hton32(pdp->teid_gn);
579 else if (pdp)
580 packet->gtp1l.h.tei=hton32(pdp->teic_gn);
581 }
582 else {
583 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
jjakoa7cd2492003-04-11 09:40:12 +0000584 return -1;
585 }
jjako52c24142002-12-16 13:33:51 +0000586
jjako08d331d2003-10-13 20:33:30 +0000587 if (fcntl(fd, F_SETFL, 0)) {
588 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
589 return -1;
590 }
591
592 if (sendto(fd, packet, len, 0,
jjako52c24142002-12-16 13:33:51 +0000593 (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
594 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000595 gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno));
jjako52c24142002-12-16 13:33:51 +0000596 return -1;
597 }
598
599 /* Use new queue structure */
600 if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) {
601 gsn->err_queuefull++;
602 gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full");
603 }
604 else {
605 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
606 qmsg->l = len;
607 qmsg->timeout = time(NULL) + 60; /* When to timeout */
608 qmsg->retrans = 0; /* No retransmissions so far */
jjako08d331d2003-10-13 20:33:30 +0000609 qmsg->cbp = NULL;
jjako52c24142002-12-16 13:33:51 +0000610 qmsg->type = 0;
jjako08d331d2003-10-13 20:33:30 +0000611 qmsg->fd = fd;
jjako52c24142002-12-16 13:33:51 +0000612 }
613 return 0;
614}
615
jjako2c381332003-10-21 19:09:53 +0000616int gtp_notification(struct gsn_t *gsn, int version,
617 union gtp_packet *packet, int len,
618 struct sockaddr_in *peer, int fd,
619 uint16_t seq) {
620
621 struct sockaddr_in addr;
622
623 memcpy(&addr, peer, sizeof(addr));
624
625 /* In GTP0 notifications are treated as replies. In GTP1 they
626 are requests for which there is no reply */
627
628 if (fd == gsn->fd1c)
629 addr.sin_port = htons(GTP1C_PORT);
630 else if (fd == gsn->fd1u)
631 addr.sin_port = htons(GTP1C_PORT);
632
633 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
634 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
635 packet->gtp0.h.seq = hton16(seq);
636 }
637 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
638 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
639 packet->gtp1l.h.seq = hton16(seq);
640 }
641 else {
642 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
643 return -1;
644 }
645
646 if (fcntl(fd, F_SETFL, 0)) {
647 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
648 return -1;
649 }
650
651 if (sendto(fd, packet, len, 0,
652 (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) {
653 gsn->err_sendto++;
654 gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno));
655 return -1;
656 }
657 return 0;
658}
659
jjako52c24142002-12-16 13:33:51 +0000660int gtp_dublicate(struct gsn_t *gsn, int version,
661 struct sockaddr_in *peer, uint16_t seq) {
662 struct qmsg_t *qmsg;
663
664 if(queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) {
665 return EOF; /* Notfound */
666 }
jjakoa7cd2492003-04-11 09:40:12 +0000667
jjako08d331d2003-10-13 20:33:30 +0000668 if (fcntl(qmsg->fd, F_SETFL, 0)) {
669 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
670 return -1;
jjako52c24142002-12-16 13:33:51 +0000671 }
jjako08d331d2003-10-13 20:33:30 +0000672
673 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
674 (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
675 gsn->err_sendto++;
676 gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", qmsg->fd, (unsigned long) &qmsg->p, qmsg->l, strerror(errno));
677 }
678 return 0;
jjako52c24142002-12-16 13:33:51 +0000679}
680
681
682
683/* Perform restoration and recovery error handling as described in 29.060 */
684static void log_restart(struct gsn_t *gsn) {
685 FILE *f;
Emmanuel Bretelle111e0542010-09-06 19:49:16 +0200686 int i, rc;
jjako52c24142002-12-16 13:33:51 +0000687 int counter = 0;
688 char filename[NAMESIZE];
689
690 filename[NAMESIZE-1] = 0; /* No null term. guarantee by strncpy */
691 strncpy(filename, gsn->statedir, NAMESIZE-1);
692 strncat(filename, RESTART_FILE,
693 NAMESIZE-1-sizeof(RESTART_FILE));
694
695 i = umask(022);
696
697 /* We try to open file. On failure we will later try to create file */
698 if (!(f = fopen(filename, "r"))) {
jjako581c9f02003-10-22 11:28:20 +0000699
700 gtp_err(LOG_ERR, __FILE__, __LINE__, "State information file (%s) not found. Creating new file.", filename);
jjako52c24142002-12-16 13:33:51 +0000701 }
702 else {
703 umask(i);
Emmanuel Bretelle111e0542010-09-06 19:49:16 +0200704 rc = fscanf(f, "%d", &counter);
705 if (rc != 1) {
706 gtp_err(LOG_ERR, __FILE__, __LINE__, "fscanf failed to read counter value");
707 return;
708 }
jjako52c24142002-12-16 13:33:51 +0000709 if (fclose(f)) {
710 gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno));
711 }
712 }
713
714 gsn->restart_counter = (unsigned char) counter;
715 gsn->restart_counter++;
716
717 if (!(f = fopen(filename, "w"))) {
718 gtp_err(LOG_ERR, __FILE__, __LINE__, "fopen(path=%s, mode=%s) failed: Error = %s", filename, "w", strerror(errno));
719 return;
720 }
721
722 umask(i);
723 fprintf(f, "%d\n", gsn->restart_counter);
724 if (fclose(f)) {
725 gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno));
726 return;
727 }
728}
729
730
731
jjako1db1c812003-07-06 20:53:57 +0000732int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
733 int mode)
jjako52c24142002-12-16 13:33:51 +0000734{
735 struct sockaddr_in addr;
jjako52c24142002-12-16 13:33:51 +0000736
737 syslog(LOG_ERR, "GTP: gtp_newgsn() started");
738
739 *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
740
741 (*gsn)->statedir = statedir;
742 log_restart(*gsn);
jjakoa7cd2492003-04-11 09:40:12 +0000743
744 /* Initialise sequence number */
745 (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
jjako52c24142002-12-16 13:33:51 +0000746
747 /* Initialise request retransmit queue */
748 queue_new(&(*gsn)->queue_req);
749 queue_new(&(*gsn)->queue_resp);
750
751 /* Initialise pdp table */
752 pdp_init();
753
754 /* Initialise call back functions */
jjako08d331d2003-10-13 20:33:30 +0000755 (*gsn)->cb_create_context_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000756 (*gsn)->cb_delete_context = 0;
jjako08d331d2003-10-13 20:33:30 +0000757 (*gsn)->cb_unsup_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000758 (*gsn)->cb_conf = 0;
jjako08d331d2003-10-13 20:33:30 +0000759 (*gsn)->cb_data_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000760
jjako08d331d2003-10-13 20:33:30 +0000761 /* Store function parameters */
762 (*gsn)->gsnc = *listen;
763 (*gsn)->gsnu = *listen;
764 (*gsn)->mode = mode;
765
766
767 /* Create GTP version 0 socket */
768 if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
jjako52c24142002-12-16 13:33:51 +0000769 (*gsn)->err_socket++;
770 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
771 return -1;
772 }
jjako52c24142002-12-16 13:33:51 +0000773
774 memset(&addr, 0, sizeof(addr));
jjako52c24142002-12-16 13:33:51 +0000775 addr.sin_family = AF_INET;
jjako52c24142002-12-16 13:33:51 +0000776 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
777 addr.sin_port = htons(GTP0_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000778#if defined(__FreeBSD__) || defined(__APPLE__)
jjako06e9f122004-01-19 18:37:58 +0000779 addr.sin_len = sizeof(addr);
780#endif
jjako52c24142002-12-16 13:33:51 +0000781
jjako08d331d2003-10-13 20:33:30 +0000782 if (bind((*gsn)->fd0, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
jjako52c24142002-12-16 13:33:51 +0000783 (*gsn)->err_socket++;
jjako08d331d2003-10-13 20:33:30 +0000784 gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd0=%d, addr=%lx, len=%d) failed: Error = %s", (*gsn)->fd0, (unsigned long) &addr, sizeof(addr), strerror(errno));
785 return -1;
786 }
787
788 /* Create GTP version 1 control plane socket */
789 if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
790 (*gsn)->err_socket++;
791 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
792 return -1;
793 }
794
795 memset(&addr, 0, sizeof(addr));
796 addr.sin_family = AF_INET;
797 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
798 addr.sin_port = htons(GTP1C_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000799#if defined(__FreeBSD__) || defined(__APPLE__)
jjako06e9f122004-01-19 18:37:58 +0000800 addr.sin_len = sizeof(addr);
801#endif
jjako08d331d2003-10-13 20:33:30 +0000802
803 if (bind((*gsn)->fd1c, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
804 (*gsn)->err_socket++;
805 gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s", (*gsn)->fd1c, (unsigned long) &addr, sizeof(addr), strerror(errno));
806 return -1;
807 }
808
809 /* Create GTP version 1 user plane socket */
810 if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
811 (*gsn)->err_socket++;
812 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
813 return -1;
814 }
815
816 memset(&addr, 0, sizeof(addr));
817 addr.sin_family = AF_INET;
818 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
819 addr.sin_port = htons(GTP1U_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000820#if defined(__FreeBSD__) || defined(__APPLE__)
jjako06e9f122004-01-19 18:37:58 +0000821 addr.sin_len = sizeof(addr);
822#endif
jjako08d331d2003-10-13 20:33:30 +0000823
824 if (bind((*gsn)->fd1u, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
825 (*gsn)->err_socket++;
826 gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s", (*gsn)->fd1c, (unsigned long) &addr, sizeof(addr), strerror(errno));
jjako52c24142002-12-16 13:33:51 +0000827 return -1;
828 }
829
jjako52c24142002-12-16 13:33:51 +0000830 return 0;
831}
832
833int gtp_free(struct gsn_t *gsn) {
834
835 /* Clean up retransmit queues */
836 queue_free(gsn->queue_req);
837 queue_free(gsn->queue_resp);
jjako08d331d2003-10-13 20:33:30 +0000838
839 close(gsn->fd0);
840 close(gsn->fd1c);
841 close(gsn->fd1u);
jjako52c24142002-12-16 13:33:51 +0000842
843 free(gsn);
844 return 0;
845}
846
847/* ***********************************************************
848 * Path management messages
849 * Messages: echo and version not supported.
850 * A path is connection between two UDP/IP endpoints
851 *
852 * A path is either using GTP0 or GTP1. A path can be
853 * established by any kind of GTP message??
854
855 * Which source port to use?
856 * GTP-C request destination port is 2123/3386
857 * GTP-U request destination port is 2152/3386
858 * T-PDU destination port is 2152/3386.
859 * For the above messages the source port is locally allocated.
860 * For response messages src=rx-dst and dst=rx-src.
861 * For simplicity we should probably use 2123+2152/3386 as
862 * src port even for the cases where src can be locally
863 * allocated. This also means that we have to listen only to
864 * the same ports.
865 * For response messages we need to be able to respond to
866 * the relevant src port even if it is locally allocated by
867 * the peer.
868 *
869 * The need for path management!
870 * We might need to keep a list of active paths. This might
871 * be in the form of remote IP address + UDP port numbers.
872 * (We will consider a path astablished if we have a context
873 * with the node in question)
874 *************************************************************/
875
876/* Send off an echo request */
jjako08d331d2003-10-13 20:33:30 +0000877int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
878 struct in_addr *inetaddr)
jjako52c24142002-12-16 13:33:51 +0000879{
880 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +0200881 unsigned int length = get_default_gtp(version, GTP_ECHO_REQ, &packet);
jjako08d331d2003-10-13 20:33:30 +0000882 return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp);
jjako52c24142002-12-16 13:33:51 +0000883}
884
jjako08d331d2003-10-13 20:33:30 +0000885/* Send off an echo reply */
886int gtp_echo_resp(struct gsn_t *gsn, int version,
887 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +0000888 void *pack, unsigned len)
889{
890 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +0200891 unsigned int length = get_default_gtp(version, GTP_ECHO_RSP, &packet);
jjako08d331d2003-10-13 20:33:30 +0000892 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, gsn->restart_counter);
893 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
894 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +0000895}
896
897
898/* Handle a received echo request */
jjako08d331d2003-10-13 20:33:30 +0000899int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
900 int fd, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000901
jjako08d331d2003-10-13 20:33:30 +0000902 /* Check if it was a dublicate request */
903 if(!gtp_dublicate(gsn, 0, peer, get_seq(pack))) return 0;
jjako52c24142002-12-16 13:33:51 +0000904
jjako08d331d2003-10-13 20:33:30 +0000905 /* Send off reply to request */
906 return gtp_echo_resp(gsn, version, peer, fd, pack, len);
jjako52c24142002-12-16 13:33:51 +0000907}
908
909/* Handle a received echo reply */
jjako08d331d2003-10-13 20:33:30 +0000910int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
jjako52c24142002-12-16 13:33:51 +0000911 void *pack, unsigned len) {
912 union gtpie_member *ie[GTPIE_SIZE];
913 unsigned char recovery;
jjako08d331d2003-10-13 20:33:30 +0000914 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +0000915 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +0000916 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +0000917
918 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +0000919 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +0000920
jjako08d331d2003-10-13 20:33:30 +0000921 /* Extract information elements into a pointer array */
922 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +0000923 gsn->invalid++;
924 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
925 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +0000926 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000927 return EOF;
928 }
929
930 if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
931 gsn->missing++;
932 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
933 "Missing mandatory field");
jjako08d331d2003-10-13 20:33:30 +0000934 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000935 return EOF;
936 }
937
jjako08d331d2003-10-13 20:33:30 +0000938 /* Echo reply packages does not have a cause information element */
939 /* Instead we return the recovery number in the callback function */
940 if (gsn->cb_conf) gsn->cb_conf(type, recovery, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000941
Harald Welte629e9862010-12-24 20:58:09 +0100942 if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery);
943
jjako52c24142002-12-16 13:33:51 +0000944 return 0;
945}
946
947/* Send off a Version Not Supported message */
948/* This message is somewhat special in that it actually is a
949 * response to some other message with unsupported GTP version
950 * For this reason it has parameters like a response, and does
951 * its own message transmission. No signalling queue is used
952 * The reply is sent to the peer IP and peer UDP. This means that
953 * the peer will be receiving a GTP0 message on a GTP1 port!
954 * In practice however this will never happen as a GTP0 GSN will
955 * only listen to the GTP0 port, and therefore will never receive
956 * anything else than GTP0 */
957
jjako08d331d2003-10-13 20:33:30 +0000958int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
959 int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000960{
961 union gtp_packet packet;
jjako52c24142002-12-16 13:33:51 +0000962
jjako08d331d2003-10-13 20:33:30 +0000963 /* GTP 1 is the highest supported protocol */
Harald Weltef54a1f42010-05-04 11:08:38 +0200964 unsigned int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet);
jjako2c381332003-10-21 19:09:53 +0000965 return gtp_notification(gsn, version, &packet, length,
966 peer, fd, 0);
jjako52c24142002-12-16 13:33:51 +0000967}
968
969/* Handle a Version Not Supported message */
jjako08d331d2003-10-13 20:33:30 +0000970int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
971 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000972
jjako08d331d2003-10-13 20:33:30 +0000973 if (gsn->cb_unsup_ind) gsn->cb_unsup_ind(peer);
jjako52c24142002-12-16 13:33:51 +0000974
jjako52c24142002-12-16 13:33:51 +0000975 return 0;
976}
977
jjako2c381332003-10-21 19:09:53 +0000978/* Send off an Supported Extension Headers Notification */
979int gtp_extheader_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
980 int fd, void *pack, unsigned len)
981{
982 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +0200983 unsigned int length = get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet);
jjako2c381332003-10-21 19:09:53 +0000984
985 uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU;
986
987 if (version < 1)
988 return 0;
989
990 /* We report back that we support only PDCP PDU headers */
991 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T, sizeof(pdcp_pdu),
992 &pdcp_pdu);
993
994 return gtp_notification(gsn, version, &packet, length,
995 peer, fd, get_seq(pack));
996}
997
998/* Handle a Supported Extension Headers Notification */
999int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
1000 void *pack, unsigned len) {
1001
1002 if (gsn->cb_extheader_ind) gsn->cb_extheader_ind(peer);
1003
1004 return 0;
1005}
1006
1007
jjako52c24142002-12-16 13:33:51 +00001008/* ***********************************************************
1009 * Session management messages
1010 * Messages: create, update and delete PDP context
1011 *
1012 * Information storage
1013 * Information storage for each PDP context is defined in
1014 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
1015 * PDP-address (IP address), sequence numbers, charging ID.
1016 * For the SGSN it also includes radio related mobility
1017 * information.
1018 *************************************************************/
1019
Harald Welte7b3347b2010-05-15 12:18:46 +02001020/* API: Send Create PDP Context Request (7.3.1) */
jjako08d331d2003-10-13 20:33:30 +00001021extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
jjako193e8b12003-11-10 12:31:41 +00001022 void *cbp) {
jjako52c24142002-12-16 13:33:51 +00001023 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02001024 unsigned int length = get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet);
jjako2c381332003-10-21 19:09:53 +00001025 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001026
jjako2c381332003-10-21 19:09:53 +00001027 /* TODO: Secondary PDP Context Activation Procedure */
1028 /* In secondary activation procedure the PDP context is identified
1029 by tei in the header. The following fields are omitted: Selection
1030 mode, IMSI, MSISDN, End User Address, Access Point Name and
1031 Protocol Configuration Options */
1032
1033 if (pdp->secondary) {
1034 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
1035 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context");
1036 return EOF;
1037 }
1038 }
1039
1040 if (pdp->version == 0) {
jjako08d331d2003-10-13 20:33:30 +00001041 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
jjako52c24142002-12-16 13:33:51 +00001042 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako2c381332003-10-21 19:09:53 +00001043 }
jjako52c24142002-12-16 13:33:51 +00001044
Harald Welte7b3347b2010-05-15 12:18:46 +02001045 /* Section 7.7.2 */
jjako2c381332003-10-21 19:09:53 +00001046 if (pdp->version == 1) {
1047 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1048 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1049 sizeof(pdp->imsi), (uint8_t*) &pdp->imsi);
1050 }
jjako52c24142002-12-16 13:33:51 +00001051
Harald Welte41af5692011-10-07 18:42:34 +02001052 /* Section 7.7.3 Routing Area Information */
1053 if (pdp->rai_given == 1)
1054 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI,
1055 pdp->rai.l, (uint8_t*) &pdp->rai.v);
1056
1057
Harald Welte7b3347b2010-05-15 12:18:46 +02001058 /* Section 7.7.11 */
jjako08d331d2003-10-13 20:33:30 +00001059 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1060 gsn->restart_counter);
jjako2c381332003-10-21 19:09:53 +00001061
Harald Welte7b3347b2010-05-15 12:18:46 +02001062 /* Section 7.7.12 */
jjako2c381332003-10-21 19:09:53 +00001063 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1064 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE,
1065 pdp->selmode);
jjako08d331d2003-10-13 20:33:30 +00001066
1067 if (pdp->version == 0) {
1068 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1069 pdp->fllu);
1070 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1071 pdp->fllc);
1072 }
1073
Harald Welte7b3347b2010-05-15 12:18:46 +02001074 /* Section 7.7.13 */
jjako08d331d2003-10-13 20:33:30 +00001075 if (pdp->version == 1) {
1076 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1077 pdp->teid_own);
jjako2c381332003-10-21 19:09:53 +00001078
Harald Welte7b3347b2010-05-15 12:18:46 +02001079 /* Section 7.7.14 */
jjako2c381332003-10-21 19:09:53 +00001080 if (!pdp->teic_confirmed)
1081 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1082 pdp->teic_own);
jjako08d331d2003-10-13 20:33:30 +00001083
Harald Welte7b3347b2010-05-15 12:18:46 +02001084 /* Section 7.7.17 */
jjakobe61ef22004-01-09 12:22:29 +00001085 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1086 pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00001087
Harald Welte7b3347b2010-05-15 12:18:46 +02001088 /* Section 7.7.17 */
jjako2c381332003-10-21 19:09:53 +00001089 if (pdp->secondary) /* Secondary PDP Context Activation Procedure */
jjakobe61ef22004-01-09 12:22:29 +00001090 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
jjako2c381332003-10-21 19:09:53 +00001091 linked_pdp->nsapi);
jjako9b4971d2004-05-27 20:30:19 +00001092
Harald Welte7b3347b2010-05-15 12:18:46 +02001093 /* Section 7.7.23 */
jjako9b4971d2004-05-27 20:30:19 +00001094 if (pdp->cch_pdp) /* Only include charging if flags are set */
1095 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C,
1096 pdp->cch_pdp);
jjako08d331d2003-10-13 20:33:30 +00001097 }
1098
1099 /* TODO
1100 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1101 pdp->traceref);
1102 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1103 pdp->tracetype); */
1104
Harald Welte7b3347b2010-05-15 12:18:46 +02001105 /* Section 7.7.27 */
jjako2c381332003-10-21 19:09:53 +00001106 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1107 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1108 pdp->eua.l, pdp->eua.v);
1109
jjako08d331d2003-10-13 20:33:30 +00001110
Harald Welte7b3347b2010-05-15 12:18:46 +02001111 /* Section 7.7.30 */
jjako2c381332003-10-21 19:09:53 +00001112 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1113 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN,
1114 pdp->apn_use.l, pdp->apn_use.v);
1115
Harald Welte7b3347b2010-05-15 12:18:46 +02001116 /* Section 7.7.31 */
jjako2c381332003-10-21 19:09:53 +00001117 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1118 if (pdp->pco_req.l)
1119 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1120 pdp->pco_req.l, pdp->pco_req.v);
jjako08d331d2003-10-13 20:33:30 +00001121
Harald Welte7b3347b2010-05-15 12:18:46 +02001122 /* Section 7.7.32 */
jjako08d331d2003-10-13 20:33:30 +00001123 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1124 pdp->gsnlc.l, pdp->gsnlc.v);
Harald Welte7b3347b2010-05-15 12:18:46 +02001125 /* Section 7.7.32 */
jjako08d331d2003-10-13 20:33:30 +00001126 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1127 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001128
Harald Welte7b3347b2010-05-15 12:18:46 +02001129 /* Section 7.7.33 */
jjako2c381332003-10-21 19:09:53 +00001130 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1131 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN,
1132 pdp->msisdn.l, pdp->msisdn.v);
jjako08d331d2003-10-13 20:33:30 +00001133
Harald Welte7b3347b2010-05-15 12:18:46 +02001134 /* Section 7.7.34 */
jjako08d331d2003-10-13 20:33:30 +00001135 if (pdp->version == 1)
1136 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1137 pdp->qos_req.l, pdp->qos_req.v);
1138
Harald Welte7b3347b2010-05-15 12:18:46 +02001139 /* Section 7.7.36 */
jjako08d331d2003-10-13 20:33:30 +00001140 if ((pdp->version == 1) && pdp->tft.l)
1141 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1142 pdp->tft.l, pdp->tft.v);
1143
Harald Welte7b3347b2010-05-15 12:18:46 +02001144 /* Section 7.7.41 */
jjako08d331d2003-10-13 20:33:30 +00001145 if ((pdp->version == 1) && pdp->triggerid.l)
1146 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1147 pdp->triggerid.l, pdp->triggerid.v);
1148
Harald Welte7b3347b2010-05-15 12:18:46 +02001149 /* Section 7.7.42 */
jjako08d331d2003-10-13 20:33:30 +00001150 if ((pdp->version == 1) && pdp->omcid.l)
1151 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1152 pdp->omcid.l, pdp->omcid.v);
1153
Yann BONNAMY944dce32010-10-29 17:07:44 +02001154 /* new R7 fields */
1155 if (pdp->rattype_given == 1)
1156 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAT_TYPE,
1157 pdp->rattype.l, pdp->rattype.v);
1158
1159 if (pdp->userloc_given == 1)
1160 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_USER_LOC,
1161 pdp->userloc.l, pdp->userloc.v);
1162
1163 if (pdp->mstz_given == 1)
1164 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MS_TZ,
1165 pdp->mstz.l, pdp->mstz.v);
1166
1167 if (pdp->imeisv_given == 1)
1168 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_IMEI_SV,
1169 pdp->imeisv.l, pdp->imeisv.v);
1170
jjako193e8b12003-11-10 12:31:41 +00001171 /* TODO hisaddr0 */
1172 gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
jjako52c24142002-12-16 13:33:51 +00001173
1174 return 0;
1175}
1176
jjako08d331d2003-10-13 20:33:30 +00001177/* API: Application response to context indication */
1178int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause) {
1179
1180 /* Now send off a reply to the peer */
1181 gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
1182
1183 if (cause != GTPCAUSE_ACC_REQ) {
1184 pdp_freepdp(pdp);
1185 }
1186
1187 return 0;
1188}
1189
1190/* API: Register create context indication callback */
1191int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
1192 int (*cb_create_context_ind) (struct pdp_t* pdp))
jjako52c24142002-12-16 13:33:51 +00001193{
jjako08d331d2003-10-13 20:33:30 +00001194 gsn->cb_create_context_ind = cb_create_context_ind;
1195 return 0;
1196}
1197
1198
1199/* Send Create PDP Context Response */
1200int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
1201 uint8_t cause) {
jjako52c24142002-12-16 13:33:51 +00001202 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02001203 unsigned int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
jjako52c24142002-12-16 13:33:51 +00001204
jjako08d331d2003-10-13 20:33:30 +00001205 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00001206
1207 if (cause == GTPCAUSE_ACC_REQ) {
jjako08d331d2003-10-13 20:33:30 +00001208
1209 if (version == 0)
1210 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1211 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1212
1213 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER,
jjako52c24142002-12-16 13:33:51 +00001214 pdp->reorder);
jjako08d331d2003-10-13 20:33:30 +00001215 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
jjako52c24142002-12-16 13:33:51 +00001216 gsn->restart_counter);
jjako08d331d2003-10-13 20:33:30 +00001217
1218 if (version == 0) {
1219 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1220 pdp->fllu);
1221 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1222 pdp->fllc);
1223 }
1224
1225 if (version == 1) {
1226 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1227 pdp->teid_own);
1228 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1229 pdp->teic_own);
1230 }
1231
jjako2c381332003-10-21 19:09:53 +00001232 /* TODO: We use teic_own as charging ID */
jjako08d331d2003-10-13 20:33:30 +00001233 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
jjako2c381332003-10-21 19:09:53 +00001234 pdp->teic_own);
1235
jjako08d331d2003-10-13 20:33:30 +00001236 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
jjako52c24142002-12-16 13:33:51 +00001237 pdp->eua.l, pdp->eua.v);
1238
1239 if (pdp->pco_neg.l) { /* Optional PCO */
jjako08d331d2003-10-13 20:33:30 +00001240 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
jjako52c24142002-12-16 13:33:51 +00001241 pdp->pco_neg.l, pdp->pco_neg.v);
1242 }
1243
jjako08d331d2003-10-13 20:33:30 +00001244 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
jjako52c24142002-12-16 13:33:51 +00001245 pdp->gsnlc.l, pdp->gsnlc.v);
jjako08d331d2003-10-13 20:33:30 +00001246 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
jjako52c24142002-12-16 13:33:51 +00001247 pdp->gsnlu.l, pdp->gsnlu.v);
jjako08d331d2003-10-13 20:33:30 +00001248
1249 if (version == 1)
1250 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1251 pdp->qos_neg.l, pdp->qos_neg.v);
1252
1253 /* TODO: Charging gateway address */
jjako52c24142002-12-16 13:33:51 +00001254 }
1255
jjako08d331d2003-10-13 20:33:30 +00001256 return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer,
1257 pdp->fd, pdp->seq, pdp->tid);
jjako52c24142002-12-16 13:33:51 +00001258}
1259
1260/* Handle Create PDP Context Request */
1261int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001262 struct sockaddr_in *peer, int fd,
1263 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00001264 struct pdp_t *pdp, *pdp_old;
1265 struct pdp_t pdp_buf;
1266 union gtpie_member* ie[GTPIE_SIZE];
1267 uint8_t recovery;
jjako52c24142002-12-16 13:33:51 +00001268
jjako08d331d2003-10-13 20:33:30 +00001269 uint16_t seq = get_seq(pack);
1270 int hlen = get_hlen(pack);
jjako2c381332003-10-21 19:09:53 +00001271 uint8_t linked_nsapi = 0;
1272 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001273
jjako2c381332003-10-21 19:09:53 +00001274 if(!gtp_dublicate(gsn, version, peer, seq)) return 0;
jjako08d331d2003-10-13 20:33:30 +00001275
1276 pdp = &pdp_buf;
1277 memset(pdp, 0, sizeof(struct pdp_t));
1278
1279 if (version == 0) {
jjakod48c5ff2004-01-26 22:25:40 +00001280 pdp->imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffffull;
1281 pdp->nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000ull) >> 60;
jjako52c24142002-12-16 13:33:51 +00001282 }
1283
jjako08d331d2003-10-13 20:33:30 +00001284 pdp->seq = seq;
1285 pdp->sa_peer = *peer;
1286 pdp->fd = fd;
1287 pdp->version = version;
1288
jjako52c24142002-12-16 13:33:51 +00001289 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001290 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001291 gsn->invalid++;
1292 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1293 "Invalid message format");
1294 if (0 == version)
1295 return EOF;
1296 else
jjako08d331d2003-10-13 20:33:30 +00001297 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_INVALID_MESSAGE);
jjako52c24142002-12-16 13:33:51 +00001298 }
1299
jjako2c381332003-10-21 19:09:53 +00001300 if (version == 1) {
1301 /* Linked NSAPI (conditional) */
1302 /* If included this is the Secondary PDP Context Activation Procedure */
1303 /* In secondary activation IMSI is not included, so the context must be */
1304 /* identified by the tei */
1305 if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) {
1306
1307 /* Find the primary PDP context */
1308 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
1309 gsn->incorrect++;
1310 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1311 "Incorrect optional information field");
1312 return gtp_create_pdp_resp(gsn, version, pdp,
1313 GTPCAUSE_OPT_IE_INCORRECT);
1314 }
1315
1316 /* Check that the primary PDP context matches linked nsapi */
1317 if (linked_pdp->nsapi != linked_nsapi) {
1318 gsn->incorrect++;
1319 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1320 "Incorrect optional information field");
1321 return gtp_create_pdp_resp(gsn, version, pdp,
1322 GTPCAUSE_OPT_IE_INCORRECT);
1323 }
1324
1325 /* Copy parameters from primary context */
1326 pdp->selmode = linked_pdp->selmode;
1327 pdp->imsi = linked_pdp->imsi;
1328 pdp->msisdn = linked_pdp->msisdn;
1329 pdp->eua = linked_pdp->eua;
1330 pdp->pco_req = linked_pdp->pco_req;
1331 pdp->apn_req = linked_pdp->apn_req;
1332 pdp->teic_gn = linked_pdp->teic_gn;
1333 pdp->secondary = 1;
1334 }
1335 } /* if (version == 1) */
1336
jjako08d331d2003-10-13 20:33:30 +00001337 if (version == 0) {
1338 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1339 pdp->qos_req0, sizeof(pdp->qos_req0))) {
1340 gsn->missing++;
1341 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1342 "Missing mandatory information field");
1343 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING);
1344 }
jjako52c24142002-12-16 13:33:51 +00001345 }
jjako2c381332003-10-21 19:09:53 +00001346
1347 if ((version == 1) && (!linked_pdp)) {
1348 /* Not Secondary PDP Context Activation Procedure */
jjako08d331d2003-10-13 20:33:30 +00001349 /* IMSI (conditional) */
1350 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) {
1351 gsn->missing++;
1352 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1353 "Missing mandatory information field");
1354 return gtp_create_pdp_resp(gsn, version, pdp,
1355 GTPCAUSE_MAN_IE_MISSING);
1356 }
1357 }
jjako2c381332003-10-21 19:09:53 +00001358
jjako08d331d2003-10-13 20:33:30 +00001359 /* Recovery (optional) */
jjako52c24142002-12-16 13:33:51 +00001360 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
Harald Welte629e9862010-12-24 20:58:09 +01001361 if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery);
jjako52c24142002-12-16 13:33:51 +00001362 }
jjako2c381332003-10-21 19:09:53 +00001363
jjako08d331d2003-10-13 20:33:30 +00001364 /* Selection mode (conditional) */
jjako2c381332003-10-21 19:09:53 +00001365 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1366 if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0,
1367 &pdp->selmode, sizeof(pdp->selmode))) {
1368 gsn->missing++;
1369 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1370 "Missing mandatory information field");
1371 return gtp_create_pdp_resp(gsn, version, pdp,
1372 GTPCAUSE_MAN_IE_MISSING);
1373 }
jjako52c24142002-12-16 13:33:51 +00001374 }
1375
jjako08d331d2003-10-13 20:33:30 +00001376 if (version == 0) {
1377 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1378 gsn->missing++;
1379 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1380 "Missing mandatory information field");
1381 return gtp_create_pdp_resp(gsn, version, pdp,
1382 GTPCAUSE_MAN_IE_MISSING);
1383 }
1384
1385 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1386 gsn->missing++;
1387 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1388 "Missing mandatory information field");
1389 return gtp_create_pdp_resp(gsn, version, pdp,
1390 GTPCAUSE_MAN_IE_MISSING);
1391 }
jjako52c24142002-12-16 13:33:51 +00001392 }
jjako2c381332003-10-21 19:09:53 +00001393
1394
jjako08d331d2003-10-13 20:33:30 +00001395 if (version == 1) {
1396 /* TEID (mandatory) */
1397 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1398 gsn->missing++;
1399 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1400 "Missing mandatory information field");
1401 return gtp_create_pdp_resp(gsn, version, pdp,
1402 GTPCAUSE_MAN_IE_MISSING);
1403 }
1404
1405 /* TEIC (conditional) */
jjako2c381332003-10-21 19:09:53 +00001406 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1407 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1408 gsn->missing++;
1409 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1410 "Missing mandatory information field");
1411 return gtp_create_pdp_resp(gsn, version, pdp,
1412 GTPCAUSE_MAN_IE_MISSING);
1413 }
jjako08d331d2003-10-13 20:33:30 +00001414 }
jjako52c24142002-12-16 13:33:51 +00001415
jjako98200df2004-01-09 15:18:42 +00001416 /* NSAPI (mandatory) */
1417 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
1418 gsn->missing++;
1419 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1420 "Missing mandatory information field");
1421 return gtp_create_pdp_resp(gsn, version, pdp,
1422 GTPCAUSE_MAN_IE_MISSING);
1423 }
jjako2c381332003-10-21 19:09:53 +00001424 }
1425
1426
jjako08d331d2003-10-13 20:33:30 +00001427 /* Charging Characteriatics (optional) */
1428 /* Trace reference (optional) */
1429 /* Trace type (optional) */
1430 /* Charging Characteriatics (optional) */
jjako2c381332003-10-21 19:09:53 +00001431
1432 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1433 /* End User Address (conditional) */
1434 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
jjako52c24142002-12-16 13:33:51 +00001435 &pdp->eua.v, sizeof(pdp->eua.v))) {
jjako2c381332003-10-21 19:09:53 +00001436 gsn->missing++;
1437 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1438 "Missing mandatory information field");
1439 return gtp_create_pdp_resp(gsn, version, pdp,
1440 GTPCAUSE_MAN_IE_MISSING);
1441 }
1442
1443 /* APN */
1444 if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l,
jjako52c24142002-12-16 13:33:51 +00001445 &pdp->apn_req.v, sizeof(pdp->apn_req.v))) {
jjako2c381332003-10-21 19:09:53 +00001446 gsn->missing++;
1447 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1448 "Missing mandatory information field");
1449 return gtp_create_pdp_resp(gsn, version, pdp,
1450 GTPCAUSE_MAN_IE_MISSING);
1451 }
1452
1453 /* Extract protocol configuration options (optional) */
1454 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1455 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1456 }
jjako52c24142002-12-16 13:33:51 +00001457 }
1458
jjako08d331d2003-10-13 20:33:30 +00001459 /* SGSN address for signalling (mandatory) */
jjako52c24142002-12-16 13:33:51 +00001460 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1461 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1462 gsn->missing++;
1463 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1464 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001465 return gtp_create_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00001466 GTPCAUSE_MAN_IE_MISSING);
1467 }
1468
jjako08d331d2003-10-13 20:33:30 +00001469 /* SGSN address for user traffic (mandatory) */
jjako52c24142002-12-16 13:33:51 +00001470 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1471 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1472 gsn->missing++;
1473 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1474 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001475 return gtp_create_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00001476 GTPCAUSE_MAN_IE_MISSING);
1477 }
1478
jjako2c381332003-10-21 19:09:53 +00001479 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1480 /* MSISDN (conditional) */
1481 if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l,
1482 &pdp->msisdn.v, sizeof(pdp->msisdn.v))) {
1483 gsn->missing++;
1484 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1485 "Missing mandatory information field");
1486 return gtp_create_pdp_resp(gsn, version, pdp,
1487 GTPCAUSE_MAN_IE_MISSING);
1488 }
jjako52c24142002-12-16 13:33:51 +00001489 }
1490
jjako08d331d2003-10-13 20:33:30 +00001491 if (version == 1) {
1492 /* QoS (mandatory) */
1493 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
1494 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
1495 gsn->missing++;
1496 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1497 "Missing mandatory information field");
1498 return gtp_create_pdp_resp(gsn, version, pdp,
1499 GTPCAUSE_MAN_IE_MISSING);
1500 }
1501
1502 /* TFT (conditional) */
1503 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
1504 &pdp->tft.v, sizeof(pdp->tft.v))) {
1505 }
jjako2c381332003-10-21 19:09:53 +00001506
jjako08d331d2003-10-13 20:33:30 +00001507 /* Trigger ID */
1508 /* OMC identity */
1509 }
1510
1511 /* Initialize our own IP addresses */
jjako52c24142002-12-16 13:33:51 +00001512 in_addr2gsna(&pdp->gsnlc, &gsn->gsnc);
1513 in_addr2gsna(&pdp->gsnlu, &gsn->gsnu);
jjako2c381332003-10-21 19:09:53 +00001514
jjako2e840a32003-01-28 16:05:18 +00001515 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Before pdp_tidget\n");
jjako2c381332003-10-21 19:09:53 +00001516
jjako08d331d2003-10-13 20:33:30 +00001517 if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) {
jjako52c24142002-12-16 13:33:51 +00001518 /* Found old pdp with same tid. Now the voodoo begins! */
jjako08d331d2003-10-13 20:33:30 +00001519 /* 09.60 / 29.060 allows create on existing context to "steal" */
1520 /* the context which was allready established */
jjako52c24142002-12-16 13:33:51 +00001521 /* We check that the APN, selection mode and MSISDN is the same */
jjako2e840a32003-01-28 16:05:18 +00001522 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n");
jjako08d331d2003-10-13 20:33:30 +00001523 if ((pdp->apn_req.l == pdp_old->apn_req.l)
jjako52c24142002-12-16 13:33:51 +00001524 && (!memcmp(pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l))
1525 && (pdp->selmode == pdp_old->selmode)
1526 && (pdp->msisdn.l == pdp_old->msisdn.l)
1527 && (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l))) {
1528 /* OK! We are dealing with the same APN. We will copy new
1529 * parameters to the old pdp and send off confirmation
1530 * We ignore the following information elements:
1531 * QoS: MS will get originally negotiated QoS.
1532 * End user address (EUA). MS will get old EUA anyway.
1533 * Protocol configuration option (PCO): Only application can verify */
jjako2e840a32003-01-28 16:05:18 +00001534
1535 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n");
jjako52c24142002-12-16 13:33:51 +00001536
1537 /* Copy remote flow label */
1538 pdp_old->flru = pdp->flru;
1539 pdp_old->flrc = pdp->flrc;
1540
jjako08d331d2003-10-13 20:33:30 +00001541 /* Copy remote tei */
1542 pdp_old->teid_gn = pdp->teid_gn;
1543 pdp_old->teic_gn = pdp->teic_gn;
1544
jjako52c24142002-12-16 13:33:51 +00001545 /* Copy peer GSN address */
1546 pdp_old->gsnrc.l = pdp->gsnrc.l;
1547 memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l);
1548 pdp_old->gsnru.l = pdp->gsnru.l;
1549 memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l);
jjako2c381332003-10-21 19:09:53 +00001550
1551 /* Copy request parameters */
1552 pdp_old->seq = pdp->seq;
1553 pdp_old->sa_peer = pdp->sa_peer;
1554 pdp_old->fd = pdp->fd = fd;
1555 pdp_old->version = pdp->version = version;
1556
1557 /* Switch to using the old pdp context */
jjako52c24142002-12-16 13:33:51 +00001558 pdp = pdp_old;
1559
1560 /* Confirm to peer that things were "successful" */
jjako08d331d2003-10-13 20:33:30 +00001561 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_ACC_REQ);
jjako52c24142002-12-16 13:33:51 +00001562 }
1563 else { /* This is not the same PDP context. Delete the old one. */
jjako2e840a32003-01-28 16:05:18 +00001564
1565 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleting old context\n");
jjako52c24142002-12-16 13:33:51 +00001566
1567 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp_old);
1568 pdp_freepdp(pdp_old);
jjako08d331d2003-10-13 20:33:30 +00001569
jjako2e840a32003-01-28 16:05:18 +00001570 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleted...\n");
jjako52c24142002-12-16 13:33:51 +00001571 }
1572 }
1573
jjako08d331d2003-10-13 20:33:30 +00001574 pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp);
jjako52c24142002-12-16 13:33:51 +00001575
1576 /* Callback function to validata login */
jjako08d331d2003-10-13 20:33:30 +00001577 if (gsn->cb_create_context_ind !=0)
1578 return gsn->cb_create_context_ind(pdp);
jjako52c24142002-12-16 13:33:51 +00001579 else {
jjako08d331d2003-10-13 20:33:30 +00001580 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1581 "No create_context_ind callback defined");
1582 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_NOT_SUPPORTED);
jjako52c24142002-12-16 13:33:51 +00001583 }
1584}
1585
1586
1587/* Handle Create PDP Context Response */
1588int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001589 struct sockaddr_in *peer,
1590 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00001591 struct pdp_t *pdp;
1592 union gtpie_member *ie[GTPIE_SIZE];
1593 uint8_t cause, recovery;
jjako08d331d2003-10-13 20:33:30 +00001594 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00001595 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +00001596 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001597
1598 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00001599 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00001600
1601 /* Find the context in question */
jjako08d331d2003-10-13 20:33:30 +00001602 if (pdp_getgtp1(&pdp, get_tei(pack))) {
jjako52c24142002-12-16 13:33:51 +00001603 gsn->err_unknownpdp++;
1604 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1605 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00001606 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00001607 return EOF;
1608 }
1609
jjako2c381332003-10-21 19:09:53 +00001610 /* Register that we have received a valid teic from GGSN */
1611 pdp->teic_confirmed = 1;
1612
jjako52c24142002-12-16 13:33:51 +00001613 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001614 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001615 gsn->invalid++;
1616 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1617 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +00001618 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001619 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1620 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001621 return EOF;
1622 }
1623
1624 /* Extract cause value (mandatory) */
1625 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
1626 gsn->missing++;
1627 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1628 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001629 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001630 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1631 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001632 return EOF;
1633 }
1634
1635 /* Extract recovery (optional) */
1636 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
Harald Welte629e9862010-12-24 20:58:09 +01001637 if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery);
jjako52c24142002-12-16 13:33:51 +00001638 }
1639
1640 /* Extract protocol configuration options (optional) */
1641 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1642 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
jjako52c24142002-12-16 13:33:51 +00001643 }
1644
1645 /* Check all conditional information elements */
1646 if (GTPCAUSE_ACC_REQ == cause) {
1647
jjako08d331d2003-10-13 20:33:30 +00001648 if (version == 0) {
1649 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1650 &pdp->qos_neg0, sizeof(pdp->qos_neg0))) {
1651 gsn->missing++;
1652 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1653 "Missing conditional information field");
1654 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001655 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1656 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001657 return EOF;
1658 }
jjako52c24142002-12-16 13:33:51 +00001659 }
jjako52c24142002-12-16 13:33:51 +00001660
1661 if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) {
1662 gsn->missing++;
1663 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1664 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001665 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001666 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1667 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001668 return EOF;
1669 }
1670
jjako08d331d2003-10-13 20:33:30 +00001671 if (version == 0) {
1672 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1673 gsn->missing++;
1674 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1675 "Missing conditional information field");
1676 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001677 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1678 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001679 return EOF;
1680 }
jjako52c24142002-12-16 13:33:51 +00001681
jjako08d331d2003-10-13 20:33:30 +00001682 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1683 gsn->missing++;
1684 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1685 "Missing conditional information field");
1686 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001687 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1688 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001689 return EOF;
1690 }
1691 }
1692
1693 if (version == 1) {
1694 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1695 gsn->missing++;
1696 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1697 "Missing conditional information field");
1698 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001699 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1700 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001701 return EOF;
1702 }
1703
1704 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1705 gsn->missing++;
1706 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1707 "Missing conditional information field");
1708 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001709 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1710 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001711 return EOF;
1712 }
jjako52c24142002-12-16 13:33:51 +00001713 }
1714
1715 if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
1716 gsn->missing++;
1717 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1718 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001719 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001720 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1721 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001722 }
1723
1724 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1725 &pdp->eua.v, sizeof(pdp->eua.v))) {
1726 gsn->missing++;
1727 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1728 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001729 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001730 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1731 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001732 return EOF;
1733 }
1734
1735 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1736 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1737 gsn->missing++;
1738 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1739 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001740 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001741 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1742 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001743 return EOF;
1744 }
1745
1746 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1747 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1748 gsn->missing++;
1749 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1750 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001751 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001752 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1753 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001754 return EOF;
1755 }
jjako52c24142002-12-16 13:33:51 +00001756
jjako08d331d2003-10-13 20:33:30 +00001757 if (version == 1) {
1758 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
1759 &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
1760 gsn->missing++;
1761 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1762 "Missing conditional information field");
1763 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001764 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1765 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001766 return EOF;
1767 }
1768 }
jjakoccc564f2003-10-25 15:40:48 +00001769
jjako08d331d2003-10-13 20:33:30 +00001770 }
1771
1772 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako52c24142002-12-16 13:33:51 +00001773
1774 return 0;
1775}
1776
jjako52c24142002-12-16 13:33:51 +00001777
jjako08d331d2003-10-13 20:33:30 +00001778/* API: Send Update PDP Context Request */
1779int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
1780 struct in_addr* inetaddr) {
1781 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02001782 unsigned int length = get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet);
jjako52c24142002-12-16 13:33:51 +00001783
jjako08d331d2003-10-13 20:33:30 +00001784 if (pdp->version == 0)
1785 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1786 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako2c381332003-10-21 19:09:53 +00001787
1788 /* Include IMSI if updating with unknown teic_gn */
1789 if ((pdp->version == 1) && (!pdp->teic_gn))
jjako08d331d2003-10-13 20:33:30 +00001790 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1791 sizeof(pdp->imsi), (uint8_t*) &pdp->imsi);
jjako2c381332003-10-21 19:09:53 +00001792
jjako08d331d2003-10-13 20:33:30 +00001793 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
jjako52c24142002-12-16 13:33:51 +00001794 gsn->restart_counter);
jjako2c381332003-10-21 19:09:53 +00001795
jjako08d331d2003-10-13 20:33:30 +00001796 if (pdp->version == 0) {
1797 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
jjako52c24142002-12-16 13:33:51 +00001798 pdp->fllu);
jjako08d331d2003-10-13 20:33:30 +00001799 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
jjako52c24142002-12-16 13:33:51 +00001800 pdp->fllc);
jjako52c24142002-12-16 13:33:51 +00001801 }
jjako2c381332003-10-21 19:09:53 +00001802
jjako08d331d2003-10-13 20:33:30 +00001803 if (pdp->version == 1) {
1804 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1805 pdp->teid_own);
jjako52c24142002-12-16 13:33:51 +00001806
jjako2c381332003-10-21 19:09:53 +00001807 if (!pdp->teic_confirmed)
1808 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1809 pdp->teic_own);
1810 }
1811
jjako08d331d2003-10-13 20:33:30 +00001812 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1813 pdp->nsapi);
jjako2c381332003-10-21 19:09:53 +00001814
jjako08d331d2003-10-13 20:33:30 +00001815 /* TODO
jjako2c381332003-10-21 19:09:53 +00001816 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1817 pdp->traceref);
1818 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1819 pdp->tracetype); */
1820
jjako08d331d2003-10-13 20:33:30 +00001821 /* TODO if ggsn update message
jjako2c381332003-10-21 19:09:53 +00001822 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1823 pdp->eua.l, pdp->eua.v);
jjako08d331d2003-10-13 20:33:30 +00001824 */
jjako2c381332003-10-21 19:09:53 +00001825
jjako08d331d2003-10-13 20:33:30 +00001826 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1827 pdp->gsnlc.l, pdp->gsnlc.v);
1828 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1829 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001830
jjako08d331d2003-10-13 20:33:30 +00001831 if (pdp->version == 1)
1832 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1833 pdp->qos_req.l, pdp->qos_req.v);
jjako2c381332003-10-21 19:09:53 +00001834
1835
jjako08d331d2003-10-13 20:33:30 +00001836 if ((pdp->version == 1) && pdp->tft.l)
1837 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1838 pdp->tft.l, pdp->tft.v);
1839
1840 if ((pdp->version == 1) && pdp->triggerid.l)
1841 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1842 pdp->triggerid.l, pdp->triggerid.v);
1843
1844 if ((pdp->version == 1) && pdp->omcid.l)
1845 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1846 pdp->omcid.l, pdp->omcid.v);
1847
1848 gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp);
1849
1850 return 0;
jjako52c24142002-12-16 13:33:51 +00001851}
1852
jjako08d331d2003-10-13 20:33:30 +00001853
1854/* Send Update PDP Context Response */
1855int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
1856 struct sockaddr_in *peer, int fd,
1857 void *pack, unsigned len,
1858 struct pdp_t *pdp, uint8_t cause) {
1859
1860 union gtp_packet packet;
Isabelle Kraemerfe504092011-07-29 16:41:38 +02001861 unsigned int length = get_default_gtp(version, GTP_UPDATE_PDP_RSP, &packet);
jjako08d331d2003-10-13 20:33:30 +00001862
1863 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
1864
1865 if (cause == GTPCAUSE_ACC_REQ) {
1866
1867 if (version == 0)
1868 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1869 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1870
1871 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1872 gsn->restart_counter);
1873
1874 if (version == 0) {
1875 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1876 pdp->fllu);
1877 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1878 pdp->fllc);
1879 }
1880
1881 if (version == 1) {
1882 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1883 pdp->teid_own);
jjako2c381332003-10-21 19:09:53 +00001884
1885 if (!pdp->teic_confirmed)
1886 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1887 pdp->teic_own);
jjako08d331d2003-10-13 20:33:30 +00001888 }
jjako2c381332003-10-21 19:09:53 +00001889
1890 /* TODO we use teid_own as charging ID address */
jjako08d331d2003-10-13 20:33:30 +00001891 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
jjako2c381332003-10-21 19:09:53 +00001892 pdp->teid_own);
1893
jjako08d331d2003-10-13 20:33:30 +00001894 /* If ggsn
jjako2c381332003-10-21 19:09:53 +00001895 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1896 pdp->eua.l, pdp->eua.v); */
1897
jjako08d331d2003-10-13 20:33:30 +00001898 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1899 pdp->gsnlc.l, pdp->gsnlc.v);
1900 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1901 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001902
jjako08d331d2003-10-13 20:33:30 +00001903 if (version == 1)
1904 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1905 pdp->qos_neg.l, pdp->qos_neg.v);
jjako2c381332003-10-21 19:09:53 +00001906
jjako08d331d2003-10-13 20:33:30 +00001907 /* TODO: Charging gateway address */
1908 }
jjako2c381332003-10-21 19:09:53 +00001909
1910 return gtp_resp(version, gsn, pdp, &packet, length, peer,
1911 fd, get_seq(pack), get_tid(pack));
jjako08d331d2003-10-13 20:33:30 +00001912}
1913
1914
jjako52c24142002-12-16 13:33:51 +00001915/* Handle Update PDP Context Request */
1916int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001917 struct sockaddr_in *peer, int fd,
1918 void *pack, unsigned len) {
1919 struct pdp_t *pdp;
1920 struct pdp_t pdp_backup;
jjako52c24142002-12-16 13:33:51 +00001921 union gtpie_member* ie[GTPIE_SIZE];
1922 uint8_t recovery;
1923
jjako08d331d2003-10-13 20:33:30 +00001924 uint16_t seq = get_seq(pack);
1925 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001926
jjako08d331d2003-10-13 20:33:30 +00001927 uint64_t imsi;
1928 uint8_t nsapi;
1929
jjako52c24142002-12-16 13:33:51 +00001930 /* Is this a dublicate ? */
jjako08d331d2003-10-13 20:33:30 +00001931 if(!gtp_dublicate(gsn, version, peer, seq)) {
jjako52c24142002-12-16 13:33:51 +00001932 return 0; /* We allready send of response once */
1933 }
jjako2c381332003-10-21 19:09:53 +00001934
jjako52c24142002-12-16 13:33:51 +00001935
1936 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001937 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001938 gsn->invalid++;
1939 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1940 "Invalid message format");
1941 if (0 == version)
1942 return EOF;
1943 else
jjako08d331d2003-10-13 20:33:30 +00001944 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1945 NULL, GTPCAUSE_INVALID_MESSAGE);
jjako52c24142002-12-16 13:33:51 +00001946 }
1947
jjako08d331d2003-10-13 20:33:30 +00001948 /* Finding PDP: */
1949 /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
1950 /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
1951 /* we have to use the tunnel endpoint identifier */
1952 if (version == 0) {
jjakod48c5ff2004-01-26 22:25:40 +00001953 imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffffull;
1954 nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000ull) >> 60;
jjako2c381332003-10-21 19:09:53 +00001955
jjako08d331d2003-10-13 20:33:30 +00001956 /* Find the context in question */
1957 if (pdp_getimsi(&pdp, imsi, nsapi)) {
1958 gsn->err_unknownpdp++;
1959 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1960 "Unknown PDP context");
1961 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1962 NULL, GTPCAUSE_NON_EXIST);
1963 }
jjako52c24142002-12-16 13:33:51 +00001964 }
jjako08d331d2003-10-13 20:33:30 +00001965 else if (version == 1) {
1966 /* NSAPI (mandatory) */
1967 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
1968 gsn->missing++;
1969 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1970 "Missing mandatory information field");
1971 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1972 NULL, GTPCAUSE_MAN_IE_MISSING);
1973 }
jjako2c381332003-10-21 19:09:53 +00001974
jjako08d331d2003-10-13 20:33:30 +00001975 /* IMSI (conditional) */
1976 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) {
1977 /* Find the context in question */
1978 if (pdp_getgtp1(&pdp, get_tei(pack))) {
1979 gsn->err_unknownpdp++;
1980 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1981 "Unknown PDP context");
1982 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1983 NULL, GTPCAUSE_NON_EXIST);
1984 }
1985 }
1986 else {
1987 /* Find the context in question */
1988 if (pdp_getimsi(&pdp, imsi, nsapi)) {
1989 gsn->err_unknownpdp++;
1990 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1991 "Unknown PDP context");
1992 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1993 NULL, GTPCAUSE_NON_EXIST);
1994 }
1995 }
1996 }
1997 else {
1998 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
1999 return EOF;
2000 }
jjako2c381332003-10-21 19:09:53 +00002001
jjako08d331d2003-10-13 20:33:30 +00002002 /* Make a backup copy in case anything is wrong */
2003 memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
2004
2005 if (version == 0) {
2006 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2007 pdp->qos_req0, sizeof(pdp->qos_req0))) {
2008 gsn->missing++;
2009 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2010 "Missing mandatory information field");
2011 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2012 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
2013 pdp, GTPCAUSE_MAN_IE_MISSING);
2014 }
2015 }
2016
2017 /* Recovery (optional) */
jjako52c24142002-12-16 13:33:51 +00002018 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
Harald Welte629e9862010-12-24 20:58:09 +01002019 if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery);
jjako52c24142002-12-16 13:33:51 +00002020 }
2021
jjako08d331d2003-10-13 20:33:30 +00002022 if (version == 0) {
2023 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
2024 gsn->missing++;
2025 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2026 "Missing mandatory information field");
2027 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2028 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2029 GTPCAUSE_MAN_IE_MISSING);
2030 }
2031
2032 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
2033 gsn->missing++;
2034 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2035 "Missing mandatory information field");
2036 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2037 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2038 GTPCAUSE_MAN_IE_MISSING);
2039 }
2040 }
2041
2042
2043 if (version == 1) {
2044 /* TEID (mandatory) */
2045 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
2046 gsn->missing++;
2047 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2048 "Missing mandatory information field");
2049 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2050 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2051 GTPCAUSE_MAN_IE_MISSING);
2052 }
jjako2c381332003-10-21 19:09:53 +00002053
jjako08d331d2003-10-13 20:33:30 +00002054 /* TEIC (conditional) */
2055 /* If TEIC is not included it means that we have allready received it */
jjako2c381332003-10-21 19:09:53 +00002056 /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
2057 /* all updated contexts, or only for one of the linked contexts */
2058 gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn);
2059
jjako08d331d2003-10-13 20:33:30 +00002060 /* NSAPI (mandatory) */
2061 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
2062 gsn->missing++;
2063 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2064 "Missing mandatory information field");
2065 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2066 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2067 GTPCAUSE_MAN_IE_MISSING);
2068 }
2069 }
2070
2071 /* Trace reference (optional) */
2072 /* Trace type (optional) */
2073
2074 /* End User Address (conditional) TODO: GGSN Initiated
2075 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2076 &pdp->eua.v, sizeof(pdp->eua.v))) {
jjako52c24142002-12-16 13:33:51 +00002077 gsn->missing++;
2078 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2079 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002080 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2081 return gtp_update_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00002082 GTPCAUSE_MAN_IE_MISSING);
jjako08d331d2003-10-13 20:33:30 +00002083 } */
jjako52c24142002-12-16 13:33:51 +00002084
jjako08d331d2003-10-13 20:33:30 +00002085
2086 /* SGSN address for signalling (mandatory) */
2087 /* It is weird that this is mandatory when TEIC is conditional */
2088 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2089 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
jjako52c24142002-12-16 13:33:51 +00002090 gsn->missing++;
2091 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2092 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002093 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2094 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002095 GTPCAUSE_MAN_IE_MISSING);
2096 }
2097
jjako08d331d2003-10-13 20:33:30 +00002098 /* SGSN address for user traffic (mandatory) */
2099 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2100 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
jjako52c24142002-12-16 13:33:51 +00002101 gsn->missing++;
2102 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2103 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002104 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2105 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002106 GTPCAUSE_MAN_IE_MISSING);
2107 }
jjako08d331d2003-10-13 20:33:30 +00002108
2109 if (version == 1) {
2110 /* QoS (mandatory) */
2111 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
2112 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
2113 gsn->missing++;
2114 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2115 "Missing mandatory information field");
2116 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2117 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2118 GTPCAUSE_MAN_IE_MISSING);
2119 }
jjako52c24142002-12-16 13:33:51 +00002120
jjako08d331d2003-10-13 20:33:30 +00002121 /* TFT (conditional) */
2122 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
2123 &pdp->tft.v, sizeof(pdp->tft.v))) {
2124 }
2125
2126 /* OMC identity */
jjako52c24142002-12-16 13:33:51 +00002127 }
2128
jjako52c24142002-12-16 13:33:51 +00002129 /* Confirm to peer that things were "successful" */
jjako08d331d2003-10-13 20:33:30 +00002130 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002131 GTPCAUSE_ACC_REQ);
2132}
2133
2134
2135/* Handle Update PDP Context Response */
2136int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
2137 struct sockaddr_in *peer,
2138 void *pack, unsigned len) {
2139 struct pdp_t *pdp;
2140 union gtpie_member *ie[GTPIE_SIZE];
2141 uint8_t cause, recovery;
jjako08d331d2003-10-13 20:33:30 +00002142 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00002143 uint8_t type = 0;
2144
2145 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00002146 if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00002147
2148 /* Find the context in question */
2149 if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) {
2150 gsn->err_unknownpdp++;
2151 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2152 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00002153 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002154 return EOF;
2155 }
2156
jjako2c381332003-10-21 19:09:53 +00002157 /* Register that we have received a valid teic from GGSN */
2158 pdp->teic_confirmed = 1;
2159
jjako52c24142002-12-16 13:33:51 +00002160 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002161 if (gtpie_decaps(ie, 0, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) {
jjako52c24142002-12-16 13:33:51 +00002162 gsn->invalid++;
2163 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2164 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +00002165 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002166 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2167 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002168 return EOF;
2169 }
2170
2171 /* Extract cause value (mandatory) */
2172 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2173 gsn->missing++;
2174 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2175 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002176 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002177 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2178 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002179 return EOF;
2180 }
2181
2182 /* Extract recovery (optional) */
2183 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
Harald Welte629e9862010-12-24 20:58:09 +01002184 if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery);
jjako52c24142002-12-16 13:33:51 +00002185 }
2186
2187 /* Check all conditional information elements */
2188 if (GTPCAUSE_ACC_REQ != cause) {
jjako08d331d2003-10-13 20:33:30 +00002189 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002190 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2191 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002192 return 0;
2193 }
2194 else {
2195 /* Check for missing conditionary information elements */
2196 if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) &&
2197 gtpie_exist(ie, GTPIE_REORDER, 0) &&
2198 gtpie_exist(ie, GTPIE_FL_DI, 0) &&
2199 gtpie_exist(ie, GTPIE_FL_C, 0) &&
2200 gtpie_exist(ie, GTPIE_CHARGING_ID, 0) &&
2201 gtpie_exist(ie, GTPIE_EUA, 0) &&
2202 gtpie_exist(ie, GTPIE_GSN_ADDR, 0) &&
2203 gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) {
2204 gsn->missing++;
2205 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2206 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00002207 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002208 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2209 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002210 return EOF;
2211 }
2212
2213 /* Update pdp with new values */
2214 gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2215 pdp->qos_neg0, sizeof(pdp->qos_neg0));
2216 gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder);
2217 gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru);
2218 gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc);
2219 gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid);
2220 gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2221 &pdp->eua.v, sizeof(pdp->eua.v));
2222 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2223 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v));
2224 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2225 &pdp->gsnru.v, sizeof(pdp->gsnru.v));
2226
jjako08d331d2003-10-13 20:33:30 +00002227 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako52c24142002-12-16 13:33:51 +00002228 return 0; /* Succes */
2229 }
2230}
2231
jjako52c24142002-12-16 13:33:51 +00002232
jjako08d331d2003-10-13 20:33:30 +00002233/* API: Send Delete PDP Context Request */
jjako2c381332003-10-21 19:09:53 +00002234int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
2235 int teardown) {
jjako08d331d2003-10-13 20:33:30 +00002236 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02002237 unsigned int length = get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
jjako08d331d2003-10-13 20:33:30 +00002238 struct in_addr addr;
jjako2c381332003-10-21 19:09:53 +00002239 struct pdp_t *linked_pdp;
2240 struct pdp_t *secondary_pdp;
2241 int n;
2242 int count = 0;
2243
jjako52c24142002-12-16 13:33:51 +00002244 if (gsna2in_addr(&addr, &pdp->gsnrc)) {
2245 gsn->err_address++;
2246 gtp_err(LOG_ERR, __FILE__, __LINE__, "GSN address conversion failed");
2247 return EOF;
2248 }
jjako2c381332003-10-21 19:09:53 +00002249
2250 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
2251 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context");
2252 return EOF;
2253 }
2254
2255 if (!teardown) {
2256 for (n=0; n< PDP_MAXNSAPI; n++)
2257 if (linked_pdp->secondary_tei[n]) count++;
2258 if (count <= 1) {
2259 gtp_err(LOG_ERR, __FILE__, __LINE__,
2260 "Must use teardown for last context");
2261 return EOF;
2262 }
2263 }
2264
jjako08d331d2003-10-13 20:33:30 +00002265 if (pdp->version == 1) {
jjako2c381332003-10-21 19:09:53 +00002266 if (teardown)
2267 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
2268 0xff);
Harald Weltecc9f0832010-05-04 11:16:09 +02002269
2270 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
2271 pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00002272 }
jjako52c24142002-12-16 13:33:51 +00002273
jjako2c381332003-10-21 19:09:53 +00002274 gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
jjako52c24142002-12-16 13:33:51 +00002275
jjako2c381332003-10-21 19:09:53 +00002276 if (teardown) { /* Remove all contexts */
2277 for (n=0; n< PDP_MAXNSAPI; n++) {
2278 if (linked_pdp->secondary_tei[n]) {
2279 if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) {
2280 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown secondary PDP context");
2281 return EOF;
2282 }
2283 if (linked_pdp != secondary_pdp) {
2284 if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp);
2285 pdp_freepdp(secondary_pdp);
2286 }
2287 }
2288 }
2289 if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp);
2290 pdp_freepdp(linked_pdp);
2291 }
2292 else {
2293 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2294 if (pdp == linked_pdp) {
2295 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2296 linked_pdp->nodata = 1;
2297 }
2298 else
2299 pdp_freepdp(pdp);
2300 }
2301
2302 return 0;
2303}
jjako08d331d2003-10-13 20:33:30 +00002304
jjako52c24142002-12-16 13:33:51 +00002305/* Send Delete PDP Context Response */
2306int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002307 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002308 void *pack, unsigned len,
jjako2c381332003-10-21 19:09:53 +00002309 struct pdp_t *pdp, struct pdp_t *linked_pdp,
2310 uint8_t cause, int teardown)
jjako52c24142002-12-16 13:33:51 +00002311{
2312 union gtp_packet packet;
jjako2c381332003-10-21 19:09:53 +00002313 struct pdp_t *secondary_pdp;
Harald Weltef54a1f42010-05-04 11:08:38 +02002314 unsigned int length = get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet);
jjako2c381332003-10-21 19:09:53 +00002315 int n;
jjako52c24142002-12-16 13:33:51 +00002316
jjako08d331d2003-10-13 20:33:30 +00002317 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00002318
jjako08d331d2003-10-13 20:33:30 +00002319 gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
jjako2c381332003-10-21 19:09:53 +00002320 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002321
jjako2c381332003-10-21 19:09:53 +00002322 if (cause == GTPCAUSE_ACC_REQ) {
2323 if ((teardown) || (version == 0)) { /* Remove all contexts */
2324 for (n=0; n< PDP_MAXNSAPI; n++) {
2325 if (linked_pdp->secondary_tei[n]) {
2326 if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) {
2327 gtp_err(LOG_ERR, __FILE__, __LINE__,
2328 "Unknown secondary PDP context");
2329 return EOF;
2330 }
2331 if (linked_pdp != secondary_pdp) {
2332 if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp);
2333 pdp_freepdp(secondary_pdp);
2334 }
2335 }
2336 }
2337 if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp);
2338 pdp_freepdp(linked_pdp);
2339 }
2340 else { /* Remove only current context */
2341 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2342 if (pdp == linked_pdp) {
2343 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2344 linked_pdp->nodata = 1;
2345 }
2346 else
2347 pdp_freepdp(pdp);
2348 }
2349 } /* if (cause == GTPCAUSE_ACC_REQ) */
jjako52c24142002-12-16 13:33:51 +00002350
jjako08d331d2003-10-13 20:33:30 +00002351 return 0;
jjako52c24142002-12-16 13:33:51 +00002352}
2353
2354/* Handle Delete PDP Context Request */
2355int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002356 struct sockaddr_in *peer, int fd,
2357 void *pack, unsigned len) {
jjako2c381332003-10-21 19:09:53 +00002358 struct pdp_t *pdp = NULL;
2359 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00002360 union gtpie_member* ie[GTPIE_SIZE];
jjako08d331d2003-10-13 20:33:30 +00002361
2362 uint16_t seq = get_seq(pack);
2363 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002364
jjako08d331d2003-10-13 20:33:30 +00002365 uint8_t nsapi;
jjako2c381332003-10-21 19:09:53 +00002366 uint8_t teardown = 0;
2367 int n;
2368 int count = 0;
2369
jjako52c24142002-12-16 13:33:51 +00002370 /* Is this a dublicate ? */
jjako08d331d2003-10-13 20:33:30 +00002371 if(!gtp_dublicate(gsn, version, peer, seq)) {
2372 return 0; /* We allready send off response once */
jjako52c24142002-12-16 13:33:51 +00002373 }
2374
jjako2c381332003-10-21 19:09:53 +00002375 /* Find the linked context in question */
2376 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
jjako52c24142002-12-16 13:33:51 +00002377 gsn->err_unknownpdp++;
2378 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2379 "Unknown PDP context");
jjako2c381332003-10-21 19:09:53 +00002380 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2381 GTPCAUSE_NON_EXIST, teardown);
jjako52c24142002-12-16 13:33:51 +00002382 }
jjako2c381332003-10-21 19:09:53 +00002383
2384 /* If version 0 this is also the secondary context */
2385 if (version == 0)
2386 pdp = linked_pdp;
jjako52c24142002-12-16 13:33:51 +00002387
2388 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002389 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00002390 gsn->invalid++;
2391 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2392 "Invalid message format");
2393 if (0 == version)
2394 return EOF;
2395 else
jjako2c381332003-10-21 19:09:53 +00002396 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2397 GTPCAUSE_INVALID_MESSAGE, teardown);
jjako52c24142002-12-16 13:33:51 +00002398 }
jjako2c381332003-10-21 19:09:53 +00002399
jjako08d331d2003-10-13 20:33:30 +00002400 if (version == 1) {
2401 /* NSAPI (mandatory) */
2402 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
2403 gsn->missing++;
2404 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2405 "Missing mandatory information field");
jjako2c381332003-10-21 19:09:53 +00002406 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2407 GTPCAUSE_MAN_IE_MISSING, teardown);
jjako08d331d2003-10-13 20:33:30 +00002408 }
jjako2c381332003-10-21 19:09:53 +00002409
2410 /* Find the context in question */
2411 if (pdp_getgtp1(&pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) {
2412 gsn->err_unknownpdp++;
2413 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2414 "Unknown PDP context");
2415 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2416 GTPCAUSE_NON_EXIST, teardown);
2417 }
jjako08d331d2003-10-13 20:33:30 +00002418
2419 /* Teardown (conditional) */
jjako2c381332003-10-21 19:09:53 +00002420 gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown);
2421
2422 if (!teardown) {
2423 for (n=0; n< PDP_MAXNSAPI; n++)
2424 if (linked_pdp->secondary_tei[n]) count++;
2425 if (count <= 1) {
2426 return 0; /* 29.060 7.3.5 Ignore message */
2427 }
jjako08d331d2003-10-13 20:33:30 +00002428 }
2429 }
jjako2c381332003-10-21 19:09:53 +00002430
2431 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2432 pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown);
jjako52c24142002-12-16 13:33:51 +00002433}
2434
2435
2436/* Handle Delete PDP Context Response */
2437int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
2438 struct sockaddr_in *peer,
2439 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00002440 union gtpie_member *ie[GTPIE_SIZE];
2441 uint8_t cause;
jjako08d331d2003-10-13 20:33:30 +00002442 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00002443 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +00002444 int hlen = get_hlen(pack);
2445
jjako52c24142002-12-16 13:33:51 +00002446 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00002447 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00002448
jjako52c24142002-12-16 13:33:51 +00002449 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002450 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00002451 gsn->invalid++;
2452 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2453 "Invalid message format");
jjako2c381332003-10-21 19:09:53 +00002454 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002455 return EOF;
2456 }
2457
jjako08d331d2003-10-13 20:33:30 +00002458 /* Extract cause value (mandatory) */
jjako52c24142002-12-16 13:33:51 +00002459 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2460 gsn->missing++;
2461 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2462 "Missing mandatory information field");
jjako2c381332003-10-21 19:09:53 +00002463 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002464 return EOF;
2465 }
2466
jjako2c381332003-10-21 19:09:53 +00002467 /* Check the cause value (again) */
2468 if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
jjako52c24142002-12-16 13:33:51 +00002469 gsn->err_cause++;
2470 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2471 "Unexpected cause value received: %d", cause);
jjako2c381332003-10-21 19:09:53 +00002472 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
2473 return EOF;
jjako52c24142002-12-16 13:33:51 +00002474 }
jjako2c381332003-10-21 19:09:53 +00002475
jjako08d331d2003-10-13 20:33:30 +00002476 /* Callback function to notify application */
jjako2c381332003-10-21 19:09:53 +00002477 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002478
2479 return 0;
2480}
2481
2482/* Send Error Indication (response to a GPDU message */
2483int gtp_error_ind_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002484 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002485 void *pack, unsigned len)
2486{
2487 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02002488 unsigned int length = get_default_gtp(version, GTP_ERROR, &packet);
jjako52c24142002-12-16 13:33:51 +00002489
jjako08d331d2003-10-13 20:33:30 +00002490 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
2491 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002492}
2493
2494/* Handle Error Indication */
2495int gtp_error_ind_conf(struct gsn_t *gsn, int version,
2496 struct sockaddr_in *peer,
2497 void *pack, unsigned len) {
2498 struct pdp_t *pdp;
2499
2500 /* Find the context in question */
2501 if (pdp_tidget(&pdp, ((union gtp_packet*)pack)->gtp0.h.tid)) {
2502 gsn->err_unknownpdp++;
2503 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2504 "Unknown PDP context");
2505 return EOF;
2506 }
2507
2508 gsn->err_unknownpdp++; /* TODO: Change counter */
2509 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2510 "Received Error Indication");
2511
2512 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2513 pdp_freepdp(pdp);
2514 return 0;
2515}
2516
2517int gtp_gpdu_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002518 struct sockaddr_in *peer, int fd,
2519 void *pack, unsigned len) {
2520
2521 int hlen = GTP1_HEADER_SIZE_SHORT;
jjako52c24142002-12-16 13:33:51 +00002522
2523 /* Need to include code to verify packet src and dest addresses */
2524 struct pdp_t *pdp;
jjako1db1c812003-07-06 20:53:57 +00002525
jjako08d331d2003-10-13 20:33:30 +00002526 if (version == 0) {
2527 if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) {
2528 gsn->err_unknownpdp++;
2529 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2530 "Unknown PDP context");
2531 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2532 }
2533 hlen = GTP0_HEADER_SIZE;
2534 }
2535 else if (version == 1) {
2536 if (pdp_getgtp1(&pdp, ntoh32(((union gtp_packet*)pack)->gtp1l.h.tei))) {
2537 gsn->err_unknownpdp++;
2538 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2539 "Unknown PDP context");
2540 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2541 }
2542
2543 /* Is this a long or a short header ? */
2544 if (((union gtp_packet*)pack)->gtp1l.h.flags & 0x07)
2545 hlen = GTP1_HEADER_SIZE_LONG;
2546 else
2547 hlen = GTP1_HEADER_SIZE_SHORT;
2548 }
2549 else {
2550 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2551 "Unknown version");
2552 }
2553
jjako1db1c812003-07-06 20:53:57 +00002554 /* If the GPDU was not from the peer GSN tell him to delete context */
2555 if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
2556 gsn->err_unknownpdp++;
2557 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2558 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00002559 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
jjako1db1c812003-07-06 20:53:57 +00002560 }
jjako08d331d2003-10-13 20:33:30 +00002561
jjako52c24142002-12-16 13:33:51 +00002562 /* Callback function */
jjako08d331d2003-10-13 20:33:30 +00002563 if (gsn->cb_data_ind !=0)
2564 return gsn->cb_data_ind(pdp, pack+hlen, len-hlen);
jjako52c24142002-12-16 13:33:51 +00002565
2566 return 0;
2567}
2568
2569
jjako08d331d2003-10-13 20:33:30 +00002570
jjako52c24142002-12-16 13:33:51 +00002571/* Receives GTP packet and sends off for further processing
2572 * Function will check the validity of the header. If the header
2573 * is not valid the packet is either dropped or a version not
2574 * supported is returned to the peer.
2575 * TODO: Need to decide on return values! */
jjako08d331d2003-10-13 20:33:30 +00002576int gtp_decaps0(struct gsn_t *gsn)
jjako52c24142002-12-16 13:33:51 +00002577{
jjako2c381332003-10-21 19:09:53 +00002578 unsigned char buffer[PACKET_MAX];
jjako52c24142002-12-16 13:33:51 +00002579 struct sockaddr_in peer;
Harald Weltef54a1f42010-05-04 11:08:38 +02002580 size_t peerlen;
jjako08d331d2003-10-13 20:33:30 +00002581 int status;
jjako52c24142002-12-16 13:33:51 +00002582 struct gtp0_header *pheader;
2583 int version = 0; /* GTP version should be determined from header!*/
jjako08d331d2003-10-13 20:33:30 +00002584 int fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00002585
jjakoa7cd2492003-04-11 09:40:12 +00002586 /* TODO: Need strategy of userspace buffering and blocking */
2587 /* Currently read is non-blocking and send is blocking. */
2588 /* This means that the program have to wait for busy send calls...*/
jjako52c24142002-12-16 13:33:51 +00002589
jjakoa7cd2492003-04-11 09:40:12 +00002590 while (1) { /* Loop until no more to read */
jjako08d331d2003-10-13 20:33:30 +00002591 if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) {
jjakoa7cd2492003-04-11 09:40:12 +00002592 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2593 return -1;
2594 }
2595 peerlen = sizeof(peer);
2596 if ((status =
jjako08d331d2003-10-13 20:33:30 +00002597 recvfrom(gsn->fd0, buffer, sizeof(buffer), 0,
jjakoa7cd2492003-04-11 09:40:12 +00002598 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
jjako08d331d2003-10-13 20:33:30 +00002599 if (errno == EAGAIN) return 0;
jjakoa7cd2492003-04-11 09:40:12 +00002600 gsn->err_readfrom++;
jjako08d331d2003-10-13 20:33:30 +00002601 gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd0=%d, buffer=%lx, len=%d) failed: status = %d error = %s", gsn->fd0, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error");
jjakoa7cd2492003-04-11 09:40:12 +00002602 return -1;
2603 }
jjako52c24142002-12-16 13:33:51 +00002604
jjakoa7cd2492003-04-11 09:40:12 +00002605 /* Need at least 1 byte in order to check version */
2606 if (status < (1)) {
2607 gsn->empty++;
2608 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2609 "Discarding packet - too small");
2610 continue;
2611 }
2612
jjako08d331d2003-10-13 20:33:30 +00002613 pheader = (struct gtp0_header *) (buffer);
jjakoa7cd2492003-04-11 09:40:12 +00002614
jjako08d331d2003-10-13 20:33:30 +00002615 /* Version should be gtp0 (or earlier) */
2616 /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
2617 /* GTP 0 messages. If other version message is received we reply that we */
2618 /* only support version 0, implying that this is the only version */
2619 /* supported on this port */
jjakoa7cd2492003-04-11 09:40:12 +00002620 if (((pheader->flags & 0xe0) > 0x00)) {
2621 gsn->unsup++;
2622 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2623 "Unsupported GTP version");
jjako08d331d2003-10-13 20:33:30 +00002624 gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */
jjakoa7cd2492003-04-11 09:40:12 +00002625 continue;
2626 }
2627
2628 /* Check length of gtp0 packet */
jjako08d331d2003-10-13 20:33:30 +00002629 if (status < GTP0_HEADER_SIZE) {
jjakoa7cd2492003-04-11 09:40:12 +00002630 gsn->tooshort++;
2631 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2632 "GTP0 packet too short");
2633 continue; /* Silently discard 29.60: 11.1.2 */
2634 }
jjako1db1c812003-07-06 20:53:57 +00002635
jjako08d331d2003-10-13 20:33:30 +00002636 /* Check packet length field versus length of packet */
2637 if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
2638 gsn->tooshort++;
2639 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2640 "GTP packet length field does not match actual length");
2641 continue; /* Silently discard */
2642 }
2643
2644 if ((gsn->mode == GTP_MODE_GGSN) &&
2645 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2646 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2647 (pheader->type == GTP_DELETE_PDP_RSP))) {
2648 gsn->unexpect++;
2649 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2650 "Unexpected GTP Signalling Message");
2651 continue; /* Silently discard 29.60: 11.1.4 */
2652 }
2653
2654 if ((gsn->mode == GTP_MODE_SGSN) &&
2655 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2656 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2657 (pheader->type == GTP_DELETE_PDP_REQ))) {
2658 gsn->unexpect++;
2659 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2660 "Unexpected GTP Signalling Message");
2661 continue; /* Silently discard 29.60: 11.1.4 */
2662 }
2663
2664 switch (pheader->type) {
2665 case GTP_ECHO_REQ:
2666 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2667 break;
2668 case GTP_ECHO_RSP:
2669 gtp_echo_conf(gsn, version, &peer, buffer, status);
2670 break;
2671 case GTP_NOT_SUPPORTED:
2672 gtp_unsup_ind(gsn, &peer, buffer, status);
2673 break;
2674 case GTP_CREATE_PDP_REQ:
2675 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status);
2676 break;
2677 case GTP_CREATE_PDP_RSP:
2678 gtp_create_pdp_conf(gsn, version, &peer, buffer, status);
2679 break;
2680 case GTP_UPDATE_PDP_REQ:
2681 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status);
2682 break;
2683 case GTP_UPDATE_PDP_RSP:
2684 gtp_update_pdp_conf(gsn, version, &peer, buffer, status);
2685 break;
2686 case GTP_DELETE_PDP_REQ:
2687 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status);
2688 break;
2689 case GTP_DELETE_PDP_RSP:
2690 gtp_delete_pdp_conf(gsn, version, &peer, buffer, status);
2691 break;
2692 case GTP_ERROR:
2693 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2694 break;
2695 case GTP_GPDU:
2696 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2697 break;
2698 default:
2699 gsn->unknown++;
2700 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2701 "Unknown GTP message type received");
2702 break;
2703 }
2704 }
2705}
2706
2707
2708int gtp_decaps1c(struct gsn_t *gsn)
2709{
jjako2c381332003-10-21 19:09:53 +00002710 unsigned char buffer[PACKET_MAX];
jjako08d331d2003-10-13 20:33:30 +00002711 struct sockaddr_in peer;
Harald Weltef54a1f42010-05-04 11:08:38 +02002712 size_t peerlen;
jjako08d331d2003-10-13 20:33:30 +00002713 int status;
2714 struct gtp1_header_short *pheader;
jjako2c381332003-10-21 19:09:53 +00002715 int version = 1; /* TODO GTP version should be determined from header!*/
jjako08d331d2003-10-13 20:33:30 +00002716 int fd = gsn->fd1c;
2717
2718 /* TODO: Need strategy of userspace buffering and blocking */
2719 /* Currently read is non-blocking and send is blocking. */
2720 /* This means that the program have to wait for busy send calls...*/
2721
2722 while (1) { /* Loop until no more to read */
jjako2c381332003-10-21 19:09:53 +00002723 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
jjako08d331d2003-10-13 20:33:30 +00002724 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2725 return -1;
2726 }
2727 peerlen = sizeof(peer);
2728 if ((status =
jjako2c381332003-10-21 19:09:53 +00002729 recvfrom(fd, buffer, sizeof(buffer), 0,
jjako08d331d2003-10-13 20:33:30 +00002730 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
2731 if (errno == EAGAIN) return 0;
2732 gsn->err_readfrom++;
jjako2c381332003-10-21 19:09:53 +00002733 gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd=%d, buffer=%lx, len=%d) failed: status = %d error = %s", fd, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error");
jjako08d331d2003-10-13 20:33:30 +00002734 return -1;
2735 }
2736
2737 /* Need at least 1 byte in order to check version */
2738 if (status < (1)) {
2739 gsn->empty++;
2740 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2741 "Discarding packet - too small");
2742 continue;
2743 }
2744
2745 pheader = (struct gtp1_header_short *) (buffer);
2746
2747 /* Version must be no larger than GTP 1 */
2748 if (((pheader->flags & 0xe0) > 0x20)) {
2749 gsn->unsup++;
2750 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2751 "Unsupported GTP version");
jjako2c381332003-10-21 19:09:53 +00002752 gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
2753 /*29.60: 11.1.1*/
jjako08d331d2003-10-13 20:33:30 +00002754 continue;
2755 }
2756
2757 /* Version must be at least GTP 1 */
2758 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2759 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2760 /* the message */
2761 if (((pheader->flags & 0xe0) < 0x20)) {
2762 gsn->unsup++;
2763 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2764 "Unsupported GTP version");
2765 continue;
2766 }
2767
2768 /* Check packet flag field */
2769 if (((pheader->flags & 0xf7) != 0x32)) {
2770 gsn->unsup++;
2771 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2772 "Unsupported packet flag");
2773 continue;
2774 }
2775
2776 /* Check length of packet */
2777 if (status < GTP1_HEADER_SIZE_LONG) {
2778 gsn->tooshort++;
2779 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2780 "GTP packet too short");
2781 continue; /* Silently discard 29.60: 11.1.2 */
2782 }
2783
2784 /* Check packet length field versus length of packet */
2785 if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
2786 gsn->tooshort++;
2787 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2788 "GTP packet length field does not match actual length");
2789 continue; /* Silently discard */
2790 }
2791
jjako2c381332003-10-21 19:09:53 +00002792 /* Check for extension headers */
2793 /* TODO: We really should cycle through the headers and determine */
2794 /* if any have the comprehension required flag set */
2795 if (((pheader->flags & 0x04) != 0x00)) {
2796 gsn->unsup++;
2797 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2798 "Unsupported extension header");
2799 gtp_extheader_req(gsn, version, &peer, fd, buffer, status);
2800
2801 continue;
2802 }
2803
jjako1db1c812003-07-06 20:53:57 +00002804 if ((gsn->mode == GTP_MODE_GGSN) &&
2805 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2806 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2807 (pheader->type == GTP_DELETE_PDP_RSP))) {
2808 gsn->unexpect++;
2809 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2810 "Unexpected GTP Signalling Message");
2811 continue; /* Silently discard 29.60: 11.1.4 */
2812 }
2813
2814 if ((gsn->mode == GTP_MODE_SGSN) &&
2815 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2816 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2817 (pheader->type == GTP_DELETE_PDP_REQ))) {
2818 gsn->unexpect++;
2819 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2820 "Unexpected GTP Signalling Message");
2821 continue; /* Silently discard 29.60: 11.1.4 */
2822 }
2823
jjakoa7cd2492003-04-11 09:40:12 +00002824 switch (pheader->type) {
2825 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +00002826 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002827 break;
2828 case GTP_ECHO_RSP:
jjako08d331d2003-10-13 20:33:30 +00002829 gtp_echo_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002830 break;
2831 case GTP_NOT_SUPPORTED:
jjako08d331d2003-10-13 20:33:30 +00002832 gtp_unsup_ind(gsn, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002833 break;
jjako2c381332003-10-21 19:09:53 +00002834 case GTP_SUPP_EXT_HEADER:
2835 gtp_extheader_ind(gsn, &peer, buffer, status);
2836 break;
jjakoa7cd2492003-04-11 09:40:12 +00002837 case GTP_CREATE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002838 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002839 break;
2840 case GTP_CREATE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002841 gtp_create_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002842 break;
2843 case GTP_UPDATE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002844 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002845 break;
2846 case GTP_UPDATE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002847 gtp_update_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002848 break;
2849 case GTP_DELETE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002850 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002851 break;
2852 case GTP_DELETE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002853 gtp_delete_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002854 break;
2855 case GTP_ERROR:
jjako08d331d2003-10-13 20:33:30 +00002856 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002857 break;
2858 default:
jjako52c24142002-12-16 13:33:51 +00002859 gsn->unknown++;
2860 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2861 "Unknown GTP message type received");
jjakoa7cd2492003-04-11 09:40:12 +00002862 break;
jjako52c24142002-12-16 13:33:51 +00002863 }
2864 }
2865}
2866
jjako08d331d2003-10-13 20:33:30 +00002867int gtp_decaps1u(struct gsn_t *gsn)
2868{
jjako2c381332003-10-21 19:09:53 +00002869 unsigned char buffer[PACKET_MAX];
jjako08d331d2003-10-13 20:33:30 +00002870 struct sockaddr_in peer;
Harald Weltef54a1f42010-05-04 11:08:38 +02002871 size_t peerlen;
jjako08d331d2003-10-13 20:33:30 +00002872 int status;
2873 struct gtp1_header_short *pheader;
2874 int version = 1; /* GTP version should be determined from header!*/
2875 int fd = gsn->fd1u;
2876
2877 /* TODO: Need strategy of userspace buffering and blocking */
2878 /* Currently read is non-blocking and send is blocking. */
2879 /* This means that the program have to wait for busy send calls...*/
2880
2881 while (1) { /* Loop until no more to read */
2882 if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) {
2883 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2884 return -1;
2885 }
2886 peerlen = sizeof(peer);
2887 if ((status =
2888 recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0,
2889 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
2890 if (errno == EAGAIN) return 0;
2891 gsn->err_readfrom++;
2892 gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd1u=%d, buffer=%lx, len=%d) failed: status = %d error = %s", gsn->fd1u, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error");
2893 return -1;
2894 }
2895
2896 /* Need at least 1 byte in order to check version */
2897 if (status < (1)) {
2898 gsn->empty++;
2899 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2900 "Discarding packet - too small");
2901 continue;
2902 }
2903
2904 pheader = (struct gtp1_header_short *) (buffer);
2905
2906 /* Version must be no larger than GTP 1 */
2907 if (((pheader->flags & 0xe0) > 0x20)) {
2908 gsn->unsup++;
2909 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2910 "Unsupported GTP version");
2911 gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status);/*29.60: 11.1.1*/
2912 continue;
2913 }
2914
2915 /* Version must be at least GTP 1 */
2916 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2917 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2918 /* the message */
2919 if (((pheader->flags & 0xe0) < 0x20)) {
2920 gsn->unsup++;
2921 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2922 "Unsupported GTP version");
2923 continue;
2924 }
2925
2926 /* Check packet flag field (allow both with and without sequence number)*/
2927 if (((pheader->flags & 0xf5) != 0x30)) {
2928 gsn->unsup++;
2929 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2930 "Unsupported packet flag");
2931 continue;
2932 }
2933
2934 /* Check length of packet */
2935 if (status < GTP1_HEADER_SIZE_SHORT) {
2936 gsn->tooshort++;
2937 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2938 "GTP packet too short");
2939 continue; /* Silently discard 29.60: 11.1.2 */
2940 }
2941
2942 /* Check packet length field versus length of packet */
2943 if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
2944 gsn->tooshort++;
2945 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2946 "GTP packet length field does not match actual length");
2947 continue; /* Silently discard */
2948 }
jjako2c381332003-10-21 19:09:53 +00002949
2950 /* Check for extension headers */
2951 /* TODO: We really should cycle through the headers and determine */
2952 /* if any have the comprehension required flag set */
2953 if (((pheader->flags & 0x04) != 0x00)) {
2954 gsn->unsup++;
2955 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2956 "Unsupported extension header");
2957 gtp_extheader_req(gsn, version, &peer, fd, buffer, status);
2958
2959 continue;
2960 }
jjako08d331d2003-10-13 20:33:30 +00002961
2962 switch (pheader->type) {
2963 case GTP_ECHO_REQ:
2964 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2965 break;
2966 case GTP_ECHO_RSP:
2967 gtp_echo_conf(gsn, version, &peer, buffer, status);
2968 break;
jjako2c381332003-10-21 19:09:53 +00002969 case GTP_SUPP_EXT_HEADER:
2970 gtp_extheader_ind(gsn, &peer, buffer, status);
2971 break;
jjako08d331d2003-10-13 20:33:30 +00002972 case GTP_ERROR:
2973 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2974 break;
2975 /* Supported header extensions */
2976 case GTP_GPDU:
2977 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2978 break;
2979 default:
2980 gsn->unknown++;
2981 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2982 "Unknown GTP message type received");
2983 break;
2984 }
2985 }
2986}
2987
2988int gtp_data_req(struct gsn_t *gsn, struct pdp_t* pdp,
jjako52c24142002-12-16 13:33:51 +00002989 void *pack, unsigned len)
2990{
2991 union gtp_packet packet;
2992 struct sockaddr_in addr;
jjako08d331d2003-10-13 20:33:30 +00002993 int fd;
2994 int length;
jjako52c24142002-12-16 13:33:51 +00002995
2996 memset(&addr, 0, sizeof(addr));
2997 addr.sin_family = AF_INET;
jjako0fe0df02004-09-17 11:30:40 +00002998#if defined(__FreeBSD__) || defined(__APPLE__)
jjako06e9f122004-01-19 18:37:58 +00002999 addr.sin_len = sizeof(addr);
3000#endif
3001
jjako52c24142002-12-16 13:33:51 +00003002 memcpy(&addr.sin_addr, pdp->gsnru.v,pdp->gsnru.l); /* TODO range check */
jjako52c24142002-12-16 13:33:51 +00003003
jjako08d331d2003-10-13 20:33:30 +00003004 if (pdp->version == 0) {
3005
3006 length = GTP0_HEADER_SIZE+len;
3007 addr.sin_port = htons(GTP0_PORT);
3008 fd = gsn->fd0;
3009
3010 get_default_gtp(0, GTP_GPDU, &packet);
3011 packet.gtp0.h.length = hton16(len);
3012 packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
3013 packet.gtp0.h.flow = hton16(pdp->flru);
jjako1ea66342004-01-28 09:27:34 +00003014 packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffffull) + ((uint64_t)pdp->nsapi << 60);
jjako52c24142002-12-16 13:33:51 +00003015
jjako08d331d2003-10-13 20:33:30 +00003016 if (len > sizeof (union gtp_packet) - sizeof(struct gtp0_header)) {
3017 gsn->err_memcpy++;
3018 gtp_err(LOG_ERR, __FILE__, __LINE__,
jjako1f158642004-02-05 20:39:57 +00003019 "Memcpy failed: %d > %d", len,
3020 sizeof (union gtp_packet) - sizeof(struct gtp0_header));
jjako08d331d2003-10-13 20:33:30 +00003021 return EOF;
jjako52c24142002-12-16 13:33:51 +00003022 }
jjako08d331d2003-10-13 20:33:30 +00003023 memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */
3024 }
3025 else if (pdp->version == 1) {
3026
3027 length = GTP1_HEADER_SIZE_LONG+len;
3028 addr.sin_port = htons(GTP1U_PORT);
3029 fd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00003030
jjako08d331d2003-10-13 20:33:30 +00003031 get_default_gtp(1, GTP_GPDU, &packet);
3032 packet.gtp1l.h.length = hton16(len-GTP1_HEADER_SIZE_SHORT+
3033 GTP1_HEADER_SIZE_LONG);
3034 packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
jjako2c381332003-10-21 19:09:53 +00003035 packet.gtp1l.h.tei = hton32(pdp->teid_gn);
jjako08d331d2003-10-13 20:33:30 +00003036
3037 if (len > sizeof (union gtp_packet) - sizeof(struct gtp1_header_long)) {
3038 gsn->err_memcpy++;
3039 gtp_err(LOG_ERR, __FILE__, __LINE__,
jjako1f158642004-02-05 20:39:57 +00003040 "Memcpy failed: %d > %d", len,
3041 sizeof (union gtp_packet) - sizeof(struct gtp0_header));
jjako08d331d2003-10-13 20:33:30 +00003042 return EOF;
3043 }
3044 memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */
3045 }
3046 else {
3047 gtp_err(LOG_ERR, __FILE__, __LINE__,
3048 "Unknown version");
3049 return EOF;
3050 }
3051
3052 if (fcntl(fd, F_SETFL, 0)) {
jjakoa7cd2492003-04-11 09:40:12 +00003053 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
3054 return -1;
3055 }
3056
jjako08d331d2003-10-13 20:33:30 +00003057 if (sendto(fd, &packet, length, 0,
jjako52c24142002-12-16 13:33:51 +00003058 (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3059 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +00003060 gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, GTP0_HEADER_SIZE+len, strerror(errno));
jjako52c24142002-12-16 13:33:51 +00003061 return EOF;
3062 }
3063 return 0;
3064}
3065
3066
3067/* ***********************************************************
3068 * Conversion functions
3069 *************************************************************/
3070
3071int char2ul_t(char* src, struct ul_t dst) {
3072 dst.l = strlen(src)+1;
3073 dst.v = malloc(dst.l);
3074 dst.v[0] = dst.l - 1;
3075 memcpy(&dst.v[1], src, dst.v[0]);
3076 return 0;
3077}
3078
3079/* ***********************************************************
3080 * IP address conversion functions
3081 * There exist several types of address representations:
3082 * - eua: End User Address. (29.060, 7.7.27, message type 128)
3083 * Used for signalling address to mobile station. Supports IPv4
3084 * IPv6 x.25 etc. etc.
3085 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
3086 * of GSN. If length is 4 it is IPv4. If length is 16 it is IPv6.
3087 * - in_addr: IPv4 address struct.
3088 * - sockaddr_in: Socket API representation of IP address and
3089 * port number.
3090 *************************************************************/
3091
3092int ipv42eua(struct ul66_t *eua, struct in_addr *src) {
3093 eua->v[0] = 0xf1; /* IETF */
3094 eua->v[1] = 0x21; /* IPv4 */
3095 if (src) {
3096 eua->l = 6;
3097 memcpy(&eua->v[2], src, 4);
3098 }
3099 else
3100 {
3101 eua->l = 2;
3102 }
3103 return 0;
3104}
3105
3106int eua2ipv4(struct in_addr *dst, struct ul66_t *eua) {
3107 if ((eua->l != 6) ||
3108 (eua->v[0] != 0xf1) ||
3109 (eua->v[1] = 0x21))
3110 return -1; /* Not IPv4 address*/
3111 memcpy(dst, &eua->v[2], 4);
3112 return 0;
3113}
3114
3115int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna) {
3116 memset(dst, 0, sizeof(struct in_addr));
3117 if (gsna->l != 4) return EOF; /* Return if not IPv4 */
3118 memcpy(dst, gsna->v, gsna->l);
3119 return 0;
3120}
3121
3122int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src) {
3123 memset(gsna, 0, sizeof(struct ul16_t));
3124 gsna->l = 4;
3125 memcpy(gsna->v, src, gsna->l);
3126 return 0;
3127}
3128