2 * OpenGGSN - Gateway GPRS Support Node
3 * Copyright (C) 2002, 2003, 2004 Mondru AB.
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.
13 * gtp.c: Contains all GTP functionality. Should be able to handle multiple
14 * tunnels in the same program.
17 * - Do we need to handle fragmentation?
24 #include <osmocom/core/logging.h>
25 #include <osmocom/core/utils.h>
27 #if defined(__FreeBSD__)
28 #include <sys/endian.h>
31 #include "../config.h"
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
52 #include <arpa/inet.h>
54 /* #include <stdint.h> ISO C99 types */
61 /* According to section 14.2 of 3GPP TS 29.006 version 6.9.0 */
66 /* Error reporting functions */
68 #define GTP_LOGPKG(pri, peer, pack, len, fmt, args...) \
69 logp2(DLGTP, pri, __FILE__, __LINE__, 0, \
70 "Packet from %s:%u, length: %d content: %s: " fmt, \
71 inet_ntoa((peer)->sin_addr), htons((peer)->sin_port), \
72 len, osmo_hexdump((const uint8_t *) pack, len), \
75 #define LOGP_WITH_ADDR(ss, level, addr, fmt, args...) \
76 LOGP(ss, level, "addr(%s:%d) " fmt, \
77 inet_ntoa((addr).sin_addr), htons((addr).sin_port), \
82 const char *gtp_version()
90 int gtp_newpdp(struct gsn_t
*gsn
, struct pdp_t
**pdp
,
91 uint64_t imsi
, uint8_t nsapi
)
93 return pdp_newpdp(pdp
, imsi
, nsapi
, NULL
);
96 int gtp_freepdp(struct gsn_t
*gsn
, struct pdp_t
*pdp
)
98 return pdp_freepdp(pdp
);
103 extern int gtp_fd(struct gsn_t
*gsn
)
110 /* gtp_retranstimeout */
112 int gtp_set_cb_unsup_ind(struct gsn_t
*gsn
,
113 int (*cb
) (struct sockaddr_in
* peer
))
115 gsn
->cb_unsup_ind
= cb
;
119 int gtp_set_cb_extheader_ind(struct gsn_t
*gsn
,
120 int (*cb
) (struct sockaddr_in
* peer
))
122 gsn
->cb_extheader_ind
= cb
;
126 /* API: Initialise delete context callback */
127 /* Called whenever a pdp context is deleted for any reason */
128 int gtp_set_cb_delete_context(struct gsn_t
*gsn
, int (*cb
) (struct pdp_t
* pdp
))
130 gsn
->cb_delete_context
= cb
;
134 int gtp_set_cb_conf(struct gsn_t
*gsn
,
135 int (*cb
) (int type
, int cause
,
136 struct pdp_t
* pdp
, void *cbp
))
142 int gtp_set_cb_recovery(struct gsn_t
*gsn
,
143 int (*cb
) (struct sockaddr_in
* peer
, uint8_t recovery
))
145 gsn
->cb_recovery
= cb
;
149 extern int gtp_set_cb_data_ind(struct gsn_t
*gsn
,
150 int (*cb_data_ind
) (struct pdp_t
* pdp
,
151 void *pack
, unsigned len
))
153 gsn
->cb_data_ind
= cb_data_ind
;
159 * Generate a GPRS Tunneling Protocol signalling packet header, depending
160 * on GTP version and message type. pdp is used for teid/flow label.
161 * *packet must be allocated by the calling function, and be large enough
162 * to hold the packet header.
163 * returns the length of the header. 0 on error.
165 static unsigned int get_default_gtp(int version
, uint8_t type
, void *packet
)
167 struct gtp0_header
*gtp0_default
= (struct gtp0_header
*)packet
;
168 struct gtp1_header_long
*gtp1_default
=
169 (struct gtp1_header_long
*)packet
;
172 /* Initialise "standard" GTP0 header */
173 memset(gtp0_default
, 0, sizeof(struct gtp0_header
));
174 gtp0_default
->flags
= 0x1e;
175 gtp0_default
->type
= hton8(type
);
176 gtp0_default
->spare1
= 0xff;
177 gtp0_default
->spare2
= 0xff;
178 gtp0_default
->spare3
= 0xff;
179 gtp0_default
->number
= 0xff;
180 return GTP0_HEADER_SIZE
;
182 /* Initialise "standard" GTP1 header */
183 /* 29.060: 8.2: S=1 and PN=0 */
184 /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */
185 /* and Supported Extension Headers Notification, the S field shall be */
187 /* Currently extension headers are not supported */
188 memset(gtp1_default
, 0, sizeof(struct gtp1_header_long
));
189 gtp1_default
->flags
= 0x32; /* No extension, enable sequence, no N-PDU */
190 gtp1_default
->type
= hton8(type
);
191 return GTP1_HEADER_SIZE_LONG
;
193 LOGP(DLGTP
, LOGL_ERROR
,
194 "Unknown GTP packet version: %d\n", version
);
201 * Get sequence number of a packet.
204 static uint16_t get_seq(void *pack
)
206 union gtp_packet
*packet
= (union gtp_packet
*)pack
;
208 if ((packet
->flags
& 0xe0) == 0x00) { /* Version 0 */
209 return ntoh16(packet
->gtp0
.h
.seq
);
210 } else if ((packet
->flags
& 0xe2) == 0x22) { /* Version 1 with seq */
211 return ntoh16(packet
->gtp1l
.h
.seq
);
219 * Get tunnel identifier of a packet.
222 static uint64_t get_tid(void *pack
)
224 union gtp_packet
*packet
= (union gtp_packet
*)pack
;
226 if ((packet
->flags
& 0xe0) == 0x00) { /* Version 0 */
227 return be64toh(packet
->gtp0
.h
.tid
);
234 * Get the header length of a packet.
237 static uint16_t get_hlen(void *pack
)
239 union gtp_packet
*packet
= (union gtp_packet
*)pack
;
241 if ((packet
->flags
& 0xe0) == 0x00) { /* Version 0 */
242 return GTP0_HEADER_SIZE
;
243 } else if ((packet
->flags
& 0xe2) == 0x22) { /* Version 1 with seq */
244 return GTP1_HEADER_SIZE_LONG
;
245 } else if ((packet
->flags
& 0xe7) == 0x20) { /* Short version 1 */
246 return GTP1_HEADER_SIZE_SHORT
;
248 LOGP(DLGTP
, LOGL_ERROR
, "Unknown packet flags: 0x%02x\n", packet
->flags
);
255 * Get the tunnel endpoint identifier (flow label) of a packet.
256 * Returns 0xffffffff on error.
258 static uint32_t get_tei(void *pack
)
260 union gtp_packet
*packet
= (union gtp_packet
*)pack
;
262 if ((packet
->flags
& 0xe0) == 0x00) { /* Version 0 */
263 return ntoh16(packet
->gtp0
.h
.flow
);
264 } else if ((packet
->flags
& 0xe0) == 0x20) { /* Version 1 */
265 return ntoh32(packet
->gtp1l
.h
.tei
);
267 LOGP(DLGTP
, LOGL_ERROR
, "Unknown packet flags: 0x%02x\n", packet
->flags
);
272 /* ***********************************************************
273 * Reliable delivery of signalling messages
275 * Sequence numbers are used for both signalling messages and
278 * For data messages each tunnel maintains a sequence counter,
279 * which is incremented by one each time a new data message
280 * is sent. The sequence number starts at (0) zero at tunnel
281 * establishment, and wraps around at 65535 (29.060 9.3.1.1
282 * and 09.60 8.1.1.1). The sequence numbers are either ignored,
283 * or can be used to check the validity of the message in the
284 * receiver, or for reordering af packets.
286 * For signalling messages the sequence number is used by
287 * signalling messages for which a response is defined. A response
288 * message should copy the sequence from the corresponding request
289 * message. The sequence number "unambiguously" identifies a request
290 * message within a given path, with a path being defined as a set of
291 * two endpoints (29.060 8.2, 29.060 7.6, 09.60 7.8). "All request
292 * messages shall be responded to, and all response messages associated
293 * with a certain request shall always include the same information"
295 * We take this to mean that the GSN transmitting a request is free to
296 * choose the sequence number, as long as it is unique within a given path.
297 * It means that we are allowed to count backwards, or roll over at 17
298 * if we prefer that. It also means that we can use the same counter for
299 * all paths. This has the advantage that the transmitted request sequence
300 * numbers are unique within each GSN, and also we dont have to mess around
301 * with path setup and teardown.
303 * If a response message is lost, the request will be retransmitted, and
304 * the receiving GSN will receive a "duplicated" request. The standard
305 * requires the receiving GSN to send a response, with the same information
306 * as in the original response. For most messages this happens automatically:
308 * Echo: Automatically dublicates the original response
309 * Create pdp context: The SGSN may send create context request even if
310 * a context allready exist (imsi+nsapi?). This means that the reply will
311 automatically dublicate the original response. It might however have
312 * side effects in the application which is asked twice to validate
314 * Update pdp context: Automatically dublicates the original response???
315 * Delete pdp context. Automatically in gtp0, but in gtp1 will generate
316 * a nonexist reply message.
318 * The correct solution will be to make a queue containing response messages.
319 * This queue should be checked whenever a request is received. If the
320 * response is allready in the queue that response should be transmitted.
321 * It should be possible to find messages in this queue on the basis of
322 * the sequence number and peer GSN IP address (The sequense number is unique
323 * within each path). This need to be implemented by a hash table. Furthermore
324 * it should be possibly to delete messages based on a timeout. This can be
325 * achieved by means of a linked list. The timeout value need to be larger
326 * than T3-RESPONSE * N3-REQUESTS (recommended value 5). These timers are
327 * set in the peer GSN, so there is no way to know these parameters. On the
328 * other hand the timeout value need to be so small that we do not receive
329 * wraparound sequence numbere before the message is deleted. 60 seconds is
330 * probably not a bad choise.
332 * This queue however is first really needed from gtp1.
335 * Send off a signalling message with appropiate sequence
336 * number. Store packet in queue.
338 * Remove an incoming confirmation from the queue
340 * Send off a response to a request. Use the same sequence
341 * number in the response as in the request.
343 * Send off a notification message. This is neither a request nor
344 * a response. Both TEI and SEQ are zero.
346 * Retransmit any outstanding packets which have exceeded
347 * a predefined timeout.
348 *************************************************************/
350 int gtp_req(struct gsn_t
*gsn
, int version
, struct pdp_t
*pdp
,
351 union gtp_packet
*packet
, int len
,
352 struct in_addr
*inetaddr
, void *cbp
)
354 struct sockaddr_in addr
;
358 memset(&addr
, 0, sizeof(addr
));
359 addr
.sin_family
= AF_INET
;
360 addr
.sin_addr
= *inetaddr
;
361 #if defined(__FreeBSD__) || defined(__APPLE__)
362 addr
.sin_len
= sizeof(addr
);
365 if ((packet
->flags
& 0xe0) == 0x00) { /* Version 0 */
366 addr
.sin_port
= htons(GTP0_PORT
);
367 packet
->gtp0
.h
.length
= hton16(len
- GTP0_HEADER_SIZE
);
368 packet
->gtp0
.h
.seq
= hton16(gsn
->seq_next
);
371 htobe64(pdp_gettid(pdp
->imsi
, pdp
->nsapi
));
373 if (pdp
&& ((packet
->gtp0
.h
.type
== GTP_GPDU
)
374 || (packet
->gtp0
.h
.type
== GTP_ERROR
)))
375 packet
->gtp0
.h
.flow
= hton16(pdp
->flru
);
377 packet
->gtp0
.h
.flow
= hton16(pdp
->flrc
);
379 } else if ((packet
->flags
& 0xe2) == 0x22) { /* Version 1 with seq */
380 addr
.sin_port
= htons(GTP1C_PORT
);
381 packet
->gtp1l
.h
.length
= hton16(len
- GTP1_HEADER_SIZE_SHORT
);
382 packet
->gtp1l
.h
.seq
= hton16(gsn
->seq_next
);
383 if (pdp
&& ((packet
->gtp1l
.h
.type
== GTP_GPDU
) ||
384 (packet
->gtp1l
.h
.type
== GTP_ERROR
)))
385 packet
->gtp1l
.h
.tei
= hton32(pdp
->teid_gn
);
387 packet
->gtp1l
.h
.tei
= hton32(pdp
->teic_gn
);
390 LOGP(DLGTP
, LOGL_ERROR
, "Unknown packet flags: 0x%02x\n", packet
->flags
);
394 if (sendto(fd
, packet
, len
, 0,
395 (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
397 LOGP(DLGTP
, LOGL_ERROR
,
398 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd
,
399 (unsigned long)&packet
, len
, strerror(errno
));
403 /* Use new queue structure */
404 if (queue_newmsg(gsn
->queue_req
, &qmsg
, &addr
, gsn
->seq_next
)) {
405 gsn
->err_queuefull
++;
406 LOGP(DLGTP
, LOGL_ERROR
,
407 "Retransmit queue is full\n");
409 memcpy(&qmsg
->p
, packet
, sizeof(union gtp_packet
));
411 qmsg
->timeout
= time(NULL
) + T3_REQUEST
; /* When to timeout */
412 qmsg
->retrans
= 0; /* No retransmissions so far */
414 qmsg
->type
= ntoh8(packet
->gtp0
.h
.type
);
417 gsn
->seq_next
++; /* Count up this time */
422 * Remove signalling packet from retransmission queue.
423 * return 0 on success, EOF if packet was not found */
425 int gtp_conf(struct gsn_t
*gsn
, int version
, struct sockaddr_in
*peer
,
426 union gtp_packet
*packet
, int len
, uint8_t * type
, void **cbp
)
431 if ((packet
->gtp0
.h
.flags
& 0xe0) == 0x00)
432 seq
= ntoh16(packet
->gtp0
.h
.seq
);
433 else if ((packet
->gtp1l
.h
.flags
& 0xe2) == 0x22)
434 seq
= ntoh16(packet
->gtp1l
.h
.seq
);
436 GTP_LOGPKG(LOGL_ERROR
, peer
, packet
, len
,
437 "Unknown GTP packet version\n");
441 if (queue_freemsg_seq(gsn
->queue_req
, peer
, seq
, type
, cbp
)) {
443 GTP_LOGPKG(LOGL_ERROR
, peer
, packet
, len
,
444 "Confirmation packet not found in queue\n");
451 int gtp_retrans(struct gsn_t
*gsn
)
453 /* Retransmit any outstanding packets */
454 /* Remove from queue if maxretrans exceeded */
458 /*printf("Retrans: New beginning %d\n", (int) now); */
460 /* get first element in queue, as long as the timeout of that
461 * element has expired */
462 while ((!queue_getfirst(gsn
->queue_req
, &qmsg
)) &&
463 (qmsg
->timeout
<= now
)) {
464 /*printf("Retrans timeout found: %d\n", (int) time(NULL)); */
465 if (qmsg
->retrans
> N3_REQUESTS
) { /* To many retrans */
467 gsn
->cb_conf(qmsg
->type
, EOF
, NULL
, qmsg
->cbp
);
468 queue_freemsg(gsn
->queue_req
, qmsg
);
470 if (sendto(qmsg
->fd
, &qmsg
->p
, qmsg
->l
, 0,
471 (struct sockaddr
*)&qmsg
->peer
,
472 sizeof(struct sockaddr_in
)) < 0) {
474 LOGP(DLGTP
, LOGL_ERROR
,
475 "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s\n",
476 gsn
->fd0
, (unsigned long)&qmsg
->p
,
477 qmsg
->l
, strerror(errno
));
479 queue_back(gsn
->queue_req
, qmsg
);
480 qmsg
->timeout
= now
+ T3_REQUEST
;
485 /* Also clean up reply timeouts */
486 while ((!queue_getfirst(gsn
->queue_resp
, &qmsg
)) &&
487 (qmsg
->timeout
< now
)) {
488 /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL)); */
489 queue_freemsg(gsn
->queue_resp
, qmsg
);
495 int gtp_retranstimeout(struct gsn_t
*gsn
, struct timeval
*timeout
)
500 if (queue_getfirst(gsn
->queue_req
, &qmsg
)) {
501 timeout
->tv_sec
= 10;
502 timeout
->tv_usec
= 0;
505 later
= qmsg
->timeout
;
506 timeout
->tv_sec
= later
- now
;
507 timeout
->tv_usec
= 0;
508 if (timeout
->tv_sec
< 0)
509 timeout
->tv_sec
= 0; /* No negative allowed */
510 if (timeout
->tv_sec
> 10)
511 timeout
->tv_sec
= 10; /* Max sleep for 10 sec */
516 int gtp_resp(int version
, struct gsn_t
*gsn
, struct pdp_t
*pdp
,
517 union gtp_packet
*packet
, int len
,
518 struct sockaddr_in
*peer
, int fd
, uint16_t seq
, uint64_t tid
)
522 if ((packet
->flags
& 0xe0) == 0x00) { /* Version 0 */
523 packet
->gtp0
.h
.length
= hton16(len
- GTP0_HEADER_SIZE
);
524 packet
->gtp0
.h
.seq
= hton16(seq
);
525 packet
->gtp0
.h
.tid
= htobe64(tid
);
526 if (pdp
&& ((packet
->gtp0
.h
.type
== GTP_GPDU
) ||
527 (packet
->gtp0
.h
.type
== GTP_ERROR
)))
528 packet
->gtp0
.h
.flow
= hton16(pdp
->flru
);
530 packet
->gtp0
.h
.flow
= hton16(pdp
->flrc
);
531 } else if ((packet
->flags
& 0xe2) == 0x22) { /* Version 1 with seq */
532 packet
->gtp1l
.h
.length
= hton16(len
- GTP1_HEADER_SIZE_SHORT
);
533 packet
->gtp1l
.h
.seq
= hton16(seq
);
534 if (pdp
&& (fd
== gsn
->fd1u
))
535 packet
->gtp1l
.h
.tei
= hton32(pdp
->teid_gn
);
537 packet
->gtp1l
.h
.tei
= hton32(pdp
->teic_gn
);
539 LOGP(DLGTP
, LOGL_ERROR
, "Unknown packet flags: 0x%02x\n", packet
->flags
);
543 if (fcntl(fd
, F_SETFL
, 0)) {
544 LOGP(DLGTP
, LOGL_ERROR
, "fnctl()\n");
548 if (sendto(fd
, packet
, len
, 0,
549 (struct sockaddr
*)peer
, sizeof(struct sockaddr_in
)) < 0) {
551 LOGP(DLGTP
, LOGL_ERROR
,
552 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd
,
553 (unsigned long)&packet
, len
, strerror(errno
));
557 /* Use new queue structure */
558 if (queue_newmsg(gsn
->queue_resp
, &qmsg
, peer
, seq
)) {
559 gsn
->err_queuefull
++;
560 LOGP(DLGTP
, LOGL_ERROR
, "Retransmit queue is full\n");
562 memcpy(&qmsg
->p
, packet
, sizeof(union gtp_packet
));
564 qmsg
->timeout
= time(NULL
) + 60; /* When to timeout */
565 qmsg
->retrans
= 0; /* No retransmissions so far */
573 int gtp_notification(struct gsn_t
*gsn
, int version
,
574 union gtp_packet
*packet
, int len
,
575 struct sockaddr_in
*peer
, int fd
, uint16_t seq
)
578 struct sockaddr_in addr
;
580 memcpy(&addr
, peer
, sizeof(addr
));
582 /* In GTP0 notifications are treated as replies. In GTP1 they
583 are requests for which there is no reply */
586 addr
.sin_port
= htons(GTP1C_PORT
);
587 else if (fd
== gsn
->fd1u
)
588 addr
.sin_port
= htons(GTP1C_PORT
);
590 if ((packet
->flags
& 0xe0) == 0x00) { /* Version 0 */
591 packet
->gtp0
.h
.length
= hton16(len
- GTP0_HEADER_SIZE
);
592 packet
->gtp0
.h
.seq
= hton16(seq
);
593 } else if ((packet
->flags
& 0xe2) == 0x22) { /* Version 1 with seq */
594 packet
->gtp1l
.h
.length
= hton16(len
- GTP1_HEADER_SIZE_SHORT
);
595 packet
->gtp1l
.h
.seq
= hton16(seq
);
597 LOGP(DLGTP
, LOGL_ERROR
, "Unknown packet flags: 0x%02x\n", packet
->flags
);
601 if (fcntl(fd
, F_SETFL
, 0)) {
602 LOGP(DLGTP
, LOGL_ERROR
, "fnctl()\n");
606 if (sendto(fd
, packet
, len
, 0,
607 (struct sockaddr
*)&addr
, sizeof(struct sockaddr_in
)) < 0) {
609 LOGP(DLGTP
, LOGL_ERROR
,
610 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd
,
611 (unsigned long)&packet
, len
, strerror(errno
));
617 int gtp_dublicate(struct gsn_t
*gsn
, int version
,
618 struct sockaddr_in
*peer
, uint16_t seq
)
622 if (queue_seqget(gsn
->queue_resp
, &qmsg
, peer
, seq
)) {
623 return EOF
; /* Notfound */
626 if (fcntl(qmsg
->fd
, F_SETFL
, 0)) {
627 LOGP(DLGTP
, LOGL_ERROR
, "fnctl()\n");
631 if (sendto(qmsg
->fd
, &qmsg
->p
, qmsg
->l
, 0,
632 (struct sockaddr
*)peer
, sizeof(struct sockaddr_in
)) < 0) {
634 LOGP(DLGTP
, LOGL_ERROR
,
635 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n",
636 qmsg
->fd
, (unsigned long)&qmsg
->p
, qmsg
->l
,
642 /* Perform restoration and recovery error handling as described in 29.060 */
643 static void log_restart(struct gsn_t
*gsn
)
650 filename
= talloc_asprintf(NULL
, "%s/%s", gsn
->statedir
, RESTART_FILE
);
651 OSMO_ASSERT(filename
);
653 /* We try to open file. On failure we will later try to create file */
654 if (!(f
= fopen(filename
, "r"))) {
655 LOGP(DLGTP
, LOGL_NOTICE
,
656 "State information file (%s) not found. Creating new file.\n",
659 rc
= fscanf(f
, "%d", &counter
);
661 LOGP(DLGTP
, LOGL_ERROR
,
662 "fscanf failed to read counter value\n");
666 LOGP(DLGTP
, LOGL_ERROR
,
667 "fclose failed: Error = %s\n", strerror(errno
));
671 gsn
->restart_counter
= (unsigned char)counter
;
672 gsn
->restart_counter
++;
674 /* Keep the umask closely wrapped around our fopen() call in case the
675 * log outputs cause file creation. */
677 f
= fopen(filename
, "w");
680 LOGP(DLGTP
, LOGL_ERROR
,
681 "fopen(path=%s, mode=%s) failed: Error = %s\n", filename
,
682 "w", strerror(errno
));
686 fprintf(f
, "%d\n", gsn
->restart_counter
);
689 LOGP(DLGTP
, LOGL_ERROR
,
690 "fclose failed: Error = %s\n", strerror(errno
));
692 talloc_free(filename
);
695 int gtp_new(struct gsn_t
**gsn
, char *statedir
, struct in_addr
*listen
,
698 struct sockaddr_in addr
;
700 LOGP(DLGTP
, LOGL_NOTICE
, "GTP: gtp_newgsn() started\n");
702 *gsn
= calloc(sizeof(struct gsn_t
), 1); /* TODO */
704 (*gsn
)->statedir
= statedir
;
707 /* Initialise sequence number */
708 (*gsn
)->seq_next
= (*gsn
)->restart_counter
* 1024;
710 /* Initialise request retransmit queue */
711 queue_new(&(*gsn
)->queue_req
);
712 queue_new(&(*gsn
)->queue_resp
);
714 /* Initialise pdp table */
717 /* Initialise call back functions */
718 (*gsn
)->cb_create_context_ind
= 0;
719 (*gsn
)->cb_delete_context
= 0;
720 (*gsn
)->cb_unsup_ind
= 0;
722 (*gsn
)->cb_data_ind
= 0;
724 /* Store function parameters */
725 (*gsn
)->gsnc
= *listen
;
726 (*gsn
)->gsnu
= *listen
;
729 /* Create GTP version 0 socket */
730 if (((*gsn
)->fd0
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
731 (*gsn
)->err_socket
++;
732 LOGP(DLGTP
, LOGL_ERROR
,
733 "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
734 AF_INET
, SOCK_DGRAM
, 0, strerror(errno
));
738 memset(&addr
, 0, sizeof(addr
));
739 addr
.sin_family
= AF_INET
;
740 addr
.sin_addr
= *listen
; /* Same IP for user traffic and signalling */
741 addr
.sin_port
= htons(GTP0_PORT
);
742 #if defined(__FreeBSD__) || defined(__APPLE__)
743 addr
.sin_len
= sizeof(addr
);
746 if (bind((*gsn
)->fd0
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
747 (*gsn
)->err_socket
++;
748 LOGP_WITH_ADDR(DLGTP
, LOGL_ERROR
, addr
,
749 "bind(fd0=%d) failed: Error = %s\n",
750 (*gsn
)->fd0
, strerror(errno
));
754 /* Create GTP version 1 control plane socket */
755 if (((*gsn
)->fd1c
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
756 (*gsn
)->err_socket
++;
757 LOGP(DLGTP
, LOGL_ERROR
,
758 "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
759 AF_INET
, SOCK_DGRAM
, 0, strerror(errno
));
763 memset(&addr
, 0, sizeof(addr
));
764 addr
.sin_family
= AF_INET
;
765 addr
.sin_addr
= *listen
; /* Same IP for user traffic and signalling */
766 addr
.sin_port
= htons(GTP1C_PORT
);
767 #if defined(__FreeBSD__) || defined(__APPLE__)
768 addr
.sin_len
= sizeof(addr
);
771 if (bind((*gsn
)->fd1c
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
772 (*gsn
)->err_socket
++;
773 LOGP_WITH_ADDR(DLGTP
, LOGL_ERROR
, addr
,
774 "bind(fd1c=%d) failed: Error = %s\n",
775 (*gsn
)->fd1c
, strerror(errno
));
779 /* Create GTP version 1 user plane socket */
780 if (((*gsn
)->fd1u
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
781 (*gsn
)->err_socket
++;
782 LOGP(DLGTP
, LOGL_ERROR
,
783 "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
784 AF_INET
, SOCK_DGRAM
, 0, strerror(errno
));
788 memset(&addr
, 0, sizeof(addr
));
789 addr
.sin_family
= AF_INET
;
790 addr
.sin_addr
= *listen
; /* Same IP for user traffic and signalling */
791 addr
.sin_port
= htons(GTP1U_PORT
);
792 #if defined(__FreeBSD__) || defined(__APPLE__)
793 addr
.sin_len
= sizeof(addr
);
796 if (bind((*gsn
)->fd1u
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
797 (*gsn
)->err_socket
++;
798 LOGP_WITH_ADDR(DLGTP
, LOGL_ERROR
, addr
,
799 "bind(fd1u=%d) failed: Error = %s\n",
800 (*gsn
)->fd1u
, strerror(errno
));
807 int gtp_free(struct gsn_t
*gsn
)
810 /* Clean up retransmit queues */
811 queue_free(gsn
->queue_req
);
812 queue_free(gsn
->queue_resp
);
822 /* ***********************************************************
823 * Path management messages
824 * Messages: echo and version not supported.
825 * A path is connection between two UDP/IP endpoints
827 * A path is either using GTP0 or GTP1. A path can be
828 * established by any kind of GTP message??
830 * Which source port to use?
831 * GTP-C request destination port is 2123/3386
832 * GTP-U request destination port is 2152/3386
833 * T-PDU destination port is 2152/3386.
834 * For the above messages the source port is locally allocated.
835 * For response messages src=rx-dst and dst=rx-src.
836 * For simplicity we should probably use 2123+2152/3386 as
837 * src port even for the cases where src can be locally
838 * allocated. This also means that we have to listen only to
840 * For response messages we need to be able to respond to
841 * the relevant src port even if it is locally allocated by
844 * The need for path management!
845 * We might need to keep a list of active paths. This might
846 * be in the form of remote IP address + UDP port numbers.
847 * (We will consider a path astablished if we have a context
848 * with the node in question)
849 *************************************************************/
851 /* Send off an echo request */
852 int gtp_echo_req(struct gsn_t
*gsn
, int version
, void *cbp
,
853 struct in_addr
*inetaddr
)
855 union gtp_packet packet
;
856 unsigned int length
= get_default_gtp(version
, GTP_ECHO_REQ
, &packet
);
857 return gtp_req(gsn
, version
, NULL
, &packet
, length
, inetaddr
, cbp
);
860 /* Send off an echo reply */
861 int gtp_echo_resp(struct gsn_t
*gsn
, int version
,
862 struct sockaddr_in
*peer
, int fd
, void *pack
, unsigned len
)
864 union gtp_packet packet
;
865 unsigned int length
= get_default_gtp(version
, GTP_ECHO_RSP
, &packet
);
866 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_RECOVERY
,
867 gsn
->restart_counter
);
868 return gtp_resp(version
, gsn
, NULL
, &packet
, length
, peer
, fd
,
869 get_seq(pack
), get_tid(pack
));
872 /* Handle a received echo request */
873 int gtp_echo_ind(struct gsn_t
*gsn
, int version
, struct sockaddr_in
*peer
,
874 int fd
, void *pack
, unsigned len
)
877 /* Check if it was a dublicate request */
878 if (!gtp_dublicate(gsn
, 0, peer
, get_seq(pack
)))
881 /* Send off reply to request */
882 return gtp_echo_resp(gsn
, version
, peer
, fd
, pack
, len
);
885 /* Handle a received echo reply */
886 int gtp_echo_conf(struct gsn_t
*gsn
, int version
, struct sockaddr_in
*peer
,
887 void *pack
, unsigned len
)
889 union gtpie_member
*ie
[GTPIE_SIZE
];
890 unsigned char recovery
;
893 int hlen
= get_hlen(pack
);
895 /* Remove packet from queue */
896 if (gtp_conf(gsn
, version
, peer
, pack
, len
, &type
, &cbp
))
899 /* Extract information elements into a pointer array */
900 if (gtpie_decaps(ie
, version
, pack
+ hlen
, len
- hlen
)) {
902 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
903 "Invalid message format\n");
905 gsn
->cb_conf(type
, EOF
, NULL
, cbp
);
909 if (gtpie_gettv1(ie
, GTPIE_RECOVERY
, 0, &recovery
)) {
911 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
912 "Missing mandatory field\n");
914 gsn
->cb_conf(type
, EOF
, NULL
, cbp
);
918 /* Echo reply packages does not have a cause information element */
919 /* Instead we return the recovery number in the callback function */
921 gsn
->cb_conf(type
, recovery
, NULL
, cbp
);
923 if (gsn
->cb_recovery
)
924 gsn
->cb_recovery(peer
, recovery
);
929 /* Send off a Version Not Supported message */
930 /* This message is somewhat special in that it actually is a
931 * response to some other message with unsupported GTP version
932 * For this reason it has parameters like a response, and does
933 * its own message transmission. No signalling queue is used
934 * The reply is sent to the peer IP and peer UDP. This means that
935 * the peer will be receiving a GTP0 message on a GTP1 port!
936 * In practice however this will never happen as a GTP0 GSN will
937 * only listen to the GTP0 port, and therefore will never receive
938 * anything else than GTP0 */
940 int gtp_unsup_req(struct gsn_t
*gsn
, int version
, struct sockaddr_in
*peer
,
941 int fd
, void *pack
, unsigned len
)
943 union gtp_packet packet
;
945 /* GTP 1 is the highest supported protocol */
946 unsigned int length
= get_default_gtp(1, GTP_NOT_SUPPORTED
, &packet
);
947 return gtp_notification(gsn
, version
, &packet
, length
, peer
, fd
, 0);
950 /* Handle a Version Not Supported message */
951 int gtp_unsup_ind(struct gsn_t
*gsn
, struct sockaddr_in
*peer
,
952 void *pack
, unsigned len
)
955 if (gsn
->cb_unsup_ind
)
956 gsn
->cb_unsup_ind(peer
);
961 /* Send off an Supported Extension Headers Notification */
962 int gtp_extheader_req(struct gsn_t
*gsn
, int version
, struct sockaddr_in
*peer
,
963 int fd
, void *pack
, unsigned len
)
965 union gtp_packet packet
;
966 unsigned int length
=
967 get_default_gtp(version
, GTP_SUPP_EXT_HEADER
, &packet
);
969 uint8_t pdcp_pdu
= GTP_EXT_PDCP_PDU
;
974 /* We report back that we support only PDCP PDU headers */
975 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_EXT_HEADER_T
,
976 sizeof(pdcp_pdu
), &pdcp_pdu
);
978 return gtp_notification(gsn
, version
, &packet
, length
,
979 peer
, fd
, get_seq(pack
));
982 /* Handle a Supported Extension Headers Notification */
983 int gtp_extheader_ind(struct gsn_t
*gsn
, struct sockaddr_in
*peer
,
984 void *pack
, unsigned len
)
987 if (gsn
->cb_extheader_ind
)
988 gsn
->cb_extheader_ind(peer
);
993 /* ***********************************************************
994 * Session management messages
995 * Messages: create, update and delete PDP context
997 * Information storage
998 * Information storage for each PDP context is defined in
999 * 23.060 section 13.3. Includes IMSI, MSISDN, APN, PDP-type,
1000 * PDP-address (IP address), sequence numbers, charging ID.
1001 * For the SGSN it also includes radio related mobility
1003 *************************************************************/
1005 /* API: Send Create PDP Context Request (7.3.1) */
1006 extern int gtp_create_context_req(struct gsn_t
*gsn
, struct pdp_t
*pdp
,
1009 union gtp_packet packet
;
1010 unsigned int length
=
1011 get_default_gtp(pdp
->version
, GTP_CREATE_PDP_REQ
, &packet
);
1012 struct pdp_t
*linked_pdp
= NULL
;
1014 /* TODO: Secondary PDP Context Activation Procedure */
1015 /* In secondary activation procedure the PDP context is identified
1016 by tei in the header. The following fields are omitted: Selection
1017 mode, IMSI, MSISDN, End User Address, Access Point Name and
1018 Protocol Configuration Options */
1020 if (pdp
->secondary
) {
1021 if (pdp_getgtp1(&linked_pdp
, pdp
->teic_own
)) {
1022 LOGP(DLGTP
, LOGL_ERROR
,
1023 "Unknown linked PDP context: %u\n", pdp
->teic_own
);
1028 if (pdp
->version
== 0) {
1029 gtpie_tv0(&packet
, &length
, GTP_MAX
, GTPIE_QOS_PROFILE0
,
1030 sizeof(pdp
->qos_req0
), pdp
->qos_req0
);
1034 if (pdp
->version
== 1) {
1035 if (!pdp
->secondary
) /* Not Secondary PDP Context Activation Procedure */
1036 gtpie_tv0(&packet
, &length
, GTP_MAX
, GTPIE_IMSI
,
1037 sizeof(pdp
->imsi
), (uint8_t *) & pdp
->imsi
);
1040 /* Section 7.7.3 Routing Area Information */
1041 if (pdp
->rai_given
== 1)
1042 gtpie_tv0(&packet
, &length
, GTP_MAX
, GTPIE_RAI
,
1043 pdp
->rai
.l
, (uint8_t *) & pdp
->rai
.v
);
1045 /* Section 7.7.11 */
1046 if (pdp
->norecovery_given
== 0)
1047 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_RECOVERY
,
1048 gsn
->restart_counter
);
1050 /* Section 7.7.12 */
1051 if (!pdp
->secondary
) /* Not Secondary PDP Context Activation Procedure */
1052 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_SELECTION_MODE
,
1055 if (pdp
->version
== 0) {
1056 gtpie_tv2(&packet
, &length
, GTP_MAX
, GTPIE_FL_DI
, pdp
->fllu
);
1057 gtpie_tv2(&packet
, &length
, GTP_MAX
, GTPIE_FL_C
, pdp
->fllc
);
1060 /* Section 7.7.13 */
1061 if (pdp
->version
== 1) {
1062 gtpie_tv4(&packet
, &length
, GTP_MAX
, GTPIE_TEI_DI
,
1065 /* Section 7.7.14 */
1066 if (!pdp
->teic_confirmed
)
1067 gtpie_tv4(&packet
, &length
, GTP_MAX
, GTPIE_TEI_C
,
1070 /* Section 7.7.17 */
1071 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_NSAPI
, pdp
->nsapi
);
1073 /* Section 7.7.17 */
1074 if (pdp
->secondary
) /* Secondary PDP Context Activation Procedure */
1075 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_NSAPI
,
1078 /* Section 7.7.23 */
1079 if (pdp
->cch_pdp
) /* Only include charging if flags are set */
1080 gtpie_tv2(&packet
, &length
, GTP_MAX
, GTPIE_CHARGING_C
,
1085 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1087 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1090 /* Section 7.7.27 */
1091 if (!pdp
->secondary
) /* Not Secondary PDP Context Activation Procedure */
1092 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_EUA
,
1093 pdp
->eua
.l
, pdp
->eua
.v
);
1095 /* Section 7.7.30 */
1096 if (!pdp
->secondary
) /* Not Secondary PDP Context Activation Procedure */
1097 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_APN
,
1098 pdp
->apn_use
.l
, pdp
->apn_use
.v
);
1100 /* Section 7.7.31 */
1101 if (!pdp
->secondary
) /* Not Secondary PDP Context Activation Procedure */
1103 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_PCO
,
1104 pdp
->pco_req
.l
, pdp
->pco_req
.v
);
1106 /* Section 7.7.32 */
1107 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_GSN_ADDR
,
1108 pdp
->gsnlc
.l
, pdp
->gsnlc
.v
);
1109 /* Section 7.7.32 */
1110 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_GSN_ADDR
,
1111 pdp
->gsnlu
.l
, pdp
->gsnlu
.v
);
1113 /* Section 7.7.33 */
1114 if (!pdp
->secondary
) /* Not Secondary PDP Context Activation Procedure */
1115 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_MSISDN
,
1116 pdp
->msisdn
.l
, pdp
->msisdn
.v
);
1118 /* Section 7.7.34 */
1119 if (pdp
->version
== 1)
1120 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_QOS_PROFILE
,
1121 pdp
->qos_req
.l
, pdp
->qos_req
.v
);
1123 /* Section 7.7.36 */
1124 if ((pdp
->version
== 1) && pdp
->tft
.l
)
1125 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_TFT
,
1126 pdp
->tft
.l
, pdp
->tft
.v
);
1128 /* Section 7.7.41 */
1129 if ((pdp
->version
== 1) && pdp
->triggerid
.l
)
1130 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_TRIGGER_ID
,
1131 pdp
->triggerid
.l
, pdp
->triggerid
.v
);
1133 /* Section 7.7.42 */
1134 if ((pdp
->version
== 1) && pdp
->omcid
.l
)
1135 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_OMC_ID
,
1136 pdp
->omcid
.l
, pdp
->omcid
.v
);
1139 if (pdp
->rattype_given
== 1)
1140 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_RAT_TYPE
,
1141 pdp
->rattype
.l
, pdp
->rattype
.v
);
1143 if (pdp
->userloc_given
== 1)
1144 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_USER_LOC
,
1145 pdp
->userloc
.l
, pdp
->userloc
.v
);
1147 if (pdp
->mstz_given
== 1)
1148 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_MS_TZ
,
1149 pdp
->mstz
.l
, pdp
->mstz
.v
);
1151 if (pdp
->imeisv_given
== 1)
1152 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_IMEI_SV
,
1153 pdp
->imeisv
.l
, pdp
->imeisv
.v
);
1156 gtp_req(gsn
, pdp
->version
, pdp
, &packet
, length
, &pdp
->hisaddr0
, cbp
);
1161 /* API: Application response to context indication */
1162 int gtp_create_context_resp(struct gsn_t
*gsn
, struct pdp_t
*pdp
, int cause
)
1165 /* Now send off a reply to the peer */
1166 gtp_create_pdp_resp(gsn
, pdp
->version
, pdp
, cause
);
1168 if (cause
!= GTPCAUSE_ACC_REQ
) {
1175 /* API: Register create context indication callback */
1176 int gtp_set_cb_create_context_ind(struct gsn_t
*gsn
,
1177 int (*cb_create_context_ind
) (struct pdp_t
*
1180 gsn
->cb_create_context_ind
= cb_create_context_ind
;
1184 /* Send Create PDP Context Response */
1185 int gtp_create_pdp_resp(struct gsn_t
*gsn
, int version
, struct pdp_t
*pdp
,
1188 union gtp_packet packet
;
1189 unsigned int length
=
1190 get_default_gtp(version
, GTP_CREATE_PDP_RSP
, &packet
);
1192 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_CAUSE
, cause
);
1194 if (cause
== GTPCAUSE_ACC_REQ
) {
1197 gtpie_tv0(&packet
, &length
, GTP_MAX
, GTPIE_QOS_PROFILE0
,
1198 sizeof(pdp
->qos_neg0
), pdp
->qos_neg0
);
1200 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_REORDER
,
1202 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_RECOVERY
,
1203 gsn
->restart_counter
);
1206 gtpie_tv2(&packet
, &length
, GTP_MAX
, GTPIE_FL_DI
,
1208 gtpie_tv2(&packet
, &length
, GTP_MAX
, GTPIE_FL_C
,
1213 gtpie_tv4(&packet
, &length
, GTP_MAX
, GTPIE_TEI_DI
,
1215 gtpie_tv4(&packet
, &length
, GTP_MAX
, GTPIE_TEI_C
,
1219 /* TODO: We use teic_own as charging ID */
1220 gtpie_tv4(&packet
, &length
, GTP_MAX
, GTPIE_CHARGING_ID
,
1223 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_EUA
,
1224 pdp
->eua
.l
, pdp
->eua
.v
);
1226 if (pdp
->pco_neg
.l
) { /* Optional PCO */
1227 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_PCO
,
1228 pdp
->pco_neg
.l
, pdp
->pco_neg
.v
);
1231 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_GSN_ADDR
,
1232 pdp
->gsnlc
.l
, pdp
->gsnlc
.v
);
1233 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_GSN_ADDR
,
1234 pdp
->gsnlu
.l
, pdp
->gsnlu
.v
);
1237 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_QOS_PROFILE
,
1238 pdp
->qos_neg
.l
, pdp
->qos_neg
.v
);
1240 /* TODO: Charging gateway address */
1243 return gtp_resp(version
, gsn
, pdp
, &packet
, length
, &pdp
->sa_peer
,
1244 pdp
->fd
, pdp
->seq
, pdp
->tid
);
1247 /* Handle Create PDP Context Request */
1248 int gtp_create_pdp_ind(struct gsn_t
*gsn
, int version
,
1249 struct sockaddr_in
*peer
, int fd
,
1250 void *pack
, unsigned len
)
1252 struct pdp_t
*pdp
, *pdp_old
;
1253 struct pdp_t pdp_buf
;
1254 union gtpie_member
*ie
[GTPIE_SIZE
];
1257 uint16_t seq
= get_seq(pack
);
1258 int hlen
= get_hlen(pack
);
1259 uint8_t linked_nsapi
= 0;
1260 struct pdp_t
*linked_pdp
= NULL
;
1262 if (!gtp_dublicate(gsn
, version
, peer
, seq
))
1266 memset(pdp
, 0, sizeof(struct pdp_t
));
1269 uint64_t tid
= be64toh(((union gtp_packet
*)pack
)->gtp0
.h
.tid
);
1271 pdp_set_imsi_nsapi(pdp
, tid
);
1275 pdp
->sa_peer
= *peer
;
1277 pdp
->version
= version
;
1279 /* Decode information elements */
1280 if (gtpie_decaps(ie
, version
, pack
+ hlen
, len
- hlen
)) {
1282 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
1283 "Invalid message format\n");
1287 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1288 GTPCAUSE_INVALID_MESSAGE
);
1292 /* Linked NSAPI (conditional) */
1293 /* If included this is the Secondary PDP Context Activation Procedure */
1294 /* In secondary activation IMSI is not included, so the context must be */
1295 /* identified by the tei */
1296 if (!gtpie_gettv1(ie
, GTPIE_NSAPI
, 1, &linked_nsapi
)) {
1298 /* Find the primary PDP context */
1299 if (pdp_getgtp1(&linked_pdp
, get_tei(pack
))) {
1301 GTP_LOGPKG(LOGL_ERROR
, peer
,
1303 "Incorrect optional information field\n");
1304 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1305 GTPCAUSE_OPT_IE_INCORRECT
);
1308 /* Check that the primary PDP context matches linked nsapi */
1309 if (linked_pdp
->nsapi
!= linked_nsapi
) {
1311 GTP_LOGPKG(LOGL_ERROR
, peer
,
1313 "Incorrect optional information field\n");
1314 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1315 GTPCAUSE_OPT_IE_INCORRECT
);
1318 /* Copy parameters from primary context */
1319 pdp
->selmode
= linked_pdp
->selmode
;
1320 pdp
->imsi
= linked_pdp
->imsi
;
1321 pdp
->msisdn
= linked_pdp
->msisdn
;
1322 pdp
->eua
= linked_pdp
->eua
;
1323 pdp
->pco_req
= linked_pdp
->pco_req
;
1324 pdp
->apn_req
= linked_pdp
->apn_req
;
1325 pdp
->teic_gn
= linked_pdp
->teic_gn
;
1329 /* if (version == 1) */
1331 if (gtpie_gettv0(ie
, GTPIE_QOS_PROFILE0
, 0,
1332 pdp
->qos_req0
, sizeof(pdp
->qos_req0
))) {
1334 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1335 len
, "Missing mandatory information field\n");
1336 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1337 GTPCAUSE_MAN_IE_MISSING
);
1341 if ((version
== 1) && (!linked_pdp
)) {
1342 /* Not Secondary PDP Context Activation Procedure */
1343 /* IMSI (conditional) */
1345 (ie
, GTPIE_IMSI
, 0, &pdp
->imsi
, sizeof(pdp
->imsi
))) {
1347 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1348 len
, "Missing mandatory information field\n");
1349 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1350 GTPCAUSE_MAN_IE_MISSING
);
1354 /* Recovery (optional) */
1355 if (!gtpie_gettv1(ie
, GTPIE_RECOVERY
, 0, &recovery
)) {
1356 if (gsn
->cb_recovery
)
1357 gsn
->cb_recovery(peer
, recovery
);
1360 /* Selection mode (conditional) */
1361 if (!linked_pdp
) { /* Not Secondary PDP Context Activation Procedure */
1362 if (gtpie_gettv0(ie
, GTPIE_SELECTION_MODE
, 0,
1363 &pdp
->selmode
, sizeof(pdp
->selmode
))) {
1365 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1366 len
, "Missing mandatory information field\n");
1367 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1368 GTPCAUSE_MAN_IE_MISSING
);
1373 if (gtpie_gettv2(ie
, GTPIE_FL_DI
, 0, &pdp
->flru
)) {
1375 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1376 len
, "Missing mandatory information field\n");
1377 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1378 GTPCAUSE_MAN_IE_MISSING
);
1381 if (gtpie_gettv2(ie
, GTPIE_FL_C
, 0, &pdp
->flrc
)) {
1383 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1384 len
, "Missing mandatory information field\n");
1385 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1386 GTPCAUSE_MAN_IE_MISSING
);
1391 /* TEID (mandatory) */
1392 if (gtpie_gettv4(ie
, GTPIE_TEI_DI
, 0, &pdp
->teid_gn
)) {
1394 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1395 len
, "Missing mandatory information field\n");
1396 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1397 GTPCAUSE_MAN_IE_MISSING
);
1400 /* TEIC (conditional) */
1401 if (!linked_pdp
) { /* Not Secondary PDP Context Activation Procedure */
1402 if (gtpie_gettv4(ie
, GTPIE_TEI_C
, 0, &pdp
->teic_gn
)) {
1404 GTP_LOGPKG(LOGL_ERROR
, peer
,
1406 "Missing mandatory information field\n");
1407 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1408 GTPCAUSE_MAN_IE_MISSING
);
1412 /* NSAPI (mandatory) */
1413 if (gtpie_gettv1(ie
, GTPIE_NSAPI
, 0, &pdp
->nsapi
)) {
1415 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1416 len
, "Missing mandatory information field\n");
1417 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1418 GTPCAUSE_MAN_IE_MISSING
);
1422 /* Charging Characteriatics (optional) */
1423 /* Trace reference (optional) */
1424 /* Trace type (optional) */
1425 /* Charging Characteriatics (optional) */
1427 if (!linked_pdp
) { /* Not Secondary PDP Context Activation Procedure */
1428 /* End User Address (conditional) */
1429 if (gtpie_gettlv(ie
, GTPIE_EUA
, 0, &pdp
->eua
.l
,
1430 &pdp
->eua
.v
, sizeof(pdp
->eua
.v
))) {
1432 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1433 len
, "Missing mandatory information field\n");
1434 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1435 GTPCAUSE_MAN_IE_MISSING
);
1439 if (gtpie_gettlv(ie
, GTPIE_APN
, 0, &pdp
->apn_req
.l
,
1440 &pdp
->apn_req
.v
, sizeof(pdp
->apn_req
.v
))) {
1442 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1443 len
, "Missing mandatory information field\n");
1444 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1445 GTPCAUSE_MAN_IE_MISSING
);
1448 /* Extract protocol configuration options (optional) */
1449 if (!gtpie_gettlv(ie
, GTPIE_PCO
, 0, &pdp
->pco_req
.l
,
1450 &pdp
->pco_req
.v
, sizeof(pdp
->pco_req
.v
))) {
1454 /* SGSN address for signalling (mandatory) */
1455 if (gtpie_gettlv(ie
, GTPIE_GSN_ADDR
, 0, &pdp
->gsnrc
.l
,
1456 &pdp
->gsnrc
.v
, sizeof(pdp
->gsnrc
.v
))) {
1458 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
1459 "Missing mandatory information field\n");
1460 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1461 GTPCAUSE_MAN_IE_MISSING
);
1464 /* SGSN address for user traffic (mandatory) */
1465 if (gtpie_gettlv(ie
, GTPIE_GSN_ADDR
, 1, &pdp
->gsnru
.l
,
1466 &pdp
->gsnru
.v
, sizeof(pdp
->gsnru
.v
))) {
1468 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
1469 "Missing mandatory information field\n");
1470 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1471 GTPCAUSE_MAN_IE_MISSING
);
1474 if (!linked_pdp
) { /* Not Secondary PDP Context Activation Procedure */
1475 /* MSISDN (conditional) */
1476 if (gtpie_gettlv(ie
, GTPIE_MSISDN
, 0, &pdp
->msisdn
.l
,
1477 &pdp
->msisdn
.v
, sizeof(pdp
->msisdn
.v
))) {
1479 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1480 len
, "Missing mandatory information field\n");
1481 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1482 GTPCAUSE_MAN_IE_MISSING
);
1487 /* QoS (mandatory) */
1488 if (gtpie_gettlv(ie
, GTPIE_QOS_PROFILE
, 0, &pdp
->qos_req
.l
,
1489 &pdp
->qos_req
.v
, sizeof(pdp
->qos_req
.v
))) {
1491 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1492 len
, "Missing mandatory information field\n");
1493 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1494 GTPCAUSE_MAN_IE_MISSING
);
1497 /* TFT (conditional) */
1498 if (gtpie_gettlv(ie
, GTPIE_TFT
, 0, &pdp
->tft
.l
,
1499 &pdp
->tft
.v
, sizeof(pdp
->tft
.v
))) {
1506 /* Initialize our own IP addresses */
1507 in_addr2gsna(&pdp
->gsnlc
, &gsn
->gsnc
);
1508 in_addr2gsna(&pdp
->gsnlu
, &gsn
->gsnu
);
1510 DEBUGP(DLGTP
, "gtp_create_pdp_ind: Before pdp_tidget\n");
1512 if (!pdp_getimsi(&pdp_old
, pdp
->imsi
, pdp
->nsapi
)) {
1513 /* Found old pdp with same tid. Now the voodoo begins! */
1514 /* 09.60 / 29.060 allows create on existing context to "steal" */
1515 /* the context which was allready established */
1516 /* We check that the APN, selection mode and MSISDN is the same */
1517 DEBUGP(DLGTP
, "gtp_create_pdp_ind: Old context found\n");
1518 if ((pdp
->apn_req
.l
== pdp_old
->apn_req
.l
)
1521 (pdp
->apn_req
.v
, pdp_old
->apn_req
.v
, pdp
->apn_req
.l
))
1522 && (pdp
->selmode
== pdp_old
->selmode
)
1523 && (pdp
->msisdn
.l
== pdp_old
->msisdn
.l
)
1525 (!memcmp(pdp
->msisdn
.v
, pdp_old
->msisdn
.v
, pdp
->msisdn
.l
)))
1527 /* OK! We are dealing with the same APN. We will copy new
1528 * parameters to the old pdp and send off confirmation
1529 * We ignore the following information elements:
1530 * QoS: MS will get originally negotiated QoS.
1531 * End user address (EUA). MS will get old EUA anyway.
1532 * Protocol configuration option (PCO): Only application can verify */
1533 DEBUGP(DLGTP
, "gtp_create_pdp_ind: Old context found\n");
1535 /* Copy remote flow label */
1536 pdp_old
->flru
= pdp
->flru
;
1537 pdp_old
->flrc
= pdp
->flrc
;
1539 /* Copy remote tei */
1540 pdp_old
->teid_gn
= pdp
->teid_gn
;
1541 pdp_old
->teic_gn
= pdp
->teic_gn
;
1543 /* Copy peer GSN address */
1544 pdp_old
->gsnrc
.l
= pdp
->gsnrc
.l
;
1545 memcpy(&pdp_old
->gsnrc
.v
, &pdp
->gsnrc
.v
, pdp
->gsnrc
.l
);
1546 pdp_old
->gsnru
.l
= pdp
->gsnru
.l
;
1547 memcpy(&pdp_old
->gsnru
.v
, &pdp
->gsnru
.v
, pdp
->gsnru
.l
);
1549 /* Copy request parameters */
1550 pdp_old
->seq
= pdp
->seq
;
1551 pdp_old
->sa_peer
= pdp
->sa_peer
;
1552 pdp_old
->fd
= pdp
->fd
= fd
;
1553 pdp_old
->version
= pdp
->version
= version
;
1555 /* Switch to using the old pdp context */
1558 /* Confirm to peer that things were "successful" */
1559 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1561 } else { /* This is not the same PDP context. Delete the old one. */
1563 DEBUGP(DLGTP
, "gtp_create_pdp_ind: Deleting old context\n");
1565 if (gsn
->cb_delete_context
)
1566 gsn
->cb_delete_context(pdp_old
);
1567 pdp_freepdp(pdp_old
);
1569 DEBUGP(DLGTP
, "gtp_create_pdp_ind: Deleted...\n");
1573 pdp_newpdp(&pdp
, pdp
->imsi
, pdp
->nsapi
, pdp
);
1575 /* Callback function to validata login */
1576 if (gsn
->cb_create_context_ind
!= 0)
1577 return gsn
->cb_create_context_ind(pdp
);
1579 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
1580 "No create_context_ind callback defined\n");
1581 return gtp_create_pdp_resp(gsn
, version
, pdp
,
1582 GTPCAUSE_NOT_SUPPORTED
);
1586 /* Handle Create PDP Context Response */
1587 int gtp_create_pdp_conf(struct gsn_t
*gsn
, int version
,
1588 struct sockaddr_in
*peer
, void *pack
, unsigned len
)
1591 union gtpie_member
*ie
[GTPIE_SIZE
];
1592 uint8_t cause
, recovery
;
1595 int hlen
= get_hlen(pack
);
1597 /* Remove packet from queue */
1598 if (gtp_conf(gsn
, version
, peer
, pack
, len
, &type
, &cbp
))
1601 /* Find the context in question */
1602 if (pdp_getgtp1(&pdp
, get_tei(pack
))) {
1603 gsn
->err_unknownpdp
++;
1604 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
1605 "Unknown PDP context: %u\n", get_tei(pack
));
1607 gsn
->cb_conf(type
, EOF
, NULL
, cbp
);
1611 /* Register that we have received a valid teic from GGSN */
1612 pdp
->teic_confirmed
= 1;
1614 /* Decode information elements */
1615 if (gtpie_decaps(ie
, version
, pack
+ hlen
, len
- hlen
)) {
1617 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
1618 "Invalid message format\n");
1620 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1621 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1622 pdp_freepdp(pdp); */
1626 /* Extract cause value (mandatory) */
1627 if (gtpie_gettv1(ie
, GTPIE_CAUSE
, 0, &cause
)) {
1629 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
1630 "Missing mandatory information field\n");
1632 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1633 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1634 pdp_freepdp(pdp); */
1638 /* Extract recovery (optional) */
1639 if (!gtpie_gettv1(ie
, GTPIE_RECOVERY
, 0, &recovery
)) {
1640 if (gsn
->cb_recovery
)
1641 gsn
->cb_recovery(peer
, recovery
);
1644 /* Extract protocol configuration options (optional) */
1645 if (!gtpie_gettlv(ie
, GTPIE_PCO
, 0, &pdp
->pco_req
.l
,
1646 &pdp
->pco_req
.v
, sizeof(pdp
->pco_req
.v
))) {
1649 /* Check all conditional information elements */
1650 if (GTPCAUSE_ACC_REQ
== cause
) {
1653 if (gtpie_gettv0(ie
, GTPIE_QOS_PROFILE0
, 0,
1655 sizeof(pdp
->qos_neg0
))) {
1657 GTP_LOGPKG(LOGL_ERROR
, peer
,
1659 "Missing conditional information field\n");
1661 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1662 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1663 pdp_freepdp(pdp); */
1668 if (gtpie_gettv1(ie
, GTPIE_REORDER
, 0, &pdp
->reorder
)) {
1670 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1672 "Missing conditional information field\n");
1674 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1675 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1676 pdp_freepdp(pdp); */
1681 if (gtpie_gettv2(ie
, GTPIE_FL_DI
, 0, &pdp
->flru
)) {
1683 GTP_LOGPKG(LOGL_ERROR
, peer
,
1685 "Missing conditional information field\n");
1687 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1688 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1689 pdp_freepdp(pdp); */
1693 if (gtpie_gettv2(ie
, GTPIE_FL_C
, 0, &pdp
->flrc
)) {
1695 GTP_LOGPKG(LOGL_ERROR
, peer
,
1697 "Missing conditional information field\n");
1699 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1700 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1701 pdp_freepdp(pdp); */
1707 if (gtpie_gettv4(ie
, GTPIE_TEI_DI
, 0, &pdp
->teid_gn
)) {
1709 GTP_LOGPKG(LOGL_ERROR
, peer
,
1711 "Missing conditional information field\n");
1713 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1714 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1715 pdp_freepdp(pdp); */
1719 if (gtpie_gettv4(ie
, GTPIE_TEI_C
, 0, &pdp
->teic_gn
)) {
1721 GTP_LOGPKG(LOGL_ERROR
, peer
,
1723 "Missing conditional information field\n");
1725 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1726 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1727 pdp_freepdp(pdp); */
1732 if (gtpie_gettv4(ie
, GTPIE_CHARGING_ID
, 0, &pdp
->cid
)) {
1734 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1736 "Missing conditional information field\n");
1738 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1739 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1740 pdp_freepdp(pdp); */
1743 if (gtpie_gettlv(ie
, GTPIE_EUA
, 0, &pdp
->eua
.l
,
1744 &pdp
->eua
.v
, sizeof(pdp
->eua
.v
))) {
1746 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1748 "Missing conditional information field\n");
1750 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1751 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1752 pdp_freepdp(pdp); */
1756 if (gtpie_gettlv(ie
, GTPIE_GSN_ADDR
, 0, &pdp
->gsnrc
.l
,
1757 &pdp
->gsnrc
.v
, sizeof(pdp
->gsnrc
.v
))) {
1759 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1761 "Missing conditional information field\n");
1763 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1764 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1765 pdp_freepdp(pdp); */
1769 if (gtpie_gettlv(ie
, GTPIE_GSN_ADDR
, 1, &pdp
->gsnru
.l
,
1770 &pdp
->gsnru
.v
, sizeof(pdp
->gsnru
.v
))) {
1772 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1774 "Missing conditional information field\n");
1776 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1777 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1778 pdp_freepdp(pdp); */
1784 (ie
, GTPIE_QOS_PROFILE
, 0, &pdp
->qos_neg
.l
,
1785 &pdp
->qos_neg
.v
, sizeof(pdp
->qos_neg
.v
))) {
1787 GTP_LOGPKG(LOGL_ERROR
, peer
,
1789 "Missing conditional information field\n");
1791 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
1792 /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
1793 pdp_freepdp(pdp); */
1801 gsn
->cb_conf(type
, cause
, pdp
, cbp
);
1806 /* API: Send Update PDP Context Request */
1807 int gtp_update_context(struct gsn_t
*gsn
, struct pdp_t
*pdp
, void *cbp
,
1808 struct in_addr
*inetaddr
)
1810 union gtp_packet packet
;
1811 unsigned int length
=
1812 get_default_gtp(pdp
->version
, GTP_UPDATE_PDP_REQ
, &packet
);
1814 if (pdp
->version
== 0)
1815 gtpie_tv0(&packet
, &length
, GTP_MAX
, GTPIE_QOS_PROFILE0
,
1816 sizeof(pdp
->qos_req0
), pdp
->qos_req0
);
1818 /* Include IMSI if updating with unknown teic_gn */
1819 if ((pdp
->version
== 1) && (!pdp
->teic_gn
))
1820 gtpie_tv0(&packet
, &length
, GTP_MAX
, GTPIE_IMSI
,
1821 sizeof(pdp
->imsi
), (uint8_t *) & pdp
->imsi
);
1823 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_RECOVERY
,
1824 gsn
->restart_counter
);
1826 if (pdp
->version
== 0) {
1827 gtpie_tv2(&packet
, &length
, GTP_MAX
, GTPIE_FL_DI
, pdp
->fllu
);
1828 gtpie_tv2(&packet
, &length
, GTP_MAX
, GTPIE_FL_C
, pdp
->fllc
);
1831 if (pdp
->version
== 1) {
1832 gtpie_tv4(&packet
, &length
, GTP_MAX
, GTPIE_TEI_DI
,
1835 if (!pdp
->teic_confirmed
)
1836 gtpie_tv4(&packet
, &length
, GTP_MAX
, GTPIE_TEI_C
,
1840 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_NSAPI
, pdp
->nsapi
);
1843 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
1845 gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
1848 /* TODO if ggsn update message
1849 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1850 pdp->eua.l, pdp->eua.v);
1853 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_GSN_ADDR
,
1854 pdp
->gsnlc
.l
, pdp
->gsnlc
.v
);
1855 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_GSN_ADDR
,
1856 pdp
->gsnlu
.l
, pdp
->gsnlu
.v
);
1858 if (pdp
->version
== 1)
1859 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_QOS_PROFILE
,
1860 pdp
->qos_req
.l
, pdp
->qos_req
.v
);
1862 if ((pdp
->version
== 1) && pdp
->tft
.l
)
1863 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_TFT
,
1864 pdp
->tft
.l
, pdp
->tft
.v
);
1866 if ((pdp
->version
== 1) && pdp
->triggerid
.l
)
1867 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_TRIGGER_ID
,
1868 pdp
->triggerid
.l
, pdp
->triggerid
.v
);
1870 if ((pdp
->version
== 1) && pdp
->omcid
.l
)
1871 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_OMC_ID
,
1872 pdp
->omcid
.l
, pdp
->omcid
.v
);
1874 gtp_req(gsn
, pdp
->version
, pdp
, &packet
, length
, inetaddr
, cbp
);
1879 /* Send Update PDP Context Response */
1880 int gtp_update_pdp_resp(struct gsn_t
*gsn
, int version
,
1881 struct sockaddr_in
*peer
, int fd
,
1882 void *pack
, unsigned len
,
1883 struct pdp_t
*pdp
, uint8_t cause
)
1886 union gtp_packet packet
;
1887 unsigned int length
=
1888 get_default_gtp(version
, GTP_UPDATE_PDP_RSP
, &packet
);
1890 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_CAUSE
, cause
);
1892 if (cause
== GTPCAUSE_ACC_REQ
) {
1895 gtpie_tv0(&packet
, &length
, GTP_MAX
, GTPIE_QOS_PROFILE0
,
1896 sizeof(pdp
->qos_neg0
), pdp
->qos_neg0
);
1898 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_RECOVERY
,
1899 gsn
->restart_counter
);
1902 gtpie_tv2(&packet
, &length
, GTP_MAX
, GTPIE_FL_DI
,
1904 gtpie_tv2(&packet
, &length
, GTP_MAX
, GTPIE_FL_C
,
1909 gtpie_tv4(&packet
, &length
, GTP_MAX
, GTPIE_TEI_DI
,
1912 if (!pdp
->teic_confirmed
)
1913 gtpie_tv4(&packet
, &length
, GTP_MAX
,
1914 GTPIE_TEI_C
, pdp
->teic_own
);
1917 /* TODO we use teid_own as charging ID address */
1918 gtpie_tv4(&packet
, &length
, GTP_MAX
, GTPIE_CHARGING_ID
,
1922 gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
1923 pdp->eua.l, pdp->eua.v); */
1925 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_GSN_ADDR
,
1926 pdp
->gsnlc
.l
, pdp
->gsnlc
.v
);
1927 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_GSN_ADDR
,
1928 pdp
->gsnlu
.l
, pdp
->gsnlu
.v
);
1931 gtpie_tlv(&packet
, &length
, GTP_MAX
, GTPIE_QOS_PROFILE
,
1932 pdp
->qos_neg
.l
, pdp
->qos_neg
.v
);
1934 /* TODO: Charging gateway address */
1937 return gtp_resp(version
, gsn
, pdp
, &packet
, length
, peer
,
1938 fd
, get_seq(pack
), get_tid(pack
));
1941 /* Handle Update PDP Context Request */
1942 int gtp_update_pdp_ind(struct gsn_t
*gsn
, int version
,
1943 struct sockaddr_in
*peer
, int fd
,
1944 void *pack
, unsigned len
)
1947 struct pdp_t pdp_backup
;
1948 union gtpie_member
*ie
[GTPIE_SIZE
];
1951 uint16_t seq
= get_seq(pack
);
1952 int hlen
= get_hlen(pack
);
1957 /* Is this a dublicate ? */
1958 if (!gtp_dublicate(gsn
, version
, peer
, seq
)) {
1959 return 0; /* We allready send of response once */
1962 /* Decode information elements */
1963 if (gtpie_decaps(ie
, version
, pack
+ hlen
, len
- hlen
)) {
1965 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
1966 "Invalid message format\n");
1970 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
,
1972 GTPCAUSE_INVALID_MESSAGE
);
1976 /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
1977 /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
1978 /* we have to use the tunnel endpoint identifier */
1980 uint64_t tid
= be64toh(((union gtp_packet
*)pack
)->gtp0
.h
.tid
);
1982 pdp_set_imsi_nsapi(pdp
, tid
);
1984 /* Find the context in question */
1985 if (pdp_getimsi(&pdp
, imsi
, nsapi
)) {
1986 gsn
->err_unknownpdp
++;
1987 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1988 len
, "Unknown PDP context\n");
1989 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
,
1991 GTPCAUSE_NON_EXIST
);
1993 } else if (version
== 1) {
1994 /* NSAPI (mandatory) */
1995 if (gtpie_gettv1(ie
, GTPIE_NSAPI
, 0, &nsapi
)) {
1997 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
1998 len
, "Missing mandatory information field\n");
1999 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
,
2001 GTPCAUSE_MAN_IE_MISSING
);
2004 /* IMSI (conditional) */
2005 if (gtpie_gettv0(ie
, GTPIE_IMSI
, 0, &imsi
, sizeof(imsi
))) {
2006 /* Find the context in question */
2007 if (pdp_getgtp1(&pdp
, get_tei(pack
))) {
2008 gsn
->err_unknownpdp
++;
2009 GTP_LOGPKG(LOGL_ERROR
, peer
,
2010 pack
, len
, "Unknown PDP context: %u\n",
2012 return gtp_update_pdp_resp(gsn
, version
, peer
,
2013 fd
, pack
, len
, NULL
,
2014 GTPCAUSE_NON_EXIST
);
2017 /* Find the context in question */
2018 if (pdp_getimsi(&pdp
, imsi
, nsapi
)) {
2019 gsn
->err_unknownpdp
++;
2020 GTP_LOGPKG(LOGL_ERROR
, peer
,
2021 pack
, len
, "Unknown PDP context\n");
2022 return gtp_update_pdp_resp(gsn
, version
, peer
,
2023 fd
, pack
, len
, NULL
,
2024 GTPCAUSE_NON_EXIST
);
2028 LOGP(DLGTP
, LOGL_ERROR
, "Unknown version: %d\n", version
);
2032 /* Make a backup copy in case anything is wrong */
2033 memcpy(&pdp_backup
, pdp
, sizeof(pdp_backup
));
2036 if (gtpie_gettv0(ie
, GTPIE_QOS_PROFILE0
, 0,
2037 pdp
->qos_req0
, sizeof(pdp
->qos_req0
))) {
2039 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
2040 len
, "Missing mandatory information field\n");
2041 memcpy(pdp
, &pdp_backup
, sizeof(pdp_backup
));
2042 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
,
2044 GTPCAUSE_MAN_IE_MISSING
);
2048 /* Recovery (optional) */
2049 if (!gtpie_gettv1(ie
, GTPIE_RECOVERY
, 0, &recovery
)) {
2050 if (gsn
->cb_recovery
)
2051 gsn
->cb_recovery(peer
, recovery
);
2055 if (gtpie_gettv2(ie
, GTPIE_FL_DI
, 0, &pdp
->flru
)) {
2057 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
2058 len
, "Missing mandatory information field\n");
2059 memcpy(pdp
, &pdp_backup
, sizeof(pdp_backup
));
2060 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
,
2062 GTPCAUSE_MAN_IE_MISSING
);
2065 if (gtpie_gettv2(ie
, GTPIE_FL_C
, 0, &pdp
->flrc
)) {
2067 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
2068 len
, "Missing mandatory information field\n");
2069 memcpy(pdp
, &pdp_backup
, sizeof(pdp_backup
));
2070 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
,
2072 GTPCAUSE_MAN_IE_MISSING
);
2077 /* TEID (mandatory) */
2078 if (gtpie_gettv4(ie
, GTPIE_TEI_DI
, 0, &pdp
->teid_gn
)) {
2080 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
2081 len
, "Missing mandatory information field\n");
2082 memcpy(pdp
, &pdp_backup
, sizeof(pdp_backup
));
2083 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
,
2085 GTPCAUSE_MAN_IE_MISSING
);
2088 /* TEIC (conditional) */
2089 /* If TEIC is not included it means that we have allready received it */
2090 /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
2091 /* all updated contexts, or only for one of the linked contexts */
2092 gtpie_gettv4(ie
, GTPIE_TEI_C
, 0, &pdp
->teic_gn
);
2094 /* NSAPI (mandatory) */
2095 if (gtpie_gettv1(ie
, GTPIE_NSAPI
, 0, &pdp
->nsapi
)) {
2097 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
2098 len
, "Missing mandatory information field\n");
2099 memcpy(pdp
, &pdp_backup
, sizeof(pdp_backup
));
2100 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
,
2102 GTPCAUSE_MAN_IE_MISSING
);
2106 /* Trace reference (optional) */
2107 /* Trace type (optional) */
2109 /* End User Address (conditional) TODO: GGSN Initiated
2110 if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
2111 &pdp->eua.v, sizeof(pdp->eua.v))) {
2113 GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
2114 "Missing mandatory information field");
2115 memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
2116 return gtp_update_pdp_resp(gsn, version, pdp,
2117 GTPCAUSE_MAN_IE_MISSING);
2120 /* SGSN address for signalling (mandatory) */
2121 /* It is weird that this is mandatory when TEIC is conditional */
2122 if (gtpie_gettlv(ie
, GTPIE_GSN_ADDR
, 0, &pdp
->gsnrc
.l
,
2123 &pdp
->gsnrc
.v
, sizeof(pdp
->gsnrc
.v
))) {
2125 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2126 "Missing mandatory information field\n");
2127 memcpy(pdp
, &pdp_backup
, sizeof(pdp_backup
));
2128 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
, len
,
2129 pdp
, GTPCAUSE_MAN_IE_MISSING
);
2132 /* SGSN address for user traffic (mandatory) */
2133 if (gtpie_gettlv(ie
, GTPIE_GSN_ADDR
, 1, &pdp
->gsnru
.l
,
2134 &pdp
->gsnru
.v
, sizeof(pdp
->gsnru
.v
))) {
2136 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2137 "Missing mandatory information field\n");
2138 memcpy(pdp
, &pdp_backup
, sizeof(pdp_backup
));
2139 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
, len
,
2140 pdp
, GTPCAUSE_MAN_IE_MISSING
);
2144 /* QoS (mandatory) */
2145 if (gtpie_gettlv(ie
, GTPIE_QOS_PROFILE
, 0, &pdp
->qos_req
.l
,
2146 &pdp
->qos_req
.v
, sizeof(pdp
->qos_req
.v
))) {
2148 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
2149 len
, "Missing mandatory information field\n");
2150 memcpy(pdp
, &pdp_backup
, sizeof(pdp_backup
));
2151 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
,
2153 GTPCAUSE_MAN_IE_MISSING
);
2156 /* TFT (conditional) */
2157 if (gtpie_gettlv(ie
, GTPIE_TFT
, 0, &pdp
->tft
.l
,
2158 &pdp
->tft
.v
, sizeof(pdp
->tft
.v
))) {
2164 /* Confirm to peer that things were "successful" */
2165 return gtp_update_pdp_resp(gsn
, version
, peer
, fd
, pack
, len
, pdp
,
2169 /* Handle Update PDP Context Response */
2170 int gtp_update_pdp_conf(struct gsn_t
*gsn
, int version
,
2171 struct sockaddr_in
*peer
, void *pack
, unsigned len
)
2174 union gtpie_member
*ie
[GTPIE_SIZE
];
2175 uint8_t cause
, recovery
;
2178 int hlen
= get_hlen(pack
);
2180 /* Remove packet from queue */
2181 if (gtp_conf(gsn
, 0, peer
, pack
, len
, &type
, &cbp
))
2184 /* Find the context in question */
2185 if (pdp_getgtp1(&pdp
, get_tei(pack
))) {
2186 gsn
->err_unknownpdp
++;
2187 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2188 "Unknown PDP context: %u\n", get_tei(pack
));
2193 /* Register that we have received a valid teic from GGSN */
2194 pdp
->teic_confirmed
= 1;
2196 /* Decode information elements */
2197 if (gtpie_decaps(ie
, version
, pack
+ hlen
, len
- hlen
)) {
2199 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2200 "Invalid message format\n");
2204 /* Extract cause value (mandatory) */
2205 if (gtpie_gettv1(ie
, GTPIE_CAUSE
, 0, &cause
)) {
2209 /* Extract recovery (optional) */
2210 if (!gtpie_gettv1(ie
, GTPIE_RECOVERY
, 0, &recovery
)) {
2211 if (gsn
->cb_recovery
)
2212 gsn
->cb_recovery(peer
, recovery
);
2215 /* Check all conditional information elements */
2216 /* TODO: This does not handle GGSN-initiated update responses */
2217 if (GTPCAUSE_ACC_REQ
== cause
) {
2219 if (gtpie_gettv0(ie
, GTPIE_QOS_PROFILE0
, 0,
2221 sizeof(pdp
->qos_neg0
))) {
2225 if (gtpie_gettv2(ie
, GTPIE_FL_DI
, 0, &pdp
->flru
)) {
2229 if (gtpie_gettv2(ie
, GTPIE_FL_C
, 0, &pdp
->flrc
)) {
2235 if (gtpie_gettv4(ie
, GTPIE_TEI_DI
, 0, &pdp
->teid_gn
)) {
2239 if (gtpie_gettv4(ie
, GTPIE_TEI_C
, 0, &pdp
->teic_gn
)) {
2244 if (gtpie_gettv4(ie
, GTPIE_CHARGING_ID
, 0, &pdp
->cid
)) {
2248 if (gtpie_gettlv(ie
, GTPIE_GSN_ADDR
, 0, &pdp
->gsnrc
.l
,
2249 &pdp
->gsnrc
.v
, sizeof(pdp
->gsnrc
.v
))) {
2253 if (gtpie_gettlv(ie
, GTPIE_GSN_ADDR
, 1, &pdp
->gsnru
.l
,
2254 &pdp
->gsnru
.v
, sizeof(pdp
->gsnru
.v
))) {
2260 (ie
, GTPIE_QOS_PROFILE
, 0, &pdp
->qos_neg
.l
,
2261 &pdp
->qos_neg
.v
, sizeof(pdp
->qos_neg
.v
))) {
2268 gsn
->cb_conf(type
, cause
, pdp
, cbp
);
2269 return 0; /* Succes */
2273 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2274 "Missing information field\n");
2277 gsn
->cb_conf(type
, EOF
, pdp
, cbp
);
2281 /* API: Send Delete PDP Context Request */
2282 int gtp_delete_context_req(struct gsn_t
*gsn
, struct pdp_t
*pdp
, void *cbp
,
2285 union gtp_packet packet
;
2286 unsigned int length
=
2287 get_default_gtp(pdp
->version
, GTP_DELETE_PDP_REQ
, &packet
);
2288 struct in_addr addr
;
2289 struct pdp_t
*linked_pdp
;
2290 struct pdp_t
*secondary_pdp
;
2294 if (gsna2in_addr(&addr
, &pdp
->gsnrc
)) {
2296 LOGP(DLGTP
, LOGL_ERROR
,
2297 "GSN address conversion failed\n");
2301 if (pdp_getgtp1(&linked_pdp
, pdp
->teic_own
)) {
2302 LOGP(DLGTP
, LOGL_ERROR
,
2303 "Unknown linked PDP context: %u\n", pdp
->teic_own
);
2308 for (n
= 0; n
< PDP_MAXNSAPI
; n
++)
2309 if (linked_pdp
->secondary_tei
[n
])
2312 LOGP(DLGTP
, LOGL_ERROR
,
2313 "Must use teardown for last context: %d\n", count
);
2318 if (pdp
->version
== 1) {
2320 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_TEARDOWN
,
2323 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_NSAPI
, pdp
->nsapi
);
2326 gtp_req(gsn
, pdp
->version
, pdp
, &packet
, length
, &addr
, cbp
);
2328 if (teardown
) { /* Remove all contexts */
2329 for (n
= 0; n
< PDP_MAXNSAPI
; n
++) {
2330 if (linked_pdp
->secondary_tei
[n
]) {
2333 linked_pdp
->secondary_tei
[n
])) {
2334 LOGP(DLGTP
, LOGL_ERROR
,
2335 "Unknown secondary PDP context\n");
2338 if (linked_pdp
!= secondary_pdp
) {
2339 if (gsn
->cb_delete_context
)
2340 gsn
->cb_delete_context
2342 pdp_freepdp(secondary_pdp
);
2346 if (gsn
->cb_delete_context
)
2347 gsn
->cb_delete_context(linked_pdp
);
2348 pdp_freepdp(linked_pdp
);
2350 if (gsn
->cb_delete_context
)
2351 gsn
->cb_delete_context(pdp
);
2352 if (pdp
== linked_pdp
) {
2353 linked_pdp
->secondary_tei
[pdp
->nsapi
& 0xf0] = 0;
2354 linked_pdp
->nodata
= 1;
2362 /* Send Delete PDP Context Response */
2363 int gtp_delete_pdp_resp(struct gsn_t
*gsn
, int version
,
2364 struct sockaddr_in
*peer
, int fd
,
2365 void *pack
, unsigned len
,
2366 struct pdp_t
*pdp
, struct pdp_t
*linked_pdp
,
2367 uint8_t cause
, int teardown
)
2369 union gtp_packet packet
;
2370 struct pdp_t
*secondary_pdp
;
2371 unsigned int length
=
2372 get_default_gtp(version
, GTP_DELETE_PDP_RSP
, &packet
);
2375 gtpie_tv1(&packet
, &length
, GTP_MAX
, GTPIE_CAUSE
, cause
);
2377 gtp_resp(version
, gsn
, pdp
, &packet
, length
, peer
, fd
,
2378 get_seq(pack
), get_tid(pack
));
2380 if (cause
== GTPCAUSE_ACC_REQ
) {
2381 if ((teardown
) || (version
== 0)) { /* Remove all contexts */
2382 for (n
= 0; n
< PDP_MAXNSAPI
; n
++) {
2383 if (linked_pdp
->secondary_tei
[n
]) {
2386 linked_pdp
->secondary_tei
[n
])) {
2387 LOGP(DLGTP
, LOGL_ERROR
,
2388 "Unknown secondary PDP context\n");
2391 if (linked_pdp
!= secondary_pdp
) {
2392 if (gsn
->cb_delete_context
)
2393 gsn
->cb_delete_context
2395 pdp_freepdp(secondary_pdp
);
2399 if (gsn
->cb_delete_context
)
2400 gsn
->cb_delete_context(linked_pdp
);
2401 pdp_freepdp(linked_pdp
);
2402 } else { /* Remove only current context */
2403 if (gsn
->cb_delete_context
)
2404 gsn
->cb_delete_context(pdp
);
2405 if (pdp
== linked_pdp
) {
2406 linked_pdp
->secondary_tei
[pdp
->nsapi
& 0xf0] =
2408 linked_pdp
->nodata
= 1;
2413 /* if (cause == GTPCAUSE_ACC_REQ) */
2417 /* Handle Delete PDP Context Request */
2418 int gtp_delete_pdp_ind(struct gsn_t
*gsn
, int version
,
2419 struct sockaddr_in
*peer
, int fd
,
2420 void *pack
, unsigned len
)
2422 struct pdp_t
*pdp
= NULL
;
2423 struct pdp_t
*linked_pdp
= NULL
;
2424 union gtpie_member
*ie
[GTPIE_SIZE
];
2426 uint16_t seq
= get_seq(pack
);
2427 int hlen
= get_hlen(pack
);
2430 uint8_t teardown
= 0;
2434 /* Is this a dublicate ? */
2435 if (!gtp_dublicate(gsn
, version
, peer
, seq
)) {
2436 return 0; /* We allready send off response once */
2439 /* Find the linked context in question */
2440 if (pdp_getgtp1(&linked_pdp
, get_tei(pack
))) {
2441 gsn
->err_unknownpdp
++;
2442 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2443 "Unknown PDP context: %u\n", get_tei(pack
));
2444 return gtp_delete_pdp_resp(gsn
, version
, peer
, fd
, pack
, len
,
2445 NULL
, NULL
, GTPCAUSE_NON_EXIST
,
2449 /* If version 0 this is also the secondary context */
2453 /* Decode information elements */
2454 if (gtpie_decaps(ie
, version
, pack
+ hlen
, len
- hlen
)) {
2456 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2457 "Invalid message format\n");
2461 return gtp_delete_pdp_resp(gsn
, version
, peer
, fd
, pack
,
2463 GTPCAUSE_INVALID_MESSAGE
,
2468 /* NSAPI (mandatory) */
2469 if (gtpie_gettv1(ie
, GTPIE_NSAPI
, 0, &nsapi
)) {
2471 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
2472 len
, "Missing mandatory information field\n");
2473 return gtp_delete_pdp_resp(gsn
, version
, peer
, fd
, pack
,
2475 GTPCAUSE_MAN_IE_MISSING
,
2479 /* Find the context in question */
2480 if (pdp_getgtp1(&pdp
, linked_pdp
->secondary_tei
[nsapi
& 0x0f])) {
2481 gsn
->err_unknownpdp
++;
2482 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
2483 len
, "Unknown PDP context\n");
2484 return gtp_delete_pdp_resp(gsn
, version
, peer
, fd
, pack
,
2490 /* Teardown (conditional) */
2491 gtpie_gettv1(ie
, GTPIE_TEARDOWN
, 0, &teardown
);
2494 for (n
= 0; n
< PDP_MAXNSAPI
; n
++)
2495 if (linked_pdp
->secondary_tei
[n
])
2498 return 0; /* 29.060 7.3.5 Ignore message */
2503 return gtp_delete_pdp_resp(gsn
, version
, peer
, fd
, pack
, len
,
2504 pdp
, linked_pdp
, GTPCAUSE_ACC_REQ
, teardown
);
2507 /* Handle Delete PDP Context Response */
2508 int gtp_delete_pdp_conf(struct gsn_t
*gsn
, int version
,
2509 struct sockaddr_in
*peer
, void *pack
, unsigned len
)
2511 union gtpie_member
*ie
[GTPIE_SIZE
];
2515 int hlen
= get_hlen(pack
);
2517 /* Remove packet from queue */
2518 if (gtp_conf(gsn
, version
, peer
, pack
, len
, &type
, &cbp
))
2521 /* Decode information elements */
2522 if (gtpie_decaps(ie
, version
, pack
+ hlen
, len
- hlen
)) {
2524 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2525 "Invalid message format\n");
2527 gsn
->cb_conf(type
, EOF
, NULL
, cbp
);
2531 /* Extract cause value (mandatory) */
2532 if (gtpie_gettv1(ie
, GTPIE_CAUSE
, 0, &cause
)) {
2534 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2535 "Missing mandatory information field\n");
2537 gsn
->cb_conf(type
, EOF
, NULL
, cbp
);
2541 /* Check the cause value (again) */
2542 if ((GTPCAUSE_ACC_REQ
!= cause
) && (GTPCAUSE_NON_EXIST
!= cause
)) {
2544 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2545 "Unexpected cause value received: %d\n", cause
);
2547 gsn
->cb_conf(type
, cause
, NULL
, cbp
);
2551 /* Callback function to notify application */
2553 gsn
->cb_conf(type
, cause
, NULL
, cbp
);
2558 /* Send Error Indication (response to a GPDU message */
2559 int gtp_error_ind_resp(struct gsn_t
*gsn
, int version
,
2560 struct sockaddr_in
*peer
, int fd
,
2561 void *pack
, unsigned len
)
2563 union gtp_packet packet
;
2564 unsigned int length
= get_default_gtp(version
, GTP_ERROR
, &packet
);
2566 return gtp_resp(version
, gsn
, NULL
, &packet
, length
, peer
, fd
,
2567 get_seq(pack
), get_tid(pack
));
2570 /* Handle Error Indication */
2571 int gtp_error_ind_conf(struct gsn_t
*gsn
, int version
,
2572 struct sockaddr_in
*peer
, void *pack
, unsigned len
)
2576 /* Find the context in question */
2577 if (pdp_tidget(&pdp
, be64toh(((union gtp_packet
*)pack
)->gtp0
.h
.tid
))) {
2578 gsn
->err_unknownpdp
++;
2579 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2580 "Unknown PDP context\n");
2584 gsn
->err_unknownpdp
++; /* TODO: Change counter */
2585 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2586 "Received Error Indication\n");
2588 if (gsn
->cb_delete_context
)
2589 gsn
->cb_delete_context(pdp
);
2594 int gtp_gpdu_ind(struct gsn_t
*gsn
, int version
,
2595 struct sockaddr_in
*peer
, int fd
, void *pack
, unsigned len
)
2598 int hlen
= GTP1_HEADER_SIZE_SHORT
;
2600 /* Need to include code to verify packet src and dest addresses */
2605 (&pdp
, ntoh16(((union gtp_packet
*)pack
)->gtp0
.h
.flow
))) {
2606 gsn
->err_unknownpdp
++;
2607 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
2608 len
, "Unknown PDP context\n");
2609 return gtp_error_ind_resp(gsn
, version
, peer
, fd
, pack
,
2612 hlen
= GTP0_HEADER_SIZE
;
2613 } else if (version
== 1) {
2615 (&pdp
, ntoh32(((union gtp_packet
*)pack
)->gtp1l
.h
.tei
))) {
2616 gsn
->err_unknownpdp
++;
2617 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
,
2618 len
, "Unknown PDP context\n");
2619 return gtp_error_ind_resp(gsn
, version
, peer
, fd
, pack
,
2623 /* Is this a long or a short header ? */
2624 if (((union gtp_packet
*)pack
)->gtp1l
.h
.flags
& 0x07)
2625 hlen
= GTP1_HEADER_SIZE_LONG
;
2627 hlen
= GTP1_HEADER_SIZE_SHORT
;
2629 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2630 "Unknown version: %d\n", version
);
2633 /* If the GPDU was not from the peer GSN tell him to delete context */
2634 if (memcmp(&peer
->sin_addr
, pdp
->gsnru
.v
, pdp
->gsnru
.l
)) { /* TODO Range? */
2635 gsn
->err_unknownpdp
++;
2636 GTP_LOGPKG(LOGL_ERROR
, peer
, pack
, len
,
2637 "Unknown PDP context\n");
2638 return gtp_error_ind_resp(gsn
, version
, peer
, fd
, pack
, len
);
2641 /* Callback function */
2642 if (gsn
->cb_data_ind
!= 0)
2643 return gsn
->cb_data_ind(pdp
, pack
+ hlen
, len
- hlen
);
2648 /* Receives GTP packet and sends off for further processing
2649 * Function will check the validity of the header. If the header
2650 * is not valid the packet is either dropped or a version not
2651 * supported is returned to the peer.
2652 * TODO: Need to decide on return values! */
2653 int gtp_decaps0(struct gsn_t
*gsn
)
2655 unsigned char buffer
[PACKET_MAX
];
2656 struct sockaddr_in peer
;
2659 struct gtp0_header
*pheader
;
2660 int version
= 0; /* GTP version should be determined from header! */
2663 /* TODO: Need strategy of userspace buffering and blocking */
2664 /* Currently read is non-blocking and send is blocking. */
2665 /* This means that the program have to wait for busy send calls... */
2667 while (1) { /* Loop until no more to read */
2668 if (fcntl(gsn
->fd0
, F_SETFL
, O_NONBLOCK
)) {
2669 LOGP(DLGTP
, LOGL_ERROR
, "fnctl()\n");
2672 peerlen
= sizeof(peer
);
2674 recvfrom(gsn
->fd0
, buffer
, sizeof(buffer
), 0,
2675 (struct sockaddr
*)&peer
, &peerlen
)) < 0) {
2676 if (errno
== EAGAIN
)
2678 gsn
->err_readfrom
++;
2679 LOGP(DLGTP
, LOGL_ERROR
,
2680 "recvfrom(fd0=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n",
2681 gsn
->fd0
, (unsigned long)buffer
, sizeof(buffer
),
2682 status
, status
? strerror(errno
) : "No error");
2686 /* Need at least 1 byte in order to check version */
2689 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2690 status
, "Discarding packet - too small\n");
2694 pheader
= (struct gtp0_header
*)(buffer
);
2696 /* Version should be gtp0 (or earlier) */
2697 /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
2698 /* GTP 0 messages. If other version message is received we reply that we */
2699 /* only support version 0, implying that this is the only version */
2700 /* supported on this port */
2701 if (((pheader
->flags
& 0xe0) > 0x00)) {
2703 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2704 status
, "Unsupported GTP version\n");
2705 gtp_unsup_req(gsn
, 0, &peer
, gsn
->fd0
, buffer
, status
); /* 29.60: 11.1.1 */
2709 /* Check length of gtp0 packet */
2710 if (status
< GTP0_HEADER_SIZE
) {
2712 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2713 status
, "GTP0 packet too short\n");
2714 continue; /* Silently discard 29.60: 11.1.2 */
2717 /* Check packet length field versus length of packet */
2718 if (status
!= (ntoh16(pheader
->length
) + GTP0_HEADER_SIZE
)) {
2720 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2722 "GTP packet length field does not match actual length\n");
2723 continue; /* Silently discard */
2726 if ((gsn
->mode
== GTP_MODE_GGSN
) &&
2727 ((pheader
->type
== GTP_CREATE_PDP_RSP
) ||
2728 (pheader
->type
== GTP_UPDATE_PDP_RSP
) ||
2729 (pheader
->type
== GTP_DELETE_PDP_RSP
))) {
2731 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2733 "Unexpected GTP Signalling Message\n");
2734 continue; /* Silently discard 29.60: 11.1.4 */
2737 if ((gsn
->mode
== GTP_MODE_SGSN
) &&
2738 ((pheader
->type
== GTP_CREATE_PDP_REQ
) ||
2739 (pheader
->type
== GTP_UPDATE_PDP_REQ
) ||
2740 (pheader
->type
== GTP_DELETE_PDP_REQ
))) {
2742 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2744 "Unexpected GTP Signalling Message\n");
2745 continue; /* Silently discard 29.60: 11.1.4 */
2748 switch (pheader
->type
) {
2750 gtp_echo_ind(gsn
, version
, &peer
, fd
, buffer
, status
);
2753 gtp_echo_conf(gsn
, version
, &peer
, buffer
, status
);
2755 case GTP_NOT_SUPPORTED
:
2756 gtp_unsup_ind(gsn
, &peer
, buffer
, status
);
2758 case GTP_CREATE_PDP_REQ
:
2759 gtp_create_pdp_ind(gsn
, version
, &peer
, fd
, buffer
,
2762 case GTP_CREATE_PDP_RSP
:
2763 gtp_create_pdp_conf(gsn
, version
, &peer
, buffer
,
2766 case GTP_UPDATE_PDP_REQ
:
2767 gtp_update_pdp_ind(gsn
, version
, &peer
, fd
, buffer
,
2770 case GTP_UPDATE_PDP_RSP
:
2771 gtp_update_pdp_conf(gsn
, version
, &peer
, buffer
,
2774 case GTP_DELETE_PDP_REQ
:
2775 gtp_delete_pdp_ind(gsn
, version
, &peer
, fd
, buffer
,
2778 case GTP_DELETE_PDP_RSP
:
2779 gtp_delete_pdp_conf(gsn
, version
, &peer
, buffer
,
2783 gtp_error_ind_conf(gsn
, version
, &peer
, buffer
, status
);
2786 gtp_gpdu_ind(gsn
, version
, &peer
, fd
, buffer
, status
);
2790 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
, status
,
2791 "Unknown GTP message type received: %d\n",
2798 int gtp_decaps1c(struct gsn_t
*gsn
)
2800 unsigned char buffer
[PACKET_MAX
];
2801 struct sockaddr_in peer
;
2804 struct gtp1_header_short
*pheader
;
2805 int version
= 1; /* TODO GTP version should be determined from header! */
2808 /* TODO: Need strategy of userspace buffering and blocking */
2809 /* Currently read is non-blocking and send is blocking. */
2810 /* This means that the program have to wait for busy send calls... */
2812 while (1) { /* Loop until no more to read */
2813 if (fcntl(fd
, F_SETFL
, O_NONBLOCK
)) {
2814 LOGP(DLGTP
, LOGL_ERROR
, "fnctl()\n");
2817 peerlen
= sizeof(peer
);
2819 recvfrom(fd
, buffer
, sizeof(buffer
), 0,
2820 (struct sockaddr
*)&peer
, &peerlen
)) < 0) {
2821 if (errno
== EAGAIN
)
2823 gsn
->err_readfrom
++;
2824 LOGP(DLGTP
, LOGL_ERROR
,
2825 "recvfrom(fd=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n",
2826 fd
, (unsigned long)buffer
, sizeof(buffer
),
2827 status
, status
? strerror(errno
) : "No error");
2831 /* Need at least 1 byte in order to check version */
2834 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2835 status
, "Discarding packet - too small\n");
2839 pheader
= (struct gtp1_header_short
*)(buffer
);
2841 /* Version must be no larger than GTP 1 */
2842 if (((pheader
->flags
& 0xe0) > 0x20)) {
2844 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2845 status
, "Unsupported GTP version\n");
2846 gtp_unsup_req(gsn
, version
, &peer
, fd
, buffer
, status
);
2851 /* Version must be at least GTP 1 */
2852 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
2853 /* GTP 1 messages. If GTP 0 message is received we silently discard */
2855 if (((pheader
->flags
& 0xe0) < 0x20)) {
2857 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2858 status
, "Unsupported GTP version\n");
2862 /* Check packet flag field */
2863 if (((pheader
->flags
& 0xf7) != 0x32)) {
2865 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2866 status
, "Unsupported packet flags: 0x%02x\n", pheader
->flags
);
2870 /* Check length of packet */
2871 if (status
< GTP1_HEADER_SIZE_LONG
) {
2873 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2874 status
, "GTP packet too short\n");
2875 continue; /* Silently discard 29.60: 11.1.2 */
2878 /* Check packet length field versus length of packet */
2880 (ntoh16(pheader
->length
) + GTP1_HEADER_SIZE_SHORT
)) {
2882 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2884 "GTP packet length field does not match actual length\n");
2885 continue; /* Silently discard */
2888 /* Check for extension headers */
2889 /* TODO: We really should cycle through the headers and determine */
2890 /* if any have the comprehension required flag set */
2891 if (((pheader
->flags
& 0x04) != 0x00)) {
2893 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2894 status
, "Unsupported extension header\n");
2895 gtp_extheader_req(gsn
, version
, &peer
, fd
, buffer
,
2901 if ((gsn
->mode
== GTP_MODE_GGSN
) &&
2902 ((pheader
->type
== GTP_CREATE_PDP_RSP
) ||
2903 (pheader
->type
== GTP_UPDATE_PDP_RSP
) ||
2904 (pheader
->type
== GTP_DELETE_PDP_RSP
))) {
2906 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2908 "Unexpected GTP Signalling Message\n");
2909 continue; /* Silently discard 29.60: 11.1.4 */
2912 if ((gsn
->mode
== GTP_MODE_SGSN
) &&
2913 ((pheader
->type
== GTP_CREATE_PDP_REQ
) ||
2914 (pheader
->type
== GTP_UPDATE_PDP_REQ
) ||
2915 (pheader
->type
== GTP_DELETE_PDP_REQ
))) {
2917 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
2919 "Unexpected GTP Signalling Message\n");
2920 continue; /* Silently discard 29.60: 11.1.4 */
2923 switch (pheader
->type
) {
2925 gtp_echo_ind(gsn
, version
, &peer
, fd
, buffer
, status
);
2928 gtp_echo_conf(gsn
, version
, &peer
, buffer
, status
);
2930 case GTP_NOT_SUPPORTED
:
2931 gtp_unsup_ind(gsn
, &peer
, buffer
, status
);
2933 case GTP_SUPP_EXT_HEADER
:
2934 gtp_extheader_ind(gsn
, &peer
, buffer
, status
);
2936 case GTP_CREATE_PDP_REQ
:
2937 gtp_create_pdp_ind(gsn
, version
, &peer
, fd
, buffer
,
2940 case GTP_CREATE_PDP_RSP
:
2941 gtp_create_pdp_conf(gsn
, version
, &peer
, buffer
,
2944 case GTP_UPDATE_PDP_REQ
:
2945 gtp_update_pdp_ind(gsn
, version
, &peer
, fd
, buffer
,
2948 case GTP_UPDATE_PDP_RSP
:
2949 gtp_update_pdp_conf(gsn
, version
, &peer
, buffer
,
2952 case GTP_DELETE_PDP_REQ
:
2953 gtp_delete_pdp_ind(gsn
, version
, &peer
, fd
, buffer
,
2956 case GTP_DELETE_PDP_RSP
:
2957 gtp_delete_pdp_conf(gsn
, version
, &peer
, buffer
,
2961 gtp_error_ind_conf(gsn
, version
, &peer
, buffer
, status
);
2965 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
, status
,
2966 "Unknown GTP message type received: %u\n",
2973 int gtp_decaps1u(struct gsn_t
*gsn
)
2975 unsigned char buffer
[PACKET_MAX
];
2976 struct sockaddr_in peer
;
2979 struct gtp1_header_short
*pheader
;
2980 int version
= 1; /* GTP version should be determined from header! */
2983 /* TODO: Need strategy of userspace buffering and blocking */
2984 /* Currently read is non-blocking and send is blocking. */
2985 /* This means that the program have to wait for busy send calls... */
2987 while (1) { /* Loop until no more to read */
2988 if (fcntl(gsn
->fd1u
, F_SETFL
, O_NONBLOCK
)) {
2989 LOGP(DLGTP
, LOGL_ERROR
, "fnctl()\n");
2992 peerlen
= sizeof(peer
);
2994 recvfrom(gsn
->fd1u
, buffer
, sizeof(buffer
), 0,
2995 (struct sockaddr
*)&peer
, &peerlen
)) < 0) {
2996 if (errno
== EAGAIN
)
2998 gsn
->err_readfrom
++;
2999 LOGP(DLGTP
, LOGL_ERROR
,
3000 "recvfrom(fd1u=%d, buffer=%lx, len=%zu) failed: status = %d error = %s\n",
3001 gsn
->fd1u
, (unsigned long)buffer
,
3002 sizeof(buffer
), status
,
3003 status
? strerror(errno
) : "No error");
3007 /* Need at least 1 byte in order to check version */
3010 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
3011 status
, "Discarding packet - too small\n");
3015 pheader
= (struct gtp1_header_short
*)(buffer
);
3017 /* Version must be no larger than GTP 1 */
3018 if (((pheader
->flags
& 0xe0) > 0x20)) {
3020 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
3021 status
, "Unsupported GTP version\n");
3022 gtp_unsup_req(gsn
, 1, &peer
, gsn
->fd1c
, buffer
, status
); /*29.60: 11.1.1 */
3026 /* Version must be at least GTP 1 */
3027 /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
3028 /* GTP 1 messages. If GTP 0 message is received we silently discard */
3030 if (((pheader
->flags
& 0xe0) < 0x20)) {
3032 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
3033 status
, "Unsupported GTP version\n");
3037 /* Check packet flag field (allow both with and without sequence number) */
3038 if (((pheader
->flags
& 0xf5) != 0x30)) {
3040 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
3041 status
, "Unsupported packet flags 0x%02x\n", pheader
->flags
);
3045 /* Check length of packet */
3046 if (status
< GTP1_HEADER_SIZE_SHORT
) {
3048 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
3049 status
, "GTP packet too short\n");
3050 continue; /* Silently discard 29.60: 11.1.2 */
3053 /* Check packet length field versus length of packet */
3055 (ntoh16(pheader
->length
) + GTP1_HEADER_SIZE_SHORT
)) {
3057 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
3059 "GTP packet length field does not match actual length\n");
3060 continue; /* Silently discard */
3063 /* Check for extension headers */
3064 /* TODO: We really should cycle through the headers and determine */
3065 /* if any have the comprehension required flag set */
3066 if (((pheader
->flags
& 0x04) != 0x00)) {
3068 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
,
3069 status
, "Unsupported extension header\n");
3070 gtp_extheader_req(gsn
, version
, &peer
, fd
, buffer
,
3076 switch (pheader
->type
) {
3078 gtp_echo_ind(gsn
, version
, &peer
, fd
, buffer
, status
);
3081 gtp_echo_conf(gsn
, version
, &peer
, buffer
, status
);
3083 case GTP_SUPP_EXT_HEADER
:
3084 gtp_extheader_ind(gsn
, &peer
, buffer
, status
);
3087 gtp_error_ind_conf(gsn
, version
, &peer
, buffer
, status
);
3089 /* Supported header extensions */
3091 gtp_gpdu_ind(gsn
, version
, &peer
, fd
, buffer
, status
);
3095 GTP_LOGPKG(LOGL_ERROR
, &peer
, buffer
, status
,
3096 "Unknown GTP message type received: %u\n",
3103 int gtp_data_req(struct gsn_t
*gsn
, struct pdp_t
*pdp
, void *pack
, unsigned len
)
3105 union gtp_packet packet
;
3106 struct sockaddr_in addr
;
3110 memset(&addr
, 0, sizeof(addr
));
3111 addr
.sin_family
= AF_INET
;
3112 #if defined(__FreeBSD__) || defined(__APPLE__)
3113 addr
.sin_len
= sizeof(addr
);
3116 memcpy(&addr
.sin_addr
, pdp
->gsnru
.v
, pdp
->gsnru
.l
); /* TODO range check */
3118 if (pdp
->version
== 0) {
3120 length
= GTP0_HEADER_SIZE
+ len
;
3121 addr
.sin_port
= htons(GTP0_PORT
);
3124 get_default_gtp(0, GTP_GPDU
, &packet
);
3125 packet
.gtp0
.h
.length
= hton16(len
);
3126 packet
.gtp0
.h
.seq
= hton16(pdp
->gtpsntx
++);
3127 packet
.gtp0
.h
.flow
= hton16(pdp
->flru
);
3128 packet
.gtp0
.h
.tid
= htobe64(pdp_gettid(pdp
->imsi
, pdp
->nsapi
));
3130 if (len
> sizeof(union gtp_packet
) - sizeof(struct gtp0_header
)) {
3132 LOGP(DLGTP
, LOGL_ERROR
,
3133 "Memcpy failed: %u > %zu\n", len
,
3134 sizeof(union gtp_packet
) -
3135 sizeof(struct gtp0_header
));
3138 memcpy(packet
.gtp0
.p
, pack
, len
); /* TODO Should be avoided! */
3139 } else if (pdp
->version
== 1) {
3141 length
= GTP1_HEADER_SIZE_LONG
+ len
;
3142 addr
.sin_port
= htons(GTP1U_PORT
);
3145 get_default_gtp(1, GTP_GPDU
, &packet
);
3146 packet
.gtp1l
.h
.length
= hton16(len
- GTP1_HEADER_SIZE_SHORT
+
3147 GTP1_HEADER_SIZE_LONG
);
3148 packet
.gtp1l
.h
.seq
= hton16(pdp
->gtpsntx
++);
3149 packet
.gtp1l
.h
.tei
= hton32(pdp
->teid_gn
);
3152 sizeof(union gtp_packet
) -
3153 sizeof(struct gtp1_header_long
)) {
3155 LOGP(DLGTP
, LOGL_ERROR
,
3156 "Memcpy failed: %u > %zu\n", len
,
3157 sizeof(union gtp_packet
) -
3158 sizeof(struct gtp0_header
));
3161 memcpy(packet
.gtp1l
.p
, pack
, len
); /* TODO Should be avoided! */
3163 LOGP(DLGTP
, LOGL_ERROR
, "Unknown version: %d\n", pdp
->version
);
3167 if (fcntl(fd
, F_SETFL
, 0)) {
3168 LOGP(DLGTP
, LOGL_ERROR
, "fnctl()\n");
3172 if (sendto(fd
, &packet
, length
, 0,
3173 (struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
3175 LOGP(DLGTP
, LOGL_ERROR
,
3176 "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd
,
3177 (unsigned long)&packet
, GTP0_HEADER_SIZE
+ len
,
3184 /* ***********************************************************
3185 * Conversion functions
3186 *************************************************************/
3188 int char2ul_t(char *src
, struct ul_t dst
)
3190 dst
.l
= strlen(src
) + 1;
3191 dst
.v
= malloc(dst
.l
);
3192 dst
.v
[0] = dst
.l
- 1;
3193 memcpy(&dst
.v
[1], src
, dst
.v
[0]);
3197 /* ***********************************************************
3198 * IP address conversion functions
3199 * There exist several types of address representations:
3200 * - eua: End User Address. (29.060, 7.7.27, message type 128)
3201 * Used for signalling address to mobile station. Supports IPv4
3202 * IPv6 x.25 etc. etc.
3203 * - gsna: GSN Address. (29.060, 7.7.32, message type 133): IP address
3204 * of GSN. If length is 4 it is IPv4. If length is 16 it is IPv6.
3205 * - in_addr: IPv4 address struct.
3206 * - sockaddr_in: Socket API representation of IP address and
3208 *************************************************************/
3210 int ipv42eua(struct ul66_t
*eua
, struct in_addr
*src
)
3212 eua
->v
[0] = 0xf1; /* IETF */
3213 eua
->v
[1] = 0x21; /* IPv4 */
3216 memcpy(&eua
->v
[2], src
, 4);
3223 int eua2ipv4(struct in_addr
*dst
, struct ul66_t
*eua
)
3225 if ((eua
->l
!= 6) || (eua
->v
[0] != 0xf1) || (eua
->v
[1] = 0x21))
3226 return -1; /* Not IPv4 address */
3227 memcpy(dst
, &eua
->v
[2], 4);
3231 int gsna2in_addr(struct in_addr
*dst
, struct ul16_t
*gsna
)
3233 memset(dst
, 0, sizeof(struct in_addr
));
3235 return EOF
; /* Return if not IPv4 */
3236 memcpy(dst
, gsna
->v
, gsna
->l
);
3240 int in_addr2gsna(struct ul16_t
*gsna
, struct in_addr
*src
)
3242 memset(gsna
, 0, sizeof(struct ul16_t
));
3244 memcpy(gsna
->v
, src
, gsna
->l
);