/src/wireshark/epan/dissectors/packet-ixiatrailer.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* packet-ixiatrailer.c |
2 | | * Routines for Ixia trailer parsing |
3 | | * |
4 | | * Dissector for Ixia Network Visibility Solutions trailer |
5 | | * Copyright Ixia 2012 |
6 | | * |
7 | | * Wireshark - Network traffic analyzer |
8 | | * By Gerald Combs <gerald@wireshark.org> |
9 | | * Copyright 1998 Gerald Combs |
10 | | * |
11 | | * SPDX-License-Identifier: GPL-2.0-or-later |
12 | | */ |
13 | | |
14 | | #include "config.h" |
15 | | |
16 | | #include <epan/packet.h> |
17 | | #include <wsutil/pint.h> |
18 | | #include <epan/prefs.h> |
19 | | #include <epan/in_cksum.h> |
20 | | #include <epan/expert.h> |
21 | | |
22 | | void proto_register_ixiatrailer(void); |
23 | | void proto_reg_handoff_ixiatrailer(void); |
24 | | |
25 | | /* Trailer "magic number". */ |
26 | 1.05k | #define IXIA_PATTERN 0xAF12 |
27 | | |
28 | | /* Trailer TLV types. |
29 | | |
30 | | TODO: which of these typestamp types are currently supported? |
31 | | Should lose the rest!! */ |
32 | 0 | #define IXIATRAILER_FTYPE_ORIGINAL_PACKET_SIZE 1 |
33 | 0 | #define IXIATRAILER_FTYPE_TIMESTAMP_LOCAL 3 |
34 | 0 | #define IXIATRAILER_FTYPE_TIMESTAMP_NTP 4 |
35 | 0 | #define IXIATRAILER_FTYPE_TIMESTAMP_GPS 5 |
36 | 0 | #define IXIATRAILER_FTYPE_TIMESTAMP_1588 6 /* PTP */ |
37 | 0 | #define IXIATRAILER_FTYPE_TIMESTAMP_HOLDOVER 7 |
38 | | |
39 | | static const value_string ixiatrailer_ftype_timestamp[] = { |
40 | | { IXIATRAILER_FTYPE_TIMESTAMP_LOCAL, "Local" }, |
41 | | { IXIATRAILER_FTYPE_TIMESTAMP_NTP, "NTP" }, |
42 | | { IXIATRAILER_FTYPE_TIMESTAMP_GPS, "GPS" }, |
43 | | { IXIATRAILER_FTYPE_TIMESTAMP_1588, "PTP" }, |
44 | | { IXIATRAILER_FTYPE_TIMESTAMP_HOLDOVER, "Holdover" }, |
45 | | { 0, NULL } |
46 | | }; |
47 | | |
48 | | /* Preference settings */ |
49 | | static bool ixiatrailer_summary_in_tree = true; |
50 | | |
51 | | static int proto_ixiatrailer; |
52 | | static int ett_ixiatrailer; |
53 | | |
54 | | static int hf_ixiatrailer_packetlen; |
55 | | static int hf_ixiatrailer_timestamp; |
56 | | static int hf_ixiatrailer_generic; |
57 | | |
58 | | static expert_field ei_ixiatrailer_field_length_invalid; |
59 | | |
60 | | /* The trailer begins with a sequence of TLVs, each of which has a |
61 | | 1-byte type, a 1-byte value length (not TLV length, so the TLV |
62 | | length is the value length + 2), and a variable-length value. |
63 | | |
64 | | Following the sequence of TLVs is: |
65 | | |
66 | | a 1-byte field giving the length of the sequence of TLVs; |
67 | | a 2-byte big-endian signature field with the value 0xAF12; |
68 | | a 2-byte big-endian checksum field, covering the sequence |
69 | | of TLVs, the sequence length, and the signature. |
70 | | */ |
71 | | static int |
72 | | dissect_ixiatrailer(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) |
73 | 620 | { |
74 | 620 | proto_tree *ti; |
75 | 620 | unsigned tvblen, trailer_length, field_length; |
76 | 620 | bool matched_without_fcs, matched_with_fcs; |
77 | 620 | proto_tree *ixiatrailer_tree = NULL; |
78 | 620 | unsigned offset = 0; |
79 | 620 | uint16_t cksum, comp_cksum; |
80 | 620 | vec_t vec; |
81 | 620 | uint8_t field_type; |
82 | | |
83 | | /* A trailer must, at minimum, include: |
84 | | |
85 | | a "original packet size" TLV, with 1 byte of type, 1 byte of |
86 | | value length, and 2 bytes of original packet ize; |
87 | | |
88 | | 1 byte of trailer length; |
89 | | |
90 | | 2 bytes of signature; |
91 | | |
92 | | 2 bytes of trailer checksum; |
93 | | |
94 | | for a total of 9 bytes. */ |
95 | 620 | tvblen = tvb_reported_length(tvb); |
96 | 620 | if (tvblen != tvb_captured_length(tvb)) { |
97 | | /* The heuristic check includes a checksum check, so we need the |
98 | | *entire* trailer to have been captured; if it wasn't, we don't |
99 | | try to check it. */ |
100 | 0 | return 0; |
101 | 0 | } |
102 | 620 | if (tvblen < 9) { |
103 | | /* This is too short, so it cannot be a valid Ixia trailer. */ |
104 | 69 | return 0; |
105 | 69 | } |
106 | | |
107 | | /* Depending upon the ethernet preference "Assume packets have FCS", we |
108 | | may be given those 4 bytes too. |
109 | | |
110 | | Try checking two locations for our pattern. */ |
111 | | |
112 | 551 | if (tvblen == 23) { |
113 | 3 | tvblen = 19; |
114 | 3 | } |
115 | | |
116 | | /* 3rd & 4th bytes from the end must match our pattern. |
117 | | First, try under the assumption that the tvbuff doesn't include |
118 | | the FCS. */ |
119 | 551 | matched_without_fcs = (tvb_get_ntohs(tvb, tvblen-4) == IXIA_PATTERN); |
120 | | |
121 | | /* If that didn't match, is the tvbuff big enough to include an Ixia |
122 | | trailer *and* an FCS? If so, try under that assumption. */ |
123 | 551 | if (!matched_without_fcs && tvblen >= 13) |
124 | 505 | matched_with_fcs = (tvb_get_ntohs(tvb, tvblen-(4+4)) == IXIA_PATTERN); |
125 | 46 | else |
126 | 46 | matched_with_fcs = false; |
127 | 551 | if (!matched_without_fcs) { |
128 | 551 | if (!matched_with_fcs) { |
129 | | /* Neither matched, so no Ixia trailer. */ |
130 | 551 | return 0; |
131 | 551 | } |
132 | | |
133 | | /* Matched under the assumption that we have an FCS, so let's |
134 | | act as if that's the case. Remove the FCS length from the |
135 | | tvbuff. */ |
136 | 0 | tvblen -= 4; |
137 | 0 | } |
138 | | |
139 | | /* Read Trailer-length field */ |
140 | 0 | trailer_length = tvb_get_uint8(tvb, tvblen-5); |
141 | | /* Should match overall length of trailer */ |
142 | 0 | if ((tvblen-5) != trailer_length) { |
143 | 0 | return 0; |
144 | 0 | } |
145 | | |
146 | | /* Last 2 bytes are the checksum */ |
147 | 0 | cksum = tvb_get_ntohs(tvb, tvblen-2); |
148 | | |
149 | | /* Verify the checksum; if not valid, it means that the trailer is not valid */ |
150 | 0 | SET_CKSUM_VEC_TVB(vec, tvb, offset, trailer_length + 3); |
151 | 0 | comp_cksum = in_cksum(&vec, 1); |
152 | 0 | if (pntoh16(&comp_cksum) != cksum) { |
153 | 0 | return 0; |
154 | 0 | } |
155 | | |
156 | | /* OK: We have our trailer - create protocol root */ |
157 | 0 | ti = proto_tree_add_item(tree, proto_ixiatrailer, tvb, offset, trailer_length + 5, ENC_NA); |
158 | | |
159 | | /* Append summary to item, if configured to */ |
160 | 0 | if (ixiatrailer_summary_in_tree) { |
161 | 0 | proto_item_append_text(ti, ", Length: %u, Checksum: 0x%x", trailer_length, cksum); |
162 | 0 | } |
163 | | |
164 | | /* Create subtree */ |
165 | 0 | ixiatrailer_tree = proto_item_add_subtree(ti, ett_ixiatrailer); |
166 | |
|
167 | 0 | while (offset < trailer_length - 2) |
168 | 0 | { |
169 | 0 | field_type = tvb_get_uint8(tvb, offset++); |
170 | 0 | field_length = tvb_get_uint8(tvb, offset++); |
171 | 0 | switch (field_type) { |
172 | 0 | case IXIATRAILER_FTYPE_ORIGINAL_PACKET_SIZE: |
173 | 0 | if (field_length != 2){ |
174 | 0 | expert_add_info_format(pinfo, ti, &ei_ixiatrailer_field_length_invalid, "Field length %u invalid", field_length); |
175 | 0 | break; |
176 | 0 | } |
177 | 0 | ti = proto_tree_add_item(ixiatrailer_tree, hf_ixiatrailer_packetlen, tvb, offset, field_length, ENC_BIG_ENDIAN); |
178 | 0 | proto_item_append_text(ti, " bytes"); |
179 | 0 | break; |
180 | 0 | case IXIATRAILER_FTYPE_TIMESTAMP_LOCAL: |
181 | 0 | case IXIATRAILER_FTYPE_TIMESTAMP_NTP: |
182 | 0 | case IXIATRAILER_FTYPE_TIMESTAMP_GPS: |
183 | 0 | case IXIATRAILER_FTYPE_TIMESTAMP_1588: |
184 | 0 | case IXIATRAILER_FTYPE_TIMESTAMP_HOLDOVER: |
185 | 0 | if (field_length != 8) { |
186 | 0 | expert_add_info_format(pinfo, ti, &ei_ixiatrailer_field_length_invalid, "Field length %u invalid", field_length); |
187 | 0 | break; |
188 | 0 | } |
189 | | /* Timestamp */ |
190 | 0 | ti = proto_tree_add_item(ixiatrailer_tree, hf_ixiatrailer_timestamp, tvb, offset, field_length, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN); |
191 | 0 | proto_item_append_text(ti, "; Source: %s", val_to_str_const(field_type, ixiatrailer_ftype_timestamp, "Unknown")); |
192 | 0 | break; |
193 | 0 | default: |
194 | | /* Not a recognized time format - just show as bytes */ |
195 | 0 | ti = proto_tree_add_item(ixiatrailer_tree, hf_ixiatrailer_generic, tvb, offset, field_length, ENC_NA); |
196 | 0 | proto_item_append_text(ti, " [Id: %u, Length: %u bytes]", field_type, field_length); |
197 | 0 | break; |
198 | 0 | }; |
199 | 0 | offset += field_length; |
200 | 0 | } |
201 | | /* We are claiming all of the bytes */ |
202 | 0 | return tvblen; |
203 | 0 | } |
204 | | |
205 | | static bool |
206 | | dissect_ixiatrailer_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
207 | 620 | { |
208 | 620 | return dissect_ixiatrailer(tvb, pinfo, tree, data) > 0; |
209 | 620 | } |
210 | | |
211 | | void |
212 | | proto_register_ixiatrailer(void) |
213 | 14 | { |
214 | | |
215 | 14 | static hf_register_info hf[] = { |
216 | 14 | { &hf_ixiatrailer_packetlen, { |
217 | 14 | "Original packet length", "ixiatrailer.packetlen", FT_UINT16, BASE_DEC, |
218 | 14 | NULL, 0x0, NULL, HFILL }}, |
219 | 14 | { &hf_ixiatrailer_timestamp, { |
220 | 14 | "Time Stamp", "ixiatrailer.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, |
221 | 14 | NULL, 0x0, NULL, HFILL }}, |
222 | 14 | { &hf_ixiatrailer_generic, { |
223 | 14 | "Generic Field", "ixiatrailer.generic", FT_BYTES, BASE_NONE, |
224 | 14 | NULL, 0x0, NULL, HFILL }}, |
225 | 14 | }; |
226 | | |
227 | 14 | static int *ixiatrailer_ett[] = { |
228 | 14 | &ett_ixiatrailer |
229 | 14 | }; |
230 | | |
231 | 14 | static ei_register_info ei[] = { |
232 | 14 | { &ei_ixiatrailer_field_length_invalid, { "ixiatrailer.field_length_invalid", PI_MALFORMED, PI_ERROR, "Field length invalid", EXPFILL }}, |
233 | 14 | }; |
234 | | |
235 | 14 | module_t *ixiatrailer_module; |
236 | 14 | expert_module_t* expert_ixiatrailer; |
237 | | |
238 | 14 | proto_ixiatrailer = proto_register_protocol("Ixia Trailer", "IXIATRAILER", "ixiatrailer"); |
239 | 14 | proto_register_field_array(proto_ixiatrailer, hf, array_length(hf)); |
240 | 14 | proto_register_subtree_array(ixiatrailer_ett, array_length(ixiatrailer_ett)); |
241 | 14 | expert_ixiatrailer = expert_register_protocol(proto_ixiatrailer); |
242 | 14 | expert_register_field_array(expert_ixiatrailer, ei, array_length(ei)); |
243 | | |
244 | 14 | ixiatrailer_module = prefs_register_protocol(proto_ixiatrailer, NULL); |
245 | 14 | prefs_register_bool_preference(ixiatrailer_module, "summary_in_tree", |
246 | 14 | "Show trailer summary in protocol tree", |
247 | 14 | "Whether the trailer summary line should be shown in the protocol tree", |
248 | 14 | &ixiatrailer_summary_in_tree); |
249 | 14 | } |
250 | | |
251 | | |
252 | | void |
253 | | proto_reg_handoff_ixiatrailer(void) |
254 | 14 | { |
255 | | /* Check for Ixia format in the ethernet trailer */ |
256 | 14 | heur_dissector_add("eth.trailer", dissect_ixiatrailer_heur, "Ixia Trailer", "ixiatrailer_eth", proto_ixiatrailer, HEURISTIC_ENABLE); |
257 | 14 | } |
258 | | |
259 | | /* |
260 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
261 | | * |
262 | | * Local Variables: |
263 | | * c-basic-offset: 2 |
264 | | * tab-width: 8 |
265 | | * indent-tabs-mode: nil |
266 | | * End: |
267 | | * |
268 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
269 | | * :indentSize=2:tabSize=8:noTabs=true: |
270 | | */ |