Untested support for AiroPeek captures.
[metze/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.26 2002/01/21 07:36:47 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_fixed_part                     = HF_EMPTY;
152 static int hf_wtp_header_sub_pdu_size                   = HF_EMPTY;
153 static int hf_wtp_header_flag_continue                  = HF_EMPTY;
154 static int hf_wtp_header_pdu_type                       = HF_EMPTY;
155 static int hf_wtp_header_flag_Trailer                   = HF_EMPTY;
156 static int hf_wtp_header_flag_RID                       = HF_EMPTY;
157 static int hf_wtp_header_flag_TID                       = HF_EMPTY;
158 static int hf_wtp_header_flag_TID_response              = HF_EMPTY;
159
160 /* These fields used by Invoke packets */
161 static int hf_wtp_header_Inv_version                    = HF_EMPTY;
162 static int hf_wtp_header_Inv_flag_TIDNew                = HF_EMPTY;
163 static int hf_wtp_header_Inv_flag_UP                    = HF_EMPTY;
164 static int hf_wtp_header_Inv_Reserved                   = HF_EMPTY;
165 static int hf_wtp_header_Inv_TransactionClass           = HF_EMPTY;
166
167
168 static int hf_wtp_header_variable_part                  = HF_EMPTY;
169 static int hf_wtp_data                                  = HF_EMPTY;
170
171 static int hf_wtp_header_Ack_flag_TVETOK                = HF_EMPTY;
172 static int hf_wtp_header_Abort_type                     = HF_EMPTY;
173 static int hf_wtp_header_Abort_reason_provider          = HF_EMPTY;
174 static int hf_wtp_header_Abort_reason_user              = HF_EMPTY;
175 static int hf_wtp_header_sequence_number                = HF_EMPTY;
176 static int hf_wtp_header_missing_packets                = HF_EMPTY;
177
178 /* Initialize the subtree pointers */
179 static gint ett_wtp                                     = ETT_EMPTY;
180 static gint ett_header                                  = ETT_EMPTY;
181
182 /* Handle for WSP dissector */
183 static dissector_handle_t wsp_handle;
184
185 /*
186  * reassembly of WSP
187  */
188 static GHashTable       *wtp_fragment_table = NULL;
189
190 static void
191 wtp_defragment_init(void)
192 {
193         fragment_table_init(&wtp_fragment_table);
194 }
195
196 /*
197  * Extract some bitfields
198  */
199 #define pdu_type(octet)                 (((octet) >> 3) & 0x0F) /* Note pdu type must not be 0x00 */
200 #define transaction_class(octet)        ((octet) & 0x03)        /* ......XX */
201 #define transmission_trailer(octet)     (((octet) >> 1) & 0x01) /* ......X. */
202
203 static char retransmission_indicator(unsigned char octet)
204 {
205         switch ( pdu_type(octet) ) {
206                 case INVOKE:
207                 case RESULT:
208                 case ACK:
209                 case SEGMENTED_INVOKE:
210                 case SEGMENTED_RESULT:
211                 case NEGATIVE_ACK:
212                         return octet & 0x01;    /* .......X */
213                 default:
214                         return 0;
215         }
216 }
217
218 /* Code to actually dissect the packets */
219 static void
220 dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
221 {
222         char            szInfo[ 50 ];
223         int             offCur          = 0; /* current offset from start of WTP data */
224
225         /* bytes at offset 0 - 3 */
226         /*
227         unsigned char  b0 = pd[offset + 0];
228         unsigned char  b3 = pd[offset + 3];
229         */
230         unsigned char  b0;
231
232         /* continuation flag */
233         unsigned char   fCon;                   /* Continue flag        */
234         unsigned char   fRID;                   /* Re-transmission indicator    */
235         unsigned char   fTTR = '\0';            /* Transmission trailer */
236         guint           cbHeader        = 0;
237         guint           vHeader         = 0;
238         int             abortType       = 0;
239
240 /* Set up structures we will need to add the protocol subtree and manage it */
241         proto_item      *ti;
242         proto_tree      *wtp_tree = NULL;
243         proto_tree      *wtp_header_fixed;
244         
245         char            pdut;
246         char            clsTransaction  = ' ';
247         int             cchInfo;
248         int             numMissing = 0;         /* Number of missing packets in a negative ack */
249         int             i;
250         tvbuff_t        *wsp_tvb = NULL;
251         fragment_data   *fd_head = NULL;
252         guint8          psn = 0;                /* Packet sequence number       */
253         guint16         TID = 0;                /* Transaction-Id       */
254
255         b0 = tvb_get_guint8 (tvb, offCur + 0);
256         /* Discover Concatenated PDUs */
257         if (b0 == 0) {
258                 if (tree) {
259                         wtp_tree = proto_tree_add_item(tree, proto_wtp, tvb, offCur, 1, bo_little_endian);
260                 }
261                 offCur = 1;
262                 i = 1;
263                 while (offCur < (int) tvb_reported_length (tvb)) {
264                         b0 = tvb_get_guint8 (tvb, offCur + 0);
265                         if (b0 & 0x80) {
266                                 vHeader = 2;
267                                 cbHeader = ((b0 & 0x7f) << 8) |
268                                             tvb_get_guint8 (tvb, offCur + 1);
269                         } else {
270                                 vHeader = 1;
271                                 cbHeader = b0;
272                         }
273                         if (tree) {
274                                 proto_tree_add_item(wtp_tree, hf_wtp_header_sub_pdu_size, tvb, offCur, vHeader, bo_big_endian);
275                         }
276                         if (i > 1 && check_col(pinfo->cinfo, COL_INFO)) {
277                                 col_append_str (pinfo->cinfo, COL_INFO, ", ");
278                         }
279                         wsp_tvb = tvb_new_subset(tvb, offCur + vHeader, -1, cbHeader);
280                         dissect_wtp_common (wsp_tvb, pinfo, wtp_tree);
281                         offCur += vHeader + cbHeader;
282                         i++;
283                 }
284                 return;
285         }
286         fCon = b0 & 0x80;
287         fRID = retransmission_indicator( b0 );
288         pdut = pdu_type( b0 );
289
290         /* Develop the string to put in the Info column */
291         cchInfo = snprintf( szInfo, sizeof( szInfo ), "WTP %s",
292                     val_to_str(pdut, vals_pdu_type, "Unknown PDU type 0x%x"));
293
294         switch( pdut ) {
295                 case INVOKE:
296                         fTTR = transmission_trailer( b0 );
297                         TID = tvb_get_ntohs(tvb, offCur + 1);
298                         psn = 0;
299                         clsTransaction = transaction_class( tvb_get_guint8 (tvb, offCur + 3) );
300                         snprintf( szInfo + cchInfo, sizeof( szInfo ) - cchInfo, " Class %d", clsTransaction  );
301                         cbHeader = 4;
302                         break;
303
304                 case SEGMENTED_INVOKE:
305                 case SEGMENTED_RESULT:
306                         fTTR = transmission_trailer( b0 );
307                         TID = tvb_get_ntohs(tvb, offCur + 1);
308                         psn = tvb_get_guint8(tvb, offCur + 3);
309                         cbHeader = 4;
310                         break;
311
312                 case ABORT:
313                         cbHeader = 4;
314                         break;
315
316                 case RESULT:
317                         fTTR = transmission_trailer( b0 );
318                         TID = tvb_get_ntohs(tvb, offCur + 1);
319                         psn = 0;
320                         cbHeader = 3;
321                         break;
322
323                 case ACK:
324                         cbHeader = 3;
325                         break;
326
327                 case NEGATIVE_ACK:
328                         /* Variable number of missing packets */
329                         numMissing = tvb_get_guint8 (tvb, offCur + 3);
330                         cbHeader = numMissing + 4;
331                         break;
332
333                 default:
334                         break;
335         };
336
337         if( fRID ) {
338                 strcat( szInfo, " R" );
339         };
340         if( fCon ) {                    /* Scan variable part (TPI's)   */
341                 unsigned char   tCon;
342                 unsigned char   tByte;
343
344                 do {
345                         tByte = tvb_get_guint8(tvb, offCur + cbHeader + vHeader);
346                         tCon = tByte & 0x80;
347                         if (tByte & 0x04)
348                                 vHeader = vHeader + tvb_get_guint8(tvb,
349                                         offCur + cbHeader + vHeader + 1) + 2;
350                         else
351                                 vHeader = vHeader + (tByte & 0x03) + 1;
352                 } while (tCon);
353         }
354
355 #ifdef DEBUG
356         fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );  
357 #endif
358
359         /* This field shows up as the "Info" column in the display; you should make
360            it, if possible, summarize what's in the packet, so that a user looking
361            at the list of packets can tell what type of packet it is. */
362         if (check_col(pinfo->cinfo, COL_INFO) &&
363             (tvb_length_remaining(tvb, offCur + cbHeader + vHeader) <= 0)) {
364 #ifdef DEBUG
365                 fprintf( stderr, "dissect_wtp: (6) About to set info_col header to %s\n", szInfo );
366 #endif
367                 col_append_str(pinfo->cinfo, COL_INFO, szInfo );
368         };
369         /* In the interest of speed, if "tree" is NULL, don't do any work not
370            necessary to generate protocol tree items. */
371         if (tree) {
372 #ifdef DEBUG
373                 fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );  
374 #endif
375                 ti = proto_tree_add_item(tree, proto_wtp, tvb, offCur, cbHeader + vHeader, bo_little_endian);
376 #ifdef DEBUG
377                 fprintf( stderr, "dissect_wtp: (7) Returned from proto_tree_add_item\n" );  
378 #endif
379                 wtp_tree = proto_item_add_subtree(ti, ett_wtp);
380
381 /* Code to process the packet goes here */
382                 {
383 #ifdef DEBUG
384                         fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );  
385                         fprintf( stderr, "dissect_wtp: offCur = %d\n", offCur );  
386                         fprintf( stderr, "dissect_wtp: About to call proto_tree_add_item with %p %d %p %d %d %d\n", 
387                                         wtp_tree, hf_wtp_header_fixed_part, tvb, offCur, cbHeader, bo_little_endian ); 
388                         ti = proto_tree_add_item( wtp_tree, hf_wtp_header_fixed_part, tvb, offCur, cbHeader, bo_little_endian );
389                         fprintf( stderr, "dissect_wtp: (6) Returned from proto_tree_add_item\n" );  
390 #endif
391                         wtp_header_fixed = proto_item_add_subtree(ti, ett_header);
392
393                         /* Add common items: only CON and PDU Type */
394                         ti = proto_tree_add_item(
395                                         wtp_header_fixed,               /* tree */
396                                         hf_wtp_header_flag_continue,    /* id */
397                                         tvb, 
398                                         offCur,                         /* start of high light */
399                                         1,                              /* length of high light */
400                                         b0                              /* value */
401                              );
402                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_pdu_type, tvb, offCur, 1, bo_little_endian );
403
404                         switch( pdut ) {
405                                 case INVOKE:
406                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian );
407                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
408                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
409                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
410
411                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_Inv_version , tvb, offCur + 3, 1, bo_little_endian );
412                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_Inv_flag_TIDNew, tvb, offCur + 3, 1, bo_little_endian );
413                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_Inv_flag_UP, tvb, offCur + 3, 1, bo_little_endian );
414                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_Inv_Reserved, tvb, offCur + 3, 1, bo_little_endian );
415                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_Inv_TransactionClass, tvb, offCur + 3, 1, bo_little_endian );
416                                         break;
417
418                                 case RESULT:
419                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian );
420                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
421                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
422                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
423                                         break;
424
425                                 case ACK:
426                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_Ack_flag_TVETOK, tvb, offCur, 1, bo_big_endian );
427
428                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
429                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
430                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
431                                         break;
432
433                                 case ABORT:
434                                         abortType = tvb_get_guint8 (tvb, offCur) & 0x07;
435                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_Abort_type , tvb, offCur , 1, bo_little_endian );
436                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
437                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
438
439                                         if (abortType == PROVIDER)
440                                         {
441                                                 ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_Abort_reason_provider , tvb, offCur + 3 , 1, bo_little_endian );
442                                         }
443                                         else if (abortType == USER)
444                                         {
445                                                 ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_Abort_reason_user , tvb, offCur + 3 , 1, bo_little_endian );
446                                         }
447                                         break;
448
449                                 case SEGMENTED_INVOKE:
450                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian );
451                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
452                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
453                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
454
455                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, bo_little_endian );
456                                         break;
457
458                                 case SEGMENTED_RESULT:
459                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian );
460                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
461                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
462                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
463
464                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, bo_little_endian );
465                                         break;
466
467                                 case NEGATIVE_ACK:
468                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian );
469                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian );
470                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian );
471
472                                         ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_missing_packets , tvb, offCur + 3, 1, bo_little_endian );
473                                         /* Iterate through missing packets */
474                                         for (i=0; i<numMissing; i++)
475                                         {
476                                                 ti = proto_tree_add_item( wtp_header_fixed, hf_wtp_header_sequence_number , tvb, offCur + i, 1, bo_little_endian );
477                                         }
478                                         break;
479
480                                 default:
481                                         break;
482                         };
483
484                         if( fCon ) {
485                                 /* There is a variable part if the Con flag is set */ 
486                                 ti = proto_tree_add_bytes_format(
487                                                 wtp_tree,                       /* tree */
488                                                 hf_wtp_header_variable_part,    /* id */
489                                                 tvb, 
490                                                 offCur + cbHeader,              /* start */
491                                                 vHeader,                        /* length */
492                                                 "What should go here!",         /* value */
493                                                 "Header (Variable part) %02X %02X %02X %02X",   /* format */
494                                                 0, 1, 2, 3
495                                     );
496                         } else {
497                                 /* There is no variable part */
498                         }       /* End of variable part of header */
499                 }
500         } else {
501 #ifdef DEBUG
502                 fprintf( stderr, "dissect_wtp: (4) tree was %p\n", tree ); 
503 #endif
504         }
505         /*
506          * Any remaining data ought to be WSP data,
507          * so hand off (defragmented) to the WSP dissector
508          */
509         if (tvb_length_remaining(tvb, offCur + cbHeader + vHeader) > 0)
510         {
511                 int     dataOffset = offCur + cbHeader + vHeader;
512                 guint32 dataLen = tvb_length_remaining(tvb, offCur + cbHeader + vHeader);
513                 gboolean save_fragmented;
514
515                 if ((pdut == SEGMENTED_INVOKE) || (pdut == SEGMENTED_RESULT) ||
516                     (((pdut == INVOKE) || (pdut == RESULT)) && (!fTTR)))        /* 1st part of segment  */
517                 {
518                         save_fragmented = pinfo->fragmented;
519                         pinfo->fragmented = TRUE;
520                         fd_head = fragment_add_seq(tvb, dataOffset, pinfo, TID,
521                                         wtp_fragment_table, psn, dataLen, !fTTR);
522                         if (fd_head != NULL)            /* Reassembled  */
523                         {
524                                 wsp_tvb = tvb_new_real_data(fd_head->data,
525                                                         fd_head->len,
526                                                         fd_head->len,
527                                                         "Reassembled");
528                                 tvb_set_child_real_data_tvbuff(tvb, wsp_tvb);
529                                 pinfo->fd->data_src = g_slist_append(pinfo->fd->data_src, wsp_tvb);
530                                 pinfo->fragmented = FALSE;
531                                 call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
532                         }
533                         else
534                         {
535                                 if (check_col(pinfo->cinfo, COL_INFO))          /* Won't call WSP so display */
536                                         col_append_str(pinfo->cinfo, COL_INFO, szInfo );
537                         }
538                         pinfo->fragmented = save_fragmented;
539                 }
540                 else                            /* Normal packet, call next dissector   */
541                 {
542                         wsp_tvb = tvb_new_subset(tvb, dataOffset, -1, dataLen);
543                         call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
544                 }
545         }
546 }
547
548 /*
549  * Called directly from UDP.
550  * Put "WTP+WSP" into the "Protocol" column.
551  */
552 static void
553 dissect_wtp_fromudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
554 {
555         if (check_col(pinfo->cinfo, COL_PROTOCOL))
556                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WTP+WSP" );
557         if (check_col(pinfo->cinfo, COL_INFO)) {
558                 col_clear(pinfo->cinfo, COL_INFO);
559         }
560
561         dissect_wtp_common(tvb, pinfo, tree);
562 }
563
564 /*
565  * Called from a higher-level WAP dissector, presumably WTLS.
566  * Put "WTLS+WSP+WTP" to the "Protocol" column.
567  *
568  * XXX - is this supposed to be called from WTLS?  If so, we're not
569  * calling it....
570  *
571  * XXX - can this be called from any other dissector?
572  */
573 static void
574 dissect_wtp_fromwap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
575 {
576         if (check_col(pinfo->cinfo, COL_PROTOCOL))
577                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WTLS+WTP+WSP" );
578         if (check_col(pinfo->cinfo, COL_INFO)) {
579                 col_clear(pinfo->cinfo, COL_INFO);
580         }
581
582         dissect_wtp_common(tvb, pinfo, tree);
583 }
584
585 /* Register the protocol with Ethereal */
586 void
587 proto_register_wtp(void)
588 {                 
589
590 /* Setup list of header fields */
591         static hf_register_info hf[] = {
592                 { &hf_wtp_header_fixed_part,
593                         {       "Header",           
594                                 "wtp.header_fixed_part",
595                                 FT_BYTES, BASE_HEX, NULL, 0x0,          
596                                 "Fixed part of the header", HFILL
597                         }
598                 },
599                 { &hf_wtp_header_sub_pdu_size,
600                         {       "Sub PDU size",           
601                                 "wtp.sub_pdu_size",
602                                 FT_BYTES, BASE_HEX, NULL, 0x0,
603                                 "Size of Sub-PDU", HFILL
604                         }
605                 },
606                 { &hf_wtp_header_flag_continue,
607                         {       "Continue Flag",           
608                                 "wtp.continue_flag",
609                                 FT_BOOLEAN, 8, TFS( &continue_truth ), 0x80,          
610                                 "Continue Flag", HFILL
611                         }
612                 },
613                 { &hf_wtp_header_pdu_type,
614                         {       "PDU Type",           
615                                 "wtp.pdu_type",
616                                  FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x78,
617                                 "PDU Type", HFILL
618                         }
619                 },
620                 { &hf_wtp_header_flag_Trailer,
621                         {       "Trailer Flags",           
622                                 "wtp.trailer_flags",
623                                  FT_UINT8, BASE_HEX, VALS( vals_transaction_trailer ), 0x06,
624                                 "Trailer Flags", HFILL
625                         }
626                 },
627                 { &hf_wtp_header_flag_RID,
628                         {       "Re-transmission Indicator",           
629                                 "wtp.RID",
630                                  FT_BOOLEAN, 8, TFS( &RID_truth ), 0x01,
631                                 "Re-transmission Indicator", HFILL
632                         }
633                 },
634                 { &hf_wtp_header_flag_TID_response,
635                         {       "TID Response",           
636                                 "wtp.TID.response",
637                                 FT_BOOLEAN, 16, TFS( &tid_response_truth ), 0x8000,
638                                 "TID Response", HFILL
639                         }
640                 },
641                 { &hf_wtp_header_flag_TID,
642                         {       "Transaction ID",           
643                                 "wtp.TID",
644                                  FT_UINT16, BASE_HEX, NULL, 0x7FFF,
645                                 "Transaction ID", HFILL
646                         }
647                 },
648                 { &hf_wtp_header_Inv_version,
649                         {       "Version",           
650                                 "wtp.header.version",
651                                  FT_UINT8, BASE_HEX, VALS( vals_version ), 0xC0,
652                                 "Version", HFILL
653                         }
654                 },
655                 { &hf_wtp_header_Inv_flag_TIDNew,
656                         {       "TIDNew",           
657                                 "wtp.header.TIDNew",
658                                  FT_BOOLEAN, 8, TFS( &TIDNew_truth ), 0x20,
659                                 "TIDNew", HFILL
660                         }
661                 },
662                 { &hf_wtp_header_Inv_flag_UP,
663                         {       "U/P flag",           
664                                 "wtp.header.UP",
665                                  FT_BOOLEAN, 8, TFS( &UP_truth ), 0x10,
666                                 "U/P Flag", HFILL
667                         }
668                 },
669                 { &hf_wtp_header_Inv_Reserved,
670                         {       "Reserved",           
671                                 "wtp.inv.reserved",
672                                  FT_UINT8, BASE_HEX, NULL, 0x0C,
673                                 "Reserved", HFILL
674                         }
675                 },
676                 { &hf_wtp_header_Inv_TransactionClass,
677                         {       "Transaction Class",           
678                                 "wtp.inv.transaction_class",
679                                  FT_UINT8, BASE_HEX, VALS( vals_transaction_classes ), 0x03,
680                                 "Transaction Class", HFILL
681                         }
682                 },
683                 { &hf_wtp_header_Ack_flag_TVETOK,
684                         {       "Tve/Tok flag",           
685                                 "wtp.ack.tvetok",
686                                  FT_BOOLEAN, 8, TFS( &TVETOK_truth ), 0x04,
687                                 "Tve/Tok flag", HFILL
688                         }
689                 },
690                 { &hf_wtp_header_Abort_type,
691                         {       "Abort Type",           
692                                 "wtp.abort.type",
693                                  FT_UINT8, BASE_HEX, VALS ( vals_abort_type ), 0x07,
694                                 "Abort Type", HFILL
695                         }
696                 },
697                 { &hf_wtp_header_Abort_reason_provider,
698                         {       "Abort Reason",           
699                                 "wtp.abort.reason.provider",
700                                  FT_UINT8, BASE_HEX, VALS ( vals_abort_reason_provider ), 0x00,
701                                 "Abort Reason", HFILL
702                         }
703                 },
704                 /* Assume WSP is the user and use its reason codes */
705                 { &hf_wtp_header_Abort_reason_user,
706                         {       "Abort Reason",           
707                                 "wtp.abort.reason.user",
708                                  FT_UINT8, BASE_HEX, VALS ( vals_wsp_reason_codes ), 0x00,
709                                 "Abort Reason", HFILL
710                         }
711                 },
712                 { &hf_wtp_header_sequence_number,
713                         {       "Packet Sequence Number",           
714                                 "wtp.header.sequence",
715                                  FT_UINT8, BASE_HEX, NULL, 0x00,
716                                 "Packet Sequence Number", HFILL
717                         }
718                 },
719                 { &hf_wtp_header_missing_packets,
720                         {       "Missing Packets",           
721                                 "wtp.header.missing_packets",
722                                  FT_UINT8, BASE_HEX, NULL, 0x00,
723                                 "Missing Packets", HFILL
724                         }
725                 },
726                 { &hf_wtp_header_variable_part,
727                         {       "Header: Variable part",           
728                                 "wtp.header_variable_part",
729                                 FT_BYTES, BASE_HEX, NULL, 0x0,          
730                                 "Variable part of the header", HFILL
731                         }
732                 },
733                 { &hf_wtp_data,
734                         {       "Data",           
735                                 "wtp.header_data",
736                                 FT_BYTES, BASE_HEX, NULL, 0x0,          
737                                 "Data", HFILL
738                         }
739                 },
740         };
741         
742 /* Setup protocol subtree array */
743         static gint *ett[] = {
744                 &ett_wtp,
745                 &ett_header,
746         };
747
748 /* Register the protocol name and description */
749         proto_wtp = proto_register_protocol(
750                 "Wireless Transaction Protocol",   /* protocol name for use by ethereal */ 
751                 "WTP",                             /* short version of name */
752                 "wap-wsp-wtp"                      /* Abbreviated protocol name, should Match IANA 
753                                                     < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
754                                                   */
755         );
756
757 /* Required function calls to register the header fields and subtrees used */
758         proto_register_field_array(proto_wtp, hf, array_length(hf));
759         proto_register_subtree_array(ett, array_length(ett));
760
761         register_dissector("wtp", dissect_wtp_fromwap, proto_wtp);
762         register_dissector("wtp-udp", dissect_wtp_fromudp, proto_wtp);
763         register_init_routine(wtp_defragment_init);
764 };
765
766 void
767 proto_reg_handoff_wtp(void)
768 {
769         dissector_handle_t wtp_fromudp_handle;
770
771         /*
772          * Get a handle for the connection-oriented WSP dissector - if WTP
773          * PDUs have data, it is WSP.
774          */
775         wsp_handle = find_dissector("wsp-co");
776
777         wtp_fromudp_handle = find_dissector("wtp-udp");
778         dissector_add("udp.port", UDP_PORT_WTP_WSP, wtp_fromudp_handle);
779 }