summaryrefslogtreecommitdiff
path: root/usr.sbin/tcpdump/print-gtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/tcpdump/print-gtp.c')
-rw-r--r--usr.sbin/tcpdump/print-gtp.c1800
1 files changed, 1800 insertions, 0 deletions
diff --git a/usr.sbin/tcpdump/print-gtp.c b/usr.sbin/tcpdump/print-gtp.c
new file mode 100644
index 00000000000..703e52c7339
--- /dev/null
+++ b/usr.sbin/tcpdump/print-gtp.c
@@ -0,0 +1,1800 @@
+/* $OpenBSD: print-gtp.c,v 1.1 2009/11/04 09:43:11 jsing Exp $ */
+/*
+ * Copyright (c) 2009 Joel Sing <jsing@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Decoder for the GPRS Trunking Protocol (GTP).
+ *
+ * This work has been kindly sponsored by SystemNet (www.systemnet.no).
+ *
+ * GTPv0 standards are available from the ETSI website:
+ *
+ * http://pda.etsi.org/pda/
+ *
+ * GTPv1 standards are available from the 3GPP website:
+ *
+ * http://www.3gpp.org/specifications
+ *
+ * The following standards have been referenced to create this decoder:
+ *
+ * ETSI GSM 09.60 - GPRS Tunnelling Protocol (GTPv0)
+ * ETSI GSM 12.15 - GPRS Charging (GTPv0')
+ *
+ * 3GPP TS 23.003 - Numbering, addressing and identification
+ * 3GPP TS 29.002 - Mobile Application Part (MAP) specification
+ * 3GPP TS 29.060 - GPRS Tunnelling Protocol (GTPv1-C/GTPv1-U)
+ * 3GPP TS 32.295 - Charging Data Record (CDR) transfer (GTPv1')
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "addrtoname.h"
+#include "interface.h"
+#include "gtp.h"
+
+void gtp_print(register const u_char *, u_int, u_short, u_short);
+void gtp_decode_ie(register const u_char *, u_short, int);
+void gtp_print_tbcd(register const u_char *, u_int);
+void gtp_print_user_address(register const u_char *, u_int);
+void gtp_print_str(const char **, u_int);
+
+void gtp_v0_print(const u_char *, u_int, u_short, u_short);
+void gtp_v0_print_prime(register const u_char *);
+int gtp_v0_print_tv(register const u_char *, u_int);
+int gtp_v0_print_tlv(register const u_char *, u_int);
+
+void gtp_v1_print(const u_char *, u_int, u_short, u_short);
+void gtp_v1_print_ctrl(register const u_char *, u_int, struct gtp_v1_hdr *);
+void gtp_v1_print_user(register const u_char *, u_int, struct gtp_v1_hdr *);
+void gtp_v1_print_prime(register const u_char *, struct gtp_v1_prime_hdr *);
+int gtp_v1_print_tv(register const u_char *, u_int);
+int gtp_v1_print_tlv(register const u_char *, u_int);
+
+/* GTPv0 message types. */
+static struct tok gtp_v0_msgtype[] = {
+
+ { 1, "Echo Request" },
+ { 2, "Echo Response" },
+ { 3, "Version Not Supported" },
+ { 4, "Node Alive Request" },
+ { 5, "Node Alive Response" },
+ { 6, "Redirection Request" },
+ { 7, "Redirection Response" },
+ { 16, "Create PDP Context Request" },
+ { 17, "Create PDP Context Response" },
+ { 18, "Update PDP Context Request" },
+ { 19, "Update PDP Context Response" },
+ { 20, "Delete PDP Context Request" },
+ { 21, "Delete PDP Context Response" },
+ { 22, "Create AA PDP Context Request" },
+ { 23, "Create AA PDP Context Response" },
+ { 24, "Delete AA PDP Context Request" },
+ { 25, "Delete AA PDP Context Response" },
+ { 26, "Error Indication" },
+ { 27, "PDU Notification Request" },
+ { 28, "PDU Notification Response" },
+ { 29, "PDU Notification Reject Request" },
+ { 30, "PDU Notification Reject Response" },
+ { 32, "Send Routeing Information Request" },
+ { 33, "Send Routeing Information Response" },
+ { 34, "Failure Report Request" },
+ { 35, "Failure Report Response" },
+ { 36, "MS GPRS Present Request" },
+ { 37, "MS GPRS Present Response" },
+ { 48, "Identification Request" },
+ { 49, "Identification Response" },
+ { 50, "SGSN Context Request" },
+ { 51, "SGSN Context Response" },
+ { 52, "SGSN Context Acknowledge" },
+ { 240, "Data Record Transfer Request" },
+ { 241, "Data Record Transfer Response" },
+ { 255, "T-PDU" },
+
+ { 0, NULL }
+};
+
+/* GTPv0 causes. */
+static struct tok gtp_v0_cause[] = {
+
+ { 0, "Request IMSI" },
+ { 1, "Request IMEI" },
+ { 2, "Request IMSI and IMEI" },
+ { 3, "No identity needed" },
+ { 4, "MS refuses" },
+ { 5, "MS is not GPRS responding" },
+ { 128, "Request accepted" },
+ { 192, "Non-existent" },
+ { 193, "Invalid message format" },
+ { 194, "IMSI not known" },
+ { 195, "MS is GPRS detached" },
+ { 196, "MS is not GPRS responding" },
+ { 197, "MS refuses" },
+ { 198, "Version not supported" },
+ { 199, "No resources available" },
+ { 200, "Service not supported" },
+ { 201, "Mandatory IE incorrect" },
+ { 202, "Mandatory IE missing" },
+ { 203, "Optional IE incorrect" },
+ { 204, "System failure" },
+ { 205, "Roaming restriction" },
+ { 206, "P-TMSI signature mismatch" },
+ { 207, "GPRS connection suspended" },
+ { 208, "Authentication failure" },
+ { 209, "User authentication failed" },
+
+ { 0, NULL }
+};
+
+/* GTPv1 message types. */
+static struct tok gtp_v1_msgtype[] = {
+
+ { 1, "Echo Request" },
+ { 2, "Echo Response" },
+ { 3, "Version Not Supported" },
+ { 4, "Node Alive Request" },
+ { 5, "Node Alive Response" },
+ { 6, "Redirection Request" },
+ { 7, "Redirection Response" },
+ { 16, "Create PDP Context Request" },
+ { 17, "Create PDP Context Response" },
+ { 18, "Update PDP Context Request" },
+ { 19, "Update PDP Context Response" },
+ { 20, "Delete PDP Context Request" },
+ { 21, "Delete PDP Context Response" },
+ { 22, "Initiate PDP Context Activiation Request" },
+ { 23, "Initiate PDP Context Activiation Response" },
+ { 26, "Error Indication" },
+ { 27, "PDU Notification Request" },
+ { 28, "PDU Notification Response" },
+ { 29, "PDU Notification Reject Request" },
+ { 30, "PDU Notification Reject Response" },
+ { 31, "Supported Extension Headers Notification" },
+ { 32, "Send Routeing Information for GPRS Request" },
+ { 33, "Send Routeing Information for GPRS Response" },
+ { 34, "Failure Report Request" },
+ { 35, "Failure Report Response" },
+ { 36, "Note MS GPRS Present Request" },
+ { 37, "Note MS GPRS Present Response" },
+ { 48, "Identification Request" },
+ { 49, "Identification Response" },
+ { 50, "SGSN Context Request" },
+ { 51, "SGSN Context Response" },
+ { 52, "SGSN Context Acknowledge" },
+ { 53, "Forward Relocation Request" },
+ { 54, "Forward Relocation Response" },
+ { 55, "Forward Relocation Complete" },
+ { 56, "Relocation Cancel Request" },
+ { 57, "Relocation Cancel Response" },
+ { 58, "Forward SRNS Context" },
+ { 59, "Forward Relocation Complete Acknowledge" },
+ { 60, "Forward SRNS Context Acknowledge" },
+ { 70, "RAN Information Relay" },
+ { 96, "MBMS Notification Request" },
+ { 97, "MBMS Notification Response" },
+ { 98, "MBMS Notification Reject Request" },
+ { 99, "MBMS Notification Reject Response" },
+ { 100, "Create MBMS Context Request" },
+ { 101, "Create MBMS Context Response" },
+ { 102, "Update MBMS Context Request" },
+ { 103, "Update MBMS Context Response" },
+ { 104, "Delete MBMS Context Request" },
+ { 105, "Delete MBMS Context Response" },
+ { 112, "MBMS Registration Request" },
+ { 113, "MBMS Registration Response" },
+ { 114, "MBMS De-Registration Request" },
+ { 115, "MBMS De-Registration Response" },
+ { 116, "MBMS Session Start Request" },
+ { 117, "MBMS Session Start Response" },
+ { 118, "MBMS Session Stop Request" },
+ { 119, "MBMS Session Stop Response" },
+ { 120, "MBMS Session Update Request" },
+ { 121, "MBMS Session Update Response" },
+ { 128, "MBMS Info Change Notification Request" },
+ { 129, "MBMS Info Change Notification Response" },
+ { 240, "Data Record Transfer Request" },
+ { 241, "Data Record Transfer Response" },
+ { 255, "G-PDU" },
+
+ { 0, NULL }
+};
+
+/* GTPv1 Causes. */
+static struct tok gtp_v1_cause[] = {
+
+ /* GTPv1-C. */
+ { 0, "Request IMSI" },
+ { 1, "Request IMEI" },
+ { 2, "Request IMSI and IMEI" },
+ { 3, "No identity needed" },
+ { 4, "MS refuses" },
+ { 5, "MS is not GPRS responding" },
+ { 128, "Request accepted" },
+ { 192, "Non-existent" },
+ { 193, "Invalid message format" },
+ { 194, "IMSI not known" },
+ { 195, "MS is GPRS detached" },
+ { 196, "MS is not GPRS responding" },
+ { 197, "MS refuses" },
+ { 198, "Version not supported" },
+ { 199, "No resources available" },
+ { 200, "Service not supported" },
+ { 201, "Mandatory IE incorrect" },
+ { 202, "Mandatory IE missing" },
+ { 203, "Optional IE incorrect" },
+ { 204, "System failure" },
+ { 205, "Roaming restriction" },
+ { 206, "P-TMSI signature mismatch" },
+ { 207, "GPRS connection suspended" },
+ { 208, "Authentication failure" },
+ { 209, "User authentication failed" },
+ { 210, "Context not found" },
+ { 211, "All dynamic PDP addresses are occupied" },
+ { 212, "No memory is available" },
+ { 213, "Relocation failure" },
+ { 214, "Unknown mandatory extension header" },
+ { 215, "Semantic error in the TFT operation" },
+ { 216, "Syntactic error in the TFT operation" },
+ { 217, "Semantic errors in packet filter(s)" },
+ { 218, "Syntactic errors in packet filter(s)" },
+ { 219, "Missing or unknown APN" },
+ { 220, "Unknown PDP address or PDP type" },
+ { 221, "PDP context without TFT already activated" },
+ { 222, "APN access denied - no subscription" },
+ { 223, "APN restriction type incompatibility with currently "
+ "active PDP contexts" },
+ { 224, "MS MBMS capabilities insufficient" },
+ { 225, "Invalid correlation-ID" },
+ { 226, "MBMS bearer context superseded" },
+
+ /* GTP'v1. */
+ { 59, "System failure" },
+ { 60, "The transmit buffers are becoming full" },
+ { 61, "The receive buffers are becoming full" },
+ { 62, "Another node is about to go down" },
+ { 63, "This node is about to go down" },
+ { 177, "CDR decoding error" },
+ { 252, "Request related to possibly duplicated packets already "
+ "fulfilled" },
+ { 253, "Request already fulfilled" },
+ { 254, "Sequence numbers of released/cancelled packets IE incorrect" },
+ { 255, "Request not fulfilled" },
+
+ { 0, NULL }
+};
+
+static int gtp_proto = -1;
+
+void
+gtp_print(register const u_char *cp, u_int length, u_short sport, u_short dport)
+{
+ int version;
+
+ /* Decode GTP version. */
+ TCHECK(cp[0]);
+ version = cp[0] >> GTP_VERSION_SHIFT;
+
+ if (version == GTP_VERSION_0)
+ gtp_v0_print(cp, length, sport, dport);
+ else if (version == GTP_VERSION_1)
+ gtp_v1_print(cp, length, sport, dport);
+ else
+ printf(" GTP (version %i)", version);
+
+ return;
+
+trunc:
+ printf(" [|GTP]");
+}
+
+/*
+ * Decode and print information elements from message. The actual work is
+ * handled in the appropriate Tag/Value (TV) or Tag/Length/Value (TLV)
+ * decoding routine.
+ */
+void
+gtp_decode_ie(register const u_char *cp, u_short version, int len)
+{
+ int val, ielen, iecount = 0;
+
+ if (len <= 0)
+ return;
+
+ printf(" {");
+
+ while (len > 0) {
+
+ iecount++;
+ if (iecount > 1)
+ printf(" ");
+
+ TCHECK(cp[0]);
+ val = (u_int)cp[0];
+ cp++;
+
+ printf("[");
+
+ switch (version) {
+ case GTP_VERSION_0:
+ if ((val & GTPV0_IE_TYPE_MASK) == 0)
+ ielen = gtp_v0_print_tv(cp, val);
+ else
+ ielen = gtp_v0_print_tlv(cp, val);
+ break;
+
+ case GTP_VERSION_1:
+ if ((val & GTPV1_IE_TYPE_MASK) == 0)
+ ielen = gtp_v1_print_tv(cp, val);
+ else
+ ielen = gtp_v1_print_tlv(cp, val);
+ break;
+
+ default:
+ /* Version not supported... */
+ ielen = -1;
+ break;
+ }
+
+ printf("]");
+
+ if (ielen < 0)
+ goto trunc;
+
+ len -= ielen;
+ cp += ielen - 1;
+ }
+
+ if (iecount > 0)
+ printf("}");
+
+ return;
+
+trunc:
+ printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
+}
+
+/*
+ * Decode and print telephony binary coded decimal.
+ */
+void
+gtp_print_tbcd(register const u_char *cp, u_int len)
+{
+ u_int8_t *data, bcd;
+ int i;
+
+ data = (u_int8_t *)cp;
+ for (i = 0; i < len; i++) {
+ bcd = *data & 0xf;
+ if (bcd != 0xf)
+ printf("%u", bcd);
+ bcd = *data >> 4;
+ if (bcd != 0xf)
+ printf("%u", bcd);
+ data++;
+ }
+}
+
+/*
+ * Decode and print an end user address. Format is detailed in
+ * GSM 09.60 section 7.9.18 and 3GPP 29.060 section 7.7.27.
+ */
+void
+gtp_print_user_address(register const u_char *cp, u_int len)
+{
+ u_int8_t org, type;
+
+ if (len < 2)
+ return;
+
+ org = (u_int8_t)cp[0] & 0xf;
+ type = (u_int8_t)cp[1];
+
+ cp += 2;
+
+ if (org == 0x0 && type == 0x1)
+ printf(": PPP");
+ else if (org == 0x1 && type == 0x21) {
+ if (len == 6)
+ printf(": %s", ipaddr_string(cp));
+ else
+ printf(": IPv4");
+#ifdef INET6
+ } else if (org == 0x1 && type == 0x57) {
+ if (len == 18)
+ printf(": %s", ip6addr_string(cp));
+ else
+ printf(": IPv6");
+#endif
+ } else
+ printf(" (org 0x%x, type 0x%x)", org, type);
+}
+
+/* Print string from array. */
+void
+gtp_print_str(const char **strs, u_int index)
+{
+
+ if (index >= (sizeof(*strs) / sizeof(*strs[0])))
+ printf(": %u", index);
+ else if (strs[index] != NULL)
+ printf(": %s", strs[index]);
+}
+
+/*
+ * Decoding routines for GTP version 0.
+ */
+void
+gtp_v0_print(const u_char *cp, u_int length, u_short sport, u_short dport)
+{
+ struct gtp_v0_hdr *gh = (struct gtp_v0_hdr *)cp;
+ int len, version;
+
+ gtp_proto = GTP_V0_PROTO;
+
+ /* Check if this is GTP prime. */
+ TCHECK(gh->flags);
+ if ((gh->flags & GTPV0_HDR_PROTO_TYPE) == 0) {
+ gtp_proto = GTP_V0_PRIME_PROTO;
+ gtp_v0_print_prime(cp);
+ return;
+ }
+
+ /* Print GTP header. */
+ TCHECK(*gh);
+ cp += sizeof(struct gtp_v0_hdr);
+ len = ntohs(gh->length);
+ printf(" GTPv0 (len %u, seqno %u, flow %u, N-PDU %u, tid 0x%llx) ",
+ ntohs(gh->length), ntohs(gh->seqno), ntohs(gh->flow),
+ ntohs(gh->npduno), betoh64(gh->tid));
+
+ /* Decode GTP message. */
+ printf("%s", tok2str(gtp_v0_msgtype, "Message Type %u", gh->msgtype));
+
+ if (!vflag)
+ return;
+
+ if (gh->msgtype == GTPV0_T_PDU) {
+
+ TCHECK(cp[0]);
+ version = cp[0] >> 4;
+
+ printf(" { ");
+
+ if (version == 4)
+ ip_print(cp, len);
+#ifdef INET6
+ else if (version == 6)
+ ip6_print(cp, len);
+#endif
+ else
+ printf("Unknown IP version %u", version);
+
+ printf(" }");
+ } else
+ gtp_decode_ie(cp, GTP_VERSION_0, len);
+
+ return;
+
+trunc:
+ printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
+}
+
+void
+gtp_v0_print_prime(register const u_char *cp)
+{
+ struct gtp_v0_prime_hdr *gph = (struct gtp_v0_prime_hdr *)cp;
+ int len;
+
+ /* Decode GTP prime header. */
+ TCHECK(*gph);
+ cp += sizeof(*gph);
+
+ len = ntohs(gph->length);
+ printf(" GTPv0' (len %u, seq %u) ", len, ntohs(gph->seqno));
+
+ /* Decode GTP message. */
+ printf("%s", tok2str(gtp_v0_msgtype, "Message Type %u", gph->msgtype));
+
+ if (vflag)
+ gtp_decode_ie(cp, GTP_VERSION_0, len);
+
+ return;
+
+trunc:
+ printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
+}
+
+int
+gtp_v0_print_tv(register const u_char *cp, u_int value)
+{
+ u_int32_t *dpl;
+ u_int16_t *dps;
+ u_int8_t data;
+ int ielen = -1;
+
+ switch (value) {
+ case GTPV0_TV_CAUSE:
+
+ /* 09.60 7.9.1 - Cause. */
+ TCHECK(cp[0]);
+ data = (u_int8_t)cp[0];
+ ielen = GTPV0_TV_CAUSE_LENGTH;
+ printf("Cause: %s", tok2str(gtp_v0_cause, "#%u", data));
+ break;
+
+ case GTPV0_TV_IMSI:
+
+ /* 09.60 7.9.2 - International Mobile Subscriber Identity. */
+ TCHECK2(cp[0], GTPV0_TV_IMSI_LENGTH - 1);
+ printf("IMSI ");
+ gtp_print_tbcd(cp, GTPV0_TV_IMSI_LENGTH - 1);
+ ielen = GTPV0_TV_IMSI_LENGTH;
+ break;
+
+ case GTPV0_TV_RAI:
+
+ /* 09.60 7.9.3 - Routing Area Identity (RAI). */
+ TCHECK2(cp[0], GTPV0_TV_RAI_LENGTH - 1);
+ printf("RAI: MCC ");
+ data = cp[1] | 0xf0;
+ gtp_print_tbcd(cp, 1);
+ gtp_print_tbcd(&data, 1);
+ printf(", MNC ");
+ data = (cp[1] >> 4) | 0xf0;
+ gtp_print_tbcd(cp + 2, 1);
+ gtp_print_tbcd(&data, 1);
+ printf(", LAC 0x%x%x", cp[3], cp[4]);
+ printf(", RAC 0x%x", cp[5]);
+ ielen = GTPV0_TV_RAI_LENGTH;
+ break;
+
+ case GTPV0_TV_TLLI:
+
+ /* 09.60 7.9.4 - Temporary Logical Link Identity (TLLI). */
+ TCHECK2(cp[0], GTPV0_TV_TLLI_LENGTH - 1);
+ dpl = (u_int32_t *)cp;
+ printf("TLLI 0x%x", ntohl(*dpl));
+ ielen = GTPV0_TV_TLLI_LENGTH;
+ break;
+
+ case GTPV0_TV_PTMSI:
+
+ /* 09.60 7.9.5 - Packet TMSI (P-TMSI). */
+ TCHECK2(cp[0], GTPV0_TV_PTMSI_LENGTH - 1);
+ dpl = (u_int32_t *)cp;
+ printf("P-TMSI 0x%x", ntohl(*dpl));
+ ielen = GTPV0_TV_PTMSI_LENGTH;
+ break;
+
+ case GTPV0_TV_QOS:
+
+ /* 09.60 7.9.6 - Quality of Service (QoS) Profile. */
+ TCHECK2(cp[0], GTPV0_TV_QOS_LENGTH - 1);
+ printf("QoS Profile"); /* XXX */
+ ielen = GTPV0_TV_QOS_LENGTH;
+ break;
+
+ case GTPV0_TV_REORDER:
+
+ /* 09.60 7.9.7 - Reordering Required. */
+ TCHECK2(cp[0], GTPV0_TV_REORDER_LENGTH - 1);
+ printf("Reordering Required: ");
+ if (cp[0] & 0x1)
+ printf("yes");
+ else
+ printf("no");
+ ielen = GTPV0_TV_REORDER_LENGTH;
+ break;
+
+ case GTPV0_TV_AUTH_TRIPLET:
+
+ /* 09.60 7.9.8 - Authentication Triplet. */
+ TCHECK2(cp[0], GTPV0_TV_AUTH_TRIPLET_LENGTH - 1);
+ printf("Authentication"); /* XXX */
+ ielen = GTPV0_TV_AUTH_TRIPLET_LENGTH;
+ break;
+
+ case GTPV0_TV_MAP_CAUSE:
+
+ /* 09.60 7.9.9 - MAP Cause. */
+ TCHECK2(cp[0], GTPV0_TV_MAP_CAUSE_LENGTH - 1);
+ printf("MAP Cause: %u", cp[0]);
+ ielen = GTPV0_TV_MAP_CAUSE_LENGTH;
+ break;
+
+ case GTPV0_TV_PTMSI_SIGNATURE:
+
+ /* 09.60 7.9.10 - P-TMSI Signature. */
+ /* Signature defined in GSM 04.08. */
+ TCHECK2(cp[0], GTPV0_TV_PTMSI_SIGNATURE_LENGTH - 1);
+ printf("PTMSI Signature: 0x%x%x%x", cp[0], cp[1], cp[2]);
+ ielen = GTPV0_TV_PTMSI_SIGNATURE_LENGTH;
+ break;
+
+ case GTPV0_TV_MS_VALIDATED:
+
+ /* 09.60 7.9.11 - MS Validated. */
+ TCHECK2(cp[0], GTPV0_TV_MS_VALIDATED_LENGTH - 1);
+ printf("MS Validated");
+ if (cp[0] & 0x1)
+ printf("yes");
+ else
+ printf("no");
+ ielen = GTPV0_TV_MS_VALIDATED_LENGTH;
+ break;
+
+ case GTPV0_TV_RECOVERY:
+
+ /* 09.60 7.9.12 - Recovery. */
+ TCHECK2(cp[0], GTPV0_TV_RECOVERY_LENGTH - 1);
+ printf("Recovery: Restart counter %u", cp[0]);
+ ielen = GTPV0_TV_RECOVERY_LENGTH;
+ break;
+
+ case GTPV0_TV_SELECTION_MODE:
+
+ /* 09.60 7.9.13 - Selection Mode. */
+ TCHECK2(cp[0], GTPV0_TV_SELECTION_MODE_LENGTH - 1);
+ printf("Selection Mode"); /* XXX */
+ ielen = GTPV0_TV_SELECTION_MODE_LENGTH;
+ break;
+
+ case GTPV0_TV_FLOW_LABEL_DATA_I:
+
+ /* 09.60 7.9.14 - Flow Label Data I. */
+ TCHECK2(cp[0], GTPV0_TV_FLOW_LABEL_DATA_I_LENGTH - 1);
+ dps = (u_int16_t *)cp;
+ printf("Flow Label Data I: %u", ntohs(*dps));
+ ielen = GTPV0_TV_FLOW_LABEL_DATA_I_LENGTH;
+ break;
+
+ case GTPV0_TV_FLOW_LABEL_SIGNALLING:
+
+ /* 09.60 7.9.15 - Flow Label Signalling. */
+ TCHECK2(cp[0], GTPV0_TV_FLOW_LABEL_SIGNALLING_LENGTH - 1);
+ dps = (u_int16_t *)cp;
+ printf("Flow Label Signalling: %u", ntohs(*dps));
+ ielen = GTPV0_TV_FLOW_LABEL_SIGNALLING_LENGTH;
+ break;
+
+ case GTPV0_TV_FLOW_LABEL_DATA_II:
+
+ /* 09.60 7.9.16 - Flow Label Data II. */
+ TCHECK2(cp[0], GTPV0_TV_FLOW_LABEL_DATA_II_LENGTH - 1);
+ data = cp[0] & 0xf;
+ dps = (u_int16_t *)(cp + 1);
+ printf("Flow Label Data II: %u, NSAPI %u", ntohs(*dps), data);
+ ielen = GTPV0_TV_FLOW_LABEL_DATA_II_LENGTH;
+ break;
+
+ case GTPV0_TV_PACKET_XFER_CMD:
+
+ /* 12.15 7.3.4.5.3 - Packet Transfer Command. */
+ TCHECK2(cp[0], GTPV0_TV_PACKET_XFER_CMD_LENGTH - 1);
+ printf("Packet Transfer Command");
+ gtp_print_str(gtp_packet_xfer_cmd, cp[0]);
+ ielen = GTPV0_TV_PACKET_XFER_CMD_LENGTH;
+ break;
+
+ case GTPV0_TV_CHARGING_ID:
+
+ /* 09.60 7.9.17 - Charging ID. */
+ TCHECK2(cp[0], GTPV0_TV_CHARGING_ID_LENGTH - 1);
+ dps = (u_int16_t *)cp;
+ printf("Charging ID: %u", ntohs(*dps));
+ ielen = GTPV0_TV_CHARGING_ID_LENGTH;
+ break;
+
+ default:
+ printf("TV %u", value);
+ }
+
+trunc:
+ return ielen;
+}
+
+int
+gtp_v0_print_tlv(register const u_char *cp, u_int value)
+{
+ u_int8_t data;
+ u_int16_t *lenp, *seqno, len;
+ u_char *buf;
+ int ielen = -1;
+
+ /* Get length of IE. */
+ TCHECK2(cp[0], 2);
+ lenp = (u_int16_t *)cp;
+ cp += 2;
+ len = ntohs(*lenp);
+ TCHECK2(cp[0], len);
+ ielen = sizeof(data) + sizeof(len) + len;
+
+ switch (value) {
+
+ case GTPV0_TLV_END_USER_ADDRESS:
+
+ /* 09.60 7.9.18 - End User Address. */
+ printf("End User Address");
+ gtp_print_user_address(cp, len);
+ break;
+
+ case GTPV0_TLV_MM_CONTEXT:
+
+ /* 09.60 7.9.19 - MM Context. */
+ printf("MM Context"); /* XXX */
+ break;
+
+ case GTPV0_TLV_PDP_CONTEXT:
+
+ /* 09.60 7.9.20 - PDP Context. */
+ printf("PDP Context"); /* XXX */
+ break;
+
+ case GTPV0_TLV_ACCESS_POINT_NAME:
+
+ /* 09.60 7.9.21 - Access Point Name. */
+ printf("AP Name:");
+ len = (u_int8_t)cp[0];
+ if ((buf = malloc(len + 1)) != NULL) {
+ bcopy(cp + 1, buf, len);
+ buf[len] = '\0';
+ printf(": %s", buf);
+ free(buf);
+ }
+ break;
+
+ case GTPV0_TLV_PROTOCOL_CONFIG_OPTIONS:
+
+ /* 09.60 7.9.22 - Protocol Configuration Options. */
+ printf("Protocol Configuration Options"); /* XXX */
+ break;
+
+ case GTPV0_TLV_GSN_ADDRESS:
+
+ /* 09.60 7.9.23 - GSN Address. */
+ printf("GSN Address");
+ if (len == 4)
+ printf(": %s", ipaddr_string(cp));
+#ifdef INET6
+ else if (len == 16)
+ printf(": %s", ip6addr_string(cp));
+#endif
+ break;
+
+ case GTPV0_TLV_MS_ISDN:
+
+ /* 09.60 7.9.24 - MS International PSTN/ISDN Number. */
+ printf("MSISDN ");
+ data = (u_int8_t)cp[0]; /* XXX - Number type. */
+ gtp_print_tbcd(cp + 1, len - 1);
+ break;
+
+ case GTPV0_TLV_CHARGING_GATEWAY_ADDRESS:
+
+ /* 09.60 7.9.25 - Charging Gateway Address. */
+ printf("Charging Gateway");
+ if (len == 4)
+ printf(": %s", ipaddr_string(cp));
+ break;
+
+ case GTPV0_TLV_DATA_RECORD_PACKET:
+
+ /* 12.15 7.3.4.5.4 - Data Record Packet. */
+ printf("Data Record: Records %u, Format %u, Format Version %u",
+ cp[0], cp[1], ntohs(*(u_int16_t *)(cp + 2)));
+ break;
+
+ case GTPV0_TLV_REQUESTS_RESPONDED:
+
+ /* 12.15 7.3.4.6 - Requests Responded. */
+ printf("Requests Responded:");
+ seqno = (u_int16_t *)cp;
+ while (len > 0) {
+ printf(" %u", ntohs(*seqno));
+ seqno++;
+ len -= sizeof(*seqno);
+ }
+ break;
+
+ case GTPV0_TLV_RECOMMENDED_NODE:
+
+ /* 12.15 7.3.4.3 - Address of Recommended Node. */
+ printf("Recommended Node");
+ if (len == 4)
+ printf(": %s", ipaddr_string(cp));
+#ifdef INET6
+ else if (len == 16)
+ printf(": %s", ip6addr_string(cp));
+#endif
+ break;
+
+ case GTPV0_TLV_PRIVATE_EXTENSION:
+
+ printf("Private Extension");
+ break;
+
+ default:
+ printf("TLV %u (len %u)", value, len);
+ }
+
+ return ielen;
+
+trunc:
+ return -1;
+}
+
+/*
+ * Decoding for GTP version 1, which consists of GTPv1-C, GTPv1-U and GTPv1'.
+ */
+void
+gtp_v1_print(const u_char *cp, u_int length, u_short sport, u_short dport)
+{
+ struct gtp_v1_hdr *gh = (struct gtp_v1_hdr *)cp;
+ struct gtp_v1_hdr_ext *ghe = 0;
+ int nexthdr, hlen;
+ u_char *p = (u_char *)cp;
+
+ TCHECK(gh->flags);
+ if ((gh->flags && GTPV1_HDR_PROTO_TYPE) == 0) {
+ printf(" GTPv1'");
+ gtp_proto = GTP_V1_PRIME_PROTO;
+ gtp_v1_print_prime(p, (struct gtp_v1_prime_hdr *)gh);
+ return;
+ }
+
+ if (dport == GTPV1_C_PORT || sport == GTPV1_C_PORT) {
+ gtp_proto = GTP_V1_CTRL_PROTO;
+ printf(" GTPv1-C");
+ } else if (dport == GTPV1_U_PORT || sport == GTPV1_U_PORT) {
+ gtp_proto = GTP_V1_USER_PROTO;
+ printf(" GTPv1-U");
+ } else if (dport == GTPV1_PRIME_PORT || sport == GTPV1_PRIME_PORT) {
+ gtp_proto = GTP_V1_PRIME_PROTO;
+ printf(" GTPv1'");
+ }
+
+ /* Decode GTP header. */
+ TCHECK(*gh);
+ p += sizeof(struct gtp_v1_hdr);
+
+ printf(" (teid %u, len %u)", ntohl(gh->teid), ntohs(gh->length));
+
+ if (gh->flags & GTPV1_HDR_EXT) {
+ ghe = (struct gtp_v1_hdr_ext *)cp;
+ TCHECK(*ghe);
+ p += sizeof(struct gtp_v1_hdr_ext) - sizeof(struct gtp_v1_hdr);
+ }
+
+ if (gh->flags & GTPV1_HDR_SN_FLAG)
+ printf(" [seq %u]", ntohs(ghe->seqno));
+
+ if (gh->flags & GTPV1_HDR_NPDU_FLAG)
+ printf(" [N-PDU %u]", ghe->npduno);
+
+ if (gh->flags & GTPV1_HDR_EH_FLAG) {
+
+ /* Process next header... */
+ nexthdr = ghe->nexthdr;
+ while (nexthdr != GTPV1_EH_NONE) {
+
+ /* Header length is a 4 octet multiplier. */
+ hlen = (int)p[0] * 4;
+ TCHECK2(p[0], hlen);
+
+ switch (nexthdr) {
+ case GTPV1_EH_MBMS_SUPPORT:
+ printf(" [MBMS Support]");
+ break;
+
+ case GTPV1_EH_MSI_CHANGE_RPT:
+ printf(" [MS Info Change Reporting]");
+ break;
+
+ case GTPV1_EH_PDCP_PDU_NO:
+ printf(" [PDCP PDU %u]",
+ ntohs(*(u_int16_t *)(p + 1)));
+ break;
+
+ case GTPV1_EH_SUSPEND_REQUEST:
+ printf(" [Suspend Request]");
+ break;
+
+ case GTPV1_EH_SUSPEND_RESPONSE:
+ printf(" [Suspend Response]");
+ break;
+
+ default:
+ printf(" [Unknown Header %u]", nexthdr);
+ }
+
+ p += hlen - 1;
+ nexthdr = (int)p[0];
+ p++;
+ }
+
+ }
+
+ hlen = p - cp;
+
+ if (dport == GTPV1_C_PORT || sport == GTPV1_C_PORT)
+ gtp_v1_print_ctrl(p, hlen, gh);
+ else if (dport == GTPV1_U_PORT || sport == GTPV1_U_PORT)
+ gtp_v1_print_user(p, hlen, gh);
+
+ return;
+
+trunc:
+ printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
+}
+
+void
+gtp_v1_print_ctrl(register const u_char *cp, u_int hlen, struct gtp_v1_hdr *gh)
+{
+ int len;
+
+ /* Decode GTP control message. */
+ printf(" %s", tok2str(gtp_v1_msgtype, "Message Type %u", gh->msgtype));
+
+ len = ntohs(gh->length) - hlen + sizeof(*gh);
+ if (vflag)
+ gtp_decode_ie(cp, GTP_VERSION_1, len);
+}
+
+void
+gtp_v1_print_user(register const u_char *cp, u_int hlen, struct gtp_v1_hdr *gh)
+{
+ int len, version;
+
+ /* Decode GTP user message. */
+ printf(" %s", tok2str(gtp_v1_msgtype, "Message Type %u", gh->msgtype));
+
+ if (!vflag)
+ return;
+
+ len = ntohs(gh->length) - hlen + sizeof(*gh);
+
+ if (gh->msgtype == GTPV1_G_PDU) {
+
+ TCHECK(cp[0]);
+ version = cp[0] >> 4;
+
+ printf(" { ");
+
+ if (version == 4)
+ ip_print(cp, len);
+#ifdef INET6
+ else if (version == 6)
+ ip6_print(cp, len);
+#endif
+ else
+ printf("Unknown IP version %u", version);
+
+ printf(" }");
+
+ } else
+ gtp_decode_ie(cp, GTP_VERSION_1, len);
+
+ return;
+
+trunc:
+ printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
+}
+
+void
+gtp_v1_print_prime(register const u_char *cp, struct gtp_v1_prime_hdr *gph)
+{
+ int len;
+
+ /* Decode GTP prime header. */
+ TCHECK(*gph);
+ cp += sizeof(struct gtp_v1_prime_hdr);
+
+ len = ntohs(gph->length);
+ printf(" (len %u, seq %u) ", len, ntohs(gph->seqno));
+
+ /* Decode GTP message. */
+ printf("%s", tok2str(gtp_v1_msgtype, "Message Type %u", gph->msgtype));
+
+ if (vflag)
+ gtp_decode_ie(cp, GTP_VERSION_1, len);
+
+ return;
+
+trunc:
+ printf(" [|%s]", tok2str(gtp_type, "GTP", gtp_proto));
+}
+
+int
+gtp_v1_print_tv(register const u_char *cp, u_int value)
+{
+ u_int32_t *dpl;
+ u_int16_t *dps;
+ u_int8_t data;
+ int ielen = -1;
+
+ switch (value) {
+ case GTPV1_TV_CAUSE:
+
+ /* 29.060 - 7.7.1 Cause. */
+ TCHECK(cp[0]);
+ data = (u_int8_t)cp[0];
+ ielen = GTPV1_TV_CAUSE_LENGTH;
+ printf("Cause: %s", tok2str(gtp_v1_cause, "#%u", data));
+ break;
+
+ case GTPV1_TV_IMSI:
+
+ /* 29.060 7.7.2 - International Mobile Subscriber Identity. */
+ TCHECK2(cp[0], GTPV1_TV_IMSI_LENGTH - 1);
+ printf("IMSI ");
+ gtp_print_tbcd(cp, GTPV1_TV_IMSI_LENGTH - 1);
+ ielen = GTPV1_TV_IMSI_LENGTH;
+ break;
+
+ case GTPV1_TV_RAI:
+
+ /* 29.060 7.7.3 - Routing Area Identity (RAI). */
+ TCHECK2(cp[0], GTPV1_TV_RAI_LENGTH - 1);
+ printf("RAI: MCC ");
+ data = cp[1] | 0xf0;
+ gtp_print_tbcd(cp, 1);
+ gtp_print_tbcd(&data, 1);
+ printf(", MNC ");
+ data = (cp[1] >> 4) | 0xf0;
+ gtp_print_tbcd(cp + 2, 1);
+ gtp_print_tbcd(&data, 1);
+ printf(", LAC 0x%x%x", cp[3], cp[4]);
+ printf(", RAC 0x%x", cp[5]);
+ ielen = GTPV1_TV_RAI_LENGTH;
+ break;
+
+ case GTPV1_TV_TLLI:
+
+ /* 29.060 7.7.4 - Temporary Logical Link Identity (TLLI). */
+ TCHECK2(cp[0], GTPV1_TV_TLLI_LENGTH - 1);
+ dpl = (u_int32_t *)cp;
+ printf("TLLI 0x%x", ntohl(*dpl));
+ ielen = GTPV1_TV_TLLI_LENGTH;
+ break;
+
+ case GTPV1_TV_PTMSI:
+
+ /* 29.060 7.7.5 - Packet TMSI (P-TMSI). */
+ TCHECK2(cp[0], GTPV1_TV_PTMSI_LENGTH - 1);
+ dpl = (u_int32_t *)cp;
+ printf("P-TMSI 0x%x", ntohl(*dpl));
+ ielen = GTPV1_TV_PTMSI_LENGTH;
+ break;
+
+ case GTPV1_TV_REORDER:
+
+ /* 29.060 7.7.6 - Reordering Required. */
+ TCHECK2(cp[0], GTPV1_TV_REORDER_LENGTH - 1);
+ printf("Reordering Required: ");
+ if (cp[0] & 0x1)
+ printf("yes");
+ else
+ printf("no");
+ ielen = GTPV1_TV_REORDER_LENGTH;
+ break;
+
+ case GTPV1_TV_AUTH:
+
+ /* 29.060 7.7.7 - Authentication Triplet. */
+ TCHECK2(cp[0], GTPV1_TV_AUTH_LENGTH - 1);
+ dpl = (u_int32_t *)cp;
+ printf("Auth: RAND 0x%x%x%x%x, SRES 0x%x, Kc 0x%x%x",
+ ntohl(dpl[0]), ntohl(dpl[1]), ntohl(dpl[2]), ntohl(dpl[3]),
+ ntohl(dpl[4]), ntohl(dpl[5]), ntohl(dpl[6]));
+ ielen = GTPV1_TV_AUTH_LENGTH;
+ break;
+
+ case GTPV1_TV_MAP_CAUSE:
+
+ /* 29.060 7.7.8 - MAP Cause. */
+ /* Cause defined in 3GPP TS 29.002. */
+ TCHECK2(cp[0], GTPV1_TV_MAP_CAUSE_LENGTH - 1);
+ printf("Map Cause: %u", cp[0]);
+ ielen = GTPV1_TV_MAP_CAUSE_LENGTH;
+ break;
+
+ case GTPV1_TV_PTMSI_SIGNATURE:
+
+ /* 29.060 7.7.9 - P-TMSI Signature. */
+ /* Signature defined in 3GPP TS 24.008. */
+ TCHECK2(cp[0], GTPV1_TV_PTMSI_SIGNATURE_LENGTH - 1);
+ printf("PTMSI Signature: 0x%x%x%x", cp[0], cp[1], cp[2]);
+ ielen = GTPV1_TV_PTMSI_SIGNATURE_LENGTH;
+ break;
+
+ case GTPV1_TV_MS_VALIDATED:
+
+ /* 29.060 7.7.10 - MS Validated. */
+ TCHECK2(cp[0], GTPV1_TV_MS_VALIDATED_LENGTH - 1);
+ printf("MS Validated: ");
+ if (cp[0] & 0x1)
+ printf("yes");
+ else
+ printf("no");
+ ielen = GTPV1_TV_MS_VALIDATED_LENGTH;
+ break;
+
+ case GTPV1_TV_RECOVERY:
+
+ /* 29.060 7.7.11 - Recovery. */
+ TCHECK2(cp[0], GTPV1_TV_RECOVERY_LENGTH - 1);
+ printf("Recovery: Restart counter %u", cp[0]);
+ ielen = GTPV1_TV_RECOVERY_LENGTH;
+ break;
+
+ case GTPV1_TV_SELECTION_MODE:
+
+ /* 29.060 7.7.12 - Selection Mode. */
+ TCHECK2(cp[0], GTPV1_TV_SELECTION_MODE_LENGTH - 1);
+ data = (u_int8_t)cp[0];
+ printf("Selection Mode: %u", data & 0x2);
+ ielen = GTPV1_TV_SELECTION_MODE_LENGTH;
+ break;
+
+ case GTPV1_TV_TEID_DATA_I:
+
+ /* 29.060 7.7.13 - Tunnel Endpoint Identifier Data I. */
+ TCHECK2(cp[0], GTPV1_TV_TEID_DATA_I_LENGTH - 1);
+ dpl = (u_int32_t *)cp;
+ printf("TEI Data I: %u", ntohl(*dpl));
+ ielen = GTPV1_TV_TEID_DATA_I_LENGTH;
+ break;
+
+ case GTPV1_TV_TEID_CTRL:
+
+ /* 29.060 7.7.14 - Tunnel Endpoint Identifier Control Plane. */
+ TCHECK2(cp[0], GTPV1_TV_TEID_CTRL_LENGTH - 1);
+ dpl = (u_int32_t *)cp;
+ printf("TEI Control Plane: %u", ntohl(*dpl));
+ ielen = GTPV1_TV_TEID_CTRL_LENGTH;
+ break;
+
+ case GTPV1_TV_TEID_DATA_II:
+
+ /* 29.060 7.7.15 - Tunnel Endpoint Identifier Data II. */
+ TCHECK2(cp[0], GTPV1_TV_TEID_DATA_II_LENGTH - 1);
+ data = cp[0] & 0xf;
+ dpl = (u_int32_t *)(cp + 1);
+ printf("TEI Data II: %u, NSAPI %u", ntohl(*dpl), data);
+ ielen = GTPV1_TV_TEID_DATA_II_LENGTH;
+ break;
+
+ case GTPV1_TV_TEARDOWN:
+
+ /* 29.060 7.7.16 - Teardown Indicator. */
+ TCHECK2(cp[0], GTPV1_TV_TEARDOWN_LENGTH - 1);
+ printf("Teardown: ");
+ if (cp[0] & 0x1)
+ printf("yes");
+ else
+ printf("no");
+ ielen = GTPV1_TV_TEARDOWN_LENGTH;
+ break;
+
+ case GTPV1_TV_NSAPI:
+
+ /* 29.060 7.7.17 - NSAPI. */
+ TCHECK2(cp[0], GTPV1_TV_NSAPI_LENGTH - 1);
+ data = (u_int8_t)cp[0];
+ printf("NSAPI %u", data & 0xf);
+ ielen = GTPV1_TV_NSAPI_LENGTH;
+ break;
+
+ case GTPV1_TV_RANAP:
+
+ /* 29.060 7.7.18 - RANAP Cause. */
+ TCHECK2(cp[0], GTPV1_TV_RANAP_LENGTH - 1);
+ printf("RANAP Cause: %u", cp[0]);
+ ielen = GTPV1_TV_RANAP_LENGTH;
+ break;
+
+ case GTPV1_TV_RAB_CONTEXT:
+
+ /* 29.060 7.7.19 - RAB Context. */
+ TCHECK2(cp[0], GTPV1_TV_RAB_CONTEXT_LENGTH - 1);
+ data = cp[0] & 0xf;
+ dps = (u_int16_t *)(cp + 1);
+ printf("RAB Context: NSAPI %u, DL GTP-U Seq No %u,"
+ "UL GTP-U Seq No %u, DL PDCP Seq No %u, UL PDCP Seq No %u",
+ data, ntohs(dps[0]), ntohs(dps[1]), ntohs(dps[2]),
+ ntohs(dps[3]));
+ ielen = GTPV1_TV_RAB_CONTEXT_LENGTH;
+ break;
+
+ case GTPV1_TV_RADIO_PRIORITY_SMS:
+
+ /* 29.060 7.7.20 - Radio Priority SMS. */
+ TCHECK2(cp[0], GTPV1_TV_RADIO_PRI_SMS_LENGTH - 1);
+ printf("Radio Priority SMS: %u", cp[0] & 0x7);
+ ielen = GTPV1_TV_RADIO_PRI_SMS_LENGTH;
+ break;
+
+ case GTPV1_TV_RADIO_PRIORITY:
+
+ /* 29.060 7.7.21 - Radio Priority. */
+ TCHECK2(cp[0], GTPV1_TV_RADIO_PRI_LENGTH - 1);
+ data = cp[0] >> 4;
+ printf("Radio Priority: %u, NSAPI %u", cp[0] & 0x7, data);
+ ielen = GTPV1_TV_RADIO_PRI_LENGTH;
+ break;
+
+ case GTPV1_TV_PACKET_FLOW_ID:
+
+ /* 29.060 7.7.22 - Packet Flow ID. */
+ TCHECK2(cp[0], GTPV1_TV_PACKET_FLOW_ID_LENGTH - 1);
+ printf("Packet Flow ID: %u, NSAPI %u", cp[1], cp[0] & 0xf);
+ ielen = GTPV1_TV_PACKET_FLOW_ID_LENGTH;
+ break;
+
+ case GTPV1_TV_CHARGING:
+
+ /* 29.060 7.7.23 - Charging Characteristics. */
+ /* Charging defined in 3GPP TS 32.298. */
+ TCHECK2(cp[0], GTPV1_TV_CHARGING_LENGTH - 1);
+ printf("Charging Characteristics"); /* XXX */
+ ielen = GTPV1_TV_CHARGING_LENGTH;
+ break;
+
+ case GTPV1_TV_TRACE_REFERENCE:
+
+ /* 29.060 7.7.24 - Trace Reference. */
+ TCHECK2(cp[0], GTPV1_TV_TRACE_REFERENCE_LENGTH - 1);
+ dps = (u_int16_t *)cp;
+ printf("Trace Reference: %u", ntohs(*dps));
+ ielen = GTPV1_TV_TRACE_REFERENCE_LENGTH;
+ break;
+
+ case GTPV1_TV_TRACE_TYPE:
+
+ /* 29.060 7.7.25 - Trace Type. */
+ /* Trace type defined in GSM 12.08. */
+ TCHECK2(cp[0], GTPV1_TV_TRACE_TYPE_LENGTH - 1);
+ dps = (u_int16_t *)cp;
+ printf("Trace Type: %u", ntohs(*dps));
+ ielen = GTPV1_TV_TRACE_TYPE_LENGTH;
+ break;
+
+ case GTPV1_TV_MSNRR:
+
+ /* 29.060 7.7.26 - MS Not Reachable Reason. */
+ /* Reason defined in 3GPP TS 23.040. */
+ TCHECK2(cp[0], GTPV1_TV_MSNRR_LENGTH - 1);
+ printf("MS NRR: %u", cp[0]);
+ ielen = GTPV1_TV_MSNRR_LENGTH;
+ break;
+
+ case GTPV1_TV_PACKET_XFER_CMD:
+
+ /* 32.295 6.2.4.5.2 - Packet Transfer Command. */
+ TCHECK2(cp[0], GTPV1_TV_PACKET_XFER_CMD_LENGTH - 1);
+ printf("Packet Transfer Command");
+ gtp_print_str(gtp_packet_xfer_cmd, cp[0]);
+ ielen = GTPV1_TV_PACKET_XFER_CMD_LENGTH;
+ break;
+
+ case GTPV1_TV_CHARGING_ID:
+
+ /* 29.060 7.7.26 - Charging ID. */
+ TCHECK2(cp[0], GTPV1_TV_CHARGING_ID_LENGTH - 1);
+ dpl = (u_int32_t *)cp;
+ printf("Charging ID: %u", ntohl(*dpl));
+ ielen = GTPV1_TV_CHARGING_ID_LENGTH;
+ break;
+
+ default:
+ printf("TV %u", value);
+ }
+
+trunc:
+ return ielen;
+}
+
+int
+gtp_v1_print_tlv(register const u_char *cp, u_int value)
+{
+ u_int8_t data;
+ u_int16_t *lenp, *seqno, len;
+ u_char *buf;
+ int ielen = -1;
+
+ /* Get length of IE. */
+ TCHECK2(cp[0], 2);
+ lenp = (u_int16_t *)cp;
+ cp += 2;
+ len = ntohs(*lenp);
+ TCHECK2(cp[0], len);
+ ielen = sizeof(data) + sizeof(len) + len;
+
+ switch (value) {
+ case GTPV1_TLV_END_USER_ADDRESS:
+
+ /* 3GPP 29.060 - 7.7.27 End User Address. */
+ printf("End User Address");
+ gtp_print_user_address(cp, len);
+ break;
+
+ case GTPV1_TLV_MM_CONTEXT:
+
+ /* 29.060 7.7.28 - MM Context. */
+ printf("MM Context"); /* XXX */
+ break;
+
+ case GTPV1_TLV_PDP_CONTEXT:
+
+ /* 29.260 7.7.29 - PDP Context. */
+ printf("PDP Context"); /* XXX */
+ break;
+
+ case GTPV1_TLV_ACCESS_POINT_NAME:
+
+ /* 29.060 7.7.30 - Access Point Name. */
+ printf("AP Name");
+ len = (u_int8_t)cp[0];
+ if ((buf = malloc(len + 1)) != NULL) {
+ bcopy(cp + 1, buf, len);
+ buf[len] = '\0';
+ printf(": %s", buf);
+ free(buf);
+ }
+ break;
+
+ case GTPV1_TLV_PROTOCOL_CONFIG_OPTIONS:
+
+ /* 29.060 7.7.31 - Protocol Configuration Options. */
+ /* Defined in 3GPP TS 24.008. */
+ printf("Config Options"); /* XXX */
+ break;
+
+ case GTPV1_TLV_GSN_ADDRESS:
+
+ /* 29.060 7.7.32 - GSN Address. */
+ /* Defined in 3GPP TS 23.003. */
+ printf("GSN Address");
+ if (len == 4)
+ printf(": %s", ipaddr_string(cp));
+#ifdef INET6
+ else if (len == 16)
+ printf(": %s", ip6addr_string(cp));
+#endif
+ break;
+
+ case GTPV1_TLV_MSISDN:
+
+ /* 29.060 7.7.33 - MS International PSTN/ISDN Number. */
+ printf("MSISDN ");
+ data = (u_int8_t)cp[0]; /* XXX - Number type. */
+ gtp_print_tbcd(cp + 1, len - 1);
+ break;
+
+ case GTPV1_TLV_QOS_PROFILE:
+
+ /* 29.060 7.7.34 - QoS Profile. */
+ /* QoS profile defined in 3GPP TS 24.008 10.5.6.5. */
+ printf("QoS Profile: ");
+ data = (u_int8_t)cp[0];
+ printf("Delay Class %u, ", (data >> 3) & 0x7);
+ printf("Reliability Class %u", data & 0x7);
+ if (vflag > 1) {
+ printf(", ");
+ data = (u_int8_t)cp[1];
+ printf("Precedence Class %u", data & 0x7);
+ /* XXX - Decode more QoS fields. */
+ }
+ break;
+
+ case GTPV1_TLV_AUTHENTICATION:
+
+ /* 29.060 7.7.35 - Authentication. */
+ printf("Authentication"); /* XXX */
+ break;
+
+ case GTPV1_TLV_TRAFFIC_FLOW:
+
+ /* 29.060 7.7.36 - Traffic Flow Template. */
+ printf("Traffic Flow Template"); /* XXX */
+ break;
+
+ case GTPV1_TLV_TARGET_IDENTIFICATION:
+
+ /* 29.060 7.7.37 - Target Identification. */
+ printf("Target ID"); /* XXX */
+ break;
+
+ case GTPV1_TLV_UTRAN_CONTAINER:
+
+ /* 29.060 7.7.38 - UTRAN Transparent Container. */
+ printf("UTRAN Container"); /* XXX */
+ break;
+
+ case GTPV1_TLV_RAB_SETUP_INFORMATION:
+
+ /* 29.060 7.7.39 - RAB Setup Information. */
+ printf("RAB Setup"); /* XXX */
+ break;
+
+ case GTPV1_TLV_EXT_HEADER_TYPE_LIST:
+
+ /* 29.060 7.7.40 - Extension Header Type List. */
+ printf("Extension Header List"); /* XXX */
+ break;
+
+ case GTPV1_TLV_TRIGGER_ID:
+
+ /* 29.060 7.7.41 - Trigger ID. */
+ printf("Trigger ID"); /* XXX */
+ break;
+
+ case GTPV1_TLV_OMC_IDENTITY:
+
+ /* 29.060 7.7.42 - OMC Identity. */
+ printf("OMC Identity"); /* XXX */
+ break;
+
+ case GTPV1_TLV_RAN_CONTAINER:
+
+ /* 29.060 7.7.43 - RAN Transparent Container. */
+ printf("RAN Container"); /* XXX */
+ break;
+
+ case GTPV1_TLV_PDP_CONTEXT_PRIORITIZATION:
+
+ /* 29.060 7.7.45 - PDP Context Prioritization. */
+ printf("PDP Context Prioritization"); /* XXX */
+ break;
+
+ case GTPV1_TLV_ADDITIONAL_RAB_SETUP_INFO:
+
+ /* 29.060 7.7.45A - Additional RAB Setup Information. */
+ printf("Additional RAB Setup"); /* XXX */
+ break;
+
+ case GTPV1_TLV_SGSN_NUMBER:
+
+ /* 29.060 7.7.47 - SGSN Number. */
+ printf("SGSN Number"); /* XXX */
+ break;
+
+ case GTPV1_TLV_COMMON_FLAGS:
+
+ /* 29.060 7.7.48 - Common Flags. */
+ printf("Common Flags"); /* XXX */
+ break;
+
+ case GTPV1_TLV_APN_RESTRICTION:
+
+ /* 29.060 7.7.49 - APN Restriction. */
+ data = (u_int8_t)cp[0];
+ printf("APN Restriction: %u", data);
+ break;
+
+ case GTPV1_TLV_RADIO_PRIORITY_LCS:
+
+ /* 29.060 7.7.25B - Radio Priority LCS. */
+ printf("Radio Priority LCS: %u", cp[0] & 0x7);
+ break;
+
+ case GTPV1_TLV_RAT_TYPE:
+
+ /* 29.060 7.7.50 - RAT Type. */
+ printf("RAT");
+ gtp_print_str(gtp_rat_type, cp[0]);
+ break;
+
+ case GTPV1_TLV_USER_LOCATION_INFO:
+
+ /* 29.060 7.7.51 - User Location Information. */
+ printf("ULI"); /* XXX */
+ break;
+
+ case GTPV1_TLV_MS_TIME_ZONE:
+
+ /* 29.060 7.7.52 - MS Time Zone. */
+ printf("MSTZ"); /* XXX */
+ break;
+
+ case GTPV1_TLV_IMEI_SV:
+
+ /* 29.060 7.7.53 - IMEI(SV). */
+ printf("IMEI(SV) ");
+ gtp_print_tbcd(cp, len);
+ break;
+
+ case GTPV1_TLV_CAMEL_CHARGING_CONTAINER:
+
+ /* 29.060 7.7.54 - CAMEL Charging Information Container. */
+ printf("CAMEL Charging"); /* XXX */
+ break;
+
+ case GTPV1_TLV_MBMS_UE_CONTEXT:
+
+ /* 29.060 7.7.55 - MBMS UE Context. */
+ printf("MBMS UE Context"); /* XXX */
+ break;
+
+ case GTPV1_TLV_TMGI:
+
+ /* 29.060 7.7.56 - Temporary Mobile Group Identity. */
+ printf("TMGI"); /* XXX */
+ break;
+
+ case GTPV1_TLV_RIM_ROUTING_ADDRESS:
+
+ /* 29.060 7.7.57 - RIM Routing Address. */
+ printf("RIM Routing Address"); /* XXX */
+ break;
+
+ case GTPV1_TLV_MBMS_PROTOCOL_CONFIG_OPTIONS:
+
+ /* 29.060 7.7.58 - MBMS Protocol Configuration Options. */
+ printf("MBMS Protocol Config Options"); /* XXX */
+ break;
+
+ case GTPV1_TLV_MBMS_SERVICE_AREA:
+
+ /* 29.060 7.7.60 - MBMS Service Area. */
+ printf("MBMS Service Area"); /* XXX */
+ break;
+
+ case GTPV1_TLV_SOURCE_RNC_PDCP_CONTEXT_INFO:
+
+ /* 29.060 7.7.61 - Source RNC PDCP Context Information. */
+ printf("Source RNC PDCP Context"); /* XXX */
+ break;
+
+ case GTPV1_TLV_ADDITIONAL_TRACE_INFO:
+
+ /* 29.060 7.7.62 - Additional Trace Information. */
+ printf("Additional Trace Info"); /* XXX */
+ break;
+
+ case GTPV1_TLV_HOP_COUNTER:
+
+ /* 29.060 7.7.63 - Hop Counter. */
+ printf("Hop Counter: %u", cp[0]);
+ break;
+
+ case GTPV1_TLV_SELECTED_PLMN_ID:
+
+ /* 29.060 7.7.64 - Selected PLMN ID. */
+ printf("Selected PLMN ID"); /* XXX */
+ break;
+
+ case GTPV1_TLV_MBMS_SESSION_IDENTIFIER:
+
+ /* 29.060 7.7.65 - MBMS Session Identifier. */
+ printf("MBMS Session ID: %u", cp[0]);
+ break;
+
+ case GTPV1_TLV_MBMS_2G_3G_INDICATOR:
+
+ /* 29.060 7.7.66 - MBMS 2G/3G Indicator. */
+ printf("MBMS 2G/3G Indicator");
+ gtp_print_str(mbms_2g3g_indicator, cp[0]);
+ break;
+
+ case GTPV1_TLV_ENHANCED_NSAPI:
+
+ /* 29.060 7.7.67 - Enhanced NSAPI. */
+ printf("Enhanced NSAPI"); /* XXX */
+ break;
+
+ case GTPV1_TLV_MBMS_SESSION_DURATION:
+
+ /* 29.060 7.7.59 - MBMS Session Duration. */
+ printf("MBMS Session Duration"); /* XXX */
+ break;
+
+ case GTPV1_TLV_ADDITIONAL_MBMS_TRACE_INFO:
+
+ /* 29.060 7.7.68 - Additional MBMS Trace Info. */
+ printf("Additional MBMS Trace Info"); /* XXX */
+ break;
+
+ case GTPV1_TLV_MBMS_SESSION_REPITITION_NO:
+
+ /* 29.060 7.7.69 - MBMS Session Repetition Number. */
+ printf("MBMS Session Repetition No: %u", cp[0]);
+ break;
+
+ case GTPV1_TLV_MBMS_TIME_TO_DATA_TRANSFER:
+
+ /* 29.060 7.7.70 - MBMS Time to Data Transfer. */
+ printf("MBMS Time to Data Transfer: %u", cp[0]);
+ break;
+
+ case GTPV1_TLV_PS_HANDOVER_REQUEST_CONTEXT:
+
+ /* 29.060 7.7.71 - PS Handover Request Context (Void). */
+ break;
+
+ case GTPV1_TLV_BSS_CONTAINER:
+
+ /* 29.060 7.7.72 - BSS Container. */
+ printf("BSS Container"); /* XXX */
+ break;
+
+ case GTPV1_TLV_CELL_IDENTIFICATION:
+
+ /* 29.060 7.7.73 - Cell Identification. */
+ printf("Cell Identification"); /* XXX */
+ break;
+
+ case GTPV1_TLV_PDU_NUMBERS:
+
+ /* 29.060 7.7.74 - PDU Numbers. */
+ printf("PDU Numbers"); /* XXX */
+ break;
+
+ case GTPV1_TLV_BSSGP_CAUSE:
+
+ /* 29.060 7.7.75 - BSSGP Cause. */
+ printf("BSSGP Cause: %u", cp[0]);
+ break;
+
+ case GTPV1_TLV_REQUIRED_MBMS_BEARER_CAP:
+
+ /* 29.060 7.7.76 - Required MBMS Bearer Cap. */
+ printf("Required MBMS Bearer Cap"); /* XXX */
+ break;
+
+ case GTPV1_TLV_RIM_ROUTING_ADDRESS_DISC:
+
+ /* 29.060 7.7.77 - RIM Routing Address Discriminator. */
+ printf("RIM Routing Address Discriminator: %u", cp[0] & 0xf);
+ break;
+
+ case GTPV1_TLV_LIST_OF_SETUP_PFCS:
+
+ /* 29.060 7.7.78 - List of Setup PFCs. */
+ printf("List of Setup PFCs"); /* XXX */
+ break;
+
+ case GTPV1_TLV_PS_HANDOVER_XID_PARAMETERS:
+
+ /* 29.060 7.7.79 - PS Handover XID Parameters. */
+ printf("PS Handover XID Parameters"); /* XXX */
+ break;
+
+ case GTPV1_TLV_MS_INFO_CHANGE_REPORTING:
+
+ /* 29.060 7.7.80 - MS Info Change Reporting. */
+ printf("MS Info Change Reporting");
+ gtp_print_str(ms_info_change_rpt, cp[0]);
+ break;
+
+ case GTPV1_TLV_DIRECT_TUNNEL_FLAGS:
+
+ /* 29.060 7.7.81 - Direct Tunnel Flags. */
+ printf("Direct Tunnel Flags"); /* XXX */
+ break;
+
+ case GTPV1_TLV_CORRELATION_ID:
+
+ /* 29.060 7.7.82 - Correlation ID. */
+ printf("Correlation ID"); /* XXX */
+ break;
+
+ case GTPV1_TLV_BEARER_CONTROL_MODE:
+
+ /* 29.060 7.7.83 - Bearer Control Mode. */
+ printf("Bearer Control Mode"); /* XXX */
+ break;
+
+ case GTPV1_TLV_MBMS_FLOW_IDENTIFIER:
+
+ /* 29.060 7.7.84 - MBMS Flow Identifier. */
+ printf("MBMS Flow Identifier"); /* XXX */
+ break;
+
+ case GTPV1_TLV_RELEASED_PACKETS:
+
+ /* 32.295 6.2.4.5.4 - Sequence Numbers of Released Packets. */
+ printf("Released Packets:");
+ seqno = (u_int16_t *)cp;
+ while (len > 0) {
+ printf(" %u", ntohs(*seqno));
+ seqno++;
+ len -= sizeof(*seqno);
+ }
+ break;
+
+ case GTPV1_TLV_CANCELLED_PACKETS:
+
+ /* 32.295 6.2.4.5.5 - Sequence Numbers of Cancelled Packets. */
+ printf("Cancelled Packets:");
+ seqno = (u_int16_t *)cp;
+ while (len > 0) {
+ printf(" %u", ntohs(*seqno));
+ seqno++;
+ len -= sizeof(*seqno);
+ }
+ break;
+
+ case GTPV1_TLV_CHARGING_GATEWAY_ADDRESS:
+
+ /* 29.060 7.7.44 - Charging Gateway Address. */
+ printf("Charging Gateway");
+ if (len == 4)
+ printf(": %s", ipaddr_string(cp));
+#ifdef INET6
+ else if (len == 16)
+ printf(": %s", ip6addr_string(cp));
+#endif
+ break;
+
+ case GTPV1_TLV_DATA_RECORD_PACKET:
+
+ /* 32.295 6.2.4.5.3 - Data Record Packet. */
+ printf("Data Record: Records %u, Format %u, Format Version %u",
+ cp[0], cp[1], ntohs(*(u_int16_t *)(cp + 2)));
+ break;
+
+ case GTPV1_TLV_REQUESTS_RESPONDED:
+
+ /* 32.295 6.2.4.6 - Requests Responded. */
+ printf("Requests Responded:");
+ seqno = (u_int16_t *)cp;
+ while (len > 0) {
+ printf(" %u", ntohs(*seqno));
+ seqno++;
+ len -= sizeof(*seqno);
+ }
+ break;
+
+ case GTPV1_TLV_ADDRESS_OF_RECOMMENDED_NODE:
+
+ /* 32.295 6.2.4.3 - Address of Recommended Node. */
+ printf("Address of Recommended Node");
+ if (len == 4)
+ printf(": %s", ipaddr_string(cp));
+#ifdef INET6
+ else if (len == 16)
+ printf(": %s", ip6addr_string(cp));
+#endif
+ break;
+
+ case GTPV1_TLV_PRIVATE_EXTENSION:
+
+ /* 29.060 7.7.46 - Private Extension. */
+ printf("Private Extension");
+ break;
+
+ default:
+ printf("TLV %u (len %u)", value, len);
+ }
+
+ return ielen;
+
+trunc:
+ return -1;
+}