9fc0553e9bb5ca4e5a71cec788b8f3c1400eb6bc
[obnox/wireshark/wip.git] / epan / dissectors / packet-xtp.c
1 /* packet-xtp.c
2  * Routines for Xpress Transport Protocol dissection
3  * Copyright 2008, Shigeo Nakamura <naka_shigeo@yahoo.co.jp>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  *
25  * Ref: http://www.packeteer.com/resources/prod-sol/XTP.pdf
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <glib.h>
33
34 #include <epan/packet.h>
35 #include <epan/ipproto.h>
36 #include <epan/in_cksum.h>
37
38
39 #define XTP_VERSION_4   0x001
40
41 /* XTP type of Service */
42 #define XTP_TOS_UNSPEC          0
43 #define XTP_TOS_UNACKED_DGRAM   1
44 #define XTP_TOS_ACKED_DGRAM     2
45 #define XTP_TOS_TRANS           3
46 #define XTP_TOS_UNICAST_STREAM  4
47 #define XTP_TOS_UNACKED_MULTICAST_STREAM 5
48 #define XTP_TOS_MULTICAST_STREAM 6
49
50 /* Address Format */
51 #define XTP_ADDR_NULL           0
52 #define XTP_ADDR_IP             1
53 #define XTP_ADDR_ISO            2
54 #define XTP_ADDR_XEROX          3
55 #define XTP_ADDR_IPX            4
56 #define XTP_ADDR_LOCAL          5
57 #define XTP_ADDR_IP6            6
58
59 /* packet type */
60 #define XTP_DATA_PKT    0
61 #define XTP_CNTL_PKT    1
62 #define XTP_FIRST_PKT   2
63 #define XTP_ECNTL_PKT   3
64 #define XTP_TCNTL_PKT   5
65 #define XTP_JOIN_PKT    6
66 #define XTP_JCNTL_PKT   7
67 #define XTP_DIAG_PKT    8
68
69 /* cmd options mask */
70 #define XTP_CMD_OPTIONS_NOCHECK         0x400000
71 #define XTP_CMD_OPTIONS_EDGE            0x200000
72 #define XTP_CMD_OPTIONS_NOERR           0x100000
73 #define XTP_CMD_OPTIONS_MULTI           0x080000
74 #define XTP_CMD_OPTIONS_RES             0x040000
75 #define XTP_CMD_OPTIONS_SORT            0x020000
76 #define XTP_CMD_OPTIONS_NOFLOW          0x010000
77 #define XTP_CMD_OPTIONS_FASTNAK         0x008000
78 #define XTP_CMD_OPTIONS_SREQ            0x004000
79 #define XTP_CMD_OPTIONS_DREQ            0x002000
80 #define XTP_CMD_OPTIONS_RCLOSE          0x001000
81 #define XTP_CMD_OPTIONS_WCLOSE          0x000800
82 #define XTP_CMD_OPTIONS_EOM             0x000400
83 #define XTP_CMD_OPTIONS_END             0x000200
84 #define XTP_CMD_OPTIONS_BTAG            0x000100
85
86 #define XTP_KEY_RTN                     ((guint64)1<<63)
87
88 /** packet structures definition **/
89 struct xtp_cntl {
90         guint64         rseq;
91         guint64         alloc;
92         guint32         echo;
93 };
94 #define XTP_CNTL_PKT_LEN        20
95
96 struct xtp_ecntl {
97         guint64         rseq;
98         guint64         alloc;
99         guint32         echo;
100         guint32         nspan;
101 };
102 #define MIN_XTP_ECNTL_PKT_LEN   24
103
104 struct xtp_traffic_cntl {
105         guint64         rseq;
106         guint64         alloc;
107         guint32         echo;
108         guint32         rsvd;
109         guint64         xkey;
110 };
111 #define XTP_TRAFFIC_CNTL_LEN    32
112
113 /* tformat = 0x00 */
114 struct xtp_traffic_spec0 {
115         guint16         tlen;
116         guint8          service;
117         guint8          tformat;
118         guint32         none;
119 };
120 #define XTP_TRAFFIC_SPEC0_LEN   8
121
122 /* tformat = 0x01 */
123 struct xtp_traffic_spec1 {
124         guint16         tlen;
125         guint8          service;
126         guint8          tformat;
127         guint32         maxdata;
128         guint32         inrate;
129         guint32         inburst;
130         guint32         outrate;
131         guint32         outburst;
132 };
133 #define XTP_TRAFFIC_SPEC1_LEN   24
134
135 struct xtp_ip_addr_seg {
136         guint16         alen;
137         guint8          adomain;
138         guint8          aformat;
139         guint32         dsthost;
140         guint32         srchost;
141         guint16         dstport;
142         guint16         srcport;
143 };
144 #define XTP_IP_ADDR_SEG_LEN     16
145 #define XTP_NULL_ADDR_SEG_LEN   8
146
147 struct xtp_diag {
148         guint32         code;
149         guint32         val;
150         gchar           *msg;
151 };
152 #define XTP_DIAG_PKT_HEADER_LEN 8
153
154 struct xtphdr {
155         guint64         key;
156         guint32         cmd;
157         guint32         cmd_options;            /* 24 bits */
158         guint8          cmd_ptype;
159         guint8          cmd_ptype_ver;          /* 3 bits */
160         guint8          cmd_ptype_pformat;      /* 5 bits */
161         guint32         dlen;
162         guint16         check;
163         guint16         sort;
164         guint32         sync;
165         guint64         seq;
166 };
167 #define XTP_HEADER_LEN          32
168
169
170 static const value_string version_vals[] = {
171         { XTP_VERSION_4, "XTP version 4.0" },
172         { 0, NULL }
173 };
174
175 static const value_string service_vals[] = {
176         { XTP_TOS_UNSPEC, "Unspecified" },
177         { XTP_TOS_UNACKED_DGRAM, "Traditional Unacknowledged Datagram Service" },
178         { XTP_TOS_ACKED_DGRAM, "Acknowledged Datagram Service" },
179         { XTP_TOS_TRANS, "Transaction Service" },
180         { XTP_TOS_UNICAST_STREAM, "Traditional Reliable Unicast Stream Service" },
181         { XTP_TOS_UNACKED_MULTICAST_STREAM, "Unacknowledged Multicast Stream Service" },
182         { XTP_TOS_MULTICAST_STREAM, "Reliable Multicast Stream Service" },
183         { 0, NULL }
184 };
185
186 static const value_string aformat_vals[] = {
187         { XTP_ADDR_NULL, "Null Address" },
188         { XTP_ADDR_IP, "Internet Protocol Address" },
189         { XTP_ADDR_ISO, "ISO Connectionless Network Layer Protocol Address" },
190         { XTP_ADDR_XEROX, "Xerox Network System Address" },
191         { XTP_ADDR_IPX, "IPX Address" },
192         { XTP_ADDR_LOCAL, "Local Address" },
193         { XTP_ADDR_IP6, "Internet Protocl Version 6 Address"  },
194         { 0, NULL }
195 };
196
197 static const value_string pformat_vals[] = {
198         { XTP_DATA_PKT, "DATA" },
199         { XTP_CNTL_PKT, "CNTL" },
200         { XTP_FIRST_PKT, "FIRST" },
201         { XTP_ECNTL_PKT, "ECNTL" },
202         { XTP_TCNTL_PKT, "TCNTL" },
203         { XTP_JOIN_PKT, "JOIN<obsolete>" },
204         { XTP_JCNTL_PKT, "JCNTL" },
205         { XTP_DIAG_PKT, "DIAG" },
206         { 0, NULL }
207 };
208
209 static const value_string diag_code_vals[] = {
210         { 1, "Context Refused" },
211         { 2, "Context Abandoned" },
212         { 3, "Invalid Context" },
213         { 4, "Request Refused" },
214         { 5, "Join Refused" },
215         { 6, "Protocol Error" },
216         { 7, "Maximum Packet Size Error" },
217         { 0, NULL }
218 };
219
220 static const value_string diag_val_vals[] = {
221         { 0, "Unspecified" },
222         { 1, "No listener" },
223         { 2, "Options refused" },
224         { 3, "Address format not supported" },
225         { 4, "Malformed address format" },
226         { 5, "Traffic format not supported" },
227         { 6, "Traffic specification refused" },
228         { 7, "Malformed traffic format" },
229         { 8, "No provider for service" },
230         { 9, "No resource" },
231         { 10, "Host going down" },
232         { 11, "Invalid retransmission request" },
233         { 12, "Context in improper state" },
234         { 13, "Join request denied" },
235         { 0, NULL }
236 };
237
238 /* Initialize the protocol and registered fields */
239 static int proto_xtp = -1;
240 /* common header */
241 static int hf_xtp_key = -1;
242 static int hf_xtp_cmd = -1;
243 static int hf_xtp_cmd_options = -1;
244 static int hf_xtp_cmd_options_nocheck = -1;
245 static int hf_xtp_cmd_options_edge = -1;
246 static int hf_xtp_cmd_options_noerr = -1;
247 static int hf_xtp_cmd_options_multi = -1;
248 static int hf_xtp_cmd_options_res = -1;
249 static int hf_xtp_cmd_options_sort = -1;
250 static int hf_xtp_cmd_options_noflow = -1;
251 static int hf_xtp_cmd_options_fastnak = -1;
252 static int hf_xtp_cmd_options_sreq = -1;
253 static int hf_xtp_cmd_options_dreq = -1;
254 static int hf_xtp_cmd_options_rclose = -1;
255 static int hf_xtp_cmd_options_wclose = -1;
256 static int hf_xtp_cmd_options_eom = -1;
257 static int hf_xtp_cmd_options_end = -1;
258 static int hf_xtp_cmd_options_btag = -1;
259 static int hf_xtp_cmd_ptype = -1;
260 static int hf_xtp_cmd_ptype_ver = -1;
261 static int hf_xtp_cmd_ptype_pformat = -1;
262 static int hf_xtp_dlen = -1;
263 static int hf_xtp_sort = -1;
264 static int hf_xtp_sync = -1;
265 static int hf_xtp_seq = -1;
266 /* control segment */
267 static int hf_xtp_cntl_rseq = -1;
268 static int hf_xtp_cntl_alloc = -1;
269 static int hf_xtp_cntl_echo = -1;
270 static int hf_xtp_ecntl_rseq = -1;
271 static int hf_xtp_ecntl_alloc = -1;
272 static int hf_xtp_ecntl_echo = -1;
273 static int hf_xtp_ecntl_nspan = -1;
274 static int hf_xtp_ecntl_span_left = -1;
275 static int hf_xtp_ecntl_span_right = -1;
276 static int hf_xtp_tcntl_rseq = -1;
277 static int hf_xtp_tcntl_alloc = -1;
278 static int hf_xtp_tcntl_echo = -1;
279 static int hf_xtp_tcntl_rsvd = -1;
280 static int hf_xtp_tcntl_xkey = -1;
281 /* traffic specifier */
282 static int hf_xtp_tspec_tlen = -1;
283 static int hf_xtp_tspec_service = -1;
284 static int hf_xtp_tspec_tformat = -1;
285 static int hf_xtp_tspec_traffic = -1;
286 static int hf_xtp_tspec_maxdata = -1;
287 static int hf_xtp_tspec_inrate = -1;
288 static int hf_xtp_tspec_outrate = -1;
289 static int hf_xtp_tspec_inburst = -1;
290 static int hf_xtp_tspec_outburst = -1;
291 /* address segment */
292 static int hf_xtp_aseg_alen = -1;
293 static int hf_xtp_aseg_adomain = -1;
294 static int hf_xtp_aseg_aformat = -1;
295 static int hf_xtp_aseg_address = -1;
296 static int hf_xtp_aseg_dsthost = -1;
297 static int hf_xtp_aseg_srchost = -1;
298 static int hf_xtp_aseg_dstport = -1;
299 static int hf_xtp_aseg_srcport = -1;
300 /* others */
301 static int hf_xtp_btag = -1;
302 static int hf_xtp_diag_code = -1;
303 static int hf_xtp_diag_val = -1;
304 static int hf_xtp_diag_msg = -1;
305
306 /* Initialize the subtree pointers */
307 static gint ett_xtp = -1;
308 static gint ett_xtp_cmd = -1;
309 static gint ett_xtp_cmd_options = -1;
310 static gint ett_xtp_cmd_ptype = -1;
311 static gint ett_xtp_cntl = -1;
312 static gint ett_xtp_ecntl = -1;
313 static gint ett_xtp_tcntl = -1;
314 static gint ett_xtp_tspec = -1;
315 static gint ett_xtp_jcntl = -1;
316 static gint ett_xtp_first = -1;
317 static gint ett_xtp_aseg = -1;
318 static gint ett_xtp_data = -1;
319 static gint ett_xtp_diag = -1;
320
321 /* dissector of each payload */
322 static int
323 dissect_xtp_aseg(tvbuff_t *tvb, proto_tree *tree, guint32 offset) {
324         guint32 len = tvb_length_remaining(tvb, offset);
325         guint32 start = offset;
326         proto_item *ti, *ti2, *top_ti;
327         proto_tree *xtp_subtree;
328         struct xtp_ip_addr_seg aseg[1];
329         int error = 0;
330
331         top_ti = proto_tree_add_text(tree, tvb, offset, len, "Address Segment");
332         xtp_subtree = proto_item_add_subtree(top_ti, ett_xtp_aseg);
333
334         if (len < XTP_NULL_ADDR_SEG_LEN) {
335                 proto_item_append_text(top_ti, ", bogus length(%u, must be at least %u)",
336                         len, XTP_NULL_ADDR_SEG_LEN);
337                 return 0;
338         }
339
340         /** parse common fields **/
341         /* alen(2) */
342         aseg->alen = tvb_get_ntohs(tvb, offset);
343         offset += 2;
344         /* adomain(1) */
345         aseg->adomain = tvb_get_guint8(tvb, offset);
346         offset++;
347         /* aformat(1) */
348         aseg->aformat = tvb_get_guint8(tvb, offset);
349         offset++;
350
351         /** display common fields **/
352         offset = start;
353         /* alen(2) */
354         ti = proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_alen,
355                                 tvb, offset, 2, aseg->alen);
356         offset += 2;
357         if (aseg->alen > len) {
358                 proto_item_append_text(ti, ", bogus length(%u, must be at most %u)",
359                         aseg->alen, len);
360                 error = 1;
361         }
362         /* adomain(1) */
363         proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_adomain,
364                         tvb, offset, 1, aseg->adomain);
365         offset++;
366         /* aformat(1) */
367         ti2 = proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_aformat,
368                         tvb, offset, 1, aseg->aformat);
369         offset++;
370         switch (aseg->aformat) {
371         case 0:
372                 if (aseg->alen != XTP_NULL_ADDR_SEG_LEN) {
373                         proto_item_append_text(ti, ", bogus length(%u, must be %u)",
374                                 aseg->alen, XTP_NULL_ADDR_SEG_LEN);
375                         error = 1;
376                 }
377                 break;
378         case 1:
379                 if (aseg->alen != XTP_IP_ADDR_SEG_LEN) {
380                         proto_item_append_text(ti, ", bogus length(%u, must be %u)",
381                                 aseg->alen, XTP_IP_ADDR_SEG_LEN);
382                         error = 1;
383                 }
384                 break;
385         default:
386                 if (aseg->aformat < 128) {
387                         proto_item_append_text(ti2,
388                                 ", Unsupported aformat(%u)", aseg->aformat);
389                         error = 1;
390                 }
391                 break;
392         }
393
394         if (error)
395                 return (offset - start);
396
397         /** parse and display each address fileds */
398         switch (aseg->aformat) {
399         case 0:
400                 /* address(4) */
401                 aseg->dsthost = tvb_get_ntohl(tvb, offset);
402                 proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_address,
403                                 tvb, offset, 4, aseg->dsthost);
404                 offset += 4;
405                 break;
406         case 1:
407                 /* dsthost(4) */
408                 aseg->dsthost = tvb_get_ipv4(tvb, offset);
409                 proto_tree_add_ipv4(xtp_subtree, hf_xtp_aseg_dsthost,
410                                 tvb, offset, 4, aseg->dsthost);
411                 offset += 4;
412                 /* srchost(4) */
413                 aseg->srchost = tvb_get_ipv4(tvb, offset);
414                 proto_tree_add_ipv4(xtp_subtree, hf_xtp_aseg_srchost,
415                                 tvb, offset, 4, aseg->srchost);
416                 offset += 4;
417                 /* dstport(2) */
418                 aseg->dstport = tvb_get_ntohs(tvb, offset);
419                 proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_dstport,
420                                 tvb, offset, 2, aseg->dstport);
421                 offset += 2;
422                 /* srcport(2) */
423                 aseg->srcport = tvb_get_ntohs(tvb, offset);
424                 proto_tree_add_uint(xtp_subtree, hf_xtp_aseg_srcport,
425                                 tvb, offset, 2, aseg->srcport);
426                 offset += 2;
427
428                 /** add summary **/
429                 proto_item_append_text(top_ti, ", Dst Port: %u", aseg->dstport);
430                 proto_item_append_text(top_ti, ", Src Port: %u", aseg->srcport);
431                 break;
432         default:
433                 break;
434         }
435
436         return (offset - start);
437 }
438
439 static int
440 dissect_xtp_traffic_cntl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
441                 guint32 offset) {
442         guint32 len = tvb_length_remaining(tvb, offset);
443         guint32 start = offset;
444         proto_item *top_ti;
445         proto_tree *xtp_subtree;
446         struct xtp_traffic_cntl tcntl[1];
447
448         top_ti = proto_tree_add_text(tree, tvb, offset, len,
449                                 "Traffic Control Segment");
450         xtp_subtree = proto_item_add_subtree(top_ti, ett_xtp_tcntl);
451
452         if (len < XTP_TRAFFIC_CNTL_LEN) {
453                 proto_item_append_text(top_ti,
454                                 ", bogus length(%u, must be at least %u)",
455                                 len, XTP_TRAFFIC_CNTL_LEN);
456                 return 0;
457         }
458
459         /** parse **/
460         /* rseq(8) */
461         tcntl->rseq = tvb_get_ntohl(tvb, offset);
462         tcntl->rseq <<= 32;
463         tcntl->rseq += tvb_get_ntohl(tvb, offset+4);
464         offset += 8;
465         /* alloc(8) */
466         tcntl->alloc = tvb_get_ntohl(tvb, offset);
467         tcntl->alloc <<= 32;
468         tcntl->alloc += tvb_get_ntohl(tvb, offset+4);
469         offset += 8;
470         /* echo(4) */
471         tcntl->echo = tvb_get_ntohl(tvb, offset);
472         offset += 4;
473         /* rsvd(4) */
474         tcntl->rsvd = tvb_get_ntohl(tvb, offset);
475         offset += 4;
476         /* xkey(8) */
477         tcntl->xkey = tvb_get_ntohl(tvb, offset);
478         tcntl->xkey <<= 32;
479         tcntl->xkey += tvb_get_ntohl(tvb, offset+4);
480
481         /** add summary **/
482         if (check_col(pinfo->cinfo, COL_INFO)) {
483                 col_append_fstr(pinfo->cinfo, COL_INFO,
484                         " Recv-Seq=%" G_GINT64_MODIFIER "u", tcntl->rseq);
485                 col_append_fstr(pinfo->cinfo, COL_INFO,
486                         " Alloc=%" G_GINT64_MODIFIER "u", tcntl->alloc);
487         }
488         proto_item_append_text(top_ti,
489                         ", Recv-Seq: %" G_GINT64_MODIFIER "u", tcntl->rseq);
490
491         /** display **/
492         offset = start;
493         /* rseq(8) */
494         proto_tree_add_uint64(xtp_subtree, hf_xtp_tcntl_rseq,
495                         tvb, offset, 8, tcntl->rseq);
496         offset += 8;
497         /* alloc(8) */
498         proto_tree_add_uint64(xtp_subtree, hf_xtp_tcntl_alloc,
499                         tvb, offset, 8, tcntl->alloc);
500         offset += 4;
501         /* echo(4) */
502         proto_tree_add_uint(xtp_subtree, hf_xtp_tcntl_echo,
503                         tvb, offset, 4, tcntl->echo);
504         offset += 4;
505         /* rsvd(4) */
506         proto_tree_add_uint(xtp_subtree, hf_xtp_tcntl_rsvd,
507                         tvb, offset, 4, tcntl->rsvd);
508         offset += 4;
509         /* xkey(8) */
510         proto_tree_add_uint64(xtp_subtree, hf_xtp_tcntl_xkey,
511                         tvb, offset, 8, tcntl->xkey);
512         offset += 8;
513
514         return (offset - start);
515 }
516
517 static int
518 dissect_xtp_tspec(tvbuff_t *tvb, proto_tree *tree, guint32 offset) {
519         guint32 len = tvb_length_remaining(tvb, offset);
520         guint32 start = offset;
521         proto_item *ti, *ti2;
522         proto_tree *xtp_subtree;
523         struct xtp_traffic_spec1 tspec[1];
524         int error = 0;
525
526         ti = proto_tree_add_text(tree, tvb, offset, len, "Traffic Specifier");
527         xtp_subtree = proto_item_add_subtree(ti, ett_xtp_tspec);
528
529         if (len < XTP_TRAFFIC_SPEC0_LEN) {
530                 proto_item_append_text(ti,
531                         ", bogus length(%u, must be at least %u)",
532                         len, XTP_TRAFFIC_SPEC0_LEN);
533                 return 0;
534         }
535
536         /** parse common fields **/
537         /* tlen(2) */
538         tspec->tlen = tvb_get_ntohs(tvb, offset);
539         offset += 2;
540         /* service(1) */
541         tspec->service = tvb_get_guint8(tvb, offset);
542         offset++;
543         /* tformat(1) */
544         tspec->tformat = tvb_get_guint8(tvb, offset);
545         offset++;
546
547         /** display common fields */
548         offset = start;
549         /* tlen(2) */
550         ti = proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_tlen,
551                         tvb, offset, 2, tspec->tlen);
552         offset += 2;
553         if (tspec->tlen > len) {
554                 proto_item_append_text(ti, ", bogus length(%u, must be at most %u)",
555                         tspec->tlen, len);
556                 error = 1;
557         }
558         /* service(1) */
559         proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_service,
560                         tvb, offset, 1, tspec->service);
561         offset++;
562         /* tformat(1) */
563         ti2 = proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_tformat,
564                         tvb, offset, 1, tspec->tformat);
565         offset++;
566         switch (tspec->tformat) {
567         case 0:
568                 if (tspec->tlen != XTP_TRAFFIC_SPEC0_LEN) {
569                         proto_item_append_text(ti, ", bogus length(%u, must be %u)",
570                                 tspec->tlen, XTP_TRAFFIC_SPEC0_LEN);
571                         error = 1;
572                 }
573                 break;
574         case 1:
575                 if (tspec->tlen != XTP_TRAFFIC_SPEC1_LEN) {
576                         proto_item_append_text(ti, ", bogus length(%u, must be %u)",
577                                 tspec->tlen, XTP_TRAFFIC_SPEC1_LEN);
578                         error = 1;
579                 }
580                 break;
581         default:
582                 proto_item_append_text(ti2, ", Unsupported tformat(%u)",
583                                 tspec->tformat);
584                 error = 1;
585                 break;
586         }
587
588         if (error)
589                 return (offset - start);
590
591         /** parse and display each traffic fields **/
592         switch (tspec->tformat) {
593         case 0:
594                 /* traffic(4) */
595                 tspec->maxdata = tvb_get_ntohl(tvb, offset);
596                 proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_traffic,
597                                 tvb, offset, 4, tspec->maxdata);
598                 offset += 4;
599                 break;
600         case 1:
601                 /* maxdata(4) */
602                 tspec->maxdata = tvb_get_ntohl(tvb, offset);
603                 proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_maxdata,
604                                 tvb, offset, 4, tspec->maxdata);
605                 offset += 4;
606                 /* inrate(4) */
607                 tspec->inrate = tvb_get_ntohl(tvb, offset);
608                 proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_inrate,
609                                 tvb, offset, 4, tspec->inrate);
610                 offset += 4;
611                 /* inburst(4) */
612                 tspec->inburst = tvb_get_ntohl(tvb, offset);
613                 proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_inburst,
614                                 tvb, offset, 4, tspec->inburst);
615                 offset += 4;
616                 /* outrate(4) */
617                 tspec->outrate = tvb_get_ntohl(tvb, offset);
618                 proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_outrate,
619                                 tvb, offset, 4, tspec->outrate);
620                 offset += 4;
621                 /* outburst(4) */
622                 tspec->outburst = tvb_get_ntohl(tvb, offset);
623                 proto_tree_add_uint(xtp_subtree, hf_xtp_tspec_outburst,
624                                 tvb, offset, 4, tspec->outburst);
625                 offset += 4;
626                 break;
627         default:
628                 break;
629         }
630
631         return (offset - start);
632 }
633
634 static void
635 dissect_xtp_data(tvbuff_t *tvb, proto_tree *tree, guint32 offset, gboolean have_btag) {
636         guint32 len = tvb_length_remaining(tvb, offset);
637         proto_item *ti;
638         proto_tree *xtp_subtree;
639         guint64 btag;
640
641         ti = proto_tree_add_text(tree, tvb, offset, len, "Data Segment");
642         xtp_subtree = proto_item_add_subtree(ti, ett_xtp_data);
643
644         if (have_btag) {
645                 btag = tvb_get_ntohl(tvb, offset);
646                 btag <<= 32;
647                 btag += tvb_get_ntohl(tvb, offset+4);
648                 proto_tree_add_uint64(xtp_subtree, hf_xtp_btag, tvb, offset, 8, btag);
649                 offset += 8;
650                 len -= 8;
651         }
652
653         proto_tree_add_text(xtp_subtree, tvb, offset, len,
654                 "Data (%u byte%s)", len,
655                 plurality(len, "", "s"));
656
657         return;
658 }
659
660 static void
661 dissect_xtp_cntl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
662                 guint32 offset) {
663         guint32 len = tvb_length_remaining(tvb, offset);
664         guint32 start = offset;
665         proto_item *top_ti;
666         proto_tree *xtp_subtree;
667         struct xtp_cntl cntl[1];
668
669         top_ti = proto_tree_add_text(tree, tvb, offset, len,
670                                 "Common Control Segment");
671         xtp_subtree = proto_item_add_subtree(top_ti, ett_xtp_cntl);
672
673         if (len != XTP_CNTL_PKT_LEN) {
674                 proto_item_append_text(top_ti, ", bogus length(%u, must be %u)",
675                         len, XTP_CNTL_PKT_LEN);
676                 return;
677         }
678
679         /** parse **/
680         /* rseq(8) */
681         cntl->rseq = tvb_get_ntohl(tvb, offset);
682         cntl->rseq <<= 32;
683         cntl->rseq += tvb_get_ntohl(tvb, offset+4);
684         offset += 8;
685         /* alloc(8) */
686         cntl->alloc = tvb_get_ntohl(tvb, offset);
687         cntl->alloc <<= 32;
688         cntl->alloc += tvb_get_ntohl(tvb, offset+4);
689         offset += 8;
690         /* echo(4) */
691         cntl->echo = tvb_get_ntohl(tvb, offset);
692
693         /** add summary **/
694         if (check_col(pinfo->cinfo, COL_INFO)) {
695                 col_append_fstr(pinfo->cinfo, COL_INFO,
696                         " Recv-Seq=%" G_GINT64_MODIFIER "u", cntl->rseq);
697                 col_append_fstr(pinfo->cinfo, COL_INFO,
698                         " Alloc=%" G_GINT64_MODIFIER "u", cntl->alloc);
699         }
700         proto_item_append_text(top_ti,
701                         ", Recv-Seq: %" G_GINT64_MODIFIER "u", cntl->rseq);
702
703         /** display **/
704         offset = start;
705         /* rseq(8) */
706         proto_tree_add_uint64(xtp_subtree, hf_xtp_cntl_rseq,
707                         tvb, offset, 8, cntl->rseq);
708         offset += 8;
709         /* alloc(8) */
710         proto_tree_add_uint64(xtp_subtree, hf_xtp_cntl_alloc,
711                         tvb, offset, 8, cntl->alloc);
712         offset += 4;
713         /* echo(4) */
714         proto_tree_add_uint(xtp_subtree, hf_xtp_cntl_echo,
715                         tvb, offset, 4, cntl->echo);
716
717         return;
718 }
719
720 static void
721 dissect_xtp_first(tvbuff_t *tvb, proto_tree *tree, guint32 offset) {
722
723         if (!dissect_xtp_aseg(tvb, tree, offset))
724                 return;
725
726         offset += XTP_IP_ADDR_SEG_LEN;
727         dissect_xtp_tspec(tvb, tree, offset);
728
729         return;
730 }
731
732 static void
733 dissect_xtp_ecntl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
734                 guint32 offset) {
735         guint32 len = tvb_length_remaining(tvb, offset);
736         guint32 start = offset;
737         proto_item *top_ti;
738         proto_tree *xtp_subtree;
739         struct xtp_ecntl ecntl[1];
740         guint64 *spans, *p;
741         guint32 spans_len;
742         guint i;
743
744         top_ti = proto_tree_add_text(tree, tvb, offset, len,
745                                 "Error Control Segment");
746         xtp_subtree = proto_item_add_subtree(top_ti, ett_xtp_ecntl);
747
748         if (len < MIN_XTP_ECNTL_PKT_LEN) {
749                 proto_item_append_text(top_ti,
750                                 ", bogus length (%u, must be at least %u)",
751                                 len, MIN_XTP_ECNTL_PKT_LEN);
752                 return;
753         }
754
755         /** parse **/
756         /* rseq(8) */
757         ecntl->rseq = tvb_get_ntohl(tvb, offset);
758         ecntl->rseq <<= 32;
759         ecntl->rseq += tvb_get_ntohl(tvb, offset+4);
760         offset += 8;
761         /* alloc(8) */
762         ecntl->alloc = tvb_get_ntohl(tvb, offset);
763         ecntl->alloc <<= 32;
764         ecntl->alloc += tvb_get_ntohl(tvb, offset+4);
765         offset += 8;
766         /* echo(4) */
767         ecntl->echo = tvb_get_ntohl(tvb, offset);
768         offset += 4;
769         /* nspan(4) */
770         ecntl->nspan = tvb_get_ntohl(tvb, offset);
771         offset += 4;
772         len = len + XTP_HEADER_LEN - offset;
773         spans_len = 16 * ecntl->nspan;
774         if (len != spans_len) {
775                 proto_item_append_text(top_ti,
776                                 ", bogus spans field length (%u, must be %u)",
777                                 len, spans_len);
778                 return;
779         }
780         /* spans(16n) */
781         spans = ep_alloc0(spans_len);
782         p = spans;
783         for (i = 0; i < ecntl->nspan*2; i++) {
784                 guint64 span = tvb_get_ntohl(tvb, offset);
785                 span <<= 32;
786                 span += tvb_get_ntohl(tvb, offset+4);
787                 *p++ = span;
788                 offset += 8;
789         }
790
791         /** add summary **/
792         if (check_col(pinfo->cinfo, COL_INFO)) {
793                 col_append_fstr(pinfo->cinfo, COL_INFO,
794                                 " Recv-Seq=%" G_GINT64_MODIFIER "u", ecntl->rseq);
795                 col_append_fstr(pinfo->cinfo, COL_INFO,
796                                 " Alloc=%" G_GINT64_MODIFIER "u", ecntl->alloc);
797         }
798         proto_item_append_text(top_ti,
799                                 ", Recv-Seq: %" G_GINT64_MODIFIER "u", ecntl->rseq);
800
801         /** display **/
802         offset = start;
803         /* rseq(8) */
804         proto_tree_add_uint64(xtp_subtree, hf_xtp_ecntl_rseq,
805                                 tvb, offset, 8, ecntl->rseq);
806         offset += 8;
807         /* alloc(8) */
808         proto_tree_add_uint64(xtp_subtree, hf_xtp_ecntl_alloc,
809                                 tvb, offset, 8, ecntl->alloc);
810         offset += 8;
811         /* echo(4) */
812         proto_tree_add_uint(xtp_subtree, hf_xtp_ecntl_echo,
813                                 tvb, offset, 4, ecntl->echo);
814         offset += 4;
815         /* nspan(4) */
816         proto_tree_add_uint(xtp_subtree, hf_xtp_ecntl_nspan,
817                                 tvb, offset, 4, ecntl->nspan);
818         offset += 4;
819         /* spans(16n) */
820         p = spans;
821         for (i = 0; i < ecntl->nspan; i++) {
822                 proto_tree_add_uint64(xtp_subtree, hf_xtp_ecntl_span_left,
823                                 tvb, offset, 8, *p);
824                 p++;
825                 offset += 8;
826                 proto_tree_add_uint64(xtp_subtree, hf_xtp_ecntl_span_right,
827                                 tvb, offset, 8, *p);
828                 p++;
829                 offset += 8;
830         }
831
832         return;
833 }
834
835 static void
836 dissect_xtp_tcntl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
837                 guint32 offset) {
838
839         if (!dissect_xtp_traffic_cntl(tvb, pinfo, tree, offset))
840                 return;
841
842         offset += XTP_TRAFFIC_CNTL_LEN;
843         dissect_xtp_tspec(tvb, tree, offset);
844
845         return;
846 }
847
848 static void
849 dissect_xtp_jcntl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
850                 guint32 offset) {
851
852         if (!dissect_xtp_traffic_cntl(tvb, pinfo, tree, offset))
853                 return;
854
855         offset += XTP_TRAFFIC_CNTL_LEN;
856         if (!dissect_xtp_aseg(tvb, tree, offset))
857                 return;
858
859         offset += XTP_IP_ADDR_SEG_LEN;
860         dissect_xtp_tspec(tvb, tree, offset);
861
862         return;
863 }
864
865 static void
866 dissect_xtp_diag(tvbuff_t *tvb, proto_tree *tree, guint32 offset) {
867         guint32 len = tvb_length_remaining(tvb, offset);
868         guint32 start = offset;
869         proto_item *ti;
870         proto_tree *xtp_subtree;
871         struct xtp_diag diag[1];
872         guint32 msg_len;
873
874         ti = proto_tree_add_text(tree, tvb, offset, len, "Diagnostic Segment");
875         xtp_subtree = proto_item_add_subtree(ti, ett_xtp_diag);
876
877         if (len < XTP_DIAG_PKT_HEADER_LEN) {
878                 proto_item_append_text(ti,
879                                 ", bogus length (%u, must be at least %u)",
880                                 len, XTP_DIAG_PKT_HEADER_LEN);
881                 return;
882         }
883
884         /** parse **/
885         /* code(4) */
886         diag->code = tvb_get_ntohl(tvb, offset);
887         offset += 4;
888         /* val(4) */
889         diag->val = tvb_get_ntohl(tvb, offset);
890         offset += 4;
891         /* message(n) */
892         msg_len = tvb_length_remaining(tvb, offset);
893         diag->msg = tvb_get_string(tvb, offset, msg_len);
894
895         /** display **/
896         offset = start;
897         /* code(4) */
898         proto_tree_add_uint(xtp_subtree, hf_xtp_diag_code,
899                         tvb, offset, 4, diag->code);
900         offset += 4;
901         /* val(4) */
902         proto_tree_add_uint(xtp_subtree, hf_xtp_diag_val,
903                         tvb, offset, 4, diag->val);
904         offset += 4;
905         /* message(4) */
906         proto_tree_add_string(xtp_subtree, hf_xtp_diag_msg,
907                         tvb, offset, msg_len, diag->msg);
908
909         return;
910 }
911
912 /* main dissector */
913 static int
914 dissect_xtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
915         guint32 offset, len;
916         proto_item *ti;
917         proto_tree *xtp_tree, *xtp_cmd_tree, *xtp_subtree;
918         struct xtphdr xtph[1];
919         int     error = 0;
920         gchar   *options = "<None>";
921         const char *fstr[] = { "<None>", "NOCHECK", "EDGE", "NOERR", "MULTI", "RES",
922                                 "SORT", "NOFLOW", "FASTNAK", "SREQ", "DREQ",
923                                 "RCLOSE", "WCLOSE", "EOM", "END", "BTAG" };
924         gint    fpos = 0, returned_length;
925         guint   i, bpos;
926         guint   cmd_options;
927         vec_t   cksum_vec[1];
928         guint16 computed_cksum;
929         gboolean have_btag;
930
931         if ((len = tvb_length(tvb)) < XTP_HEADER_LEN)
932                 return 0;
933
934         col_set_str(pinfo->cinfo, COL_PROTOCOL, "XTP");
935         col_clear(pinfo->cinfo, COL_INFO);
936
937         /** parse header **/
938         offset = 0;
939         /* key(8) */
940         xtph->key               = tvb_get_ntohl(tvb, offset);
941         xtph->key <<= 32;
942         xtph->key += tvb_get_ntohl(tvb, offset+4);
943         offset += 8;
944         /* cmd(4) */
945         xtph->cmd               = tvb_get_ntohl(tvb, offset);
946         xtph->cmd_options       = xtph->cmd >> 8;
947         xtph->cmd_ptype         = xtph->cmd & 0xff;
948         xtph->cmd_ptype_ver     = (xtph->cmd_ptype & 0xe0) >> 5;
949         xtph->cmd_ptype_pformat = xtph->cmd_ptype & 0x1f;
950         offset += 4;
951         /* dlen(4) */
952         xtph->dlen              = tvb_get_ntohl(tvb, offset);
953         offset += 4;
954         /* check(2) */
955         xtph->check             = tvb_get_ntohs(tvb, offset);
956         offset += 2;
957         /* sort(2) */
958         xtph->sort              = tvb_get_ntohs(tvb, offset);
959         offset += 2;
960         /* sync(4) */
961         xtph->sync              = tvb_get_ntohl(tvb, offset);
962         offset += 4;
963         /* seq(8) */
964         xtph->seq               = tvb_get_ntohl(tvb, offset);
965         xtph->seq <<= 32;
966         xtph->seq += tvb_get_ntohl(tvb, offset+4);
967
968 #define MAX_OPTIONS_LEN 128
969         options=ep_alloc(MAX_OPTIONS_LEN);
970         options[0]=0;
971         cmd_options = xtph->cmd_options >> 8;
972         for (i = 0; i < 16; i++) {
973                 bpos = 1 << (15 - i);
974                 if (cmd_options & bpos) {
975                         returned_length = g_snprintf(&options[fpos],
976                         MAX_OPTIONS_LEN-fpos, "%s%s",
977                         fpos?", ":"",
978                         fstr[i]);
979                         fpos += MIN(returned_length, MAX_OPTIONS_LEN-fpos);
980                 }
981         }
982
983         if (check_col(pinfo->cinfo, COL_INFO)) {
984                 col_add_str(pinfo->cinfo, COL_INFO,
985                             val_to_str(xtph->cmd_ptype_pformat,
986                                         pformat_vals, "Unknown pformat (%u)"));
987                 col_append_fstr(pinfo->cinfo, COL_INFO, " [%s]", options);
988                 col_append_fstr(pinfo->cinfo, COL_INFO,
989                                 " Seq=%" G_GINT64_MODIFIER "u", xtph->seq);
990                 col_append_fstr(pinfo->cinfo, COL_INFO, " Len=%u", xtph->dlen);
991         }
992
993         if (tree) {
994                 ti = proto_tree_add_item(tree, proto_xtp, tvb, 0, -1, ENC_NA);
995                 /** add summary **/
996                 proto_item_append_text(ti,
997                                 ", Key: 0x%016" G_GINT64_MODIFIER "X", xtph->key);
998                 proto_item_append_text(ti,
999                                 ", Seq: %" G_GINT64_MODIFIER "u", xtph->seq);
1000                 proto_item_append_text(ti, ", Len: %u", xtph->dlen);
1001
1002                 xtp_tree = proto_item_add_subtree(ti, ett_xtp);
1003                 /* key(8) */
1004                 offset = 0;
1005                 proto_tree_add_uint64(xtp_tree, hf_xtp_key,
1006                                         tvb, offset, 8, xtph->key);
1007                 offset += 8;
1008                 /* cmd(4) */
1009                 ti = proto_tree_add_uint(xtp_tree, hf_xtp_cmd,
1010                                         tvb, offset, 4, xtph->cmd);
1011                 xtp_cmd_tree = proto_item_add_subtree(ti, ett_xtp_cmd);
1012                 ti = proto_tree_add_uint(xtp_cmd_tree, hf_xtp_cmd_options,
1013                                         tvb, offset, 3, xtph->cmd_options);
1014                 /** add summary **/
1015                 proto_item_append_text(ti, " [%s]", options);
1016
1017                 xtp_subtree = proto_item_add_subtree(ti, ett_xtp_cmd_options);
1018                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_nocheck,
1019                                         tvb, offset, 3, xtph->cmd_options);
1020                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_edge,
1021                                         tvb, offset, 3, xtph->cmd_options);
1022                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_noerr,
1023                                         tvb, offset, 3, xtph->cmd_options);
1024                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_multi,
1025                                         tvb, offset, 3, xtph->cmd_options);
1026                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_res,
1027                                         tvb, offset, 3, xtph->cmd_options);
1028                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_sort,
1029                                         tvb, offset, 3, xtph->cmd_options);
1030                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_noflow,
1031                                         tvb, offset, 3, xtph->cmd_options);
1032                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_fastnak,
1033                                         tvb, offset, 3, xtph->cmd_options);
1034                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_sreq,
1035                                         tvb, offset, 3, xtph->cmd_options);
1036                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_dreq,
1037                                         tvb, offset, 3, xtph->cmd_options);
1038                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_rclose,
1039                                         tvb, offset, 3, xtph->cmd_options);
1040                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_wclose,
1041                                         tvb, offset, 3, xtph->cmd_options);
1042                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_eom,
1043                                         tvb, offset, 3, xtph->cmd_options);
1044                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_end,
1045                                         tvb, offset, 3, xtph->cmd_options);
1046                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_btag,
1047                                         tvb, offset, 3, xtph->cmd_options);
1048                 offset += 3;
1049                 ti = proto_tree_add_uint(xtp_cmd_tree, hf_xtp_cmd_ptype,
1050                                         tvb, offset, 1, xtph->cmd_ptype);
1051                 xtp_subtree = proto_item_add_subtree(ti, ett_xtp_cmd_ptype);
1052                 proto_tree_add_uint(xtp_subtree, hf_xtp_cmd_ptype_ver,
1053                                         tvb, offset, 1, xtph->cmd_ptype_ver);
1054                 if (xtph->cmd_ptype_ver != XTP_VERSION_4) {
1055                         proto_item_append_text(ti,
1056                                 ", Unknown XTP version (%03X)", xtph->cmd_ptype_ver);
1057                         error = 1;
1058                 }
1059                 proto_tree_add_uint(xtp_subtree, hf_xtp_cmd_ptype_pformat,
1060                                 tvb, offset, 1, xtph->cmd_ptype_pformat);
1061                 offset++;
1062                 /* dlen(4) */
1063                 ti = proto_tree_add_uint(xtp_tree, hf_xtp_dlen,
1064                                 tvb, offset, 4, xtph->dlen);
1065                 if (xtph->dlen != len - XTP_HEADER_LEN) {
1066                         proto_item_append_text(ti, ", bogus length (%u, must be %u)",
1067                                 xtph->dlen, len - XTP_HEADER_LEN);
1068                         error = 1;
1069                 }
1070                 offset += 4;
1071                 /* check(2) */
1072                 if (!pinfo->fragmented) {
1073                         guint32 check_len = XTP_HEADER_LEN;
1074                         if (!(xtph->cmd_options & XTP_CMD_OPTIONS_NOCHECK))
1075                                 check_len += xtph->dlen;
1076                         cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, check_len);
1077                         cksum_vec[0].len = check_len;
1078                         computed_cksum = in_cksum(cksum_vec, 1);
1079                         if (computed_cksum == 0) {
1080                                 proto_tree_add_text(xtp_tree, tvb, offset, 2,
1081                                         "Checksum: 0x%04x [correct]", xtph->check);
1082                         } else {
1083                                 proto_tree_add_text(xtp_tree, tvb, offset, 2,
1084                                         "Checksum: 0x%04x [incorrect, should be 0x%04x]",
1085                                         xtph->check,
1086                                         in_cksum_shouldbe(xtph->check, computed_cksum));
1087                         }
1088                 }
1089                 else {
1090                         proto_tree_add_text(xtp_tree, tvb, offset, 2,
1091                                         "Checksum: 0x%04x", xtph->check);
1092                 }
1093                 offset += 2;
1094                 /* sort(2) */
1095                 proto_tree_add_uint(xtp_tree, hf_xtp_sort, tvb, offset, 2, xtph->sort);
1096                 offset += 2;
1097                 /* sync(4) */
1098                 proto_tree_add_uint(xtp_tree, hf_xtp_sync, tvb, offset, 4, xtph->sync);
1099                 offset += 4;
1100                 /* seq(8) */
1101                 proto_tree_add_uint64(xtp_tree, hf_xtp_seq, tvb, offset, 8, xtph->seq);
1102                 offset += 8;
1103
1104                 if (!error) {
1105                         switch (xtph->cmd_ptype_pformat) {
1106                         case XTP_DATA_PKT:
1107                                 have_btag = !!(xtph->cmd_options & XTP_CMD_OPTIONS_BTAG);
1108                                 dissect_xtp_data(tvb, xtp_tree, offset, have_btag);
1109                                 break;
1110                         case XTP_CNTL_PKT:
1111                                 dissect_xtp_cntl(tvb, pinfo, xtp_tree, offset);
1112                                 break;
1113                         case XTP_FIRST_PKT:
1114                                 dissect_xtp_first(tvb, xtp_tree, offset);
1115                                 break;
1116                         case XTP_ECNTL_PKT:
1117                                 dissect_xtp_ecntl(tvb, pinfo, xtp_tree, offset);
1118                                 break;
1119                         case XTP_TCNTL_PKT:
1120                                 dissect_xtp_tcntl(tvb, pinfo, xtp_tree, offset);
1121                                 break;
1122                         case XTP_JOIN_PKT:
1123                                 /* obsolete */
1124                                 break;
1125                         case XTP_JCNTL_PKT:
1126                                 dissect_xtp_jcntl(tvb, pinfo, xtp_tree, offset);
1127                                 break;
1128                         case XTP_DIAG_PKT:
1129                                 dissect_xtp_diag(tvb, xtp_tree, offset);
1130                                 break;
1131                         default:
1132                                 /* error */
1133                                 break;
1134                         }
1135                 }
1136         }
1137
1138         return tvb_length(tvb);
1139 }
1140
1141 void
1142 proto_register_xtp(void)
1143 {
1144         static hf_register_info hf[] = {
1145                 /* command header */
1146                 { &hf_xtp_key,
1147                         { "Key",           "xtp.key",
1148                         FT_UINT64, BASE_HEX, NULL, 0x0,
1149                         NULL, HFILL }
1150                 },
1151                 { &hf_xtp_cmd,
1152                         { "Command", "xtp.cmd",
1153                         FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }
1154                 },
1155                 { &hf_xtp_cmd_options,
1156                         { "Options", "xtp.cmd.options",
1157                         FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL }
1158                 },
1159                 { &hf_xtp_cmd_options_nocheck,
1160                         { "NOCHECK", "xtp.cmd.options.nocheck",
1161                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1162                         XTP_CMD_OPTIONS_NOCHECK, NULL, HFILL }
1163                 },
1164                 { &hf_xtp_cmd_options_edge,
1165                         { "EDGE", "xtp.cmd.options.edge",
1166                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1167                         XTP_CMD_OPTIONS_EDGE, NULL, HFILL }
1168                 },
1169                 { &hf_xtp_cmd_options_noerr,
1170                         { "NOERR", "xtp.cmd.options.noerr",
1171                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1172                         XTP_CMD_OPTIONS_NOERR, NULL, HFILL }
1173                 },
1174                 { &hf_xtp_cmd_options_multi,
1175                         { "MULTI", "xtp.cmd.options.multi",
1176                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1177                         XTP_CMD_OPTIONS_MULTI, NULL, HFILL }
1178                 },
1179                 { &hf_xtp_cmd_options_res,
1180                         { "RES", "xtp.cmd.options.res",
1181                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1182                         XTP_CMD_OPTIONS_RES, NULL, HFILL }
1183                 },
1184                 { &hf_xtp_cmd_options_sort,
1185                         { "SORT", "xtp.cmd.options.sort",
1186                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1187                         XTP_CMD_OPTIONS_SORT, NULL, HFILL }
1188                 },
1189                 { &hf_xtp_cmd_options_noflow,
1190                         { "NOFLOW", "xtp.cmd.options.noflow",
1191                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1192                         XTP_CMD_OPTIONS_NOFLOW, NULL, HFILL }
1193                 },
1194                 { &hf_xtp_cmd_options_fastnak,
1195                         { "FASTNAK", "xtp.cmd.options.fastnak",
1196                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1197                         XTP_CMD_OPTIONS_FASTNAK, NULL, HFILL }
1198                 },
1199                 { &hf_xtp_cmd_options_sreq,
1200                         { "SREQ", "xtp.cmd.options.sreq",
1201                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1202                         XTP_CMD_OPTIONS_SREQ, NULL, HFILL }
1203                 },
1204                 { &hf_xtp_cmd_options_dreq,
1205                         { "DREQ", "xtp.cmd.options.dreq",
1206                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1207                         XTP_CMD_OPTIONS_DREQ, NULL, HFILL }
1208                 },
1209                 { &hf_xtp_cmd_options_rclose,
1210                         { "RCLOSE", "xtp.cmd.options.rclose",
1211                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1212                         XTP_CMD_OPTIONS_RCLOSE, NULL, HFILL }
1213                 },
1214                 { &hf_xtp_cmd_options_wclose,
1215                         { "WCLOSE", "xtp.cmd.options.wclose",
1216                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1217                         XTP_CMD_OPTIONS_WCLOSE, NULL, HFILL }
1218                 },
1219                 { &hf_xtp_cmd_options_eom,
1220                         { "EOM", "xtp.cmd.options.eom",
1221                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1222                         XTP_CMD_OPTIONS_EOM, NULL, HFILL }
1223                 },
1224                 { &hf_xtp_cmd_options_end,
1225                         { "END", "xtp.cmd.options.end",
1226                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1227                         XTP_CMD_OPTIONS_END, NULL, HFILL }
1228                 },
1229                 { &hf_xtp_cmd_options_btag,
1230                         { "BTAG", "xtp.cmd.options.btag",
1231                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1232                         XTP_CMD_OPTIONS_BTAG, NULL, HFILL }
1233                 },
1234                 { &hf_xtp_cmd_ptype,
1235                         { "Packet type", "xtp.cmd.ptype",
1236                         FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
1237                 },
1238                 { &hf_xtp_cmd_ptype_ver,
1239                         { "Version", "xtp.cmd.ptype.ver",
1240                         FT_UINT8, BASE_DEC, VALS(version_vals), 0x0, NULL, HFILL }
1241                 },
1242                 { &hf_xtp_cmd_ptype_pformat,
1243                         { "Format", "xtp.cmd.ptype.pformat",
1244                         FT_UINT8, BASE_DEC, VALS(pformat_vals), 0x0, NULL, HFILL }
1245                 },
1246                 { &hf_xtp_dlen,
1247                         { "Data length", "xtp.dlen",
1248                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1249                 },
1250                 { &hf_xtp_sort,
1251                         { "Sort", "xtp.sort",
1252                         FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1253                 },
1254                 { &hf_xtp_sync,
1255                         { "Synchronizing handshake", "xtp.sync",
1256                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1257                 },
1258                 { &hf_xtp_seq,
1259                         { "Sequence number", "xtp.seq",
1260                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1261                 },
1262                 /* control segment */
1263                 { &hf_xtp_cntl_rseq,
1264                         { "Received sequence number", "xtp.cntl.rseq",
1265                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1266                 },
1267                 { &hf_xtp_cntl_alloc,
1268                         { "Allocation", "xtp.cntl.alloc",
1269                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1270                 },
1271                 { &hf_xtp_cntl_echo,
1272                         { "Synchronizing handshake echo", "xtp.cntl.echo",
1273                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1274                 },
1275                 { &hf_xtp_ecntl_rseq,
1276                         { "Received sequence number", "xtp.ecntl.rseq",
1277                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1278                 },
1279                 { &hf_xtp_ecntl_alloc,
1280                         { "Allocation", "xtp.ecntl.alloc",
1281                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1282                 },
1283                 { &hf_xtp_ecntl_echo,
1284                         { "Synchronizing handshake echo", "xtp.ecntl.echo",
1285                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1286                 },
1287                 { &hf_xtp_ecntl_nspan,
1288                         { "Number of spans", "xtp.ecntl.nspan",
1289                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1290                 },
1291                 { &hf_xtp_ecntl_span_left,
1292                         { "Span left edge", "xtp.ecntl.span_le",
1293                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1294                 },
1295                 { &hf_xtp_ecntl_span_right,
1296                         { "Span right edge", "xtp.ecntl.span_re",
1297                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1298                 },
1299                 { &hf_xtp_tcntl_rseq,
1300                         { "Received sequence number", "xtp.tcntl.rseq",
1301                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1302                 },
1303                 { &hf_xtp_tcntl_alloc,
1304                         { "Allocation", "xtp.tcntl.alloc",
1305                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1306                 },
1307                 { &hf_xtp_tcntl_echo,
1308                         { "Synchronizing handshake echo", "xtp.tcntl.echo",
1309                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1310                 },
1311                 { &hf_xtp_tcntl_rsvd,
1312                         { "Reserved", "xtp.tcntl.rsvd",
1313                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1314                 },
1315                 { &hf_xtp_tcntl_xkey,
1316                         { "Exchange key", "xtp.tcntl.xkey",
1317                         FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }
1318                 },
1319                 /* traffic specifier */
1320                 { &hf_xtp_tspec_tlen,
1321                         { "Length", "xtp.tspec.tlen",
1322                         FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1323                 },
1324                 { &hf_xtp_tspec_service,
1325                         { "Service", "xtp.tspec.service",
1326                         FT_UINT8, BASE_DEC, VALS(service_vals), 0x0, NULL, HFILL }
1327                 },
1328                 { &hf_xtp_tspec_tformat,
1329                         { "Format", "xtp.tspec.format",
1330                         FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }
1331                 },
1332                 { &hf_xtp_tspec_traffic,
1333                         { "Traffic", "xtp.tspec.traffic",
1334                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1335                 },
1336                 { &hf_xtp_tspec_maxdata,
1337                         { "Maxdata", "xtp.tspec.maxdata",
1338                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1339                 },
1340                 { &hf_xtp_tspec_inrate,
1341                         { "Incoming rate", "xtp.tspec.inrate",
1342                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1343                 },
1344                 { &hf_xtp_tspec_inburst,
1345                         { "Incoming burst size", "xtp.tspec.inburst",
1346                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1347                 },
1348                 { &hf_xtp_tspec_outrate,
1349                         { "Outgoing rate", "xtp.tspec.outrate",
1350                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1351                 },
1352                 { &hf_xtp_tspec_outburst,
1353                         { "Outgoing burst size", "xtp.tspec.outburst",
1354                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1355                 },
1356                 /* address segment */
1357                 { &hf_xtp_aseg_alen,
1358                         { "Length", "xtp.aseg.alen",
1359                         FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1360                 },
1361                 { &hf_xtp_aseg_adomain,
1362                         { "Domain", "xtp.aseg.alen",
1363                         FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }
1364                 },
1365                 { &hf_xtp_aseg_aformat,
1366                         { "Format", "xtp.aseg.aformat",
1367                         FT_UINT8, BASE_DEC, VALS(aformat_vals), 0x0, NULL, HFILL }
1368                 },
1369                 { &hf_xtp_aseg_address,
1370                         { "Traffic", "xtp.aseg.address",
1371                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1372                 },
1373                 { &hf_xtp_aseg_dsthost,
1374                         { "Destination host", "xtp.aseg.dsthost",
1375                         FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }
1376                 },
1377                 { &hf_xtp_aseg_srchost,
1378                         { "Source host", "xtp.aseg.srchost",
1379                         FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }
1380                 },
1381                 { &hf_xtp_aseg_dstport,
1382                         { "Destination port", "xtp.aseg.dstport",
1383                         FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1384                 },
1385                 { &hf_xtp_aseg_srcport,
1386                         { "Source port", "xtp.aseg.srcport",
1387                         FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1388                 },
1389                 /* others */
1390                 { &hf_xtp_btag,
1391                         { "Beginning tag", "xtp.data.btag",
1392                         FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }
1393                 },
1394                 { &hf_xtp_diag_code,
1395                         { "Diagnostic code", "xtp.diag.code",
1396                         FT_UINT32, BASE_DEC, VALS(diag_code_vals), 0x0, NULL, HFILL }
1397                 },
1398                 { &hf_xtp_diag_val,
1399                         { "Diagnostic value", "xtp.diag.val",
1400                         FT_UINT32, BASE_DEC, VALS(diag_val_vals), 0x0, NULL, HFILL }
1401                 },
1402                 { &hf_xtp_diag_msg,
1403                         { "Message", "xtp.diag.msg",
1404                         FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1405                 },
1406         };
1407
1408         static gint *ett[] = {
1409                 &ett_xtp,
1410                 &ett_xtp_cmd,
1411                 &ett_xtp_cmd_options,
1412                 &ett_xtp_cmd_ptype,
1413                 &ett_xtp_cntl,
1414                 &ett_xtp_ecntl,
1415                 &ett_xtp_tcntl,
1416                 &ett_xtp_tspec,
1417                 &ett_xtp_jcntl,
1418                 &ett_xtp_first,
1419                 &ett_xtp_aseg,
1420                 &ett_xtp_data,
1421                 &ett_xtp_diag,
1422         };
1423
1424         proto_xtp = proto_register_protocol("Xpress Transport Protocol",
1425             "XTP", "xtp");
1426         proto_register_field_array(proto_xtp, hf, array_length(hf));
1427         proto_register_subtree_array(ett, array_length(ett));
1428 }
1429
1430 void
1431 proto_reg_handoff_xtp(void)
1432 {
1433         dissector_handle_t xtp_handle;
1434
1435         xtp_handle = new_create_dissector_handle(dissect_xtp, proto_xtp);
1436         dissector_add_uint("ip.proto", IP_PROTO_XTP, xtp_handle);
1437 }