diff options
Diffstat (limited to 'epan/dissectors/packet-xtp.c')
-rw-r--r-- | epan/dissectors/packet-xtp.c | 1398 |
1 files changed, 1398 insertions, 0 deletions
diff --git a/epan/dissectors/packet-xtp.c b/epan/dissectors/packet-xtp.c new file mode 100644 index 00000000..b85abf16 --- /dev/null +++ b/epan/dissectors/packet-xtp.c @@ -0,0 +1,1398 @@ +/* packet-xtp.c + * Routines for Xpress Transport Protocol dissection + * Copyright 2008, Shigeo Nakamura <naka_shigeo@yahoo.co.jp> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Ref: http://www.packeteer.com/resources/prod-sol/XTP.pdf + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/exceptions.h> +#include <epan/expert.h> +#include <epan/ipproto.h> +#include <epan/in_cksum.h> + +#define XTP_VERSION_4 0x001 + +/* XTP type of Service */ +#define XTP_TOS_UNSPEC 0 +#define XTP_TOS_UNACKED_DGRAM 1 +#define XTP_TOS_ACKED_DGRAM 2 +#define XTP_TOS_TRANS 3 +#define XTP_TOS_UNICAST_STREAM 4 +#define XTP_TOS_UNACKED_MULTICAST_STREAM 5 +#define XTP_TOS_MULTICAST_STREAM 6 + +/* Address Format */ +#define XTP_ADDR_NULL 0 +#define XTP_ADDR_IP 1 +#define XTP_ADDR_ISO 2 +#define XTP_ADDR_XEROX 3 +#define XTP_ADDR_IPX 4 +#define XTP_ADDR_LOCAL 5 +#define XTP_ADDR_IP6 6 + +/* packet type */ +#define XTP_DATA_PKT 0 +#define XTP_CNTL_PKT 1 +#define XTP_FIRST_PKT 2 +#define XTP_ECNTL_PKT 3 +#define XTP_TCNTL_PKT 5 +#define XTP_JOIN_PKT 6 +#define XTP_JCNTL_PKT 7 +#define XTP_DIAG_PKT 8 + +/* cmd options mask */ +#define XTP_CMD_OPTIONS_NOCHECK 0x400000 +#define XTP_CMD_OPTIONS_EDGE 0x200000 +#define XTP_CMD_OPTIONS_NOERR 0x100000 +#define XTP_CMD_OPTIONS_MULTI 0x080000 +#define XTP_CMD_OPTIONS_RES 0x040000 +#define XTP_CMD_OPTIONS_SORT 0x020000 +#define XTP_CMD_OPTIONS_NOFLOW 0x010000 +#define XTP_CMD_OPTIONS_FASTNAK 0x008000 +#define XTP_CMD_OPTIONS_SREQ 0x004000 +#define XTP_CMD_OPTIONS_DREQ 0x002000 +#define XTP_CMD_OPTIONS_RCLOSE 0x001000 +#define XTP_CMD_OPTIONS_WCLOSE 0x000800 +#define XTP_CMD_OPTIONS_EOM 0x000400 +#define XTP_CMD_OPTIONS_END 0x000200 +#define XTP_CMD_OPTIONS_BTAG 0x000100 + +#define XTP_KEY_RTN ((guint64)1<<63) + +void proto_register_xtp(void); +void proto_reg_handoff_xtp(void); + +static dissector_handle_t xtp_handle; + +/** packet structures definition **/ +struct xtp_cntl { + guint64 rseq; + guint64 alloc; + guint32 echo; +}; +#define XTP_CNTL_PKT_LEN 20 + +struct xtp_ecntl { + guint64 rseq; + guint64 alloc; + guint32 echo; + guint32 nspan; +}; +#define MIN_XTP_ECNTL_PKT_LEN 24 + +struct xtp_traffic_cntl { + guint64 rseq; + guint64 alloc; + guint32 echo; + guint32 rsvd; + guint64 xkey; +}; +#define XTP_TRAFFIC_CNTL_LEN 32 + +/* tformat = 0x00 */ +struct xtp_traffic_spec0 { + guint16 tlen; + guint8 service; + guint8 tformat; + guint32 none; +}; +#define XTP_TRAFFIC_SPEC0_LEN 8 + +/* tformat = 0x01 */ +struct xtp_traffic_spec1 { + guint16 tlen; + guint8 service; + guint8 tformat; + guint32 maxdata; + guint32 inrate; + guint32 inburst; + guint32 outrate; + guint32 outburst; +}; +#define XTP_TRAFFIC_SPEC1_LEN 24 + +struct xtp_ip_addr_seg { + guint16 alen; + guint8 adomain; + guint8 aformat; + guint32 dsthost; + guint32 srchost; + guint16 dstport; + guint16 srcport; +}; +#define XTP_IP_ADDR_SEG_LEN 16 +#define XTP_NULL_ADDR_SEG_LEN 8 + +struct xtp_diag { + guint32 code; + guint32 val; + gchar *msg; +}; +#define XTP_DIAG_PKT_HEADER_LEN 8 + +struct xtphdr { + guint64 key; + guint32 cmd; + guint32 cmd_options; /* 24 bits */ + guint8 cmd_ptype; + guint8 cmd_ptype_ver; /* 3 bits */ + guint8 cmd_ptype_pformat; /* 5 bits */ + guint32 dlen; + guint16 check; + guint16 sort; + guint32 sync; + guint64 seq; +}; +#define XTP_HEADER_LEN 32 + + +static const value_string version_vals[] = { + { XTP_VERSION_4, "XTP version 4.0" }, + { 0, NULL } +}; + +static const value_string service_vals[] = { + { XTP_TOS_UNSPEC, "Unspecified" }, + { XTP_TOS_UNACKED_DGRAM, "Traditional Unacknowledged Datagram Service" }, + { XTP_TOS_ACKED_DGRAM, "Acknowledged Datagram Service" }, + { XTP_TOS_TRANS, "Transaction Service" }, + { XTP_TOS_UNICAST_STREAM, "Traditional Reliable Unicast Stream Service" }, + { XTP_TOS_UNACKED_MULTICAST_STREAM, "Unacknowledged Multicast Stream Service" }, + { XTP_TOS_MULTICAST_STREAM, "Reliable Multicast Stream Service" }, + { 0, NULL } +}; + +static const value_string aformat_vals[] = { + { XTP_ADDR_NULL, "Null Address" }, + { XTP_ADDR_IP, "Internet Protocol Address" }, + { XTP_ADDR_ISO, "ISO Connectionless Network Layer Protocol Address" }, + { XTP_ADDR_XEROX, "Xerox Network System Address" }, + { XTP_ADDR_IPX, "IPX Address" }, + { XTP_ADDR_LOCAL, "Local Address" }, + { XTP_ADDR_IP6, "Internet Protocol Version 6 Address" }, + { 0, NULL } +}; + +static const value_string pformat_vals[] = { + { XTP_DATA_PKT, "DATA" }, + { XTP_CNTL_PKT, "CNTL" }, + { XTP_FIRST_PKT, "FIRST" }, + { XTP_ECNTL_PKT, "ECNTL" }, + { XTP_TCNTL_PKT, "TCNTL" }, + { XTP_JOIN_PKT, "JOIN<obsolete>" }, + { XTP_JCNTL_PKT, "JCNTL" }, + { XTP_DIAG_PKT, "DIAG" }, + { 0, NULL } +}; + +static const value_string diag_code_vals[] = { + { 1, "Context Refused" }, + { 2, "Context Abandoned" }, + { 3, "Invalid Context" }, + { 4, "Request Refused" }, + { 5, "Join Refused" }, + { 6, "Protocol Error" }, + { 7, "Maximum Packet Size Error" }, + { 0, NULL } +}; + +static const value_string diag_val_vals[] = { + { 0, "Unspecified" }, + { 1, "No listener" }, + { 2, "Options refused" }, + { 3, "Address format not supported" }, + { 4, "Malformed address format" }, + { 5, "Traffic format not supported" }, + { 6, "Traffic specification refused" }, + { 7, "Malformed traffic format" }, + { 8, "No provider for service" }, + { 9, "No resource" }, + { 10, "Host going down" }, + { 11, "Invalid retransmission request" }, + { 12, "Context in improper state" }, + { 13, "Join request denied" }, + { 0, NULL } +}; + +/* Initialize the protocol and registered fields */ +static int proto_xtp = -1; +/* common header */ +static int hf_xtp_key = -1; +static int hf_xtp_cmd = -1; +static int hf_xtp_cmd_options = -1; +static int hf_xtp_cmd_options_nocheck = -1; +static int hf_xtp_cmd_options_edge = -1; +static int hf_xtp_cmd_options_noerr = -1; +static int hf_xtp_cmd_options_multi = -1; +static int hf_xtp_cmd_options_res = -1; +static int hf_xtp_cmd_options_sort = -1; +static int hf_xtp_cmd_options_noflow = -1; +static int hf_xtp_cmd_options_fastnak = -1; +static int hf_xtp_cmd_options_sreq = -1; +static int hf_xtp_cmd_options_dreq = -1; +static int hf_xtp_cmd_options_rclose = -1; +static int hf_xtp_cmd_options_wclose = -1; +static int hf_xtp_cmd_options_eom = -1; +static int hf_xtp_cmd_options_end = -1; +static int hf_xtp_cmd_options_btag = -1; +static int hf_xtp_cmd_ptype = -1; +static int hf_xtp_cmd_ptype_ver = -1; +static int hf_xtp_cmd_ptype_pformat = -1; +static int hf_xtp_dlen = -1; +static int hf_xtp_sort = -1; +static int hf_xtp_sync = -1; +static int hf_xtp_seq = -1; +/* control segment */ +static int hf_xtp_cntl_rseq = -1; +static int hf_xtp_cntl_alloc = -1; +static int hf_xtp_cntl_echo = -1; +static int hf_xtp_ecntl_rseq = -1; +static int hf_xtp_ecntl_alloc = -1; +static int hf_xtp_ecntl_echo = -1; +static int hf_xtp_ecntl_nspan = -1; +static int hf_xtp_ecntl_span_left = -1; +static int hf_xtp_ecntl_span_right = -1; +static int hf_xtp_tcntl_rseq = -1; +static int hf_xtp_tcntl_alloc = -1; +static int hf_xtp_tcntl_echo = -1; +static int hf_xtp_tcntl_rsvd = -1; +static int hf_xtp_tcntl_xkey = -1; +/* traffic specifier */ +static int hf_xtp_tspec_tlen = -1; +static int hf_xtp_tspec_service = -1; +static int hf_xtp_tspec_tformat = -1; +static int hf_xtp_tspec_traffic = -1; +static int hf_xtp_tspec_maxdata = -1; +static int hf_xtp_tspec_inrate = -1; +static int hf_xtp_tspec_outrate = -1; +static int hf_xtp_tspec_inburst = -1; +static int hf_xtp_tspec_outburst = -1; +/* address segment */ +static int hf_xtp_aseg_alen = -1; +static int hf_xtp_aseg_adomain = -1; +static int hf_xtp_aseg_aformat = -1; +static int hf_xtp_aseg_address = -1; +static int hf_xtp_aseg_dsthost = -1; +static int hf_xtp_aseg_srchost = -1; +static int hf_xtp_aseg_dstport = -1; +static int hf_xtp_aseg_srcport = -1; +/* others */ +static int hf_xtp_btag = -1; +static int hf_xtp_diag_code = -1; +static int hf_xtp_diag_val = -1; +static int hf_xtp_diag_msg = -1; +static int hf_xtp_checksum = -1; +static int hf_xtp_checksum_status = -1; +static int hf_xtp_data = -1; + +/* Initialize the subtree pointers */ +static gint ett_xtp = -1; +static gint ett_xtp_cmd = -1; +static gint ett_xtp_cmd_options = -1; +static gint ett_xtp_cmd_ptype = -1; +static gint ett_xtp_cntl = -1; +static gint ett_xtp_ecntl = -1; +static gint ett_xtp_tcntl = -1; +static gint ett_xtp_tspec = -1; +static gint ett_xtp_jcntl = -1; +static gint ett_xtp_first = -1; +static gint ett_xtp_aseg = -1; +static gint ett_xtp_data = -1; +static gint ett_xtp_diag = -1; + +static expert_field ei_xtp_spans_bad = EI_INIT; +static expert_field ei_xtp_checksum = EI_INIT; + +/* dissector of each payload */ +static int +dissect_xtp_aseg(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { + guint32 len = tvb_reported_length_remaining(tvb, offset); + guint32 start = offset; + proto_item *ti, *ti2, *top_ti; + proto_tree *xtp_subtree; + struct xtp_ip_addr_seg aseg[1]; + int error = 0; + + xtp_subtree = proto_tree_add_subtree(tree, tvb, offset, len, ett_xtp_aseg, &top_ti, "Address Segment"); + + if (len < XTP_NULL_ADDR_SEG_LEN) { + proto_item_append_text(top_ti, ", bogus length(%u, must be at least %u)", + len, XTP_NULL_ADDR_SEG_LEN); + return 0; + } + + /** parse common fields **/ + /* alen(2) */ + aseg->alen = tvb_get_ntohs(tvb, offset); + offset += 2; + /* adomain(1) */ + aseg->adomain = tvb_get_guint8(tvb, offset); + offset++; + /* aformat(1) */ + aseg->aformat = tvb_get_guint8(tvb, offset); + + /** display common fields **/ + offset = start; + /* alen(2) */ + ti = proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_alen, + tvb, offset, 2, aseg->alen); + offset += 2; + if (aseg->alen > len) { + proto_item_append_text(ti, ", bogus length(%u, must be at most %u)", + aseg->alen, len); + error = 1; + } + /* adomain(1) */ + proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_adomain, + tvb, offset, 1, aseg->adomain); + offset++; + /* aformat(1) */ + ti2 = proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_aformat, + tvb, offset, 1, aseg->aformat); + offset++; + switch (aseg->aformat) { + case 0: + if (aseg->alen != XTP_NULL_ADDR_SEG_LEN) { + proto_item_append_text(ti, ", bogus length(%u, must be %u)", + aseg->alen, XTP_NULL_ADDR_SEG_LEN); + error = 1; + } + break; + case 1: + if (aseg->alen != XTP_IP_ADDR_SEG_LEN) { + proto_item_append_text(ti, ", bogus length(%u, must be %u)", + aseg->alen, XTP_IP_ADDR_SEG_LEN); + error = 1; + } + break; + default: + if (aseg->aformat < 128) { + proto_item_append_text(ti2, + ", Unsupported aformat(%u)", aseg->aformat); + error = 1; + } + break; + } + + if (error) + return (offset - start); + + /** parse and display each address fileds */ + switch (aseg->aformat) { + case 0: + /* address(4) */ + aseg->dsthost = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_address, + tvb, offset, 4, aseg->dsthost); + offset += 4; + break; + case 1: + /* dsthost(4) */ + aseg->dsthost = tvb_get_ipv4(tvb, offset); + proto_tree_add_ipv4(xtp_subtree, hf_xtp_aseg_dsthost, + tvb, offset, 4, aseg->dsthost); + offset += 4; + /* srchost(4) */ + aseg->srchost = tvb_get_ipv4(tvb, offset); + proto_tree_add_ipv4(xtp_subtree, hf_xtp_aseg_srchost, + tvb, offset, 4, aseg->srchost); + offset += 4; + /* dstport(2) */ + aseg->dstport = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_dstport, + tvb, offset, 2, aseg->dstport); + offset += 2; + /* srcport(2) */ + aseg->srcport = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_srcport, + tvb, offset, 2, aseg->srcport); + offset += 2; + + /** add summary **/ + proto_item_append_text(top_ti, ", Dst Port: %u", aseg->dstport); + proto_item_append_text(top_ti, ", Src Port: %u", aseg->srcport); + break; + default: + break; + } + + return (offset - start); +} + +static int +dissect_xtp_traffic_cntl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + guint32 offset) { + guint32 len = tvb_reported_length_remaining(tvb, offset); + guint32 start = offset; + proto_item *top_ti; + proto_tree *xtp_subtree; + struct xtp_traffic_cntl tcntl[1]; + + xtp_subtree = proto_tree_add_subtree(tree, tvb, offset, len, + ett_xtp_tcntl, &top_ti, "Traffic Control Segment"); + + if (len < XTP_TRAFFIC_CNTL_LEN) { + proto_item_append_text(top_ti, + ", bogus length(%u, must be at least %u)", + len, XTP_TRAFFIC_CNTL_LEN); + return 0; + } + + /** parse **/ + /* rseq(8) */ + tcntl->rseq = tvb_get_ntohl(tvb, offset); + tcntl->rseq <<= 32; + tcntl->rseq += tvb_get_ntohl(tvb, offset+4); + offset += 8; + /* alloc(8) */ + tcntl->alloc = tvb_get_ntohl(tvb, offset); + tcntl->alloc <<= 32; + tcntl->alloc += tvb_get_ntohl(tvb, offset+4); + offset += 8; + /* echo(4) */ + tcntl->echo = tvb_get_ntohl(tvb, offset); + offset += 4; + /* rsvd(4) */ + tcntl->rsvd = tvb_get_ntohl(tvb, offset); + offset += 4; + /* xkey(8) */ + tcntl->xkey = tvb_get_ntohl(tvb, offset); + tcntl->xkey <<= 32; + tcntl->xkey += tvb_get_ntohl(tvb, offset+4); + + /** add summary **/ + col_append_fstr(pinfo->cinfo, COL_INFO, + " Recv-Seq=%" PRIu64, tcntl->rseq); + col_append_fstr(pinfo->cinfo, COL_INFO, + " Alloc=%" PRIu64, tcntl->alloc); + + proto_item_append_text(top_ti, + ", Recv-Seq: %" PRIu64, tcntl->rseq); + + /** display **/ + offset = start; + /* rseq(8) */ + proto_tree_add_uint64(xtp_subtree, hf_xtp_tcntl_rseq, + tvb, offset, 8, tcntl->rseq); + offset += 8; + /* alloc(8) */ + proto_tree_add_uint64(xtp_subtree, hf_xtp_tcntl_alloc, + tvb, offset, 8, tcntl->alloc); + offset += 4; + /* echo(4) */ + proto_tree_add_uint(xtp_subtree, hf_xtp_tcntl_echo, + tvb, offset, 4, tcntl->echo); + offset += 4; + /* rsvd(4) */ + proto_tree_add_uint(xtp_subtree, hf_xtp_tcntl_rsvd, + tvb, offset, 4, tcntl->rsvd); + offset += 4; + /* xkey(8) */ + proto_tree_add_uint64(xtp_subtree, hf_xtp_tcntl_xkey, + tvb, offset, 8, tcntl->xkey); + offset += 8; + + return (offset - start); +} + +static int +dissect_xtp_tspec(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { + guint32 len = tvb_reported_length_remaining(tvb, offset); + guint32 start = offset; + proto_item *ti, *ti2; + proto_tree *xtp_subtree; + struct xtp_traffic_spec1 tspec[1]; + int error = 0; + + xtp_subtree = proto_tree_add_subtree(tree, tvb, offset, len, ett_xtp_tspec, &ti, "Traffic Specifier"); + + if (len < XTP_TRAFFIC_SPEC0_LEN) { + proto_item_append_text(ti, + ", bogus length(%u, must be at least %u)", + len, XTP_TRAFFIC_SPEC0_LEN); + return 0; + } + + /** parse common fields **/ + /* tlen(2) */ + tspec->tlen = tvb_get_ntohs(tvb, offset); + offset += 2; + /* service(1) */ + tspec->service = tvb_get_guint8(tvb, offset); + offset++; + /* tformat(1) */ + tspec->tformat = tvb_get_guint8(tvb, offset); + + /** display common fields */ + offset = start; + /* tlen(2) */ + ti = proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_tlen, + tvb, offset, 2, tspec->tlen); + offset += 2; + if (tspec->tlen > len) { + proto_item_append_text(ti, ", bogus length(%u, must be at most %u)", + tspec->tlen, len); + error = 1; + } + /* service(1) */ + proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_service, + tvb, offset, 1, tspec->service); + offset++; + /* tformat(1) */ + ti2 = proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_tformat, + tvb, offset, 1, tspec->tformat); + offset++; + switch (tspec->tformat) { + case 0: + if (tspec->tlen != XTP_TRAFFIC_SPEC0_LEN) { + proto_item_append_text(ti, ", bogus length(%u, must be %u)", + tspec->tlen, XTP_TRAFFIC_SPEC0_LEN); + error = 1; + } + break; + case 1: + if (tspec->tlen != XTP_TRAFFIC_SPEC1_LEN) { + proto_item_append_text(ti, ", bogus length(%u, must be %u)", + tspec->tlen, XTP_TRAFFIC_SPEC1_LEN); + error = 1; + } + break; + default: + proto_item_append_text(ti2, ", Unsupported tformat(%u)", + tspec->tformat); + error = 1; + break; + } + + if (error) + return (offset - start); + + /** parse and display each traffic fields **/ + switch (tspec->tformat) { + case 0: + /* traffic(4) */ + tspec->maxdata = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_traffic, + tvb, offset, 4, tspec->maxdata); + offset += 4; + break; + case 1: + /* maxdata(4) */ + tspec->maxdata = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_maxdata, + tvb, offset, 4, tspec->maxdata); + offset += 4; + /* inrate(4) */ + tspec->inrate = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_inrate, + tvb, offset, 4, tspec->inrate); + offset += 4; + /* inburst(4) */ + tspec->inburst = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_inburst, + tvb, offset, 4, tspec->inburst); + offset += 4; + /* outrate(4) */ + tspec->outrate = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_outrate, + tvb, offset, 4, tspec->outrate); + offset += 4; + /* outburst(4) */ + tspec->outburst = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_outburst, + tvb, offset, 4, tspec->outburst); + offset += 4; + break; + default: + break; + } + + return (offset - start); +} + +static void +dissect_xtp_data(tvbuff_t *tvb, proto_tree *tree, guint32 offset, gboolean have_btag) { + guint32 len = tvb_reported_length_remaining(tvb, offset); + proto_tree *xtp_subtree; + guint64 btag; + + xtp_subtree = proto_tree_add_subtree(tree, tvb, offset, len, ett_xtp_data, NULL, "Data Segment"); + + if (have_btag) { + btag = tvb_get_ntohl(tvb, offset); + btag <<= 32; + btag += tvb_get_ntohl(tvb, offset+4); + proto_tree_add_uint64(xtp_subtree, hf_xtp_btag, tvb, offset, 8, btag); + offset += 8; + len -= 8; + } + + proto_tree_add_item(xtp_subtree, hf_xtp_data, tvb, offset, len, ENC_NA); + + return; +} + +static void +dissect_xtp_cntl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + guint32 offset) { + guint32 len = tvb_reported_length_remaining(tvb, offset); + guint32 start = offset; + proto_item *top_ti; + proto_tree *xtp_subtree; + struct xtp_cntl cntl[1]; + + xtp_subtree = proto_tree_add_subtree(tree, tvb, offset, len, + ett_xtp_cntl, &top_ti, "Common Control Segment"); + + if (len != XTP_CNTL_PKT_LEN) { + proto_item_append_text(top_ti, ", bogus length(%u, must be %u)", + len, XTP_CNTL_PKT_LEN); + return; + } + + /** parse **/ + /* rseq(8) */ + cntl->rseq = tvb_get_ntohl(tvb, offset); + cntl->rseq <<= 32; + cntl->rseq += tvb_get_ntohl(tvb, offset+4); + offset += 8; + /* alloc(8) */ + cntl->alloc = tvb_get_ntohl(tvb, offset); + cntl->alloc <<= 32; + cntl->alloc += tvb_get_ntohl(tvb, offset+4); + offset += 8; + /* echo(4) */ + cntl->echo = tvb_get_ntohl(tvb, offset); + + /** add summary **/ + col_append_fstr(pinfo->cinfo, COL_INFO, + " Recv-Seq=%" PRIu64, cntl->rseq); + col_append_fstr(pinfo->cinfo, COL_INFO, + " Alloc=%" PRIu64, cntl->alloc); + + proto_item_append_text(top_ti, + ", Recv-Seq: %" PRIu64, cntl->rseq); + + /** display **/ + offset = start; + /* rseq(8) */ + proto_tree_add_uint64(xtp_subtree, hf_xtp_cntl_rseq, + tvb, offset, 8, cntl->rseq); + offset += 8; + /* alloc(8) */ + proto_tree_add_uint64(xtp_subtree, hf_xtp_cntl_alloc, + tvb, offset, 8, cntl->alloc); + offset += 4; + /* echo(4) */ + proto_tree_add_uint(xtp_subtree, hf_xtp_cntl_echo, + tvb, offset, 4, cntl->echo); + + return; +} + +static void +dissect_xtp_first(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { + + if (!dissect_xtp_aseg(tvb, tree, offset)) + return; + + offset += XTP_IP_ADDR_SEG_LEN; + dissect_xtp_tspec(tvb, tree, offset); + + return; +} + +#define XTP_MAX_NSPANS 10000 /* Arbitrary. (Documentation link is dead.) */ +static void +dissect_xtp_ecntl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + guint32 offset) { + guint32 len = tvb_reported_length_remaining(tvb, offset); + guint32 start = offset; + proto_item *top_ti; + proto_tree *xtp_subtree; + struct xtp_ecntl ecntl[1]; + guint spans_len; + guint i; + + xtp_subtree = proto_tree_add_subtree(tree, tvb, offset, len, + ett_xtp_ecntl, &top_ti, "Error Control Segment"); + + if (len < MIN_XTP_ECNTL_PKT_LEN) { + proto_item_append_text(top_ti, + ", bogus length (%u, must be at least %u)", + len, MIN_XTP_ECNTL_PKT_LEN); + return; + } + + /** parse **/ + /* rseq(8) */ + ecntl->rseq = tvb_get_ntohl(tvb, offset); + ecntl->rseq <<= 32; + ecntl->rseq += tvb_get_ntohl(tvb, offset+4); + offset += 8; + /* alloc(8) */ + ecntl->alloc = tvb_get_ntohl(tvb, offset); + ecntl->alloc <<= 32; + ecntl->alloc += tvb_get_ntohl(tvb, offset+4); + offset += 8; + /* echo(4) */ + ecntl->echo = tvb_get_ntohl(tvb, offset); + offset += 4; + /* nspan(4) */ + ecntl->nspan = tvb_get_ntohl(tvb, offset); + offset += 4; + len = len + XTP_HEADER_LEN - offset; + spans_len = 16 * ecntl->nspan; + + if (len != spans_len) { + expert_add_info_format(pinfo, top_ti, &ei_xtp_spans_bad, "Number of spans (%u) incorrect. Should be %u.", ecntl->nspan, len); + return; + } + + if (ecntl->nspan > XTP_MAX_NSPANS) { + expert_add_info_format(pinfo, top_ti, &ei_xtp_spans_bad, "Too many spans: %u", ecntl->nspan); + return; + } + + /** add summary **/ + col_append_fstr(pinfo->cinfo, COL_INFO, + " Recv-Seq=%" PRIu64, ecntl->rseq); + col_append_fstr(pinfo->cinfo, COL_INFO, + " Alloc=%" PRIu64, ecntl->alloc); + + proto_item_append_text(top_ti, + ", Recv-Seq: %" PRIu64, ecntl->rseq); + + /** display **/ + offset = start; + /* rseq(8) */ + proto_tree_add_uint64(xtp_subtree, hf_xtp_ecntl_rseq, + tvb, offset, 8, ecntl->rseq); + offset += 8; + /* alloc(8) */ + proto_tree_add_uint64(xtp_subtree, hf_xtp_ecntl_alloc, + tvb, offset, 8, ecntl->alloc); + offset += 8; + /* echo(4) */ + proto_tree_add_uint(xtp_subtree, hf_xtp_ecntl_echo, + tvb, offset, 4, ecntl->echo); + offset += 4; + /* nspan(4) */ + proto_tree_add_uint(xtp_subtree, hf_xtp_ecntl_nspan, + tvb, offset, 4, ecntl->nspan); + offset += 4; + /* spans(16n) */ + for (i = 0; i < ecntl->nspan; i++) { + proto_tree_add_item(xtp_subtree, hf_xtp_ecntl_span_left, + tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + proto_tree_add_item(xtp_subtree, hf_xtp_ecntl_span_right, + tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + } + + return; +} + +static void +dissect_xtp_tcntl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + guint32 offset) { + + if (!dissect_xtp_traffic_cntl(tvb, pinfo, tree, offset)) + return; + + offset += XTP_TRAFFIC_CNTL_LEN; + dissect_xtp_tspec(tvb, tree, offset); + + return; +} + +static void +dissect_xtp_jcntl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + guint32 offset) { + + if (!dissect_xtp_traffic_cntl(tvb, pinfo, tree, offset)) + return; + + offset += XTP_TRAFFIC_CNTL_LEN; + if (!dissect_xtp_aseg(tvb, tree, offset)) + return; + + offset += XTP_IP_ADDR_SEG_LEN; + dissect_xtp_tspec(tvb, tree, offset); + + return; +} + +static void +dissect_xtp_diag(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { + guint32 len = tvb_reported_length_remaining(tvb, offset); + proto_item *ti; + proto_tree *xtp_subtree; + + xtp_subtree = proto_tree_add_subtree(tree, tvb, offset, len, ett_xtp_diag, &ti, "Diagnostic Segment"); + + if (len < XTP_DIAG_PKT_HEADER_LEN) { + proto_item_append_text(ti, + ", bogus length (%u, must be at least %u)", + len, XTP_DIAG_PKT_HEADER_LEN); + return; + } + + /* code(4) */ + proto_tree_add_item(xtp_subtree, hf_xtp_diag_code, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + /* val(4) */ + proto_tree_add_item(xtp_subtree, hf_xtp_diag_val, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + /* message(n) */ + proto_tree_add_item(xtp_subtree, hf_xtp_diag_msg, + tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_ASCII); + + return; +} + +/* main dissector */ +static int +dissect_xtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { + guint32 offset, len; + proto_item *ti; + proto_tree *xtp_tree, *xtp_cmd_tree, *xtp_subtree; + struct xtphdr xtph[1]; + int error = 0; + gchar *options; + static const char *fstr[] = { "<None>", "NOCHECK", "EDGE", "NOERR", "MULTI", "RES", + "SORT", "NOFLOW", "FASTNAK", "SREQ", "DREQ", + "RCLOSE", "WCLOSE", "EOM", "END", "BTAG" }; + gint fpos = 0, returned_length; + guint i, bpos; + guint cmd_options; + vec_t cksum_vec[1]; + gboolean have_btag; + static int * const cmd_options_flags[] = { + &hf_xtp_cmd_options_nocheck, + &hf_xtp_cmd_options_edge, + &hf_xtp_cmd_options_noerr, + &hf_xtp_cmd_options_multi, + &hf_xtp_cmd_options_res, + &hf_xtp_cmd_options_sort, + &hf_xtp_cmd_options_noflow, + &hf_xtp_cmd_options_fastnak, + &hf_xtp_cmd_options_sreq, + &hf_xtp_cmd_options_dreq, + &hf_xtp_cmd_options_rclose, + &hf_xtp_cmd_options_wclose, + &hf_xtp_cmd_options_eom, + &hf_xtp_cmd_options_end, + &hf_xtp_cmd_options_btag, + NULL + }; + + if ((len = tvb_reported_length(tvb)) < XTP_HEADER_LEN) + return 0; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "XTP"); + col_clear(pinfo->cinfo, COL_INFO); + + /** parse header **/ + offset = 0; + /* key(8) */ + xtph->key = tvb_get_ntohl(tvb, offset); + xtph->key <<= 32; + xtph->key += tvb_get_ntohl(tvb, offset+4); + offset += 8; + /* cmd(4) */ + xtph->cmd = tvb_get_ntohl(tvb, offset); + xtph->cmd_options = xtph->cmd >> 8; + xtph->cmd_ptype = xtph->cmd & 0xff; + xtph->cmd_ptype_ver = (xtph->cmd_ptype & 0xe0) >> 5; + xtph->cmd_ptype_pformat = xtph->cmd_ptype & 0x1f; + offset += 4; + /* dlen(4) */ + xtph->dlen = tvb_get_ntohl(tvb, offset); + offset += 4; + /* check(2) */ + xtph->check = tvb_get_ntohs(tvb, offset); + offset += 2; + /* sort(2) */ + xtph->sort = tvb_get_ntohs(tvb, offset); + offset += 2; + /* sync(4) */ + xtph->sync = tvb_get_ntohl(tvb, offset); + offset += 4; + /* seq(8) */ + xtph->seq = tvb_get_ntohl(tvb, offset); + xtph->seq <<= 32; + xtph->seq += tvb_get_ntohl(tvb, offset+4); + +#define MAX_OPTIONS_LEN 128 + options=(gchar *)wmem_alloc(pinfo->pool, MAX_OPTIONS_LEN); + options[0]=0; + cmd_options = xtph->cmd_options >> 8; + for (i = 0; i < 16; i++) { + bpos = 1 << (15 - i); + if (cmd_options & bpos) { + returned_length = snprintf(&options[fpos], + MAX_OPTIONS_LEN-fpos, "%s%s", + fpos?", ":"", + fstr[i]); + fpos += MIN(returned_length, MAX_OPTIONS_LEN-fpos); + } + } + + col_add_str(pinfo->cinfo, COL_INFO, + val_to_str(xtph->cmd_ptype_pformat, + pformat_vals, "Unknown pformat (%u)")); + col_append_fstr(pinfo->cinfo, COL_INFO, " [%s]", options); + col_append_fstr(pinfo->cinfo, COL_INFO, + " Seq=%" PRIu64, xtph->seq); + col_append_fstr(pinfo->cinfo, COL_INFO, " Len=%u", xtph->dlen); + + /* if (tree) */ { + ti = proto_tree_add_item(tree, proto_xtp, tvb, 0, -1, ENC_NA); + /** add summary **/ + proto_item_append_text(ti, + ", Key: 0x%016" PRIX64, xtph->key); + proto_item_append_text(ti, + ", Seq: %" PRIu64, xtph->seq); + proto_item_append_text(ti, ", Len: %u", xtph->dlen); + + xtp_tree = proto_item_add_subtree(ti, ett_xtp); + /* key(8) */ + offset = 0; + proto_tree_add_uint64(xtp_tree, hf_xtp_key, + tvb, offset, 8, xtph->key); + offset += 8; + /* cmd(4) */ + ti = proto_tree_add_uint(xtp_tree, hf_xtp_cmd, + tvb, offset, 4, xtph->cmd); + xtp_cmd_tree = proto_item_add_subtree(ti, ett_xtp_cmd); + proto_tree_add_bitmask(xtp_cmd_tree, tvb, offset, hf_xtp_cmd_options, ett_xtp_cmd_options, cmd_options_flags, ENC_BIG_ENDIAN); + offset += 3; + + ti = proto_tree_add_uint(xtp_cmd_tree, hf_xtp_cmd_ptype, + tvb, offset, 1, xtph->cmd_ptype); + xtp_subtree = proto_item_add_subtree(ti, ett_xtp_cmd_ptype); + proto_tree_add_uint(xtp_subtree, hf_xtp_cmd_ptype_ver, + tvb, offset, 1, xtph->cmd_ptype_ver); + if (xtph->cmd_ptype_ver != XTP_VERSION_4) { + proto_item_append_text(ti, + ", Unknown XTP version (%03X)", xtph->cmd_ptype_ver); + error = 1; + } + proto_tree_add_uint(xtp_subtree, hf_xtp_cmd_ptype_pformat, + tvb, offset, 1, xtph->cmd_ptype_pformat); + offset++; + /* dlen(4) */ + ti = proto_tree_add_uint(xtp_tree, hf_xtp_dlen, + tvb, offset, 4, xtph->dlen); + if (xtph->dlen != len - XTP_HEADER_LEN) { + proto_item_append_text(ti, ", bogus length (%u, must be %u)", + xtph->dlen, len - XTP_HEADER_LEN); + error = 1; + } + offset += 4; + /* check(2) */ + if (!pinfo->fragmented) { + guint32 check_len = XTP_HEADER_LEN; + if (!(xtph->cmd_options & XTP_CMD_OPTIONS_NOCHECK)) + check_len += xtph->dlen; + SET_CKSUM_VEC_TVB(cksum_vec[0], tvb, 0, check_len); + proto_tree_add_checksum(xtp_tree, tvb, offset, hf_xtp_checksum, hf_xtp_checksum_status, &ei_xtp_checksum, + pinfo, in_cksum(cksum_vec, 1), ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_IN_CKSUM); + } + else { + proto_tree_add_checksum(xtp_tree, tvb, offset, hf_xtp_checksum, hf_xtp_checksum_status, &ei_xtp_checksum, + pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); + } + offset += 2; + /* sort(2) */ + proto_tree_add_uint(xtp_tree, hf_xtp_sort, tvb, offset, 2, xtph->sort); + offset += 2; + /* sync(4) */ + proto_tree_add_uint(xtp_tree, hf_xtp_sync, tvb, offset, 4, xtph->sync); + offset += 4; + /* seq(8) */ + proto_tree_add_uint64(xtp_tree, hf_xtp_seq, tvb, offset, 8, xtph->seq); + offset += 8; + + if (!error) { + switch (xtph->cmd_ptype_pformat) { + case XTP_DATA_PKT: + have_btag = !!(xtph->cmd_options & XTP_CMD_OPTIONS_BTAG); + dissect_xtp_data(tvb, xtp_tree, offset, have_btag); + break; + case XTP_CNTL_PKT: + dissect_xtp_cntl(tvb, pinfo, xtp_tree, offset); + break; + case XTP_FIRST_PKT: + dissect_xtp_first(tvb, xtp_tree, offset); + break; + case XTP_ECNTL_PKT: + dissect_xtp_ecntl(tvb, pinfo, xtp_tree, offset); + break; + case XTP_TCNTL_PKT: + dissect_xtp_tcntl(tvb, pinfo, xtp_tree, offset); + break; + case XTP_JOIN_PKT: + /* obsolete */ + break; + case XTP_JCNTL_PKT: + dissect_xtp_jcntl(tvb, pinfo, xtp_tree, offset); + break; + case XTP_DIAG_PKT: + dissect_xtp_diag(tvb, xtp_tree, offset); + break; + default: + /* error */ + break; + } + } + } + + return tvb_reported_length(tvb); +} + +void +proto_register_xtp(void) +{ + static hf_register_info hf[] = { + /* command header */ + { &hf_xtp_key, + { "Key", "xtp.key", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_xtp_cmd, + { "Command", "xtp.cmd", + FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_cmd_options, + { "Options", "xtp.cmd.options", + FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_cmd_options_nocheck, + { "NOCHECK", "xtp.cmd.options.nocheck", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_NOCHECK, NULL, HFILL } + }, + { &hf_xtp_cmd_options_edge, + { "EDGE", "xtp.cmd.options.edge", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_EDGE, NULL, HFILL } + }, + { &hf_xtp_cmd_options_noerr, + { "NOERR", "xtp.cmd.options.noerr", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_NOERR, NULL, HFILL } + }, + { &hf_xtp_cmd_options_multi, + { "MULTI", "xtp.cmd.options.multi", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_MULTI, NULL, HFILL } + }, + { &hf_xtp_cmd_options_res, + { "RES", "xtp.cmd.options.res", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_RES, NULL, HFILL } + }, + { &hf_xtp_cmd_options_sort, + { "SORT", "xtp.cmd.options.sort", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_SORT, NULL, HFILL } + }, + { &hf_xtp_cmd_options_noflow, + { "NOFLOW", "xtp.cmd.options.noflow", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_NOFLOW, NULL, HFILL } + }, + { &hf_xtp_cmd_options_fastnak, + { "FASTNAK", "xtp.cmd.options.fastnak", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_FASTNAK, NULL, HFILL } + }, + { &hf_xtp_cmd_options_sreq, + { "SREQ", "xtp.cmd.options.sreq", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_SREQ, NULL, HFILL } + }, + { &hf_xtp_cmd_options_dreq, + { "DREQ", "xtp.cmd.options.dreq", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_DREQ, NULL, HFILL } + }, + { &hf_xtp_cmd_options_rclose, + { "RCLOSE", "xtp.cmd.options.rclose", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_RCLOSE, NULL, HFILL } + }, + { &hf_xtp_cmd_options_wclose, + { "WCLOSE", "xtp.cmd.options.wclose", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_WCLOSE, NULL, HFILL } + }, + { &hf_xtp_cmd_options_eom, + { "EOM", "xtp.cmd.options.eom", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_EOM, NULL, HFILL } + }, + { &hf_xtp_cmd_options_end, + { "END", "xtp.cmd.options.end", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_END, NULL, HFILL } + }, + { &hf_xtp_cmd_options_btag, + { "BTAG", "xtp.cmd.options.btag", + FT_BOOLEAN, 24, TFS(&tfs_set_notset), + XTP_CMD_OPTIONS_BTAG, NULL, HFILL } + }, + { &hf_xtp_cmd_ptype, + { "Packet type", "xtp.cmd.ptype", + FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_cmd_ptype_ver, + { "Version", "xtp.cmd.ptype.ver", + FT_UINT8, BASE_DEC, VALS(version_vals), 0x0, NULL, HFILL } + }, + { &hf_xtp_cmd_ptype_pformat, + { "Format", "xtp.cmd.ptype.pformat", + FT_UINT8, BASE_DEC, VALS(pformat_vals), 0x0, NULL, HFILL } + }, + { &hf_xtp_dlen, + { "Data length", "xtp.dlen", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_sort, + { "Sort", "xtp.sort", + FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_sync, + { "Synchronizing handshake", "xtp.sync", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_seq, + { "Sequence number", "xtp.seq", + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + /* control segment */ + { &hf_xtp_cntl_rseq, + { "Received sequence number", "xtp.cntl.rseq", + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_cntl_alloc, + { "Allocation", "xtp.cntl.alloc", + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_cntl_echo, + { "Synchronizing handshake echo", "xtp.cntl.echo", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_ecntl_rseq, + { "Received sequence number", "xtp.ecntl.rseq", + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_ecntl_alloc, + { "Allocation", "xtp.ecntl.alloc", + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_ecntl_echo, + { "Synchronizing handshake echo", "xtp.ecntl.echo", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_ecntl_nspan, + { "Number of spans", "xtp.ecntl.nspan", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_ecntl_span_left, + { "Span left edge", "xtp.ecntl.span_le", + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_ecntl_span_right, + { "Span right edge", "xtp.ecntl.span_re", + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tcntl_rseq, + { "Received sequence number", "xtp.tcntl.rseq", + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tcntl_alloc, + { "Allocation", "xtp.tcntl.alloc", + FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tcntl_echo, + { "Synchronizing handshake echo", "xtp.tcntl.echo", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tcntl_rsvd, + { "Reserved", "xtp.tcntl.rsvd", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tcntl_xkey, + { "Exchange key", "xtp.tcntl.xkey", + FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } + }, + /* traffic specifier */ + { &hf_xtp_tspec_tlen, + { "Length", "xtp.tspec.tlen", + FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tspec_service, + { "Service", "xtp.tspec.service", + FT_UINT8, BASE_DEC, VALS(service_vals), 0x0, NULL, HFILL } + }, + { &hf_xtp_tspec_tformat, + { "Format", "xtp.tspec.format", + FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tspec_traffic, + { "Traffic", "xtp.tspec.traffic", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tspec_maxdata, + { "Maxdata", "xtp.tspec.maxdata", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tspec_inrate, + { "Incoming rate", "xtp.tspec.inrate", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tspec_inburst, + { "Incoming burst size", "xtp.tspec.inburst", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tspec_outrate, + { "Outgoing rate", "xtp.tspec.outrate", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_tspec_outburst, + { "Outgoing burst size", "xtp.tspec.outburst", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + /* address segment */ + { &hf_xtp_aseg_alen, + { "Length", "xtp.aseg.alen", + FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_aseg_adomain, + { "Domain", "xtp.aseg.adomain", + FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_aseg_aformat, + { "Format", "xtp.aseg.aformat", + FT_UINT8, BASE_DEC, VALS(aformat_vals), 0x0, NULL, HFILL } + }, + { &hf_xtp_aseg_address, + { "Traffic", "xtp.aseg.address", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_aseg_dsthost, + { "Destination host", "xtp.aseg.dsthost", + FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_aseg_srchost, + { "Source host", "xtp.aseg.srchost", + FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_aseg_dstport, + { "Destination port", "xtp.aseg.dstport", + FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_aseg_srcport, + { "Source port", "xtp.aseg.srcport", + FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } + }, + /* others */ + { &hf_xtp_btag, + { "Beginning tag", "xtp.data.btag", + FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_diag_code, + { "Diagnostic code", "xtp.diag.code", + FT_UINT32, BASE_DEC, VALS(diag_code_vals), 0x0, NULL, HFILL } + }, + { &hf_xtp_diag_val, + { "Diagnostic value", "xtp.diag.val", + FT_UINT32, BASE_DEC, VALS(diag_val_vals), 0x0, NULL, HFILL } + }, + { &hf_xtp_diag_msg, + { "Message", "xtp.diag.msg", + FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_checksum, + { "Checksum", "xtp.checksum", + FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } + }, + { &hf_xtp_checksum_status, + { "Checksum Status", "xtp.checksum.status", + FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL } + }, + { &hf_xtp_data, + { "Data", "xtp.data", + FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } + }, + }; + + static gint *ett[] = { + &ett_xtp, + &ett_xtp_cmd, + &ett_xtp_cmd_options, + &ett_xtp_cmd_ptype, + &ett_xtp_cntl, + &ett_xtp_ecntl, + &ett_xtp_tcntl, + &ett_xtp_tspec, + &ett_xtp_jcntl, + &ett_xtp_first, + &ett_xtp_aseg, + &ett_xtp_data, + &ett_xtp_diag, + }; + + static ei_register_info ei[] = { + { &ei_xtp_spans_bad, + { "xtp.spans_bad", PI_MALFORMED, PI_ERROR, "Number of spans incorrect", EXPFILL }}, + { &ei_xtp_checksum, + { "xtp.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }}, + }; + + expert_module_t* expert_xtp; + + proto_xtp = proto_register_protocol("Xpress Transport Protocol", "XTP", "xtp"); + proto_register_field_array(proto_xtp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + expert_xtp = expert_register_protocol(proto_xtp); + expert_register_field_array(expert_xtp, ei, array_length(ei)); + + xtp_handle = register_dissector("xtp", dissect_xtp, proto_xtp); +} + +void +proto_reg_handoff_xtp(void) +{ + dissector_add_uint("ip.proto", IP_PROTO_XTP, xtp_handle); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ |