/src/wireshark/epan/dissectors/packet-xip-serval.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-xip-serval.c |
2 | | * Routines for XIP Serval dissection |
3 | | * |
4 | | * Wireshark - Network traffic analyzer |
5 | | * By Gerald Combs <gerald@wireshark.org> |
6 | | * Copyright 1998 Gerald Combs |
7 | | * |
8 | | * SPDX-License-Identifier: GPL-2.0-or-later |
9 | | * |
10 | | * Serval is a service-centric architecture that has been ported to XIA to |
11 | | * allow applications to communicate using service names. |
12 | | */ |
13 | | |
14 | | #include "config.h" |
15 | | #include <epan/packet.h> |
16 | | #include <epan/expert.h> |
17 | | #include <epan/in_cksum.h> |
18 | | #include <epan/tfs.h> |
19 | | #include <epan/unit_strings.h> |
20 | | |
21 | | #include <wsutil/array.h> |
22 | | #include <ipproto.h> |
23 | | |
24 | | void proto_register_xip_serval(void); |
25 | | void proto_reg_handoff_xip_serval(void); |
26 | | |
27 | | static dissector_handle_t tcp_handle; |
28 | | static dissector_handle_t udp_handle; |
29 | | |
30 | | static int proto_xip_serval; |
31 | | |
32 | | /* XIP Serval header. */ |
33 | | static int hf_xip_serval_hl; |
34 | | static int hf_xip_serval_proto; |
35 | | static int hf_xip_serval_check; |
36 | | static int hf_xip_serval_check_status; |
37 | | |
38 | | /* XIP Serval general extension header. */ |
39 | | static int hf_xip_serval_ext_type; |
40 | | static int hf_xip_serval_ext_length; |
41 | | |
42 | | /* XIP Serval control extension header. */ |
43 | | static int hf_xip_serval_cext; |
44 | | static int hf_xip_serval_cext_flags; |
45 | | static int hf_xip_serval_cext_syn; |
46 | | static int hf_xip_serval_cext_rsyn; |
47 | | static int hf_xip_serval_cext_ack; |
48 | | static int hf_xip_serval_cext_nack; |
49 | | static int hf_xip_serval_cext_rst; |
50 | | static int hf_xip_serval_cext_fin; |
51 | | static int hf_xip_serval_cext_verno; |
52 | | static int hf_xip_serval_cext_ackno; |
53 | | static int hf_xip_serval_cext_nonce; |
54 | | |
55 | | static int ett_xip_serval_tree; |
56 | | static int ett_xip_serval_cext; |
57 | | static int ett_xip_serval_cext_flags; |
58 | | |
59 | | static expert_field ei_xip_serval_bad_len; |
60 | | static expert_field ei_xip_serval_bad_proto; |
61 | | static expert_field ei_xip_serval_bad_checksum; |
62 | | static expert_field ei_xip_serval_bad_ext; |
63 | | |
64 | 1 | #define XIP_SERVAL_PROTO_DATA 0 |
65 | | static const value_string xip_serval_proto_vals[] = { |
66 | | { XIP_SERVAL_PROTO_DATA, "Data" }, |
67 | | { IP_PROTO_TCP, "TCP" }, |
68 | | { IP_PROTO_UDP, "UDP" }, |
69 | | { 0, NULL }, |
70 | | }; |
71 | | |
72 | | static int * const xip_serval_cext_flags[] = { |
73 | | &hf_xip_serval_cext_syn, |
74 | | &hf_xip_serval_cext_rsyn, |
75 | | &hf_xip_serval_cext_ack, |
76 | | &hf_xip_serval_cext_nack, |
77 | | &hf_xip_serval_cext_rst, |
78 | | &hf_xip_serval_cext_fin, |
79 | | NULL |
80 | | }; |
81 | | |
82 | 13 | #define XIP_SERVAL_MIN_LEN 4 |
83 | | |
84 | 39 | #define XIP_SERVAL_EXT_MIN_LEN 2 |
85 | 32 | #define XIP_SERVAL_EXT_TYPE_MASK 0xF0 |
86 | 25 | #define XIP_SERVAL_EXT_TYPE_CONTROL 0 |
87 | | |
88 | | #define XIP_SERVAL_CEXT_FLAGS_WIDTH 8 |
89 | | #define XIP_SERVAL_CEXT_NONCE_SIZE 8 |
90 | 25 | #define XIP_SERVAL_CEXT_LEN 20 |
91 | | |
92 | 26 | #define XSRVL_LEN 0 |
93 | 26 | #define XSRVL_PRO 1 |
94 | 13 | #define XSRVL_CHK 2 |
95 | 13 | #define XSRVL_EXT 4 |
96 | | |
97 | | static uint8_t |
98 | | display_xip_serval_control_ext(tvbuff_t *tvb, proto_tree *xip_serval_tree, |
99 | | int offset, uint8_t type, uint8_t length) |
100 | 25 | { |
101 | 25 | proto_tree *cext_tree; |
102 | 25 | proto_item *ti; |
103 | | |
104 | | /* Create Serval Control Extension tree. */ |
105 | 25 | ti = proto_tree_add_item(xip_serval_tree, hf_xip_serval_cext, tvb, |
106 | 25 | offset, length, ENC_NA); |
107 | 25 | cext_tree = proto_item_add_subtree(ti, ett_xip_serval_cext); |
108 | | |
109 | | /* Add XIP Serval extension type. */ |
110 | 25 | proto_tree_add_uint(cext_tree, hf_xip_serval_ext_type, tvb, |
111 | 25 | offset, 1, type); |
112 | 25 | offset++; |
113 | | |
114 | | /* Add XIP Serval extension length. */ |
115 | 25 | proto_tree_add_item(cext_tree, hf_xip_serval_ext_length, tvb, |
116 | 25 | offset, 1, ENC_BIG_ENDIAN); |
117 | 25 | offset++; |
118 | | |
119 | | /* Create XIP Serval Control Extension flags tree. */ |
120 | 25 | proto_tree_add_bitmask(cext_tree, tvb, offset, |
121 | 25 | hf_xip_serval_cext_flags, ett_xip_serval_cext_flags, |
122 | 25 | xip_serval_cext_flags, ENC_BIG_ENDIAN); |
123 | | |
124 | | /* Skip two bits for res1. */ |
125 | 25 | offset++; |
126 | | |
127 | | /* Skip a byte for res2. */ |
128 | 25 | offset++; |
129 | | |
130 | | /* Add verification number. */ |
131 | 25 | proto_tree_add_item(cext_tree, hf_xip_serval_cext_verno, |
132 | 25 | tvb, offset, 4, ENC_BIG_ENDIAN); |
133 | 25 | offset += 4; |
134 | | |
135 | | /* Add acknowledgement number. */ |
136 | 25 | proto_tree_add_item(cext_tree, hf_xip_serval_cext_ackno, |
137 | 25 | tvb, offset, 4, ENC_BIG_ENDIAN); |
138 | 25 | offset += 4; |
139 | | |
140 | | /* Add nonce. */ |
141 | 25 | proto_tree_add_item(cext_tree, hf_xip_serval_cext_nonce, |
142 | 25 | tvb, offset, 8, ENC_NA); |
143 | | |
144 | | /* Displayed XIP_SERVAL_CEXT_LEN bytes. */ |
145 | 25 | return XIP_SERVAL_CEXT_LEN; |
146 | 25 | } |
147 | | |
148 | | static uint8_t |
149 | | display_xip_serval_ext(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti, |
150 | | proto_tree *xip_serval_tree, int offset) |
151 | 32 | { |
152 | 32 | uint8_t type = tvb_get_uint8(tvb, offset) & XIP_SERVAL_EXT_TYPE_MASK; |
153 | 32 | uint8_t length = tvb_get_uint8(tvb, offset + 1); |
154 | | |
155 | | /* For now, the only type of extension header in XIP Serval is |
156 | | * the control extension header. |
157 | | */ |
158 | 32 | switch (type) { |
159 | 25 | case XIP_SERVAL_EXT_TYPE_CONTROL: |
160 | 25 | return display_xip_serval_control_ext(tvb, xip_serval_tree, |
161 | 25 | offset, type, length); |
162 | 6 | default: |
163 | 6 | expert_add_info_format(pinfo, ti, &ei_xip_serval_bad_ext, |
164 | 6 | "Unrecognized Serval extension header type: 0x%02x", |
165 | 6 | type); |
166 | 6 | return 0; |
167 | 32 | } |
168 | 32 | } |
169 | | |
170 | | static void |
171 | | display_xip_serval(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) |
172 | 13 | { |
173 | 13 | proto_tree *xip_serval_tree; |
174 | 13 | proto_item *ti, *hl_ti; |
175 | 13 | tvbuff_t *next_tvb; |
176 | | |
177 | 13 | vec_t cksum_vec; |
178 | 13 | int offset; |
179 | 13 | uint8_t xsh_len, protocol, bytes_remaining; |
180 | | |
181 | | /* Get XIP Serval header length, stored as number of 32-bit words. */ |
182 | 13 | xsh_len = tvb_get_uint8(tvb, XSRVL_LEN) << 2; |
183 | | |
184 | | /* Create XIP Serval header tree. */ |
185 | 13 | ti = proto_tree_add_item(tree, proto_xip_serval, tvb, |
186 | 13 | 0, xsh_len, ENC_NA); |
187 | 13 | xip_serval_tree = proto_item_add_subtree(ti, ett_xip_serval_tree); |
188 | | |
189 | | /* Add XIP Serval header length. */ |
190 | 13 | hl_ti = proto_tree_add_item(xip_serval_tree, hf_xip_serval_hl, tvb, |
191 | 13 | XSRVL_LEN, 1, ENC_BIG_ENDIAN); |
192 | 13 | if (tvb_captured_length(tvb) < xsh_len) |
193 | 2 | expert_add_info_format(pinfo, hl_ti, &ei_xip_serval_bad_len, |
194 | 2 | "Header Length field (%d bytes) cannot be greater than actual number of bytes left in packet (%d bytes)", |
195 | 2 | xsh_len, tvb_captured_length(tvb)); |
196 | | |
197 | | /* Add XIP Serval protocol. If it's not data, TCP, or UDP, the |
198 | | * packet is malformed. |
199 | | */ |
200 | 13 | proto_tree_add_item(xip_serval_tree, hf_xip_serval_proto, tvb, |
201 | 13 | XSRVL_PRO, 1, ENC_BIG_ENDIAN); |
202 | 13 | protocol = tvb_get_uint8(tvb, XSRVL_PRO); |
203 | 13 | if (!try_val_to_str(protocol, xip_serval_proto_vals)) |
204 | 7 | expert_add_info_format(pinfo, ti, &ei_xip_serval_bad_proto, |
205 | 7 | "Unrecognized protocol type: %d", protocol); |
206 | | |
207 | | /* Compute checksum. */ |
208 | 13 | SET_CKSUM_VEC_TVB(cksum_vec, tvb, 0, xsh_len); |
209 | | |
210 | 13 | proto_tree_add_checksum(xip_serval_tree, tvb, XSRVL_CHK, hf_xip_serval_check, hf_xip_serval_check_status, &ei_xip_serval_bad_checksum, pinfo, in_cksum(&cksum_vec, 1), |
211 | 13 | ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_IN_CKSUM); |
212 | 13 | offset = XSRVL_EXT; |
213 | | |
214 | | /* If there's still more room, check for extension headers. */ |
215 | 13 | bytes_remaining = xsh_len - offset; |
216 | 39 | while (bytes_remaining >= XIP_SERVAL_EXT_MIN_LEN) { |
217 | 32 | int8_t bytes_displayed = display_xip_serval_ext(tvb, pinfo, ti, |
218 | 32 | xip_serval_tree, offset); |
219 | | |
220 | | /* Extension headers are malformed, so we can't say |
221 | | * what the rest of the packet holds. Stop dissecting. |
222 | | */ |
223 | 32 | if (bytes_displayed <= 0) |
224 | 6 | return; |
225 | | |
226 | 26 | offset += bytes_displayed; |
227 | 26 | bytes_remaining -= bytes_displayed; |
228 | 26 | } |
229 | | |
230 | 7 | switch (protocol) { |
231 | 1 | case XIP_SERVAL_PROTO_DATA: |
232 | 1 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
233 | 1 | call_data_dissector(next_tvb, pinfo, tree); |
234 | 1 | break; |
235 | 0 | case IP_PROTO_TCP: { |
236 | | /* Get the Data Offset field of the TCP header, which is |
237 | | * the high nibble of the 12th octet and represents the |
238 | | * size of the TCP header of 32-bit words. |
239 | | */ |
240 | 0 | uint8_t tcp_len = hi_nibble(tvb_get_uint8(tvb, offset + 12))*4; |
241 | 0 | next_tvb = tvb_new_subset_length(tvb, offset, tcp_len); |
242 | 0 | call_dissector(tcp_handle, next_tvb, pinfo, tree); |
243 | 0 | break; |
244 | 0 | } |
245 | 0 | case IP_PROTO_UDP: |
246 | | /* The UDP header is always 8 bytes. */ |
247 | 0 | next_tvb = tvb_new_subset_length(tvb, offset, 8); |
248 | 0 | call_dissector(udp_handle, next_tvb, pinfo, tree); |
249 | 0 | break; |
250 | 1 | default: |
251 | 1 | break; |
252 | 7 | } |
253 | 7 | } |
254 | | |
255 | | static int |
256 | | dissect_xip_serval(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
257 | | void *data _U_) |
258 | 13 | { |
259 | 13 | if (tvb_reported_length(tvb) < XIP_SERVAL_MIN_LEN) |
260 | 0 | return 0; |
261 | | |
262 | 13 | col_append_str(pinfo->cinfo, COL_INFO, " (with Serval)"); |
263 | | |
264 | 13 | display_xip_serval(tvb, pinfo, tree); |
265 | 13 | return tvb_captured_length(tvb); |
266 | 13 | } |
267 | | |
268 | | void |
269 | | proto_register_xip_serval(void) |
270 | 14 | { |
271 | 14 | static hf_register_info hf[] = { |
272 | | |
273 | | /* Serval Header. */ |
274 | | |
275 | 14 | { &hf_xip_serval_hl, |
276 | 14 | { "Header Length", "xip_serval.hl", FT_UINT8, |
277 | 14 | BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL }}, |
278 | | |
279 | 14 | { &hf_xip_serval_proto, |
280 | 14 | { "Protocol", "xip_serval.proto", FT_UINT8, |
281 | 14 | BASE_DEC, VALS(xip_serval_proto_vals), 0x0, NULL, HFILL }}, |
282 | | |
283 | 14 | { &hf_xip_serval_check, |
284 | 14 | { "Checksum", "xip_serval.check", FT_UINT16, |
285 | 14 | BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
286 | | |
287 | 14 | { &hf_xip_serval_check_status, |
288 | 14 | { "Checksum Status", "xip_serval.check.status", FT_UINT8, |
289 | 14 | BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL }}, |
290 | | |
291 | | /* Serval Extension Header. */ |
292 | | |
293 | 14 | { &hf_xip_serval_ext_type, |
294 | 14 | { "Extension Type", "xip_serval.ext_type", FT_UINT8, |
295 | 14 | BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
296 | | |
297 | 14 | { &hf_xip_serval_ext_length, |
298 | 14 | { "Extension Length", "xip_serval.ext_length", FT_UINT8, |
299 | 14 | BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL }}, |
300 | | |
301 | | /* Serval Control Extension Header. */ |
302 | | |
303 | 14 | { &hf_xip_serval_cext, |
304 | 14 | { "Serval Control Extension", "xip_serval.cext", |
305 | 14 | FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
306 | | |
307 | 14 | { &hf_xip_serval_cext_flags, |
308 | 14 | { "Flags", "xip_serval.cext_flags", FT_UINT8, BASE_HEX, |
309 | 14 | NULL, 0x0, NULL, HFILL }}, |
310 | | |
311 | 14 | { &hf_xip_serval_cext_syn, |
312 | 14 | { "SYN", "xip_serval.cext_syn", FT_BOOLEAN, 8, |
313 | 14 | TFS(&tfs_set_notset), 0x80, NULL, HFILL }}, |
314 | | |
315 | 14 | { &hf_xip_serval_cext_rsyn, |
316 | 14 | { "RSYN", "xip_serval.cext_rsyn", FT_BOOLEAN, 8, |
317 | 14 | TFS(&tfs_set_notset), 0x40, NULL, HFILL }}, |
318 | | |
319 | 14 | { &hf_xip_serval_cext_ack, |
320 | 14 | { "ACK", "xip_serval.cext_ack", FT_BOOLEAN, 8, |
321 | 14 | TFS(&tfs_set_notset), 0x20, NULL, HFILL }}, |
322 | | |
323 | 14 | { &hf_xip_serval_cext_nack, |
324 | 14 | { "NACK", "xip_serval.cext_nack", FT_BOOLEAN, 8, |
325 | 14 | TFS(&tfs_set_notset), 0x10, NULL, HFILL }}, |
326 | | |
327 | 14 | { &hf_xip_serval_cext_rst, |
328 | 14 | { "RST", "xip_serval.cext_rst", FT_BOOLEAN, 8, |
329 | 14 | TFS(&tfs_set_notset), 0x08, NULL, HFILL }}, |
330 | | |
331 | 14 | { &hf_xip_serval_cext_fin, |
332 | 14 | { "FIN", "xip_serval.cext_fin", FT_BOOLEAN, 8, |
333 | 14 | TFS(&tfs_set_notset), 0x04, NULL, HFILL }}, |
334 | | |
335 | 14 | { &hf_xip_serval_cext_verno, |
336 | 14 | { "Version Number", "xip_serval.cext_verno", FT_UINT32, |
337 | 14 | BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
338 | | |
339 | 14 | { &hf_xip_serval_cext_ackno, |
340 | 14 | { "Acknowledgement Number", "xip_serval.cext_ackno", |
341 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
342 | | |
343 | 14 | { &hf_xip_serval_cext_nonce, |
344 | 14 | { "Nonce", "xip_serval.cext_nonce", FT_BYTES, |
345 | 14 | SEP_SPACE, NULL, 0x0, NULL, HFILL }} |
346 | 14 | }; |
347 | | |
348 | 14 | static int *ett[] = { |
349 | 14 | &ett_xip_serval_tree, |
350 | 14 | &ett_xip_serval_cext, |
351 | 14 | &ett_xip_serval_cext_flags |
352 | 14 | }; |
353 | | |
354 | 14 | static ei_register_info ei[] = { |
355 | | |
356 | 14 | { &ei_xip_serval_bad_len, |
357 | 14 | { "xip_serval.bad_len", PI_MALFORMED, PI_ERROR, |
358 | 14 | "Bad header length", EXPFILL }}, |
359 | | |
360 | 14 | { &ei_xip_serval_bad_ext, |
361 | 14 | { "xip_serval.bad_ext", PI_MALFORMED, PI_ERROR, |
362 | 14 | "Bad extension header type", EXPFILL }}, |
363 | | |
364 | 14 | { &ei_xip_serval_bad_proto, |
365 | 14 | { "xip_serval.bad_proto", PI_MALFORMED, PI_ERROR, |
366 | 14 | "Bad protocol type", EXPFILL }}, |
367 | | |
368 | 14 | { &ei_xip_serval_bad_checksum, |
369 | 14 | { "xip_serval.bad_checksum", PI_MALFORMED, PI_ERROR, |
370 | 14 | "Incorrect checksum", EXPFILL }} |
371 | 14 | }; |
372 | | |
373 | 14 | expert_module_t* expert_xip_serval; |
374 | | |
375 | 14 | proto_xip_serval = proto_register_protocol("XIP Serval", "XIP Serval", "xipserval"); |
376 | 14 | register_dissector("xipserval", dissect_xip_serval, |
377 | 14 | proto_xip_serval); |
378 | 14 | proto_register_field_array(proto_xip_serval, hf, array_length(hf)); |
379 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
380 | | |
381 | 14 | expert_xip_serval = expert_register_protocol(proto_xip_serval); |
382 | 14 | expert_register_field_array(expert_xip_serval, ei, array_length(ei)); |
383 | 14 | } |
384 | | |
385 | | void |
386 | | proto_reg_handoff_xip_serval(void) |
387 | 14 | { |
388 | 14 | tcp_handle = find_dissector_add_dependency("tcp", proto_xip_serval); |
389 | 14 | udp_handle = find_dissector_add_dependency("udp", proto_xip_serval); |
390 | 14 | } |
391 | | |
392 | | /* |
393 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
394 | | * |
395 | | * Local variables: |
396 | | * c-basic-offset: 8 |
397 | | * tab-width: 8 |
398 | | * indent-tabs-mode: t |
399 | | * End: |
400 | | * |
401 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
402 | | * :indentSize=8:tabSize=8:noTabs=false: |
403 | | */ |