Get rid of an unused variable.
[obnox/wireshark/wip.git] / packet-wtp.c
1 /* packet-wtp.c
2  *
3  * Routines to dissect WTP component of WAP traffic.
4  * 
5  * $Id: packet-wtp.c,v 1.32 2002/04/17 08:30:17 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * WAP dissector based on original work by Ben Fowler
12  * Updated by Neil Hunter <neil.hunter@energis-squared.com>
13  * WTLS support by Alexandre P. Ferreira (Splice IP)
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  * 
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  * 
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
39 #endif
40
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
43 #endif
44
45 #ifdef NEED_SNPRINTF_H
46 # ifdef HAVE_STDARG_H
47 #  include <stdarg.h>
48 # else
49 #  include <varargs.h>
50 # endif
51 # include "snprintf.h"
52 #endif
53
54 #include <string.h>
55 #include <glib.h>
56 #include <epan/packet.h>
57 #include "reassemble.h"
58 #include "packet-wap.h"
59 #include "packet-wtp.h"
60 #include "packet-wsp.h"
61
62 static const true_false_string continue_truth = { 
63         "TPI Present" ,
64         "No TPI"
65 };
66
67 static const true_false_string RID_truth = { 
68         "Re-Transmission",
69         "First transmission"
70 };
71
72 static const true_false_string TIDNew_truth = { 
73         "TID is new" ,
74         "TID is valid"
75 };
76
77 static const true_false_string tid_response_truth = { 
78         "Response" ,
79         "Original"
80 };
81
82 static const true_false_string UP_truth = { 
83         "User Acknowledgement required" ,
84         "User Acknowledgement optional"
85 };
86
87 static const true_false_string TVETOK_truth = {
88         "True",
89         "False"
90 };
91
92 static const value_string vals_pdu_type[] = {
93         { 0, "Not Allowed" },
94         { 1, "Invoke" },
95         { 2, "Result" },
96         { 3, "Ack" },
97         { 4, "Abort" },
98         { 5, "Segmented Invoke" },
99         { 6, "Segmented Result" },
100         { 7, "Negative Ack" },
101         { 0, NULL }
102 };
103
104 static const value_string vals_transaction_trailer[] = {
105         { 0, "Not last packet" },
106         { 1, "Last packet of message" },
107         { 2, "Last packet of group" },
108         { 3, "Re-assembly not supported" },
109         { 0, NULL }
110 };
111
112 static const value_string vals_version[] = {
113         { 0, "Current" },
114         { 1, "Undefined" },
115         { 2, "Undefined" },
116         { 3, "Undefined" },
117         { 0, NULL }
118 };
119
120 static const value_string vals_abort_type[] = {
121         { 0, "Provider" },
122         { 1, "User (WSP)" },
123         { 0, NULL }
124 };
125
126 static const value_string vals_abort_reason_provider[] = {
127         { 0x00, "Unknown" },
128         { 0x01, "Protocol Error" },
129         { 0x02, "Invalid TID" },
130         { 0x03, "Not Implemented Class 2" },
131         { 0x04, "Not Implemented SAR" },
132         { 0x05, "Not Implemented User Acknowledgement" },
133         { 0x06, "WTP Version Zero" },
134         { 0x07, "Capacity Temporarily Exceeded" },
135         { 0x08, "No Response" },
136         { 0x09, "Message Too Large" },
137         { 0x00, NULL }
138 };
139
140 static const value_string vals_transaction_classes[] = {
141         { 0x00, "Unreliable Invoke without Result" },
142         { 0x01, "Reliable Invoke without Result" },
143         { 0x02, "Reliable Invoke with Reliable Result" },
144         { 0x00, NULL }
145 };
146
147 /* File scoped variables for the protocol and registered fields */
148 static int proto_wtp                                    = HF_EMPTY;
149
150 /* These fields used by fixed part of header */
151 static int hf_wtp_header_sub_pdu_size                   = HF_EMPTY;
152 static int hf_wtp_header_flag_continue                  = HF_EMPTY;
153 static int hf_wtp_header_pdu_type                       = HF_EMPTY;
154 static int hf_wtp_header_flag_Trailer                   = HF_EMPTY;
155 static int hf_wtp_header_flag_RID                       = HF_EMPTY;
156 static int hf_wtp_header_flag_TID                       = HF_EMPTY;
157 static int hf_wtp_header_flag_TID_response              = HF_EMPTY;
158
159 /* These fields used by Invoke packets */
160 static int hf_wtp_header_Inv_version                    = HF_EMPTY;
161 static int hf_wtp_header_Inv_flag_TIDNew                = HF_EMPTY;
162 static int hf_wtp_header_Inv_flag_UP                    = HF_EMPTY;
163 static int hf_wtp_header_Inv_Reserved                   = HF_EMPTY;
164 static int hf_wtp_header_Inv_TransactionClass           = HF_EMPTY;
165
166
167 static int hf_wtp_header_variable_part                  = HF_EMPTY;
168 static int hf_wtp_data                                  = HF_EMPTY;
169
170 static int hf_wtp_header_Ack_flag_TVETOK                = HF_EMPTY;
171 static int hf_wtp_header_Abort_type                     = HF_EMPTY;
172 static int hf_wtp_header_Abort_reason_provider          = HF_EMPTY;
173 static int hf_wtp_header_Abort_reason_user              = HF_EMPTY;
174 static int hf_wtp_header_sequence_number                = HF_EMPTY;
175 static int hf_wtp_header_missing_packets                = HF_EMPTY;
176
177 /* These fields used when reassembling WTP fragments */
178 static int hf_wtp_fragments                             = HF_EMPTY;
179 static int hf_wtp_fragment                              = HF_EMPTY;
180 static int hf_wtp_fragment_overlap                      = HF_EMPTY;
181 static int hf_wtp_fragment_overlap_conflict             = HF_EMPTY;
182 static int hf_wtp_fragment_multiple_tails               = HF_EMPTY;
183 static int hf_wtp_fragment_too_long_fragment            = HF_EMPTY;
184 static int hf_wtp_fragment_error                        = HF_EMPTY;
185
186 /* Initialize the subtree pointers */
187 static gint ett_wtp                                     = ETT_EMPTY;
188 static gint ett_header                                  = ETT_EMPTY;
189 static gint ett_wsp_fragments                           = ETT_EMPTY;
190 static gint ett_wtp_fragment                            = ETT_EMPTY;
191
192 /* Handle for WSP dissector */
193 static dissector_handle_t wsp_handle;
194
195 /*
196  * reassembly of WSP
197  */
198 static GHashTable       *wtp_fragment_table = NULL;
199
200 static void
201 wtp_defragment_init(void)
202 {
203         fragment_table_init(&wtp_fragment_table);
204 }
205
206 /*
207  * Extract some bitfields
208  */
209 #define pdu_type(octet)                 (((octet) >> 3) & 0x0F) /* Note pdu type must not be 0x00 */
210 #define transaction_class(octet)        ((octet) & 0x03)        /* ......XX */
211 #define transmission_trailer(octet)     (((octet) >> 1) & 0x01) /* ......X. */
212
213 static char retransmission_indicator(unsigned char octet)
214 {
215         switch ( pdu_type(octet) ) {
216                 case INVOKE:
217                 case RESULT:
218                 case ACK:
219                 case SEGMENTED_INVOKE:
220                 case SEGMENTED_RESULT:
221                 case NEGATIVE_ACK:
222                         return octet & 0x01;    /* .......X */
223                 default:
224                         return 0;
225         }
226 }
227
228 static void show_fragments(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
229                            fragment_data *fd_head)
230 {
231         guint32 offset;
232         fragment_data *fd;
233         proto_tree *ft;
234         proto_item *fi;
235
236         fi = proto_tree_add_item(tree, hf_wtp_fragments, tvb, 0, -1, FALSE);
237         ft = proto_item_add_subtree(fi, ett_wsp_fragments);
238         offset = 0;
239         for (fd=fd_head->next; fd; fd=fd->next){
240                 if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT
241                     |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
242                         /* this fragment has some flags set, create a subtree
243                            for it and display the flags. */
244                         proto_tree *fet=NULL;
245                         proto_item *fei=NULL;
246                         int hf;
247
248                         if (fd->flags & (FD_OVERLAPCONFLICT
249                             |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
250                                 hf = hf_wtp_fragment_error;
251                         } else {
252                                 hf = hf_wtp_fragment;
253                         }
254                         fei = proto_tree_add_none_format(ft, hf, 
255                             tvb, offset, fd->len,
256                             "Frame:%u payload:%u-%u",
257                             fd->frame, offset, offset+fd->len-1);
258                         fet = proto_item_add_subtree(fei, ett_wtp_fragment);
259                         if (fd->flags&FD_OVERLAP) {
260                                 proto_tree_add_boolean(fet, 
261                                     hf_wtp_fragment_overlap, tvb, 0, 0, 
262                                     TRUE);
263                         }
264                         if (fd->flags&FD_OVERLAPCONFLICT) {
265                                 proto_tree_add_boolean(fet, 
266                                     hf_wtp_fragment_overlap_conflict, tvb, 0, 0,
267                                     TRUE);
268                         }
269                         if (fd->flags&FD_MULTIPLETAILS) {
270                                 proto_tree_add_boolean(fet, 
271                                     hf_wtp_fragment_multiple_tails, tvb, 0, 0,
272                                     TRUE);
273                         }
274                         if (fd->flags&FD_TOOLONGFRAGMENT) {
275                                 proto_tree_add_boolean(fet, 
276                                     hf_wtp_fragment_too_long_fragment, tvb, 0, 0,
277                                     TRUE);
278                         }
279                 } else {
280                         /* nothing of interest for this fragment */
281                         proto_tree_add_none_format(ft, hf_wtp_fragment, 
282                             tvb, offset, fd->len,
283                             "Frame:%u payload:%u-%u",
284                             fd->frame, offset, offset+fd->len-1);
285                 }
286                 offset += fd->len;
287         }
288         if (fd_head->flags & (FD_OVERLAPCONFLICT
289                         |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
290                 if (check_col(pinfo->cinfo, COL_INFO))
291                         col_set_str(pinfo->cinfo, COL_INFO, "[Illegal fragments]");
292         }
293 }
294
295 /* Code to actually dissect the packets */
296 static void
297 dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
298 {
299         char            szInfo[ 50 ];
300         int             offCur          = 0; /* current offset from start of WTP data */
301
302         /* bytes at offset 0 - 3 */
303         /*
304         unsigned char  b0 = pd[offset + 0];
305         unsigned char  b3 = pd[offset + 3];
306         */
307         unsigned char  b0;
308
309         /* continuation flag */
310         unsigned char   fCon;                   /* Continue flag        */
311         unsigned char   fRID;                   /* Re-transmission indicator    */
312         unsigned char   fTTR = '\0';            /* Transmission trailer */
313         guint           cbHeader        = 0;
314         guint           vHeader         = 0;
315         int             abortType       = 0;
316
317 /* Set up structures we will need to add the protocol subtree and manage it */
318         proto_item      *ti;
319         proto_tree      *wtp_tree = NULL;
320         
321         char            pdut;
322         char            clsTransaction  = ' ';
323         int             cchInfo;
324         int             numMissing = 0;         /* Number of missing packets in a negative ack */
325         int             i;
326         tvbuff_t        *wsp_tvb = NULL;
327         fragment_data   *fd_head = NULL;
328         guint8          psn = 0;                /* Packet sequence number       */
329         guint16         TID = 0;                /* Transaction-Id       */
330
331         b0 = tvb_get_guint8 (tvb, offCur + 0);
332         /* Discover Concatenated PDUs */
333         if (b0 == 0) {
334                 if (tree) {
335                         ti = proto_tree_add_item(tree, proto_wtp, tvb, offCur, 1, bo_little_endian);
336                         wtp_tree = proto_item_add_subtree(ti, ett_wtp);
337                 }
338                 offCur = 1;
339                 i = 1;
340                 while (offCur < (int) tvb_reported_length (tvb)) {
341                         b0 = tvb_get_guint8 (tvb, offCur + 0);
342                         if (b0 & 0x80) {
343                                 vHeader = 2;
344                                 cbHeader = ((b0 & 0x7f) << 8) |
345                                             tvb_get_guint8 (tvb, offCur + 1);
346                         } else {
347                                 vHeader = 1;
348                                 cbHeader = b0;
349                         }
350                         if (tree) {
351                                 proto_tree_add_item(wtp_tree, hf_wtp_header_sub_pdu_size, tvb, offCur, vHeader, bo_big_endian);
352                         }
353                         if (i > 1 && check_col(pinfo->cinfo, COL_INFO)) {
354                                 col_append_str (pinfo->cinfo, COL_INFO, ", ");
355                         }
356                         wsp_tvb = tvb_new_subset(tvb, offCur + vHeader, -1, cbHeader);
357                         dissect_wtp_common (wsp_tvb, pinfo, wtp_tree);
358                         offCur += vHeader + cbHeader;
359                         i++;
360                 }
361                 return;
362         }
363         fCon = b0 & 0x80;
364         fRID = retransmission_indicator( b0 );
365         pdut = pdu_type( b0 );
366
367         /* Develop the string to put in the Info column */
368         cchInfo = snprintf( szInfo, sizeof( szInfo ), "WTP %s",
369                     val_to_str(pdut, vals_pdu_type, "Unknown PDU type 0x%x"));
370
371         switch( pdut ) {
372                 case INVOKE:
373                         fTTR = transmission_trailer( b0 );
374                         TID = tvb_get_ntohs(tvb, offCur + 1);
375                         psn = 0;
376                         clsTransaction = transaction_class( tvb_get_guint8 (tvb, offCur + 3) );
377                         snprintf( szInfo + cchInfo, sizeof( szInfo ) - cchInfo, " Class %d", clsTransaction  );
378                         cbHeader = 4;
379                         break;
380
381                 case SEGMENTED_INVOKE:
382                 case SEGMENTED_RESULT:
383                         fTTR = transmission_trailer( b0 );
384                         TID = tvb_get_ntohs(tvb, offCur + 1);
385                         psn = tvb_get_guint8(tvb, offCur + 3);
386                         cbHeader = 4;
387                         break;
388
389                 case ABORT:
390                         cbHeader = 4;
391                         break;
392
393                 case RESULT:
394                         fTTR = transmission_trailer( b0 );
395                         TID = tvb_get_ntohs(tvb, offCur + 1);
396                         psn = 0;
397                         cbHeader = 3;
398                         break;
399
400                 case ACK:
401                         cbHeader = 3;
402                         break;
403
404                 case NEGATIVE_ACK:
405                         /* Variable number of missing packets */
406                         numMissing = tvb_get_guint8 (tvb, offCur + 3);
407                         cbHeader = numMissing + 4;
408                         break;
409
410                 default:
411                         break;
412         };
413
414         if( fRID ) {
415                 strcat( szInfo, " R" );
416         };
417         if( fCon ) {                    /* Scan variable part (TPI's)   */
418                 unsigned char   tCon;
419                 unsigned char   tByte;
420
421                 do {
422                         tByte = tvb_get_guint8(tvb, offCur + cbHeader + vHeader);
423                         tCon = tByte & 0x80;
424                         if (tByte & 0x04)
425                                 vHeader = vHeader + tvb_get_guint8(tvb,
426                                         offCur + cbHeader + vHeader + 1) + 2;
427                         else
428                                 vHeader = vHeader + (tByte & 0x03) + 1;
429                 } while (tCon);
430         }
431
432 #ifdef DEBUG
433         fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );  
434 #endif
435
436         /* This field shows up as the "Info" column in the display; you should make
437            it, if possible, summarize what's in the packet, so that a user looking
438            at the list of packets can tell what type of packet it is. */
439         if (check_col(pinfo->cinfo, COL_INFO) &&
440             (tvb_length_remaining(tvb, offCur + cbHeader + vHeader) <= 0)) {
441 #ifdef DEBUG
442                 fprintf( stderr, "dissect_wtp: (6) About to set info_col header to %s\n", szInfo );
443 #endif
444                 col_append_str(pinfo->cinfo, COL_INFO, szInfo );
445         };
446         /* In the interest of speed, if "tree" is NULL, don't do any work not
447            necessary to generate protocol tree items. */
448         if (tree) {
449 #ifdef DEBUG
450                 fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );  
451 #endif
452                 ti = proto_tree_add_item(tree, proto_wtp, tvb, offCur, cbHeader + vHeader, bo_little_endian);
453 #ifdef DEBUG
454                 fprintf( stderr, "dissect_wtp: (7) Returned from proto_tree_add_item\n" );  
455 #endif
456                 wtp_tree = proto_item_add_subtree(ti, ett_wtp);
457
458 /* Code to process the packet goes here */
459                 {
460 #ifdef DEBUG
461                         fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );  
462                         fprintf( stderr, "dissect_wtp: offCur = %d\n", offCur );  
463 #endif
464                         /* Add common items: only CON and PDU Type */
465                         proto_tree_add_item(
466                                         wtp_tree,                       /* tree */
467                                         hf_wtp_header_flag_continue,    /* id */
468                                         tvb, 
469                                         offCur,                         /* start of high light */
470                                         1,                              /* length of high light */
471                                         b0                              /* value */
472                              );
473                         proto_tree_add_item( wtp_tree, hf_wtp_header_pdu_type, tvb, offCur, 1, bo_little_endian );
474
475                         switch( pdut ) {
476                                 case INVOKE:
477                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian );
478                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
479                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
480                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
481
482                                         proto_tree_add_item( wtp_tree, hf_wtp_header_Inv_version , tvb, offCur + 3, 1, bo_little_endian );
483                                         proto_tree_add_item( wtp_tree, hf_wtp_header_Inv_flag_TIDNew, tvb, offCur + 3, 1, bo_little_endian );
484                                         proto_tree_add_item( wtp_tree, hf_wtp_header_Inv_flag_UP, tvb, offCur + 3, 1, bo_little_endian );
485                                         proto_tree_add_item( wtp_tree, hf_wtp_header_Inv_Reserved, tvb, offCur + 3, 1, bo_little_endian );
486                                         proto_tree_add_item( wtp_tree, hf_wtp_header_Inv_TransactionClass, tvb, offCur + 3, 1, bo_little_endian );
487                                         break;
488
489                                 case RESULT:
490                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian );
491                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
492                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
493                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
494                                         break;
495
496                                 case ACK:
497                                         proto_tree_add_item( wtp_tree, hf_wtp_header_Ack_flag_TVETOK, tvb, offCur, 1, bo_big_endian );
498
499                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
500                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
501                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
502                                         break;
503
504                                 case ABORT:
505                                         abortType = tvb_get_guint8 (tvb, offCur) & 0x07;
506                                         proto_tree_add_item( wtp_tree, hf_wtp_header_Abort_type , tvb, offCur , 1, bo_little_endian );
507                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
508                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
509
510                                         if (abortType == PROVIDER)
511                                         {
512                                                 proto_tree_add_item( wtp_tree, hf_wtp_header_Abort_reason_provider , tvb, offCur + 3 , 1, bo_little_endian );
513                                         }
514                                         else if (abortType == USER)
515                                         {
516                                                 proto_tree_add_item( wtp_tree, hf_wtp_header_Abort_reason_user , tvb, offCur + 3 , 1, bo_little_endian );
517                                         }
518                                         break;
519
520                                 case SEGMENTED_INVOKE:
521                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian );
522                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
523                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
524                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
525
526                                         proto_tree_add_item( wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, bo_little_endian );
527                                         break;
528
529                                 case SEGMENTED_RESULT:
530                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian );
531                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
532                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
533                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
534
535                                         proto_tree_add_item( wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, bo_little_endian );
536                                         break;
537
538                                 case NEGATIVE_ACK:
539                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
540                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
541                                         proto_tree_add_item( wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
542
543                                         proto_tree_add_item( wtp_tree, hf_wtp_header_missing_packets , tvb, offCur + 3, 1, bo_little_endian );
544                                         /* Iterate through missing packets */
545                                         for (i=0; i<numMissing; i++)
546                                         {
547                                                 proto_tree_add_item( wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + i, 1, bo_little_endian );
548                                         }
549                                         break;
550
551                                 default:
552                                         break;
553                         };
554
555                         if( fCon ) {
556                                 /* There is a variable part if the Con flag is set */ 
557                                 proto_tree_add_bytes_format(
558                                                 wtp_tree,                       /* tree */
559                                                 hf_wtp_header_variable_part,    /* id */
560                                                 tvb, 
561                                                 offCur + cbHeader,              /* start */
562                                                 vHeader,                        /* length */
563                                                 "What should go here!",         /* value */
564                                                 "Header (Variable part) %02X %02X %02X %02X",   /* format */
565                                                 0, 1, 2, 3
566                                     );
567                         } else {
568                                 /* There is no variable part */
569                         }       /* End of variable part of header */
570                 }
571         } else {
572 #ifdef DEBUG
573                 fprintf( stderr, "dissect_wtp: (4) tree was %p\n", tree ); 
574 #endif
575         }
576         /*
577          * Any remaining data ought to be WSP data,
578          * so hand off (defragmented) to the WSP dissector
579          */
580         if (tvb_length_remaining(tvb, offCur + cbHeader + vHeader) > 0)
581         {
582                 int     dataOffset = offCur + cbHeader + vHeader;
583                 guint32 dataLen = tvb_length_remaining(tvb, offCur + cbHeader + vHeader);
584                 gboolean save_fragmented;
585
586                 if ((pdut == SEGMENTED_INVOKE) || (pdut == SEGMENTED_RESULT) ||
587                     (((pdut == INVOKE) || (pdut == RESULT)) && (!fTTR)))        /* 1st part of segment  */
588                 {
589                         save_fragmented = pinfo->fragmented;
590                         pinfo->fragmented = TRUE;
591                         fd_head = fragment_add_seq(tvb, dataOffset, pinfo, TID,
592                                         wtp_fragment_table, psn, dataLen, !fTTR);
593                         if (fd_head != NULL)            /* Reassembled  */
594                         {
595                                 wsp_tvb = tvb_new_real_data(fd_head->data,
596                                                         fd_head->len,
597                                                         fd_head->len);
598                                 tvb_set_child_real_data_tvbuff(tvb, wsp_tvb);
599                                 add_new_data_source(pinfo->fd, wsp_tvb,
600                                                         "Reassembled WTP");
601                                 pinfo->fragmented = FALSE;
602
603                                 /* show all fragments */
604                                 show_fragments(wsp_tvb, pinfo, wtp_tree, fd_head);
605
606                                 call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
607                         }
608                         else
609                         {
610                                 if (check_col(pinfo->cinfo, COL_INFO))          /* Won't call WSP so display */
611                                         col_append_str(pinfo->cinfo, COL_INFO, szInfo );
612                         }
613                         pinfo->fragmented = save_fragmented;
614                 }
615                 else                            /* Normal packet, call next dissector   */
616                 {
617                         wsp_tvb = tvb_new_subset(tvb, dataOffset, -1, dataLen);
618                         call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
619                 }
620         }
621 }
622
623 /*
624  * Called directly from UDP.
625  * Put "WTP+WSP" into the "Protocol" column.
626  */
627 static void
628 dissect_wtp_fromudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
629 {
630         if (check_col(pinfo->cinfo, COL_PROTOCOL))
631                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WTP+WSP" );
632         if (check_col(pinfo->cinfo, COL_INFO)) {
633                 col_clear(pinfo->cinfo, COL_INFO);
634         }
635
636         dissect_wtp_common(tvb, pinfo, tree);
637 }
638
639 /*
640  * Called from a higher-level WAP dissector, presumably WTLS.
641  * Put "WTLS+WSP+WTP" to the "Protocol" column.
642  *
643  * XXX - is this supposed to be called from WTLS?  If so, we're not
644  * calling it....
645  *
646  * XXX - can this be called from any other dissector?
647  */
648 static void
649 dissect_wtp_fromwap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
650 {
651         if (check_col(pinfo->cinfo, COL_PROTOCOL))
652                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WTLS+WTP+WSP" );
653         if (check_col(pinfo->cinfo, COL_INFO)) {
654                 col_clear(pinfo->cinfo, COL_INFO);
655         }
656
657         dissect_wtp_common(tvb, pinfo, tree);
658 }
659
660 /* Register the protocol with Ethereal */
661 void
662 proto_register_wtp(void)
663 {                 
664
665 /* Setup list of header fields */
666         static hf_register_info hf[] = {
667                 { &hf_wtp_header_sub_pdu_size,
668                         {       "Sub PDU size",           
669                                 "wtp.sub_pdu_size",
670                                 FT_BYTES, BASE_HEX, NULL, 0x0,
671                                 "Size of Sub-PDU", HFILL
672                         }
673                 },
674                 { &hf_wtp_header_flag_continue,
675                         {       "Continue Flag",           
676                                 "wtp.continue_flag",
677                                 FT_BOOLEAN, 8, TFS( &continue_truth ), 0x80,          
678                                 "Continue Flag", HFILL
679                         }
680                 },
681                 { &hf_wtp_header_pdu_type,
682                         {       "PDU Type",           
683                                 "wtp.pdu_type",
684                                  FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x78,
685                                 "PDU Type", HFILL
686                         }
687                 },
688                 { &hf_wtp_header_flag_Trailer,
689                         {       "Trailer Flags",           
690                                 "wtp.trailer_flags",
691                                  FT_UINT8, BASE_HEX, VALS( vals_transaction_trailer ), 0x06,
692                                 "Trailer Flags", HFILL
693                         }
694                 },
695                 { &hf_wtp_header_flag_RID,
696                         {       "Re-transmission Indicator",           
697                                 "wtp.RID",
698                                  FT_BOOLEAN, 8, TFS( &RID_truth ), 0x01,
699                                 "Re-transmission Indicator", HFILL
700                         }
701                 },
702                 { &hf_wtp_header_flag_TID_response,
703                         {       "TID Response",           
704                                 "wtp.TID.response",
705                                 FT_BOOLEAN, 16, TFS( &tid_response_truth ), 0x8000,
706                                 "TID Response", HFILL
707                         }
708                 },
709                 { &hf_wtp_header_flag_TID,
710                         {       "Transaction ID",           
711                                 "wtp.TID",
712                                  FT_UINT16, BASE_HEX, NULL, 0x7FFF,
713                                 "Transaction ID", HFILL
714                         }
715                 },
716                 { &hf_wtp_header_Inv_version,
717                         {       "Version",           
718                                 "wtp.header.version",
719                                  FT_UINT8, BASE_HEX, VALS( vals_version ), 0xC0,
720                                 "Version", HFILL
721                         }
722                 },
723                 { &hf_wtp_header_Inv_flag_TIDNew,
724                         {       "TIDNew",           
725                                 "wtp.header.TIDNew",
726                                  FT_BOOLEAN, 8, TFS( &TIDNew_truth ), 0x20,
727                                 "TIDNew", HFILL
728                         }
729                 },
730                 { &hf_wtp_header_Inv_flag_UP,
731                         {       "U/P flag",           
732                                 "wtp.header.UP",
733                                  FT_BOOLEAN, 8, TFS( &UP_truth ), 0x10,
734                                 "U/P Flag", HFILL
735                         }
736                 },
737                 { &hf_wtp_header_Inv_Reserved,
738                         {       "Reserved",           
739                                 "wtp.inv.reserved",
740                                  FT_UINT8, BASE_HEX, NULL, 0x0C,
741                                 "Reserved", HFILL
742                         }
743                 },
744                 { &hf_wtp_header_Inv_TransactionClass,
745                         {       "Transaction Class",           
746                                 "wtp.inv.transaction_class",
747                                  FT_UINT8, BASE_HEX, VALS( vals_transaction_classes ), 0x03,
748                                 "Transaction Class", HFILL
749                         }
750                 },
751                 { &hf_wtp_header_Ack_flag_TVETOK,
752                         {       "Tve/Tok flag",           
753                                 "wtp.ack.tvetok",
754                                  FT_BOOLEAN, 8, TFS( &TVETOK_truth ), 0x04,
755                                 "Tve/Tok flag", HFILL
756                         }
757                 },
758                 { &hf_wtp_header_Abort_type,
759                         {       "Abort Type",           
760                                 "wtp.abort.type",
761                                  FT_UINT8, BASE_HEX, VALS ( vals_abort_type ), 0x07,
762                                 "Abort Type", HFILL
763                         }
764                 },
765                 { &hf_wtp_header_Abort_reason_provider,
766                         {       "Abort Reason",           
767                                 "wtp.abort.reason.provider",
768                                  FT_UINT8, BASE_HEX, VALS ( vals_abort_reason_provider ), 0x00,
769                                 "Abort Reason", HFILL
770                         }
771                 },
772                 /* Assume WSP is the user and use its reason codes */
773                 { &hf_wtp_header_Abort_reason_user,
774                         {       "Abort Reason",           
775                                 "wtp.abort.reason.user",
776                                  FT_UINT8, BASE_HEX, VALS ( vals_wsp_reason_codes ), 0x00,
777                                 "Abort Reason", HFILL
778                         }
779                 },
780                 { &hf_wtp_header_sequence_number,
781                         {       "Packet Sequence Number",           
782                                 "wtp.header.sequence",
783                                  FT_UINT8, BASE_HEX, NULL, 0x00,
784                                 "Packet Sequence Number", HFILL
785                         }
786                 },
787                 { &hf_wtp_header_missing_packets,
788                         {       "Missing Packets",           
789                                 "wtp.header.missing_packets",
790                                  FT_UINT8, BASE_HEX, NULL, 0x00,
791                                 "Missing Packets", HFILL
792                         }
793                 },
794                 { &hf_wtp_header_variable_part,
795                         {       "Header: Variable part",           
796                                 "wtp.header_variable_part",
797                                 FT_BYTES, BASE_HEX, NULL, 0x0,          
798                                 "Variable part of the header", HFILL
799                         }
800                 },
801                 { &hf_wtp_data,
802                         {       "Data",           
803                                 "wtp.header_data",
804                                 FT_BYTES, BASE_HEX, NULL, 0x0,          
805                                 "Data", HFILL
806                         }
807                 },
808
809                 /* Fragment fields */
810                 { &hf_wtp_fragment_overlap,
811                         {       "Fragment overlap",
812                                 "wtp.fragment.overlap",
813                                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
814                                 "Fragment overlaps with other fragments", HFILL
815                                 }
816                         },
817                 { &hf_wtp_fragment_overlap_conflict,
818                         {       "Conflicting data in fragment overlap",
819                                 "wtp.fragment.overlap.conflict",
820                                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
821                                 "Overlapping fragments contained conflicting data", HFILL
822                         }
823                 },
824                 { &hf_wtp_fragment_multiple_tails,
825                         {       "Multiple tail fragments found",
826                                 "wtp.fragment.multipletails",
827                                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
828                                 "Several tails were found when defragmenting the packet", HFILL
829                         }
830                 },
831                 { &hf_wtp_fragment_too_long_fragment,
832                         {       "Fragment too long",
833                                 "wtp.fragment.toolongfragment",
834                                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
835                                 "Fragment contained data past end of packet", HFILL
836                         }
837                 },
838                 { &hf_wtp_fragment_error,
839                         {       "Defragmentation error",
840                                 "wtp.fragment.error",
841                                 FT_NONE, BASE_NONE, NULL, 0x0,
842                                 "Defragmentation error due to illegal fragments", HFILL
843                         }
844                 },
845                 { &hf_wtp_fragment,
846                         {       "WTP Fragment",
847                                 "wtp.fragment",
848                                 FT_NONE, BASE_NONE, NULL, 0x0,
849                                 "WTP Fragment", HFILL
850                         }
851                 },
852                 { &hf_wtp_fragments,
853                         {       "WTP Fragments",
854                                 "wtp.fragments",
855                                 FT_NONE, BASE_NONE, NULL, 0x0,
856                                 "WTP Fragments", HFILL
857                         }
858                 },
859         };
860         
861 /* Setup protocol subtree array */
862         static gint *ett[] = {
863                 &ett_wtp,
864                 &ett_header,
865                 &ett_wsp_fragments,
866                 &ett_wtp_fragment,
867         };
868
869 /* Register the protocol name and description */
870         proto_wtp = proto_register_protocol(
871                 "Wireless Transaction Protocol",   /* protocol name for use by ethereal */ 
872                 "WTP",                             /* short version of name */
873                 "wap-wsp-wtp"                      /* Abbreviated protocol name, should Match IANA 
874                                                     < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
875                                                   */
876         );
877
878 /* Required function calls to register the header fields and subtrees used */
879         proto_register_field_array(proto_wtp, hf, array_length(hf));
880         proto_register_subtree_array(ett, array_length(ett));
881
882         register_dissector("wtp", dissect_wtp_fromwap, proto_wtp);
883         register_dissector("wtp-udp", dissect_wtp_fromudp, proto_wtp);
884         register_init_routine(wtp_defragment_init);
885 };
886
887 void
888 proto_reg_handoff_wtp(void)
889 {
890         dissector_handle_t wtp_fromudp_handle;
891
892         /*
893          * Get a handle for the connection-oriented WSP dissector - if WTP
894          * PDUs have data, it is WSP.
895          */
896         wsp_handle = find_dissector("wsp-co");
897
898         wtp_fromudp_handle = find_dissector("wtp-udp");
899         dissector_add("udp.port", UDP_PORT_WTP_WSP, wtp_fromudp_handle);
900 }