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.
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
37 #include <epan/conversation.h>
38 #include <epan/emem.h>
39 #include <epan/packet.h>
40 #include <epan/to_str.h>
41 #include <epan/prefs.h>
42 #include <epan/addr_resolv.h>
44 #include "packet-ipmi.h"
47 * See the IPMI specifications at
49 * http://www.intel.com/design/servers/ipmi/
52 /* Define IPMI_DEBUG to enable printing the process of request-response pairing */
53 /* #define IPMI_DEBUG */
55 /* Top-level search structure: list of registered handlers for a given netFn */
56 struct ipmi_netfn_root {
64 /* We need more than a conversation. Over the same RMCP session
65 (or IPMB), there may be several addresses/SWIDs. Thus, in a single
66 Wireshark-maintained conversation we might need to find our own... */
67 struct ipmi_saved_data {
69 guint32 saved_data[NSAVED_DATA];
88 struct ipmi_reqresp *next;
89 struct ipmi_saved_data *data;
90 int (*whichresponse)(struct ipmi_header *hdr, struct ipmi_reqresp *rr);
94 } frames[MAX_RQRS_FRAMES];
100 struct ipmi_reqresp *rr;
103 struct ipmi_keytree {
107 struct ipmi_parse_typelen {
108 void (*get_len)(guint *, guint *, tvbuff_t *, guint, guint, gboolean);
109 void (*parse)(char *, tvbuff_t *, guint, guint);
113 struct ipmi_header *ipmi_current_hdr;
115 static gint proto_ipmi = -1;
117 static gboolean fru_langcode_is_english = TRUE;
118 static guint response_after_req = 5000;
119 static guint response_before_req = 0;
120 static guint message_format = MSGFMT_GUESS;
121 static guint selected_oem = IPMI_OEM_NONE;
123 static gint hf_ipmi_message = -1;
124 static gint hf_ipmi_session_handle = -1;
125 static gint hf_ipmi_header_broadcast = -1;
126 static gint hf_ipmi_header_trg = -1;
127 static gint hf_ipmi_header_trg_lun = -1;
128 static gint hf_ipmi_header_netfn = -1;
129 static gint hf_ipmi_header_crc = -1;
130 static gint hf_ipmi_header_src = -1;
131 static gint hf_ipmi_header_src_lun = -1;
132 static gint hf_ipmi_header_sequence = -1;
133 static gint hf_ipmi_header_command = -1;
134 static gint hf_ipmi_header_completion = -1;
135 static gint hf_ipmi_header_sig = -1;
136 static gint hf_ipmi_data_crc = -1;
137 static gint hf_ipmi_response_to = -1;
138 static gint hf_ipmi_response_in = -1;
139 static gint hf_ipmi_response_time = -1;
140 static gint hf_ipmi_bad_checksum = -1;
142 static gint ett_ipmi = -1;
143 static gint ett_header = -1;
144 static gint ett_header_byte_1 = -1;
145 static gint ett_header_byte_4 = -1;
146 static gint ett_data = -1;
147 static gint ett_typelen = -1;
149 static guint nest_level;
150 static packet_info *current_pinfo;
151 static struct ipmi_saved_data *current_saved_data;
152 static struct ipmi_netfn_root ipmi_cmd_tab[IPMI_NETFN_MAX];
156 debug_printf(const gchar *fmt _U_, ...)
158 #if defined(IPMI_DEBUG)
162 vfprintf(stderr, fmt, ap);
167 /* ----------------------------------------------------------------
168 Support for request-response caching.
169 ---------------------------------------------------------------- */
171 /* Key generation; returns the same key for requests and responses */
173 makekey(struct ipmi_header *hdr)
175 guint32 trg, src, res;
177 trg = (hdr->trg_sa << 2) | hdr->trg_lun;
178 src = (hdr->src_sa << 2) | hdr->src_lun;
179 res = trg < src ? (trg << 10) | src : (src << 10) | trg;
180 return (hdr->seq << 20) | res;
183 static struct ipmi_reqresp *
184 key_lookup_reqresp(struct ipmi_keyhead *kh, struct ipmi_header *hdr, frame_data *fd)
186 struct ipmi_reqresp *rr, *best_rr = NULL;
188 double d, best_d = (double)(2 * response_after_req);
189 guint8 netfn = hdr->netfn & 0x3e; /* disregard 'response' bit */
190 guint8 is_resp = hdr->netfn & 0x01;
193 /* Source/target SA/LUN and sequence number are assumed to match; se_tree*
194 ensure that. While checking for "being here", we can't rely on flags.visited,
195 as we may have more than one IPMI message in a single frame. */
196 for (rr = kh->rr; rr; rr = rr->next) {
197 if (rr->netfn != netfn || rr->cmd != hdr->cmd) {
201 for (i = 0; i < MAX_RQRS_FRAMES; i++) {
202 /* RQ=0 - 0th element is request frame number; RS/RS2 -
203 responses are non zero */
204 if (((!i) ^ is_resp) && rr->frames[i].num == fd->num) {
205 /* Already been here */
210 /* Reject responses before requests or more than 5 seconds ahead */
212 nstime_delta(&delta, &fd->abs_ts, &rr->frames[RQ].time);
214 /* Use RS here, not RS2 - frames[RS] is always filled if we had
215 at least one response */ /* TBD */
216 nstime_delta(&delta, &rr->frames[RS].time, &fd->abs_ts);
218 d = nstime_to_msec(&delta);
219 if (d < -(double)response_before_req || d > (double)response_after_req) {
223 if (fabs(d) < best_d) {
233 key_insert_reqresp(struct ipmi_keyhead *kh, struct ipmi_reqresp *rr)
235 /* Insert to head, so that the search would find most recent response */
240 static inline gboolean
241 set_framenums(struct ipmi_header *hdr, struct ipmi_reqresp *rr, frame_data *fd)
243 int which = hdr->netfn & 0x01 ? rr->whichresponse ? rr->whichresponse(hdr, rr) : RS : RQ;
245 if (rr->frames[which].num && rr->frames[which].num != fd->num) {
248 rr->frames[which].num = fd->num;
249 rr->frames[which].time = fd->abs_ts;
253 #define IS_SENDMSG(hdr) (((hdr)->netfn & 0x3e) == IPMI_APP_REQ && (hdr)->cmd == 0x34)
256 ipmi_sendmsg_whichresponse(struct ipmi_header *hdr, struct ipmi_reqresp *rr)
258 if (!IS_SENDMSG(hdr)) {
259 /* Not a Send Message: just a simple response */
263 if (hdr->data_len > 0) {
264 /* Trivial case: response with non-null data can only be a
265 response in AMC.0 style */
268 /* Otherwise, we need to somehow determine 1st and 2nd responses. Note
269 that both them may lack the data - in case that the embedded response
270 returned with error. Thus, employ the following algo:
271 - First, assign to [RS] frame (this also won't conflict with full response
272 received - it could only happen if send message succeeded)
273 - In case we see another data-less response, see that we assign the one
274 with success completion code to [RS] and with non-success code to [RS2].
276 We assume that we can't receive 2 responses with non-successful completion
277 (if the outmost Send Message failed, how was the embedded one sent?)
279 if (!rr->frames[RS].num) {
283 /* In case we received "success", move the other response to [RS2] */
285 if (!rr->frames[RS2].num) {
286 rr->frames[RS2] = rr->frames[RS];
291 /* [RS] occupied, non-successful */
296 ipmi_sendmsg_otheridx(struct ipmi_header *hdr)
298 return IS_SENDMSG(hdr) ? nest_level : RS;
302 ipmi_sendmsg_getheaders(struct ipmi_header *base, void *arg, guint i)
304 static struct ipmi_header hdr;
305 struct ipmi_header *wrapper = arg;
307 /* The problem stems from the fact that the original IPMI
308 specification (before errata came) did not specify the response
309 to Send Message (and even the fact that there are 2 responses -
310 to Send Message and to embedded command). Even then, there is
311 one vagueness remaining - whether the response should use
312 the sequence number from the wrapper or from the embedded message.
314 Thus, there are 3 types of responses to Send Message
316 * AMC.0-style: the response is embedded in a normal Send Message
317 response. Easiest case: such responses will be correctly detected
318 with the default code in ipmi_do_dissect.
320 * IPMI-style, with both variants of sequence numbers. Note that
321 most tools dealing with Send Message (e.g. ipmitool) circumvent
322 this vagueness by using the same sequence number in both wrapper
323 and embedded messages. If we detect such "smart" messages, we
324 provide only one extra header. For correctness, we have to provide
325 for both variants, however.
328 if (i >= 2 || (i == 1 && wrapper->seq == base->seq)) {
332 /* Construct hybrid header */
333 hdr.trg_sa = wrapper->trg_sa;
334 hdr.trg_lun = wrapper->trg_lun;
335 hdr.src_sa = wrapper->src_sa;
336 hdr.src_lun = wrapper->src_lun;
337 hdr.netfn = base->netfn;
339 hdr.seq = i ? base->seq : wrapper->seq;
340 hdr.ccode = base->ccode;
341 hdr.data_len = base->data_len;
346 maybe_insert_reqresp(ipmi_dissect_format_t *dfmt, struct ipmi_header *hdr)
349 struct ipmi_keytree *kt;
350 struct ipmi_keyhead *kh;
351 struct ipmi_reqresp *rr;
354 cnv = find_or_create_conversation(current_pinfo);
356 kt = conversation_get_proto_data(cnv, proto_ipmi);
358 kt = se_alloc(sizeof(struct ipmi_keytree));
359 kt->heads = se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK,
361 conversation_add_proto_data(cnv, proto_ipmi, kt);
364 debug_printf("--> maybe_insert_reqresp( %d )\n", current_pinfo->fd->num);
367 debug_printf("Checking [ (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
368 hdr->trg_sa, hdr->trg_lun, hdr->src_sa, hdr->src_lun, hdr->seq,
369 hdr->netfn, hdr->cmd);
371 kh = se_tree_lookup32(kt->heads, key);
373 kh = se_alloc0(sizeof(struct ipmi_keyhead));
374 se_tree_insert32(kt->heads, key, kh);
376 if ((rr = key_lookup_reqresp(kh, hdr, current_pinfo->fd)) != NULL) {
377 /* Already recorded - set frame number and be done. Look no
378 further - even if there are several responses, we have
379 found the right one. */
380 debug_printf("Found existing [ <%d,%d,%d> (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
381 rr->frames[0].num, rr->frames[1].num, rr->frames[2].num,
382 hdr->trg_sa, hdr->trg_lun, hdr->src_sa, hdr->src_lun, hdr->seq,
384 if (!rr->whichresponse) {
385 rr->whichresponse = dfmt->whichresponse;
387 if (set_framenums(hdr, rr, current_pinfo->fd)) {
388 debug_printf("Set frames [ <%d,%d,%d> (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
389 rr->frames[0].num, rr->frames[1].num, rr->frames[2].num,
390 hdr->trg_sa, hdr->trg_lun, hdr->src_sa, hdr->src_lun, hdr->seq,
392 current_saved_data = rr->data;
396 /* Found, but already occupied. Fall through to allocating the structures */
397 current_saved_data = NULL;
399 /* Not found; allocate new structures */
400 if (!current_saved_data) {
401 /* One 'ipmi_saved_data' for all 'ipmi_req_resp' allocated */
402 current_saved_data = se_alloc0(sizeof(struct ipmi_saved_data));
404 rr = se_alloc0(sizeof(struct ipmi_reqresp));
405 rr->whichresponse = dfmt->whichresponse;
406 rr->netfn = hdr->netfn & 0x3e;
408 rr->data = current_saved_data;
409 set_framenums(hdr, rr, current_pinfo->fd);
410 key_insert_reqresp(kh, rr);
411 debug_printf("Inserted [ <%d,%d,%d> (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
412 rr->frames[0].num, rr->frames[1].num, rr->frames[2].num,
413 hdr->trg_sa, hdr->trg_lun, hdr->src_sa, hdr->src_lun, hdr->seq,
416 /* Do we have other headers to insert? */
417 hdr = dfmt->getmoreheaders ? dfmt->getmoreheaders(hdr, dfmt->arg, i++) : NULL;
422 add_reqresp_info(ipmi_dissect_format_t *dfmt, struct ipmi_header *hdr, proto_tree *tree, tvbuff_t *tvb)
425 struct ipmi_keytree *kt;
426 struct ipmi_keyhead *kh;
427 struct ipmi_reqresp *rr = NULL;
428 guint32 key, i, other_idx;
432 debug_printf("--> add_reqresp_info( %d )\n", current_pinfo->fd->num);
434 /* [0] is request; [1..MAX_RS_LEVEL] are responses */
435 other_idx = (hdr->netfn & 0x01) ? RQ : dfmt->otheridx ? dfmt->otheridx(hdr) : RS;
437 if (other_idx >= MAX_RQRS_FRAMES) {
438 /* No chance; we don't look that deep into nested Send Message.
439 Note that we'll use the other_idx value to distinguish
440 request from response. */
444 /* Here, we don't try to create any object - everything is assumed
445 to be created in maybe_insert_reqresp() */
446 if ((cnv = find_conversation(current_pinfo->fd->num, ¤t_pinfo->src,
447 ¤t_pinfo->dst, current_pinfo->ptype,
448 current_pinfo->srcport, current_pinfo->destport, 0)) == NULL) {
451 if ((kt = conversation_get_proto_data(cnv, proto_ipmi)) == NULL) {
457 debug_printf("Looking for [ (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
458 hdr->trg_sa, hdr->trg_lun, hdr->src_sa, hdr->src_lun, hdr->seq,
459 hdr->netfn, hdr->cmd);
461 if ((kh = se_tree_lookup32(kt->heads, key)) != NULL &&
462 (rr = key_lookup_reqresp(kh, hdr, current_pinfo->fd)) != NULL) {
463 debug_printf("Found [ <%d,%d,%d> (%02x,%1x <-> %02x,%1x : %02x) %02x %02x ]\n",
464 rr->frames[0].num, rr->frames[1].num, rr->frames[2].num,
465 hdr->trg_sa, hdr->trg_lun, hdr->src_sa, hdr->src_lun, hdr->seq,
467 if (rr->frames[other_idx].num) {
472 /* Do we have other headers to check? */
473 hdr = dfmt->getmoreheaders ? dfmt->getmoreheaders(hdr, dfmt->arg, i++) : NULL;
479 if (hdr->netfn & 0x01) {
481 ti = proto_tree_add_uint(tree, hf_ipmi_response_to,
482 tvb, 0, 0, rr->frames[RQ].num);
483 PROTO_ITEM_SET_GENERATED(ti);
484 nstime_delta(&ns, ¤t_pinfo->fd->abs_ts, &rr->frames[RQ].time);
485 ti = proto_tree_add_time(tree, hf_ipmi_response_time,
487 PROTO_ITEM_SET_GENERATED(ti);
490 ti = proto_tree_add_uint(tree, hf_ipmi_response_in,
491 tvb, 0, 0, rr->frames[other_idx].num);
492 PROTO_ITEM_SET_GENERATED(ti);
497 ti = proto_tree_add_text(tree, tvb, 0, 0, "No corresponding %s",
498 other_idx ? "response" : "request");
499 PROTO_ITEM_SET_GENERATED(ti);
502 /* Save data in request, retrieve in response */
504 ipmi_setsaveddata(guint idx, guint32 val)
506 DISSECTOR_ASSERT(idx < NSAVED_DATA);
507 current_saved_data->saved_data[idx] = val;
508 current_saved_data->set_data |= (1 << idx);
512 ipmi_getsaveddata(guint idx, guint32 *pval)
514 DISSECTOR_ASSERT(idx < NSAVED_DATA);
515 if (current_saved_data->set_data & (1 << idx)) {
516 *pval = current_saved_data->saved_data[idx];
522 /* ----------------------------------------------------------------
523 Support for Type/Length fields parsing.
524 ---------------------------------------------------------------- */
527 get_len_binary(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
528 guint len, gboolean len_is_bytes _U_)
535 parse_binary(char *p, tvbuff_t *tvb, guint offs, guint len)
537 static const char hex[] = "0123456789ABCDEF";
541 for (i = 0; i < len / 3; i++) {
542 v = tvb_get_guint8(tvb, offs + i);
553 static struct ipmi_parse_typelen ptl_binary = {
554 get_len_binary, parse_binary, "Binary"
558 get_len_bcdplus(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
559 guint len, gboolean len_is_bytes)
565 *blen = (len + 1) / 2;
571 parse_bcdplus(char *p, tvbuff_t *tvb, guint offs, guint len)
573 static const char bcd[] = "0123456789 -.:,_";
574 guint i, msk = 0xf0, shft = 4;
577 for (i = 0; i < len; i++) {
578 v = (tvb_get_guint8(tvb, offs + i / 2) & msk) >> shft;
585 static struct ipmi_parse_typelen ptl_bcdplus = {
586 get_len_bcdplus, parse_bcdplus, "BCD+"
590 get_len_6bit_ascii(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
591 guint len, gboolean len_is_bytes)
597 *blen = (len * 3 + 3) / 4;
603 parse_6bit_ascii(char *p, tvbuff_t *tvb, guint offs, guint len)
608 /* First, handle "full" triplets of bytes, 4 characters each */
609 for (i = 0; i < len / 4; i++) {
610 v = tvb_get_letoh24(tvb, offs + i * 3);
611 p[0] = ' ' + (v & 0x3f);
612 p[1] = ' ' + ((v >> 6) & 0x3f);
613 p[2] = ' ' + ((v >> 12) & 0x3f);
614 p[3] = ' ' + ((v >> 18) & 0x3f);
618 /* Do we have any characters left? */
623 v = (tvb_get_guint8(tvb, offs + 2) << 4) | (tvb_get_guint8(tvb, offs + 1) >> 4);
624 p[2] = ' ' + (v & 0x3f);
627 v = (tvb_get_guint8(tvb, offs + 1) << 2) | (tvb_get_guint8(tvb, offs) >> 6);
628 p[1] = ' ' + (v & 0x3f);
631 v = tvb_get_guint8(tvb, offs) & 0x3f;
632 p[0] = ' ' + (v & 0x3f);
636 static struct ipmi_parse_typelen ptl_6bit_ascii = {
637 get_len_6bit_ascii, parse_6bit_ascii, "6-bit ASCII"
641 get_len_8bit_ascii(guint *clen, guint *blen, tvbuff_t *tvb, guint offs,
642 guint len, gboolean len_is_bytes _U_)
647 *blen = len; /* One byte is one character */
649 for (i = 0; i < len; i++) {
650 ch = tvb_get_guint8(tvb, offs + i);
651 *clen += (ch >= 0x20 && ch <= 0x7f) ? 1 : 4;
656 parse_8bit_ascii(char *p, tvbuff_t *tvb, guint offs, guint len)
663 ch = tvb_get_guint8(tvb, offs++);
664 if (ch >= 0x20 && ch <= 0x7f) {
667 g_snprintf(p, 5, "\\x%02x", ch);
673 static struct ipmi_parse_typelen ptl_8bit_ascii = {
674 get_len_8bit_ascii, parse_8bit_ascii, "ASCII+Latin1"
678 get_len_unicode(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
679 guint len _U_, gboolean len_is_bytes)
682 *clen = len * 3; /* Each 2 bytes result in 6 chars printed: \Uxxxx */
691 parse_unicode(char *p, tvbuff_t *tvb, guint offs, guint len)
693 char *pmax = p + len;
697 ch0 = tvb_get_guint8(tvb, offs++);
698 ch1 = tvb_get_guint8(tvb, offs++);
699 g_snprintf(p, 7, "\\U%02x%02x", ch0, ch1);
704 static struct ipmi_parse_typelen ptl_unicode = {
705 get_len_unicode, parse_unicode, "Unicode"
709 ipmi_add_typelen(proto_tree *tree, const char *desc, tvbuff_t *tvb,
710 guint offs, gboolean is_fru)
712 static struct ipmi_parse_typelen *fru_eng[4] = {
713 &ptl_binary, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_8bit_ascii
715 static struct ipmi_parse_typelen *fru_noneng[4] = {
716 &ptl_binary, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_unicode
718 static struct ipmi_parse_typelen *ipmi[4] = {
719 &ptl_unicode, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_8bit_ascii
721 struct ipmi_parse_typelen *ptr;
724 guint type, msk, clen, blen, len;
729 typelen = tvb_get_guint8(tvb, offs);
733 ptr = (fru_langcode_is_english ? fru_eng : fru_noneng)[type];
742 ptr->get_len(&clen, &blen, tvb, offs + 1, len, is_fru);
744 str = ep_alloc(clen + 1);
745 ptr->parse(str, tvb, offs + 1, clen);
748 ti = proto_tree_add_text(tree, tvb, offs, 1, "%s Type/Length byte: %s, %d %s",
749 desc, ptr->desc, len, unit);
750 s_tree = proto_item_add_subtree(ti, ett_typelen);
751 proto_tree_add_text(s_tree, tvb, offs, 1, "%sType: %s (0x%02x)",
752 ipmi_dcd8(typelen, 0xc0), ptr->desc, type);
753 proto_tree_add_text(s_tree, tvb, offs, 1, "%sLength: %d %s",
754 ipmi_dcd8(typelen, msk), len, unit);
756 proto_tree_add_text(tree, tvb, offs + 1, blen, "%s: [%s] '%s'",
757 desc, ptr->desc, str);
760 /* ----------------------------------------------------------------
761 Timestamp, IPMI-style.
762 ---------------------------------------------------------------- */
764 ipmi_add_timestamp(proto_tree *tree, gint hf, tvbuff_t *tvb, guint offset)
766 guint32 ts = tvb_get_letohl(tvb, offset);
768 if (ts == 0xffffffff) {
769 proto_tree_add_uint_format_value(tree, hf, tvb, offset, 4,
770 ts, "Unspecified/Invalid");
771 } else if (ts <= 0x20000000) {
772 proto_tree_add_uint_format_value(tree, hf, tvb, offset, 4,
773 ts, "%s since SEL device's initialization",
774 time_secs_to_str_unsigned(ts));
776 proto_tree_add_uint_format_value(tree, hf, tvb, offset, 4,
777 ts, "%s", abs_time_secs_to_str(ts, ABSOLUTE_TIME_UTC, TRUE));
781 /* ----------------------------------------------------------------
783 ---------------------------------------------------------------- */
786 ipmi_add_guid(proto_tree *tree, gint hf, tvbuff_t *tvb, guint offset)
791 guid.data1 = tvb_get_letohl(tvb, offset + 12);
792 guid.data2 = tvb_get_letohs(tvb, offset + 10);
793 guid.data3 = tvb_get_letohs(tvb, offset + 8);
794 for (i = 0; i < 8; i++) {
795 guid.data4[i] = tvb_get_guint8(tvb, offset + 7 - i);
797 proto_tree_add_guid(tree, hf, tvb, offset, 16, &guid);
800 /* ----------------------------------------------------------------
801 Routines for registering/looking up command parsers.
802 ---------------------------------------------------------------- */
805 ipmi_netfn_setdesc(guint32 netfn, const char *desc, guint32 siglen)
807 struct ipmi_netfn_root *inr;
809 inr = &ipmi_cmd_tab[netfn >> 1];
811 inr->siglen = siglen;
815 ipmi_register_netfn_cmdtab(guint32 netfn, guint oem_selector,
816 const guint8 *sig, guint32 siglen, const char *desc,
817 ipmi_cmd_t *cmdtab, guint32 cmdtablen)
819 struct ipmi_netfn_root *inr;
822 netfn >>= 1; /* Requests and responses grouped together */
823 if (netfn >= IPMI_NETFN_MAX) {
824 g_warning("NetFn too large: %x", netfn * 2);
828 inr = &ipmi_cmd_tab[netfn];
829 if (inr->siglen != siglen) {
830 /* All handlers per netFn should have the same signature length */
831 g_warning("NetFn %d: different signature lengths: %d vs %d",
832 netfn * 2, inr->siglen, siglen);
836 inh = g_malloc(sizeof(struct ipmi_netfn_handler));
838 inh->oem_selector = oem_selector;
840 inh->cmdtab = cmdtab;
841 inh->cmdtablen = cmdtablen;
843 inh->next = inr->list;
848 ipmi_getsiglen(guint32 netfn)
850 return ipmi_cmd_tab[netfn >> 1].siglen;
854 ipmi_getnetfnname(guint32 netfn, ipmi_netfn_t *nf)
858 dn = ipmi_cmd_tab[netfn >> 1].desc ?
859 ipmi_cmd_tab[netfn >> 1].desc : "Reserved";
860 db = nf ? nf->desc : NULL;
862 return ep_strdup_printf("%s (%s)", db, dn);
869 ipmi_getnetfn(guint32 netfn, const guint8 *sig)
871 struct ipmi_netfn_root *inr;
874 inr = &ipmi_cmd_tab[netfn >> 1];
875 for (inh = inr->list; inh; inh = inh->next) {
876 if ((inh->oem_selector == selected_oem || inh->oem_selector == IPMI_OEM_NONE)
877 && (!inr->siglen || !memcmp(sig, inh->sig, inr->siglen))) {
882 /* Either unknown netFn or signature does not match */
887 ipmi_getcmd(ipmi_netfn_t *nf, guint32 cmd)
889 static ipmi_cmd_t ipmi_cmd_unknown = {
891 ipmi_notimpl, /* request */
892 ipmi_notimpl, /* response */
893 NULL, /* command codes */
894 NULL, /* subfunctions */
903 for (ic = nf->cmdtab, i = 0; i < len; i++, ic++) {
904 if (ic->cmd == cmd) {
910 return &ipmi_cmd_unknown;
913 /* ----------------------------------------------------------------
914 Various utility functions.
915 ---------------------------------------------------------------- */
918 ipmi_notimpl(tvbuff_t *tvb, proto_tree *tree)
921 proto_tree_add_text(tree, tvb, 0, -1, "[PARSER NOT IMPLEMENTED]");
926 ipmi_dcd8(guint32 val, guint32 mask)
930 decode_bitfield_value(buf, val, mask, 8);
935 ipmi_fmt_10ms_1based(gchar *s, guint32 v)
937 g_snprintf(s, ITEM_LABEL_LENGTH, "%d.%03d seconds", v / 100, (v % 100) * 10);
941 ipmi_fmt_500ms_0based(gchar *s, guint32 v)
943 ipmi_fmt_500ms_1based(s, ++v);
947 ipmi_fmt_500ms_1based(gchar *s, guint32 v)
949 g_snprintf(s, ITEM_LABEL_LENGTH, "%d.%03d seconds", v / 2, (v % 2) * 500);
953 ipmi_fmt_1s_0based(gchar *s, guint32 v)
955 ipmi_fmt_1s_1based(s, ++v);
959 ipmi_fmt_1s_1based(gchar *s, guint32 v)
961 g_snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", v);
965 ipmi_fmt_2s_0based(gchar *s, guint32 v)
967 g_snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", (v + 1) * 2);
971 ipmi_fmt_5s_1based(gchar *s, guint32 v)
973 g_snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", v * 5);
977 ipmi_fmt_version(gchar *s, guint32 v)
979 g_snprintf(s, ITEM_LABEL_LENGTH, "%d.%d", v & 0x0f, (v >> 4) & 0x0f);
983 ipmi_fmt_channel(gchar *s, guint32 v)
985 static const value_string chan_vals[] = {
986 { 0x00, "Primary IPMB (IPMB-0)" },
988 { 0x0e, "Current channel" },
989 { 0x0f, "System Interface" },
993 g_snprintf(s, ITEM_LABEL_LENGTH, "%s (0x%02x)",
994 val_to_str(v, chan_vals, "Channel #%d"), v);
998 ipmi_fmt_udpport(gchar *s, guint32 v)
1000 g_snprintf(s, ITEM_LABEL_LENGTH, "%s (%d)", get_udp_port(v), v);
1004 ipmi_fmt_percent(gchar *s, guint32 v)
1006 g_snprintf(s, ITEM_LABEL_LENGTH, "%d%%", v);
1010 ipmi_get_completion_code(guint8 completion, ipmi_cmd_t *cmd)
1012 static const value_string std_completion_codes[] = {
1013 { 0x00, "Command Completed Normally" },
1014 { 0xc0, "Node Busy" },
1015 { 0xc1, "Invalid Command" },
1016 { 0xc2, "Command invalid for given LUN" },
1017 { 0xc3, "Timeout while processing command, response unavailable" },
1018 { 0xc4, "Out of space" },
1019 { 0xc5, "Reservation Canceled or Invalid Reservation ID" },
1020 { 0xc6, "Request data truncated" },
1021 { 0xc7, "Request data length invalid" },
1022 { 0xc8, "Request data field length limit exceeded" },
1023 { 0xc9, "Parameter out of range" },
1024 { 0xca, "Cannot return number of requested data bytes" },
1025 { 0xcb, "Requested Sensor, data, or record not present" },
1026 { 0xcc, "Invalid data field in Request" },
1027 { 0xcd, "Command illegal for specified sensor or record type" },
1028 { 0xce, "Command response could not be provided" },
1029 { 0xcf, "Cannot execute duplicated request" },
1030 { 0xd0, "Command response could not be provided: SDR Repository in update mode" },
1031 { 0xd1, "Command response could not be provided: device in firmware update mode" },
1032 { 0xd2, "Command response could not be provided: BMC initialization or initialization agent in progress" },
1033 { 0xd3, "Destination unavailable" },
1034 { 0xd4, "Cannot execute command: insufficient privilege level or other security-based restriction" },
1035 { 0xd5, "Cannot execute command: command, or request parameter(s), not supported in present state" },
1036 { 0xd6, "Cannot execute command: parameter is illegal because subfunction is disabled or unavailable" },
1037 { 0xff, "Unspecified error" },
1043 if (completion >= 0x01 && completion <= 0x7e) {
1044 return "Device specific (OEM) completion code";
1047 if (completion >= 0x80 && completion <= 0xbe) {
1048 if (cmd && cmd->cs_cc && (res = match_strval(completion, cmd->cs_cc)) != NULL) {
1051 return "Standard command-specific code";
1054 return val_to_str(completion, std_completion_codes, "Unknown");
1057 /* Guess the parsing flags for a message
1060 ipmi_guess_dissect_flags(tvbuff_t *tvb)
1065 switch (message_format) {
1069 return IPMI_D_TRG_SA;
1071 return IPMI_D_TRG_SA|IPMI_D_SESSION_HANDLE;
1074 /* Try to guess the format */
1075 DISSECTOR_ASSERT(message_format == MSGFMT_GUESS);
1077 /* 6 is shortest message - Get Message with empty data */
1078 if (tvb_length(tvb) < 6) {
1082 /* Fetch the beginning */
1083 for (i = 0; i < 6; i++) {
1084 buf[i] = tvb_get_guint8(tvb, i);
1087 if ((buf[0] + buf[1] + buf[2]) % 0x100 == 0) {
1088 /* Looks like IPMB: first 3 bytes are zero module 256 */
1089 return IPMI_D_TRG_SA;
1092 if ((buf[1] + buf[2] + buf[3]) % 0x100 == 0) {
1093 /* Looks like LAN: like IPMB, prepended with extra byte (session handle) */
1094 return IPMI_D_TRG_SA|IPMI_D_SESSION_HANDLE;
1101 /* Print out IPMB packet.
1104 ipmi_do_dissect(tvbuff_t *tvb, proto_tree *ipmi_tree, ipmi_dissect_format_t *dfmt)
1106 proto_tree *hdr_tree, *data_tree, *s_tree;
1109 ipmi_netfn_t *in = NULL;
1110 ipmi_cmd_t *ic = NULL;
1111 ipmi_cmd_handler_t hnd = NULL;
1112 struct ipmi_saved_data *saved_saved_data;
1113 struct ipmi_header hdr, *saved_hdr;
1114 guint8 hdr_crc, hdr_exp_crc, data_crc, data_exp_crc;
1115 guint8 is_resp, is_broadcast = 0, tmp;
1116 guint i, len, siglen, hdrlen, offs, data_chk_offs;
1117 const char *bcast, *ndesc, *cdesc, *ccdesc;
1119 if (dfmt->flags & IPMI_D_NONE) {
1120 /* No parsing requested */
1121 g_snprintf(dfmt->info, ITEM_LABEL_LENGTH, "Unknown message (not parsed)");
1122 proto_tree_add_item(ipmi_tree, hf_ipmi_message, tvb, 0, tvb_length(tvb), TRUE);
1128 memset(&hdr, 0, sizeof(hdr));
1129 debug_printf("--> do_dissect(%d, nl %u, tree %s null)\n",
1130 current_pinfo->fd->num, nest_level, ipmi_tree ? "IS NOT" : "IS");
1132 /* Optional byte: in Send Message targeted to session-based channels */
1133 if (dfmt->flags & IPMI_D_SESSION_HANDLE) {
1137 /* Optional byte: 00 indicates General Call address - broadcast message */
1138 if ((dfmt->flags & IPMI_D_BROADCAST) && tvb_get_guint8(tvb, offs) == 0x00) {
1143 /* Byte 1: target slave address, may be absent (in Get Message) */
1144 hdr.trg_sa = (dfmt->flags & IPMI_D_TRG_SA) ? tvb_get_guint8(tvb, offs++) : 0;
1146 /* Byte 2: network function + target LUN */
1147 tmp = tvb_get_guint8(tvb, offs++);
1148 hdr.trg_lun = tmp & 0x03;
1149 hdr.netfn = (tmp >> 2) & 0x3f;
1150 hdr_exp_crc = (0 - hdr.trg_sa - tmp) & 0xff;
1152 /* Byte 3: header checksum */
1153 hdr_crc = tvb_get_guint8(tvb, offs++);
1155 /* Byte 4: source slave address */
1156 hdr.src_sa = tvb_get_guint8(tvb, offs++);
1158 /* Byte 5: sequence number + source LUN */
1159 tmp = tvb_get_guint8(tvb, offs++);
1160 hdr.src_lun = tmp & 0x03;
1161 hdr.seq = (tmp >> 2) & 0x3f;
1163 /* Byte 6: command code */
1164 hdr.cmd = tvb_get_guint8(tvb, offs++);
1166 /* Byte 7: completion code (in response) */
1167 is_resp = (hdr.netfn & 0x1) ? 1 : 0;
1168 hdr.ccode = is_resp ? tvb_get_guint8(tvb, offs++) : 0;
1170 /* 0-3 bytes: signature of the defining body */
1171 siglen = ipmi_getsiglen(hdr.netfn);
1172 in = ipmi_getnetfn(hdr.netfn, tvb_get_ptr(tvb, offs, siglen));
1175 /* Save header length */
1177 hdr.data_len = tvb_length(tvb) - hdrlen - 1;
1179 /* Get some text descriptions */
1180 ic = ipmi_getcmd(in, hdr.cmd);
1181 ndesc = ipmi_getnetfnname(hdr.netfn, in);
1183 ccdesc = ipmi_get_completion_code(hdr.ccode, ic);
1184 if (!is_broadcast) {
1186 } else if (ic->flags & CMD_MAYBROADCAST) {
1187 bcast = " (BROADCAST: command may not be broadcast)";
1189 bcast = " (BROADCAST)";
1193 /* Save globals - we may be called recursively */
1194 saved_hdr = ipmi_current_hdr;
1195 ipmi_current_hdr = &hdr;
1196 saved_saved_data = current_saved_data;
1197 current_saved_data = NULL;
1199 /* Select sub-handler */
1200 hnd = is_resp ? ic->parse_resp : ic->parse_req;
1202 /* Start new conversation if needed */
1203 if (!is_resp && (ic->flags & CMD_NEWCONV)) {
1204 conversation_new(current_pinfo->fd->num, ¤t_pinfo->src,
1205 ¤t_pinfo->dst, current_pinfo->ptype,
1206 current_pinfo->srcport, current_pinfo->destport, 0);
1209 /* Check if we need to insert request-response pair */
1210 maybe_insert_reqresp(dfmt, &hdr);
1212 /* Create data subset: all but header and last byte (checksum) */
1213 data_tvb = tvb_new_subset(tvb, hdrlen, hdr.data_len, hdr.data_len);
1215 /* Brief description of a packet */
1216 g_snprintf(dfmt->info, ITEM_LABEL_LENGTH, "%s, %s, seq 0x%02x%s%s%s",
1217 is_resp ? "Rsp" : "Req", cdesc, hdr.seq, bcast,
1218 hdr.ccode ? ", " : "", hdr.ccode ? ccdesc : "");
1220 if (!is_resp && (ic->flags & CMD_CALLRQ)) {
1221 hnd(data_tvb, NULL);
1225 add_reqresp_info(dfmt, &hdr, ipmi_tree, tvb);
1227 ti = proto_tree_add_text(ipmi_tree, tvb, 0, hdrlen,
1228 "Header: %s (%s) from 0x%02x to 0x%02x%s", cdesc,
1229 is_resp ? "Response" : "Request", hdr.src_sa, hdr.trg_sa, bcast);
1230 hdr_tree = proto_item_add_subtree(ti, ett_header);
1234 if (dfmt->flags & IPMI_D_SESSION_HANDLE) {
1235 proto_tree_add_item(hdr_tree, hf_ipmi_session_handle,
1236 tvb, offs++, 1, TRUE);
1239 /* Broadcast byte (optional) */
1241 proto_tree_add_uint_format(hdr_tree, hf_ipmi_header_broadcast,
1242 tvb, offs++, 1, 0x00, "Broadcast message");
1245 /* Target SA, if present */
1246 if (dfmt->flags & IPMI_D_TRG_SA) {
1247 proto_tree_add_item(hdr_tree, hf_ipmi_header_trg, tvb, offs++, 1, TRUE);
1250 /* Network function + target LUN */
1251 ti = proto_tree_add_text(hdr_tree, tvb, offs, 1,
1252 "Target LUN: 0x%02x, NetFN: %s %s (0x%02x)", hdr.trg_lun,
1253 ndesc, is_resp ? "Response" : "Request", hdr.netfn);
1254 s_tree = proto_item_add_subtree(ti, ett_header_byte_1);
1256 proto_tree_add_item(s_tree, hf_ipmi_header_trg_lun, tvb, offs, 1, TRUE);
1257 proto_tree_add_uint_format(s_tree, hf_ipmi_header_netfn, tvb, offs, 1,
1258 hdr.netfn << 2, "%sNetFn: %s %s (0x%02x)",
1259 ipmi_dcd8(hdr.netfn << 2, 0xfc),
1260 ndesc, is_resp ? "Response" : "Request", hdr.netfn);
1263 /* Header checksum */
1264 if (hdr_crc == hdr_exp_crc) {
1265 proto_tree_add_uint_format(hdr_tree, hf_ipmi_header_crc, tvb, offs++, 1,
1266 hdr_crc, "Header checksum: 0x%02x (correct)", hdr_crc);
1269 ti = proto_tree_add_boolean(hdr_tree, hf_ipmi_bad_checksum, tvb, 0, 0, TRUE);
1270 PROTO_ITEM_SET_HIDDEN(ti);
1271 proto_tree_add_uint_format(hdr_tree, hf_ipmi_header_crc, tvb, offs++, 1,
1272 hdr_crc, "Header checksum: 0x%02x (incorrect, expected 0x%02x)",
1273 hdr_crc, hdr_exp_crc);
1276 /* Remember where chk2 bytes start */
1277 data_chk_offs = offs;
1280 proto_tree_add_item(hdr_tree, hf_ipmi_header_src, tvb, offs++, 1, TRUE);
1282 /* Sequence number + source LUN */
1283 ti = proto_tree_add_text(hdr_tree, tvb, offs, 1,
1284 "Source LUN: 0x%02x, SeqNo: 0x%02x",
1285 hdr.src_lun, hdr.seq);
1286 s_tree = proto_item_add_subtree(ti, ett_header_byte_4);
1288 proto_tree_add_item(s_tree, hf_ipmi_header_src_lun, tvb, offs, 1, TRUE);
1289 proto_tree_add_item(s_tree, hf_ipmi_header_sequence, tvb, offs, 1, TRUE);
1293 proto_tree_add_uint_format(hdr_tree, hf_ipmi_header_command, tvb, offs++, 1,
1294 hdr.cmd, "Command: %s (0x%02x)", cdesc, hdr.cmd);
1296 /* Response code (if present) */
1298 proto_tree_add_uint_format(hdr_tree, hf_ipmi_header_completion, tvb, offs++, 1,
1299 hdr.ccode, "Completion code: %s (0x%02x)", ccdesc, hdr.ccode);
1302 /* Defining body signature (if present) */
1304 ti = proto_tree_add_item(hdr_tree, hf_ipmi_header_sig, tvb, offs, siglen, TRUE);
1305 proto_item_append_text(ti, " (%s)", ndesc);
1309 /* Call data parser */
1310 if (tvb_length(data_tvb) && hnd) {
1311 ti = proto_tree_add_text(ipmi_tree, data_tvb, 0, -1, "Data");
1312 data_tree = proto_item_add_subtree(ti, ett_data);
1313 hnd(data_tvb, data_tree);
1316 /* Checksum all but the last byte */
1317 len = tvb_length(tvb) - 1;
1318 data_crc = tvb_get_guint8(tvb, len);
1320 for (i = data_chk_offs; i < len; i++) {
1321 data_exp_crc += tvb_get_guint8(tvb, i);
1323 data_exp_crc = (0 - data_exp_crc) & 0xff;
1325 if (data_crc == data_exp_crc) {
1326 proto_tree_add_uint_format(ipmi_tree, hf_ipmi_data_crc, tvb, len, 1,
1327 data_crc, "Data checksum: 0x%02x (correct)", data_crc);
1330 ti = proto_tree_add_boolean(hdr_tree, hf_ipmi_bad_checksum, tvb, 0, 0, TRUE);
1331 PROTO_ITEM_SET_HIDDEN(ti);
1332 proto_tree_add_uint_format(ipmi_tree, hf_ipmi_data_crc, tvb, len, 1,
1333 data_crc, "Data checksum: 0x%02x (incorrect, expected 0x%02x)",
1334 data_crc, data_exp_crc);
1338 /* Restore globals, in case we've been called recursively */
1339 ipmi_current_hdr = saved_hdr;
1340 current_saved_data = saved_saved_data;
1345 dissect_ipmi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1347 proto_tree *ipmi_tree = NULL;
1349 ipmi_dissect_format_t dfmt;
1351 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPMI/ATCA");
1353 current_pinfo = pinfo;
1356 ti = proto_tree_add_item(tree, proto_ipmi, tvb, 0, -1, FALSE);
1357 ipmi_tree = proto_item_add_subtree(ti, ett_ipmi);
1360 memset(&dfmt, 0, sizeof(dfmt));
1361 dfmt.flags = IPMI_D_BROADCAST | IPMI_D_TRG_SA;
1362 ipmi_do_dissect(tvb, ipmi_tree, &dfmt);
1364 col_add_str(pinfo->cinfo, COL_INFO, dfmt.info);
1368 /* Register IPMB protocol.
1371 proto_reg_handoff_ipmi(void)
1376 proto_register_ipmi(void)
1378 static hf_register_info hf[] = {
1379 { &hf_ipmi_message, { "Message", "ipmi.message", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
1380 { &hf_ipmi_session_handle, { "Session handle", "ipmi.session_handle", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1381 { &hf_ipmi_header_broadcast, { "Broadcast message", "ipmi.header.broadcast", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1382 { &hf_ipmi_header_trg, { "Target Address", "ipmi.header.target", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1383 { &hf_ipmi_header_trg_lun, { "Target LUN", "ipmi.header.trg_lun", FT_UINT8, BASE_HEX, NULL, 0x03, NULL, HFILL }},
1384 { &hf_ipmi_header_netfn, { "NetFN", "ipmi.header.netfn", FT_UINT8, BASE_HEX, NULL, 0xfc, NULL, HFILL }},
1385 { &hf_ipmi_header_crc, { "Header Checksum", "ipmi.header.crc", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1386 { &hf_ipmi_header_src, { "Source Address", "ipmi.header.source", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1387 { &hf_ipmi_header_src_lun, { "Source LUN", "ipmi.header.src_lun", FT_UINT8, BASE_HEX, NULL, 0x03, NULL, HFILL }},
1388 { &hf_ipmi_header_sequence, { "Sequence Number", "ipmi.header.sequence", FT_UINT8, BASE_HEX, NULL, 0xfc, NULL, HFILL }},
1389 { &hf_ipmi_header_command, { "Command", "ipmi.header.command", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1390 { &hf_ipmi_header_completion, { "Completion Code", "ipmi.header.completion", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1391 { &hf_ipmi_header_sig, { "Signature", "ipmi.header.signature", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
1392 { &hf_ipmi_data_crc, { "Data checksum", "ipmi.data.crc", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1393 { &hf_ipmi_response_to, { "Response to", "ipmi.response_to", FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }},
1394 { &hf_ipmi_response_in, { "Response in", "ipmi.response_in", FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }},
1395 { &hf_ipmi_response_time, { "Responded in", "ipmi.response_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, NULL, HFILL }},
1396 { &hf_ipmi_bad_checksum, { "Bad checksum", "ipmi.bad_checksum", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }}
1398 static gint *ett[] = {
1406 static const enum_val_t msgfmt_vals[] = {
1407 { "none", "None", MSGFMT_NONE },
1408 { "ipmb", "IPMB", MSGFMT_IPMB },
1409 { "lan", "Session-based (LAN, ...)", MSGFMT_LAN },
1410 { "guess", "Use heuristics", MSGFMT_GUESS },
1413 static const enum_val_t oemsel_vals[] = {
1414 { "none", "None", IPMI_OEM_NONE },
1415 { "pps", "Pigeon Point Systems", IPMI_OEM_PPS },
1421 proto_ipmi = proto_register_protocol("Intelligent Platform Management Interface",
1425 proto_register_field_array(proto_ipmi, hf, array_length(hf));
1426 proto_register_subtree_array(ett, array_length(ett));
1428 ipmi_netfn_setdesc(IPMI_CHASSIS_REQ, "Chassis", 0);
1429 ipmi_netfn_setdesc(IPMI_BRIDGE_REQ, "Bridge", 0);
1430 ipmi_netfn_setdesc(IPMI_SE_REQ, "Sensor/Event", 0);
1431 ipmi_netfn_setdesc(IPMI_APP_REQ, "Application", 0);
1432 ipmi_netfn_setdesc(IPMI_UPDATE_REQ, "Firmware Update", 0);
1433 ipmi_netfn_setdesc(IPMI_STORAGE_REQ, "Storage", 0);
1434 ipmi_netfn_setdesc(IPMI_TRANSPORT_REQ, "Transport", 0);
1435 ipmi_netfn_setdesc(IPMI_GROUP_REQ, "Group", 1);
1436 ipmi_netfn_setdesc(IPMI_OEM_REQ, "OEM/Group", 3);
1437 for (i = 0x30; i < 0x40; i += 2) {
1438 ipmi_netfn_setdesc(i, "OEM", 0);
1441 ipmi_register_chassis(proto_ipmi);
1442 ipmi_register_bridge(proto_ipmi);
1443 ipmi_register_se(proto_ipmi);
1444 ipmi_register_app(proto_ipmi);
1445 ipmi_register_update(proto_ipmi);
1446 ipmi_register_storage(proto_ipmi);
1447 ipmi_register_transport(proto_ipmi);
1448 ipmi_register_picmg(proto_ipmi);
1449 ipmi_register_pps(proto_ipmi);
1451 register_dissector("ipmi", dissect_ipmi, proto_ipmi);
1453 m = prefs_register_protocol(proto_ipmi, NULL);
1454 prefs_register_bool_preference(m, "fru_langcode_is_english", "FRU Language Code is English",
1455 "FRU Language Code is English; strings are ASCII+LATIN1 (vs. Unicode)",
1456 &fru_langcode_is_english);
1457 prefs_register_uint_preference(m, "response_after_req", "Maximum delay of response message",
1458 "Do not search for responses coming after this timeout (milliseconds)",
1459 10, &response_after_req);
1460 prefs_register_uint_preference(m, "response_before_req", "Response ahead of request",
1461 "Allow for responses before requests (milliseconds)",
1462 10, &response_before_req);
1463 prefs_register_enum_preference(m, "msgfmt", "Format of embedded messages",
1464 "Format of messages embedded into Send/Get/Forward Message",
1465 &message_format, msgfmt_vals, FALSE);
1466 prefs_register_enum_preference(m, "selected_oem", "OEM commands parsed as",
1467 "Selects which OEM format is used for commands that IPMI does not define",
1468 &selected_oem, oemsel_vals, FALSE);