diff options
author | etxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7> | 2011-12-03 12:11:01 +0000 |
---|---|---|
committer | etxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7> | 2011-12-03 12:11:01 +0000 |
commit | 67e43f518ed72fce24f48e368ee7cca5585c76ff (patch) | |
tree | 05308e7543cf2e63f002dce40c97ee3dc46ce705 /epan/dissectors | |
parent | b8440e8e0755b6b500e34fca3114bde941f9295d (diff) |
Handle 20 byte GTP' V0 header.
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@40081 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'epan/dissectors')
-rw-r--r-- | epan/dissectors/packet-gtp.c | 689 |
1 files changed, 359 insertions, 330 deletions
diff --git a/epan/dissectors/packet-gtp.c b/epan/dissectors/packet-gtp.c index 0c4a35d583..5af95cea40 100644 --- a/epan/dissectors/packet-gtp.c +++ b/epan/dissectors/packet-gtp.c @@ -38,8 +38,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Ref: 3GPP TS 29.060 + * Ref: 3GPP TS 29.060 * http://www.3gpp.org/ftp/Specs/html-info/29060.htm + * GTP' 3GPP TS 32.295 */ #ifdef HAVE_CONFIG_H @@ -119,6 +120,7 @@ static int hf_gtp_flags_ver = -1; static int hf_gtp_prime_flags_ver = -1; static int hf_gtp_flags_pt = -1; static int hf_gtp_flags_spare1 = -1; +static int hf_gtp_flags_hdr_length = -1; static int hf_gtp_flags_snn = -1; static int hf_gtp_flags_spare2 = -1; static int hf_gtp_flags_e = -1; @@ -337,6 +339,11 @@ static int gtp_tap = -1; /* Definition of flags masks */ #define GTP_VER_MASK 0xE0 +static const true_false_string gtp_hdr_length_vals = { + "6-Octet Header", + "20-Octet Header" +}; + static const value_string ver_types[] = { {0, "GTP release 97/98 version"}, {1, "GTP release 99 version"}, @@ -6744,339 +6751,356 @@ static int decode_gtp_unknown(tvbuff_t * tvb, int offset, packet_info * pinfo _U static void dissect_gtp_common(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { - struct _gtp_hdr gtp_hdr; - proto_tree *gtp_tree, *flags_tree, *ext_tree; - proto_item *ti, *tf, *item; - int i, offset, length, gtp_prime, checked_field, mandatory; - int seq_no=0, flow_label=0; - guint8 pdu_no, next_hdr = 0, ext_hdr_val, noOfExtHdrs = 0, ext_hdr_length; - gchar *tid_str; - guint32 teid = 0; - tvbuff_t *next_tvb; - guint8 sub_proto, acfield_len = 0, control_field; - gtp_msg_hash_t *gcrp=NULL; - conversation_t *conversation=NULL; - gtp_conv_info_t *gtp_info; - void* pd_save; - - - col_set_str(pinfo->cinfo, COL_PROTOCOL, "GTP"); - col_clear(pinfo->cinfo, COL_INFO); - - /* - * Do we have a conversation for this connection? - */ - conversation = find_or_create_conversation(pinfo); - - /* - * Do we already know this conversation? - */ - gtp_info = conversation_get_proto_data(conversation, proto_gtp); - if (gtp_info == NULL) { - /* No. Attach that information to the conversation, and add - * it to the list of information structures. - */ - gtp_info = g_malloc(sizeof(gtp_conv_info_t)); - /*Request/response matching tables*/ - gtp_info->matched = g_hash_table_new(gtp_sn_hash, gtp_sn_equal_matched); - gtp_info->unmatched = g_hash_table_new(gtp_sn_hash, gtp_sn_equal_unmatched); - - conversation_add_proto_data(conversation, proto_gtp, gtp_info); - - gtp_info->next = gtp_info_items; - gtp_info_items = gtp_info; - } - pd_save = pinfo->private_data; - pinfo->private_data = gtp_info; - - tvb_memcpy(tvb, (guint8 *) & gtp_hdr, 0, 4); - - if (!(gtp_hdr.flags & 0x10)) - gtp_prime = 1; - else - gtp_prime = 0; - - switch ((gtp_hdr.flags >> 5) & 0x07) { - case 0: - gtp_version = 0; - break; - case 1: - gtp_version = 1; - break; - default: - gtp_version = 1; - break; - } - - col_add_str(pinfo->cinfo, COL_INFO, val_to_str_ext_const(gtp_hdr.message, >p_message_type_ext, "Unknown")); - - if (tree) { - ti = proto_tree_add_item(tree, proto_gtp, tvb, 0, -1, ENC_NA); - gtp_tree = proto_item_add_subtree(ti, ett_gtp); - - tf = proto_tree_add_uint(gtp_tree, hf_gtp_flags, tvb, 0, 1, gtp_hdr.flags); - flags_tree = proto_item_add_subtree(tf, ett_gtp_flags); - - if(gtp_prime==0){ - proto_tree_add_uint(flags_tree, hf_gtp_flags_ver, tvb, 0, 1, gtp_hdr.flags); - }else{ - proto_tree_add_uint(flags_tree, hf_gtp_prime_flags_ver, tvb, 0, 1, gtp_hdr.flags); - } - - proto_tree_add_uint(flags_tree, hf_gtp_flags_pt, tvb, 0, 1, gtp_hdr.flags); - - if((gtp_prime==1)||(gtp_version==0)){ - proto_tree_add_uint(flags_tree, hf_gtp_flags_spare1, tvb, 0, 1, gtp_hdr.flags); - proto_tree_add_boolean(flags_tree, hf_gtp_flags_snn, tvb, 0, 1, gtp_hdr.flags); - }else{ - proto_tree_add_uint(flags_tree, hf_gtp_flags_spare2, tvb, 0, 1, gtp_hdr.flags); - proto_tree_add_boolean(flags_tree, hf_gtp_flags_e, tvb, 0, 1, gtp_hdr.flags); - proto_tree_add_boolean(flags_tree, hf_gtp_flags_s, tvb, 0, 1, gtp_hdr.flags); - proto_tree_add_boolean(flags_tree, hf_gtp_flags_pn, tvb, 0, 1, gtp_hdr.flags); - } - - proto_tree_add_uint(gtp_tree, hf_gtp_message_type, tvb, 1, 1, gtp_hdr.message); - - gtp_hdr.length = g_ntohs(gtp_hdr.length); - proto_tree_add_uint(gtp_tree, hf_gtp_length, tvb, 2, 2, gtp_hdr.length); - - offset = 4; - - if (gtp_prime) { - seq_no = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(gtp_tree, hf_gtp_seq_number, tvb, offset, 2, seq_no); - offset += 2; - } else - switch (gtp_version) { - case 0: - seq_no = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(gtp_tree, hf_gtp_seq_number, tvb, offset, 2, seq_no); - offset += 2; - - flow_label = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(gtp_tree, hf_gtp_flow_label, tvb, offset, 2, flow_label); - offset += 2; - - pdu_no = tvb_get_guint8(tvb, offset); - proto_tree_add_uint(gtp_tree, hf_gtp_sndcp_number, tvb, offset, 1, pdu_no); - offset += 4; - - tid_str = id_to_str(tvb, offset); - proto_tree_add_string(gtp_tree, hf_gtp_tid, tvb, offset, 8, tid_str); - offset += 8; - break; - case 1: - teid = tvb_get_ntohl(tvb, offset); - proto_tree_add_uint(gtp_tree, hf_gtp_teid, tvb, offset, 4, teid); - offset += 4; - - /* Are sequence number/N-PDU Number/extension header present? */ - if (gtp_hdr.flags & 0x07) { - seq_no = tvb_get_ntohs(tvb, offset); - proto_tree_add_uint(gtp_tree, hf_gtp_seq_number, tvb, offset, 2, seq_no); - offset += 2; - - pdu_no = tvb_get_guint8(tvb, offset); - proto_tree_add_uint(gtp_tree, hf_gtp_npdu_number, tvb, offset, 1, pdu_no); - offset++; - - next_hdr = tvb_get_guint8(tvb, offset); - - /* Don't add extension header, we'll add a subtree for that */ - /* proto_tree_add_uint(gtp_tree, hf_gtp_next, tvb, offset, 1, next_hdr); */ - - offset++; - - /* Change to while? */ - if (next_hdr) { - - /* TODO Add support for more than one extension header */ - - noOfExtHdrs++; - - tf = proto_tree_add_uint(gtp_tree, hf_gtp_ext_hdr, tvb, offset, 4, next_hdr); - ext_tree = proto_item_add_subtree(tf, ett_gtp_ext_hdr); - - /* PDCP PDU - * 3GPP 29.281 v9.0.0, 5.2.2.2 PDCP PDU Number - * - * "This extension header is transmitted, for example in UTRAN, at SRNS relocation time, - * to provide the PDCP sequence number of not yet acknowledged N-PDUs. It is 4 octets long, - * and therefore the Length field has value 1. - * - * When used between two eNBs at the X2 interface in E-UTRAN, bits 5-8 of octet 2 are spare. - * The meaning of the spare bits shall be set to zero. - * - * Wireshark Note: TS 29.060 does not define bit 5-6 as spare, so no check is possible unless a preference is used. - */ - if (next_hdr == GTP_EXT_HDR_PDCP_SN) { - - /* First byte is length (should be 1) */ - ext_hdr_length = tvb_get_guint8(tvb, offset); - if (ext_hdr_length != 1) { - expert_add_info_format(pinfo, ext_tree, PI_PROTOCOL, PI_WARN, "The length field for the PDCP SN Extension header should be 1."); - } - proto_tree_add_item(ext_tree, hf_gtp_ext_hdr_length, tvb, offset,1, ENC_BIG_ENDIAN); - offset++; - - proto_tree_add_item(ext_tree, hf_gtp_ext_hdr_pdcpsn, tvb, offset, 2, ENC_BIG_ENDIAN); - offset += 2; - - /* Last is next_hdr */ - next_hdr = tvb_get_guint8(tvb, offset); - item = proto_tree_add_item(ext_tree, hf_gtp_ext_hdr_next, tvb, offset, 1, ENC_BIG_ENDIAN); - - if (next_hdr) { - expert_add_info_format(pinfo, item, PI_UNDECODED, PI_WARN, "Can't decode more than one extension header."); - } - offset++; - } - } - } - break; - default: - break; - } - - if (gtp_hdr.message != GTP_MSG_TPDU) { - /* TODO: This code should be cleaned up to handle more than one - * header and possibly display the header content */ - if (next_hdr) { - offset++; - switch (next_hdr) { - case 1: - /* MBMS support indication */ - proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- MBMS support indication header ---]"); - offset += 3; - break; - case 2: - /* MS Info Change Reporting support indication */ - proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- MS Info Change Reporting support indication header ---]"); - offset += 3; - break; - case 0xc0: - /* PDCP PDU number */ - proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- PDCP PDU number header ---]"); - offset += 3; - break; - case 0xc1: - /* Suspend Request */ - proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- Suspend Request header ---]"); - offset += 3; - break; - case 0xc2: - /* Suspend Response */ - proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- Suspend Response header ---]"); - offset += 3; - break; - default: - proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- Unknown extension header ---]"); - offset += 3; - break; - } - next_hdr = tvb_get_guint8(tvb, offset); - proto_tree_add_uint(gtp_tree, hf_gtp_next, tvb, offset, 1, next_hdr); - offset++; - } - /* proto_tree_add_text(gtp_tree, tvb, 0, 0, "[--- end of GTP header, beginning of extension headers ---]");*/ - length = tvb_length(tvb); - mandatory = 0; /* check order of GTP fields against ETSI */ - for (;;) { - if (offset >= length) - break; - if (next_hdr) { - ext_hdr_val = next_hdr; - next_hdr = 0; - } else - ext_hdr_val = tvb_get_guint8(tvb, offset); - if (g_gtp_etsi_order) { - checked_field = check_field_presence(gtp_hdr.message, ext_hdr_val, (int *) &mandatory); - switch (checked_field) { - case -2: - proto_tree_add_text(gtp_tree, tvb, 0, 0, "[WARNING] message not found"); - break; - case -1: - proto_tree_add_text(gtp_tree, tvb, 0, 0, "[WARNING] field not present"); - break; - case 0: - break; - default: - proto_tree_add_text(gtp_tree, tvb, offset, 1, "[WARNING] wrong next field, should be: %s", - val_to_str_ext_const(checked_field, >p_val_ext, "Unknown extension field")); - break; - } - } - - i = -1; - while (gtpopt[++i].optcode) - if (gtpopt[i].optcode == ext_hdr_val) - break; - offset = offset + (*gtpopt[i].decode) (tvb, offset, pinfo, gtp_tree); - } - - /*Use sequence number to track Req/Resp pairs*/ - if (seq_no) { - gcrp = gtp_match_response(tvb, pinfo, gtp_tree, seq_no, gtp_hdr.message); - /*pass packet to tap for response time reporting*/ - if (gcrp) { - tap_queue_packet(gtp_tap,pinfo,gcrp); - } - } - } - proto_item_set_len (ti, offset); - } - - if ((gtp_hdr.message == GTP_MSG_TPDU) && g_gtp_tpdu) { - - if (gtp_prime) - offset = 6; - else if (gtp_version == 1) { - if (gtp_hdr.flags & 0x07) { - offset = 11; - if (tvb_get_guint8(tvb, offset) == 0) - offset++; - } else - offset = 8; - } else - offset = 20; - - /* Can only handle one extension header type... */ - if (noOfExtHdrs != 0) offset+= 1 + noOfExtHdrs*4; + struct _gtp_hdr gtp_hdr; + proto_tree *gtp_tree, *flags_tree, *ext_tree; + proto_item *ti, *tf, *item; + int i, offset, length, gtp_prime, checked_field, mandatory; + int seq_no=0, flow_label=0; + guint8 pdu_no, next_hdr = 0, ext_hdr_val, noOfExtHdrs = 0, ext_hdr_length; + gchar *tid_str; + guint32 teid = 0; + tvbuff_t *next_tvb; + guint8 sub_proto, acfield_len = 0, control_field; + gtp_msg_hash_t *gcrp=NULL; + conversation_t *conversation=NULL; + gtp_conv_info_t *gtp_info; + void* pd_save; + + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "GTP"); + col_clear(pinfo->cinfo, COL_INFO); + + /* + * Do we have a conversation for this connection? + */ + conversation = find_or_create_conversation(pinfo); + + /* + * Do we already know this conversation? + */ + gtp_info = conversation_get_proto_data(conversation, proto_gtp); + if (gtp_info == NULL) { + /* No. Attach that information to the conversation, and add + * it to the list of information structures. + */ + gtp_info = g_malloc(sizeof(gtp_conv_info_t)); + /*Request/response matching tables*/ + gtp_info->matched = g_hash_table_new(gtp_sn_hash, gtp_sn_equal_matched); + gtp_info->unmatched = g_hash_table_new(gtp_sn_hash, gtp_sn_equal_unmatched); + + conversation_add_proto_data(conversation, proto_gtp, gtp_info); + + gtp_info->next = gtp_info_items; + gtp_info_items = gtp_info; + } + pd_save = pinfo->private_data; + pinfo->private_data = gtp_info; + + tvb_memcpy(tvb, (guint8 *) & gtp_hdr, 0, 4); + + if (!(gtp_hdr.flags & 0x10)) + gtp_prime = 1; + else + gtp_prime = 0; + + switch ((gtp_hdr.flags >> 5) & 0x07) { + case 0: + gtp_version = 0; + break; + case 1: + gtp_version = 1; + break; + default: + gtp_version = 1; + break; + } - sub_proto = tvb_get_guint8(tvb, offset); + col_add_str(pinfo->cinfo, COL_INFO, val_to_str_ext_const(gtp_hdr.message, >p_message_type_ext, "Unknown")); - 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 */ + if (tree) { + ti = proto_tree_add_item(tree, proto_gtp, tvb, 0, -1, ENC_NA); + gtp_tree = proto_item_add_subtree(ti, ett_gtp); - next_tvb = tvb_new_subset_remaining(tvb, offset); - call_dissector(ip_handle, next_tvb, pinfo, tree); + tf = proto_tree_add_uint(gtp_tree, hf_gtp_flags, tvb, 0, 1, gtp_hdr.flags); + flags_tree = proto_item_add_subtree(tf, ett_gtp_flags); - } else if ((sub_proto & 0xf0) == 0x60) { - /* this is most likely an IPv6 packet */ - next_tvb = tvb_new_subset_remaining(tvb, offset); - call_dissector(ipv6_handle, next_tvb, pinfo, tree); - } else { - /* this seems to be a PPP packet */ - - if (sub_proto == 0xff) { - /* this might be an address field, even it shouldn't be here */ - control_field = tvb_get_guint8(tvb, 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_remaining(tvb, offset + acfield_len); - call_dissector(ppp_handle, next_tvb, pinfo, tree); - } + if(gtp_prime==1){ + /* Octet 8 7 6 5 4 3 2 1 + * 1 Version | PT| Spare '1 1 1 '| ' 0/1 ' + */ + proto_tree_add_uint(flags_tree, hf_gtp_prime_flags_ver, tvb, 0, 1, gtp_hdr.flags); + proto_tree_add_uint(flags_tree, hf_gtp_flags_pt, tvb, 0, 1, gtp_hdr.flags); + proto_tree_add_uint(flags_tree, hf_gtp_flags_spare1, tvb, 0, 1, gtp_hdr.flags); + /* Bit 1 of octet 1 is not used in GTP' (except in v0), and it is marked '0' + * in the GTP' header. It is in use in GTP' v0 and distinguishes the used header-length. + * In the case of GTP' v0, this bit being marked one (1) indicates the usage of the 6 + * octets header. If the bit is set to '0' (usually the case) the 20-octet header is used. + * For all other versions of GTP', this bit is not used and is set to '0'. However, + * this does not suggest the use of the 20-octet header, rather a shorter 6-octet header. + */ + if(gtp_version==0){ + proto_tree_add_item(flags_tree, hf_gtp_flags_hdr_length, tvb, 0, 1, ENC_BIG_ENDIAN); + } + }else{ + proto_tree_add_uint(flags_tree, hf_gtp_flags_ver, tvb, 0, 1, gtp_hdr.flags); + proto_tree_add_uint(flags_tree, hf_gtp_flags_pt, tvb, 0, 1, gtp_hdr.flags); + if(gtp_version==0){ + proto_tree_add_uint(flags_tree, hf_gtp_flags_spare1, tvb, 0, 1, gtp_hdr.flags); + proto_tree_add_boolean(flags_tree, hf_gtp_flags_snn, tvb, 0, 1, gtp_hdr.flags); + }else{ + proto_tree_add_uint(flags_tree, hf_gtp_flags_spare2, tvb, 0, 1, gtp_hdr.flags); + proto_tree_add_boolean(flags_tree, hf_gtp_flags_e, tvb, 0, 1, gtp_hdr.flags); + proto_tree_add_boolean(flags_tree, hf_gtp_flags_s, tvb, 0, 1, gtp_hdr.flags); + proto_tree_add_boolean(flags_tree, hf_gtp_flags_pn, tvb, 0, 1, gtp_hdr.flags); + } + } + + proto_tree_add_uint(gtp_tree, hf_gtp_message_type, tvb, 1, 1, gtp_hdr.message); + + gtp_hdr.length = g_ntohs(gtp_hdr.length); + proto_tree_add_uint(gtp_tree, hf_gtp_length, tvb, 2, 2, gtp_hdr.length); + + offset = 4; + + if (gtp_prime) { + seq_no = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(gtp_tree, hf_gtp_seq_number, tvb, offset, 2, seq_no); + offset += 2; + /* If GTP' version is 0 and bit 1 is 0 20 bytes header is used, step past it */ + if( (gtp_version==0)&&((gtp_hdr.flags & 0x01)==0) ){ + offset = GTPv0_HDR_LENGTH; + } + } else + switch (gtp_version) { + case 0: + seq_no = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(gtp_tree, hf_gtp_seq_number, tvb, offset, 2, seq_no); + offset += 2; + + flow_label = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(gtp_tree, hf_gtp_flow_label, tvb, offset, 2, flow_label); + offset += 2; + + pdu_no = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(gtp_tree, hf_gtp_sndcp_number, tvb, offset, 1, pdu_no); + offset += 4; + + tid_str = id_to_str(tvb, offset); + proto_tree_add_string(gtp_tree, hf_gtp_tid, tvb, offset, 8, tid_str); + offset += 8; + break; + case 1: + teid = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(gtp_tree, hf_gtp_teid, tvb, offset, 4, teid); + offset += 4; + + /* Are sequence number/N-PDU Number/extension header present? */ + if (gtp_hdr.flags & 0x07) { + seq_no = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(gtp_tree, hf_gtp_seq_number, tvb, offset, 2, seq_no); + offset += 2; + + pdu_no = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(gtp_tree, hf_gtp_npdu_number, tvb, offset, 1, pdu_no); + offset++; + + next_hdr = tvb_get_guint8(tvb, offset); + + /* Don't add extension header, we'll add a subtree for that */ + /* proto_tree_add_uint(gtp_tree, hf_gtp_next, tvb, offset, 1, next_hdr); */ + + offset++; + + /* Change to while? */ + if (next_hdr) { + + /* TODO Add support for more than one extension header */ + + noOfExtHdrs++; + + tf = proto_tree_add_uint(gtp_tree, hf_gtp_ext_hdr, tvb, offset, 4, next_hdr); + ext_tree = proto_item_add_subtree(tf, ett_gtp_ext_hdr); + + /* PDCP PDU + * 3GPP 29.281 v9.0.0, 5.2.2.2 PDCP PDU Number + * + * "This extension header is transmitted, for example in UTRAN, at SRNS relocation time, + * to provide the PDCP sequence number of not yet acknowledged N-PDUs. It is 4 octets long, + * and therefore the Length field has value 1. + * + * When used between two eNBs at the X2 interface in E-UTRAN, bits 5-8 of octet 2 are spare. + * The meaning of the spare bits shall be set to zero. + * + * Wireshark Note: TS 29.060 does not define bit 5-6 as spare, so no check is possible unless a preference is used. + */ + if (next_hdr == GTP_EXT_HDR_PDCP_SN) { + + /* First byte is length (should be 1) */ + ext_hdr_length = tvb_get_guint8(tvb, offset); + if (ext_hdr_length != 1) { + expert_add_info_format(pinfo, ext_tree, PI_PROTOCOL, PI_WARN, "The length field for the PDCP SN Extension header should be 1."); + } + proto_tree_add_item(ext_tree, hf_gtp_ext_hdr_length, tvb, offset,1, ENC_BIG_ENDIAN); + offset++; + + proto_tree_add_item(ext_tree, hf_gtp_ext_hdr_pdcpsn, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* Last is next_hdr */ + next_hdr = tvb_get_guint8(tvb, offset); + item = proto_tree_add_item(ext_tree, hf_gtp_ext_hdr_next, tvb, offset, 1, ENC_BIG_ENDIAN); + + if (next_hdr) { + expert_add_info_format(pinfo, item, PI_UNDECODED, PI_WARN, "Can't decode more than one extension header."); + } + offset++; + } + } + } + break; + default: + break; + } + + if (gtp_hdr.message != GTP_MSG_TPDU) { + /* TODO: This code should be cleaned up to handle more than one + * header and possibly display the header content */ + if (next_hdr) { + offset++; + switch (next_hdr) { + case 1: + /* MBMS support indication */ + proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- MBMS support indication header ---]"); + offset += 3; + break; + case 2: + /* MS Info Change Reporting support indication */ + proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- MS Info Change Reporting support indication header ---]"); + offset += 3; + break; + case 0xc0: + /* PDCP PDU number */ + proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- PDCP PDU number header ---]"); + offset += 3; + break; + case 0xc1: + /* Suspend Request */ + proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- Suspend Request header ---]"); + offset += 3; + break; + case 0xc2: + /* Suspend Response */ + proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- Suspend Response header ---]"); + offset += 3; + break; + default: + proto_tree_add_text(gtp_tree, tvb, offset, 4, "[--- Unknown extension header ---]"); + offset += 3; + break; + } + next_hdr = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(gtp_tree, hf_gtp_next, tvb, offset, 1, next_hdr); + offset++; + } + /* proto_tree_add_text(gtp_tree, tvb, 0, 0, "[--- end of GTP header, beginning of extension headers ---]");*/ + length = tvb_length(tvb); + mandatory = 0; /* check order of GTP fields against ETSI */ + for (;;) { + if (offset >= length) + break; + if (next_hdr) { + ext_hdr_val = next_hdr; + next_hdr = 0; + } else + ext_hdr_val = tvb_get_guint8(tvb, offset); + if (g_gtp_etsi_order) { + checked_field = check_field_presence(gtp_hdr.message, ext_hdr_val, (int *) &mandatory); + switch (checked_field) { + case -2: + proto_tree_add_text(gtp_tree, tvb, 0, 0, "[WARNING] message not found"); + break; + case -1: + proto_tree_add_text(gtp_tree, tvb, 0, 0, "[WARNING] field not present"); + break; + case 0: + break; + default: + proto_tree_add_text(gtp_tree, tvb, offset, 1, "[WARNING] wrong next field, should be: %s", + val_to_str_ext_const(checked_field, >p_val_ext, "Unknown extension field")); + break; + } + } + + i = -1; + while (gtpopt[++i].optcode) + if (gtpopt[i].optcode == ext_hdr_val) + break; + offset = offset + (*gtpopt[i].decode) (tvb, offset, pinfo, gtp_tree); + } + + /*Use sequence number to track Req/Resp pairs*/ + if (seq_no) { + gcrp = gtp_match_response(tvb, pinfo, gtp_tree, seq_no, gtp_hdr.message); + /*pass packet to tap for response time reporting*/ + if (gcrp) { + tap_queue_packet(gtp_tap,pinfo,gcrp); + } + } + } + proto_item_set_len (ti, offset); + } - col_prepend_fstr(pinfo->cinfo, COL_PROTOCOL, "GTP <"); - col_append_str(pinfo->cinfo, COL_PROTOCOL, ">"); - } - pinfo->private_data = pd_save; + if ((gtp_hdr.message == GTP_MSG_TPDU) && g_gtp_tpdu) { + + if (gtp_prime) + offset = 6; + else if (gtp_version == 1) { + if (gtp_hdr.flags & 0x07) { + offset = 11; + if (tvb_get_guint8(tvb, offset) == 0) + offset++; + } else + offset = 8; + } else + offset = 20; + + /* Can only handle one extension header type... */ + if (noOfExtHdrs != 0) offset+= 1 + noOfExtHdrs*4; + + sub_proto = tvb_get_guint8(tvb, offset); + + 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_remaining(tvb, offset); + 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_remaining(tvb, offset); + call_dissector(ipv6_handle, next_tvb, pinfo, tree); + } else { + /* this seems to be a PPP packet */ + + if (sub_proto == 0xff) { + /* this might be an address field, even it shouldn't be here */ + control_field = tvb_get_guint8(tvb, 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_remaining(tvb, offset + acfield_len); + call_dissector(ppp_handle, next_tvb, pinfo, tree); + } + + col_prepend_fstr(pinfo->cinfo, COL_PROTOCOL, "GTP <"); + col_append_str(pinfo->cinfo, COL_PROTOCOL, ">"); + } + pinfo->private_data = pd_save; } static void dissect_gtpprim(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) @@ -7188,7 +7212,12 @@ void proto_register_gtp(void) FT_UINT8, BASE_DEC, NULL, GTP_SPARE1_MASK, "Reserved (shall be sent as '111' )", HFILL} }, - {&hf_gtp_flags_snn, + {&hf_gtp_flags_hdr_length, + {"Header length", "gtp.flags._hdr_length", + FT_BOOLEAN, 8, TFS(>p_hdr_length_vals), 0x01, + NULL, HFILL} + }, + {&hf_gtp_flags_snn, {"Is SNDCP N-PDU included?", "gtp.flags.snn", FT_BOOLEAN, 8, TFS(&yes_no_tfs), GTP_SNN_MASK, "Is SNDCP N-PDU LLC Number included? (1 = yes, 0 = no)", HFILL}}, {&hf_gtp_flags_spare2, |