blob: d33a1ff8aeac5ea5b06ad044f619e0658f3bf680 [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
jjako08d331d2003-10-13 20:33:30 +0000163extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
164 int (*cb_data_ind) (struct pdp_t* pdp,
jjako52c24142002-12-16 13:33:51 +0000165 void* pack,
166 unsigned len))
167{
jjako08d331d2003-10-13 20:33:30 +0000168 gsn->cb_data_ind = cb_data_ind;
jjako52c24142002-12-16 13:33:51 +0000169 return 0;
170}
171
jjako08d331d2003-10-13 20:33:30 +0000172/**
173 * get_default_gtp()
174 * Generate a GPRS Tunneling Protocol signalling packet header, depending
175 * on GTP version and message type. pdp is used for teid/flow label.
176 * *packet must be allocated by the calling function, and be large enough
177 * to hold the packet header.
178 * returns the length of the header. 0 on error.
179 **/
Harald Weltef54a1f42010-05-04 11:08:38 +0200180static unsigned int get_default_gtp(int version, uint8_t type, void *packet) {
jjakoa7cd2492003-04-11 09:40:12 +0000181 struct gtp0_header *gtp0_default = (struct gtp0_header*) packet;
182 struct gtp1_header_long *gtp1_default = (struct gtp1_header_long*) packet;
jjako52c24142002-12-16 13:33:51 +0000183 switch (version) {
184 case 0:
jjakoa7cd2492003-04-11 09:40:12 +0000185 /* Initialise "standard" GTP0 header */
jjako08d331d2003-10-13 20:33:30 +0000186 memset(gtp0_default, 0, sizeof(struct gtp0_header));
jjakoa7cd2492003-04-11 09:40:12 +0000187 gtp0_default->flags=0x1e;
jjako08d331d2003-10-13 20:33:30 +0000188 gtp0_default->type=hton8(type);
jjakoa7cd2492003-04-11 09:40:12 +0000189 gtp0_default->spare1=0xff;
190 gtp0_default->spare2=0xff;
191 gtp0_default->spare3=0xff;
192 gtp0_default->number=0xff;
jjako08d331d2003-10-13 20:33:30 +0000193 return GTP0_HEADER_SIZE;
jjako52c24142002-12-16 13:33:51 +0000194 case 1:
jjakoa7cd2492003-04-11 09:40:12 +0000195 /* Initialise "standard" GTP1 header */
jjako08d331d2003-10-13 20:33:30 +0000196 /* 29.060: 8.2: S=1 and PN=0 */
197 /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */
198 /* and Supported Extension Headers Notification, the S field shall be */
199 /* set to 1 */
200 /* Currently extension headers are not supported */
201 memset(gtp1_default, 0, sizeof(struct gtp1_header_long));
202 gtp1_default->flags=0x32; /* No extension, enable sequence, no N-PDU */
203 gtp1_default->type=hton8(type);
204 return GTP1_HEADER_SIZE_LONG;
205 default:
206 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown GTP packet version");
207 return 0;
jjako52c24142002-12-16 13:33:51 +0000208 }
209}
210
jjako08d331d2003-10-13 20:33:30 +0000211/**
212 * get_seq()
213 * Get sequence number of a packet.
214 * Returns 0 on error
215 **/
216static uint16_t get_seq(void *pack) {
217 union gtp_packet *packet = (union gtp_packet *) pack;
218
219 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
220 return ntoh16(packet->gtp0.h.seq);
221 }
222 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
223 return ntoh16(packet->gtp1l.h.seq);
224 } else {
225 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
226 return 0;
227 }
228}
229
230/**
231 * get_tid()
232 * Get tunnel identifier of a packet.
233 * Returns 0 on error
234 **/
235static uint64_t get_tid(void *pack) {
236 union gtp_packet *packet = (union gtp_packet *) pack;
237
238 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
239 return packet->gtp0.h.tid;
240 }
241 return 0;
242}
243
244/**
245 * get_hlen()
246 * Get the header length of a packet.
247 * Returns 0 on error
248 **/
249static uint16_t get_hlen(void *pack) {
250 union gtp_packet *packet = (union gtp_packet *) pack;
251
252 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
253 return GTP0_HEADER_SIZE;
254 }
255 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
256 return GTP1_HEADER_SIZE_LONG;
257 }
258 else if ((packet->flags & 0xe7) == 0x20) { /* Short version 1 */
259 return GTP1_HEADER_SIZE_SHORT;
260 } else {
261 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
262 return 0;
263 }
264}
265
266/**
267 * get_tei()
268 * Get the tunnel endpoint identifier (flow label) of a packet.
269 * Returns 0xffffffff on error.
270 **/
271static uint32_t get_tei(void *pack) {
272 union gtp_packet *packet = (union gtp_packet *) pack;
273
274 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
275 return ntoh16(packet->gtp0.h.flow);
276 }
277 else if ((packet->flags & 0xe0) == 0x20) { /* Version 1 */
278 return ntoh32(packet->gtp1l.h.tei);
279 }
280 else {
281 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
282 return 0xffffffff;
283 }
284}
jjakoa7cd2492003-04-11 09:40:12 +0000285
286
jjako52c24142002-12-16 13:33:51 +0000287int print_packet(void *packet, unsigned len)
288{
Harald Weltef54a1f42010-05-04 11:08:38 +0200289 unsigned int i;
jjako52c24142002-12-16 13:33:51 +0000290 printf("The packet looks like this (%d bytes):\n", len);
291 for( i=0; i<len; i++) {
292 printf("%02x ", (unsigned char)*(char *)(packet+i));
293 if (!((i+1)%16)) printf("\n");
294 };
295 printf("\n");
296 return 0;
297}
298
299char* snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer,
300 void *pack, unsigned len, char *buf, int size) {
Harald Weltef54a1f42010-05-04 11:08:38 +0200301 unsigned int n;
jjako52c24142002-12-16 13:33:51 +0000302 int pos;
303 snprintf(buf, size, "Packet from %s:%u, length: %d, content:",
304 inet_ntoa(peer->sin_addr),
305 ntohs(peer->sin_port),
306 len);
jjako2e840a32003-01-28 16:05:18 +0000307 buf[size-1] = 0;
jjako52c24142002-12-16 13:33:51 +0000308 pos = strlen(buf);
309 for(n=0; n<len; n++) {
310 if ((pos+4)<size) {
311 sprintf((buf+pos), " %02hhx", ((unsigned char*)pack)[n]);
312 pos += 3;
313 }
314 }
315 buf[pos] = 0;
316 return buf;
317}
318
jjako52c24142002-12-16 13:33:51 +0000319
320/* ***********************************************************
321 * Reliable delivery of signalling messages
322 *
323 * Sequence numbers are used for both signalling messages and
324 * data messages.
325 *
326 * For data messages each tunnel maintains a sequence counter,
327 * which is incremented by one each time a new data message
328 * is sent. The sequence number starts at (0) zero at tunnel
329 * establishment, and wraps around at 65535 (29.060 9.3.1.1
330 * and 09.60 8.1.1.1). The sequence numbers are either ignored,
331 * or can be used to check the validity of the message in the
332 * receiver, or for reordering af packets.
333 *
334 * For signalling messages the sequence number is used by
335 * signalling messages for which a response is defined. A response
336 * message should copy the sequence from the corresponding request
337 * message. The sequence number "unambiguously" identifies a request
338 * message within a given path, with a path being defined as a set of
339 * two endpoints (29.060 8.2, 29.060 7.6, 09.60 7.8). "All request
340 * messages shall be responded to, and all response messages associated
341 * with a certain request shall always include the same information"
342 *
343 * We take this to mean that the GSN transmitting a request is free to
344 * choose the sequence number, as long as it is unique within a given path.
345 * It means that we are allowed to count backwards, or roll over at 17
346 * if we prefer that. It also means that we can use the same counter for
347 * all paths. This has the advantage that the transmitted request sequence
348 * numbers are unique within each GSN, and also we dont have to mess around
349 * with path setup and teardown.
350 *
351 * If a response message is lost, the request will be retransmitted, and
352 * the receiving GSN will receive a "duplicated" request. The standard
353 * requires the receiving GSN to send a response, with the same information
354 * as in the original response. For most messages this happens automatically:
355 *
356 * Echo: Automatically dublicates the original response
357 * Create pdp context: The SGSN may send create context request even if
358 * a context allready exist (imsi+nsapi?). This means that the reply will
359 automatically dublicate the original response. It might however have
jjako08d331d2003-10-13 20:33:30 +0000360 * side effects in the application which is asked twice to validate
361 * the login.
jjako52c24142002-12-16 13:33:51 +0000362 * Update pdp context: Automatically dublicates the original response???
363 * Delete pdp context. Automatically in gtp0, but in gtp1 will generate
364 * a nonexist reply message.
365 *
366 * The correct solution will be to make a queue containing response messages.
367 * This queue should be checked whenever a request is received. If the
368 * response is allready in the queue that response should be transmitted.
369 * It should be possible to find messages in this queue on the basis of
370 * the sequence number and peer GSN IP address (The sequense number is unique
371 * within each path). This need to be implemented by a hash table. Furthermore
372 * it should be possibly to delete messages based on a timeout. This can be
373 * achieved by means of a linked list. The timeout value need to be larger
374 * than T3-RESPONSE * N3-REQUESTS (recommended value 5). These timers are
375 * set in the peer GSN, so there is no way to know these parameters. On the
376 * other hand the timeout value need to be so small that we do not receive
377 * wraparound sequence numbere before the message is deleted. 60 seconds is
378 * probably not a bad choise.
379 *
380 * This queue however is first really needed from gtp1.
381 *
382 * gtp_req:
383 * Send off a signalling message with appropiate sequence
384 * number. Store packet in queue.
385 * gtp_conf:
386 * Remove an incoming confirmation from the queue
387 * gtp_resp:
jjako08d331d2003-10-13 20:33:30 +0000388 * Send off a response to a request. Use the same sequence
jjako52c24142002-12-16 13:33:51 +0000389 * number in the response as in the request.
jjako2c381332003-10-21 19:09:53 +0000390 * gtp_notification:
391 * Send off a notification message. This is neither a request nor
392 * a response. Both TEI and SEQ are zero.
jjako52c24142002-12-16 13:33:51 +0000393 * gtp_retrans:
394 * Retransmit any outstanding packets which have exceeded
395 * a predefined timeout.
396 *************************************************************/
397
jjako08d331d2003-10-13 20:33:30 +0000398int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp,
399 union gtp_packet *packet, int len,
400 struct in_addr *inetaddr, void *cbp) {
jjako52c24142002-12-16 13:33:51 +0000401 struct sockaddr_in addr;
402 struct qmsg_t *qmsg;
jjako08d331d2003-10-13 20:33:30 +0000403 int fd;
404
jjako52c24142002-12-16 13:33:51 +0000405 memset(&addr, 0, sizeof(addr));
406 addr.sin_family = AF_INET;
407 addr.sin_addr = *inetaddr;
jjako0fe0df02004-09-17 11:30:40 +0000408#if defined(__FreeBSD__) || defined(__APPLE__)
jjako06e9f122004-01-19 18:37:58 +0000409 addr.sin_len = sizeof(addr);
410#endif
jjako52c24142002-12-16 13:33:51 +0000411
jjako08d331d2003-10-13 20:33:30 +0000412 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
413 addr.sin_port = htons(GTP0_PORT);
414 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
415 packet->gtp0.h.seq = hton16(gsn->seq_next);
416 if (pdp)
jjakod48c5ff2004-01-26 22:25:40 +0000417 packet->gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffffull) +
jjako08d331d2003-10-13 20:33:30 +0000418 ((uint64_t)pdp->nsapi << 60);
419 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
420 (packet->gtp0.h.type == GTP_ERROR)))
421 packet->gtp0.h.flow=hton16(pdp->flru);
422 else if (pdp)
423 packet->gtp0.h.flow=hton16(pdp->flrc);
424 fd = gsn->fd0;
425 }
426 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
427 addr.sin_port = htons(GTP1C_PORT);
428 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
429 packet->gtp1l.h.seq = hton16(gsn->seq_next);
430 if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) ||
431 (packet->gtp1l.h.type == GTP_ERROR)))
432 packet->gtp1l.h.tei=hton32(pdp->teid_gn);
433 else if (pdp)
434 packet->gtp1l.h.tei=hton32(pdp->teic_gn);
435 fd = gsn->fd1c;
436 } else {
437 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
438 return -1;
439 }
jjako52c24142002-12-16 13:33:51 +0000440
jjako08d331d2003-10-13 20:33:30 +0000441 if (sendto(fd, packet, len, 0,
jjako52c24142002-12-16 13:33:51 +0000442 (struct sockaddr *) &addr, sizeof(addr)) < 0) {
443 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000444 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 +0000445 return -1;
446 }
447
448 /* Use new queue structure */
449 if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) {
450 gsn->err_queuefull++;
451 gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full");
452 }
453 else {
454 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
455 qmsg->l = len;
456 qmsg->timeout = time(NULL) + 3; /* When to timeout */
457 qmsg->retrans = 0; /* No retransmissions so far */
jjako08d331d2003-10-13 20:33:30 +0000458 qmsg->cbp = cbp;
jjako52c24142002-12-16 13:33:51 +0000459 qmsg->type = ntoh8(packet->gtp0.h.type);
jjako08d331d2003-10-13 20:33:30 +0000460 qmsg->fd = fd;
jjako52c24142002-12-16 13:33:51 +0000461 }
462 gsn->seq_next++; /* Count up this time */
463 return 0;
464}
465
466/* gtp_conf
467 * Remove signalling packet from retransmission queue.
468 * return 0 on success, EOF if packet was not found */
469
470int gtp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
jjako08d331d2003-10-13 20:33:30 +0000471 union gtp_packet *packet, int len, uint8_t *type, void **cbp) {
jjako52c24142002-12-16 13:33:51 +0000472
jjako08d331d2003-10-13 20:33:30 +0000473 uint16_t seq;
474
475 if ((packet->gtp0.h.flags & 0xe0) == 0x00)
476 seq = ntoh16(packet->gtp0.h.seq);
477 else if ((packet->gtp1l.h.flags & 0xe2) == 0x22)
478 seq = ntoh16(packet->gtp1l.h.seq);
479 else {
480 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
481 "Unknown GTP packet version");
482 return EOF;
483 }
484
485 if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) {
jjako52c24142002-12-16 13:33:51 +0000486 gsn->err_seq++;
487 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
488 "Confirmation packet not found in queue");
489 return EOF;
490 }
491
492 return 0;
493}
494
495int gtp_retrans(struct gsn_t *gsn) {
496 /* Retransmit any outstanding packets */
497 /* Remove from queue if maxretrans exceeded */
498 time_t now;
499 struct qmsg_t *qmsg;
500 now = time(NULL);
501 /*printf("Retrans: New beginning %d\n", (int) now);*/
502
503 while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
504 (qmsg->timeout <= now)) {
505 /*printf("Retrans timeout found: %d\n", (int) time(NULL));*/
506 if (qmsg->retrans > 3) { /* To many retrans */
jjako08d331d2003-10-13 20:33:30 +0000507 if (gsn->cb_conf) gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
jjako52c24142002-12-16 13:33:51 +0000508 queue_freemsg(gsn->queue_req, qmsg);
509 }
510 else {
jjako08d331d2003-10-13 20:33:30 +0000511 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
jjako52c24142002-12-16 13:33:51 +0000512 (struct sockaddr *) &qmsg->peer, sizeof(struct sockaddr_in)) < 0) {
513 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000514 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 +0000515 }
516 queue_back(gsn->queue_req, qmsg);
517 qmsg->timeout = now + 3;
518 qmsg->retrans++;
519 }
520 }
521
522 /* Also clean up reply timeouts */
523 while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
524 (qmsg->timeout < now)) {
525 /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL));*/
526 queue_freemsg(gsn->queue_resp, qmsg);
527 }
528
529 return 0;
530}
531
532int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) {
533 time_t now, later;
534 struct qmsg_t *qmsg;
535
536 if (queue_getfirst(gsn->queue_req, &qmsg)) {
537 timeout->tv_sec = 10;
538 timeout->tv_usec = 0;
539 }
540 else {
541 now = time(NULL);
542 later = qmsg->timeout;
543 timeout->tv_sec = later - now;
544 timeout->tv_usec = 0;
545 if (timeout->tv_sec < 0) timeout->tv_sec = 0; /* No negative allowed */
546 if (timeout->tv_sec > 10) timeout->tv_sec = 10; /* Max sleep for 10 sec*/
547 }
548 return 0;
549}
550
jjako08d331d2003-10-13 20:33:30 +0000551int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp,
552 union gtp_packet *packet, int len,
553 struct sockaddr_in *peer, int fd,
554 uint16_t seq, uint64_t tid) {
jjako52c24142002-12-16 13:33:51 +0000555 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000556
jjako08d331d2003-10-13 20:33:30 +0000557 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
558 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
559 packet->gtp0.h.seq = hton16(seq);
560 packet->gtp0.h.tid = tid;
561 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
562 (packet->gtp0.h.type == GTP_ERROR)))
563 packet->gtp0.h.flow=hton16(pdp->flru);
564 else if (pdp)
565 packet->gtp0.h.flow=hton16(pdp->flrc);
566 }
567 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
568 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
569 packet->gtp1l.h.seq = hton16(seq);
570 if (pdp && (fd == gsn->fd1u))
571 packet->gtp1l.h.tei=hton32(pdp->teid_gn);
572 else if (pdp)
573 packet->gtp1l.h.tei=hton32(pdp->teic_gn);
574 }
575 else {
576 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
jjakoa7cd2492003-04-11 09:40:12 +0000577 return -1;
578 }
jjako52c24142002-12-16 13:33:51 +0000579
jjako08d331d2003-10-13 20:33:30 +0000580 if (fcntl(fd, F_SETFL, 0)) {
581 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
582 return -1;
583 }
584
585 if (sendto(fd, packet, len, 0,
jjako52c24142002-12-16 13:33:51 +0000586 (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
587 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000588 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 +0000589 return -1;
590 }
591
592 /* Use new queue structure */
593 if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) {
594 gsn->err_queuefull++;
595 gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full");
596 }
597 else {
598 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
599 qmsg->l = len;
600 qmsg->timeout = time(NULL) + 60; /* When to timeout */
601 qmsg->retrans = 0; /* No retransmissions so far */
jjako08d331d2003-10-13 20:33:30 +0000602 qmsg->cbp = NULL;
jjako52c24142002-12-16 13:33:51 +0000603 qmsg->type = 0;
jjako08d331d2003-10-13 20:33:30 +0000604 qmsg->fd = fd;
jjako52c24142002-12-16 13:33:51 +0000605 }
606 return 0;
607}
608
jjako2c381332003-10-21 19:09:53 +0000609int gtp_notification(struct gsn_t *gsn, int version,
610 union gtp_packet *packet, int len,
611 struct sockaddr_in *peer, int fd,
612 uint16_t seq) {
613
614 struct sockaddr_in addr;
615
616 memcpy(&addr, peer, sizeof(addr));
617
618 /* In GTP0 notifications are treated as replies. In GTP1 they
619 are requests for which there is no reply */
620
621 if (fd == gsn->fd1c)
622 addr.sin_port = htons(GTP1C_PORT);
623 else if (fd == gsn->fd1u)
624 addr.sin_port = htons(GTP1C_PORT);
625
626 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
627 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
628 packet->gtp0.h.seq = hton16(seq);
629 }
630 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
631 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
632 packet->gtp1l.h.seq = hton16(seq);
633 }
634 else {
635 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
636 return -1;
637 }
638
639 if (fcntl(fd, F_SETFL, 0)) {
640 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
641 return -1;
642 }
643
644 if (sendto(fd, packet, len, 0,
645 (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) {
646 gsn->err_sendto++;
647 gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno));
648 return -1;
649 }
650 return 0;
651}
652
jjako52c24142002-12-16 13:33:51 +0000653int gtp_dublicate(struct gsn_t *gsn, int version,
654 struct sockaddr_in *peer, uint16_t seq) {
655 struct qmsg_t *qmsg;
656
657 if(queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) {
658 return EOF; /* Notfound */
659 }
jjakoa7cd2492003-04-11 09:40:12 +0000660
jjako08d331d2003-10-13 20:33:30 +0000661 if (fcntl(qmsg->fd, F_SETFL, 0)) {
662 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
663 return -1;
jjako52c24142002-12-16 13:33:51 +0000664 }
jjako08d331d2003-10-13 20:33:30 +0000665
666 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
667 (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
668 gsn->err_sendto++;
669 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));
670 }
671 return 0;
jjako52c24142002-12-16 13:33:51 +0000672}
673
674
675
676/* Perform restoration and recovery error handling as described in 29.060 */
677static void log_restart(struct gsn_t *gsn) {
678 FILE *f;
679 int i;
680 int counter = 0;
681 char filename[NAMESIZE];
682
683 filename[NAMESIZE-1] = 0; /* No null term. guarantee by strncpy */
684 strncpy(filename, gsn->statedir, NAMESIZE-1);
685 strncat(filename, RESTART_FILE,
686 NAMESIZE-1-sizeof(RESTART_FILE));
687
688 i = umask(022);
689
690 /* We try to open file. On failure we will later try to create file */
691 if (!(f = fopen(filename, "r"))) {
jjako581c9f02003-10-22 11:28:20 +0000692
693 gtp_err(LOG_ERR, __FILE__, __LINE__, "State information file (%s) not found. Creating new file.", filename);
jjako52c24142002-12-16 13:33:51 +0000694 }
695 else {
696 umask(i);
697 fscanf(f, "%d", &counter);
698 if (fclose(f)) {
699 gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno));
700 }
701 }
702
703 gsn->restart_counter = (unsigned char) counter;
704 gsn->restart_counter++;
705
706 if (!(f = fopen(filename, "w"))) {
707 gtp_err(LOG_ERR, __FILE__, __LINE__, "fopen(path=%s, mode=%s) failed: Error = %s", filename, "w", strerror(errno));
708 return;
709 }
710
711 umask(i);
712 fprintf(f, "%d\n", gsn->restart_counter);
713 if (fclose(f)) {
714 gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno));
715 return;
716 }
717}
718
719
720
jjako1db1c812003-07-06 20:53:57 +0000721int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
722 int mode)
jjako52c24142002-12-16 13:33:51 +0000723{
724 struct sockaddr_in addr;
jjako52c24142002-12-16 13:33:51 +0000725
726 syslog(LOG_ERR, "GTP: gtp_newgsn() started");
727
728 *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
729
730 (*gsn)->statedir = statedir;
731 log_restart(*gsn);
jjakoa7cd2492003-04-11 09:40:12 +0000732
733 /* Initialise sequence number */
734 (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
jjako52c24142002-12-16 13:33:51 +0000735
736 /* Initialise request retransmit queue */
737 queue_new(&(*gsn)->queue_req);
738 queue_new(&(*gsn)->queue_resp);
739
740 /* Initialise pdp table */
741 pdp_init();
742
743 /* Initialise call back functions */
jjako08d331d2003-10-13 20:33:30 +0000744 (*gsn)->cb_create_context_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000745 (*gsn)->cb_delete_context = 0;
jjako08d331d2003-10-13 20:33:30 +0000746 (*gsn)->cb_unsup_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000747 (*gsn)->cb_conf = 0;
jjako08d331d2003-10-13 20:33:30 +0000748 (*gsn)->cb_data_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000749
jjako08d331d2003-10-13 20:33:30 +0000750 /* Store function parameters */
751 (*gsn)->gsnc = *listen;
752 (*gsn)->gsnu = *listen;
753 (*gsn)->mode = mode;
754
755
756 /* Create GTP version 0 socket */
757 if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
jjako52c24142002-12-16 13:33:51 +0000758 (*gsn)->err_socket++;
759 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
760 return -1;
761 }
jjako52c24142002-12-16 13:33:51 +0000762
763 memset(&addr, 0, sizeof(addr));
jjako52c24142002-12-16 13:33:51 +0000764 addr.sin_family = AF_INET;
jjako52c24142002-12-16 13:33:51 +0000765 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
766 addr.sin_port = htons(GTP0_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000767#if defined(__FreeBSD__) || defined(__APPLE__)
jjako06e9f122004-01-19 18:37:58 +0000768 addr.sin_len = sizeof(addr);
769#endif
jjako52c24142002-12-16 13:33:51 +0000770
jjako08d331d2003-10-13 20:33:30 +0000771 if (bind((*gsn)->fd0, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
jjako52c24142002-12-16 13:33:51 +0000772 (*gsn)->err_socket++;
jjako08d331d2003-10-13 20:33:30 +0000773 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));
774 return -1;
775 }
776
777 /* Create GTP version 1 control plane socket */
778 if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
779 (*gsn)->err_socket++;
780 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
781 return -1;
782 }
783
784 memset(&addr, 0, sizeof(addr));
785 addr.sin_family = AF_INET;
786 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
787 addr.sin_port = htons(GTP1C_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000788#if defined(__FreeBSD__) || defined(__APPLE__)
jjako06e9f122004-01-19 18:37:58 +0000789 addr.sin_len = sizeof(addr);
790#endif
jjako08d331d2003-10-13 20:33:30 +0000791
792 if (bind((*gsn)->fd1c, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
793 (*gsn)->err_socket++;
794 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));
795 return -1;
796 }
797
798 /* Create GTP version 1 user plane socket */
799 if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
800 (*gsn)->err_socket++;
801 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
802 return -1;
803 }
804
805 memset(&addr, 0, sizeof(addr));
806 addr.sin_family = AF_INET;
807 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
808 addr.sin_port = htons(GTP1U_PORT);
jjako0fe0df02004-09-17 11:30:40 +0000809#if defined(__FreeBSD__) || defined(__APPLE__)
jjako06e9f122004-01-19 18:37:58 +0000810 addr.sin_len = sizeof(addr);
811#endif
jjako08d331d2003-10-13 20:33:30 +0000812
813 if (bind((*gsn)->fd1u, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
814 (*gsn)->err_socket++;
815 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 +0000816 return -1;
817 }
818
jjako52c24142002-12-16 13:33:51 +0000819 return 0;
820}
821
822int gtp_free(struct gsn_t *gsn) {
823
824 /* Clean up retransmit queues */
825 queue_free(gsn->queue_req);
826 queue_free(gsn->queue_resp);
jjako08d331d2003-10-13 20:33:30 +0000827
828 close(gsn->fd0);
829 close(gsn->fd1c);
830 close(gsn->fd1u);
jjako52c24142002-12-16 13:33:51 +0000831
832 free(gsn);
833 return 0;
834}
835
836/* ***********************************************************
837 * Path management messages
838 * Messages: echo and version not supported.
839 * A path is connection between two UDP/IP endpoints
840 *
841 * A path is either using GTP0 or GTP1. A path can be
842 * established by any kind of GTP message??
843
844 * Which source port to use?
845 * GTP-C request destination port is 2123/3386
846 * GTP-U request destination port is 2152/3386
847 * T-PDU destination port is 2152/3386.
848 * For the above messages the source port is locally allocated.
849 * For response messages src=rx-dst and dst=rx-src.
850 * For simplicity we should probably use 2123+2152/3386 as
851 * src port even for the cases where src can be locally
852 * allocated. This also means that we have to listen only to
853 * the same ports.
854 * For response messages we need to be able to respond to
855 * the relevant src port even if it is locally allocated by
856 * the peer.
857 *
858 * The need for path management!
859 * We might need to keep a list of active paths. This might
860 * be in the form of remote IP address + UDP port numbers.
861 * (We will consider a path astablished if we have a context
862 * with the node in question)
863 *************************************************************/
864
865/* Send off an echo request */
jjako08d331d2003-10-13 20:33:30 +0000866int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
867 struct in_addr *inetaddr)
jjako52c24142002-12-16 13:33:51 +0000868{
869 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +0200870 unsigned int length = get_default_gtp(version, GTP_ECHO_REQ, &packet);
jjako08d331d2003-10-13 20:33:30 +0000871 return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp);
jjako52c24142002-12-16 13:33:51 +0000872}
873
jjako08d331d2003-10-13 20:33:30 +0000874/* Send off an echo reply */
875int gtp_echo_resp(struct gsn_t *gsn, int version,
876 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +0000877 void *pack, unsigned len)
878{
879 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +0200880 unsigned int length = get_default_gtp(version, GTP_ECHO_RSP, &packet);
jjako08d331d2003-10-13 20:33:30 +0000881 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, gsn->restart_counter);
882 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
883 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +0000884}
885
886
887/* Handle a received echo request */
jjako08d331d2003-10-13 20:33:30 +0000888int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
889 int fd, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000890
jjako08d331d2003-10-13 20:33:30 +0000891 /* Check if it was a dublicate request */
892 if(!gtp_dublicate(gsn, 0, peer, get_seq(pack))) return 0;
jjako52c24142002-12-16 13:33:51 +0000893
jjako08d331d2003-10-13 20:33:30 +0000894 /* Send off reply to request */
895 return gtp_echo_resp(gsn, version, peer, fd, pack, len);
jjako52c24142002-12-16 13:33:51 +0000896}
897
898/* Handle a received echo reply */
jjako08d331d2003-10-13 20:33:30 +0000899int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
jjako52c24142002-12-16 13:33:51 +0000900 void *pack, unsigned len) {
901 union gtpie_member *ie[GTPIE_SIZE];
902 unsigned char recovery;
jjako08d331d2003-10-13 20:33:30 +0000903 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +0000904 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +0000905 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +0000906
907 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +0000908 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +0000909
jjako08d331d2003-10-13 20:33:30 +0000910 /* Extract information elements into a pointer array */
911 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +0000912 gsn->invalid++;
913 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
914 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +0000915 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000916 return EOF;
917 }
918
919 if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
920 gsn->missing++;
921 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
922 "Missing mandatory field");
jjako08d331d2003-10-13 20:33:30 +0000923 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000924 return EOF;
925 }
926
jjako08d331d2003-10-13 20:33:30 +0000927 /* Echo reply packages does not have a cause information element */
928 /* Instead we return the recovery number in the callback function */
929 if (gsn->cb_conf) gsn->cb_conf(type, recovery, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000930
931 return 0;
932}
933
934/* Send off a Version Not Supported message */
935/* This message is somewhat special in that it actually is a
936 * response to some other message with unsupported GTP version
937 * For this reason it has parameters like a response, and does
938 * its own message transmission. No signalling queue is used
939 * The reply is sent to the peer IP and peer UDP. This means that
940 * the peer will be receiving a GTP0 message on a GTP1 port!
941 * In practice however this will never happen as a GTP0 GSN will
942 * only listen to the GTP0 port, and therefore will never receive
943 * anything else than GTP0 */
944
jjako08d331d2003-10-13 20:33:30 +0000945int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
946 int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000947{
948 union gtp_packet packet;
jjako52c24142002-12-16 13:33:51 +0000949
jjako08d331d2003-10-13 20:33:30 +0000950 /* GTP 1 is the highest supported protocol */
Harald Weltef54a1f42010-05-04 11:08:38 +0200951 unsigned int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet);
jjako2c381332003-10-21 19:09:53 +0000952 return gtp_notification(gsn, version, &packet, length,
953 peer, fd, 0);
jjako52c24142002-12-16 13:33:51 +0000954}
955
956/* Handle a Version Not Supported message */
jjako08d331d2003-10-13 20:33:30 +0000957int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
958 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000959
jjako08d331d2003-10-13 20:33:30 +0000960 if (gsn->cb_unsup_ind) gsn->cb_unsup_ind(peer);
jjako52c24142002-12-16 13:33:51 +0000961
jjako52c24142002-12-16 13:33:51 +0000962 return 0;
963}
964
jjako2c381332003-10-21 19:09:53 +0000965/* Send off an Supported Extension Headers Notification */
966int gtp_extheader_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
967 int fd, void *pack, unsigned len)
968{
969 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +0200970 unsigned int length = get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet);
jjako2c381332003-10-21 19:09:53 +0000971
972 uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU;
973
974 if (version < 1)
975 return 0;
976
977 /* We report back that we support only PDCP PDU headers */
978 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T, sizeof(pdcp_pdu),
979 &pdcp_pdu);
980
981 return gtp_notification(gsn, version, &packet, length,
982 peer, fd, get_seq(pack));
983}
984
985/* Handle a Supported Extension Headers Notification */
986int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
987 void *pack, unsigned len) {
988
989 if (gsn->cb_extheader_ind) gsn->cb_extheader_ind(peer);
990
991 return 0;
992}
993
994
jjako52c24142002-12-16 13:33:51 +0000995/* ***********************************************************
996 * Session management messages
997 * Messages: create, update and delete PDP context
998 *
999 * Information storage
1000 * Information storage for each PDP context is defined in
1001 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
1002 * PDP-address (IP address), sequence numbers, charging ID.
1003 * For the SGSN it also includes radio related mobility
1004 * information.
1005 *************************************************************/
1006
jjako08d331d2003-10-13 20:33:30 +00001007/* API: Send Create PDP Context Request */
1008extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
jjako193e8b12003-11-10 12:31:41 +00001009 void *cbp) {
jjako52c24142002-12-16 13:33:51 +00001010 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02001011 unsigned int length = get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet);
jjako2c381332003-10-21 19:09:53 +00001012 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001013
jjako2c381332003-10-21 19:09:53 +00001014 /* TODO: Secondary PDP Context Activation Procedure */
1015 /* In secondary activation procedure the PDP context is identified
1016 by tei in the header. The following fields are omitted: Selection
1017 mode, IMSI, MSISDN, End User Address, Access Point Name and
1018 Protocol Configuration Options */
1019
1020 if (pdp->secondary) {
1021 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
1022 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context");
1023 return EOF;
1024 }
1025 }
1026
1027 if (pdp->version == 0) {
jjako08d331d2003-10-13 20:33:30 +00001028 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
jjako52c24142002-12-16 13:33:51 +00001029 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako2c381332003-10-21 19:09:53 +00001030 }
jjako52c24142002-12-16 13:33:51 +00001031
jjako2c381332003-10-21 19:09:53 +00001032 if (pdp->version == 1) {
1033 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1034 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1035 sizeof(pdp->imsi), (uint8_t*) &pdp->imsi);
1036 }
jjako52c24142002-12-16 13:33:51 +00001037
jjako08d331d2003-10-13 20:33:30 +00001038 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1039 gsn->restart_counter);
jjako2c381332003-10-21 19:09:53 +00001040
1041 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1042 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE,
1043 pdp->selmode);
jjako08d331d2003-10-13 20:33:30 +00001044
1045 if (pdp->version == 0) {
1046 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1047 pdp->fllu);
1048 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1049 pdp->fllc);
1050 }
1051
1052 if (pdp->version == 1) {
1053 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1054 pdp->teid_own);
jjako2c381332003-10-21 19:09:53 +00001055
1056 if (!pdp->teic_confirmed)
1057 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1058 pdp->teic_own);
jjako08d331d2003-10-13 20:33:30 +00001059
jjakobe61ef22004-01-09 12:22:29 +00001060 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1061 pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00001062
jjako2c381332003-10-21 19:09:53 +00001063 if (pdp->secondary) /* Secondary PDP Context Activation Procedure */
jjakobe61ef22004-01-09 12:22:29 +00001064 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
jjako2c381332003-10-21 19:09:53 +00001065 linked_pdp->nsapi);
jjako9b4971d2004-05-27 20:30:19 +00001066
1067 if (pdp->cch_pdp) /* Only include charging if flags are set */
1068 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C,
1069 pdp->cch_pdp);
jjako08d331d2003-10-13 20:33:30 +00001070 }
1071
1072 /* TODO
1073 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1074 pdp->traceref);
1075 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1076 pdp->tracetype); */
1077
jjako2c381332003-10-21 19:09:53 +00001078 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1079 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1080 pdp->eua.l, pdp->eua.v);
1081
jjako08d331d2003-10-13 20:33:30 +00001082
jjako2c381332003-10-21 19:09:53 +00001083 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1084 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN,
1085 pdp->apn_use.l, pdp->apn_use.v);
1086
1087 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1088 if (pdp->pco_req.l)
1089 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1090 pdp->pco_req.l, pdp->pco_req.v);
jjako08d331d2003-10-13 20:33:30 +00001091
1092 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1093 pdp->gsnlc.l, pdp->gsnlc.v);
1094 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1095 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001096
1097 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1098 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN,
1099 pdp->msisdn.l, pdp->msisdn.v);
jjako08d331d2003-10-13 20:33:30 +00001100
1101 if (pdp->version == 1)
1102 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1103 pdp->qos_req.l, pdp->qos_req.v);
1104
1105
1106 if ((pdp->version == 1) && pdp->tft.l)
1107 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1108 pdp->tft.l, pdp->tft.v);
1109
1110 if ((pdp->version == 1) && pdp->triggerid.l)
1111 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1112 pdp->triggerid.l, pdp->triggerid.v);
1113
1114 if ((pdp->version == 1) && pdp->omcid.l)
1115 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1116 pdp->omcid.l, pdp->omcid.v);
1117
jjako193e8b12003-11-10 12:31:41 +00001118 /* TODO hisaddr0 */
1119 gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
jjako52c24142002-12-16 13:33:51 +00001120
1121 return 0;
1122}
1123
jjako08d331d2003-10-13 20:33:30 +00001124/* API: Application response to context indication */
1125int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause) {
1126
1127 /* Now send off a reply to the peer */
1128 gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
1129
1130 if (cause != GTPCAUSE_ACC_REQ) {
1131 pdp_freepdp(pdp);
1132 }
1133
1134 return 0;
1135}
1136
1137/* API: Register create context indication callback */
1138int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
1139 int (*cb_create_context_ind) (struct pdp_t* pdp))
jjako52c24142002-12-16 13:33:51 +00001140{
jjako08d331d2003-10-13 20:33:30 +00001141 gsn->cb_create_context_ind = cb_create_context_ind;
1142 return 0;
1143}
1144
1145
1146/* Send Create PDP Context Response */
1147int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
1148 uint8_t cause) {
jjako52c24142002-12-16 13:33:51 +00001149 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02001150 unsigned int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
jjako52c24142002-12-16 13:33:51 +00001151
jjako08d331d2003-10-13 20:33:30 +00001152 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00001153
1154 if (cause == GTPCAUSE_ACC_REQ) {
jjako08d331d2003-10-13 20:33:30 +00001155
1156 if (version == 0)
1157 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1158 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1159
1160 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER,
jjako52c24142002-12-16 13:33:51 +00001161 pdp->reorder);
jjako08d331d2003-10-13 20:33:30 +00001162 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
jjako52c24142002-12-16 13:33:51 +00001163 gsn->restart_counter);
jjako08d331d2003-10-13 20:33:30 +00001164
1165 if (version == 0) {
1166 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1167 pdp->fllu);
1168 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1169 pdp->fllc);
1170 }
1171
1172 if (version == 1) {
1173 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1174 pdp->teid_own);
1175 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1176 pdp->teic_own);
1177 }
1178
jjako2c381332003-10-21 19:09:53 +00001179 /* TODO: We use teic_own as charging ID */
jjako08d331d2003-10-13 20:33:30 +00001180 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
jjako2c381332003-10-21 19:09:53 +00001181 pdp->teic_own);
1182
jjako08d331d2003-10-13 20:33:30 +00001183 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
jjako52c24142002-12-16 13:33:51 +00001184 pdp->eua.l, pdp->eua.v);
1185
1186 if (pdp->pco_neg.l) { /* Optional PCO */
jjako08d331d2003-10-13 20:33:30 +00001187 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
jjako52c24142002-12-16 13:33:51 +00001188 pdp->pco_neg.l, pdp->pco_neg.v);
1189 }
1190
jjako08d331d2003-10-13 20:33:30 +00001191 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
jjako52c24142002-12-16 13:33:51 +00001192 pdp->gsnlc.l, pdp->gsnlc.v);
jjako08d331d2003-10-13 20:33:30 +00001193 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
jjako52c24142002-12-16 13:33:51 +00001194 pdp->gsnlu.l, pdp->gsnlu.v);
jjako08d331d2003-10-13 20:33:30 +00001195
1196 if (version == 1)
1197 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1198 pdp->qos_neg.l, pdp->qos_neg.v);
1199
1200 /* TODO: Charging gateway address */
jjako52c24142002-12-16 13:33:51 +00001201 }
1202
jjako08d331d2003-10-13 20:33:30 +00001203 return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer,
1204 pdp->fd, pdp->seq, pdp->tid);
jjako52c24142002-12-16 13:33:51 +00001205}
1206
1207/* Handle Create PDP Context Request */
1208int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001209 struct sockaddr_in *peer, int fd,
1210 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00001211 struct pdp_t *pdp, *pdp_old;
1212 struct pdp_t pdp_buf;
1213 union gtpie_member* ie[GTPIE_SIZE];
1214 uint8_t recovery;
jjako52c24142002-12-16 13:33:51 +00001215
jjako08d331d2003-10-13 20:33:30 +00001216 uint16_t seq = get_seq(pack);
1217 int hlen = get_hlen(pack);
jjako2c381332003-10-21 19:09:53 +00001218 uint8_t linked_nsapi = 0;
1219 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001220
jjako2c381332003-10-21 19:09:53 +00001221 if(!gtp_dublicate(gsn, version, peer, seq)) return 0;
jjako08d331d2003-10-13 20:33:30 +00001222
1223 pdp = &pdp_buf;
1224 memset(pdp, 0, sizeof(struct pdp_t));
1225
1226 if (version == 0) {
jjakod48c5ff2004-01-26 22:25:40 +00001227 pdp->imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffffull;
1228 pdp->nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000ull) >> 60;
jjako52c24142002-12-16 13:33:51 +00001229 }
1230
jjako08d331d2003-10-13 20:33:30 +00001231 pdp->seq = seq;
1232 pdp->sa_peer = *peer;
1233 pdp->fd = fd;
1234 pdp->version = version;
1235
jjako52c24142002-12-16 13:33:51 +00001236 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001237 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001238 gsn->invalid++;
1239 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1240 "Invalid message format");
1241 if (0 == version)
1242 return EOF;
1243 else
jjako08d331d2003-10-13 20:33:30 +00001244 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_INVALID_MESSAGE);
jjako52c24142002-12-16 13:33:51 +00001245 }
1246
jjako2c381332003-10-21 19:09:53 +00001247 if (version == 1) {
1248 /* Linked NSAPI (conditional) */
1249 /* If included this is the Secondary PDP Context Activation Procedure */
1250 /* In secondary activation IMSI is not included, so the context must be */
1251 /* identified by the tei */
1252 if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) {
1253
1254 /* Find the primary PDP context */
1255 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
1256 gsn->incorrect++;
1257 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1258 "Incorrect optional information field");
1259 return gtp_create_pdp_resp(gsn, version, pdp,
1260 GTPCAUSE_OPT_IE_INCORRECT);
1261 }
1262
1263 /* Check that the primary PDP context matches linked nsapi */
1264 if (linked_pdp->nsapi != linked_nsapi) {
1265 gsn->incorrect++;
1266 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1267 "Incorrect optional information field");
1268 return gtp_create_pdp_resp(gsn, version, pdp,
1269 GTPCAUSE_OPT_IE_INCORRECT);
1270 }
1271
1272 /* Copy parameters from primary context */
1273 pdp->selmode = linked_pdp->selmode;
1274 pdp->imsi = linked_pdp->imsi;
1275 pdp->msisdn = linked_pdp->msisdn;
1276 pdp->eua = linked_pdp->eua;
1277 pdp->pco_req = linked_pdp->pco_req;
1278 pdp->apn_req = linked_pdp->apn_req;
1279 pdp->teic_gn = linked_pdp->teic_gn;
1280 pdp->secondary = 1;
1281 }
1282 } /* if (version == 1) */
1283
jjako08d331d2003-10-13 20:33:30 +00001284 if (version == 0) {
1285 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1286 pdp->qos_req0, sizeof(pdp->qos_req0))) {
1287 gsn->missing++;
1288 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1289 "Missing mandatory information field");
1290 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING);
1291 }
jjako52c24142002-12-16 13:33:51 +00001292 }
jjako2c381332003-10-21 19:09:53 +00001293
1294 if ((version == 1) && (!linked_pdp)) {
1295 /* Not Secondary PDP Context Activation Procedure */
jjako08d331d2003-10-13 20:33:30 +00001296 /* IMSI (conditional) */
1297 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) {
1298 gsn->missing++;
1299 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1300 "Missing mandatory information field");
1301 return gtp_create_pdp_resp(gsn, version, pdp,
1302 GTPCAUSE_MAN_IE_MISSING);
1303 }
1304 }
jjako2c381332003-10-21 19:09:53 +00001305
jjako08d331d2003-10-13 20:33:30 +00001306 /* Recovery (optional) */
jjako52c24142002-12-16 13:33:51 +00001307 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1308 /* TODO: Handle received recovery IE */
1309 }
jjako2c381332003-10-21 19:09:53 +00001310
jjako08d331d2003-10-13 20:33:30 +00001311 /* Selection mode (conditional) */
jjako2c381332003-10-21 19:09:53 +00001312 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1313 if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0,
1314 &pdp->selmode, sizeof(pdp->selmode))) {
1315 gsn->missing++;
1316 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1317 "Missing mandatory information field");
1318 return gtp_create_pdp_resp(gsn, version, pdp,
1319 GTPCAUSE_MAN_IE_MISSING);
1320 }
jjako52c24142002-12-16 13:33:51 +00001321 }
1322
jjako08d331d2003-10-13 20:33:30 +00001323 if (version == 0) {
1324 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1325 gsn->missing++;
1326 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1327 "Missing mandatory information field");
1328 return gtp_create_pdp_resp(gsn, version, pdp,
1329 GTPCAUSE_MAN_IE_MISSING);
1330 }
1331
1332 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1333 gsn->missing++;
1334 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1335 "Missing mandatory information field");
1336 return gtp_create_pdp_resp(gsn, version, pdp,
1337 GTPCAUSE_MAN_IE_MISSING);
1338 }
jjako52c24142002-12-16 13:33:51 +00001339 }
jjako2c381332003-10-21 19:09:53 +00001340
1341
jjako08d331d2003-10-13 20:33:30 +00001342 if (version == 1) {
1343 /* TEID (mandatory) */
1344 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1345 gsn->missing++;
1346 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1347 "Missing mandatory information field");
1348 return gtp_create_pdp_resp(gsn, version, pdp,
1349 GTPCAUSE_MAN_IE_MISSING);
1350 }
1351
1352 /* TEIC (conditional) */
jjako2c381332003-10-21 19:09:53 +00001353 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1354 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1355 gsn->missing++;
1356 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1357 "Missing mandatory information field");
1358 return gtp_create_pdp_resp(gsn, version, pdp,
1359 GTPCAUSE_MAN_IE_MISSING);
1360 }
jjako08d331d2003-10-13 20:33:30 +00001361 }
jjako52c24142002-12-16 13:33:51 +00001362
jjako98200df2004-01-09 15:18:42 +00001363 /* NSAPI (mandatory) */
1364 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
1365 gsn->missing++;
1366 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1367 "Missing mandatory information field");
1368 return gtp_create_pdp_resp(gsn, version, pdp,
1369 GTPCAUSE_MAN_IE_MISSING);
1370 }
jjako2c381332003-10-21 19:09:53 +00001371 }
1372
1373
jjako08d331d2003-10-13 20:33:30 +00001374 /* Charging Characteriatics (optional) */
1375 /* Trace reference (optional) */
1376 /* Trace type (optional) */
1377 /* Charging Characteriatics (optional) */
jjako2c381332003-10-21 19:09:53 +00001378
1379 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1380 /* End User Address (conditional) */
1381 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
jjako52c24142002-12-16 13:33:51 +00001382 &pdp->eua.v, sizeof(pdp->eua.v))) {
jjako2c381332003-10-21 19:09:53 +00001383 gsn->missing++;
1384 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1385 "Missing mandatory information field");
1386 return gtp_create_pdp_resp(gsn, version, pdp,
1387 GTPCAUSE_MAN_IE_MISSING);
1388 }
1389
1390 /* APN */
1391 if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l,
jjako52c24142002-12-16 13:33:51 +00001392 &pdp->apn_req.v, sizeof(pdp->apn_req.v))) {
jjako2c381332003-10-21 19:09:53 +00001393 gsn->missing++;
1394 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1395 "Missing mandatory information field");
1396 return gtp_create_pdp_resp(gsn, version, pdp,
1397 GTPCAUSE_MAN_IE_MISSING);
1398 }
1399
1400 /* Extract protocol configuration options (optional) */
1401 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1402 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1403 }
jjako52c24142002-12-16 13:33:51 +00001404 }
1405
jjako08d331d2003-10-13 20:33:30 +00001406 /* SGSN address for signalling (mandatory) */
jjako52c24142002-12-16 13:33:51 +00001407 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1408 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1409 gsn->missing++;
1410 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1411 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001412 return gtp_create_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00001413 GTPCAUSE_MAN_IE_MISSING);
1414 }
1415
jjako08d331d2003-10-13 20:33:30 +00001416 /* SGSN address for user traffic (mandatory) */
jjako52c24142002-12-16 13:33:51 +00001417 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1418 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1419 gsn->missing++;
1420 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1421 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001422 return gtp_create_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00001423 GTPCAUSE_MAN_IE_MISSING);
1424 }
1425
jjako2c381332003-10-21 19:09:53 +00001426 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1427 /* MSISDN (conditional) */
1428 if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l,
1429 &pdp->msisdn.v, sizeof(pdp->msisdn.v))) {
1430 gsn->missing++;
1431 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1432 "Missing mandatory information field");
1433 return gtp_create_pdp_resp(gsn, version, pdp,
1434 GTPCAUSE_MAN_IE_MISSING);
1435 }
jjako52c24142002-12-16 13:33:51 +00001436 }
1437
jjako08d331d2003-10-13 20:33:30 +00001438 if (version == 1) {
1439 /* QoS (mandatory) */
1440 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
1441 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
1442 gsn->missing++;
1443 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1444 "Missing mandatory information field");
1445 return gtp_create_pdp_resp(gsn, version, pdp,
1446 GTPCAUSE_MAN_IE_MISSING);
1447 }
1448
1449 /* TFT (conditional) */
1450 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
1451 &pdp->tft.v, sizeof(pdp->tft.v))) {
1452 }
jjako2c381332003-10-21 19:09:53 +00001453
jjako08d331d2003-10-13 20:33:30 +00001454 /* Trigger ID */
1455 /* OMC identity */
1456 }
1457
1458 /* Initialize our own IP addresses */
jjako52c24142002-12-16 13:33:51 +00001459 in_addr2gsna(&pdp->gsnlc, &gsn->gsnc);
1460 in_addr2gsna(&pdp->gsnlu, &gsn->gsnu);
jjako2c381332003-10-21 19:09:53 +00001461
jjako2e840a32003-01-28 16:05:18 +00001462 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Before pdp_tidget\n");
jjako2c381332003-10-21 19:09:53 +00001463
jjako08d331d2003-10-13 20:33:30 +00001464 if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) {
jjako52c24142002-12-16 13:33:51 +00001465 /* Found old pdp with same tid. Now the voodoo begins! */
jjako08d331d2003-10-13 20:33:30 +00001466 /* 09.60 / 29.060 allows create on existing context to "steal" */
1467 /* the context which was allready established */
jjako52c24142002-12-16 13:33:51 +00001468 /* We check that the APN, selection mode and MSISDN is the same */
jjako2e840a32003-01-28 16:05:18 +00001469 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n");
jjako08d331d2003-10-13 20:33:30 +00001470 if ((pdp->apn_req.l == pdp_old->apn_req.l)
jjako52c24142002-12-16 13:33:51 +00001471 && (!memcmp(pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l))
1472 && (pdp->selmode == pdp_old->selmode)
1473 && (pdp->msisdn.l == pdp_old->msisdn.l)
1474 && (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l))) {
1475 /* OK! We are dealing with the same APN. We will copy new
1476 * parameters to the old pdp and send off confirmation
1477 * We ignore the following information elements:
1478 * QoS: MS will get originally negotiated QoS.
1479 * End user address (EUA). MS will get old EUA anyway.
1480 * Protocol configuration option (PCO): Only application can verify */
jjako2e840a32003-01-28 16:05:18 +00001481
1482 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n");
jjako52c24142002-12-16 13:33:51 +00001483
1484 /* Copy remote flow label */
1485 pdp_old->flru = pdp->flru;
1486 pdp_old->flrc = pdp->flrc;
1487
jjako08d331d2003-10-13 20:33:30 +00001488 /* Copy remote tei */
1489 pdp_old->teid_gn = pdp->teid_gn;
1490 pdp_old->teic_gn = pdp->teic_gn;
1491
jjako52c24142002-12-16 13:33:51 +00001492 /* Copy peer GSN address */
1493 pdp_old->gsnrc.l = pdp->gsnrc.l;
1494 memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l);
1495 pdp_old->gsnru.l = pdp->gsnru.l;
1496 memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l);
jjako2c381332003-10-21 19:09:53 +00001497
1498 /* Copy request parameters */
1499 pdp_old->seq = pdp->seq;
1500 pdp_old->sa_peer = pdp->sa_peer;
1501 pdp_old->fd = pdp->fd = fd;
1502 pdp_old->version = pdp->version = version;
1503
1504 /* Switch to using the old pdp context */
jjako52c24142002-12-16 13:33:51 +00001505 pdp = pdp_old;
1506
1507 /* Confirm to peer that things were "successful" */
jjako08d331d2003-10-13 20:33:30 +00001508 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_ACC_REQ);
jjako52c24142002-12-16 13:33:51 +00001509 }
1510 else { /* This is not the same PDP context. Delete the old one. */
jjako2e840a32003-01-28 16:05:18 +00001511
1512 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleting old context\n");
jjako52c24142002-12-16 13:33:51 +00001513
1514 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp_old);
1515 pdp_freepdp(pdp_old);
jjako08d331d2003-10-13 20:33:30 +00001516
jjako2e840a32003-01-28 16:05:18 +00001517 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleted...\n");
jjako52c24142002-12-16 13:33:51 +00001518 }
1519 }
1520
jjako08d331d2003-10-13 20:33:30 +00001521 pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp);
jjako52c24142002-12-16 13:33:51 +00001522
1523 /* Callback function to validata login */
jjako08d331d2003-10-13 20:33:30 +00001524 if (gsn->cb_create_context_ind !=0)
1525 return gsn->cb_create_context_ind(pdp);
jjako52c24142002-12-16 13:33:51 +00001526 else {
jjako08d331d2003-10-13 20:33:30 +00001527 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1528 "No create_context_ind callback defined");
1529 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_NOT_SUPPORTED);
jjako52c24142002-12-16 13:33:51 +00001530 }
1531}
1532
1533
1534/* Handle Create PDP Context Response */
1535int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001536 struct sockaddr_in *peer,
1537 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00001538 struct pdp_t *pdp;
1539 union gtpie_member *ie[GTPIE_SIZE];
1540 uint8_t cause, recovery;
jjako08d331d2003-10-13 20:33:30 +00001541 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00001542 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +00001543 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001544
1545 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00001546 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00001547
1548 /* Find the context in question */
jjako08d331d2003-10-13 20:33:30 +00001549 if (pdp_getgtp1(&pdp, get_tei(pack))) {
jjako52c24142002-12-16 13:33:51 +00001550 gsn->err_unknownpdp++;
1551 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1552 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00001553 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00001554 return EOF;
1555 }
1556
jjako2c381332003-10-21 19:09:53 +00001557 /* Register that we have received a valid teic from GGSN */
1558 pdp->teic_confirmed = 1;
1559
jjako52c24142002-12-16 13:33:51 +00001560 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001561 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001562 gsn->invalid++;
1563 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1564 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +00001565 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001566 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1567 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001568 return EOF;
1569 }
1570
1571 /* Extract cause value (mandatory) */
1572 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
1573 gsn->missing++;
1574 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1575 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001576 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001577 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1578 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001579 return EOF;
1580 }
1581
1582 /* Extract recovery (optional) */
1583 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1584 /* TODO: Handle received recovery IE */
1585 }
1586
1587 /* Extract protocol configuration options (optional) */
1588 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1589 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
jjako52c24142002-12-16 13:33:51 +00001590 }
1591
1592 /* Check all conditional information elements */
1593 if (GTPCAUSE_ACC_REQ == cause) {
1594
jjako08d331d2003-10-13 20:33:30 +00001595 if (version == 0) {
1596 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1597 &pdp->qos_neg0, sizeof(pdp->qos_neg0))) {
1598 gsn->missing++;
1599 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1600 "Missing conditional information field");
1601 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001602 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1603 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001604 return EOF;
1605 }
jjako52c24142002-12-16 13:33:51 +00001606 }
jjako52c24142002-12-16 13:33:51 +00001607
1608 if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) {
1609 gsn->missing++;
1610 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1611 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001612 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001613 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1614 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001615 return EOF;
1616 }
1617
jjako08d331d2003-10-13 20:33:30 +00001618 if (version == 0) {
1619 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1620 gsn->missing++;
1621 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1622 "Missing conditional information field");
1623 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001624 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1625 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001626 return EOF;
1627 }
jjako52c24142002-12-16 13:33:51 +00001628
jjako08d331d2003-10-13 20:33:30 +00001629 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1630 gsn->missing++;
1631 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1632 "Missing conditional information field");
1633 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001634 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1635 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001636 return EOF;
1637 }
1638 }
1639
1640 if (version == 1) {
1641 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1642 gsn->missing++;
1643 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1644 "Missing conditional information field");
1645 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001646 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1647 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001648 return EOF;
1649 }
1650
1651 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1652 gsn->missing++;
1653 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1654 "Missing conditional information field");
1655 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001656 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1657 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001658 return EOF;
1659 }
jjako52c24142002-12-16 13:33:51 +00001660 }
1661
1662 if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
1663 gsn->missing++;
1664 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1665 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001666 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001667 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1668 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001669 }
1670
1671 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1672 &pdp->eua.v, sizeof(pdp->eua.v))) {
1673 gsn->missing++;
1674 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1675 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001676 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); */
jjako52c24142002-12-16 13:33:51 +00001679 return EOF;
1680 }
1681
1682 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1683 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1684 gsn->missing++;
1685 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1686 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001687 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001688 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1689 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001690 return EOF;
1691 }
1692
1693 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1694 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1695 gsn->missing++;
1696 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1697 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001698 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); */
jjako52c24142002-12-16 13:33:51 +00001701 return EOF;
1702 }
jjako52c24142002-12-16 13:33:51 +00001703
jjako08d331d2003-10-13 20:33:30 +00001704 if (version == 1) {
1705 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
1706 &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
1707 gsn->missing++;
1708 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1709 "Missing conditional information field");
1710 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001711 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1712 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001713 return EOF;
1714 }
1715 }
jjakoccc564f2003-10-25 15:40:48 +00001716
jjako08d331d2003-10-13 20:33:30 +00001717 }
1718
1719 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako52c24142002-12-16 13:33:51 +00001720
1721 return 0;
1722}
1723
jjako52c24142002-12-16 13:33:51 +00001724
jjako08d331d2003-10-13 20:33:30 +00001725/* API: Send Update PDP Context Request */
1726int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
1727 struct in_addr* inetaddr) {
1728 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02001729 unsigned int length = get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet);
jjako52c24142002-12-16 13:33:51 +00001730
jjako08d331d2003-10-13 20:33:30 +00001731 if (pdp->version == 0)
1732 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1733 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako2c381332003-10-21 19:09:53 +00001734
1735 /* Include IMSI if updating with unknown teic_gn */
1736 if ((pdp->version == 1) && (!pdp->teic_gn))
jjako08d331d2003-10-13 20:33:30 +00001737 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1738 sizeof(pdp->imsi), (uint8_t*) &pdp->imsi);
jjako2c381332003-10-21 19:09:53 +00001739
jjako08d331d2003-10-13 20:33:30 +00001740 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
jjako52c24142002-12-16 13:33:51 +00001741 gsn->restart_counter);
jjako2c381332003-10-21 19:09:53 +00001742
jjako08d331d2003-10-13 20:33:30 +00001743 if (pdp->version == 0) {
1744 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
jjako52c24142002-12-16 13:33:51 +00001745 pdp->fllu);
jjako08d331d2003-10-13 20:33:30 +00001746 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
jjako52c24142002-12-16 13:33:51 +00001747 pdp->fllc);
jjako52c24142002-12-16 13:33:51 +00001748 }
jjako2c381332003-10-21 19:09:53 +00001749
jjako08d331d2003-10-13 20:33:30 +00001750 if (pdp->version == 1) {
1751 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1752 pdp->teid_own);
jjako52c24142002-12-16 13:33:51 +00001753
jjako2c381332003-10-21 19:09:53 +00001754 if (!pdp->teic_confirmed)
1755 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1756 pdp->teic_own);
1757 }
1758
jjako08d331d2003-10-13 20:33:30 +00001759 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1760 pdp->nsapi);
jjako2c381332003-10-21 19:09:53 +00001761
jjako08d331d2003-10-13 20:33:30 +00001762 /* TODO
jjako2c381332003-10-21 19:09:53 +00001763 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1764 pdp->traceref);
1765 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1766 pdp->tracetype); */
1767
jjako08d331d2003-10-13 20:33:30 +00001768 /* TODO if ggsn update message
jjako2c381332003-10-21 19:09:53 +00001769 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1770 pdp->eua.l, pdp->eua.v);
jjako08d331d2003-10-13 20:33:30 +00001771 */
jjako2c381332003-10-21 19:09:53 +00001772
jjako08d331d2003-10-13 20:33:30 +00001773 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1774 pdp->gsnlc.l, pdp->gsnlc.v);
1775 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1776 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001777
jjako08d331d2003-10-13 20:33:30 +00001778 if (pdp->version == 1)
1779 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1780 pdp->qos_req.l, pdp->qos_req.v);
jjako2c381332003-10-21 19:09:53 +00001781
1782
jjako08d331d2003-10-13 20:33:30 +00001783 if ((pdp->version == 1) && pdp->tft.l)
1784 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1785 pdp->tft.l, pdp->tft.v);
1786
1787 if ((pdp->version == 1) && pdp->triggerid.l)
1788 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1789 pdp->triggerid.l, pdp->triggerid.v);
1790
1791 if ((pdp->version == 1) && pdp->omcid.l)
1792 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1793 pdp->omcid.l, pdp->omcid.v);
1794
1795 gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp);
1796
1797 return 0;
jjako52c24142002-12-16 13:33:51 +00001798}
1799
jjako08d331d2003-10-13 20:33:30 +00001800
1801/* Send Update PDP Context Response */
1802int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
1803 struct sockaddr_in *peer, int fd,
1804 void *pack, unsigned len,
1805 struct pdp_t *pdp, uint8_t cause) {
1806
1807 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02001808 unsigned int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
jjako08d331d2003-10-13 20:33:30 +00001809
1810 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
1811
1812 if (cause == GTPCAUSE_ACC_REQ) {
1813
1814 if (version == 0)
1815 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1816 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1817
1818 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1819 gsn->restart_counter);
1820
1821 if (version == 0) {
1822 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1823 pdp->fllu);
1824 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1825 pdp->fllc);
1826 }
1827
1828 if (version == 1) {
1829 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1830 pdp->teid_own);
jjako2c381332003-10-21 19:09:53 +00001831
1832 if (!pdp->teic_confirmed)
1833 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1834 pdp->teic_own);
jjako08d331d2003-10-13 20:33:30 +00001835 }
jjako2c381332003-10-21 19:09:53 +00001836
1837 /* TODO we use teid_own as charging ID address */
jjako08d331d2003-10-13 20:33:30 +00001838 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
jjako2c381332003-10-21 19:09:53 +00001839 pdp->teid_own);
1840
jjako08d331d2003-10-13 20:33:30 +00001841 /* If ggsn
jjako2c381332003-10-21 19:09:53 +00001842 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1843 pdp->eua.l, pdp->eua.v); */
1844
jjako08d331d2003-10-13 20:33:30 +00001845 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1846 pdp->gsnlc.l, pdp->gsnlc.v);
1847 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1848 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001849
jjako08d331d2003-10-13 20:33:30 +00001850 if (version == 1)
1851 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1852 pdp->qos_neg.l, pdp->qos_neg.v);
jjako2c381332003-10-21 19:09:53 +00001853
jjako08d331d2003-10-13 20:33:30 +00001854 /* TODO: Charging gateway address */
1855 }
jjako2c381332003-10-21 19:09:53 +00001856
1857 return gtp_resp(version, gsn, pdp, &packet, length, peer,
1858 fd, get_seq(pack), get_tid(pack));
jjako08d331d2003-10-13 20:33:30 +00001859}
1860
1861
jjako52c24142002-12-16 13:33:51 +00001862/* Handle Update PDP Context Request */
1863int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001864 struct sockaddr_in *peer, int fd,
1865 void *pack, unsigned len) {
1866 struct pdp_t *pdp;
1867 struct pdp_t pdp_backup;
jjako52c24142002-12-16 13:33:51 +00001868 union gtpie_member* ie[GTPIE_SIZE];
1869 uint8_t recovery;
1870
jjako08d331d2003-10-13 20:33:30 +00001871 uint16_t seq = get_seq(pack);
1872 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001873
jjako08d331d2003-10-13 20:33:30 +00001874 uint64_t imsi;
1875 uint8_t nsapi;
1876
jjako52c24142002-12-16 13:33:51 +00001877 /* Is this a dublicate ? */
jjako08d331d2003-10-13 20:33:30 +00001878 if(!gtp_dublicate(gsn, version, peer, seq)) {
jjako52c24142002-12-16 13:33:51 +00001879 return 0; /* We allready send of response once */
1880 }
jjako2c381332003-10-21 19:09:53 +00001881
jjako52c24142002-12-16 13:33:51 +00001882
1883 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001884 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001885 gsn->invalid++;
1886 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1887 "Invalid message format");
1888 if (0 == version)
1889 return EOF;
1890 else
jjako08d331d2003-10-13 20:33:30 +00001891 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1892 NULL, GTPCAUSE_INVALID_MESSAGE);
jjako52c24142002-12-16 13:33:51 +00001893 }
1894
jjako08d331d2003-10-13 20:33:30 +00001895 /* Finding PDP: */
1896 /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
1897 /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
1898 /* we have to use the tunnel endpoint identifier */
1899 if (version == 0) {
jjakod48c5ff2004-01-26 22:25:40 +00001900 imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffffull;
1901 nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000ull) >> 60;
jjako2c381332003-10-21 19:09:53 +00001902
jjako08d331d2003-10-13 20:33:30 +00001903 /* Find the context in question */
1904 if (pdp_getimsi(&pdp, imsi, nsapi)) {
1905 gsn->err_unknownpdp++;
1906 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1907 "Unknown PDP context");
1908 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1909 NULL, GTPCAUSE_NON_EXIST);
1910 }
jjako52c24142002-12-16 13:33:51 +00001911 }
jjako08d331d2003-10-13 20:33:30 +00001912 else if (version == 1) {
1913 /* NSAPI (mandatory) */
1914 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
1915 gsn->missing++;
1916 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1917 "Missing mandatory information field");
1918 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1919 NULL, GTPCAUSE_MAN_IE_MISSING);
1920 }
jjako2c381332003-10-21 19:09:53 +00001921
jjako08d331d2003-10-13 20:33:30 +00001922 /* IMSI (conditional) */
1923 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) {
1924 /* Find the context in question */
1925 if (pdp_getgtp1(&pdp, get_tei(pack))) {
1926 gsn->err_unknownpdp++;
1927 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1928 "Unknown PDP context");
1929 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1930 NULL, GTPCAUSE_NON_EXIST);
1931 }
1932 }
1933 else {
1934 /* Find the context in question */
1935 if (pdp_getimsi(&pdp, imsi, nsapi)) {
1936 gsn->err_unknownpdp++;
1937 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1938 "Unknown PDP context");
1939 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1940 NULL, GTPCAUSE_NON_EXIST);
1941 }
1942 }
1943 }
1944 else {
1945 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
1946 return EOF;
1947 }
jjako2c381332003-10-21 19:09:53 +00001948
jjako08d331d2003-10-13 20:33:30 +00001949 /* Make a backup copy in case anything is wrong */
1950 memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
1951
1952 if (version == 0) {
1953 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1954 pdp->qos_req0, sizeof(pdp->qos_req0))) {
1955 gsn->missing++;
1956 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1957 "Missing mandatory information field");
1958 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1959 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1960 pdp, GTPCAUSE_MAN_IE_MISSING);
1961 }
1962 }
1963
1964 /* Recovery (optional) */
jjako52c24142002-12-16 13:33:51 +00001965 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1966 /* TODO: Handle received recovery IE */
1967 }
1968
jjako08d331d2003-10-13 20:33:30 +00001969 if (version == 0) {
1970 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1971 gsn->missing++;
1972 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1973 "Missing mandatory information field");
1974 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1975 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
1976 GTPCAUSE_MAN_IE_MISSING);
1977 }
1978
1979 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1980 gsn->missing++;
1981 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1982 "Missing mandatory information field");
1983 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1984 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
1985 GTPCAUSE_MAN_IE_MISSING);
1986 }
1987 }
1988
1989
1990 if (version == 1) {
1991 /* TEID (mandatory) */
1992 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1993 gsn->missing++;
1994 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1995 "Missing mandatory information field");
1996 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1997 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
1998 GTPCAUSE_MAN_IE_MISSING);
1999 }
jjako2c381332003-10-21 19:09:53 +00002000
jjako08d331d2003-10-13 20:33:30 +00002001 /* TEIC (conditional) */
2002 /* If TEIC is not included it means that we have allready received it */
jjako2c381332003-10-21 19:09:53 +00002003 /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
2004 /* all updated contexts, or only for one of the linked contexts */
2005 gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn);
2006
jjako08d331d2003-10-13 20:33:30 +00002007 /* NSAPI (mandatory) */
2008 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
2009 gsn->missing++;
2010 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2011 "Missing mandatory information field");
2012 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2013 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2014 GTPCAUSE_MAN_IE_MISSING);
2015 }
2016 }
2017
2018 /* Trace reference (optional) */
2019 /* Trace type (optional) */
2020
2021 /* End User Address (conditional) TODO: GGSN Initiated
2022 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2023 &pdp->eua.v, sizeof(pdp->eua.v))) {
jjako52c24142002-12-16 13:33:51 +00002024 gsn->missing++;
2025 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2026 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002027 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2028 return gtp_update_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00002029 GTPCAUSE_MAN_IE_MISSING);
jjako08d331d2003-10-13 20:33:30 +00002030 } */
jjako52c24142002-12-16 13:33:51 +00002031
jjako08d331d2003-10-13 20:33:30 +00002032
2033 /* SGSN address for signalling (mandatory) */
2034 /* It is weird that this is mandatory when TEIC is conditional */
2035 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2036 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
jjako52c24142002-12-16 13:33:51 +00002037 gsn->missing++;
2038 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2039 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002040 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2041 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002042 GTPCAUSE_MAN_IE_MISSING);
2043 }
2044
jjako08d331d2003-10-13 20:33:30 +00002045 /* SGSN address for user traffic (mandatory) */
2046 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2047 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
jjako52c24142002-12-16 13:33:51 +00002048 gsn->missing++;
2049 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2050 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002051 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2052 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002053 GTPCAUSE_MAN_IE_MISSING);
2054 }
jjako08d331d2003-10-13 20:33:30 +00002055
2056 if (version == 1) {
2057 /* QoS (mandatory) */
2058 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
2059 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
2060 gsn->missing++;
2061 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2062 "Missing mandatory information field");
2063 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2064 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2065 GTPCAUSE_MAN_IE_MISSING);
2066 }
jjako52c24142002-12-16 13:33:51 +00002067
jjako08d331d2003-10-13 20:33:30 +00002068 /* TFT (conditional) */
2069 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
2070 &pdp->tft.v, sizeof(pdp->tft.v))) {
2071 }
2072
2073 /* OMC identity */
jjako52c24142002-12-16 13:33:51 +00002074 }
2075
jjako52c24142002-12-16 13:33:51 +00002076 /* Confirm to peer that things were "successful" */
jjako08d331d2003-10-13 20:33:30 +00002077 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002078 GTPCAUSE_ACC_REQ);
2079}
2080
2081
2082/* Handle Update PDP Context Response */
2083int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
2084 struct sockaddr_in *peer,
2085 void *pack, unsigned len) {
2086 struct pdp_t *pdp;
2087 union gtpie_member *ie[GTPIE_SIZE];
2088 uint8_t cause, recovery;
jjako08d331d2003-10-13 20:33:30 +00002089 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00002090 uint8_t type = 0;
2091
2092 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00002093 if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00002094
2095 /* Find the context in question */
2096 if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) {
2097 gsn->err_unknownpdp++;
2098 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2099 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00002100 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002101 return EOF;
2102 }
2103
jjako2c381332003-10-21 19:09:53 +00002104 /* Register that we have received a valid teic from GGSN */
2105 pdp->teic_confirmed = 1;
2106
jjako52c24142002-12-16 13:33:51 +00002107 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002108 if (gtpie_decaps(ie, 0, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) {
jjako52c24142002-12-16 13:33:51 +00002109 gsn->invalid++;
2110 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2111 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +00002112 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002113 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2114 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002115 return EOF;
2116 }
2117
2118 /* Extract cause value (mandatory) */
2119 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2120 gsn->missing++;
2121 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2122 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002123 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002124 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2125 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002126 return EOF;
2127 }
2128
2129 /* Extract recovery (optional) */
2130 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
2131 /* TODO: Handle received recovery IE */
2132 }
2133
2134 /* Check all conditional information elements */
2135 if (GTPCAUSE_ACC_REQ != cause) {
jjako08d331d2003-10-13 20:33:30 +00002136 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002137 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2138 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002139 return 0;
2140 }
2141 else {
2142 /* Check for missing conditionary information elements */
2143 if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) &&
2144 gtpie_exist(ie, GTPIE_REORDER, 0) &&
2145 gtpie_exist(ie, GTPIE_FL_DI, 0) &&
2146 gtpie_exist(ie, GTPIE_FL_C, 0) &&
2147 gtpie_exist(ie, GTPIE_CHARGING_ID, 0) &&
2148 gtpie_exist(ie, GTPIE_EUA, 0) &&
2149 gtpie_exist(ie, GTPIE_GSN_ADDR, 0) &&
2150 gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) {
2151 gsn->missing++;
2152 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2153 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00002154 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002155 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2156 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002157 return EOF;
2158 }
2159
2160 /* Update pdp with new values */
2161 gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2162 pdp->qos_neg0, sizeof(pdp->qos_neg0));
2163 gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder);
2164 gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru);
2165 gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc);
2166 gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid);
2167 gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2168 &pdp->eua.v, sizeof(pdp->eua.v));
2169 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2170 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v));
2171 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2172 &pdp->gsnru.v, sizeof(pdp->gsnru.v));
2173
jjako08d331d2003-10-13 20:33:30 +00002174 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako52c24142002-12-16 13:33:51 +00002175 return 0; /* Succes */
2176 }
2177}
2178
jjako52c24142002-12-16 13:33:51 +00002179
jjako08d331d2003-10-13 20:33:30 +00002180/* API: Send Delete PDP Context Request */
jjako2c381332003-10-21 19:09:53 +00002181int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
2182 int teardown) {
jjako08d331d2003-10-13 20:33:30 +00002183 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02002184 unsigned int length = get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
jjako08d331d2003-10-13 20:33:30 +00002185 struct in_addr addr;
jjako2c381332003-10-21 19:09:53 +00002186 struct pdp_t *linked_pdp;
2187 struct pdp_t *secondary_pdp;
2188 int n;
2189 int count = 0;
2190
jjako52c24142002-12-16 13:33:51 +00002191 if (gsna2in_addr(&addr, &pdp->gsnrc)) {
2192 gsn->err_address++;
2193 gtp_err(LOG_ERR, __FILE__, __LINE__, "GSN address conversion failed");
2194 return EOF;
2195 }
jjako2c381332003-10-21 19:09:53 +00002196
2197 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
2198 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context");
2199 return EOF;
2200 }
2201
2202 if (!teardown) {
2203 for (n=0; n< PDP_MAXNSAPI; n++)
2204 if (linked_pdp->secondary_tei[n]) count++;
2205 if (count <= 1) {
2206 gtp_err(LOG_ERR, __FILE__, __LINE__,
2207 "Must use teardown for last context");
2208 return EOF;
2209 }
2210 }
2211
jjako08d331d2003-10-13 20:33:30 +00002212 if (pdp->version == 1) {
2213 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
2214 pdp->nsapi);
jjako2c381332003-10-21 19:09:53 +00002215
2216 if (teardown)
2217 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
2218 0xff);
jjako08d331d2003-10-13 20:33:30 +00002219 }
jjako52c24142002-12-16 13:33:51 +00002220
jjako2c381332003-10-21 19:09:53 +00002221 gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
jjako52c24142002-12-16 13:33:51 +00002222
jjako2c381332003-10-21 19:09:53 +00002223 if (teardown) { /* Remove all contexts */
2224 for (n=0; n< PDP_MAXNSAPI; n++) {
2225 if (linked_pdp->secondary_tei[n]) {
2226 if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) {
2227 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown secondary PDP context");
2228 return EOF;
2229 }
2230 if (linked_pdp != secondary_pdp) {
2231 if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp);
2232 pdp_freepdp(secondary_pdp);
2233 }
2234 }
2235 }
2236 if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp);
2237 pdp_freepdp(linked_pdp);
2238 }
2239 else {
2240 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2241 if (pdp == linked_pdp) {
2242 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2243 linked_pdp->nodata = 1;
2244 }
2245 else
2246 pdp_freepdp(pdp);
2247 }
2248
2249 return 0;
2250}
jjako08d331d2003-10-13 20:33:30 +00002251
jjako52c24142002-12-16 13:33:51 +00002252/* Send Delete PDP Context Response */
2253int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002254 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002255 void *pack, unsigned len,
jjako2c381332003-10-21 19:09:53 +00002256 struct pdp_t *pdp, struct pdp_t *linked_pdp,
2257 uint8_t cause, int teardown)
jjako52c24142002-12-16 13:33:51 +00002258{
2259 union gtp_packet packet;
jjako2c381332003-10-21 19:09:53 +00002260 struct pdp_t *secondary_pdp;
Harald Weltef54a1f42010-05-04 11:08:38 +02002261 unsigned int length = get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet);
jjako2c381332003-10-21 19:09:53 +00002262 int n;
jjako52c24142002-12-16 13:33:51 +00002263
jjako08d331d2003-10-13 20:33:30 +00002264 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00002265
jjako08d331d2003-10-13 20:33:30 +00002266 gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
jjako2c381332003-10-21 19:09:53 +00002267 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002268
jjako2c381332003-10-21 19:09:53 +00002269 if (cause == GTPCAUSE_ACC_REQ) {
2270 if ((teardown) || (version == 0)) { /* Remove all contexts */
2271 for (n=0; n< PDP_MAXNSAPI; n++) {
2272 if (linked_pdp->secondary_tei[n]) {
2273 if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) {
2274 gtp_err(LOG_ERR, __FILE__, __LINE__,
2275 "Unknown secondary PDP context");
2276 return EOF;
2277 }
2278 if (linked_pdp != secondary_pdp) {
2279 if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp);
2280 pdp_freepdp(secondary_pdp);
2281 }
2282 }
2283 }
2284 if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp);
2285 pdp_freepdp(linked_pdp);
2286 }
2287 else { /* Remove only current context */
2288 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2289 if (pdp == linked_pdp) {
2290 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2291 linked_pdp->nodata = 1;
2292 }
2293 else
2294 pdp_freepdp(pdp);
2295 }
2296 } /* if (cause == GTPCAUSE_ACC_REQ) */
jjako52c24142002-12-16 13:33:51 +00002297
jjako08d331d2003-10-13 20:33:30 +00002298 return 0;
jjako52c24142002-12-16 13:33:51 +00002299}
2300
2301/* Handle Delete PDP Context Request */
2302int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002303 struct sockaddr_in *peer, int fd,
2304 void *pack, unsigned len) {
jjako2c381332003-10-21 19:09:53 +00002305 struct pdp_t *pdp = NULL;
2306 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00002307 union gtpie_member* ie[GTPIE_SIZE];
jjako08d331d2003-10-13 20:33:30 +00002308
2309 uint16_t seq = get_seq(pack);
2310 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002311
jjako08d331d2003-10-13 20:33:30 +00002312 uint8_t nsapi;
jjako2c381332003-10-21 19:09:53 +00002313 uint8_t teardown = 0;
2314 int n;
2315 int count = 0;
2316
jjako52c24142002-12-16 13:33:51 +00002317 /* Is this a dublicate ? */
jjako08d331d2003-10-13 20:33:30 +00002318 if(!gtp_dublicate(gsn, version, peer, seq)) {
2319 return 0; /* We allready send off response once */
jjako52c24142002-12-16 13:33:51 +00002320 }
2321
jjako2c381332003-10-21 19:09:53 +00002322 /* Find the linked context in question */
2323 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
jjako52c24142002-12-16 13:33:51 +00002324 gsn->err_unknownpdp++;
2325 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2326 "Unknown PDP context");
jjako2c381332003-10-21 19:09:53 +00002327 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2328 GTPCAUSE_NON_EXIST, teardown);
jjako52c24142002-12-16 13:33:51 +00002329 }
jjako2c381332003-10-21 19:09:53 +00002330
2331 /* If version 0 this is also the secondary context */
2332 if (version == 0)
2333 pdp = linked_pdp;
jjako52c24142002-12-16 13:33:51 +00002334
2335 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002336 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00002337 gsn->invalid++;
2338 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2339 "Invalid message format");
2340 if (0 == version)
2341 return EOF;
2342 else
jjako2c381332003-10-21 19:09:53 +00002343 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2344 GTPCAUSE_INVALID_MESSAGE, teardown);
jjako52c24142002-12-16 13:33:51 +00002345 }
jjako2c381332003-10-21 19:09:53 +00002346
jjako08d331d2003-10-13 20:33:30 +00002347 if (version == 1) {
2348 /* NSAPI (mandatory) */
2349 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
2350 gsn->missing++;
2351 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2352 "Missing mandatory information field");
jjako2c381332003-10-21 19:09:53 +00002353 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2354 GTPCAUSE_MAN_IE_MISSING, teardown);
jjako08d331d2003-10-13 20:33:30 +00002355 }
jjako2c381332003-10-21 19:09:53 +00002356
2357 /* Find the context in question */
2358 if (pdp_getgtp1(&pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) {
2359 gsn->err_unknownpdp++;
2360 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2361 "Unknown PDP context");
2362 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2363 GTPCAUSE_NON_EXIST, teardown);
2364 }
jjako08d331d2003-10-13 20:33:30 +00002365
2366 /* Teardown (conditional) */
jjako2c381332003-10-21 19:09:53 +00002367 gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown);
2368
2369 if (!teardown) {
2370 for (n=0; n< PDP_MAXNSAPI; n++)
2371 if (linked_pdp->secondary_tei[n]) count++;
2372 if (count <= 1) {
2373 return 0; /* 29.060 7.3.5 Ignore message */
2374 }
jjako08d331d2003-10-13 20:33:30 +00002375 }
2376 }
jjako2c381332003-10-21 19:09:53 +00002377
2378 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2379 pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown);
jjako52c24142002-12-16 13:33:51 +00002380}
2381
2382
2383/* Handle Delete PDP Context Response */
2384int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
2385 struct sockaddr_in *peer,
2386 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00002387 union gtpie_member *ie[GTPIE_SIZE];
2388 uint8_t cause;
jjako08d331d2003-10-13 20:33:30 +00002389 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00002390 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +00002391 int hlen = get_hlen(pack);
2392
jjako52c24142002-12-16 13:33:51 +00002393 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00002394 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00002395
jjako52c24142002-12-16 13:33:51 +00002396 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002397 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00002398 gsn->invalid++;
2399 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2400 "Invalid message format");
jjako2c381332003-10-21 19:09:53 +00002401 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002402 return EOF;
2403 }
2404
jjako08d331d2003-10-13 20:33:30 +00002405 /* Extract cause value (mandatory) */
jjako52c24142002-12-16 13:33:51 +00002406 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2407 gsn->missing++;
2408 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2409 "Missing mandatory information field");
jjako2c381332003-10-21 19:09:53 +00002410 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002411 return EOF;
2412 }
2413
jjako2c381332003-10-21 19:09:53 +00002414 /* Check the cause value (again) */
2415 if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
jjako52c24142002-12-16 13:33:51 +00002416 gsn->err_cause++;
2417 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2418 "Unexpected cause value received: %d", cause);
jjako2c381332003-10-21 19:09:53 +00002419 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
2420 return EOF;
jjako52c24142002-12-16 13:33:51 +00002421 }
jjako2c381332003-10-21 19:09:53 +00002422
jjako08d331d2003-10-13 20:33:30 +00002423 /* Callback function to notify application */
jjako2c381332003-10-21 19:09:53 +00002424 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002425
2426 return 0;
2427}
2428
2429/* Send Error Indication (response to a GPDU message */
2430int gtp_error_ind_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002431 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002432 void *pack, unsigned len)
2433{
2434 union gtp_packet packet;
Harald Weltef54a1f42010-05-04 11:08:38 +02002435 unsigned int length = get_default_gtp(version, GTP_ERROR, &packet);
jjako52c24142002-12-16 13:33:51 +00002436
jjako08d331d2003-10-13 20:33:30 +00002437 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
2438 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002439}
2440
2441/* Handle Error Indication */
2442int gtp_error_ind_conf(struct gsn_t *gsn, int version,
2443 struct sockaddr_in *peer,
2444 void *pack, unsigned len) {
2445 struct pdp_t *pdp;
2446
2447 /* Find the context in question */
2448 if (pdp_tidget(&pdp, ((union gtp_packet*)pack)->gtp0.h.tid)) {
2449 gsn->err_unknownpdp++;
2450 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2451 "Unknown PDP context");
2452 return EOF;
2453 }
2454
2455 gsn->err_unknownpdp++; /* TODO: Change counter */
2456 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2457 "Received Error Indication");
2458
2459 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2460 pdp_freepdp(pdp);
2461 return 0;
2462}
2463
2464int gtp_gpdu_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002465 struct sockaddr_in *peer, int fd,
2466 void *pack, unsigned len) {
2467
2468 int hlen = GTP1_HEADER_SIZE_SHORT;
jjako52c24142002-12-16 13:33:51 +00002469
2470 /* Need to include code to verify packet src and dest addresses */
2471 struct pdp_t *pdp;
jjako1db1c812003-07-06 20:53:57 +00002472
jjako08d331d2003-10-13 20:33:30 +00002473 if (version == 0) {
2474 if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) {
2475 gsn->err_unknownpdp++;
2476 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2477 "Unknown PDP context");
2478 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2479 }
2480 hlen = GTP0_HEADER_SIZE;
2481 }
2482 else if (version == 1) {
2483 if (pdp_getgtp1(&pdp, ntoh32(((union gtp_packet*)pack)->gtp1l.h.tei))) {
2484 gsn->err_unknownpdp++;
2485 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2486 "Unknown PDP context");
2487 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2488 }
2489
2490 /* Is this a long or a short header ? */
2491 if (((union gtp_packet*)pack)->gtp1l.h.flags & 0x07)
2492 hlen = GTP1_HEADER_SIZE_LONG;
2493 else
2494 hlen = GTP1_HEADER_SIZE_SHORT;
2495 }
2496 else {
2497 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2498 "Unknown version");
2499 }
2500
jjako1db1c812003-07-06 20:53:57 +00002501 /* If the GPDU was not from the peer GSN tell him to delete context */
2502 if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
2503 gsn->err_unknownpdp++;
2504 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2505 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00002506 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
jjako1db1c812003-07-06 20:53:57 +00002507 }
jjako08d331d2003-10-13 20:33:30 +00002508
jjako52c24142002-12-16 13:33:51 +00002509 /* Callback function */
jjako08d331d2003-10-13 20:33:30 +00002510 if (gsn->cb_data_ind !=0)
2511 return gsn->cb_data_ind(pdp, pack+hlen, len-hlen);
jjako52c24142002-12-16 13:33:51 +00002512
2513 return 0;
2514}
2515
2516
jjako08d331d2003-10-13 20:33:30 +00002517
jjako52c24142002-12-16 13:33:51 +00002518/* Receives GTP packet and sends off for further processing
2519 * Function will check the validity of the header. If the header
2520 * is not valid the packet is either dropped or a version not
2521 * supported is returned to the peer.
2522 * TODO: Need to decide on return values! */
jjako08d331d2003-10-13 20:33:30 +00002523int gtp_decaps0(struct gsn_t *gsn)
jjako52c24142002-12-16 13:33:51 +00002524{
jjako2c381332003-10-21 19:09:53 +00002525 unsigned char buffer[PACKET_MAX];
jjako52c24142002-12-16 13:33:51 +00002526 struct sockaddr_in peer;
Harald Weltef54a1f42010-05-04 11:08:38 +02002527 size_t peerlen;
jjako08d331d2003-10-13 20:33:30 +00002528 int status;
jjako52c24142002-12-16 13:33:51 +00002529 struct gtp0_header *pheader;
2530 int version = 0; /* GTP version should be determined from header!*/
jjako08d331d2003-10-13 20:33:30 +00002531 int fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00002532
jjakoa7cd2492003-04-11 09:40:12 +00002533 /* TODO: Need strategy of userspace buffering and blocking */
2534 /* Currently read is non-blocking and send is blocking. */
2535 /* This means that the program have to wait for busy send calls...*/
jjako52c24142002-12-16 13:33:51 +00002536
jjakoa7cd2492003-04-11 09:40:12 +00002537 while (1) { /* Loop until no more to read */
jjako08d331d2003-10-13 20:33:30 +00002538 if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) {
jjakoa7cd2492003-04-11 09:40:12 +00002539 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2540 return -1;
2541 }
2542 peerlen = sizeof(peer);
2543 if ((status =
jjako08d331d2003-10-13 20:33:30 +00002544 recvfrom(gsn->fd0, buffer, sizeof(buffer), 0,
jjakoa7cd2492003-04-11 09:40:12 +00002545 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
jjako08d331d2003-10-13 20:33:30 +00002546 if (errno == EAGAIN) return 0;
jjakoa7cd2492003-04-11 09:40:12 +00002547 gsn->err_readfrom++;
jjako08d331d2003-10-13 20:33:30 +00002548 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 +00002549 return -1;
2550 }
jjako52c24142002-12-16 13:33:51 +00002551
jjakoa7cd2492003-04-11 09:40:12 +00002552 /* Need at least 1 byte in order to check version */
2553 if (status < (1)) {
2554 gsn->empty++;
2555 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2556 "Discarding packet - too small");
2557 continue;
2558 }
2559
jjako08d331d2003-10-13 20:33:30 +00002560 pheader = (struct gtp0_header *) (buffer);
jjakoa7cd2492003-04-11 09:40:12 +00002561
jjako08d331d2003-10-13 20:33:30 +00002562 /* Version should be gtp0 (or earlier) */
2563 /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
2564 /* GTP 0 messages. If other version message is received we reply that we */
2565 /* only support version 0, implying that this is the only version */
2566 /* supported on this port */
jjakoa7cd2492003-04-11 09:40:12 +00002567 if (((pheader->flags & 0xe0) > 0x00)) {
2568 gsn->unsup++;
2569 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2570 "Unsupported GTP version");
jjako08d331d2003-10-13 20:33:30 +00002571 gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */
jjakoa7cd2492003-04-11 09:40:12 +00002572 continue;
2573 }
2574
2575 /* Check length of gtp0 packet */
jjako08d331d2003-10-13 20:33:30 +00002576 if (status < GTP0_HEADER_SIZE) {
jjakoa7cd2492003-04-11 09:40:12 +00002577 gsn->tooshort++;
2578 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2579 "GTP0 packet too short");
2580 continue; /* Silently discard 29.60: 11.1.2 */
2581 }
jjako1db1c812003-07-06 20:53:57 +00002582
jjako08d331d2003-10-13 20:33:30 +00002583 /* Check packet length field versus length of packet */
2584 if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
2585 gsn->tooshort++;
2586 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2587 "GTP packet length field does not match actual length");
2588 continue; /* Silently discard */
2589 }
2590
2591 if ((gsn->mode == GTP_MODE_GGSN) &&
2592 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2593 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2594 (pheader->type == GTP_DELETE_PDP_RSP))) {
2595 gsn->unexpect++;
2596 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2597 "Unexpected GTP Signalling Message");
2598 continue; /* Silently discard 29.60: 11.1.4 */
2599 }
2600
2601 if ((gsn->mode == GTP_MODE_SGSN) &&
2602 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2603 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2604 (pheader->type == GTP_DELETE_PDP_REQ))) {
2605 gsn->unexpect++;
2606 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2607 "Unexpected GTP Signalling Message");
2608 continue; /* Silently discard 29.60: 11.1.4 */
2609 }
2610
2611 switch (pheader->type) {
2612 case GTP_ECHO_REQ:
2613 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2614 break;
2615 case GTP_ECHO_RSP:
2616 gtp_echo_conf(gsn, version, &peer, buffer, status);
2617 break;
2618 case GTP_NOT_SUPPORTED:
2619 gtp_unsup_ind(gsn, &peer, buffer, status);
2620 break;
2621 case GTP_CREATE_PDP_REQ:
2622 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status);
2623 break;
2624 case GTP_CREATE_PDP_RSP:
2625 gtp_create_pdp_conf(gsn, version, &peer, buffer, status);
2626 break;
2627 case GTP_UPDATE_PDP_REQ:
2628 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status);
2629 break;
2630 case GTP_UPDATE_PDP_RSP:
2631 gtp_update_pdp_conf(gsn, version, &peer, buffer, status);
2632 break;
2633 case GTP_DELETE_PDP_REQ:
2634 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status);
2635 break;
2636 case GTP_DELETE_PDP_RSP:
2637 gtp_delete_pdp_conf(gsn, version, &peer, buffer, status);
2638 break;
2639 case GTP_ERROR:
2640 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2641 break;
2642 case GTP_GPDU:
2643 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2644 break;
2645 default:
2646 gsn->unknown++;
2647 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2648 "Unknown GTP message type received");
2649 break;
2650 }
2651 }
2652}
2653
2654
2655int gtp_decaps1c(struct gsn_t *gsn)
2656{
jjako2c381332003-10-21 19:09:53 +00002657 unsigned char buffer[PACKET_MAX];
jjako08d331d2003-10-13 20:33:30 +00002658 struct sockaddr_in peer;
Harald Weltef54a1f42010-05-04 11:08:38 +02002659 size_t peerlen;
jjako08d331d2003-10-13 20:33:30 +00002660 int status;
2661 struct gtp1_header_short *pheader;
jjako2c381332003-10-21 19:09:53 +00002662 int version = 1; /* TODO GTP version should be determined from header!*/
jjako08d331d2003-10-13 20:33:30 +00002663 int fd = gsn->fd1c;
2664
2665 /* TODO: Need strategy of userspace buffering and blocking */
2666 /* Currently read is non-blocking and send is blocking. */
2667 /* This means that the program have to wait for busy send calls...*/
2668
2669 while (1) { /* Loop until no more to read */
jjako2c381332003-10-21 19:09:53 +00002670 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
jjako08d331d2003-10-13 20:33:30 +00002671 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2672 return -1;
2673 }
2674 peerlen = sizeof(peer);
2675 if ((status =
jjako2c381332003-10-21 19:09:53 +00002676 recvfrom(fd, buffer, sizeof(buffer), 0,
jjako08d331d2003-10-13 20:33:30 +00002677 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
2678 if (errno == EAGAIN) return 0;
2679 gsn->err_readfrom++;
jjako2c381332003-10-21 19:09:53 +00002680 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 +00002681 return -1;
2682 }
2683
2684 /* Need at least 1 byte in order to check version */
2685 if (status < (1)) {
2686 gsn->empty++;
2687 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2688 "Discarding packet - too small");
2689 continue;
2690 }
2691
2692 pheader = (struct gtp1_header_short *) (buffer);
2693
2694 /* Version must be no larger than GTP 1 */
2695 if (((pheader->flags & 0xe0) > 0x20)) {
2696 gsn->unsup++;
2697 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2698 "Unsupported GTP version");
jjako2c381332003-10-21 19:09:53 +00002699 gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
2700 /*29.60: 11.1.1*/
jjako08d331d2003-10-13 20:33:30 +00002701 continue;
2702 }
2703
2704 /* Version must be at least GTP 1 */
2705 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2706 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2707 /* the message */
2708 if (((pheader->flags & 0xe0) < 0x20)) {
2709 gsn->unsup++;
2710 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2711 "Unsupported GTP version");
2712 continue;
2713 }
2714
2715 /* Check packet flag field */
2716 if (((pheader->flags & 0xf7) != 0x32)) {
2717 gsn->unsup++;
2718 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2719 "Unsupported packet flag");
2720 continue;
2721 }
2722
2723 /* Check length of packet */
2724 if (status < GTP1_HEADER_SIZE_LONG) {
2725 gsn->tooshort++;
2726 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2727 "GTP packet too short");
2728 continue; /* Silently discard 29.60: 11.1.2 */
2729 }
2730
2731 /* Check packet length field versus length of packet */
2732 if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
2733 gsn->tooshort++;
2734 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2735 "GTP packet length field does not match actual length");
2736 continue; /* Silently discard */
2737 }
2738
jjako2c381332003-10-21 19:09:53 +00002739 /* Check for extension headers */
2740 /* TODO: We really should cycle through the headers and determine */
2741 /* if any have the comprehension required flag set */
2742 if (((pheader->flags & 0x04) != 0x00)) {
2743 gsn->unsup++;
2744 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2745 "Unsupported extension header");
2746 gtp_extheader_req(gsn, version, &peer, fd, buffer, status);
2747
2748 continue;
2749 }
2750
jjako1db1c812003-07-06 20:53:57 +00002751 if ((gsn->mode == GTP_MODE_GGSN) &&
2752 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2753 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2754 (pheader->type == GTP_DELETE_PDP_RSP))) {
2755 gsn->unexpect++;
2756 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2757 "Unexpected GTP Signalling Message");
2758 continue; /* Silently discard 29.60: 11.1.4 */
2759 }
2760
2761 if ((gsn->mode == GTP_MODE_SGSN) &&
2762 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2763 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2764 (pheader->type == GTP_DELETE_PDP_REQ))) {
2765 gsn->unexpect++;
2766 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2767 "Unexpected GTP Signalling Message");
2768 continue; /* Silently discard 29.60: 11.1.4 */
2769 }
2770
jjakoa7cd2492003-04-11 09:40:12 +00002771 switch (pheader->type) {
2772 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +00002773 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002774 break;
2775 case GTP_ECHO_RSP:
jjako08d331d2003-10-13 20:33:30 +00002776 gtp_echo_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002777 break;
2778 case GTP_NOT_SUPPORTED:
jjako08d331d2003-10-13 20:33:30 +00002779 gtp_unsup_ind(gsn, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002780 break;
jjako2c381332003-10-21 19:09:53 +00002781 case GTP_SUPP_EXT_HEADER:
2782 gtp_extheader_ind(gsn, &peer, buffer, status);
2783 break;
jjakoa7cd2492003-04-11 09:40:12 +00002784 case GTP_CREATE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002785 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002786 break;
2787 case GTP_CREATE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002788 gtp_create_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002789 break;
2790 case GTP_UPDATE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002791 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002792 break;
2793 case GTP_UPDATE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002794 gtp_update_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002795 break;
2796 case GTP_DELETE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002797 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002798 break;
2799 case GTP_DELETE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002800 gtp_delete_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002801 break;
2802 case GTP_ERROR:
jjako08d331d2003-10-13 20:33:30 +00002803 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002804 break;
2805 default:
jjako52c24142002-12-16 13:33:51 +00002806 gsn->unknown++;
2807 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2808 "Unknown GTP message type received");
jjakoa7cd2492003-04-11 09:40:12 +00002809 break;
jjako52c24142002-12-16 13:33:51 +00002810 }
2811 }
2812}
2813
jjako08d331d2003-10-13 20:33:30 +00002814int gtp_decaps1u(struct gsn_t *gsn)
2815{
jjako2c381332003-10-21 19:09:53 +00002816 unsigned char buffer[PACKET_MAX];
jjako08d331d2003-10-13 20:33:30 +00002817 struct sockaddr_in peer;
Harald Weltef54a1f42010-05-04 11:08:38 +02002818 size_t peerlen;
jjako08d331d2003-10-13 20:33:30 +00002819 int status;
2820 struct gtp1_header_short *pheader;
2821 int version = 1; /* GTP version should be determined from header!*/
2822 int fd = gsn->fd1u;
2823
2824 /* TODO: Need strategy of userspace buffering and blocking */
2825 /* Currently read is non-blocking and send is blocking. */
2826 /* This means that the program have to wait for busy send calls...*/
2827
2828 while (1) { /* Loop until no more to read */
2829 if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) {
2830 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2831 return -1;
2832 }
2833 peerlen = sizeof(peer);
2834 if ((status =
2835 recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0,
2836 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
2837 if (errno == EAGAIN) return 0;
2838 gsn->err_readfrom++;
2839 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");
2840 return -1;
2841 }
2842
2843 /* Need at least 1 byte in order to check version */
2844 if (status < (1)) {
2845 gsn->empty++;
2846 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2847 "Discarding packet - too small");
2848 continue;
2849 }
2850
2851 pheader = (struct gtp1_header_short *) (buffer);
2852
2853 /* Version must be no larger than GTP 1 */
2854 if (((pheader->flags & 0xe0) > 0x20)) {
2855 gsn->unsup++;
2856 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2857 "Unsupported GTP version");
2858 gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status);/*29.60: 11.1.1*/
2859 continue;
2860 }
2861
2862 /* Version must be at least GTP 1 */
2863 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2864 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2865 /* the message */
2866 if (((pheader->flags & 0xe0) < 0x20)) {
2867 gsn->unsup++;
2868 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2869 "Unsupported GTP version");
2870 continue;
2871 }
2872
2873 /* Check packet flag field (allow both with and without sequence number)*/
2874 if (((pheader->flags & 0xf5) != 0x30)) {
2875 gsn->unsup++;
2876 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2877 "Unsupported packet flag");
2878 continue;
2879 }
2880
2881 /* Check length of packet */
2882 if (status < GTP1_HEADER_SIZE_SHORT) {
2883 gsn->tooshort++;
2884 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2885 "GTP packet too short");
2886 continue; /* Silently discard 29.60: 11.1.2 */
2887 }
2888
2889 /* Check packet length field versus length of packet */
2890 if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
2891 gsn->tooshort++;
2892 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2893 "GTP packet length field does not match actual length");
2894 continue; /* Silently discard */
2895 }
jjako2c381332003-10-21 19:09:53 +00002896
2897 /* Check for extension headers */
2898 /* TODO: We really should cycle through the headers and determine */
2899 /* if any have the comprehension required flag set */
2900 if (((pheader->flags & 0x04) != 0x00)) {
2901 gsn->unsup++;
2902 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2903 "Unsupported extension header");
2904 gtp_extheader_req(gsn, version, &peer, fd, buffer, status);
2905
2906 continue;
2907 }
jjako08d331d2003-10-13 20:33:30 +00002908
2909 switch (pheader->type) {
2910 case GTP_ECHO_REQ:
2911 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2912 break;
2913 case GTP_ECHO_RSP:
2914 gtp_echo_conf(gsn, version, &peer, buffer, status);
2915 break;
jjako2c381332003-10-21 19:09:53 +00002916 case GTP_SUPP_EXT_HEADER:
2917 gtp_extheader_ind(gsn, &peer, buffer, status);
2918 break;
jjako08d331d2003-10-13 20:33:30 +00002919 case GTP_ERROR:
2920 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2921 break;
2922 /* Supported header extensions */
2923 case GTP_GPDU:
2924 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2925 break;
2926 default:
2927 gsn->unknown++;
2928 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2929 "Unknown GTP message type received");
2930 break;
2931 }
2932 }
2933}
2934
2935int gtp_data_req(struct gsn_t *gsn, struct pdp_t* pdp,
jjako52c24142002-12-16 13:33:51 +00002936 void *pack, unsigned len)
2937{
2938 union gtp_packet packet;
2939 struct sockaddr_in addr;
jjako08d331d2003-10-13 20:33:30 +00002940 int fd;
2941 int length;
jjako52c24142002-12-16 13:33:51 +00002942
2943 memset(&addr, 0, sizeof(addr));
2944 addr.sin_family = AF_INET;
jjako0fe0df02004-09-17 11:30:40 +00002945#if defined(__FreeBSD__) || defined(__APPLE__)
jjako06e9f122004-01-19 18:37:58 +00002946 addr.sin_len = sizeof(addr);
2947#endif
2948
jjako52c24142002-12-16 13:33:51 +00002949 memcpy(&addr.sin_addr, pdp->gsnru.v,pdp->gsnru.l); /* TODO range check */
jjako52c24142002-12-16 13:33:51 +00002950
jjako08d331d2003-10-13 20:33:30 +00002951 if (pdp->version == 0) {
2952
2953 length = GTP0_HEADER_SIZE+len;
2954 addr.sin_port = htons(GTP0_PORT);
2955 fd = gsn->fd0;
2956
2957 get_default_gtp(0, GTP_GPDU, &packet);
2958 packet.gtp0.h.length = hton16(len);
2959 packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
2960 packet.gtp0.h.flow = hton16(pdp->flru);
jjako1ea66342004-01-28 09:27:34 +00002961 packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffffull) + ((uint64_t)pdp->nsapi << 60);
jjako52c24142002-12-16 13:33:51 +00002962
jjako08d331d2003-10-13 20:33:30 +00002963 if (len > sizeof (union gtp_packet) - sizeof(struct gtp0_header)) {
2964 gsn->err_memcpy++;
2965 gtp_err(LOG_ERR, __FILE__, __LINE__,
jjako1f158642004-02-05 20:39:57 +00002966 "Memcpy failed: %d > %d", len,
2967 sizeof (union gtp_packet) - sizeof(struct gtp0_header));
jjako08d331d2003-10-13 20:33:30 +00002968 return EOF;
jjako52c24142002-12-16 13:33:51 +00002969 }
jjako08d331d2003-10-13 20:33:30 +00002970 memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */
2971 }
2972 else if (pdp->version == 1) {
2973
2974 length = GTP1_HEADER_SIZE_LONG+len;
2975 addr.sin_port = htons(GTP1U_PORT);
2976 fd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00002977
jjako08d331d2003-10-13 20:33:30 +00002978 get_default_gtp(1, GTP_GPDU, &packet);
2979 packet.gtp1l.h.length = hton16(len-GTP1_HEADER_SIZE_SHORT+
2980 GTP1_HEADER_SIZE_LONG);
2981 packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
jjako2c381332003-10-21 19:09:53 +00002982 packet.gtp1l.h.tei = hton32(pdp->teid_gn);
jjako08d331d2003-10-13 20:33:30 +00002983
2984 if (len > sizeof (union gtp_packet) - sizeof(struct gtp1_header_long)) {
2985 gsn->err_memcpy++;
2986 gtp_err(LOG_ERR, __FILE__, __LINE__,
jjako1f158642004-02-05 20:39:57 +00002987 "Memcpy failed: %d > %d", len,
2988 sizeof (union gtp_packet) - sizeof(struct gtp0_header));
jjako08d331d2003-10-13 20:33:30 +00002989 return EOF;
2990 }
2991 memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */
2992 }
2993 else {
2994 gtp_err(LOG_ERR, __FILE__, __LINE__,
2995 "Unknown version");
2996 return EOF;
2997 }
2998
2999 if (fcntl(fd, F_SETFL, 0)) {
jjakoa7cd2492003-04-11 09:40:12 +00003000 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
3001 return -1;
3002 }
3003
jjako08d331d2003-10-13 20:33:30 +00003004 if (sendto(fd, &packet, length, 0,
jjako52c24142002-12-16 13:33:51 +00003005 (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3006 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +00003007 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 +00003008 return EOF;
3009 }
3010 return 0;
3011}
3012
3013
3014/* ***********************************************************
3015 * Conversion functions
3016 *************************************************************/
3017
3018int char2ul_t(char* src, struct ul_t dst) {
3019 dst.l = strlen(src)+1;
3020 dst.v = malloc(dst.l);
3021 dst.v[0] = dst.l - 1;
3022 memcpy(&dst.v[1], src, dst.v[0]);
3023 return 0;
3024}
3025
3026/* ***********************************************************
3027 * IP address conversion functions
3028 * There exist several types of address representations:
3029 * - eua: End User Address. (29.060, 7.7.27, message type 128)
3030 * Used for signalling address to mobile station. Supports IPv4
3031 * IPv6 x.25 etc. etc.
3032 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
3033 * of GSN. If length is 4 it is IPv4. If length is 16 it is IPv6.
3034 * - in_addr: IPv4 address struct.
3035 * - sockaddr_in: Socket API representation of IP address and
3036 * port number.
3037 *************************************************************/
3038
3039int ipv42eua(struct ul66_t *eua, struct in_addr *src) {
3040 eua->v[0] = 0xf1; /* IETF */
3041 eua->v[1] = 0x21; /* IPv4 */
3042 if (src) {
3043 eua->l = 6;
3044 memcpy(&eua->v[2], src, 4);
3045 }
3046 else
3047 {
3048 eua->l = 2;
3049 }
3050 return 0;
3051}
3052
3053int eua2ipv4(struct in_addr *dst, struct ul66_t *eua) {
3054 if ((eua->l != 6) ||
3055 (eua->v[0] != 0xf1) ||
3056 (eua->v[1] = 0x21))
3057 return -1; /* Not IPv4 address*/
3058 memcpy(dst, &eua->v[2], 4);
3059 return 0;
3060}
3061
3062int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna) {
3063 memset(dst, 0, sizeof(struct in_addr));
3064 if (gsna->l != 4) return EOF; /* Return if not IPv4 */
3065 memcpy(dst, gsna->v, gsna->l);
3066 return 0;
3067}
3068
3069int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src) {
3070 memset(gsna, 0, sizeof(struct ul16_t));
3071 gsna->l = 4;
3072 memcpy(gsna->v, src, gsna->l);
3073 return 0;
3074}
3075