blob: 899a16a9c43afb2e934ccf8d69a07a820a71389c [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;
jjako52c24142002-12-16 13:33:51 +0000410
jjako08d331d2003-10-13 20:33:30 +0000411 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
412 addr.sin_port = htons(GTP0_PORT);
413 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
414 packet->gtp0.h.seq = hton16(gsn->seq_next);
415 if (pdp)
416 packet->gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffff) +
417 ((uint64_t)pdp->nsapi << 60);
418 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
419 (packet->gtp0.h.type == GTP_ERROR)))
420 packet->gtp0.h.flow=hton16(pdp->flru);
421 else if (pdp)
422 packet->gtp0.h.flow=hton16(pdp->flrc);
423 fd = gsn->fd0;
424 }
425 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
426 addr.sin_port = htons(GTP1C_PORT);
427 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
428 packet->gtp1l.h.seq = hton16(gsn->seq_next);
429 if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) ||
430 (packet->gtp1l.h.type == GTP_ERROR)))
431 packet->gtp1l.h.tei=hton32(pdp->teid_gn);
432 else if (pdp)
433 packet->gtp1l.h.tei=hton32(pdp->teic_gn);
434 fd = gsn->fd1c;
435 } else {
436 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
437 return -1;
438 }
jjako52c24142002-12-16 13:33:51 +0000439
jjako08d331d2003-10-13 20:33:30 +0000440 if (sendto(fd, packet, len, 0,
jjako52c24142002-12-16 13:33:51 +0000441 (struct sockaddr *) &addr, sizeof(addr)) < 0) {
442 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000443 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 +0000444 return -1;
445 }
446
447 /* Use new queue structure */
448 if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) {
449 gsn->err_queuefull++;
450 gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full");
451 }
452 else {
453 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
454 qmsg->l = len;
455 qmsg->timeout = time(NULL) + 3; /* When to timeout */
456 qmsg->retrans = 0; /* No retransmissions so far */
jjako08d331d2003-10-13 20:33:30 +0000457 qmsg->cbp = cbp;
jjako52c24142002-12-16 13:33:51 +0000458 qmsg->type = ntoh8(packet->gtp0.h.type);
jjako08d331d2003-10-13 20:33:30 +0000459 qmsg->fd = fd;
jjako52c24142002-12-16 13:33:51 +0000460 }
461 gsn->seq_next++; /* Count up this time */
462 return 0;
463}
464
465/* gtp_conf
466 * Remove signalling packet from retransmission queue.
467 * return 0 on success, EOF if packet was not found */
468
469int gtp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
jjako08d331d2003-10-13 20:33:30 +0000470 union gtp_packet *packet, int len, uint8_t *type, void **cbp) {
jjako52c24142002-12-16 13:33:51 +0000471
jjako08d331d2003-10-13 20:33:30 +0000472 uint16_t seq;
473
474 if ((packet->gtp0.h.flags & 0xe0) == 0x00)
475 seq = ntoh16(packet->gtp0.h.seq);
476 else if ((packet->gtp1l.h.flags & 0xe2) == 0x22)
477 seq = ntoh16(packet->gtp1l.h.seq);
478 else {
479 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
480 "Unknown GTP packet version");
481 return EOF;
482 }
483
484 if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) {
jjako52c24142002-12-16 13:33:51 +0000485 gsn->err_seq++;
486 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
487 "Confirmation packet not found in queue");
488 return EOF;
489 }
490
491 return 0;
492}
493
494int gtp_retrans(struct gsn_t *gsn) {
495 /* Retransmit any outstanding packets */
496 /* Remove from queue if maxretrans exceeded */
497 time_t now;
498 struct qmsg_t *qmsg;
499 now = time(NULL);
500 /*printf("Retrans: New beginning %d\n", (int) now);*/
501
502 while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
503 (qmsg->timeout <= now)) {
504 /*printf("Retrans timeout found: %d\n", (int) time(NULL));*/
505 if (qmsg->retrans > 3) { /* To many retrans */
jjako08d331d2003-10-13 20:33:30 +0000506 if (gsn->cb_conf) gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
jjako52c24142002-12-16 13:33:51 +0000507 queue_freemsg(gsn->queue_req, qmsg);
508 }
509 else {
jjako08d331d2003-10-13 20:33:30 +0000510 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
jjako52c24142002-12-16 13:33:51 +0000511 (struct sockaddr *) &qmsg->peer, sizeof(struct sockaddr_in)) < 0) {
512 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000513 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 +0000514 }
515 queue_back(gsn->queue_req, qmsg);
516 qmsg->timeout = now + 3;
517 qmsg->retrans++;
518 }
519 }
520
521 /* Also clean up reply timeouts */
522 while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
523 (qmsg->timeout < now)) {
524 /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL));*/
525 queue_freemsg(gsn->queue_resp, qmsg);
526 }
527
528 return 0;
529}
530
531int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) {
532 time_t now, later;
533 struct qmsg_t *qmsg;
534
535 if (queue_getfirst(gsn->queue_req, &qmsg)) {
536 timeout->tv_sec = 10;
537 timeout->tv_usec = 0;
538 }
539 else {
540 now = time(NULL);
541 later = qmsg->timeout;
542 timeout->tv_sec = later - now;
543 timeout->tv_usec = 0;
544 if (timeout->tv_sec < 0) timeout->tv_sec = 0; /* No negative allowed */
545 if (timeout->tv_sec > 10) timeout->tv_sec = 10; /* Max sleep for 10 sec*/
546 }
547 return 0;
548}
549
jjako08d331d2003-10-13 20:33:30 +0000550int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp,
551 union gtp_packet *packet, int len,
552 struct sockaddr_in *peer, int fd,
553 uint16_t seq, uint64_t tid) {
jjako52c24142002-12-16 13:33:51 +0000554 struct qmsg_t *qmsg;
jjako52c24142002-12-16 13:33:51 +0000555
jjako08d331d2003-10-13 20:33:30 +0000556 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
557 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
558 packet->gtp0.h.seq = hton16(seq);
559 packet->gtp0.h.tid = tid;
560 if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
561 (packet->gtp0.h.type == GTP_ERROR)))
562 packet->gtp0.h.flow=hton16(pdp->flru);
563 else if (pdp)
564 packet->gtp0.h.flow=hton16(pdp->flrc);
565 }
566 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
567 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
568 packet->gtp1l.h.seq = hton16(seq);
569 if (pdp && (fd == gsn->fd1u))
570 packet->gtp1l.h.tei=hton32(pdp->teid_gn);
571 else if (pdp)
572 packet->gtp1l.h.tei=hton32(pdp->teic_gn);
573 }
574 else {
575 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
jjakoa7cd2492003-04-11 09:40:12 +0000576 return -1;
577 }
jjako52c24142002-12-16 13:33:51 +0000578
jjako08d331d2003-10-13 20:33:30 +0000579 if (fcntl(fd, F_SETFL, 0)) {
580 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
581 return -1;
582 }
583
584 if (sendto(fd, packet, len, 0,
jjako52c24142002-12-16 13:33:51 +0000585 (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
586 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +0000587 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 +0000588 return -1;
589 }
590
591 /* Use new queue structure */
592 if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) {
593 gsn->err_queuefull++;
594 gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full");
595 }
596 else {
597 memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
598 qmsg->l = len;
599 qmsg->timeout = time(NULL) + 60; /* When to timeout */
600 qmsg->retrans = 0; /* No retransmissions so far */
jjako08d331d2003-10-13 20:33:30 +0000601 qmsg->cbp = NULL;
jjako52c24142002-12-16 13:33:51 +0000602 qmsg->type = 0;
jjako08d331d2003-10-13 20:33:30 +0000603 qmsg->fd = fd;
jjako52c24142002-12-16 13:33:51 +0000604 }
605 return 0;
606}
607
jjako2c381332003-10-21 19:09:53 +0000608int gtp_notification(struct gsn_t *gsn, int version,
609 union gtp_packet *packet, int len,
610 struct sockaddr_in *peer, int fd,
611 uint16_t seq) {
612
613 struct sockaddr_in addr;
614
615 memcpy(&addr, peer, sizeof(addr));
616
617 /* In GTP0 notifications are treated as replies. In GTP1 they
618 are requests for which there is no reply */
619
620 if (fd == gsn->fd1c)
621 addr.sin_port = htons(GTP1C_PORT);
622 else if (fd == gsn->fd1u)
623 addr.sin_port = htons(GTP1C_PORT);
624
625 if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
626 packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
627 packet->gtp0.h.seq = hton16(seq);
628 }
629 else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
630 packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
631 packet->gtp1l.h.seq = hton16(seq);
632 }
633 else {
634 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
635 return -1;
636 }
637
638 if (fcntl(fd, F_SETFL, 0)) {
639 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
640 return -1;
641 }
642
643 if (sendto(fd, packet, len, 0,
644 (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) {
645 gsn->err_sendto++;
646 gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno));
647 return -1;
648 }
649 return 0;
650}
651
jjako52c24142002-12-16 13:33:51 +0000652int gtp_dublicate(struct gsn_t *gsn, int version,
653 struct sockaddr_in *peer, uint16_t seq) {
654 struct qmsg_t *qmsg;
655
656 if(queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) {
657 return EOF; /* Notfound */
658 }
jjakoa7cd2492003-04-11 09:40:12 +0000659
jjako08d331d2003-10-13 20:33:30 +0000660 if (fcntl(qmsg->fd, F_SETFL, 0)) {
661 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
662 return -1;
jjako52c24142002-12-16 13:33:51 +0000663 }
jjako08d331d2003-10-13 20:33:30 +0000664
665 if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
666 (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
667 gsn->err_sendto++;
668 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));
669 }
670 return 0;
jjako52c24142002-12-16 13:33:51 +0000671}
672
673
674
675/* Perform restoration and recovery error handling as described in 29.060 */
676static void log_restart(struct gsn_t *gsn) {
677 FILE *f;
678 int i;
679 int counter = 0;
680 char filename[NAMESIZE];
681
682 filename[NAMESIZE-1] = 0; /* No null term. guarantee by strncpy */
683 strncpy(filename, gsn->statedir, NAMESIZE-1);
684 strncat(filename, RESTART_FILE,
685 NAMESIZE-1-sizeof(RESTART_FILE));
686
687 i = umask(022);
688
689 /* We try to open file. On failure we will later try to create file */
690 if (!(f = fopen(filename, "r"))) {
jjako581c9f02003-10-22 11:28:20 +0000691
692 gtp_err(LOG_ERR, __FILE__, __LINE__, "State information file (%s) not found. Creating new file.", filename);
jjako52c24142002-12-16 13:33:51 +0000693 }
694 else {
695 umask(i);
696 fscanf(f, "%d", &counter);
697 if (fclose(f)) {
698 gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno));
699 }
700 }
701
702 gsn->restart_counter = (unsigned char) counter;
703 gsn->restart_counter++;
704
705 if (!(f = fopen(filename, "w"))) {
706 gtp_err(LOG_ERR, __FILE__, __LINE__, "fopen(path=%s, mode=%s) failed: Error = %s", filename, "w", strerror(errno));
707 return;
708 }
709
710 umask(i);
711 fprintf(f, "%d\n", gsn->restart_counter);
712 if (fclose(f)) {
713 gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno));
714 return;
715 }
716}
717
718
719
jjako1db1c812003-07-06 20:53:57 +0000720int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
721 int mode)
jjako52c24142002-12-16 13:33:51 +0000722{
723 struct sockaddr_in addr;
jjako52c24142002-12-16 13:33:51 +0000724
725 syslog(LOG_ERR, "GTP: gtp_newgsn() started");
726
727 *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
728
729 (*gsn)->statedir = statedir;
730 log_restart(*gsn);
jjakoa7cd2492003-04-11 09:40:12 +0000731
732 /* Initialise sequence number */
733 (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
jjako52c24142002-12-16 13:33:51 +0000734
735 /* Initialise request retransmit queue */
736 queue_new(&(*gsn)->queue_req);
737 queue_new(&(*gsn)->queue_resp);
738
739 /* Initialise pdp table */
740 pdp_init();
741
742 /* Initialise call back functions */
jjako08d331d2003-10-13 20:33:30 +0000743 (*gsn)->cb_create_context_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000744 (*gsn)->cb_delete_context = 0;
jjako08d331d2003-10-13 20:33:30 +0000745 (*gsn)->cb_unsup_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000746 (*gsn)->cb_conf = 0;
jjako08d331d2003-10-13 20:33:30 +0000747 (*gsn)->cb_data_ind = 0;
jjako52c24142002-12-16 13:33:51 +0000748
jjako08d331d2003-10-13 20:33:30 +0000749 /* Store function parameters */
750 (*gsn)->gsnc = *listen;
751 (*gsn)->gsnu = *listen;
752 (*gsn)->mode = mode;
753
754
755 /* Create GTP version 0 socket */
756 if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
jjako52c24142002-12-16 13:33:51 +0000757 (*gsn)->err_socket++;
758 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
759 return -1;
760 }
jjako52c24142002-12-16 13:33:51 +0000761
762 memset(&addr, 0, sizeof(addr));
jjako52c24142002-12-16 13:33:51 +0000763 addr.sin_family = AF_INET;
jjako52c24142002-12-16 13:33:51 +0000764 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
765 addr.sin_port = htons(GTP0_PORT);
766
jjako08d331d2003-10-13 20:33:30 +0000767 if (bind((*gsn)->fd0, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
jjako52c24142002-12-16 13:33:51 +0000768 (*gsn)->err_socket++;
jjako08d331d2003-10-13 20:33:30 +0000769 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));
770 return -1;
771 }
772
773 /* Create GTP version 1 control plane socket */
774 if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
775 (*gsn)->err_socket++;
776 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
777 return -1;
778 }
779
780 memset(&addr, 0, sizeof(addr));
781 addr.sin_family = AF_INET;
782 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
783 addr.sin_port = htons(GTP1C_PORT);
784
785 if (bind((*gsn)->fd1c, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
786 (*gsn)->err_socket++;
787 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));
788 return -1;
789 }
790
791 /* Create GTP version 1 user plane socket */
792 if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
793 (*gsn)->err_socket++;
794 gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
795 return -1;
796 }
797
798 memset(&addr, 0, sizeof(addr));
799 addr.sin_family = AF_INET;
800 addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
801 addr.sin_port = htons(GTP1U_PORT);
802
803 if (bind((*gsn)->fd1u, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
804 (*gsn)->err_socket++;
805 gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s", (*gsn)->fd1c, (unsigned long) &addr, sizeof(addr), strerror(errno));
jjako52c24142002-12-16 13:33:51 +0000806 return -1;
807 }
808
jjako52c24142002-12-16 13:33:51 +0000809 return 0;
810}
811
812int gtp_free(struct gsn_t *gsn) {
813
814 /* Clean up retransmit queues */
815 queue_free(gsn->queue_req);
816 queue_free(gsn->queue_resp);
jjako08d331d2003-10-13 20:33:30 +0000817
818 close(gsn->fd0);
819 close(gsn->fd1c);
820 close(gsn->fd1u);
jjako52c24142002-12-16 13:33:51 +0000821
822 free(gsn);
823 return 0;
824}
825
826/* ***********************************************************
827 * Path management messages
828 * Messages: echo and version not supported.
829 * A path is connection between two UDP/IP endpoints
830 *
831 * A path is either using GTP0 or GTP1. A path can be
832 * established by any kind of GTP message??
833
834 * Which source port to use?
835 * GTP-C request destination port is 2123/3386
836 * GTP-U request destination port is 2152/3386
837 * T-PDU destination port is 2152/3386.
838 * For the above messages the source port is locally allocated.
839 * For response messages src=rx-dst and dst=rx-src.
840 * For simplicity we should probably use 2123+2152/3386 as
841 * src port even for the cases where src can be locally
842 * allocated. This also means that we have to listen only to
843 * the same ports.
844 * For response messages we need to be able to respond to
845 * the relevant src port even if it is locally allocated by
846 * the peer.
847 *
848 * The need for path management!
849 * We might need to keep a list of active paths. This might
850 * be in the form of remote IP address + UDP port numbers.
851 * (We will consider a path astablished if we have a context
852 * with the node in question)
853 *************************************************************/
854
855/* Send off an echo request */
jjako08d331d2003-10-13 20:33:30 +0000856int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
857 struct in_addr *inetaddr)
jjako52c24142002-12-16 13:33:51 +0000858{
859 union gtp_packet packet;
jjako08d331d2003-10-13 20:33:30 +0000860 int length = get_default_gtp(version, GTP_ECHO_REQ, &packet);
861 return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp);
jjako52c24142002-12-16 13:33:51 +0000862}
863
jjako08d331d2003-10-13 20:33:30 +0000864/* Send off an echo reply */
865int gtp_echo_resp(struct gsn_t *gsn, int version,
866 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +0000867 void *pack, unsigned len)
868{
869 union gtp_packet packet;
jjako08d331d2003-10-13 20:33:30 +0000870 int length = get_default_gtp(version, GTP_ECHO_RSP, &packet);
871 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, gsn->restart_counter);
872 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
873 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +0000874}
875
876
877/* Handle a received echo request */
jjako08d331d2003-10-13 20:33:30 +0000878int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
879 int fd, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000880
jjako08d331d2003-10-13 20:33:30 +0000881 /* Check if it was a dublicate request */
882 if(!gtp_dublicate(gsn, 0, peer, get_seq(pack))) return 0;
jjako52c24142002-12-16 13:33:51 +0000883
jjako08d331d2003-10-13 20:33:30 +0000884 /* Send off reply to request */
885 return gtp_echo_resp(gsn, version, peer, fd, pack, len);
jjako52c24142002-12-16 13:33:51 +0000886}
887
888/* Handle a received echo reply */
jjako08d331d2003-10-13 20:33:30 +0000889int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
jjako52c24142002-12-16 13:33:51 +0000890 void *pack, unsigned len) {
891 union gtpie_member *ie[GTPIE_SIZE];
892 unsigned char recovery;
jjako08d331d2003-10-13 20:33:30 +0000893 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +0000894 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +0000895 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +0000896
897 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +0000898 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +0000899
jjako08d331d2003-10-13 20:33:30 +0000900 /* Extract information elements into a pointer array */
901 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +0000902 gsn->invalid++;
903 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
904 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +0000905 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000906 return EOF;
907 }
908
909 if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
910 gsn->missing++;
911 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
912 "Missing mandatory field");
jjako08d331d2003-10-13 20:33:30 +0000913 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000914 return EOF;
915 }
916
jjako08d331d2003-10-13 20:33:30 +0000917 /* Echo reply packages does not have a cause information element */
918 /* Instead we return the recovery number in the callback function */
919 if (gsn->cb_conf) gsn->cb_conf(type, recovery, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +0000920
921 return 0;
922}
923
924/* Send off a Version Not Supported message */
925/* This message is somewhat special in that it actually is a
926 * response to some other message with unsupported GTP version
927 * For this reason it has parameters like a response, and does
928 * its own message transmission. No signalling queue is used
929 * The reply is sent to the peer IP and peer UDP. This means that
930 * the peer will be receiving a GTP0 message on a GTP1 port!
931 * In practice however this will never happen as a GTP0 GSN will
932 * only listen to the GTP0 port, and therefore will never receive
933 * anything else than GTP0 */
934
jjako08d331d2003-10-13 20:33:30 +0000935int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
936 int fd, void *pack, unsigned len)
jjako52c24142002-12-16 13:33:51 +0000937{
938 union gtp_packet packet;
jjako52c24142002-12-16 13:33:51 +0000939
jjako08d331d2003-10-13 20:33:30 +0000940 /* GTP 1 is the highest supported protocol */
jjako2c381332003-10-21 19:09:53 +0000941 int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet);
942 return gtp_notification(gsn, version, &packet, length,
943 peer, fd, 0);
jjako52c24142002-12-16 13:33:51 +0000944}
945
946/* Handle a Version Not Supported message */
jjako08d331d2003-10-13 20:33:30 +0000947int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
948 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000949
jjako08d331d2003-10-13 20:33:30 +0000950 if (gsn->cb_unsup_ind) gsn->cb_unsup_ind(peer);
jjako52c24142002-12-16 13:33:51 +0000951
jjako52c24142002-12-16 13:33:51 +0000952 return 0;
953}
954
jjako2c381332003-10-21 19:09:53 +0000955/* Send off an Supported Extension Headers Notification */
956int gtp_extheader_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
957 int fd, void *pack, unsigned len)
958{
959 union gtp_packet packet;
960 int length = get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet);
961
962 uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU;
963
964 if (version < 1)
965 return 0;
966
967 /* We report back that we support only PDCP PDU headers */
968 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T, sizeof(pdcp_pdu),
969 &pdcp_pdu);
970
971 return gtp_notification(gsn, version, &packet, length,
972 peer, fd, get_seq(pack));
973}
974
975/* Handle a Supported Extension Headers Notification */
976int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
977 void *pack, unsigned len) {
978
979 if (gsn->cb_extheader_ind) gsn->cb_extheader_ind(peer);
980
981 return 0;
982}
983
984
jjako52c24142002-12-16 13:33:51 +0000985/* ***********************************************************
986 * Session management messages
987 * Messages: create, update and delete PDP context
988 *
989 * Information storage
990 * Information storage for each PDP context is defined in
991 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
992 * PDP-address (IP address), sequence numbers, charging ID.
993 * For the SGSN it also includes radio related mobility
994 * information.
995 *************************************************************/
996
jjako08d331d2003-10-13 20:33:30 +0000997/* API: Send Create PDP Context Request */
998extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
jjako193e8b12003-11-10 12:31:41 +0000999 void *cbp) {
jjako52c24142002-12-16 13:33:51 +00001000 union gtp_packet packet;
jjako08d331d2003-10-13 20:33:30 +00001001 int length = get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet);
jjako2c381332003-10-21 19:09:53 +00001002 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001003
jjako2c381332003-10-21 19:09:53 +00001004 /* TODO: Secondary PDP Context Activation Procedure */
1005 /* In secondary activation procedure the PDP context is identified
1006 by tei in the header. The following fields are omitted: Selection
1007 mode, IMSI, MSISDN, End User Address, Access Point Name and
1008 Protocol Configuration Options */
1009
1010 if (pdp->secondary) {
1011 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
1012 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context");
1013 return EOF;
1014 }
1015 }
1016
1017 if (pdp->version == 0) {
jjako08d331d2003-10-13 20:33:30 +00001018 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
jjako52c24142002-12-16 13:33:51 +00001019 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako2c381332003-10-21 19:09:53 +00001020 }
jjako52c24142002-12-16 13:33:51 +00001021
jjako2c381332003-10-21 19:09:53 +00001022 if (pdp->version == 1) {
1023 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1024 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1025 sizeof(pdp->imsi), (uint8_t*) &pdp->imsi);
1026 }
jjako52c24142002-12-16 13:33:51 +00001027
jjako08d331d2003-10-13 20:33:30 +00001028 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1029 gsn->restart_counter);
jjako2c381332003-10-21 19:09:53 +00001030
1031 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1032 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE,
1033 pdp->selmode);
jjako08d331d2003-10-13 20:33:30 +00001034
1035 if (pdp->version == 0) {
1036 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1037 pdp->fllu);
1038 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1039 pdp->fllc);
1040 }
1041
1042 if (pdp->version == 1) {
1043 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1044 pdp->teid_own);
jjako2c381332003-10-21 19:09:53 +00001045
1046 if (!pdp->teic_confirmed)
1047 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1048 pdp->teic_own);
jjako08d331d2003-10-13 20:33:30 +00001049
jjakobe61ef22004-01-09 12:22:29 +00001050 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1051 pdp->nsapi);
jjako08d331d2003-10-13 20:33:30 +00001052
jjako08d331d2003-10-13 20:33:30 +00001053
jjako2c381332003-10-21 19:09:53 +00001054 if (pdp->secondary) /* Secondary PDP Context Activation Procedure */
jjakobe61ef22004-01-09 12:22:29 +00001055 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
jjako2c381332003-10-21 19:09:53 +00001056 linked_pdp->nsapi);
1057
jjako08d331d2003-10-13 20:33:30 +00001058 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C,
1059 pdp->cch_pdp);
1060 }
1061
1062 /* TODO
1063 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1064 pdp->traceref);
1065 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1066 pdp->tracetype); */
1067
jjako2c381332003-10-21 19:09:53 +00001068 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1069 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1070 pdp->eua.l, pdp->eua.v);
1071
jjako08d331d2003-10-13 20:33:30 +00001072
jjako2c381332003-10-21 19:09:53 +00001073 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1074 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN,
1075 pdp->apn_use.l, pdp->apn_use.v);
1076
1077 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1078 if (pdp->pco_req.l)
1079 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
1080 pdp->pco_req.l, pdp->pco_req.v);
jjako08d331d2003-10-13 20:33:30 +00001081
1082 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1083 pdp->gsnlc.l, pdp->gsnlc.v);
1084 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1085 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001086
1087 if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
1088 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN,
1089 pdp->msisdn.l, pdp->msisdn.v);
jjako08d331d2003-10-13 20:33:30 +00001090
1091 if (pdp->version == 1)
1092 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1093 pdp->qos_req.l, pdp->qos_req.v);
1094
1095
1096 if ((pdp->version == 1) && pdp->tft.l)
1097 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1098 pdp->tft.l, pdp->tft.v);
1099
1100 if ((pdp->version == 1) && pdp->triggerid.l)
1101 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1102 pdp->triggerid.l, pdp->triggerid.v);
1103
1104 if ((pdp->version == 1) && pdp->omcid.l)
1105 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1106 pdp->omcid.l, pdp->omcid.v);
1107
jjako193e8b12003-11-10 12:31:41 +00001108 /* TODO hisaddr0 */
1109 gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
jjako52c24142002-12-16 13:33:51 +00001110
1111 return 0;
1112}
1113
jjako08d331d2003-10-13 20:33:30 +00001114/* API: Application response to context indication */
1115int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause) {
1116
1117 /* Now send off a reply to the peer */
1118 gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
1119
1120 if (cause != GTPCAUSE_ACC_REQ) {
1121 pdp_freepdp(pdp);
1122 }
1123
1124 return 0;
1125}
1126
1127/* API: Register create context indication callback */
1128int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
1129 int (*cb_create_context_ind) (struct pdp_t* pdp))
jjako52c24142002-12-16 13:33:51 +00001130{
jjako08d331d2003-10-13 20:33:30 +00001131 gsn->cb_create_context_ind = cb_create_context_ind;
1132 return 0;
1133}
1134
1135
1136/* Send Create PDP Context Response */
1137int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
1138 uint8_t cause) {
jjako52c24142002-12-16 13:33:51 +00001139 union gtp_packet packet;
jjako08d331d2003-10-13 20:33:30 +00001140 int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
jjako52c24142002-12-16 13:33:51 +00001141
jjako08d331d2003-10-13 20:33:30 +00001142 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00001143
1144 if (cause == GTPCAUSE_ACC_REQ) {
jjako08d331d2003-10-13 20:33:30 +00001145
1146 if (version == 0)
1147 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1148 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1149
1150 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER,
jjako52c24142002-12-16 13:33:51 +00001151 pdp->reorder);
jjako08d331d2003-10-13 20:33:30 +00001152 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
jjako52c24142002-12-16 13:33:51 +00001153 gsn->restart_counter);
jjako08d331d2003-10-13 20:33:30 +00001154
1155 if (version == 0) {
1156 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1157 pdp->fllu);
1158 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1159 pdp->fllc);
1160 }
1161
1162 if (version == 1) {
1163 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1164 pdp->teid_own);
1165 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1166 pdp->teic_own);
1167 }
1168
jjako2c381332003-10-21 19:09:53 +00001169 /* TODO: We use teic_own as charging ID */
jjako08d331d2003-10-13 20:33:30 +00001170 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
jjako2c381332003-10-21 19:09:53 +00001171 pdp->teic_own);
1172
jjako08d331d2003-10-13 20:33:30 +00001173 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
jjako52c24142002-12-16 13:33:51 +00001174 pdp->eua.l, pdp->eua.v);
1175
1176 if (pdp->pco_neg.l) { /* Optional PCO */
jjako08d331d2003-10-13 20:33:30 +00001177 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
jjako52c24142002-12-16 13:33:51 +00001178 pdp->pco_neg.l, pdp->pco_neg.v);
1179 }
1180
jjako08d331d2003-10-13 20:33:30 +00001181 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
jjako52c24142002-12-16 13:33:51 +00001182 pdp->gsnlc.l, pdp->gsnlc.v);
jjako08d331d2003-10-13 20:33:30 +00001183 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
jjako52c24142002-12-16 13:33:51 +00001184 pdp->gsnlu.l, pdp->gsnlu.v);
jjako08d331d2003-10-13 20:33:30 +00001185
1186 if (version == 1)
1187 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1188 pdp->qos_neg.l, pdp->qos_neg.v);
1189
1190 /* TODO: Charging gateway address */
jjako52c24142002-12-16 13:33:51 +00001191 }
1192
jjako08d331d2003-10-13 20:33:30 +00001193 return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer,
1194 pdp->fd, pdp->seq, pdp->tid);
jjako52c24142002-12-16 13:33:51 +00001195}
1196
1197/* Handle Create PDP Context Request */
1198int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001199 struct sockaddr_in *peer, int fd,
1200 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00001201 struct pdp_t *pdp, *pdp_old;
1202 struct pdp_t pdp_buf;
1203 union gtpie_member* ie[GTPIE_SIZE];
1204 uint8_t recovery;
jjako52c24142002-12-16 13:33:51 +00001205
jjako08d331d2003-10-13 20:33:30 +00001206 uint16_t seq = get_seq(pack);
1207 int hlen = get_hlen(pack);
jjako2c381332003-10-21 19:09:53 +00001208 uint8_t linked_nsapi = 0;
1209 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00001210
jjako2c381332003-10-21 19:09:53 +00001211 if(!gtp_dublicate(gsn, version, peer, seq)) return 0;
jjako08d331d2003-10-13 20:33:30 +00001212
1213 pdp = &pdp_buf;
1214 memset(pdp, 0, sizeof(struct pdp_t));
1215
1216 if (version == 0) {
1217 pdp->imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffff;
1218 pdp->nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000) >> 60;
jjako52c24142002-12-16 13:33:51 +00001219 }
1220
jjako08d331d2003-10-13 20:33:30 +00001221 pdp->seq = seq;
1222 pdp->sa_peer = *peer;
1223 pdp->fd = fd;
1224 pdp->version = version;
1225
jjako52c24142002-12-16 13:33:51 +00001226 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001227 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001228 gsn->invalid++;
1229 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1230 "Invalid message format");
1231 if (0 == version)
1232 return EOF;
1233 else
jjako08d331d2003-10-13 20:33:30 +00001234 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_INVALID_MESSAGE);
jjako52c24142002-12-16 13:33:51 +00001235 }
1236
jjako2c381332003-10-21 19:09:53 +00001237 if (version == 1) {
1238 /* Linked NSAPI (conditional) */
1239 /* If included this is the Secondary PDP Context Activation Procedure */
1240 /* In secondary activation IMSI is not included, so the context must be */
1241 /* identified by the tei */
1242 if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) {
1243
1244 /* Find the primary PDP context */
1245 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
1246 gsn->incorrect++;
1247 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1248 "Incorrect optional information field");
1249 return gtp_create_pdp_resp(gsn, version, pdp,
1250 GTPCAUSE_OPT_IE_INCORRECT);
1251 }
1252
1253 /* Check that the primary PDP context matches linked nsapi */
1254 if (linked_pdp->nsapi != linked_nsapi) {
1255 gsn->incorrect++;
1256 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1257 "Incorrect optional information field");
1258 return gtp_create_pdp_resp(gsn, version, pdp,
1259 GTPCAUSE_OPT_IE_INCORRECT);
1260 }
1261
1262 /* Copy parameters from primary context */
1263 pdp->selmode = linked_pdp->selmode;
1264 pdp->imsi = linked_pdp->imsi;
1265 pdp->msisdn = linked_pdp->msisdn;
1266 pdp->eua = linked_pdp->eua;
1267 pdp->pco_req = linked_pdp->pco_req;
1268 pdp->apn_req = linked_pdp->apn_req;
1269 pdp->teic_gn = linked_pdp->teic_gn;
1270 pdp->secondary = 1;
1271 }
1272 } /* if (version == 1) */
1273
jjako08d331d2003-10-13 20:33:30 +00001274 if (version == 0) {
1275 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1276 pdp->qos_req0, sizeof(pdp->qos_req0))) {
1277 gsn->missing++;
1278 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1279 "Missing mandatory information field");
1280 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING);
1281 }
jjako52c24142002-12-16 13:33:51 +00001282 }
jjako2c381332003-10-21 19:09:53 +00001283
1284 if ((version == 1) && (!linked_pdp)) {
1285 /* Not Secondary PDP Context Activation Procedure */
jjako08d331d2003-10-13 20:33:30 +00001286 /* IMSI (conditional) */
1287 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) {
1288 gsn->missing++;
1289 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1290 "Missing mandatory information field");
1291 return gtp_create_pdp_resp(gsn, version, pdp,
1292 GTPCAUSE_MAN_IE_MISSING);
1293 }
1294 }
jjako2c381332003-10-21 19:09:53 +00001295
jjako08d331d2003-10-13 20:33:30 +00001296 /* Recovery (optional) */
jjako52c24142002-12-16 13:33:51 +00001297 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1298 /* TODO: Handle received recovery IE */
1299 }
jjako2c381332003-10-21 19:09:53 +00001300
jjako08d331d2003-10-13 20:33:30 +00001301 /* Selection mode (conditional) */
jjako2c381332003-10-21 19:09:53 +00001302 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1303 if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0,
1304 &pdp->selmode, sizeof(pdp->selmode))) {
1305 gsn->missing++;
1306 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1307 "Missing mandatory information field");
1308 return gtp_create_pdp_resp(gsn, version, pdp,
1309 GTPCAUSE_MAN_IE_MISSING);
1310 }
jjako52c24142002-12-16 13:33:51 +00001311 }
1312
jjako08d331d2003-10-13 20:33:30 +00001313 if (version == 0) {
1314 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1315 gsn->missing++;
1316 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1317 "Missing mandatory information field");
1318 return gtp_create_pdp_resp(gsn, version, pdp,
1319 GTPCAUSE_MAN_IE_MISSING);
1320 }
1321
1322 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1323 gsn->missing++;
1324 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1325 "Missing mandatory information field");
1326 return gtp_create_pdp_resp(gsn, version, pdp,
1327 GTPCAUSE_MAN_IE_MISSING);
1328 }
jjako52c24142002-12-16 13:33:51 +00001329 }
jjako2c381332003-10-21 19:09:53 +00001330
1331
jjako08d331d2003-10-13 20:33:30 +00001332 if (version == 1) {
1333 /* TEID (mandatory) */
1334 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
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 }
1341
1342 /* TEIC (conditional) */
jjako2c381332003-10-21 19:09:53 +00001343 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1344 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1345 gsn->missing++;
1346 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1347 "Missing mandatory information field");
1348 return gtp_create_pdp_resp(gsn, version, pdp,
1349 GTPCAUSE_MAN_IE_MISSING);
1350 }
jjako08d331d2003-10-13 20:33:30 +00001351 }
jjako52c24142002-12-16 13:33:51 +00001352
jjako98200df2004-01-09 15:18:42 +00001353 /* NSAPI (mandatory) */
1354 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
1355 gsn->missing++;
1356 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1357 "Missing mandatory information field");
1358 return gtp_create_pdp_resp(gsn, version, pdp,
1359 GTPCAUSE_MAN_IE_MISSING);
1360 }
jjako2c381332003-10-21 19:09:53 +00001361 }
1362
1363
jjako08d331d2003-10-13 20:33:30 +00001364 /* Charging Characteriatics (optional) */
1365 /* Trace reference (optional) */
1366 /* Trace type (optional) */
1367 /* Charging Characteriatics (optional) */
jjako2c381332003-10-21 19:09:53 +00001368
1369 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1370 /* End User Address (conditional) */
1371 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
jjako52c24142002-12-16 13:33:51 +00001372 &pdp->eua.v, sizeof(pdp->eua.v))) {
jjako2c381332003-10-21 19:09:53 +00001373 gsn->missing++;
1374 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1375 "Missing mandatory information field");
1376 return gtp_create_pdp_resp(gsn, version, pdp,
1377 GTPCAUSE_MAN_IE_MISSING);
1378 }
1379
1380 /* APN */
1381 if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l,
jjako52c24142002-12-16 13:33:51 +00001382 &pdp->apn_req.v, sizeof(pdp->apn_req.v))) {
jjako2c381332003-10-21 19:09:53 +00001383 gsn->missing++;
1384 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1385 "Missing mandatory information field");
1386 return gtp_create_pdp_resp(gsn, version, pdp,
1387 GTPCAUSE_MAN_IE_MISSING);
1388 }
1389
1390 /* Extract protocol configuration options (optional) */
1391 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1392 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
1393 }
jjako52c24142002-12-16 13:33:51 +00001394 }
1395
jjako08d331d2003-10-13 20:33:30 +00001396 /* SGSN address for signalling (mandatory) */
jjako52c24142002-12-16 13:33:51 +00001397 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1398 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1399 gsn->missing++;
1400 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1401 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001402 return gtp_create_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00001403 GTPCAUSE_MAN_IE_MISSING);
1404 }
1405
jjako08d331d2003-10-13 20:33:30 +00001406 /* SGSN address for user traffic (mandatory) */
jjako52c24142002-12-16 13:33:51 +00001407 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1408 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1409 gsn->missing++;
1410 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1411 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001412 return gtp_create_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00001413 GTPCAUSE_MAN_IE_MISSING);
1414 }
1415
jjako2c381332003-10-21 19:09:53 +00001416 if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
1417 /* MSISDN (conditional) */
1418 if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l,
1419 &pdp->msisdn.v, sizeof(pdp->msisdn.v))) {
1420 gsn->missing++;
1421 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1422 "Missing mandatory information field");
1423 return gtp_create_pdp_resp(gsn, version, pdp,
1424 GTPCAUSE_MAN_IE_MISSING);
1425 }
jjako52c24142002-12-16 13:33:51 +00001426 }
1427
jjako08d331d2003-10-13 20:33:30 +00001428 if (version == 1) {
1429 /* QoS (mandatory) */
1430 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
1431 &pdp->qos_req.v, sizeof(pdp->qos_req.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 }
1438
1439 /* TFT (conditional) */
1440 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
1441 &pdp->tft.v, sizeof(pdp->tft.v))) {
1442 }
jjako2c381332003-10-21 19:09:53 +00001443
jjako08d331d2003-10-13 20:33:30 +00001444 /* Trigger ID */
1445 /* OMC identity */
1446 }
1447
1448 /* Initialize our own IP addresses */
jjako52c24142002-12-16 13:33:51 +00001449 in_addr2gsna(&pdp->gsnlc, &gsn->gsnc);
1450 in_addr2gsna(&pdp->gsnlu, &gsn->gsnu);
jjako2c381332003-10-21 19:09:53 +00001451
jjako2e840a32003-01-28 16:05:18 +00001452 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Before pdp_tidget\n");
jjako2c381332003-10-21 19:09:53 +00001453
jjako08d331d2003-10-13 20:33:30 +00001454 if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) {
jjako52c24142002-12-16 13:33:51 +00001455 /* Found old pdp with same tid. Now the voodoo begins! */
jjako08d331d2003-10-13 20:33:30 +00001456 /* 09.60 / 29.060 allows create on existing context to "steal" */
1457 /* the context which was allready established */
jjako52c24142002-12-16 13:33:51 +00001458 /* We check that the APN, selection mode and MSISDN is the same */
jjako2e840a32003-01-28 16:05:18 +00001459 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n");
jjako08d331d2003-10-13 20:33:30 +00001460 if ((pdp->apn_req.l == pdp_old->apn_req.l)
jjako52c24142002-12-16 13:33:51 +00001461 && (!memcmp(pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l))
1462 && (pdp->selmode == pdp_old->selmode)
1463 && (pdp->msisdn.l == pdp_old->msisdn.l)
1464 && (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l))) {
1465 /* OK! We are dealing with the same APN. We will copy new
1466 * parameters to the old pdp and send off confirmation
1467 * We ignore the following information elements:
1468 * QoS: MS will get originally negotiated QoS.
1469 * End user address (EUA). MS will get old EUA anyway.
1470 * Protocol configuration option (PCO): Only application can verify */
jjako2e840a32003-01-28 16:05:18 +00001471
1472 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n");
jjako52c24142002-12-16 13:33:51 +00001473
1474 /* Copy remote flow label */
1475 pdp_old->flru = pdp->flru;
1476 pdp_old->flrc = pdp->flrc;
1477
jjako08d331d2003-10-13 20:33:30 +00001478 /* Copy remote tei */
1479 pdp_old->teid_gn = pdp->teid_gn;
1480 pdp_old->teic_gn = pdp->teic_gn;
1481
jjako52c24142002-12-16 13:33:51 +00001482 /* Copy peer GSN address */
1483 pdp_old->gsnrc.l = pdp->gsnrc.l;
1484 memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l);
1485 pdp_old->gsnru.l = pdp->gsnru.l;
1486 memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l);
jjako2c381332003-10-21 19:09:53 +00001487
1488 /* Copy request parameters */
1489 pdp_old->seq = pdp->seq;
1490 pdp_old->sa_peer = pdp->sa_peer;
1491 pdp_old->fd = pdp->fd = fd;
1492 pdp_old->version = pdp->version = version;
1493
1494 /* Switch to using the old pdp context */
jjako52c24142002-12-16 13:33:51 +00001495 pdp = pdp_old;
1496
1497 /* Confirm to peer that things were "successful" */
jjako08d331d2003-10-13 20:33:30 +00001498 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_ACC_REQ);
jjako52c24142002-12-16 13:33:51 +00001499 }
1500 else { /* This is not the same PDP context. Delete the old one. */
jjako2e840a32003-01-28 16:05:18 +00001501
1502 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleting old context\n");
jjako52c24142002-12-16 13:33:51 +00001503
1504 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp_old);
1505 pdp_freepdp(pdp_old);
jjako08d331d2003-10-13 20:33:30 +00001506
jjako2e840a32003-01-28 16:05:18 +00001507 if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleted...\n");
jjako52c24142002-12-16 13:33:51 +00001508 }
1509 }
1510
jjako08d331d2003-10-13 20:33:30 +00001511 pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp);
jjako52c24142002-12-16 13:33:51 +00001512
1513 /* Callback function to validata login */
jjako08d331d2003-10-13 20:33:30 +00001514 if (gsn->cb_create_context_ind !=0)
1515 return gsn->cb_create_context_ind(pdp);
jjako52c24142002-12-16 13:33:51 +00001516 else {
jjako08d331d2003-10-13 20:33:30 +00001517 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1518 "No create_context_ind callback defined");
1519 return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_NOT_SUPPORTED);
jjako52c24142002-12-16 13:33:51 +00001520 }
1521}
1522
1523
1524/* Handle Create PDP Context Response */
1525int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001526 struct sockaddr_in *peer,
1527 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00001528 struct pdp_t *pdp;
1529 union gtpie_member *ie[GTPIE_SIZE];
1530 uint8_t cause, recovery;
jjako08d331d2003-10-13 20:33:30 +00001531 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00001532 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +00001533 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001534
1535 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00001536 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00001537
1538 /* Find the context in question */
jjako08d331d2003-10-13 20:33:30 +00001539 if (pdp_getgtp1(&pdp, get_tei(pack))) {
jjako52c24142002-12-16 13:33:51 +00001540 gsn->err_unknownpdp++;
1541 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1542 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00001543 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00001544 return EOF;
1545 }
1546
jjako2c381332003-10-21 19:09:53 +00001547 /* Register that we have received a valid teic from GGSN */
1548 pdp->teic_confirmed = 1;
1549
jjako52c24142002-12-16 13:33:51 +00001550 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001551 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001552 gsn->invalid++;
1553 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1554 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +00001555 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001556 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1557 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001558 return EOF;
1559 }
1560
1561 /* Extract cause value (mandatory) */
1562 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
1563 gsn->missing++;
1564 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1565 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00001566 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001567 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1568 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001569 return EOF;
1570 }
1571
1572 /* Extract recovery (optional) */
1573 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1574 /* TODO: Handle received recovery IE */
1575 }
1576
1577 /* Extract protocol configuration options (optional) */
1578 if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
1579 &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
jjako52c24142002-12-16 13:33:51 +00001580 }
1581
1582 /* Check all conditional information elements */
1583 if (GTPCAUSE_ACC_REQ == cause) {
1584
jjako08d331d2003-10-13 20:33:30 +00001585 if (version == 0) {
1586 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1587 &pdp->qos_neg0, sizeof(pdp->qos_neg0))) {
1588 gsn->missing++;
1589 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1590 "Missing conditional information field");
1591 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001592 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1593 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001594 return EOF;
1595 }
jjako52c24142002-12-16 13:33:51 +00001596 }
jjako52c24142002-12-16 13:33:51 +00001597
1598 if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) {
1599 gsn->missing++;
1600 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1601 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001602 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001603 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1604 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001605 return EOF;
1606 }
1607
jjako08d331d2003-10-13 20:33:30 +00001608 if (version == 0) {
1609 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1610 gsn->missing++;
1611 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1612 "Missing conditional information field");
1613 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001614 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1615 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001616 return EOF;
1617 }
jjako52c24142002-12-16 13:33:51 +00001618
jjako08d331d2003-10-13 20:33:30 +00001619 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1620 gsn->missing++;
1621 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1622 "Missing conditional information field");
1623 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001624 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1625 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001626 return EOF;
1627 }
1628 }
1629
1630 if (version == 1) {
1631 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
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 if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
1642 gsn->missing++;
1643 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1644 "Missing conditional information field");
1645 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001646 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1647 pdp_freepdp(pdp); */
jjako08d331d2003-10-13 20:33:30 +00001648 return EOF;
1649 }
jjako52c24142002-12-16 13:33:51 +00001650 }
1651
1652 if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
1653 gsn->missing++;
1654 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1655 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001656 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001657 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1658 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001659 }
1660
1661 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
1662 &pdp->eua.v, sizeof(pdp->eua.v))) {
1663 gsn->missing++;
1664 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1665 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001666 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001667 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1668 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001669 return EOF;
1670 }
1671
1672 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
1673 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
1674 gsn->missing++;
1675 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1676 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001677 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001678 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1679 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001680 return EOF;
1681 }
1682
1683 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
1684 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
1685 gsn->missing++;
1686 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1687 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00001688 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00001689 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1690 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00001691 return EOF;
1692 }
jjako52c24142002-12-16 13:33:51 +00001693
jjako08d331d2003-10-13 20:33:30 +00001694 if (version == 1) {
1695 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
1696 &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
1697 gsn->missing++;
1698 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1699 "Missing conditional information field");
1700 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); */
jjako08d331d2003-10-13 20:33:30 +00001703 return EOF;
1704 }
1705 }
jjakoccc564f2003-10-25 15:40:48 +00001706
jjako08d331d2003-10-13 20:33:30 +00001707 }
1708
1709 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako52c24142002-12-16 13:33:51 +00001710
1711 return 0;
1712}
1713
jjako52c24142002-12-16 13:33:51 +00001714
jjako08d331d2003-10-13 20:33:30 +00001715/* API: Send Update PDP Context Request */
1716int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
1717 struct in_addr* inetaddr) {
1718 union gtp_packet packet;
1719 int length = get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet);
jjako52c24142002-12-16 13:33:51 +00001720
jjako08d331d2003-10-13 20:33:30 +00001721 if (pdp->version == 0)
1722 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1723 sizeof(pdp->qos_req0), pdp->qos_req0);
jjako2c381332003-10-21 19:09:53 +00001724
1725 /* Include IMSI if updating with unknown teic_gn */
1726 if ((pdp->version == 1) && (!pdp->teic_gn))
jjako08d331d2003-10-13 20:33:30 +00001727 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
1728 sizeof(pdp->imsi), (uint8_t*) &pdp->imsi);
jjako2c381332003-10-21 19:09:53 +00001729
jjako08d331d2003-10-13 20:33:30 +00001730 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
jjako52c24142002-12-16 13:33:51 +00001731 gsn->restart_counter);
jjako2c381332003-10-21 19:09:53 +00001732
jjako08d331d2003-10-13 20:33:30 +00001733 if (pdp->version == 0) {
1734 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
jjako52c24142002-12-16 13:33:51 +00001735 pdp->fllu);
jjako08d331d2003-10-13 20:33:30 +00001736 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
jjako52c24142002-12-16 13:33:51 +00001737 pdp->fllc);
jjako52c24142002-12-16 13:33:51 +00001738 }
jjako2c381332003-10-21 19:09:53 +00001739
jjako08d331d2003-10-13 20:33:30 +00001740 if (pdp->version == 1) {
1741 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1742 pdp->teid_own);
jjako52c24142002-12-16 13:33:51 +00001743
jjako2c381332003-10-21 19:09:53 +00001744 if (!pdp->teic_confirmed)
1745 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1746 pdp->teic_own);
1747 }
1748
jjako08d331d2003-10-13 20:33:30 +00001749 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
1750 pdp->nsapi);
jjako2c381332003-10-21 19:09:53 +00001751
jjako08d331d2003-10-13 20:33:30 +00001752 /* TODO
jjako2c381332003-10-21 19:09:53 +00001753 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1754 pdp->traceref);
1755 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1756 pdp->tracetype); */
1757
jjako08d331d2003-10-13 20:33:30 +00001758 /* TODO if ggsn update message
jjako2c381332003-10-21 19:09:53 +00001759 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1760 pdp->eua.l, pdp->eua.v);
jjako08d331d2003-10-13 20:33:30 +00001761 */
jjako2c381332003-10-21 19:09:53 +00001762
jjako08d331d2003-10-13 20:33:30 +00001763 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1764 pdp->gsnlc.l, pdp->gsnlc.v);
1765 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1766 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001767
jjako08d331d2003-10-13 20:33:30 +00001768 if (pdp->version == 1)
1769 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1770 pdp->qos_req.l, pdp->qos_req.v);
jjako2c381332003-10-21 19:09:53 +00001771
1772
jjako08d331d2003-10-13 20:33:30 +00001773 if ((pdp->version == 1) && pdp->tft.l)
1774 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
1775 pdp->tft.l, pdp->tft.v);
1776
1777 if ((pdp->version == 1) && pdp->triggerid.l)
1778 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
1779 pdp->triggerid.l, pdp->triggerid.v);
1780
1781 if ((pdp->version == 1) && pdp->omcid.l)
1782 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
1783 pdp->omcid.l, pdp->omcid.v);
1784
1785 gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp);
1786
1787 return 0;
jjako52c24142002-12-16 13:33:51 +00001788}
1789
jjako08d331d2003-10-13 20:33:30 +00001790
1791/* Send Update PDP Context Response */
1792int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
1793 struct sockaddr_in *peer, int fd,
1794 void *pack, unsigned len,
1795 struct pdp_t *pdp, uint8_t cause) {
1796
1797 union gtp_packet packet;
1798 int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
1799
1800 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
1801
1802 if (cause == GTPCAUSE_ACC_REQ) {
1803
1804 if (version == 0)
1805 gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
1806 sizeof(pdp->qos_neg0), pdp->qos_neg0);
1807
1808 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
1809 gsn->restart_counter);
1810
1811 if (version == 0) {
1812 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
1813 pdp->fllu);
1814 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
1815 pdp->fllc);
1816 }
1817
1818 if (version == 1) {
1819 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
1820 pdp->teid_own);
jjako2c381332003-10-21 19:09:53 +00001821
1822 if (!pdp->teic_confirmed)
1823 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
1824 pdp->teic_own);
jjako08d331d2003-10-13 20:33:30 +00001825 }
jjako2c381332003-10-21 19:09:53 +00001826
1827 /* TODO we use teid_own as charging ID address */
jjako08d331d2003-10-13 20:33:30 +00001828 gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
jjako2c381332003-10-21 19:09:53 +00001829 pdp->teid_own);
1830
jjako08d331d2003-10-13 20:33:30 +00001831 /* If ggsn
jjako2c381332003-10-21 19:09:53 +00001832 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1833 pdp->eua.l, pdp->eua.v); */
1834
jjako08d331d2003-10-13 20:33:30 +00001835 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1836 pdp->gsnlc.l, pdp->gsnlc.v);
1837 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
1838 pdp->gsnlu.l, pdp->gsnlu.v);
jjako2c381332003-10-21 19:09:53 +00001839
jjako08d331d2003-10-13 20:33:30 +00001840 if (version == 1)
1841 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
1842 pdp->qos_neg.l, pdp->qos_neg.v);
jjako2c381332003-10-21 19:09:53 +00001843
jjako08d331d2003-10-13 20:33:30 +00001844 /* TODO: Charging gateway address */
1845 }
jjako2c381332003-10-21 19:09:53 +00001846
1847 return gtp_resp(version, gsn, pdp, &packet, length, peer,
1848 fd, get_seq(pack), get_tid(pack));
jjako08d331d2003-10-13 20:33:30 +00001849}
1850
1851
jjako52c24142002-12-16 13:33:51 +00001852/* Handle Update PDP Context Request */
1853int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00001854 struct sockaddr_in *peer, int fd,
1855 void *pack, unsigned len) {
1856 struct pdp_t *pdp;
1857 struct pdp_t pdp_backup;
jjako52c24142002-12-16 13:33:51 +00001858 union gtpie_member* ie[GTPIE_SIZE];
1859 uint8_t recovery;
1860
jjako08d331d2003-10-13 20:33:30 +00001861 uint16_t seq = get_seq(pack);
1862 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00001863
jjako08d331d2003-10-13 20:33:30 +00001864 uint64_t imsi;
1865 uint8_t nsapi;
1866
jjako52c24142002-12-16 13:33:51 +00001867 /* Is this a dublicate ? */
jjako08d331d2003-10-13 20:33:30 +00001868 if(!gtp_dublicate(gsn, version, peer, seq)) {
jjako52c24142002-12-16 13:33:51 +00001869 return 0; /* We allready send of response once */
1870 }
jjako2c381332003-10-21 19:09:53 +00001871
jjako52c24142002-12-16 13:33:51 +00001872
1873 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00001874 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00001875 gsn->invalid++;
1876 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1877 "Invalid message format");
1878 if (0 == version)
1879 return EOF;
1880 else
jjako08d331d2003-10-13 20:33:30 +00001881 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1882 NULL, GTPCAUSE_INVALID_MESSAGE);
jjako52c24142002-12-16 13:33:51 +00001883 }
1884
jjako08d331d2003-10-13 20:33:30 +00001885 /* Finding PDP: */
1886 /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
1887 /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
1888 /* we have to use the tunnel endpoint identifier */
1889 if (version == 0) {
1890 imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffff;
1891 nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000) >> 60;
jjako2c381332003-10-21 19:09:53 +00001892
jjako08d331d2003-10-13 20:33:30 +00001893 /* Find the context in question */
1894 if (pdp_getimsi(&pdp, imsi, nsapi)) {
1895 gsn->err_unknownpdp++;
1896 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1897 "Unknown PDP context");
1898 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1899 NULL, GTPCAUSE_NON_EXIST);
1900 }
jjako52c24142002-12-16 13:33:51 +00001901 }
jjako08d331d2003-10-13 20:33:30 +00001902 else if (version == 1) {
1903 /* NSAPI (mandatory) */
1904 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
1905 gsn->missing++;
1906 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1907 "Missing mandatory information field");
1908 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1909 NULL, GTPCAUSE_MAN_IE_MISSING);
1910 }
jjako2c381332003-10-21 19:09:53 +00001911
jjako08d331d2003-10-13 20:33:30 +00001912 /* IMSI (conditional) */
1913 if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) {
1914 /* Find the context in question */
1915 if (pdp_getgtp1(&pdp, get_tei(pack))) {
1916 gsn->err_unknownpdp++;
1917 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1918 "Unknown PDP context");
1919 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1920 NULL, GTPCAUSE_NON_EXIST);
1921 }
1922 }
1923 else {
1924 /* Find the context in question */
1925 if (pdp_getimsi(&pdp, imsi, nsapi)) {
1926 gsn->err_unknownpdp++;
1927 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1928 "Unknown PDP context");
1929 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1930 NULL, GTPCAUSE_NON_EXIST);
1931 }
1932 }
1933 }
1934 else {
1935 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
1936 return EOF;
1937 }
jjako2c381332003-10-21 19:09:53 +00001938
jjako08d331d2003-10-13 20:33:30 +00001939 /* Make a backup copy in case anything is wrong */
1940 memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
1941
1942 if (version == 0) {
1943 if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
1944 pdp->qos_req0, sizeof(pdp->qos_req0))) {
1945 gsn->missing++;
1946 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1947 "Missing mandatory information field");
1948 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1949 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
1950 pdp, GTPCAUSE_MAN_IE_MISSING);
1951 }
1952 }
1953
1954 /* Recovery (optional) */
jjako52c24142002-12-16 13:33:51 +00001955 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
1956 /* TODO: Handle received recovery IE */
1957 }
1958
jjako08d331d2003-10-13 20:33:30 +00001959 if (version == 0) {
1960 if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
1961 gsn->missing++;
1962 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1963 "Missing mandatory information field");
1964 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1965 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
1966 GTPCAUSE_MAN_IE_MISSING);
1967 }
1968
1969 if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
1970 gsn->missing++;
1971 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1972 "Missing mandatory information field");
1973 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1974 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
1975 GTPCAUSE_MAN_IE_MISSING);
1976 }
1977 }
1978
1979
1980 if (version == 1) {
1981 /* TEID (mandatory) */
1982 if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
1983 gsn->missing++;
1984 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
1985 "Missing mandatory information field");
1986 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
1987 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
1988 GTPCAUSE_MAN_IE_MISSING);
1989 }
jjako2c381332003-10-21 19:09:53 +00001990
jjako08d331d2003-10-13 20:33:30 +00001991 /* TEIC (conditional) */
1992 /* If TEIC is not included it means that we have allready received it */
jjako2c381332003-10-21 19:09:53 +00001993 /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
1994 /* all updated contexts, or only for one of the linked contexts */
1995 gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn);
1996
jjako08d331d2003-10-13 20:33:30 +00001997 /* NSAPI (mandatory) */
1998 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
1999 gsn->missing++;
2000 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2001 "Missing mandatory information field");
2002 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2003 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2004 GTPCAUSE_MAN_IE_MISSING);
2005 }
2006 }
2007
2008 /* Trace reference (optional) */
2009 /* Trace type (optional) */
2010
2011 /* End User Address (conditional) TODO: GGSN Initiated
2012 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2013 &pdp->eua.v, sizeof(pdp->eua.v))) {
jjako52c24142002-12-16 13:33:51 +00002014 gsn->missing++;
2015 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2016 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002017 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2018 return gtp_update_pdp_resp(gsn, version, pdp,
jjako52c24142002-12-16 13:33:51 +00002019 GTPCAUSE_MAN_IE_MISSING);
jjako08d331d2003-10-13 20:33:30 +00002020 } */
jjako52c24142002-12-16 13:33:51 +00002021
jjako08d331d2003-10-13 20:33:30 +00002022
2023 /* SGSN address for signalling (mandatory) */
2024 /* It is weird that this is mandatory when TEIC is conditional */
2025 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2026 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
jjako52c24142002-12-16 13:33:51 +00002027 gsn->missing++;
2028 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2029 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002030 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2031 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002032 GTPCAUSE_MAN_IE_MISSING);
2033 }
2034
jjako08d331d2003-10-13 20:33:30 +00002035 /* SGSN address for user traffic (mandatory) */
2036 if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2037 &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
jjako52c24142002-12-16 13:33:51 +00002038 gsn->missing++;
2039 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2040 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002041 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2042 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002043 GTPCAUSE_MAN_IE_MISSING);
2044 }
jjako08d331d2003-10-13 20:33:30 +00002045
2046 if (version == 1) {
2047 /* QoS (mandatory) */
2048 if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
2049 &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
2050 gsn->missing++;
2051 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2052 "Missing mandatory information field");
2053 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2054 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
2055 GTPCAUSE_MAN_IE_MISSING);
2056 }
jjako52c24142002-12-16 13:33:51 +00002057
jjako08d331d2003-10-13 20:33:30 +00002058 /* TFT (conditional) */
2059 if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
2060 &pdp->tft.v, sizeof(pdp->tft.v))) {
2061 }
2062
2063 /* OMC identity */
jjako52c24142002-12-16 13:33:51 +00002064 }
2065
jjako52c24142002-12-16 13:33:51 +00002066 /* Confirm to peer that things were "successful" */
jjako08d331d2003-10-13 20:33:30 +00002067 return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
jjako52c24142002-12-16 13:33:51 +00002068 GTPCAUSE_ACC_REQ);
2069}
2070
2071
2072/* Handle Update PDP Context Response */
2073int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
2074 struct sockaddr_in *peer,
2075 void *pack, unsigned len) {
2076 struct pdp_t *pdp;
2077 union gtpie_member *ie[GTPIE_SIZE];
2078 uint8_t cause, recovery;
jjako08d331d2003-10-13 20:33:30 +00002079 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00002080 uint8_t type = 0;
2081
2082 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00002083 if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00002084
2085 /* Find the context in question */
2086 if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) {
2087 gsn->err_unknownpdp++;
2088 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2089 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00002090 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002091 return EOF;
2092 }
2093
jjako2c381332003-10-21 19:09:53 +00002094 /* Register that we have received a valid teic from GGSN */
2095 pdp->teic_confirmed = 1;
2096
jjako52c24142002-12-16 13:33:51 +00002097 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002098 if (gtpie_decaps(ie, 0, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) {
jjako52c24142002-12-16 13:33:51 +00002099 gsn->invalid++;
2100 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2101 "Invalid message format");
jjako08d331d2003-10-13 20:33:30 +00002102 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002103 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2104 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002105 return EOF;
2106 }
2107
2108 /* Extract cause value (mandatory) */
2109 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2110 gsn->missing++;
2111 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2112 "Missing mandatory information field");
jjako08d331d2003-10-13 20:33:30 +00002113 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002114 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2115 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002116 return EOF;
2117 }
2118
2119 /* Extract recovery (optional) */
2120 if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
2121 /* TODO: Handle received recovery IE */
2122 }
2123
2124 /* Check all conditional information elements */
2125 if (GTPCAUSE_ACC_REQ != cause) {
jjako08d331d2003-10-13 20:33:30 +00002126 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002127 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2128 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002129 return 0;
2130 }
2131 else {
2132 /* Check for missing conditionary information elements */
2133 if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) &&
2134 gtpie_exist(ie, GTPIE_REORDER, 0) &&
2135 gtpie_exist(ie, GTPIE_FL_DI, 0) &&
2136 gtpie_exist(ie, GTPIE_FL_C, 0) &&
2137 gtpie_exist(ie, GTPIE_CHARGING_ID, 0) &&
2138 gtpie_exist(ie, GTPIE_EUA, 0) &&
2139 gtpie_exist(ie, GTPIE_GSN_ADDR, 0) &&
2140 gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) {
2141 gsn->missing++;
2142 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2143 "Missing conditional information field");
jjako08d331d2003-10-13 20:33:30 +00002144 if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
jjako0b076a32003-10-25 15:59:31 +00002145 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2146 pdp_freepdp(pdp); */
jjako52c24142002-12-16 13:33:51 +00002147 return EOF;
2148 }
2149
2150 /* Update pdp with new values */
2151 gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
2152 pdp->qos_neg0, sizeof(pdp->qos_neg0));
2153 gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder);
2154 gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru);
2155 gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc);
2156 gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid);
2157 gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2158 &pdp->eua.v, sizeof(pdp->eua.v));
2159 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
2160 &pdp->gsnrc.v, sizeof(pdp->gsnrc.v));
2161 gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
2162 &pdp->gsnru.v, sizeof(pdp->gsnru.v));
2163
jjako08d331d2003-10-13 20:33:30 +00002164 if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
jjako52c24142002-12-16 13:33:51 +00002165 return 0; /* Succes */
2166 }
2167}
2168
jjako52c24142002-12-16 13:33:51 +00002169
jjako08d331d2003-10-13 20:33:30 +00002170/* API: Send Delete PDP Context Request */
jjako2c381332003-10-21 19:09:53 +00002171int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
2172 int teardown) {
jjako08d331d2003-10-13 20:33:30 +00002173 union gtp_packet packet;
jjako2c381332003-10-21 19:09:53 +00002174 int length = get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
jjako08d331d2003-10-13 20:33:30 +00002175 struct in_addr addr;
jjako2c381332003-10-21 19:09:53 +00002176 struct pdp_t *linked_pdp;
2177 struct pdp_t *secondary_pdp;
2178 int n;
2179 int count = 0;
2180
jjako52c24142002-12-16 13:33:51 +00002181 if (gsna2in_addr(&addr, &pdp->gsnrc)) {
2182 gsn->err_address++;
2183 gtp_err(LOG_ERR, __FILE__, __LINE__, "GSN address conversion failed");
2184 return EOF;
2185 }
jjako2c381332003-10-21 19:09:53 +00002186
2187 if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
2188 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context");
2189 return EOF;
2190 }
2191
2192 if (!teardown) {
2193 for (n=0; n< PDP_MAXNSAPI; n++)
2194 if (linked_pdp->secondary_tei[n]) count++;
2195 if (count <= 1) {
2196 gtp_err(LOG_ERR, __FILE__, __LINE__,
2197 "Must use teardown for last context");
2198 return EOF;
2199 }
2200 }
2201
jjako08d331d2003-10-13 20:33:30 +00002202 if (pdp->version == 1) {
2203 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
2204 pdp->nsapi);
jjako2c381332003-10-21 19:09:53 +00002205
2206 if (teardown)
2207 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
2208 0xff);
jjako08d331d2003-10-13 20:33:30 +00002209 }
jjako52c24142002-12-16 13:33:51 +00002210
jjako2c381332003-10-21 19:09:53 +00002211 gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
jjako52c24142002-12-16 13:33:51 +00002212
jjako2c381332003-10-21 19:09:53 +00002213 if (teardown) { /* Remove all contexts */
2214 for (n=0; n< PDP_MAXNSAPI; n++) {
2215 if (linked_pdp->secondary_tei[n]) {
2216 if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) {
2217 gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown secondary PDP context");
2218 return EOF;
2219 }
2220 if (linked_pdp != secondary_pdp) {
2221 if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp);
2222 pdp_freepdp(secondary_pdp);
2223 }
2224 }
2225 }
2226 if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp);
2227 pdp_freepdp(linked_pdp);
2228 }
2229 else {
2230 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2231 if (pdp == linked_pdp) {
2232 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2233 linked_pdp->nodata = 1;
2234 }
2235 else
2236 pdp_freepdp(pdp);
2237 }
2238
2239 return 0;
2240}
jjako08d331d2003-10-13 20:33:30 +00002241
jjako52c24142002-12-16 13:33:51 +00002242/* Send Delete PDP Context Response */
2243int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002244 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002245 void *pack, unsigned len,
jjako2c381332003-10-21 19:09:53 +00002246 struct pdp_t *pdp, struct pdp_t *linked_pdp,
2247 uint8_t cause, int teardown)
jjako52c24142002-12-16 13:33:51 +00002248{
2249 union gtp_packet packet;
jjako2c381332003-10-21 19:09:53 +00002250 struct pdp_t *secondary_pdp;
jjako08d331d2003-10-13 20:33:30 +00002251 int length = get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet);
jjako2c381332003-10-21 19:09:53 +00002252 int n;
jjako52c24142002-12-16 13:33:51 +00002253
jjako08d331d2003-10-13 20:33:30 +00002254 gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
jjako52c24142002-12-16 13:33:51 +00002255
jjako08d331d2003-10-13 20:33:30 +00002256 gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
jjako2c381332003-10-21 19:09:53 +00002257 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002258
jjako2c381332003-10-21 19:09:53 +00002259 if (cause == GTPCAUSE_ACC_REQ) {
2260 if ((teardown) || (version == 0)) { /* Remove all contexts */
2261 for (n=0; n< PDP_MAXNSAPI; n++) {
2262 if (linked_pdp->secondary_tei[n]) {
2263 if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) {
2264 gtp_err(LOG_ERR, __FILE__, __LINE__,
2265 "Unknown secondary PDP context");
2266 return EOF;
2267 }
2268 if (linked_pdp != secondary_pdp) {
2269 if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp);
2270 pdp_freepdp(secondary_pdp);
2271 }
2272 }
2273 }
2274 if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp);
2275 pdp_freepdp(linked_pdp);
2276 }
2277 else { /* Remove only current context */
2278 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2279 if (pdp == linked_pdp) {
2280 linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
2281 linked_pdp->nodata = 1;
2282 }
2283 else
2284 pdp_freepdp(pdp);
2285 }
2286 } /* if (cause == GTPCAUSE_ACC_REQ) */
jjako52c24142002-12-16 13:33:51 +00002287
jjako08d331d2003-10-13 20:33:30 +00002288 return 0;
jjako52c24142002-12-16 13:33:51 +00002289}
2290
2291/* Handle Delete PDP Context Request */
2292int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002293 struct sockaddr_in *peer, int fd,
2294 void *pack, unsigned len) {
jjako2c381332003-10-21 19:09:53 +00002295 struct pdp_t *pdp = NULL;
2296 struct pdp_t *linked_pdp = NULL;
jjako52c24142002-12-16 13:33:51 +00002297 union gtpie_member* ie[GTPIE_SIZE];
jjako08d331d2003-10-13 20:33:30 +00002298
2299 uint16_t seq = get_seq(pack);
2300 int hlen = get_hlen(pack);
jjako52c24142002-12-16 13:33:51 +00002301
jjako08d331d2003-10-13 20:33:30 +00002302 uint8_t nsapi;
jjako2c381332003-10-21 19:09:53 +00002303 uint8_t teardown = 0;
2304 int n;
2305 int count = 0;
2306
jjako52c24142002-12-16 13:33:51 +00002307 /* Is this a dublicate ? */
jjako08d331d2003-10-13 20:33:30 +00002308 if(!gtp_dublicate(gsn, version, peer, seq)) {
2309 return 0; /* We allready send off response once */
jjako52c24142002-12-16 13:33:51 +00002310 }
2311
jjako2c381332003-10-21 19:09:53 +00002312 /* Find the linked context in question */
2313 if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
jjako52c24142002-12-16 13:33:51 +00002314 gsn->err_unknownpdp++;
2315 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2316 "Unknown PDP context");
jjako2c381332003-10-21 19:09:53 +00002317 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2318 GTPCAUSE_NON_EXIST, teardown);
jjako52c24142002-12-16 13:33:51 +00002319 }
jjako2c381332003-10-21 19:09:53 +00002320
2321 /* If version 0 this is also the secondary context */
2322 if (version == 0)
2323 pdp = linked_pdp;
jjako52c24142002-12-16 13:33:51 +00002324
2325 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002326 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00002327 gsn->invalid++;
2328 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2329 "Invalid message format");
2330 if (0 == version)
2331 return EOF;
2332 else
jjako2c381332003-10-21 19:09:53 +00002333 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2334 GTPCAUSE_INVALID_MESSAGE, teardown);
jjako52c24142002-12-16 13:33:51 +00002335 }
jjako2c381332003-10-21 19:09:53 +00002336
jjako08d331d2003-10-13 20:33:30 +00002337 if (version == 1) {
2338 /* NSAPI (mandatory) */
2339 if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
2340 gsn->missing++;
2341 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2342 "Missing mandatory information field");
jjako2c381332003-10-21 19:09:53 +00002343 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2344 GTPCAUSE_MAN_IE_MISSING, teardown);
jjako08d331d2003-10-13 20:33:30 +00002345 }
jjako2c381332003-10-21 19:09:53 +00002346
2347 /* Find the context in question */
2348 if (pdp_getgtp1(&pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) {
2349 gsn->err_unknownpdp++;
2350 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2351 "Unknown PDP context");
2352 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
2353 GTPCAUSE_NON_EXIST, teardown);
2354 }
jjako08d331d2003-10-13 20:33:30 +00002355
2356 /* Teardown (conditional) */
jjako2c381332003-10-21 19:09:53 +00002357 gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown);
2358
2359 if (!teardown) {
2360 for (n=0; n< PDP_MAXNSAPI; n++)
2361 if (linked_pdp->secondary_tei[n]) count++;
2362 if (count <= 1) {
2363 return 0; /* 29.060 7.3.5 Ignore message */
2364 }
jjako08d331d2003-10-13 20:33:30 +00002365 }
2366 }
jjako2c381332003-10-21 19:09:53 +00002367
2368 return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
2369 pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown);
jjako52c24142002-12-16 13:33:51 +00002370}
2371
2372
2373/* Handle Delete PDP Context Response */
2374int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
2375 struct sockaddr_in *peer,
2376 void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +00002377 union gtpie_member *ie[GTPIE_SIZE];
2378 uint8_t cause;
jjako08d331d2003-10-13 20:33:30 +00002379 void *cbp = NULL;
jjako52c24142002-12-16 13:33:51 +00002380 uint8_t type = 0;
jjako08d331d2003-10-13 20:33:30 +00002381 int hlen = get_hlen(pack);
2382
jjako52c24142002-12-16 13:33:51 +00002383 /* Remove packet from queue */
jjako08d331d2003-10-13 20:33:30 +00002384 if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
jjako52c24142002-12-16 13:33:51 +00002385
jjako52c24142002-12-16 13:33:51 +00002386 /* Decode information elements */
jjako08d331d2003-10-13 20:33:30 +00002387 if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
jjako52c24142002-12-16 13:33:51 +00002388 gsn->invalid++;
2389 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2390 "Invalid message format");
jjako2c381332003-10-21 19:09:53 +00002391 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002392 return EOF;
2393 }
2394
jjako08d331d2003-10-13 20:33:30 +00002395 /* Extract cause value (mandatory) */
jjako52c24142002-12-16 13:33:51 +00002396 if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
2397 gsn->missing++;
2398 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2399 "Missing mandatory information field");
jjako2c381332003-10-21 19:09:53 +00002400 if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002401 return EOF;
2402 }
2403
jjako2c381332003-10-21 19:09:53 +00002404 /* Check the cause value (again) */
2405 if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
jjako52c24142002-12-16 13:33:51 +00002406 gsn->err_cause++;
2407 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2408 "Unexpected cause value received: %d", cause);
jjako2c381332003-10-21 19:09:53 +00002409 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
2410 return EOF;
jjako52c24142002-12-16 13:33:51 +00002411 }
jjako2c381332003-10-21 19:09:53 +00002412
jjako08d331d2003-10-13 20:33:30 +00002413 /* Callback function to notify application */
jjako2c381332003-10-21 19:09:53 +00002414 if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
jjako52c24142002-12-16 13:33:51 +00002415
2416 return 0;
2417}
2418
2419/* Send Error Indication (response to a GPDU message */
2420int gtp_error_ind_resp(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002421 struct sockaddr_in *peer, int fd,
jjako52c24142002-12-16 13:33:51 +00002422 void *pack, unsigned len)
2423{
2424 union gtp_packet packet;
jjako08d331d2003-10-13 20:33:30 +00002425 int length = get_default_gtp(version, GTP_ERROR, &packet);
jjako52c24142002-12-16 13:33:51 +00002426
jjako08d331d2003-10-13 20:33:30 +00002427 return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
2428 get_seq(pack), get_tid(pack));
jjako52c24142002-12-16 13:33:51 +00002429}
2430
2431/* Handle Error Indication */
2432int gtp_error_ind_conf(struct gsn_t *gsn, int version,
2433 struct sockaddr_in *peer,
2434 void *pack, unsigned len) {
2435 struct pdp_t *pdp;
2436
2437 /* Find the context in question */
2438 if (pdp_tidget(&pdp, ((union gtp_packet*)pack)->gtp0.h.tid)) {
2439 gsn->err_unknownpdp++;
2440 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2441 "Unknown PDP context");
2442 return EOF;
2443 }
2444
2445 gsn->err_unknownpdp++; /* TODO: Change counter */
2446 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2447 "Received Error Indication");
2448
2449 if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
2450 pdp_freepdp(pdp);
2451 return 0;
2452}
2453
2454int gtp_gpdu_ind(struct gsn_t *gsn, int version,
jjako08d331d2003-10-13 20:33:30 +00002455 struct sockaddr_in *peer, int fd,
2456 void *pack, unsigned len) {
2457
2458 int hlen = GTP1_HEADER_SIZE_SHORT;
jjako52c24142002-12-16 13:33:51 +00002459
2460 /* Need to include code to verify packet src and dest addresses */
2461 struct pdp_t *pdp;
jjako1db1c812003-07-06 20:53:57 +00002462
jjako08d331d2003-10-13 20:33:30 +00002463 if (version == 0) {
2464 if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) {
2465 gsn->err_unknownpdp++;
2466 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2467 "Unknown PDP context");
2468 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2469 }
2470 hlen = GTP0_HEADER_SIZE;
2471 }
2472 else if (version == 1) {
2473 if (pdp_getgtp1(&pdp, ntoh32(((union gtp_packet*)pack)->gtp1l.h.tei))) {
2474 gsn->err_unknownpdp++;
2475 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2476 "Unknown PDP context");
2477 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
2478 }
2479
2480 /* Is this a long or a short header ? */
2481 if (((union gtp_packet*)pack)->gtp1l.h.flags & 0x07)
2482 hlen = GTP1_HEADER_SIZE_LONG;
2483 else
2484 hlen = GTP1_HEADER_SIZE_SHORT;
2485 }
2486 else {
2487 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2488 "Unknown version");
2489 }
2490
jjako1db1c812003-07-06 20:53:57 +00002491 /* If the GPDU was not from the peer GSN tell him to delete context */
2492 if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
2493 gsn->err_unknownpdp++;
2494 gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
2495 "Unknown PDP context");
jjako08d331d2003-10-13 20:33:30 +00002496 return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
jjako1db1c812003-07-06 20:53:57 +00002497 }
jjako08d331d2003-10-13 20:33:30 +00002498
jjako52c24142002-12-16 13:33:51 +00002499 /* Callback function */
jjako08d331d2003-10-13 20:33:30 +00002500 if (gsn->cb_data_ind !=0)
2501 return gsn->cb_data_ind(pdp, pack+hlen, len-hlen);
jjako52c24142002-12-16 13:33:51 +00002502
2503 return 0;
2504}
2505
2506
jjako08d331d2003-10-13 20:33:30 +00002507
jjako52c24142002-12-16 13:33:51 +00002508/* Receives GTP packet and sends off for further processing
2509 * Function will check the validity of the header. If the header
2510 * is not valid the packet is either dropped or a version not
2511 * supported is returned to the peer.
2512 * TODO: Need to decide on return values! */
jjako08d331d2003-10-13 20:33:30 +00002513int gtp_decaps0(struct gsn_t *gsn)
jjako52c24142002-12-16 13:33:51 +00002514{
jjako2c381332003-10-21 19:09:53 +00002515 unsigned char buffer[PACKET_MAX];
jjako52c24142002-12-16 13:33:51 +00002516 struct sockaddr_in peer;
2517 int peerlen;
jjako08d331d2003-10-13 20:33:30 +00002518 int status;
jjako52c24142002-12-16 13:33:51 +00002519 struct gtp0_header *pheader;
2520 int version = 0; /* GTP version should be determined from header!*/
jjako08d331d2003-10-13 20:33:30 +00002521 int fd = gsn->fd0;
jjako52c24142002-12-16 13:33:51 +00002522
jjakoa7cd2492003-04-11 09:40:12 +00002523 /* TODO: Need strategy of userspace buffering and blocking */
2524 /* Currently read is non-blocking and send is blocking. */
2525 /* This means that the program have to wait for busy send calls...*/
jjako52c24142002-12-16 13:33:51 +00002526
jjakoa7cd2492003-04-11 09:40:12 +00002527 while (1) { /* Loop until no more to read */
jjako08d331d2003-10-13 20:33:30 +00002528 if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) {
jjakoa7cd2492003-04-11 09:40:12 +00002529 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2530 return -1;
2531 }
2532 peerlen = sizeof(peer);
2533 if ((status =
jjako08d331d2003-10-13 20:33:30 +00002534 recvfrom(gsn->fd0, buffer, sizeof(buffer), 0,
jjakoa7cd2492003-04-11 09:40:12 +00002535 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
jjako08d331d2003-10-13 20:33:30 +00002536 if (errno == EAGAIN) return 0;
jjakoa7cd2492003-04-11 09:40:12 +00002537 gsn->err_readfrom++;
jjako08d331d2003-10-13 20:33:30 +00002538 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 +00002539 return -1;
2540 }
jjako52c24142002-12-16 13:33:51 +00002541
jjakoa7cd2492003-04-11 09:40:12 +00002542 /* Need at least 1 byte in order to check version */
2543 if (status < (1)) {
2544 gsn->empty++;
2545 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2546 "Discarding packet - too small");
2547 continue;
2548 }
2549
jjako08d331d2003-10-13 20:33:30 +00002550 pheader = (struct gtp0_header *) (buffer);
jjakoa7cd2492003-04-11 09:40:12 +00002551
jjako08d331d2003-10-13 20:33:30 +00002552 /* Version should be gtp0 (or earlier) */
2553 /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
2554 /* GTP 0 messages. If other version message is received we reply that we */
2555 /* only support version 0, implying that this is the only version */
2556 /* supported on this port */
jjakoa7cd2492003-04-11 09:40:12 +00002557 if (((pheader->flags & 0xe0) > 0x00)) {
2558 gsn->unsup++;
2559 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2560 "Unsupported GTP version");
jjako08d331d2003-10-13 20:33:30 +00002561 gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */
jjakoa7cd2492003-04-11 09:40:12 +00002562 continue;
2563 }
2564
2565 /* Check length of gtp0 packet */
jjako08d331d2003-10-13 20:33:30 +00002566 if (status < GTP0_HEADER_SIZE) {
jjakoa7cd2492003-04-11 09:40:12 +00002567 gsn->tooshort++;
2568 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2569 "GTP0 packet too short");
2570 continue; /* Silently discard 29.60: 11.1.2 */
2571 }
jjako1db1c812003-07-06 20:53:57 +00002572
jjako08d331d2003-10-13 20:33:30 +00002573 /* Check packet length field versus length of packet */
2574 if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
2575 gsn->tooshort++;
2576 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2577 "GTP packet length field does not match actual length");
2578 continue; /* Silently discard */
2579 }
2580
2581 if ((gsn->mode == GTP_MODE_GGSN) &&
2582 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2583 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2584 (pheader->type == GTP_DELETE_PDP_RSP))) {
2585 gsn->unexpect++;
2586 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2587 "Unexpected GTP Signalling Message");
2588 continue; /* Silently discard 29.60: 11.1.4 */
2589 }
2590
2591 if ((gsn->mode == GTP_MODE_SGSN) &&
2592 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2593 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2594 (pheader->type == GTP_DELETE_PDP_REQ))) {
2595 gsn->unexpect++;
2596 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2597 "Unexpected GTP Signalling Message");
2598 continue; /* Silently discard 29.60: 11.1.4 */
2599 }
2600
2601 switch (pheader->type) {
2602 case GTP_ECHO_REQ:
2603 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2604 break;
2605 case GTP_ECHO_RSP:
2606 gtp_echo_conf(gsn, version, &peer, buffer, status);
2607 break;
2608 case GTP_NOT_SUPPORTED:
2609 gtp_unsup_ind(gsn, &peer, buffer, status);
2610 break;
2611 case GTP_CREATE_PDP_REQ:
2612 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status);
2613 break;
2614 case GTP_CREATE_PDP_RSP:
2615 gtp_create_pdp_conf(gsn, version, &peer, buffer, status);
2616 break;
2617 case GTP_UPDATE_PDP_REQ:
2618 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status);
2619 break;
2620 case GTP_UPDATE_PDP_RSP:
2621 gtp_update_pdp_conf(gsn, version, &peer, buffer, status);
2622 break;
2623 case GTP_DELETE_PDP_REQ:
2624 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status);
2625 break;
2626 case GTP_DELETE_PDP_RSP:
2627 gtp_delete_pdp_conf(gsn, version, &peer, buffer, status);
2628 break;
2629 case GTP_ERROR:
2630 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2631 break;
2632 case GTP_GPDU:
2633 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2634 break;
2635 default:
2636 gsn->unknown++;
2637 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2638 "Unknown GTP message type received");
2639 break;
2640 }
2641 }
2642}
2643
2644
2645int gtp_decaps1c(struct gsn_t *gsn)
2646{
jjako2c381332003-10-21 19:09:53 +00002647 unsigned char buffer[PACKET_MAX];
jjako08d331d2003-10-13 20:33:30 +00002648 struct sockaddr_in peer;
2649 int peerlen;
2650 int status;
2651 struct gtp1_header_short *pheader;
jjako2c381332003-10-21 19:09:53 +00002652 int version = 1; /* TODO GTP version should be determined from header!*/
jjako08d331d2003-10-13 20:33:30 +00002653 int fd = gsn->fd1c;
2654
2655 /* TODO: Need strategy of userspace buffering and blocking */
2656 /* Currently read is non-blocking and send is blocking. */
2657 /* This means that the program have to wait for busy send calls...*/
2658
2659 while (1) { /* Loop until no more to read */
jjako2c381332003-10-21 19:09:53 +00002660 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
jjako08d331d2003-10-13 20:33:30 +00002661 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2662 return -1;
2663 }
2664 peerlen = sizeof(peer);
2665 if ((status =
jjako2c381332003-10-21 19:09:53 +00002666 recvfrom(fd, buffer, sizeof(buffer), 0,
jjako08d331d2003-10-13 20:33:30 +00002667 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
2668 if (errno == EAGAIN) return 0;
2669 gsn->err_readfrom++;
jjako2c381332003-10-21 19:09:53 +00002670 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 +00002671 return -1;
2672 }
2673
2674 /* Need at least 1 byte in order to check version */
2675 if (status < (1)) {
2676 gsn->empty++;
2677 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2678 "Discarding packet - too small");
2679 continue;
2680 }
2681
2682 pheader = (struct gtp1_header_short *) (buffer);
2683
2684 /* Version must be no larger than GTP 1 */
2685 if (((pheader->flags & 0xe0) > 0x20)) {
2686 gsn->unsup++;
2687 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2688 "Unsupported GTP version");
jjako2c381332003-10-21 19:09:53 +00002689 gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
2690 /*29.60: 11.1.1*/
jjako08d331d2003-10-13 20:33:30 +00002691 continue;
2692 }
2693
2694 /* Version must be at least GTP 1 */
2695 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2696 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2697 /* the message */
2698 if (((pheader->flags & 0xe0) < 0x20)) {
2699 gsn->unsup++;
2700 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2701 "Unsupported GTP version");
2702 continue;
2703 }
2704
2705 /* Check packet flag field */
2706 if (((pheader->flags & 0xf7) != 0x32)) {
2707 gsn->unsup++;
2708 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2709 "Unsupported packet flag");
2710 continue;
2711 }
2712
2713 /* Check length of packet */
2714 if (status < GTP1_HEADER_SIZE_LONG) {
2715 gsn->tooshort++;
2716 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2717 "GTP packet too short");
2718 continue; /* Silently discard 29.60: 11.1.2 */
2719 }
2720
2721 /* Check packet length field versus length of packet */
2722 if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
2723 gsn->tooshort++;
2724 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2725 "GTP packet length field does not match actual length");
2726 continue; /* Silently discard */
2727 }
2728
jjako2c381332003-10-21 19:09:53 +00002729 /* Check for extension headers */
2730 /* TODO: We really should cycle through the headers and determine */
2731 /* if any have the comprehension required flag set */
2732 if (((pheader->flags & 0x04) != 0x00)) {
2733 gsn->unsup++;
2734 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2735 "Unsupported extension header");
2736 gtp_extheader_req(gsn, version, &peer, fd, buffer, status);
2737
2738 continue;
2739 }
2740
jjako1db1c812003-07-06 20:53:57 +00002741 if ((gsn->mode == GTP_MODE_GGSN) &&
2742 ((pheader->type == GTP_CREATE_PDP_RSP) ||
2743 (pheader->type == GTP_UPDATE_PDP_RSP) ||
2744 (pheader->type == GTP_DELETE_PDP_RSP))) {
2745 gsn->unexpect++;
2746 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2747 "Unexpected GTP Signalling Message");
2748 continue; /* Silently discard 29.60: 11.1.4 */
2749 }
2750
2751 if ((gsn->mode == GTP_MODE_SGSN) &&
2752 ((pheader->type == GTP_CREATE_PDP_REQ) ||
2753 (pheader->type == GTP_UPDATE_PDP_REQ) ||
2754 (pheader->type == GTP_DELETE_PDP_REQ))) {
2755 gsn->unexpect++;
2756 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2757 "Unexpected GTP Signalling Message");
2758 continue; /* Silently discard 29.60: 11.1.4 */
2759 }
2760
jjakoa7cd2492003-04-11 09:40:12 +00002761 switch (pheader->type) {
2762 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +00002763 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002764 break;
2765 case GTP_ECHO_RSP:
jjako08d331d2003-10-13 20:33:30 +00002766 gtp_echo_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002767 break;
2768 case GTP_NOT_SUPPORTED:
jjako08d331d2003-10-13 20:33:30 +00002769 gtp_unsup_ind(gsn, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002770 break;
jjako2c381332003-10-21 19:09:53 +00002771 case GTP_SUPP_EXT_HEADER:
2772 gtp_extheader_ind(gsn, &peer, buffer, status);
2773 break;
jjakoa7cd2492003-04-11 09:40:12 +00002774 case GTP_CREATE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002775 gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002776 break;
2777 case GTP_CREATE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002778 gtp_create_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002779 break;
2780 case GTP_UPDATE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002781 gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002782 break;
2783 case GTP_UPDATE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002784 gtp_update_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002785 break;
2786 case GTP_DELETE_PDP_REQ:
jjako08d331d2003-10-13 20:33:30 +00002787 gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002788 break;
2789 case GTP_DELETE_PDP_RSP:
jjako08d331d2003-10-13 20:33:30 +00002790 gtp_delete_pdp_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002791 break;
2792 case GTP_ERROR:
jjako08d331d2003-10-13 20:33:30 +00002793 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
jjakoa7cd2492003-04-11 09:40:12 +00002794 break;
2795 default:
jjako52c24142002-12-16 13:33:51 +00002796 gsn->unknown++;
2797 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2798 "Unknown GTP message type received");
jjakoa7cd2492003-04-11 09:40:12 +00002799 break;
jjako52c24142002-12-16 13:33:51 +00002800 }
2801 }
2802}
2803
jjako08d331d2003-10-13 20:33:30 +00002804int gtp_decaps1u(struct gsn_t *gsn)
2805{
jjako2c381332003-10-21 19:09:53 +00002806 unsigned char buffer[PACKET_MAX];
jjako08d331d2003-10-13 20:33:30 +00002807 struct sockaddr_in peer;
2808 int peerlen;
2809 int status;
2810 struct gtp1_header_short *pheader;
2811 int version = 1; /* GTP version should be determined from header!*/
2812 int fd = gsn->fd1u;
2813
2814 /* TODO: Need strategy of userspace buffering and blocking */
2815 /* Currently read is non-blocking and send is blocking. */
2816 /* This means that the program have to wait for busy send calls...*/
2817
2818 while (1) { /* Loop until no more to read */
2819 if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) {
2820 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2821 return -1;
2822 }
2823 peerlen = sizeof(peer);
2824 if ((status =
2825 recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0,
2826 (struct sockaddr *) &peer, &peerlen)) < 0 ) {
2827 if (errno == EAGAIN) return 0;
2828 gsn->err_readfrom++;
2829 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");
2830 return -1;
2831 }
2832
2833 /* Need at least 1 byte in order to check version */
2834 if (status < (1)) {
2835 gsn->empty++;
2836 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2837 "Discarding packet - too small");
2838 continue;
2839 }
2840
2841 pheader = (struct gtp1_header_short *) (buffer);
2842
2843 /* Version must be no larger than GTP 1 */
2844 if (((pheader->flags & 0xe0) > 0x20)) {
2845 gsn->unsup++;
2846 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2847 "Unsupported GTP version");
2848 gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status);/*29.60: 11.1.1*/
2849 continue;
2850 }
2851
2852 /* Version must be at least GTP 1 */
2853 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2854 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2855 /* the message */
2856 if (((pheader->flags & 0xe0) < 0x20)) {
2857 gsn->unsup++;
2858 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2859 "Unsupported GTP version");
2860 continue;
2861 }
2862
2863 /* Check packet flag field (allow both with and without sequence number)*/
2864 if (((pheader->flags & 0xf5) != 0x30)) {
2865 gsn->unsup++;
2866 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2867 "Unsupported packet flag");
2868 continue;
2869 }
2870
2871 /* Check length of packet */
2872 if (status < GTP1_HEADER_SIZE_SHORT) {
2873 gsn->tooshort++;
2874 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2875 "GTP packet too short");
2876 continue; /* Silently discard 29.60: 11.1.2 */
2877 }
2878
2879 /* Check packet length field versus length of packet */
2880 if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
2881 gsn->tooshort++;
2882 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2883 "GTP packet length field does not match actual length");
2884 continue; /* Silently discard */
2885 }
jjako2c381332003-10-21 19:09:53 +00002886
2887 /* Check for extension headers */
2888 /* TODO: We really should cycle through the headers and determine */
2889 /* if any have the comprehension required flag set */
2890 if (((pheader->flags & 0x04) != 0x00)) {
2891 gsn->unsup++;
2892 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2893 "Unsupported extension header");
2894 gtp_extheader_req(gsn, version, &peer, fd, buffer, status);
2895
2896 continue;
2897 }
jjako08d331d2003-10-13 20:33:30 +00002898
2899 switch (pheader->type) {
2900 case GTP_ECHO_REQ:
2901 gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
2902 break;
2903 case GTP_ECHO_RSP:
2904 gtp_echo_conf(gsn, version, &peer, buffer, status);
2905 break;
jjako2c381332003-10-21 19:09:53 +00002906 case GTP_SUPP_EXT_HEADER:
2907 gtp_extheader_ind(gsn, &peer, buffer, status);
2908 break;
jjako08d331d2003-10-13 20:33:30 +00002909 case GTP_ERROR:
2910 gtp_error_ind_conf(gsn, version, &peer, buffer, status);
2911 break;
2912 /* Supported header extensions */
2913 case GTP_GPDU:
2914 gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
2915 break;
2916 default:
2917 gsn->unknown++;
2918 gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
2919 "Unknown GTP message type received");
2920 break;
2921 }
2922 }
2923}
2924
2925int gtp_data_req(struct gsn_t *gsn, struct pdp_t* pdp,
jjako52c24142002-12-16 13:33:51 +00002926 void *pack, unsigned len)
2927{
2928 union gtp_packet packet;
2929 struct sockaddr_in addr;
jjako08d331d2003-10-13 20:33:30 +00002930 int fd;
2931 int length;
jjako52c24142002-12-16 13:33:51 +00002932
2933 memset(&addr, 0, sizeof(addr));
2934 addr.sin_family = AF_INET;
jjako52c24142002-12-16 13:33:51 +00002935 memcpy(&addr.sin_addr, pdp->gsnru.v,pdp->gsnru.l); /* TODO range check */
jjako52c24142002-12-16 13:33:51 +00002936
jjako08d331d2003-10-13 20:33:30 +00002937 if (pdp->version == 0) {
2938
2939 length = GTP0_HEADER_SIZE+len;
2940 addr.sin_port = htons(GTP0_PORT);
2941 fd = gsn->fd0;
2942
2943 get_default_gtp(0, GTP_GPDU, &packet);
2944 packet.gtp0.h.length = hton16(len);
2945 packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
2946 packet.gtp0.h.flow = hton16(pdp->flru);
2947 packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffff) + ((uint64_t)pdp->nsapi << 60);
jjako52c24142002-12-16 13:33:51 +00002948
jjako08d331d2003-10-13 20:33:30 +00002949 if (len > sizeof (union gtp_packet) - sizeof(struct gtp0_header)) {
2950 gsn->err_memcpy++;
2951 gtp_err(LOG_ERR, __FILE__, __LINE__,
2952 "Memcpy failed");
2953 return EOF;
jjako52c24142002-12-16 13:33:51 +00002954 }
jjako08d331d2003-10-13 20:33:30 +00002955 memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */
2956 }
2957 else if (pdp->version == 1) {
2958
2959 length = GTP1_HEADER_SIZE_LONG+len;
2960 addr.sin_port = htons(GTP1U_PORT);
2961 fd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00002962
jjako08d331d2003-10-13 20:33:30 +00002963 get_default_gtp(1, GTP_GPDU, &packet);
2964 packet.gtp1l.h.length = hton16(len-GTP1_HEADER_SIZE_SHORT+
2965 GTP1_HEADER_SIZE_LONG);
2966 packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
jjako2c381332003-10-21 19:09:53 +00002967 packet.gtp1l.h.tei = hton32(pdp->teid_gn);
jjako08d331d2003-10-13 20:33:30 +00002968
2969 if (len > sizeof (union gtp_packet) - sizeof(struct gtp1_header_long)) {
2970 gsn->err_memcpy++;
2971 gtp_err(LOG_ERR, __FILE__, __LINE__,
2972 "Memcpy failed");
2973 return EOF;
2974 }
2975 memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */
2976 }
2977 else {
2978 gtp_err(LOG_ERR, __FILE__, __LINE__,
2979 "Unknown version");
2980 return EOF;
2981 }
2982
2983 if (fcntl(fd, F_SETFL, 0)) {
jjakoa7cd2492003-04-11 09:40:12 +00002984 gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
2985 return -1;
2986 }
2987
jjako08d331d2003-10-13 20:33:30 +00002988 if (sendto(fd, &packet, length, 0,
jjako52c24142002-12-16 13:33:51 +00002989 (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2990 gsn->err_sendto++;
jjako08d331d2003-10-13 20:33:30 +00002991 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 +00002992 return EOF;
2993 }
2994 return 0;
2995}
2996
2997
2998/* ***********************************************************
2999 * Conversion functions
3000 *************************************************************/
3001
3002int char2ul_t(char* src, struct ul_t dst) {
3003 dst.l = strlen(src)+1;
3004 dst.v = malloc(dst.l);
3005 dst.v[0] = dst.l - 1;
3006 memcpy(&dst.v[1], src, dst.v[0]);
3007 return 0;
3008}
3009
3010/* ***********************************************************
3011 * IP address conversion functions
3012 * There exist several types of address representations:
3013 * - eua: End User Address. (29.060, 7.7.27, message type 128)
3014 * Used for signalling address to mobile station. Supports IPv4
3015 * IPv6 x.25 etc. etc.
3016 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
3017 * of GSN. If length is 4 it is IPv4. If length is 16 it is IPv6.
3018 * - in_addr: IPv4 address struct.
3019 * - sockaddr_in: Socket API representation of IP address and
3020 * port number.
3021 *************************************************************/
3022
3023int ipv42eua(struct ul66_t *eua, struct in_addr *src) {
3024 eua->v[0] = 0xf1; /* IETF */
3025 eua->v[1] = 0x21; /* IPv4 */
3026 if (src) {
3027 eua->l = 6;
3028 memcpy(&eua->v[2], src, 4);
3029 }
3030 else
3031 {
3032 eua->l = 2;
3033 }
3034 return 0;
3035}
3036
3037int eua2ipv4(struct in_addr *dst, struct ul66_t *eua) {
3038 if ((eua->l != 6) ||
3039 (eua->v[0] != 0xf1) ||
3040 (eua->v[1] = 0x21))
3041 return -1; /* Not IPv4 address*/
3042 memcpy(dst, &eua->v[2], 4);
3043 return 0;
3044}
3045
3046int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna) {
3047 memset(dst, 0, sizeof(struct in_addr));
3048 if (gsna->l != 4) return EOF; /* Return if not IPv4 */
3049 memcpy(dst, gsna->v, gsna->l);
3050 return 0;
3051}
3052
3053int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src) {
3054 memset(gsna, 0, sizeof(struct ul16_t));
3055 gsna->l = 4;
3056 memcpy(gsna->v, src, gsna->l);
3057 return 0;
3058}
3059