epan/dissectors/pidl/ C99 drsuapi
[wireshark-sm.git] / epan / dissectors / packet-wtp.c
blobc0b0957fc1d6eb79c3e7d019c49bb3b67202b312
1 /* packet-wtp.c
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"
18 #include "config.h"
19 #include <wireshark.h>
21 #include <epan/packet.h>
22 #include <epan/reassemble.h>
23 #include <epan/tfs.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 = {
33 "TPI Present" ,
34 "No TPI"
37 static const true_false_string RID_truth = {
38 "Re-Transmission",
39 "First transmission"
42 static const true_false_string TIDNew_truth = {
43 "TID is new" ,
44 "TID is valid"
47 static const true_false_string tid_response_truth = {
48 "Response" ,
49 "Original"
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[] = {
58 { 0, "Not Allowed" },
59 { 1, "Invoke" },
60 { 2, "Result" },
61 { 3, "Ack" },
62 { 4, "Abort" },
63 { 5, "Segmented Invoke" },
64 { 6, "Segmented Result" },
65 { 7, "Negative Ack" },
66 { 0, NULL }
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" },
74 { 0, NULL }
77 static const value_string vals_version[] = {
78 { 0, "Current" },
79 { 1, "Undefined" },
80 { 2, "Undefined" },
81 { 3, "Undefined" },
82 { 0, NULL }
85 static const value_string vals_abort_type[] = {
86 { 0, "Provider" },
87 { 1, "User (WSP)" },
88 { 0, NULL }
91 static const value_string vals_abort_reason_provider[] = {
92 { 0x00, "Unknown" },
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" },
102 { 0x00, NULL }
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" },
109 { 0x00, NULL }
112 static const value_string vals_tpi_type[] = {
113 { 0x00, "Error" },
114 { 0x01, "Info" },
115 { 0x02, "Option" },
116 { 0x03, "Packet sequence number" },
117 { 0x04, "SDU boundary" },
118 { 0x05, "Frame boundary" },
119 { 0x00, NULL }
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" },
129 { 0x00, NULL }
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 */
181 static int ett_wtp;
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 = {
189 &ett_wtp_fragment,
190 &ett_wsp_fragments,
191 &hf_wtp_fragments,
192 &hf_wtp_fragment,
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 */
202 NULL,
203 "fragments"
206 /* Handle for WSP dissector */
207 static dissector_handle_t wsp_handle;
208 static dissector_handle_t wtp_fromudp_handle;
211 * reassembly of WSP
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)) {
225 case INVOKE:
226 case RESULT:
227 case ACK:
228 case SEGMENTED_INVOKE:
229 case SEGMENTED_RESULT:
230 case NEGATIVE_ACK:
231 return octet & 0x01; /* .......X */
232 default:
233 return 0;
238 * dissect a TPI
240 static void
241 wtp_handle_tpi(proto_tree *tree, tvbuff_t *tvb)
243 int offset = 0;
244 unsigned char tByte;
245 unsigned char tType;
246 unsigned char tLen;
247 proto_tree *subTree = NULL;
248 proto_item *pi;
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++);
254 else
255 tLen = tByte & 0x03;
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);
259 switch (tType) {
260 case 0x00: /* Error*/
261 /* \todo */
262 break;
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);
267 break;
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);
273 break;
274 case 0x03: /* PSN */
275 proto_tree_add_item(subTree, hf_wtp_tpi_psn,
276 tvb, offset, 1, ENC_LITTLE_ENDIAN);
277 break;
278 case 0x04: /* SDU boundary */
279 /* \todo */
280 break;
281 case 0x05: /* Frame boundary */
282 /* \todo */
283 break;
284 default:
285 break;
289 /* Code to actually dissect the packets */
290 static void
291 // NOLINTNEXTLINE(misc-no-recursion)
292 dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
294 char *szInfo;
295 int offCur = 0; /* current offset from start of WTP data */
296 int returned_length, str_index = 0;
298 unsigned char b0;
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*/
306 int abortType = 0;
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;
312 char pdut;
313 char clsTransaction = 3;
314 int numMissing = 0; /* Number of missing packets in a negative ack */
315 int i;
316 tvbuff_t *wsp_tvb = NULL;
317 uint8_t psn = 0; /* Packet sequence number*/
318 uint16_t TID = 0; /* Transaction-Id */
319 int dataOffset;
320 int dataLen;
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 */
327 if (b0 == 0) {
328 unsigned c_fieldlen = 0; /* Length of length-field */
329 unsigned c_pdulen = 0; /* Length of conc. PDU */
331 if (tree) {
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");
337 offCur = 1;
338 i = 1;
339 while (offCur < (int) tvb_reported_length(tvb)) {
340 tvbuff_t *wtp_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);
348 if (b0 & 0x80) {
349 c_fieldlen = 2;
350 c_pdulen = ((b0 & 0x7f) << 8) | tvb_get_uint8(tvb, offCur + 1);
351 } else {
352 c_fieldlen = 1;
353 c_pdulen = b0;
355 if (tree) {
356 proto_tree_add_uint(wtp_tree, hf_wtp_header_sub_pdu_size,
357 tvb, offCur, c_fieldlen, c_pdulen);
359 if (i > 1) {
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;
367 i++;
369 if (tree) {
370 proto_item_append_text(ti, ", PDU count: %u", i);
372 return;
374 /* No concatenation */
375 fCon = b0 & 0x80;
376 fRID = retransmission_indicator(b0);
377 pdut = pdu_type(b0);
379 ws_debug("WTP packet %u: tree = %p, pdu = %s (%u) length: %u\n",
380 pinfo->num, tree,
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);
389 switch (pdut) {
390 case INVOKE:
391 fTTR = transmission_trailer(b0);
392 TID = tvb_get_ntohs(tvb, offCur + 1);
393 psn = 0;
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);
398 cbHeader = 4;
399 break;
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);
406 if (psn != 0) {
407 returned_length = snprintf(&szInfo[str_index], SZINFO_SIZE-str_index,
408 " (%u)", psn);
409 str_index += MIN(returned_length, SZINFO_SIZE-str_index);
411 cbHeader = 4;
412 break;
414 case ABORT:
415 cbHeader = 4;
416 break;
418 case RESULT:
419 fTTR = transmission_trailer(b0);
420 TID = tvb_get_ntohs(tvb, offCur + 1);
421 psn = 0;
422 cbHeader = 3;
423 break;
425 case ACK:
426 cbHeader = 3;
427 break;
429 case NEGATIVE_ACK:
430 /* Variable number of missing packets */
431 numMissing = tvb_get_uint8(tvb, offCur + 3);
432 cbHeader = numMissing + 4;
433 break;
435 default:
436 break;
438 if (fRID) {
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. */
444 if (tree) {
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 */
454 proto_tree_add_item(
455 wtp_tree, /* tree */
456 hf_wtp_header_flag_continue, /* id */
457 tvb,
458 offCur, /* start of highlight */
459 1, /* length of highlight*/
460 b0 /* value */
462 proto_tree_add_item(wtp_tree, hf_wtp_header_pdu_type, tvb, offCur, 1, ENC_LITTLE_ENDIAN);
464 switch(pdut) {
465 case INVOKE:
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,
477 ", PDU: Invoke (%u)"
478 ", Transaction Class: %s (%u)",
479 INVOKE,
480 val_to_str_const(clsTransaction, vals_transaction_classes, "Undefined"),
481 clsTransaction);
482 break;
484 case RESULT:
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);
490 break;
492 case ACK:
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);
499 break;
501 case ABORT:
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,
511 ", PDU: Abort (%u)"
512 ", Type: Provider (%u)"
513 ", Reason: %s (%u)",
514 ABORT,
515 PROVIDER,
516 val_to_str_const(reason, vals_abort_reason_provider, "Undefined"),
517 reason);
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,
523 ", PDU: Abort (%u)"
524 ", Type: User (%u)"
525 ", Reason: %s (%u)",
526 ABORT,
527 PROVIDER,
528 val_to_str_ext_const(reason, &vals_wsp_reason_codes_ext, "Undefined"),
529 reason);
531 break;
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);
544 break;
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);
557 break;
559 case NEGATIVE_ACK:
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);
574 break;
576 default:
577 break;
579 if (fRID) {
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 */
587 uint8_t tCon;
588 uint8_t tByte;
589 unsigned tpiLen;
590 tvbuff_t *tmp_tvb;
592 vHeader = 0; /* Start scan all over */
594 do {
595 tByte = tvb_get_uint8(tvb, offCur + cbHeader + vHeader);
596 tCon = tByte & 0x80;
597 if (tByte & 0x04) /* Long TPI */
598 tpiLen = 2 + tvb_get_uint8(tvb, offCur + cbHeader + vHeader + 1);
599 else
600 tpiLen = 1 + (tByte & 0x03);
601 if (tree)
603 tmp_tvb = tvb_new_subset_length(tvb, offCur + cbHeader + vHeader, tpiLen);
604 wtp_handle_tpi(wtp_tree, tmp_tvb);
606 vHeader += tpiLen;
607 } while (tCon);
608 } else {
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 */
614 if (tree)
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
623 * WSP dissector.
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,
683 NULL, wtp_tree);
684 ws_debug("WTP: Packet %u %s -> %d: wsp_tvb = %p, fd_wtp = %p",
685 pinfo->num,
686 fd_wtp ? "Reassembled" : "Not reassembled",
687 fd_wtp ? fd_wtp->reassembled_in : 0,
688 wsp_tvb,
689 fd_wtp
691 if (fd_wtp) {
692 /* Reassembled */
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);
698 } else {
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);
706 } else {
707 /* Not reassembled yet, or not reassembled at all */
708 col_append_fstr(pinfo->cinfo, COL_INFO,
709 "%s (Unreassembled fragment %u)",
710 szInfo, psn);
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);
723 else
725 /* Nothing to hand to subdissector */
726 col_append_str(pinfo->cinfo, COL_INFO, szInfo);
729 else
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.
740 static int
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
755 * calling it....
757 * XXX - can this be called from any other dissector?
759 static int
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 */
770 void
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,
785 NULL, HFILL
788 { &hf_wtp_header_pdu_type,
789 { "PDU Type", "wtp.pdu_type",
790 FT_UINT8, BASE_HEX, VALS( vals_wtp_pdu_type ), 0x78,
791 NULL, HFILL
794 { &hf_wtp_header_flag_Trailer,
795 { "Trailer Flags", "wtp.trailer_flags",
796 FT_UINT8, BASE_HEX, VALS( vals_transaction_trailer ), 0x06,
797 NULL, HFILL
800 { &hf_wtp_header_flag_RID,
801 { "Re-transmission Indicator", "wtp.RID",
802 FT_BOOLEAN, 8, TFS( &RID_truth ), 0x01,
803 NULL, HFILL
806 { &hf_wtp_header_flag_TID_response,
807 { "TID Response", "wtp.TID.response",
808 FT_BOOLEAN, 16, TFS( &tid_response_truth ), 0x8000,
809 NULL, HFILL
812 { &hf_wtp_header_flag_TID,
813 { "Transaction ID", "wtp.TID",
814 FT_UINT16, BASE_HEX, NULL, 0x7FFF,
815 NULL, HFILL
818 { &hf_wtp_header_Inv_version,
819 { "Version", "wtp.header.version",
820 FT_UINT8, BASE_HEX, VALS( vals_version ), 0xC0,
821 NULL, HFILL
824 { &hf_wtp_header_Inv_flag_TIDNew,
825 { "TIDNew", "wtp.header.TIDNew",
826 FT_BOOLEAN, 8, TFS( &TIDNew_truth ), 0x20,
827 NULL, HFILL
830 { &hf_wtp_header_Inv_flag_UP,
831 { "U/P flag", "wtp.header.UP",
832 FT_BOOLEAN, 8, TFS( &UP_truth ), 0x10,
833 NULL, HFILL
836 { &hf_wtp_header_Inv_Reserved,
837 { "Reserved", "wtp.inv.reserved",
838 FT_UINT8, BASE_HEX, NULL, 0x0C,
839 NULL, HFILL
842 { &hf_wtp_header_Inv_TransactionClass,
843 { "Transaction Class", "wtp.inv.transaction_class",
844 FT_UINT8, BASE_HEX, VALS( vals_transaction_classes ), 0x03,
845 NULL, HFILL
848 { &hf_wtp_header_Ack_flag_TVETOK,
849 { "Tve/Tok flag", "wtp.ack.tvetok",
850 FT_BOOLEAN, 8, NULL, 0x04,
851 NULL, HFILL
854 { &hf_wtp_header_Abort_type,
855 { "Abort Type", "wtp.abort.type",
856 FT_UINT8, BASE_HEX, VALS ( vals_abort_type ), 0x07,
857 NULL, HFILL
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,
863 NULL, HFILL
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,
870 NULL, HFILL
873 { &hf_wtp_header_sequence_number,
874 { "Packet Sequence Number", "wtp.header.sequence",
875 FT_UINT8, BASE_DEC, NULL, 0x00,
876 NULL, HFILL
879 { &hf_wtp_header_missing_packets,
880 { "Missing Packets", "wtp.header.missing_packets",
881 FT_UINT8, BASE_DEC, NULL, 0x00,
882 NULL, HFILL
885 { &hf_wtp_payload,
886 { "Payload", "wtp.payload",
887 FT_BYTES, BASE_NONE, NULL, 0x00,
888 NULL, HFILL
891 #if 0
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
898 { &hf_wtp_data,
899 { "Data", "wtp.header_data",
900 FT_BYTES, BASE_NONE, NULL, 0x0,
901 NULL, HFILL
904 #endif
905 { &hf_wtp_tpi_type,
906 { "TPI", "wtp.tpi",
907 FT_UINT8, BASE_HEX, VALS(vals_tpi_type), 0x00,
908 "Identification of the Transport Information Item", HFILL
911 { &hf_wtp_tpi_psn,
912 { "Packet sequence number", "wtp.tpi.psn",
913 FT_UINT8, BASE_DEC, NULL, 0x00,
914 "Sequence number of this packet", HFILL
917 { &hf_wtp_tpi_opt,
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
929 { &hf_wtp_tpi_info,
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,
970 NULL, HFILL
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
985 { &hf_wtp_fragment,
986 { "WTP Fragment", "wtp.fragment",
987 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
988 NULL, HFILL
991 { &hf_wtp_fragments,
992 { "WTP Fragments", "wtp.fragments",
993 FT_NONE, BASE_NONE, NULL, 0x0,
994 NULL, HFILL
999 /* Setup protocol subtree array */
1000 static int *ett[] = {
1001 &ett_wtp,
1002 &ett_wtp_sub_pdu_tree,
1003 &ett_header,
1004 &ett_tpilist,
1005 &ett_wsp_fragments,
1006 &ett_wtp_fragment,
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);
1023 void
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
1040 * Local variables:
1041 * c-basic-offset: 4
1042 * tab-width: 8
1043 * indent-tabs-mode: nil
1044 * End:
1046 * vi: set shiftwidth=4 tabstop=8 expandtab:
1047 * :indentSize=4:tabSize=8:noTabs=true: