/src/wireshark/epan/dissectors/packet-stt.c
Line | Count | Source |
1 | | /* packet-stt.c |
2 | | * |
3 | | * Routines for Stateless Transport Tunneling (STT) packet dissection |
4 | | * Remi Vichery <remi.vichery@gmail.com> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | * |
12 | | * Protocol ref: |
13 | | * https://tools.ietf.org/html/draft-davie-stt-07 |
14 | | */ |
15 | | |
16 | | #include "config.h" |
17 | | |
18 | | #include <epan/packet.h> |
19 | | #include <epan/expert.h> |
20 | | #include <epan/in_cksum.h> |
21 | | #include <epan/prefs.h> |
22 | | #include <epan/reassemble.h> |
23 | | #include <epan/tfs.h> |
24 | | #include <epan/unit_strings.h> |
25 | | #include <epan/iana-info.h> |
26 | | |
27 | | #include <wsutil/array.h> |
28 | | |
29 | | #include "packet-ip.h" |
30 | | |
31 | | static bool pref_reassemble = true; |
32 | | static bool pref_check_checksum; |
33 | | |
34 | | /* IANA ref: |
35 | | * https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml |
36 | | */ |
37 | 0 | #define TCP_PORT_STT 7471 |
38 | | |
39 | | /* Length of entire overloaded TCP header. */ |
40 | 4 | #define STT_TCP_HDR_LEN 20 |
41 | | |
42 | | /* Sum of STT header field sizes plus trailing padding. */ |
43 | 0 | #define STT_HEADER_SIZE 18 |
44 | | |
45 | 0 | #define STT_TCP_OFF_DPORT 2 |
46 | 0 | #define STT_TCP_OFF_PKT_LEN 4 |
47 | 0 | #define STT_TCP_OFF_SEG_OFF 6 |
48 | 0 | #define STT_TCP_OFF_PKT_ID 8 |
49 | | |
50 | 16 | #define STT_PCP_MASK 0xE000 |
51 | 16 | #define STT_V_MASK 0x1000 |
52 | 16 | #define STT_VLANID_MASK 0x0FFF |
53 | | |
54 | 0 | #define FLAG_OFFLOAD_MASK 0x02 |
55 | | |
56 | | void proto_register_stt(void); |
57 | | void proto_reg_handoff_stt(void); |
58 | | |
59 | | static int proto_stt; |
60 | | |
61 | | static int hf_stt_stream_id; |
62 | | static int hf_stt_dport; |
63 | | static int hf_stt_pkt_len; |
64 | | static int hf_stt_seg_off; |
65 | | static int hf_stt_pkt_id; |
66 | | static int hf_stt_checksum; |
67 | | static int hf_stt_checksum_status; |
68 | | static int hf_stt_tcp_data; |
69 | | static int hf_stt_tcp_data_offset; |
70 | | static int hf_stt_tcp_flags; |
71 | | static int hf_stt_tcp_rsvd; |
72 | | static int hf_stt_tcp_ns; |
73 | | static int hf_stt_tcp_cwr; |
74 | | static int hf_stt_tcp_ece; |
75 | | static int hf_stt_tcp_urg; |
76 | | static int hf_stt_tcp_ack; |
77 | | static int hf_stt_tcp_psh; |
78 | | static int hf_stt_tcp_rst; |
79 | | static int hf_stt_tcp_syn; |
80 | | static int hf_stt_tcp_fin; |
81 | | static int hf_stt_tcp_window; |
82 | | static int hf_stt_tcp_urg_ptr; |
83 | | |
84 | | static int hf_stt_version; |
85 | | static int hf_stt_flags; |
86 | | static int hf_stt_flag_rsvd; |
87 | | static int hf_stt_flag_tcp; |
88 | | static int hf_stt_flag_ipv4; |
89 | | static int hf_stt_flag_partial; |
90 | | static int hf_stt_flag_verified; |
91 | | static int hf_stt_l4_offset; |
92 | | static int hf_stt_reserved_8; |
93 | | static int hf_stt_mss; |
94 | | static int hf_stt_vlan; |
95 | | static int hf_stt_pcp; |
96 | | static int hf_stt_v; |
97 | | static int hf_stt_vlan_id; |
98 | | static int hf_stt_context_id; |
99 | | static int hf_stt_padding; |
100 | | |
101 | | static int hf_segments; |
102 | | static int hf_segment; |
103 | | static int hf_segment_overlap; |
104 | | static int hf_segment_overlap_conflict; |
105 | | static int hf_segment_multiple_tails; |
106 | | static int hf_segment_too_long_fragment; |
107 | | static int hf_segment_error; |
108 | | static int hf_segment_count; |
109 | | static int hf_reassembled_in; |
110 | | static int hf_reassembled_length; |
111 | | |
112 | | static int ett_stt; |
113 | | static int ett_stt_tcp_data; |
114 | | static int ett_stt_tcp_flags; |
115 | | static int ett_stt_flgs; |
116 | | static int ett_stt_vlan; |
117 | | static int ett_segment; |
118 | | static int ett_segments; |
119 | | |
120 | | static reassembly_table stt_reassembly_table; |
121 | | |
122 | | static expert_field ei_stt_ver_unknown; |
123 | | static expert_field ei_stt_checksum_bad; |
124 | | static expert_field ei_stt_data_offset_bad; |
125 | | static expert_field ei_stt_l4_offset; |
126 | | static expert_field ei_stt_mss; |
127 | | |
128 | | static dissector_handle_t eth_handle; |
129 | | |
130 | | /* From Table G-2 of IEEE standard 802.1Q-2005 */ |
131 | | static const value_string pri_vals[] = { |
132 | | { 1, "Background" }, |
133 | | { 0, "Best Effort (default)" }, |
134 | | { 2, "Excellent Effort" }, |
135 | | { 3, "Critical Applications" }, |
136 | | { 4, "Video, < 100ms latency and jitter" }, |
137 | | { 5, "Voice, < 10ms latency and jitter" }, |
138 | | { 6, "Internetwork Control" }, |
139 | | { 7, "Network Control" }, |
140 | | { 0, NULL } |
141 | | }; |
142 | | |
143 | | static const fragment_items frag_items = { |
144 | | &ett_segment, |
145 | | &ett_segments, |
146 | | &hf_segments, |
147 | | &hf_segment, |
148 | | &hf_segment_overlap, |
149 | | &hf_segment_overlap_conflict, |
150 | | &hf_segment_multiple_tails, |
151 | | &hf_segment_too_long_fragment, |
152 | | &hf_segment_error, |
153 | | &hf_segment_count, |
154 | | &hf_reassembled_in, |
155 | | &hf_reassembled_length, |
156 | | NULL, /* Reassembled data */ |
157 | | "STT segments" |
158 | | }; |
159 | | |
160 | | static tvbuff_t * |
161 | | handle_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
162 | | uint32_t pkt_id, uint16_t pkt_len, uint16_t seg_off) |
163 | 0 | { |
164 | 0 | fragment_head *frags; |
165 | 0 | int offset; |
166 | 0 | uint32_t frag_data_len; |
167 | 0 | bool more_frags; |
168 | | |
169 | | /* Skip fake TCP header after the first segment. */ |
170 | 0 | if (seg_off == 0) { |
171 | 0 | offset = 0; |
172 | 0 | } else { |
173 | 0 | offset = STT_TCP_HDR_LEN; |
174 | | /* We saved the TCP header on the first packet (only), which skews the |
175 | | * segment offset. */ |
176 | 0 | seg_off += STT_TCP_HDR_LEN; |
177 | 0 | } |
178 | |
|
179 | 0 | frag_data_len = tvb_reported_length_remaining(tvb, offset); |
180 | 0 | more_frags = seg_off + frag_data_len < pkt_len; |
181 | |
|
182 | 0 | frags = fragment_add_check(&stt_reassembly_table, tvb, offset, pinfo, |
183 | 0 | pkt_id, NULL, seg_off, frag_data_len, |
184 | 0 | more_frags); |
185 | | |
186 | | /* Update reassembly fields in UI if reassembly is complete. */ |
187 | 0 | if (frags) { |
188 | 0 | return process_reassembled_data(tvb, offset, pinfo, "Reassembled STT", |
189 | 0 | frags, &frag_items, NULL, tree); |
190 | 0 | } |
191 | | |
192 | 0 | return NULL; |
193 | 0 | } |
194 | | |
195 | | static void |
196 | | dissect_stt_checksum(tvbuff_t *tvb, packet_info *pinfo, proto_tree *stt_tree) |
197 | 0 | { |
198 | 0 | bool can_checksum = !pinfo->fragmented && |
199 | 0 | tvb_bytes_exist(tvb, 0, tvb_reported_length(tvb)); |
200 | |
|
201 | 0 | if (can_checksum && pref_check_checksum) { |
202 | 0 | vec_t cksum_vec[4]; |
203 | 0 | uint32_t phdr[2]; |
204 | | |
205 | | /* Set up the fields of the pseudo-header. */ |
206 | 0 | SET_CKSUM_VEC_PTR(cksum_vec[0], (const uint8_t *)pinfo->src.data, |
207 | 0 | pinfo->src.len); |
208 | 0 | SET_CKSUM_VEC_PTR(cksum_vec[1], (const uint8_t *)pinfo->dst.data, |
209 | 0 | pinfo->dst.len); |
210 | 0 | switch (pinfo->src.type) { |
211 | 0 | case AT_IPv4: |
212 | 0 | phdr[0] = g_htonl((IP_PROTO_TCP<<16) + tvb_reported_length(tvb)); |
213 | 0 | SET_CKSUM_VEC_PTR(cksum_vec[2], (const uint8_t *)phdr, 4); |
214 | 0 | break; |
215 | | |
216 | 0 | case AT_IPv6: |
217 | 0 | phdr[0] = g_htonl(tvb_reported_length(tvb)); |
218 | 0 | phdr[1] = g_htonl(IP_PROTO_TCP); |
219 | 0 | SET_CKSUM_VEC_PTR(cksum_vec[2], (const uint8_t *)phdr, 8); |
220 | 0 | break; |
221 | | |
222 | 0 | default: |
223 | | /* STT runs only atop IPv4 and IPv6.... */ |
224 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
225 | 0 | break; |
226 | 0 | } |
227 | 0 | SET_CKSUM_VEC_TVB(cksum_vec[3], tvb, 0, tvb_reported_length(tvb)); |
228 | |
|
229 | 0 | proto_tree_add_checksum(stt_tree, tvb, 16, hf_stt_checksum, hf_stt_checksum_status, &ei_stt_checksum_bad, pinfo, |
230 | 0 | in_cksum(cksum_vec, 4), ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
231 | 0 | } else { |
232 | 0 | proto_tree_add_checksum(stt_tree, tvb, 16, hf_stt_checksum, hf_stt_checksum_status, &ei_stt_checksum_bad, pinfo, |
233 | 0 | 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | | static int |
238 | | dissect_tcp_flags(proto_tree *tree, tvbuff_t *tvb, int offset) |
239 | 0 | { |
240 | 0 | static int * const flags[] = { |
241 | 0 | &hf_stt_tcp_rsvd, |
242 | 0 | &hf_stt_tcp_ns, |
243 | 0 | &hf_stt_tcp_cwr, |
244 | 0 | &hf_stt_tcp_ece, |
245 | 0 | &hf_stt_tcp_urg, |
246 | 0 | &hf_stt_tcp_ack, |
247 | 0 | &hf_stt_tcp_psh, |
248 | 0 | &hf_stt_tcp_rst, |
249 | 0 | &hf_stt_tcp_syn, |
250 | 0 | &hf_stt_tcp_fin, |
251 | 0 | NULL |
252 | 0 | }; |
253 | |
|
254 | 0 | proto_tree_add_bitmask(tree, tvb, offset, hf_stt_tcp_flags, |
255 | 0 | ett_stt_tcp_flags, flags, ENC_BIG_ENDIAN); |
256 | 0 | offset += 2; |
257 | |
|
258 | 0 | return offset; |
259 | 0 | } |
260 | | |
261 | | static void |
262 | | dissect_tcp_tree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *stt_tree) |
263 | 0 | { |
264 | 0 | unsigned offset = 0; |
265 | 0 | proto_tree *tcp_tree; |
266 | 0 | proto_item *tcp_item, *data_offset_item; |
267 | 0 | int data_offset; |
268 | |
|
269 | 0 | proto_tree_add_item(stt_tree, hf_stt_stream_id, tvb, offset, 2, ENC_BIG_ENDIAN); |
270 | 0 | offset += 2; |
271 | |
|
272 | 0 | proto_tree_add_item(stt_tree, hf_stt_dport, tvb, offset, 2, ENC_BIG_ENDIAN); |
273 | 0 | offset += 2; |
274 | |
|
275 | 0 | proto_tree_add_item(stt_tree, hf_stt_pkt_len, tvb, offset, 2, ENC_BIG_ENDIAN); |
276 | 0 | offset += 2; |
277 | |
|
278 | 0 | proto_tree_add_item(stt_tree, hf_stt_seg_off, tvb, offset, 2, ENC_BIG_ENDIAN); |
279 | 0 | offset += 2; |
280 | |
|
281 | 0 | proto_tree_add_item(stt_tree, hf_stt_pkt_id, tvb, offset, 4, ENC_BIG_ENDIAN); |
282 | 0 | offset += 4; |
283 | |
|
284 | 0 | tcp_item = proto_tree_add_item(stt_tree, hf_stt_tcp_data, tvb, offset, |
285 | 0 | 8, ENC_NA); |
286 | 0 | tcp_tree = proto_item_add_subtree(tcp_item, ett_stt_tcp_data); |
287 | 0 | proto_item_set_text(tcp_item, "TCP Data"); |
288 | |
|
289 | 0 | data_offset = hi_nibble(tvb_get_uint8(tvb, offset)) * 4; |
290 | 0 | data_offset_item = proto_tree_add_uint(tcp_tree, |
291 | 0 | hf_stt_tcp_data_offset, |
292 | 0 | tvb, offset, 1, |
293 | 0 | data_offset); |
294 | 0 | if (data_offset != STT_TCP_HDR_LEN) { |
295 | 0 | expert_add_info(pinfo, data_offset_item, &ei_stt_data_offset_bad); |
296 | 0 | } |
297 | |
|
298 | 0 | offset = dissect_tcp_flags(tcp_tree, tvb, offset); |
299 | |
|
300 | 0 | proto_tree_add_item(tcp_tree, hf_stt_tcp_window, tvb, offset, 2, |
301 | 0 | ENC_BIG_ENDIAN); |
302 | 0 | offset += 2; |
303 | |
|
304 | 0 | dissect_stt_checksum(tvb, pinfo, stt_tree); |
305 | 0 | offset += 2; |
306 | |
|
307 | 0 | proto_tree_add_item(tcp_tree, hf_stt_tcp_urg_ptr, tvb, offset, 2, |
308 | 0 | ENC_BIG_ENDIAN); |
309 | 0 | } |
310 | | |
311 | | static int |
312 | | dissect_stt_flags(proto_tree *tree, tvbuff_t *tvb, int offset) |
313 | 0 | { |
314 | 0 | static int * const flags[] = { |
315 | 0 | &hf_stt_flag_rsvd, |
316 | 0 | &hf_stt_flag_tcp, |
317 | 0 | &hf_stt_flag_ipv4, |
318 | 0 | &hf_stt_flag_partial, |
319 | 0 | &hf_stt_flag_verified, |
320 | 0 | NULL |
321 | 0 | }; |
322 | |
|
323 | 0 | proto_tree_add_bitmask(tree, tvb, offset, hf_stt_flags, |
324 | 0 | ett_stt_flgs, flags, ENC_BIG_ENDIAN); |
325 | 0 | offset += 1; |
326 | |
|
327 | 0 | return offset; |
328 | 0 | } |
329 | | |
330 | | static void |
331 | | dissect_stt_tree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *stt_tree, |
332 | | proto_item *stt_item) |
333 | 0 | { |
334 | 0 | proto_tree *vlan_tree; |
335 | 0 | proto_item *ver_item, *l4_offset_item, *vlan_item, *mss_item; |
336 | 0 | uint8_t flags; |
337 | 0 | uint32_t version, l4_offset, mss, attributes; |
338 | 0 | uint64_t context_id; |
339 | 0 | int offset = STT_TCP_HDR_LEN; |
340 | | |
341 | | /* |
342 | | 0 1 2 3 |
343 | | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
344 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
345 | | | Version | Flags | L4 Offset | Reserved | |
346 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
347 | | | Max. Segment Size | PCP |V| VLAN ID | |
348 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
349 | | | | |
350 | | + Context ID (64 bits) + |
351 | | | | |
352 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
353 | | | Padding | Data | |
354 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |
355 | | | | |
356 | | */ |
357 | | |
358 | | /* Protocol version */ |
359 | 0 | ver_item = proto_tree_add_item_ret_uint(stt_tree, hf_stt_version, tvb, |
360 | 0 | offset, 1, ENC_BIG_ENDIAN, &version); |
361 | 0 | if (version != 0) { |
362 | 0 | expert_add_info_format(pinfo, ver_item, &ei_stt_ver_unknown, |
363 | 0 | "Unknown version %u", version); |
364 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown STT version %u", version); |
365 | 0 | } |
366 | 0 | offset++; |
367 | | |
368 | | /* Flags */ |
369 | 0 | flags = tvb_get_uint8(tvb, offset); |
370 | 0 | offset = dissect_stt_flags(stt_tree, tvb, offset); |
371 | | |
372 | | /* Layer 4 offset */ |
373 | 0 | l4_offset_item = proto_tree_add_item_ret_uint(stt_tree, hf_stt_l4_offset, |
374 | 0 | tvb, offset, 1, |
375 | 0 | ENC_BIG_ENDIAN, &l4_offset); |
376 | | /* Display an error if offset is != 0 when offloading is not in use */ |
377 | 0 | if ( !(flags & FLAG_OFFLOAD_MASK) && (l4_offset != 0) ) { |
378 | 0 | expert_add_info_format(pinfo, l4_offset_item, &ei_stt_l4_offset, "Incorrect offset, should be equal to zero"); |
379 | 0 | } |
380 | | /* Display an error if offset equals 0 when there is offloading */ |
381 | 0 | if ( (flags & FLAG_OFFLOAD_MASK) && (l4_offset == 0) ) { |
382 | 0 | expert_add_info_format(pinfo, l4_offset_item, &ei_stt_l4_offset, "Incorrect offset, should be greater than zero"); |
383 | 0 | } |
384 | 0 | offset ++; |
385 | | |
386 | | /* Reserved field (1 byte). MUST be 0 on transmission, |
387 | | ignored on receipt. */ |
388 | 0 | proto_tree_add_item(stt_tree, hf_stt_reserved_8, tvb, offset, 1, |
389 | 0 | ENC_BIG_ENDIAN); |
390 | 0 | offset ++; |
391 | | |
392 | | /* Maximum Segment Size. MUST be 0 if segmentation offload |
393 | | is not in use. */ |
394 | 0 | mss_item = proto_tree_add_item_ret_uint(stt_tree, hf_stt_mss, tvb, |
395 | 0 | offset, 2, ENC_BIG_ENDIAN, &mss); |
396 | | /* Display an error if MSS is != 0 when offloading is not in use */ |
397 | 0 | if ( !(flags & FLAG_OFFLOAD_MASK) && (mss != 0) ) { |
398 | 0 | expert_add_info_format(pinfo, mss_item, &ei_stt_mss, "Incorrect max segment size, should be equal to zero"); |
399 | 0 | } |
400 | 0 | offset += 2; |
401 | | |
402 | | /* Tag Control Information like header. If V flag is set, it |
403 | | indicates the presence of a valid VLAN ID in the following field |
404 | | and valid PCP in the preceding field. */ |
405 | 0 | vlan_item = proto_tree_add_item_ret_uint(stt_tree, hf_stt_vlan, tvb, offset, |
406 | 0 | 2, ENC_BIG_ENDIAN, &attributes); |
407 | 0 | vlan_tree = proto_item_add_subtree(vlan_item, ett_stt_vlan); |
408 | 0 | proto_item_set_text(vlan_item, "VLAN Priority %u, ID %u", |
409 | 0 | (attributes >> 13), (attributes & STT_VLANID_MASK)); |
410 | |
|
411 | 0 | proto_tree_add_item(vlan_tree, hf_stt_pcp, tvb, offset, 2, ENC_BIG_ENDIAN); |
412 | 0 | proto_tree_add_item(vlan_tree, hf_stt_v, tvb, offset, 2, ENC_BIG_ENDIAN); |
413 | 0 | proto_tree_add_item(vlan_tree, hf_stt_vlan_id, tvb, offset, 2, ENC_BIG_ENDIAN); |
414 | 0 | if (attributes & STT_V_MASK) { |
415 | | /* Display priority code point and VLAN ID when V flag is set */ |
416 | 0 | proto_item_append_text(stt_item, ", Priority: %u, VLAN ID: %u", |
417 | 0 | attributes >> 13, |
418 | 0 | attributes & STT_VLANID_MASK); |
419 | 0 | } |
420 | | /* Show if any part of this is set to aid debugging bad implementations. */ |
421 | 0 | if (attributes == 0) { |
422 | 0 | proto_item_set_hidden(vlan_item); |
423 | 0 | } |
424 | 0 | offset += 2; |
425 | | |
426 | | /* Context ID */ |
427 | 0 | proto_tree_add_item_ret_uint64(stt_tree, hf_stt_context_id, tvb, offset, 8, ENC_BIG_ENDIAN, &context_id); |
428 | 0 | proto_item_append_text(stt_item, ", Context ID: 0x%" PRIx64, |
429 | 0 | context_id); |
430 | 0 | offset += 8; |
431 | | |
432 | | /* Padding */ |
433 | 0 | proto_tree_add_item(stt_tree, hf_stt_padding, tvb, offset, |
434 | 0 | 2, ENC_BIG_ENDIAN); |
435 | 0 | } |
436 | | |
437 | | static void |
438 | | dissect_stt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) |
439 | 0 | { |
440 | 0 | proto_item *stt_item; |
441 | 0 | proto_tree *stt_tree; |
442 | 0 | tvbuff_t *next_tvb; |
443 | 0 | uint16_t seg_off, pkt_len, rx_bytes; |
444 | 0 | uint8_t sub_off; |
445 | 0 | bool frag_save, is_seg; |
446 | | |
447 | | /* Make entry in Protocol column on summary display. */ |
448 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "STT"); |
449 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
450 | |
|
451 | 0 | stt_item = proto_tree_add_item(tree, proto_stt, tvb, 0, |
452 | 0 | STT_TCP_HDR_LEN, ENC_NA); |
453 | 0 | stt_tree = proto_item_add_subtree(stt_item, ett_stt); |
454 | |
|
455 | 0 | dissect_tcp_tree(tvb, pinfo, stt_tree); |
456 | |
|
457 | 0 | frag_save = pinfo->fragmented; |
458 | |
|
459 | 0 | seg_off = tvb_get_ntohs(tvb, STT_TCP_OFF_SEG_OFF); |
460 | 0 | pkt_len = tvb_get_ntohs(tvb, STT_TCP_OFF_PKT_LEN); |
461 | 0 | rx_bytes = tvb_reported_length_remaining(tvb, STT_TCP_HDR_LEN); |
462 | 0 | is_seg = pkt_len > rx_bytes; |
463 | |
|
464 | 0 | if (is_seg) { |
465 | 0 | uint32_t pkt_id = tvb_get_ntohl(tvb, STT_TCP_OFF_PKT_ID); |
466 | |
|
467 | 0 | pinfo->fragmented = true; |
468 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, |
469 | 0 | "STT Segment (ID: 0x%x Len: %hu, Off: %hu)", |
470 | 0 | pkt_id, pkt_len, seg_off); |
471 | | |
472 | | /* Reassemble segments unless the user has disabled reassembly. */ |
473 | 0 | if (pref_reassemble && tvb_bytes_exist(tvb, 0, rx_bytes)) { |
474 | 0 | tvbuff_t *reasm_tvb; |
475 | |
|
476 | 0 | reasm_tvb = handle_segment(tvb, pinfo, stt_tree, pkt_id, |
477 | 0 | pkt_len, seg_off); |
478 | 0 | if (reasm_tvb) { |
479 | 0 | tvb = reasm_tvb; |
480 | 0 | pinfo->fragmented = frag_save; |
481 | 0 | is_seg = false; |
482 | 0 | } |
483 | 0 | } else if (seg_off == 0) { |
484 | | /* If we're not reassembling, move ahead as if we have the |
485 | | * whole frame. */ |
486 | 0 | is_seg = false; |
487 | 0 | } |
488 | 0 | } |
489 | | |
490 | | /* Only full packets have a STT header (following the fake TCP header). */ |
491 | 0 | if (!is_seg) { |
492 | 0 | sub_off = STT_TCP_HDR_LEN + STT_HEADER_SIZE; |
493 | 0 | dissect_stt_tree(tvb, pinfo, stt_tree, stt_item); |
494 | 0 | } else { |
495 | 0 | sub_off = STT_TCP_HDR_LEN; |
496 | 0 | } |
497 | |
|
498 | 0 | if (seg_off == 0) { |
499 | 0 | proto_item_set_len(stt_item, sub_off); |
500 | 0 | } |
501 | 0 | next_tvb = tvb_new_subset_remaining(tvb, sub_off); |
502 | | |
503 | | /* Only dissect inner frame if not segmented or if we aren't |
504 | | doing reassembly. */ |
505 | 0 | if (!is_seg) { |
506 | 0 | call_dissector(eth_handle, next_tvb, pinfo, tree); |
507 | 0 | } else { |
508 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
509 | 0 | } |
510 | |
|
511 | 0 | pinfo->fragmented = frag_save; |
512 | 0 | } |
513 | | |
514 | | static bool |
515 | | dissect_stt_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
516 | | void *iph) |
517 | 701 | { |
518 | | /* Make sure we at least have a TCP header */ |
519 | 701 | if (ws_ip_protocol(iph) != IP_PROTO_TCP || |
520 | 701 | tvb_captured_length(tvb) < STT_TCP_HDR_LEN) { |
521 | 701 | return false; |
522 | 701 | } |
523 | | |
524 | | /* Check the TCP destination port */ |
525 | 0 | if (tvb_get_ntohs(tvb, STT_TCP_OFF_DPORT) != TCP_PORT_STT) { |
526 | 0 | return false; |
527 | 0 | } |
528 | | |
529 | 0 | dissect_stt(tvb, pinfo, tree); |
530 | 0 | return true; |
531 | 0 | } |
532 | | |
533 | | /* Register STT with Wireshark */ |
534 | | void |
535 | | proto_register_stt(void) |
536 | 16 | { |
537 | 16 | expert_module_t* expert_stt; |
538 | 16 | module_t *stt_prefs; |
539 | | |
540 | 16 | static hf_register_info hf[] = { |
541 | | /* Overloaded fake TCP header fields. */ |
542 | 16 | { &hf_stt_stream_id, |
543 | 16 | { "Stream ID", "stt.stream_id", |
544 | 16 | FT_UINT16, BASE_HEX, NULL, 0x0, |
545 | 16 | NULL, HFILL |
546 | 16 | }, |
547 | 16 | }, |
548 | 16 | { &hf_stt_dport, |
549 | 16 | { "Destination Port", "stt.dport", |
550 | 16 | FT_UINT16, BASE_DEC, NULL, 0x0, |
551 | 16 | NULL, HFILL |
552 | 16 | }, |
553 | 16 | }, |
554 | 16 | { &hf_stt_pkt_len, |
555 | 16 | { "Packet Length", "stt.pkt_len", |
556 | 16 | FT_UINT16, BASE_DEC, NULL, 0x0, |
557 | 16 | NULL, HFILL |
558 | 16 | }, |
559 | 16 | }, |
560 | 16 | { &hf_stt_seg_off, |
561 | 16 | { "Segment Offset", "stt.seg_off", |
562 | 16 | FT_UINT16, BASE_DEC, NULL, 0x0, |
563 | 16 | NULL, HFILL |
564 | 16 | }, |
565 | 16 | }, |
566 | 16 | { &hf_stt_pkt_id, |
567 | 16 | { "Packet ID", "stt.pkt_id", |
568 | 16 | FT_UINT32, BASE_HEX, NULL, 0x0, |
569 | 16 | NULL, HFILL |
570 | 16 | }, |
571 | 16 | }, |
572 | 16 | { &hf_stt_tcp_data, |
573 | 16 | { "TCP Data", "stt.tcp", |
574 | 16 | FT_BYTES, BASE_NONE, NULL, 0x0, |
575 | 16 | NULL, HFILL |
576 | 16 | }, |
577 | 16 | }, |
578 | 16 | { &hf_stt_tcp_data_offset, |
579 | 16 | { "Data Offset", "stt.tcp.data_offset", |
580 | 16 | FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, |
581 | 16 | NULL, HFILL |
582 | 16 | }, |
583 | 16 | }, |
584 | 16 | { &hf_stt_tcp_flags, |
585 | 16 | { "Flags", "stt.tcp.flags", |
586 | 16 | FT_UINT16, BASE_HEX, NULL, 0x0FFF, |
587 | 16 | NULL, HFILL |
588 | 16 | }, |
589 | 16 | }, |
590 | 16 | { &hf_stt_tcp_rsvd, |
591 | 16 | { "Reserved", "stt.tcp.flags.rsvd", |
592 | 16 | FT_BOOLEAN, 12, NULL, 0xE00, |
593 | 16 | NULL, HFILL |
594 | 16 | }, |
595 | 16 | }, |
596 | 16 | { &hf_stt_tcp_ns, |
597 | 16 | { "Nonce", "stt.tcp.flags.ns", |
598 | 16 | FT_BOOLEAN, 12, NULL, 0x100, |
599 | 16 | NULL, HFILL |
600 | 16 | }, |
601 | 16 | }, |
602 | 16 | { &hf_stt_tcp_cwr, |
603 | 16 | { "Congestion Window Reduced (CWR)", "stt.tcp.flags.cwr", |
604 | 16 | FT_BOOLEAN, 12, NULL, 0x080, |
605 | 16 | NULL, HFILL |
606 | 16 | }, |
607 | 16 | }, |
608 | 16 | { &hf_stt_tcp_ece, |
609 | 16 | { "ECN-Echo", "stt.tcp.flags.ece", |
610 | 16 | FT_BOOLEAN, 12, NULL, 0x040, |
611 | 16 | NULL, HFILL |
612 | 16 | }, |
613 | 16 | }, |
614 | 16 | { &hf_stt_tcp_urg, |
615 | 16 | { "Urgent", "stt.tcp.flags.urg", |
616 | 16 | FT_BOOLEAN, 12, NULL, 0x020, |
617 | 16 | NULL, HFILL |
618 | 16 | }, |
619 | 16 | }, |
620 | 16 | { &hf_stt_tcp_ack, |
621 | 16 | { "Acknowledgement", "stt.tcp.flags.ack", |
622 | 16 | FT_BOOLEAN, 12, NULL, 0x010, |
623 | 16 | NULL, HFILL |
624 | 16 | }, |
625 | 16 | }, |
626 | 16 | { &hf_stt_tcp_psh, |
627 | 16 | { "Push", "stt.tcp.flags.psh", |
628 | 16 | FT_BOOLEAN, 12, NULL, 0x008, |
629 | 16 | NULL, HFILL |
630 | 16 | }, |
631 | 16 | }, |
632 | 16 | { &hf_stt_tcp_rst, |
633 | 16 | { "Reset", "stt.tcp.flags.rst", |
634 | 16 | FT_BOOLEAN, 12, NULL, 0x004, |
635 | 16 | NULL, HFILL |
636 | 16 | }, |
637 | 16 | }, |
638 | 16 | { &hf_stt_tcp_syn, |
639 | 16 | { "Syn", "stt.tcp.flags.syn", |
640 | 16 | FT_BOOLEAN, 12, NULL, 0x002, |
641 | 16 | NULL, HFILL |
642 | 16 | }, |
643 | 16 | }, |
644 | 16 | { &hf_stt_tcp_fin, |
645 | 16 | { "Fin", "stt.tcp.flags.fin", |
646 | 16 | FT_BOOLEAN, 12, NULL, 0x001, |
647 | 16 | NULL, HFILL |
648 | 16 | }, |
649 | 16 | }, |
650 | 16 | { &hf_stt_tcp_window, |
651 | 16 | { "Window", "stt.tcp.window", |
652 | 16 | FT_UINT16, BASE_DEC, NULL, 0x0, |
653 | 16 | NULL, HFILL |
654 | 16 | }, |
655 | 16 | }, |
656 | 16 | { &hf_stt_tcp_urg_ptr, |
657 | 16 | { "Urgent Pointer", "stt.tcp.urg_ptr", |
658 | 16 | FT_UINT16, BASE_DEC, NULL, 0x0, |
659 | 16 | NULL, HFILL |
660 | 16 | }, |
661 | 16 | }, |
662 | | |
663 | | /* STT header fields. */ |
664 | 16 | { &hf_stt_version, |
665 | 16 | { "Version", "stt.version", |
666 | 16 | FT_UINT8, BASE_DEC, NULL, 0x0, |
667 | 16 | NULL, HFILL |
668 | 16 | }, |
669 | 16 | }, |
670 | 16 | { &hf_stt_flags, |
671 | 16 | { "Flags", "stt.flags", |
672 | 16 | FT_UINT8, BASE_HEX, NULL, 0x0, |
673 | 16 | NULL, HFILL |
674 | 16 | }, |
675 | 16 | }, |
676 | 16 | { &hf_stt_flag_rsvd, |
677 | 16 | { "Reserved", "stt.flags.rsvd", |
678 | 16 | FT_BOOLEAN, 8, NULL, 0xF0, |
679 | 16 | NULL, HFILL |
680 | 16 | }, |
681 | 16 | }, |
682 | 16 | { &hf_stt_flag_tcp, |
683 | 16 | { "TCP payload", "stt.flags.tcp", |
684 | 16 | FT_BOOLEAN, 8, NULL, 0x08, |
685 | 16 | NULL, HFILL |
686 | 16 | }, |
687 | 16 | }, |
688 | 16 | { &hf_stt_flag_ipv4, |
689 | 16 | { "IPv4 packet", "stt.flags.ipv4", |
690 | 16 | FT_BOOLEAN, 8, NULL, 0x04, |
691 | 16 | NULL, HFILL |
692 | 16 | }, |
693 | 16 | }, |
694 | 16 | { &hf_stt_flag_partial, |
695 | 16 | { "Checksum partial", "stt.flags.csum_partial", |
696 | 16 | FT_BOOLEAN, 8, NULL, 0x02, |
697 | 16 | NULL, HFILL |
698 | 16 | }, |
699 | 16 | }, |
700 | 16 | { &hf_stt_flag_verified, |
701 | 16 | { "Checksum verified", "stt.flags.csum_verified", |
702 | 16 | FT_BOOLEAN, 8, NULL, 0x01, |
703 | 16 | NULL, HFILL |
704 | 16 | }, |
705 | 16 | }, |
706 | 16 | { &hf_stt_l4_offset, |
707 | 16 | { "L4 Offset", "stt.l4offset", |
708 | 16 | FT_UINT8, BASE_DEC, NULL, 0x0, |
709 | 16 | NULL, HFILL |
710 | 16 | }, |
711 | 16 | }, |
712 | 16 | { &hf_stt_reserved_8, |
713 | 16 | { "Reserved", "stt.reserved", |
714 | 16 | FT_UINT8, BASE_HEX, NULL, 0x0, |
715 | 16 | NULL, HFILL |
716 | 16 | }, |
717 | 16 | }, |
718 | 16 | { &hf_stt_mss, |
719 | 16 | { "Max Segment Size", "stt.mss", |
720 | 16 | FT_UINT16, BASE_DEC, NULL, 0x0, |
721 | 16 | NULL, HFILL |
722 | 16 | }, |
723 | 16 | }, |
724 | 16 | { &hf_stt_vlan, |
725 | 16 | { "VLAN", "stt.vlan", |
726 | 16 | FT_UINT16, BASE_HEX, NULL, 0x0, |
727 | 16 | NULL, HFILL |
728 | 16 | }, |
729 | 16 | }, |
730 | 16 | { &hf_stt_pcp, |
731 | 16 | { "PCP", "stt.vlan.pcp", |
732 | 16 | FT_UINT16, BASE_DEC, VALS(pri_vals), STT_PCP_MASK, |
733 | 16 | NULL, HFILL |
734 | 16 | }, |
735 | 16 | }, |
736 | 16 | { &hf_stt_v, |
737 | 16 | { "V flag", "stt.vlan.v", |
738 | 16 | FT_UINT16, BASE_DEC, NULL, STT_V_MASK, |
739 | 16 | NULL, HFILL |
740 | 16 | }, |
741 | 16 | }, |
742 | 16 | { &hf_stt_vlan_id, |
743 | 16 | { "VLAN ID", "stt.vlan.id", |
744 | 16 | FT_UINT16, BASE_DEC, NULL, STT_VLANID_MASK, |
745 | 16 | NULL, HFILL |
746 | 16 | }, |
747 | 16 | }, |
748 | 16 | { &hf_stt_context_id, |
749 | 16 | { "Context ID", "stt.context_id", |
750 | 16 | FT_UINT64, BASE_HEX, NULL, 0x0, |
751 | 16 | NULL, HFILL |
752 | 16 | }, |
753 | 16 | }, |
754 | 16 | { &hf_stt_padding, |
755 | 16 | { "Padding", "stt.padding", |
756 | 16 | FT_UINT16, BASE_HEX, NULL, 0x0, |
757 | 16 | NULL, HFILL |
758 | 16 | }, |
759 | 16 | }, |
760 | | |
761 | | /* Checksum validation fields */ |
762 | 16 | { &hf_stt_checksum, |
763 | 16 | { "Checksum", "stt.checksum", |
764 | 16 | FT_UINT16, BASE_HEX, NULL, 0x0, |
765 | 16 | "Details at: https://www.wireshark.org/docs/wsug_html_chunked/ChAdvChecksums.html", HFILL |
766 | 16 | }, |
767 | 16 | }, |
768 | 16 | { &hf_stt_checksum_status, |
769 | 16 | { "Checksum Status", "stt.checksum.status", |
770 | 16 | FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, |
771 | 16 | NULL, HFILL |
772 | 16 | }, |
773 | 16 | }, |
774 | | |
775 | | /* Segment reassembly information. */ |
776 | 16 | { &hf_segment_overlap, |
777 | 16 | { "Segment overlap", "stt.segment.overlap", |
778 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
779 | 16 | "Segment overlaps with other segments", HFILL |
780 | 16 | }, |
781 | 16 | }, |
782 | 16 | { &hf_segment_overlap_conflict, |
783 | 16 | { "Conflicting data in segment overlap", "stt.segment.overlap.conflict", |
784 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
785 | 16 | "Overlapping segments contained conflicting data", HFILL |
786 | 16 | }, |
787 | 16 | }, |
788 | 16 | { &hf_segment_multiple_tails, |
789 | 16 | { "Multiple tail segments found", "stt.segment.multipletails", |
790 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
791 | 16 | "Several tails were found when reassembling the packet", HFILL |
792 | 16 | }, |
793 | 16 | }, |
794 | 16 | { &hf_segment_too_long_fragment, |
795 | 16 | { "Segment too long", "stt.segment.toolongfragment", |
796 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
797 | 16 | "Segment contained data past end of the packet", HFILL |
798 | 16 | }, |
799 | 16 | }, |
800 | 16 | { &hf_segment_error, |
801 | 16 | { "Reassembling error", "stt.segment.error", |
802 | 16 | FT_FRAMENUM, BASE_NONE, NULL, 0x0, |
803 | 16 | "Reassembling error due to illegal segments", HFILL |
804 | 16 | }, |
805 | 16 | }, |
806 | 16 | { &hf_segment_count, |
807 | 16 | { "Segment count", "stt.segment.count", |
808 | 16 | FT_UINT32, BASE_DEC, NULL, 0x0, |
809 | 16 | NULL, HFILL |
810 | 16 | }, |
811 | 16 | }, |
812 | 16 | { &hf_segment, |
813 | 16 | { "STT Segment", "stt.segment", |
814 | 16 | FT_FRAMENUM, BASE_NONE, NULL, 0x0, |
815 | 16 | NULL, HFILL |
816 | 16 | }, |
817 | 16 | }, |
818 | 16 | { &hf_segments, |
819 | 16 | { "Reassembled STT Segments", "stt.segments", |
820 | 16 | FT_NONE, BASE_NONE, NULL, 0x0, |
821 | 16 | NULL, HFILL |
822 | 16 | }, |
823 | 16 | }, |
824 | 16 | { &hf_reassembled_in, |
825 | 16 | { "Reassembled PDU in frame", "stt.reassembled_in", |
826 | 16 | FT_FRAMENUM, BASE_NONE, NULL, 0x0, |
827 | 16 | "The STT packet is reassembled in this frame", HFILL |
828 | 16 | }, |
829 | 16 | }, |
830 | 16 | { &hf_reassembled_length, |
831 | 16 | { "Reassembled STT length", "stt.reassembled.length", |
832 | 16 | FT_UINT32, BASE_DEC, NULL, 0x0, |
833 | 16 | "The total length of the reassembled payload", HFILL |
834 | 16 | }, |
835 | 16 | }, |
836 | 16 | }; |
837 | | |
838 | | /* Setup protocol subtree array */ |
839 | 16 | static int *ett[] = { |
840 | 16 | &ett_stt, |
841 | 16 | &ett_stt_tcp_data, |
842 | 16 | &ett_stt_tcp_flags, |
843 | 16 | &ett_stt_flgs, |
844 | 16 | &ett_stt_vlan, |
845 | 16 | &ett_segment, |
846 | 16 | &ett_segments |
847 | 16 | }; |
848 | | |
849 | 16 | static ei_register_info ei[] = { |
850 | 16 | { &ei_stt_checksum_bad, |
851 | 16 | { "stt.checksum_bad.expert", PI_CHECKSUM, |
852 | 16 | PI_ERROR, "Bad checksum", EXPFILL |
853 | 16 | } |
854 | 16 | }, |
855 | 16 | { &ei_stt_data_offset_bad, |
856 | 16 | { "stt.data_offset_bad.expert", PI_PROTOCOL, |
857 | 16 | PI_WARN, "TCP Data Offset should be 20 bytes", EXPFILL |
858 | 16 | } |
859 | 16 | }, |
860 | 16 | { &ei_stt_ver_unknown, |
861 | 16 | { "stt.version_unknown.expert", PI_PROTOCOL, |
862 | 16 | PI_WARN, "Unknown version", EXPFILL |
863 | 16 | } |
864 | 16 | }, |
865 | 16 | { &ei_stt_l4_offset, |
866 | 16 | { "stt.l4offset_bad.expert", PI_PROTOCOL, |
867 | 16 | PI_WARN, "Bad L4 Offset", EXPFILL |
868 | 16 | } |
869 | 16 | }, |
870 | 16 | { &ei_stt_mss, |
871 | 16 | { "stt.mss_bad.expert", PI_PROTOCOL, |
872 | 16 | PI_WARN, "Bad MSS", EXPFILL |
873 | 16 | } |
874 | 16 | }, |
875 | 16 | }; |
876 | | |
877 | | /* Register the protocol name and description */ |
878 | 16 | proto_stt = proto_register_protocol("Stateless Transport Tunneling", |
879 | 16 | "STT", "stt"); |
880 | | |
881 | 16 | expert_stt = expert_register_protocol(proto_stt); |
882 | 16 | expert_register_field_array(expert_stt, ei, array_length(ei)); |
883 | | |
884 | | /* Required function calls to register the header fields and |
885 | | subtrees used */ |
886 | 16 | proto_register_field_array(proto_stt, hf, array_length(hf)); |
887 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
888 | | |
889 | 16 | stt_prefs = prefs_register_protocol(proto_stt, NULL); |
890 | 16 | prefs_register_bool_preference(stt_prefs, "reassemble", |
891 | 16 | "Reassemble segmented STT packets", |
892 | 16 | "Reassembles greater than MTU sized STT packets broken into segments on transmit", |
893 | 16 | &pref_reassemble); |
894 | 16 | prefs_register_bool_preference(stt_prefs, "check_checksum", |
895 | 16 | "Validate the STT checksum if possible", |
896 | 16 | "Whether to validate the STT checksum or not.", |
897 | 16 | &pref_check_checksum); |
898 | | |
899 | 16 | reassembly_table_register(&stt_reassembly_table, |
900 | 16 | &addresses_reassembly_table_functions); |
901 | 16 | } |
902 | | |
903 | | void |
904 | | proto_reg_handoff_stt(void) |
905 | 16 | { |
906 | | /* |
907 | | * The I-D doesn't explicitly indicate that the FCS isn't present |
908 | | * in the tunneled Ethernet frames, but it is missing from the |
909 | | * captures attached to bug 10282. |
910 | | */ |
911 | 16 | eth_handle = find_dissector_add_dependency("eth_withoutfcs", proto_stt); |
912 | | |
913 | 16 | heur_dissector_add("ip", dissect_stt_heur, "Stateless Transport Tunneling over IP", "stt_ip", proto_stt, HEURISTIC_ENABLE); |
914 | 16 | } |
915 | | |
916 | | /* |
917 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
918 | | * |
919 | | * Local variables: |
920 | | * c-basic-offset: 4 |
921 | | * tab-width: 8 |
922 | | * indent-tabs-mode: nil |
923 | | * End: |
924 | | * |
925 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
926 | | * :indentSize=4:tabSize=8:noTabs=true: |
927 | | */ |