blob: d4e5d74711cf4ca5c35184ca19a1b17433cbbba7 [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
3 * Copyright (C) 2002 Mondru AB.
4 *
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 *
10 * The initial developer of the original code is
11 * Jens Jakobsen <jj@openggsn.org>
12 *
13 * Contributor(s):
14 *
15 */
16
17/*
18 * gtp.c: Contains all GTP functionality. Should be able to handle multiple
19 * tunnels in the same program.
20 *
21 * TODO:
22 * - Do we need to handle fragmentation?
23 */
24
25
26#ifdef __linux__
27#define _GNU_SOURCE 1
28#endif
29
30
31#include <syslog.h>
32#include <stdio.h>
33#include <stdarg.h>
34#include <stdlib.h>
35#include <sys/time.h>
36#include <sys/types.h>
37#include <sys/socket.h>
38#include <netinet/in.h>
39#include <arpa/inet.h>
40#include <sys/stat.h>
41#include <time.h>
42#include <unistd.h>
43#include <string.h>
44#include <errno.h>
45#include <fcntl.h>
46
47#include <arpa/inet.h>
48
jjakobae2cd42004-01-09 12:04:39 +000049/* #include <stdint.h> ISO C99 types */
jjako52c24142002-12-16 13:33:51 +000050
jjako3c13e302003-01-28 22:17:29 +000051#include "../config.h"
jjako52c24142002-12-16 13:33:51 +000052#include "pdp.h"
53#include "gtp.h"
54#include "gtpie.h"
55#include "queue.h"
56
jjako1db1c812003-07-06 20:53:57 +000057
58/* Error reporting functions */
59
60void gtp_err(int priority, char *filename, int linenum, char *fmt, ...) {
61 va_list args;
62 char buf[ERRMSG_SIZE];
63
64 va_start(args, fmt);
65 vsnprintf(buf, ERRMSG_SIZE, fmt, args);
66 va_end(args);
67 buf[ERRMSG_SIZE-1] = 0;
68 syslog(priority, "%s: %d: %s", filename, linenum, buf);
69}
70
71void gtp_errpack(int pri, char *fn, int ln, struct sockaddr_in *peer,
72 void *pack, unsigned len, char *fmt, ...) {
73
74 va_list args;
75 char buf[ERRMSG_SIZE];
76 char buf2[ERRMSG_SIZE];
77 int n;
78 int pos;
79
80 va_start(args, fmt);
81 vsnprintf(buf, ERRMSG_SIZE, fmt, args);
82 va_end(args);
83 buf[ERRMSG_SIZE-1] = 0;
84
85 snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:",
86 inet_ntoa(peer->sin_addr),
87 ntohs(peer->sin_port),
88 len);
89 buf2[ERRMSG_SIZE-1] = 0;
90 pos = strlen(buf2);
91 for(n=0; n<len; n++) {
92 if ((pos+4)<ERRMSG_SIZE) {
93 sprintf((buf2+pos), " %02hhx", ((unsigned char*)pack)[n]);
94 pos += 3;
95 }
96 }
97 buf2[pos] = 0;
98
99 syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
100
101}
102
103
104
105
jjako52c24142002-12-16 13:33:51 +0000106/* API Functions */
107
108const char* gtp_version()
109{
110 return VERSION;
111}
112
113/* gtp_new */
114/* gtp_free */
115
116int gtp_newpdp(struct gsn_t* gsn, struct pdp_t **pdp,
117 uint64_t imsi, uint8_t nsapi) {
118 return pdp_newpdp(pdp, imsi, nsapi, NULL);
119}
120
121int gtp_freepdp(struct gsn_t* gsn, struct pdp_t *pdp) {
122 return pdp_freepdp(pdp);
123}
124
jjako52c24142002-12-16 13:33:51 +0000125/* gtp_gpdu */
126
127extern int gtp_fd(struct gsn_t *gsn) {
jjako08d331d2003-10-13 20:33:30 +0000128 return gsn->fd0;
jjako52c24142002-12-16 13:33:51 +0000129}
130
131/* gtp_decaps */
132/* gtp_retrans */
133/* gtp_retranstimeout */
134
jjako08d331d2003-10-13 20:33:30 +0000135
136int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
137 int (*cb) (struct sockaddr_in *peer)) {
138 gsn->cb_unsup_ind = cb;
139 return 0;
140}
141
jjako2c381332003-10-21 19:09:53 +0000142int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
143 int (*cb) (struct sockaddr_in *peer)) {
144 gsn->cb_extheader_ind = cb;
145 return 0;
146}
147
jjako08d331d2003-10-13 20:33:30 +0000148
149/* API: Initialise delete context callback */
150/* Called whenever a pdp context is deleted for any reason */
jjako52c24142002-12-16 13:33:51 +0000151int gtp_set_cb_delete_context(struct gsn_t *gsn,
jjako08d331d2003-10-13 20:33:30 +0000152 int (*cb) (struct pdp_t* pdp))
jjako52c24142002-12-16 13:33:51 +0000153{
jjako08d331d2003-10-13 20:33:30 +0000154 gsn->cb_delete_context = cb;
jjako52c24142002-12-16 13:33:51 +0000155 return 0;
156}
157
jjako52c24142002-12-16 13:33:51 +0000158int gtp_set_cb_conf(struct gsn_t *gsn,
159 int (*cb) (int type, int cause,
jjako08d331d2003-10-13 20:33:30 +0000160 struct pdp_t* pdp, void *cbp)) {
jjako52c24142002-12-16 13:33:51 +0000161 gsn->cb_conf = cb;
162 return 0;
163}
164
jjako08d331d2003-10-13 20:33:30 +0000165extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
166 int (*cb_data_ind) (struct pdp_t* pdp,
jjako52c24142002-12-16 13:33:51 +0000167 void* pack,
168 unsigned len))
169{
jjako08d331d2003-10-13 20:33:30 +0000170 gsn->cb_data_ind = cb_data_ind;
jjako52c24142002-12-16 13:33:51 +0000171 return 0;
172}
173
jjako08d331d2003-10-13 20:33:30 +0000174/**
175 * get_default_gtp()
176 * Generate a GPRS Tunneling Protocol signalling packet header, depending
177 * on GTP version and message type. pdp is used for teid/flow label.
178 * *packet must be allocated by the calling function, and be large enough
179 * to hold the packet header.
180 * returns the length of the header. 0 on error.
181 **/
jjakob7b93fc2004-01-09 11:56:48 +0000182static int get_default_gtp(int version, uint8_t type, void *packet) {
jjakoa7cd2492003-04-11 09:40:12 +0000183 struct gtp0_header *gtp0_default = (struct gtp0_header*) packet;
184 struct gtp1_header_long *gtp1_default = (struct gtp1_header_long*) packet;
jjako52c24142002-12-16 13:33:51 +0000185 switch (version) {
186 case 0:
jjakoa7cd2492003-04-11 09:40:12 +0000187 /* Initialise "standard" GTP0 header */
jjako08d331d2003-10-13 20:33:30 +0000188 memset(gtp0_default, 0, sizeof(struct gtp0_header));
jjakoa7cd2492003-04-11 09:40:12 +0000189 gtp0_default->flags=0x1e;
jjako08d331d2003-10-13 20:33:30 +0000190 gtp0_default->type=hton8(type);
jjakoa7cd2492003-04-11 09:40:12 +0000191 gtp0_default->spare1=0xff;
192 gtp0_default->spare2=0xff;
193 gtp0_default->spare3=0xff;
194 gtp0_default->number=0xff;
jjako08d331d2003-10-13 20:33:30 +0000195 return GTP0_HEADER_SIZE;
jjako52c24142002-12-16 13:33:51 +0000196 case 1:
jjakoa7cd2492003-04-11 09:40:12 +0000197 /* Initialise "standard" GTP1 header */
jjako08d331d2003-10-13 20:33:30 +0000198 /* 29.060: 8.2: S=1 and PN=0 */
199 /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */
200 /* and Supported Extension Headers Notification, the S field shall be */
201 /* set to 1 */
202 /* Currently extension headers are not supported */
203 memset(gtp1_default, 0, sizeof(struct gtp1_header_long));
204 gtp1_default->flags=0x32; /* No extension, enable sequence, no N-PDU */
205 gtp1_default->type=hton8(type);
206 return GTP1_HEADER_SIZE_LONG;
207 default:
208 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown GTP packet version");
209 return 0;
jjako52c24142002-12-16 13:33:51 +0000210 }
211}
212
jjako08d331d2003-10-13 20:33:30 +0000213/**
214 * get_seq()
215 * Get sequence number of a packet.
216 * Returns 0 on error
217 **/
218static uint16_t get_seq(void *pack) {
219 union gtp_packet *packet = (union gtp_packet *) pack;
220
221 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
222 return ntoh16(packet->gtp0.h.seq);
223 }
224 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
225 return ntoh16(packet->gtp1l.h.seq);
226 } else {
227 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
228 return 0;
229 }
230}
231
232/**
233 * get_tid()
234 * Get tunnel identifier of a packet.
235 * Returns 0 on error
236 **/
237static uint64_t get_tid(void *pack) {
238 union gtp_packet *packet = (union gtp_packet *) pack;
239
240 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
241 return packet->gtp0.h.tid;
242 }
243 return 0;
244}
245
246/**
247 * get_hlen()
248 * Get the header length of a packet.
249 * Returns 0 on error
250 **/
251static uint16_t get_hlen(void *pack) {
252 union gtp_packet *packet = (union gtp_packet *) pack;
253
254 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
255 return GTP0_HEADER_SIZE;
256 }
257 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
258 return GTP1_HEADER_SIZE_LONG;
259 }
260 else if ((packet->flags & 0xe7) == 0x20) { /* Short version 1 */
261 return GTP1_HEADER_SIZE_SHORT;
262 } else {
263 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
264 return 0;
265 }
266}
267
268/**
269 * get_tei()
270 * Get the tunnel endpoint identifier (flow label) of a packet.
271 * Returns 0xffffffff on error.
272 **/
273static uint32_t get_tei(void *pack) {
274 union gtp_packet *packet = (union gtp_packet *) pack;
275
276 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
277 return ntoh16(packet->gtp0.h.flow);
278 }
279 else if ((packet->flags & 0xe0) == 0x20) { /* Version 1 */
280 return ntoh32(packet->gtp1l.h.tei);
281 }
282 else {
283 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
284 return 0xffffffff;
285 }
286}
jjakoa7cd2492003-04-11 09:40:12 +0000287
288
jjako52c24142002-12-16 13:33:51 +0000289int print_packet(void *packet, unsigned len)
290{
291 int i;
292 printf("The packet looks like this (%d bytes):\n", len);
293 for( i=0; i<len; i++) {
294 printf("%02x ", (unsigned char)*(char *)(packet+i));
295 if (!((i+1)%16)) printf("\n");
296 };
297 printf("\n");
298 return 0;
299}
300
301char* snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer,
302 void *pack, unsigned len, char *buf, int size) {
303 int n;
304 int pos;
305 snprintf(buf, size, "Packet from %s:%u, length: %d, content:",
306 inet_ntoa(peer->sin_addr),
307 ntohs(peer->sin_port),
308 len);
jjako2e840a32003-01-28 16:05:18 +0000309 buf[size-1] = 0;
jjako52c24142002-12-16 13:33:51 +0000310 pos = strlen(buf);
311 for(n=0; n<len; n++) {
312 if ((pos+4)<size) {
313 sprintf((buf+pos), " %02hhx", ((unsigned char*)pack)[n]);
314 pos += 3;
315 }
316 }
317 buf[pos] = 0;
318 return buf;
319}
320
jjako52c24142002-12-16 13:33:51 +0000321
322/* ***********************************************************
323 * Reliable delivery of signalling messages
324 *
325 * Sequence numbers are used for both signalling messages and
326 * data messages.
327 *
328 * For data messages each tunnel maintains a sequence counter,
329 * which is incremented by one each time a new data message
330 * is sent. The sequence number starts at (0) zero at tunnel
331 * establishment, and wraps around at 65535 (29.060 9.3.1.1
332 * and 09.60 8.1.1.1). The sequence numbers are either ignored,
333 * or can be used to check the validity of the message in the
334 * receiver, or for reordering af packets.
335 *
336 * For signalling messages the sequence number is used by
337 * signalling messages for which a response is defined. A response
338 * message should copy the sequence from the corresponding request
339 * message. The sequence number "unambiguously" identifies a request
340 * message within a given path, with a path being defined as a set of
341 * two endpoints (29.060 8.2, 29.060 7.6, 09.60 7.8). "All request
342 * messages shall be responded to, and all response messages associated
343 * with a certain request shall always include the same information"
344 *
345 * We take this to mean that the GSN transmitting a request is free to
346 * choose the sequence number, as long as it is unique within a given path.
347 * It means that we are allowed to count backwards, or roll over at 17
348 * if we prefer that. It also means that we can use the same counter for
349 * all paths. This has the advantage that the transmitted request sequence
350 * numbers are unique within each GSN, and also we dont have to mess around
351 * with path setup and teardown.
352 *
353 * If a response message is lost, the request will be retransmitted, and
354 * the receiving GSN will receive a "duplicated" request. The standard
355 * requires the receiving GSN to send a response, with the same information
356 * as in the original response. For most messages this happens automatically:
357 *
358 * Echo: Automatically dublicates the original response
359 * Create pdp context: The SGSN may send create context request even if
360 * a context allready exist (imsi+nsapi?). This means that the reply will
361 automatically dublicate the original response. It might however have
jjako08d331d2003-10-13 20:33:30 +0000362 * side effects in the application which is asked twice to validate
363 * the login.
jjako52c24142002-12-16 13:33:51 +0000364 * Update pdp context: Automatically dublicates the original response???
365 * Delete pdp context. Automatically in gtp0, but in gtp1 will generate
366 * a nonexist reply message.
367 *
368 * The correct solution will be to make a queue containing response messages.
369 * This queue should be checked whenever a request is received. If the
370 * response is allready in the queue that response should be transmitted.
371 * It should be possible to find messages in this queue on the basis of
372 * the sequence number and peer GSN IP address (The sequense number is unique
373 * within each path). This need to be implemented by a hash table. Furthermore
374 * it should be possibly to delete messages based on a timeout. This can be
375 * achieved by means of a linked list. The timeout value need to be larger
376 * than T3-RESPONSE * N3-REQUESTS (recommended value 5). These timers are
377 * set in the peer GSN, so there is no way to know these parameters. On the
378 * other hand the timeout value need to be so small that we do not receive
379 * wraparound sequence numbere before the message is deleted. 60 seconds is
380 * probably not a bad choise.
381 *
382 * This queue however is first really needed from gtp1.
383 *
384 * gtp_req:
385 * Send off a signalling message with appropiate sequence
386 * number. Store packet in queue.
387 * gtp_conf:
388 * Remove an incoming confirmation from the queue
389 * gtp_resp:
jjako08d331d2003-10-13 20:33:30 +0000390 * Send off a response to a request. Use the same sequence
jjako52c24142002-12-16 13:33:51 +0000391 * number in the response as in the request.
jjako2c381332003-10-21 19:09:53 +0000392 * gtp_notification:
393 * Send off a notification message. This is neither a request nor
394 * a response. Both TEI and SEQ are zero.
jjako52c24142002-12-16 13:33:51 +0000395 * gtp_retrans:
396 * Retransmit any outstanding packets which have exceeded
397 * a predefined timeout.
398 *************************************************************/
399
jjako08d331d2003-10-13 20:33:30 +0000400int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp,
401 union gtp_packet *packet, int len,
402 struct in_addr *inetaddr, void *cbp) {
jjako52c24142002-12-16 13:33:51 +0000403 struct sockaddr_in addr;
404 struct qmsg_t *qmsg;
jjako08d331d2003-10-13 20:33:30 +0000405 int fd;
406
jjako52c24142002-12-16 13:33:51 +0000407 memset(&addr, 0, sizeof(addr));
408 addr.sin_family = AF_INET;
409 addr.sin_addr = *inetaddr;
jjako1f158642004-02-05 20:39:57 +0000410#if defined(__FreeBSD__)
jjako06e9f122004-01-19 18:37:58 +0000411 addr.sin_len = sizeof(addr);
412#endif
jjako52c24142002-12-16 13:33:51 +0000413
jjako08d331d2003-10-13 20:33:30 +0000414 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
415 addr.sin_port = htons(GTP0_PORT);
416 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
417 packet->gtp0.h.seq = hton16(gsn->seq_next);
418 if (pdp)
jjakod48c5ff2004-01-26 22:25:40 +0000419 packet->gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffffull) +
jjako08d331d2003-10-13 20:33:30 +0000420 ((uint64_t)pdp->nsapi << 60);
421 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
422 (packet->gtp0.h.type == GTP_ERROR)))
423 packet->gtp0.h.flow=hton16(pdp->flru);
424 else if (pdp)
425 packet->gtp0.h.flow=hton16(pdp->flrc);
426 fd = gsn->fd0;
427 }
428 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
429 addr.sin_port = htons(GTP1C_PORT);
430 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
431 packet->gtp1l.h.seq = hton16(gsn->seq_next);
432 if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) ||
433 (packet->gtp1l.h.type == GTP_ERROR)))
434 packet->gtp1l.h.tei=hton32(pdp->teid_gn);
435 else if (pdp)
436 packet->gtp1l.h.tei=hton32(pdp->teic_gn);
437 fd = gsn->fd1c;
438 } else {
439 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
440 return -1;
441 }
jjako52c24142002-12-16 13:33:51 +0000442
jjako08d331d2003-10-13 20:33:30 +0000443 if (sendto(fd, packet, len, 0,
jjako52c24142002-12-16 13:33:51 +0000444 (struct sockaddr *) &addr, sizeof(addr)) < 0) {
445 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000446 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 +0000447 return -1;
448 }
449
450 /* Use new queue structure */
451 if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) {
452 gsn->err_queuefull++;
453 gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full");
454 }
455 else {
456 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
457 qmsg->l = len;
458 qmsg->timeout = time(NULL) + 3; /* When to timeout */
459 qmsg->retrans = 0; /* No retransmissions so far */
jjako08d331d2003-10-13 20:33:30 +0000460 qmsg->cbp = cbp;
jjako52c24142002-12-16 13:33:51 +0000461 qmsg->type = ntoh8(packet->gtp0.h.type);
jjako08d331d2003-10-13 20:33:30 +0000462 qmsg->fd = fd;
jjako52c24142002-12-16 13:33:51 +0000463 }
464 gsn->seq_next++; /* Count up this time */
465 return 0;
466}
467
468/* gtp_conf
469 * Remove signalling packet from retransmission queue.
470 * return 0 on success, EOF if packet was not found */
471
472int gtp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
jjako08d331d2003-10-13 20:33:30 +0000473 union gtp_packet *packet, int len, uint8_t *type, void **cbp) {
jjako52c24142002-12-16 13:33:51 +0000474
jjako08d331d2003-10-13 20:33:30 +0000475 uint16_t seq;
476
477 if ((packet->gtp0.h.flags & 0xe0) == 0x00)
478 seq = ntoh16(packet->gtp0.h.seq);
479 else if ((packet->gtp1l.h.flags & 0xe2) == 0x22)
480 seq = ntoh16(packet->gtp1l.h.seq);
481 else {
482 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
483 "Unknown GTP packet version");
484 return EOF;
485 }
486
487 if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) {
jjako52c24142002-12-16 13:33:51 +0000488 gsn->err_seq++;
489 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
490 "Confirmation packet not found in queue");
491 return EOF;
492 }
493
494 return 0;
495}
496
497int gtp_retrans(struct gsn_t *gsn) {
498 /* Retransmit any outstanding packets */
499 /* Remove from queue if maxretrans exceeded */
500 time_t now;
501 struct qmsg_t *qmsg;
502 now = time(NULL);
503 /*printf("Retrans: New beginning %d\n", (int) now);*/
504
505 while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
506 (qmsg->timeout <= now)) {
507 /*printf("Retrans timeout found: %d\n", (int) time(NULL));*/
508 if (qmsg->retrans > 3) { /* To many retrans */
jjako08d331d2003-10-13 20:33:30 +0000509 if (gsn->cb_conf) gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
jjako52c24142002-12-16 13:33:51 +0000510 queue_freemsg(gsn->queue_req, qmsg);
511 }
512 else {
jjako08d331d2003-10-13 20:33:30 +0000513 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
jjako52c24142002-12-16 13:33:51 +0000514 (struct sockaddr *) &qmsg->peer, sizeof(struct sockaddr_in)) < 0) {
515 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000516 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 +0000517 }
518 queue_back(gsn->queue_req, qmsg);
519 qmsg->timeout = now + 3;
520 qmsg->retrans++;
521 }
522 }
523
524 /* Also clean up reply timeouts */
525 while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
526 (qmsg->timeout < now)) {
527 /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL));*/
528 queue_freemsg(gsn->queue_resp, qmsg);
529 }
530
531 return 0;
532}
533
534int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) {
535 time_t now, later;
536 struct qmsg_t *qmsg;
537
538 if (queue_getfirst(gsn->queue_req, &qmsg)) {
539 timeout->tv_sec = 10;
540 timeout->tv_usec = 0;
541 }
542 else {
543 now = time(NULL);
544 later = qmsg->timeout;
545 timeout->tv_sec = later - now;
546 timeout->tv_usec = 0;
547 if (timeout->tv_sec < 0) timeout->tv_sec = 0; /* No negative allowed */
548 if (timeout->tv_sec > 10) timeout->tv_sec = 10; /* Max sleep for 10 sec*/
549 }
550 return 0;
551}
552
jjako08d331d2003-10-13 20:33:30 +0000553int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp,
554 union gtp_packet *packet, int len,
555 struct sockaddr_in *peer, int fd,
556 uint16_t seq, uint64_t tid) {
jjako52c24142002-12-16 13:33:51 +0000557 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000558
jjako08d331d2003-10-13 20:33:30 +0000559 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
560 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
561 packet->gtp0.h.seq = hton16(seq);
562 packet->gtp0.h.tid = tid;
563 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
564 (packet->gtp0.h.type == GTP_ERROR)))
565 packet->gtp0.h.flow=hton16(pdp->flru);
566 else if (pdp)
567 packet->gtp0.h.flow=hton16(pdp->flrc);
568 }
569 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
570 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
571 packet->gtp1l.h.seq = hton16(seq);
572 if (pdp && (fd == gsn->fd1u))
573 packet->gtp1l.h.tei=hton32(pdp->teid_gn);
574 else if (pdp)
575 packet->gtp1l.h.tei=hton32(pdp->teic_gn);
576 }
577 else {
578 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
jjakoa7cd2492003-04-11 09:40:12 +0000579 return -1;
580 }
jjako52c24142002-12-16 13:33:51 +0000581
jjako08d331d2003-10-13 20:33:30 +0000582 if (fcntl(fd, F_SETFL, 0)) {
583 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
584 return -1;
585 }
586
587 if (sendto(fd, packet, len, 0,
jjako52c24142002-12-16 13:33:51 +0000588 (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
589 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000590 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 +0000591 return -1;
592 }
593
594 /* Use new queue structure */
595 if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) {
596 gsn->err_queuefull++;
597 gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full");
598 }
599 else {
600 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
601 qmsg->l = len;
602 qmsg->timeout = time(NULL) + 60; /* When to timeout */
603 qmsg->retrans = 0; /* No retransmissions so far */
jjako08d331d2003-10-13 20:33:30 +0000604 qmsg->cbp = NULL;
jjako52c24142002-12-16 13:33:51 +0000605 qmsg->type = 0;
jjako08d331d2003-10-13 20:33:30 +0000606 qmsg->fd = fd;
jjako52c24142002-12-16 13:33:51 +0000607 }
608 return 0;
609}
610
jjako2c381332003-10-21 19:09:53 +0000611int gtp_notification(struct gsn_t *gsn, int version,
612 union gtp_packet *packet, int len,
613 struct sockaddr_in *peer, int fd,
614 uint16_t seq) {
615
616 struct sockaddr_in addr;
617
618 memcpy(&addr, peer, sizeof(addr));
619
620 /* In GTP0 notifications are treated as replies. In GTP1 they
621 are requests for which there is no reply */
622
623 if (fd == gsn->fd1c)
624 addr.sin_port = htons(GTP1C_PORT);
625 else if (fd == gsn->fd1u)
626 addr.sin_port = htons(GTP1C_PORT);
627
628 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
629 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
630 packet->gtp0.h.seq = hton16(seq);
631 }
632 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
633 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
634 packet->gtp1l.h.seq = hton16(seq);
635 }
636 else {
637 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
638 return -1;
639 }
640
641 if (fcntl(fd, F_SETFL, 0)) {
642 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
643 return -1;
644 }
645
646 if (sendto(fd, packet, len, 0,
647 (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) {
648 gsn->err_sendto++;
649 gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno));
650 return -1;
651 }
652 return 0;
653}
654
jjako52c24142002-12-16 13:33:51 +0000655int gtp_dublicate(struct gsn_t *gsn, int version,
656 struct sockaddr_in *peer, uint16_t seq) {
657 struct qmsg_t *qmsg;
658
659 if(queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) {
660 return EOF; /* Notfound */
661 }
jjakoa7cd2492003-04-11 09:40:12 +0000662
jjako08d331d2003-10-13 20:33:30 +0000663 if (fcntl(qmsg->fd, F_SETFL, 0)) {
664 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
665 return -1;
jjako52c24142002-12-16 13:33:51 +0000666 }
jjako08d331d2003-10-13 20:33:30 +0000667
668 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
669 (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
670 gsn->err_sendto++;
671 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));
672 }
673 return 0;
jjako52c24142002-12-16 13:33:51 +0000674}
675
676
677
678/* Perform restoration and recovery error handling as described in 29.060 */
679static void log_restart(struct gsn_t *gsn) {
680 FILE *f;
681 int i;
682 int counter = 0;
683 char filename[NAMESIZE];
684
685 filename[NAMESIZE-1] = 0; /* No null term. guarantee by strncpy */
686 strncpy(filename, gsn->statedir, NAMESIZE-1);
687 strncat(filename, RESTART_FILE,
688 NAMESIZE-1-sizeof(RESTART_FILE));
689
690 i = umask(022);
691
692 /* We try to open file. On failure we will later try to create file */
693 if (!(f = fopen(filename, "r"))) {
jjako581c9f02003-10-22 11:28:20 +0000694
695 gtp_err(LOG_ERR, __FILE__, __LINE__, "State information file (%s) not found. Creating new file.", filename);
jjako52c24142002-12-16 13:33:51 +0000696 }
697 else {
698 umask(i);
699 fscanf(f, "%d", &counter);
700 if (fclose(f)) {
701 gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno));
702 }
703 }
704
705 gsn->restart_counter = (unsigned char) counter;
706 gsn->restart_counter++;
707
708 if (!(f = fopen(filename, "w"))) {
709 gtp_err(LOG_ERR, __FILE__, __LINE__, "fopen(path=%s, mode=%s) failed: Error = %s", filename, "w", strerror(errno));
710 return;
711 }
712
713 umask(i);
714 fprintf(f, "%d\n", gsn->restart_counter);
715 if (fclose(f)) {
716 gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno));
717 return;
718 }
719}
720
721
722
jjako1db1c812003-07-06 20:53:57 +0000723int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
724 int mode)
jjako52c24142002-12-16 13:33:51 +0000725{
726 struct sockaddr_in addr;
jjako52c24142002-12-16 13:33:51 +0000727
728 syslog(LOG_ERR, "GTP: gtp_newgsn() started");
729
730 *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
731
732 (*gsn)->statedir = statedir;
733 log_restart(*gsn);
jjakoa7cd2492003-04-11 09:40:12 +0000734
735 /* Initialise sequence number */
736 (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
jjako52c24142002-12-16 13:33:51 +0000737
738 /* Initialise request retransmit queue */
739 queue_new(&(*gsn)->queue_req);
740 queue_new(&(*gsn)->queue_resp);
741
742 /* Initialise pdp table */
743 pdp_init();
744
745 /* Initialise call back functions */
jjako08d331d2003-10-13 20:33:30 +0000746 (*gsn)->cb_create_context_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000747 (*gsn)->cb_delete_context = 0;
jjako08d331d2003-10-13 20:33:30 +0000748 (*gsn)->cb_unsup_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000749 (*gsn)->cb_conf = 0;
jjako08d331d2003-10-13 20:33:30 +0000750 (*gsn)->cb_data_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000751
jjako08d331d2003-10-13 20:33:30 +0000752 /* Store function parameters */
753 (*gsn)->gsnc = *listen;
754 (*gsn)->gsnu = *listen;
755 (*gsn)->mode = mode;
756
757
758 /* Create GTP version 0 socket */
759 if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
jjako52c24142002-12-16 13:33:51 +0000760 (*gsn)->err_socket++;
761 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
762 return -1;
763 }
jjako52c24142002-12-16 13:33:51 +0000764
765 memset(&addr, 0, sizeof(addr));
jjako52c24142002-12-16 13:33:51 +0000766 addr.sin_family = AF_INET;
jjako52c24142002-12-16 13:33:51 +0000767 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
768 addr.sin_port = htons(GTP0_PORT);
jjako1f158642004-02-05 20:39:57 +0000769#if defined(__FreeBSD__)
jjako06e9f122004-01-19 18:37:58 +0000770 addr.sin_len = sizeof(addr);
771#endif
jjako52c24142002-12-16 13:33:51 +0000772
jjako08d331d2003-10-13 20:33:30 +0000773 if (bind((*gsn)->fd0, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
jjako52c24142002-12-16 13:33:51 +0000774 (*gsn)->err_socket++;
jjako08d331d2003-10-13 20:33:30 +0000775 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));
776 return -1;
777 }
778
779 /* Create GTP version 1 control plane socket */
780 if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
781 (*gsn)->err_socket++;
782 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
783 return -1;
784 }
785
786 memset(&addr, 0, sizeof(addr));
787 addr.sin_family = AF_INET;
788 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
789 addr.sin_port = htons(GTP1C_PORT);
jjako1f158642004-02-05 20:39:57 +0000790#if defined(__FreeBSD__)
jjako06e9f122004-01-19 18:37:58 +0000791 addr.sin_len = sizeof(addr);
792#endif
jjako08d331d2003-10-13 20:33:30 +0000793
794 if (bind((*gsn)->fd1c, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
795 (*gsn)->err_socket++;
796 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));
797 return -1;
798 }
799
800 /* Create GTP version 1 user plane socket */
801 if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
802 (*gsn)->err_socket++;
803 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
804 return -1;
805 }
806
807 memset(&addr, 0, sizeof(addr));
808 addr.sin_family = AF_INET;
809 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
810 addr.sin_port = htons(GTP1U_PORT);
jjako1f158642004-02-05 20:39:57 +0000811#if defined(__FreeBSD__)
jjako06e9f122004-01-19 18:37:58 +0000812 addr.sin_len = sizeof(addr);
813#endif
jjako08d331d2003-10-13 20:33:30 +0000814
815 if (bind((*gsn)->fd1u, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
816 (*gsn)->err_socket++;
817 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 +0000818 return -1;
819 }
820
jjako52c24142002-12-16 13:33:51 +0000821 return 0;
822}
823
824int gtp_free(struct gsn_t *gsn) {
825
826 /* Clean up retransmit queues */
827 queue_free(gsn->queue_req);
828 queue_free(gsn->queue_resp);
jjako08d331d2003-10-13 20:33:30 +0000829
830 close(gsn->fd0);
831 close(gsn->fd1c);
832 close(gsn->fd1u);
jjako52c24142002-12-16 13:33:51 +0000833
834 free(gsn);
835 return 0;
836}
837
838/* ***********************************************************
839 * Path management messages
840 * Messages: echo and version not supported.
841 * A path is connection between two UDP/IP endpoints
842 *
843 * A path is either using GTP0 or GTP1. A path can be
844 * established by any kind of GTP message??
845
846 * Which source port to use?
847 * GTP-C request destination port is 2123/3386
848 * GTP-U request destination port is 2152/3386
849 * T-PDU destination port is 2152/3386.
850 * For the above messages the source port is locally allocated.
851 * For response messages src=rx-dst and dst=rx-src.
852 * For simplicity we should probably use 2123+2152/3386 as
853 * src port even for the cases where src can be locally
854 * allocated. This also means that we have to listen only to
855 * the same ports.
856 * For response messages we need to be able to respond to
857 * the relevant src port even if it is locally allocated by
858 * the peer.
859 *
860 * The need for path management!
861 * We might need to keep a list of active paths. This might
862 * be in the form of remote IP address + UDP port numbers.
863 * (We will consider a path astablished if we have a context
864 * with the node in question)
865 *************************************************************/
866
867/* Send off an echo request */
jjako08d331d2003-10-13 20:33:30 +0000868int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
869 struct in_addr *inetaddr)
jjako52c24142002-12-16 13:33:51 +0000870{
871 union gtp_packet packet;
jjako08d331d2003-10-13 20:33:30 +0000872 int length = get_default_gtp(version, GTP_ECHO_REQ, &packet);
873 return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp);
jjako52c24142002-12-16 13:33:51 +0000874}
875
jjako08d331d2003-10-13 20:33:30 +0000876/* Send off an echo reply */
877int gtp_echo_resp(struct gsn_t *gsn, int version,
878 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +0000879 void *pack, unsigned len)
880{
881 union gtp_packet packet;
jjako08d331d2003-10-13 20:33:30 +0000882 int length = get_default_gtp(version, GTP_ECHO_RSP, &packet);
883 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, gsn->restart_counter);
884 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
885 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +0000886}
887
888
889/* Handle a received echo request */
jjako08d331d2003-10-13 20:33:30 +0000890int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
891 int fd, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000892
jjako08d331d2003-10-13 20:33:30 +0000893 /* Check if it was a dublicate request */
894 if(!gtp_dublicate(gsn, 0, peer, get_seq(pack))) return 0;
jjako52c24142002-12-16 13:33:51 +0000895
jjako08d331d2003-10-13 20:33:30 +0000896 /* Send off reply to request */
897 return gtp_echo_resp(gsn, version, peer, fd, pack, len);
jjako52c24142002-12-16 13:33:51 +0000898}
899
900/* Handle a received echo reply */
jjako08d331d2003-10-13 20:33:30 +0000901int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
jjako52c24142002-12-16 13:33:51 +0000902 void *pack, unsigned len) {
903 union gtpie_member *ie[GTPIE_SIZE];
904 unsigned char recovery;
jjako08d331d2003-10-13 20:33:30 +0000905 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +0000906 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +0000907 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +0000908
909 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +0000910 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +0000911
jjako08d331d2003-10-13 20:33:30 +0000912 /* Extract information elements into a pointer array */
913 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +0000914 gsn->invalid++;
915 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
916 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +0000917 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000918 return EOF;
919 }
920
921 if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
922 gsn->missing++;
923 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
924 "Missing mandatory field");
jjako08d331d2003-10-13 20:33:30 +0000925 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000926 return EOF;
927 }
928
jjako08d331d2003-10-13 20:33:30 +0000929 /* Echo reply packages does not have a cause information element */
930 /* Instead we return the recovery number in the callback function */
931 if (gsn->cb_conf) gsn->cb_conf(type, recovery, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000932
933 return 0;
934}
935
936/* Send off a Version Not Supported message */
937/* This message is somewhat special in that it actually is a
938 * response to some other message with unsupported GTP version
939 * For this reason it has parameters like a response, and does
940 * its own message transmission. No signalling queue is used
941 * The reply is sent to the peer IP and peer UDP. This means that
942 * the peer will be receiving a GTP0 message on a GTP1 port!
943 * In practice however this will never happen as a GTP0 GSN will
944 * only listen to the GTP0 port, and therefore will never receive
945 * anything else than GTP0 */
946
jjako08d331d2003-10-13 20:33:30 +0000947int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
948 int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000949{
950 union gtp_packet packet;
jjako52c24142002-12-16 13:33:51 +0000951
jjako08d331d2003-10-13 20:33:30 +0000952 /* GTP 1 is the highest supported protocol */
jjako2c381332003-10-21 19:09:53 +0000953 int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet);
954 return gtp_notification(gsn, version, &packet, length,
955 peer, fd, 0);
jjako52c24142002-12-16 13:33:51 +0000956}
957
958/* Handle a Version Not Supported message */
jjako08d331d2003-10-13 20:33:30 +0000959int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
960 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000961
jjako08d331d2003-10-13 20:33:30 +0000962 if (gsn->cb_unsup_ind) gsn->cb_unsup_ind(peer);
jjako52c24142002-12-16 13:33:51 +0000963
jjako52c24142002-12-16 13:33:51 +0000964 return 0;
965}
966
jjako2c381332003-10-21 19:09:53 +0000967/* Send off an Supported Extension Headers Notification */
968int gtp_extheader_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
969 int fd, void *pack, unsigned len)
970{
971 union gtp_packet packet;
972 int length = get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet);
973
974 uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU;
975
976 if (version < 1)
977 return 0;
978
979 /* We report back that we support only PDCP PDU headers */
980 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T, sizeof(pdcp_pdu),
981 &pdcp_pdu);
982
983 return gtp_notification(gsn, version, &packet, length,
984 peer, fd, get_seq(pack));
985}
986
987/* Handle a Supported Extension Headers Notification */
988int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
989 void *pack, unsigned len) {
990
991 if (gsn->cb_extheader_ind) gsn->cb_extheader_ind(peer);
992
993 return 0;
994}
995
996
jjako52c24142002-12-16 13:33:51 +0000997/* ***********************************************************
998 * Session management messages
999 * Messages: create, update and delete PDP context
1000 *
1001 * Information storage
1002 * Information storage for each PDP context is defined in
1003 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
1004 * PDP-address (IP address), sequence numbers, charging ID.
1005 * For the SGSN it also includes radio related mobility
1006 * information.
1007 *************************************************************/
1008
jjako08d331d2003-10-13 20:33:30 +00001009/* API: Send Create PDP Context Request */
1010extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
jjako193e8b12003-11-10 12:31:41 +00001011 void *cbp) {
jjako52c24142002-12-16 13:33:51 +00001012 union gtp_packet packet;
jjako08d331d2003-10-13 20:33:30 +00001013 int length = get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet);
jjako2c381332003-10-21 19:09:53 +00001014 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001015
jjako2c381332003-10-21 19:09:53 +00001016 /* TODO: Secondary PDP Context Activation Procedure */
1017 /* In secondary activation procedure the PDP context is identified
1018 by tei in the header. The following fields are omitted: Selection
1019 mode, IMSI, MSISDN, End User Address, Access Point Name and
1020 Protocol Configuration Options */
1021
1022 if (pdp->secondary) {
1023 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
1024 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context");
1025 return EOF;
1026 }
1027 }
1028
1029 if (pdp->version == 0) {
jjako08d331d2003-10-13 20:33:30 +00001030 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
jjako52c24142002-12-16 13:33:51 +00001031 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako2c381332003-10-21 19:09:53 +00001032 }
jjako52c24142002-12-16 13:33:51 +00001033
jjako2c381332003-10-21 19:09:53 +00001034 if (pdp->version == 1) {
1035 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1036 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1037 sizeof(pdp->imsi), (uint8_t*) &pdp->imsi);
1038 }
jjako52c24142002-12-16 13:33:51 +00001039
jjako08d331d2003-10-13 20:33:30 +00001040 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1041 gsn->restart_counter);
jjako2c381332003-10-21 19:09:53 +00001042
1043 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1044 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE,
1045 pdp->selmode);
jjako08d331d2003-10-13 20:33:30 +00001046
1047 if (pdp->version == 0) {
1048 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1049 pdp->fllu);
1050 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1051 pdp->fllc);
1052 }
1053
1054 if (pdp->version == 1) {
1055 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1056 pdp->teid_own);
jjako2c381332003-10-21 19:09:53 +00001057
1058 if (!pdp->teic_confirmed)
1059 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1060 pdp->teic_own);
jjako08d331d2003-10-13 20:33:30 +00001061
jjakobe61ef22004-01-09 12:22:29 +00001062 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1063 pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00001064
jjako08d331d2003-10-13 20:33:30 +00001065
jjako2c381332003-10-21 19:09:53 +00001066 if (pdp->secondary) /* Secondary PDP Context Activation Procedure */
jjakobe61ef22004-01-09 12:22:29 +00001067 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
jjako2c381332003-10-21 19:09:53 +00001068 linked_pdp->nsapi);
1069
jjako08d331d2003-10-13 20:33:30 +00001070 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C,
1071 pdp->cch_pdp);
1072 }
1073
1074 /* TODO
1075 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1076 pdp->traceref);
1077 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1078 pdp->tracetype); */
1079
jjako2c381332003-10-21 19:09:53 +00001080 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1081 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1082 pdp->eua.l, pdp->eua.v);
1083
jjako08d331d2003-10-13 20:33:30 +00001084
jjako2c381332003-10-21 19:09:53 +00001085 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1086 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN,
1087 pdp->apn_use.l, pdp->apn_use.v);
1088
1089 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1090 if (pdp->pco_req.l)
1091 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1092 pdp->pco_req.l, pdp->pco_req.v);
jjako08d331d2003-10-13 20:33:30 +00001093
1094 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1095 pdp->gsnlc.l, pdp->gsnlc.v);
1096 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1097 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001098
1099 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1100 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN,
1101 pdp->msisdn.l, pdp->msisdn.v);
jjako08d331d2003-10-13 20:33:30 +00001102
1103 if (pdp->version == 1)
1104 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1105 pdp->qos_req.l, pdp->qos_req.v);
1106
1107
1108 if ((pdp->version == 1) && pdp->tft.l)
1109 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1110 pdp->tft.l, pdp->tft.v);
1111
1112 if ((pdp->version == 1) && pdp->triggerid.l)
1113 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1114 pdp->triggerid.l, pdp->triggerid.v);
1115
1116 if ((pdp->version == 1) && pdp->omcid.l)
1117 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1118 pdp->omcid.l, pdp->omcid.v);
1119
jjako193e8b12003-11-10 12:31:41 +00001120 /* TODO hisaddr0 */
1121 gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
jjako52c24142002-12-16 13:33:51 +00001122
1123 return 0;
1124}
1125
jjako08d331d2003-10-13 20:33:30 +00001126/* API: Application response to context indication */
1127int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause) {
1128
1129 /* Now send off a reply to the peer */
1130 gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
1131
1132 if (cause != GTPCAUSE_ACC_REQ) {
1133 pdp_freepdp(pdp);
1134 }
1135
1136 return 0;
1137}
1138
1139/* API: Register create context indication callback */
1140int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
1141 int (*cb_create_context_ind) (struct pdp_t* pdp))
jjako52c24142002-12-16 13:33:51 +00001142{
jjako08d331d2003-10-13 20:33:30 +00001143 gsn->cb_create_context_ind = cb_create_context_ind;
1144 return 0;
1145}
1146
1147
1148/* Send Create PDP Context Response */
1149int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
1150 uint8_t cause) {
jjako52c24142002-12-16 13:33:51 +00001151 union gtp_packet packet;
jjako08d331d2003-10-13 20:33:30 +00001152 int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
jjako52c24142002-12-16 13:33:51 +00001153
jjako08d331d2003-10-13 20:33:30 +00001154 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00001155
1156 if (cause == GTPCAUSE_ACC_REQ) {
jjako08d331d2003-10-13 20:33:30 +00001157
1158 if (version == 0)
1159 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1160 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1161
1162 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER,
jjako52c24142002-12-16 13:33:51 +00001163 pdp->reorder);
jjako08d331d2003-10-13 20:33:30 +00001164 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
jjako52c24142002-12-16 13:33:51 +00001165 gsn->restart_counter);
jjako08d331d2003-10-13 20:33:30 +00001166
1167 if (version == 0) {
1168 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1169 pdp->fllu);
1170 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1171 pdp->fllc);
1172 }
1173
1174 if (version == 1) {
1175 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1176 pdp->teid_own);
1177 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1178 pdp->teic_own);
1179 }
1180
jjako2c381332003-10-21 19:09:53 +00001181 /* TODO: We use teic_own as charging ID */
jjako08d331d2003-10-13 20:33:30 +00001182 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
jjako2c381332003-10-21 19:09:53 +00001183 pdp->teic_own);
1184
jjako08d331d2003-10-13 20:33:30 +00001185 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
jjako52c24142002-12-16 13:33:51 +00001186 pdp->eua.l, pdp->eua.v);
1187
1188 if (pdp->pco_neg.l) { /* Optional PCO */
jjako08d331d2003-10-13 20:33:30 +00001189 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
jjako52c24142002-12-16 13:33:51 +00001190 pdp->pco_neg.l, pdp->pco_neg.v);
1191 }
1192
jjako08d331d2003-10-13 20:33:30 +00001193 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
jjako52c24142002-12-16 13:33:51 +00001194 pdp->gsnlc.l, pdp->gsnlc.v);
jjako08d331d2003-10-13 20:33:30 +00001195 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
jjako52c24142002-12-16 13:33:51 +00001196 pdp->gsnlu.l, pdp->gsnlu.v);
jjako08d331d2003-10-13 20:33:30 +00001197
1198 if (version == 1)
1199 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1200 pdp->qos_neg.l, pdp->qos_neg.v);
1201
1202 /* TODO: Charging gateway address */
jjako52c24142002-12-16 13:33:51 +00001203 }
1204
jjako08d331d2003-10-13 20:33:30 +00001205 return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer,
1206 pdp->fd, pdp->seq, pdp->tid);
jjako52c24142002-12-16 13:33:51 +00001207}
1208
1209/* Handle Create PDP Context Request */
1210int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001211 struct sockaddr_in *peer, int fd,
1212 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00001213 struct pdp_t *pdp, *pdp_old;
1214 struct pdp_t pdp_buf;
1215 union gtpie_member* ie[GTPIE_SIZE];
1216 uint8_t recovery;
jjako52c24142002-12-16 13:33:51 +00001217
jjako08d331d2003-10-13 20:33:30 +00001218 uint16_t seq = get_seq(pack);
1219 int hlen = get_hlen(pack);
jjako2c381332003-10-21 19:09:53 +00001220 uint8_t linked_nsapi = 0;
1221 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001222
jjako2c381332003-10-21 19:09:53 +00001223 if(!gtp_dublicate(gsn, version, peer, seq)) return 0;
jjako08d331d2003-10-13 20:33:30 +00001224
1225 pdp = &pdp_buf;
1226 memset(pdp, 0, sizeof(struct pdp_t));
1227
1228 if (version == 0) {
jjakod48c5ff2004-01-26 22:25:40 +00001229 pdp->imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffffull;
1230 pdp->nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000ull) >> 60;
jjako52c24142002-12-16 13:33:51 +00001231 }
1232
jjako08d331d2003-10-13 20:33:30 +00001233 pdp->seq = seq;
1234 pdp->sa_peer = *peer;
1235 pdp->fd = fd;
1236 pdp->version = version;
1237
jjako52c24142002-12-16 13:33:51 +00001238 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001239 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001240 gsn->invalid++;
1241 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1242 "Invalid message format");
1243 if (0 == version)
1244 return EOF;
1245 else
jjako08d331d2003-10-13 20:33:30 +00001246 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_INVALID_MESSAGE);
jjako52c24142002-12-16 13:33:51 +00001247 }
1248
jjako2c381332003-10-21 19:09:53 +00001249 if (version == 1) {
1250 /* Linked NSAPI (conditional) */
1251 /* If included this is the Secondary PDP Context Activation Procedure */
1252 /* In secondary activation IMSI is not included, so the context must be */
1253 /* identified by the tei */
1254 if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) {
1255
1256 /* Find the primary PDP context */
1257 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
1258 gsn->incorrect++;
1259 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1260 "Incorrect optional information field");
1261 return gtp_create_pdp_resp(gsn, version, pdp,
1262 GTPCAUSE_OPT_IE_INCORRECT);
1263 }
1264
1265 /* Check that the primary PDP context matches linked nsapi */
1266 if (linked_pdp->nsapi != linked_nsapi) {
1267 gsn->incorrect++;
1268 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1269 "Incorrect optional information field");
1270 return gtp_create_pdp_resp(gsn, version, pdp,
1271 GTPCAUSE_OPT_IE_INCORRECT);
1272 }
1273
1274 /* Copy parameters from primary context */
1275 pdp->selmode = linked_pdp->selmode;
1276 pdp->imsi = linked_pdp->imsi;
1277 pdp->msisdn = linked_pdp->msisdn;
1278 pdp->eua = linked_pdp->eua;
1279 pdp->pco_req = linked_pdp->pco_req;
1280 pdp->apn_req = linked_pdp->apn_req;
1281 pdp->teic_gn = linked_pdp->teic_gn;
1282 pdp->secondary = 1;
1283 }
1284 } /* if (version == 1) */
1285
jjako08d331d2003-10-13 20:33:30 +00001286 if (version == 0) {
1287 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1288 pdp->qos_req0, sizeof(pdp->qos_req0))) {
1289 gsn->missing++;
1290 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1291 "Missing mandatory information field");
1292 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING);
1293 }
jjako52c24142002-12-16 13:33:51 +00001294 }
jjako2c381332003-10-21 19:09:53 +00001295
1296 if ((version == 1) && (!linked_pdp)) {
1297 /* Not Secondary PDP Context Activation Procedure */
jjako08d331d2003-10-13 20:33:30 +00001298 /* IMSI (conditional) */
1299 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) {
1300 gsn->missing++;
1301 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1302 "Missing mandatory information field");
1303 return gtp_create_pdp_resp(gsn, version, pdp,
1304 GTPCAUSE_MAN_IE_MISSING);
1305 }
1306 }
jjako2c381332003-10-21 19:09:53 +00001307
jjako08d331d2003-10-13 20:33:30 +00001308 /* Recovery (optional) */
jjako52c24142002-12-16 13:33:51 +00001309 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1310 /* TODO: Handle received recovery IE */
1311 }
jjako2c381332003-10-21 19:09:53 +00001312
jjako08d331d2003-10-13 20:33:30 +00001313 /* Selection mode (conditional) */
jjako2c381332003-10-21 19:09:53 +00001314 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1315 if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0,
1316 &pdp->selmode, sizeof(pdp->selmode))) {
1317 gsn->missing++;
1318 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1319 "Missing mandatory information field");
1320 return gtp_create_pdp_resp(gsn, version, pdp,
1321 GTPCAUSE_MAN_IE_MISSING);
1322 }
jjako52c24142002-12-16 13:33:51 +00001323 }
1324
jjako08d331d2003-10-13 20:33:30 +00001325 if (version == 0) {
1326 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1327 gsn->missing++;
1328 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1329 "Missing mandatory information field");
1330 return gtp_create_pdp_resp(gsn, version, pdp,
1331 GTPCAUSE_MAN_IE_MISSING);
1332 }
1333
1334 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1335 gsn->missing++;
1336 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1337 "Missing mandatory information field");
1338 return gtp_create_pdp_resp(gsn, version, pdp,
1339 GTPCAUSE_MAN_IE_MISSING);
1340 }
jjako52c24142002-12-16 13:33:51 +00001341 }
jjako2c381332003-10-21 19:09:53 +00001342
1343
jjako08d331d2003-10-13 20:33:30 +00001344 if (version == 1) {
1345 /* TEID (mandatory) */
1346 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1347 gsn->missing++;
1348 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1349 "Missing mandatory information field");
1350 return gtp_create_pdp_resp(gsn, version, pdp,
1351 GTPCAUSE_MAN_IE_MISSING);
1352 }
1353
1354 /* TEIC (conditional) */
jjako2c381332003-10-21 19:09:53 +00001355 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1356 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1357 gsn->missing++;
1358 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1359 "Missing mandatory information field");
1360 return gtp_create_pdp_resp(gsn, version, pdp,
1361 GTPCAUSE_MAN_IE_MISSING);
1362 }
jjako08d331d2003-10-13 20:33:30 +00001363 }
jjako52c24142002-12-16 13:33:51 +00001364
jjako98200df2004-01-09 15:18:42 +00001365 /* NSAPI (mandatory) */
1366 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
1367 gsn->missing++;
1368 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1369 "Missing mandatory information field");
1370 return gtp_create_pdp_resp(gsn, version, pdp,
1371 GTPCAUSE_MAN_IE_MISSING);
1372 }
jjako2c381332003-10-21 19:09:53 +00001373 }
1374
1375
jjako08d331d2003-10-13 20:33:30 +00001376 /* Charging Characteriatics (optional) */
1377 /* Trace reference (optional) */
1378 /* Trace type (optional) */
1379 /* Charging Characteriatics (optional) */
jjako2c381332003-10-21 19:09:53 +00001380
1381 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1382 /* End User Address (conditional) */
1383 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
jjako52c24142002-12-16 13:33:51 +00001384 &pdp->eua.v, sizeof(pdp->eua.v))) {
jjako2c381332003-10-21 19:09:53 +00001385 gsn->missing++;
1386 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1387 "Missing mandatory information field");
1388 return gtp_create_pdp_resp(gsn, version, pdp,
1389 GTPCAUSE_MAN_IE_MISSING);
1390 }
1391
1392 /* APN */
1393 if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l,
jjako52c24142002-12-16 13:33:51 +00001394 &pdp->apn_req.v, sizeof(pdp->apn_req.v))) {
jjako2c381332003-10-21 19:09:53 +00001395 gsn->missing++;
1396 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1397 "Missing mandatory information field");
1398 return gtp_create_pdp_resp(gsn, version, pdp,
1399 GTPCAUSE_MAN_IE_MISSING);
1400 }
1401
1402 /* Extract protocol configuration options (optional) */
1403 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1404 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1405 }
jjako52c24142002-12-16 13:33:51 +00001406 }
1407
jjako08d331d2003-10-13 20:33:30 +00001408 /* SGSN address for signalling (mandatory) */
jjako52c24142002-12-16 13:33:51 +00001409 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1410 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1411 gsn->missing++;
1412 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1413 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001414 return gtp_create_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00001415 GTPCAUSE_MAN_IE_MISSING);
1416 }
1417
jjako08d331d2003-10-13 20:33:30 +00001418 /* SGSN address for user traffic (mandatory) */
jjako52c24142002-12-16 13:33:51 +00001419 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1420 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1421 gsn->missing++;
1422 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1423 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001424 return gtp_create_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00001425 GTPCAUSE_MAN_IE_MISSING);
1426 }
1427
jjako2c381332003-10-21 19:09:53 +00001428 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1429 /* MSISDN (conditional) */
1430 if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l,
1431 &pdp->msisdn.v, sizeof(pdp->msisdn.v))) {
1432 gsn->missing++;
1433 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1434 "Missing mandatory information field");
1435 return gtp_create_pdp_resp(gsn, version, pdp,
1436 GTPCAUSE_MAN_IE_MISSING);
1437 }
jjako52c24142002-12-16 13:33:51 +00001438 }
1439
jjako08d331d2003-10-13 20:33:30 +00001440 if (version == 1) {
1441 /* QoS (mandatory) */
1442 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
1443 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
1444 gsn->missing++;
1445 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1446 "Missing mandatory information field");
1447 return gtp_create_pdp_resp(gsn, version, pdp,
1448 GTPCAUSE_MAN_IE_MISSING);
1449 }
1450
1451 /* TFT (conditional) */
1452 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
1453 &pdp->tft.v, sizeof(pdp->tft.v))) {
1454 }
jjako2c381332003-10-21 19:09:53 +00001455
jjako08d331d2003-10-13 20:33:30 +00001456 /* Trigger ID */
1457 /* OMC identity */
1458 }
1459
1460 /* Initialize our own IP addresses */
jjako52c24142002-12-16 13:33:51 +00001461 in_addr2gsna(&pdp->gsnlc, &gsn->gsnc);
1462 in_addr2gsna(&pdp->gsnlu, &gsn->gsnu);
jjako2c381332003-10-21 19:09:53 +00001463
jjako2e840a32003-01-28 16:05:18 +00001464 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Before pdp_tidget\n");
jjako2c381332003-10-21 19:09:53 +00001465
jjako08d331d2003-10-13 20:33:30 +00001466 if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) {
jjako52c24142002-12-16 13:33:51 +00001467 /* Found old pdp with same tid. Now the voodoo begins! */
jjako08d331d2003-10-13 20:33:30 +00001468 /* 09.60 / 29.060 allows create on existing context to "steal" */
1469 /* the context which was allready established */
jjako52c24142002-12-16 13:33:51 +00001470 /* We check that the APN, selection mode and MSISDN is the same */
jjako2e840a32003-01-28 16:05:18 +00001471 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n");
jjako08d331d2003-10-13 20:33:30 +00001472 if ((pdp->apn_req.l == pdp_old->apn_req.l)
jjako52c24142002-12-16 13:33:51 +00001473 && (!memcmp(pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l))
1474 && (pdp->selmode == pdp_old->selmode)
1475 && (pdp->msisdn.l == pdp_old->msisdn.l)
1476 && (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l))) {
1477 /* OK! We are dealing with the same APN. We will copy new
1478 * parameters to the old pdp and send off confirmation
1479 * We ignore the following information elements:
1480 * QoS: MS will get originally negotiated QoS.
1481 * End user address (EUA). MS will get old EUA anyway.
1482 * Protocol configuration option (PCO): Only application can verify */
jjako2e840a32003-01-28 16:05:18 +00001483
1484 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n");
jjako52c24142002-12-16 13:33:51 +00001485
1486 /* Copy remote flow label */
1487 pdp_old->flru = pdp->flru;
1488 pdp_old->flrc = pdp->flrc;
1489
jjako08d331d2003-10-13 20:33:30 +00001490 /* Copy remote tei */
1491 pdp_old->teid_gn = pdp->teid_gn;
1492 pdp_old->teic_gn = pdp->teic_gn;
1493
jjako52c24142002-12-16 13:33:51 +00001494 /* Copy peer GSN address */
1495 pdp_old->gsnrc.l = pdp->gsnrc.l;
1496 memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l);
1497 pdp_old->gsnru.l = pdp->gsnru.l;
1498 memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l);
jjako2c381332003-10-21 19:09:53 +00001499
1500 /* Copy request parameters */
1501 pdp_old->seq = pdp->seq;
1502 pdp_old->sa_peer = pdp->sa_peer;
1503 pdp_old->fd = pdp->fd = fd;
1504 pdp_old->version = pdp->version = version;
1505
1506 /* Switch to using the old pdp context */
jjako52c24142002-12-16 13:33:51 +00001507 pdp = pdp_old;
1508
1509 /* Confirm to peer that things were "successful" */
jjako08d331d2003-10-13 20:33:30 +00001510 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_ACC_REQ);
jjako52c24142002-12-16 13:33:51 +00001511 }
1512 else { /* This is not the same PDP context. Delete the old one. */
jjako2e840a32003-01-28 16:05:18 +00001513
1514 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleting old context\n");
jjako52c24142002-12-16 13:33:51 +00001515
1516 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp_old);
1517 pdp_freepdp(pdp_old);
jjako08d331d2003-10-13 20:33:30 +00001518
jjako2e840a32003-01-28 16:05:18 +00001519 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleted...\n");
jjako52c24142002-12-16 13:33:51 +00001520 }
1521 }
1522
jjako08d331d2003-10-13 20:33:30 +00001523 pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp);
jjako52c24142002-12-16 13:33:51 +00001524
1525 /* Callback function to validata login */
jjako08d331d2003-10-13 20:33:30 +00001526 if (gsn->cb_create_context_ind !=0)
1527 return gsn->cb_create_context_ind(pdp);
jjako52c24142002-12-16 13:33:51 +00001528 else {
jjako08d331d2003-10-13 20:33:30 +00001529 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1530 "No create_context_ind callback defined");
1531 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_NOT_SUPPORTED);
jjako52c24142002-12-16 13:33:51 +00001532 }
1533}
1534
1535
1536/* Handle Create PDP Context Response */
1537int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001538 struct sockaddr_in *peer,
1539 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00001540 struct pdp_t *pdp;
1541 union gtpie_member *ie[GTPIE_SIZE];
1542 uint8_t cause, recovery;
jjako08d331d2003-10-13 20:33:30 +00001543 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00001544 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +00001545 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001546
1547 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00001548 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00001549
1550 /* Find the context in question */
jjako08d331d2003-10-13 20:33:30 +00001551 if (pdp_getgtp1(&pdp, get_tei(pack))) {
jjako52c24142002-12-16 13:33:51 +00001552 gsn->err_unknownpdp++;
1553 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1554 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00001555 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00001556 return EOF;
1557 }
1558
jjako2c381332003-10-21 19:09:53 +00001559 /* Register that we have received a valid teic from GGSN */
1560 pdp->teic_confirmed = 1;
1561
jjako52c24142002-12-16 13:33:51 +00001562 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001563 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001564 gsn->invalid++;
1565 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1566 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +00001567 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001568 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1569 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001570 return EOF;
1571 }
1572
1573 /* Extract cause value (mandatory) */
1574 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
1575 gsn->missing++;
1576 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1577 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001578 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001579 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1580 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001581 return EOF;
1582 }
1583
1584 /* Extract recovery (optional) */
1585 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1586 /* TODO: Handle received recovery IE */
1587 }
1588
1589 /* Extract protocol configuration options (optional) */
1590 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1591 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
jjako52c24142002-12-16 13:33:51 +00001592 }
1593
1594 /* Check all conditional information elements */
1595 if (GTPCAUSE_ACC_REQ == cause) {
1596
jjako08d331d2003-10-13 20:33:30 +00001597 if (version == 0) {
1598 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1599 &pdp->qos_neg0, sizeof(pdp->qos_neg0))) {
1600 gsn->missing++;
1601 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1602 "Missing conditional information field");
1603 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001604 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1605 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001606 return EOF;
1607 }
jjako52c24142002-12-16 13:33:51 +00001608 }
jjako52c24142002-12-16 13:33:51 +00001609
1610 if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) {
1611 gsn->missing++;
1612 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1613 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001614 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001615 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1616 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001617 return EOF;
1618 }
1619
jjako08d331d2003-10-13 20:33:30 +00001620 if (version == 0) {
1621 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1622 gsn->missing++;
1623 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1624 "Missing conditional information field");
1625 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001626 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1627 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001628 return EOF;
1629 }
jjako52c24142002-12-16 13:33:51 +00001630
jjako08d331d2003-10-13 20:33:30 +00001631 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1632 gsn->missing++;
1633 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1634 "Missing conditional information field");
1635 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001636 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1637 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001638 return EOF;
1639 }
1640 }
1641
1642 if (version == 1) {
1643 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1644 gsn->missing++;
1645 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1646 "Missing conditional information field");
1647 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001648 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1649 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001650 return EOF;
1651 }
1652
1653 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1654 gsn->missing++;
1655 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1656 "Missing conditional information field");
1657 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001658 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1659 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001660 return EOF;
1661 }
jjako52c24142002-12-16 13:33:51 +00001662 }
1663
1664 if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
1665 gsn->missing++;
1666 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1667 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001668 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001669 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1670 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001671 }
1672
1673 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1674 &pdp->eua.v, sizeof(pdp->eua.v))) {
1675 gsn->missing++;
1676 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1677 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001678 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001679 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1680 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001681 return EOF;
1682 }
1683
1684 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1685 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1686 gsn->missing++;
1687 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1688 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001689 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001690 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1691 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001692 return EOF;
1693 }
1694
1695 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1696 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1697 gsn->missing++;
1698 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1699 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001700 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001701 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1702 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001703 return EOF;
1704 }
jjako52c24142002-12-16 13:33:51 +00001705
jjako08d331d2003-10-13 20:33:30 +00001706 if (version == 1) {
1707 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
1708 &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
1709 gsn->missing++;
1710 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1711 "Missing conditional information field");
1712 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001713 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1714 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001715 return EOF;
1716 }
1717 }
jjakoccc564f2003-10-25 15:40:48 +00001718
jjako08d331d2003-10-13 20:33:30 +00001719 }
1720
1721 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako52c24142002-12-16 13:33:51 +00001722
1723 return 0;
1724}
1725
jjako52c24142002-12-16 13:33:51 +00001726
jjako08d331d2003-10-13 20:33:30 +00001727/* API: Send Update PDP Context Request */
1728int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
1729 struct in_addr* inetaddr) {
1730 union gtp_packet packet;
1731 int length = get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet);
jjako52c24142002-12-16 13:33:51 +00001732
jjako08d331d2003-10-13 20:33:30 +00001733 if (pdp->version == 0)
1734 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1735 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako2c381332003-10-21 19:09:53 +00001736
1737 /* Include IMSI if updating with unknown teic_gn */
1738 if ((pdp->version == 1) && (!pdp->teic_gn))
jjako08d331d2003-10-13 20:33:30 +00001739 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1740 sizeof(pdp->imsi), (uint8_t*) &pdp->imsi);
jjako2c381332003-10-21 19:09:53 +00001741
jjako08d331d2003-10-13 20:33:30 +00001742 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
jjako52c24142002-12-16 13:33:51 +00001743 gsn->restart_counter);
jjako2c381332003-10-21 19:09:53 +00001744
jjako08d331d2003-10-13 20:33:30 +00001745 if (pdp->version == 0) {
1746 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
jjako52c24142002-12-16 13:33:51 +00001747 pdp->fllu);
jjako08d331d2003-10-13 20:33:30 +00001748 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
jjako52c24142002-12-16 13:33:51 +00001749 pdp->fllc);
jjako52c24142002-12-16 13:33:51 +00001750 }
jjako2c381332003-10-21 19:09:53 +00001751
jjako08d331d2003-10-13 20:33:30 +00001752 if (pdp->version == 1) {
1753 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1754 pdp->teid_own);
jjako52c24142002-12-16 13:33:51 +00001755
jjako2c381332003-10-21 19:09:53 +00001756 if (!pdp->teic_confirmed)
1757 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1758 pdp->teic_own);
1759 }
1760
jjako08d331d2003-10-13 20:33:30 +00001761 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1762 pdp->nsapi);
jjako2c381332003-10-21 19:09:53 +00001763
jjako08d331d2003-10-13 20:33:30 +00001764 /* TODO
jjako2c381332003-10-21 19:09:53 +00001765 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1766 pdp->traceref);
1767 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1768 pdp->tracetype); */
1769
jjako08d331d2003-10-13 20:33:30 +00001770 /* TODO if ggsn update message
jjako2c381332003-10-21 19:09:53 +00001771 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1772 pdp->eua.l, pdp->eua.v);
jjako08d331d2003-10-13 20:33:30 +00001773 */
jjako2c381332003-10-21 19:09:53 +00001774
jjako08d331d2003-10-13 20:33:30 +00001775 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1776 pdp->gsnlc.l, pdp->gsnlc.v);
1777 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1778 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001779
jjako08d331d2003-10-13 20:33:30 +00001780 if (pdp->version == 1)
1781 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1782 pdp->qos_req.l, pdp->qos_req.v);
jjako2c381332003-10-21 19:09:53 +00001783
1784
jjako08d331d2003-10-13 20:33:30 +00001785 if ((pdp->version == 1) && pdp->tft.l)
1786 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1787 pdp->tft.l, pdp->tft.v);
1788
1789 if ((pdp->version == 1) && pdp->triggerid.l)
1790 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1791 pdp->triggerid.l, pdp->triggerid.v);
1792
1793 if ((pdp->version == 1) && pdp->omcid.l)
1794 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1795 pdp->omcid.l, pdp->omcid.v);
1796
1797 gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp);
1798
1799 return 0;
jjako52c24142002-12-16 13:33:51 +00001800}
1801
jjako08d331d2003-10-13 20:33:30 +00001802
1803/* Send Update PDP Context Response */
1804int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
1805 struct sockaddr_in *peer, int fd,
1806 void *pack, unsigned len,
1807 struct pdp_t *pdp, uint8_t cause) {
1808
1809 union gtp_packet packet;
1810 int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
1811
1812 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
1813
1814 if (cause == GTPCAUSE_ACC_REQ) {
1815
1816 if (version == 0)
1817 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1818 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1819
1820 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1821 gsn->restart_counter);
1822
1823 if (version == 0) {
1824 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1825 pdp->fllu);
1826 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1827 pdp->fllc);
1828 }
1829
1830 if (version == 1) {
1831 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1832 pdp->teid_own);
jjako2c381332003-10-21 19:09:53 +00001833
1834 if (!pdp->teic_confirmed)
1835 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1836 pdp->teic_own);
jjako08d331d2003-10-13 20:33:30 +00001837 }
jjako2c381332003-10-21 19:09:53 +00001838
1839 /* TODO we use teid_own as charging ID address */
jjako08d331d2003-10-13 20:33:30 +00001840 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
jjako2c381332003-10-21 19:09:53 +00001841 pdp->teid_own);
1842
jjako08d331d2003-10-13 20:33:30 +00001843 /* If ggsn
jjako2c381332003-10-21 19:09:53 +00001844 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1845 pdp->eua.l, pdp->eua.v); */
1846
jjako08d331d2003-10-13 20:33:30 +00001847 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1848 pdp->gsnlc.l, pdp->gsnlc.v);
1849 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1850 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001851
jjako08d331d2003-10-13 20:33:30 +00001852 if (version == 1)
1853 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1854 pdp->qos_neg.l, pdp->qos_neg.v);
jjako2c381332003-10-21 19:09:53 +00001855
jjako08d331d2003-10-13 20:33:30 +00001856 /* TODO: Charging gateway address */
1857 }
jjako2c381332003-10-21 19:09:53 +00001858
1859 return gtp_resp(version, gsn, pdp, &packet, length, peer,
1860 fd, get_seq(pack), get_tid(pack));
jjako08d331d2003-10-13 20:33:30 +00001861}
1862
1863
jjako52c24142002-12-16 13:33:51 +00001864/* Handle Update PDP Context Request */
1865int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001866 struct sockaddr_in *peer, int fd,
1867 void *pack, unsigned len) {
1868 struct pdp_t *pdp;
1869 struct pdp_t pdp_backup;
jjako52c24142002-12-16 13:33:51 +00001870 union gtpie_member* ie[GTPIE_SIZE];
1871 uint8_t recovery;
1872
jjako08d331d2003-10-13 20:33:30 +00001873 uint16_t seq = get_seq(pack);
1874 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001875
jjako08d331d2003-10-13 20:33:30 +00001876 uint64_t imsi;
1877 uint8_t nsapi;
1878
jjako52c24142002-12-16 13:33:51 +00001879 /* Is this a dublicate ? */
jjako08d331d2003-10-13 20:33:30 +00001880 if(!gtp_dublicate(gsn, version, peer, seq)) {
jjako52c24142002-12-16 13:33:51 +00001881 return 0; /* We allready send of response once */
1882 }
jjako2c381332003-10-21 19:09:53 +00001883
jjako52c24142002-12-16 13:33:51 +00001884
1885 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001886 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001887 gsn->invalid++;
1888 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1889 "Invalid message format");
1890 if (0 == version)
1891 return EOF;
1892 else
jjako08d331d2003-10-13 20:33:30 +00001893 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1894 NULL, GTPCAUSE_INVALID_MESSAGE);
jjako52c24142002-12-16 13:33:51 +00001895 }
1896
jjako08d331d2003-10-13 20:33:30 +00001897 /* Finding PDP: */
1898 /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
1899 /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
1900 /* we have to use the tunnel endpoint identifier */
1901 if (version == 0) {
jjakod48c5ff2004-01-26 22:25:40 +00001902 imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffffull;
1903 nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000ull) >> 60;
jjako2c381332003-10-21 19:09:53 +00001904
jjako08d331d2003-10-13 20:33:30 +00001905 /* Find the context in question */
1906 if (pdp_getimsi(&pdp, imsi, nsapi)) {
1907 gsn->err_unknownpdp++;
1908 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1909 "Unknown PDP context");
1910 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1911 NULL, GTPCAUSE_NON_EXIST);
1912 }
jjako52c24142002-12-16 13:33:51 +00001913 }
jjako08d331d2003-10-13 20:33:30 +00001914 else if (version == 1) {
1915 /* NSAPI (mandatory) */
1916 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
1917 gsn->missing++;
1918 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1919 "Missing mandatory information field");
1920 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1921 NULL, GTPCAUSE_MAN_IE_MISSING);
1922 }
jjako2c381332003-10-21 19:09:53 +00001923
jjako08d331d2003-10-13 20:33:30 +00001924 /* IMSI (conditional) */
1925 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) {
1926 /* Find the context in question */
1927 if (pdp_getgtp1(&pdp, get_tei(pack))) {
1928 gsn->err_unknownpdp++;
1929 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1930 "Unknown PDP context");
1931 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1932 NULL, GTPCAUSE_NON_EXIST);
1933 }
1934 }
1935 else {
1936 /* Find the context in question */
1937 if (pdp_getimsi(&pdp, imsi, nsapi)) {
1938 gsn->err_unknownpdp++;
1939 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1940 "Unknown PDP context");
1941 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1942 NULL, GTPCAUSE_NON_EXIST);
1943 }
1944 }
1945 }
1946 else {
1947 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
1948 return EOF;
1949 }
jjako2c381332003-10-21 19:09:53 +00001950
jjako08d331d2003-10-13 20:33:30 +00001951 /* Make a backup copy in case anything is wrong */
1952 memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
1953
1954 if (version == 0) {
1955 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1956 pdp->qos_req0, sizeof(pdp->qos_req0))) {
1957 gsn->missing++;
1958 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1959 "Missing mandatory information field");
1960 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1961 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1962 pdp, GTPCAUSE_MAN_IE_MISSING);
1963 }
1964 }
1965
1966 /* Recovery (optional) */
jjako52c24142002-12-16 13:33:51 +00001967 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1968 /* TODO: Handle received recovery IE */
1969 }
1970
jjako08d331d2003-10-13 20:33:30 +00001971 if (version == 0) {
1972 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1973 gsn->missing++;
1974 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1975 "Missing mandatory information field");
1976 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1977 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
1978 GTPCAUSE_MAN_IE_MISSING);
1979 }
1980
1981 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1982 gsn->missing++;
1983 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1984 "Missing mandatory information field");
1985 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1986 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
1987 GTPCAUSE_MAN_IE_MISSING);
1988 }
1989 }
1990
1991
1992 if (version == 1) {
1993 /* TEID (mandatory) */
1994 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1995 gsn->missing++;
1996 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1997 "Missing mandatory information field");
1998 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1999 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2000 GTPCAUSE_MAN_IE_MISSING);
2001 }
jjako2c381332003-10-21 19:09:53 +00002002
jjako08d331d2003-10-13 20:33:30 +00002003 /* TEIC (conditional) */
2004 /* If TEIC is not included it means that we have allready received it */
jjako2c381332003-10-21 19:09:53 +00002005 /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
2006 /* all updated contexts, or only for one of the linked contexts */
2007 gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn);
2008
jjako08d331d2003-10-13 20:33:30 +00002009 /* NSAPI (mandatory) */
2010 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
2011 gsn->missing++;
2012 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2013 "Missing mandatory information field");
2014 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2015 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2016 GTPCAUSE_MAN_IE_MISSING);
2017 }
2018 }
2019
2020 /* Trace reference (optional) */
2021 /* Trace type (optional) */
2022
2023 /* End User Address (conditional) TODO: GGSN Initiated
2024 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2025 &pdp->eua.v, sizeof(pdp->eua.v))) {
jjako52c24142002-12-16 13:33:51 +00002026 gsn->missing++;
2027 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2028 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002029 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2030 return gtp_update_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00002031 GTPCAUSE_MAN_IE_MISSING);
jjako08d331d2003-10-13 20:33:30 +00002032 } */
jjako52c24142002-12-16 13:33:51 +00002033
jjako08d331d2003-10-13 20:33:30 +00002034
2035 /* SGSN address for signalling (mandatory) */
2036 /* It is weird that this is mandatory when TEIC is conditional */
2037 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2038 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
jjako52c24142002-12-16 13:33:51 +00002039 gsn->missing++;
2040 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2041 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002042 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2043 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002044 GTPCAUSE_MAN_IE_MISSING);
2045 }
2046
jjako08d331d2003-10-13 20:33:30 +00002047 /* SGSN address for user traffic (mandatory) */
2048 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2049 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
jjako52c24142002-12-16 13:33:51 +00002050 gsn->missing++;
2051 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2052 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002053 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2054 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002055 GTPCAUSE_MAN_IE_MISSING);
2056 }
jjako08d331d2003-10-13 20:33:30 +00002057
2058 if (version == 1) {
2059 /* QoS (mandatory) */
2060 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
2061 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
2062 gsn->missing++;
2063 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2064 "Missing mandatory information field");
2065 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2066 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2067 GTPCAUSE_MAN_IE_MISSING);
2068 }
jjako52c24142002-12-16 13:33:51 +00002069
jjako08d331d2003-10-13 20:33:30 +00002070 /* TFT (conditional) */
2071 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
2072 &pdp->tft.v, sizeof(pdp->tft.v))) {
2073 }
2074
2075 /* OMC identity */
jjako52c24142002-12-16 13:33:51 +00002076 }
2077
jjako52c24142002-12-16 13:33:51 +00002078 /* Confirm to peer that things were "successful" */
jjako08d331d2003-10-13 20:33:30 +00002079 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002080 GTPCAUSE_ACC_REQ);
2081}
2082
2083
2084/* Handle Update PDP Context Response */
2085int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
2086 struct sockaddr_in *peer,
2087 void *pack, unsigned len) {
2088 struct pdp_t *pdp;
2089 union gtpie_member *ie[GTPIE_SIZE];
2090 uint8_t cause, recovery;
jjako08d331d2003-10-13 20:33:30 +00002091 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00002092 uint8_t type = 0;
2093
2094 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00002095 if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00002096
2097 /* Find the context in question */
2098 if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) {
2099 gsn->err_unknownpdp++;
2100 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2101 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00002102 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002103 return EOF;
2104 }
2105
jjako2c381332003-10-21 19:09:53 +00002106 /* Register that we have received a valid teic from GGSN */
2107 pdp->teic_confirmed = 1;
2108
jjako52c24142002-12-16 13:33:51 +00002109 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002110 if (gtpie_decaps(ie, 0, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) {
jjako52c24142002-12-16 13:33:51 +00002111 gsn->invalid++;
2112 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2113 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +00002114 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002115 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2116 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002117 return EOF;
2118 }
2119
2120 /* Extract cause value (mandatory) */
2121 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2122 gsn->missing++;
2123 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2124 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002125 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002126 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2127 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002128 return EOF;
2129 }
2130
2131 /* Extract recovery (optional) */
2132 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
2133 /* TODO: Handle received recovery IE */
2134 }
2135
2136 /* Check all conditional information elements */
2137 if (GTPCAUSE_ACC_REQ != cause) {
jjako08d331d2003-10-13 20:33:30 +00002138 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002139 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2140 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002141 return 0;
2142 }
2143 else {
2144 /* Check for missing conditionary information elements */
2145 if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) &&
2146 gtpie_exist(ie, GTPIE_REORDER, 0) &&
2147 gtpie_exist(ie, GTPIE_FL_DI, 0) &&
2148 gtpie_exist(ie, GTPIE_FL_C, 0) &&
2149 gtpie_exist(ie, GTPIE_CHARGING_ID, 0) &&
2150 gtpie_exist(ie, GTPIE_EUA, 0) &&
2151 gtpie_exist(ie, GTPIE_GSN_ADDR, 0) &&
2152 gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) {
2153 gsn->missing++;
2154 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2155 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00002156 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002157 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2158 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002159 return EOF;
2160 }
2161
2162 /* Update pdp with new values */
2163 gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2164 pdp->qos_neg0, sizeof(pdp->qos_neg0));
2165 gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder);
2166 gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru);
2167 gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc);
2168 gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid);
2169 gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2170 &pdp->eua.v, sizeof(pdp->eua.v));
2171 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2172 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v));
2173 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2174 &pdp->gsnru.v, sizeof(pdp->gsnru.v));
2175
jjako08d331d2003-10-13 20:33:30 +00002176 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako52c24142002-12-16 13:33:51 +00002177 return 0; /* Succes */
2178 }
2179}
2180
jjako52c24142002-12-16 13:33:51 +00002181
jjako08d331d2003-10-13 20:33:30 +00002182/* API: Send Delete PDP Context Request */
jjako2c381332003-10-21 19:09:53 +00002183int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
2184 int teardown) {
jjako08d331d2003-10-13 20:33:30 +00002185 union gtp_packet packet;
jjako2c381332003-10-21 19:09:53 +00002186 int length = get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
jjako08d331d2003-10-13 20:33:30 +00002187 struct in_addr addr;
jjako2c381332003-10-21 19:09:53 +00002188 struct pdp_t *linked_pdp;
2189 struct pdp_t *secondary_pdp;
2190 int n;
2191 int count = 0;
2192
jjako52c24142002-12-16 13:33:51 +00002193 if (gsna2in_addr(&addr, &pdp->gsnrc)) {
2194 gsn->err_address++;
2195 gtp_err(LOG_ERR, __FILE__, __LINE__, "GSN address conversion failed");
2196 return EOF;
2197 }
jjako2c381332003-10-21 19:09:53 +00002198
2199 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
2200 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context");
2201 return EOF;
2202 }
2203
2204 if (!teardown) {
2205 for (n=0; n< PDP_MAXNSAPI; n++)
2206 if (linked_pdp->secondary_tei[n]) count++;
2207 if (count <= 1) {
2208 gtp_err(LOG_ERR, __FILE__, __LINE__,
2209 "Must use teardown for last context");
2210 return EOF;
2211 }
2212 }
2213
jjako08d331d2003-10-13 20:33:30 +00002214 if (pdp->version == 1) {
2215 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
2216 pdp->nsapi);
jjako2c381332003-10-21 19:09:53 +00002217
2218 if (teardown)
2219 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
2220 0xff);
jjako08d331d2003-10-13 20:33:30 +00002221 }
jjako52c24142002-12-16 13:33:51 +00002222
jjako2c381332003-10-21 19:09:53 +00002223 gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
jjako52c24142002-12-16 13:33:51 +00002224
jjako2c381332003-10-21 19:09:53 +00002225 if (teardown) { /* Remove all contexts */
2226 for (n=0; n< PDP_MAXNSAPI; n++) {
2227 if (linked_pdp->secondary_tei[n]) {
2228 if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) {
2229 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown secondary PDP context");
2230 return EOF;
2231 }
2232 if (linked_pdp != secondary_pdp) {
2233 if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp);
2234 pdp_freepdp(secondary_pdp);
2235 }
2236 }
2237 }
2238 if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp);
2239 pdp_freepdp(linked_pdp);
2240 }
2241 else {
2242 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2243 if (pdp == linked_pdp) {
2244 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2245 linked_pdp->nodata = 1;
2246 }
2247 else
2248 pdp_freepdp(pdp);
2249 }
2250
2251 return 0;
2252}
jjako08d331d2003-10-13 20:33:30 +00002253
jjako52c24142002-12-16 13:33:51 +00002254/* Send Delete PDP Context Response */
2255int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002256 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002257 void *pack, unsigned len,
jjako2c381332003-10-21 19:09:53 +00002258 struct pdp_t *pdp, struct pdp_t *linked_pdp,
2259 uint8_t cause, int teardown)
jjako52c24142002-12-16 13:33:51 +00002260{
2261 union gtp_packet packet;
jjako2c381332003-10-21 19:09:53 +00002262 struct pdp_t *secondary_pdp;
jjako08d331d2003-10-13 20:33:30 +00002263 int length = get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet);
jjako2c381332003-10-21 19:09:53 +00002264 int n;
jjako52c24142002-12-16 13:33:51 +00002265
jjako08d331d2003-10-13 20:33:30 +00002266 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00002267
jjako08d331d2003-10-13 20:33:30 +00002268 gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
jjako2c381332003-10-21 19:09:53 +00002269 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002270
jjako2c381332003-10-21 19:09:53 +00002271 if (cause == GTPCAUSE_ACC_REQ) {
2272 if ((teardown) || (version == 0)) { /* Remove all contexts */
2273 for (n=0; n< PDP_MAXNSAPI; n++) {
2274 if (linked_pdp->secondary_tei[n]) {
2275 if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) {
2276 gtp_err(LOG_ERR, __FILE__, __LINE__,
2277 "Unknown secondary PDP context");
2278 return EOF;
2279 }
2280 if (linked_pdp != secondary_pdp) {
2281 if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp);
2282 pdp_freepdp(secondary_pdp);
2283 }
2284 }
2285 }
2286 if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp);
2287 pdp_freepdp(linked_pdp);
2288 }
2289 else { /* Remove only current context */
2290 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2291 if (pdp == linked_pdp) {
2292 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2293 linked_pdp->nodata = 1;
2294 }
2295 else
2296 pdp_freepdp(pdp);
2297 }
2298 } /* if (cause == GTPCAUSE_ACC_REQ) */
jjako52c24142002-12-16 13:33:51 +00002299
jjako08d331d2003-10-13 20:33:30 +00002300 return 0;
jjako52c24142002-12-16 13:33:51 +00002301}
2302
2303/* Handle Delete PDP Context Request */
2304int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002305 struct sockaddr_in *peer, int fd,
2306 void *pack, unsigned len) {
jjako2c381332003-10-21 19:09:53 +00002307 struct pdp_t *pdp = NULL;
2308 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00002309 union gtpie_member* ie[GTPIE_SIZE];
jjako08d331d2003-10-13 20:33:30 +00002310
2311 uint16_t seq = get_seq(pack);
2312 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002313
jjako08d331d2003-10-13 20:33:30 +00002314 uint8_t nsapi;
jjako2c381332003-10-21 19:09:53 +00002315 uint8_t teardown = 0;
2316 int n;
2317 int count = 0;
2318
jjako52c24142002-12-16 13:33:51 +00002319 /* Is this a dublicate ? */
jjako08d331d2003-10-13 20:33:30 +00002320 if(!gtp_dublicate(gsn, version, peer, seq)) {
2321 return 0; /* We allready send off response once */
jjako52c24142002-12-16 13:33:51 +00002322 }
2323
jjako2c381332003-10-21 19:09:53 +00002324 /* Find the linked context in question */
2325 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
jjako52c24142002-12-16 13:33:51 +00002326 gsn->err_unknownpdp++;
2327 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2328 "Unknown PDP context");
jjako2c381332003-10-21 19:09:53 +00002329 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2330 GTPCAUSE_NON_EXIST, teardown);
jjako52c24142002-12-16 13:33:51 +00002331 }
jjako2c381332003-10-21 19:09:53 +00002332
2333 /* If version 0 this is also the secondary context */
2334 if (version == 0)
2335 pdp = linked_pdp;
jjako52c24142002-12-16 13:33:51 +00002336
2337 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002338 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00002339 gsn->invalid++;
2340 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2341 "Invalid message format");
2342 if (0 == version)
2343 return EOF;
2344 else
jjako2c381332003-10-21 19:09:53 +00002345 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2346 GTPCAUSE_INVALID_MESSAGE, teardown);
jjako52c24142002-12-16 13:33:51 +00002347 }
jjako2c381332003-10-21 19:09:53 +00002348
jjako08d331d2003-10-13 20:33:30 +00002349 if (version == 1) {
2350 /* NSAPI (mandatory) */
2351 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
2352 gsn->missing++;
2353 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2354 "Missing mandatory information field");
jjako2c381332003-10-21 19:09:53 +00002355 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2356 GTPCAUSE_MAN_IE_MISSING, teardown);
jjako08d331d2003-10-13 20:33:30 +00002357 }
jjako2c381332003-10-21 19:09:53 +00002358
2359 /* Find the context in question */
2360 if (pdp_getgtp1(&pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) {
2361 gsn->err_unknownpdp++;
2362 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2363 "Unknown PDP context");
2364 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2365 GTPCAUSE_NON_EXIST, teardown);
2366 }
jjako08d331d2003-10-13 20:33:30 +00002367
2368 /* Teardown (conditional) */
jjako2c381332003-10-21 19:09:53 +00002369 gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown);
2370
2371 if (!teardown) {
2372 for (n=0; n< PDP_MAXNSAPI; n++)
2373 if (linked_pdp->secondary_tei[n]) count++;
2374 if (count <= 1) {
2375 return 0; /* 29.060 7.3.5 Ignore message */
2376 }
jjako08d331d2003-10-13 20:33:30 +00002377 }
2378 }
jjako2c381332003-10-21 19:09:53 +00002379
2380 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2381 pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown);
jjako52c24142002-12-16 13:33:51 +00002382}
2383
2384
2385/* Handle Delete PDP Context Response */
2386int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
2387 struct sockaddr_in *peer,
2388 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00002389 union gtpie_member *ie[GTPIE_SIZE];
2390 uint8_t cause;
jjako08d331d2003-10-13 20:33:30 +00002391 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00002392 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +00002393 int hlen = get_hlen(pack);
2394
jjako52c24142002-12-16 13:33:51 +00002395 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00002396 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00002397
jjako52c24142002-12-16 13:33:51 +00002398 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002399 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00002400 gsn->invalid++;
2401 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2402 "Invalid message format");
jjako2c381332003-10-21 19:09:53 +00002403 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002404 return EOF;
2405 }
2406
jjako08d331d2003-10-13 20:33:30 +00002407 /* Extract cause value (mandatory) */
jjako52c24142002-12-16 13:33:51 +00002408 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2409 gsn->missing++;
2410 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2411 "Missing mandatory information field");
jjako2c381332003-10-21 19:09:53 +00002412 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002413 return EOF;
2414 }
2415
jjako2c381332003-10-21 19:09:53 +00002416 /* Check the cause value (again) */
2417 if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
jjako52c24142002-12-16 13:33:51 +00002418 gsn->err_cause++;
2419 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2420 "Unexpected cause value received: %d", cause);
jjako2c381332003-10-21 19:09:53 +00002421 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
2422 return EOF;
jjako52c24142002-12-16 13:33:51 +00002423 }
jjako2c381332003-10-21 19:09:53 +00002424
jjako08d331d2003-10-13 20:33:30 +00002425 /* Callback function to notify application */
jjako2c381332003-10-21 19:09:53 +00002426 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002427
2428 return 0;
2429}
2430
2431/* Send Error Indication (response to a GPDU message */
2432int gtp_error_ind_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002433 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002434 void *pack, unsigned len)
2435{
2436 union gtp_packet packet;
jjako08d331d2003-10-13 20:33:30 +00002437 int length = get_default_gtp(version, GTP_ERROR, &packet);
jjako52c24142002-12-16 13:33:51 +00002438
jjako08d331d2003-10-13 20:33:30 +00002439 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
2440 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002441}
2442
2443/* Handle Error Indication */
2444int gtp_error_ind_conf(struct gsn_t *gsn, int version,
2445 struct sockaddr_in *peer,
2446 void *pack, unsigned len) {
2447 struct pdp_t *pdp;
2448
2449 /* Find the context in question */
2450 if (pdp_tidget(&pdp, ((union gtp_packet*)pack)->gtp0.h.tid)) {
2451 gsn->err_unknownpdp++;
2452 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2453 "Unknown PDP context");
2454 return EOF;
2455 }
2456
2457 gsn->err_unknownpdp++; /* TODO: Change counter */
2458 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2459 "Received Error Indication");
2460
2461 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2462 pdp_freepdp(pdp);
2463 return 0;
2464}
2465
2466int gtp_gpdu_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002467 struct sockaddr_in *peer, int fd,
2468 void *pack, unsigned len) {
2469
2470 int hlen = GTP1_HEADER_SIZE_SHORT;
jjako52c24142002-12-16 13:33:51 +00002471
2472 /* Need to include code to verify packet src and dest addresses */
2473 struct pdp_t *pdp;
jjako1db1c812003-07-06 20:53:57 +00002474
jjako08d331d2003-10-13 20:33:30 +00002475 if (version == 0) {
2476 if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) {
2477 gsn->err_unknownpdp++;
2478 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2479 "Unknown PDP context");
2480 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2481 }
2482 hlen = GTP0_HEADER_SIZE;
2483 }
2484 else if (version == 1) {
2485 if (pdp_getgtp1(&pdp, ntoh32(((union gtp_packet*)pack)->gtp1l.h.tei))) {
2486 gsn->err_unknownpdp++;
2487 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2488 "Unknown PDP context");
2489 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2490 }
2491
2492 /* Is this a long or a short header ? */
2493 if (((union gtp_packet*)pack)->gtp1l.h.flags & 0x07)
2494 hlen = GTP1_HEADER_SIZE_LONG;
2495 else
2496 hlen = GTP1_HEADER_SIZE_SHORT;
2497 }
2498 else {
2499 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2500 "Unknown version");
2501 }
2502
jjako1db1c812003-07-06 20:53:57 +00002503 /* If the GPDU was not from the peer GSN tell him to delete context */
2504 if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
2505 gsn->err_unknownpdp++;
2506 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2507 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00002508 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
jjako1db1c812003-07-06 20:53:57 +00002509 }
jjako08d331d2003-10-13 20:33:30 +00002510
jjako52c24142002-12-16 13:33:51 +00002511 /* Callback function */
jjako08d331d2003-10-13 20:33:30 +00002512 if (gsn->cb_data_ind !=0)
2513 return gsn->cb_data_ind(pdp, pack+hlen, len-hlen);
jjako52c24142002-12-16 13:33:51 +00002514
2515 return 0;
2516}
2517
2518
jjako08d331d2003-10-13 20:33:30 +00002519
jjako52c24142002-12-16 13:33:51 +00002520/* Receives GTP packet and sends off for further processing
2521 * Function will check the validity of the header. If the header
2522 * is not valid the packet is either dropped or a version not
2523 * supported is returned to the peer.
2524 * TODO: Need to decide on return values! */
jjako08d331d2003-10-13 20:33:30 +00002525int gtp_decaps0(struct gsn_t *gsn)
jjako52c24142002-12-16 13:33:51 +00002526{
jjako2c381332003-10-21 19:09:53 +00002527 unsigned char buffer[PACKET_MAX];
jjako52c24142002-12-16 13:33:51 +00002528 struct sockaddr_in peer;
2529 int peerlen;
jjako08d331d2003-10-13 20:33:30 +00002530 int status;
jjako52c24142002-12-16 13:33:51 +00002531 struct gtp0_header *pheader;
2532 int version = 0; /* GTP version should be determined from header!*/
jjako08d331d2003-10-13 20:33:30 +00002533 int fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00002534
jjakoa7cd2492003-04-11 09:40:12 +00002535 /* TODO: Need strategy of userspace buffering and blocking */
2536 /* Currently read is non-blocking and send is blocking. */
2537 /* This means that the program have to wait for busy send calls...*/
jjako52c24142002-12-16 13:33:51 +00002538
jjakoa7cd2492003-04-11 09:40:12 +00002539 while (1) { /* Loop until no more to read */
jjako08d331d2003-10-13 20:33:30 +00002540 if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) {
jjakoa7cd2492003-04-11 09:40:12 +00002541 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2542 return -1;
2543 }
2544 peerlen = sizeof(peer);
2545 if ((status =
jjako08d331d2003-10-13 20:33:30 +00002546 recvfrom(gsn->fd0, buffer, sizeof(buffer), 0,
jjakoa7cd2492003-04-11 09:40:12 +00002547 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
jjako08d331d2003-10-13 20:33:30 +00002548 if (errno == EAGAIN) return 0;
jjakoa7cd2492003-04-11 09:40:12 +00002549 gsn->err_readfrom++;
jjako08d331d2003-10-13 20:33:30 +00002550 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 +00002551 return -1;
2552 }
jjako52c24142002-12-16 13:33:51 +00002553
jjakoa7cd2492003-04-11 09:40:12 +00002554 /* Need at least 1 byte in order to check version */
2555 if (status < (1)) {
2556 gsn->empty++;
2557 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2558 "Discarding packet - too small");
2559 continue;
2560 }
2561
jjako08d331d2003-10-13 20:33:30 +00002562 pheader = (struct gtp0_header *) (buffer);
jjakoa7cd2492003-04-11 09:40:12 +00002563
jjako08d331d2003-10-13 20:33:30 +00002564 /* Version should be gtp0 (or earlier) */
2565 /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
2566 /* GTP 0 messages. If other version message is received we reply that we */
2567 /* only support version 0, implying that this is the only version */
2568 /* supported on this port */
jjakoa7cd2492003-04-11 09:40:12 +00002569 if (((pheader->flags & 0xe0) > 0x00)) {
2570 gsn->unsup++;
2571 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2572 "Unsupported GTP version");
jjako08d331d2003-10-13 20:33:30 +00002573 gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */
jjakoa7cd2492003-04-11 09:40:12 +00002574 continue;
2575 }
2576
2577 /* Check length of gtp0 packet */
jjako08d331d2003-10-13 20:33:30 +00002578 if (status < GTP0_HEADER_SIZE) {
jjakoa7cd2492003-04-11 09:40:12 +00002579 gsn->tooshort++;
2580 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2581 "GTP0 packet too short");
2582 continue; /* Silently discard 29.60: 11.1.2 */
2583 }
jjako1db1c812003-07-06 20:53:57 +00002584
jjako08d331d2003-10-13 20:33:30 +00002585 /* Check packet length field versus length of packet */
2586 if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
2587 gsn->tooshort++;
2588 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2589 "GTP packet length field does not match actual length");
2590 continue; /* Silently discard */
2591 }
2592
2593 if ((gsn->mode == GTP_MODE_GGSN) &&
2594 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2595 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2596 (pheader->type == GTP_DELETE_PDP_RSP))) {
2597 gsn->unexpect++;
2598 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2599 "Unexpected GTP Signalling Message");
2600 continue; /* Silently discard 29.60: 11.1.4 */
2601 }
2602
2603 if ((gsn->mode == GTP_MODE_SGSN) &&
2604 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2605 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2606 (pheader->type == GTP_DELETE_PDP_REQ))) {
2607 gsn->unexpect++;
2608 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2609 "Unexpected GTP Signalling Message");
2610 continue; /* Silently discard 29.60: 11.1.4 */
2611 }
2612
2613 switch (pheader->type) {
2614 case GTP_ECHO_REQ:
2615 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2616 break;
2617 case GTP_ECHO_RSP:
2618 gtp_echo_conf(gsn, version, &peer, buffer, status);
2619 break;
2620 case GTP_NOT_SUPPORTED:
2621 gtp_unsup_ind(gsn, &peer, buffer, status);
2622 break;
2623 case GTP_CREATE_PDP_REQ:
2624 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status);
2625 break;
2626 case GTP_CREATE_PDP_RSP:
2627 gtp_create_pdp_conf(gsn, version, &peer, buffer, status);
2628 break;
2629 case GTP_UPDATE_PDP_REQ:
2630 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status);
2631 break;
2632 case GTP_UPDATE_PDP_RSP:
2633 gtp_update_pdp_conf(gsn, version, &peer, buffer, status);
2634 break;
2635 case GTP_DELETE_PDP_REQ:
2636 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status);
2637 break;
2638 case GTP_DELETE_PDP_RSP:
2639 gtp_delete_pdp_conf(gsn, version, &peer, buffer, status);
2640 break;
2641 case GTP_ERROR:
2642 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2643 break;
2644 case GTP_GPDU:
2645 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2646 break;
2647 default:
2648 gsn->unknown++;
2649 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2650 "Unknown GTP message type received");
2651 break;
2652 }
2653 }
2654}
2655
2656
2657int gtp_decaps1c(struct gsn_t *gsn)
2658{
jjako2c381332003-10-21 19:09:53 +00002659 unsigned char buffer[PACKET_MAX];
jjako08d331d2003-10-13 20:33:30 +00002660 struct sockaddr_in peer;
2661 int peerlen;
2662 int status;
2663 struct gtp1_header_short *pheader;
jjako2c381332003-10-21 19:09:53 +00002664 int version = 1; /* TODO GTP version should be determined from header!*/
jjako08d331d2003-10-13 20:33:30 +00002665 int fd = gsn->fd1c;
2666
2667 /* TODO: Need strategy of userspace buffering and blocking */
2668 /* Currently read is non-blocking and send is blocking. */
2669 /* This means that the program have to wait for busy send calls...*/
2670
2671 while (1) { /* Loop until no more to read */
jjako2c381332003-10-21 19:09:53 +00002672 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
jjako08d331d2003-10-13 20:33:30 +00002673 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2674 return -1;
2675 }
2676 peerlen = sizeof(peer);
2677 if ((status =
jjako2c381332003-10-21 19:09:53 +00002678 recvfrom(fd, buffer, sizeof(buffer), 0,
jjako08d331d2003-10-13 20:33:30 +00002679 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
2680 if (errno == EAGAIN) return 0;
2681 gsn->err_readfrom++;
jjako2c381332003-10-21 19:09:53 +00002682 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 +00002683 return -1;
2684 }
2685
2686 /* Need at least 1 byte in order to check version */
2687 if (status < (1)) {
2688 gsn->empty++;
2689 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2690 "Discarding packet - too small");
2691 continue;
2692 }
2693
2694 pheader = (struct gtp1_header_short *) (buffer);
2695
2696 /* Version must be no larger than GTP 1 */
2697 if (((pheader->flags & 0xe0) > 0x20)) {
2698 gsn->unsup++;
2699 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2700 "Unsupported GTP version");
jjako2c381332003-10-21 19:09:53 +00002701 gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
2702 /*29.60: 11.1.1*/
jjako08d331d2003-10-13 20:33:30 +00002703 continue;
2704 }
2705
2706 /* Version must be at least GTP 1 */
2707 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2708 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2709 /* the message */
2710 if (((pheader->flags & 0xe0) < 0x20)) {
2711 gsn->unsup++;
2712 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2713 "Unsupported GTP version");
2714 continue;
2715 }
2716
2717 /* Check packet flag field */
2718 if (((pheader->flags & 0xf7) != 0x32)) {
2719 gsn->unsup++;
2720 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2721 "Unsupported packet flag");
2722 continue;
2723 }
2724
2725 /* Check length of packet */
2726 if (status < GTP1_HEADER_SIZE_LONG) {
2727 gsn->tooshort++;
2728 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2729 "GTP packet too short");
2730 continue; /* Silently discard 29.60: 11.1.2 */
2731 }
2732
2733 /* Check packet length field versus length of packet */
2734 if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
2735 gsn->tooshort++;
2736 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2737 "GTP packet length field does not match actual length");
2738 continue; /* Silently discard */
2739 }
2740
jjako2c381332003-10-21 19:09:53 +00002741 /* Check for extension headers */
2742 /* TODO: We really should cycle through the headers and determine */
2743 /* if any have the comprehension required flag set */
2744 if (((pheader->flags & 0x04) != 0x00)) {
2745 gsn->unsup++;
2746 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2747 "Unsupported extension header");
2748 gtp_extheader_req(gsn, version, &peer, fd, buffer, status);
2749
2750 continue;
2751 }
2752
jjako1db1c812003-07-06 20:53:57 +00002753 if ((gsn->mode == GTP_MODE_GGSN) &&
2754 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2755 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2756 (pheader->type == GTP_DELETE_PDP_RSP))) {
2757 gsn->unexpect++;
2758 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2759 "Unexpected GTP Signalling Message");
2760 continue; /* Silently discard 29.60: 11.1.4 */
2761 }
2762
2763 if ((gsn->mode == GTP_MODE_SGSN) &&
2764 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2765 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2766 (pheader->type == GTP_DELETE_PDP_REQ))) {
2767 gsn->unexpect++;
2768 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2769 "Unexpected GTP Signalling Message");
2770 continue; /* Silently discard 29.60: 11.1.4 */
2771 }
2772
jjakoa7cd2492003-04-11 09:40:12 +00002773 switch (pheader->type) {
2774 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +00002775 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002776 break;
2777 case GTP_ECHO_RSP:
jjako08d331d2003-10-13 20:33:30 +00002778 gtp_echo_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002779 break;
2780 case GTP_NOT_SUPPORTED:
jjako08d331d2003-10-13 20:33:30 +00002781 gtp_unsup_ind(gsn, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002782 break;
jjako2c381332003-10-21 19:09:53 +00002783 case GTP_SUPP_EXT_HEADER:
2784 gtp_extheader_ind(gsn, &peer, buffer, status);
2785 break;
jjakoa7cd2492003-04-11 09:40:12 +00002786 case GTP_CREATE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002787 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002788 break;
2789 case GTP_CREATE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002790 gtp_create_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002791 break;
2792 case GTP_UPDATE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002793 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002794 break;
2795 case GTP_UPDATE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002796 gtp_update_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002797 break;
2798 case GTP_DELETE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002799 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002800 break;
2801 case GTP_DELETE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002802 gtp_delete_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002803 break;
2804 case GTP_ERROR:
jjako08d331d2003-10-13 20:33:30 +00002805 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002806 break;
2807 default:
jjako52c24142002-12-16 13:33:51 +00002808 gsn->unknown++;
2809 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2810 "Unknown GTP message type received");
jjakoa7cd2492003-04-11 09:40:12 +00002811 break;
jjako52c24142002-12-16 13:33:51 +00002812 }
2813 }
2814}
2815
jjako08d331d2003-10-13 20:33:30 +00002816int gtp_decaps1u(struct gsn_t *gsn)
2817{
jjako2c381332003-10-21 19:09:53 +00002818 unsigned char buffer[PACKET_MAX];
jjako08d331d2003-10-13 20:33:30 +00002819 struct sockaddr_in peer;
2820 int peerlen;
2821 int status;
2822 struct gtp1_header_short *pheader;
2823 int version = 1; /* GTP version should be determined from header!*/
2824 int fd = gsn->fd1u;
2825
2826 /* TODO: Need strategy of userspace buffering and blocking */
2827 /* Currently read is non-blocking and send is blocking. */
2828 /* This means that the program have to wait for busy send calls...*/
2829
2830 while (1) { /* Loop until no more to read */
2831 if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) {
2832 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2833 return -1;
2834 }
2835 peerlen = sizeof(peer);
2836 if ((status =
2837 recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0,
2838 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
2839 if (errno == EAGAIN) return 0;
2840 gsn->err_readfrom++;
2841 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");
2842 return -1;
2843 }
2844
2845 /* Need at least 1 byte in order to check version */
2846 if (status < (1)) {
2847 gsn->empty++;
2848 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2849 "Discarding packet - too small");
2850 continue;
2851 }
2852
2853 pheader = (struct gtp1_header_short *) (buffer);
2854
2855 /* Version must be no larger than GTP 1 */
2856 if (((pheader->flags & 0xe0) > 0x20)) {
2857 gsn->unsup++;
2858 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2859 "Unsupported GTP version");
2860 gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status);/*29.60: 11.1.1*/
2861 continue;
2862 }
2863
2864 /* Version must be at least GTP 1 */
2865 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2866 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2867 /* the message */
2868 if (((pheader->flags & 0xe0) < 0x20)) {
2869 gsn->unsup++;
2870 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2871 "Unsupported GTP version");
2872 continue;
2873 }
2874
2875 /* Check packet flag field (allow both with and without sequence number)*/
2876 if (((pheader->flags & 0xf5) != 0x30)) {
2877 gsn->unsup++;
2878 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2879 "Unsupported packet flag");
2880 continue;
2881 }
2882
2883 /* Check length of packet */
2884 if (status < GTP1_HEADER_SIZE_SHORT) {
2885 gsn->tooshort++;
2886 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2887 "GTP packet too short");
2888 continue; /* Silently discard 29.60: 11.1.2 */
2889 }
2890
2891 /* Check packet length field versus length of packet */
2892 if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
2893 gsn->tooshort++;
2894 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2895 "GTP packet length field does not match actual length");
2896 continue; /* Silently discard */
2897 }
jjako2c381332003-10-21 19:09:53 +00002898
2899 /* Check for extension headers */
2900 /* TODO: We really should cycle through the headers and determine */
2901 /* if any have the comprehension required flag set */
2902 if (((pheader->flags & 0x04) != 0x00)) {
2903 gsn->unsup++;
2904 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2905 "Unsupported extension header");
2906 gtp_extheader_req(gsn, version, &peer, fd, buffer, status);
2907
2908 continue;
2909 }
jjako08d331d2003-10-13 20:33:30 +00002910
2911 switch (pheader->type) {
2912 case GTP_ECHO_REQ:
2913 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2914 break;
2915 case GTP_ECHO_RSP:
2916 gtp_echo_conf(gsn, version, &peer, buffer, status);
2917 break;
jjako2c381332003-10-21 19:09:53 +00002918 case GTP_SUPP_EXT_HEADER:
2919 gtp_extheader_ind(gsn, &peer, buffer, status);
2920 break;
jjako08d331d2003-10-13 20:33:30 +00002921 case GTP_ERROR:
2922 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2923 break;
2924 /* Supported header extensions */
2925 case GTP_GPDU:
2926 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2927 break;
2928 default:
2929 gsn->unknown++;
2930 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2931 "Unknown GTP message type received");
2932 break;
2933 }
2934 }
2935}
2936
2937int gtp_data_req(struct gsn_t *gsn, struct pdp_t* pdp,
jjako52c24142002-12-16 13:33:51 +00002938 void *pack, unsigned len)
2939{
2940 union gtp_packet packet;
2941 struct sockaddr_in addr;
jjako08d331d2003-10-13 20:33:30 +00002942 int fd;
2943 int length;
jjako52c24142002-12-16 13:33:51 +00002944
2945 memset(&addr, 0, sizeof(addr));
2946 addr.sin_family = AF_INET;
jjako1f158642004-02-05 20:39:57 +00002947#if defined(__FreeBSD__)
jjako06e9f122004-01-19 18:37:58 +00002948 addr.sin_len = sizeof(addr);
2949#endif
2950
jjako52c24142002-12-16 13:33:51 +00002951 memcpy(&addr.sin_addr, pdp->gsnru.v,pdp->gsnru.l); /* TODO range check */
jjako52c24142002-12-16 13:33:51 +00002952
jjako08d331d2003-10-13 20:33:30 +00002953 if (pdp->version == 0) {
2954
2955 length = GTP0_HEADER_SIZE+len;
2956 addr.sin_port = htons(GTP0_PORT);
2957 fd = gsn->fd0;
2958
2959 get_default_gtp(0, GTP_GPDU, &packet);
2960 packet.gtp0.h.length = hton16(len);
2961 packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
2962 packet.gtp0.h.flow = hton16(pdp->flru);
jjako1ea66342004-01-28 09:27:34 +00002963 packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffffull) + ((uint64_t)pdp->nsapi << 60);
jjako52c24142002-12-16 13:33:51 +00002964
jjako08d331d2003-10-13 20:33:30 +00002965 if (len > sizeof (union gtp_packet) - sizeof(struct gtp0_header)) {
2966 gsn->err_memcpy++;
2967 gtp_err(LOG_ERR, __FILE__, __LINE__,
jjako1f158642004-02-05 20:39:57 +00002968 "Memcpy failed: %d > %d", len,
2969 sizeof (union gtp_packet) - sizeof(struct gtp0_header));
jjako08d331d2003-10-13 20:33:30 +00002970 return EOF;
jjako52c24142002-12-16 13:33:51 +00002971 }
jjako08d331d2003-10-13 20:33:30 +00002972 memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */
2973 }
2974 else if (pdp->version == 1) {
2975
2976 length = GTP1_HEADER_SIZE_LONG+len;
2977 addr.sin_port = htons(GTP1U_PORT);
2978 fd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00002979
jjako08d331d2003-10-13 20:33:30 +00002980 get_default_gtp(1, GTP_GPDU, &packet);
2981 packet.gtp1l.h.length = hton16(len-GTP1_HEADER_SIZE_SHORT+
2982 GTP1_HEADER_SIZE_LONG);
2983 packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
jjako2c381332003-10-21 19:09:53 +00002984 packet.gtp1l.h.tei = hton32(pdp->teid_gn);
jjako08d331d2003-10-13 20:33:30 +00002985
2986 if (len > sizeof (union gtp_packet) - sizeof(struct gtp1_header_long)) {
2987 gsn->err_memcpy++;
2988 gtp_err(LOG_ERR, __FILE__, __LINE__,
jjako1f158642004-02-05 20:39:57 +00002989 "Memcpy failed: %d > %d", len,
2990 sizeof (union gtp_packet) - sizeof(struct gtp0_header));
jjako08d331d2003-10-13 20:33:30 +00002991 return EOF;
2992 }
2993 memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */
2994 }
2995 else {
2996 gtp_err(LOG_ERR, __FILE__, __LINE__,
2997 "Unknown version");
2998 return EOF;
2999 }
3000
3001 if (fcntl(fd, F_SETFL, 0)) {
jjakoa7cd2492003-04-11 09:40:12 +00003002 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
3003 return -1;
3004 }
3005
jjako08d331d2003-10-13 20:33:30 +00003006 if (sendto(fd, &packet, length, 0,
jjako52c24142002-12-16 13:33:51 +00003007 (struct sockaddr *) &addr, sizeof(addr)) < 0) {
3008 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +00003009 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 +00003010 return EOF;
3011 }
3012 return 0;
3013}
3014
3015
3016/* ***********************************************************
3017 * Conversion functions
3018 *************************************************************/
3019
3020int char2ul_t(char* src, struct ul_t dst) {
3021 dst.l = strlen(src)+1;
3022 dst.v = malloc(dst.l);
3023 dst.v[0] = dst.l - 1;
3024 memcpy(&dst.v[1], src, dst.v[0]);
3025 return 0;
3026}
3027
3028/* ***********************************************************
3029 * IP address conversion functions
3030 * There exist several types of address representations:
3031 * - eua: End User Address. (29.060, 7.7.27, message type 128)
3032 * Used for signalling address to mobile station. Supports IPv4
3033 * IPv6 x.25 etc. etc.
3034 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
3035 * of GSN. If length is 4 it is IPv4. If length is 16 it is IPv6.
3036 * - in_addr: IPv4 address struct.
3037 * - sockaddr_in: Socket API representation of IP address and
3038 * port number.
3039 *************************************************************/
3040
3041int ipv42eua(struct ul66_t *eua, struct in_addr *src) {
3042 eua->v[0] = 0xf1; /* IETF */
3043 eua->v[1] = 0x21; /* IPv4 */
3044 if (src) {
3045 eua->l = 6;
3046 memcpy(&eua->v[2], src, 4);
3047 }
3048 else
3049 {
3050 eua->l = 2;
3051 }
3052 return 0;
3053}
3054
3055int eua2ipv4(struct in_addr *dst, struct ul66_t *eua) {
3056 if ((eua->l != 6) ||
3057 (eua->v[0] != 0xf1) ||
3058 (eua->v[1] = 0x21))
3059 return -1; /* Not IPv4 address*/
3060 memcpy(dst, &eua->v[2], 4);
3061 return 0;
3062}
3063
3064int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna) {
3065 memset(dst, 0, sizeof(struct in_addr));
3066 if (gsna->l != 4) return EOF; /* Return if not IPv4 */
3067 memcpy(dst, gsna->v, gsna->l);
3068 return 0;
3069}
3070
3071int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src) {
3072 memset(gsna, 0, sizeof(struct ul16_t));
3073 gsna->l = 4;
3074 memcpy(gsna->v, src, gsna->l);
3075 return 0;
3076}
3077