2 * Routines for IPMI dissection
3 * Copyright 2002-2008, Alexey Neyman, Pigeon Point Systems <avn@pigeonpoint.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 #include <epan/packet.h>
31 #include <epan/conversation.h>
32 #include <epan/wmem/wmem.h>
33 #include <epan/to_str.h>
34 #include <epan/prefs.h>
35 #include <epan/addr_resolv.h>
37 #include "packet-ipmi.h"
39 void proto_register_ipmi(void);
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 {
64 struct ipmi_parse_typelen {
65 void (*get_len)(guint *, guint *, tvbuff_t *, guint, guint, gboolean);
66 void (*parse)(char *, tvbuff_t *, guint, guint);
70 /* IPMI parsing context */
79 /* Temporary request-response matching data. */
83 /* Frame number where the request resides */
85 /* Nest level of the request in the frame */
89 /* List of request-response matching data */
90 typedef wmem_list_t ipmi_request_list_t;
94 /* Per-command data */
96 guint32 matched_frame_num;
97 guint32 saved_data[NSAVED_DATA];
102 ipmi_cmd_data_t * cmd_data[3];
106 /* RB tree of frame data */
107 typedef wmem_tree_t ipmi_frame_tree_t;
109 /* cached dissector data */
111 /* tree of cached frame data */
112 ipmi_frame_tree_t * frame_tree;
113 /* list of cached requests */
114 ipmi_request_list_t * request_list;
115 /* currently dissected frame number */
116 guint32 curr_frame_num;
117 /* currently dissected frame */
118 ipmi_frame_data_t * curr_frame;
119 /* current nesting level */
121 /* subsequent nesting level */
123 /* top level message channel */
125 /* top level message direction */
127 /* pointer to current command */
128 const ipmi_header_t * curr_hdr;
129 /* current completion code */
131 } ipmi_packet_data_t;
133 /* Maximum nest level where it worth caching data */
134 #define MAX_NEST_LEVEL 3
136 static dissector_handle_t data_dissector;
138 gint proto_ipmi = -1;
139 static gint proto_ipmb = -1;
140 static gint proto_kcs = -1;
141 static gint proto_tmode = -1;
143 static gboolean fru_langcode_is_english = TRUE;
144 static guint response_after_req = 5000;
145 static guint response_before_req = 0;
146 static guint message_format = MSGFMT_GUESS;
147 static guint selected_oem = IPMI_OEM_NONE;
149 static gint hf_ipmi_session_handle = -1;
150 static gint hf_ipmi_header_trg = -1;
151 static gint hf_ipmi_header_trg_lun = -1;
152 static gint hf_ipmi_header_netfn = -1;
153 static gint hf_ipmi_header_crc = -1;
154 static gint hf_ipmi_header_src = -1;
155 static gint hf_ipmi_header_src_lun = -1;
156 static gint hf_ipmi_header_bridged = -1;
157 static gint hf_ipmi_header_sequence = -1;
158 static gint hf_ipmi_header_command = -1;
159 static gint hf_ipmi_header_completion = -1;
160 static gint hf_ipmi_header_sig = -1;
161 static gint hf_ipmi_data_crc = -1;
162 static gint hf_ipmi_response_to = -1;
163 static gint hf_ipmi_response_in = -1;
164 static gint hf_ipmi_response_time = -1;
166 static gint ett_ipmi = -1;
167 static gint ett_header = -1;
168 static gint ett_header_byte_1 = -1;
169 static gint ett_header_byte_4 = -1;
170 static gint ett_data = -1;
171 static gint ett_typelen = -1;
173 static expert_field ei_impi_parser_not_implemented = EI_INIT;
175 static struct ipmi_netfn_root ipmi_cmd_tab[IPMI_NETFN_MAX];
177 static ipmi_packet_data_t *
178 get_packet_data(packet_info * pinfo)
180 ipmi_packet_data_t * data;
182 /* get conversation data */
183 conversation_t * conv = find_or_create_conversation(pinfo);
185 /* get protocol-specific data */
186 data = (ipmi_packet_data_t *)
187 conversation_get_proto_data(conv, proto_ipmi);
190 /* allocate per-packet data */
191 data = wmem_new0(wmem_file_scope(), ipmi_packet_data_t);
193 /* allocate request list and frame tree */
194 data->frame_tree = wmem_tree_new(wmem_file_scope());
195 data->request_list = wmem_list_new(wmem_file_scope());
197 /* add protocol data */
198 conversation_add_proto_data(conv, proto_ipmi, data);
201 /* check if packet has changed */
202 if (pinfo->fd->num != data->curr_frame_num) {
203 data->curr_level = 0;
204 data->next_level = 0;
210 static ipmi_frame_data_t *
211 get_frame_data(ipmi_packet_data_t * data, guint32 frame_num)
213 ipmi_frame_data_t * frame = (ipmi_frame_data_t *)
214 wmem_tree_lookup32(data->frame_tree, frame_num);
217 frame = wmem_new0(wmem_file_scope(), ipmi_frame_data_t);
219 wmem_tree_insert32(data->frame_tree, frame_num, frame);
224 static ipmi_request_t *
225 get_matched_request(ipmi_packet_data_t * data, const ipmi_header_t * rs_hdr,
228 wmem_list_frame_t * iter = wmem_list_head(data->request_list);
229 ipmi_header_t rq_hdr;
231 /* reset message context */
235 rq_hdr.channel = data->curr_channel;
237 /* toggle packet direction */
238 rq_hdr.dir = rs_hdr->dir ^ 1;
240 rq_hdr.session = rs_hdr->session;
242 /* swap responder address/lun */
243 rq_hdr.rs_sa = rs_hdr->rq_sa;
244 rq_hdr.rs_lun = rs_hdr->rq_lun;
246 /* remove reply flag */
247 rq_hdr.netfn = rs_hdr->netfn & ~1;
249 /* swap requester address/lun */
250 rq_hdr.rq_sa = rs_hdr->rs_sa;
251 rq_hdr.rq_lun = rs_hdr->rs_lun;
254 rq_hdr.rq_seq = rs_hdr->rq_seq;
257 rq_hdr.cmd = rs_hdr->cmd;
259 /* TODO: copy prefix bytes */
262 fprintf(stderr, "%d, %d: rq_hdr : {\n"
272 data->curr_frame_num, data->curr_level,
273 rq_hdr.channel, rq_hdr.dir, rq_hdr.rs_sa, rq_hdr.rs_lun,
274 rq_hdr.netfn, rq_hdr.rq_sa, rq_hdr.rq_lun, rq_hdr.rq_seq,
279 ipmi_request_t * rq = (ipmi_request_t *) wmem_list_frame_data(iter);
281 /* check if in Get Message context */
282 if (rs_hdr->context == IPMI_E_GETMSG && !(flags & IPMI_D_TRG_SA)) {
284 rq_hdr.rq_sa = rq->hdr.rq_sa;
287 /* compare command headers */
288 if (!memcmp(&rq_hdr, &rq->hdr, sizeof(rq_hdr))) {
292 /* proceed to next request */
293 iter = wmem_list_frame_next(iter);
300 remove_old_requests(ipmi_packet_data_t * data, const nstime_t * curr_time)
302 wmem_list_frame_t * iter = wmem_list_head(data->request_list);
305 ipmi_request_t * rq = (ipmi_request_t *) wmem_list_frame_data(iter);
306 ipmi_frame_data_t * frame = get_frame_data(data, rq->frame_num);
309 /* calculate time delta */
310 nstime_delta(&delta, curr_time, &frame->ts);
312 if (nstime_to_msec(&delta) > response_after_req) {
313 wmem_list_frame_t * del = iter;
315 /* proceed to next request */
316 iter = wmem_list_frame_next(iter);
318 /* free request data */
319 wmem_free(wmem_file_scope(), rq);
321 /* remove list item */
322 wmem_list_remove_frame(data->request_list, del);
330 match_request_response(ipmi_packet_data_t * data, const ipmi_header_t * hdr,
333 /* get current frame */
334 ipmi_frame_data_t * rs_frame = data->curr_frame;
336 /* get current command data */
337 ipmi_cmd_data_t * rs_data = rs_frame->cmd_data[data->curr_level];
339 /* check if parse response for the first time */
343 /* allocate command data */
344 rs_data = wmem_new0(wmem_file_scope(), ipmi_cmd_data_t);
346 /* search for matching request */
347 rq = get_matched_request(data, hdr, flags);
349 /* check if matching request is found */
351 /* get request frame data */
352 ipmi_frame_data_t * rq_frame =
353 get_frame_data(data, rq->frame_num);
355 /* get command data */
356 ipmi_cmd_data_t * rq_data = rq_frame->cmd_data[rq->nest_level];
358 /* save matched frame numbers */
359 rq_data->matched_frame_num = data->curr_frame_num;
360 rs_data->matched_frame_num = rq->frame_num;
362 /* copy saved command data information */
363 rs_data->saved_data[0] = rq_data->saved_data[0];
364 rs_data->saved_data[1] = rq_data->saved_data[1];
366 /* remove request from the list */
367 wmem_list_remove(data->request_list, rq);
369 /* delete request data */
370 wmem_free(wmem_file_scope(), rq);
373 /* save command data pointer in frame */
374 rs_frame->cmd_data[data->curr_level] = rs_data;
379 add_request(ipmi_packet_data_t * data, const ipmi_header_t * hdr)
381 /* get current frame */
382 ipmi_frame_data_t * rq_frame = data->curr_frame;
384 /* get current command data */
385 ipmi_cmd_data_t * rq_data = rq_frame->cmd_data[data->curr_level];
387 /* check if parse response for the first time */
391 /* allocate command data */
392 rq_data = wmem_new0(wmem_file_scope(), ipmi_cmd_data_t);
394 /* set command data pointer */
395 rq_frame->cmd_data[data->curr_level] = rq_data;
397 /* allocate request data */
398 rq = wmem_new0(wmem_file_scope(), ipmi_request_t);
400 /* copy request header */
401 memcpy(&rq->hdr, hdr, sizeof(rq->hdr));
403 /* override context, channel and direction */
405 rq->hdr.channel = data->curr_channel;
406 rq->hdr.dir = data->curr_dir;
408 /* set request frame number */
409 rq->frame_num = data->curr_frame_num;
411 /* set command nest level */
412 rq->nest_level = data->curr_level;
414 /* append request to list */
415 wmem_list_append(data->request_list, rq);
418 fprintf(stderr, "%d, %d: hdr : {\n"
428 data->curr_frame_num, data->curr_level,
429 rq->hdr.channel, rq->hdr.dir, rq->hdr.rs_sa, rq->hdr.rs_lun,
430 rq->hdr.netfn, rq->hdr.rq_sa, rq->hdr.rq_lun, rq->hdr.rq_seq,
437 add_command_info(packet_info *pinfo, ipmi_cmd_t * cmd,
438 gboolean resp, guint8 cc_val, const char * cc_str, gboolean broadcast)
441 col_add_fstr(pinfo->cinfo, COL_INFO, "Rsp, %s, %s (%02xh)",
442 cmd->desc, cc_str, cc_val);
444 col_add_fstr(pinfo->cinfo, COL_INFO, "Req, %s%s",
445 broadcast ? "Broadcast " : "", cmd->desc);
450 dissect_ipmi_cmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
451 gint hf_parent_item, gint ett_tree, const ipmi_context_t * ctx)
453 ipmi_packet_data_t * data;
454 ipmi_netfn_t * cmd_list;
457 proto_tree * cmd_tree = NULL, * tmp_tree;
458 guint8 prev_level, cc_val;
459 guint offset, siglen, is_resp;
460 const char * cc_str, * netfn_str;
462 /* get packet data */
463 data = get_packet_data(pinfo);
468 /* get prefix length */
469 siglen = ipmi_getsiglen(ctx->hdr.netfn);
471 /* get response flag */
472 is_resp = ctx->hdr.netfn & 1;
474 /* check message length */
475 if (tvb_captured_length(tvb) < ctx->hdr_len + siglen + is_resp
476 + !(ctx->flags & IPMI_D_NO_CKS)) {
477 /* don bother with anything */
478 return call_dissector(data_dissector, tvb, pinfo, tree);
481 /* save nest level */
482 prev_level = data->curr_level;
484 /* assign next nest level */
485 data->curr_level = data->next_level;
487 /* increment next nest level */
490 /* check for the first invocation */
491 if (!data->curr_level) {
492 /* get current frame data */
493 data->curr_frame = get_frame_data(data, pinfo->fd->num);
494 data->curr_frame_num = pinfo->fd->num;
496 /* copy frame timestamp */
497 memcpy(&data->curr_frame->ts, &pinfo->fd->abs_ts, sizeof(nstime_t));
499 /* cache channel and direction */
500 data->curr_channel = ctx->hdr.channel;
501 data->curr_dir = ctx->hdr.dir;
503 /* remove requests which are too old */
504 remove_old_requests(data, &pinfo->fd->abs_ts);
507 if (data->curr_level < MAX_NEST_LEVEL) {
508 if (ctx->hdr.netfn & 1) {
509 /* perform request/response matching */
510 match_request_response(data, &ctx->hdr, ctx->flags);
512 /* add request to the list for later matching */
513 add_request(data, &ctx->hdr);
517 /* get command list by network function code */
518 cmd_list = ipmi_getnetfn(ctx->hdr.netfn,
519 tvb_get_ptr(tvb, ctx->hdr_len + is_resp, siglen));
521 /* get command descriptor */
522 cmd = ipmi_getcmd(cmd_list, ctx->hdr.cmd);
524 /* check if response */
526 /* get completion code */
527 cc_val = tvb_get_guint8(tvb, ctx->hdr_len);
529 /* get completion code desc */
530 cc_str = ipmi_get_completion_code(cc_val, cmd);
536 /* check if not inside a message */
537 if (!data->curr_level) {
538 /* add packet info */
539 add_command_info(pinfo, cmd, is_resp, cc_val, cc_str,
540 ctx->flags & IPMI_D_BROADCAST ? TRUE : FALSE);
544 /* add parent node */
545 if (!data->curr_level) {
546 ti = proto_tree_add_item(tree, hf_parent_item, tvb, 0, -1, ENC_NA);
548 char str[ITEM_LABEL_LENGTH];
551 g_snprintf(str, ITEM_LABEL_LENGTH, "Rsp, %s, %s",
554 g_snprintf(str, ITEM_LABEL_LENGTH, "Req, %s", cmd->desc);
556 if (proto_registrar_get_ftype(hf_parent_item) == FT_STRING)
557 ti = proto_tree_add_string(tree, hf_parent_item, tvb, 0, -1, str);
559 ti = proto_tree_add_text(tree, tvb, 0, -1, "%s", str);
562 /* add message sub-tree */
563 cmd_tree = proto_item_add_subtree(ti, ett_tree);
565 if (data->curr_level < MAX_NEST_LEVEL) {
566 /* check if response */
567 if (ctx->hdr.netfn & 1) {
568 /* get current command data */
569 ipmi_cmd_data_t * rs_data =
570 data->curr_frame->cmd_data[data->curr_level];
572 if (rs_data->matched_frame_num) {
575 /* add "Request to:" field */
576 ti = proto_tree_add_uint(cmd_tree, hf_ipmi_response_to,
577 tvb, 0, 0, rs_data->matched_frame_num);
579 /* mark field as a generated one */
580 PROTO_ITEM_SET_GENERATED(ti);
582 /* calculate delta time */
583 nstime_delta(&ns, &pinfo->fd->abs_ts,
584 &get_frame_data(data,
585 rs_data->matched_frame_num)->ts);
587 /* add "Response time" field */
588 ti = proto_tree_add_time(cmd_tree, hf_ipmi_response_time,
591 /* mark field as a generated one */
592 PROTO_ITEM_SET_GENERATED(ti);
595 /* get current command data */
596 ipmi_cmd_data_t * rq_data =
597 data->curr_frame->cmd_data[data->curr_level];
599 if (rq_data->matched_frame_num) {
600 /* add "Response in:" field */
601 ti = proto_tree_add_uint(cmd_tree, hf_ipmi_response_in,
602 tvb, 0, 0, rq_data->matched_frame_num);
604 /* mark field as a generated one */
605 PROTO_ITEM_SET_GENERATED(ti);
610 /* set starting offset */
613 /* check if message is broadcast */
614 if (ctx->flags & IPMI_D_BROADCAST) {
615 /* skip first byte */
619 /* check if session handle is specified */
620 if (ctx->flags & IPMI_D_SESSION_HANDLE) {
621 /* add session handle field */
622 proto_tree_add_item(cmd_tree, hf_ipmi_session_handle,
623 tvb, offset++, 1, ENC_LITTLE_ENDIAN);
626 /* check if responder address is specified */
627 if (ctx->flags & IPMI_D_TRG_SA) {
628 /* add response address field */
629 proto_tree_add_item(cmd_tree, hf_ipmi_header_trg, tvb,
630 offset++, 1, ENC_LITTLE_ENDIAN);
633 /* get NetFn string */
634 netfn_str = ipmi_getnetfnname(ctx->hdr.netfn, cmd_list);
636 /* Network function + target LUN */
637 tmp_tree = proto_tree_add_subtree_format(cmd_tree, tvb, offset, 1,
638 ett_header_byte_1, NULL, "Target LUN: 0x%02x, NetFN: %s %s (0x%02x)",
639 ctx->hdr.rs_lun, netfn_str,
640 is_resp ? "Response" : "Request", ctx->hdr.netfn);
643 proto_tree_add_uint_format(tmp_tree, hf_ipmi_header_netfn, tvb,
644 offset, 1, ctx->hdr.netfn << 2,
645 "NetFn: %s %s (0x%02x)", netfn_str,
646 is_resp ? "Response" : "Request", ctx->hdr.netfn);
648 proto_tree_add_item(tmp_tree, hf_ipmi_header_trg_lun, tvb,
649 offset++, 1, ENC_LITTLE_ENDIAN);
651 /* check if cks1 is specified */
652 if (!(ctx->flags & IPMI_D_NO_CKS)) {
653 guint8 cks = tvb_get_guint8(tvb, offset);
655 /* Header checksum */
657 guint8 correct = cks - ctx->cks1;
659 proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_header_crc,
660 tvb, offset++, 1, cks,
661 "0x%02x (incorrect, expected 0x%02x)", cks, correct);
663 proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_header_crc,
664 tvb, offset++, 1, cks,
665 "0x%02x (correct)", cks);
669 /* check if request address is specified */
670 if (!(ctx->flags & IPMI_D_NO_RQ_SA)) {
671 /* add request address field */
672 proto_tree_add_item(cmd_tree, hf_ipmi_header_src, tvb,
673 offset++, 1, ENC_LITTLE_ENDIAN);
676 /* check if request sequence is specified */
677 if (!(ctx->flags & IPMI_D_NO_SEQ)) {
678 /* Sequence number + source LUN */
679 tmp_tree = proto_tree_add_subtree_format(cmd_tree, tvb, offset, 1,
680 ett_header_byte_4, NULL, "%s: 0x%02x, SeqNo: 0x%02x",
681 (ctx->flags & IPMI_D_TMODE) ? "Bridged" : "Source LUN",
682 ctx->hdr.rq_lun, ctx->hdr.rq_seq);
684 if (ctx->flags & IPMI_D_TMODE) {
685 proto_tree_add_item(tmp_tree, hf_ipmi_header_bridged,
686 tvb, offset, 1, ENC_LITTLE_ENDIAN);
688 proto_tree_add_item(tmp_tree, hf_ipmi_header_src_lun,
689 tvb, offset, 1, ENC_LITTLE_ENDIAN);
693 proto_tree_add_item(tmp_tree, hf_ipmi_header_sequence, tvb,
694 offset++, 1, ENC_LITTLE_ENDIAN);
698 proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_header_command,
699 tvb, offset++, 1, ctx->hdr.cmd, "%s (0x%02x)",
700 cmd->desc, ctx->hdr.cmd);
703 /* completion code */
704 proto_tree_add_uint_format_value(cmd_tree,
705 hf_ipmi_header_completion, tvb, offset++, 1,
706 cc_val, "%s (0x%02x)", cc_str, cc_val);
710 /* command prefix (if present) */
711 ti = proto_tree_add_item(cmd_tree, hf_ipmi_header_sig, tvb,
712 offset, siglen, ENC_NA);
713 proto_item_append_text(ti, " (%s)", netfn_str);
717 if (tree || (cmd->flags & CMD_CALLRQ)) {
718 /* calculate message data length */
719 guint data_len = tvb_captured_length(tvb)
723 - !(ctx->flags & IPMI_D_NO_CKS);
725 /* create data subset */
726 tvbuff_t * data_tvb = tvb_new_subset_length(tvb,
727 ctx->hdr_len + siglen + (is_resp ? 1 : 0), data_len);
729 /* Select sub-handler */
730 ipmi_cmd_handler_t hnd = is_resp ? cmd->parse_resp : cmd->parse_req;
732 if (hnd && tvb_captured_length(data_tvb)) {
733 /* create data field */
734 tmp_tree = proto_tree_add_subtree(cmd_tree, data_tvb, 0, -1, ett_data, NULL, "Data");
736 /* save current command */
737 data->curr_hdr = &ctx->hdr;
739 /* save current completion code */
740 data->curr_ccode = cc_val;
742 /* call command parser */
743 hnd(data_tvb, pinfo, tmp_tree);
747 /* check if cks2 is specified */
748 if (tree && !(ctx->flags & IPMI_D_NO_CKS)) {
751 /* get cks2 offset */
752 offset = tvb_captured_length(tvb) - 1;
755 cks = tvb_get_guint8(tvb, offset);
757 /* Header checksum */
759 guint8 correct = cks - ctx->cks2;
761 proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_data_crc,
763 "0x%02x (incorrect, expected 0x%02x)", cks, correct);
765 proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_data_crc,
767 "0x%02x (correct)", cks);
771 /* decrement next nest level */
772 data->next_level = data->curr_level;
774 /* restore previous nest level */
775 data->curr_level = prev_level;
777 return tvb_captured_length(tvb);
780 /* Get currently parsed message header */
781 const ipmi_header_t * ipmi_get_hdr(packet_info * pinfo)
783 ipmi_packet_data_t * data = get_packet_data(pinfo);
784 return data->curr_hdr;
787 /* Get completion code for currently parsed message */
788 guint8 ipmi_get_ccode(packet_info * pinfo)
790 ipmi_packet_data_t * data = get_packet_data(pinfo);
791 return data->curr_ccode;
794 /* Save request data for later use in response */
795 void ipmi_set_data(packet_info *pinfo, guint idx, guint32 value)
797 ipmi_packet_data_t * data = get_packet_data(pinfo);
800 if (data->curr_level >= MAX_NEST_LEVEL || idx >= NSAVED_DATA ) {
805 data->curr_frame->cmd_data[data->curr_level]->saved_data[idx] = value;
808 /* Get saved request data */
809 gboolean ipmi_get_data(packet_info *pinfo, guint idx, guint32 * value)
811 ipmi_packet_data_t * data = get_packet_data(pinfo);
814 if (data->curr_level >= MAX_NEST_LEVEL || idx >= NSAVED_DATA ) {
819 *value = data->curr_frame->cmd_data[data->curr_level]->saved_data[idx];
823 /* ----------------------------------------------------------------
824 Support for Type/Length fields parsing.
825 ---------------------------------------------------------------- */
828 get_len_binary(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
829 guint len, gboolean len_is_bytes _U_)
836 parse_binary(char *p, tvbuff_t *tvb, guint offs, guint len)
838 static const char hex[] = "0123456789ABCDEF";
842 for (i = 0; i < len / 3; i++) {
843 v = tvb_get_guint8(tvb, offs + i);
854 static struct ipmi_parse_typelen ptl_binary = {
855 get_len_binary, parse_binary, "Binary"
859 get_len_bcdplus(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
860 guint len, gboolean len_is_bytes)
866 *blen = (len + 1) / 2;
872 parse_bcdplus(char *p, tvbuff_t *tvb, guint offs, guint len)
874 static const char bcd[] = "0123456789 -.:,_";
875 guint i, msk = 0xf0, shft = 4;
878 for (i = 0; i < len; i++) {
879 v = (tvb_get_guint8(tvb, offs + i / 2) & msk) >> shft;
886 static struct ipmi_parse_typelen ptl_bcdplus = {
887 get_len_bcdplus, parse_bcdplus, "BCD+"
891 get_len_6bit_ascii(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
892 guint len, gboolean len_is_bytes)
898 *blen = (len * 3 + 3) / 4;
904 parse_6bit_ascii(char *p, tvbuff_t *tvb, guint offs, guint len)
909 /* First, handle "full" triplets of bytes, 4 characters each */
910 for (i = 0; i < len / 4; i++) {
911 v = tvb_get_letoh24(tvb, offs + i * 3);
912 p[0] = ' ' + (v & 0x3f);
913 p[1] = ' ' + ((v >> 6) & 0x3f);
914 p[2] = ' ' + ((v >> 12) & 0x3f);
915 p[3] = ' ' + ((v >> 18) & 0x3f);
919 /* Do we have any characters left? */
924 v = (tvb_get_guint8(tvb, offs + 2) << 4) | (tvb_get_guint8(tvb, offs + 1) >> 4);
925 p[2] = ' ' + (v & 0x3f);
928 v = (tvb_get_guint8(tvb, offs + 1) << 2) | (tvb_get_guint8(tvb, offs) >> 6);
929 p[1] = ' ' + (v & 0x3f);
932 v = tvb_get_guint8(tvb, offs) & 0x3f;
933 p[0] = ' ' + (v & 0x3f);
937 static struct ipmi_parse_typelen ptl_6bit_ascii = {
938 get_len_6bit_ascii, parse_6bit_ascii, "6-bit ASCII"
942 get_len_8bit_ascii(guint *clen, guint *blen, tvbuff_t *tvb, guint offs,
943 guint len, gboolean len_is_bytes _U_)
948 *blen = len; /* One byte is one character */
950 for (i = 0; i < len; i++) {
951 ch = tvb_get_guint8(tvb, offs + i);
952 *clen += (ch >= 0x20 && ch <= 0x7f) ? 1 : 4;
957 parse_8bit_ascii(char *p, tvbuff_t *tvb, guint offs, guint len)
964 ch = tvb_get_guint8(tvb, offs++);
965 if (ch >= 0x20 && ch <= 0x7f) {
968 g_snprintf(p, 5, "\\x%02x", ch);
974 static struct ipmi_parse_typelen ptl_8bit_ascii = {
975 get_len_8bit_ascii, parse_8bit_ascii, "ASCII+Latin1"
979 get_len_unicode(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
980 guint len _U_, gboolean len_is_bytes)
983 *clen = len * 3; /* Each 2 bytes result in 6 chars printed: \Uxxxx */
992 parse_unicode(char *p, tvbuff_t *tvb, guint offs, guint len)
994 char *pmax = p + len;
998 ch0 = tvb_get_guint8(tvb, offs++);
999 ch1 = tvb_get_guint8(tvb, offs++);
1000 g_snprintf(p, 7, "\\U%02x%02x", ch0, ch1);
1005 static struct ipmi_parse_typelen ptl_unicode = {
1006 get_len_unicode, parse_unicode, "Unicode"
1010 ipmi_add_typelen(proto_tree *tree, const char *desc, tvbuff_t *tvb,
1011 guint offs, gboolean is_fru)
1013 static struct ipmi_parse_typelen *fru_eng[4] = {
1014 &ptl_binary, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_8bit_ascii
1016 static struct ipmi_parse_typelen *fru_noneng[4] = {
1017 &ptl_binary, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_unicode
1019 static struct ipmi_parse_typelen *ipmi[4] = {
1020 &ptl_unicode, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_8bit_ascii
1022 struct ipmi_parse_typelen *ptr;
1024 guint type, msk, clen, blen, len;
1029 typelen = tvb_get_guint8(tvb, offs);
1030 type = typelen >> 6;
1033 ptr = (fru_langcode_is_english ? fru_eng : fru_noneng)[type];
1038 unit = "characters";
1041 len = typelen & msk;
1042 ptr->get_len(&clen, &blen, tvb, offs + 1, len, is_fru);
1044 str = (char *)wmem_alloc(wmem_packet_scope(), clen + 1);
1045 ptr->parse(str, tvb, offs + 1, clen);
1048 s_tree = proto_tree_add_subtree_format(tree, tvb, offs, 1, ett_typelen, NULL,
1049 "%s Type/Length byte: %s, %d %s", desc, ptr->desc, len, unit);
1050 proto_tree_add_text(s_tree, tvb, offs, 1, "%sType: %s (0x%02x)",
1051 ipmi_dcd8(typelen, 0xc0), ptr->desc, type);
1052 proto_tree_add_text(s_tree, tvb, offs, 1, "%sLength: %d %s",
1053 ipmi_dcd8(typelen, msk), len, unit);
1055 proto_tree_add_text(tree, tvb, offs + 1, blen, "%s: [%s] '%s'",
1056 desc, ptr->desc, str);
1059 /* ----------------------------------------------------------------
1060 Timestamp, IPMI-style.
1061 ---------------------------------------------------------------- */
1063 ipmi_add_timestamp(proto_tree *tree, gint hf, tvbuff_t *tvb, guint offset)
1065 guint32 ts = tvb_get_letohl(tvb, offset);
1067 if (ts == 0xffffffff) {
1068 proto_tree_add_uint_format_value(tree, hf, tvb, offset, 4,
1069 ts, "Unspecified/Invalid");
1070 } else if (ts <= 0x20000000) {
1071 proto_tree_add_uint_format_value(tree, hf, tvb, offset, 4,
1072 ts, "%s since SEL device's initialization",
1073 time_secs_to_str_unsigned(wmem_packet_scope(), ts));
1075 proto_tree_add_uint_format_value(tree, hf, tvb, offset, 4,
1076 ts, "%s", abs_time_secs_to_str(wmem_packet_scope(), ts, ABSOLUTE_TIME_UTC, TRUE));
1080 /* ----------------------------------------------------------------
1082 ---------------------------------------------------------------- */
1085 ipmi_add_guid(proto_tree *tree, gint hf, tvbuff_t *tvb, guint offset)
1090 guid.data1 = tvb_get_letohl(tvb, offset + 12);
1091 guid.data2 = tvb_get_letohs(tvb, offset + 10);
1092 guid.data3 = tvb_get_letohs(tvb, offset + 8);
1093 for (i = 0; i < 8; i++) {
1094 guid.data4[i] = tvb_get_guint8(tvb, offset + 7 - i);
1096 proto_tree_add_guid(tree, hf, tvb, offset, 16, &guid);
1099 /* ----------------------------------------------------------------
1100 Routines for registering/looking up command parsers.
1101 ---------------------------------------------------------------- */
1104 ipmi_netfn_setdesc(guint32 netfn, const char *desc, guint32 siglen)
1106 struct ipmi_netfn_root *inr;
1108 inr = &ipmi_cmd_tab[netfn >> 1];
1110 inr->siglen = siglen;
1114 ipmi_register_netfn_cmdtab(guint32 netfn, guint oem_selector,
1115 const guint8 *sig, guint32 siglen, const char *desc,
1116 ipmi_cmd_t *cmdtab, guint32 cmdtablen)
1118 struct ipmi_netfn_root *inr;
1121 netfn >>= 1; /* Requests and responses grouped together */
1122 if (netfn >= IPMI_NETFN_MAX) {
1126 inr = &ipmi_cmd_tab[netfn];
1127 if (inr->siglen != siglen) {
1131 inh = (struct ipmi_netfn_handler *)g_malloc(sizeof(struct ipmi_netfn_handler));
1133 inh->oem_selector = oem_selector;
1135 inh->cmdtab = cmdtab;
1136 inh->cmdtablen = cmdtablen;
1138 inh->next = inr->list;
1143 ipmi_getsiglen(guint32 netfn)
1145 return ipmi_cmd_tab[netfn >> 1].siglen;
1149 ipmi_getnetfnname(guint32 netfn, ipmi_netfn_t *nf)
1151 const char *dn, *db;
1153 dn = ipmi_cmd_tab[netfn >> 1].desc ?
1154 ipmi_cmd_tab[netfn >> 1].desc : "Reserved";
1155 db = nf ? nf->desc : NULL;
1157 return wmem_strdup_printf(wmem_packet_scope(), "%s (%s)", db, dn);
1164 ipmi_getnetfn(guint32 netfn, const guint8 *sig)
1166 struct ipmi_netfn_root *inr;
1169 inr = &ipmi_cmd_tab[netfn >> 1];
1170 for (inh = inr->list; inh; inh = inh->next) {
1171 if ((inh->oem_selector == selected_oem || inh->oem_selector == IPMI_OEM_NONE)
1172 && (!inr->siglen || !memcmp(sig, inh->sig, inr->siglen))) {
1177 /* Either unknown netFn or signature does not match */
1182 ipmi_getcmd(ipmi_netfn_t *nf, guint32 cmd)
1184 static ipmi_cmd_t ipmi_cmd_unknown = {
1186 ipmi_notimpl, /* request */
1187 ipmi_notimpl, /* response */
1188 NULL, /* command codes */
1189 NULL, /* subfunctions */
1197 len = nf->cmdtablen;
1198 for (ic = nf->cmdtab, i = 0; i < len; i++, ic++) {
1199 if (ic->cmd == cmd) {
1205 return &ipmi_cmd_unknown;
1208 /* ----------------------------------------------------------------
1209 Various utility functions.
1210 ---------------------------------------------------------------- */
1213 ipmi_notimpl(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1215 proto_tree_add_expert(tree, pinfo, &ei_impi_parser_not_implemented, tvb, 0, -1);
1219 ipmi_dcd8(guint32 val, guint32 mask)
1221 static char buf[64];
1223 decode_bitfield_value(buf, val, mask, 8);
1228 ipmi_fmt_10ms_1based(gchar *s, guint32 v)
1230 g_snprintf(s, ITEM_LABEL_LENGTH, "%d.%03d seconds", v / 100, (v % 100) * 10);
1234 ipmi_fmt_500ms_0based(gchar *s, guint32 v)
1236 ipmi_fmt_500ms_1based(s, ++v);
1240 ipmi_fmt_500ms_1based(gchar *s, guint32 v)
1242 g_snprintf(s, ITEM_LABEL_LENGTH, "%d.%03d seconds", v / 2, (v % 2) * 500);
1246 ipmi_fmt_1s_0based(gchar *s, guint32 v)
1248 ipmi_fmt_1s_1based(s, ++v);
1252 ipmi_fmt_1s_1based(gchar *s, guint32 v)
1254 g_snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", v);
1258 ipmi_fmt_2s_0based(gchar *s, guint32 v)
1260 g_snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", (v + 1) * 2);
1264 ipmi_fmt_5s_1based(gchar *s, guint32 v)
1266 g_snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", v * 5);
1270 ipmi_fmt_version(gchar *s, guint32 v)
1272 g_snprintf(s, ITEM_LABEL_LENGTH, "%d.%d", v & 0x0f, (v >> 4) & 0x0f);
1276 ipmi_fmt_channel(gchar *s, guint32 v)
1278 static const value_string chan_vals[] = {
1279 { 0x00, "Primary IPMB (IPMB-0)" },
1281 { 0x0e, "Current channel" },
1282 { 0x0f, "System Interface" },
1286 g_snprintf(s, ITEM_LABEL_LENGTH, "%s (0x%02x)",
1287 val_to_str(v, chan_vals, "Channel #%d"), v);
1291 ipmi_fmt_udpport(gchar *s, guint32 v)
1293 g_snprintf(s, ITEM_LABEL_LENGTH, "%s (%d)", ep_udp_port_to_display(v), v);
1297 ipmi_fmt_percent(gchar *s, guint32 v)
1299 g_snprintf(s, ITEM_LABEL_LENGTH, "%d%%", v);
1303 ipmi_get_completion_code(guint8 completion, ipmi_cmd_t *cmd)
1305 static const value_string std_completion_codes[] = {
1306 { 0x00, "Command Completed Normally" },
1307 { 0xc0, "Node Busy" },
1308 { 0xc1, "Invalid Command" },
1309 { 0xc2, "Command invalid for given LUN" },
1310 { 0xc3, "Timeout while processing command, response unavailable" },
1311 { 0xc4, "Out of space" },
1312 { 0xc5, "Reservation Canceled or Invalid Reservation ID" },
1313 { 0xc6, "Request data truncated" },
1314 { 0xc7, "Request data length invalid" },
1315 { 0xc8, "Request data field length limit exceeded" },
1316 { 0xc9, "Parameter out of range" },
1317 { 0xca, "Cannot return number of requested data bytes" },
1318 { 0xcb, "Requested Sensor, data, or record not present" },
1319 { 0xcc, "Invalid data field in Request" },
1320 { 0xcd, "Command illegal for specified sensor or record type" },
1321 { 0xce, "Command response could not be provided" },
1322 { 0xcf, "Cannot execute duplicated request" },
1323 { 0xd0, "Command response could not be provided: SDR Repository in update mode" },
1324 { 0xd1, "Command response could not be provided: device in firmware update mode" },
1325 { 0xd2, "Command response could not be provided: BMC initialization or initialization agent in progress" },
1326 { 0xd3, "Destination unavailable" },
1327 { 0xd4, "Cannot execute command: insufficient privilege level or other security-based restriction" },
1328 { 0xd5, "Cannot execute command: command, or request parameter(s), not supported in present state" },
1329 { 0xd6, "Cannot execute command: parameter is illegal because subfunction is disabled or unavailable" },
1330 { 0xff, "Unspecified error" },
1336 if (completion >= 0x01 && completion <= 0x7e) {
1337 return "Device specific (OEM) completion code";
1340 if (completion >= 0x80 && completion <= 0xbe) {
1341 if (cmd && cmd->cs_cc && (res = try_val_to_str(completion, cmd->cs_cc)) != NULL) {
1344 return "Standard command-specific code";
1347 return val_to_str_const(completion, std_completion_codes, "Unknown");
1351 dissect_tmode(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1353 ipmi_dissect_arg_t * arg = (ipmi_dissect_arg_t *) data;
1355 guint tvb_len = tvb_captured_length(tvb);
1358 /* TMode message is at least 3 bytes length */
1363 memset(&ctx, 0, sizeof(ctx));
1365 /* get Net Fn/RS LUN field */
1366 tmp = tvb_get_guint8(tvb, 0);
1369 ctx.hdr.netfn = tmp >> 2;
1372 * NOTE: request/response matching code swaps RQ LUN with RS LUN
1373 * fields in IPMB-like manner in order to find corresponding request
1374 * so, we set both RS LUN and RQ LUN here for correct
1375 * request/response matching
1377 ctx.hdr.rq_lun = tmp & 3;
1378 ctx.hdr.rs_lun = tmp & 3;
1380 /* get RQ Seq field */
1381 ctx.hdr.rq_seq = tvb_get_guint8(tvb, 1) >> 2;
1384 * NOTE: bridge field is ignored in request/response matching
1387 /* get command code */
1388 ctx.hdr.cmd = tvb_get_guint8(tvb, 2);
1390 /* set dissect flags */
1391 ctx.flags = IPMI_D_TMODE|IPMI_D_NO_CKS|IPMI_D_NO_RQ_SA;
1393 /* set header length */
1396 /* copy channel number and direction */
1397 ctx.hdr.context = arg ? arg->context : IPMI_E_NONE;
1398 ctx.hdr.channel = arg ? arg->channel : 0;
1399 ctx.hdr.dir = arg ? arg->flags >> 7 : ctx.hdr.netfn & 1;
1401 if (ctx.hdr.context == IPMI_E_NONE) {
1402 /* set source column */
1403 col_set_str(pinfo->cinfo, COL_DEF_SRC,
1404 ctx.hdr.dir ? "Console" : "BMC");
1406 /* set destination column */
1407 col_set_str(pinfo->cinfo, COL_DEF_DST,
1408 ctx.hdr.dir ? "BMC" : "Console");
1411 /* dissect IPMI command */
1412 return dissect_ipmi_cmd(tvb, pinfo, tree, proto_tmode, ett_ipmi, &ctx);
1416 dissect_kcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1418 ipmi_dissect_arg_t * arg = (ipmi_dissect_arg_t *) data;
1420 guint tvb_len = tvb_captured_length(tvb);
1423 /* KCS message is at least 2 bytes length */
1428 memset(&ctx, 0, sizeof(ctx));
1430 /* get Net Fn/RS LUN field */
1431 tmp = tvb_get_guint8(tvb, 0);
1434 ctx.hdr.netfn = tmp >> 2;
1437 * NOTE: request/response matching code swaps RQ LUN with RS LUN
1438 * fields in IPMB-like manner in order to find corresponding request
1439 * so, we set both RS LUN and RQ LUN here for correct
1440 * request/response matching
1442 ctx.hdr.rq_lun = tmp & 3;
1443 ctx.hdr.rs_lun = tmp & 3;
1445 /* get command code */
1446 ctx.hdr.cmd = tvb_get_guint8(tvb, 1);
1448 /* set dissect flags */
1449 ctx.flags = IPMI_D_NO_CKS|IPMI_D_NO_RQ_SA|IPMI_D_NO_SEQ;
1451 /* set header length */
1454 /* copy channel number and direction */
1455 ctx.hdr.context = arg ? arg->context : 0;
1456 ctx.hdr.channel = arg ? arg->channel : 0;
1457 ctx.hdr.dir = arg ? arg->flags >> 7 : ctx.hdr.netfn & 1;
1459 if (ctx.hdr.context == IPMI_E_NONE) {
1460 /* set source column */
1461 col_set_str(pinfo->cinfo, COL_DEF_SRC, ctx.hdr.dir ? "HOST" : "BMC");
1463 /* set destination column */
1464 col_set_str(pinfo->cinfo, COL_DEF_DST, ctx.hdr.dir ? "BMC" : "HOST");
1467 /* dissect IPMI command */
1468 return dissect_ipmi_cmd(tvb, pinfo, tree, proto_kcs, ett_ipmi, &ctx);
1471 static guint8 calc_cks(guint8 start, tvbuff_t * tvb, guint off, guint len)
1474 start += tvb_get_guint8(tvb, off++);
1480 static gboolean guess_imb_format(tvbuff_t *tvb, guint8 env,
1481 guint8 channel, guint * imb_flags, guint8 * cks1, guint8 * cks2)
1483 gboolean check_bc = FALSE;
1484 gboolean check_sh = FALSE;
1485 gboolean check_sa = FALSE;
1491 if (message_format == MSGFMT_NONE) {
1493 } else if (message_format == MSGFMT_IPMB) {
1494 *imb_flags = IPMI_D_TRG_SA;
1495 } else if (message_format == MSGFMT_LAN) {
1496 *imb_flags = IPMI_D_TRG_SA|IPMI_D_SESSION_HANDLE;
1497 /* channel 0 is primary IPMB */
1498 } else if (!channel) {
1499 /* check for broadcast if not in send message command */
1500 if (env == IPMI_E_NONE) {
1501 /* check broadcast */
1504 /* slave address must be present */
1505 *imb_flags = IPMI_D_TRG_SA;
1506 /* check if in send message command */
1507 } else if (env != IPMI_E_GETMSG) {
1508 /* slave address must be present */
1509 *imb_flags = IPMI_D_TRG_SA;
1510 } else /* IPMI_E_GETMSG */ {
1513 /* channel 15 is System Interface */
1514 } else if (channel == 15) {
1515 /* slave address must be present */
1516 *imb_flags = IPMI_D_TRG_SA;
1518 /* check if in get message command */
1519 if (env == IPMI_E_GETMSG) {
1520 /* session handle must be present */
1521 *imb_flags |= IPMI_D_SESSION_HANDLE;
1523 /* for other channels */
1525 if (env == IPMI_E_NONE) {
1526 /* check broadcast */
1529 /* slave address must be present */
1530 *imb_flags = IPMI_D_TRG_SA;
1531 } else if (env == IPMI_E_SENDMSG_RQ) {
1532 /* check session handle */
1535 /* slave address must be present */
1536 *imb_flags = IPMI_D_TRG_SA;
1537 } else if (env == IPMI_E_SENDMSG_RS) {
1538 /* slave address must be present */
1539 *imb_flags = IPMI_D_TRG_SA;
1540 } else /* IPMI_E_GETMSG */ {
1541 /* check session handle */
1544 /* check slave address presence */
1547 /* no pre-requisites */
1552 /* get message length */
1553 tvb_len = tvb_captured_length(tvb);
1556 * broadcast message starts with null,
1557 * does not contain session handle
1558 * but contains responder address
1562 && !tvb_get_guint8(tvb, 0)
1563 && !calc_cks(0, tvb, 1, 3)
1564 && !calc_cks(0, tvb, 4, tvb_len - 4)) {
1565 *imb_flags = IPMI_D_BROADCAST|IPMI_D_TRG_SA;
1572 * message with the starts with session handle
1573 * and contain responder address
1577 && !calc_cks(0, tvb, 1, 3)
1578 && !calc_cks(0, tvb, 4, tvb_len - 4)) {
1579 *imb_flags = IPMI_D_SESSION_HANDLE|IPMI_D_TRG_SA;
1586 * message with responder address
1590 && !calc_cks(0, tvb, 0, 3)
1591 && !calc_cks(0, tvb, 3, tvb_len - 3)) {
1592 *imb_flags = IPMI_D_TRG_SA;
1599 if (*imb_flags & IPMI_D_SESSION_HANDLE) {
1603 } else if (*imb_flags & IPMI_D_TRG_SA) {
1613 /* check message length */
1614 if (tvb_len < 6 + sh_len + sa_len) {
1618 /* calculate checksum deltas */
1619 *cks1 = calc_cks(rs_sa, tvb, sh_len, sa_len + 2);
1620 *cks2 = calc_cks(0, tvb, sh_len + sa_len + 2,
1621 tvb_len - sh_len - sa_len - 2);
1627 do_dissect_ipmb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1628 gint hf_parent_item, gint ett_tree, ipmi_dissect_arg_t * arg)
1634 memset(&ctx, 0, sizeof(ctx));
1636 /* copy message context and channel */
1637 ctx.hdr.context = arg ? arg->context : 0;
1638 ctx.hdr.channel = arg ? arg->channel : 0;
1640 /* guess IPMB message format */
1641 if (!guess_imb_format(tvb, ctx.hdr.context, ctx.hdr.channel,
1642 &ctx.flags, &ctx.cks1, &ctx.cks2)) {
1646 /* check if message is broadcast */
1647 if (ctx.flags & IPMI_D_BROADCAST) {
1648 /* skip first byte */
1652 /* check is session handle is specified */
1653 if (ctx.flags & IPMI_D_SESSION_HANDLE) {
1654 ctx.hdr.session = tvb_get_guint8(tvb, offset++);
1657 /* check is response address is specified */
1658 if (ctx.flags & IPMI_D_TRG_SA) {
1659 ctx.hdr.rs_sa = tvb_get_guint8(tvb, offset++);
1661 ctx.hdr.rs_sa = 0x20;
1664 /* get Net Fn/RS LUN field */
1665 tmp = tvb_get_guint8(tvb, offset++);
1667 /* set Net Fn and RS LUN */
1668 ctx.hdr.netfn = tmp >> 2;
1669 ctx.hdr.rs_lun = tmp & 3;
1675 ctx.hdr.rq_sa = tvb_get_guint8(tvb, offset++);
1677 /* get RQ Seq/RQ LUN field */
1678 tmp = tvb_get_guint8(tvb, offset++);
1680 /* set RQ Seq and RQ LUN */
1681 ctx.hdr.rq_seq = tmp >> 2;
1682 ctx.hdr.rq_lun = tmp & 3;
1684 /* get command code */
1685 ctx.hdr.cmd = tvb_get_guint8(tvb, offset++);
1687 /* set header length */
1688 ctx.hdr_len = offset;
1690 /* copy direction */
1691 ctx.hdr.dir = arg ? arg->flags >> 7 : ctx.hdr.netfn & 1;
1693 if (ctx.hdr.context == IPMI_E_NONE) {
1694 guint red = arg ? (arg->flags & 0x40) : 0;
1696 if (!ctx.hdr.channel) {
1697 col_add_fstr(pinfo->cinfo, COL_DEF_SRC,
1698 "0x%02x(%s)", ctx.hdr.rq_sa, red ? "IPMB-B" : "IPMB-A");
1700 col_add_fstr(pinfo->cinfo, COL_DEF_SRC,
1701 "0x%02x", ctx.hdr.rq_sa);
1704 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%02x", ctx.hdr.rs_sa);
1707 /* dissect IPMI command */
1708 return dissect_ipmi_cmd(tvb, pinfo, tree, hf_parent_item, ett_tree, &ctx);
1712 dissect_ipmi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1714 return do_dissect_ipmb(tvb, pinfo, tree, proto_ipmb, ett_ipmi,
1715 (ipmi_dissect_arg_t *) data);
1718 /* Register IPMB protocol.
1721 proto_register_ipmi(void)
1723 static hf_register_info hf[] = {
1724 { &hf_ipmi_session_handle, { "Session handle", "ipmi.session_handle", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1725 { &hf_ipmi_header_trg, { "Target Address", "ipmi.header.target", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1726 { &hf_ipmi_header_trg_lun, { "Target LUN", "ipmi.header.trg_lun", FT_UINT8, BASE_HEX, NULL, 0x03, NULL, HFILL }},
1727 { &hf_ipmi_header_netfn, { "NetFN", "ipmi.header.netfn", FT_UINT8, BASE_HEX, NULL, 0xfc, NULL, HFILL }},
1728 { &hf_ipmi_header_crc, { "Header Checksum", "ipmi.header.crc", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1729 { &hf_ipmi_header_src, { "Source Address", "ipmi.header.source", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1730 { &hf_ipmi_header_src_lun, { "Source LUN", "ipmi.header.src_lun", FT_UINT8, BASE_HEX, NULL, 0x03, NULL, HFILL }},
1731 { &hf_ipmi_header_bridged, { "Bridged", "ipmi.header.bridged", FT_UINT8, BASE_HEX, NULL, 0x03, NULL, HFILL }},
1732 { &hf_ipmi_header_sequence, { "Sequence Number", "ipmi.header.sequence", FT_UINT8, BASE_HEX, NULL, 0xfc, NULL, HFILL }},
1733 { &hf_ipmi_header_command, { "Command", "ipmi.header.command", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1734 { &hf_ipmi_header_completion, { "Completion Code", "ipmi.header.completion", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1735 { &hf_ipmi_header_sig, { "Signature", "ipmi.header.signature", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
1736 { &hf_ipmi_data_crc, { "Data checksum", "ipmi.data.crc", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1737 { &hf_ipmi_response_to, { "Response to", "ipmi.response_to", FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }},
1738 { &hf_ipmi_response_in, { "Response in", "ipmi.response_in", FT_FRAMENUM, BASE_NONE, NULL, 0, NULL, HFILL }},
1739 { &hf_ipmi_response_time, { "Responded in", "ipmi.response_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, NULL, HFILL }}
1741 static gint *ett[] = {
1749 static const enum_val_t msgfmt_vals[] = {
1750 { "none", "None", MSGFMT_NONE },
1751 { "ipmb", "IPMB", MSGFMT_IPMB },
1752 { "lan", "Session-based (LAN, ...)", MSGFMT_LAN },
1753 { "guess", "Use heuristics", MSGFMT_GUESS },
1756 static const enum_val_t oemsel_vals[] = {
1757 { "none", "None", IPMI_OEM_NONE },
1758 { "pps", "Pigeon Point Systems", IPMI_OEM_PPS },
1762 static ei_register_info ei[] = {
1763 { &ei_impi_parser_not_implemented, { "ipmi.parser_not_implemented", PI_UNDECODED, PI_WARN, "[PARSER NOT IMPLEMENTED]", EXPFILL }},
1767 expert_module_t* expert_ipmi;
1770 proto_ipmi = proto_register_protocol("Intelligent Platform Management Interface",
1774 proto_ipmb = proto_register_protocol("Intelligent Platform Management Bus",
1777 proto_kcs = proto_register_protocol("Keyboard Controller Style Interface",
1780 proto_tmode = proto_register_protocol("Serial Terminal Mode Interface",
1784 proto_register_field_array(proto_ipmi, hf, array_length(hf));
1785 proto_register_subtree_array(ett, array_length(ett));
1787 expert_ipmi = expert_register_protocol(proto_ipmi);
1788 expert_register_field_array(expert_ipmi, ei, array_length(ei));
1790 ipmi_netfn_setdesc(IPMI_CHASSIS_REQ, "Chassis", 0);
1791 ipmi_netfn_setdesc(IPMI_BRIDGE_REQ, "Bridge", 0);
1792 ipmi_netfn_setdesc(IPMI_SE_REQ, "Sensor/Event", 0);
1793 ipmi_netfn_setdesc(IPMI_APP_REQ, "Application", 0);
1794 ipmi_netfn_setdesc(IPMI_UPDATE_REQ, "Firmware Update", 0);
1795 ipmi_netfn_setdesc(IPMI_STORAGE_REQ, "Storage", 0);
1796 ipmi_netfn_setdesc(IPMI_TRANSPORT_REQ, "Transport", 0);
1797 ipmi_netfn_setdesc(IPMI_GROUP_REQ, "Group", 1);
1798 ipmi_netfn_setdesc(IPMI_OEM_REQ, "OEM/Group", 3);
1799 for (i = 0x30; i < 0x40; i += 2) {
1800 ipmi_netfn_setdesc(i, "OEM", 0);
1803 new_register_dissector("ipmi", dissect_ipmi, proto_ipmi);
1804 new_register_dissector("ipmb", dissect_ipmi, proto_ipmb);
1805 new_register_dissector("kcs", dissect_kcs, proto_kcs);
1806 new_register_dissector("tmode", dissect_tmode, proto_tmode);
1808 data_dissector = find_dissector("data");
1810 m = prefs_register_protocol(proto_ipmi, NULL);
1811 prefs_register_bool_preference(m, "fru_langcode_is_english", "FRU Language Code is English",
1812 "FRU Language Code is English; strings are ASCII+LATIN1 (vs. Unicode)",
1813 &fru_langcode_is_english);
1814 prefs_register_uint_preference(m, "response_after_req", "Maximum delay of response message",
1815 "Do not search for responses coming after this timeout (milliseconds)",
1816 10, &response_after_req);
1817 prefs_register_uint_preference(m, "response_before_req", "Response ahead of request",
1818 "Allow for responses before requests (milliseconds)",
1819 10, &response_before_req);
1820 prefs_register_enum_preference(m, "msgfmt", "Format of embedded messages",
1821 "Format of messages embedded into Send/Get/Forward Message",
1822 &message_format, msgfmt_vals, FALSE);
1823 prefs_register_enum_preference(m, "selected_oem", "OEM commands parsed as",
1824 "Selects which OEM format is used for commands that IPMI does not define",
1825 &selected_oem, oemsel_vals, FALSE);
1829 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1834 * indent-tabs-mode: t
1837 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1838 * :indentSize=8:tabSize=8:noTabs=false: