aboutsummaryrefslogtreecommitdiffstats
path: root/gtp/gtpie.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtp/gtpie.c')
-rw-r--r--gtp/gtpie.c513
1 files changed, 513 insertions, 0 deletions
diff --git a/gtp/gtpie.c b/gtp/gtpie.c
new file mode 100644
index 0000000..8fd4a20
--- /dev/null
+++ b/gtp/gtpie.c
@@ -0,0 +1,513 @@
+/*
+ * OpenGGSN - Gateway GPRS Support Node
+ * Copyright (C) 2002 Mondru AB.
+ *
+ * The contents of this file may be used under the terms of the GNU
+ * General Public License Version 2, provided that the above copyright
+ * notice and this permission notice is included in all copies or
+ * substantial portions of the software.
+ *
+ * The initial developer of the original code is
+ * Jens Jakobsen <jj@openggsn.org>
+ *
+ * Contributor(s):
+ *
+ */
+
+/*
+ * gtpie.c: Contains functions to encapsulate and decapsulate GTP
+ * information elements
+ *
+ *
+ * Encapsulation
+ * - gtpie_tlv, gtpie_tv0, gtpie_tv1, gtpie_tv2 ... Adds information
+ * elements to a buffer.
+ *
+ * Decapsulation
+ * - gtpie_decaps: Returns array with pointers to information elements.
+ * - getie_getie: Returns the pointer of a particular element.
+ * - gtpie_gettlv: Copies tlv information element. Return 0 on success.
+ * - gtpie_gettv: Copies tv information element. Return 0 on success.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <string.h>
+
+#include "gtpie.h"
+
+int gtpie_tlv(void *p, int *length, int size, u_int8_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, int *length, int size, u_int8_t t, int l, u_int8_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, int *length, int size, u_int8_t t, u_int8_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, int *length, int size, u_int8_t t, u_int16_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, int *length, int size, u_int8_t t, u_int32_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_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_gettlv(union gtpie_member* ie[], int type, int instance,
+ int *length, void *dst, 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, 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_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_decaps(union gtpie_member* ie[], void *pack, unsigned len) {
+ int i;
+ int j = 0;
+ unsigned char *p;
+ unsigned char *end;
+
+ end = (unsigned char*) pack + len;
+ p = pack;
+
+ memset(ie, 0, 4 * GTPIE_SIZE);
+
+ while (p<end) {
+ 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");
+ }
+
+ 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 */
+ case GTPIE_FL_C:
+ case GTPIE_PFI:
+ 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:
+ if (j<GTPIE_SIZE) {
+ /* 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_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 */
+ case GTPIE_RAI:
+ if (j<GTPIE_SIZE) {
+ ie[j] = (union gtpie_member*) p;
+ if (GTPIE_DEBUG) printf("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_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_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 (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 */
+ }
+}
+
+int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len) {
+ int i;
+ unsigned char *p;
+ unsigned char *end;
+ union gtpie_member *m;
+ int iesize;
+
+ p = pack;
+
+ 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[], int size,
+ void *pack, unsigned *len) {
+ 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<GTPIE_SIZE; j++) for (i=0; i<size; i++) if (ie[i].t == j) {
+ if (GTPIE_DEBUG) printf("gtpie_encaps. Number %d, Type %d\n", i, ie[i].t);
+ m=(union gtpie_member *)p;
+ switch (ie[i].t) {
+ 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_PFI: /* TV GTPIE types with value length 2 */
+ 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:
+ case GTPIE_TEI_C:
+ 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_CHARGING_ID: /* TLV GTPIE types with length length 2 */
+ case GTPIE_EUA:
+ 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;
+}