/src/wireshark/epan/dissectors/packet-ipmi-trace.c
Line | Count | Source |
1 | | /* packet-ipmi-trace.c |
2 | | * Routines for HPM.2 Trace Data Block disassembly |
3 | | * By Dmitry Bazhenov <dima_b@pigeonpoint.com> |
4 | | * Copyright 2014 Pigeon Point Systems |
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 | | |
13 | | #include "config.h" |
14 | | |
15 | | #include <epan/packet.h> |
16 | | #include <wiretap/wtap.h> |
17 | | #include "packet-ipmi.h" |
18 | | |
19 | | /* |
20 | | * See |
21 | | * |
22 | | * http://www.picmg.org/v2internal/resourcepage2.cfm?id=12 |
23 | | */ |
24 | | |
25 | | /* Trace data block types. */ |
26 | | enum { |
27 | | HPM2_TRACE_PACKET_DATA = 0, |
28 | | HPM2_CHN_STATE_NOTIFY = 1, |
29 | | HPM2_EMBED_ASCII_MSG = 2 |
30 | | }; |
31 | | |
32 | | /* Data directions. */ |
33 | | enum { |
34 | | HPM2_TRACE_DATA_OUT = 0, /* From IPM controller */ |
35 | | HPM2_TRACE_DATA_IN = 1 /* To IPM controller */ |
36 | | }; |
37 | | |
38 | | /* Redundant channel indicators. */ |
39 | | enum { |
40 | | HPM2_TRACE_1ST_CHN = 0, |
41 | | HPM2_TRACE_2ND_CHN = 1 |
42 | | }; |
43 | | |
44 | | /* IPMB local status values. */ |
45 | | enum { |
46 | | HPM2_IPMB_S_OK = 0, |
47 | | HPM2_IPMB_S_ERR_SCL_HI = 1, |
48 | | HPM2_IPMB_S_ERR_SDA_HI = 2, |
49 | | HPM2_IPMB_S_ERR_SCL_LO = 3, |
50 | | HPM2_IPMB_S_ERR_SDA_LO = 4, |
51 | | HPM2_IPMB_S_SCL_TIMEOUT = 5, |
52 | | HPM2_IPMB_S_UNDER_TEST = 6, |
53 | | HPM2_IPMB_S_UNKNOWN_ERR = 7 |
54 | | }; |
55 | | |
56 | | /* IPMI channel protocol types. */ |
57 | | enum { |
58 | | IPMI_PROTO_IPMB_1_0 = 0x01, |
59 | | IPMI_PROTO_ICMB_1_0 = 0x02, |
60 | | IPMI_PROTO_IPMI_SMBUS = 0x04, |
61 | | IPMI_PROTO_KCS = 0x05, |
62 | | IPMI_PROTO_SMIC = 0x06, |
63 | | IPMI_PROTO_BT_10 = 0x07, |
64 | | IPMI_PROTO_BT_15 = 0x08, |
65 | | IPMI_PROTO_TMODE = 0x09, |
66 | | IPMI_PROTO_OEM_1 = 0x1C, |
67 | | IPMI_PROTO_OEM_2 = 0x1D, |
68 | | IPMI_PROTO_OEM_3 = 0x1E, |
69 | | IPMI_PROTO_OEM_4 = 0x1F |
70 | | }; |
71 | | |
72 | | /* IPMB override status values. */ |
73 | | enum { |
74 | | HPM2_IPMB_S_ISOLATED = 0, |
75 | | HPM2_IPMB_S_LOCAL_CTRL = 1 |
76 | | }; |
77 | | |
78 | | void proto_register_ipmi_trace(void); |
79 | | void proto_reg_handoff_ipmi_trace(void); |
80 | | |
81 | | static dissector_handle_t ipmi_trace_handle; |
82 | | |
83 | | static int proto_ipmi_trace; |
84 | | |
85 | | static dissector_table_t proto_dissector_table; |
86 | | |
87 | | static int ett_ipmi_trace; |
88 | | static int ett_trace_block_type; |
89 | | static int ett_trace_timestamp; |
90 | | static int ett_trace_protocol_data; |
91 | | static int ett_trace_ipmb_state; |
92 | | |
93 | | static int hf_trace_block_type; |
94 | | static int hf_trace_channel_num; |
95 | | static int hf_trace_packet_type; |
96 | | static int hf_trace_timestamp; |
97 | | static int hf_trace_timestamp_sec; |
98 | | static int hf_trace_timestamp_msec; |
99 | | static int hf_trace_data_type; |
100 | | static int hf_trace_protocol_data; |
101 | | static int hf_trace_dir; |
102 | | static int hf_trace_ipmb_red_chn; |
103 | | static int hf_trace_ipmb_link_num; |
104 | | static int hf_trace_data_len; |
105 | | static int hf_trace_notify_format; |
106 | | static int hf_trace_ipmb_state; |
107 | | static int hf_trace_ipmb_ovr_state; |
108 | | static int hf_trace_ipmb_loc_state; |
109 | | |
110 | | static const value_string str_packet_types[] = { |
111 | | { 0, "IPMI Trace Packet Data" }, |
112 | | { 1, "Channel State Change Notification" }, |
113 | | { 2, "Embedded ASCII message" }, |
114 | | { 0, NULL } |
115 | | }; |
116 | | |
117 | | static const value_string str_protocol_types[] = { |
118 | | { 0, "n/a" }, |
119 | | { 1, "IPMB-1.0" }, |
120 | | { 2, "ICMB-1.0" }, |
121 | | { 4, "IPMI-SMBus" }, |
122 | | { 5, "KCS" }, |
123 | | { 6, "SMIC" }, |
124 | | { 7, "BT-10" }, |
125 | | { 8, "BT-15" }, |
126 | | { 9, "TMode" }, |
127 | | { 0x1C, "OEM Protocol 1" }, |
128 | | { 0x1D, "OEM Protocol 2" }, |
129 | | { 0x1E, "OEM Protocol 3" }, |
130 | | { 0x1F, "OEM Protocol 4" }, |
131 | | { 0, NULL } |
132 | | }; |
133 | | |
134 | | static const value_string str_redund_chns[] = { |
135 | | { 0, "First channel" }, |
136 | | { 1, "Second channel" }, |
137 | | { 0, NULL } |
138 | | }; |
139 | | |
140 | | static const value_string str_trace_dirs[] = { |
141 | | { 0, "From IPM Controller" }, |
142 | | { 1, "To IPM Controller" }, |
143 | | { 0, NULL } |
144 | | }; |
145 | | |
146 | | static const value_string str_ipmb_notify_formats[] = { |
147 | | { 0, "Derived from PICMG 3.0" }, |
148 | | { 0, NULL } |
149 | | }; |
150 | | |
151 | | static const value_string str_ipmb_ovr_statuses[] = { |
152 | | { 0, "Override status, bus isolated" }, |
153 | | { 1, "Local Control State" }, |
154 | | { 0, NULL } |
155 | | }; |
156 | | |
157 | | static const value_string str_ipmb_loc_statuses[] = { |
158 | | { 0, "No Failure" }, |
159 | | { 1, "Unable to drive clock HI" }, |
160 | | { 2, "Unable to drive data HI" }, |
161 | | { 3, "Unable to drive clock LO" }, |
162 | | { 4, "Unable to drive data LO" }, |
163 | | { 5, "Clock low timeout" }, |
164 | | { 6, "Under test" }, |
165 | | { 7, "Undiagnosed Communications Failure" }, |
166 | | { 0, NULL } |
167 | | }; |
168 | | |
169 | | static int * const bits_trace_block_type[] = { |
170 | | &hf_trace_channel_num, |
171 | | &hf_trace_packet_type, |
172 | | NULL |
173 | | }; |
174 | | |
175 | | static int * const bits_ipmb_protocol_data[] = { |
176 | | &hf_trace_ipmb_link_num, |
177 | | &hf_trace_ipmb_red_chn, |
178 | | &hf_trace_dir, |
179 | | NULL |
180 | | }; |
181 | | |
182 | | static int * const bits_host_protocol_data[] = { |
183 | | &hf_trace_dir, |
184 | | NULL |
185 | | }; |
186 | | |
187 | | static int * const bits_chn_state_info[] = { |
188 | | &hf_trace_ipmb_ovr_state, |
189 | | &hf_trace_ipmb_loc_state, |
190 | | NULL |
191 | | }; |
192 | | |
193 | | /* HPM.2 Trace Collection tree indices. */ |
194 | | static int * ipmi_trace_ett[] = { |
195 | | &ett_ipmi_trace, |
196 | | &ett_trace_block_type, |
197 | | &ett_trace_timestamp, |
198 | | &ett_trace_protocol_data, |
199 | | &ett_trace_ipmb_state |
200 | | }; |
201 | | |
202 | | /* HPM.2 Trace Collection header fields. */ |
203 | | static hf_register_info ipmi_trace_hf[] = { |
204 | | { &hf_trace_block_type, { |
205 | | "Trace Data Block Type", "ipmi.trace.block.type", |
206 | | FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, |
207 | | { &hf_trace_channel_num, { |
208 | | "IPMI Channel Number being traced", "ipmi.trace.chn.num", |
209 | | FT_UINT8, BASE_DEC_HEX, NULL, 0x0F, NULL, HFILL } }, |
210 | | { &hf_trace_packet_type, { |
211 | | "Packet Type", "ipmi.trace.packet.type", |
212 | | FT_UINT8, BASE_DEC, VALS(str_packet_types), 0x30, NULL, HFILL } }, |
213 | | { &hf_trace_timestamp, { |
214 | | "Timestamp", "ipmi.trace.stamp", |
215 | | FT_RELATIVE_TIME, BASE_NONE, NULL, 0, NULL, HFILL } }, |
216 | | { &hf_trace_timestamp_sec, { |
217 | | "Seconds part", "ipmi.trace.stamp.sec", |
218 | | FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } }, |
219 | | { &hf_trace_timestamp_msec, { |
220 | | "Milliseconds part", "ipmi.trace.stamp.msec", |
221 | | FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, |
222 | | { &hf_trace_data_type, { |
223 | | "Trace Data Type", "ipmi.trace.data.type", |
224 | | FT_UINT8, BASE_HEX, VALS(str_protocol_types), 0, NULL, HFILL } }, |
225 | | { &hf_trace_protocol_data, { |
226 | | "Additional protocol specific data", "ipmi.trace.proto.data", |
227 | | FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } }, |
228 | | { &hf_trace_ipmb_link_num, { |
229 | | "Radial IPMB Link Number", "ipmi.trace.ipmb.link.num", |
230 | | FT_UINT16, BASE_DEC_HEX, NULL, 0x003F, NULL, HFILL } }, |
231 | | { &hf_trace_ipmb_red_chn, { |
232 | | "Redundant Channel Indicator", "ipmi.trace.ipmb.red.chn", |
233 | | FT_UINT16, BASE_DEC, VALS(str_redund_chns), 0x0040, NULL, HFILL } }, |
234 | | { &hf_trace_dir, { |
235 | | "Direction", "ipmi.trace.dir", |
236 | | FT_UINT16, BASE_DEC, VALS(str_trace_dirs), 0x0080, NULL, HFILL } }, |
237 | | { &hf_trace_data_len, { |
238 | | "Data length", "ipmi.trace.data.len", |
239 | | FT_UINT8, BASE_DEC_HEX, NULL, 0, NULL, HFILL } }, |
240 | | { &hf_trace_notify_format, { |
241 | | "Data format", "ipmi.trace.data.format", |
242 | | FT_UINT8, BASE_HEX, VALS(str_ipmb_notify_formats), 0, NULL, HFILL } }, |
243 | | { &hf_trace_ipmb_state, { |
244 | | "State Change Information", "ipmi.trace.ipmb.state", |
245 | | FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, |
246 | | { &hf_trace_ipmb_ovr_state, { |
247 | | "IPMB Override status", "ipmi.trace.ipmb.state.ovr", |
248 | | FT_UINT8, BASE_DEC, VALS(str_ipmb_ovr_statuses), 0x8, NULL, HFILL } }, |
249 | | { &hf_trace_ipmb_loc_state, { |
250 | | "IPMB Local status", "ipmi.trace.ipmb.state.loc", |
251 | | FT_UINT8, BASE_DEC, VALS(str_ipmb_loc_statuses), 0x7, NULL, HFILL } }, |
252 | | }; |
253 | | |
254 | | static void |
255 | | dissect_ipmb_state_notify(tvbuff_t * tvb, proto_tree * tree) |
256 | 0 | { |
257 | | /* add data format */ |
258 | 0 | proto_tree_add_item(tree, hf_trace_notify_format, |
259 | 0 | tvb, 0, 1, ENC_LITTLE_ENDIAN); |
260 | | |
261 | | /* add host-specific data */ |
262 | 0 | proto_tree_add_bitmask(tree, tvb, 1, |
263 | 0 | hf_trace_ipmb_state, ett_trace_ipmb_state, |
264 | 0 | bits_chn_state_info, ENC_LITTLE_ENDIAN); |
265 | 0 | } |
266 | | |
267 | | static int |
268 | | dissect_ipmi_trace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
269 | 9 | { |
270 | 9 | unsigned block_type, chn_num, data_type, tmp; |
271 | 9 | tvbuff_t * next_tvb; |
272 | | |
273 | 9 | if (tvb_captured_length(tvb) < 11) { |
274 | | /* TODO: add expert info */ |
275 | 1 | call_data_dissector(tvb, pinfo, tree); |
276 | 1 | return tvb_captured_length(tvb); |
277 | 1 | } |
278 | | |
279 | | /* get first byte */ |
280 | 8 | tmp = tvb_get_uint8(tvb, 0); |
281 | | |
282 | | /* get block type */ |
283 | 8 | block_type = (tmp >> 4) & 3; |
284 | | |
285 | | /* get channel number */ |
286 | 8 | chn_num = tmp & 0xF; |
287 | | |
288 | | /* get trace data type */ |
289 | 8 | data_type = tvb_get_uint8(tvb, 7); |
290 | | |
291 | | |
292 | 8 | col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "Channel %d", chn_num); |
293 | 8 | col_add_str(pinfo->cinfo, COL_PROTOCOL, |
294 | 8 | val_to_str(pinfo->pool, data_type, str_protocol_types, |
295 | 8 | "Reserved (0x%02x)")); |
296 | | |
297 | 8 | col_clear(pinfo->cinfo, COL_INFO); |
298 | | |
299 | 8 | if (block_type == HPM2_TRACE_PACKET_DATA) { |
300 | 2 | col_set_str(pinfo->cinfo, COL_INFO, "Trace Packet Data"); |
301 | 6 | } else if (block_type == HPM2_CHN_STATE_NOTIFY) { |
302 | 1 | col_set_str(pinfo->cinfo, COL_INFO, |
303 | 1 | "Channel State Change Notification"); |
304 | 5 | } else if (block_type == HPM2_EMBED_ASCII_MSG) { |
305 | 2 | char *str; |
306 | | |
307 | | /* get data length */ |
308 | 2 | unsigned str_len = tvb_get_uint8(tvb, 10); |
309 | | |
310 | 2 | if (str_len) { |
311 | | /* copy string */ |
312 | 1 | str = (char *) tvb_get_string_enc(pinfo->pool, tvb, 11, str_len, ENC_ASCII|ENC_NA); |
313 | | |
314 | | /* print the string right inside the column */ |
315 | 1 | col_add_str(pinfo->cinfo, COL_INFO, str); |
316 | 1 | } |
317 | 3 | } else { |
318 | 3 | col_set_str(pinfo->cinfo, COL_INFO, "Reserved"); |
319 | 3 | } |
320 | | |
321 | | |
322 | 8 | if ( tree ) { |
323 | 7 | proto_item * ti; |
324 | 7 | proto_tree * trace_tree; |
325 | 7 | proto_tree * stamp_tree; |
326 | 7 | nstime_t timestamp; |
327 | 7 | int millisecs; |
328 | | |
329 | | /* add protocol label */ |
330 | 7 | ti = proto_tree_add_item(tree, proto_ipmi_trace, tvb, 0, -1, ENC_NA); |
331 | | |
332 | | /* create protocol sub-tree */ |
333 | 7 | trace_tree = proto_item_add_subtree(ti, ett_ipmi_trace); |
334 | | |
335 | | /* add block type/channel bitmask */ |
336 | 7 | proto_tree_add_bitmask(trace_tree, tvb, 0, hf_trace_block_type, |
337 | 7 | ett_trace_block_type, bits_trace_block_type, |
338 | 7 | ENC_LITTLE_ENDIAN); |
339 | | |
340 | | /* get seconds part */ |
341 | 7 | timestamp.secs = tvb_get_letohl(tvb, 1); |
342 | | |
343 | | /* get milliseconds part */ |
344 | 7 | millisecs = tvb_get_letohs(tvb, 5); |
345 | 7 | if (millisecs < 1000) { |
346 | 1 | timestamp.nsecs = millisecs * 1000000; |
347 | 6 | } else { |
348 | | /* invalid */ |
349 | 6 | timestamp.nsecs = 0; |
350 | 6 | } |
351 | | |
352 | | /* add timestamp */ |
353 | 7 | ti = proto_tree_add_time(trace_tree, hf_trace_timestamp, tvb, 1, |
354 | 7 | 6, ×tamp); |
355 | | |
356 | | /* create timestamp sub-tree */ |
357 | 7 | stamp_tree = proto_item_add_subtree(ti, ett_trace_timestamp); |
358 | | |
359 | | /* add seconds part */ |
360 | 7 | proto_tree_add_item(stamp_tree, hf_trace_timestamp_sec, |
361 | 7 | tvb, 1, 4, ENC_LITTLE_ENDIAN); |
362 | | |
363 | | /* add milliseconds part */ |
364 | 7 | proto_tree_add_item(stamp_tree, hf_trace_timestamp_msec, |
365 | 7 | tvb, 5, 2, ENC_LITTLE_ENDIAN); |
366 | | |
367 | | /* add trace data type */ |
368 | 7 | proto_tree_add_item(trace_tree, hf_trace_data_type, |
369 | 7 | tvb, 7, 1, ENC_LITTLE_ENDIAN); |
370 | | |
371 | 7 | if (data_type == IPMI_PROTO_IPMB_1_0) { |
372 | | /* add ipmb-specific data */ |
373 | 1 | proto_tree_add_bitmask(trace_tree, tvb, 8, |
374 | 1 | hf_trace_protocol_data, ett_trace_protocol_data, |
375 | 1 | bits_ipmb_protocol_data, ENC_LITTLE_ENDIAN); |
376 | 6 | } else if (data_type == IPMI_PROTO_KCS |
377 | 6 | || data_type == IPMI_PROTO_SMIC |
378 | 6 | || data_type == IPMI_PROTO_BT_10 |
379 | 6 | || data_type == IPMI_PROTO_BT_15) { |
380 | | /* add host-specific data */ |
381 | 1 | proto_tree_add_bitmask(trace_tree, tvb, 8, |
382 | 1 | hf_trace_protocol_data, ett_trace_protocol_data, |
383 | 1 | bits_host_protocol_data, ENC_LITTLE_ENDIAN); |
384 | 5 | } else { |
385 | | /* add protocol specific data */ |
386 | 5 | proto_tree_add_item(trace_tree, hf_trace_protocol_data, tvb, |
387 | 5 | 8, 2, ENC_LITTLE_ENDIAN); |
388 | 5 | } |
389 | | |
390 | | /* add data length*/ |
391 | 7 | proto_tree_add_item(trace_tree, hf_trace_data_len, tvb, |
392 | 7 | 10, 1, ENC_LITTLE_ENDIAN); |
393 | 7 | } |
394 | | |
395 | | /* get pointer to remaining data buffer */ |
396 | 8 | next_tvb = tvb_new_subset_remaining(tvb, 11); |
397 | | |
398 | 8 | if (block_type == HPM2_TRACE_PACKET_DATA) { |
399 | 2 | ipmi_dissect_arg_t arg; |
400 | | |
401 | | /* setup IPMI protocol argument */ |
402 | 2 | arg.context = IPMI_E_NONE; |
403 | 2 | arg.channel = chn_num; |
404 | 2 | arg.flags = tvb_get_uint8(tvb, 8); |
405 | | |
406 | 2 | if (!dissector_try_uint_with_data(proto_dissector_table, |
407 | 2 | data_type, next_tvb, pinfo, tree, true, &arg)) { |
408 | 2 | call_data_dissector(next_tvb, pinfo, tree); |
409 | 2 | } |
410 | 6 | } else if (block_type == HPM2_CHN_STATE_NOTIFY |
411 | 1 | && data_type == IPMI_PROTO_IPMB_1_0) { |
412 | 0 | dissect_ipmb_state_notify(next_tvb, tree); |
413 | 6 | } else { |
414 | 6 | call_data_dissector(next_tvb, pinfo, tree); |
415 | 6 | } |
416 | 8 | return tvb_captured_length(tvb); |
417 | 9 | } |
418 | | |
419 | | void |
420 | | proto_register_ipmi_trace(void) |
421 | 16 | { |
422 | | /* register protocol for HPM.2 trace data block */ |
423 | 16 | proto_ipmi_trace = proto_register_protocol("IPMI Trace Data Collection", |
424 | 16 | "ipmi-trace", "ipmi.trace"); |
425 | | |
426 | | /* register HPM.2 header fields */ |
427 | 16 | proto_register_field_array(proto_ipmi_trace, ipmi_trace_hf, |
428 | 16 | array_length(ipmi_trace_hf)); |
429 | | |
430 | | /* register HPM.2 sub-tree indices */ |
431 | 16 | proto_register_subtree_array(ipmi_trace_ett, |
432 | 16 | array_length(ipmi_trace_ett)); |
433 | | |
434 | | /* register dissector table for IPMI messaging protocols */ |
435 | 16 | proto_dissector_table = register_dissector_table("ipmi.protocol", |
436 | 16 | "IPMI Channel Protocol Type", proto_ipmi_trace, FT_UINT8, BASE_HEX); |
437 | | |
438 | 16 | ipmi_trace_handle = register_dissector("ipmi.trace", dissect_ipmi_trace, proto_ipmi_trace); |
439 | 16 | } |
440 | | |
441 | | void |
442 | | proto_reg_handoff_ipmi_trace(void) |
443 | 16 | { |
444 | 16 | dissector_add_uint("wtap_encap", WTAP_ENCAP_IPMI_TRACE, ipmi_trace_handle); |
445 | | |
446 | 16 | dissector_add_uint("ipmi.protocol", IPMI_PROTO_IPMB_1_0, |
447 | 16 | find_dissector("ipmb")); |
448 | 16 | dissector_add_uint("ipmi.protocol", IPMI_PROTO_KCS, |
449 | 16 | find_dissector("kcs")); |
450 | 16 | dissector_add_uint("ipmi.protocol", IPMI_PROTO_TMODE, |
451 | 16 | find_dissector("tmode")); |
452 | 16 | } |
453 | | |
454 | | /* |
455 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
456 | | * |
457 | | * Local variables: |
458 | | * c-basic-offset: 8 |
459 | | * tab-width: 8 |
460 | | * indent-tabs-mode: t |
461 | | * End: |
462 | | * |
463 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
464 | | * :indentSize=8:tabSize=8:noTabs=false: |
465 | | */ |