aboutsummaryrefslogtreecommitdiffstats
path: root/gtp/gtp.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-11-02 13:06:18 +0100
committerHarald Welte <laforge@gnumonks.org>2011-11-02 13:06:18 +0100
commitbed35df298f4914fabedfc7c9387af3f2f9a9e9f (patch)
tree0079fe22d0839637d8c777d2eebb91cd35b065c2 /gtp/gtp.c
parentca36f293648ee19056df7ea9a1cbfcc93c800dc8 (diff)
Convert all code to Linux coding style
After so many years of silence, we don't expect the original author to return to the project. To make things a bit simpler for us, we convert the coding style to what we are used to (Linux style). The conversion was made using the 'Lindent' script which is part of the Linux kernel.
Diffstat (limited to 'gtp/gtp.c')
-rw-r--r--gtp/gtp.c5425
1 files changed, 2804 insertions, 2621 deletions
diff --git a/gtp/gtp.c b/gtp/gtp.c
index 4f75fd5..768d8c7 100644
--- a/gtp/gtp.c
+++ b/gtp/gtp.c
@@ -17,7 +17,6 @@
* - Do we need to handle fragmentation?
*/
-
#ifdef __linux__
#define _GNU_SOURCE 1
#endif
@@ -52,128 +51,127 @@
#include "gtpie.h"
#include "queue.h"
-
/* Error reporting functions */
-void gtp_err(int priority, char *filename, int linenum, char *fmt, ...) {
- va_list args;
- char buf[ERRMSG_SIZE];
-
- va_start(args, fmt);
- vsnprintf(buf, ERRMSG_SIZE, fmt, args);
- va_end(args);
- buf[ERRMSG_SIZE-1] = 0;
- syslog(priority, "%s: %d: %s", filename, linenum, buf);
+void gtp_err(int priority, char *filename, int linenum, char *fmt, ...)
+{
+ va_list args;
+ char buf[ERRMSG_SIZE];
+
+ va_start(args, fmt);
+ vsnprintf(buf, ERRMSG_SIZE, fmt, args);
+ va_end(args);
+ buf[ERRMSG_SIZE - 1] = 0;
+ syslog(priority, "%s: %d: %s", filename, linenum, buf);
}
void gtp_errpack(int pri, char *fn, int ln, struct sockaddr_in *peer,
- void *pack, unsigned len, char *fmt, ...) {
-
- va_list args;
- char buf[ERRMSG_SIZE];
- char buf2[ERRMSG_SIZE];
- unsigned int n;
- int pos;
-
- va_start(args, fmt);
- vsnprintf(buf, ERRMSG_SIZE, fmt, args);
- va_end(args);
- buf[ERRMSG_SIZE-1] = 0;
-
- snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:",
- inet_ntoa(peer->sin_addr),
- ntohs(peer->sin_port),
- len);
- buf2[ERRMSG_SIZE-1] = 0;
- pos = strlen(buf2);
- for(n=0; n<len; n++) {
- if ((pos+4)<ERRMSG_SIZE) {
- sprintf((buf2+pos), " %02hhx", ((unsigned char*)pack)[n]);
- pos += 3;
- }
- }
- buf2[pos] = 0;
-
- syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
-
-}
+ void *pack, unsigned len, char *fmt, ...)
+{
+ va_list args;
+ char buf[ERRMSG_SIZE];
+ char buf2[ERRMSG_SIZE];
+ unsigned int n;
+ int pos;
+
+ va_start(args, fmt);
+ vsnprintf(buf, ERRMSG_SIZE, fmt, args);
+ va_end(args);
+ buf[ERRMSG_SIZE - 1] = 0;
+
+ snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:",
+ inet_ntoa(peer->sin_addr), ntohs(peer->sin_port), len);
+ buf2[ERRMSG_SIZE - 1] = 0;
+ pos = strlen(buf2);
+ for (n = 0; n < len; n++) {
+ if ((pos + 4) < ERRMSG_SIZE) {
+ sprintf((buf2 + pos), " %02hhx",
+ ((unsigned char *)pack)[n]);
+ pos += 3;
+ }
+ }
+ buf2[pos] = 0;
+ syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
+}
/* API Functions */
-const char* gtp_version()
+const char *gtp_version()
{
- return VERSION;
+ return VERSION;
}
/* gtp_new */
/* gtp_free */
-int gtp_newpdp(struct gsn_t* gsn, struct pdp_t **pdp,
- uint64_t imsi, uint8_t nsapi) {
- return pdp_newpdp(pdp, imsi, nsapi, NULL);
+int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
+ uint64_t imsi, uint8_t nsapi)
+{
+ return pdp_newpdp(pdp, imsi, nsapi, NULL);
}
-int gtp_freepdp(struct gsn_t* gsn, struct pdp_t *pdp) {
- return pdp_freepdp(pdp);
+int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp)
+{
+ return pdp_freepdp(pdp);
}
/* gtp_gpdu */
-extern int gtp_fd(struct gsn_t *gsn) {
- return gsn->fd0;
+extern int gtp_fd(struct gsn_t *gsn)
+{
+ return gsn->fd0;
}
/* gtp_decaps */
/* gtp_retrans */
/* gtp_retranstimeout */
-
int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in *peer)) {
- gsn->cb_unsup_ind = cb;
- return 0;
+ int (*cb) (struct sockaddr_in * peer))
+{
+ gsn->cb_unsup_ind = cb;
+ return 0;
}
int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in *peer)) {
- gsn->cb_extheader_ind = cb;
- return 0;
+ int (*cb) (struct sockaddr_in * peer))
+{
+ gsn->cb_extheader_ind = cb;
+ return 0;
}
-
/* API: Initialise delete context callback */
/* Called whenever a pdp context is deleted for any reason */
-int gtp_set_cb_delete_context(struct gsn_t *gsn,
- int (*cb) (struct pdp_t* pdp))
+int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb) (struct pdp_t * pdp))
{
- gsn->cb_delete_context = cb;
- return 0;
+ gsn->cb_delete_context = cb;
+ return 0;
}
int gtp_set_cb_conf(struct gsn_t *gsn,
- int (*cb) (int type, int cause,
- struct pdp_t* pdp, void *cbp)) {
- gsn->cb_conf = cb;
- return 0;
+ int (*cb) (int type, int cause,
+ struct pdp_t * pdp, void *cbp))
+{
+ gsn->cb_conf = cb;
+ return 0;
}
int gtp_set_cb_recovery(struct gsn_t *gsn,
- int (*cb) (struct sockaddr_in *peer,
- uint8_t recovery)) {
- gsn->cb_recovery = cb;
- return 0;
+ int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
+{
+ gsn->cb_recovery = cb;
+ return 0;
}
extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
- int (*cb_data_ind) (struct pdp_t* pdp,
- void* pack,
- unsigned len))
+ int (*cb_data_ind) (struct pdp_t * pdp,
+ void *pack, unsigned len))
{
- gsn->cb_data_ind = cb_data_ind;
- return 0;
+ gsn->cb_data_ind = cb_data_ind;
+ return 0;
}
/**
@@ -184,35 +182,38 @@ extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
* to hold the packet header.
* returns the length of the header. 0 on error.
**/
-static unsigned int get_default_gtp(int version, uint8_t type, void *packet) {
- struct gtp0_header *gtp0_default = (struct gtp0_header*) packet;
- struct gtp1_header_long *gtp1_default = (struct gtp1_header_long*) packet;
- switch (version) {
- case 0:
- /* Initialise "standard" GTP0 header */
- memset(gtp0_default, 0, sizeof(struct gtp0_header));
- gtp0_default->flags=0x1e;
- gtp0_default->type=hton8(type);
- gtp0_default->spare1=0xff;
- gtp0_default->spare2=0xff;
- gtp0_default->spare3=0xff;
- gtp0_default->number=0xff;
- return GTP0_HEADER_SIZE;
- case 1:
- /* Initialise "standard" GTP1 header */
- /* 29.060: 8.2: S=1 and PN=0 */
- /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */
- /* and Supported Extension Headers Notification, the S field shall be */
- /* set to 1 */
- /* Currently extension headers are not supported */
- memset(gtp1_default, 0, sizeof(struct gtp1_header_long));
- gtp1_default->flags=0x32; /* No extension, enable sequence, no N-PDU */
- gtp1_default->type=hton8(type);
- return GTP1_HEADER_SIZE_LONG;
- default:
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown GTP packet version");
- return 0;
- }
+static unsigned int get_default_gtp(int version, uint8_t type, void *packet)
+{
+ struct gtp0_header *gtp0_default = (struct gtp0_header *)packet;
+ struct gtp1_header_long *gtp1_default =
+ (struct gtp1_header_long *)packet;
+ switch (version) {
+ case 0:
+ /* Initialise "standard" GTP0 header */
+ memset(gtp0_default, 0, sizeof(struct gtp0_header));
+ gtp0_default->flags = 0x1e;
+ gtp0_default->type = hton8(type);
+ gtp0_default->spare1 = 0xff;
+ gtp0_default->spare2 = 0xff;
+ gtp0_default->spare3 = 0xff;
+ gtp0_default->number = 0xff;
+ return GTP0_HEADER_SIZE;
+ case 1:
+ /* Initialise "standard" GTP1 header */
+ /* 29.060: 8.2: S=1 and PN=0 */
+ /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */
+ /* and Supported Extension Headers Notification, the S field shall be */
+ /* set to 1 */
+ /* Currently extension headers are not supported */
+ memset(gtp1_default, 0, sizeof(struct gtp1_header_long));
+ gtp1_default->flags = 0x32; /* No extension, enable sequence, no N-PDU */
+ gtp1_default->type = hton8(type);
+ return GTP1_HEADER_SIZE_LONG;
+ default:
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Unknown GTP packet version");
+ return 0;
+ }
}
/**
@@ -220,18 +221,18 @@ static unsigned int get_default_gtp(int version, uint8_t type, void *packet) {
* Get sequence number of a packet.
* Returns 0 on error
**/
-static uint16_t get_seq(void *pack) {
- union gtp_packet *packet = (union gtp_packet *) pack;
-
- if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
- return ntoh16(packet->gtp0.h.seq);
- }
- else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
- return ntoh16(packet->gtp1l.h.seq);
- } else {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
- return 0;
- }
+static uint16_t get_seq(void *pack)
+{
+ union gtp_packet *packet = (union gtp_packet *)pack;
+
+ if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
+ return ntoh16(packet->gtp0.h.seq);
+ } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
+ return ntoh16(packet->gtp1l.h.seq);
+ } else {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
+ return 0;
+ }
}
/**
@@ -239,13 +240,14 @@ static uint16_t get_seq(void *pack) {
* Get tunnel identifier of a packet.
* Returns 0 on error
**/
-static uint64_t get_tid(void *pack) {
- union gtp_packet *packet = (union gtp_packet *) pack;
-
- if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
- return packet->gtp0.h.tid;
- }
- return 0;
+static uint64_t get_tid(void *pack)
+{
+ union gtp_packet *packet = (union gtp_packet *)pack;
+
+ if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
+ return packet->gtp0.h.tid;
+ }
+ return 0;
}
/**
@@ -253,21 +255,20 @@ static uint64_t get_tid(void *pack) {
* Get the header length of a packet.
* Returns 0 on error
**/
-static uint16_t get_hlen(void *pack) {
- union gtp_packet *packet = (union gtp_packet *) pack;
-
- if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
- return GTP0_HEADER_SIZE;
- }
- else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
- return GTP1_HEADER_SIZE_LONG;
- }
- else if ((packet->flags & 0xe7) == 0x20) { /* Short version 1 */
- return GTP1_HEADER_SIZE_SHORT;
- } else {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
- return 0;
- }
+static uint16_t get_hlen(void *pack)
+{
+ union gtp_packet *packet = (union gtp_packet *)pack;
+
+ if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
+ return GTP0_HEADER_SIZE;
+ } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
+ return GTP1_HEADER_SIZE_LONG;
+ } else if ((packet->flags & 0xe7) == 0x20) { /* Short version 1 */
+ return GTP1_HEADER_SIZE_SHORT;
+ } else {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
+ return 0;
+ }
}
/**
@@ -275,55 +276,53 @@ static uint16_t get_hlen(void *pack) {
* Get the tunnel endpoint identifier (flow label) of a packet.
* Returns 0xffffffff on error.
**/
-static uint32_t get_tei(void *pack) {
- union gtp_packet *packet = (union gtp_packet *) pack;
-
- if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
- return ntoh16(packet->gtp0.h.flow);
- }
- else if ((packet->flags & 0xe0) == 0x20) { /* Version 1 */
- return ntoh32(packet->gtp1l.h.tei);
- }
- else {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
- return 0xffffffff;
- }
+static uint32_t get_tei(void *pack)
+{
+ union gtp_packet *packet = (union gtp_packet *)pack;
+
+ if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
+ return ntoh16(packet->gtp0.h.flow);
+ } else if ((packet->flags & 0xe0) == 0x20) { /* Version 1 */
+ return ntoh32(packet->gtp1l.h.tei);
+ } else {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
+ return 0xffffffff;
+ }
}
-
int print_packet(void *packet, unsigned len)
{
- unsigned int i;
- printf("The packet looks like this (%d bytes):\n", len);
- for( i=0; i<len; i++) {
- printf("%02x ", (unsigned char)*(char *)(packet+i));
- if (!((i+1)%16)) printf("\n");
- };
- printf("\n");
- return 0;
+ unsigned int i;
+ printf("The packet looks like this (%d bytes):\n", len);
+ for (i = 0; i < len; i++) {
+ printf("%02x ", (unsigned char)*(char *)(packet + i));
+ if (!((i + 1) % 16))
+ printf("\n");
+ };
+ printf("\n");
+ return 0;
}
-char* snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer,
- void *pack, unsigned len, char *buf, int size) {
- unsigned int n;
- int pos;
- snprintf(buf, size, "Packet from %s:%u, length: %d, content:",
- inet_ntoa(peer->sin_addr),
- ntohs(peer->sin_port),
- len);
- buf[size-1] = 0;
- pos = strlen(buf);
- for(n=0; n<len; n++) {
- if ((pos+4)<size) {
- sprintf((buf+pos), " %02hhx", ((unsigned char*)pack)[n]);
- pos += 3;
- }
- }
- buf[pos] = 0;
- return buf;
+char *snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer,
+ void *pack, unsigned len, char *buf, int size)
+{
+ unsigned int n;
+ int pos;
+ snprintf(buf, size, "Packet from %s:%u, length: %d, content:",
+ inet_ntoa(peer->sin_addr), ntohs(peer->sin_port), len);
+ buf[size - 1] = 0;
+ pos = strlen(buf);
+ for (n = 0; n < len; n++) {
+ if ((pos + 4) < size) {
+ sprintf((buf + pos), " %02hhx",
+ ((unsigned char *)pack)[n]);
+ pos += 3;
+ }
+ }
+ buf[pos] = 0;
+ return buf;
}
-
/* ***********************************************************
* Reliable delivery of signalling messages
*
@@ -403,71 +402,74 @@ char* snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer,
*************************************************************/
int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp,
- union gtp_packet *packet, int len,
- struct in_addr *inetaddr, void *cbp) {
- struct sockaddr_in addr;
- struct qmsg_t *qmsg;
- int fd;
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = *inetaddr;
+ union gtp_packet *packet, int len,
+ struct in_addr *inetaddr, void *cbp)
+{
+ struct sockaddr_in addr;
+ struct qmsg_t *qmsg;
+ int fd;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr = *inetaddr;
#if defined(__FreeBSD__) || defined(__APPLE__)
- addr.sin_len = sizeof(addr);
+ addr.sin_len = sizeof(addr);
#endif
- if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
- addr.sin_port = htons(GTP0_PORT);
- packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
- packet->gtp0.h.seq = hton16(gsn->seq_next);
- if (pdp)
- packet->gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffffull) +
- ((uint64_t)pdp->nsapi << 60);
- if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
- (packet->gtp0.h.type == GTP_ERROR)))
- packet->gtp0.h.flow=hton16(pdp->flru);
- else if (pdp)
- packet->gtp0.h.flow=hton16(pdp->flrc);
- fd = gsn->fd0;
- }
- else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
- addr.sin_port = htons(GTP1C_PORT);
- packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
- packet->gtp1l.h.seq = hton16(gsn->seq_next);
- if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) ||
- (packet->gtp1l.h.type == GTP_ERROR)))
- packet->gtp1l.h.tei=hton32(pdp->teid_gn);
- else if (pdp)
- packet->gtp1l.h.tei=hton32(pdp->teic_gn);
- fd = gsn->fd1c;
- } else {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
- return -1;
- }
-
- if (sendto(fd, packet, len, 0,
- (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- gsn->err_sendto++;
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno));
- return -1;
- }
-
- /* Use new queue structure */
- if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) {
- gsn->err_queuefull++;
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full");
- }
- else {
- memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
- qmsg->l = len;
- qmsg->timeout = time(NULL) + 3; /* When to timeout */
- qmsg->retrans = 0; /* No retransmissions so far */
- qmsg->cbp = cbp;
- qmsg->type = ntoh8(packet->gtp0.h.type);
- qmsg->fd = fd;
- }
- gsn->seq_next++; /* Count up this time */
- return 0;
+ if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
+ addr.sin_port = htons(GTP0_PORT);
+ packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
+ packet->gtp0.h.seq = hton16(gsn->seq_next);
+ if (pdp)
+ packet->gtp0.h.tid =
+ (pdp->imsi & 0x0fffffffffffffffull) +
+ ((uint64_t) pdp->nsapi << 60);
+ if (pdp && ((packet->gtp0.h.type == GTP_GPDU)
+ || (packet->gtp0.h.type == GTP_ERROR)))
+ packet->gtp0.h.flow = hton16(pdp->flru);
+ else if (pdp)
+ packet->gtp0.h.flow = hton16(pdp->flrc);
+ fd = gsn->fd0;
+ } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
+ addr.sin_port = htons(GTP1C_PORT);
+ packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
+ packet->gtp1l.h.seq = hton16(gsn->seq_next);
+ if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) ||
+ (packet->gtp1l.h.type == GTP_ERROR)))
+ packet->gtp1l.h.tei = hton32(pdp->teid_gn);
+ else if (pdp)
+ packet->gtp1l.h.tei = hton32(pdp->teic_gn);
+ fd = gsn->fd1c;
+ } else {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
+ return -1;
+ }
+
+ if (sendto(fd, packet, len, 0,
+ (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ gsn->err_sendto++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
+ (unsigned long)&packet, len, strerror(errno));
+ return -1;
+ }
+
+ /* Use new queue structure */
+ if (queue_newmsg(gsn->queue_req, &qmsg, &addr, gsn->seq_next)) {
+ gsn->err_queuefull++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Retransmit queue is full");
+ } else {
+ memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
+ qmsg->l = len;
+ qmsg->timeout = time(NULL) + 3; /* When to timeout */
+ qmsg->retrans = 0; /* No retransmissions so far */
+ qmsg->cbp = cbp;
+ qmsg->type = ntoh8(packet->gtp0.h.type);
+ qmsg->fd = fd;
+ }
+ gsn->seq_next++; /* Count up this time */
+ return 0;
}
/* gtp_conf
@@ -475,373 +477,402 @@ int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp,
* return 0 on success, EOF if packet was not found */
int gtp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
- union gtp_packet *packet, int len, uint8_t *type, void **cbp) {
-
- uint16_t seq;
-
- if ((packet->gtp0.h.flags & 0xe0) == 0x00)
- seq = ntoh16(packet->gtp0.h.seq);
- else if ((packet->gtp1l.h.flags & 0xe2) == 0x22)
- seq = ntoh16(packet->gtp1l.h.seq);
- else {
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
- "Unknown GTP packet version");
- return EOF;
- }
-
- if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) {
- gsn->err_seq++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
- "Confirmation packet not found in queue");
- return EOF;
- }
-
- return 0;
+ union gtp_packet *packet, int len, uint8_t * type, void **cbp)
+{
+
+ uint16_t seq;
+
+ if ((packet->gtp0.h.flags & 0xe0) == 0x00)
+ seq = ntoh16(packet->gtp0.h.seq);
+ else if ((packet->gtp1l.h.flags & 0xe2) == 0x22)
+ seq = ntoh16(packet->gtp1l.h.seq);
+ else {
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
+ "Unknown GTP packet version");
+ return EOF;
+ }
+
+ if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) {
+ gsn->err_seq++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len,
+ "Confirmation packet not found in queue");
+ return EOF;
+ }
+
+ return 0;
}
-int gtp_retrans(struct gsn_t *gsn) {
- /* Retransmit any outstanding packets */
- /* Remove from queue if maxretrans exceeded */
- time_t now;
- struct qmsg_t *qmsg;
- now = time(NULL);
- /*printf("Retrans: New beginning %d\n", (int) now);*/
-
- while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
- (qmsg->timeout <= now)) {
- /*printf("Retrans timeout found: %d\n", (int) time(NULL));*/
- if (qmsg->retrans > 3) { /* To many retrans */
- if (gsn->cb_conf) gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
- queue_freemsg(gsn->queue_req, qmsg);
- }
- else {
- if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
- (struct sockaddr *) &qmsg->peer, sizeof(struct sockaddr_in)) < 0) {
- gsn->err_sendto++;
- 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));
- }
- queue_back(gsn->queue_req, qmsg);
- qmsg->timeout = now + 3;
- qmsg->retrans++;
- }
- }
-
- /* Also clean up reply timeouts */
- while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
- (qmsg->timeout < now)) {
- /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL));*/
- queue_freemsg(gsn->queue_resp, qmsg);
- }
-
- return 0;
+int gtp_retrans(struct gsn_t *gsn)
+{
+ /* Retransmit any outstanding packets */
+ /* Remove from queue if maxretrans exceeded */
+ time_t now;
+ struct qmsg_t *qmsg;
+ now = time(NULL);
+ /*printf("Retrans: New beginning %d\n", (int) now); */
+
+ while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
+ (qmsg->timeout <= now)) {
+ /*printf("Retrans timeout found: %d\n", (int) time(NULL)); */
+ if (qmsg->retrans > 3) { /* To many retrans */
+ if (gsn->cb_conf)
+ gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
+ queue_freemsg(gsn->queue_req, qmsg);
+ } else {
+ if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
+ (struct sockaddr *)&qmsg->peer,
+ sizeof(struct sockaddr_in)) < 0) {
+ gsn->err_sendto++;
+ 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));
+ }
+ queue_back(gsn->queue_req, qmsg);
+ qmsg->timeout = now + 3;
+ qmsg->retrans++;
+ }
+ }
+
+ /* Also clean up reply timeouts */
+ while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
+ (qmsg->timeout < now)) {
+ /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL)); */
+ queue_freemsg(gsn->queue_resp, qmsg);
+ }
+
+ return 0;
}
-int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) {
- time_t now, later;
- struct qmsg_t *qmsg;
-
- if (queue_getfirst(gsn->queue_req, &qmsg)) {
- timeout->tv_sec = 10;
- timeout->tv_usec = 0;
- }
- else {
- now = time(NULL);
- later = qmsg->timeout;
- timeout->tv_sec = later - now;
- timeout->tv_usec = 0;
- if (timeout->tv_sec < 0) timeout->tv_sec = 0; /* No negative allowed */
- if (timeout->tv_sec > 10) timeout->tv_sec = 10; /* Max sleep for 10 sec*/
- }
- return 0;
+int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
+{
+ time_t now, later;
+ struct qmsg_t *qmsg;
+
+ if (queue_getfirst(gsn->queue_req, &qmsg)) {
+ timeout->tv_sec = 10;
+ timeout->tv_usec = 0;
+ } else {
+ now = time(NULL);
+ later = qmsg->timeout;
+ timeout->tv_sec = later - now;
+ timeout->tv_usec = 0;
+ if (timeout->tv_sec < 0)
+ timeout->tv_sec = 0; /* No negative allowed */
+ if (timeout->tv_sec > 10)
+ timeout->tv_sec = 10; /* Max sleep for 10 sec */
+ }
+ return 0;
}
-int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp,
+int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp,
union gtp_packet *packet, int len,
- struct sockaddr_in *peer, int fd,
- uint16_t seq, uint64_t tid) {
- struct qmsg_t *qmsg;
-
- if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
- packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
- packet->gtp0.h.seq = hton16(seq);
- packet->gtp0.h.tid = tid;
- if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
- (packet->gtp0.h.type == GTP_ERROR)))
- packet->gtp0.h.flow=hton16(pdp->flru);
- else if (pdp)
- packet->gtp0.h.flow=hton16(pdp->flrc);
- }
- else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
- packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
- packet->gtp1l.h.seq = hton16(seq);
- if (pdp && (fd == gsn->fd1u))
- packet->gtp1l.h.tei=hton32(pdp->teid_gn);
- else if (pdp)
- packet->gtp1l.h.tei=hton32(pdp->teic_gn);
- }
- else {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
- return -1;
- }
-
- if (fcntl(fd, F_SETFL, 0)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
- return -1;
- }
-
- if (sendto(fd, packet, len, 0,
- (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
- gsn->err_sendto++;
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno));
- return -1;
- }
-
- /* Use new queue structure */
- if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) {
- gsn->err_queuefull++;
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Retransmit queue is full");
- }
- else {
- memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
- qmsg->l = len;
- qmsg->timeout = time(NULL) + 60; /* When to timeout */
- qmsg->retrans = 0; /* No retransmissions so far */
- qmsg->cbp = NULL;
- qmsg->type = 0;
- qmsg->fd = fd;
- }
- return 0;
+ struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
+{
+ struct qmsg_t *qmsg;
+
+ if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
+ packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
+ packet->gtp0.h.seq = hton16(seq);
+ packet->gtp0.h.tid = tid;
+ if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
+ (packet->gtp0.h.type == GTP_ERROR)))
+ packet->gtp0.h.flow = hton16(pdp->flru);
+ else if (pdp)
+ packet->gtp0.h.flow = hton16(pdp->flrc);
+ } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
+ packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
+ packet->gtp1l.h.seq = hton16(seq);
+ if (pdp && (fd == gsn->fd1u))
+ packet->gtp1l.h.tei = hton32(pdp->teid_gn);
+ else if (pdp)
+ packet->gtp1l.h.tei = hton32(pdp->teic_gn);
+ } else {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFL, 0)) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
+ return -1;
+ }
+
+ if (sendto(fd, packet, len, 0,
+ (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
+ gsn->err_sendto++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
+ (unsigned long)&packet, len, strerror(errno));
+ return -1;
+ }
+
+ /* Use new queue structure */
+ if (queue_newmsg(gsn->queue_resp, &qmsg, peer, seq)) {
+ gsn->err_queuefull++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Retransmit queue is full");
+ } else {
+ memcpy(&qmsg->p, packet, sizeof(union gtp_packet));
+ qmsg->l = len;
+ qmsg->timeout = time(NULL) + 60; /* When to timeout */
+ qmsg->retrans = 0; /* No retransmissions so far */
+ qmsg->cbp = NULL;
+ qmsg->type = 0;
+ qmsg->fd = fd;
+ }
+ return 0;
}
int gtp_notification(struct gsn_t *gsn, int version,
union gtp_packet *packet, int len,
- struct sockaddr_in *peer, int fd,
- uint16_t seq) {
-
- struct sockaddr_in addr;
-
- memcpy(&addr, peer, sizeof(addr));
-
- /* In GTP0 notifications are treated as replies. In GTP1 they
- are requests for which there is no reply */
-
- if (fd == gsn->fd1c)
- addr.sin_port = htons(GTP1C_PORT);
- else if (fd == gsn->fd1u)
- addr.sin_port = htons(GTP1C_PORT);
-
- if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
- packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
- packet->gtp0.h.seq = hton16(seq);
- }
- else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
- packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
- packet->gtp1l.h.seq = hton16(seq);
- }
- else {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
- return -1;
- }
-
- if (fcntl(fd, F_SETFL, 0)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
- return -1;
- }
-
- if (sendto(fd, packet, len, 0,
- (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) {
- gsn->err_sendto++;
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno));
- return -1;
- }
- return 0;
-}
+ struct sockaddr_in *peer, int fd, uint16_t seq)
+{
+
+ struct sockaddr_in addr;
+
+ memcpy(&addr, peer, sizeof(addr));
+
+ /* In GTP0 notifications are treated as replies. In GTP1 they
+ are requests for which there is no reply */
+
+ if (fd == gsn->fd1c)
+ addr.sin_port = htons(GTP1C_PORT);
+ else if (fd == gsn->fd1u)
+ addr.sin_port = htons(GTP1C_PORT);
-int gtp_dublicate(struct gsn_t *gsn, int version,
- struct sockaddr_in *peer, uint16_t seq) {
- struct qmsg_t *qmsg;
-
- if(queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) {
- return EOF; /* Notfound */
- }
-
- if (fcntl(qmsg->fd, F_SETFL, 0)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
- return -1;
- }
-
- if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
- (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
- gsn->err_sendto++;
- 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));
- }
- return 0;
+ if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */
+ packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
+ packet->gtp0.h.seq = hton16(seq);
+ } else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */
+ packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
+ packet->gtp1l.h.seq = hton16(seq);
+ } else {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag");
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFL, 0)) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
+ return -1;
+ }
+
+ if (sendto(fd, packet, len, 0,
+ (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
+ gsn->err_sendto++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd,
+ (unsigned long)&packet, len, strerror(errno));
+ return -1;
+ }
+ return 0;
}
+int gtp_dublicate(struct gsn_t *gsn, int version,
+ struct sockaddr_in *peer, uint16_t seq)
+{
+ struct qmsg_t *qmsg;
+ if (queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) {
+ return EOF; /* Notfound */
+ }
+
+ if (fcntl(qmsg->fd, F_SETFL, 0)) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
+ return -1;
+ }
+
+ if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
+ (struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
+ gsn->err_sendto++;
+ 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));
+ }
+ return 0;
+}
/* Perform restoration and recovery error handling as described in 29.060 */
-static void log_restart(struct gsn_t *gsn) {
+static void log_restart(struct gsn_t *gsn)
+{
FILE *f;
int i, rc;
int counter = 0;
char filename[NAMESIZE];
- filename[NAMESIZE-1] = 0; /* No null term. guarantee by strncpy */
- strncpy(filename, gsn->statedir, NAMESIZE-1);
- strncat(filename, RESTART_FILE,
- NAMESIZE-1-sizeof(RESTART_FILE));
+ filename[NAMESIZE - 1] = 0; /* No null term. guarantee by strncpy */
+ strncpy(filename, gsn->statedir, NAMESIZE - 1);
+ strncat(filename, RESTART_FILE, NAMESIZE - 1 - sizeof(RESTART_FILE));
i = umask(022);
/* We try to open file. On failure we will later try to create file */
if (!(f = fopen(filename, "r"))) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "State information file (%s) not found. Creating new file.", filename);
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "State information file (%s) not found. Creating new file.",
+ filename);
+ } else {
+ umask(i);
+ rc = fscanf(f, "%d", &counter);
+ if (rc != 1) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "fscanf failed to read counter value");
+ return;
+ }
+ if (fclose(f)) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "fclose failed: Error = %s", strerror(errno));
+ }
}
- else {
- umask(i);
- rc = fscanf(f, "%d", &counter);
- if (rc != 1) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fscanf failed to read counter value");
- return;
- }
- if (fclose(f)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno));
- }
- }
-
- gsn->restart_counter = (unsigned char) counter;
+
+ gsn->restart_counter = (unsigned char)counter;
gsn->restart_counter++;
-
+
if (!(f = fopen(filename, "w"))) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fopen(path=%s, mode=%s) failed: Error = %s", filename, "w", strerror(errno));
- return;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "fopen(path=%s, mode=%s) failed: Error = %s", filename,
+ "w", strerror(errno));
+ return;
}
umask(i);
fprintf(f, "%d\n", gsn->restart_counter);
if (fclose(f)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fclose failed: Error = %s", strerror(errno));
- return;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "fclose failed: Error = %s", strerror(errno));
+ return;
}
}
-
-
int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
- int mode)
+ int mode)
{
- struct sockaddr_in addr;
-
- syslog(LOG_ERR, "GTP: gtp_newgsn() started");
-
- *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
-
- (*gsn)->statedir = statedir;
- log_restart(*gsn);
-
- /* Initialise sequence number */
- (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
-
- /* Initialise request retransmit queue */
- queue_new(&(*gsn)->queue_req);
- queue_new(&(*gsn)->queue_resp);
-
- /* Initialise pdp table */
- pdp_init();
-
- /* Initialise call back functions */
- (*gsn)->cb_create_context_ind = 0;
- (*gsn)->cb_delete_context = 0;
- (*gsn)->cb_unsup_ind = 0;
- (*gsn)->cb_conf = 0;
- (*gsn)->cb_data_ind = 0;
-
- /* Store function parameters */
- (*gsn)->gsnc = *listen;
- (*gsn)->gsnu = *listen;
- (*gsn)->mode = mode;
-
-
- /* Create GTP version 0 socket */
- if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
- (*gsn)->err_socket++;
- gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
- addr.sin_port = htons(GTP0_PORT);
+ struct sockaddr_in addr;
+
+ syslog(LOG_ERR, "GTP: gtp_newgsn() started");
+
+ *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
+
+ (*gsn)->statedir = statedir;
+ log_restart(*gsn);
+
+ /* Initialise sequence number */
+ (*gsn)->seq_next = (*gsn)->restart_counter * 1024;
+
+ /* Initialise request retransmit queue */
+ queue_new(&(*gsn)->queue_req);
+ queue_new(&(*gsn)->queue_resp);
+
+ /* Initialise pdp table */
+ pdp_init();
+
+ /* Initialise call back functions */
+ (*gsn)->cb_create_context_ind = 0;
+ (*gsn)->cb_delete_context = 0;
+ (*gsn)->cb_unsup_ind = 0;
+ (*gsn)->cb_conf = 0;
+ (*gsn)->cb_data_ind = 0;
+
+ /* Store function parameters */
+ (*gsn)->gsnc = *listen;
+ (*gsn)->gsnu = *listen;
+ (*gsn)->mode = mode;
+
+ /* Create GTP version 0 socket */
+ if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ (*gsn)->err_socket++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s",
+ AF_INET, SOCK_DGRAM, 0, strerror(errno));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
+ addr.sin_port = htons(GTP0_PORT);
#if defined(__FreeBSD__) || defined(__APPLE__)
- addr.sin_len = sizeof(addr);
+ addr.sin_len = sizeof(addr);
#endif
-
- if (bind((*gsn)->fd0, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- (*gsn)->err_socket++;
- 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));
- return -1;
- }
-
- /* Create GTP version 1 control plane socket */
- if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
- (*gsn)->err_socket++;
- gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
- addr.sin_port = htons(GTP1C_PORT);
+
+ if (bind((*gsn)->fd0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ (*gsn)->err_socket++;
+ 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));
+ return -1;
+ }
+
+ /* Create GTP version 1 control plane socket */
+ if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ (*gsn)->err_socket++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s",
+ AF_INET, SOCK_DGRAM, 0, strerror(errno));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
+ addr.sin_port = htons(GTP1C_PORT);
#if defined(__FreeBSD__) || defined(__APPLE__)
- addr.sin_len = sizeof(addr);
+ addr.sin_len = sizeof(addr);
#endif
-
- if (bind((*gsn)->fd1c, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- (*gsn)->err_socket++;
- 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));
- return -1;
- }
-
- /* Create GTP version 1 user plane socket */
- if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
- (*gsn)->err_socket++;
- gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno));
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/
- addr.sin_port = htons(GTP1U_PORT);
+
+ if (bind((*gsn)->fd1c, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ (*gsn)->err_socket++;
+ 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));
+ return -1;
+ }
+
+ /* Create GTP version 1 user plane socket */
+ if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ (*gsn)->err_socket++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s",
+ AF_INET, SOCK_DGRAM, 0, strerror(errno));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
+ addr.sin_port = htons(GTP1U_PORT);
#if defined(__FreeBSD__) || defined(__APPLE__)
- addr.sin_len = sizeof(addr);
+ addr.sin_len = sizeof(addr);
#endif
-
- if (bind((*gsn)->fd1u, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- (*gsn)->err_socket++;
- 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));
- return -1;
- }
-
- return 0;
+
+ if (bind((*gsn)->fd1u, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ (*gsn)->err_socket++;
+ 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));
+ return -1;
+ }
+
+ return 0;
}
-int gtp_free(struct gsn_t *gsn) {
+int gtp_free(struct gsn_t *gsn)
+{
- /* Clean up retransmit queues */
- queue_free(gsn->queue_req);
- queue_free(gsn->queue_resp);
-
- close(gsn->fd0);
- close(gsn->fd1c);
- close(gsn->fd1u);
+ /* Clean up retransmit queues */
+ queue_free(gsn->queue_req);
+ queue_free(gsn->queue_resp);
- free(gsn);
- return 0;
+ close(gsn->fd0);
+ close(gsn->fd1c);
+ close(gsn->fd1u);
+
+ free(gsn);
+ return 0;
}
/* ***********************************************************
@@ -877,71 +908,78 @@ int gtp_free(struct gsn_t *gsn) {
int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
struct in_addr *inetaddr)
{
- union gtp_packet packet;
- unsigned int length = get_default_gtp(version, GTP_ECHO_REQ, &packet);
- return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp);
+ union gtp_packet packet;
+ unsigned int length = get_default_gtp(version, GTP_ECHO_REQ, &packet);
+ return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp);
}
/* Send off an echo reply */
int gtp_echo_resp(struct gsn_t *gsn, int version,
- struct sockaddr_in *peer, int fd,
- void *pack, unsigned len)
+ struct sockaddr_in *peer, int fd, void *pack, unsigned len)
{
- union gtp_packet packet;
- unsigned int length = get_default_gtp(version, GTP_ECHO_RSP, &packet);
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, gsn->restart_counter);
- return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
- get_seq(pack), get_tid(pack));
+ union gtp_packet packet;
+ unsigned int length = get_default_gtp(version, GTP_ECHO_RSP, &packet);
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
+ gsn->restart_counter);
+ return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
+ get_seq(pack), get_tid(pack));
}
-
/* Handle a received echo request */
-int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
- int fd, void *pack, unsigned len) {
+int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
+ int fd, void *pack, unsigned len)
+{
- /* Check if it was a dublicate request */
- if(!gtp_dublicate(gsn, 0, peer, get_seq(pack))) return 0;
+ /* Check if it was a dublicate request */
+ if (!gtp_dublicate(gsn, 0, peer, get_seq(pack)))
+ return 0;
- /* Send off reply to request */
- return gtp_echo_resp(gsn, version, peer, fd, pack, len);
+ /* Send off reply to request */
+ return gtp_echo_resp(gsn, version, peer, fd, pack, len);
}
/* Handle a received echo reply */
int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
- void *pack, unsigned len) {
- union gtpie_member *ie[GTPIE_SIZE];
- unsigned char recovery;
- void *cbp = NULL;
- uint8_t type = 0;
- int hlen = get_hlen(pack);
-
- /* Remove packet from queue */
- if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
-
- /* Extract information elements into a pointer array */
- if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
- gsn->invalid++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Invalid message format");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
- return EOF;
- }
-
- if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
- return EOF;
- }
-
- /* Echo reply packages does not have a cause information element */
- /* Instead we return the recovery number in the callback function */
- if (gsn->cb_conf) gsn->cb_conf(type, recovery, NULL, cbp);
-
- if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery);
-
- return 0;
+ void *pack, unsigned len)
+{
+ union gtpie_member *ie[GTPIE_SIZE];
+ unsigned char recovery;
+ void *cbp = NULL;
+ uint8_t type = 0;
+ int hlen = get_hlen(pack);
+
+ /* Remove packet from queue */
+ if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
+ return EOF;
+
+ /* Extract information elements into a pointer array */
+ if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
+ gsn->invalid++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Invalid message format");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, NULL, cbp);
+ return EOF;
+ }
+
+ if (gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Missing mandatory field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, NULL, cbp);
+ return EOF;
+ }
+
+ /* Echo reply packages does not have a cause information element */
+ /* Instead we return the recovery number in the callback function */
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, recovery, NULL, cbp);
+
+ if (gsn->cb_recovery)
+ gsn->cb_recovery(peer, recovery);
+
+ return 0;
}
/* Send off a Version Not Supported message */
@@ -958,52 +996,55 @@ int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
int fd, void *pack, unsigned len)
{
- union gtp_packet packet;
+ union gtp_packet packet;
- /* GTP 1 is the highest supported protocol */
- unsigned int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet);
- return gtp_notification(gsn, version, &packet, length,
- peer, fd, 0);
+ /* GTP 1 is the highest supported protocol */
+ unsigned int length = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet);
+ return gtp_notification(gsn, version, &packet, length, peer, fd, 0);
}
/* Handle a Version Not Supported message */
-int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
- void *pack, unsigned len) {
+int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
+ void *pack, unsigned len)
+{
- if (gsn->cb_unsup_ind) gsn->cb_unsup_ind(peer);
-
- return 0;
+ if (gsn->cb_unsup_ind)
+ gsn->cb_unsup_ind(peer);
+
+ return 0;
}
/* Send off an Supported Extension Headers Notification */
int gtp_extheader_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
int fd, void *pack, unsigned len)
{
- union gtp_packet packet;
- unsigned int length = get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet);
+ union gtp_packet packet;
+ unsigned int length =
+ get_default_gtp(version, GTP_SUPP_EXT_HEADER, &packet);
- uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU;
+ uint8_t pdcp_pdu = GTP_EXT_PDCP_PDU;
- if (version < 1)
- return 0;
+ if (version < 1)
+ return 0;
- /* We report back that we support only PDCP PDU headers */
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T, sizeof(pdcp_pdu),
- &pdcp_pdu);
+ /* We report back that we support only PDCP PDU headers */
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EXT_HEADER_T,
+ sizeof(pdcp_pdu), &pdcp_pdu);
- return gtp_notification(gsn, version, &packet, length,
- peer, fd, get_seq(pack));
+ return gtp_notification(gsn, version, &packet, length,
+ peer, fd, get_seq(pack));
}
/* Handle a Supported Extension Headers Notification */
-int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
- void *pack, unsigned len) {
+int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
+ void *pack, unsigned len)
+{
- if (gsn->cb_extheader_ind) gsn->cb_extheader_ind(peer);
-
- return 0;
-}
+ if (gsn->cb_extheader_ind)
+ gsn->cb_extheader_ind(peer);
+ return 0;
+}
/* ***********************************************************
* Session management messages
@@ -1018,1466 +1059,1564 @@ int gtp_extheader_ind(struct gsn_t *gsn, struct sockaddr_in *peer,
*************************************************************/
/* API: Send Create PDP Context Request (7.3.1) */
-extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
- void *cbp) {
- union gtp_packet packet;
- unsigned int length = get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet);
- struct pdp_t *linked_pdp = NULL;
-
- /* TODO: Secondary PDP Context Activation Procedure */
- /* In secondary activation procedure the PDP context is identified
- by tei in the header. The following fields are omitted: Selection
- mode, IMSI, MSISDN, End User Address, Access Point Name and
- Protocol Configuration Options */
-
- if (pdp->secondary) {
- if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context");
- return EOF;
- }
- }
-
- if (pdp->version == 0) {
- gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
- sizeof(pdp->qos_req0), pdp->qos_req0);
- }
-
- /* Section 7.7.2 */
- if (pdp->version == 1) {
- if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
- gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
- sizeof(pdp->imsi), (uint8_t*) &pdp->imsi);
- }
-
- /* Section 7.7.3 Routing Area Information */
- if (pdp->rai_given == 1)
- gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI,
- pdp->rai.l, (uint8_t*) &pdp->rai.v);
-
-
- /* Section 7.7.11 */
- if (pdp->norecovery_given == 0)
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
- gsn->restart_counter);
-
- /* Section 7.7.12 */
- if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE,
- pdp->selmode);
-
- if (pdp->version == 0) {
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
- pdp->fllu);
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
- pdp->fllc);
- }
-
- /* Section 7.7.13 */
- if (pdp->version == 1) {
- gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
- pdp->teid_own);
-
- /* Section 7.7.14 */
- if (!pdp->teic_confirmed)
- gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
- pdp->teic_own);
-
- /* Section 7.7.17 */
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
- pdp->nsapi);
-
- /* Section 7.7.17 */
- if (pdp->secondary) /* Secondary PDP Context Activation Procedure */
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
- linked_pdp->nsapi);
-
- /* Section 7.7.23 */
- if (pdp->cch_pdp) /* Only include charging if flags are set */
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C,
- pdp->cch_pdp);
- }
-
- /* TODO
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
- pdp->traceref);
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
- pdp->tracetype); */
-
- /* Section 7.7.27 */
- if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
- pdp->eua.l, pdp->eua.v);
-
-
- /* Section 7.7.30 */
- if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN,
- pdp->apn_use.l, pdp->apn_use.v);
-
- /* Section 7.7.31 */
- if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
- if (pdp->pco_req.l)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
- pdp->pco_req.l, pdp->pco_req.v);
-
- /* Section 7.7.32 */
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
- pdp->gsnlc.l, pdp->gsnlc.v);
- /* Section 7.7.32 */
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
- pdp->gsnlu.l, pdp->gsnlu.v);
-
- /* Section 7.7.33 */
- if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN,
- pdp->msisdn.l, pdp->msisdn.v);
-
- /* Section 7.7.34 */
- if (pdp->version == 1)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
- pdp->qos_req.l, pdp->qos_req.v);
-
- /* Section 7.7.36 */
- if ((pdp->version == 1) && pdp->tft.l)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
- pdp->tft.l, pdp->tft.v);
-
- /* Section 7.7.41 */
- if ((pdp->version == 1) && pdp->triggerid.l)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
- pdp->triggerid.l, pdp->triggerid.v);
-
- /* Section 7.7.42 */
- if ((pdp->version == 1) && pdp->omcid.l)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
- pdp->omcid.l, pdp->omcid.v);
-
- /* new R7 fields */
- if (pdp->rattype_given == 1)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAT_TYPE,
- pdp->rattype.l, pdp->rattype.v);
-
- if (pdp->userloc_given == 1)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_USER_LOC,
- pdp->userloc.l, pdp->userloc.v);
-
- if (pdp->mstz_given == 1)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MS_TZ,
- pdp->mstz.l, pdp->mstz.v);
-
- if (pdp->imeisv_given == 1)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_IMEI_SV,
- pdp->imeisv.l, pdp->imeisv.v);
-
- /* TODO hisaddr0 */
- gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
-
- return 0;
+extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
+ void *cbp)
+{
+ union gtp_packet packet;
+ unsigned int length =
+ get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet);
+ struct pdp_t *linked_pdp = NULL;
+
+ /* TODO: Secondary PDP Context Activation Procedure */
+ /* In secondary activation procedure the PDP context is identified
+ by tei in the header. The following fields are omitted: Selection
+ mode, IMSI, MSISDN, End User Address, Access Point Name and
+ Protocol Configuration Options */
+
+ if (pdp->secondary) {
+ if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Unknown linked PDP context");
+ return EOF;
+ }
+ }
+
+ if (pdp->version == 0) {
+ gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
+ sizeof(pdp->qos_req0), pdp->qos_req0);
+ }
+
+ /* Section 7.7.2 */
+ if (pdp->version == 1) {
+ if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
+ gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
+ sizeof(pdp->imsi), (uint8_t *) & pdp->imsi);
+ }
+
+ /* Section 7.7.3 Routing Area Information */
+ if (pdp->rai_given == 1)
+ gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI,
+ pdp->rai.l, (uint8_t *) & pdp->rai.v);
+
+ /* Section 7.7.11 */
+ if (pdp->norecovery_given == 0)
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
+ gsn->restart_counter);
+
+ /* Section 7.7.12 */
+ if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE,
+ pdp->selmode);
+
+ if (pdp->version == 0) {
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu);
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc);
+ }
+
+ /* Section 7.7.13 */
+ if (pdp->version == 1) {
+ gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
+ pdp->teid_own);
+
+ /* Section 7.7.14 */
+ if (!pdp->teic_confirmed)
+ gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
+ pdp->teic_own);
+
+ /* Section 7.7.17 */
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
+
+ /* Section 7.7.17 */
+ if (pdp->secondary) /* Secondary PDP Context Activation Procedure */
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
+ linked_pdp->nsapi);
+
+ /* Section 7.7.23 */
+ if (pdp->cch_pdp) /* Only include charging if flags are set */
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C,
+ pdp->cch_pdp);
+ }
+
+ /* TODO
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
+ pdp->traceref);
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
+ pdp->tracetype); */
+
+ /* Section 7.7.27 */
+ if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
+ pdp->eua.l, pdp->eua.v);
+
+ /* Section 7.7.30 */
+ if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN,
+ pdp->apn_use.l, pdp->apn_use.v);
+
+ /* Section 7.7.31 */
+ if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
+ if (pdp->pco_req.l)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
+ pdp->pco_req.l, pdp->pco_req.v);
+
+ /* Section 7.7.32 */
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
+ pdp->gsnlc.l, pdp->gsnlc.v);
+ /* Section 7.7.32 */
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
+ pdp->gsnlu.l, pdp->gsnlu.v);
+
+ /* Section 7.7.33 */
+ if (!pdp->secondary) /* Not Secondary PDP Context Activation Procedure */
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN,
+ pdp->msisdn.l, pdp->msisdn.v);
+
+ /* Section 7.7.34 */
+ if (pdp->version == 1)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
+ pdp->qos_req.l, pdp->qos_req.v);
+
+ /* Section 7.7.36 */
+ if ((pdp->version == 1) && pdp->tft.l)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
+ pdp->tft.l, pdp->tft.v);
+
+ /* Section 7.7.41 */
+ if ((pdp->version == 1) && pdp->triggerid.l)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
+ pdp->triggerid.l, pdp->triggerid.v);
+
+ /* Section 7.7.42 */
+ if ((pdp->version == 1) && pdp->omcid.l)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
+ pdp->omcid.l, pdp->omcid.v);
+
+ /* new R7 fields */
+ if (pdp->rattype_given == 1)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAT_TYPE,
+ pdp->rattype.l, pdp->rattype.v);
+
+ if (pdp->userloc_given == 1)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_USER_LOC,
+ pdp->userloc.l, pdp->userloc.v);
+
+ if (pdp->mstz_given == 1)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MS_TZ,
+ pdp->mstz.l, pdp->mstz.v);
+
+ if (pdp->imeisv_given == 1)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_IMEI_SV,
+ pdp->imeisv.l, pdp->imeisv.v);
+
+ /* TODO hisaddr0 */
+ gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
+
+ return 0;
}
/* API: Application response to context indication */
-int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause) {
-
- /* Now send off a reply to the peer */
- gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
-
- if (cause != GTPCAUSE_ACC_REQ) {
- pdp_freepdp(pdp);
- }
-
- return 0;
+int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause)
+{
+
+ /* Now send off a reply to the peer */
+ gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
+
+ if (cause != GTPCAUSE_ACC_REQ) {
+ pdp_freepdp(pdp);
+ }
+
+ return 0;
}
/* API: Register create context indication callback */
int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
- int (*cb_create_context_ind) (struct pdp_t* pdp))
+ int (*cb_create_context_ind) (struct pdp_t *
+ pdp))
{
- gsn->cb_create_context_ind = cb_create_context_ind;
- return 0;
+ gsn->cb_create_context_ind = cb_create_context_ind;
+ return 0;
}
-
/* Send Create PDP Context Response */
-int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
- uint8_t cause) {
- union gtp_packet packet;
- unsigned int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
-
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
-
- if (cause == GTPCAUSE_ACC_REQ) {
-
- if (version == 0)
- gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
- sizeof(pdp->qos_neg0), pdp->qos_neg0);
-
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER,
- pdp->reorder);
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
- gsn->restart_counter);
-
- if (version == 0) {
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
- pdp->fllu);
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
- pdp->fllc);
- }
-
- if (version == 1) {
- gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
- pdp->teid_own);
- gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
- pdp->teic_own);
- }
-
- /* TODO: We use teic_own as charging ID */
- gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
- pdp->teic_own);
-
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
- pdp->eua.l, pdp->eua.v);
-
- if (pdp->pco_neg.l) { /* Optional PCO */
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
- pdp->pco_neg.l, pdp->pco_neg.v);
- }
-
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
- pdp->gsnlc.l, pdp->gsnlc.v);
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
- pdp->gsnlu.l, pdp->gsnlu.v);
-
- if (version == 1)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
- pdp->qos_neg.l, pdp->qos_neg.v);
-
- /* TODO: Charging gateway address */
- }
-
- return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer,
- pdp->fd, pdp->seq, pdp->tid);
+int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
+ uint8_t cause)
+{
+ union gtp_packet packet;
+ unsigned int length =
+ get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet);
+
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
+
+ if (cause == GTPCAUSE_ACC_REQ) {
+
+ if (version == 0)
+ gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
+ sizeof(pdp->qos_neg0), pdp->qos_neg0);
+
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER,
+ pdp->reorder);
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
+ gsn->restart_counter);
+
+ if (version == 0) {
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
+ pdp->fllu);
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
+ pdp->fllc);
+ }
+
+ if (version == 1) {
+ gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
+ pdp->teid_own);
+ gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
+ pdp->teic_own);
+ }
+
+ /* TODO: We use teic_own as charging ID */
+ gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
+ pdp->teic_own);
+
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
+ pdp->eua.l, pdp->eua.v);
+
+ if (pdp->pco_neg.l) { /* Optional PCO */
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO,
+ pdp->pco_neg.l, pdp->pco_neg.v);
+ }
+
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
+ pdp->gsnlc.l, pdp->gsnlc.v);
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
+ pdp->gsnlu.l, pdp->gsnlu.v);
+
+ if (version == 1)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
+ pdp->qos_neg.l, pdp->qos_neg.v);
+
+ /* TODO: Charging gateway address */
+ }
+
+ return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer,
+ pdp->fd, pdp->seq, pdp->tid);
}
/* Handle Create PDP Context Request */
int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
- struct sockaddr_in *peer, int fd,
- void *pack, unsigned len) {
- struct pdp_t *pdp, *pdp_old;
- struct pdp_t pdp_buf;
- union gtpie_member* ie[GTPIE_SIZE];
- uint8_t recovery;
-
- uint16_t seq = get_seq(pack);
- int hlen = get_hlen(pack);
- uint8_t linked_nsapi = 0;
- struct pdp_t *linked_pdp = NULL;
-
- if(!gtp_dublicate(gsn, version, peer, seq)) return 0;
-
- pdp = &pdp_buf;
- memset(pdp, 0, sizeof(struct pdp_t));
-
- if (version == 0) {
- pdp->imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffffull;
- pdp->nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000ull) >> 60;
- }
-
- pdp->seq = seq;
- pdp->sa_peer = *peer;
- pdp->fd = fd;
- pdp->version = version;
-
- /* Decode information elements */
- if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
- gsn->invalid++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Invalid message format");
- if (0 == version)
- return EOF;
- else
- return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_INVALID_MESSAGE);
- }
-
- if (version == 1) {
- /* Linked NSAPI (conditional) */
- /* If included this is the Secondary PDP Context Activation Procedure */
- /* In secondary activation IMSI is not included, so the context must be */
- /* identified by the tei */
- if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) {
-
- /* Find the primary PDP context */
- if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
- gsn->incorrect++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Incorrect optional information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_OPT_IE_INCORRECT);
- }
-
- /* Check that the primary PDP context matches linked nsapi */
- if (linked_pdp->nsapi != linked_nsapi) {
- gsn->incorrect++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Incorrect optional information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_OPT_IE_INCORRECT);
- }
-
- /* Copy parameters from primary context */
- pdp->selmode = linked_pdp->selmode;
- pdp->imsi = linked_pdp->imsi;
- pdp->msisdn = linked_pdp->msisdn;
- pdp->eua = linked_pdp->eua;
- pdp->pco_req = linked_pdp->pco_req;
- pdp->apn_req = linked_pdp->apn_req;
- pdp->teic_gn = linked_pdp->teic_gn;
- pdp->secondary = 1;
- }
- } /* if (version == 1) */
-
- if (version == 0) {
- if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
- pdp->qos_req0, sizeof(pdp->qos_req0))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING);
- }
- }
-
- if ((version == 1) && (!linked_pdp)) {
- /* Not Secondary PDP Context Activation Procedure */
- /* IMSI (conditional) */
- if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
- }
-
- /* Recovery (optional) */
- if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery);
- }
-
- /* Selection mode (conditional) */
- if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
- if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0,
- &pdp->selmode, sizeof(pdp->selmode))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
- }
-
- if (version == 0) {
- if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
- }
-
-
- if (version == 1) {
- /* TEID (mandatory) */
- if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- /* TEIC (conditional) */
- if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
- if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
- }
-
- /* NSAPI (mandatory) */
- if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
- }
-
-
- /* Charging Characteriatics (optional) */
- /* Trace reference (optional) */
- /* Trace type (optional) */
- /* Charging Characteriatics (optional) */
-
- if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
- /* End User Address (conditional) */
- if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
- &pdp->eua.v, sizeof(pdp->eua.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- /* APN */
- if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l,
- &pdp->apn_req.v, sizeof(pdp->apn_req.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- /* Extract protocol configuration options (optional) */
- if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
- &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
- }
- }
-
- /* SGSN address for signalling (mandatory) */
- if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
- &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- /* SGSN address for user traffic (mandatory) */
- if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
- &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
- /* MSISDN (conditional) */
- if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l,
- &pdp->msisdn.v, sizeof(pdp->msisdn.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
- }
-
- if (version == 1) {
- /* QoS (mandatory) */
- if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
- &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_create_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- /* TFT (conditional) */
- if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
- &pdp->tft.v, sizeof(pdp->tft.v))) {
- }
-
- /* Trigger ID */
- /* OMC identity */
- }
-
- /* Initialize our own IP addresses */
- in_addr2gsna(&pdp->gsnlc, &gsn->gsnc);
- in_addr2gsna(&pdp->gsnlu, &gsn->gsnu);
-
- if (GTP_DEBUG) printf("gtp_create_pdp_ind: Before pdp_tidget\n");
-
- if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) {
- /* Found old pdp with same tid. Now the voodoo begins! */
- /* 09.60 / 29.060 allows create on existing context to "steal" */
- /* the context which was allready established */
- /* We check that the APN, selection mode and MSISDN is the same */
- if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n");
- if ((pdp->apn_req.l == pdp_old->apn_req.l)
- && (!memcmp(pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l))
- && (pdp->selmode == pdp_old->selmode)
- && (pdp->msisdn.l == pdp_old->msisdn.l)
- && (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l))) {
- /* OK! We are dealing with the same APN. We will copy new
- * parameters to the old pdp and send off confirmation
- * We ignore the following information elements:
- * QoS: MS will get originally negotiated QoS.
- * End user address (EUA). MS will get old EUA anyway.
- * Protocol configuration option (PCO): Only application can verify */
-
- if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n");
-
- /* Copy remote flow label */
- pdp_old->flru = pdp->flru;
- pdp_old->flrc = pdp->flrc;
-
- /* Copy remote tei */
- pdp_old->teid_gn = pdp->teid_gn;
- pdp_old->teic_gn = pdp->teic_gn;
-
- /* Copy peer GSN address */
- pdp_old->gsnrc.l = pdp->gsnrc.l;
- memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l);
- pdp_old->gsnru.l = pdp->gsnru.l;
- memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l);
-
- /* Copy request parameters */
- pdp_old->seq = pdp->seq;
- pdp_old->sa_peer = pdp->sa_peer;
- pdp_old->fd = pdp->fd = fd;
- pdp_old->version = pdp->version = version;
-
- /* Switch to using the old pdp context */
- pdp = pdp_old;
-
- /* Confirm to peer that things were "successful" */
- return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_ACC_REQ);
- }
- else { /* This is not the same PDP context. Delete the old one. */
-
- if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleting old context\n");
-
- if (gsn->cb_delete_context) gsn->cb_delete_context(pdp_old);
- pdp_freepdp(pdp_old);
-
- if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleted...\n");
- }
- }
-
- pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp);
-
- /* Callback function to validata login */
- if (gsn->cb_create_context_ind !=0)
- return gsn->cb_create_context_ind(pdp);
- else {
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "No create_context_ind callback defined");
- return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_NOT_SUPPORTED);
- }
-}
+ struct sockaddr_in *peer, int fd,
+ void *pack, unsigned len)
+{
+ struct pdp_t *pdp, *pdp_old;
+ struct pdp_t pdp_buf;
+ union gtpie_member *ie[GTPIE_SIZE];
+ uint8_t recovery;
+
+ uint16_t seq = get_seq(pack);
+ int hlen = get_hlen(pack);
+ uint8_t linked_nsapi = 0;
+ struct pdp_t *linked_pdp = NULL;
+
+ if (!gtp_dublicate(gsn, version, peer, seq))
+ return 0;
+
+ pdp = &pdp_buf;
+ memset(pdp, 0, sizeof(struct pdp_t));
+
+ if (version == 0) {
+ pdp->imsi =
+ ((union gtp_packet *)pack)->gtp0.
+ h.tid & 0x0fffffffffffffffull;
+ pdp->nsapi =
+ (((union gtp_packet *)pack)->gtp0.
+ h.tid & 0xf000000000000000ull) >> 60;
+ }
+
+ pdp->seq = seq;
+ pdp->sa_peer = *peer;
+ pdp->fd = fd;
+ pdp->version = version;
+
+ /* Decode information elements */
+ if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
+ gsn->invalid++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Invalid message format");
+ if (0 == version)
+ return EOF;
+ else
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_INVALID_MESSAGE);
+ }
+
+ if (version == 1) {
+ /* Linked NSAPI (conditional) */
+ /* If included this is the Secondary PDP Context Activation Procedure */
+ /* In secondary activation IMSI is not included, so the context must be */
+ /* identified by the tei */
+ if (!gtpie_gettv1(ie, GTPIE_NSAPI, 1, &linked_nsapi)) {
+
+ /* Find the primary PDP context */
+ if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
+ gsn->incorrect++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len,
+ "Incorrect optional information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_OPT_IE_INCORRECT);
+ }
+
+ /* Check that the primary PDP context matches linked nsapi */
+ if (linked_pdp->nsapi != linked_nsapi) {
+ gsn->incorrect++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len,
+ "Incorrect optional information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_OPT_IE_INCORRECT);
+ }
+
+ /* Copy parameters from primary context */
+ pdp->selmode = linked_pdp->selmode;
+ pdp->imsi = linked_pdp->imsi;
+ pdp->msisdn = linked_pdp->msisdn;
+ pdp->eua = linked_pdp->eua;
+ pdp->pco_req = linked_pdp->pco_req;
+ pdp->apn_req = linked_pdp->apn_req;
+ pdp->teic_gn = linked_pdp->teic_gn;
+ pdp->secondary = 1;
+ }
+ }
+ /* if (version == 1) */
+ if (version == 0) {
+ if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
+ pdp->qos_req0, sizeof(pdp->qos_req0))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+ }
+
+ if ((version == 1) && (!linked_pdp)) {
+ /* Not Secondary PDP Context Activation Procedure */
+ /* IMSI (conditional) */
+ if (gtpie_gettv0
+ (ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+ }
+
+ /* Recovery (optional) */
+ if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
+ if (gsn->cb_recovery)
+ gsn->cb_recovery(peer, recovery);
+ }
+
+ /* Selection mode (conditional) */
+ if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
+ if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0,
+ &pdp->selmode, sizeof(pdp->selmode))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+ }
+
+ if (version == 0) {
+ if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+ }
+
+ if (version == 1) {
+ /* TEID (mandatory) */
+ if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ /* TEIC (conditional) */
+ if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
+ if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len,
+ "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+ }
+
+ /* NSAPI (mandatory) */
+ if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+ }
+
+ /* Charging Characteriatics (optional) */
+ /* Trace reference (optional) */
+ /* Trace type (optional) */
+ /* Charging Characteriatics (optional) */
+
+ if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
+ /* End User Address (conditional) */
+ if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
+ &pdp->eua.v, sizeof(pdp->eua.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ /* APN */
+ if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l,
+ &pdp->apn_req.v, sizeof(pdp->apn_req.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ /* Extract protocol configuration options (optional) */
+ if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
+ &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
+ }
+ }
+ /* SGSN address for signalling (mandatory) */
+ if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
+ &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ /* SGSN address for user traffic (mandatory) */
+ if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
+ &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ if (!linked_pdp) { /* Not Secondary PDP Context Activation Procedure */
+ /* MSISDN (conditional) */
+ if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l,
+ &pdp->msisdn.v, sizeof(pdp->msisdn.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+ }
+
+ if (version == 1) {
+ /* QoS (mandatory) */
+ if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
+ &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ /* TFT (conditional) */
+ if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
+ &pdp->tft.v, sizeof(pdp->tft.v))) {
+ }
+
+ /* Trigger ID */
+ /* OMC identity */
+ }
+
+ /* Initialize our own IP addresses */
+ in_addr2gsna(&pdp->gsnlc, &gsn->gsnc);
+ in_addr2gsna(&pdp->gsnlu, &gsn->gsnu);
+
+ if (GTP_DEBUG)
+ printf("gtp_create_pdp_ind: Before pdp_tidget\n");
+
+ if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) {
+ /* Found old pdp with same tid. Now the voodoo begins! */
+ /* 09.60 / 29.060 allows create on existing context to "steal" */
+ /* the context which was allready established */
+ /* We check that the APN, selection mode and MSISDN is the same */
+ if (GTP_DEBUG)
+ printf("gtp_create_pdp_ind: Old context found\n");
+ if ((pdp->apn_req.l == pdp_old->apn_req.l)
+ &&
+ (!memcmp
+ (pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l))
+ && (pdp->selmode == pdp_old->selmode)
+ && (pdp->msisdn.l == pdp_old->msisdn.l)
+ &&
+ (!memcmp(pdp->msisdn.v, pdp_old->msisdn.v, pdp->msisdn.l)))
+ {
+ /* OK! We are dealing with the same APN. We will copy new
+ * parameters to the old pdp and send off confirmation
+ * We ignore the following information elements:
+ * QoS: MS will get originally negotiated QoS.
+ * End user address (EUA). MS will get old EUA anyway.
+ * Protocol configuration option (PCO): Only application can verify */
+
+ if (GTP_DEBUG)
+ printf
+ ("gtp_create_pdp_ind: Old context found\n");
+
+ /* Copy remote flow label */
+ pdp_old->flru = pdp->flru;
+ pdp_old->flrc = pdp->flrc;
+
+ /* Copy remote tei */
+ pdp_old->teid_gn = pdp->teid_gn;
+ pdp_old->teic_gn = pdp->teic_gn;
+
+ /* Copy peer GSN address */
+ pdp_old->gsnrc.l = pdp->gsnrc.l;
+ memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l);
+ pdp_old->gsnru.l = pdp->gsnru.l;
+ memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l);
+
+ /* Copy request parameters */
+ pdp_old->seq = pdp->seq;
+ pdp_old->sa_peer = pdp->sa_peer;
+ pdp_old->fd = pdp->fd = fd;
+ pdp_old->version = pdp->version = version;
+
+ /* Switch to using the old pdp context */
+ pdp = pdp_old;
+
+ /* Confirm to peer that things were "successful" */
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_ACC_REQ);
+ } else { /* This is not the same PDP context. Delete the old one. */
+
+ if (GTP_DEBUG)
+ printf
+ ("gtp_create_pdp_ind: Deleting old context\n");
+
+ if (gsn->cb_delete_context)
+ gsn->cb_delete_context(pdp_old);
+ pdp_freepdp(pdp_old);
+
+ if (GTP_DEBUG)
+ printf("gtp_create_pdp_ind: Deleted...\n");
+ }
+ }
+
+ pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp);
+
+ /* Callback function to validata login */
+ if (gsn->cb_create_context_ind != 0)
+ return gsn->cb_create_context_ind(pdp);
+ else {
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "No create_context_ind callback defined");
+ return gtp_create_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_NOT_SUPPORTED);
+ }
+}
/* Handle Create PDP Context Response */
int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
- struct sockaddr_in *peer,
- void *pack, unsigned len) {
- struct pdp_t *pdp;
- union gtpie_member *ie[GTPIE_SIZE];
- uint8_t cause, recovery;
- void *cbp = NULL;
- uint8_t type = 0;
- int hlen = get_hlen(pack);
-
- /* Remove packet from queue */
- if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
-
- /* Find the context in question */
- if (pdp_getgtp1(&pdp, get_tei(pack))) {
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
- return EOF;
- }
-
- /* Register that we have received a valid teic from GGSN */
- pdp->teic_confirmed = 1;
-
- /* Decode information elements */
- if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
- gsn->invalid++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Invalid message format");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- /* Extract cause value (mandatory) */
- if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- /* Extract recovery (optional) */
- if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery);
- }
-
- /* Extract protocol configuration options (optional) */
- if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
- &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
- }
-
- /* Check all conditional information elements */
- if (GTPCAUSE_ACC_REQ == cause) {
-
- if (version == 0) {
- if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
- &pdp->qos_neg0, sizeof(pdp->qos_neg0))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
- }
-
- if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- if (version == 0) {
- if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
- }
-
- if (version == 1) {
- if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
- }
-
- if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- }
-
- if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
- &pdp->eua.v, sizeof(pdp->eua.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
- &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
- &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- if (version == 1) {
- if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
- &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
- }
-
- }
-
- if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
-
- return 0;
-}
+ struct sockaddr_in *peer, void *pack, unsigned len)
+{
+ struct pdp_t *pdp;
+ union gtpie_member *ie[GTPIE_SIZE];
+ uint8_t cause, recovery;
+ void *cbp = NULL;
+ uint8_t type = 0;
+ int hlen = get_hlen(pack);
+
+ /* Remove packet from queue */
+ if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
+ return EOF;
+
+ /* Find the context in question */
+ if (pdp_getgtp1(&pdp, get_tei(pack))) {
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Unknown PDP context");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, NULL, cbp);
+ return EOF;
+ }
+ /* Register that we have received a valid teic from GGSN */
+ pdp->teic_confirmed = 1;
+
+ /* Decode information elements */
+ if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
+ gsn->invalid++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Invalid message format");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ /* Extract cause value (mandatory) */
+ if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Missing mandatory information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ /* Extract recovery (optional) */
+ if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
+ if (gsn->cb_recovery)
+ gsn->cb_recovery(peer, recovery);
+ }
+
+ /* Extract protocol configuration options (optional) */
+ if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l,
+ &pdp->pco_req.v, sizeof(pdp->pco_req.v))) {
+ }
+
+ /* Check all conditional information elements */
+ if (GTPCAUSE_ACC_REQ == cause) {
+
+ if (version == 0) {
+ if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
+ &pdp->qos_neg0,
+ sizeof(pdp->qos_neg0))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+ }
+
+ if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ if (version == 0) {
+ if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+ }
+
+ if (version == 1) {
+ if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+ }
+
+ if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ }
+
+ if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
+ &pdp->eua.v, sizeof(pdp->eua.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
+ &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
+ &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ if (version == 1) {
+ if (gtpie_gettlv
+ (ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l,
+ &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+ }
+
+ }
+
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, cause, pdp, cbp);
+
+ return 0;
+}
/* API: Send Update PDP Context Request */
int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
- struct in_addr* inetaddr) {
- union gtp_packet packet;
- unsigned int length = get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet);
-
- if (pdp->version == 0)
- gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
- sizeof(pdp->qos_req0), pdp->qos_req0);
-
- /* Include IMSI if updating with unknown teic_gn */
- if ((pdp->version == 1) && (!pdp->teic_gn))
- gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
- sizeof(pdp->imsi), (uint8_t*) &pdp->imsi);
-
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
- gsn->restart_counter);
-
- if (pdp->version == 0) {
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
- pdp->fllu);
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
- pdp->fllc);
- }
-
- if (pdp->version == 1) {
- gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
- pdp->teid_own);
-
- if (!pdp->teic_confirmed)
- gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
- pdp->teic_own);
- }
-
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
- pdp->nsapi);
-
- /* TODO
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
- pdp->traceref);
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
- pdp->tracetype); */
-
- /* TODO if ggsn update message
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
- pdp->eua.l, pdp->eua.v);
- */
-
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
- pdp->gsnlc.l, pdp->gsnlc.v);
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
- pdp->gsnlu.l, pdp->gsnlu.v);
-
- if (pdp->version == 1)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
- pdp->qos_req.l, pdp->qos_req.v);
-
-
- if ((pdp->version == 1) && pdp->tft.l)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
- pdp->tft.l, pdp->tft.v);
-
- if ((pdp->version == 1) && pdp->triggerid.l)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
- pdp->triggerid.l, pdp->triggerid.v);
-
- if ((pdp->version == 1) && pdp->omcid.l)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
- pdp->omcid.l, pdp->omcid.v);
-
- gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp);
-
- return 0;
-}
+ struct in_addr *inetaddr)
+{
+ union gtp_packet packet;
+ unsigned int length =
+ get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet);
+
+ if (pdp->version == 0)
+ gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
+ sizeof(pdp->qos_req0), pdp->qos_req0);
+
+ /* Include IMSI if updating with unknown teic_gn */
+ if ((pdp->version == 1) && (!pdp->teic_gn))
+ gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI,
+ sizeof(pdp->imsi), (uint8_t *) & pdp->imsi);
+
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
+ gsn->restart_counter);
+
+ if (pdp->version == 0) {
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, pdp->fllu);
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, pdp->fllc);
+ }
+
+ if (pdp->version == 1) {
+ gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
+ pdp->teid_own);
+
+ if (!pdp->teic_confirmed)
+ gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
+ pdp->teic_own);
+ }
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
+
+ /* TODO
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF,
+ pdp->traceref);
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE,
+ pdp->tracetype); */
+
+ /* TODO if ggsn update message
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
+ pdp->eua.l, pdp->eua.v);
+ */
+
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
+ pdp->gsnlc.l, pdp->gsnlc.v);
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
+ pdp->gsnlu.l, pdp->gsnlu.v);
+
+ if (pdp->version == 1)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
+ pdp->qos_req.l, pdp->qos_req.v);
+
+ if ((pdp->version == 1) && pdp->tft.l)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT,
+ pdp->tft.l, pdp->tft.v);
+
+ if ((pdp->version == 1) && pdp->triggerid.l)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID,
+ pdp->triggerid.l, pdp->triggerid.v);
+
+ if ((pdp->version == 1) && pdp->omcid.l)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
+ pdp->omcid.l, pdp->omcid.v);
+
+ gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp);
+
+ return 0;
+}
/* Send Update PDP Context Response */
-int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
- struct sockaddr_in *peer, int fd,
+int gtp_update_pdp_resp(struct gsn_t *gsn, int version,
+ struct sockaddr_in *peer, int fd,
void *pack, unsigned len,
- struct pdp_t *pdp, uint8_t cause) {
-
- union gtp_packet packet;
- unsigned int length = get_default_gtp(version, GTP_UPDATE_PDP_RSP, &packet);
-
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
-
- if (cause == GTPCAUSE_ACC_REQ) {
-
- if (version == 0)
- gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
- sizeof(pdp->qos_neg0), pdp->qos_neg0);
-
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
- gsn->restart_counter);
-
- if (version == 0) {
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
- pdp->fllu);
- gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
- pdp->fllc);
- }
-
- if (version == 1) {
- gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
- pdp->teid_own);
-
- if (!pdp->teic_confirmed)
- gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C,
- pdp->teic_own);
- }
-
- /* TODO we use teid_own as charging ID address */
- gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
- pdp->teid_own);
-
- /* If ggsn
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
- pdp->eua.l, pdp->eua.v); */
-
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
- pdp->gsnlc.l, pdp->gsnlc.v);
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
- pdp->gsnlu.l, pdp->gsnlu.v);
-
- if (version == 1)
- gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
- pdp->qos_neg.l, pdp->qos_neg.v);
-
- /* TODO: Charging gateway address */
- }
-
- return gtp_resp(version, gsn, pdp, &packet, length, peer,
- fd, get_seq(pack), get_tid(pack));
-}
+ struct pdp_t *pdp, uint8_t cause)
+{
+
+ union gtp_packet packet;
+ unsigned int length =
+ get_default_gtp(version, GTP_UPDATE_PDP_RSP, &packet);
+
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
+
+ if (cause == GTPCAUSE_ACC_REQ) {
+
+ if (version == 0)
+ gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
+ sizeof(pdp->qos_neg0), pdp->qos_neg0);
+
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY,
+ gsn->restart_counter);
+
+ if (version == 0) {
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI,
+ pdp->fllu);
+ gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C,
+ pdp->fllc);
+ }
+
+ if (version == 1) {
+ gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI,
+ pdp->teid_own);
+
+ if (!pdp->teic_confirmed)
+ gtpie_tv4(&packet, &length, GTP_MAX,
+ GTPIE_TEI_C, pdp->teic_own);
+ }
+
+ /* TODO we use teid_own as charging ID address */
+ gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID,
+ pdp->teid_own);
+
+ /* If ggsn
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA,
+ pdp->eua.l, pdp->eua.v); */
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
+ pdp->gsnlc.l, pdp->gsnlc.v);
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR,
+ pdp->gsnlu.l, pdp->gsnlu.v);
+
+ if (version == 1)
+ gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE,
+ pdp->qos_neg.l, pdp->qos_neg.v);
+
+ /* TODO: Charging gateway address */
+ }
+
+ return gtp_resp(version, gsn, pdp, &packet, length, peer,
+ fd, get_seq(pack), get_tid(pack));
+}
/* Handle Update PDP Context Request */
int gtp_update_pdp_ind(struct gsn_t *gsn, int version,
- struct sockaddr_in *peer, int fd,
- void *pack, unsigned len) {
- struct pdp_t *pdp;
- struct pdp_t pdp_backup;
- union gtpie_member* ie[GTPIE_SIZE];
- uint8_t recovery;
-
- uint16_t seq = get_seq(pack);
- int hlen = get_hlen(pack);
-
- uint64_t imsi;
- uint8_t nsapi;
-
- /* Is this a dublicate ? */
- if(!gtp_dublicate(gsn, version, peer, seq)) {
- return 0; /* We allready send of response once */
- }
-
-
- /* Decode information elements */
- if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
- gsn->invalid++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Invalid message format");
- if (0 == version)
- return EOF;
- else
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
- NULL, GTPCAUSE_INVALID_MESSAGE);
- }
-
- /* Finding PDP: */
- /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
- /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
- /* we have to use the tunnel endpoint identifier */
- if (version == 0) {
- imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffffull;
- nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000ull) >> 60;
-
- /* Find the context in question */
- if (pdp_getimsi(&pdp, imsi, nsapi)) {
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
- NULL, GTPCAUSE_NON_EXIST);
- }
- }
- else if (version == 1) {
- /* NSAPI (mandatory) */
- if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
- NULL, GTPCAUSE_MAN_IE_MISSING);
- }
-
- /* IMSI (conditional) */
- if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) {
- /* Find the context in question */
- if (pdp_getgtp1(&pdp, get_tei(pack))) {
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
- NULL, GTPCAUSE_NON_EXIST);
- }
- }
- else {
- /* Find the context in question */
- if (pdp_getimsi(&pdp, imsi, nsapi)) {
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
- NULL, GTPCAUSE_NON_EXIST);
- }
- }
- }
- else {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
- return EOF;
- }
-
- /* Make a backup copy in case anything is wrong */
- memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
-
- if (version == 0) {
- if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
- pdp->qos_req0, sizeof(pdp->qos_req0))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
- pdp, GTPCAUSE_MAN_IE_MISSING);
- }
- }
-
- /* Recovery (optional) */
- if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery);
- }
-
- if (version == 0) {
- if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
- }
-
-
- if (version == 1) {
- /* TEID (mandatory) */
- if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- /* TEIC (conditional) */
- /* If TEIC is not included it means that we have allready received it */
- /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
- /* all updated contexts, or only for one of the linked contexts */
- gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn);
-
- /* NSAPI (mandatory) */
- if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
- }
-
- /* Trace reference (optional) */
- /* Trace type (optional) */
-
- /* End User Address (conditional) TODO: GGSN Initiated
- if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
- &pdp->eua.v, sizeof(pdp->eua.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
- return gtp_update_pdp_resp(gsn, version, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- } */
-
-
- /* SGSN address for signalling (mandatory) */
- /* It is weird that this is mandatory when TEIC is conditional */
- if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
- &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- /* SGSN address for user traffic (mandatory) */
- if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
- &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- if (version == 1) {
- /* QoS (mandatory) */
- if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
- &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
- GTPCAUSE_MAN_IE_MISSING);
- }
-
- /* TFT (conditional) */
- if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
- &pdp->tft.v, sizeof(pdp->tft.v))) {
- }
-
- /* OMC identity */
- }
-
- /* Confirm to peer that things were "successful" */
- return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
- GTPCAUSE_ACC_REQ);
-}
+ struct sockaddr_in *peer, int fd,
+ void *pack, unsigned len)
+{
+ struct pdp_t *pdp;
+ struct pdp_t pdp_backup;
+ union gtpie_member *ie[GTPIE_SIZE];
+ uint8_t recovery;
+
+ uint16_t seq = get_seq(pack);
+ int hlen = get_hlen(pack);
+
+ uint64_t imsi;
+ uint8_t nsapi;
+
+ /* Is this a dublicate ? */
+ if (!gtp_dublicate(gsn, version, peer, seq)) {
+ return 0; /* We allready send of response once */
+ }
+
+ /* Decode information elements */
+ if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
+ gsn->invalid++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Invalid message format");
+ if (0 == version)
+ return EOF;
+ else
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
+ len, NULL,
+ GTPCAUSE_INVALID_MESSAGE);
+ }
+
+ /* Finding PDP: */
+ /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */
+ /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */
+ /* we have to use the tunnel endpoint identifier */
+ if (version == 0) {
+ imsi =
+ ((union gtp_packet *)pack)->gtp0.
+ h.tid & 0x0fffffffffffffffull;
+ nsapi =
+ (((union gtp_packet *)pack)->gtp0.
+ h.tid & 0xf000000000000000ull) >> 60;
+
+ /* Find the context in question */
+ if (pdp_getimsi(&pdp, imsi, nsapi)) {
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Unknown PDP context");
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
+ len, NULL,
+ GTPCAUSE_NON_EXIST);
+ }
+ } else if (version == 1) {
+ /* NSAPI (mandatory) */
+ if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
+ len, NULL,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ /* IMSI (conditional) */
+ if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) {
+ /* Find the context in question */
+ if (pdp_getgtp1(&pdp, get_tei(pack))) {
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len, "Unknown PDP context");
+ return gtp_update_pdp_resp(gsn, version, peer,
+ fd, pack, len, NULL,
+ GTPCAUSE_NON_EXIST);
+ }
+ } else {
+ /* Find the context in question */
+ if (pdp_getimsi(&pdp, imsi, nsapi)) {
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer,
+ pack, len, "Unknown PDP context");
+ return gtp_update_pdp_resp(gsn, version, peer,
+ fd, pack, len, NULL,
+ GTPCAUSE_NON_EXIST);
+ }
+ }
+ } else {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
+ return EOF;
+ }
+
+ /* Make a backup copy in case anything is wrong */
+ memcpy(&pdp_backup, pdp, sizeof(pdp_backup));
+
+ if (version == 0) {
+ if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
+ pdp->qos_req0, sizeof(pdp->qos_req0))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
+ len, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+ }
+
+ /* Recovery (optional) */
+ if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
+ if (gsn->cb_recovery)
+ gsn->cb_recovery(peer, recovery);
+ }
+
+ if (version == 0) {
+ if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
+ len, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
+ len, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+ }
+
+ if (version == 1) {
+ /* TEID (mandatory) */
+ if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
+ len, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ /* TEIC (conditional) */
+ /* If TEIC is not included it means that we have allready received it */
+ /* TODO: From 29.060 it is not clear if TEI_C MUST be included for */
+ /* all updated contexts, or only for one of the linked contexts */
+ gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn);
+
+ /* NSAPI (mandatory) */
+ if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
+ len, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+ }
+
+ /* Trace reference (optional) */
+ /* Trace type (optional) */
+
+ /* End User Address (conditional) TODO: GGSN Initiated
+ if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
+ &pdp->eua.v, sizeof(pdp->eua.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Missing mandatory information field");
+ memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
+ return gtp_update_pdp_resp(gsn, version, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ } */
+
+ /* SGSN address for signalling (mandatory) */
+ /* It is weird that this is mandatory when TEIC is conditional */
+ if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
+ &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Missing mandatory information field");
+ memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
+ pdp, GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ /* SGSN address for user traffic (mandatory) */
+ if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
+ &pdp->gsnru.v, sizeof(pdp->gsnru.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Missing mandatory information field");
+ memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len,
+ pdp, GTPCAUSE_MAN_IE_MISSING);
+ }
+ if (version == 1) {
+ /* QoS (mandatory) */
+ if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l,
+ &pdp->qos_req.v, sizeof(pdp->qos_req.v))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ memcpy(pdp, &pdp_backup, sizeof(pdp_backup));
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack,
+ len, pdp,
+ GTPCAUSE_MAN_IE_MISSING);
+ }
+
+ /* TFT (conditional) */
+ if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l,
+ &pdp->tft.v, sizeof(pdp->tft.v))) {
+ }
+
+ /* OMC identity */
+ }
+
+ /* Confirm to peer that things were "successful" */
+ return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp,
+ GTPCAUSE_ACC_REQ);
+}
/* Handle Update PDP Context Response */
int gtp_update_pdp_conf(struct gsn_t *gsn, int version,
- struct sockaddr_in *peer,
- void *pack, unsigned len) {
- struct pdp_t *pdp;
- union gtpie_member *ie[GTPIE_SIZE];
- uint8_t cause, recovery;
- void *cbp = NULL;
- uint8_t type = 0;
-
- /* Remove packet from queue */
- if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp)) return EOF;
-
- /* Find the context in question */
- if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) {
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
- return EOF;
- }
-
- /* Register that we have received a valid teic from GGSN */
- pdp->teic_confirmed = 1;
-
- /* Decode information elements */
- if (gtpie_decaps(ie, 0, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) {
- gsn->invalid++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Invalid message format");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- /* Extract cause value (mandatory) */
- if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- /* Extract recovery (optional) */
- if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery) gsn->cb_recovery(peer, recovery);
- }
-
- /* Check all conditional information elements */
- if (GTPCAUSE_ACC_REQ != cause) {
- if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return 0;
- }
- else {
- /* Check for missing conditionary information elements */
- if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) &&
- gtpie_exist(ie, GTPIE_REORDER, 0) &&
- gtpie_exist(ie, GTPIE_FL_DI, 0) &&
- gtpie_exist(ie, GTPIE_FL_C, 0) &&
- gtpie_exist(ie, GTPIE_CHARGING_ID, 0) &&
- gtpie_exist(ie, GTPIE_EUA, 0) &&
- gtpie_exist(ie, GTPIE_GSN_ADDR, 0) &&
- gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing conditional information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp);
- /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp); */
- return EOF;
- }
-
- /* Update pdp with new values */
- gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
- pdp->qos_neg0, sizeof(pdp->qos_neg0));
- gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder);
- gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru);
- gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc);
- gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid);
- gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
- &pdp->eua.v, sizeof(pdp->eua.v));
- gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
- &pdp->gsnrc.v, sizeof(pdp->gsnrc.v));
- gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
- &pdp->gsnru.v, sizeof(pdp->gsnru.v));
-
- if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp);
- return 0; /* Succes */
- }
-}
+ struct sockaddr_in *peer, void *pack, unsigned len)
+{
+ struct pdp_t *pdp;
+ union gtpie_member *ie[GTPIE_SIZE];
+ uint8_t cause, recovery;
+ void *cbp = NULL;
+ uint8_t type = 0;
+
+ /* Remove packet from queue */
+ if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp))
+ return EOF;
+
+ /* Find the context in question */
+ if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) {
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Unknown PDP context");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, cause, NULL, cbp);
+ return EOF;
+ }
+ /* Register that we have received a valid teic from GGSN */
+ pdp->teic_confirmed = 1;
+
+ /* Decode information elements */
+ if (gtpie_decaps
+ (ie, 0, pack + GTP0_HEADER_SIZE, len - GTP0_HEADER_SIZE)) {
+ gsn->invalid++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Invalid message format");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ /* Extract cause value (mandatory) */
+ if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Missing mandatory information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ /* Extract recovery (optional) */
+ if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
+ if (gsn->cb_recovery)
+ gsn->cb_recovery(peer, recovery);
+ }
+
+ /* Check all conditional information elements */
+ if (GTPCAUSE_ACC_REQ != cause) {
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, cause, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return 0;
+ } else {
+ /* Check for missing conditionary information elements */
+ if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) &&
+ gtpie_exist(ie, GTPIE_REORDER, 0) &&
+ gtpie_exist(ie, GTPIE_FL_DI, 0) &&
+ gtpie_exist(ie, GTPIE_FL_C, 0) &&
+ gtpie_exist(ie, GTPIE_CHARGING_ID, 0) &&
+ gtpie_exist(ie, GTPIE_EUA, 0) &&
+ gtpie_exist(ie, GTPIE_GSN_ADDR, 0) &&
+ gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len,
+ "Missing conditional information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, pdp, cbp);
+ /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp); */
+ return EOF;
+ }
+
+ /* Update pdp with new values */
+ gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
+ pdp->qos_neg0, sizeof(pdp->qos_neg0));
+ gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder);
+ gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru);
+ gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc);
+ gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid);
+ gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l,
+ &pdp->eua.v, sizeof(pdp->eua.v));
+ gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l,
+ &pdp->gsnrc.v, sizeof(pdp->gsnrc.v));
+ gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l,
+ &pdp->gsnru.v, sizeof(pdp->gsnru.v));
+
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, cause, pdp, cbp);
+ return 0; /* Succes */
+ }
+}
/* API: Send Delete PDP Context Request */
int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp,
- int teardown) {
- union gtp_packet packet;
- unsigned int length = get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
- struct in_addr addr;
- struct pdp_t *linked_pdp;
- struct pdp_t *secondary_pdp;
- int n;
- int count = 0;
-
- if (gsna2in_addr(&addr, &pdp->gsnrc)) {
- gsn->err_address++;
- gtp_err(LOG_ERR, __FILE__, __LINE__, "GSN address conversion failed");
- return EOF;
- }
-
- if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown linked PDP context");
- return EOF;
- }
-
- if (!teardown) {
- for (n=0; n< PDP_MAXNSAPI; n++)
- if (linked_pdp->secondary_tei[n]) count++;
- if (count <= 1) {
- gtp_err(LOG_ERR, __FILE__, __LINE__,
- "Must use teardown for last context");
- return EOF;
- }
- }
-
- if (pdp->version == 1) {
- if (teardown)
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
- 0xff);
-
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI,
- pdp->nsapi);
- }
-
- gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
-
- if (teardown) { /* Remove all contexts */
- for (n=0; n< PDP_MAXNSAPI; n++) {
- if (linked_pdp->secondary_tei[n]) {
- if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown secondary PDP context");
- return EOF;
- }
- if (linked_pdp != secondary_pdp) {
- if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp);
- pdp_freepdp(secondary_pdp);
- }
- }
- }
- if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp);
- pdp_freepdp(linked_pdp);
- }
- else {
- if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- if (pdp == linked_pdp) {
- linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
- linked_pdp->nodata = 1;
- }
- else
- pdp_freepdp(pdp);
- }
-
- return 0;
+ int teardown)
+{
+ union gtp_packet packet;
+ unsigned int length =
+ get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet);
+ struct in_addr addr;
+ struct pdp_t *linked_pdp;
+ struct pdp_t *secondary_pdp;
+ int n;
+ int count = 0;
+
+ if (gsna2in_addr(&addr, &pdp->gsnrc)) {
+ gsn->err_address++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "GSN address conversion failed");
+ return EOF;
+ }
+
+ if (pdp_getgtp1(&linked_pdp, pdp->teic_own)) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Unknown linked PDP context");
+ return EOF;
+ }
+
+ if (!teardown) {
+ for (n = 0; n < PDP_MAXNSAPI; n++)
+ if (linked_pdp->secondary_tei[n])
+ count++;
+ if (count <= 1) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Must use teardown for last context");
+ return EOF;
+ }
+ }
+
+ if (pdp->version == 1) {
+ if (teardown)
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN,
+ 0xff);
+
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, pdp->nsapi);
+ }
+
+ gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp);
+
+ if (teardown) { /* Remove all contexts */
+ for (n = 0; n < PDP_MAXNSAPI; n++) {
+ if (linked_pdp->secondary_tei[n]) {
+ if (pdp_getgtp1
+ (&secondary_pdp,
+ linked_pdp->secondary_tei[n])) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Unknown secondary PDP context");
+ return EOF;
+ }
+ if (linked_pdp != secondary_pdp) {
+ if (gsn->cb_delete_context)
+ gsn->cb_delete_context
+ (secondary_pdp);
+ pdp_freepdp(secondary_pdp);
+ }
+ }
+ }
+ if (gsn->cb_delete_context)
+ gsn->cb_delete_context(linked_pdp);
+ pdp_freepdp(linked_pdp);
+ } else {
+ if (gsn->cb_delete_context)
+ gsn->cb_delete_context(pdp);
+ if (pdp == linked_pdp) {
+ linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
+ linked_pdp->nodata = 1;
+ } else
+ pdp_freepdp(pdp);
+ }
+
+ return 0;
}
/* Send Delete PDP Context Response */
int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
struct sockaddr_in *peer, int fd,
- void *pack, unsigned len,
- struct pdp_t *pdp, struct pdp_t *linked_pdp,
+ void *pack, unsigned len,
+ struct pdp_t *pdp, struct pdp_t *linked_pdp,
uint8_t cause, int teardown)
{
- union gtp_packet packet;
- struct pdp_t *secondary_pdp;
- unsigned int length = get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet);
- int n;
-
- gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
-
- gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
- get_seq(pack), get_tid(pack));
-
- if (cause == GTPCAUSE_ACC_REQ) {
- if ((teardown) || (version == 0)) { /* Remove all contexts */
- for (n=0; n< PDP_MAXNSAPI; n++) {
- if (linked_pdp->secondary_tei[n]) {
- if (pdp_getgtp1(&secondary_pdp, linked_pdp->secondary_tei[n])) {
- gtp_err(LOG_ERR, __FILE__, __LINE__,
- "Unknown secondary PDP context");
- return EOF;
- }
- if (linked_pdp != secondary_pdp) {
- if (gsn->cb_delete_context) gsn->cb_delete_context(secondary_pdp);
- pdp_freepdp(secondary_pdp);
- }
- }
- }
- if (gsn->cb_delete_context) gsn->cb_delete_context(linked_pdp);
- pdp_freepdp(linked_pdp);
- }
- else { /* Remove only current context */
- if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- if (pdp == linked_pdp) {
- linked_pdp->secondary_tei[pdp->nsapi & 0xf0] = 0;
- linked_pdp->nodata = 1;
- }
- else
- pdp_freepdp(pdp);
- }
- } /* if (cause == GTPCAUSE_ACC_REQ) */
-
- return 0;
+ union gtp_packet packet;
+ struct pdp_t *secondary_pdp;
+ unsigned int length =
+ get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet);
+ int n;
+
+ gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
+
+ gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
+ get_seq(pack), get_tid(pack));
+
+ if (cause == GTPCAUSE_ACC_REQ) {
+ if ((teardown) || (version == 0)) { /* Remove all contexts */
+ for (n = 0; n < PDP_MAXNSAPI; n++) {
+ if (linked_pdp->secondary_tei[n]) {
+ if (pdp_getgtp1
+ (&secondary_pdp,
+ linked_pdp->secondary_tei[n])) {
+ gtp_err(LOG_ERR, __FILE__,
+ __LINE__,
+ "Unknown secondary PDP context");
+ return EOF;
+ }
+ if (linked_pdp != secondary_pdp) {
+ if (gsn->cb_delete_context)
+ gsn->cb_delete_context
+ (secondary_pdp);
+ pdp_freepdp(secondary_pdp);
+ }
+ }
+ }
+ if (gsn->cb_delete_context)
+ gsn->cb_delete_context(linked_pdp);
+ pdp_freepdp(linked_pdp);
+ } else { /* Remove only current context */
+ if (gsn->cb_delete_context)
+ gsn->cb_delete_context(pdp);
+ if (pdp == linked_pdp) {
+ linked_pdp->secondary_tei[pdp->nsapi & 0xf0] =
+ 0;
+ linked_pdp->nodata = 1;
+ } else
+ pdp_freepdp(pdp);
+ }
+ }
+ /* if (cause == GTPCAUSE_ACC_REQ) */
+ return 0;
}
/* Handle Delete PDP Context Request */
int gtp_delete_pdp_ind(struct gsn_t *gsn, int version,
struct sockaddr_in *peer, int fd,
- void *pack, unsigned len) {
- struct pdp_t *pdp = NULL;
- struct pdp_t *linked_pdp = NULL;
- union gtpie_member* ie[GTPIE_SIZE];
-
- uint16_t seq = get_seq(pack);
- int hlen = get_hlen(pack);
-
- uint8_t nsapi;
- uint8_t teardown = 0;
- int n;
- int count = 0;
-
- /* Is this a dublicate ? */
- if(!gtp_dublicate(gsn, version, peer, seq)) {
- return 0; /* We allready send off response once */
- }
-
- /* Find the linked context in question */
- if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
- GTPCAUSE_NON_EXIST, teardown);
- }
-
- /* If version 0 this is also the secondary context */
- if (version == 0)
- pdp = linked_pdp;
-
- /* Decode information elements */
- if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
- gsn->invalid++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Invalid message format");
- if (0 == version)
- return EOF;
- else
- return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
- GTPCAUSE_INVALID_MESSAGE, teardown);
- }
-
- if (version == 1) {
- /* NSAPI (mandatory) */
- if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
- GTPCAUSE_MAN_IE_MISSING, teardown);
- }
-
- /* Find the context in question */
- if (pdp_getgtp1(&pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) {
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, NULL, NULL,
- GTPCAUSE_NON_EXIST, teardown);
- }
-
- /* Teardown (conditional) */
- gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown);
-
- if (!teardown) {
- for (n=0; n< PDP_MAXNSAPI; n++)
- if (linked_pdp->secondary_tei[n]) count++;
- if (count <= 1) {
- return 0; /* 29.060 7.3.5 Ignore message */
- }
- }
- }
-
- return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
- pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown);
-}
+ void *pack, unsigned len)
+{
+ struct pdp_t *pdp = NULL;
+ struct pdp_t *linked_pdp = NULL;
+ union gtpie_member *ie[GTPIE_SIZE];
+ uint16_t seq = get_seq(pack);
+ int hlen = get_hlen(pack);
+
+ uint8_t nsapi;
+ uint8_t teardown = 0;
+ int n;
+ int count = 0;
+
+ /* Is this a dublicate ? */
+ if (!gtp_dublicate(gsn, version, peer, seq)) {
+ return 0; /* We allready send off response once */
+ }
+
+ /* Find the linked context in question */
+ if (pdp_getgtp1(&linked_pdp, get_tei(pack))) {
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Unknown PDP context");
+ return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
+ NULL, NULL, GTPCAUSE_NON_EXIST,
+ teardown);
+ }
+
+ /* If version 0 this is also the secondary context */
+ if (version == 0)
+ pdp = linked_pdp;
+
+ /* Decode information elements */
+ if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
+ gsn->invalid++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Invalid message format");
+ if (0 == version)
+ return EOF;
+ else
+ return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
+ len, NULL, NULL,
+ GTPCAUSE_INVALID_MESSAGE,
+ teardown);
+ }
+
+ if (version == 1) {
+ /* NSAPI (mandatory) */
+ if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Missing mandatory information field");
+ return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
+ len, NULL, NULL,
+ GTPCAUSE_MAN_IE_MISSING,
+ teardown);
+ }
+
+ /* Find the context in question */
+ if (pdp_getgtp1(&pdp, linked_pdp->secondary_tei[nsapi & 0x0f])) {
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Unknown PDP context");
+ return gtp_delete_pdp_resp(gsn, version, peer, fd, pack,
+ len, NULL, NULL,
+ GTPCAUSE_NON_EXIST,
+ teardown);
+ }
+
+ /* Teardown (conditional) */
+ gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown);
+
+ if (!teardown) {
+ for (n = 0; n < PDP_MAXNSAPI; n++)
+ if (linked_pdp->secondary_tei[n])
+ count++;
+ if (count <= 1) {
+ return 0; /* 29.060 7.3.5 Ignore message */
+ }
+ }
+ }
+
+ return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len,
+ pdp, linked_pdp, GTPCAUSE_ACC_REQ, teardown);
+}
/* Handle Delete PDP Context Response */
int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
- struct sockaddr_in *peer,
- void *pack, unsigned len) {
- union gtpie_member *ie[GTPIE_SIZE];
- uint8_t cause;
- void *cbp = NULL;
- uint8_t type = 0;
- int hlen = get_hlen(pack);
-
- /* Remove packet from queue */
- if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF;
-
- /* Decode information elements */
- if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) {
- gsn->invalid++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Invalid message format");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
- return EOF;
- }
-
- /* Extract cause value (mandatory) */
- if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
- gsn->missing++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Missing mandatory information field");
- if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp);
- return EOF;
- }
-
- /* Check the cause value (again) */
- if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
- gsn->err_cause++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unexpected cause value received: %d", cause);
- if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
- return EOF;
- }
-
- /* Callback function to notify application */
- if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp);
-
- return 0;
+ struct sockaddr_in *peer, void *pack, unsigned len)
+{
+ union gtpie_member *ie[GTPIE_SIZE];
+ uint8_t cause;
+ void *cbp = NULL;
+ uint8_t type = 0;
+ int hlen = get_hlen(pack);
+
+ /* Remove packet from queue */
+ if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
+ return EOF;
+
+ /* Decode information elements */
+ if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
+ gsn->invalid++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Invalid message format");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, NULL, cbp);
+ return EOF;
+ }
+
+ /* Extract cause value (mandatory) */
+ if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
+ gsn->missing++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Missing mandatory information field");
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, EOF, NULL, cbp);
+ return EOF;
+ }
+
+ /* Check the cause value (again) */
+ if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
+ gsn->err_cause++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Unexpected cause value received: %d", cause);
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, cause, NULL, cbp);
+ return EOF;
+ }
+
+ /* Callback function to notify application */
+ if (gsn->cb_conf)
+ gsn->cb_conf(type, cause, NULL, cbp);
+
+ return 0;
}
/* Send Error Indication (response to a GPDU message */
@@ -2485,89 +2624,90 @@ int gtp_error_ind_resp(struct gsn_t *gsn, int version,
struct sockaddr_in *peer, int fd,
void *pack, unsigned len)
{
- union gtp_packet packet;
- unsigned int length = get_default_gtp(version, GTP_ERROR, &packet);
-
- return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
- get_seq(pack), get_tid(pack));
+ union gtp_packet packet;
+ unsigned int length = get_default_gtp(version, GTP_ERROR, &packet);
+
+ return gtp_resp(version, gsn, NULL, &packet, length, peer, fd,
+ get_seq(pack), get_tid(pack));
}
/* Handle Error Indication */
int gtp_error_ind_conf(struct gsn_t *gsn, int version,
- struct sockaddr_in *peer,
- void *pack, unsigned len) {
- struct pdp_t *pdp;
-
- /* Find the context in question */
- if (pdp_tidget(&pdp, ((union gtp_packet*)pack)->gtp0.h.tid)) {
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- return EOF;
- }
-
- gsn->err_unknownpdp++; /* TODO: Change counter */
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Received Error Indication");
-
- if (gsn->cb_delete_context) gsn->cb_delete_context(pdp);
- pdp_freepdp(pdp);
- return 0;
+ struct sockaddr_in *peer, void *pack, unsigned len)
+{
+ struct pdp_t *pdp;
+
+ /* Find the context in question */
+ if (pdp_tidget(&pdp, ((union gtp_packet *)pack)->gtp0.h.tid)) {
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Unknown PDP context");
+ return EOF;
+ }
+
+ gsn->err_unknownpdp++; /* TODO: Change counter */
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Received Error Indication");
+
+ if (gsn->cb_delete_context)
+ gsn->cb_delete_context(pdp);
+ pdp_freepdp(pdp);
+ return 0;
}
int gtp_gpdu_ind(struct gsn_t *gsn, int version,
- struct sockaddr_in *peer, int fd,
- void *pack, unsigned len) {
-
- int hlen = GTP1_HEADER_SIZE_SHORT;
-
- /* Need to include code to verify packet src and dest addresses */
- struct pdp_t *pdp;
-
- if (version == 0) {
- if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) {
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
- }
- hlen = GTP0_HEADER_SIZE;
- }
- else if (version == 1) {
- if (pdp_getgtp1(&pdp, ntoh32(((union gtp_packet*)pack)->gtp1l.h.tei))) {
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
- }
-
- /* Is this a long or a short header ? */
- if (((union gtp_packet*)pack)->gtp1l.h.flags & 0x07)
- hlen = GTP1_HEADER_SIZE_LONG;
- else
- hlen = GTP1_HEADER_SIZE_SHORT;
- }
- else {
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown version");
- }
-
- /* If the GPDU was not from the peer GSN tell him to delete context */
- if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
- gsn->err_unknownpdp++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
- "Unknown PDP context");
- return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
- }
-
- /* Callback function */
- if (gsn->cb_data_ind !=0)
- return gsn->cb_data_ind(pdp, pack+hlen, len-hlen);
-
- return 0;
-}
+ struct sockaddr_in *peer, int fd, void *pack, unsigned len)
+{
+ int hlen = GTP1_HEADER_SIZE_SHORT;
+
+ /* Need to include code to verify packet src and dest addresses */
+ struct pdp_t *pdp;
+
+ if (version == 0) {
+ if (pdp_getgtp0
+ (&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) {
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Unknown PDP context");
+ return gtp_error_ind_resp(gsn, version, peer, fd, pack,
+ len);
+ }
+ hlen = GTP0_HEADER_SIZE;
+ } else if (version == 1) {
+ if (pdp_getgtp1
+ (&pdp, ntoh32(((union gtp_packet *)pack)->gtp1l.h.tei))) {
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack,
+ len, "Unknown PDP context");
+ return gtp_error_ind_resp(gsn, version, peer, fd, pack,
+ len);
+ }
+
+ /* Is this a long or a short header ? */
+ if (((union gtp_packet *)pack)->gtp1l.h.flags & 0x07)
+ hlen = GTP1_HEADER_SIZE_LONG;
+ else
+ hlen = GTP1_HEADER_SIZE_SHORT;
+ } else {
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Unknown version");
+ }
+
+ /* If the GPDU was not from the peer GSN tell him to delete context */
+ if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
+ gsn->err_unknownpdp++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+ "Unknown PDP context");
+ return gtp_error_ind_resp(gsn, version, peer, fd, pack, len);
+ }
+ /* Callback function */
+ if (gsn->cb_data_ind != 0)
+ return gsn->cb_data_ind(pdp, pack + hlen, len - hlen);
+
+ return 0;
+}
/* Receives GTP packet and sends off for further processing
* Function will check the validity of the header. If the header
@@ -2576,505 +2716,548 @@ int gtp_gpdu_ind(struct gsn_t *gsn, int version,
* TODO: Need to decide on return values! */
int gtp_decaps0(struct gsn_t *gsn)
{
- unsigned char buffer[PACKET_MAX];
- struct sockaddr_in peer;
- size_t peerlen;
- int status;
- struct gtp0_header *pheader;
- int version = 0; /* GTP version should be determined from header!*/
- int fd = gsn->fd0;
-
- /* TODO: Need strategy of userspace buffering and blocking */
- /* Currently read is non-blocking and send is blocking. */
- /* This means that the program have to wait for busy send calls...*/
-
- while (1) { /* Loop until no more to read */
- if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
- return -1;
- }
- peerlen = sizeof(peer);
- if ((status =
- recvfrom(gsn->fd0, buffer, sizeof(buffer), 0,
- (struct sockaddr *) &peer, &peerlen)) < 0 ) {
- if (errno == EAGAIN) return 0;
- gsn->err_readfrom++;
- 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");
- return -1;
- }
-
- /* Need at least 1 byte in order to check version */
- if (status < (1)) {
- gsn->empty++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Discarding packet - too small");
- continue;
- }
-
- pheader = (struct gtp0_header *) (buffer);
-
- /* Version should be gtp0 (or earlier) */
- /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
- /* GTP 0 messages. If other version message is received we reply that we */
- /* only support version 0, implying that this is the only version */
- /* supported on this port */
- if (((pheader->flags & 0xe0) > 0x00)) {
- gsn->unsup++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unsupported GTP version");
- gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */
- continue;
- }
-
- /* Check length of gtp0 packet */
- if (status < GTP0_HEADER_SIZE) {
- gsn->tooshort++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "GTP0 packet too short");
- continue; /* Silently discard 29.60: 11.1.2 */
- }
-
- /* Check packet length field versus length of packet */
- if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
- gsn->tooshort++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "GTP packet length field does not match actual length");
- continue; /* Silently discard */
- }
-
- if ((gsn->mode == GTP_MODE_GGSN) &&
- ((pheader->type == GTP_CREATE_PDP_RSP) ||
- (pheader->type == GTP_UPDATE_PDP_RSP) ||
- (pheader->type == GTP_DELETE_PDP_RSP))) {
- gsn->unexpect++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unexpected GTP Signalling Message");
- continue; /* Silently discard 29.60: 11.1.4 */
- }
-
- if ((gsn->mode == GTP_MODE_SGSN) &&
- ((pheader->type == GTP_CREATE_PDP_REQ) ||
- (pheader->type == GTP_UPDATE_PDP_REQ) ||
- (pheader->type == GTP_DELETE_PDP_REQ))) {
- gsn->unexpect++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unexpected GTP Signalling Message");
- continue; /* Silently discard 29.60: 11.1.4 */
- }
-
- switch (pheader->type) {
- case GTP_ECHO_REQ:
- gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
- break;
- case GTP_ECHO_RSP:
- gtp_echo_conf(gsn, version, &peer, buffer, status);
- break;
- case GTP_NOT_SUPPORTED:
- gtp_unsup_ind(gsn, &peer, buffer, status);
- break;
- case GTP_CREATE_PDP_REQ:
- gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status);
- break;
- case GTP_CREATE_PDP_RSP:
- gtp_create_pdp_conf(gsn, version, &peer, buffer, status);
- break;
- case GTP_UPDATE_PDP_REQ:
- gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status);
- break;
- case GTP_UPDATE_PDP_RSP:
- gtp_update_pdp_conf(gsn, version, &peer, buffer, status);
- break;
- case GTP_DELETE_PDP_REQ:
- gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status);
- break;
- case GTP_DELETE_PDP_RSP:
- gtp_delete_pdp_conf(gsn, version, &peer, buffer, status);
- break;
- case GTP_ERROR:
- gtp_error_ind_conf(gsn, version, &peer, buffer, status);
- break;
- case GTP_GPDU:
- gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
- break;
- default:
- gsn->unknown++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unknown GTP message type received");
- break;
- }
- }
+ unsigned char buffer[PACKET_MAX];
+ struct sockaddr_in peer;
+ size_t peerlen;
+ int status;
+ struct gtp0_header *pheader;
+ int version = 0; /* GTP version should be determined from header! */
+ int fd = gsn->fd0;
+
+ /* TODO: Need strategy of userspace buffering and blocking */
+ /* Currently read is non-blocking and send is blocking. */
+ /* This means that the program have to wait for busy send calls... */
+
+ while (1) { /* Loop until no more to read */
+ if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
+ return -1;
+ }
+ peerlen = sizeof(peer);
+ if ((status =
+ recvfrom(gsn->fd0, buffer, sizeof(buffer), 0,
+ (struct sockaddr *)&peer, &peerlen)) < 0) {
+ if (errno == EAGAIN)
+ return 0;
+ gsn->err_readfrom++;
+ 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");
+ return -1;
+ }
+
+ /* Need at least 1 byte in order to check version */
+ if (status < (1)) {
+ gsn->empty++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Discarding packet - too small");
+ continue;
+ }
+
+ pheader = (struct gtp0_header *)(buffer);
+
+ /* Version should be gtp0 (or earlier) */
+ /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
+ /* GTP 0 messages. If other version message is received we reply that we */
+ /* only support version 0, implying that this is the only version */
+ /* supported on this port */
+ if (((pheader->flags & 0xe0) > 0x00)) {
+ gsn->unsup++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Unsupported GTP version");
+ gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */
+ continue;
+ }
+
+ /* Check length of gtp0 packet */
+ if (status < GTP0_HEADER_SIZE) {
+ gsn->tooshort++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "GTP0 packet too short");
+ continue; /* Silently discard 29.60: 11.1.2 */
+ }
+
+ /* Check packet length field versus length of packet */
+ if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
+ gsn->tooshort++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status,
+ "GTP packet length field does not match actual length");
+ continue; /* Silently discard */
+ }
+
+ if ((gsn->mode == GTP_MODE_GGSN) &&
+ ((pheader->type == GTP_CREATE_PDP_RSP) ||
+ (pheader->type == GTP_UPDATE_PDP_RSP) ||
+ (pheader->type == GTP_DELETE_PDP_RSP))) {
+ gsn->unexpect++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status,
+ "Unexpected GTP Signalling Message");
+ continue; /* Silently discard 29.60: 11.1.4 */
+ }
+
+ if ((gsn->mode == GTP_MODE_SGSN) &&
+ ((pheader->type == GTP_CREATE_PDP_REQ) ||
+ (pheader->type == GTP_UPDATE_PDP_REQ) ||
+ (pheader->type == GTP_DELETE_PDP_REQ))) {
+ gsn->unexpect++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status,
+ "Unexpected GTP Signalling Message");
+ continue; /* Silently discard 29.60: 11.1.4 */
+ }
+
+ switch (pheader->type) {
+ case GTP_ECHO_REQ:
+ gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
+ break;
+ case GTP_ECHO_RSP:
+ gtp_echo_conf(gsn, version, &peer, buffer, status);
+ break;
+ case GTP_NOT_SUPPORTED:
+ gtp_unsup_ind(gsn, &peer, buffer, status);
+ break;
+ case GTP_CREATE_PDP_REQ:
+ gtp_create_pdp_ind(gsn, version, &peer, fd, buffer,
+ status);
+ break;
+ case GTP_CREATE_PDP_RSP:
+ gtp_create_pdp_conf(gsn, version, &peer, buffer,
+ status);
+ break;
+ case GTP_UPDATE_PDP_REQ:
+ gtp_update_pdp_ind(gsn, version, &peer, fd, buffer,
+ status);
+ break;
+ case GTP_UPDATE_PDP_RSP:
+ gtp_update_pdp_conf(gsn, version, &peer, buffer,
+ status);
+ break;
+ case GTP_DELETE_PDP_REQ:
+ gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer,
+ status);
+ break;
+ case GTP_DELETE_PDP_RSP:
+ gtp_delete_pdp_conf(gsn, version, &peer, buffer,
+ status);
+ break;
+ case GTP_ERROR:
+ gtp_error_ind_conf(gsn, version, &peer, buffer, status);
+ break;
+ case GTP_GPDU:
+ gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
+ break;
+ default:
+ gsn->unknown++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status,
+ "Unknown GTP message type received");
+ break;
+ }
+ }
}
-
int gtp_decaps1c(struct gsn_t *gsn)
{
- unsigned char buffer[PACKET_MAX];
- struct sockaddr_in peer;
- size_t peerlen;
- int status;
- struct gtp1_header_short *pheader;
- int version = 1; /* TODO GTP version should be determined from header!*/
- int fd = gsn->fd1c;
-
- /* TODO: Need strategy of userspace buffering and blocking */
- /* Currently read is non-blocking and send is blocking. */
- /* This means that the program have to wait for busy send calls...*/
-
- while (1) { /* Loop until no more to read */
- if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
- return -1;
- }
- peerlen = sizeof(peer);
- if ((status =
- recvfrom(fd, buffer, sizeof(buffer), 0,
- (struct sockaddr *) &peer, &peerlen)) < 0 ) {
- if (errno == EAGAIN) return 0;
- gsn->err_readfrom++;
- 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");
- return -1;
- }
-
- /* Need at least 1 byte in order to check version */
- if (status < (1)) {
- gsn->empty++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Discarding packet - too small");
- continue;
- }
-
- pheader = (struct gtp1_header_short *) (buffer);
-
- /* Version must be no larger than GTP 1 */
- if (((pheader->flags & 0xe0) > 0x20)) {
- gsn->unsup++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unsupported GTP version");
- gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
- /*29.60: 11.1.1*/
- continue;
- }
-
- /* Version must be at least GTP 1 */
- /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
- /* GTP 1 messages. If GTP 0 message is received we silently discard */
- /* the message */
- if (((pheader->flags & 0xe0) < 0x20)) {
- gsn->unsup++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unsupported GTP version");
- continue;
- }
-
- /* Check packet flag field */
- if (((pheader->flags & 0xf7) != 0x32)) {
- gsn->unsup++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unsupported packet flag");
- continue;
- }
-
- /* Check length of packet */
- if (status < GTP1_HEADER_SIZE_LONG) {
- gsn->tooshort++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "GTP packet too short");
- continue; /* Silently discard 29.60: 11.1.2 */
- }
-
- /* Check packet length field versus length of packet */
- if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
- gsn->tooshort++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "GTP packet length field does not match actual length");
- continue; /* Silently discard */
- }
-
- /* Check for extension headers */
- /* TODO: We really should cycle through the headers and determine */
- /* if any have the comprehension required flag set */
- if (((pheader->flags & 0x04) != 0x00)) {
- gsn->unsup++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unsupported extension header");
- gtp_extheader_req(gsn, version, &peer, fd, buffer, status);
-
- continue;
- }
-
- if ((gsn->mode == GTP_MODE_GGSN) &&
- ((pheader->type == GTP_CREATE_PDP_RSP) ||
- (pheader->type == GTP_UPDATE_PDP_RSP) ||
- (pheader->type == GTP_DELETE_PDP_RSP))) {
- gsn->unexpect++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unexpected GTP Signalling Message");
- continue; /* Silently discard 29.60: 11.1.4 */
- }
-
- if ((gsn->mode == GTP_MODE_SGSN) &&
- ((pheader->type == GTP_CREATE_PDP_REQ) ||
- (pheader->type == GTP_UPDATE_PDP_REQ) ||
- (pheader->type == GTP_DELETE_PDP_REQ))) {
- gsn->unexpect++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unexpected GTP Signalling Message");
- continue; /* Silently discard 29.60: 11.1.4 */
- }
-
- switch (pheader->type) {
- case GTP_ECHO_REQ:
- gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
- break;
- case GTP_ECHO_RSP:
- gtp_echo_conf(gsn, version, &peer, buffer, status);
- break;
- case GTP_NOT_SUPPORTED:
- gtp_unsup_ind(gsn, &peer, buffer, status);
- break;
- case GTP_SUPP_EXT_HEADER:
- gtp_extheader_ind(gsn, &peer, buffer, status);
- break;
- case GTP_CREATE_PDP_REQ:
- gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status);
- break;
- case GTP_CREATE_PDP_RSP:
- gtp_create_pdp_conf(gsn, version, &peer, buffer, status);
- break;
- case GTP_UPDATE_PDP_REQ:
- gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status);
- break;
- case GTP_UPDATE_PDP_RSP:
- gtp_update_pdp_conf(gsn, version, &peer, buffer, status);
- break;
- case GTP_DELETE_PDP_REQ:
- gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status);
- break;
- case GTP_DELETE_PDP_RSP:
- gtp_delete_pdp_conf(gsn, version, &peer, buffer, status);
- break;
- case GTP_ERROR:
- gtp_error_ind_conf(gsn, version, &peer, buffer, status);
- break;
- default:
- gsn->unknown++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unknown GTP message type received");
- break;
- }
- }
+ unsigned char buffer[PACKET_MAX];
+ struct sockaddr_in peer;
+ size_t peerlen;
+ int status;
+ struct gtp1_header_short *pheader;
+ int version = 1; /* TODO GTP version should be determined from header! */
+ int fd = gsn->fd1c;
+
+ /* TODO: Need strategy of userspace buffering and blocking */
+ /* Currently read is non-blocking and send is blocking. */
+ /* This means that the program have to wait for busy send calls... */
+
+ while (1) { /* Loop until no more to read */
+ if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
+ return -1;
+ }
+ peerlen = sizeof(peer);
+ if ((status =
+ recvfrom(fd, buffer, sizeof(buffer), 0,
+ (struct sockaddr *)&peer, &peerlen)) < 0) {
+ if (errno == EAGAIN)
+ return 0;
+ gsn->err_readfrom++;
+ 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");
+ return -1;
+ }
+
+ /* Need at least 1 byte in order to check version */
+ if (status < (1)) {
+ gsn->empty++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Discarding packet - too small");
+ continue;
+ }
+
+ pheader = (struct gtp1_header_short *)(buffer);
+
+ /* Version must be no larger than GTP 1 */
+ if (((pheader->flags & 0xe0) > 0x20)) {
+ gsn->unsup++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Unsupported GTP version");
+ gtp_unsup_req(gsn, version, &peer, fd, buffer, status);
+ /*29.60: 11.1.1 */
+ continue;
+ }
+
+ /* Version must be at least GTP 1 */
+ /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
+ /* GTP 1 messages. If GTP 0 message is received we silently discard */
+ /* the message */
+ if (((pheader->flags & 0xe0) < 0x20)) {
+ gsn->unsup++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Unsupported GTP version");
+ continue;
+ }
+
+ /* Check packet flag field */
+ if (((pheader->flags & 0xf7) != 0x32)) {
+ gsn->unsup++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Unsupported packet flag");
+ continue;
+ }
+
+ /* Check length of packet */
+ if (status < GTP1_HEADER_SIZE_LONG) {
+ gsn->tooshort++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "GTP packet too short");
+ continue; /* Silently discard 29.60: 11.1.2 */
+ }
+
+ /* Check packet length field versus length of packet */
+ if (status !=
+ (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
+ gsn->tooshort++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status,
+ "GTP packet length field does not match actual length");
+ continue; /* Silently discard */
+ }
+
+ /* Check for extension headers */
+ /* TODO: We really should cycle through the headers and determine */
+ /* if any have the comprehension required flag set */
+ if (((pheader->flags & 0x04) != 0x00)) {
+ gsn->unsup++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Unsupported extension header");
+ gtp_extheader_req(gsn, version, &peer, fd, buffer,
+ status);
+
+ continue;
+ }
+
+ if ((gsn->mode == GTP_MODE_GGSN) &&
+ ((pheader->type == GTP_CREATE_PDP_RSP) ||
+ (pheader->type == GTP_UPDATE_PDP_RSP) ||
+ (pheader->type == GTP_DELETE_PDP_RSP))) {
+ gsn->unexpect++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status,
+ "Unexpected GTP Signalling Message");
+ continue; /* Silently discard 29.60: 11.1.4 */
+ }
+
+ if ((gsn->mode == GTP_MODE_SGSN) &&
+ ((pheader->type == GTP_CREATE_PDP_REQ) ||
+ (pheader->type == GTP_UPDATE_PDP_REQ) ||
+ (pheader->type == GTP_DELETE_PDP_REQ))) {
+ gsn->unexpect++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status,
+ "Unexpected GTP Signalling Message");
+ continue; /* Silently discard 29.60: 11.1.4 */
+ }
+
+ switch (pheader->type) {
+ case GTP_ECHO_REQ:
+ gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
+ break;
+ case GTP_ECHO_RSP:
+ gtp_echo_conf(gsn, version, &peer, buffer, status);
+ break;
+ case GTP_NOT_SUPPORTED:
+ gtp_unsup_ind(gsn, &peer, buffer, status);
+ break;
+ case GTP_SUPP_EXT_HEADER:
+ gtp_extheader_ind(gsn, &peer, buffer, status);
+ break;
+ case GTP_CREATE_PDP_REQ:
+ gtp_create_pdp_ind(gsn, version, &peer, fd, buffer,
+ status);
+ break;
+ case GTP_CREATE_PDP_RSP:
+ gtp_create_pdp_conf(gsn, version, &peer, buffer,
+ status);
+ break;
+ case GTP_UPDATE_PDP_REQ:
+ gtp_update_pdp_ind(gsn, version, &peer, fd, buffer,
+ status);
+ break;
+ case GTP_UPDATE_PDP_RSP:
+ gtp_update_pdp_conf(gsn, version, &peer, buffer,
+ status);
+ break;
+ case GTP_DELETE_PDP_REQ:
+ gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer,
+ status);
+ break;
+ case GTP_DELETE_PDP_RSP:
+ gtp_delete_pdp_conf(gsn, version, &peer, buffer,
+ status);
+ break;
+ case GTP_ERROR:
+ gtp_error_ind_conf(gsn, version, &peer, buffer, status);
+ break;
+ default:
+ gsn->unknown++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status,
+ "Unknown GTP message type received");
+ break;
+ }
+ }
}
int gtp_decaps1u(struct gsn_t *gsn)
{
- unsigned char buffer[PACKET_MAX];
- struct sockaddr_in peer;
- size_t peerlen;
- int status;
- struct gtp1_header_short *pheader;
- int version = 1; /* GTP version should be determined from header!*/
- int fd = gsn->fd1u;
-
- /* TODO: Need strategy of userspace buffering and blocking */
- /* Currently read is non-blocking and send is blocking. */
- /* This means that the program have to wait for busy send calls...*/
-
- while (1) { /* Loop until no more to read */
- if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
- return -1;
- }
- peerlen = sizeof(peer);
- if ((status =
- recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0,
- (struct sockaddr *) &peer, &peerlen)) < 0 ) {
- if (errno == EAGAIN) return 0;
- gsn->err_readfrom++;
- 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");
- return -1;
- }
-
- /* Need at least 1 byte in order to check version */
- if (status < (1)) {
- gsn->empty++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Discarding packet - too small");
- continue;
- }
-
- pheader = (struct gtp1_header_short *) (buffer);
-
- /* Version must be no larger than GTP 1 */
- if (((pheader->flags & 0xe0) > 0x20)) {
- gsn->unsup++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unsupported GTP version");
- gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status);/*29.60: 11.1.1*/
- continue;
- }
-
- /* Version must be at least GTP 1 */
- /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
- /* GTP 1 messages. If GTP 0 message is received we silently discard */
- /* the message */
- if (((pheader->flags & 0xe0) < 0x20)) {
- gsn->unsup++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unsupported GTP version");
- continue;
- }
-
- /* Check packet flag field (allow both with and without sequence number)*/
- if (((pheader->flags & 0xf5) != 0x30)) {
- gsn->unsup++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unsupported packet flag");
- continue;
- }
-
- /* Check length of packet */
- if (status < GTP1_HEADER_SIZE_SHORT) {
- gsn->tooshort++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "GTP packet too short");
- continue; /* Silently discard 29.60: 11.1.2 */
- }
-
- /* Check packet length field versus length of packet */
- if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
- gsn->tooshort++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "GTP packet length field does not match actual length");
- continue; /* Silently discard */
- }
-
- /* Check for extension headers */
- /* TODO: We really should cycle through the headers and determine */
- /* if any have the comprehension required flag set */
- if (((pheader->flags & 0x04) != 0x00)) {
- gsn->unsup++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unsupported extension header");
- gtp_extheader_req(gsn, version, &peer, fd, buffer, status);
-
- continue;
- }
-
- switch (pheader->type) {
- case GTP_ECHO_REQ:
- gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
- break;
- case GTP_ECHO_RSP:
- gtp_echo_conf(gsn, version, &peer, buffer, status);
- break;
- case GTP_SUPP_EXT_HEADER:
- gtp_extheader_ind(gsn, &peer, buffer, status);
- break;
- case GTP_ERROR:
- gtp_error_ind_conf(gsn, version, &peer, buffer, status);
- break;
- /* Supported header extensions */
- case GTP_GPDU:
- gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
- break;
- default:
- gsn->unknown++;
- gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
- "Unknown GTP message type received");
- break;
- }
- }
+ unsigned char buffer[PACKET_MAX];
+ struct sockaddr_in peer;
+ size_t peerlen;
+ int status;
+ struct gtp1_header_short *pheader;
+ int version = 1; /* GTP version should be determined from header! */
+ int fd = gsn->fd1u;
+
+ /* TODO: Need strategy of userspace buffering and blocking */
+ /* Currently read is non-blocking and send is blocking. */
+ /* This means that the program have to wait for busy send calls... */
+
+ while (1) { /* Loop until no more to read */
+ if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
+ return -1;
+ }
+ peerlen = sizeof(peer);
+ if ((status =
+ recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0,
+ (struct sockaddr *)&peer, &peerlen)) < 0) {
+ if (errno == EAGAIN)
+ return 0;
+ gsn->err_readfrom++;
+ 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");
+ return -1;
+ }
+
+ /* Need at least 1 byte in order to check version */
+ if (status < (1)) {
+ gsn->empty++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Discarding packet - too small");
+ continue;
+ }
+
+ pheader = (struct gtp1_header_short *)(buffer);
+
+ /* Version must be no larger than GTP 1 */
+ if (((pheader->flags & 0xe0) > 0x20)) {
+ gsn->unsup++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Unsupported GTP version");
+ gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status); /*29.60: 11.1.1 */
+ continue;
+ }
+
+ /* Version must be at least GTP 1 */
+ /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */
+ /* GTP 1 messages. If GTP 0 message is received we silently discard */
+ /* the message */
+ if (((pheader->flags & 0xe0) < 0x20)) {
+ gsn->unsup++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Unsupported GTP version");
+ continue;
+ }
+
+ /* Check packet flag field (allow both with and without sequence number) */
+ if (((pheader->flags & 0xf5) != 0x30)) {
+ gsn->unsup++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Unsupported packet flag");
+ continue;
+ }
+
+ /* Check length of packet */
+ if (status < GTP1_HEADER_SIZE_SHORT) {
+ gsn->tooshort++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "GTP packet too short");
+ continue; /* Silently discard 29.60: 11.1.2 */
+ }
+
+ /* Check packet length field versus length of packet */
+ if (status !=
+ (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
+ gsn->tooshort++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status,
+ "GTP packet length field does not match actual length");
+ continue; /* Silently discard */
+ }
+
+ /* Check for extension headers */
+ /* TODO: We really should cycle through the headers and determine */
+ /* if any have the comprehension required flag set */
+ if (((pheader->flags & 0x04) != 0x00)) {
+ gsn->unsup++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status, "Unsupported extension header");
+ gtp_extheader_req(gsn, version, &peer, fd, buffer,
+ status);
+
+ continue;
+ }
+
+ switch (pheader->type) {
+ case GTP_ECHO_REQ:
+ gtp_echo_ind(gsn, version, &peer, fd, buffer, status);
+ break;
+ case GTP_ECHO_RSP:
+ gtp_echo_conf(gsn, version, &peer, buffer, status);
+ break;
+ case GTP_SUPP_EXT_HEADER:
+ gtp_extheader_ind(gsn, &peer, buffer, status);
+ break;
+ case GTP_ERROR:
+ gtp_error_ind_conf(gsn, version, &peer, buffer, status);
+ break;
+ /* Supported header extensions */
+ case GTP_GPDU:
+ gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status);
+ break;
+ default:
+ gsn->unknown++;
+ gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer,
+ status,
+ "Unknown GTP message type received");
+ break;
+ }
+ }
}
-int gtp_data_req(struct gsn_t *gsn, struct pdp_t* pdp,
- void *pack, unsigned len)
+int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len)
{
- union gtp_packet packet;
- struct sockaddr_in addr;
- int fd;
- int length;
+ union gtp_packet packet;
+ struct sockaddr_in addr;
+ int fd;
+ int length;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
#if defined(__FreeBSD__) || defined(__APPLE__)
- addr.sin_len = sizeof(addr);
+ addr.sin_len = sizeof(addr);
#endif
- memcpy(&addr.sin_addr, pdp->gsnru.v,pdp->gsnru.l); /* TODO range check */
-
- if (pdp->version == 0) {
-
- length = GTP0_HEADER_SIZE+len;
- addr.sin_port = htons(GTP0_PORT);
- fd = gsn->fd0;
-
- get_default_gtp(0, GTP_GPDU, &packet);
- packet.gtp0.h.length = hton16(len);
- packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
- packet.gtp0.h.flow = hton16(pdp->flru);
- packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffffull) + ((uint64_t)pdp->nsapi << 60);
-
- if (len > sizeof (union gtp_packet) - sizeof(struct gtp0_header)) {
- gsn->err_memcpy++;
- gtp_err(LOG_ERR, __FILE__, __LINE__,
- "Memcpy failed: %d > %d", len,
- sizeof (union gtp_packet) - sizeof(struct gtp0_header));
- return EOF;
- }
- memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */
- }
- else if (pdp->version == 1) {
-
- length = GTP1_HEADER_SIZE_LONG+len;
- addr.sin_port = htons(GTP1U_PORT);
- fd = gsn->fd1u;
-
- get_default_gtp(1, GTP_GPDU, &packet);
- packet.gtp1l.h.length = hton16(len-GTP1_HEADER_SIZE_SHORT+
- GTP1_HEADER_SIZE_LONG);
- packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
- packet.gtp1l.h.tei = hton32(pdp->teid_gn);
-
- if (len > sizeof (union gtp_packet) - sizeof(struct gtp1_header_long)) {
- gsn->err_memcpy++;
- gtp_err(LOG_ERR, __FILE__, __LINE__,
- "Memcpy failed: %d > %d", len,
- sizeof (union gtp_packet) - sizeof(struct gtp0_header));
- return EOF;
- }
- memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */
- }
- else {
- gtp_err(LOG_ERR, __FILE__, __LINE__,
- "Unknown version");
- return EOF;
- }
-
- if (fcntl(fd, F_SETFL, 0)) {
- gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
- return -1;
- }
-
- if (sendto(fd, &packet, length, 0,
- (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- gsn->err_sendto++;
- 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));
- return EOF;
- }
- return 0;
-}
+ memcpy(&addr.sin_addr, pdp->gsnru.v, pdp->gsnru.l); /* TODO range check */
+
+ if (pdp->version == 0) {
+
+ length = GTP0_HEADER_SIZE + len;
+ addr.sin_port = htons(GTP0_PORT);
+ fd = gsn->fd0;
+
+ get_default_gtp(0, GTP_GPDU, &packet);
+ packet.gtp0.h.length = hton16(len);
+ packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
+ packet.gtp0.h.flow = hton16(pdp->flru);
+ packet.gtp0.h.tid =
+ (pdp->imsi & 0x0fffffffffffffffull) +
+ ((uint64_t) pdp->nsapi << 60);
+
+ if (len > sizeof(union gtp_packet) - sizeof(struct gtp0_header)) {
+ gsn->err_memcpy++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Memcpy failed: %d > %d", len,
+ sizeof(union gtp_packet) -
+ sizeof(struct gtp0_header));
+ return EOF;
+ }
+ memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */
+ } else if (pdp->version == 1) {
+
+ length = GTP1_HEADER_SIZE_LONG + len;
+ addr.sin_port = htons(GTP1U_PORT);
+ fd = gsn->fd1u;
+
+ get_default_gtp(1, GTP_GPDU, &packet);
+ packet.gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT +
+ GTP1_HEADER_SIZE_LONG);
+ packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
+ packet.gtp1l.h.tei = hton32(pdp->teid_gn);
+
+ if (len >
+ sizeof(union gtp_packet) -
+ sizeof(struct gtp1_header_long)) {
+ gsn->err_memcpy++;
+ gtp_err(LOG_ERR, __FILE__, __LINE__,
+ "Memcpy failed: %d > %d", len,
+ sizeof(union gtp_packet) -
+ sizeof(struct gtp0_header));
+ return EOF;
+ }
+ memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */
+ } else {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version");
+ return EOF;
+ }
+ if (fcntl(fd, F_SETFL, 0)) {
+ gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()");
+ return -1;
+ }
+
+ if (sendto(fd, &packet, length, 0,
+ (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ gsn->err_sendto++;
+ 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));
+ return EOF;
+ }
+ return 0;
+}
/* ***********************************************************
* Conversion functions
*************************************************************/
-int char2ul_t(char* src, struct ul_t dst) {
- dst.l = strlen(src)+1;
- dst.v = malloc(dst.l);
- dst.v[0] = dst.l - 1;
- memcpy(&dst.v[1], src, dst.v[0]);
- return 0;
+int char2ul_t(char *src, struct ul_t dst)
+{
+ dst.l = strlen(src) + 1;
+ dst.v = malloc(dst.l);
+ dst.v[0] = dst.l - 1;
+ memcpy(&dst.v[1], src, dst.v[0]);
+ return 0;
}
/* ***********************************************************
@@ -3090,40 +3273,40 @@ int char2ul_t(char* src, struct ul_t dst) {
* port number.
*************************************************************/
-int ipv42eua(struct ul66_t *eua, struct in_addr *src) {
- eua->v[0] = 0xf1; /* IETF */
- eua->v[1] = 0x21; /* IPv4 */
- if (src) {
- eua->l = 6;
- memcpy(&eua->v[2], src, 4);
- }
- else
- {
- eua->l = 2;
- }
- return 0;
+int ipv42eua(struct ul66_t *eua, struct in_addr *src)
+{
+ eua->v[0] = 0xf1; /* IETF */
+ eua->v[1] = 0x21; /* IPv4 */
+ if (src) {
+ eua->l = 6;
+ memcpy(&eua->v[2], src, 4);
+ } else {
+ eua->l = 2;
+ }
+ return 0;
}
-int eua2ipv4(struct in_addr *dst, struct ul66_t *eua) {
- if ((eua->l != 6) ||
- (eua->v[0] != 0xf1) ||
- (eua->v[1] = 0x21))
- return -1; /* Not IPv4 address*/
- memcpy(dst, &eua->v[2], 4);
- return 0;
+int eua2ipv4(struct in_addr *dst, struct ul66_t *eua)
+{
+ if ((eua->l != 6) || (eua->v[0] != 0xf1) || (eua->v[1] = 0x21))
+ return -1; /* Not IPv4 address */
+ memcpy(dst, &eua->v[2], 4);
+ return 0;
}
-int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna) {
- memset(dst, 0, sizeof(struct in_addr));
- if (gsna->l != 4) return EOF; /* Return if not IPv4 */
- memcpy(dst, gsna->v, gsna->l);
- return 0;
+int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna)
+{
+ memset(dst, 0, sizeof(struct in_addr));
+ if (gsna->l != 4)
+ return EOF; /* Return if not IPv4 */
+ memcpy(dst, gsna->v, gsna->l);
+ return 0;
}
-int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src) {
- memset(gsna, 0, sizeof(struct ul16_t));
- gsna->l = 4;
- memcpy(gsna->v, src, gsna->l);
- return 0;
+int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src)
+{
+ memset(gsna, 0, sizeof(struct ul16_t));
+ gsna->l = 4;
+ memcpy(gsna->v, src, gsna->l);
+ return 0;
}
-