Rename the routines that handle dissector tables with unsigned integer
[metze/wireshark/wip.git] / epan / dissectors / packet-wtp.c
1 /* packet-wtp.c
2  *
3  * Routines to dissect WTP component of WAP traffic.
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
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 #include <glib.h>
38 #include <epan/packet.h>
39 #include <epan/reassemble.h>
40 #include <epan/emem.h>
41 #include "packet-wap.h"
42 #include "packet-wtp.h"
43 #include "packet-wsp.h"
44
45 static const true_false_string continue_truth = {
46     "TPI Present" ,
47     "No TPI"
48 };
49
50 static const true_false_string RID_truth = {
51     "Re-Transmission",
52     "First transmission"
53 };
54
55 static const true_false_string TIDNew_truth = {
56     "TID is new" ,
57     "TID is valid"
58 };
59
60 static const true_false_string tid_response_truth = {
61     "Response" ,
62     "Original"
63 };
64
65 static const true_false_string UP_truth = {
66     "User Acknowledgement required" ,
67     "User Acknowledgement optional"
68 };
69
70 static const true_false_string TVETOK_truth = {
71     "True",
72     "False"
73 };
74
75 static const value_string vals_wtp_pdu_type[] = {
76     { 0, "Not Allowed" },
77     { 1, "Invoke" },
78     { 2, "Result" },
79     { 3, "Ack" },
80     { 4, "Abort" },
81     { 5, "Segmented Invoke" },
82     { 6, "Segmented Result" },
83     { 7, "Negative Ack" },
84     { 0, NULL }
85 };
86
87 static const value_string vals_transaction_trailer[] = {
88     { 0, "Not last packet" },
89     { 1, "Last packet of message" },
90     { 2, "Last packet of group" },
91     { 3, "Re-assembly not supported" },
92     { 0, NULL }
93 };
94
95 static const value_string vals_version[] = {
96     { 0, "Current" },
97     { 1, "Undefined" },
98     { 2, "Undefined" },
99     { 3, "Undefined" },
100     { 0, NULL }
101 };
102
103 static const value_string vals_abort_type[] = {
104     { 0, "Provider" },
105     { 1, "User (WSP)" },
106     { 0, NULL }
107 };
108
109 static const value_string vals_abort_reason_provider[] = {
110     { 0x00, "Unknown" },
111     { 0x01, "Protocol Error" },
112     { 0x02, "Invalid TID" },
113     { 0x03, "Not Implemented Class 2" },
114     { 0x04, "Not Implemented SAR" },
115     { 0x05, "Not Implemented User Acknowledgement" },
116     { 0x06, "WTP Version Zero" },
117     { 0x07, "Capacity Temporarily Exceeded" },
118     { 0x08, "No Response" },
119     { 0x09, "Message Too Large" },
120     { 0x00, NULL }
121 };
122
123 static const value_string vals_transaction_classes[] = {
124     { 0x00, "Unreliable Invoke without Result" },
125     { 0x01, "Reliable Invoke without Result" },
126     { 0x02, "Reliable Invoke with Reliable Result" },
127     { 0x00, NULL }
128 };
129
130 static const value_string vals_tpi_type[] = {
131     { 0x00, "Error" },
132     { 0x01, "Info" },
133     { 0x02, "Option" },
134     { 0x03, "Packet sequence number" },
135     { 0x04, "SDU boundary" },
136     { 0x05, "Frame boundary" },
137     { 0x00, NULL }
138 };
139
140 static const value_string vals_tpi_opt[] = {
141     { 0x01, "Maximum receive unit" },
142     { 0x02, "Total message size" },
143     { 0x03, "Delay transmission timer" },
144     { 0x04, "Maximum group" },
145     { 0x05, "Current TID" },
146     { 0x06, "No cached TID" },
147     { 0x00, NULL }
148 };
149
150 /* File scoped variables for the protocol and registered fields */
151 static int proto_wtp                            = HF_EMPTY;
152
153 /* These fields used by fixed part of header */
154 static int hf_wtp_header_sub_pdu_size           = HF_EMPTY;
155 static int hf_wtp_header_flag_continue          = HF_EMPTY;
156 static int hf_wtp_header_pdu_type               = HF_EMPTY;
157 static int hf_wtp_header_flag_Trailer           = HF_EMPTY;
158 static int hf_wtp_header_flag_RID               = HF_EMPTY;
159 static int hf_wtp_header_flag_TID               = HF_EMPTY;
160 static int hf_wtp_header_flag_TID_response      = HF_EMPTY;
161
162 /* These fields used by Invoke packets */
163 static int hf_wtp_header_Inv_version            = HF_EMPTY;
164 static int hf_wtp_header_Inv_flag_TIDNew        = HF_EMPTY;
165 static int hf_wtp_header_Inv_flag_UP            = HF_EMPTY;
166 static int hf_wtp_header_Inv_Reserved           = HF_EMPTY;
167 static int hf_wtp_header_Inv_TransactionClass   = HF_EMPTY;
168
169
170 static int hf_wtp_header_variable_part          = HF_EMPTY;
171 static int hf_wtp_data                          = HF_EMPTY;
172
173 static int hf_wtp_tpi_type                      = HF_EMPTY;
174 static int hf_wtp_tpi_psn                       = HF_EMPTY;
175 static int hf_wtp_tpi_opt                       = HF_EMPTY;
176 static int hf_wtp_tpi_optval                    = HF_EMPTY;
177 static int hf_wtp_tpi_info                      = HF_EMPTY;
178
179 static int hf_wtp_header_Ack_flag_TVETOK        = HF_EMPTY;
180 static int hf_wtp_header_Abort_type             = HF_EMPTY;
181 static int hf_wtp_header_Abort_reason_provider  = HF_EMPTY;
182 static int hf_wtp_header_Abort_reason_user      = HF_EMPTY;
183 static int hf_wtp_header_sequence_number        = HF_EMPTY;
184 static int hf_wtp_header_missing_packets        = HF_EMPTY;
185
186 /* These fields used when reassembling WTP fragments */
187 static int hf_wtp_fragments                     = HF_EMPTY;
188 static int hf_wtp_fragment                      = HF_EMPTY;
189 static int hf_wtp_fragment_overlap              = HF_EMPTY;
190 static int hf_wtp_fragment_overlap_conflict     = HF_EMPTY;
191 static int hf_wtp_fragment_multiple_tails       = HF_EMPTY;
192 static int hf_wtp_fragment_too_long_fragment    = HF_EMPTY;
193 static int hf_wtp_fragment_error                = HF_EMPTY;
194 static int hf_wtp_reassembled_in                = HF_EMPTY;
195 static int hf_wtp_reassembled_length            = HF_EMPTY;
196
197 /* Initialize the subtree pointers */
198 static gint ett_wtp                             = ETT_EMPTY;
199 static gint ett_wtp_sub_pdu_tree        = ETT_EMPTY;
200 static gint ett_header                          = ETT_EMPTY;
201 static gint ett_tpilist                         = ETT_EMPTY;
202 static gint ett_wsp_fragments                   = ETT_EMPTY;
203 static gint ett_wtp_fragment                    = ETT_EMPTY;
204
205 static const fragment_items wtp_frag_items = {
206     &ett_wtp_fragment,
207     &ett_wsp_fragments,
208     &hf_wtp_fragments,
209     &hf_wtp_fragment,
210     &hf_wtp_fragment_overlap,
211     &hf_wtp_fragment_overlap_conflict,
212     &hf_wtp_fragment_multiple_tails,
213     &hf_wtp_fragment_too_long_fragment,
214     &hf_wtp_fragment_error,
215     &hf_wtp_reassembled_in,
216     &hf_wtp_reassembled_length,
217     "fragments"
218 };
219
220 /* Handle for WSP dissector */
221 static dissector_handle_t wsp_handle;
222
223 /*
224  * reassembly of WSP
225  */
226 static GHashTable       *wtp_fragment_table = NULL;
227
228 static void
229 wtp_defragment_init(void)
230 {
231     fragment_table_init(&wtp_fragment_table);
232 }
233
234 /*
235  * Extract some bitfields
236  */
237 #define pdu_type(octet)                 (((octet) >> 3) & 0x0F) /* Note pdu type must not be 0x00 */
238 #define transaction_class(octet)        ((octet) & 0x03)        /* ......XX */
239 #define transmission_trailer(octet)     (((octet) >> 1) & 0x01) /* ......X. */
240
241 static char retransmission_indicator(unsigned char octet)
242 {
243     switch (pdu_type(octet)) {
244         case INVOKE:
245         case RESULT:
246         case ACK:
247         case SEGMENTED_INVOKE:
248         case SEGMENTED_RESULT:
249         case NEGATIVE_ACK:
250             return octet & 0x01;        /* .......X */
251         default:
252             return 0;
253     }
254 }
255
256 /*
257  * dissect a TPI
258  */
259 static void
260 wtp_handle_tpi(proto_tree *tree, tvbuff_t *tvb)
261 {
262     int                  offset = 0;
263     unsigned char        tByte;
264     unsigned char        tType;
265     unsigned char        tLen;
266     proto_item          *subTree = NULL;
267
268     tByte = tvb_get_guint8(tvb, offset++);
269     tType = (tByte & 0x78) >> 3;
270     if (tByte & 0x04)                           /* Long TPI     */
271         tLen = tvb_get_guint8(tvb, offset++);
272     else
273         tLen = tByte & 0x03;
274     subTree = proto_tree_add_uint(tree, hf_wtp_tpi_type,
275                                   tvb, 0, tvb_length(tvb), tType);
276     proto_item_add_subtree(subTree, ett_tpilist);
277     switch (tType) {
278         case 0x00:                      /* Error*/
279             /* \todo    */
280             break;
281         case 0x01:                      /* Info */
282             /* Beware, untested case here       */
283             proto_tree_add_item(subTree, hf_wtp_tpi_info,
284                                 tvb, offset, tLen, bo_little_endian);
285             break;
286         case 0x02:                      /* Option       */
287             proto_tree_add_item(subTree, hf_wtp_tpi_opt,
288                                 tvb, offset++, 1, bo_little_endian);
289             proto_tree_add_item(subTree, hf_wtp_tpi_optval,
290                                 tvb, offset, tLen - 1, bo_little_endian);
291             break;
292         case 0x03:                      /* PSN  */
293             proto_tree_add_item(subTree, hf_wtp_tpi_psn,
294                                 tvb, offset, 1, bo_little_endian);
295             break;
296         case 0x04:                      /* SDU boundary */
297             /* \todo    */
298             break;
299         case 0x05:                      /* Frame boundary       */
300             /* \todo    */
301             break;
302         default:
303             break;
304     }
305 }
306
307 /* Code to actually dissect the packets */
308 static void
309 dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
310 {
311     char *szInfo;
312     int                 offCur          = 0;   /* current offset from start of WTP data */
313     gint                returned_length, str_index = 0;
314
315     unsigned char       b0;
316
317     /* continuation flag */
318     unsigned char       fCon;                   /* Continue flag        */
319     unsigned char       fRID;                   /* Re-transmission indicator*/
320     unsigned char       fTTR = '\0';            /* Transmission trailer */
321     guint               cbHeader        = 0;    /* Fixed header length  */
322     guint               vHeader         = 0;    /* Variable header length*/
323     int                 abortType       = 0;
324
325     /* Set up structures we'll need to add the protocol subtree and manage it */
326     proto_item          *ti = NULL;
327     proto_tree          *wtp_tree = NULL;
328
329     char                pdut;
330     char                clsTransaction = 3;
331     int                 numMissing = 0;         /* Number of missing packets in a negative ack */
332     int                 i;
333     tvbuff_t            *wsp_tvb = NULL;
334     guint8              psn = 0;                /* Packet sequence number*/
335     guint16             TID = 0;                /* Transaction-Id       */
336     int                 dataOffset;
337     gint                dataLen;
338
339 #define SZINFO_SIZE 256
340     szInfo=ep_alloc(SZINFO_SIZE);
341
342     b0 = tvb_get_guint8 (tvb, offCur + 0);
343     /* Discover Concatenated PDUs */
344     if (b0 == 0) {
345         guint   c_fieldlen = 0;         /* Length of length-field       */
346         guint   c_pdulen = 0;           /* Length of conc. PDU  */
347
348         if (tree) {
349             ti = proto_tree_add_item(tree, proto_wtp,
350                                     tvb, offCur, 1, bo_little_endian);
351             wtp_tree = proto_item_add_subtree(ti, ett_wtp_sub_pdu_tree);
352                 proto_item_append_text(ti, ", PDU concatenation");
353         }
354         offCur = 1;
355         i = 1;
356         while (offCur < (int) tvb_reported_length(tvb)) {
357             tvbuff_t *wtp_tvb;
358             /* The length of an embedded WTP PDU is coded as either:
359              *  - a 7-bit value contained in one octet with highest bit == 0.
360              *  - a 15-bit value contained in two octets (little endian)
361              *    if the 1st octet has its highest bit == 1.
362              * This means that this is NOT encoded as an uintvar-integer!!!
363              */
364             b0 = tvb_get_guint8(tvb, offCur + 0);
365             if (b0 & 0x80) {
366                 c_fieldlen = 2;
367                 c_pdulen = ((b0 & 0x7f) << 8) | tvb_get_guint8(tvb, offCur + 1);
368             } else {
369                 c_fieldlen = 1;
370                 c_pdulen = b0;
371             }
372             if (tree) {
373                 proto_tree_add_uint(wtp_tree, hf_wtp_header_sub_pdu_size,
374                                     tvb, offCur, c_fieldlen, c_pdulen);
375             }
376             if (i > 1) {
377                 col_append_str(pinfo->cinfo, COL_INFO, ", ");
378             }
379             /* Skip the length field for the WTP sub-tvb */
380             wtp_tvb = tvb_new_subset(tvb, offCur + c_fieldlen, c_pdulen, c_pdulen);
381             dissect_wtp_common(wtp_tvb, pinfo, wtp_tree);
382             offCur += c_fieldlen + c_pdulen;
383             i++;
384         }
385         if (tree) {
386                 proto_item_append_text(ti, ", PDU count: %u", i);
387         }
388         return;
389     }
390     /* No concatenation */
391     fCon = b0 & 0x80;
392     fRID = retransmission_indicator(b0);
393     pdut = pdu_type(b0);
394
395 #ifdef DEBUG
396         printf("WTP packet %u: tree = %p, pdu = %s (%u) length: %u\n",
397                         pinfo->fd->num, tree,
398                         val_to_str(pdut, vals_wtp_pdu_type, "Unknown PDU type 0x%x"),
399                         pdut, tvb_length(tvb));
400 #endif
401
402     /* Develop the string to put in the Info column */
403     returned_length =  g_snprintf(szInfo, SZINFO_SIZE, "WTP %s",
404                     val_to_str(pdut, vals_wtp_pdu_type, "Unknown PDU type 0x%x"));
405     str_index += MIN(returned_length, SZINFO_SIZE-str_index);
406
407     switch (pdut) {
408         case INVOKE:
409             fTTR = transmission_trailer(b0);
410             TID = tvb_get_ntohs(tvb, offCur + 1);
411             psn = 0;
412             clsTransaction = transaction_class(tvb_get_guint8(tvb, offCur + 3));
413             returned_length = g_snprintf(&szInfo[str_index], SZINFO_SIZE-str_index,
414                 " Class %d", clsTransaction);
415             str_index += MIN(returned_length, SZINFO_SIZE-str_index);
416             cbHeader = 4;
417             break;
418
419         case SEGMENTED_INVOKE:
420         case SEGMENTED_RESULT:
421             fTTR = transmission_trailer(b0);
422             TID = tvb_get_ntohs(tvb, offCur + 1);
423             psn = tvb_get_guint8(tvb, offCur + 3);
424             if (psn != 0) {
425                 returned_length = g_snprintf(&szInfo[str_index], SZINFO_SIZE-str_index,
426                         " (%u)", psn);
427                 str_index += MIN(returned_length, SZINFO_SIZE-str_index);
428             }
429             cbHeader = 4;
430             break;
431
432         case ABORT:
433             cbHeader = 4;
434             break;
435
436         case RESULT:
437             fTTR = transmission_trailer(b0);
438             TID = tvb_get_ntohs(tvb, offCur + 1);
439             psn = 0;
440             cbHeader = 3;
441             break;
442
443         case ACK:
444             cbHeader = 3;
445             break;
446
447         case NEGATIVE_ACK:
448             /* Variable number of missing packets */
449             numMissing = tvb_get_guint8(tvb, offCur + 3);
450             cbHeader = numMissing + 4;
451             break;
452
453         default:
454             break;
455     };
456     if (fRID) {
457         returned_length = g_snprintf(&szInfo[str_index], SZINFO_SIZE-str_index, " R" );
458         str_index += MIN(returned_length, SZINFO_SIZE-str_index);
459     };
460     /* In the interest of speed, if "tree" is NULL, don't do any work not
461        necessary to generate protocol tree items. */
462     if (tree) {
463 #ifdef DEBUG
464         fprintf(stderr, "dissect_wtp: cbHeader = %d\n", cbHeader);
465 #endif
466         /* NOTE - Length will be set when we process the TPI */
467         ti = proto_tree_add_item(tree, proto_wtp, tvb, offCur, 0, bo_little_endian);
468 #ifdef DEBUG
469         fprintf(stderr, "dissect_wtp: (7) Returned from proto_tree_add_item\n");
470 #endif
471         wtp_tree = proto_item_add_subtree(ti, ett_wtp);
472
473 /* Code to process the packet goes here */
474 #ifdef DEBUG
475         fprintf(stderr, "dissect_wtp: cbHeader = %d\n", cbHeader);
476         fprintf(stderr, "dissect_wtp: offCur = %d\n", offCur);
477 #endif
478         /* Add common items: only CON and PDU Type */
479         proto_tree_add_item(
480                         wtp_tree,                       /* tree */
481                         hf_wtp_header_flag_continue,    /* id */
482                         tvb,
483                         offCur,                         /* start of highlight */
484                         1,                              /* length of highlight*/
485                         b0                              /* value */
486              );
487         proto_tree_add_item(wtp_tree, hf_wtp_header_pdu_type, tvb, offCur, 1, bo_little_endian);
488
489         switch(pdut) {
490             case INVOKE:
491                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian);
492                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian);
493                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian);
494                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
495
496                 proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_version , tvb, offCur + 3, 1, bo_little_endian);
497                 proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_flag_TIDNew, tvb, offCur + 3, 1, bo_little_endian);
498                 proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_flag_UP, tvb, offCur + 3, 1, bo_little_endian);
499                 proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_Reserved, tvb, offCur + 3, 1, bo_little_endian);
500                 proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_TransactionClass, tvb, offCur + 3, 1, bo_little_endian);
501                 proto_item_append_text(ti,
502                                 ", PDU: Invoke (%u)"
503                                 ", Transaction Class: %s (%u)",
504                                 INVOKE,
505                                 val_to_str(clsTransaction, vals_transaction_classes, "Undefined"),
506                                 clsTransaction);
507                 break;
508
509             case RESULT:
510                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian);
511                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian);
512                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian);
513                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
514                 proto_item_append_text(ti, ", PDU: Result (%u)", RESULT);
515                 break;
516
517             case ACK:
518                 proto_tree_add_item(wtp_tree, hf_wtp_header_Ack_flag_TVETOK, tvb, offCur, 1, bo_big_endian);
519
520                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian);
521                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian);
522                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
523                 proto_item_append_text(ti, ", PDU: ACK (%u)", ACK);
524                 break;
525
526             case ABORT:
527                 abortType = tvb_get_guint8 (tvb, offCur) & 0x07;
528                 proto_tree_add_item(wtp_tree, hf_wtp_header_Abort_type , tvb, offCur , 1, bo_little_endian);
529                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian);
530                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
531
532                 if (abortType == PROVIDER)
533                 {
534                         guint8 reason = tvb_get_guint8(tvb, offCur + 3);
535                     proto_tree_add_item( wtp_tree, hf_wtp_header_Abort_reason_provider , tvb, offCur + 3 , 1, bo_little_endian);
536                         proto_item_append_text(ti,
537                                         ", PDU: Abort (%u)"
538                                         ", Type: Provider (%u)"
539                                         ", Reason: %s (%u)",
540                                         ABORT,
541                                         PROVIDER,
542                                         val_to_str(reason, vals_abort_reason_provider, "Undefined"),
543                                         reason);
544                 }
545                 else if (abortType == USER)
546                 {
547                         guint8 reason = tvb_get_guint8(tvb, offCur + 3);
548                     proto_tree_add_item(wtp_tree, hf_wtp_header_Abort_reason_user , tvb, offCur + 3 , 1, bo_little_endian);
549                         proto_item_append_text(ti,
550                                         ", PDU: Abort (%u)"
551                                         ", Type: User (%u)"
552                                         ", Reason: %s (%u)",
553                                         ABORT,
554                                         PROVIDER,
555                                         val_to_str_ext_const(reason, &vals_wsp_reason_codes_ext, "Undefined"),
556                                         reason);
557                 }
558                 break;
559
560             case SEGMENTED_INVOKE:
561                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian);
562                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian);
563                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian);
564                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
565
566                 proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, bo_little_endian);
567                 proto_item_append_text(ti,
568                                 ", PDU: Segmented Invoke (%u)"
569                                 ", Packet Sequence Number: %u",
570                                 SEGMENTED_INVOKE, psn);
571                 break;
572
573             case SEGMENTED_RESULT:
574                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, bo_little_endian);
575                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian);
576                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian);
577                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
578
579                 proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, bo_little_endian);
580                 proto_item_append_text(ti,
581                                 ", PDU: Segmented Result (%u)"
582                                 ", Packet Sequence Number: %u",
583                                 SEGMENTED_RESULT, psn);
584                 break;
585
586             case NEGATIVE_ACK:
587                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian);
588                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian);
589                 proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
590
591                 proto_tree_add_item(wtp_tree, hf_wtp_header_missing_packets , tvb, offCur + 3, 1, bo_little_endian);
592                 /* Iterate through missing packets */
593                 for (i = 0; i < numMissing; i++)
594                 {
595                     proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number, tvb, offCur + 4 + i, 1, bo_little_endian);
596                 }
597                 proto_item_append_text(ti,
598                                 ", PDU: Negative Ack (%u)"
599                                 ", Missing Packets: %u",
600                                 NEGATIVE_ACK, numMissing);
601                 break;
602
603             default:
604                 break;
605         };
606         if (fRID) {
607                 proto_item_append_text(ti, ", Retransmission");
608         }
609     } else { /* tree is NULL */
610 #ifdef DEBUG
611         fprintf(stderr, "dissect_wtp: (4) tree was %p\n", tree);
612 #endif
613     }
614         /* Process the variable part */
615         if (fCon) {                     /* Now, analyze variable part   */
616             unsigned char        tCon;
617             unsigned char        tByte;
618             unsigned char        tpiLen;
619             tvbuff_t            *tmp_tvb;
620
621             vHeader = 0;                /* Start scan all over  */
622
623             do {
624                 tByte = tvb_get_guint8(tvb, offCur + cbHeader + vHeader);
625                 tCon = tByte & 0x80;
626                 if (tByte & 0x04)       /* Long TPI     */
627                     tpiLen = 2 + tvb_get_guint8(tvb,
628                                             offCur + cbHeader + vHeader + 1);
629                 else
630                     tpiLen = 1 + (tByte & 0x03);
631                 if (tree)
632                 {
633                 tmp_tvb = tvb_new_subset(tvb, offCur + cbHeader + vHeader,
634                                         tpiLen, tpiLen);
635                 wtp_handle_tpi(wtp_tree, tmp_tvb);
636                 }
637                 vHeader += tpiLen;
638             } while (tCon);
639         } else {
640                 /* There is no variable part */
641         }       /* End of variable part of header */
642
643         /* Set the length of the WTP protocol part now we know the length of the
644          * fixed and variable WTP headers */
645         if (tree)
646         proto_item_set_len(ti, cbHeader + vHeader);
647
648 #ifdef DEBUG
649     fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );
650 #endif
651
652     /*
653      * Any remaining data ought to be WSP data (if not WTP ACK, NACK
654      * or ABORT pdu), so, if we have any remaining data, and it's
655      * not an ACK, NACK, or ABORT PDU, hand it off (defragmented) to the
656      * WSP dissector.
657      * Note that the last packet of a fragmented WTP message needn't
658      * contain any data, so we allow payloadless packets to be
659      * reassembled.  (XXX - does the reassembly code handle this
660      * for packets other than the last packet?)
661      *
662          * Try calling a subdissector only if:
663          *      - The WTP payload is ressembled in this very packet,
664          *      - The WTP payload is not fragmented across packets.
665          */
666     dataOffset = offCur + cbHeader + vHeader;
667     dataLen = tvb_reported_length_remaining(tvb, dataOffset);
668     if ((dataLen >= 0) &&
669                         ! ((pdut==ACK) || (pdut==NEGATIVE_ACK) || (pdut==ABORT)))
670     {
671                 /* Try to reassemble if needed, and hand over to WSP
672                  * A fragmented WTP packet is either:
673                  *      - An INVOKE with fTTR (transmission trailer) not set,
674                  *      - a SEGMENTED_INVOKE,
675                  *      - A RESULT with fTTR (transmission trailer) not set,
676                  *      - a SEGMENTED_RESULT.
677                  */
678                 if ( ( (pdut == SEGMENTED_INVOKE) || (pdut == SEGMENTED_RESULT)
679                                 || ( ((pdut == INVOKE) || (pdut == RESULT)) && (!fTTR) )
680                         ) && tvb_bytes_exist(tvb, dataOffset, dataLen) )
681                 {
682                         /* Try reassembling fragments */
683                         fragment_data *fd_wtp = NULL;
684                         guint32 reassembled_in = 0;
685                         gboolean save_fragmented = pinfo->fragmented;
686
687                         pinfo->fragmented = TRUE;
688                         fd_wtp = fragment_add_seq(tvb, dataOffset, pinfo, TID,
689                                         wtp_fragment_table, psn, dataLen, !fTTR);
690                         /* XXX - fragment_add_seq() yields NULL unless Wireshark knows
691                          * that the packet is part of a reassembled whole. This means
692                          * that fd_wtp will be NULL as long as Wireshark did not encounter
693                          * (and process) the packet containing the last fragment.
694                          * This implies that Wireshark needs two passes over the data for
695                          * correct reassembly. At the first pass, a capture containing
696                          * three fragments plus a retransmssion of the last fragment
697                          * will progressively show:
698                          *
699                          *              Packet 1: (Unreassembled fragment 1)
700                          *              Packet 2: (Unreassembled fragment 2)
701                          *              Packet 3: (Reassembled WTP)
702                          *              Packet 4: (WTP payload reassembled in packet 3)
703                          *
704                          * However at subsequent evaluation (e.g., by applying a display
705                          * filter) the packet summary will show:
706                          *
707                          *              Packet 1: (WTP payload reassembled in packet 3)
708                          *              Packet 2: (WTP payload reassembled in packet 3)
709                          *              Packet 3: (Reassembled WTP)
710                          *              Packet 4: (WTP payload reassembled in packet 3)
711                          *
712                          * This is important to know, and also affects read filters!
713                          */
714                         wsp_tvb = process_reassembled_data(tvb, dataOffset, pinfo,
715                                         "Reassembled WTP", fd_wtp, &wtp_frag_items,
716                                         NULL, wtp_tree);
717 #ifdef DEBUG
718                         printf("WTP: Packet %u %s -> %d: wsp_tvb = %p, fd_wtp = %p, frame = %u\n",
719                                         pinfo->fd->num,
720                                         fd_wtp ? "Reassembled" : "Not reassembled",
721                                         fd_wtp ? fd_wtp->reassembled_in : -1,
722                                         wsp_tvb,
723                                         fd_wtp
724                                         );
725 #endif
726                         if (fd_wtp) {
727                                 /* Reassembled */
728                                 reassembled_in = fd_wtp->reassembled_in;
729                                 if (pinfo->fd->num == reassembled_in) {
730                                         /* Reassembled in this very packet:
731                                          * We can safely hand the tvb to the WSP dissector */
732                                         call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
733                                 } else {
734                                         /* Not reassembled in this packet */
735                                         if (check_col(pinfo->cinfo, COL_INFO)) {
736                                                 col_append_fstr(pinfo->cinfo, COL_INFO,
737                                                                 "%s (WTP payload reassembled in packet %u)",
738                                                                 szInfo, fd_wtp->reassembled_in);
739                                         }
740                                         if (tree) {
741                                                 proto_tree_add_text(wtp_tree, tvb, dataOffset, -1,
742                                                                 "Payload");
743                                         }
744                                 }
745                         } else {
746                                 /* Not reassembled yet, or not reassembled at all */
747                                 if (check_col(pinfo->cinfo, COL_INFO)) {
748                                         col_append_fstr(pinfo->cinfo, COL_INFO,
749                                                                 "%s (Unreassembled fragment %u)",
750                                                                 szInfo, psn);
751                                 }
752                                 if (tree) {
753                                         proto_tree_add_text(wtp_tree, tvb, dataOffset, -1,
754                                                         "Payload");
755                                 }
756                         }
757                         /* Now reset fragmentation information in pinfo */
758                         pinfo->fragmented = save_fragmented;
759                 }
760                 else if ( ((pdut == INVOKE) || (pdut == RESULT)) && (fTTR) )
761                 {
762                         /* Non-fragmented payload */
763                         wsp_tvb = tvb_new_subset_remaining(tvb, dataOffset);
764                         /* We can safely hand the tvb to the WSP dissector */
765                         call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
766                 }
767                 else
768                 {
769                         /* Nothing to hand to subdissector */
770                         if (check_col(pinfo->cinfo, COL_INFO))
771                                 col_append_str(pinfo->cinfo, COL_INFO, szInfo);
772                 }
773         }
774         else
775         {
776                 /* Nothing to hand to subdissector */
777                 if (check_col(pinfo->cinfo, COL_INFO))
778                         col_append_str(pinfo->cinfo, COL_INFO, szInfo);
779         }
780 }
781
782 /*
783  * Called directly from UDP.
784  * Put "WTP+WSP" into the "Protocol" column.
785  */
786 static void
787 dissect_wtp_fromudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
788 {
789     col_set_str(pinfo->cinfo, COL_PROTOCOL, "WTP+WSP");
790     col_clear(pinfo->cinfo, COL_INFO);
791
792     dissect_wtp_common(tvb, pinfo, tree);
793 }
794
795 /*
796  * Called from a higher-level WAP dissector, presumably WTLS.
797  * Put "WTLS+WSP+WTP" to the "Protocol" column.
798  *
799  * XXX - is this supposed to be called from WTLS?  If so, we're not
800  * calling it....
801  *
802  * XXX - can this be called from any other dissector?
803  */
804 static void
805 dissect_wtp_fromwtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
806 {
807     col_set_str(pinfo->cinfo, COL_PROTOCOL, "WTLS+WTP+WSP");
808     col_clear(pinfo->cinfo, COL_INFO);
809
810     dissect_wtp_common(tvb, pinfo, tree);
811 }
812
813 /* Register the protocol with Wireshark */
814 void
815 proto_register_wtp(void)
816 {
817
818     /* Setup list of header fields */
819     static hf_register_info hf[] = {
820         { &hf_wtp_header_sub_pdu_size,
821             {   "Sub PDU size",
822                 "wtp.sub_pdu_size",
823                 FT_UINT16, BASE_DEC, NULL, 0x0,
824                 "Size of Sub-PDU (bytes)", HFILL
825             }
826         },
827         { &hf_wtp_header_flag_continue,
828             {   "Continue Flag",
829                 "wtp.continue_flag",
830                 FT_BOOLEAN, 8, TFS( &continue_truth ), 0x80,
831                 NULL, HFILL
832             }
833         },
834         { &hf_wtp_header_pdu_type,
835             {   "PDU Type",
836                 "wtp.pdu_type",
837                 FT_UINT8, BASE_HEX, VALS( vals_wtp_pdu_type ), 0x78,
838                 NULL, HFILL
839             }
840         },
841         { &hf_wtp_header_flag_Trailer,
842             {   "Trailer Flags",
843                 "wtp.trailer_flags",
844                 FT_UINT8, BASE_HEX, VALS( vals_transaction_trailer ), 0x06,
845                 NULL, HFILL
846             }
847         },
848         { &hf_wtp_header_flag_RID,
849             {   "Re-transmission Indicator",
850                 "wtp.RID",
851                 FT_BOOLEAN, 8, TFS( &RID_truth ), 0x01,
852                 NULL, HFILL
853             }
854         },
855         { &hf_wtp_header_flag_TID_response,
856             {   "TID Response",
857                 "wtp.TID.response",
858                 FT_BOOLEAN, 16, TFS( &tid_response_truth ), 0x8000,
859                 NULL, HFILL
860             }
861         },
862         { &hf_wtp_header_flag_TID,
863             {   "Transaction ID",
864                 "wtp.TID",
865                 FT_UINT16, BASE_HEX, NULL, 0x7FFF,
866                 NULL, HFILL
867             }
868         },
869         { &hf_wtp_header_Inv_version,
870             {   "Version",
871                 "wtp.header.version",
872                 FT_UINT8, BASE_HEX, VALS( vals_version ), 0xC0,
873                 NULL, HFILL
874             }
875         },
876         { &hf_wtp_header_Inv_flag_TIDNew,
877             {   "TIDNew",
878                 "wtp.header.TIDNew",
879                 FT_BOOLEAN, 8, TFS( &TIDNew_truth ), 0x20,
880                 NULL, HFILL
881             }
882         },
883         { &hf_wtp_header_Inv_flag_UP,
884             {   "U/P flag",
885                 "wtp.header.UP",
886                 FT_BOOLEAN, 8, TFS( &UP_truth ), 0x10,
887                 NULL, HFILL
888             }
889         },
890         { &hf_wtp_header_Inv_Reserved,
891             {   "Reserved",
892                 "wtp.inv.reserved",
893                 FT_UINT8, BASE_HEX, NULL, 0x0C,
894                 NULL, HFILL
895             }
896         },
897         { &hf_wtp_header_Inv_TransactionClass,
898             {   "Transaction Class",
899                 "wtp.inv.transaction_class",
900                 FT_UINT8, BASE_HEX, VALS( vals_transaction_classes ), 0x03,
901                 NULL, HFILL
902             }
903         },
904         { &hf_wtp_header_Ack_flag_TVETOK,
905             {   "Tve/Tok flag",
906                 "wtp.ack.tvetok",
907                 FT_BOOLEAN, 8, TFS( &TVETOK_truth ), 0x04,
908                 NULL, HFILL
909             }
910         },
911         { &hf_wtp_header_Abort_type,
912             {   "Abort Type",
913                 "wtp.abort.type",
914                 FT_UINT8, BASE_HEX, VALS ( vals_abort_type ), 0x07,
915                 NULL, HFILL
916             }
917         },
918         { &hf_wtp_header_Abort_reason_provider,
919             {   "Abort Reason",
920                 "wtp.abort.reason.provider",
921                 FT_UINT8, BASE_HEX, VALS ( vals_abort_reason_provider ), 0x00,
922                 NULL, HFILL
923             }
924         },
925         /* Assume WSP is the user and use its reason codes */
926         { &hf_wtp_header_Abort_reason_user,
927             {   "Abort Reason",
928                 "wtp.abort.reason.user",
929                 FT_UINT8, BASE_HEX|BASE_EXT_STRING, &vals_wsp_reason_codes_ext, 0x00,
930                 NULL, HFILL
931             }
932         },
933         { &hf_wtp_header_sequence_number,
934             {   "Packet Sequence Number",
935                 "wtp.header.sequence",
936                 FT_UINT8, BASE_DEC, NULL, 0x00,
937                 NULL, HFILL
938             }
939         },
940         { &hf_wtp_header_missing_packets,
941             {   "Missing Packets",
942                 "wtp.header.missing_packets",
943                 FT_UINT8, BASE_DEC, NULL, 0x00,
944                 NULL, HFILL
945             }
946         },
947         { &hf_wtp_header_variable_part,
948             {   "Header: Variable part",
949                 "wtp.header_variable_part",
950                 FT_BYTES, BASE_NONE, NULL, 0x0,
951                 "Variable part of the header", HFILL
952             }
953         },
954         { &hf_wtp_data,
955             {   "Data",
956                 "wtp.header_data",
957                 FT_BYTES, BASE_NONE, NULL, 0x0,
958                 NULL, HFILL
959             }
960         },
961         { &hf_wtp_tpi_type,
962             {   "TPI",
963                 "wtp.tpi",
964                 FT_UINT8, BASE_HEX, VALS(vals_tpi_type), 0x00,
965                 "Identification of the Transport Information Item", HFILL
966             }
967         },
968         { &hf_wtp_tpi_psn,
969             {   "Packet sequence number",
970                 "wtp.tpi.psn",
971                 FT_UINT8, BASE_DEC, NULL, 0x00,
972                 "Sequence number of this packet", HFILL
973             }
974         },
975         { &hf_wtp_tpi_opt,
976             {   "Option",
977                 "wtp.tpi.opt",
978                 FT_UINT8, BASE_HEX, VALS(vals_tpi_opt), 0x00,
979                 "The given option for this TPI", HFILL
980             }
981         },
982         { &hf_wtp_tpi_optval,
983             {   "Option Value",
984                 "wtp.tpi.opt.val",
985                 FT_NONE, BASE_NONE, NULL, 0x00,
986                 "The value that is supplied with this option", HFILL
987             }
988         },
989         { &hf_wtp_tpi_info,
990             {   "Information",
991                 "wtp.tpi.info",
992                 FT_NONE, BASE_NONE, NULL, 0x00,
993                 "The information being send by this TPI", HFILL
994             }
995         },
996
997         /* Fragment fields */
998         { &hf_wtp_fragment_overlap,
999             {   "Fragment overlap",
1000                 "wtp.fragment.overlap",
1001                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1002                 "Fragment overlaps with other fragments", HFILL
1003             }
1004         },
1005         { &hf_wtp_fragment_overlap_conflict,
1006             {   "Conflicting data in fragment overlap",
1007                 "wtp.fragment.overlap.conflict",
1008                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1009                 "Overlapping fragments contained conflicting data", HFILL
1010             }
1011         },
1012         { &hf_wtp_fragment_multiple_tails,
1013             {   "Multiple tail fragments found",
1014                 "wtp.fragment.multipletails",
1015                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1016                 "Several tails were found when defragmenting the packet", HFILL
1017             }
1018         },
1019         { &hf_wtp_fragment_too_long_fragment,
1020             {   "Fragment too long",
1021                 "wtp.fragment.toolongfragment",
1022                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1023                 "Fragment contained data past end of packet", HFILL
1024             }
1025         },
1026         { &hf_wtp_fragment_error,
1027             {   "Defragmentation error",
1028                 "wtp.fragment.error",
1029                 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1030                 "Defragmentation error due to illegal fragments", HFILL
1031             }
1032         },
1033         { &hf_wtp_reassembled_in,
1034             {   "Reassembled in",
1035                 "wtp.reassembled.in",
1036                 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1037                 "WTP fragments are reassembled in the given packet", HFILL
1038             }
1039         },
1040         { &hf_wtp_reassembled_length,
1041             {   "Reassembled WTP length",
1042                 "wtp.reassembled.length",
1043                 FT_UINT32, BASE_DEC, NULL, 0x0,
1044                 "The total length of the reassembled payload", HFILL
1045             }
1046         },
1047         { &hf_wtp_fragment,
1048             {   "WTP Fragment",
1049                 "wtp.fragment",
1050                 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1051                 NULL, HFILL
1052             }
1053         },
1054         { &hf_wtp_fragments,
1055             {   "WTP Fragments",
1056                 "wtp.fragments",
1057                 FT_NONE, BASE_NONE, NULL, 0x0,
1058                 NULL, HFILL
1059             }
1060         },
1061     };
1062
1063     /* Setup protocol subtree array */
1064     static gint *ett[] = {
1065         &ett_wtp,
1066         &ett_wtp_sub_pdu_tree,
1067         &ett_header,
1068         &ett_tpilist,
1069         &ett_wsp_fragments,
1070         &ett_wtp_fragment,
1071     };
1072
1073     /* Register the protocol name and description */
1074     proto_wtp = proto_register_protocol(
1075         "Wireless Transaction Protocol",   /* protocol name for use by wireshark */
1076         "WTP",                             /* short version of name */
1077         "wtp"                      /* Abbreviated protocol name, should Match IANA
1078                                             < URL:http://www.iana.org/assignments/port-numbers/ >
1079                                             */
1080     );
1081
1082     /* Required calls to register the header fields and subtrees used */
1083     proto_register_field_array(proto_wtp, hf, array_length(hf));
1084     proto_register_subtree_array(ett, array_length(ett));
1085
1086     register_dissector("wtp-wtls", dissect_wtp_fromwtls, proto_wtp);
1087     register_dissector("wtp-udp", dissect_wtp_fromudp, proto_wtp);
1088     register_init_routine(wtp_defragment_init);
1089 }
1090
1091 void
1092 proto_reg_handoff_wtp(void)
1093 {
1094     dissector_handle_t wtp_fromudp_handle;
1095
1096     /*
1097      * Get a handle for the connection-oriented WSP dissector - if WTP
1098      * PDUs have data, it is WSP.
1099      */
1100     wsp_handle = find_dissector("wsp-co");
1101
1102     wtp_fromudp_handle = find_dissector("wtp-udp");
1103     dissector_add_uint("udp.port", UDP_PORT_WTP_WSP, wtp_fromudp_handle);
1104     dissector_add_uint("gsm-sms-ud.udh.port", UDP_PORT_WTP_WSP, wtp_fromudp_handle);
1105         dissector_add_uint("gsm-sms.udh.port", UDP_PORT_WTP_WSP, wtp_fromudp_handle);
1106 }