FAQ was updated
[obnox/wireshark/wip.git] / packet-gtp.c
index e30956cab094ae774c572e6bbbc28fe46d8a3c8a..bec0f708cefd100573abc7e0e3f77f70b2baba8c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2001, Michal Melerowicz <michal.melerowicz@nokia.com>
  *                 Nicolas Balkota <balkota@mac.com>
  *
- * $Id: packet-gtp.c,v 1.39 2002/10/26 06:13:33 guy Exp $
+ * $Id: packet-gtp.c,v 1.53 2003/02/07 19:57:19 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -38,7 +38,7 @@
 #include <epan/packet.h>
 #include "packet-gtp.h"
 #include "packet-ipv6.h"
-#include "ppptypes.h"
+#include "packet-ppp.h"
 #include "prefs.h"
 
 /*
@@ -347,7 +347,6 @@ static gboolean     gtpv1_etsi_order        = FALSE;
 static int     gtpv0_port              = 0;
 static int     gtpv1c_port             = 0;
 static int     gtpv1u_port             = 0;
-static gboolean ppp_reorder            = TRUE;
 
 /* Definition of flags masks */
 #define GTP_VER_MASK 0xE0
@@ -459,12 +458,6 @@ static const value_string ver_types[] = {
 #define GTP_MSG_DATA_TRANSF_RESP       0xF1
 #define GTP_MSG_TPDU                   0xFF
 
-#define GTP_PPP_0x00                   0x00
-#define GTP_PPP_0xC0                   0xC0
-#define GTP_PPP_0x80                   0x80
-#define GTP_PPP_0xC2                   0xC2
-#define GTP_PPP_REQ_ERROR              0xFF
-
 static const value_string message_type[] = {
        { GTP_MSG_UNKNOWN,              "For future use" },
        { GTP_MSG_ECHO_REQ,             "Echo request" },
@@ -584,7 +577,7 @@ static const value_string message_type[] = {
 
 static const value_string gtp_val[] = {
        { GTP_EXT_CAUSE,        "Cause of operation" },
-       { GTP_EXT_IMSI,         "IMSI " },
+       { GTP_EXT_IMSI,         "IMSI" },
        { GTP_EXT_RAI,          "Routing Area Identity" },
        { GTP_EXT_TLLI,         "Temporary Logical Link Identity" },
        { GTP_EXT_PTMSI,        "Packet TMSI" },
@@ -618,14 +611,14 @@ static const value_string gtp_val[] = {
        { GTP_EXT_RAB_CNTXT,    "RAB context" },                                        /* 3G */
        { GTP_EXT_RP_SMS,       "Radio Priority for MO SMS" },                  /* 3G */
        { GTP_EXT_RP,           "Radio Priority" },                                     /* 3G */
-       { GTP_EXT_PKT_FLOW_ID,  "Packet Flow ID " },                                    /* 3G */
+       { GTP_EXT_PKT_FLOW_ID,  "Packet Flow ID" },                                     /* 3G */
        { GTP_EXT_CHRG_CHAR,    "Charging characteristics" },                           /* 3G */
        { GTP_EXT_TRACE_REF,    "Trace references" },                                   /* 3G */
        { GTP_EXT_TRACE_TYPE,   "Trace type" },                                 /* 3G */
        { GTPv1_EXT_MS_REASON,  "MS not reachable reason" },                            /* 3G */
        { GTP_EXT_TR_COMM,      "Packet transfer command" },                            /* charging */
        { GTP_EXT_CHRG_ID,      "Charging ID" },
-       { GTP_EXT_USER_ADDR,    "End user address " },
+       { GTP_EXT_USER_ADDR,    "End user address" },
        { GTP_EXT_MM_CNTXT,     "MM context" },
        { GTP_EXT_PDP_CNTXT,    "PDP context" },
        { GTP_EXT_APN,          "Access Point Name" },
@@ -638,16 +631,16 @@ static const value_string gtp_val[] = {
        { GTP_EXT_TARGET_ID,    "Target (RNC) identification" },                        /* 3G */
        { GTP_EXT_UTRAN_CONT,   "UTRAN transparent field" },                            /* 3G */
        { GTP_EXT_RAB_SETUP,    "RAB setup information" },                              /* 3G */
-       { GTP_EXT_HDR_LIST,     "Extension Header Types List " },                       /* 3G */
-       { GTP_EXT_TRIGGER_ID,   "Trigger Id " },                                        /* 3G */
-       { GTP_EXT_OMC_ID,       "OMC Identity " },                                      /* 3G */
+       { GTP_EXT_HDR_LIST,     "Extension Header Types List" },                        /* 3G */
+       { GTP_EXT_TRIGGER_ID,   "Trigger Id" },                                 /* 3G */
+       { GTP_EXT_OMC_ID,       "OMC Identity" },                                       /* 3G */
        { GTP_EXT_REL_PACK,     "Sequence numbers of released packets IE" },            /* charging */
        { GTP_EXT_CAN_PACK,     "Sequence numbers of canceled packets IE" },            /* charging */
        { GTP_EXT_CHRG_ADDR,    "Charging Gateway address" },
        { GTP_EXT_DATA_REQ,     "Data record packet" },                         /* charging */
        { GTP_EXT_DATA_RESP,    "Requests responded" },                         /* charging */
        { GTP_EXT_NODE_ADDR,    "Address of recommended node" },                        /* charging */
-       { GTP_EXT_PRIV_EXT,     "Private Extension " },
+       { GTP_EXT_PRIV_EXT,     "Private Extension" },
        { 0, NULL }
 };
 
@@ -1202,7 +1195,7 @@ static const value_string mm_rr_mess[] = {
        { 0x10, "Channel mode modify" },
        { 0x12, "RR status" },
        { 0x17, "Channel mode modify ack" },
-       { 0x14, "Frequency redefinition " },
+       { 0x14, "Frequency redefinition" },
        { 0x15, "Measurement report" },
        { 0x16, "Classmark change" },
        { 0x13, "Classmark enquiry" },
@@ -1336,7 +1329,9 @@ static const value_string cdr_close_type[] = {
 };
 
 static dissector_handle_t ip_handle;
+static dissector_handle_t ipv6_handle;
 static dissector_handle_t ppp_handle;
+static dissector_handle_t data_handle;
 
 static int decode_gtp_cause            (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
 static int decode_gtp_imsi             (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
@@ -1677,6 +1672,23 @@ id_to_str(const guint8 *ad) {
        return p;
 }
 
+static gchar *
+imsi_to_str(const guint8 *ad) {
+
+       static gchar    *str[16];
+       gchar           *p;
+       guint8          i, j = 0;
+       
+       p = (gchar *)&str[0];
+       for (i=0;i<8;i++) {
+               if ((ad[i] & 0x0F) <= 9) p[j++] = (ad[i] & 0x0F) + 0x30;
+               if (((ad[i] >> 4) & 0x0F) <= 9) p[j++] = ((ad[i] >> 4) & 0x0F) + 0x30;
+       }
+       p[j] = 0;
+       
+       return p;
+}
+
 static gchar *
 msisdn_to_str(const guint8 *ad, int len) {
 
@@ -2499,14 +2511,13 @@ decode_gtp_cause(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *
 static int
 decode_gtp_imsi(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree) {
 
-       guint8  tid_val[8];
-       gchar   *tid_str;
+       guint8  imsi_val[8];
+       gchar   *imsi_str;
 
-       tvb_memcpy(tvb, tid_val, offset+1, 8);
-       tid_val[1] = tid_val[1] & 0x0F;
-       tid_str = id_to_str(tid_val);
+       tvb_memcpy(tvb, imsi_val, offset+1, 8);
+       imsi_str = imsi_to_str (imsi_val);
 
-       proto_tree_add_string(tree, gtp_version ? hf_gtpv1_imsi : hf_gtpv0_imsi, tvb, offset, 9, tid_str);
+       proto_tree_add_string(tree, gtp_version ? hf_gtpv1_imsi : hf_gtpv0_imsi, tvb, offset, 9, imsi_str);
 
        return 9;
 }
@@ -3053,7 +3064,7 @@ decode_gtp_ms_reason(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tr
 }
 
 
-/* GPRS:       12.15
+/* GPRS:       12.15 v7.6.0, chapter 7.3.3, page 45
  * UMTS:       33.015
  */
 static int
@@ -3061,7 +3072,7 @@ decode_gtp_tr_comm(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree
 
        guint8  tr_command;
 
-       tr_command = tvb_get_ntohl(tvb, offset+1);
+       tr_command = tvb_get_guint8(tvb, offset+1);
 
        proto_tree_add_uint(tree, gtp_version ? hf_gtpv1_tr_comm : hf_gtpv0_tr_comm, tvb, offset, 2, tr_command);
 
@@ -3200,7 +3211,6 @@ decode_gtp_mm_cntxt(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tre
 
        guint16         length, quint_len, net_cap, con_len;
        guint8          cksn, count, sec_mode, cipher, trans_id, proto_disc, message, drx_split, drx_len, drx_ccch, non_drx_timer;
-       guint32         kc[4], ik[4];
        proto_tree      *ext_tree_mm;
        proto_item      *te;
 
@@ -3232,10 +3242,8 @@ decode_gtp_mm_cntxt(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tre
                        } else {
                                proto_tree_add_text(ext_tree_mm, tvb, offset+4, 1, "Ciphering: GEA/%u", cipher);
                        }
-                       tvb_memcpy(tvb, (guint8 *)&kc, offset+5, 16);
-                       proto_tree_add_text(ext_tree_mm, tvb, offset+5, 16, "Ciphering key CK: %x%x%x%x", kc[0], kc[1], kc[2], kc[3]);
-                       tvb_memcpy(tvb, (guint8 *)&ik, offset+21, 16);
-                       proto_tree_add_text(ext_tree_mm, tvb, offset+21, 16, "Integrity key CK: %x%x%x%x", ik[0], ik[1], ik[2], ik[3]);
+                       proto_tree_add_text(ext_tree_mm, tvb, offset+5, 16, "Ciphering key CK: %s", tvb_bytes_to_str(tvb, offset+5, 16));
+                       proto_tree_add_text(ext_tree_mm, tvb, offset+21, 16, "Integrity key CK: %s", tvb_bytes_to_str(tvb, offset+21, 16));
                        quint_len = tvb_get_ntohs(tvb, offset+37);
                        proto_tree_add_text(ext_tree_mm, tvb, offset+37, 2, "Quintuplets length: %x", quint_len);
 
@@ -3249,17 +3257,14 @@ decode_gtp_mm_cntxt(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tre
                        } else {
                                proto_tree_add_text(ext_tree_mm, tvb, offset+4, 1, "Ciphering: GEA/%u", cipher);
                        }
-                       tvb_memcpy(tvb, (guint8 *)&kc, offset+5, 8);
-                       proto_tree_add_text(ext_tree_mm, tvb, offset+5, 8, "Ciphering key Kc: %x%x", kc[0], kc[1]);
+                       proto_tree_add_text(ext_tree_mm, tvb, offset+5, 8, "Ciphering key Kc: %s", tvb_bytes_to_str(tvb, offset+5, 8));
 
                        offset = offset + decode_triplet(tvb, offset+13, ext_tree_mm, count) + 13;
 
                        break;
                case 2:
-                       tvb_memcpy(tvb, (guint8 *)&kc, offset+5, 16);
-                       proto_tree_add_text(ext_tree_mm, tvb, offset+5, 16, "Ciphering key CK: %x%x%x%x", kc[0], kc[1], kc[2], kc[3]);
-                       tvb_memcpy(tvb, (guint8 *)&ik, offset+21, 16);
-                       proto_tree_add_text(ext_tree_mm, tvb, offset+21, 16, "Integrity key CK: %x%x%x%x", ik[0], ik[1], ik[2], ik[3]);
+                       proto_tree_add_text(ext_tree_mm, tvb, offset+5, 16, "Ciphering key CK: %s", tvb_bytes_to_str(tvb, offset+5, 16));
+                       proto_tree_add_text(ext_tree_mm, tvb, offset+21, 16, "Integrity key CK: %s", tvb_bytes_to_str(tvb, offset+21, 16));
                        quint_len = tvb_get_ntohs(tvb, offset+37);
                        proto_tree_add_text(ext_tree_mm, tvb, offset+37, 2, "Quintuplets length: %x", quint_len);
 
@@ -3272,8 +3277,7 @@ decode_gtp_mm_cntxt(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tre
                        } else {
                                proto_tree_add_text(ext_tree_mm, tvb, offset+4, 1, "Ciphering: GEA/%u", cipher);
                        }
-                       tvb_memcpy(tvb, (guint8 *)&kc, offset+5, 8);
-                       proto_tree_add_text(ext_tree_mm, tvb, offset+5, 8, "Ciphering key Kc: %x%x", kc[0], kc[1]);
+                       proto_tree_add_text(ext_tree_mm, tvb, offset+5, 8, "Ciphering key Kc: %s", tvb_bytes_to_str(tvb, offset+5, 8));
                        quint_len = tvb_get_ntohs(tvb, offset+13);
                        proto_tree_add_text(ext_tree_mm, tvb, offset+13, 2, "Quintuplets length: %x", quint_len);
 
@@ -3373,8 +3377,13 @@ decode_qos_umts(tvbuff_t *tvb, int offset, proto_tree *tree, gchar* qos_str, gui
        guint8      utf8_type = 1;
 
        /* In RADIUS messages the QoS has a version field of two octets prepended.
+        * As of 29.061 v.3.a.0, there is an hyphen between "Release Indicator" and
+        * <release specific QoS IE UTF-8 encoding>. Even if it sounds rather
+        * inconsistent and unuseful, I will check hyphen presence here and
+        * will signal its presence.
         * */
        guint8          version_buffer[2];
+       guint8      hyphen;
 
        /* Will keep the value that will be returned
         * */
@@ -3410,6 +3419,15 @@ decode_qos_umts(tvbuff_t *tvb, int offset, proto_tree *tree, gchar* qos_str, gui
                        version_buffer[1] = tvb_get_guint8(tvb, offset + 2);
                        proto_tree_add_text (ext_tree_qos, tvb, offset + 1, 2, "Version: %c%c", version_buffer[0], version_buffer[1]);
 
+                       /* Hyphen handling */
+                       hyphen = tvb_get_guint8(tvb, offset + 3);
+                       if (hyphen == ((guint8) '-'))
+                       {
+                               /* Hyphen is present, put in protocol tree */
+                               proto_tree_add_text (ext_tree_qos, tvb, offset + 3, 1, "Hyphen separator: -");
+                               offset++; /* "Get rid" of hyphen */
+                       }
+                       
                        /* Now, we modify offset here and in order to use type later
                         * effectively.*/
                        offset += 2;
@@ -3763,10 +3781,12 @@ int
 decode_gtp_proto_conf(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) {
 
        guint16         length, proto_offset;
-       guint8          *ptr, conf, proto_len, tmp, msg, cnt = 1;
+       guint16         proto_id;
+       guint8          conf, proto_len, cnt = 1;
        tvbuff_t        *next_tvb;
        proto_tree      *ext_tree_proto;
        proto_item      *te;
+       gboolean        save_writable;
 
        length = tvb_get_ntohs(tvb, offset + 1);
 
@@ -3785,36 +3805,39 @@ decode_gtp_proto_conf(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree
 
        for (;;) {
                if (proto_offset >= length) break;
+               proto_id = tvb_get_ntohs (tvb, offset);
                proto_len = tvb_get_guint8 (tvb, offset + 2);
                proto_offset += proto_len + 3;          /* 3 = proto id + length byte */
 
-               if ((proto_len > 0) && ppp_reorder) {
-
-                       /* this part changes layout of GTP payload:
-                        * it swaps "length field" with "protocol header"  */
-
-                       ptr = (guint8 *)tvb_get_ptr(tvb, offset, 3);
-
-                       tmp = ptr[2];
-                       ptr[2] = ptr[1];
-                       ptr[1] = ptr[0];
-                       ptr[0] = tmp;
-
-                       proto_tree_add_text (ext_tree_proto, tvb, offset, 3, "[WARNING] Next 3 bytes were swapped to allow processing PPP section");
-                       proto_tree_add_text (ext_tree_proto, tvb, offset, 1, "Protocol %u length: %u", cnt, proto_len);
-
-                       next_tvb = tvb_new_subset (tvb, offset + 1, proto_len + 2, proto_len + 2);
-                       call_dissector(ppp_handle, next_tvb, pinfo, ext_tree_proto);
-
-                       if (check_col(pinfo->cinfo, COL_PROTOCOL))
-                               col_set_str(pinfo->cinfo, COL_PROTOCOL, "GTP");
-
-                       if (check_col(pinfo->cinfo, COL_INFO)) {
-
-                               msg = tvb_get_guint8(tvb, 1);
-
-                               col_set_str(pinfo->cinfo, COL_INFO, val_to_str(msg, message_type, "Unknown"));
+               if (proto_len > 0) {
+
+                       proto_tree_add_text (ext_tree_proto, tvb, offset, 2, "Protocol %u ID: %s (0x%04x)",
+                           cnt, val_to_str(proto_id, ppp_vals, "Unknown"),
+                           proto_id);
+                       proto_tree_add_text (ext_tree_proto, tvb, offset+2, 1, "Protocol %u length: %u", cnt, proto_len);
+
+                       /*
+                        * Don't allow the dissector for the configuration
+                        * protocol in question to update the columns - this
+                        * is GTP, not PPP.
+                        */
+                       save_writable = col_get_writable(pinfo->cinfo);
+                       col_set_writable(pinfo->cinfo, FALSE);
+
+                       /*
+                        * XXX - should we have our own dissector table,
+                        * solely for configuration protocols, so that bogus
+                        * values don't cause us to dissect the protocol
+                        * data as, for example, IP?
+                        */
+                       next_tvb = tvb_new_subset (tvb, offset + 3, proto_len, proto_len);
+                       if (!dissector_try_port(ppp_subdissector_table,
+                           proto_id, next_tvb, pinfo, ext_tree_proto)) {
+                               call_dissector(data_handle, next_tvb, pinfo,
+                                   ext_tree_proto);
                        }
+
+                       col_set_writable(pinfo->cinfo, save_writable);
                }
 
                offset += proto_len + 3;
@@ -3933,7 +3956,8 @@ static int
 decode_gtp_tft(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree) {
 
        guint16         length, port1, port2, tos;
-       guint8          tft_flags, tft_code, no_packet_filters, i, pf_id, pf_eval, pf_len, pf_content_id, pf_offset, proto, spare;
+       guint8          tft_flags, tft_code, no_packet_filters, i, pf_id, pf_eval, pf_len, pf_content_id, proto, spare;
+       guint           pf_offset;
        guint32         mask_ipv4, addr_ipv4, ipsec_id, label;
        struct  e_in6_addr addr_ipv6, mask_ipv6;
        proto_tree      *ext_tree_tft, *ext_tree_tft_pf, *ext_tree_tft_flags;
@@ -4862,6 +4886,7 @@ dissect_gtpv0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
                gtpv0_hdr.length = g_ntohs(gtpv0_hdr.length);
                gtpv0_hdr.seq_no = g_ntohs(gtpv0_hdr.seq_no);
+               gtpv0_hdr.flow_label = g_ntohs(gtpv0_hdr.flow_label);
                proto_tree_add_uint(gtpv0_tree, hf_gtpv0_message_type, tvb, 1, 1, gtpv0_hdr.message);
                proto_tree_add_uint(gtpv0_tree, hf_gtpv0_length, tvb, 2, 2, gtpv0_hdr.length);
                proto_tree_add_uint(gtpv0_tree, hf_gtpv0_seq_number, tvb, 4, 2, gtpv0_hdr.seq_no);
@@ -4907,16 +4932,44 @@ dissect_gtpv0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                }
        }
 
-/* next part dissects sublayers of GTP
- * right now it's only IP */
+/* next part dissects sublayers of GTP */
 
        if ((gtpv0_hdr.message == GTP_MSG_TPDU) && gtp_tpdu) {
-               next_tvb = tvb_new_subset(tvb, 20, -1, -1);
-               call_dissector(ip_handle, next_tvb, pinfo, tree);
-               if (check_col(pinfo->cinfo, COL_PROTOCOL))
-                       col_append_str_gtp(pinfo->cinfo, COL_PROTOCOL, "GTP");
+                guint8 sub_proto;
+            
+               sub_proto = tvb_get_guint8(tvb,GTPv0_HDR_LENGTH);
+
+                if ((sub_proto >= 0x45) &&  (sub_proto <= 0x4e)) {
+                    /* this is most likely an IPv4 packet */
+                    /* we can exclude 0x40 - 0x44 because the minimum header size is 20 octets */
+                    /* 0x4f is excluded because PPP protocol type "IPv6 header compression" 
+                       with protocol field compression is more likely than a plain IPv4 packet with 60 octet header size */    
+                    
+                    next_tvb = tvb_new_subset(tvb, GTPv0_HDR_LENGTH, -1, -1);
+                    call_dissector(ip_handle, next_tvb, pinfo, tree);
+                } else
+                if ((sub_proto & 0xf0) == 0x60) {
+                    /* this is most likely an IPv6 packet */
+                    next_tvb = tvb_new_subset(tvb, GTPv0_HDR_LENGTH, -1, -1);
+                    call_dissector(ipv6_handle, next_tvb, pinfo, tree);
+                } else {
+                    /* this seems to be a PPP packet */
+                    guint8 acfield_len = 0;
+
+                    if (sub_proto == 0xff) {
+                        /* this might be an address field, even it shouldn't be here */
+                        guint8 control_field = tvb_get_guint8(tvb,GTPv0_HDR_LENGTH + 1);
+                        if (control_field == 0x03) {
+                            /* now we are pretty sure that address and control field are mistakenly inserted -> ignore it for PPP dissection */
+                            acfield_len = 2;
+                        }
+                    }
+                    next_tvb = tvb_new_subset(tvb, GTPv0_HDR_LENGTH + acfield_len, -1, -1);
+                    call_dissector(ppp_handle, next_tvb, pinfo, tree);
+                }
+            if (check_col(pinfo->cinfo, COL_PROTOCOL))
+                    col_append_str_gtp(pinfo->cinfo, COL_PROTOCOL, "GTP");
        }
-
 }
 
 /* GTP v1 dissector */
@@ -5034,46 +5087,39 @@ dissect_gtpv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
 
                sub_proto = tvb_get_guint8(tvb,GTPv1_HDR_LENGTH - hdr_offset);
 
-               switch(sub_proto) {
-                       case GTP_PPP_0x00:
-                       case GTP_PPP_0xC0:
-                       case GTP_PPP_0x80:
-                       case GTP_PPP_0xC2:
-                               next_tvb = tvb_new_subset(tvb, GTPv1_HDR_LENGTH - hdr_offset, -1, -1);
-                               call_dissector(ppp_handle, next_tvb, pinfo, tree);
-                               if (check_col(pinfo->cinfo, COL_PROTOCOL))
-                                       col_append_str_gtp(pinfo->cinfo, COL_PROTOCOL, "PPP");
-                               break;
-
-                       case GTP_PPP_REQ_ERROR:
-                               sub_proto = tvb_get_guint8(tvb,GTPv1_HDR_LENGTH - hdr_offset+2);
-                               switch(sub_proto) {
-                                       case GTP_PPP_0x00:
-                                       case GTP_PPP_0xC0:
-                                       case GTP_PPP_0x80:
-                                       case GTP_PPP_0xC2:
-                                               next_tvb = tvb_new_subset(tvb, GTPv1_HDR_LENGTH - hdr_offset+2, -1, -1);
-                                               call_dissector(ppp_handle, next_tvb, pinfo, tree);
-                                               if (check_col(pinfo->cinfo, COL_PROTOCOL))
-                                                       col_append_str_gtp(pinfo->cinfo, COL_PROTOCOL, "PPP");
-                                               break;
-
-
-                                       default:
-                                               next_tvb = tvb_new_subset(tvb, GTPv1_HDR_LENGTH - hdr_offset+2, -1, -1);
-                                               call_dissector(ip_handle, next_tvb, pinfo, tree);
-                                               if (check_col(pinfo->cinfo, COL_PROTOCOL))
-                                                       col_append_str_gtp(pinfo->cinfo, COL_PROTOCOL, "GTP-U");
-                                               break;
-                               }
-                               break;
-                       default:
-                               next_tvb = tvb_new_subset(tvb, GTPv1_HDR_LENGTH - hdr_offset, -1, -1);
-                               call_dissector(ip_handle, next_tvb, pinfo, tree);
-                               if (check_col(pinfo->cinfo, COL_PROTOCOL))
-                                       col_append_str_gtp(pinfo->cinfo, COL_PROTOCOL, "GTP-U");
-                               break;
-               }
+                if ((sub_proto >= 0x45) &&  (sub_proto <= 0x4e)) {
+                    /* this is most likely an IPv4 packet */
+                    /* we can exclude 0x40 - 0x44 because the minimum header size is 20 octets */
+                    /* 0x4f is excluded because PPP protocol type "IPv6 header compression" 
+                       with protocol field compression is more likely than a plain IPv4 packet with 60 octet header size */    
+                    
+                    next_tvb = tvb_new_subset(tvb, GTPv1_HDR_LENGTH - hdr_offset, -1, -1);
+                    call_dissector(ip_handle, next_tvb, pinfo, tree);
+                } else
+                if ((sub_proto & 0xf0) == 0x60)
+                {
+                    /* this is most likely an IPv6 packet */
+                    next_tvb = tvb_new_subset(tvb, GTPv1_HDR_LENGTH - hdr_offset, -1, -1);
+                    call_dissector(ipv6_handle, next_tvb, pinfo, tree);
+                } else {
+                    /* this seems to be a PPP packet */
+                    guint8 acfield_len = 0;
+
+                    if (sub_proto == 0xff) {
+                        /* this might be an address field, even it shouldn't be here */
+                        guint8 control_field; 
+                        control_field = tvb_get_guint8(tvb,GTPv1_HDR_LENGTH - hdr_offset + 1);
+                        if (control_field == 0x03)
+                        {
+                            /* now we are pretty sure that address and control field are mistakenly inserted -> ignore it for PPP dissection */
+                            acfield_len = 2;
+                        }
+                    }
+                    next_tvb = tvb_new_subset(tvb, GTPv1_HDR_LENGTH - hdr_offset + acfield_len, -1, -1);
+                    call_dissector(ppp_handle, next_tvb, pinfo, tree);
+                }
+            if (check_col(pinfo->cinfo, COL_PROTOCOL))
+                    col_append_str_gtp(pinfo->cinfo, COL_PROTOCOL, "GTP-U");
        }
 }
 
@@ -5121,8 +5167,8 @@ proto_register_gtp(void)
        { &hf_gtpv0_ms_valid,           { "MS validated",       "gtpv0.ms_valid",               FT_BOOLEAN,     BASE_NONE,NULL, 0, "MS validated", HFILL }},
        { &hf_gtpv0_recovery,           { "Recovery",           "gtpv0.recovery",               FT_UINT8,       BASE_DEC, NULL, 0, "Restart counter", HFILL }},
        { &hf_gtpv0_sel_mode,           { "Selection mode",     "gtpv0.sel_mode",               FT_UINT8,       BASE_DEC, VALS(sel_mode_type), 0, "Selection Mode", HFILL }},
-       { &hf_gtpv0_ext_flow_label,     { "Flow Label Data I",  "gtpv0.ext_flow_label",         FT_UINT16,      BASE_DEC, NULL, 0, "Flow label data", HFILL }},
-       { &hf_gtpv0_flow_sig,           { "Flow label Signalling",      "gtpv0.flow_sig",       FT_UINT16,      BASE_DEC, NULL, 0, "Flow label signalling", HFILL }},
+       { &hf_gtpv0_ext_flow_label,     { "Flow Label Data I",  "gtpv0.ext_flow_label",         FT_UINT16,      BASE_HEX, NULL, 0, "Flow label data", HFILL }},
+       { &hf_gtpv0_flow_sig,           { "Flow label Signalling",      "gtpv0.flow_sig",       FT_UINT16,      BASE_HEX, NULL, 0, "Flow label signalling", HFILL }},
        { &hf_gtpv0_nsapi,              { "NSAPI ",             "gtpv0.nsapi",                  FT_UINT8,       BASE_DEC, NULL, 0, "Network layer Service Access Point Identifier", HFILL }},
        { &hf_gtpv0_flow_ii,            { "Flow Label Data II ","gtpv0.flow_ii",                FT_UINT16,      BASE_DEC, NULL, 0, "Downlink flow label data", HFILL }},
        { &hf_gtpv0_ms_reason,          { "MS not reachable reason",    "gtpv0.ms_reason",      FT_UINT8,       BASE_DEC, VALS(ms_not_reachable_type), 0, "MS Not Reachable Reason", HFILL }},
@@ -5190,7 +5236,7 @@ proto_register_gtp(void)
        { &hf_gtpv1_teid_cp,            { "TEID Control Plane", "gtpv1.teid_cp",                FT_UINT32,      BASE_HEX, NULL, 0, "Tunnel Endpoint Identifier Control Plane", HFILL }},
        { &hf_gtpv1_nsapi,              { "NSAPI",              "gtpv1.nsapi",                  FT_UINT8,       BASE_DEC, NULL, 0, "Network layer Service Access Point Identifier", HFILL }},
        { &hf_gtpv1_teid_ii,            { "TEID Data II",       "gtpv1.teid_ii",                FT_UINT32,      BASE_HEX, NULL, 0, "Tunnel Endpoint Identifier Data II", HFILL }},
-       { &hf_gtpv1_tear_ind,           { "Teardown indication","gtpv1.tear_ind",               FT_BOOLEAN,     BASE_NONE,NULL, 0, "Teardown Indication", HFILL }},
+       { &hf_gtpv1_tear_ind,           { "Teardown Indicator","gtpv1.tear_ind",                FT_BOOLEAN,     BASE_NONE,NULL, 0, "Teardown Indicator", HFILL }},
        { &hf_gtpv1_ranap_cause,                { "RANAP cause",        "gtpv1.ranap_cause",            FT_UINT8,       BASE_DEC, VALS(ranap_cause_type), 0, "RANAP cause", HFILL }},
        { &hf_gtpv1_rab_gtpu_dn,                { "Downlink GTP-U seq number",  "gtpv1.rab_gtp_dn",     FT_UINT16,      BASE_DEC, NULL, 0, "Downlink GTP-U sequence number", HFILL }},
        { &hf_gtpv1_rab_gtpu_up,                { "Uplink GTP-U seq number",    "gtpv1.rab_gtp_up",     FT_UINT16,      BASE_DEC, NULL, 0, "Uplink GTP-U sequence number", HFILL }},
@@ -5308,18 +5354,17 @@ proto_register_gtp(void)
 
        gtp_module = prefs_register_protocol(proto_gtp, proto_reg_handoff_gtp);
 
-       prefs_register_uint_preference(gtp_module, "gtpv0_port", "GTPv0 port ", "GTPv0 port (default 3386)", 10, &g_gtpv0_port);
-       prefs_register_uint_preference(gtp_module, "gtpv1c_port", "GTPv1 control plane (GTP-C) port ", "GTPv1 control plane port (default 2123)", 10, &g_gtpv1c_port);
-       prefs_register_uint_preference(gtp_module, "gtpv1u_port", "GTPv1 user plane (GTP-U) port ", "GTPv1 user plane port (default 2152)", 10, &g_gtpv1u_port);
-       prefs_register_bool_preference(gtp_module, "gtp_dissect_tpdu", "Dissect T-PDU ", "Dissect T-PDU", &gtp_tpdu);
-       prefs_register_enum_preference(gtp_module, "gtpv0_dissect_cdr_as", "Dissect GTP'v0 CDRs as ", "Dissect GTP'v0 CDRs as", &gtpv0_cdr_as, gtpv0_cdr_options, FALSE);
-       prefs_register_bool_preference(gtp_module, "gtpv0_check_etsi", "Compare GTPv0 order with ETSI ", "GTPv0 ETSI order", &gtpv0_etsi_order);
-       prefs_register_bool_preference(gtp_module, "gtpv1_check_etsi", "Compare GTPv1 order with ETSI ", "GTPv1 ETSI order", &gtpv1_etsi_order);
-       prefs_register_bool_preference(gtp_module, "ppp_reorder", "Reorder & dissect PPP in Protocol conf. options", "Reorder & dissect PPP inside of Protocol Configuration Options, 3 bytes will be swapped to allow processing PPP section: 1 byte of length with 2 bytes of protocol id (refer to ETSI 29.060, 7.7.21 & 24.008 10.5.6.3)", &ppp_reorder);
+       prefs_register_uint_preference(gtp_module, "v0_port", "GTPv0 port", "GTPv0 port (default 3386)", 10, &g_gtpv0_port);
+       prefs_register_uint_preference(gtp_module, "v1c_port", "GTPv1 control plane (GTP-C) port", "GTPv1 control plane port (default 2123)", 10, &g_gtpv1c_port);
+       prefs_register_uint_preference(gtp_module, "v1u_port", "GTPv1 user plane (GTP-U) port", "GTPv1 user plane port (default 2152)", 10, &g_gtpv1u_port);
+       prefs_register_bool_preference(gtp_module, "dissect_tpdu", "Dissect T-PDU", "Dissect T-PDU", &gtp_tpdu);
+       prefs_register_enum_preference(gtp_module, "v0_dissect_cdr_as", "Dissect GTP'v0 CDRs as", "Dissect GTP'v0 CDRs as", &gtpv0_cdr_as, gtpv0_cdr_options, FALSE);
+       prefs_register_bool_preference(gtp_module, "v0_check_etsi", "Compare GTPv0 order with ETSI", "GTPv0 ETSI order", &gtpv0_etsi_order);
+       prefs_register_bool_preference(gtp_module, "v1_check_etsi", "Compare GTPv1 order with ETSI", "GTPv1 ETSI order", &gtpv1_etsi_order);
+       prefs_register_obsolete_preference(gtp_module, "ppp_reorder");
 
        register_dissector("gtpv0", dissect_gtpv0, proto_gtpv0);
        register_dissector("gtpv1", dissect_gtpv1, proto_gtpv1);
-
 }
 
 void
@@ -5363,8 +5408,9 @@ proto_reg_handoff_gtp(void)
        dissector_add("tcp.port", g_gtpv1c_port, gtpv1_handle);
        dissector_add("udp.port", g_gtpv1u_port, gtpv1_handle);
        dissector_add("tcp.port", g_gtpv1u_port, gtpv1_handle);
-       dissector_add("ppp.protocol", PPP_IP, ip_handle);
 
        ip_handle = find_dissector("ip");
+        ipv6_handle = find_dissector("ipv6");
        ppp_handle = find_dissector("ppp");
+       data_handle = find_dissector("data");
 }