3 * Routines to dissect WTP component of WAP traffic.
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * WAP dissector based on original work by Ben Fowler
10 * Updated by Neil Hunter <neil.hunter@energis-squared.com>
11 * WTLS support by Alexandre P. Ferreira (Splice IP)
13 * SPDX-License-Identifier: GPL-2.0-or-later
16 #define WS_LOG_DOMAIN "packet-wtp"
19 #include <wireshark.h>
21 #include <epan/packet.h>
22 #include <epan/reassemble.h>
24 #include <wsutil/array.h>
25 #include "packet-wap.h"
26 #include "packet-wtp.h"
27 #include "packet-wsp.h"
29 void proto_register_wtp(void);
30 void proto_reg_handoff_wtp(void);
32 static const true_false_string continue_truth
= {
37 static const true_false_string RID_truth
= {
42 static const true_false_string TIDNew_truth
= {
47 static const true_false_string tid_response_truth
= {
52 static const true_false_string UP_truth
= {
53 "User Acknowledgement required" ,
54 "User Acknowledgement optional"
57 static const value_string vals_wtp_pdu_type
[] = {
63 { 5, "Segmented Invoke" },
64 { 6, "Segmented Result" },
65 { 7, "Negative Ack" },
69 static const value_string vals_transaction_trailer
[] = {
70 { 0, "Not last packet" },
71 { 1, "Last packet of message" },
72 { 2, "Last packet of group" },
73 { 3, "Re-assembly not supported" },
77 static const value_string vals_version
[] = {
85 static const value_string vals_abort_type
[] = {
91 static const value_string vals_abort_reason_provider
[] = {
93 { 0x01, "Protocol Error" },
94 { 0x02, "Invalid TID" },
95 { 0x03, "Not Implemented Class 2" },
96 { 0x04, "Not Implemented SAR" },
97 { 0x05, "Not Implemented User Acknowledgement" },
98 { 0x06, "WTP Version Zero" },
99 { 0x07, "Capacity Temporarily Exceeded" },
100 { 0x08, "No Response" },
101 { 0x09, "Message Too Large" },
105 static const value_string vals_transaction_classes
[] = {
106 { 0x00, "Unreliable Invoke without Result" },
107 { 0x01, "Reliable Invoke without Result" },
108 { 0x02, "Reliable Invoke with Reliable Result" },
112 static const value_string vals_tpi_type
[] = {
116 { 0x03, "Packet sequence number" },
117 { 0x04, "SDU boundary" },
118 { 0x05, "Frame boundary" },
122 static const value_string vals_tpi_opt
[] = {
123 { 0x01, "Maximum receive unit" },
124 { 0x02, "Total message size" },
125 { 0x03, "Delay transmission timer" },
126 { 0x04, "Maximum group" },
127 { 0x05, "Current TID" },
128 { 0x06, "No cached TID" },
132 /* File scoped variables for the protocol and registered fields */
133 static int proto_wtp
;
135 /* These fields used by fixed part of header */
136 static int hf_wtp_header_sub_pdu_size
;
137 static int hf_wtp_header_flag_continue
;
138 static int hf_wtp_header_pdu_type
;
139 static int hf_wtp_header_flag_Trailer
;
140 static int hf_wtp_header_flag_RID
;
141 static int hf_wtp_header_flag_TID
;
142 static int hf_wtp_header_flag_TID_response
;
144 /* These fields used by Invoke packets */
145 static int hf_wtp_header_Inv_version
;
146 static int hf_wtp_header_Inv_flag_TIDNew
;
147 static int hf_wtp_header_Inv_flag_UP
;
148 static int hf_wtp_header_Inv_Reserved
;
149 static int hf_wtp_header_Inv_TransactionClass
;
151 /* static int hf_wtp_header_variable_part; */
152 /* static int hf_wtp_data; */
154 static int hf_wtp_tpi_type
;
155 static int hf_wtp_tpi_psn
;
156 static int hf_wtp_tpi_opt
;
157 static int hf_wtp_tpi_optval
;
158 static int hf_wtp_tpi_info
;
160 static int hf_wtp_header_Ack_flag_TVETOK
;
161 static int hf_wtp_header_Abort_type
;
162 static int hf_wtp_header_Abort_reason_provider
;
163 static int hf_wtp_header_Abort_reason_user
;
164 static int hf_wtp_header_sequence_number
;
165 static int hf_wtp_header_missing_packets
;
166 static int hf_wtp_payload
;
168 /* These fields used when reassembling WTP fragments */
169 static int hf_wtp_fragments
;
170 static int hf_wtp_fragment
;
171 static int hf_wtp_fragment_overlap
;
172 static int hf_wtp_fragment_overlap_conflict
;
173 static int hf_wtp_fragment_multiple_tails
;
174 static int hf_wtp_fragment_too_long_fragment
;
175 static int hf_wtp_fragment_error
;
176 static int hf_wtp_fragment_count
;
177 static int hf_wtp_reassembled_in
;
178 static int hf_wtp_reassembled_length
;
180 /* Initialize the subtree pointers */
182 static int ett_wtp_sub_pdu_tree
;
183 static int ett_header
;
184 static int ett_tpilist
;
185 static int ett_wsp_fragments
;
186 static int ett_wtp_fragment
;
188 static const fragment_items wtp_frag_items
= {
193 &hf_wtp_fragment_overlap
,
194 &hf_wtp_fragment_overlap_conflict
,
195 &hf_wtp_fragment_multiple_tails
,
196 &hf_wtp_fragment_too_long_fragment
,
197 &hf_wtp_fragment_error
,
198 &hf_wtp_fragment_count
,
199 &hf_wtp_reassembled_in
,
200 &hf_wtp_reassembled_length
,
201 /* Reassembled data field */
206 /* Handle for WSP dissector */
207 static dissector_handle_t wsp_handle
;
208 static dissector_handle_t wtp_fromudp_handle
;
213 static reassembly_table wtp_reassembly_table
;
216 * Extract some bitfields
218 #define pdu_type(octet) (((octet) >> 3) & 0x0F) /* Note pdu type must not be 0x00 */
219 #define transaction_class(octet) ((octet) & 0x03) /* ......XX */
220 #define transmission_trailer(octet) (((octet) >> 1) & 0x01) /* ......X. */
222 static char retransmission_indicator(unsigned char octet
)
224 switch (pdu_type(octet
)) {
228 case SEGMENTED_INVOKE
:
229 case SEGMENTED_RESULT
:
231 return octet
& 0x01; /* .......X */
241 wtp_handle_tpi(proto_tree
*tree
, tvbuff_t
*tvb
)
247 proto_tree
*subTree
= NULL
;
250 tByte
= tvb_get_uint8(tvb
, offset
++);
251 tType
= (tByte
& 0x78) >> 3;
252 if (tByte
& 0x04) /* Long TPI */
253 tLen
= tvb_get_uint8(tvb
, offset
++);
256 pi
= proto_tree_add_uint(tree
, hf_wtp_tpi_type
,
257 tvb
, 0, tvb_captured_length(tvb
), tType
);
258 subTree
= proto_item_add_subtree(pi
, ett_tpilist
);
260 case 0x00: /* Error*/
263 case 0x01: /* Info */
264 /* Beware, untested case here */
265 proto_tree_add_item(subTree
, hf_wtp_tpi_info
,
266 tvb
, offset
, tLen
, ENC_NA
);
268 case 0x02: /* Option */
269 proto_tree_add_item(subTree
, hf_wtp_tpi_opt
,
270 tvb
, offset
++, 1, ENC_LITTLE_ENDIAN
);
271 proto_tree_add_item(subTree
, hf_wtp_tpi_optval
,
272 tvb
, offset
, tLen
- 1, ENC_NA
);
275 proto_tree_add_item(subTree
, hf_wtp_tpi_psn
,
276 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
278 case 0x04: /* SDU boundary */
281 case 0x05: /* Frame boundary */
289 /* Code to actually dissect the packets */
291 // NOLINTNEXTLINE(misc-no-recursion)
292 dissect_wtp_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
295 int offCur
= 0; /* current offset from start of WTP data */
296 int returned_length
, str_index
= 0;
300 /* continuation flag */
301 unsigned char fCon
; /* Continue flag */
302 unsigned char fRID
; /* Re-transmission indicator*/
303 unsigned char fTTR
= '\0'; /* Transmission trailer */
304 unsigned cbHeader
= 0; /* Fixed header length */
305 unsigned vHeader
= 0; /* Variable header length*/
308 /* Set up structures we'll need to add the protocol subtree and manage it */
309 proto_item
*ti
= NULL
;
310 proto_tree
*wtp_tree
= NULL
;
313 char clsTransaction
= 3;
314 int numMissing
= 0; /* Number of missing packets in a negative ack */
316 tvbuff_t
*wsp_tvb
= NULL
;
317 uint8_t psn
= 0; /* Packet sequence number*/
318 uint16_t TID
= 0; /* Transaction-Id */
322 #define SZINFO_SIZE 256
323 szInfo
=(char *)wmem_alloc(pinfo
->pool
, SZINFO_SIZE
);
325 b0
= tvb_get_uint8 (tvb
, offCur
+ 0);
326 /* Discover Concatenated PDUs */
328 unsigned c_fieldlen
= 0; /* Length of length-field */
329 unsigned c_pdulen
= 0; /* Length of conc. PDU */
332 ti
= proto_tree_add_item(tree
, proto_wtp
,
333 tvb
, offCur
, 1, ENC_NA
);
334 wtp_tree
= proto_item_add_subtree(ti
, ett_wtp_sub_pdu_tree
);
335 proto_item_append_text(ti
, ", PDU concatenation");
339 while (offCur
< (int) tvb_reported_length(tvb
)) {
341 /* The length of an embedded WTP PDU is coded as either:
342 * - a 7-bit value contained in one octet with highest bit == 0.
343 * - a 15-bit value contained in two octets (little endian)
344 * if the 1st octet has its highest bit == 1.
345 * This means that this is NOT encoded as an uintvar-integer!!!
347 b0
= tvb_get_uint8(tvb
, offCur
+ 0);
350 c_pdulen
= ((b0
& 0x7f) << 8) | tvb_get_uint8(tvb
, offCur
+ 1);
356 proto_tree_add_uint(wtp_tree
, hf_wtp_header_sub_pdu_size
,
357 tvb
, offCur
, c_fieldlen
, c_pdulen
);
360 col_append_str(pinfo
->cinfo
, COL_INFO
, ", ");
362 /* Skip the length field for the WTP sub-tvb */
363 wtp_tvb
= tvb_new_subset_length(tvb
, offCur
+ c_fieldlen
, c_pdulen
);
364 // We recurse here, but we'll run out of packet before we run out of stack.
365 dissect_wtp_common(wtp_tvb
, pinfo
, wtp_tree
);
366 offCur
+= c_fieldlen
+ c_pdulen
;
370 proto_item_append_text(ti
, ", PDU count: %u", i
);
374 /* No concatenation */
376 fRID
= retransmission_indicator(b0
);
379 ws_debug("WTP packet %u: tree = %p, pdu = %s (%u) length: %u\n",
381 val_to_str(pdut
, vals_wtp_pdu_type
, "Unknown PDU type 0x%x"),
382 pdut
, tvb_captured_length(tvb
));
384 /* Develop the string to put in the Info column */
385 returned_length
= snprintf(szInfo
, SZINFO_SIZE
, "WTP %s",
386 val_to_str(pdut
, vals_wtp_pdu_type
, "Unknown PDU type 0x%x"));
387 str_index
+= MIN(returned_length
, SZINFO_SIZE
-str_index
);
391 fTTR
= transmission_trailer(b0
);
392 TID
= tvb_get_ntohs(tvb
, offCur
+ 1);
394 clsTransaction
= transaction_class(tvb_get_uint8(tvb
, offCur
+ 3));
395 returned_length
= snprintf(&szInfo
[str_index
], SZINFO_SIZE
-str_index
,
396 " Class %d", clsTransaction
);
397 str_index
+= MIN(returned_length
, SZINFO_SIZE
-str_index
);
401 case SEGMENTED_INVOKE
:
402 case SEGMENTED_RESULT
:
403 fTTR
= transmission_trailer(b0
);
404 TID
= tvb_get_ntohs(tvb
, offCur
+ 1);
405 psn
= tvb_get_uint8(tvb
, offCur
+ 3);
407 returned_length
= snprintf(&szInfo
[str_index
], SZINFO_SIZE
-str_index
,
409 str_index
+= MIN(returned_length
, SZINFO_SIZE
-str_index
);
419 fTTR
= transmission_trailer(b0
);
420 TID
= tvb_get_ntohs(tvb
, offCur
+ 1);
430 /* Variable number of missing packets */
431 numMissing
= tvb_get_uint8(tvb
, offCur
+ 3);
432 cbHeader
= numMissing
+ 4;
439 /*returned_length =*/ snprintf(&szInfo
[str_index
], SZINFO_SIZE
-str_index
, " R" );
440 /*str_index += MIN(returned_length, SZINFO_SIZE-str_index);*/
442 /* In the interest of speed, if "tree" is NULL, don't do any work not
443 necessary to generate protocol tree items. */
445 ws_debug("cbHeader = %d", cbHeader
);
446 /* NOTE - Length will be set when we process the TPI */
447 ti
= proto_tree_add_item(tree
, proto_wtp
, tvb
, offCur
, -1, ENC_NA
);
448 ws_debug("(7) Returned from proto_tree_add_item");
449 wtp_tree
= proto_item_add_subtree(ti
, ett_wtp
);
451 /* Code to process the packet goes here */
452 ws_debug("cbHeader=%d offCur=%d", cbHeader
, offCur
);
453 /* Add common items: only CON and PDU Type */
456 hf_wtp_header_flag_continue
, /* id */
458 offCur
, /* start of highlight */
459 1, /* length of highlight*/
462 proto_tree_add_item(wtp_tree
, hf_wtp_header_pdu_type
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
466 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_Trailer
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
467 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_RID
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
468 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID_response
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
469 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
471 proto_tree_add_item(wtp_tree
, hf_wtp_header_Inv_version
, tvb
, offCur
+ 3, 1, ENC_LITTLE_ENDIAN
);
472 proto_tree_add_item(wtp_tree
, hf_wtp_header_Inv_flag_TIDNew
, tvb
, offCur
+ 3, 1, ENC_LITTLE_ENDIAN
);
473 proto_tree_add_item(wtp_tree
, hf_wtp_header_Inv_flag_UP
, tvb
, offCur
+ 3, 1, ENC_LITTLE_ENDIAN
);
474 proto_tree_add_item(wtp_tree
, hf_wtp_header_Inv_Reserved
, tvb
, offCur
+ 3, 1, ENC_LITTLE_ENDIAN
);
475 proto_tree_add_item(wtp_tree
, hf_wtp_header_Inv_TransactionClass
, tvb
, offCur
+ 3, 1, ENC_LITTLE_ENDIAN
);
476 proto_item_append_text(ti
,
478 ", Transaction Class: %s (%u)",
480 val_to_str_const(clsTransaction
, vals_transaction_classes
, "Undefined"),
485 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_Trailer
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
486 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_RID
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
487 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID_response
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
488 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
489 proto_item_append_text(ti
, ", PDU: Result (%u)", RESULT
);
493 proto_tree_add_item(wtp_tree
, hf_wtp_header_Ack_flag_TVETOK
, tvb
, offCur
, 1, ENC_BIG_ENDIAN
);
495 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_RID
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
496 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID_response
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
497 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
498 proto_item_append_text(ti
, ", PDU: ACK (%u)", ACK
);
502 abortType
= tvb_get_uint8 (tvb
, offCur
) & 0x07;
503 proto_tree_add_item(wtp_tree
, hf_wtp_header_Abort_type
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
504 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID_response
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
505 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
507 if (abortType
== PROVIDER
) {
508 uint8_t reason
= tvb_get_uint8(tvb
, offCur
+ 3);
509 proto_tree_add_item( wtp_tree
, hf_wtp_header_Abort_reason_provider
, tvb
, offCur
+ 3 , 1, ENC_LITTLE_ENDIAN
);
510 proto_item_append_text(ti
,
512 ", Type: Provider (%u)"
516 val_to_str_const(reason
, vals_abort_reason_provider
, "Undefined"),
519 else if (abortType
== USER
) {
520 uint8_t reason
= tvb_get_uint8(tvb
, offCur
+ 3);
521 proto_tree_add_item(wtp_tree
, hf_wtp_header_Abort_reason_user
, tvb
, offCur
+ 3 , 1, ENC_LITTLE_ENDIAN
);
522 proto_item_append_text(ti
,
528 val_to_str_ext_const(reason
, &vals_wsp_reason_codes_ext
, "Undefined"),
533 case SEGMENTED_INVOKE
:
534 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_Trailer
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
535 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_RID
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
536 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID_response
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
537 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
539 proto_tree_add_item(wtp_tree
, hf_wtp_header_sequence_number
, tvb
, offCur
+ 3, 1, ENC_LITTLE_ENDIAN
);
540 proto_item_append_text(ti
,
541 ", PDU: Segmented Invoke (%u)"
542 ", Packet Sequence Number: %u",
543 SEGMENTED_INVOKE
, psn
);
546 case SEGMENTED_RESULT
:
547 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_Trailer
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
548 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_RID
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
549 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID_response
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
550 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
552 proto_tree_add_item(wtp_tree
, hf_wtp_header_sequence_number
, tvb
, offCur
+ 3, 1, ENC_LITTLE_ENDIAN
);
553 proto_item_append_text(ti
,
554 ", PDU: Segmented Result (%u)"
555 ", Packet Sequence Number: %u",
556 SEGMENTED_RESULT
, psn
);
560 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_RID
, tvb
, offCur
, 1, ENC_LITTLE_ENDIAN
);
561 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID_response
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
562 proto_tree_add_item(wtp_tree
, hf_wtp_header_flag_TID
, tvb
, offCur
+ 1, 2, ENC_BIG_ENDIAN
);
564 proto_tree_add_item(wtp_tree
, hf_wtp_header_missing_packets
, tvb
, offCur
+ 3, 1, ENC_LITTLE_ENDIAN
);
565 /* Iterate through missing packets */
566 for (i
= 0; i
< numMissing
; i
++)
568 proto_tree_add_item(wtp_tree
, hf_wtp_header_sequence_number
, tvb
, offCur
+ 4 + i
, 1, ENC_LITTLE_ENDIAN
);
570 proto_item_append_text(ti
,
571 ", PDU: Negative Ack (%u)"
572 ", Missing Packets: %u",
573 NEGATIVE_ACK
, numMissing
);
580 proto_item_append_text(ti
, ", Retransmission");
582 } else { /* tree is NULL */
583 ws_debug("(4) tree was %p", tree
);
585 /* Process the variable part */
586 if (fCon
) { /* Now, analyze variable part */
592 vHeader
= 0; /* Start scan all over */
595 tByte
= tvb_get_uint8(tvb
, offCur
+ cbHeader
+ vHeader
);
597 if (tByte
& 0x04) /* Long TPI */
598 tpiLen
= 2 + tvb_get_uint8(tvb
, offCur
+ cbHeader
+ vHeader
+ 1);
600 tpiLen
= 1 + (tByte
& 0x03);
603 tmp_tvb
= tvb_new_subset_length(tvb
, offCur
+ cbHeader
+ vHeader
, tpiLen
);
604 wtp_handle_tpi(wtp_tree
, tmp_tvb
);
609 /* There is no variable part */
610 } /* End of variable part of header */
612 /* Set the length of the WTP protocol part now we know the length of the
613 * fixed and variable WTP headers */
615 proto_item_set_len(ti
, cbHeader
+ vHeader
);
617 ws_debug("cbHeader = %d", cbHeader
);
620 * Any remaining data ought to be WSP data (if not WTP ACK, NACK
621 * or ABORT pdu), so, if we have any remaining data, and it's
622 * not an ACK, NACK, or ABORT PDU, hand it off (defragmented) to the
624 * Note that the last packet of a fragmented WTP message needn't
625 * contain any data, so we allow payloadless packets to be
626 * reassembled. (XXX - does the reassembly code handle this
627 * for packets other than the last packet?)
629 * Try calling a subdissector only if:
630 * - The WTP payload is resembled in this very packet,
631 * - The WTP payload is not fragmented across packets.
633 dataOffset
= offCur
+ cbHeader
+ vHeader
;
634 dataLen
= tvb_reported_length_remaining(tvb
, dataOffset
);
635 if ((dataLen
>= 0) &&
636 ! ((pdut
==ACK
) || (pdut
==NEGATIVE_ACK
) || (pdut
==ABORT
)))
638 /* Try to reassemble if needed, and hand over to WSP
639 * A fragmented WTP packet is either:
640 * - An INVOKE with fTTR (transmission trailer) not set,
641 * - a SEGMENTED_INVOKE,
642 * - A RESULT with fTTR (transmission trailer) not set,
643 * - a SEGMENTED_RESULT.
645 if ( ( (pdut
== SEGMENTED_INVOKE
) || (pdut
== SEGMENTED_RESULT
)
646 || ( ((pdut
== INVOKE
) || (pdut
== RESULT
)) && (!fTTR
) )
647 ) && tvb_bytes_exist(tvb
, dataOffset
, dataLen
) )
649 /* Try reassembling fragments */
650 fragment_head
*fd_wtp
= NULL
;
651 uint32_t reassembled_in
= 0;
652 bool save_fragmented
= pinfo
->fragmented
;
654 pinfo
->fragmented
= true;
655 fd_wtp
= fragment_add_seq(&wtp_reassembly_table
, tvb
, dataOffset
,
656 pinfo
, TID
, NULL
, psn
, dataLen
, !fTTR
, 0);
657 /* XXX - fragment_add_seq() yields NULL unless Wireshark knows
658 * that the packet is part of a reassembled whole. This means
659 * that fd_wtp will be NULL as long as Wireshark did not encounter
660 * (and process) the packet containing the last fragment.
661 * This implies that Wireshark needs two passes over the data for
662 * correct reassembly. At the first pass, a capture containing
663 * three fragments plus a retransmssion of the last fragment
664 * will progressively show:
666 * Packet 1: (Unreassembled fragment 1)
667 * Packet 2: (Unreassembled fragment 2)
668 * Packet 3: (Reassembled WTP)
669 * Packet 4: (WTP payload reassembled in packet 3)
671 * However at subsequent evaluation (e.g., by applying a display
672 * filter) the packet summary will show:
674 * Packet 1: (WTP payload reassembled in packet 3)
675 * Packet 2: (WTP payload reassembled in packet 3)
676 * Packet 3: (Reassembled WTP)
677 * Packet 4: (WTP payload reassembled in packet 3)
679 * This is important to know, and also affects read filters!
681 wsp_tvb
= process_reassembled_data(tvb
, dataOffset
, pinfo
,
682 "Reassembled WTP", fd_wtp
, &wtp_frag_items
,
684 ws_debug("WTP: Packet %u %s -> %d: wsp_tvb = %p, fd_wtp = %p",
686 fd_wtp
? "Reassembled" : "Not reassembled",
687 fd_wtp
? fd_wtp
->reassembled_in
: 0,
693 reassembled_in
= fd_wtp
->reassembled_in
;
694 if (pinfo
->num
== reassembled_in
) {
695 /* Reassembled in this very packet:
696 * We can safely hand the tvb to the WSP dissector */
697 call_dissector(wsp_handle
, wsp_tvb
, pinfo
, tree
);
699 /* Not reassembled in this packet */
700 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
701 "%s (WTP payload reassembled in packet %u)",
702 szInfo
, fd_wtp
->reassembled_in
);
704 proto_tree_add_item(wtp_tree
, hf_wtp_payload
, tvb
, dataOffset
, -1, ENC_NA
);
707 /* Not reassembled yet, or not reassembled at all */
708 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
709 "%s (Unreassembled fragment %u)",
711 proto_tree_add_item(wtp_tree
, hf_wtp_payload
, tvb
, dataOffset
, -1, ENC_NA
);
713 /* Now reset fragmentation information in pinfo */
714 pinfo
->fragmented
= save_fragmented
;
716 else if ( ((pdut
== INVOKE
) || (pdut
== RESULT
)) && (fTTR
) )
718 /* Non-fragmented payload */
719 wsp_tvb
= tvb_new_subset_remaining(tvb
, dataOffset
);
720 /* We can safely hand the tvb to the WSP dissector */
721 call_dissector(wsp_handle
, wsp_tvb
, pinfo
, tree
);
725 /* Nothing to hand to subdissector */
726 col_append_str(pinfo
->cinfo
, COL_INFO
, szInfo
);
731 /* Nothing to hand to subdissector */
732 col_append_str(pinfo
->cinfo
, COL_INFO
, szInfo
);
737 * Called directly from UDP.
738 * Put "WTP+WSP" into the "Protocol" column.
741 dissect_wtp_fromudp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
743 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "WTP+WSP");
744 col_clear(pinfo
->cinfo
, COL_INFO
);
746 dissect_wtp_common(tvb
, pinfo
, tree
);
747 return tvb_captured_length(tvb
);
751 * Called from a higher-level WAP dissector, presumably WTLS.
752 * Put "WTLS+WSP+WTP" to the "Protocol" column.
754 * XXX - is this supposed to be called from WTLS? If so, we're not
757 * XXX - can this be called from any other dissector?
760 dissect_wtp_fromwtls(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
762 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "WTLS+WTP+WSP");
763 col_clear(pinfo
->cinfo
, COL_INFO
);
765 dissect_wtp_common(tvb
, pinfo
, tree
);
766 return tvb_captured_length(tvb
);
769 /* Register the protocol with Wireshark */
771 proto_register_wtp(void)
774 /* Setup list of header fields */
775 static hf_register_info hf
[] = {
776 { &hf_wtp_header_sub_pdu_size
,
777 { "Sub PDU size", "wtp.sub_pdu_size",
778 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
779 "Size of Sub-PDU (bytes)", HFILL
782 { &hf_wtp_header_flag_continue
,
783 { "Continue Flag", "wtp.continue_flag",
784 FT_BOOLEAN
, 8, TFS( &continue_truth
), 0x80,
788 { &hf_wtp_header_pdu_type
,
789 { "PDU Type", "wtp.pdu_type",
790 FT_UINT8
, BASE_HEX
, VALS( vals_wtp_pdu_type
), 0x78,
794 { &hf_wtp_header_flag_Trailer
,
795 { "Trailer Flags", "wtp.trailer_flags",
796 FT_UINT8
, BASE_HEX
, VALS( vals_transaction_trailer
), 0x06,
800 { &hf_wtp_header_flag_RID
,
801 { "Re-transmission Indicator", "wtp.RID",
802 FT_BOOLEAN
, 8, TFS( &RID_truth
), 0x01,
806 { &hf_wtp_header_flag_TID_response
,
807 { "TID Response", "wtp.TID.response",
808 FT_BOOLEAN
, 16, TFS( &tid_response_truth
), 0x8000,
812 { &hf_wtp_header_flag_TID
,
813 { "Transaction ID", "wtp.TID",
814 FT_UINT16
, BASE_HEX
, NULL
, 0x7FFF,
818 { &hf_wtp_header_Inv_version
,
819 { "Version", "wtp.header.version",
820 FT_UINT8
, BASE_HEX
, VALS( vals_version
), 0xC0,
824 { &hf_wtp_header_Inv_flag_TIDNew
,
825 { "TIDNew", "wtp.header.TIDNew",
826 FT_BOOLEAN
, 8, TFS( &TIDNew_truth
), 0x20,
830 { &hf_wtp_header_Inv_flag_UP
,
831 { "U/P flag", "wtp.header.UP",
832 FT_BOOLEAN
, 8, TFS( &UP_truth
), 0x10,
836 { &hf_wtp_header_Inv_Reserved
,
837 { "Reserved", "wtp.inv.reserved",
838 FT_UINT8
, BASE_HEX
, NULL
, 0x0C,
842 { &hf_wtp_header_Inv_TransactionClass
,
843 { "Transaction Class", "wtp.inv.transaction_class",
844 FT_UINT8
, BASE_HEX
, VALS( vals_transaction_classes
), 0x03,
848 { &hf_wtp_header_Ack_flag_TVETOK
,
849 { "Tve/Tok flag", "wtp.ack.tvetok",
850 FT_BOOLEAN
, 8, NULL
, 0x04,
854 { &hf_wtp_header_Abort_type
,
855 { "Abort Type", "wtp.abort.type",
856 FT_UINT8
, BASE_HEX
, VALS ( vals_abort_type
), 0x07,
860 { &hf_wtp_header_Abort_reason_provider
,
861 { "Abort Reason", "wtp.abort.reason.provider",
862 FT_UINT8
, BASE_HEX
, VALS ( vals_abort_reason_provider
), 0x00,
866 /* Assume WSP is the user and use its reason codes */
867 { &hf_wtp_header_Abort_reason_user
,
868 { "Abort Reason", "wtp.abort.reason.user",
869 FT_UINT8
, BASE_HEX
|BASE_EXT_STRING
, &vals_wsp_reason_codes_ext
, 0x00,
873 { &hf_wtp_header_sequence_number
,
874 { "Packet Sequence Number", "wtp.header.sequence",
875 FT_UINT8
, BASE_DEC
, NULL
, 0x00,
879 { &hf_wtp_header_missing_packets
,
880 { "Missing Packets", "wtp.header.missing_packets",
881 FT_UINT8
, BASE_DEC
, NULL
, 0x00,
886 { "Payload", "wtp.payload",
887 FT_BYTES
, BASE_NONE
, NULL
, 0x00,
892 { &hf_wtp_header_variable_part
,
893 { "Header: Variable part", "wtp.header_variable_part",
894 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
895 "Variable part of the header", HFILL
899 { "Data", "wtp.header_data",
900 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
907 FT_UINT8
, BASE_HEX
, VALS(vals_tpi_type
), 0x00,
908 "Identification of the Transport Information Item", HFILL
912 { "Packet sequence number", "wtp.tpi.psn",
913 FT_UINT8
, BASE_DEC
, NULL
, 0x00,
914 "Sequence number of this packet", HFILL
918 { "Option", "wtp.tpi.opt",
919 FT_UINT8
, BASE_HEX
, VALS(vals_tpi_opt
), 0x00,
920 "The given option for this TPI", HFILL
923 { &hf_wtp_tpi_optval
,
924 { "Option Value", "wtp.tpi.opt.val",
925 FT_NONE
, BASE_NONE
, NULL
, 0x00,
926 "The value that is supplied with this option", HFILL
930 { "Information", "wtp.tpi.info",
931 FT_NONE
, BASE_NONE
, NULL
, 0x00,
932 "The information being send by this TPI", HFILL
936 /* Fragment fields */
937 { &hf_wtp_fragment_overlap
,
938 { "Fragment overlap", "wtp.fragment.overlap",
939 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
940 "Fragment overlaps with other fragments", HFILL
943 { &hf_wtp_fragment_overlap_conflict
,
944 { "Conflicting data in fragment overlap", "wtp.fragment.overlap.conflict",
945 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
946 "Overlapping fragments contained conflicting data", HFILL
949 { &hf_wtp_fragment_multiple_tails
,
950 { "Multiple tail fragments found", "wtp.fragment.multipletails",
951 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
952 "Several tails were found when defragmenting the packet", HFILL
955 { &hf_wtp_fragment_too_long_fragment
,
956 { "Fragment too long", "wtp.fragment.toolongfragment",
957 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
958 "Fragment contained data past end of packet", HFILL
961 { &hf_wtp_fragment_error
,
962 { "Defragmentation error", "wtp.fragment.error",
963 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
964 "Defragmentation error due to illegal fragments", HFILL
967 { &hf_wtp_fragment_count
,
968 { "Fragment count", "wtp.fragment.count",
969 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
973 { &hf_wtp_reassembled_in
,
974 { "Reassembled in", "wtp.reassembled.in",
975 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
976 "WTP fragments are reassembled in the given packet", HFILL
979 { &hf_wtp_reassembled_length
,
980 { "Reassembled WTP length", "wtp.reassembled.length",
981 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
982 "The total length of the reassembled payload", HFILL
986 { "WTP Fragment", "wtp.fragment",
987 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
992 { "WTP Fragments", "wtp.fragments",
993 FT_NONE
, BASE_NONE
, NULL
, 0x0,
999 /* Setup protocol subtree array */
1000 static int *ett
[] = {
1002 &ett_wtp_sub_pdu_tree
,
1009 /* Register the protocol name and description */
1010 /* Abbreviated protocol name should Match IANA: https://www.iana.org/assignments/port-numbers/ */
1011 proto_wtp
= proto_register_protocol("Wireless Transaction Protocol", "WTP", "wtp");
1013 /* Required calls to register the header fields and subtrees used */
1014 proto_register_field_array(proto_wtp
, hf
, array_length(hf
));
1015 proto_register_subtree_array(ett
, array_length(ett
));
1017 register_dissector("wtp-wtls", dissect_wtp_fromwtls
, proto_wtp
);
1018 wtp_fromudp_handle
= register_dissector("wtp-udp", dissect_wtp_fromudp
, proto_wtp
);
1019 reassembly_table_register(&wtp_reassembly_table
,
1020 &addresses_reassembly_table_functions
);
1024 proto_reg_handoff_wtp(void)
1027 * Get a handle for the connection-oriented WSP dissector - if WTP
1028 * PDUs have data, it is WSP.
1030 wsp_handle
= find_dissector_add_dependency("wsp-co", proto_wtp
);
1032 dissector_add_uint_with_preference("udp.port", UDP_PORT_WTP_WSP
, wtp_fromudp_handle
);
1033 dissector_add_uint("gsm_sms_ud.udh.port", UDP_PORT_WTP_WSP
, wtp_fromudp_handle
);
1034 dissector_add_uint("gsm_sms.udh.port", UDP_PORT_WTP_WSP
, wtp_fromudp_handle
);
1038 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1043 * indent-tabs-mode: nil
1046 * vi: set shiftwidth=4 tabstop=8 expandtab:
1047 * :indentSize=4:tabSize=8:noTabs=true: