Fix memory leaks involving tvb_get_string[z]().
[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         g_free(diag->msg);
909
910         return;
911 }
912
913 /* main dissector */
914 static int
915 dissect_xtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
916         guint32 offset, len;
917         proto_item *ti;
918         proto_tree *xtp_tree, *xtp_cmd_tree, *xtp_subtree;
919         struct xtphdr xtph[1];
920         int     error = 0;
921         gchar   *options = "<None>";
922         const char *fstr[] = { "<None>", "NOCHECK", "EDGE", "NOERR", "MULTI", "RES",
923                                 "SORT", "NOFLOW", "FASTNAK", "SREQ", "DREQ",
924                                 "RCLOSE", "WCLOSE", "EOM", "END", "BTAG" };
925         gint    fpos = 0, returned_length;
926         guint   i, bpos;
927         guint   cmd_options;
928         vec_t   cksum_vec[1];
929         guint16 computed_cksum;
930         gboolean have_btag;
931
932         if ((len = tvb_length(tvb)) < XTP_HEADER_LEN)
933                 return 0;
934
935         col_set_str(pinfo->cinfo, COL_PROTOCOL, "XTP");
936         col_clear(pinfo->cinfo, COL_INFO);
937
938         /** parse header **/
939         offset = 0;
940         /* key(8) */
941         xtph->key               = tvb_get_ntohl(tvb, offset);
942         xtph->key <<= 32;
943         xtph->key += tvb_get_ntohl(tvb, offset+4);
944         offset += 8;
945         /* cmd(4) */
946         xtph->cmd               = tvb_get_ntohl(tvb, offset);
947         xtph->cmd_options       = xtph->cmd >> 8;
948         xtph->cmd_ptype         = xtph->cmd & 0xff;
949         xtph->cmd_ptype_ver     = (xtph->cmd_ptype & 0xe0) >> 5;
950         xtph->cmd_ptype_pformat = xtph->cmd_ptype & 0x1f;
951         offset += 4;
952         /* dlen(4) */
953         xtph->dlen              = tvb_get_ntohl(tvb, offset);
954         offset += 4;
955         /* check(2) */
956         xtph->check             = tvb_get_ntohs(tvb, offset);
957         offset += 2;
958         /* sort(2) */
959         xtph->sort              = tvb_get_ntohs(tvb, offset);
960         offset += 2;
961         /* sync(4) */
962         xtph->sync              = tvb_get_ntohl(tvb, offset);
963         offset += 4;
964         /* seq(8) */
965         xtph->seq               = tvb_get_ntohl(tvb, offset);
966         xtph->seq <<= 32;
967         xtph->seq += tvb_get_ntohl(tvb, offset+4);
968
969 #define MAX_OPTIONS_LEN 128
970         options=ep_alloc(MAX_OPTIONS_LEN);
971         options[0]=0;
972         cmd_options = xtph->cmd_options >> 8;
973         for (i = 0; i < 16; i++) {
974                 bpos = 1 << (15 - i);
975                 if (cmd_options & bpos) {
976                         returned_length = g_snprintf(&options[fpos],
977                         MAX_OPTIONS_LEN-fpos, "%s%s",
978                         fpos?", ":"",
979                         fstr[i]);
980                         fpos += MIN(returned_length, MAX_OPTIONS_LEN-fpos);
981                 }
982         }
983
984         if (check_col(pinfo->cinfo, COL_INFO)) {
985                 col_add_str(pinfo->cinfo, COL_INFO,
986                             val_to_str(xtph->cmd_ptype_pformat,
987                                         pformat_vals, "Unknown pformat (%u)"));
988                 col_append_fstr(pinfo->cinfo, COL_INFO, " [%s]", options);
989                 col_append_fstr(pinfo->cinfo, COL_INFO,
990                                 " Seq=%" G_GINT64_MODIFIER "u", xtph->seq);
991                 col_append_fstr(pinfo->cinfo, COL_INFO, " Len=%u", xtph->dlen);
992         }
993
994         if (tree) {
995                 ti = proto_tree_add_item(tree, proto_xtp, tvb, 0, -1, ENC_NA);
996                 /** add summary **/
997                 proto_item_append_text(ti,
998                                 ", Key: 0x%016" G_GINT64_MODIFIER "X", xtph->key);
999                 proto_item_append_text(ti,
1000                                 ", Seq: %" G_GINT64_MODIFIER "u", xtph->seq);
1001                 proto_item_append_text(ti, ", Len: %u", xtph->dlen);
1002
1003                 xtp_tree = proto_item_add_subtree(ti, ett_xtp);
1004                 /* key(8) */
1005                 offset = 0;
1006                 proto_tree_add_uint64(xtp_tree, hf_xtp_key,
1007                                         tvb, offset, 8, xtph->key);
1008                 offset += 8;
1009                 /* cmd(4) */
1010                 ti = proto_tree_add_uint(xtp_tree, hf_xtp_cmd,
1011                                         tvb, offset, 4, xtph->cmd);
1012                 xtp_cmd_tree = proto_item_add_subtree(ti, ett_xtp_cmd);
1013                 ti = proto_tree_add_uint(xtp_cmd_tree, hf_xtp_cmd_options,
1014                                         tvb, offset, 3, xtph->cmd_options);
1015                 /** add summary **/
1016                 proto_item_append_text(ti, " [%s]", options);
1017
1018                 xtp_subtree = proto_item_add_subtree(ti, ett_xtp_cmd_options);
1019                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_nocheck,
1020                                         tvb, offset, 3, xtph->cmd_options);
1021                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_edge,
1022                                         tvb, offset, 3, xtph->cmd_options);
1023                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_noerr,
1024                                         tvb, offset, 3, xtph->cmd_options);
1025                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_multi,
1026                                         tvb, offset, 3, xtph->cmd_options);
1027                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_res,
1028                                         tvb, offset, 3, xtph->cmd_options);
1029                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_sort,
1030                                         tvb, offset, 3, xtph->cmd_options);
1031                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_noflow,
1032                                         tvb, offset, 3, xtph->cmd_options);
1033                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_fastnak,
1034                                         tvb, offset, 3, xtph->cmd_options);
1035                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_sreq,
1036                                         tvb, offset, 3, xtph->cmd_options);
1037                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_dreq,
1038                                         tvb, offset, 3, xtph->cmd_options);
1039                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_rclose,
1040                                         tvb, offset, 3, xtph->cmd_options);
1041                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_wclose,
1042                                         tvb, offset, 3, xtph->cmd_options);
1043                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_eom,
1044                                         tvb, offset, 3, xtph->cmd_options);
1045                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_end,
1046                                         tvb, offset, 3, xtph->cmd_options);
1047                 proto_tree_add_boolean(xtp_subtree, hf_xtp_cmd_options_btag,
1048                                         tvb, offset, 3, xtph->cmd_options);
1049                 offset += 3;
1050                 ti = proto_tree_add_uint(xtp_cmd_tree, hf_xtp_cmd_ptype,
1051                                         tvb, offset, 1, xtph->cmd_ptype);
1052                 xtp_subtree = proto_item_add_subtree(ti, ett_xtp_cmd_ptype);
1053                 proto_tree_add_uint(xtp_subtree, hf_xtp_cmd_ptype_ver,
1054                                         tvb, offset, 1, xtph->cmd_ptype_ver);
1055                 if (xtph->cmd_ptype_ver != XTP_VERSION_4) {
1056                         proto_item_append_text(ti,
1057                                 ", Unknown XTP version (%03X)", xtph->cmd_ptype_ver);
1058                         error = 1;
1059                 }
1060                 proto_tree_add_uint(xtp_subtree, hf_xtp_cmd_ptype_pformat,
1061                                 tvb, offset, 1, xtph->cmd_ptype_pformat);
1062                 offset++;
1063                 /* dlen(4) */
1064                 ti = proto_tree_add_uint(xtp_tree, hf_xtp_dlen,
1065                                 tvb, offset, 4, xtph->dlen);
1066                 if (xtph->dlen != len - XTP_HEADER_LEN) {
1067                         proto_item_append_text(ti, ", bogus length (%u, must be %u)",
1068                                 xtph->dlen, len - XTP_HEADER_LEN);
1069                         error = 1;
1070                 }
1071                 offset += 4;
1072                 /* check(2) */
1073                 if (!pinfo->fragmented) {
1074                         guint32 check_len = XTP_HEADER_LEN;
1075                         if (!(xtph->cmd_options & XTP_CMD_OPTIONS_NOCHECK))
1076                                 check_len += xtph->dlen;
1077                         cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, check_len);
1078                         cksum_vec[0].len = check_len;
1079                         computed_cksum = in_cksum(cksum_vec, 1);
1080                         if (computed_cksum == 0) {
1081                                 proto_tree_add_text(xtp_tree, tvb, offset, 2,
1082                                         "Checksum: 0x%04x [correct]", xtph->check);
1083                         } else {
1084                                 proto_tree_add_text(xtp_tree, tvb, offset, 2,
1085                                         "Checksum: 0x%04x [incorrect, should be 0x%04x]",
1086                                         xtph->check,
1087                                         in_cksum_shouldbe(xtph->check, computed_cksum));
1088                         }
1089                 }
1090                 else {
1091                         proto_tree_add_text(xtp_tree, tvb, offset, 2,
1092                                         "Checksum: 0x%04x", xtph->check);
1093                 }
1094                 offset += 2;
1095                 /* sort(2) */
1096                 proto_tree_add_uint(xtp_tree, hf_xtp_sort, tvb, offset, 2, xtph->sort);
1097                 offset += 2;
1098                 /* sync(4) */
1099                 proto_tree_add_uint(xtp_tree, hf_xtp_sync, tvb, offset, 4, xtph->sync);
1100                 offset += 4;
1101                 /* seq(8) */
1102                 proto_tree_add_uint64(xtp_tree, hf_xtp_seq, tvb, offset, 8, xtph->seq);
1103                 offset += 8;
1104
1105                 if (!error) {
1106                         switch (xtph->cmd_ptype_pformat) {
1107                         case XTP_DATA_PKT:
1108                                 have_btag = !!(xtph->cmd_options & XTP_CMD_OPTIONS_BTAG);
1109                                 dissect_xtp_data(tvb, xtp_tree, offset, have_btag);
1110                                 break;
1111                         case XTP_CNTL_PKT:
1112                                 dissect_xtp_cntl(tvb, pinfo, xtp_tree, offset);
1113                                 break;
1114                         case XTP_FIRST_PKT:
1115                                 dissect_xtp_first(tvb, xtp_tree, offset);
1116                                 break;
1117                         case XTP_ECNTL_PKT:
1118                                 dissect_xtp_ecntl(tvb, pinfo, xtp_tree, offset);
1119                                 break;
1120                         case XTP_TCNTL_PKT:
1121                                 dissect_xtp_tcntl(tvb, pinfo, xtp_tree, offset);
1122                                 break;
1123                         case XTP_JOIN_PKT:
1124                                 /* obsolete */
1125                                 break;
1126                         case XTP_JCNTL_PKT:
1127                                 dissect_xtp_jcntl(tvb, pinfo, xtp_tree, offset);
1128                                 break;
1129                         case XTP_DIAG_PKT:
1130                                 dissect_xtp_diag(tvb, xtp_tree, offset);
1131                                 break;
1132                         default:
1133                                 /* error */
1134                                 break;
1135                         }
1136                 }
1137         }
1138
1139         return tvb_length(tvb);
1140 }
1141
1142 void
1143 proto_register_xtp(void)
1144 {
1145         static hf_register_info hf[] = {
1146                 /* command header */
1147                 { &hf_xtp_key,
1148                         { "Key",           "xtp.key",
1149                         FT_UINT64, BASE_HEX, NULL, 0x0,
1150                         NULL, HFILL }
1151                 },
1152                 { &hf_xtp_cmd,
1153                         { "Command", "xtp.cmd",
1154                         FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }
1155                 },
1156                 { &hf_xtp_cmd_options,
1157                         { "Options", "xtp.cmd.options",
1158                         FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL }
1159                 },
1160                 { &hf_xtp_cmd_options_nocheck,
1161                         { "NOCHECK", "xtp.cmd.options.nocheck",
1162                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1163                         XTP_CMD_OPTIONS_NOCHECK, NULL, HFILL }
1164                 },
1165                 { &hf_xtp_cmd_options_edge,
1166                         { "EDGE", "xtp.cmd.options.edge",
1167                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1168                         XTP_CMD_OPTIONS_EDGE, NULL, HFILL }
1169                 },
1170                 { &hf_xtp_cmd_options_noerr,
1171                         { "NOERR", "xtp.cmd.options.noerr",
1172                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1173                         XTP_CMD_OPTIONS_NOERR, NULL, HFILL }
1174                 },
1175                 { &hf_xtp_cmd_options_multi,
1176                         { "MULTI", "xtp.cmd.options.multi",
1177                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1178                         XTP_CMD_OPTIONS_MULTI, NULL, HFILL }
1179                 },
1180                 { &hf_xtp_cmd_options_res,
1181                         { "RES", "xtp.cmd.options.res",
1182                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1183                         XTP_CMD_OPTIONS_RES, NULL, HFILL }
1184                 },
1185                 { &hf_xtp_cmd_options_sort,
1186                         { "SORT", "xtp.cmd.options.sort",
1187                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1188                         XTP_CMD_OPTIONS_SORT, NULL, HFILL }
1189                 },
1190                 { &hf_xtp_cmd_options_noflow,
1191                         { "NOFLOW", "xtp.cmd.options.noflow",
1192                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1193                         XTP_CMD_OPTIONS_NOFLOW, NULL, HFILL }
1194                 },
1195                 { &hf_xtp_cmd_options_fastnak,
1196                         { "FASTNAK", "xtp.cmd.options.fastnak",
1197                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1198                         XTP_CMD_OPTIONS_FASTNAK, NULL, HFILL }
1199                 },
1200                 { &hf_xtp_cmd_options_sreq,
1201                         { "SREQ", "xtp.cmd.options.sreq",
1202                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1203                         XTP_CMD_OPTIONS_SREQ, NULL, HFILL }
1204                 },
1205                 { &hf_xtp_cmd_options_dreq,
1206                         { "DREQ", "xtp.cmd.options.dreq",
1207                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1208                         XTP_CMD_OPTIONS_DREQ, NULL, HFILL }
1209                 },
1210                 { &hf_xtp_cmd_options_rclose,
1211                         { "RCLOSE", "xtp.cmd.options.rclose",
1212                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1213                         XTP_CMD_OPTIONS_RCLOSE, NULL, HFILL }
1214                 },
1215                 { &hf_xtp_cmd_options_wclose,
1216                         { "WCLOSE", "xtp.cmd.options.wclose",
1217                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1218                         XTP_CMD_OPTIONS_WCLOSE, NULL, HFILL }
1219                 },
1220                 { &hf_xtp_cmd_options_eom,
1221                         { "EOM", "xtp.cmd.options.eom",
1222                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1223                         XTP_CMD_OPTIONS_EOM, NULL, HFILL }
1224                 },
1225                 { &hf_xtp_cmd_options_end,
1226                         { "END", "xtp.cmd.options.end",
1227                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1228                         XTP_CMD_OPTIONS_END, NULL, HFILL }
1229                 },
1230                 { &hf_xtp_cmd_options_btag,
1231                         { "BTAG", "xtp.cmd.options.btag",
1232                         FT_BOOLEAN, 24, TFS(&tfs_set_notset),
1233                         XTP_CMD_OPTIONS_BTAG, NULL, HFILL }
1234                 },
1235                 { &hf_xtp_cmd_ptype,
1236                         { "Packet type", "xtp.cmd.ptype",
1237                         FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
1238                 },
1239                 { &hf_xtp_cmd_ptype_ver,
1240                         { "Version", "xtp.cmd.ptype.ver",
1241                         FT_UINT8, BASE_DEC, VALS(version_vals), 0x0, NULL, HFILL }
1242                 },
1243                 { &hf_xtp_cmd_ptype_pformat,
1244                         { "Format", "xtp.cmd.ptype.pformat",
1245                         FT_UINT8, BASE_DEC, VALS(pformat_vals), 0x0, NULL, HFILL }
1246                 },
1247                 { &hf_xtp_dlen,
1248                         { "Data length", "xtp.dlen",
1249                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1250                 },
1251                 { &hf_xtp_sort,
1252                         { "Sort", "xtp.sort",
1253                         FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1254                 },
1255                 { &hf_xtp_sync,
1256                         { "Synchronizing handshake", "xtp.sync",
1257                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1258                 },
1259                 { &hf_xtp_seq,
1260                         { "Sequence number", "xtp.seq",
1261                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1262                 },
1263                 /* control segment */
1264                 { &hf_xtp_cntl_rseq,
1265                         { "Received sequence number", "xtp.cntl.rseq",
1266                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1267                 },
1268                 { &hf_xtp_cntl_alloc,
1269                         { "Allocation", "xtp.cntl.alloc",
1270                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1271                 },
1272                 { &hf_xtp_cntl_echo,
1273                         { "Synchronizing handshake echo", "xtp.cntl.echo",
1274                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1275                 },
1276                 { &hf_xtp_ecntl_rseq,
1277                         { "Received sequence number", "xtp.ecntl.rseq",
1278                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1279                 },
1280                 { &hf_xtp_ecntl_alloc,
1281                         { "Allocation", "xtp.ecntl.alloc",
1282                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1283                 },
1284                 { &hf_xtp_ecntl_echo,
1285                         { "Synchronizing handshake echo", "xtp.ecntl.echo",
1286                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1287                 },
1288                 { &hf_xtp_ecntl_nspan,
1289                         { "Number of spans", "xtp.ecntl.nspan",
1290                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1291                 },
1292                 { &hf_xtp_ecntl_span_left,
1293                         { "Span left edge", "xtp.ecntl.span_le",
1294                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1295                 },
1296                 { &hf_xtp_ecntl_span_right,
1297                         { "Span right edge", "xtp.ecntl.span_re",
1298                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1299                 },
1300                 { &hf_xtp_tcntl_rseq,
1301                         { "Received sequence number", "xtp.tcntl.rseq",
1302                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1303                 },
1304                 { &hf_xtp_tcntl_alloc,
1305                         { "Allocation", "xtp.tcntl.alloc",
1306                         FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
1307                 },
1308                 { &hf_xtp_tcntl_echo,
1309                         { "Synchronizing handshake echo", "xtp.tcntl.echo",
1310                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1311                 },
1312                 { &hf_xtp_tcntl_rsvd,
1313                         { "Reserved", "xtp.tcntl.rsvd",
1314                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1315                 },
1316                 { &hf_xtp_tcntl_xkey,
1317                         { "Exchange key", "xtp.tcntl.xkey",
1318                         FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }
1319                 },
1320                 /* traffic specifier */
1321                 { &hf_xtp_tspec_tlen,
1322                         { "Length", "xtp.tspec.tlen",
1323                         FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1324                 },
1325                 { &hf_xtp_tspec_service,
1326                         { "Service", "xtp.tspec.service",
1327                         FT_UINT8, BASE_DEC, VALS(service_vals), 0x0, NULL, HFILL }
1328                 },
1329                 { &hf_xtp_tspec_tformat,
1330                         { "Format", "xtp.tspec.format",
1331                         FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }
1332                 },
1333                 { &hf_xtp_tspec_traffic,
1334                         { "Traffic", "xtp.tspec.traffic",
1335                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1336                 },
1337                 { &hf_xtp_tspec_maxdata,
1338                         { "Maxdata", "xtp.tspec.maxdata",
1339                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1340                 },
1341                 { &hf_xtp_tspec_inrate,
1342                         { "Incoming rate", "xtp.tspec.inrate",
1343                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1344                 },
1345                 { &hf_xtp_tspec_inburst,
1346                         { "Incoming burst size", "xtp.tspec.inburst",
1347                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1348                 },
1349                 { &hf_xtp_tspec_outrate,
1350                         { "Outgoing rate", "xtp.tspec.outrate",
1351                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1352                 },
1353                 { &hf_xtp_tspec_outburst,
1354                         { "Outgoing burst size", "xtp.tspec.outburst",
1355                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1356                 },
1357                 /* address segment */
1358                 { &hf_xtp_aseg_alen,
1359                         { "Length", "xtp.aseg.alen",
1360                         FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1361                 },
1362                 { &hf_xtp_aseg_adomain,
1363                         { "Domain", "xtp.aseg.alen",
1364                         FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }
1365                 },
1366                 { &hf_xtp_aseg_aformat,
1367                         { "Format", "xtp.aseg.aformat",
1368                         FT_UINT8, BASE_DEC, VALS(aformat_vals), 0x0, NULL, HFILL }
1369                 },
1370                 { &hf_xtp_aseg_address,
1371                         { "Traffic", "xtp.aseg.address",
1372                         FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1373                 },
1374                 { &hf_xtp_aseg_dsthost,
1375                         { "Destination host", "xtp.aseg.dsthost",
1376                         FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }
1377                 },
1378                 { &hf_xtp_aseg_srchost,
1379                         { "Source host", "xtp.aseg.srchost",
1380                         FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }
1381                 },
1382                 { &hf_xtp_aseg_dstport,
1383                         { "Destination port", "xtp.aseg.dstport",
1384                         FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1385                 },
1386                 { &hf_xtp_aseg_srcport,
1387                         { "Source port", "xtp.aseg.srcport",
1388                         FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1389                 },
1390                 /* others */
1391                 { &hf_xtp_btag,
1392                         { "Beginning tag", "xtp.data.btag",
1393                         FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }
1394                 },
1395                 { &hf_xtp_diag_code,
1396                         { "Diagnostic code", "xtp.diag.code",
1397                         FT_UINT32, BASE_DEC, VALS(diag_code_vals), 0x0, NULL, HFILL }
1398                 },
1399                 { &hf_xtp_diag_val,
1400                         { "Diagnostic value", "xtp.diag.val",
1401                         FT_UINT32, BASE_DEC, VALS(diag_val_vals), 0x0, NULL, HFILL }
1402                 },
1403                 { &hf_xtp_diag_msg,
1404                         { "Message", "xtp.diag.msg",
1405                         FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1406                 },
1407         };
1408
1409         static gint *ett[] = {
1410                 &ett_xtp,
1411                 &ett_xtp_cmd,
1412                 &ett_xtp_cmd_options,
1413                 &ett_xtp_cmd_ptype,
1414                 &ett_xtp_cntl,
1415                 &ett_xtp_ecntl,
1416                 &ett_xtp_tcntl,
1417                 &ett_xtp_tspec,
1418                 &ett_xtp_jcntl,
1419                 &ett_xtp_first,
1420                 &ett_xtp_aseg,
1421                 &ett_xtp_data,
1422                 &ett_xtp_diag,
1423         };
1424
1425         proto_xtp = proto_register_protocol("Xpress Transport Protocol",
1426             "XTP", "xtp");
1427         proto_register_field_array(proto_xtp, hf, array_length(hf));
1428         proto_register_subtree_array(ett, array_length(ett));
1429 }
1430
1431 void
1432 proto_reg_handoff_xtp(void)
1433 {
1434         dissector_handle_t xtp_handle;
1435
1436         xtp_handle = new_create_dissector_handle(dissect_xtp, proto_xtp);
1437         dissector_add_uint("ip.proto", IP_PROTO_XTP, xtp_handle);
1438 }