Define some fcns & vars as static...
[metze/wireshark/wip.git] / epan / dissectors / packet-ipmi.c
1 /* packet-ipmi.c
2  * Routines for IPMI dissection
3  * Copyright 2002-2008, Alexey Neyman, Pigeon Point Systems <avn@pigeonpoint.com>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
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.
15  *
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.
20  *
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.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33 #include <string.h>
34 #include <time.h>
35 #include <math.h>
36
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>
43
44 #include "packet-ipmi.h"
45
46 /*
47  * See the IPMI specifications at
48  *
49  *      http://www.intel.com/design/servers/ipmi/
50  */
51
52 /* Define IPMI_DEBUG to enable printing the process of request-response pairing */
53 /* #define IPMI_DEBUG */
54
55 /* Top-level search structure: list of registered handlers for a given netFn */
56 struct ipmi_netfn_root {
57         ipmi_netfn_t *list;
58         const char *desc;
59         guint32 siglen;
60 };
61
62 #define NSAVED_DATA 2
63
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 {
68         guint32 set_data;
69         guint32 saved_data[NSAVED_DATA];
70 };
71
72 enum {
73         RQ = 0,
74         RS,
75         RS2,
76
77         MAX_RQRS_FRAMES
78 };
79
80 enum {
81         MSGFMT_NONE = 0,
82         MSGFMT_IPMB,
83         MSGFMT_LAN,
84         MSGFMT_GUESS
85 };
86
87 struct ipmi_reqresp {
88         struct ipmi_reqresp *next;
89         struct ipmi_saved_data *data;
90         int (*whichresponse)(struct ipmi_header *hdr, struct ipmi_reqresp *rr);
91         struct {
92                 guint32 num;
93                 nstime_t time;
94         } frames[MAX_RQRS_FRAMES];
95         guint8 netfn;
96         guint8 cmd;
97 };
98
99 struct ipmi_keyhead {
100         struct ipmi_reqresp *rr;
101 };
102
103 struct ipmi_keytree {
104         emem_tree_t *heads;
105 };
106
107 struct ipmi_parse_typelen {
108         void (*get_len)(guint *, guint *, tvbuff_t *, guint, guint, gboolean);
109         void (*parse)(char *, tvbuff_t *, guint, guint);
110         const char *desc;
111 };
112
113 struct ipmi_header *ipmi_current_hdr;
114
115 static gint proto_ipmi = -1;
116
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;
122
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;
141
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;
148
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];
153
154 /* Debug support */
155 static void
156 debug_printf(const gchar *fmt _U_, ...)
157 {
158 #if defined(IPMI_DEBUG)
159         va_list ap;
160
161         va_start(ap, fmt);
162         vfprintf(stderr, fmt, ap);
163         va_end(ap);
164 #endif
165 }
166
167 /* ----------------------------------------------------------------
168    Support for request-response caching.
169 ---------------------------------------------------------------- */
170
171 /* Key generation; returns the same key for requests and responses */
172 static guint32
173 makekey(struct ipmi_header *hdr)
174 {
175         guint32 trg, src, res;
176
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;
181 }
182
183 static struct ipmi_reqresp *
184 key_lookup_reqresp(struct ipmi_keyhead *kh, struct ipmi_header *hdr, frame_data *fd)
185 {
186         struct ipmi_reqresp *rr, *best_rr = NULL;
187         nstime_t delta;
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;
191         int i;
192
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) {
198                         continue;
199                 }
200
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 */
206                                 return rr;
207                         }
208                 }
209
210                 /* Reject responses before requests or more than 5 seconds ahead */
211                 if (is_resp) {
212                         nstime_delta(&delta, &fd->abs_ts, &rr->frames[RQ].time);
213                 } else {
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);
217                 }
218                 d = nstime_to_msec(&delta);
219                 if (d < -(double)response_before_req || d > (double)response_after_req) {
220                         continue;
221                 }
222
223                 if (fabs(d) < best_d) {
224                         best_rr = rr;
225                         best_d = fabs(d);
226                 }
227         }
228
229         return best_rr;
230 }
231
232 static void
233 key_insert_reqresp(struct ipmi_keyhead *kh, struct ipmi_reqresp *rr)
234 {
235         /* Insert to head, so that the search would find most recent response */
236         rr->next = kh->rr;
237         kh->rr = rr;
238 }
239
240 static inline gboolean
241 set_framenums(struct ipmi_header *hdr, struct ipmi_reqresp *rr, frame_data *fd)
242 {
243         int which = hdr->netfn & 0x01 ? rr->whichresponse ? rr->whichresponse(hdr, rr) : RS : RQ;
244
245         if (rr->frames[which].num && rr->frames[which].num != fd->num) {
246                 return FALSE;
247         }
248         rr->frames[which].num = fd->num;
249         rr->frames[which].time = fd->abs_ts;
250         return TRUE;
251 }
252
253 #define IS_SENDMSG(hdr) (((hdr)->netfn & 0x3e) == IPMI_APP_REQ && (hdr)->cmd == 0x34)
254
255 int
256 ipmi_sendmsg_whichresponse(struct ipmi_header *hdr, struct ipmi_reqresp *rr)
257 {
258         if (!IS_SENDMSG(hdr)) {
259                 /* Not a Send Message: just a simple response */
260                 return RS;
261         }
262
263         if (hdr->data_len > 0) {
264                 /* Trivial case: response with non-null data can only be a
265                    response in AMC.0 style */
266                 return RS2;
267         }
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].
275
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?)
278         */
279         if (!rr->frames[RS].num) {
280                 return RS;
281         }
282
283         /* In case we received "success", move the other response to [RS2] */
284         if (!hdr->ccode) {
285                 if (!rr->frames[RS2].num) {
286                         rr->frames[RS2] = rr->frames[RS];
287                 }
288                 return RS;
289         }
290
291         /* [RS] occupied, non-successful */
292         return RS2;
293 }
294
295 int
296 ipmi_sendmsg_otheridx(struct ipmi_header *hdr)
297 {
298         return IS_SENDMSG(hdr) ? nest_level : RS;
299 }
300
301 struct ipmi_header *
302 ipmi_sendmsg_getheaders(struct ipmi_header *base, void *arg, guint i)
303 {
304         static struct ipmi_header hdr;
305         struct ipmi_header *wrapper = arg;
306
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.
313
314            Thus, there are 3 types of responses to Send Message
315
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.
319
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.
326         */
327
328         if (i >= 2 || (i == 1 && wrapper->seq == base->seq)) {
329                 return NULL;
330         }
331
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;
338         hdr.cmd = base->cmd;
339         hdr.seq = i ? base->seq : wrapper->seq;
340         hdr.ccode = base->ccode;
341         hdr.data_len = base->data_len;
342         return &hdr;
343 }
344
345 static void
346 maybe_insert_reqresp(ipmi_dissect_format_t *dfmt, struct ipmi_header *hdr)
347 {
348         conversation_t *cnv;
349         struct ipmi_keytree *kt;
350         struct ipmi_keyhead *kh;
351         struct ipmi_reqresp *rr;
352         guint32 key, i;
353
354         cnv = find_or_create_conversation(current_pinfo);
355
356         kt = conversation_get_proto_data(cnv, proto_ipmi);
357         if (!kt) {
358                 kt = se_alloc(sizeof(struct ipmi_keytree));
359                 kt->heads = se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK,
360                                 "ipmi_key_heads");
361                 conversation_add_proto_data(cnv, proto_ipmi, kt);
362         }
363
364         debug_printf("--> maybe_insert_reqresp( %d )\n", current_pinfo->fd->num);
365         i = 0;
366         do {
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);
370                 key = makekey(hdr);
371                 kh = se_tree_lookup32(kt->heads, key);
372                 if (!kh) {
373                         kh = se_alloc0(sizeof(struct ipmi_keyhead));
374                         se_tree_insert32(kt->heads, key, kh);
375                 }
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,
383                                         rr->netfn, rr->cmd);
384                         if (!rr->whichresponse) {
385                                 rr->whichresponse = dfmt->whichresponse;
386                         }
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,
391                                                 rr->netfn, rr->cmd);
392                                 current_saved_data = rr->data;
393                                 return;
394                         }
395
396                         /* Found, but already occupied. Fall through to allocating the structures */
397                         current_saved_data = NULL;
398                 }
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));
403                 }
404                 rr = se_alloc0(sizeof(struct ipmi_reqresp));
405                 rr->whichresponse = dfmt->whichresponse;
406                 rr->netfn = hdr->netfn & 0x3e;
407                 rr->cmd = hdr->cmd;
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,
414                                 rr->netfn, rr->cmd);
415
416                 /* Do we have other headers to insert? */
417                 hdr = dfmt->getmoreheaders ? dfmt->getmoreheaders(hdr, dfmt->arg, i++) : NULL;
418         } while (hdr);
419 }
420
421 static void
422 add_reqresp_info(ipmi_dissect_format_t *dfmt, struct ipmi_header *hdr, proto_tree *tree, tvbuff_t *tvb)
423 {
424         conversation_t *cnv;
425         struct ipmi_keytree *kt;
426         struct ipmi_keyhead *kh;
427         struct ipmi_reqresp *rr = NULL;
428         guint32 key, i, other_idx;
429         proto_item *ti;
430         nstime_t ns;
431
432         debug_printf("--> add_reqresp_info( %d )\n", current_pinfo->fd->num);
433
434         /* [0] is request; [1..MAX_RS_LEVEL] are responses */
435         other_idx = (hdr->netfn & 0x01) ? RQ : dfmt->otheridx ? dfmt->otheridx(hdr) : RS;
436
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. */
441                 goto fallback;
442         }
443
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, &current_pinfo->src,
447                         &current_pinfo->dst, current_pinfo->ptype,
448                         current_pinfo->srcport, current_pinfo->destport, 0)) == NULL) {
449                 goto fallback;
450         }
451         if ((kt = conversation_get_proto_data(cnv, proto_ipmi)) == NULL) {
452                 goto fallback;
453         }
454
455         i = 0;
456         while (1) {
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);
460                 key = makekey(hdr);
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,
466                                         rr->netfn, rr->cmd);
467                         if (rr->frames[other_idx].num) {
468                                 break;
469                         }
470                 }
471
472                 /* Do we have other headers to check? */
473                 hdr = dfmt->getmoreheaders ? dfmt->getmoreheaders(hdr, dfmt->arg, i++) : NULL;
474                 if (!hdr) {
475                         goto fallback;
476                 }
477         }
478
479         if (hdr->netfn & 0x01) {
480                 /* Response */
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, &current_pinfo->fd->abs_ts, &rr->frames[RQ].time);
485                 ti = proto_tree_add_time(tree, hf_ipmi_response_time,
486                                 tvb, 0, 0, &ns);
487                 PROTO_ITEM_SET_GENERATED(ti);
488         } else {
489                 /* Request */
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);
493         }
494         return;
495
496 fallback:
497         ti = proto_tree_add_text(tree, tvb, 0, 0, "No corresponding %s",
498                         other_idx ? "response" : "request");
499         PROTO_ITEM_SET_GENERATED(ti);
500 }
501
502 /* Save data in request, retrieve in response */
503 void
504 ipmi_setsaveddata(guint idx, guint32 val)
505 {
506         DISSECTOR_ASSERT(idx < NSAVED_DATA);
507         current_saved_data->saved_data[idx] = val;
508         current_saved_data->set_data |= (1 << idx);
509 }
510
511 gboolean
512 ipmi_getsaveddata(guint idx, guint32 *pval)
513 {
514         DISSECTOR_ASSERT(idx < NSAVED_DATA);
515         if (current_saved_data->set_data & (1 << idx)) {
516                 *pval = current_saved_data->saved_data[idx];
517                 return TRUE;
518         }
519         return FALSE;
520 }
521
522 /* ----------------------------------------------------------------
523    Support for Type/Length fields parsing.
524 ---------------------------------------------------------------- */
525
526 static void
527 get_len_binary(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
528                 guint len, gboolean len_is_bytes _U_)
529 {
530         *clen = len * 3;
531         *blen = len;
532 }
533
534 static void
535 parse_binary(char *p, tvbuff_t *tvb, guint offs, guint len)
536 {
537         static const char hex[] = "0123456789ABCDEF";
538         guint8 v;
539         guint i;
540
541         for (i = 0; i < len / 3; i++) {
542                 v = tvb_get_guint8(tvb, offs + i);
543                 *p++ = hex[v >> 4];
544                 *p++ = hex[v & 0xf];
545                 *p++ = ' ';
546         }
547
548         if (i) {
549                 *--p = '\0';
550         }
551 }
552
553 static struct ipmi_parse_typelen ptl_binary = {
554         get_len_binary, parse_binary, "Binary"
555 };
556
557 static void
558 get_len_bcdplus(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
559                 guint len, gboolean len_is_bytes)
560 {
561         if (len_is_bytes) {
562                 *clen = len * 2;
563                 *blen = len;
564         } else {
565                 *blen = (len + 1) / 2;
566                 *clen = len;
567         }
568 }
569
570 static void
571 parse_bcdplus(char *p, tvbuff_t *tvb, guint offs, guint len)
572 {
573         static const char bcd[] = "0123456789 -.:,_";
574         guint i, msk = 0xf0, shft = 4;
575         guint8 v;
576
577         for (i = 0; i < len; i++) {
578                 v = (tvb_get_guint8(tvb, offs + i / 2) & msk) >> shft;
579                 *p++ = bcd[v];
580                 msk ^= 0xff;
581                 shft = 4 - shft;
582         }
583 }
584
585 static struct ipmi_parse_typelen ptl_bcdplus = {
586         get_len_bcdplus, parse_bcdplus, "BCD+"
587 };
588
589 static void
590 get_len_6bit_ascii(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
591                 guint len, gboolean len_is_bytes)
592 {
593         if (len_is_bytes) {
594                 *clen = len * 4 / 3;
595                 *blen = len;
596         } else {
597                 *blen = (len * 3 + 3) / 4;
598                 *clen = len;
599         }
600 }
601
602 static void
603 parse_6bit_ascii(char *p, tvbuff_t *tvb, guint offs, guint len)
604 {
605         guint32 v;
606         guint i;
607
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);
615                 p += 4;
616         }
617
618         /* Do we have any characters left? */
619         offs += len / 4;
620         len &= 0x3;
621         switch (len) {
622         case 3:
623                 v = (tvb_get_guint8(tvb, offs + 2) << 4) | (tvb_get_guint8(tvb, offs + 1) >> 4);
624                 p[2] = ' ' + (v & 0x3f);
625                 /* Fall thru */
626         case 2:
627                 v = (tvb_get_guint8(tvb, offs + 1) << 2) | (tvb_get_guint8(tvb, offs) >> 6);
628                 p[1] = ' ' + (v & 0x3f);
629                 /* Fall thru */
630         case 1:
631                 v = tvb_get_guint8(tvb, offs) & 0x3f;
632                 p[0] = ' ' + (v & 0x3f);
633         }
634 }
635
636 static struct ipmi_parse_typelen ptl_6bit_ascii = {
637         get_len_6bit_ascii, parse_6bit_ascii, "6-bit ASCII"
638 };
639
640 static void
641 get_len_8bit_ascii(guint *clen, guint *blen, tvbuff_t *tvb, guint offs,
642                 guint len, gboolean len_is_bytes _U_)
643 {
644         guint i;
645         guint8 ch;
646
647         *blen = len;    /* One byte is one character */
648         *clen = 0;
649         for (i = 0; i < len; i++) {
650                 ch = tvb_get_guint8(tvb, offs + i);
651                 *clen += (ch >= 0x20 && ch <= 0x7f) ? 1 : 4;
652         }
653 }
654
655 static void
656 parse_8bit_ascii(char *p, tvbuff_t *tvb, guint offs, guint len)
657 {
658         guint8 ch;
659         char *pmax;
660
661         pmax = p + len;
662         while (p < pmax) {
663                 ch = tvb_get_guint8(tvb, offs++);
664                 if (ch >= 0x20 && ch <= 0x7f) {
665                         *p++ = ch;
666                 } else {
667                         g_snprintf(p, 5, "\\x%02x", ch);
668                         p += 4;
669                 }
670         }
671 }
672
673 static struct ipmi_parse_typelen ptl_8bit_ascii = {
674         get_len_8bit_ascii, parse_8bit_ascii, "ASCII+Latin1"
675 };
676
677 static void
678 get_len_unicode(guint *clen, guint *blen, tvbuff_t *tvb _U_, guint offs _U_,
679                 guint len _U_, gboolean len_is_bytes)
680 {
681         if (len_is_bytes) {
682                 *clen = len * 3; /* Each 2 bytes result in 6 chars printed: \Uxxxx */
683                 *blen = len;
684         } else {
685                 *clen = len * 6;
686                 *blen = len * 2;
687         }
688 }
689
690 static void
691 parse_unicode(char *p, tvbuff_t *tvb, guint offs, guint len)
692 {
693         char *pmax = p + len;
694         guint8 ch0, ch1;
695
696         while (p < pmax) {
697                 ch0 = tvb_get_guint8(tvb, offs++);
698                 ch1 = tvb_get_guint8(tvb, offs++);
699                 g_snprintf(p, 7, "\\U%02x%02x", ch0, ch1);
700                 p += 6;
701         }
702 }
703
704 static struct ipmi_parse_typelen ptl_unicode = {
705         get_len_unicode, parse_unicode, "Unicode"
706 };
707
708 void
709 ipmi_add_typelen(proto_tree *tree, const char *desc, tvbuff_t *tvb,
710                 guint offs, gboolean is_fru)
711 {
712         static struct ipmi_parse_typelen *fru_eng[4] = {
713                 &ptl_binary, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_8bit_ascii
714         };
715         static struct ipmi_parse_typelen *fru_noneng[4] = {
716                 &ptl_binary, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_unicode
717         };
718         static struct ipmi_parse_typelen *ipmi[4] = {
719                 &ptl_unicode, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_8bit_ascii
720         };
721         struct ipmi_parse_typelen *ptr;
722         proto_tree *s_tree;
723         proto_item *ti;
724         guint type, msk, clen, blen, len;
725         const char *unit;
726         char *str;
727         guint8 typelen;
728
729         typelen = tvb_get_guint8(tvb, offs);
730         type = typelen >> 6;
731         if (is_fru) {
732                 msk = 0x3f;
733                 ptr = (fru_langcode_is_english ? fru_eng : fru_noneng)[type];
734                 unit = "bytes";
735         } else {
736                 msk = 0x1f;
737                 ptr = ipmi[type];
738                 unit = "characters";
739         }
740
741         len = typelen & msk;
742         ptr->get_len(&clen, &blen, tvb, offs + 1, len, is_fru);
743
744         str = ep_alloc(clen + 1);
745         ptr->parse(str, tvb, offs + 1, clen);
746         str[clen] = '\0';
747
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);
755
756         proto_tree_add_text(tree, tvb, offs + 1, blen, "%s: [%s] '%s'",
757                         desc, ptr->desc, str);
758 }
759
760 /* ----------------------------------------------------------------
761    Timestamp, IPMI-style.
762 ---------------------------------------------------------------- */
763 void
764 ipmi_add_timestamp(proto_tree *tree, gint hf, tvbuff_t *tvb, guint offset)
765 {
766         guint32 ts = tvb_get_letohl(tvb, offset);
767
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));
775         } else {
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));
778         }
779 }
780
781 /* ----------------------------------------------------------------
782    GUID, IPMI-style.
783 ---------------------------------------------------------------- */
784
785 void
786 ipmi_add_guid(proto_tree *tree, gint hf, tvbuff_t *tvb, guint offset)
787 {
788         e_guid_t guid;
789         int i;
790
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);
796         }
797         proto_tree_add_guid(tree, hf, tvb, offset, 16, &guid);
798 }
799
800 /* ----------------------------------------------------------------
801    Routines for registering/looking up command parsers.
802 ---------------------------------------------------------------- */
803
804 static void
805 ipmi_netfn_setdesc(guint32 netfn, const char *desc, guint32 siglen)
806 {
807         struct ipmi_netfn_root *inr;
808
809         inr = &ipmi_cmd_tab[netfn >> 1];
810         inr->desc = desc;
811         inr->siglen = siglen;
812 }
813
814 void
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)
818 {
819         struct ipmi_netfn_root *inr;
820         ipmi_netfn_t *inh;
821
822         netfn >>= 1;    /* Requests and responses grouped together */
823         if (netfn >= IPMI_NETFN_MAX) {
824                 g_warning("NetFn too large: %x", netfn * 2);
825                 return;
826         }
827
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);
833                 return;
834         }
835
836         inh = g_malloc(sizeof(struct ipmi_netfn_handler));
837         inh->desc = desc;
838         inh->oem_selector = oem_selector;
839         inh->sig = sig;
840         inh->cmdtab = cmdtab;
841         inh->cmdtablen = cmdtablen;
842
843         inh->next = inr->list;
844         inr->list = inh;
845 }
846
847 guint32
848 ipmi_getsiglen(guint32 netfn)
849 {
850         return ipmi_cmd_tab[netfn >> 1].siglen;
851 }
852
853 const char *
854 ipmi_getnetfnname(guint32 netfn, ipmi_netfn_t *nf)
855 {
856         const char *dn, *db;
857
858         dn = ipmi_cmd_tab[netfn >> 1].desc ?
859                 ipmi_cmd_tab[netfn >> 1].desc : "Reserved";
860         db = nf ? nf->desc : NULL;
861         if (db) {
862                 return ep_strdup_printf("%s (%s)", db, dn);
863         } else {
864                 return dn;
865         }
866 }
867
868 ipmi_netfn_t *
869 ipmi_getnetfn(guint32 netfn, const guint8 *sig)
870 {
871         struct ipmi_netfn_root *inr;
872         ipmi_netfn_t *inh;
873
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))) {
878                         return inh;
879                 }
880         }
881
882         /* Either unknown netFn or signature does not match */
883         return NULL;
884 }
885
886 ipmi_cmd_t *
887 ipmi_getcmd(ipmi_netfn_t *nf, guint32 cmd)
888 {
889         static ipmi_cmd_t ipmi_cmd_unknown = {
890                 0x00,           /* Code */
891                 ipmi_notimpl,   /* request */
892                 ipmi_notimpl,   /* response */
893                 NULL,           /* command codes */
894                 NULL,           /* subfunctions */
895                 "Unknown command",
896                 0               /* flag */
897         };
898         ipmi_cmd_t *ic;
899         size_t i, len;
900
901         if (nf) {
902                 len = nf->cmdtablen;
903                 for (ic = nf->cmdtab, i = 0; i < len; i++, ic++) {
904                         if (ic->cmd == cmd) {
905                                 return ic;
906                         }
907                 }
908         }
909
910         return &ipmi_cmd_unknown;
911 }
912
913 /* ----------------------------------------------------------------
914    Various utility functions.
915 ---------------------------------------------------------------- */
916
917 void
918 ipmi_notimpl(tvbuff_t *tvb, proto_tree *tree)
919 {
920         if (tree) {
921                 proto_tree_add_text(tree, tvb, 0, -1, "[PARSER NOT IMPLEMENTED]");
922         }
923 }
924
925 char *
926 ipmi_dcd8(guint32 val, guint32 mask)
927 {
928         static char buf[64];
929
930         decode_bitfield_value(buf, val, mask, 8);
931         return buf;
932 }
933
934 void
935 ipmi_fmt_10ms_1based(gchar *s, guint32 v)
936 {
937         g_snprintf(s, ITEM_LABEL_LENGTH, "%d.%03d seconds", v / 100, (v % 100) * 10);
938 }
939
940 void
941 ipmi_fmt_500ms_0based(gchar *s, guint32 v)
942 {
943         ipmi_fmt_500ms_1based(s, ++v);
944 }
945
946 void
947 ipmi_fmt_500ms_1based(gchar *s, guint32 v)
948 {
949         g_snprintf(s, ITEM_LABEL_LENGTH, "%d.%03d seconds", v / 2, (v % 2) * 500);
950 }
951
952 void
953 ipmi_fmt_1s_0based(gchar *s, guint32 v)
954 {
955         ipmi_fmt_1s_1based(s, ++v);
956 }
957
958 void
959 ipmi_fmt_1s_1based(gchar *s, guint32 v)
960 {
961         g_snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", v);
962 }
963
964 void
965 ipmi_fmt_2s_0based(gchar *s, guint32 v)
966 {
967         g_snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", (v + 1) * 2);
968 }
969
970 void
971 ipmi_fmt_5s_1based(gchar *s, guint32 v)
972 {
973         g_snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", v * 5);
974 }
975
976 void
977 ipmi_fmt_version(gchar *s, guint32 v)
978 {
979         g_snprintf(s, ITEM_LABEL_LENGTH, "%d.%d", v & 0x0f, (v >> 4) & 0x0f);
980 }
981
982 void
983 ipmi_fmt_channel(gchar *s, guint32 v)
984 {
985         static const value_string chan_vals[] = {
986                 { 0x00, "Primary IPMB (IPMB-0)" },
987                 { 0x07, "IPMB-L" },
988                 { 0x0e, "Current channel" },
989                 { 0x0f, "System Interface" },
990                 { 0, NULL }
991         };
992
993         g_snprintf(s, ITEM_LABEL_LENGTH, "%s (0x%02x)",
994                         val_to_str(v, chan_vals, "Channel #%d"), v);
995 }
996
997 void
998 ipmi_fmt_udpport(gchar *s, guint32 v)
999 {
1000         g_snprintf(s, ITEM_LABEL_LENGTH, "%s (%d)", get_udp_port(v), v);
1001 }
1002
1003 void
1004 ipmi_fmt_percent(gchar *s, guint32 v)
1005 {
1006         g_snprintf(s, ITEM_LABEL_LENGTH, "%d%%", v);
1007 }
1008
1009 const char *
1010 ipmi_get_completion_code(guint8 completion, ipmi_cmd_t *cmd)
1011 {
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" },
1038
1039                 { 0, NULL }
1040         };
1041         const char *res;
1042
1043         if (completion >= 0x01 && completion <= 0x7e) {
1044                 return "Device specific (OEM) completion code";
1045         }
1046
1047         if (completion >= 0x80 && completion <= 0xbe) {
1048                 if (cmd && cmd->cs_cc && (res = match_strval(completion, cmd->cs_cc)) != NULL) {
1049                         return res;
1050                 }
1051                 return "Standard command-specific code";
1052         }
1053
1054         return val_to_str(completion, std_completion_codes, "Unknown");
1055 }
1056
1057 /* Guess the parsing flags for a message
1058  */
1059 int
1060 ipmi_guess_dissect_flags(tvbuff_t *tvb)
1061 {
1062         int i;
1063         guint8 buf[6];
1064
1065         switch (message_format) {
1066         case MSGFMT_NONE:
1067                 return IPMI_D_NONE;
1068         case MSGFMT_IPMB:
1069                 return IPMI_D_TRG_SA;
1070         case MSGFMT_LAN:
1071                 return IPMI_D_TRG_SA|IPMI_D_SESSION_HANDLE;
1072         }
1073
1074         /* Try to guess the format */
1075         DISSECTOR_ASSERT(message_format == MSGFMT_GUESS);
1076
1077         /* 6 is shortest message - Get Message with empty data */
1078         if (tvb_length(tvb) < 6) {
1079                 return IPMI_D_NONE;
1080         }
1081
1082         /* Fetch the beginning */
1083         for (i = 0; i < 6; i++) {
1084                 buf[i] = tvb_get_guint8(tvb, i);
1085         }
1086
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;
1090         }
1091
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;
1095         }
1096
1097         /* Can't guess */
1098         return IPMI_D_NONE;
1099 }
1100
1101 /* Print out IPMB packet.
1102  */
1103 void
1104 ipmi_do_dissect(tvbuff_t *tvb, proto_tree *ipmi_tree, ipmi_dissect_format_t *dfmt)
1105 {
1106         proto_tree *hdr_tree, *data_tree, *s_tree;
1107         proto_item *ti;
1108         tvbuff_t *data_tvb;
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;
1118
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);
1123                 return;
1124         }
1125
1126         nest_level++;
1127         offs = 0;
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");
1131
1132         /* Optional byte: in Send Message targeted to session-based channels */
1133         if (dfmt->flags & IPMI_D_SESSION_HANDLE) {
1134                 offs++;
1135         }
1136
1137         /* Optional byte: 00 indicates General Call address - broadcast message */
1138         if ((dfmt->flags & IPMI_D_BROADCAST) && tvb_get_guint8(tvb, offs) == 0x00) {
1139                 is_broadcast = 1;
1140                 offs++;
1141         }
1142
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;
1145
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;
1151
1152         /* Byte 3: header checksum */
1153         hdr_crc = tvb_get_guint8(tvb, offs++);
1154
1155         /* Byte 4: source slave address */
1156         hdr.src_sa = tvb_get_guint8(tvb, offs++);
1157
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;
1162
1163         /* Byte 6: command code */
1164         hdr.cmd = tvb_get_guint8(tvb, offs++);
1165
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;
1169
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));
1173         offs += siglen;
1174
1175         /* Save header length */
1176         hdrlen = offs;
1177         hdr.data_len = tvb_length(tvb) - hdrlen - 1;
1178
1179         /* Get some text descriptions */
1180         ic = ipmi_getcmd(in, hdr.cmd);
1181         ndesc = ipmi_getnetfnname(hdr.netfn, in);
1182         cdesc = ic->desc;
1183         ccdesc = ipmi_get_completion_code(hdr.ccode, ic);
1184         if (!is_broadcast) {
1185                 bcast = "";
1186         } else if (ic->flags & CMD_MAYBROADCAST) {
1187                 bcast = " (BROADCAST: command may not be broadcast)";
1188         } else {
1189                 bcast = " (BROADCAST)";
1190         }
1191
1192
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;
1198
1199         /* Select sub-handler */
1200         hnd = is_resp ? ic->parse_resp : ic->parse_req;
1201
1202         /* Start new conversation if needed */
1203         if (!is_resp && (ic->flags & CMD_NEWCONV)) {
1204                 conversation_new(current_pinfo->fd->num, &current_pinfo->src,
1205                                 &current_pinfo->dst, current_pinfo->ptype,
1206                                 current_pinfo->srcport, current_pinfo->destport, 0);
1207         }
1208
1209         /* Check if we need to insert request-response pair */
1210         maybe_insert_reqresp(dfmt, &hdr);
1211
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);
1214
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 : "");
1219
1220         if (!is_resp && (ic->flags & CMD_CALLRQ)) {
1221                 hnd(data_tvb, NULL);
1222         }
1223
1224         if (ipmi_tree) {
1225                 add_reqresp_info(dfmt, &hdr, ipmi_tree, tvb);
1226
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);
1231
1232                 offs = 0;
1233
1234                 if (dfmt->flags & IPMI_D_SESSION_HANDLE) {
1235                         proto_tree_add_item(hdr_tree, hf_ipmi_session_handle,
1236                                         tvb, offs++, 1, TRUE);
1237                 }
1238
1239                 /* Broadcast byte (optional) */
1240                 if (is_broadcast) {
1241                         proto_tree_add_uint_format(hdr_tree, hf_ipmi_header_broadcast,
1242                                         tvb, offs++, 1, 0x00, "Broadcast message");
1243                 }
1244
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);
1248                 }
1249
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);
1255
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);
1261                 offs++;
1262
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);
1267                 }
1268                 else {
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);
1274                 }
1275
1276                 /* Remember where chk2 bytes start */
1277                 data_chk_offs = offs;
1278
1279                 /* Source SA */
1280                 proto_tree_add_item(hdr_tree, hf_ipmi_header_src, tvb, offs++, 1, TRUE);
1281
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);
1287
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);
1290                 offs++;
1291
1292                 /* Command */
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);
1295
1296                 /* Response code (if present) */
1297                 if (is_resp) {
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);
1300                 }
1301
1302                 /* Defining body signature (if present) */
1303                 if (siglen) {
1304                         ti = proto_tree_add_item(hdr_tree, hf_ipmi_header_sig, tvb, offs, siglen, TRUE);
1305                         proto_item_append_text(ti, " (%s)", ndesc);
1306                         offs += siglen;
1307                 }
1308
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);
1314                 }
1315
1316                 /* Checksum all but the last byte */
1317                 len = tvb_length(tvb) - 1;
1318                 data_crc = tvb_get_guint8(tvb, len);
1319                 data_exp_crc = 0;
1320                 for (i = data_chk_offs; i < len; i++) {
1321                         data_exp_crc += tvb_get_guint8(tvb, i);
1322                 }
1323                 data_exp_crc = (0 - data_exp_crc) & 0xff;
1324
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);
1328                 }
1329                 else {
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);
1335                 }
1336         }
1337
1338         /* Restore globals, in case we've been called recursively */
1339         ipmi_current_hdr = saved_hdr;
1340         current_saved_data = saved_saved_data;
1341         nest_level--;
1342 }
1343
1344 static void
1345 dissect_ipmi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1346 {
1347         proto_tree *ipmi_tree = NULL;
1348         proto_item *ti;
1349         ipmi_dissect_format_t dfmt;
1350
1351         col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPMI/ATCA");
1352
1353         current_pinfo = pinfo;
1354
1355         if (tree) {
1356                 ti = proto_tree_add_item(tree, proto_ipmi, tvb, 0, -1, FALSE);
1357                 ipmi_tree = proto_item_add_subtree(ti, ett_ipmi);
1358         }
1359
1360         memset(&dfmt, 0, sizeof(dfmt));
1361         dfmt.flags = IPMI_D_BROADCAST | IPMI_D_TRG_SA;
1362         ipmi_do_dissect(tvb, ipmi_tree, &dfmt);
1363
1364         col_add_str(pinfo->cinfo, COL_INFO, dfmt.info);
1365
1366 }
1367
1368 /* Register IPMB protocol.
1369  */
1370 void
1371 proto_reg_handoff_ipmi(void)
1372 {
1373 }
1374
1375 void
1376 proto_register_ipmi(void)
1377 {
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 }}
1397         };
1398         static gint *ett[] = {
1399                 &ett_ipmi,
1400                 &ett_header,
1401                 &ett_header_byte_1,
1402                 &ett_header_byte_4,
1403                 &ett_data,
1404                 &ett_typelen
1405         };
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 },
1411                 { NULL, NULL, 0 }
1412         };
1413         static const enum_val_t oemsel_vals[] = {
1414                 { "none", "None", IPMI_OEM_NONE },
1415                 { "pps", "Pigeon Point Systems", IPMI_OEM_PPS },
1416                 { NULL, NULL, 0 }
1417         };
1418         module_t *m;
1419         guint32 i;
1420
1421         proto_ipmi = proto_register_protocol("Intelligent Platform Management Interface",
1422                                 "IPMI/ATCA",
1423                                 "ipmi");
1424
1425         proto_register_field_array(proto_ipmi, hf, array_length(hf));
1426         proto_register_subtree_array(ett, array_length(ett));
1427
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);
1439         }
1440
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);
1450
1451         register_dissector("ipmi", dissect_ipmi, proto_ipmi);
1452
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);
1469 }