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