2 * Routines for IPMI dissection
3 * Copyright 2002-2008, Alexey Neyman, Pigeon Point Systems <avn@pigeonpoint.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32 #include <epan/packet.h>
33 #include <epan/conversation.h>
34 #include <epan/wmem/wmem.h>
35 #include <epan/to_str.h>
36 #include <epan/prefs.h>
37 #include <epan/addr_resolv.h>
39 #include "packet-ipmi.h"
42 * See the IPMI specifications at
44 * http://www.intel.com/design/servers/ipmi/
47 /* Define IPMI_DEBUG to enable printing the process of request-response pairing */
48 /* #define IPMI_DEBUG */
50 /* Top-level search structure: list of registered handlers for a given netFn */
51 struct ipmi_netfn_root
{
59 /* We need more than a conversation. Over the same RMCP session
60 (or IPMB), there may be several addresses/SWIDs. Thus, in a single
61 Wireshark-maintained conversation we might need to find our own... */
62 struct ipmi_saved_data
{
64 guint32 saved_data
[NSAVED_DATA
];
83 struct ipmi_reqresp
*next
;
84 struct ipmi_saved_data
*data
;
85 int (*whichresponse
)(struct ipmi_header
*hdr
, struct ipmi_reqresp
*rr
);
89 } frames
[MAX_RQRS_FRAMES
];
95 struct ipmi_reqresp
*rr
;
102 struct ipmi_parse_typelen
{
103 void (*get_len
)(guint
*, guint
*, tvbuff_t
*, guint
, guint
, gboolean
);
104 void (*parse
)(char *, tvbuff_t
*, guint
, guint
);
108 struct ipmi_header
*ipmi_current_hdr
;
110 static gint proto_ipmi
= -1;
112 static gboolean fru_langcode_is_english
= TRUE
;
113 static guint response_after_req
= 5000;
114 static guint response_before_req
= 0;
115 static guint message_format
= MSGFMT_GUESS
;
116 static guint selected_oem
= IPMI_OEM_NONE
;
118 static gint hf_ipmi_message
= -1;
119 static gint hf_ipmi_session_handle
= -1;
120 static gint hf_ipmi_header_broadcast
= -1;
121 static gint hf_ipmi_header_trg
= -1;
122 static gint hf_ipmi_header_trg_lun
= -1;
123 static gint hf_ipmi_header_netfn
= -1;
124 static gint hf_ipmi_header_crc
= -1;
125 static gint hf_ipmi_header_src
= -1;
126 static gint hf_ipmi_header_src_lun
= -1;
127 static gint hf_ipmi_header_sequence
= -1;
128 static gint hf_ipmi_header_command
= -1;
129 static gint hf_ipmi_header_completion
= -1;
130 static gint hf_ipmi_header_sig
= -1;
131 static gint hf_ipmi_data_crc
= -1;
132 static gint hf_ipmi_response_to
= -1;
133 static gint hf_ipmi_response_in
= -1;
134 static gint hf_ipmi_response_time
= -1;
135 static gint hf_ipmi_bad_checksum
= -1;
137 static gint ett_ipmi
= -1;
138 static gint ett_header
= -1;
139 static gint ett_header_byte_1
= -1;
140 static gint ett_header_byte_4
= -1;
141 static gint ett_data
= -1;
142 static gint ett_typelen
= -1;
144 static guint nest_level
;
145 static struct ipmi_saved_data
*current_saved_data
;
146 static struct ipmi_netfn_root ipmi_cmd_tab
[IPMI_NETFN_MAX
];
150 debug_printf(const gchar
*fmt _U_
, ...)
152 #if defined(IPMI_DEBUG)
156 vfprintf(stderr
, fmt
, ap
);
161 /* ----------------------------------------------------------------
162 Support for request-response caching.
163 ---------------------------------------------------------------- */
165 /* Key generation; returns the same key for requests and responses */
167 makekey(struct ipmi_header
*hdr
)
169 guint32 trg
, src
, res
;
171 trg
= (hdr
->trg_sa
<< 2) | hdr
->trg_lun
;
172 src
= (hdr
->src_sa
<< 2) | hdr
->src_lun
;
173 res
= trg
< src
? (trg
<< 10) | src
: (src
<< 10) | trg
;
174 return (hdr
->seq
<< 20) | res
;
177 static struct ipmi_reqresp
*
178 key_lookup_reqresp(struct ipmi_keyhead
*kh
, struct ipmi_header
*hdr
, frame_data
*fd
)
180 struct ipmi_reqresp
*rr
, *best_rr
= NULL
;
182 double d
, best_d
= (double)(2 * response_after_req
);
183 guint8 netfn
= hdr
->netfn
& 0x3e; /* disregard 'response' bit */
184 guint8 is_resp
= hdr
->netfn
& 0x01;
187 /* Source/target SA/LUN and sequence number are assumed to match; wmem_tree*
188 ensure that. While checking for "being here", we can't rely on flags.visited,
189 as we may have more than one IPMI message in a single frame. */
190 for (rr
= kh
->rr
; rr
; rr
= rr
->next
) {
191 if (rr
->netfn
!= netfn
|| rr
->cmd
!= hdr
->cmd
) {
195 for (i
= 0; i
< MAX_RQRS_FRAMES
; i
++) {
196 /* RQ=0 - 0th element is request frame number; RS/RS2 -
197 responses are non zero */
198 if (((!i
) ^ is_resp
) && rr
->frames
[i
].num
== fd
->num
) {
199 /* Already been here */
204 /* Reject responses before requests or more than 5 seconds ahead */
206 nstime_delta(&delta
, &fd
->abs_ts
, &rr
->frames
[RQ
].time
);
208 /* Use RS here, not RS2 - frames[RS] is always filled if we had
209 at least one response */ /* TBD */
210 nstime_delta(&delta
, &rr
->frames
[RS
].time
, &fd
->abs_ts
);
212 d
= nstime_to_msec(&delta
);
213 if (d
< -(double)response_before_req
|| d
> (double)response_after_req
) {
217 if (fabs(d
) < best_d
) {
227 key_insert_reqresp(struct ipmi_keyhead
*kh
, struct ipmi_reqresp
*rr
)
229 /* Insert to head, so that the search would find most recent response */
234 static inline gboolean
235 set_framenums(struct ipmi_header
*hdr
, struct ipmi_reqresp
*rr
, frame_data
*fd
)
237 int which
= hdr
->netfn
& 0x01 ? rr
->whichresponse
? rr
->whichresponse(hdr
, rr
) : RS
: RQ
;
239 if (rr
->frames
[which
].num
&& rr
->frames
[which
].num
!= fd
->num
) {
242 rr
->frames
[which
].num
= fd
->num
;
243 rr
->frames
[which
].time
= fd
->abs_ts
;
247 #define IS_SENDMSG(hdr) (((hdr)->netfn & 0x3e) == IPMI_APP_REQ && (hdr)->cmd == 0x34)
250 ipmi_sendmsg_whichresponse(struct ipmi_header
*hdr
, struct ipmi_reqresp
*rr
)
252 if (!IS_SENDMSG(hdr
)) {
253 /* Not a Send Message: just a simple response */
257 if (hdr
->data_len
> 0) {
258 /* Trivial case: response with non-null data can only be a
259 response in AMC.0 style */
262 /* Otherwise, we need to somehow determine 1st and 2nd responses. Note
263 that both them may lack the data - in case that the embedded response
264 returned with error. Thus, employ the following algo:
265 - First, assign to [RS] frame (this also won't conflict with full response
266 received - it could only happen if send message succeeded)
267 - In case we see another data-less response, see that we assign the one
268 with success completion code to [RS] and with non-success code to [RS2].
270 We assume that we can't receive 2 responses with non-successful completion
271 (if the outmost Send Message failed, how was the embedded one sent?)
273 if (!rr
->frames
[RS
].num
) {
277 /* In case we received "success", move the other response to [RS2] */
279 if (!rr
->frames
[RS2
].num
) {
280 rr
->frames
[RS2
] = rr
->frames
[RS
];
285 /* [RS] occupied, non-successful */
290 ipmi_sendmsg_otheridx(struct ipmi_header
*hdr
)
292 return IS_SENDMSG(hdr
) ? nest_level
: RS
;
296 ipmi_sendmsg_getheaders(struct ipmi_header
*base
, void *arg
, guint i
)
298 static struct ipmi_header hdr
;
299 struct ipmi_header
*wrapper
= (struct ipmi_header
*)arg
;
301 /* The problem stems from the fact that the original IPMI
302 specification (before errata came) did not specify the response
303 to Send Message (and even the fact that there are 2 responses -
304 to Send Message and to embedded command). Even then, there is
305 one vagueness remaining - whether the response should use
306 the sequence number from the wrapper or from the embedded message.
308 Thus, there are 3 types of responses to Send Message
310 * AMC.0-style: the response is embedded in a normal Send Message
311 response. Easiest case: such responses will be correctly detected
312 with the default code in ipmi_do_dissect.
314 * IPMI-style, with both variants of sequence numbers. Note that
315 most tools dealing with Send Message (e.g. ipmitool) circumvent
316 this vagueness by using the same sequence number in both wrapper
317 and embedded messages. If we detect such "smart" messages, we
318 provide only one extra header. For correctness, we have to provide
319 for both variants, however.
322 if (i
>= 2 || (i
== 1 && wrapper
->seq
== base
->seq
)) {
326 /* Construct hybrid header */
327 hdr
.trg_sa
= wrapper
->trg_sa
;
328 hdr
.trg_lun
= wrapper
->trg_lun
;
329 hdr
.src_sa
= wrapper
->src_sa
;
330 hdr
.src_lun
= wrapper
->src_lun
;
331 hdr
.netfn
= base
->netfn
;
333 hdr
.seq
= i
? base
->seq
: wrapper
->seq
;
334 hdr
.ccode
= base
->ccode
;
335 hdr
.data_len
= base
->data_len
;
340 maybe_insert_reqresp(packet_info
*pinfo
, ipmi_dissect_format_t
*dfmt
, struct ipmi_header
*hdr
)
343 struct ipmi_keytree
*kt
;
344 struct ipmi_keyhead
*kh
;
345 struct ipmi_reqresp
*rr
;
348 cnv
= find_or_create_conversation(pinfo
);
350 kt
= (struct ipmi_keytree
*)conversation_get_proto_data(cnv
, proto_ipmi
);
352 kt
= wmem_new(wmem_file_scope(), struct ipmi_keytree
);
353 kt
->heads
= wmem_tree_new(wmem_file_scope());
354 conversation_add_proto_data(cnv
, proto_ipmi
, kt
);
357 debug_printf("--> maybe_insert_reqresp( %d )\n", pinfo
->fd
->num
);
360 debug_printf("Checking [ (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
361 hdr
->trg_sa
, hdr
->trg_lun
, hdr
->src_sa
, hdr
->src_lun
, hdr
->seq
,
362 hdr
->netfn
, hdr
->cmd
);
364 kh
= (struct ipmi_keyhead
*)wmem_tree_lookup32(kt
->heads
, key
);
366 kh
= wmem_new0(wmem_file_scope(), struct ipmi_keyhead
);
367 wmem_tree_insert32(kt
->heads
, key
, kh
);
369 if ((rr
= key_lookup_reqresp(kh
, hdr
, pinfo
->fd
)) != NULL
) {
370 /* Already recorded - set frame number and be done. Look no
371 further - even if there are several responses, we have
372 found the right one. */
373 debug_printf("Found existing [ <%d,%d,%d> (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
374 rr
->frames
[0].num
, rr
->frames
[1].num
, rr
->frames
[2].num
,
375 hdr
->trg_sa
, hdr
->trg_lun
, hdr
->src_sa
, hdr
->src_lun
, hdr
->seq
,
377 if (!rr
->whichresponse
) {
378 rr
->whichresponse
= dfmt
->whichresponse
;
380 if (set_framenums(hdr
, rr
, pinfo
->fd
)) {
381 debug_printf("Set frames [ <%d,%d,%d> (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
382 rr
->frames
[0].num
, rr
->frames
[1].num
, rr
->frames
[2].num
,
383 hdr
->trg_sa
, hdr
->trg_lun
, hdr
->src_sa
, hdr
->src_lun
, hdr
->seq
,
385 current_saved_data
= rr
->data
;
389 /* Found, but already occupied. Fall through to allocating the structures */
390 current_saved_data
= NULL
;
392 /* Not found; allocate new structures */
393 if (!current_saved_data
) {
394 /* One 'ipmi_saved_data' for all 'ipmi_req_resp' allocated */
395 current_saved_data
= wmem_new0(wmem_file_scope(), struct ipmi_saved_data
);
397 rr
= wmem_new0(wmem_file_scope(), struct ipmi_reqresp
);
398 rr
->whichresponse
= dfmt
->whichresponse
;
399 rr
->netfn
= hdr
->netfn
& 0x3e;
401 rr
->data
= current_saved_data
;
402 set_framenums(hdr
, rr
, pinfo
->fd
);
403 key_insert_reqresp(kh
, rr
);
404 debug_printf("Inserted [ <%d,%d,%d> (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
405 rr
->frames
[0].num
, rr
->frames
[1].num
, rr
->frames
[2].num
,
406 hdr
->trg_sa
, hdr
->trg_lun
, hdr
->src_sa
, hdr
->src_lun
, hdr
->seq
,
409 /* Do we have other headers to insert? */
410 hdr
= dfmt
->getmoreheaders
? dfmt
->getmoreheaders(hdr
, dfmt
->arg
, i
++) : NULL
;
415 add_reqresp_info(ipmi_dissect_format_t
*dfmt
, struct ipmi_header
*hdr
, proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
)
418 struct ipmi_keytree
*kt
;
419 struct ipmi_keyhead
*kh
;
420 struct ipmi_reqresp
*rr
= NULL
;
421 guint32 key
, i
, other_idx
;
425 debug_printf("--> add_reqresp_info( %d )\n", pinfo
->fd
->num
);
427 /* [0] is request; [1..MAX_RS_LEVEL] are responses */
428 other_idx
= (hdr
->netfn
& 0x01) ? RQ
: dfmt
->otheridx
? dfmt
->otheridx(hdr
) : RS
;
430 if (other_idx
>= MAX_RQRS_FRAMES
) {
431 /* No chance; we don't look that deep into nested Send Message.
432 Note that we'll use the other_idx value to distinguish
433 request from response. */
437 /* Here, we don't try to create any object - everything is assumed
438 to be created in maybe_insert_reqresp() */
439 if ((cnv
= find_conversation(pinfo
->fd
->num
, &pinfo
->src
,
440 &pinfo
->dst
, pinfo
->ptype
,
441 pinfo
->srcport
, pinfo
->destport
, 0)) == NULL
) {
444 if ((kt
= (struct ipmi_keytree
*)conversation_get_proto_data(cnv
, proto_ipmi
)) == NULL
) {
450 debug_printf("Looking for [ (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
451 hdr
->trg_sa
, hdr
->trg_lun
, hdr
->src_sa
, hdr
->src_lun
, hdr
->seq
,
452 hdr
->netfn
, hdr
->cmd
);
454 if ((kh
= (struct ipmi_keyhead
*)wmem_tree_lookup32(kt
->heads
, key
)) != NULL
&&
455 (rr
= key_lookup_reqresp(kh
, hdr
, pinfo
->fd
)) != NULL
) {
456 debug_printf("Found [ <%d,%d,%d> (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
457 rr
->frames
[0].num
, rr
->frames
[1].num
, rr
->frames
[2].num
,
458 hdr
->trg_sa
, hdr
->trg_lun
, hdr
->src_sa
, hdr
->src_lun
, hdr
->seq
,
460 if (rr
->frames
[other_idx
].num
) {
465 /* Do we have other headers to check? */
466 hdr
= dfmt
->getmoreheaders
? dfmt
->getmoreheaders(hdr
, dfmt
->arg
, i
++) : NULL
;
472 if (hdr
->netfn
& 0x01) {
474 ti
= proto_tree_add_uint(tree
, hf_ipmi_response_to
,
475 tvb
, 0, 0, rr
->frames
[RQ
].num
);
476 PROTO_ITEM_SET_GENERATED(ti
);
477 nstime_delta(&ns
, &pinfo
->fd
->abs_ts
, &rr
->frames
[RQ
].time
);
478 ti
= proto_tree_add_time(tree
, hf_ipmi_response_time
,
480 PROTO_ITEM_SET_GENERATED(ti
);
483 ti
= proto_tree_add_uint(tree
, hf_ipmi_response_in
,
484 tvb
, 0, 0, rr
->frames
[other_idx
].num
);
485 PROTO_ITEM_SET_GENERATED(ti
);
490 ti
= proto_tree_add_text(tree
, tvb
, 0, 0, "No corresponding %s",
491 other_idx
? "response" : "request");
492 PROTO_ITEM_SET_GENERATED(ti
);
495 /* Save data in request, retrieve in response */
497 ipmi_setsaveddata(guint idx
, guint32 val
)
499 DISSECTOR_ASSERT(idx
< NSAVED_DATA
);
500 current_saved_data
->saved_data
[idx
] = val
;
501 current_saved_data
->set_data
|= (1 << idx
);
505 ipmi_getsaveddata(guint idx
, guint32
*pval
)
507 DISSECTOR_ASSERT(idx
< NSAVED_DATA
);
508 if (current_saved_data
->set_data
& (1 << idx
)) {
509 *pval
= current_saved_data
->saved_data
[idx
];
515 /* ----------------------------------------------------------------
516 Support for Type/Length fields parsing.
517 ---------------------------------------------------------------- */
520 get_len_binary(guint
*clen
, guint
*blen
, tvbuff_t
*tvb _U_
, guint offs _U_
,
521 guint len
, gboolean len_is_bytes _U_
)
528 parse_binary(char *p
, tvbuff_t
*tvb
, guint offs
, guint len
)
530 static const char hex
[] = "0123456789ABCDEF";
534 for (i
= 0; i
< len
/ 3; i
++) {
535 v
= tvb_get_guint8(tvb
, offs
+ i
);
546 static struct ipmi_parse_typelen ptl_binary
= {
547 get_len_binary
, parse_binary
, "Binary"
551 get_len_bcdplus(guint
*clen
, guint
*blen
, tvbuff_t
*tvb _U_
, guint offs _U_
,
552 guint len
, gboolean len_is_bytes
)
558 *blen
= (len
+ 1) / 2;
564 parse_bcdplus(char *p
, tvbuff_t
*tvb
, guint offs
, guint len
)
566 static const char bcd
[] = "0123456789 -.:,_";
567 guint i
, msk
= 0xf0, shft
= 4;
570 for (i
= 0; i
< len
; i
++) {
571 v
= (tvb_get_guint8(tvb
, offs
+ i
/ 2) & msk
) >> shft
;
578 static struct ipmi_parse_typelen ptl_bcdplus
= {
579 get_len_bcdplus
, parse_bcdplus
, "BCD+"
583 get_len_6bit_ascii(guint
*clen
, guint
*blen
, tvbuff_t
*tvb _U_
, guint offs _U_
,
584 guint len
, gboolean len_is_bytes
)
590 *blen
= (len
* 3 + 3) / 4;
596 parse_6bit_ascii(char *p
, tvbuff_t
*tvb
, guint offs
, guint len
)
601 /* First, handle "full" triplets of bytes, 4 characters each */
602 for (i
= 0; i
< len
/ 4; i
++) {
603 v
= tvb_get_letoh24(tvb
, offs
+ i
* 3);
604 p
[0] = ' ' + (v
& 0x3f);
605 p
[1] = ' ' + ((v
>> 6) & 0x3f);
606 p
[2] = ' ' + ((v
>> 12) & 0x3f);
607 p
[3] = ' ' + ((v
>> 18) & 0x3f);
611 /* Do we have any characters left? */
616 v
= (tvb_get_guint8(tvb
, offs
+ 2) << 4) | (tvb_get_guint8(tvb
, offs
+ 1) >> 4);
617 p
[2] = ' ' + (v
& 0x3f);
620 v
= (tvb_get_guint8(tvb
, offs
+ 1) << 2) | (tvb_get_guint8(tvb
, offs
) >> 6);
621 p
[1] = ' ' + (v
& 0x3f);
624 v
= tvb_get_guint8(tvb
, offs
) & 0x3f;
625 p
[0] = ' ' + (v
& 0x3f);
629 static struct ipmi_parse_typelen ptl_6bit_ascii
= {
630 get_len_6bit_ascii
, parse_6bit_ascii
, "6-bit ASCII"
634 get_len_8bit_ascii(guint
*clen
, guint
*blen
, tvbuff_t
*tvb
, guint offs
,
635 guint len
, gboolean len_is_bytes _U_
)
640 *blen
= len
; /* One byte is one character */
642 for (i
= 0; i
< len
; i
++) {
643 ch
= tvb_get_guint8(tvb
, offs
+ i
);
644 *clen
+= (ch
>= 0x20 && ch
<= 0x7f) ? 1 : 4;
649 parse_8bit_ascii(char *p
, tvbuff_t
*tvb
, guint offs
, guint len
)
656 ch
= tvb_get_guint8(tvb
, offs
++);
657 if (ch
>= 0x20 && ch
<= 0x7f) {
660 g_snprintf(p
, 5, "\\x%02x", ch
);
666 static struct ipmi_parse_typelen ptl_8bit_ascii
= {
667 get_len_8bit_ascii
, parse_8bit_ascii
, "ASCII+Latin1"
671 get_len_unicode(guint
*clen
, guint
*blen
, tvbuff_t
*tvb _U_
, guint offs _U_
,
672 guint len _U_
, gboolean len_is_bytes
)
675 *clen
= len
* 3; /* Each 2 bytes result in 6 chars printed: \Uxxxx */
684 parse_unicode(char *p
, tvbuff_t
*tvb
, guint offs
, guint len
)
686 char *pmax
= p
+ len
;
690 ch0
= tvb_get_guint8(tvb
, offs
++);
691 ch1
= tvb_get_guint8(tvb
, offs
++);
692 g_snprintf(p
, 7, "\\U%02x%02x", ch0
, ch1
);
697 static struct ipmi_parse_typelen ptl_unicode
= {
698 get_len_unicode
, parse_unicode
, "Unicode"
702 ipmi_add_typelen(proto_tree
*tree
, const char *desc
, tvbuff_t
*tvb
,
703 guint offs
, gboolean is_fru
)
705 static struct ipmi_parse_typelen
*fru_eng
[4] = {
706 &ptl_binary
, &ptl_bcdplus
, &ptl_6bit_ascii
, &ptl_8bit_ascii
708 static struct ipmi_parse_typelen
*fru_noneng
[4] = {
709 &ptl_binary
, &ptl_bcdplus
, &ptl_6bit_ascii
, &ptl_unicode
711 static struct ipmi_parse_typelen
*ipmi
[4] = {
712 &ptl_unicode
, &ptl_bcdplus
, &ptl_6bit_ascii
, &ptl_8bit_ascii
714 struct ipmi_parse_typelen
*ptr
;
717 guint type
, msk
, clen
, blen
, len
;
722 typelen
= tvb_get_guint8(tvb
, offs
);
726 ptr
= (fru_langcode_is_english
? fru_eng
: fru_noneng
)[type
];
735 ptr
->get_len(&clen
, &blen
, tvb
, offs
+ 1, len
, is_fru
);
737 str
= (char *)wmem_alloc(wmem_packet_scope(), clen
+ 1);
738 ptr
->parse(str
, tvb
, offs
+ 1, clen
);
741 ti
= proto_tree_add_text(tree
, tvb
, offs
, 1, "%s Type/Length byte: %s, %d %s",
742 desc
, ptr
->desc
, len
, unit
);
743 s_tree
= proto_item_add_subtree(ti
, ett_typelen
);
744 proto_tree_add_text(s_tree
, tvb
, offs
, 1, "%sType: %s (0x%02x)",
745 ipmi_dcd8(typelen
, 0xc0), ptr
->desc
, type
);
746 proto_tree_add_text(s_tree
, tvb
, offs
, 1, "%sLength: %d %s",
747 ipmi_dcd8(typelen
, msk
), len
, unit
);
749 proto_tree_add_text(tree
, tvb
, offs
+ 1, blen
, "%s: [%s] '%s'",
750 desc
, ptr
->desc
, str
);
753 /* ----------------------------------------------------------------
754 Timestamp, IPMI-style.
755 ---------------------------------------------------------------- */
757 ipmi_add_timestamp(proto_tree
*tree
, gint hf
, tvbuff_t
*tvb
, guint offset
)
759 guint32 ts
= tvb_get_letohl(tvb
, offset
);
761 if (ts
== 0xffffffff) {
762 proto_tree_add_uint_format_value(tree
, hf
, tvb
, offset
, 4,
763 ts
, "Unspecified/Invalid");
764 } else if (ts
<= 0x20000000) {
765 proto_tree_add_uint_format_value(tree
, hf
, tvb
, offset
, 4,
766 ts
, "%s since SEL device's initialization",
767 time_secs_to_str_unsigned(ts
));
769 proto_tree_add_uint_format_value(tree
, hf
, tvb
, offset
, 4,
770 ts
, "%s", abs_time_secs_to_str(ts
, ABSOLUTE_TIME_UTC
, TRUE
));
774 /* ----------------------------------------------------------------
776 ---------------------------------------------------------------- */
779 ipmi_add_guid(proto_tree
*tree
, gint hf
, tvbuff_t
*tvb
, guint offset
)
784 guid
.data1
= tvb_get_letohl(tvb
, offset
+ 12);
785 guid
.data2
= tvb_get_letohs(tvb
, offset
+ 10);
786 guid
.data3
= tvb_get_letohs(tvb
, offset
+ 8);
787 for (i
= 0; i
< 8; i
++) {
788 guid
.data4
[i
] = tvb_get_guint8(tvb
, offset
+ 7 - i
);
790 proto_tree_add_guid(tree
, hf
, tvb
, offset
, 16, &guid
);
793 /* ----------------------------------------------------------------
794 Routines for registering/looking up command parsers.
795 ---------------------------------------------------------------- */
798 ipmi_netfn_setdesc(guint32 netfn
, const char *desc
, guint32 siglen
)
800 struct ipmi_netfn_root
*inr
;
802 inr
= &ipmi_cmd_tab
[netfn
>> 1];
804 inr
->siglen
= siglen
;
808 ipmi_register_netfn_cmdtab(guint32 netfn
, guint oem_selector
,
809 const guint8
*sig
, guint32 siglen
, const char *desc
,
810 ipmi_cmd_t
*cmdtab
, guint32 cmdtablen
)
812 struct ipmi_netfn_root
*inr
;
815 netfn
>>= 1; /* Requests and responses grouped together */
816 if (netfn
>= IPMI_NETFN_MAX
) {
817 g_warning("NetFn too large: %x", netfn
* 2);
821 inr
= &ipmi_cmd_tab
[netfn
];
822 if (inr
->siglen
!= siglen
) {
823 /* All handlers per netFn should have the same signature length */
824 g_warning("NetFn %d: different signature lengths: %d vs %d",
825 netfn
* 2, inr
->siglen
, siglen
);
829 inh
= (struct ipmi_netfn_handler
*)g_malloc(sizeof(struct ipmi_netfn_handler
));
831 inh
->oem_selector
= oem_selector
;
833 inh
->cmdtab
= cmdtab
;
834 inh
->cmdtablen
= cmdtablen
;
836 inh
->next
= inr
->list
;
841 ipmi_getsiglen(guint32 netfn
)
843 return ipmi_cmd_tab
[netfn
>> 1].siglen
;
847 ipmi_getnetfnname(guint32 netfn
, ipmi_netfn_t
*nf
)
851 dn
= ipmi_cmd_tab
[netfn
>> 1].desc
?
852 ipmi_cmd_tab
[netfn
>> 1].desc
: "Reserved";
853 db
= nf
? nf
->desc
: NULL
;
855 return wmem_strdup_printf(wmem_packet_scope(), "%s (%s)", db
, dn
);
862 ipmi_getnetfn(guint32 netfn
, const guint8
*sig
)
864 struct ipmi_netfn_root
*inr
;
867 inr
= &ipmi_cmd_tab
[netfn
>> 1];
868 for (inh
= inr
->list
; inh
; inh
= inh
->next
) {
869 if ((inh
->oem_selector
== selected_oem
|| inh
->oem_selector
== IPMI_OEM_NONE
)
870 && (!inr
->siglen
|| !memcmp(sig
, inh
->sig
, inr
->siglen
))) {
875 /* Either unknown netFn or signature does not match */
880 ipmi_getcmd(ipmi_netfn_t
*nf
, guint32 cmd
)
882 static ipmi_cmd_t ipmi_cmd_unknown
= {
884 ipmi_notimpl
, /* request */
885 ipmi_notimpl
, /* response */
886 NULL
, /* command codes */
887 NULL
, /* subfunctions */
896 for (ic
= nf
->cmdtab
, i
= 0; i
< len
; i
++, ic
++) {
897 if (ic
->cmd
== cmd
) {
903 return &ipmi_cmd_unknown
;
906 /* ----------------------------------------------------------------
907 Various utility functions.
908 ---------------------------------------------------------------- */
911 ipmi_notimpl(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
)
914 proto_tree_add_text(tree
, tvb
, 0, -1, "[PARSER NOT IMPLEMENTED]");
919 ipmi_dcd8(guint32 val
, guint32 mask
)
923 decode_bitfield_value(buf
, val
, mask
, 8);
928 ipmi_fmt_10ms_1based(gchar
*s
, guint32 v
)
930 g_snprintf(s
, ITEM_LABEL_LENGTH
, "%d.%03d seconds", v
/ 100, (v
% 100) * 10);
934 ipmi_fmt_500ms_0based(gchar
*s
, guint32 v
)
936 ipmi_fmt_500ms_1based(s
, ++v
);
940 ipmi_fmt_500ms_1based(gchar
*s
, guint32 v
)
942 g_snprintf(s
, ITEM_LABEL_LENGTH
, "%d.%03d seconds", v
/ 2, (v
% 2) * 500);
946 ipmi_fmt_1s_0based(gchar
*s
, guint32 v
)
948 ipmi_fmt_1s_1based(s
, ++v
);
952 ipmi_fmt_1s_1based(gchar
*s
, guint32 v
)
954 g_snprintf(s
, ITEM_LABEL_LENGTH
, "%d seconds", v
);
958 ipmi_fmt_2s_0based(gchar
*s
, guint32 v
)
960 g_snprintf(s
, ITEM_LABEL_LENGTH
, "%d seconds", (v
+ 1) * 2);
964 ipmi_fmt_5s_1based(gchar
*s
, guint32 v
)
966 g_snprintf(s
, ITEM_LABEL_LENGTH
, "%d seconds", v
* 5);
970 ipmi_fmt_version(gchar
*s
, guint32 v
)
972 g_snprintf(s
, ITEM_LABEL_LENGTH
, "%d.%d", v
& 0x0f, (v
>> 4) & 0x0f);
976 ipmi_fmt_channel(gchar
*s
, guint32 v
)
978 static const value_string chan_vals
[] = {
979 { 0x00, "Primary IPMB (IPMB-0)" },
981 { 0x0e, "Current channel" },
982 { 0x0f, "System Interface" },
986 g_snprintf(s
, ITEM_LABEL_LENGTH
, "%s (0x%02x)",
987 val_to_str(v
, chan_vals
, "Channel #%d"), v
);
991 ipmi_fmt_udpport(gchar
*s
, guint32 v
)
993 g_snprintf(s
, ITEM_LABEL_LENGTH
, "%s (%d)", get_udp_port(v
), v
);
997 ipmi_fmt_percent(gchar
*s
, guint32 v
)
999 g_snprintf(s
, ITEM_LABEL_LENGTH
, "%d%%", v
);
1003 ipmi_get_completion_code(guint8 completion
, ipmi_cmd_t
*cmd
)
1005 static const value_string std_completion_codes
[] = {
1006 { 0x00, "Command Completed Normally" },
1007 { 0xc0, "Node Busy" },
1008 { 0xc1, "Invalid Command" },
1009 { 0xc2, "Command invalid for given LUN" },
1010 { 0xc3, "Timeout while processing command, response unavailable" },
1011 { 0xc4, "Out of space" },
1012 { 0xc5, "Reservation Canceled or Invalid Reservation ID" },
1013 { 0xc6, "Request data truncated" },
1014 { 0xc7, "Request data length invalid" },
1015 { 0xc8, "Request data field length limit exceeded" },
1016 { 0xc9, "Parameter out of range" },
1017 { 0xca, "Cannot return number of requested data bytes" },
1018 { 0xcb, "Requested Sensor, data, or record not present" },
1019 { 0xcc, "Invalid data field in Request" },
1020 { 0xcd, "Command illegal for specified sensor or record type" },
1021 { 0xce, "Command response could not be provided" },
1022 { 0xcf, "Cannot execute duplicated request" },
1023 { 0xd0, "Command response could not be provided: SDR Repository in update mode" },
1024 { 0xd1, "Command response could not be provided: device in firmware update mode" },
1025 { 0xd2, "Command response could not be provided: BMC initialization or initialization agent in progress" },
1026 { 0xd3, "Destination unavailable" },
1027 { 0xd4, "Cannot execute command: insufficient privilege level or other security-based restriction" },
1028 { 0xd5, "Cannot execute command: command, or request parameter(s), not supported in present state" },
1029 { 0xd6, "Cannot execute command: parameter is illegal because subfunction is disabled or unavailable" },
1030 { 0xff, "Unspecified error" },
1036 if (completion
>= 0x01 && completion
<= 0x7e) {
1037 return "Device specific (OEM) completion code";
1040 if (completion
>= 0x80 && completion
<= 0xbe) {
1041 if (cmd
&& cmd
->cs_cc
&& (res
= try_val_to_str(completion
, cmd
->cs_cc
)) != NULL
) {
1044 return "Standard command-specific code";
1047 return val_to_str_const(completion
, std_completion_codes
, "Unknown");
1050 /* Guess the parsing flags for a message
1053 ipmi_guess_dissect_flags(tvbuff_t
*tvb
)
1058 switch (message_format
) {
1062 return IPMI_D_TRG_SA
;
1064 return IPMI_D_TRG_SA
|IPMI_D_SESSION_HANDLE
;
1067 /* Try to guess the format */
1068 DISSECTOR_ASSERT(message_format
== MSGFMT_GUESS
);
1070 /* 6 is shortest message - Get Message with empty data */
1071 if (tvb_length(tvb
) < 6) {
1075 /* Fetch the beginning */
1076 for (i
= 0; i
< 6; i
++) {
1077 buf
[i
] = tvb_get_guint8(tvb
, i
);
1080 if ((buf
[0] + buf
[1] + buf
[2]) % 0x100 == 0) {
1081 /* Looks like IPMB: first 3 bytes are zero module 256 */
1082 return IPMI_D_TRG_SA
;
1085 if ((buf
[1] + buf
[2] + buf
[3]) % 0x100 == 0) {
1086 /* Looks like LAN: like IPMB, prepended with extra byte (session handle) */
1087 return IPMI_D_TRG_SA
|IPMI_D_SESSION_HANDLE
;
1094 /* Print out IPMB packet.
1097 ipmi_do_dissect(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*ipmi_tree
, ipmi_dissect_format_t
*dfmt
)
1099 proto_tree
*hdr_tree
, *data_tree
, *s_tree
;
1102 ipmi_netfn_t
*in
= NULL
;
1103 ipmi_cmd_t
*ic
= NULL
;
1104 ipmi_cmd_handler_t hnd
= NULL
;
1105 struct ipmi_saved_data
*saved_saved_data
;
1106 struct ipmi_header hdr
, *saved_hdr
;
1107 guint8 hdr_crc
, hdr_exp_crc
, data_crc
, data_exp_crc
;
1108 guint8 is_resp
, is_broadcast
= 0, tmp
;
1109 guint i
, len
, siglen
, hdrlen
, offs
, data_chk_offs
;
1110 const char *bcast
, *ndesc
, *cdesc
, *ccdesc
;
1112 if (dfmt
->flags
& IPMI_D_NONE
) {
1113 /* No parsing requested */
1114 g_snprintf(dfmt
->info
, ITEM_LABEL_LENGTH
, "Unknown message (not parsed)");
1115 proto_tree_add_item(ipmi_tree
, hf_ipmi_message
, tvb
, 0, tvb_length(tvb
), ENC_NA
);
1121 memset(&hdr
, 0, sizeof(hdr
));
1122 debug_printf("--> do_dissect(%d, nl %u, tree %s null)\n",
1123 pinfo
->fd
->num
, nest_level
, ipmi_tree
? "IS NOT" : "IS");
1125 /* Optional byte: in Send Message targeted to session-based channels */
1126 if (dfmt
->flags
& IPMI_D_SESSION_HANDLE
) {
1130 /* Optional byte: 00 indicates General Call address - broadcast message */
1131 if ((dfmt
->flags
& IPMI_D_BROADCAST
) && tvb_get_guint8(tvb
, offs
) == 0x00) {
1136 /* Byte 1: target slave address, may be absent (in Get Message) */
1137 hdr
.trg_sa
= (dfmt
->flags
& IPMI_D_TRG_SA
) ? tvb_get_guint8(tvb
, offs
++) : 0;
1139 /* Byte 2: network function + target LUN */
1140 tmp
= tvb_get_guint8(tvb
, offs
++);
1141 hdr
.trg_lun
= tmp
& 0x03;
1142 hdr
.netfn
= (tmp
>> 2) & 0x3f;
1143 hdr_exp_crc
= (0 - hdr
.trg_sa
- tmp
) & 0xff;
1145 /* Byte 3: header checksum */
1146 hdr_crc
= tvb_get_guint8(tvb
, offs
++);
1148 /* Byte 4: source slave address */
1149 hdr
.src_sa
= tvb_get_guint8(tvb
, offs
++);
1151 /* Byte 5: sequence number + source LUN */
1152 tmp
= tvb_get_guint8(tvb
, offs
++);
1153 hdr
.src_lun
= tmp
& 0x03;
1154 hdr
.seq
= (tmp
>> 2) & 0x3f;
1156 /* Byte 6: command code */
1157 hdr
.cmd
= tvb_get_guint8(tvb
, offs
++);
1159 /* Byte 7: completion code (in response) */
1160 is_resp
= (hdr
.netfn
& 0x1) ? 1 : 0;
1161 hdr
.ccode
= is_resp
? tvb_get_guint8(tvb
, offs
++) : 0;
1163 /* 0-3 bytes: signature of the defining body */
1164 siglen
= ipmi_getsiglen(hdr
.netfn
);
1165 in
= ipmi_getnetfn(hdr
.netfn
, tvb_get_ptr(tvb
, offs
, siglen
));
1168 /* Save header length */
1170 hdr
.data_len
= tvb_length(tvb
) - hdrlen
- 1;
1172 /* Get some text descriptions */
1173 ic
= ipmi_getcmd(in
, hdr
.cmd
);
1174 ndesc
= ipmi_getnetfnname(hdr
.netfn
, in
);
1176 ccdesc
= ipmi_get_completion_code(hdr
.ccode
, ic
);
1177 if (!is_broadcast
) {
1179 } else if (ic
->flags
& CMD_MAYBROADCAST
) {
1180 bcast
= " (BROADCAST: command may not be broadcast)";
1182 bcast
= " (BROADCAST)";
1186 /* Save globals - we may be called recursively */
1187 saved_hdr
= ipmi_current_hdr
;
1188 ipmi_current_hdr
= &hdr
;
1189 saved_saved_data
= current_saved_data
;
1190 current_saved_data
= NULL
;
1192 /* Select sub-handler */
1193 hnd
= is_resp
? ic
->parse_resp
: ic
->parse_req
;
1195 /* Start new conversation if needed */
1196 if (!is_resp
&& (ic
->flags
& CMD_NEWCONV
)) {
1197 conversation_new(pinfo
->fd
->num
, &pinfo
->src
,
1198 &pinfo
->dst
, pinfo
->ptype
,
1199 pinfo
->srcport
, pinfo
->destport
, 0);
1202 /* Check if we need to insert request-response pair */
1203 maybe_insert_reqresp(pinfo
, dfmt
, &hdr
);
1205 /* Create data subset: all but header and last byte (checksum) */
1206 data_tvb
= tvb_new_subset(tvb
, hdrlen
, hdr
.data_len
, hdr
.data_len
);
1208 /* Brief description of a packet */
1209 g_snprintf(dfmt
->info
, ITEM_LABEL_LENGTH
, "%s, %s, seq 0x%02x%s%s%s",
1210 is_resp
? "Rsp" : "Req", cdesc
, hdr
.seq
, bcast
,
1211 hdr
.ccode
? ", " : "", hdr
.ccode
? ccdesc
: "");
1213 if (!is_resp
&& (ic
->flags
& CMD_CALLRQ
)) {
1214 hnd(data_tvb
, pinfo
, NULL
);
1218 add_reqresp_info(dfmt
, &hdr
, ipmi_tree
, tvb
, pinfo
);
1220 ti
= proto_tree_add_text(ipmi_tree
, tvb
, 0, hdrlen
,
1221 "Header: %s (%s) from 0x%02x to 0x%02x%s", cdesc
,
1222 is_resp
? "Response" : "Request", hdr
.src_sa
, hdr
.trg_sa
, bcast
);
1223 hdr_tree
= proto_item_add_subtree(ti
, ett_header
);
1227 if (dfmt
->flags
& IPMI_D_SESSION_HANDLE
) {
1228 proto_tree_add_item(hdr_tree
, hf_ipmi_session_handle
,
1229 tvb
, offs
++, 1, ENC_LITTLE_ENDIAN
);
1232 /* Broadcast byte (optional) */
1234 proto_tree_add_uint_format(hdr_tree
, hf_ipmi_header_broadcast
,
1235 tvb
, offs
++, 1, 0x00, "Broadcast message");
1238 /* Target SA, if present */
1239 if (dfmt
->flags
& IPMI_D_TRG_SA
) {
1240 proto_tree_add_item(hdr_tree
, hf_ipmi_header_trg
, tvb
, offs
++, 1, ENC_LITTLE_ENDIAN
);
1243 /* Network function + target LUN */
1244 ti
= proto_tree_add_text(hdr_tree
, tvb
, offs
, 1,
1245 "Target LUN: 0x%02x, NetFN: %s %s (0x%02x)", hdr
.trg_lun
,
1246 ndesc
, is_resp
? "Response" : "Request", hdr
.netfn
);
1247 s_tree
= proto_item_add_subtree(ti
, ett_header_byte_1
);
1249 proto_tree_add_item(s_tree
, hf_ipmi_header_trg_lun
, tvb
, offs
, 1, ENC_LITTLE_ENDIAN
);
1250 proto_tree_add_uint_format(s_tree
, hf_ipmi_header_netfn
, tvb
, offs
, 1,
1251 hdr
.netfn
<< 2, "%sNetFn: %s %s (0x%02x)",
1252 ipmi_dcd8(hdr
.netfn
<< 2, 0xfc),
1253 ndesc
, is_resp
? "Response" : "Request", hdr
.netfn
);
1256 /* Header checksum */
1257 if (hdr_crc
== hdr_exp_crc
) {
1258 proto_tree_add_uint_format_value(hdr_tree
, hf_ipmi_header_crc
, tvb
, offs
++, 1,
1259 hdr_crc
, "0x%02x (correct)", hdr_crc
);
1262 ti
= proto_tree_add_boolean(hdr_tree
, hf_ipmi_bad_checksum
, tvb
, 0, 0, TRUE
);
1263 PROTO_ITEM_SET_HIDDEN(ti
);
1264 proto_tree_add_uint_format_value(hdr_tree
, hf_ipmi_header_crc
, tvb
, offs
++, 1,
1265 hdr_crc
, "0x%02x (incorrect, expected 0x%02x)",
1266 hdr_crc
, hdr_exp_crc
);
1269 /* Remember where chk2 bytes start */
1270 data_chk_offs
= offs
;
1273 proto_tree_add_item(hdr_tree
, hf_ipmi_header_src
, tvb
, offs
++, 1, ENC_LITTLE_ENDIAN
);
1275 /* Sequence number + source LUN */
1276 ti
= proto_tree_add_text(hdr_tree
, tvb
, offs
, 1,
1277 "Source LUN: 0x%02x, SeqNo: 0x%02x",
1278 hdr
.src_lun
, hdr
.seq
);
1279 s_tree
= proto_item_add_subtree(ti
, ett_header_byte_4
);
1281 proto_tree_add_item(s_tree
, hf_ipmi_header_src_lun
, tvb
, offs
, 1, ENC_LITTLE_ENDIAN
);
1282 proto_tree_add_item(s_tree
, hf_ipmi_header_sequence
, tvb
, offs
, 1, ENC_LITTLE_ENDIAN
);
1286 proto_tree_add_uint_format_value(hdr_tree
, hf_ipmi_header_command
, tvb
, offs
++, 1,
1287 hdr
.cmd
, "%s (0x%02x)", cdesc
, hdr
.cmd
);
1289 /* Response code (if present) */
1291 proto_tree_add_uint_format_value(hdr_tree
, hf_ipmi_header_completion
, tvb
, offs
++, 1,
1292 hdr
.ccode
, "%s (0x%02x)", ccdesc
, hdr
.ccode
);
1295 /* Defining body signature (if present) */
1297 ti
= proto_tree_add_item(hdr_tree
, hf_ipmi_header_sig
, tvb
, offs
, siglen
, ENC_NA
);
1298 proto_item_append_text(ti
, " (%s)", ndesc
);
1302 /* Call data parser */
1303 if (tvb_length(data_tvb
) && hnd
) {
1304 ti
= proto_tree_add_text(ipmi_tree
, data_tvb
, 0, -1, "Data");
1305 data_tree
= proto_item_add_subtree(ti
, ett_data
);
1306 hnd(data_tvb
, pinfo
, data_tree
);
1309 /* Checksum all but the last byte */
1310 len
= tvb_length(tvb
) - 1;
1311 data_crc
= tvb_get_guint8(tvb
, len
);
1313 for (i
= data_chk_offs
; i
< len
; i
++) {
1314 data_exp_crc
+= tvb_get_guint8(tvb
, i
);
1316 data_exp_crc
= (0 - data_exp_crc
) & 0xff;
1318 if (data_crc
== data_exp_crc
) {
1319 proto_tree_add_uint_format_value(ipmi_tree
, hf_ipmi_data_crc
, tvb
, len
, 1,
1320 data_crc
, "0x%02x (correct)", data_crc
);
1323 ti
= proto_tree_add_boolean(hdr_tree
, hf_ipmi_bad_checksum
, tvb
, 0, 0, TRUE
);
1324 PROTO_ITEM_SET_HIDDEN(ti
);
1325 proto_tree_add_uint_format_value(ipmi_tree
, hf_ipmi_data_crc
, tvb
, len
, 1,
1326 data_crc
, "0x%02x (incorrect, expected 0x%02x)",
1327 data_crc
, data_exp_crc
);
1331 /* Restore globals, in case we've been called recursively */
1332 ipmi_current_hdr
= saved_hdr
;
1333 current_saved_data
= saved_saved_data
;
1338 dissect_ipmi(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1340 proto_tree
*ipmi_tree
= NULL
;
1342 ipmi_dissect_format_t dfmt
;
1344 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IPMI/ATCA");
1347 ti
= proto_tree_add_item(tree
, proto_ipmi
, tvb
, 0, -1, ENC_NA
);
1348 ipmi_tree
= proto_item_add_subtree(ti
, ett_ipmi
);
1351 memset(&dfmt
, 0, sizeof(dfmt
));
1352 dfmt
.flags
= IPMI_D_BROADCAST
| IPMI_D_TRG_SA
;
1353 ipmi_do_dissect(tvb
, pinfo
, ipmi_tree
, &dfmt
);
1355 col_add_str(pinfo
->cinfo
, COL_INFO
, dfmt
.info
);
1359 /* Register IPMB protocol.
1362 proto_reg_handoff_ipmi(void)
1367 proto_register_ipmi(void)
1369 static hf_register_info hf
[] = {
1370 { &hf_ipmi_message
, { "Message", "ipmi.message", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
1371 { &hf_ipmi_session_handle
, { "Session handle", "ipmi.session_handle", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
1372 { &hf_ipmi_header_broadcast
, { "Broadcast message", "ipmi.header.broadcast", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
1373 { &hf_ipmi_header_trg
, { "Target Address", "ipmi.header.target", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1374 { &hf_ipmi_header_trg_lun
, { "Target LUN", "ipmi.header.trg_lun", FT_UINT8
, BASE_HEX
, NULL
, 0x03, NULL
, HFILL
}},
1375 { &hf_ipmi_header_netfn
, { "NetFN", "ipmi.header.netfn", FT_UINT8
, BASE_HEX
, NULL
, 0xfc, NULL
, HFILL
}},
1376 { &hf_ipmi_header_crc
, { "Header Checksum", "ipmi.header.crc", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
1377 { &hf_ipmi_header_src
, { "Source Address", "ipmi.header.source", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
1378 { &hf_ipmi_header_src_lun
, { "Source LUN", "ipmi.header.src_lun", FT_UINT8
, BASE_HEX
, NULL
, 0x03, NULL
, HFILL
}},
1379 { &hf_ipmi_header_sequence
, { "Sequence Number", "ipmi.header.sequence", FT_UINT8
, BASE_HEX
, NULL
, 0xfc, NULL
, HFILL
}},
1380 { &hf_ipmi_header_command
, { "Command", "ipmi.header.command", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
1381 { &hf_ipmi_header_completion
, { "Completion Code", "ipmi.header.completion", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
1382 { &hf_ipmi_header_sig
, { "Signature", "ipmi.header.signature", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
1383 { &hf_ipmi_data_crc
, { "Data checksum", "ipmi.data.crc", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
1384 { &hf_ipmi_response_to
, { "Response to", "ipmi.response_to", FT_FRAMENUM
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
1385 { &hf_ipmi_response_in
, { "Response in", "ipmi.response_in", FT_FRAMENUM
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
1386 { &hf_ipmi_response_time
, { "Responded in", "ipmi.response_time", FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
1387 { &hf_ipmi_bad_checksum
, { "Bad checksum", "ipmi.bad_checksum", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}}
1389 static gint
*ett
[] = {
1397 static const enum_val_t msgfmt_vals
[] = {
1398 { "none", "None", MSGFMT_NONE
},
1399 { "ipmb", "IPMB", MSGFMT_IPMB
},
1400 { "lan", "Session-based (LAN, ...)", MSGFMT_LAN
},
1401 { "guess", "Use heuristics", MSGFMT_GUESS
},
1404 static const enum_val_t oemsel_vals
[] = {
1405 { "none", "None", IPMI_OEM_NONE
},
1406 { "pps", "Pigeon Point Systems", IPMI_OEM_PPS
},
1412 proto_ipmi
= proto_register_protocol("Intelligent Platform Management Interface",
1416 proto_register_field_array(proto_ipmi
, hf
, array_length(hf
));
1417 proto_register_subtree_array(ett
, array_length(ett
));
1419 ipmi_netfn_setdesc(IPMI_CHASSIS_REQ
, "Chassis", 0);
1420 ipmi_netfn_setdesc(IPMI_BRIDGE_REQ
, "Bridge", 0);
1421 ipmi_netfn_setdesc(IPMI_SE_REQ
, "Sensor/Event", 0);
1422 ipmi_netfn_setdesc(IPMI_APP_REQ
, "Application", 0);
1423 ipmi_netfn_setdesc(IPMI_UPDATE_REQ
, "Firmware Update", 0);
1424 ipmi_netfn_setdesc(IPMI_STORAGE_REQ
, "Storage", 0);
1425 ipmi_netfn_setdesc(IPMI_TRANSPORT_REQ
, "Transport", 0);
1426 ipmi_netfn_setdesc(IPMI_GROUP_REQ
, "Group", 1);
1427 ipmi_netfn_setdesc(IPMI_OEM_REQ
, "OEM/Group", 3);
1428 for (i
= 0x30; i
< 0x40; i
+= 2) {
1429 ipmi_netfn_setdesc(i
, "OEM", 0);
1432 ipmi_register_chassis(proto_ipmi
);
1433 ipmi_register_bridge(proto_ipmi
);
1434 ipmi_register_se(proto_ipmi
);
1435 ipmi_register_app(proto_ipmi
);
1436 ipmi_register_update(proto_ipmi
);
1437 ipmi_register_storage(proto_ipmi
);
1438 ipmi_register_transport(proto_ipmi
);
1439 ipmi_register_picmg(proto_ipmi
);
1440 ipmi_register_pps(proto_ipmi
);
1442 register_dissector("ipmi", dissect_ipmi
, proto_ipmi
);
1444 m
= prefs_register_protocol(proto_ipmi
, NULL
);
1445 prefs_register_bool_preference(m
, "fru_langcode_is_english", "FRU Language Code is English",
1446 "FRU Language Code is English; strings are ASCII+LATIN1 (vs. Unicode)",
1447 &fru_langcode_is_english
);
1448 prefs_register_uint_preference(m
, "response_after_req", "Maximum delay of response message",
1449 "Do not search for responses coming after this timeout (milliseconds)",
1450 10, &response_after_req
);
1451 prefs_register_uint_preference(m
, "response_before_req", "Response ahead of request",
1452 "Allow for responses before requests (milliseconds)",
1453 10, &response_before_req
);
1454 prefs_register_enum_preference(m
, "msgfmt", "Format of embedded messages",
1455 "Format of messages embedded into Send/Get/Forward Message",
1456 &message_format
, msgfmt_vals
, FALSE
);
1457 prefs_register_enum_preference(m
, "selected_oem", "OEM commands parsed as",
1458 "Selects which OEM format is used for commands that IPMI does not define",
1459 &selected_oem
, oemsel_vals
, FALSE
);