From bed35df298f4914fabedfc7c9387af3f2f9a9e9f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 2 Nov 2011 13:06:18 +0100 Subject: 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. --- gtp/gtp.c | 5425 +++++++++++++++++++++++++++++---------------------------- gtp/gtp.h | 457 +++-- gtp/gtpie.c | 1029 ++++++----- gtp/gtpie.h | 289 ++- gtp/lookupa.c | 256 +-- gtp/lookupa.h | 8 +- gtp/pdp.c | 309 ++-- gtp/pdp.h | 274 ++- gtp/queue.c | 402 +++-- gtp/queue.h | 55 +- 10 files changed, 4431 insertions(+), 4073 deletions(-) (limited to 'gtp') 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; nsin_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; isin_addr), - ntohs(peer->sin_port), - len); - buf[size-1] = 0; - pos = strlen(buf); - for(n=0; nsin_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; } - diff --git a/gtp/gtp.h b/gtp/gtp.h index fb4cc3d..7417f08 100644 --- a/gtp/gtp.h +++ b/gtp/gtp.h @@ -12,7 +12,7 @@ #ifndef _GTP_H #define _GTP_H -#define GTP_DEBUG 0 /* Print debug information */ +#define GTP_DEBUG 0 /* Print debug information */ #define GTP_MODE_GGSN 1 #define GTP_MODE_SGSN 2 @@ -22,7 +22,7 @@ #define GTP1U_PORT 2152 #define PACKET_MAX 8196 -#define GTP_MAX 0xffff /* TODO: Choose right number */ +#define GTP_MAX 0xffff /* TODO: Choose right number */ #define GTP0_HEADER_SIZE 20 #define GTP1_HEADER_SIZE_SHORT 8 #define GTP1_HEADER_SIZE_LONG 12 @@ -34,107 +34,104 @@ #define NAMESIZE 1024 /* GTP version 1 extension header type definitions. */ -#define GTP_EXT_PDCP_PDU 0xC0 /* PDCP PDU Number */ +#define GTP_EXT_PDCP_PDU 0xC0 /* PDCP PDU Number */ /* GTP version 1 message type definitions. Also covers version 0 except * * for anonymous PDP context which was superceded in version 1 */ /* 0 For future use. */ -#define GTP_ECHO_REQ 1 /* Echo Request */ -#define GTP_ECHO_RSP 2 /* Echo Response */ -#define GTP_NOT_SUPPORTED 3 /* Version Not Supported */ -#define GTP_ALIVE_REQ 4 /* Node Alive Request */ -#define GTP_ALIVE_RSP 5 /* Node Alive Response */ -#define GTP_REDIR_REQ 6 /* Redirection Request */ -#define GTP_REDIR_RSP 7 /* Redirection Response */ +#define GTP_ECHO_REQ 1 /* Echo Request */ +#define GTP_ECHO_RSP 2 /* Echo Response */ +#define GTP_NOT_SUPPORTED 3 /* Version Not Supported */ +#define GTP_ALIVE_REQ 4 /* Node Alive Request */ +#define GTP_ALIVE_RSP 5 /* Node Alive Response */ +#define GTP_REDIR_REQ 6 /* Redirection Request */ +#define GTP_REDIR_RSP 7 /* Redirection Response */ /* 8-15 For future use. */ -#define GTP_CREATE_PDP_REQ 16 /* Create PDP Context Request */ -#define GTP_CREATE_PDP_RSP 17 /* Create PDP Context Response */ -#define GTP_UPDATE_PDP_REQ 18 /* Update PDP Context Request */ -#define GTP_UPDATE_PDP_RSP 19 /* Update PDP Context Response */ -#define GTP_DELETE_PDP_REQ 20 /* Delete PDP Context Request */ -#define GTP_DELETE_PDP_RSP 21 /* Delete PDP Context Response */ -/* 22-25 For future use. */ /* In version GTP 1 anonomous PDP context */ -#define GTP_ERROR 26 /* Error Indication */ -#define GTP_PDU_NOT_REQ 27 /* PDU Notification Request */ -#define GTP_PDU_NOT_RSP 28 /* PDU Notification Response */ -#define GTP_PDU_NOT_REJ_REQ 29 /* PDU Notification Reject Request */ -#define GTP_PDU_NOT_REJ_RSP 30 /* PDU Notification Reject Response */ -#define GTP_SUPP_EXT_HEADER 31 /* Supported Extension Headers Notification */ -#define GTP_SND_ROUTE_REQ 32 /* Send Routeing Information for GPRS Request */ -#define GTP_SND_ROUTE_RSP 33 /* Send Routeing Information for GPRS Response */ -#define GTP_FAILURE_REQ 34 /* Failure Report Request */ -#define GTP_FAILURE_RSP 35 /* Failure Report Response */ -#define GTP_MS_PRESENT_REQ 36 /* Note MS GPRS Present Request */ -#define GTP_MS_PRESENT_RSP 37 /* Note MS GPRS Present Response */ -/* 38-47 For future use. */ -#define GTP_IDEN_REQ 48 /* Identification Request */ -#define GTP_IDEN_RSP 49 /* Identification Response */ -#define GTP_SGSN_CONTEXT_REQ 50 /* SGSN Context Request */ -#define GTP_SGSN_CONTEXT_RSP 51 /* SGSN Context Response */ -#define GTP_SGSN_CONTEXT_ACK 52 /* SGSN Context Acknowledge */ -#define GTP_FWD_RELOC_REQ 53 /* Forward Relocation Request */ -#define GTP_FWD_RELOC_RSP 54 /* Forward Relocation Response */ -#define GTP_FWD_RELOC_COMPL 55 /* Forward Relocation Complete */ -#define GTP_RELOC_CANCEL_REQ 56 /* Relocation Cancel Request */ -#define GTP_RELOC_CANCEL_RSP 57 /* Relocation Cancel Response */ -#define GTP_FWD_SRNS 58 /* Forward SRNS Context */ -#define GTP_FWD_RELOC_ACK 59 /* Forward Relocation Complete Acknowledge */ -#define GTP_FWD_SRNS_ACK 60 /* Forward SRNS Context Acknowledge */ +#define GTP_CREATE_PDP_REQ 16 /* Create PDP Context Request */ +#define GTP_CREATE_PDP_RSP 17 /* Create PDP Context Response */ +#define GTP_UPDATE_PDP_REQ 18 /* Update PDP Context Request */ +#define GTP_UPDATE_PDP_RSP 19 /* Update PDP Context Response */ +#define GTP_DELETE_PDP_REQ 20 /* Delete PDP Context Request */ +#define GTP_DELETE_PDP_RSP 21 /* Delete PDP Context Response */ + /* 22-25 For future use. *//* In version GTP 1 anonomous PDP context */ +#define GTP_ERROR 26 /* Error Indication */ +#define GTP_PDU_NOT_REQ 27 /* PDU Notification Request */ +#define GTP_PDU_NOT_RSP 28 /* PDU Notification Response */ +#define GTP_PDU_NOT_REJ_REQ 29 /* PDU Notification Reject Request */ +#define GTP_PDU_NOT_REJ_RSP 30 /* PDU Notification Reject Response */ +#define GTP_SUPP_EXT_HEADER 31 /* Supported Extension Headers Notification */ +#define GTP_SND_ROUTE_REQ 32 /* Send Routeing Information for GPRS Request */ +#define GTP_SND_ROUTE_RSP 33 /* Send Routeing Information for GPRS Response */ +#define GTP_FAILURE_REQ 34 /* Failure Report Request */ +#define GTP_FAILURE_RSP 35 /* Failure Report Response */ +#define GTP_MS_PRESENT_REQ 36 /* Note MS GPRS Present Request */ +#define GTP_MS_PRESENT_RSP 37 /* Note MS GPRS Present Response */ +/* 38-47 For future use. */ +#define GTP_IDEN_REQ 48 /* Identification Request */ +#define GTP_IDEN_RSP 49 /* Identification Response */ +#define GTP_SGSN_CONTEXT_REQ 50 /* SGSN Context Request */ +#define GTP_SGSN_CONTEXT_RSP 51 /* SGSN Context Response */ +#define GTP_SGSN_CONTEXT_ACK 52 /* SGSN Context Acknowledge */ +#define GTP_FWD_RELOC_REQ 53 /* Forward Relocation Request */ +#define GTP_FWD_RELOC_RSP 54 /* Forward Relocation Response */ +#define GTP_FWD_RELOC_COMPL 55 /* Forward Relocation Complete */ +#define GTP_RELOC_CANCEL_REQ 56 /* Relocation Cancel Request */ +#define GTP_RELOC_CANCEL_RSP 57 /* Relocation Cancel Response */ +#define GTP_FWD_SRNS 58 /* Forward SRNS Context */ +#define GTP_FWD_RELOC_ACK 59 /* Forward Relocation Complete Acknowledge */ +#define GTP_FWD_SRNS_ACK 60 /* Forward SRNS Context Acknowledge */ /* 61-239 For future use. */ -#define GTP_DATA_TRAN_REQ 240 /* Data Record Transfer Request */ -#define GTP_DATA_TRAN_RSP 241 /* Data Record Transfer Response */ +#define GTP_DATA_TRAN_REQ 240 /* Data Record Transfer Request */ +#define GTP_DATA_TRAN_RSP 241 /* Data Record Transfer Response */ /* 242-254 For future use. */ -#define GTP_GPDU 255 /* G-PDU */ - +#define GTP_GPDU 255 /* G-PDU */ /* GTP information element cause codes from 29.060 v3.9.0 7.7 */ /* */ -#define GTPCAUSE_REQ_IMSI 0 /* Request IMSI */ -#define GTPCAUSE_REQ_IMEI 1 /* Request IMEI */ -#define GTPCAUSE_REQ_IMSI_IMEI 2 /* Request IMSI and IMEI */ -#define GTPCAUSE_NO_ID_NEEDED 3 /* No identity needed */ -#define GTPCAUSE_MS_REFUSES_X 4 /* MS refuses */ -#define GTPCAUSE_MS_NOT_RESP_X 5 /* MS is not GPRS responding */ -#define GTPCAUSE_006 6 /* For future use 6-48 */ -#define GTPCAUSE_049 49 /* Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) 49-63 */ -#define GTPCAUSE_064 64 /* For future use 64-127 */ -#define GTPCAUSE_ACC_REQ 128 /* Request accepted */ -#define GTPCAUSE_129 129 /* For future use 129-176 */ -#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */ -#define GTPCAUSE_NON_EXIST 192 /* Non-existent */ -#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */ -#define GTPCAUSE_IMSI_NOT_KNOWN 194 /* IMSI not known */ -#define GTPCAUSE_MS_DETACHED 195 /* MS is GPRS detached */ -#define GTPCAUSE_MS_NOT_RESP 196 /* MS is not GPRS responding */ -#define GTPCAUSE_MS_REFUSES 197 /* MS refuses */ -#define GTPCAUSE_198 198 /* For future use */ -#define GTPCAUSE_NO_RESOURCES 199 /* No resources available */ -#define GTPCAUSE_NOT_SUPPORTED 200 /* Service not supported */ -#define GTPCAUSE_MAN_IE_INCORRECT 201 /* Mandatory IE incorrect */ -#define GTPCAUSE_MAN_IE_MISSING 202 /* Mandatory IE missing */ -#define GTPCAUSE_OPT_IE_INCORRECT 203 /* Optional IE incorrect */ -#define GTPCAUSE_SYS_FAIL 204 /* System failure */ -#define GTPCAUSE_ROAMING_REST 205 /* Roaming Restriction */ -#define GTPCAUSE_PTIMSI_MISMATCH 206 /* P-TMSI signature mismatch */ -#define GTPCAUSE_CONN_SUSP 207 /* GPRS connection suspended */ -#define GTPCAUSE_AUTH_FAIL 208 /* Authentication failure */ -#define GTPCAUSE_USER_AUTH_FAIL 209 /* User authentication failed */ -#define GTPCAUSE_CONTEXT_NOT_FOUND 210 /* Context not found */ -#define GTPCAUSE_ADDR_OCCUPIED 211 /* All dynamic PDP addresses are occupied */ -#define GTPCAUSE_NO_MEMORY 212 /* No memory is available */ -#define GTPCAUSE_RELOC_FAIL 213 /* Relocation failure */ -#define GTPCAUSE_UNKNOWN_MAN_EXTHEADER 214 /* Unknown mandatory extension header */ -#define GTPCAUSE_SEM_ERR_TFT 215 /* Semantic error in the TFT operation */ -#define GTPCAUSE_SYN_ERR_TFT 216 /* Syntactic error in the TFT operation */ -#define GTPCAUSE_SEM_ERR_FILTER 217 /* Semantic errors in packet filter(s) */ -#define GTPCAUSE_SYN_ERR_FILTER 218 /* Syntactic errors in packet filter(s) */ -#define GTPCAUSE_MISSING_APN 219 /* Missing or unknown APN*/ -#define GTPCAUSE_UNKNOWN_PDP 220 /* Unknown PDP address or PDP type */ -#define GTPCAUSE_221 221 /* For Future Use 221-240 */ -#define GTPCAUSE_241 241 /* Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) 241-255 */ - - +#define GTPCAUSE_REQ_IMSI 0 /* Request IMSI */ +#define GTPCAUSE_REQ_IMEI 1 /* Request IMEI */ +#define GTPCAUSE_REQ_IMSI_IMEI 2 /* Request IMSI and IMEI */ +#define GTPCAUSE_NO_ID_NEEDED 3 /* No identity needed */ +#define GTPCAUSE_MS_REFUSES_X 4 /* MS refuses */ +#define GTPCAUSE_MS_NOT_RESP_X 5 /* MS is not GPRS responding */ +#define GTPCAUSE_006 6 /* For future use 6-48 */ +#define GTPCAUSE_049 49 /* Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) 49-63 */ +#define GTPCAUSE_064 64 /* For future use 64-127 */ +#define GTPCAUSE_ACC_REQ 128 /* Request accepted */ +#define GTPCAUSE_129 129 /* For future use 129-176 */ +#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */ +#define GTPCAUSE_NON_EXIST 192 /* Non-existent */ +#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */ +#define GTPCAUSE_IMSI_NOT_KNOWN 194 /* IMSI not known */ +#define GTPCAUSE_MS_DETACHED 195 /* MS is GPRS detached */ +#define GTPCAUSE_MS_NOT_RESP 196 /* MS is not GPRS responding */ +#define GTPCAUSE_MS_REFUSES 197 /* MS refuses */ +#define GTPCAUSE_198 198 /* For future use */ +#define GTPCAUSE_NO_RESOURCES 199 /* No resources available */ +#define GTPCAUSE_NOT_SUPPORTED 200 /* Service not supported */ +#define GTPCAUSE_MAN_IE_INCORRECT 201 /* Mandatory IE incorrect */ +#define GTPCAUSE_MAN_IE_MISSING 202 /* Mandatory IE missing */ +#define GTPCAUSE_OPT_IE_INCORRECT 203 /* Optional IE incorrect */ +#define GTPCAUSE_SYS_FAIL 204 /* System failure */ +#define GTPCAUSE_ROAMING_REST 205 /* Roaming Restriction */ +#define GTPCAUSE_PTIMSI_MISMATCH 206 /* P-TMSI signature mismatch */ +#define GTPCAUSE_CONN_SUSP 207 /* GPRS connection suspended */ +#define GTPCAUSE_AUTH_FAIL 208 /* Authentication failure */ +#define GTPCAUSE_USER_AUTH_FAIL 209 /* User authentication failed */ +#define GTPCAUSE_CONTEXT_NOT_FOUND 210 /* Context not found */ +#define GTPCAUSE_ADDR_OCCUPIED 211 /* All dynamic PDP addresses are occupied */ +#define GTPCAUSE_NO_MEMORY 212 /* No memory is available */ +#define GTPCAUSE_RELOC_FAIL 213 /* Relocation failure */ +#define GTPCAUSE_UNKNOWN_MAN_EXTHEADER 214 /* Unknown mandatory extension header */ +#define GTPCAUSE_SEM_ERR_TFT 215 /* Semantic error in the TFT operation */ +#define GTPCAUSE_SYN_ERR_TFT 216 /* Syntactic error in the TFT operation */ +#define GTPCAUSE_SEM_ERR_FILTER 217 /* Semantic errors in packet filter(s) */ +#define GTPCAUSE_SYN_ERR_FILTER 218 /* Syntactic errors in packet filter(s) */ +#define GTPCAUSE_MISSING_APN 219 /* Missing or unknown APN */ +#define GTPCAUSE_UNKNOWN_PDP 220 /* Unknown PDP address or PDP type */ +#define GTPCAUSE_221 221 /* For Future Use 221-240 */ +#define GTPCAUSE_241 241 /* Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) 241-255 */ /* GTP 0 header. * Explanation to some of the fields: @@ -147,75 +144,72 @@ * Tunnel ID is IMSI+NSAPI. Unique identifier of PDP context. Is somewhat * redundant because the header also includes flow. */ -struct gtp0_header { /* Descriptions from 3GPP 09.60 */ - uint8_t flags; /* 01 bitfield, with typical values */ - /* 000..... Version: 1 (0) */ - /* ...1111. Spare (7) */ - /* .......0 SNDCP N-PDU Number flag (0) */ - uint8_t type; /* 02 Message type. T-PDU = 0xff */ - uint16_t length; /* 03 Length (of G-PDU excluding header) */ - uint16_t seq; /* 05 Sequence Number */ - uint16_t flow; /* 07 Flow Label ( = 0 for signalling) */ - uint8_t number; /* 09 SNDCP N-PDU LCC Number ( 0 = 0xff) */ - uint8_t spare1; /* 10 Spare */ - uint8_t spare2; /* 11 Spare */ - uint8_t spare3; /* 12 Spare */ - uint64_t tid; /* 13 Tunnel ID */ -}; /* 20 */ - -struct gtp1_header_short { /* Descriptions from 3GPP 29060 */ - uint8_t flags; /* 01 bitfield, with typical values */ - /* 001..... Version: 1 */ - /* ...1.... Protocol Type: GTP=1, GTP'=0 */ - /* ....0... Spare = 0 */ - /* .....0.. Extension header flag: 0 */ - /* ......0. Sequence number flag: 0 */ - /* .......0 PN: N-PDU Number flag */ - uint8_t type; /* 02 Message type. T-PDU = 0xff */ - uint16_t length; /* 03 Length (of IP packet or signalling) */ - uint32_t tei; /* 05 - 08 Tunnel Endpoint ID */ +struct gtp0_header { /* Descriptions from 3GPP 09.60 */ + uint8_t flags; /* 01 bitfield, with typical values */ + /* 000..... Version: 1 (0) */ + /* ...1111. Spare (7) */ + /* .......0 SNDCP N-PDU Number flag (0) */ + uint8_t type; /* 02 Message type. T-PDU = 0xff */ + uint16_t length; /* 03 Length (of G-PDU excluding header) */ + uint16_t seq; /* 05 Sequence Number */ + uint16_t flow; /* 07 Flow Label ( = 0 for signalling) */ + uint8_t number; /* 09 SNDCP N-PDU LCC Number ( 0 = 0xff) */ + uint8_t spare1; /* 10 Spare */ + uint8_t spare2; /* 11 Spare */ + uint8_t spare3; /* 12 Spare */ + uint64_t tid; /* 13 Tunnel ID */ +}; /* 20 */ + +struct gtp1_header_short { /* Descriptions from 3GPP 29060 */ + uint8_t flags; /* 01 bitfield, with typical values */ + /* 001..... Version: 1 */ + /* ...1.... Protocol Type: GTP=1, GTP'=0 */ + /* ....0... Spare = 0 */ + /* .....0.. Extension header flag: 0 */ + /* ......0. Sequence number flag: 0 */ + /* .......0 PN: N-PDU Number flag */ + uint8_t type; /* 02 Message type. T-PDU = 0xff */ + uint16_t length; /* 03 Length (of IP packet or signalling) */ + uint32_t tei; /* 05 - 08 Tunnel Endpoint ID */ }; -struct gtp1_header_long { /* Descriptions from 3GPP 29060 */ - uint8_t flags; /* 01 bitfield, with typical values */ - /* 001..... Version: 1 */ - /* ...1.... Protocol Type: GTP=1, GTP'=0 */ - /* ....0... Spare = 0 */ - /* .....0.. Extension header flag: 0 */ - /* ......1. Sequence number flag: 1 */ - /* .......0 PN: N-PDU Number flag */ - uint8_t type; /* 02 Message type. T-PDU = 0xff */ - uint16_t length; /* 03 Length (of IP packet or signalling) */ - uint32_t tei; /* 05 Tunnel Endpoint ID */ - uint16_t seq; /* 10 Sequence Number */ - uint8_t npdu; /* 11 N-PDU Number */ - uint8_t next; /* 12 Next extension header type. Empty = 0 */ +struct gtp1_header_long { /* Descriptions from 3GPP 29060 */ + uint8_t flags; /* 01 bitfield, with typical values */ + /* 001..... Version: 1 */ + /* ...1.... Protocol Type: GTP=1, GTP'=0 */ + /* ....0... Spare = 0 */ + /* .....0.. Extension header flag: 0 */ + /* ......1. Sequence number flag: 1 */ + /* .......0 PN: N-PDU Number flag */ + uint8_t type; /* 02 Message type. T-PDU = 0xff */ + uint16_t length; /* 03 Length (of IP packet or signalling) */ + uint32_t tei; /* 05 Tunnel Endpoint ID */ + uint16_t seq; /* 10 Sequence Number */ + uint8_t npdu; /* 11 N-PDU Number */ + uint8_t next; /* 12 Next extension header type. Empty = 0 */ }; struct gtp0_packet { - struct gtp0_header h; - uint8_t p[GTP_MAX]; -} __attribute__((packed)); + struct gtp0_header h; + uint8_t p[GTP_MAX]; +} __attribute__ ((packed)); struct gtp1_packet_short { - struct gtp1_header_short h; - uint8_t p[GTP_MAX]; -} __attribute__((packed)); + struct gtp1_header_short h; + uint8_t p[GTP_MAX]; +} __attribute__ ((packed)); struct gtp1_packet_long { - struct gtp1_header_long h; - uint8_t p[GTP_MAX]; -} __attribute__((packed)); + struct gtp1_header_long h; + uint8_t p[GTP_MAX]; +} __attribute__ ((packed)); union gtp_packet { - uint8_t flags; - struct gtp0_packet gtp0; - struct gtp1_packet_short gtp1s; - struct gtp1_packet_long gtp1l; -} __attribute__((packed)); - - - + uint8_t flags; + struct gtp0_packet gtp0; + struct gtp1_packet_short gtp1s; + struct gtp1_packet_long gtp1l; +} __attribute__ ((packed)); /* *********************************************************** * Information storage for each gsn instance @@ -233,64 +227,63 @@ union gtp_packet { *************************************************************/ struct gsn_t { - /* Parameters related to the network interface */ - - int fd0; /* GTP0 file descriptor */ - int fd1c; /* GTP1 control plane file descriptor */ - int fd1u; /* GTP0 user plane file descriptor */ - int mode; /* Mode of operation: GGSN or SGSN */ - struct in_addr gsnc; /* IP address of this gsn for signalling */ - struct in_addr gsnu; /* IP address of this gsn for user traffic */ - - /* Parameters related to signalling messages */ - uint16_t seq_next; /* Next sequence number to use */ - int seq_first; /* First packet in queue (oldest timeout) */ - int seq_last; /* Last packet in queue (youngest timeout) */ - - unsigned char restart_counter; /* Increment on restart. Stored on disk */ - char *statedir; /* Disk location for permanent storage */ - - struct queue_t *queue_req; /* Request queue */ - struct queue_t *queue_resp; /* Response queue */ - - /* Call back functions */ - int (*cb_delete_context) (struct pdp_t*); - int (*cb_create_context_ind) (struct pdp_t*); - int (*cb_unsup_ind) (struct sockaddr_in *peer); - int (*cb_extheader_ind) (struct sockaddr_in *peer); - int (*cb_conf) (int type, int cause, struct pdp_t *pdp, void* cbp); - int (*cb_data_ind) (struct pdp_t* pdp, void* pack, unsigned len); - int (*cb_recovery) (struct sockaddr_in *peer, uint8_t recovery); - - /* Counters */ - - uint64_t err_socket; /* Number of socket errors */ - uint64_t err_readfrom; /* Number of readfrom errors */ - uint64_t err_sendto; /* Number of sendto errors */ - uint64_t err_memcpy; /* Number of memcpy */ - uint64_t err_queuefull; /* Number of times queue was full */ - uint64_t err_seq; /* Number of seq out of range */ - uint64_t err_address; /* GSN address conversion failed */ - uint64_t err_unknownpdp; /* GSN address conversion failed */ - uint64_t err_unknowntid; /* Application supplied unknown imsi+nsapi */ - uint64_t err_cause; /* Unexpected cause value received */ - uint64_t err_outofpdp; /* Out of storage for PDP contexts */ - - uint64_t empty; /* Number of empty packets */ - uint64_t unsup; /* Number of unsupported version 29.60 11.1.1 */ - uint64_t tooshort; /* Number of too short headers 29.60 11.1.2 */ - uint64_t unknown; /* Number of unknown messages 29.60 11.1.3 */ - uint64_t unexpect; /* Number of unexpected messages 29.60 11.1.4 */ - uint64_t dublicate; /* Number of dublicate or unsolicited replies */ - uint64_t missing; /* Number of missing information field messages */ - uint64_t incorrect; /* Number of incorrect information field messages */ - uint64_t invalid; /* Number of invalid message format messages */ + /* Parameters related to the network interface */ + + int fd0; /* GTP0 file descriptor */ + int fd1c; /* GTP1 control plane file descriptor */ + int fd1u; /* GTP0 user plane file descriptor */ + int mode; /* Mode of operation: GGSN or SGSN */ + struct in_addr gsnc; /* IP address of this gsn for signalling */ + struct in_addr gsnu; /* IP address of this gsn for user traffic */ + + /* Parameters related to signalling messages */ + uint16_t seq_next; /* Next sequence number to use */ + int seq_first; /* First packet in queue (oldest timeout) */ + int seq_last; /* Last packet in queue (youngest timeout) */ + + unsigned char restart_counter; /* Increment on restart. Stored on disk */ + char *statedir; /* Disk location for permanent storage */ + + struct queue_t *queue_req; /* Request queue */ + struct queue_t *queue_resp; /* Response queue */ + + /* Call back functions */ + int (*cb_delete_context) (struct pdp_t *); + int (*cb_create_context_ind) (struct pdp_t *); + int (*cb_unsup_ind) (struct sockaddr_in * peer); + int (*cb_extheader_ind) (struct sockaddr_in * peer); + int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp); + int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len); + int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery); + + /* Counters */ + + uint64_t err_socket; /* Number of socket errors */ + uint64_t err_readfrom; /* Number of readfrom errors */ + uint64_t err_sendto; /* Number of sendto errors */ + uint64_t err_memcpy; /* Number of memcpy */ + uint64_t err_queuefull; /* Number of times queue was full */ + uint64_t err_seq; /* Number of seq out of range */ + uint64_t err_address; /* GSN address conversion failed */ + uint64_t err_unknownpdp; /* GSN address conversion failed */ + uint64_t err_unknowntid; /* Application supplied unknown imsi+nsapi */ + uint64_t err_cause; /* Unexpected cause value received */ + uint64_t err_outofpdp; /* Out of storage for PDP contexts */ + + uint64_t empty; /* Number of empty packets */ + uint64_t unsup; /* Number of unsupported version 29.60 11.1.1 */ + uint64_t tooshort; /* Number of too short headers 29.60 11.1.2 */ + uint64_t unknown; /* Number of unknown messages 29.60 11.1.3 */ + uint64_t unexpect; /* Number of unexpected messages 29.60 11.1.4 */ + uint64_t dublicate; /* Number of dublicate or unsolicited replies */ + uint64_t missing; /* Number of missing information field messages */ + uint64_t incorrect; /* Number of incorrect information field messages */ + uint64_t invalid; /* Number of invalid message format messages */ }; - /* External API functions */ -extern const char* gtp_version(); +extern const char *gtp_version(); extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, int mode); @@ -300,27 +293,29 @@ extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi); extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp); -extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp, +extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp); extern 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)); -extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, +extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause); -extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, - void *cbp, struct in_addr* inetaddr); +extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, + void *cbp, struct in_addr *inetaddr); -extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, +extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, int teardown); extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len); 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)); extern int gtp_fd(struct gsn_t *gsn); extern int gtp_decaps0(struct gsn_t *gsn); @@ -329,45 +324,46 @@ extern int gtp_decaps1u(struct gsn_t *gsn); extern int gtp_retrans(struct gsn_t *gsn); extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout); -extern int gtp_set_cb_delete_context(struct gsn_t *gsn, - int (*cb_delete_context) (struct pdp_t* pdp)); +extern int gtp_set_cb_delete_context(struct gsn_t *gsn, + int (*cb_delete_context) (struct pdp_t * + pdp)); /*extern int gtp_set_cb_create_context(struct gsn_t *gsn, int (*cb_create_context) (struct pdp_t* pdp)); */ extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in *peer)); + int (*cb) (struct sockaddr_in * peer)); extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in *peer)); - + int (*cb) (struct sockaddr_in * peer)); extern int gtp_set_cb_conf(struct gsn_t *gsn, - int (*cb) (int type, int cause, struct pdp_t* pdp, void *cbp)); + int (*cb) (int type, int cause, struct pdp_t * pdp, + void *cbp)); int gtp_set_cb_recovery(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in *peer, uint8_t recovery)); + int (*cb) (struct sockaddr_in * peer, + uint8_t recovery)); /* Internal functions (not part of the API */ extern int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp, struct in_addr *inetaddrs); -extern int gtp_echo_resp(struct gsn_t *gsn, int version, +extern int gtp_echo_resp(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, void *pack, unsigned len); -extern int gtp_echo_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, int fd, +extern int gtp_echo_ind(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, int fd, void *pack, unsigned len); -extern int gtp_echo_conf(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, unsigned len); +extern int gtp_echo_conf(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, void *pack, unsigned len); -extern int gtp_unsup_req(struct gsn_t *gsn, int version, +extern int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, void *pack, unsigned len); extern int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer, void *pack, unsigned len); -extern int gtp_create_pdp_resp(struct gsn_t *gsn, int version, +extern int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp, uint8_t cause); extern int gtp_create_pdp_ind(struct gsn_t *gsn, int version, @@ -379,14 +375,14 @@ extern int gtp_create_pdp_conf(struct gsn_t *gsn, int version, void *pack, unsigned len); extern int gtp_update_pdp_req(struct gsn_t *gsn, int version, void *cbp, - struct in_addr* inetaddr, struct pdp_t *pdp); + struct in_addr *inetaddr, struct pdp_t *pdp); extern int gtp_delete_pdp_req(struct gsn_t *gsn, int version, void *cbp, struct pdp_t *pdp); extern int gtp_delete_pdp_resp(struct gsn_t *gsn, int version, struct sockaddr_in *peer, int fd, - void *pack, unsigned len, + void *pack, unsigned len, struct pdp_t *pdp, struct pdp_t *linked_pdp, uint8_t cause, int teardown); @@ -398,10 +394,9 @@ extern int gtp_delete_pdp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer, void *pack, unsigned len); - extern int ipv42eua(struct ul66_t *eua, struct in_addr *src); extern int eua2ipv4(struct in_addr *dst, struct ul66_t *eua); extern int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna); extern int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src); -#endif /* !_GTP_H */ +#endif /* !_GTP_H */ diff --git a/gtp/gtpie.c b/gtp/gtpie.c index 39561d2..232183e 100644 --- a/gtp/gtpie.c +++ b/gtp/gtpie.c @@ -39,523 +39,592 @@ #include "gtpie.h" -int gtpie_tlv(void *p, unsigned int *length, unsigned int size, uint8_t t, int l, void *v) { - if ((*length + 3 + l) >= size) return 1; - ((union gtpie_member*) (p + *length))->tlv.t = hton8(t); - ((union gtpie_member*) (p + *length))->tlv.l = hton16(l); - memcpy((void*) (p + *length +3), v, l); - *length += 3 + l; - return 0; +int gtpie_tlv(void *p, unsigned int *length, unsigned int size, uint8_t t, + int l, void *v) +{ + if ((*length + 3 + l) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tlv.t = hton8(t); + ((union gtpie_member *)(p + *length))->tlv.l = hton16(l); + memcpy((void *)(p + *length + 3), v, l); + *length += 3 + l; + return 0; } -int gtpie_tv0(void *p, unsigned int *length, unsigned int size, uint8_t t, int l, uint8_t *v) { - if ((*length + 1 + l) >= size) return 1; - ((union gtpie_member*) (p + *length))->tv0.t = hton8(t); - memcpy((void*) (p + *length +1), v, l); - *length += 1 + l; - return 0; +int gtpie_tv0(void *p, unsigned int *length, unsigned int size, uint8_t t, + int l, uint8_t * v) +{ + if ((*length + 1 + l) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tv0.t = hton8(t); + memcpy((void *)(p + *length + 1), v, l); + *length += 1 + l; + return 0; } -int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t, uint8_t v) { - if ((*length + 2) >= size) return 1; - ((union gtpie_member*) (p + *length))->tv1.t = hton8(t); - ((union gtpie_member*) (p + *length))->tv1.v = hton8(v); - *length += 2; - return 0; +int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t, + uint8_t v) +{ + if ((*length + 2) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tv1.t = hton8(t); + ((union gtpie_member *)(p + *length))->tv1.v = hton8(v); + *length += 2; + return 0; } -int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t, uint16_t v) { - if ((*length + 3) >= size) return 1; - ((union gtpie_member*) (p + *length))->tv2.t = hton8(t); - ((union gtpie_member*) (p + *length))->tv2.v = hton16(v); - *length += 3; - return 0; +int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t, + uint16_t v) +{ + if ((*length + 3) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tv2.t = hton8(t); + ((union gtpie_member *)(p + *length))->tv2.v = hton16(v); + *length += 3; + return 0; } -int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t, uint32_t v) { - if ((*length + 5) >= size) return 1; - ((union gtpie_member*) (p + *length))->tv4.t = hton8(t); - ((union gtpie_member*) (p + *length))->tv4.v = hton32(v); - *length += 5; - return 0; +int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t, + uint32_t v) +{ + if ((*length + 5) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tv4.t = hton8(t); + ((union gtpie_member *)(p + *length))->tv4.v = hton32(v); + *length += 5; + return 0; } -int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t, uint64_t v) { - if ((*length + 9) >= size) return 1; - ((union gtpie_member*) (p + *length))->tv8.t = hton8(t); - ((union gtpie_member*) (p + *length))->tv8.v = hton64(v); - *length += 9; - return 0; +int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t, + uint64_t v) +{ + if ((*length + 9) >= size) + return 1; + ((union gtpie_member *)(p + *length))->tv8.t = hton8(t); + ((union gtpie_member *)(p + *length))->tv8.v = hton64(v); + *length += 9; + return 0; } -int gtpie_getie(union gtpie_member* ie[], int type, int instance) { - int j; - for (j=0; j< GTPIE_SIZE; j++) { - if ((ie[j] != 0) && (ie[j]->t == type)) { - if (instance-- == 0) return j; - } - } - return -1; +int gtpie_getie(union gtpie_member *ie[], int type, int instance) +{ + int j; + for (j = 0; j < GTPIE_SIZE; j++) { + if ((ie[j] != 0) && (ie[j]->t == type)) { + if (instance-- == 0) + return j; + } + } + return -1; } -int gtpie_exist(union gtpie_member* ie[], int type, int instance) { - int j; - for (j=0; j< GTPIE_SIZE; j++) { - if ((ie[j] != 0) && (ie[j]->t == type)) { - if (instance-- == 0) return 1; - } - } - return 0; +int gtpie_exist(union gtpie_member *ie[], int type, int instance) +{ + int j; + for (j = 0; j < GTPIE_SIZE; j++) { + if ((ie[j] != 0) && (ie[j]->t == type)) { + if (instance-- == 0) + return 1; + } + } + return 0; } -int gtpie_gettlv(union gtpie_member* ie[], int type, int instance, - unsigned int *length, void *dst, unsigned int size){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) { - *length = ntoh16(ie[ien]->tlv.l); - if (*length <= size) - memcpy(dst, ie[ien]->tlv.v, *length); - else - return EOF; - } - return 0; +int gtpie_gettlv(union gtpie_member *ie[], int type, int instance, + unsigned int *length, void *dst, unsigned int size) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) { + *length = ntoh16(ie[ien]->tlv.l); + if (*length <= size) + memcpy(dst, ie[ien]->tlv.v, *length); + else + return EOF; + } + return 0; } -int gtpie_gettv0(union gtpie_member* ie[], int type, int instance, - void *dst, unsigned int size){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) - memcpy(dst, ie[ien]->tv0.v, size); - else - return EOF; - return 0; +int gtpie_gettv0(union gtpie_member *ie[], int type, int instance, + void *dst, unsigned int size) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) + memcpy(dst, ie[ien]->tv0.v, size); + else + return EOF; + return 0; } -int gtpie_gettv1(union gtpie_member* ie[], int type, int instance, - uint8_t *dst){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) - *dst = ntoh8(ie[ien]->tv1.v); - else - return EOF; - return 0; +int gtpie_gettv1(union gtpie_member *ie[], int type, int instance, + uint8_t * dst) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) + *dst = ntoh8(ie[ien]->tv1.v); + else + return EOF; + return 0; } -int gtpie_gettv2(union gtpie_member* ie[], int type, int instance, - uint16_t *dst){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) - *dst = ntoh16(ie[ien]->tv2.v); - else - return EOF; - return 0; +int gtpie_gettv2(union gtpie_member *ie[], int type, int instance, + uint16_t * dst) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) + *dst = ntoh16(ie[ien]->tv2.v); + else + return EOF; + return 0; } -int gtpie_gettv4(union gtpie_member* ie[], int type, int instance, - uint32_t *dst){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) - *dst = ntoh32(ie[ien]->tv4.v); - else - return EOF; - return 0; +int gtpie_gettv4(union gtpie_member *ie[], int type, int instance, + uint32_t * dst) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) + *dst = ntoh32(ie[ien]->tv4.v); + else + return EOF; + return 0; } -int gtpie_gettv8(union gtpie_member* ie[], int type, int instance, - uint64_t *dst){ - int ien; - ien = gtpie_getie(ie, type, instance); - if (ien>=0) - *dst = ntoh64(ie[ien]->tv8.v); - else - return EOF; - return 0; +int gtpie_gettv8(union gtpie_member *ie[], int type, int instance, + uint64_t * dst) +{ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien >= 0) + *dst = ntoh64(ie[ien]->tv8.v); + else + return EOF; + return 0; } -int gtpie_decaps(union gtpie_member* ie[], int version, void *pack, unsigned len) { - int i; - int j = 0; - unsigned char *p; - unsigned char *end; +int gtpie_decaps(union gtpie_member *ie[], int version, void *pack, + unsigned len) +{ + int i; + int j = 0; + unsigned char *p; + unsigned char *end; + + end = (unsigned char *)pack + len; + p = pack; - end = (unsigned char*) pack + len; - p = pack; + memset(ie, 0, sizeof(union gtpie_member *) * GTPIE_SIZE); - memset(ie, 0, sizeof(union gtpie_member *) * GTPIE_SIZE); + while ((p < end) && (j < GTPIE_SIZE)) { + if (GTPIE_DEBUG) { + printf("The packet looks like this:\n"); + for (i = 0; i < (end - p); i++) { + printf("%02x ", + (unsigned char)*(char *)(p + i)); + if (!((i + 1) % 16)) + printf("\n"); + }; + printf("\n"); + } - while ((ptv1.t, ie[j]->tv1.v); - p+= 1 + 1; - j++; - } - break; - case GTPIE_FL_DI: /* TV GTPIE types with value length 2 or 4 */ - case GTPIE_FL_C: - if (version != 0) { - if (jtv4.t, ie[j]->tv4.v); - p+= 1 + 4; - j++; + switch (*p) { + case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */ + case GTPIE_REORDER: + case GTPIE_MAP_CAUSE: + case GTPIE_MS_VALIDATED: + case GTPIE_RECOVERY: + case GTPIE_SELECTION_MODE: + case GTPIE_TEARDOWN: + case GTPIE_NSAPI: + case GTPIE_RANAP_CAUSE: + case GTPIE_RP_SMS: + case GTPIE_RP: + case GTPIE_MS_NOT_REACH: + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE TV1 found. Type %d, value %d\n", + ie[j]->tv1.t, ie[j]->tv1.v); + p += 1 + 1; + j++; + } + break; + case GTPIE_FL_DI: /* TV GTPIE types with value length 2 or 4 */ + case GTPIE_FL_C: + if (version != 0) { + if (j < GTPIE_SIZE) { /* GTPIE_TEI_DI & GTPIE_TEI_C with length 4 */ + /* case GTPIE_TEI_DI: gtp1 */ + /* case GTPIE_TEI_C: gtp1 */ + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE TV 4 found. Type %d, value %d\n", + ie[j]->tv4.t, + ie[j]->tv4.v); + p += 1 + 4; + j++; + } + break; + } + case GTPIE_PFI: /* TV GTPIE types with value length 2 */ + case GTPIE_CHARGING_C: + case GTPIE_TRACE_REF: + case GTPIE_TRACE_TYPE: + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE TV2 found. Type %d, value %d\n", + ie[j]->tv2.t, ie[j]->tv2.v); + p += 1 + 2; + j++; + } + break; + case GTPIE_QOS_PROFILE0: /* TV GTPIE types with value length 3 */ + case GTPIE_P_TMSI_S: + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE TV 3 found. Type %d, value %d, %d, %d\n", + ie[j]->tv0.t, ie[j]->tv0.v[0], + ie[j]->tv0.v[1], ie[j]->tv0.v[2]); + p += 1 + 3; + j++; + } + break; + case GTPIE_TLLI: /* TV GTPIE types with value length 4 */ + case GTPIE_P_TMSI: + case GTPIE_CHARGING_ID: + /* case GTPIE_TEI_DI: Handled by GTPIE_FL_DI */ + /* case GTPIE_TEI_C: Handled by GTPIE_FL_DI */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE TV 4 found. Type %d, value %d\n", + ie[j]->tv4.t, ie[j]->tv4.v); + p += 1 + 4; + j++; + } + break; + case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf("GTPIE TV 5 found. Type %d\n", + ie[j]->tv0.t); + p += 1 + 5; + j++; + } + break; + case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf("GTPIE TV 7 found. Type %d\n", + ie[j]->tv0.t); + p += 1 + 7; + j++; + } + break; + case GTPIE_IMSI: /* TV GTPIE types with value length 8 */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE_IMSI - GTPIE TV 8 found. Type %d, value 0x%llx\n", + ie[j]->tv0.t, ie[j]->tv8.v); + p += 1 + 8; + j++; + } + break; + case GTPIE_RAI: /* TV GTPIE types with value length 6 */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE_RAI - GTPIE TV 6 found. Type %d, value 0x%llx\n", + ie[j]->tv0.t, ie[j]->tv8.v); + p += 1 + 6; + j++; + } + break; + case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf("GTPIE TV 28 found. Type %d\n", + ie[j]->tv0.t); + p += 1 + 28; + j++; + } + break; + case GTPIE_EXT_HEADER_T: /* GTP extension header */ + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf + ("GTPIE GTP extension header found. Type %d\n", + ie[j]->ext.t); + p += 2 + ntoh8(ie[j]->ext.l); + j++; + } + break; + case GTPIE_EUA: /* TLV GTPIE types with variable length */ + case GTPIE_MM_CONTEXT: + case GTPIE_PDP_CONTEXT: + case GTPIE_APN: + case GTPIE_PCO: + case GTPIE_GSN_ADDR: + case GTPIE_MSISDN: + case GTPIE_QOS_PROFILE: + case GTPIE_AUTH_QUINTUP: + case GTPIE_TFT: + case GTPIE_TARGET_INF: + case GTPIE_UTRAN_TRANS: + case GTPIE_RAB_SETUP: + case GTPIE_TRIGGER_ID: + case GTPIE_OMC_ID: + case GTPIE_CHARGING_ADDR: + case GTPIE_RAT_TYPE: + case GTPIE_USER_LOC: + case GTPIE_MS_TZ: + case GTPIE_IMEI_SV: + case GTPIE_PRIVATE: + if (j < GTPIE_SIZE) { + ie[j] = (union gtpie_member *)p; + if (GTPIE_DEBUG) + printf("GTPIE TLV found. Type %d\n", + ie[j]->tlv.t); + p += 3 + ntoh16(ie[j]->tlv.l); + j++; + } + break; + default: + if (GTPIE_DEBUG) + printf("GTPIE something unknown. Type %d\n", + *p); + return EOF; /* We received something unknown */ + } + } + if (p == end) { + if (GTPIE_DEBUG) + printf("GTPIE normal return. %lx %lx\n", + (unsigned long)p, (unsigned long)end); + return 0; /* We landed at the end of the packet: OK */ + } else if (!(j < GTPIE_SIZE)) { + if (GTPIE_DEBUG) + printf("GTPIE too many elements.\n"); + return EOF; /* We received too many information elements */ + } else { + if (GTPIE_DEBUG) + printf("GTPIE exceeded end of packet. %lx %lx\n", + (unsigned long)p, (unsigned long)end); + return EOF; /* We exceeded the end of the packet: Error */ } - break; - } - case GTPIE_PFI: /* TV GTPIE types with value length 2 */ - case GTPIE_CHARGING_C: - case GTPIE_TRACE_REF: - case GTPIE_TRACE_TYPE: - if (jtv2.t, ie[j]->tv2.v); - p+= 1 + 2; - j++; - } - break; - case GTPIE_QOS_PROFILE0: /* TV GTPIE types with value length 3 */ - case GTPIE_P_TMSI_S: - if (jtv0.t, ie[j]->tv0.v[0], - ie[j]->tv0.v[1], ie[j]->tv0.v[2]); - p+= 1 + 3; - j++; - } - break; - case GTPIE_TLLI: /* TV GTPIE types with value length 4 */ - case GTPIE_P_TMSI: - case GTPIE_CHARGING_ID: - /* case GTPIE_TEI_DI: Handled by GTPIE_FL_DI */ - /* case GTPIE_TEI_C: Handled by GTPIE_FL_DI */ - if (jtv4.t, ie[j]->tv4.v); - p+= 1 + 4; - j++; - } - break; - case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */ - if (jtv0.t); - p+= 1 + 5; - j++; - } - break; - case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */ - if (jtv0.t); - p+= 1 + 7; - j++; - } - break; - case GTPIE_IMSI: /* TV GTPIE types with value length 8 */ - if (jtv0.t, ie[j]->tv8.v); - p+= 1 + 8; - j++; - } - break; - case GTPIE_RAI: /* TV GTPIE types with value length 6 */ - if (jtv0.t, ie[j]->tv8.v); - p+= 1 + 6; - j++; - } - break; - case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */ - if (jtv0.t); - p+= 1 + 28; - j++; - } - break; - case GTPIE_EXT_HEADER_T: /* GTP extension header */ - if (jext.t); - p+= 2 + ntoh8(ie[j]->ext.l); - j++; - } - break; - case GTPIE_EUA: /* TLV GTPIE types with variable length */ - case GTPIE_MM_CONTEXT: - case GTPIE_PDP_CONTEXT: - case GTPIE_APN: - case GTPIE_PCO: - case GTPIE_GSN_ADDR: - case GTPIE_MSISDN: - case GTPIE_QOS_PROFILE: - case GTPIE_AUTH_QUINTUP: - case GTPIE_TFT: - case GTPIE_TARGET_INF: - case GTPIE_UTRAN_TRANS: - case GTPIE_RAB_SETUP: - case GTPIE_TRIGGER_ID: - case GTPIE_OMC_ID: - case GTPIE_CHARGING_ADDR: - case GTPIE_RAT_TYPE: - case GTPIE_USER_LOC: - case GTPIE_MS_TZ: - case GTPIE_IMEI_SV: - case GTPIE_PRIVATE: - if (jtlv.t); - p+= 3 + ntoh16(ie[j]->tlv.l); - j++; - } - break; - default: - if (GTPIE_DEBUG) printf("GTPIE something unknown. Type %d\n", *p); - return EOF; /* We received something unknown */ - } - } - if (p==end) { - if (GTPIE_DEBUG) printf("GTPIE normal return. %lx %lx\n", - (unsigned long) p, (unsigned long) end); - return 0; /* We landed at the end of the packet: OK */ - } - else if (!(jext.l); - break; - case GTPIE_EUA: /* TLV GTPIE types with length length 2 */ - case GTPIE_MM_CONTEXT: - case GTPIE_PDP_CONTEXT: - case GTPIE_APN: - case GTPIE_PCO: - case GTPIE_GSN_ADDR: - case GTPIE_MSISDN: - case GTPIE_QOS_PROFILE: - case GTPIE_AUTH_QUINTUP: - case GTPIE_TFT: - case GTPIE_TARGET_INF: - case GTPIE_UTRAN_TRANS: - case GTPIE_RAB_SETUP: - case GTPIE_TRIGGER_ID: - case GTPIE_OMC_ID: - case GTPIE_CHARGING_ADDR: - case GTPIE_PRIVATE: - iesize = 3 + hton16(ie[i]->tlv.l); - break; - default: - return 2; /* We received something unknown */ - } - if (p+iesize < end) { - memcpy(p, ie[i], iesize); - p += iesize; - *len += iesize; - } - else return 2; /* Out of space */ - } - return 0; + memset(pack, 0, GTPIE_MAX); + end = p + GTPIE_MAX; + for (i = 1; i < GTPIE_SIZE; i++) + if (ie[i] != 0) { + if (GTPIE_DEBUG) + printf("gtpie_encaps. Type %d\n", i); + m = (union gtpie_member *)p; + switch (i) { + case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */ + case GTPIE_REORDER: + case GTPIE_MAP_CAUSE: + case GTPIE_MS_VALIDATED: + case GTPIE_RECOVERY: + case GTPIE_SELECTION_MODE: + case GTPIE_TEARDOWN: + case GTPIE_NSAPI: + case GTPIE_RANAP_CAUSE: + case GTPIE_RP_SMS: + case GTPIE_RP: + case GTPIE_MS_NOT_REACH: + iesize = 2; + break; + case GTPIE_FL_DI: /* TV GTPIE types with value length 2 */ + case GTPIE_FL_C: + case GTPIE_PFI: + case GTPIE_CHARGING_C: + case GTPIE_TRACE_REF: + case GTPIE_TRACE_TYPE: + iesize = 3; + break; + case GTPIE_QOS_PROFILE0: /* TV GTPIE types with value length 3 */ + case GTPIE_P_TMSI_S: + iesize = 4; + break; + case GTPIE_TLLI: /* TV GTPIE types with value length 4 */ + case GTPIE_P_TMSI: + /* case GTPIE_TEI_DI: only in gtp1 */ + /* case GTPIE_TEI_C: only in gtp1 */ + case GTPIE_CHARGING_ID: + iesize = 5; + break; + case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */ + iesize = 6; + break; + case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */ + iesize = 8; + break; + case GTPIE_IMSI: /* TV GTPIE types with value length 8 */ + case GTPIE_RAI: + iesize = 9; + break; + case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */ + iesize = 29; + break; + case GTPIE_EXT_HEADER_T: /* GTP extension header */ + iesize = 2 + hton8(ie[i]->ext.l); + break; + case GTPIE_EUA: /* TLV GTPIE types with length length 2 */ + case GTPIE_MM_CONTEXT: + case GTPIE_PDP_CONTEXT: + case GTPIE_APN: + case GTPIE_PCO: + case GTPIE_GSN_ADDR: + case GTPIE_MSISDN: + case GTPIE_QOS_PROFILE: + case GTPIE_AUTH_QUINTUP: + case GTPIE_TFT: + case GTPIE_TARGET_INF: + case GTPIE_UTRAN_TRANS: + case GTPIE_RAB_SETUP: + case GTPIE_TRIGGER_ID: + case GTPIE_OMC_ID: + case GTPIE_CHARGING_ADDR: + case GTPIE_PRIVATE: + iesize = 3 + hton16(ie[i]->tlv.l); + break; + default: + return 2; /* We received something unknown */ + } + if (p + iesize < end) { + memcpy(p, ie[i], iesize); + p += iesize; + *len += iesize; + } else + return 2; /* Out of space */ + } + return 0; } int gtpie_encaps2(union gtpie_member ie[], unsigned int size, - void *pack, unsigned *len) { - unsigned int i, j; - unsigned char *p; - unsigned char *end; - union gtpie_member *m; - int iesize; - - p = pack; + void *pack, unsigned *len) +{ + unsigned int i, j; + unsigned char *p; + unsigned char *end; + union gtpie_member *m; + int iesize; + + p = pack; - memset(pack, 0, GTPIE_MAX); - end = p + GTPIE_MAX; - for (j=0; j> 32; - l = (uint32_t) q; + register uint32_t u, l; + u = q >> 32; + l = (uint32_t) q; - return htonl(u) | ((uint64_t)htonl(l) << 32); + return htonl(u) | ((uint64_t) htonl(l) << 32); } #define ntoh64(_x) hton64(_x) @@ -42,127 +41,124 @@ hton64(uint64_t q) #error "Please fix " #endif +#define GTPIE_SIZE 256 /* Max number of information elements */ +#define GTPIE_MAX 0xffff /* Max length of information elements */ +#define GTPIE_MAX_TV 28 /* Max length of type value pair */ +#define GTPIE_MAX_TLV 0xffff-3 /* Max length of TLV (GTP length is 16 bit) */ -#define GTPIE_SIZE 256 /* Max number of information elements */ -#define GTPIE_MAX 0xffff /* Max length of information elements */ -#define GTPIE_MAX_TV 28 /* Max length of type value pair */ -#define GTPIE_MAX_TLV 0xffff-3 /* Max length of TLV (GTP length is 16 bit) */ - -#define GTPIE_DEBUG 0 /* Print debug information */ +#define GTPIE_DEBUG 0 /* Print debug information */ /* GTP Information elements from 29.060 v3.9.0 7.7 Information Elements */ /* Also covers version 0. Note that version 0 6: QOS Profile was superceded * * by 135: QOS Profile in version 1 */ -#define GTPIE_CAUSE 1 /* Cause 1 */ -#define GTPIE_IMSI 2 /* International Mobile Subscriber Identity 8 */ -#define GTPIE_RAI 3 /* Routing Area Identity (RAI) 8 */ -#define GTPIE_TLLI 4 /* Temporary Logical Link Identity (TLLI) 4 */ -#define GTPIE_P_TMSI 5 /* Packet TMSI (P-TMSI) 4 */ -#define GTPIE_QOS_PROFILE0 6 /* Quality of Service Profile GTP version 0 3*/ - /* 6-7 SPARE */ /* 6 is QoS Profile vers 0 */ -#define GTPIE_REORDER 8 /* Reordering Required 1 */ -#define GTPIE_AUTH_TRIPLET 9 /* Authentication Triplet 28 */ - /* 10 SPARE */ -#define GTPIE_MAP_CAUSE 11 /* MAP Cause 1 */ -#define GTPIE_P_TMSI_S 12 /* P-TMSI Signature 3 */ -#define GTPIE_MS_VALIDATED 13 /* MS Validated 1 */ -#define GTPIE_RECOVERY 14 /* Recovery 1 */ -#define GTPIE_SELECTION_MODE 15 /* Selection Mode 1 */ -#define GTPIE_FL_DI 16 /* Flow Label Data I 2 */ -#define GTPIE_TEI_DI 16 /* Tunnel Endpoint Identifier Data I 4 */ -#define GTPIE_TEI_C 17 /* Tunnel Endpoint Identifier Control Plane 4 */ -#define GTPIE_FL_C 17 /* Flow Label Signalling 2 */ -#define GTPIE_TEI_DII 18 /* Tunnel Endpoint Identifier Data II 5 */ -#define GTPIE_TEARDOWN 19 /* Teardown Ind 1 */ -#define GTPIE_NSAPI 20 /* NSAPI 1 */ -#define GTPIE_RANAP_CAUSE 21 /* RANAP Cause 1 */ -#define GTPIE_RAB_CONTEXT 22 /* RAB Context 7 */ -#define GTPIE_RP_SMS 23 /* Radio Priority SMS 1 */ -#define GTPIE_RP 24 /* Radio Priority 1 */ -#define GTPIE_PFI 25 /* Packet Flow Id 2 */ -#define GTPIE_CHARGING_C 26 /* Charging Characteristics 2 */ -#define GTPIE_TRACE_REF 27 /* Trace Reference 2 */ -#define GTPIE_TRACE_TYPE 28 /* Trace Type 2 */ -#define GTPIE_MS_NOT_REACH 29 /* MS Not Reachable Reason 1 */ - /* 30-116 UNUSED */ +#define GTPIE_CAUSE 1 /* Cause 1 */ +#define GTPIE_IMSI 2 /* International Mobile Subscriber Identity 8 */ +#define GTPIE_RAI 3 /* Routing Area Identity (RAI) 8 */ +#define GTPIE_TLLI 4 /* Temporary Logical Link Identity (TLLI) 4 */ +#define GTPIE_P_TMSI 5 /* Packet TMSI (P-TMSI) 4 */ +#define GTPIE_QOS_PROFILE0 6 /* Quality of Service Profile GTP version 0 3 */ + /* 6-7 SPARE *//* 6 is QoS Profile vers 0 */ +#define GTPIE_REORDER 8 /* Reordering Required 1 */ +#define GTPIE_AUTH_TRIPLET 9 /* Authentication Triplet 28 */ + /* 10 SPARE */ +#define GTPIE_MAP_CAUSE 11 /* MAP Cause 1 */ +#define GTPIE_P_TMSI_S 12 /* P-TMSI Signature 3 */ +#define GTPIE_MS_VALIDATED 13 /* MS Validated 1 */ +#define GTPIE_RECOVERY 14 /* Recovery 1 */ +#define GTPIE_SELECTION_MODE 15 /* Selection Mode 1 */ +#define GTPIE_FL_DI 16 /* Flow Label Data I 2 */ +#define GTPIE_TEI_DI 16 /* Tunnel Endpoint Identifier Data I 4 */ +#define GTPIE_TEI_C 17 /* Tunnel Endpoint Identifier Control Plane 4 */ +#define GTPIE_FL_C 17 /* Flow Label Signalling 2 */ +#define GTPIE_TEI_DII 18 /* Tunnel Endpoint Identifier Data II 5 */ +#define GTPIE_TEARDOWN 19 /* Teardown Ind 1 */ +#define GTPIE_NSAPI 20 /* NSAPI 1 */ +#define GTPIE_RANAP_CAUSE 21 /* RANAP Cause 1 */ +#define GTPIE_RAB_CONTEXT 22 /* RAB Context 7 */ +#define GTPIE_RP_SMS 23 /* Radio Priority SMS 1 */ +#define GTPIE_RP 24 /* Radio Priority 1 */ +#define GTPIE_PFI 25 /* Packet Flow Id 2 */ +#define GTPIE_CHARGING_C 26 /* Charging Characteristics 2 */ +#define GTPIE_TRACE_REF 27 /* Trace Reference 2 */ +#define GTPIE_TRACE_TYPE 28 /* Trace Type 2 */ +#define GTPIE_MS_NOT_REACH 29 /* MS Not Reachable Reason 1 */ + /* 30-116 UNUSED */ /* 117-126 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */ -#define GTPIE_CHARGING_ID 127 /* Charging ID 4 */ -#define GTPIE_EUA 128 /* End User Address */ -#define GTPIE_MM_CONTEXT 129 /* MM Context */ -#define GTPIE_PDP_CONTEXT 130 /* PDP Context */ -#define GTPIE_APN 131 /* Access Point Name */ -#define GTPIE_PCO 132 /* Protocol Configuration Options */ -#define GTPIE_GSN_ADDR 133 /* GSN Address */ -#define GTPIE_MSISDN 134 /* MS International PSTN/ISDN Number */ -#define GTPIE_QOS_PROFILE 135 /* Quality of Service Profile */ -#define GTPIE_AUTH_QUINTUP 136 /* Authentication Quintuplet */ -#define GTPIE_TFT 137 /* Traffic Flow Template */ -#define GTPIE_TARGET_INF 138 /* Target Identification */ -#define GTPIE_UTRAN_TRANS 139 /* UTRAN Transparent Container */ -#define GTPIE_RAB_SETUP 140 /* RAB Setup Information */ -#define GTPIE_EXT_HEADER_T 141 /* Extension Header Type List */ -#define GTPIE_TRIGGER_ID 142 /* Trigger Id */ -#define GTPIE_OMC_ID 143 /* OMC Identity */ -#define GTPIE_RAT_TYPE 151 /* Radio Access Technology Type */ -#define GTPIE_USER_LOC 152 /* User Location Information */ -#define GTPIE_MS_TZ 153 /* MS Time Zone */ -#define GTPIE_IMEI_SV 154 /* IMEI Software Version */ +#define GTPIE_CHARGING_ID 127 /* Charging ID 4 */ +#define GTPIE_EUA 128 /* End User Address */ +#define GTPIE_MM_CONTEXT 129 /* MM Context */ +#define GTPIE_PDP_CONTEXT 130 /* PDP Context */ +#define GTPIE_APN 131 /* Access Point Name */ +#define GTPIE_PCO 132 /* Protocol Configuration Options */ +#define GTPIE_GSN_ADDR 133 /* GSN Address */ +#define GTPIE_MSISDN 134 /* MS International PSTN/ISDN Number */ +#define GTPIE_QOS_PROFILE 135 /* Quality of Service Profile */ +#define GTPIE_AUTH_QUINTUP 136 /* Authentication Quintuplet */ +#define GTPIE_TFT 137 /* Traffic Flow Template */ +#define GTPIE_TARGET_INF 138 /* Target Identification */ +#define GTPIE_UTRAN_TRANS 139 /* UTRAN Transparent Container */ +#define GTPIE_RAB_SETUP 140 /* RAB Setup Information */ +#define GTPIE_EXT_HEADER_T 141 /* Extension Header Type List */ +#define GTPIE_TRIGGER_ID 142 /* Trigger Id */ +#define GTPIE_OMC_ID 143 /* OMC Identity */ +#define GTPIE_RAT_TYPE 151 /* Radio Access Technology Type */ +#define GTPIE_USER_LOC 152 /* User Location Information */ +#define GTPIE_MS_TZ 153 /* MS Time Zone */ +#define GTPIE_IMEI_SV 154 /* IMEI Software Version */ /* 239-250 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */ -#define GTPIE_CHARGING_ADDR 251 /* Charging Gateway Address */ +#define GTPIE_CHARGING_ADDR 251 /* Charging Gateway Address */ /* 252-254 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */ -#define GTPIE_PRIVATE 255 /* Private Extension */ - +#define GTPIE_PRIVATE 255 /* Private Extension */ /* GTP information element structs in network order */ -struct gtpie_ext { /* Extension header */ - uint8_t t; /* Type */ - uint8_t l; /* Length */ - uint8_t *p; /* Value */ -} __attribute__((packed)); - -struct gtpie_tlv { /* Type length value pair */ - uint8_t t; /* Type */ - uint16_t l; /* Length */ - uint8_t v[GTPIE_MAX_TLV]; /* Value */ -} __attribute__((packed)); - -struct gtpie_tv0 { /* 1 byte type value pair */ - uint8_t t; /* Type */ - uint8_t v[GTPIE_MAX_TV]; /* Pointer to value */ -}__attribute__((packed)); - -struct gtpie_tv1 { /* 1 byte type value pair */ - uint8_t t; /* Type */ - uint8_t v; /* Value */ -}__attribute__((packed)); - -struct gtpie_tv2 { /* 2 byte type value pair */ - uint8_t t; /* Type */ - uint16_t v; /* Value */ -}__attribute__((packed)); - -struct gtpie_tv4 { /* 4 byte type value pair */ - uint8_t t; /* Type */ - uint32_t v; /* Value */ -}__attribute__((packed)); - -struct gtpie_tv8 { /* 8 byte type value pair */ - uint8_t t; /* Type */ - uint64_t v; /* Value */ -}__attribute__((packed)); - +struct gtpie_ext { /* Extension header */ + uint8_t t; /* Type */ + uint8_t l; /* Length */ + uint8_t *p; /* Value */ +} __attribute__ ((packed)); + +struct gtpie_tlv { /* Type length value pair */ + uint8_t t; /* Type */ + uint16_t l; /* Length */ + uint8_t v[GTPIE_MAX_TLV]; /* Value */ +} __attribute__ ((packed)); + +struct gtpie_tv0 { /* 1 byte type value pair */ + uint8_t t; /* Type */ + uint8_t v[GTPIE_MAX_TV]; /* Pointer to value */ +} __attribute__ ((packed)); + +struct gtpie_tv1 { /* 1 byte type value pair */ + uint8_t t; /* Type */ + uint8_t v; /* Value */ +} __attribute__ ((packed)); + +struct gtpie_tv2 { /* 2 byte type value pair */ + uint8_t t; /* Type */ + uint16_t v; /* Value */ +} __attribute__ ((packed)); + +struct gtpie_tv4 { /* 4 byte type value pair */ + uint8_t t; /* Type */ + uint32_t v; /* Value */ +} __attribute__ ((packed)); + +struct gtpie_tv8 { /* 8 byte type value pair */ + uint8_t t; /* Type */ + uint64_t v; /* Value */ +} __attribute__ ((packed)); union gtpie_member { - uint8_t t; - struct gtpie_ext ext; - struct gtpie_tlv tlv; - struct gtpie_tv0 tv0; - struct gtpie_tv1 tv1; - struct gtpie_tv2 tv2; - struct gtpie_tv4 tv4; - struct gtpie_tv8 tv8; -}__attribute__((packed)); + uint8_t t; + struct gtpie_ext ext; + struct gtpie_tlv tlv; + struct gtpie_tv0 tv0; + struct gtpie_tv1 tv1; + struct gtpie_tv2 tv2; + struct gtpie_tv4 tv4; + struct gtpie_tv8 tv8; +} __attribute__ ((packed)); /* cause @@ -214,45 +210,46 @@ private */ struct tlv1 { - uint8_t type; - uint8_t length; -}__attribute__((packed)); + uint8_t type; + uint8_t length; +} __attribute__ ((packed)); struct tlv2 { - uint8_t type; - uint16_t length; -}__attribute__((packed)); + uint8_t type; + uint16_t length; +} __attribute__ ((packed)); extern int gtpie_tlv(void *p, unsigned int *length, unsigned int size, uint8_t t, int l, void *v); -extern int gtpie_tv0(void *p, unsigned int *length, unsigned int size, - uint8_t t, int l, uint8_t *v); -extern int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t, uint8_t v); -extern int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t, uint16_t v); -extern int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t, uint32_t v); -extern int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t, uint64_t v); -extern int gtpie_getie(union gtpie_member* ie[], int type, int instance); -extern int gtpie_exist(union gtpie_member* ie[], int type, int instance); -extern int gtpie_gettlv(union gtpie_member* ie[], int type, int instance, +extern int gtpie_tv0(void *p, unsigned int *length, unsigned int size, + uint8_t t, int l, uint8_t * v); +extern int gtpie_tv1(void *p, unsigned int *length, unsigned int size, + uint8_t t, uint8_t v); +extern int gtpie_tv2(void *p, unsigned int *length, unsigned int size, + uint8_t t, uint16_t v); +extern int gtpie_tv4(void *p, unsigned int *length, unsigned int size, + uint8_t t, uint32_t v); +extern int gtpie_tv8(void *p, unsigned int *length, unsigned int size, + uint8_t t, uint64_t v); +extern int gtpie_getie(union gtpie_member *ie[], int type, int instance); +extern int gtpie_exist(union gtpie_member *ie[], int type, int instance); +extern int gtpie_gettlv(union gtpie_member *ie[], int type, int instance, unsigned int *length, void *dst, unsigned int size); -extern int gtpie_gettv0(union gtpie_member* ie[], int type, int instance, +extern int gtpie_gettv0(union gtpie_member *ie[], int type, int instance, void *dst, unsigned int size); -extern int gtpie_gettv1(union gtpie_member* ie[], int type, int instance, - uint8_t *dst); -extern int gtpie_gettv2(union gtpie_member* ie[], int type, int instance, - uint16_t *dst); -extern int gtpie_gettv4(union gtpie_member* ie[], int type, int instance, - uint32_t *dst); -extern int gtpie_gettv8(union gtpie_member* ie[], int type, int instance, - uint64_t *dst); - -extern int gtpie_decaps(union gtpie_member* ie[], int version, +extern int gtpie_gettv1(union gtpie_member *ie[], int type, int instance, + uint8_t * dst); +extern int gtpie_gettv2(union gtpie_member *ie[], int type, int instance, + uint16_t * dst); +extern int gtpie_gettv4(union gtpie_member *ie[], int type, int instance, + uint32_t * dst); +extern int gtpie_gettv8(union gtpie_member *ie[], int type, int instance, + uint64_t * dst); + +extern int gtpie_decaps(union gtpie_member *ie[], int version, void *pack, unsigned len); -extern int gtpie_encaps(union gtpie_member* ie[], void *pack, unsigned *len); +extern int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len); extern int gtpie_encaps2(union gtpie_member ie[], unsigned int size, - void *pack, unsigned *len); - - -#endif /* !_GTPIE_H */ - + void *pack, unsigned *len); +#endif /* !_GTPIE_H */ diff --git a/gtp/lookupa.c b/gtp/lookupa.c index 8ff114b..1eff74a 100644 --- a/gtp/lookupa.c +++ b/gtp/lookupa.c @@ -81,52 +81,64 @@ acceptable. Do NOT use for cryptographic purposes. -------------------------------------------------------------------- */ -ub4 lookup( k, length, level) -register ub1 *k; /* the key */ -register ub4 length; /* the length of the key */ -register ub4 level; /* the previous hash, or an arbitrary value */ +ub4 lookup(k, length, level) +register ub1 *k; /* the key */ +register ub4 length; /* the length of the key */ +register ub4 level; /* the previous hash, or an arbitrary value */ { - register ub4 a,b,c,len; + register ub4 a, b, c, len; - /* Set up the internal state */ - len = length; - a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ - c = level; /* the previous hash value */ + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = level; /* the previous hash value */ /*---------------------------------------- handle most of the key */ - while (len >= 12) - { - a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); - b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); - c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); - mix(a,b,c); - k += 12; len -= 12; - } + while (len >= 12) { + a += (k[0] + ((ub4) k[1] << 8) + ((ub4) k[2] << 16) + + ((ub4) k[3] << 24)); + b += (k[4] + ((ub4) k[5] << 8) + ((ub4) k[6] << 16) + + ((ub4) k[7] << 24)); + c += (k[8] + ((ub4) k[9] << 8) + ((ub4) k[10] << 16) + + ((ub4) k[11] << 24)); + mix(a, b, c); + k += 12; + len -= 12; + } /*------------------------------------- handle the last 11 bytes */ - c += length; - switch(len) /* all the case statements fall through */ - { - case 11: c+=((ub4)k[10]<<24); - case 10: c+=((ub4)k[9]<<16); - case 9 : c+=((ub4)k[8]<<8); - /* the first byte of c is reserved for the length */ - case 8 : b+=((ub4)k[7]<<24); - case 7 : b+=((ub4)k[6]<<16); - case 6 : b+=((ub4)k[5]<<8); - case 5 : b+=k[4]; - case 4 : a+=((ub4)k[3]<<24); - case 3 : a+=((ub4)k[2]<<16); - case 2 : a+=((ub4)k[1]<<8); - case 1 : a+=k[0]; - /* case 0: nothing left to add */ - } - mix(a,b,c); + c += length; + switch (len) { /* all the case statements fall through */ + case 11: + c += ((ub4) k[10] << 24); + case 10: + c += ((ub4) k[9] << 16); + case 9: + c += ((ub4) k[8] << 8); + /* the first byte of c is reserved for the length */ + case 8: + b += ((ub4) k[7] << 24); + case 7: + b += ((ub4) k[6] << 16); + case 6: + b += ((ub4) k[5] << 8); + case 5: + b += k[4]; + case 4: + a += ((ub4) k[3] << 24); + case 3: + a += ((ub4) k[2] << 16); + case 2: + a += ((ub4) k[1] << 8); + case 1: + a += k[0]; + /* case 0: nothing left to add */ + } + mix(a, b, c); /*-------------------------------------------- report the result */ - return c; + return c; } - /* -------------------------------------------------------------------- mixc -- mixc 8 4-bit values as quickly and thoroughly as possible. @@ -169,78 +181,120 @@ Use to detect changes between revisions of documents, assuming nobody is trying to cause collisions. Do NOT use for cryptography. -------------------------------------------------------------------- */ -void checksum( k, len, state) +void checksum(k, len, state) register ub1 *k; -register ub4 len; +register ub4 len; register ub4 *state; { - register ub4 a,b,c,d,e,f,g,h,length; + register ub4 a, b, c, d, e, f, g, h, length; - /* Use the length and level; add in the golden ratio. */ - length = len; - a=state[0]; b=state[1]; c=state[2]; d=state[3]; - e=state[4]; f=state[5]; g=state[6]; h=state[7]; + /* Use the length and level; add in the golden ratio. */ + length = len; + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; /*---------------------------------------- handle most of the key */ - while (len >= 32) - { - a += (k[0] +(k[1]<<8) +(k[2]<<16) +(k[3]<<24)); - b += (k[4] +(k[5]<<8) +(k[6]<<16) +(k[7]<<24)); - c += (k[8] +(k[9]<<8) +(k[10]<<16)+(k[11]<<24)); - d += (k[12]+(k[13]<<8)+(k[14]<<16)+(k[15]<<24)); - e += (k[16]+(k[17]<<8)+(k[18]<<16)+(k[19]<<24)); - f += (k[20]+(k[21]<<8)+(k[22]<<16)+(k[23]<<24)); - g += (k[24]+(k[25]<<8)+(k[26]<<16)+(k[27]<<24)); - h += (k[28]+(k[29]<<8)+(k[30]<<16)+(k[31]<<24)); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - k += 32; len -= 32; - } + while (len >= 32) { + a += (k[0] + (k[1] << 8) + (k[2] << 16) + (k[3] << 24)); + b += (k[4] + (k[5] << 8) + (k[6] << 16) + (k[7] << 24)); + c += (k[8] + (k[9] << 8) + (k[10] << 16) + (k[11] << 24)); + d += (k[12] + (k[13] << 8) + (k[14] << 16) + (k[15] << 24)); + e += (k[16] + (k[17] << 8) + (k[18] << 16) + (k[19] << 24)); + f += (k[20] + (k[21] << 8) + (k[22] << 16) + (k[23] << 24)); + g += (k[24] + (k[25] << 8) + (k[26] << 16) + (k[27] << 24)); + h += (k[28] + (k[29] << 8) + (k[30] << 16) + (k[31] << 24)); + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); + k += 32; + len -= 32; + } /*------------------------------------- handle the last 31 bytes */ - h += length; - switch(len) - { - case 31: h+=(k[30]<<24); - case 30: h+=(k[29]<<16); - case 29: h+=(k[28]<<8); - case 28: g+=(k[27]<<24); - case 27: g+=(k[26]<<16); - case 26: g+=(k[25]<<8); - case 25: g+=k[24]; - case 24: f+=(k[23]<<24); - case 23: f+=(k[22]<<16); - case 22: f+=(k[21]<<8); - case 21: f+=k[20]; - case 20: e+=(k[19]<<24); - case 19: e+=(k[18]<<16); - case 18: e+=(k[17]<<8); - case 17: e+=k[16]; - case 16: d+=(k[15]<<24); - case 15: d+=(k[14]<<16); - case 14: d+=(k[13]<<8); - case 13: d+=k[12]; - case 12: c+=(k[11]<<24); - case 11: c+=(k[10]<<16); - case 10: c+=(k[9]<<8); - case 9 : c+=k[8]; - case 8 : b+=(k[7]<<24); - case 7 : b+=(k[6]<<16); - case 6 : b+=(k[5]<<8); - case 5 : b+=k[4]; - case 4 : a+=(k[3]<<24); - case 3 : a+=(k[2]<<16); - case 2 : a+=(k[1]<<8); - case 1 : a+=k[0]; - } - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); - mixc(a,b,c,d,e,f,g,h); + h += length; + switch (len) { + case 31: + h += (k[30] << 24); + case 30: + h += (k[29] << 16); + case 29: + h += (k[28] << 8); + case 28: + g += (k[27] << 24); + case 27: + g += (k[26] << 16); + case 26: + g += (k[25] << 8); + case 25: + g += k[24]; + case 24: + f += (k[23] << 24); + case 23: + f += (k[22] << 16); + case 22: + f += (k[21] << 8); + case 21: + f += k[20]; + case 20: + e += (k[19] << 24); + case 19: + e += (k[18] << 16); + case 18: + e += (k[17] << 8); + case 17: + e += k[16]; + case 16: + d += (k[15] << 24); + case 15: + d += (k[14] << 16); + case 14: + d += (k[13] << 8); + case 13: + d += k[12]; + case 12: + c += (k[11] << 24); + case 11: + c += (k[10] << 16); + case 10: + c += (k[9] << 8); + case 9: + c += k[8]; + case 8: + b += (k[7] << 24); + case 7: + b += (k[6] << 16); + case 6: + b += (k[5] << 8); + case 5: + b += k[4]; + case 4: + a += (k[3] << 24); + case 3: + a += (k[2] << 16); + case 2: + a += (k[1] << 8); + case 1: + a += k[0]; + } + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); + mixc(a, b, c, d, e, f, g, h); /*-------------------------------------------- report the result */ - state[0]=a; state[1]=b; state[2]=c; state[3]=d; - state[4]=e; state[5]=f; state[6]=g; state[7]=h; + state[0] = a; + state[1] = b; + state[2] = c; + state[3] = d; + state[4] = e; + state[5] = f; + state[6] = g; + state[7] = h; } diff --git a/gtp/lookupa.h b/gtp/lookupa.h index 16784a9..a733509 100644 --- a/gtp/lookupa.h +++ b/gtp/lookupa.h @@ -16,14 +16,14 @@ Source is http://burtleburtle.net/bob/c/lookupa.h #ifndef LOOKUPA #define LOOKUPA -typedef unsigned long int ub4; /* unsigned 4-byte quantities */ -typedef unsigned char ub1; +typedef unsigned long int ub4; /* unsigned 4-byte quantities */ +typedef unsigned char ub1; #define CHECKSTATE 8 #define hashsize(n) ((ub4)1<<(n)) #define hashmask(n) (hashsize(n)-1) -ub4 lookup(/*_ ub1 *k, ub4 length, ub4 level _*/); -void checksum(/*_ ub1 *k, ub4 length, ub4 *state _*/); +ub4 lookup( /*_ ub1 *k, ub4 length, ub4 level _*/ ); +void checksum( /*_ ub1 *k, ub4 length, ub4 *state _*/ ); #endif /* LOOKUPA */ diff --git a/gtp/pdp.c b/gtp/pdp.c index 648d70d..7ce9128 100644 --- a/gtp/pdp.c +++ b/gtp/pdp.c @@ -31,8 +31,8 @@ * Global variables TODO: most should be moved to gsn_t *************************************************************/ -struct pdp_t pdpa[PDP_MAX]; /* PDP storage */ -struct pdp_t* hashtid[PDP_MAX];/* Hash table for IMSI + NSAPI */ +struct pdp_t pdpa[PDP_MAX]; /* PDP storage */ +struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */ /* struct pdp_t* haship[PDP_MAX]; Hash table for IP and network interface */ /* *********************************************************** @@ -107,144 +107,171 @@ struct pdp_t* hashtid[PDP_MAX];/* Hash table for IMSI + NSAPI */ * *************************************************************/ -int pdp_init() { - memset(&pdpa, 0, sizeof(pdpa)); - memset(&hashtid, 0, sizeof(hashtid)); - /* memset(&haship, 0, sizeof(haship)); */ +int pdp_init() +{ + memset(&pdpa, 0, sizeof(pdpa)); + memset(&hashtid, 0, sizeof(hashtid)); + /* memset(&haship, 0, sizeof(haship)); */ - return 0; + return 0; } -int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi, - struct pdp_t *pdp_old){ - int n; - for (n=0; ninuse = 1; - (*pdp)->imsi = imsi; - (*pdp)->nsapi = nsapi; - (*pdp)->fllc = (uint16_t) n + 1; - (*pdp)->fllu = (uint16_t) n + 1; - (*pdp)->teid_own = (uint32_t) n + 1; - if (!(*pdp)->secondary) (*pdp)->teic_own = (uint32_t) n + 1; - pdp_tidset(*pdp, pdp_gettid(imsi, nsapi)); - - /* Insert reference in primary context */ - if (((*pdp)->teic_own > 0 ) && ((*pdp)->teic_own <= PDP_MAX)) { - pdpa[(*pdp)->teic_own-1].secondary_tei[(*pdp)->nsapi & 0x0f] = - (*pdp)->teid_own; - } - - return 0; - } - } - return EOF; /* No more available */ +int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi, + struct pdp_t *pdp_old) +{ + int n; + for (n = 0; n < PDP_MAX; n++) { /* TODO: Need to do better than linear search */ + if (pdpa[n].inuse == 0) { + *pdp = &pdpa[n]; + if (NULL != pdp_old) + memcpy(*pdp, pdp_old, sizeof(struct pdp_t)); + else + memset(*pdp, 0, sizeof(struct pdp_t)); + (*pdp)->inuse = 1; + (*pdp)->imsi = imsi; + (*pdp)->nsapi = nsapi; + (*pdp)->fllc = (uint16_t) n + 1; + (*pdp)->fllu = (uint16_t) n + 1; + (*pdp)->teid_own = (uint32_t) n + 1; + if (!(*pdp)->secondary) + (*pdp)->teic_own = (uint32_t) n + 1; + pdp_tidset(*pdp, pdp_gettid(imsi, nsapi)); + + /* Insert reference in primary context */ + if (((*pdp)->teic_own > 0) + && ((*pdp)->teic_own <= PDP_MAX)) { + pdpa[(*pdp)->teic_own - + 1].secondary_tei[(*pdp)->nsapi & 0x0f] = + (*pdp)->teid_own; + } + + return 0; + } + } + return EOF; /* No more available */ } -int pdp_freepdp(struct pdp_t *pdp){ - pdp_tiddel(pdp); +int pdp_freepdp(struct pdp_t *pdp) +{ + pdp_tiddel(pdp); - /* Remove any references in primary context */ - if ((pdp->secondary) && (pdp->teic_own > 0 ) && (pdp->teic_own <= PDP_MAX)) { - pdpa[pdp->teic_own-1].secondary_tei[pdp->nsapi & 0x0f] = 0; - } + /* Remove any references in primary context */ + if ((pdp->secondary) && (pdp->teic_own > 0) + && (pdp->teic_own <= PDP_MAX)) { + pdpa[pdp->teic_own - 1].secondary_tei[pdp->nsapi & 0x0f] = 0; + } - memset(pdp, 0, sizeof(struct pdp_t)); - return 0; + memset(pdp, 0, sizeof(struct pdp_t)); + return 0; } -int pdp_getpdp(struct pdp_t **pdp){ - *pdp = &pdpa[0]; - return 0; +int pdp_getpdp(struct pdp_t **pdp) +{ + *pdp = &pdpa[0]; + return 0; } -int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl){ - if ((fl>PDP_MAX) || (fl<1)) { - return EOF; /* Not found */ - } - else { - *pdp = &pdpa[fl-1]; - if ((*pdp)->inuse) return 0; - else return EOF; - /* Context exists. We do no further validity checking. */ - } +int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl) +{ + if ((fl > PDP_MAX) || (fl < 1)) { + return EOF; /* Not found */ + } else { + *pdp = &pdpa[fl - 1]; + if ((*pdp)->inuse) + return 0; + else + return EOF; + /* Context exists. We do no further validity checking. */ + } } -int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei){ - if ((tei>PDP_MAX) || (tei<1)) { - return EOF; /* Not found */ - } - else { - *pdp = &pdpa[tei-1]; - if ((*pdp)->inuse) return 0; - else return EOF; - /* Context exists. We do no further validity checking. */ - } +int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei) +{ + if ((tei > PDP_MAX) || (tei < 1)) { + return EOF; /* Not found */ + } else { + *pdp = &pdpa[tei - 1]; + if ((*pdp)->inuse) + return 0; + else + return EOF; + /* Context exists. We do no further validity checking. */ + } } - -int pdp_tidhash(uint64_t tid) { - return (lookup(&tid, sizeof(tid), 0) % PDP_MAX); +int pdp_tidhash(uint64_t tid) +{ + return (lookup(&tid, sizeof(tid), 0) % PDP_MAX); } -int pdp_tidset(struct pdp_t *pdp, uint64_t tid) { - int hash = pdp_tidhash(tid); - struct pdp_t *pdp2; - struct pdp_t *pdp_prev = NULL; - if (PDP_DEBUG) printf("Begin pdp_tidset tid = %llx\n", tid); - pdp->tidnext = NULL; - pdp->tid = tid; - for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) - pdp_prev = pdp2; - if (!pdp_prev) - hashtid[hash] = pdp; - else - pdp_prev->tidnext = pdp; - if (PDP_DEBUG) printf("End pdp_tidset\n"); - return 0; +int pdp_tidset(struct pdp_t *pdp, uint64_t tid) +{ + int hash = pdp_tidhash(tid); + struct pdp_t *pdp2; + struct pdp_t *pdp_prev = NULL; + if (PDP_DEBUG) + printf("Begin pdp_tidset tid = %llx\n", tid); + pdp->tidnext = NULL; + pdp->tid = tid; + for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) + pdp_prev = pdp2; + if (!pdp_prev) + hashtid[hash] = pdp; + else + pdp_prev->tidnext = pdp; + if (PDP_DEBUG) + printf("End pdp_tidset\n"); + return 0; } -int pdp_tiddel(struct pdp_t *pdp) { - int hash = pdp_tidhash(pdp->tid); - struct pdp_t *pdp2; - struct pdp_t *pdp_prev = NULL; - if (PDP_DEBUG) printf("Begin pdp_tiddel tid = %llx\n", pdp->tid); - for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) { - if (pdp2 == pdp) { - if (!pdp_prev) - hashtid[hash] = pdp2->tidnext; - else - pdp_prev->tidnext = pdp2->tidnext; - if (PDP_DEBUG) printf("End pdp_tiddel: PDP found\n"); - return 0; - } - pdp_prev = pdp2; - } - if (PDP_DEBUG) printf("End pdp_tiddel: PDP not found\n"); - return EOF; /* End of linked list and not found */ +int pdp_tiddel(struct pdp_t *pdp) +{ + int hash = pdp_tidhash(pdp->tid); + struct pdp_t *pdp2; + struct pdp_t *pdp_prev = NULL; + if (PDP_DEBUG) + printf("Begin pdp_tiddel tid = %llx\n", pdp->tid); + for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) { + if (pdp2 == pdp) { + if (!pdp_prev) + hashtid[hash] = pdp2->tidnext; + else + pdp_prev->tidnext = pdp2->tidnext; + if (PDP_DEBUG) + printf("End pdp_tiddel: PDP found\n"); + return 0; + } + pdp_prev = pdp2; + } + if (PDP_DEBUG) + printf("End pdp_tiddel: PDP not found\n"); + return EOF; /* End of linked list and not found */ } -int pdp_tidget(struct pdp_t **pdp, uint64_t tid) { - int hash = pdp_tidhash(tid); - struct pdp_t *pdp2; - if (PDP_DEBUG) printf("Begin pdp_tidget tid = %llx\n", tid); - for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) { - if (pdp2->tid == tid) { - *pdp = pdp2; - if (PDP_DEBUG) printf("Begin pdp_tidget. Found\n"); - return 0; - } - } - if (PDP_DEBUG) printf("Begin pdp_tidget. Not found\n"); - return EOF; /* End of linked list and not found */ +int pdp_tidget(struct pdp_t **pdp, uint64_t tid) +{ + int hash = pdp_tidhash(tid); + struct pdp_t *pdp2; + if (PDP_DEBUG) + printf("Begin pdp_tidget tid = %llx\n", tid); + for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) { + if (pdp2->tid == tid) { + *pdp = pdp2; + if (PDP_DEBUG) + printf("Begin pdp_tidget. Found\n"); + return 0; + } + } + if (PDP_DEBUG) + printf("Begin pdp_tidget. Not found\n"); + return EOF; /* End of linked list and not found */ } -int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi) { - return pdp_tidget(pdp, - (imsi & 0x0fffffffffffffffull) + ((uint64_t)nsapi << 60)); +int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi) +{ + return pdp_tidget(pdp, + (imsi & 0x0fffffffffffffffull) + + ((uint64_t) nsapi << 60)); } /* @@ -320,32 +347,36 @@ int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) { */ /* Various conversion functions */ -int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua) { - eua->l=6; - eua->v[0]=0xf1; /* IETF */ - eua->v[1]=0x21; /* IPv4 */ - memcpy(&eua->v[2], src, 4); /* Copy a 4 byte address */ - return 0; +int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua) +{ + eua->l = 6; + eua->v[0] = 0xf1; /* IETF */ + eua->v[1] = 0x21; /* IPv4 */ + memcpy(&eua->v[2], src, 4); /* Copy a 4 byte address */ + return 0; } -int pdp_euaton(struct ul66_t *eua, struct in_addr *dst) { - if((eua->l!=6) || (eua->v[0]!=0xf1) || (eua->v[1]!=0x21)) { - return EOF; - } - memcpy(dst, &eua->v[2], 4); /* Copy a 4 byte address */ - return 0; +int pdp_euaton(struct ul66_t *eua, struct in_addr *dst) +{ + if ((eua->l != 6) || (eua->v[0] != 0xf1) || (eua->v[1] != 0x21)) { + return EOF; + } + memcpy(dst, &eua->v[2], 4); /* Copy a 4 byte address */ + return 0; } -uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi) { - return (imsi & 0x0fffffffffffffffull) + ((uint64_t)nsapi << 60); +uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi) +{ + return (imsi & 0x0fffffffffffffffull) + ((uint64_t) nsapi << 60); } -int ulcpy(void* dst, void* src, size_t size) { - if (((struct ul255_t*)src)->l <= size) { - ((struct ul255_t*)dst)->l = ((struct ul255_t*)src)->l; - memcpy(((struct ul255_t*)dst)->v, ((struct ul255_t*)src)->v, - ((struct ul255_t*)dst)->l); - return 0; - } - else return EOF; +int ulcpy(void *dst, void *src, size_t size) +{ + if (((struct ul255_t *)src)->l <= size) { + ((struct ul255_t *)dst)->l = ((struct ul255_t *)src)->l; + memcpy(((struct ul255_t *)dst)->v, ((struct ul255_t *)src)->v, + ((struct ul255_t *)dst)->l); + return 0; + } else + return EOF; } diff --git a/gtp/pdp.h b/gtp/pdp.h index e3bd06d..b069a6f 100644 --- a/gtp/pdp.h +++ b/gtp/pdp.h @@ -12,42 +12,40 @@ #ifndef _PDP_H #define _PDP_H -#define PDP_MAX 1024 /* Max number of PDP contexts */ -#define PDP_MAXNSAPI 16 /* Max number of NSAPI */ +#define PDP_MAX 1024 /* Max number of PDP contexts */ +#define PDP_MAXNSAPI 16 /* Max number of NSAPI */ -#define PDP_DEBUG 0 /* Print debug information */ +#define PDP_DEBUG 0 /* Print debug information */ /* GTP Information elements from 29.060 v3.9.0 7.7 Information Elements */ /* Also covers version 0. Note that version 0 6: QOS Profile was superceded * * by 135: QOS Profile in version 1 */ - struct sl_t { -unsigned int l; -char *v; + unsigned int l; + char *v; }; struct ul_t { -unsigned int l; -unsigned char *v; + unsigned int l; + unsigned char *v; }; struct ul16_t { -unsigned int l; -unsigned char v[16]; + unsigned int l; + unsigned char v[16]; }; struct ul66_t { -unsigned int l; -unsigned char v[66]; + unsigned int l; + unsigned char v[66]; }; struct ul255_t { -unsigned int l; -unsigned char v[255]; + unsigned int l; + unsigned char v[255]; }; - /* ***************************************************************** * Information storage for each PDP context * @@ -103,131 +101,130 @@ unsigned char v[255]; *****************************************************************/ struct pdp_t { - /* Parameter determining if this PDP is in use. */ - uint8_t inuse; /* 0=free. 1=used by somebody */ - - /* Pointers related to hash tables */ - struct pdp_t *tidnext; - struct pdp_t *ipnext; - - /* Parameters shared by all PDP context belonging to the same MS */ - - void *ipif; /* IP network interface */ - void *peer; /* Pointer to peer protocol */ - void *asap; /* Application specific service access point */ - - uint64_t imsi; /* International Mobile Subscriber Identity.*/ - struct ul16_t msisdn; /* The basic MSISDN of the MS. */ - uint8_t mnrg; /* Indicates whether the MS is marked as not reachable for PS at the HLR. (1 bit, not transmitted) */ - uint8_t cch_sub; /* The charging characteristics for the MS, e.g. normal, prepaid, flat-rate, and/or hot billing subscription. (not transmitted) */ - uint16_t traceref; /* Identifies a record or a collection of records for a particular trace. */ - uint16_t tracetype;/* Indicates the type of trace. */ - struct ul_t triggerid;/* Identifies the entity that initiated the trace. */ - struct ul_t omcid; /* Identifies the OMC that shall receive the trace record(s). */ - uint8_t rec_hlr; /* Indicates if HLR or VLR is performing database recovery. (1 bit, not transmitted) */ - - /* Parameters specific to each individual PDP context */ - - uint8_t pdp_id; /* Index of the PDP context. (PDP context identifier) */ - uint8_t pdp_state;/* PDP State Packet data protocol state, INACTIVE or ACTIVE. (1 bit, not transmitted) */ - /* struct ul_t pdp_type; * PDP type; e.g. PPP or IP. */ - /* struct ul_t pdp_addr; * PDP address; e.g. an IP address. */ - struct ul66_t eua; /* End user address. PDP type and address combined */ - uint8_t pdp_dyn; /* Indicates whether PDP Address is static or dynamic. (1 bit, not transmitted) */ - struct ul255_t apn_req;/* The APN requested. */ - struct ul255_t apn_sub;/* The APN received from the HLR. */ - struct ul255_t apn_use;/* The APN Network Identifier currently used. */ - uint8_t nsapi; /* Network layer Service Access Point Identifier. (4 bit) */ - uint16_t ti; /* Transaction Identifier. (4 or 12 bit) */ - - uint32_t teic_own; /* (Own Tunnel Endpoint Identifier Control) */ - uint32_t teid_own; /* (Own Tunnel Endpoint Identifier Data I) */ - uint32_t teic_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Control plane) */ - uint32_t teid_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Data I) */ - uint32_t tei_iu; /* Tunnel Endpoint Identifier for the Iu interface. */ - - uint16_t fllc; /* (Local Flow Label Control, gtp0) */ - uint16_t fllu; /* (Local Flow Label Data I, gtp0) */ - uint16_t flrc; /* (Remote gn/gp Flow Label Control, gtp0) */ - uint16_t flru; /* (Remote gn/gp Flow Label Data I, gtp0) */ - - struct ul255_t tft; /* Traffic flow template. */ - /*struct ul16_t sgsnc; * The IP address of the SGSN currently serving this MS. (Control plane) */ - /*struct ul16_t sgsnu; * The IP address of the SGSN currently serving this MS. (User plane) */ - /*struct ul16_t ggsnc; * The IP address of the GGSN currently used. (Control plane) */ - /*struct ul16_t ggsnu; * The IP address of the GGSN currently used. (User plane) */ - - struct ul16_t gsnlc; /* The IP address of the local GSN. (Control plane) */ - struct ul16_t gsnlu; /* The IP address of the local GSN. (User plane) */ - struct ul16_t gsnrc; /* The IP address of the remote GSN. (Control plane) */ - struct ul16_t gsnru; /* The IP address of the remote GSN. (User plane) */ - - uint8_t vplmn_allow; /* Specifies whether the MS is allowed to use the APN in the domain of the HPLMN only, or additionally the APN in the domain of the VPLMN. (1 bit) */ - uint8_t qos_sub0[3]; /* The quality of service profile subscribed. */ - uint8_t qos_req0[3]; /* The quality of service profile requested. */ - uint8_t qos_neg0[3]; /* The quality of service profile negotiated. */ - struct ul255_t qos_sub; /* The quality of service profile subscribed. */ - struct ul255_t qos_req; /* The quality of service profile requested. */ - struct ul255_t qos_neg; /* The quality of service profile negotiated. */ - uint8_t radio_pri;/* The RLC/MAC radio priority level for uplink user data transmission. (4 bit) */ - uint16_t flow_id; /* Packet flow identifier. */ - /* struct ul_t bssqos_neg; * The aggregate BSS quality of service profile negotiated for the packet flow that this PDP context belongs to. (NOT GTP)*/ - uint8_t sndcpd; /* SNDCP sequence number of the next downlink N-PDU to be sent to the MS. */ - uint8_t sndcpu; /* SNDCP sequence number of the next uplink N-PDU expected from the MS. */ - uint8_t rec_sgsn; /* Indicates if the SGSN is performing database recovery. (1 bit, not transmitted) */ + /* Parameter determining if this PDP is in use. */ + uint8_t inuse; /* 0=free. 1=used by somebody */ + + /* Pointers related to hash tables */ + struct pdp_t *tidnext; + struct pdp_t *ipnext; + + /* Parameters shared by all PDP context belonging to the same MS */ + + void *ipif; /* IP network interface */ + void *peer; /* Pointer to peer protocol */ + void *asap; /* Application specific service access point */ + + uint64_t imsi; /* International Mobile Subscriber Identity. */ + struct ul16_t msisdn; /* The basic MSISDN of the MS. */ + uint8_t mnrg; /* Indicates whether the MS is marked as not reachable for PS at the HLR. (1 bit, not transmitted) */ + uint8_t cch_sub; /* The charging characteristics for the MS, e.g. normal, prepaid, flat-rate, and/or hot billing subscription. (not transmitted) */ + uint16_t traceref; /* Identifies a record or a collection of records for a particular trace. */ + uint16_t tracetype; /* Indicates the type of trace. */ + struct ul_t triggerid; /* Identifies the entity that initiated the trace. */ + struct ul_t omcid; /* Identifies the OMC that shall receive the trace record(s). */ + uint8_t rec_hlr; /* Indicates if HLR or VLR is performing database recovery. (1 bit, not transmitted) */ + + /* Parameters specific to each individual PDP context */ + + uint8_t pdp_id; /* Index of the PDP context. (PDP context identifier) */ + uint8_t pdp_state; /* PDP State Packet data protocol state, INACTIVE or ACTIVE. (1 bit, not transmitted) */ + /* struct ul_t pdp_type; * PDP type; e.g. PPP or IP. */ + /* struct ul_t pdp_addr; * PDP address; e.g. an IP address. */ + struct ul66_t eua; /* End user address. PDP type and address combined */ + uint8_t pdp_dyn; /* Indicates whether PDP Address is static or dynamic. (1 bit, not transmitted) */ + struct ul255_t apn_req; /* The APN requested. */ + struct ul255_t apn_sub; /* The APN received from the HLR. */ + struct ul255_t apn_use; /* The APN Network Identifier currently used. */ + uint8_t nsapi; /* Network layer Service Access Point Identifier. (4 bit) */ + uint16_t ti; /* Transaction Identifier. (4 or 12 bit) */ + + uint32_t teic_own; /* (Own Tunnel Endpoint Identifier Control) */ + uint32_t teid_own; /* (Own Tunnel Endpoint Identifier Data I) */ + uint32_t teic_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Control plane) */ + uint32_t teid_gn; /* Tunnel Endpoint Identifier for the Gn and Gp interfaces. (Data I) */ + uint32_t tei_iu; /* Tunnel Endpoint Identifier for the Iu interface. */ + + uint16_t fllc; /* (Local Flow Label Control, gtp0) */ + uint16_t fllu; /* (Local Flow Label Data I, gtp0) */ + uint16_t flrc; /* (Remote gn/gp Flow Label Control, gtp0) */ + uint16_t flru; /* (Remote gn/gp Flow Label Data I, gtp0) */ + + struct ul255_t tft; /* Traffic flow template. */ + /*struct ul16_t sgsnc; * The IP address of the SGSN currently serving this MS. (Control plane) */ + /*struct ul16_t sgsnu; * The IP address of the SGSN currently serving this MS. (User plane) */ + /*struct ul16_t ggsnc; * The IP address of the GGSN currently used. (Control plane) */ + /*struct ul16_t ggsnu; * The IP address of the GGSN currently used. (User plane) */ + + struct ul16_t gsnlc; /* The IP address of the local GSN. (Control plane) */ + struct ul16_t gsnlu; /* The IP address of the local GSN. (User plane) */ + struct ul16_t gsnrc; /* The IP address of the remote GSN. (Control plane) */ + struct ul16_t gsnru; /* The IP address of the remote GSN. (User plane) */ + + uint8_t vplmn_allow; /* Specifies whether the MS is allowed to use the APN in the domain of the HPLMN only, or additionally the APN in the domain of the VPLMN. (1 bit) */ + uint8_t qos_sub0[3]; /* The quality of service profile subscribed. */ + uint8_t qos_req0[3]; /* The quality of service profile requested. */ + uint8_t qos_neg0[3]; /* The quality of service profile negotiated. */ + struct ul255_t qos_sub; /* The quality of service profile subscribed. */ + struct ul255_t qos_req; /* The quality of service profile requested. */ + struct ul255_t qos_neg; /* The quality of service profile negotiated. */ + uint8_t radio_pri; /* The RLC/MAC radio priority level for uplink user data transmission. (4 bit) */ + uint16_t flow_id; /* Packet flow identifier. */ + /* struct ul_t bssqos_neg; * The aggregate BSS quality of service profile negotiated for the packet flow that this PDP context belongs to. (NOT GTP) */ + uint8_t sndcpd; /* SNDCP sequence number of the next downlink N-PDU to be sent to the MS. */ + uint8_t sndcpu; /* SNDCP sequence number of the next uplink N-PDU expected from the MS. */ + uint8_t rec_sgsn; /* Indicates if the SGSN is performing database recovery. (1 bit, not transmitted) */ /* uint16_t gtpsnd; GTP-U sequence number of the next downlink N-PDU to be sent to the SGSN / received from the GGSN. */ /* uint16_t gtpsnu; GTP-U sequence number of the next uplink N-PDU to be received from the SGSN / sent to the GGSN */ - uint16_t gtpsntx; /* GTP-U sequence number of the next downlink N-PDU to be sent (09.60 section 8.1.1.1) */ - uint16_t gtpsnrx; /* GTP-U sequence number of the next uplink N-PDU to be received (09.60 section 8.1.1.1) */ - uint8_t pdcpsndd; /* Sequence number of the next downlink in-sequence PDCP-PDU to be sent to the MS. */ - uint8_t pdcpsndu; /* Sequence number of the next uplink in-sequence PDCP-PDU expected from the MS. */ - uint32_t cid; /* Charging identifier, identifies charging records generated by SGSN and GGSN. */ - uint16_t cch_pdp; /* The charging characteristics for this PDP context, e.g. normal, prepaid, flat-rate, and/or hot billing. */ - struct ul16_t rnc_addr;/* The IP address of the RNC currently used. */ - uint8_t reorder; /* Specifies whether the GGSN shall reorder N-PDUs received from the SGSN / Specifies whether the SGSN shall reorder N-PDUs before delivering the N-PSUs to the MS. (1 bit) */ - struct ul255_t pco_req; /* Requested packet control options. */ - struct ul255_t pco_neg; /* Negotiated packet control options. */ - uint32_t selmode; /* Selection mode. */ - struct ul255_t rattype; /* Radio Access Technology Type */ - int rattype_given; /* Radio Access Technology Type given*/ - struct ul255_t userloc; /* User Location Information */ - int userloc_given; /* User Location Information given*/ - struct ul255_t rai; /* Routing Area Information */ - int rai_given; /* Routing Area Information given*/ - struct ul255_t mstz; /* MS Time Zone */ - int mstz_given; /* MS Time Zone given*/ - struct ul255_t imeisv; /* IMEI Software Version */ - int imeisv_given; /* IMEI Software Version given*/ - int norecovery_given; /* norecovery given*/ - - /* Additional parameters used by library */ - - int version; /* Protocol version currently in use. 0 or 1 */ - - uint64_t tid; /* Combination of imsi and nsapi */ - uint16_t seq; /* Sequence number of last request */ - struct sockaddr_in sa_peer; /* Address of last request */ - int fd; /* File descriptor request was received on */ - - uint8_t teic_confirmed; /* 0: Not confirmed. 1: Confirmed */ - - /* Parameters used for secondary activation procedure (tei data) */ - /* If (secondary == 1) then teic_own indicates linked PDP context */ - uint8_t secondary; /* 0: Primary (control). 1: Secondary (data only) */ - uint8_t nodata; /* 0: User plane PDP context. 1: No user plane */ - - /* Secondary contexts of this primary context */ - uint32_t secondary_tei[PDP_MAXNSAPI]; - - /* IP address used for Create and Update PDP Context Requests */ - struct in_addr hisaddr0; /* Server address */ - struct in_addr hisaddr1; /* Server address */ - - /* to be used by libgtp callers/users (to attach their own private state) */ - void *priv; + uint16_t gtpsntx; /* GTP-U sequence number of the next downlink N-PDU to be sent (09.60 section 8.1.1.1) */ + uint16_t gtpsnrx; /* GTP-U sequence number of the next uplink N-PDU to be received (09.60 section 8.1.1.1) */ + uint8_t pdcpsndd; /* Sequence number of the next downlink in-sequence PDCP-PDU to be sent to the MS. */ + uint8_t pdcpsndu; /* Sequence number of the next uplink in-sequence PDCP-PDU expected from the MS. */ + uint32_t cid; /* Charging identifier, identifies charging records generated by SGSN and GGSN. */ + uint16_t cch_pdp; /* The charging characteristics for this PDP context, e.g. normal, prepaid, flat-rate, and/or hot billing. */ + struct ul16_t rnc_addr; /* The IP address of the RNC currently used. */ + uint8_t reorder; /* Specifies whether the GGSN shall reorder N-PDUs received from the SGSN / Specifies whether the SGSN shall reorder N-PDUs before delivering the N-PSUs to the MS. (1 bit) */ + struct ul255_t pco_req; /* Requested packet control options. */ + struct ul255_t pco_neg; /* Negotiated packet control options. */ + uint32_t selmode; /* Selection mode. */ + struct ul255_t rattype; /* Radio Access Technology Type */ + int rattype_given; /* Radio Access Technology Type given */ + struct ul255_t userloc; /* User Location Information */ + int userloc_given; /* User Location Information given */ + struct ul255_t rai; /* Routing Area Information */ + int rai_given; /* Routing Area Information given */ + struct ul255_t mstz; /* MS Time Zone */ + int mstz_given; /* MS Time Zone given */ + struct ul255_t imeisv; /* IMEI Software Version */ + int imeisv_given; /* IMEI Software Version given */ + int norecovery_given; /* norecovery given */ + + /* Additional parameters used by library */ + + int version; /* Protocol version currently in use. 0 or 1 */ + + uint64_t tid; /* Combination of imsi and nsapi */ + uint16_t seq; /* Sequence number of last request */ + struct sockaddr_in sa_peer; /* Address of last request */ + int fd; /* File descriptor request was received on */ + + uint8_t teic_confirmed; /* 0: Not confirmed. 1: Confirmed */ + + /* Parameters used for secondary activation procedure (tei data) */ + /* If (secondary == 1) then teic_own indicates linked PDP context */ + uint8_t secondary; /* 0: Primary (control). 1: Secondary (data only) */ + uint8_t nodata; /* 0: User plane PDP context. 1: No user plane */ + + /* Secondary contexts of this primary context */ + uint32_t secondary_tei[PDP_MAXNSAPI]; + + /* IP address used for Create and Update PDP Context Requests */ + struct in_addr hisaddr0; /* Server address */ + struct in_addr hisaddr1; /* Server address */ + + /* to be used by libgtp callers/users (to attach their own private state) */ + void *priv; }; - /* functions related to pdp_t management */ int pdp_init(); int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi, @@ -245,7 +242,6 @@ int pdp_tidset(struct pdp_t *pdp, uint64_t tid); int pdp_tiddel(struct pdp_t *pdp); int pdp_tidget(struct pdp_t **pdp, uint64_t tid); - /* int pdp_iphash(void* ipif, struct ul66_t *eua); int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua); @@ -256,6 +252,6 @@ int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua); int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua); int pdp_euaton(struct ul66_t *eua, struct in_addr *dst); uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi); -int ulcpy(void* dst, void* src, size_t size); +int ulcpy(void *dst, void *src, size_t size); -#endif /* !_PDP_H */ +#endif /* !_PDP_H */ diff --git a/gtp/queue.c b/gtp/queue.c index 7fdf9df..02c18ec 100644 --- a/gtp/queue.c +++ b/gtp/queue.c @@ -29,224 +29,260 @@ #include "gtp.h" #include "queue.h" -int queue_print(struct queue_t *queue) { - int n; - printf("Queue: %x Next: %d First: %d Last: %d\n", (int) queue, queue->next, queue->first, queue->last); - printf("# State seq next prev timeout retrans\n"); - for (n=0; nqmsga[n].state, - queue->qmsga[n].seq, - queue->qmsga[n].next, - queue->qmsga[n].prev, - (int) queue->qmsga[n].timeout, - queue->qmsga[n].retrans); - } - return 0; +int queue_print(struct queue_t *queue) +{ + int n; + printf("Queue: %x Next: %d First: %d Last: %d\n", (int)queue, + queue->next, queue->first, queue->last); + printf("# State seq next prev timeout retrans\n"); + for (n = 0; n < QUEUE_SIZE; n++) { + printf("%d %d %d %d %d %d %d\n", + n, + queue->qmsga[n].state, + queue->qmsga[n].seq, + queue->qmsga[n].next, + queue->qmsga[n].prev, + (int)queue->qmsga[n].timeout, queue->qmsga[n].retrans); + } + return 0; } -int queue_seqhash(struct sockaddr_in *peer, uint16_t seq) { - /* With QUEUE_HASH_SIZE = 2^16 this describes all possible - seq values. Thus we have perfect hash for the request queue. - For the response queue we might have collisions, but not very - often. - For performance optimisation we should remove the modulus - operator, but this is only valid for QUEUE_HASH_SIZE = 2^16 */ - return seq % QUEUE_HASH_SIZE; +int queue_seqhash(struct sockaddr_in *peer, uint16_t seq) +{ + /* With QUEUE_HASH_SIZE = 2^16 this describes all possible + seq values. Thus we have perfect hash for the request queue. + For the response queue we might have collisions, but not very + often. + For performance optimisation we should remove the modulus + operator, but this is only valid for QUEUE_HASH_SIZE = 2^16 */ + return seq % QUEUE_HASH_SIZE; } int queue_seqset(struct queue_t *queue, struct qmsg_t *qmsg, - struct sockaddr_in *peer, uint16_t seq) { - int hash = queue_seqhash(peer, seq); - struct qmsg_t *qmsg2; - struct qmsg_t *qmsg_prev = NULL; - - if (QUEUE_DEBUG) printf("Begin queue_seqset seq = %d\n", (int) seq); - if (QUEUE_DEBUG) printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer), sizeof(*peer)); - - qmsg->seq = seq; - memcpy(&qmsg->peer, peer, sizeof(*peer)); - - for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) - qmsg_prev = qmsg2; - if (!qmsg_prev) - queue->hashseq[hash] = qmsg; - else - qmsg_prev->seqnext = qmsg; - if (QUEUE_DEBUG) printf("End queue_seqset\n"); - return 0; -} + struct sockaddr_in *peer, uint16_t seq) +{ + int hash = queue_seqhash(peer, seq); + struct qmsg_t *qmsg2; + struct qmsg_t *qmsg_prev = NULL; + + if (QUEUE_DEBUG) + printf("Begin queue_seqset seq = %d\n", (int)seq); + if (QUEUE_DEBUG) + printf("SIZEOF PEER %d, *PEER %d\n", sizeof(peer), + sizeof(*peer)); + qmsg->seq = seq; + memcpy(&qmsg->peer, peer, sizeof(*peer)); -int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg) { - int hash = queue_seqhash(&qmsg->peer, qmsg->seq); - struct qmsg_t *qmsg2; - struct qmsg_t *qmsg_prev = NULL; - if (QUEUE_DEBUG) printf("Begin queue_seqdel seq = %d\n", (int) qmsg->seq); - - for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) { - if (qmsg == qmsg) { - if (!qmsg_prev) - queue->hashseq[hash] = qmsg2->seqnext; - else - qmsg_prev->seqnext = qmsg2->seqnext; - if (QUEUE_DEBUG) printf("End queue_seqset: SEQ found\n"); - return 0; - } - qmsg_prev = qmsg2; - } - printf("End queue_seqset: SEQ not found\n"); - return EOF; /* End of linked list and not found */ + for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) + qmsg_prev = qmsg2; + if (!qmsg_prev) + queue->hashseq[hash] = qmsg; + else + qmsg_prev->seqnext = qmsg; + if (QUEUE_DEBUG) + printf("End queue_seqset\n"); + return 0; } +int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg) +{ + int hash = queue_seqhash(&qmsg->peer, qmsg->seq); + struct qmsg_t *qmsg2; + struct qmsg_t *qmsg_prev = NULL; + if (QUEUE_DEBUG) + printf("Begin queue_seqdel seq = %d\n", (int)qmsg->seq); + + for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) { + if (qmsg == qmsg) { + if (!qmsg_prev) + queue->hashseq[hash] = qmsg2->seqnext; + else + qmsg_prev->seqnext = qmsg2->seqnext; + if (QUEUE_DEBUG) + printf("End queue_seqset: SEQ found\n"); + return 0; + } + qmsg_prev = qmsg2; + } + printf("End queue_seqset: SEQ not found\n"); + return EOF; /* End of linked list and not found */ +} /* Allocates and initialises new queue structure */ -int queue_new(struct queue_t **queue) { - if (QUEUE_DEBUG) printf("queue_new\n"); - *queue = calloc(1, sizeof(struct queue_t)); - (*queue)->next = 0; - (*queue)->first = -1; - (*queue)->last = -1; - - if (QUEUE_DEBUG) queue_print(*queue); - if (*queue) return 0; - else return EOF; +int queue_new(struct queue_t **queue) +{ + if (QUEUE_DEBUG) + printf("queue_new\n"); + *queue = calloc(1, sizeof(struct queue_t)); + (*queue)->next = 0; + (*queue)->first = -1; + (*queue)->last = -1; + + if (QUEUE_DEBUG) + queue_print(*queue); + if (*queue) + return 0; + else + return EOF; } /* Deallocates queue structure */ -int queue_free(struct queue_t *queue) { - if (QUEUE_DEBUG) printf("queue_free\n"); - if (QUEUE_DEBUG) queue_print(queue); - free(queue); - return 0; +int queue_free(struct queue_t *queue) +{ + if (QUEUE_DEBUG) + printf("queue_free\n"); + if (QUEUE_DEBUG) + queue_print(queue); + free(queue); + return 0; } int queue_newmsg(struct queue_t *queue, struct qmsg_t **qmsg, - struct sockaddr_in *peer, uint16_t seq) { - if (QUEUE_DEBUG) printf("queue_newmsg %d\n", (int) seq); - if (queue->qmsga[queue->next].state == 1) { - return EOF; /* Queue is full */ - } - else { - *qmsg = &queue->qmsga[queue->next]; - queue_seqset(queue, *qmsg, peer, seq); - (*qmsg)->state = 1; /* Space taken */ - (*qmsg)->this = queue->next; - (*qmsg)->next=-1; /* End of the queue */ - (*qmsg)->prev=queue->last; /* Link to the previous */ - if (queue->last != -1) - queue->qmsga[queue->last].next=queue->next; /* Link previous to us */ - queue->last = queue->next; /* End of queue */ - if (queue->first == -1) queue->first = queue->next; - queue->next = (queue->next+1) % QUEUE_SIZE; /* Increment */ - if (QUEUE_DEBUG) queue_print(queue); - return 0; - } + struct sockaddr_in *peer, uint16_t seq) +{ + if (QUEUE_DEBUG) + printf("queue_newmsg %d\n", (int)seq); + if (queue->qmsga[queue->next].state == 1) { + return EOF; /* Queue is full */ + } else { + *qmsg = &queue->qmsga[queue->next]; + queue_seqset(queue, *qmsg, peer, seq); + (*qmsg)->state = 1; /* Space taken */ + (*qmsg)->this = queue->next; + (*qmsg)->next = -1; /* End of the queue */ + (*qmsg)->prev = queue->last; /* Link to the previous */ + if (queue->last != -1) + queue->qmsga[queue->last].next = queue->next; /* Link previous to us */ + queue->last = queue->next; /* End of queue */ + if (queue->first == -1) + queue->first = queue->next; + queue->next = (queue->next + 1) % QUEUE_SIZE; /* Increment */ + if (QUEUE_DEBUG) + queue_print(queue); + return 0; + } } -int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg) { - if (QUEUE_DEBUG) printf("queue_freemsg\n"); - if (qmsg->state != 1) { - return EOF; /* Not in queue */ - } +int queue_freemsg(struct queue_t *queue, struct qmsg_t *qmsg) +{ + if (QUEUE_DEBUG) + printf("queue_freemsg\n"); + if (qmsg->state != 1) { + return EOF; /* Not in queue */ + } - queue_seqdel(queue, qmsg); + queue_seqdel(queue, qmsg); - if (qmsg->next == -1) /* Are we the last in queue? */ - queue->last = qmsg->prev; - else - queue->qmsga[qmsg->next].prev = qmsg->prev; - - if (qmsg->prev == -1) /* Are we the first in queue? */ - queue->first = qmsg->next; - else - queue->qmsga[qmsg->prev].next = qmsg->next; + if (qmsg->next == -1) /* Are we the last in queue? */ + queue->last = qmsg->prev; + else + queue->qmsga[qmsg->next].prev = qmsg->prev; - memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */ + if (qmsg->prev == -1) /* Are we the first in queue? */ + queue->first = qmsg->next; + else + queue->qmsga[qmsg->prev].next = qmsg->next; - if (QUEUE_DEBUG) queue_print(queue); + memset(qmsg, 0, sizeof(struct qmsg_t)); /* Just to be safe */ - return 0; + if (QUEUE_DEBUG) + queue_print(queue); + + return 0; } -int queue_back(struct queue_t *queue, struct qmsg_t *qmsg) { - if (QUEUE_DEBUG) printf("queue_back\n"); - if (qmsg->state != 1) { - return EOF; /* Not in queue */ - } - - /* Insert stuff to maintain hash table */ - - if (qmsg->next != -1) {/* Only swop if there are others */ - queue->qmsga[qmsg->next].prev = qmsg->prev; - queue->first = qmsg->next; - - qmsg->next = -1; - qmsg->prev = queue->last; - if (queue->last != -1) queue->qmsga[queue->last].next = qmsg->this; - queue->last = qmsg->this; - } - if (QUEUE_DEBUG) queue_print(queue); - return 0; +int queue_back(struct queue_t *queue, struct qmsg_t *qmsg) +{ + if (QUEUE_DEBUG) + printf("queue_back\n"); + if (qmsg->state != 1) { + return EOF; /* Not in queue */ + } + + /* Insert stuff to maintain hash table */ + + if (qmsg->next != -1) { /* Only swop if there are others */ + queue->qmsga[qmsg->next].prev = qmsg->prev; + queue->first = qmsg->next; + + qmsg->next = -1; + qmsg->prev = queue->last; + if (queue->last != -1) + queue->qmsga[queue->last].next = qmsg->this; + queue->last = qmsg->this; + } + if (QUEUE_DEBUG) + queue_print(queue); + return 0; } /* Get the element with a particular sequence number */ -int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg) { - /*printf("queue_getfirst\n");*/ - if (queue->first == -1) { - *qmsg = NULL; - return EOF; /* End of queue = queue is empty. */ - } - *qmsg = &queue->qmsga[queue->first]; - if (QUEUE_DEBUG) queue_print(queue); - return 0; +int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg) +{ + /*printf("queue_getfirst\n"); */ + if (queue->first == -1) { + *qmsg = NULL; + return EOF; /* End of queue = queue is empty. */ + } + *qmsg = &queue->qmsga[queue->first]; + if (QUEUE_DEBUG) + queue_print(queue); + return 0; } int queue_getseqx(struct queue_t *queue, struct qmsg_t **qmsg, - struct sockaddr_in *peer, uint16_t seq) { - int n; - if (QUEUE_DEBUG) printf("queue_getseq, %d\n", (int) seq); - if (QUEUE_DEBUG) queue_print(queue); - for (n=0; nqmsga[n].seq == seq) && - (!memcmp(&queue->qmsga[n].peer, peer, sizeof(*peer)))) { - *qmsg = &queue->qmsga[n]; - return 0; - } - } - return EOF; /* Not found */ + struct sockaddr_in *peer, uint16_t seq) +{ + int n; + if (QUEUE_DEBUG) + printf("queue_getseq, %d\n", (int)seq); + if (QUEUE_DEBUG) + queue_print(queue); + for (n = 0; n < QUEUE_SIZE; n++) { + if ((queue->qmsga[n].seq == seq) && + (!memcmp(&queue->qmsga[n].peer, peer, sizeof(*peer)))) { + *qmsg = &queue->qmsga[n]; + return 0; + } + } + return EOF; /* Not found */ } int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg, - struct sockaddr_in *peer, uint16_t seq) { - int hash = queue_seqhash(peer, seq); - struct qmsg_t *qmsg2; - if (QUEUE_DEBUG) printf("Begin queue_seqget seq = %d\n", (int) seq); - for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) { - if ((qmsg2->seq == seq) && - (!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) { - *qmsg = qmsg2; - if (QUEUE_DEBUG) printf("End queue_seqget. Found\n"); - return 0; - } - } - if (QUEUE_DEBUG) printf("End queue_seqget. Not found\n"); - return EOF; /* End of linked list and not found */ + struct sockaddr_in *peer, uint16_t seq) +{ + int hash = queue_seqhash(peer, seq); + struct qmsg_t *qmsg2; + if (QUEUE_DEBUG) + printf("Begin queue_seqget seq = %d\n", (int)seq); + for (qmsg2 = queue->hashseq[hash]; qmsg2; qmsg2 = qmsg2->seqnext) { + if ((qmsg2->seq == seq) && + (!memcmp(&qmsg2->peer, peer, sizeof(*peer)))) { + *qmsg = qmsg2; + if (QUEUE_DEBUG) + printf("End queue_seqget. Found\n"); + return 0; + } + } + if (QUEUE_DEBUG) + printf("End queue_seqget. Not found\n"); + return EOF; /* End of linked list and not found */ } -int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer, - uint16_t seq, uint8_t *type, void **cbp) { - struct qmsg_t *qmsg; - if (queue_seqget(queue, &qmsg, peer, seq)) { - *cbp = NULL; - *type = 0; - return EOF; - } - *cbp = qmsg->cbp; - *type = qmsg->type; - if (queue_freemsg(queue, qmsg)) { - return EOF; - } - return 0; +int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer, + uint16_t seq, uint8_t * type, void **cbp) +{ + struct qmsg_t *qmsg; + if (queue_seqget(queue, &qmsg, peer, seq)) { + *cbp = NULL; + *type = 0; + return EOF; + } + *cbp = qmsg->cbp; + *type = qmsg->type; + if (queue_freemsg(queue, qmsg)) { + return EOF; + } + return 0; } diff --git a/gtp/queue.h b/gtp/queue.h index 46fa22d..556b6ef 100644 --- a/gtp/queue.h +++ b/gtp/queue.h @@ -17,37 +17,36 @@ #ifndef _QUEUE_H #define _QUEUE_H -#define QUEUE_DEBUG 0 /* Print debug information */ +#define QUEUE_DEBUG 0 /* Print debug information */ -#define QUEUE_SIZE 1024 /* Size of retransmission queue */ -#define QUEUE_HASH_SIZE 65536 /* Size of hash table (2^16) */ +#define QUEUE_SIZE 1024 /* Size of retransmission queue */ +#define QUEUE_HASH_SIZE 65536 /* Size of hash table (2^16) */ -struct qmsg_t { /* Holder for queued packets */ - int state; /* 0=empty, 1=full */ - uint16_t seq; /* The sequence number */ - uint8_t type; /* The type of packet */ - void *cbp; /* Application specific pointer */ - union gtp_packet p; /* The packet stored */ - int l; /* Length of the packet */ - int fd; /* Socket packet was sent to / received from */ - struct sockaddr_in peer;/* Address packet was sent to / received from */ - struct qmsg_t *seqnext; /* Pointer to next in sequence hash list */ - int next; /* Pointer to the next in queue. -1: Last */ - int prev; /* Pointer to the previous in queue. -1: First */ - int this; /* Pointer to myself */ - time_t timeout; /* When do we retransmit this packet? */ - int retrans; /* How many times did we retransmit this? */ +struct qmsg_t { /* Holder for queued packets */ + int state; /* 0=empty, 1=full */ + uint16_t seq; /* The sequence number */ + uint8_t type; /* The type of packet */ + void *cbp; /* Application specific pointer */ + union gtp_packet p; /* The packet stored */ + int l; /* Length of the packet */ + int fd; /* Socket packet was sent to / received from */ + struct sockaddr_in peer; /* Address packet was sent to / received from */ + struct qmsg_t *seqnext; /* Pointer to next in sequence hash list */ + int next; /* Pointer to the next in queue. -1: Last */ + int prev; /* Pointer to the previous in queue. -1: First */ + int this; /* Pointer to myself */ + time_t timeout; /* When do we retransmit this packet? */ + int retrans; /* How many times did we retransmit this? */ }; struct queue_t { - struct qmsg_t qmsga[QUEUE_SIZE]; /* Array holding signalling messages */ - void *hashseq[QUEUE_HASH_SIZE]; /* Hash array */ - int next; /* Next location in queue to use */ - int first; /* First packet in queue (oldest timeout) */ - int last; /* Last packet in queue (youngest timeout) */ + struct qmsg_t qmsga[QUEUE_SIZE]; /* Array holding signalling messages */ + void *hashseq[QUEUE_HASH_SIZE]; /* Hash array */ + int next; /* Next location in queue to use */ + int first; /* First packet in queue (oldest timeout) */ + int last; /* Last packet in queue (youngest timeout) */ }; - /* Allocates and initialises new queue structure */ int queue_new(struct queue_t **queue); /* Deallocates queue structure */ @@ -63,11 +62,9 @@ int queue_back(struct queue_t *queue, struct qmsg_t *qmsg); int queue_getfirst(struct queue_t *queue, struct qmsg_t **qmsg); /* Get the element with a particular sequence number */ int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg, - struct sockaddr_in *peer, uint16_t seq); + struct sockaddr_in *peer, uint16_t seq); /* Free message based on sequence number */ int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer, - uint16_t seq, uint8_t *type, void **cbp); - - -#endif /* !_QUEUE_H */ + uint16_t seq, uint8_t * type, void **cbp); +#endif /* !_QUEUE_H */ -- cgit v1.2.3