Coverage Report

Created: 2026-06-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-ipmi.c
Line
Count
Source
1
/* packet-ipmi.c
2
 * Routines for IPMI dissection
3
 * Copyright 2002-2008, Alexey Neyman, Pigeon Point Systems <avn@pigeonpoint.com>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
#include "config.h"
13
0
#define WS_LOG_DOMAIN "packet-ipmi"
14
#include <wireshark.h>
15
16
#include <epan/packet.h>
17
#include <epan/conversation.h>
18
#include <epan/prefs.h>
19
#include <epan/addr_resolv.h>
20
21
#include "packet-ipmi.h"
22
23
static dissector_handle_t ipmi_i2c_handle;
24
25
void proto_register_ipmi(void);
26
void proto_reg_handoff_ipmi(void);
27
28
/*
29
 * See the IPMI specifications at
30
 *
31
 *  http://www.intel.com/design/servers/ipmi/
32
 */
33
34
/* Top-level search structure: list of registered handlers for a given netFn */
35
struct ipmi_netfn_root {
36
  ipmi_netfn_t *list;
37
  const char *desc;
38
  uint32_t siglen;
39
};
40
41
enum {
42
  MSGFMT_NONE = 0,
43
  MSGFMT_IPMB,
44
  MSGFMT_LAN,
45
  MSGFMT_GUESS
46
};
47
48
struct ipmi_parse_typelen {
49
  void (*get_len)(unsigned *, unsigned *, tvbuff_t *, unsigned, unsigned, bool);
50
  void (*parse)(char *, tvbuff_t *, unsigned, unsigned);
51
  const char *desc;
52
};
53
54
/* IPMI parsing context */
55
typedef struct {
56
  ipmi_header_t hdr;
57
  unsigned      hdr_len;
58
  unsigned      flags;
59
  uint8_t     cks1;
60
  uint8_t     cks2;
61
} ipmi_context_t;
62
63
/* Temporary request-response matching data. */
64
typedef struct {
65
  /* Request header */
66
  ipmi_header_t hdr;
67
  /* Frame number where the request resides */
68
  uint32_t      frame_num;
69
  /* Nest level of the request in the frame */
70
  uint8_t     nest_level;
71
} ipmi_request_t;
72
73
/* List of request-response matching data */
74
typedef wmem_list_t ipmi_request_list_t;
75
76
0
#define NSAVED_DATA 2
77
78
/* Per-command data */
79
typedef struct {
80
  uint32_t    matched_frame_num;
81
  uint32_t    saved_data[NSAVED_DATA];
82
} ipmi_cmd_data_t;
83
84
/* Per-frame data */
85
typedef struct {
86
  ipmi_cmd_data_t * cmd_data[3];
87
  nstime_t      ts;
88
} ipmi_frame_data_t;
89
90
/* RB tree of frame data */
91
typedef wmem_tree_t ipmi_frame_tree_t;
92
93
/* cached dissector data */
94
typedef struct {
95
  /* tree of cached frame data */
96
  ipmi_frame_tree_t *   frame_tree;
97
  /* list of cached requests */
98
  ipmi_request_list_t * request_list;
99
  /* currently dissected frame number */
100
  uint32_t          curr_frame_num;
101
  /* currently dissected frame */
102
  ipmi_frame_data_t *   curr_frame;
103
  /* current nesting level */
104
  uint8_t         curr_level;
105
  /* subsequent nesting level */
106
  uint8_t         next_level;
107
  /* top level message channel */
108
  uint8_t         curr_channel;
109
  /* top level message direction */
110
  uint8_t         curr_dir;
111
  /* pointer to current command */
112
  const ipmi_header_t *   curr_hdr;
113
  /* current completion code */
114
  uint8_t         curr_ccode;
115
} ipmi_packet_data_t;
116
117
/* Maximum nest level where it worth caching data */
118
0
#define MAX_NEST_LEVEL  3
119
120
int proto_ipmi;
121
static int proto_ipmb;
122
static int proto_kcs;
123
static int proto_tmode;
124
125
/* WARNING: Setting this to true might result in the entire dissector being
126
   disabled by default or removed completely. */
127
static bool dissect_bus_commands;
128
static bool fru_langcode_is_english = true;
129
static unsigned response_after_req = 5000;
130
static unsigned response_before_req;
131
static int message_format = MSGFMT_GUESS;
132
static int selected_oem = IPMI_OEM_NONE;
133
134
static int hf_ipmi_command_data;
135
static int hf_ipmi_session_handle;
136
static int hf_ipmi_header_trg;
137
static int hf_ipmi_header_trg_lun;
138
static int hf_ipmi_header_netfn;
139
static int hf_ipmi_header_crc;
140
static int hf_ipmi_header_src;
141
static int hf_ipmi_header_src_lun;
142
static int hf_ipmi_header_bridged;
143
static int hf_ipmi_header_sequence;
144
static int hf_ipmi_header_command;
145
static int hf_ipmi_header_completion;
146
static int hf_ipmi_header_sig;
147
static int hf_ipmi_data_crc;
148
static int hf_ipmi_response_to;
149
static int hf_ipmi_response_in;
150
static int hf_ipmi_response_time;
151
152
static int ett_ipmi;
153
static int ett_header;
154
static int ett_header_byte_1;
155
static int ett_header_byte_4;
156
static int ett_data;
157
static int ett_typelen;
158
159
static expert_field ei_impi_parser_not_implemented;
160
161
static struct ipmi_netfn_root ipmi_cmd_tab[IPMI_NETFN_MAX];
162
163
static ipmi_packet_data_t *
164
get_packet_data(packet_info * pinfo)
165
0
{
166
0
  ipmi_packet_data_t * data;
167
168
  /* get conversation data */
169
0
  conversation_t * conv = find_or_create_conversation(pinfo);
170
171
  /* get protocol-specific data */
172
0
  data = (ipmi_packet_data_t *)
173
0
      conversation_get_proto_data(conv, proto_ipmi);
174
175
0
  if (!data) {
176
    /* allocate per-packet data */
177
0
    data = wmem_new0(wmem_file_scope(), ipmi_packet_data_t);
178
179
    /* allocate request list and frame tree */
180
0
    data->frame_tree = wmem_tree_new(wmem_file_scope());
181
0
    data->request_list = wmem_list_new(wmem_file_scope());
182
183
    /* add protocol data */
184
0
    conversation_add_proto_data(conv, proto_ipmi, data);
185
0
  }
186
187
  /* check if packet has changed */
188
0
  if (pinfo->num != data->curr_frame_num) {
189
0
    data->curr_level = 0;
190
0
    data->next_level = 0;
191
0
  }
192
193
0
  return data;
194
0
}
195
196
static ipmi_frame_data_t *
197
get_frame_data(ipmi_packet_data_t * data, uint32_t frame_num)
198
0
{
199
0
  ipmi_frame_data_t * frame = (ipmi_frame_data_t *)
200
0
      wmem_tree_lookup32(data->frame_tree, frame_num);
201
202
0
  if (frame == NULL) {
203
0
    frame = wmem_new0(wmem_file_scope(), ipmi_frame_data_t);
204
205
0
    wmem_tree_insert32(data->frame_tree, frame_num, frame);
206
0
  }
207
0
  return frame;
208
0
}
209
210
static ipmi_request_t *
211
get_matched_request(ipmi_packet_data_t * data, const ipmi_header_t * rs_hdr,
212
    unsigned flags)
213
0
{
214
0
  wmem_list_frame_t * iter = wmem_list_head(data->request_list);
215
0
  ipmi_header_t rq_hdr;
216
217
  /* reset message context */
218
0
  rq_hdr.context = 0;
219
220
  /* copy channel */
221
0
  rq_hdr.channel = data->curr_channel;
222
223
  /* toggle packet direction */
224
0
  rq_hdr.dir = rs_hdr->dir ^ 1;
225
226
0
  rq_hdr.session = rs_hdr->session;
227
228
  /* swap responder address/lun */
229
0
  rq_hdr.rs_sa = rs_hdr->rq_sa;
230
0
  rq_hdr.rs_lun = rs_hdr->rq_lun;
231
232
  /* remove reply flag */
233
0
  rq_hdr.netfn = rs_hdr->netfn & ~1;
234
235
  /* swap requester address/lun */
236
0
  rq_hdr.rq_sa = rs_hdr->rs_sa;
237
0
  rq_hdr.rq_lun = rs_hdr->rs_lun;
238
239
  /* copy sequence */
240
0
  rq_hdr.rq_seq = rs_hdr->rq_seq;
241
242
  /* copy command */
243
0
  rq_hdr.cmd = rs_hdr->cmd;
244
245
  /* TODO: copy prefix bytes */
246
247
0
  ws_debug("%d, %d: rq_hdr : {"
248
0
      "\tchannel=%d"
249
0
      "\tdir=%d"
250
0
      "\trs_sa=%x"
251
0
      "\trs_lun=%d"
252
0
      "\tnetfn=%x"
253
0
      "\trq_sa=%x"
254
0
      "\trq_lun=%d"
255
0
      "\trq_seq=%x"
256
0
      "\tcmd=%x }",
257
0
      data->curr_frame_num, data->curr_level,
258
0
      rq_hdr.channel, rq_hdr.dir, rq_hdr.rs_sa, rq_hdr.rs_lun,
259
0
      rq_hdr.netfn, rq_hdr.rq_sa, rq_hdr.rq_lun, rq_hdr.rq_seq,
260
0
      rq_hdr.cmd);
261
262
0
  while (iter) {
263
0
    ipmi_request_t * rq = (ipmi_request_t *) wmem_list_frame_data(iter);
264
265
    /* check if in Get Message context */
266
0
    if (rs_hdr->context == IPMI_E_GETMSG && !(flags & IPMI_D_TRG_SA)) {
267
      /* diregard rsSA */
268
0
      rq_hdr.rq_sa = rq->hdr.rq_sa;
269
0
    }
270
271
    /* compare command headers */
272
0
    if (!memcmp(&rq_hdr, &rq->hdr, sizeof(rq_hdr))) {
273
0
      return rq;
274
0
    }
275
276
    /* proceed to next request */
277
0
    iter = wmem_list_frame_next(iter);
278
0
  }
279
280
0
  return NULL;
281
0
}
282
283
static void
284
remove_old_requests(ipmi_packet_data_t * data, const nstime_t * curr_time)
285
0
{
286
0
  wmem_list_frame_t * iter = wmem_list_head(data->request_list);
287
288
0
  while (iter) {
289
0
    ipmi_request_t * rq = (ipmi_request_t *) wmem_list_frame_data(iter);
290
0
    ipmi_frame_data_t * frame = get_frame_data(data, rq->frame_num);
291
0
    nstime_t delta;
292
293
    /* calculate time delta */
294
0
    nstime_delta(&delta, curr_time, &frame->ts);
295
296
0
    if (nstime_to_msec(&delta) > response_after_req) {
297
0
      wmem_list_frame_t * del = iter;
298
299
      /* proceed to next request */
300
0
      iter = wmem_list_frame_next(iter);
301
302
      /* free request data */
303
0
      wmem_free(wmem_file_scope(), rq);
304
305
      /* remove list item */
306
0
      wmem_list_remove_frame(data->request_list, del);
307
0
    } else {
308
0
      break;
309
0
    }
310
0
  }
311
0
}
312
313
static void
314
match_request_response(ipmi_packet_data_t * data, const ipmi_header_t * hdr,
315
    unsigned flags)
316
0
{
317
  /* get current frame */
318
0
  ipmi_frame_data_t * rs_frame = data->curr_frame;
319
320
  /* get current command data */
321
0
  ipmi_cmd_data_t * rs_data = rs_frame->cmd_data[data->curr_level];
322
323
  /* check if parse response for the first time */
324
0
  if (!rs_data) {
325
0
    ipmi_request_t * rq;
326
327
    /* allocate command data */
328
0
    rs_data = wmem_new0(wmem_file_scope(), ipmi_cmd_data_t);
329
330
    /* search for matching request */
331
0
    rq = get_matched_request(data, hdr, flags);
332
333
    /* check if matching request is found */
334
0
    if (rq) {
335
      /* get request frame data */
336
0
      ipmi_frame_data_t * rq_frame =
337
0
          get_frame_data(data, rq->frame_num);
338
339
      /* get command data */
340
0
      ipmi_cmd_data_t * rq_data = rq_frame->cmd_data[rq->nest_level];
341
342
      /* save matched frame numbers */
343
0
      rq_data->matched_frame_num = data->curr_frame_num;
344
0
      rs_data->matched_frame_num = rq->frame_num;
345
346
      /* copy saved command data information */
347
0
      rs_data->saved_data[0] = rq_data->saved_data[0];
348
0
      rs_data->saved_data[1] = rq_data->saved_data[1];
349
350
      /* remove request from the list */
351
0
      wmem_list_remove(data->request_list, rq);
352
353
      /* delete request data */
354
0
      wmem_free(wmem_file_scope(), rq);
355
0
    }
356
357
    /* save command data pointer in frame */
358
0
    rs_frame->cmd_data[data->curr_level] = rs_data;
359
0
  }
360
0
}
361
362
static void
363
add_request(ipmi_packet_data_t * data, const ipmi_header_t * hdr)
364
0
{
365
  /* get current frame */
366
0
  ipmi_frame_data_t * rq_frame = data->curr_frame;
367
368
  /* get current command data */
369
0
  ipmi_cmd_data_t * rq_data = rq_frame->cmd_data[data->curr_level];
370
371
  /* check if parse response for the first time */
372
0
  if (!rq_data) {
373
0
    ipmi_request_t * rq;
374
375
    /* allocate command data */
376
0
    rq_data = wmem_new0(wmem_file_scope(), ipmi_cmd_data_t);
377
378
    /* set command data pointer */
379
0
    rq_frame->cmd_data[data->curr_level] = rq_data;
380
381
    /* allocate request data */
382
0
    rq = wmem_new0(wmem_file_scope(), ipmi_request_t);
383
384
    /* copy request header */
385
0
    memcpy(&rq->hdr, hdr, sizeof(rq->hdr));
386
387
    /* override context, channel and direction */
388
0
    rq->hdr.context = 0;
389
0
    rq->hdr.channel = data->curr_channel;
390
0
    rq->hdr.dir = data->curr_dir;
391
392
    /* set request frame number */
393
0
    rq->frame_num = data->curr_frame_num;
394
395
    /* set command nest level */
396
0
    rq->nest_level = data->curr_level;
397
398
    /* append request to list */
399
0
    wmem_list_append(data->request_list, rq);
400
401
0
  ws_debug("%d, %d: rq_hdr : {"
402
0
      "\tchannel=%d"
403
0
      "\tdir=%d"
404
0
      "\trs_sa=%x"
405
0
      "\trs_lun=%d"
406
0
      "\tnetfn=%x"
407
0
      "\trq_sa=%x"
408
0
      "\trq_lun=%d"
409
0
      "\trq_seq=%x"
410
0
      "\tcmd=%x }",
411
0
      data->curr_frame_num, data->curr_level,
412
0
      rq->hdr.channel, rq->hdr.dir, rq->hdr.rs_sa, rq->hdr.rs_lun,
413
0
      rq->hdr.netfn, rq->hdr.rq_sa, rq->hdr.rq_lun, rq->hdr.rq_seq,
414
0
      rq->hdr.cmd);
415
0
  }
416
0
}
417
418
static void
419
add_command_info(packet_info *pinfo, const ipmi_cmd_t * cmd,
420
    bool resp, uint8_t cc_val, const char * cc_str, bool broadcast)
421
0
{
422
0
  if (resp) {
423
0
    col_add_fstr(pinfo->cinfo, COL_INFO, "Rsp, %s, %s (%02xh)",
424
0
        cmd->desc, cc_str, cc_val);
425
0
  } else {
426
0
    col_add_fstr(pinfo->cinfo, COL_INFO, "Req, %s%s",
427
0
        broadcast ? "Broadcast " : "", cmd->desc);
428
0
  }
429
0
}
430
431
static int
432
dissect_ipmi_cmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
433
    int hf_parent_item, int ett_tree, const ipmi_context_t * ctx)
434
5
{
435
5
  ipmi_packet_data_t * data;
436
5
  ipmi_netfn_t * cmd_list;
437
5
  const ipmi_cmd_t * cmd;
438
5
  proto_item * ti;
439
5
  proto_tree * cmd_tree = NULL, * tmp_tree;
440
5
  uint8_t prev_level, cc_val;
441
5
  unsigned offset, siglen, is_resp;
442
5
  const char * cc_str, * netfn_str;
443
444
5
  if (!dissect_bus_commands) {
445
5
    ti = proto_tree_add_item(tree, hf_parent_item, tvb, 0, -1, ENC_NA);
446
5
    cmd_tree = proto_item_add_subtree(ti, ett_tree);
447
5
    proto_tree_add_item(cmd_tree, hf_ipmi_command_data, tvb, 0, -1, ENC_NA);
448
5
    return 0;
449
5
  }
450
451
  /* get packet data */
452
0
  data = get_packet_data(pinfo);
453
0
  if (!data) {
454
0
    return 0;
455
0
  }
456
457
  /* get prefix length */
458
0
  siglen = ipmi_getsiglen(ctx->hdr.netfn);
459
460
  /* get response flag */
461
0
  is_resp = ctx->hdr.netfn & 1;
462
463
  /* check message length */
464
0
  if (tvb_captured_length(tvb) < ctx->hdr_len + siglen + is_resp
465
0
      + !(ctx->flags & IPMI_D_NO_CKS)) {
466
    /* don bother with anything */
467
0
    return call_data_dissector(tvb, pinfo, tree);
468
0
  }
469
470
  /* save nest level */
471
0
  prev_level = data->curr_level;
472
473
  /* assign next nest level */
474
0
  data->curr_level = data->next_level;
475
476
  /* increment next nest level */
477
0
  data->next_level++;
478
479
  /* check for the first invocation */
480
0
  if (!data->curr_level) {
481
    /* get current frame data */
482
0
    data->curr_frame = get_frame_data(data, pinfo->num);
483
0
    data->curr_frame_num = pinfo->num;
484
485
    /* copy frame timestamp */
486
0
    memcpy(&data->curr_frame->ts, &pinfo->abs_ts, sizeof(nstime_t));
487
488
    /* cache channel and direction */
489
0
    data->curr_channel = ctx->hdr.channel;
490
0
    data->curr_dir = ctx->hdr.dir;
491
492
    /* remove requests which are too old */
493
0
    remove_old_requests(data, &pinfo->abs_ts);
494
0
  }
495
496
0
  if (data->curr_level < MAX_NEST_LEVEL) {
497
0
    if (ctx->hdr.netfn & 1) {
498
      /* perform request/response matching */
499
0
      match_request_response(data, &ctx->hdr, ctx->flags);
500
0
    } else {
501
      /* add request to the list for later matching */
502
0
      add_request(data, &ctx->hdr);
503
0
    }
504
0
  }
505
506
  /* get command list by network function code */
507
0
  cmd_list = ipmi_getnetfn(ctx->hdr.netfn,
508
0
      tvb_get_ptr(tvb, ctx->hdr_len + is_resp, siglen));
509
510
  /* get command descriptor */
511
0
  cmd = ipmi_getcmd(cmd_list, ctx->hdr.cmd);
512
513
  /* check if response */
514
0
  if (is_resp) {
515
    /* get completion code */
516
0
    cc_val = tvb_get_uint8(tvb, ctx->hdr_len);
517
518
    /* get completion code desc */
519
0
    cc_str = ipmi_get_completion_code(cc_val, cmd);
520
0
  } else {
521
0
    cc_val = 0;
522
0
    cc_str = NULL;
523
0
  }
524
525
  /* check if not inside a message */
526
0
  if (!data->curr_level) {
527
    /* add packet info */
528
0
    add_command_info(pinfo, cmd, is_resp, cc_val, cc_str,
529
0
        ctx->flags & IPMI_D_BROADCAST ? true : false);
530
0
  }
531
532
0
  if (tree) {
533
    /* add parent node */
534
0
    if (!data->curr_level) {
535
0
      ti = proto_tree_add_item(tree, hf_parent_item, tvb, 0, -1, ENC_NA);
536
0
      cmd_tree = proto_item_add_subtree(ti, ett_tree);
537
0
    } else {
538
0
      char str[ITEM_LABEL_LENGTH];
539
540
0
      if (is_resp) {
541
0
        snprintf(str, ITEM_LABEL_LENGTH, "Rsp, %s, %s",
542
0
            cmd->desc, cc_str);
543
0
      } else {
544
0
        snprintf(str, ITEM_LABEL_LENGTH, "Req, %s", cmd->desc);
545
0
      }
546
0
      if (proto_registrar_get_ftype(hf_parent_item) == FT_STRING) {
547
0
        ti = proto_tree_add_string(tree, hf_parent_item, tvb, 0, -1, str);
548
0
        cmd_tree = proto_item_add_subtree(ti, ett_tree);
549
0
      }
550
0
      else
551
0
        cmd_tree = proto_tree_add_subtree(tree, tvb, 0, -1, ett_tree, NULL, str);
552
0
    }
553
554
0
    if (data->curr_level < MAX_NEST_LEVEL) {
555
      /* check if response */
556
0
      if (ctx->hdr.netfn & 1) {
557
        /* get current command data */
558
0
        ipmi_cmd_data_t * rs_data =
559
0
            data->curr_frame->cmd_data[data->curr_level];
560
561
0
        if (rs_data->matched_frame_num) {
562
0
          nstime_t ns;
563
564
          /* add "Request to:" field */
565
0
          ti = proto_tree_add_uint(cmd_tree, hf_ipmi_response_to,
566
0
              tvb, 0, 0, rs_data->matched_frame_num);
567
568
          /* mark field as a generated one */
569
0
          proto_item_set_generated(ti);
570
571
          /* calculate delta time */
572
0
          nstime_delta(&ns, &pinfo->abs_ts,
573
0
              &get_frame_data(data,
574
0
                  rs_data->matched_frame_num)->ts);
575
576
          /* add "Response time" field */
577
0
          ti = proto_tree_add_time(cmd_tree, hf_ipmi_response_time,
578
0
              tvb, 0, 0, &ns);
579
580
          /* mark field as a generated one */
581
0
          proto_item_set_generated(ti);
582
0
          }
583
0
      } else {
584
        /* get current command data */
585
0
        ipmi_cmd_data_t * rq_data =
586
0
            data->curr_frame->cmd_data[data->curr_level];
587
588
0
        if (rq_data->matched_frame_num) {
589
          /* add "Response in:" field  */
590
0
          ti = proto_tree_add_uint(cmd_tree, hf_ipmi_response_in,
591
0
              tvb, 0, 0, rq_data->matched_frame_num);
592
593
          /* mark field as a generated one */
594
0
          proto_item_set_generated(ti);
595
0
        }
596
0
      }
597
0
    }
598
599
    /* set starting offset */
600
0
    offset = 0;
601
602
    /* check if message is broadcast */
603
0
    if (ctx->flags & IPMI_D_BROADCAST) {
604
      /* skip first byte */
605
0
      offset++;
606
0
    }
607
608
    /* check if session handle is specified */
609
0
    if (ctx->flags & IPMI_D_SESSION_HANDLE) {
610
      /* add session handle field */
611
0
      proto_tree_add_item(cmd_tree, hf_ipmi_session_handle,
612
0
          tvb, offset++, 1, ENC_LITTLE_ENDIAN);
613
0
    }
614
615
    /* check if responder address is specified */
616
0
    if (ctx->flags & IPMI_D_TRG_SA) {
617
      /* add response address field */
618
0
      proto_tree_add_item(cmd_tree, hf_ipmi_header_trg, tvb,
619
0
          offset++, 1, ENC_LITTLE_ENDIAN);
620
0
    }
621
622
    /* get NetFn string */
623
0
    netfn_str = ipmi_getnetfnname(pinfo->pool, ctx->hdr.netfn, cmd_list);
624
625
    /* Network function + target LUN */
626
0
    tmp_tree = proto_tree_add_subtree_format(cmd_tree, tvb, offset, 1,
627
0
        ett_header_byte_1, NULL, "Target LUN: 0x%02x, NetFN: %s %s (0x%02x)",
628
0
        ctx->hdr.rs_lun, netfn_str,
629
0
        is_resp ? "Response" : "Request", ctx->hdr.netfn);
630
631
    /* add Net Fn */
632
0
    proto_tree_add_uint_format(tmp_tree, hf_ipmi_header_netfn, tvb,
633
0
        offset, 1, ctx->hdr.netfn << 2,
634
0
        "NetFn: %s %s (0x%02x)", netfn_str,
635
0
        is_resp ? "Response" : "Request", ctx->hdr.netfn);
636
637
0
    proto_tree_add_item(tmp_tree, hf_ipmi_header_trg_lun, tvb,
638
0
        offset++, 1, ENC_LITTLE_ENDIAN);
639
640
    /* check if cks1 is specified */
641
0
    if (!(ctx->flags & IPMI_D_NO_CKS)) {
642
0
      uint8_t cks = tvb_get_uint8(tvb, offset);
643
644
      /* Header checksum */
645
0
      if (ctx->cks1) {
646
0
        uint8_t correct = cks - ctx->cks1;
647
648
0
        proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_header_crc,
649
0
            tvb, offset++, 1, cks,
650
0
            "0x%02x (incorrect, expected 0x%02x)", cks, correct);
651
0
      } else {
652
0
        proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_header_crc,
653
0
            tvb, offset++, 1, cks,
654
0
            "0x%02x (correct)", cks);
655
0
      }
656
0
    }
657
658
    /* check if request address is specified */
659
0
    if (!(ctx->flags & IPMI_D_NO_RQ_SA)) {
660
      /* add request address field */
661
0
      proto_tree_add_item(cmd_tree, hf_ipmi_header_src, tvb,
662
0
          offset++, 1, ENC_LITTLE_ENDIAN);
663
0
    }
664
665
    /* check if request sequence is specified */
666
0
    if (!(ctx->flags & IPMI_D_NO_SEQ)) {
667
      /* Sequence number + source LUN */
668
0
      tmp_tree = proto_tree_add_subtree_format(cmd_tree, tvb, offset, 1,
669
0
          ett_header_byte_4, NULL, "%s: 0x%02x, SeqNo: 0x%02x",
670
0
          (ctx->flags & IPMI_D_TMODE) ? "Bridged" : "Source LUN",
671
0
              ctx->hdr.rq_lun, ctx->hdr.rq_seq);
672
673
0
      if (ctx->flags & IPMI_D_TMODE) {
674
0
        proto_tree_add_item(tmp_tree, hf_ipmi_header_bridged,
675
0
            tvb, offset, 1, ENC_LITTLE_ENDIAN);
676
0
      } else {
677
0
        proto_tree_add_item(tmp_tree, hf_ipmi_header_src_lun,
678
0
            tvb, offset, 1, ENC_LITTLE_ENDIAN);
679
0
      }
680
681
      /* print seq no */
682
0
      proto_tree_add_item(tmp_tree, hf_ipmi_header_sequence, tvb,
683
0
          offset++, 1, ENC_LITTLE_ENDIAN);
684
0
    }
685
686
    /* command code */
687
0
    proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_header_command,
688
0
        tvb, offset++, 1, ctx->hdr.cmd, "%s (0x%02x)",
689
0
        cmd->desc, ctx->hdr.cmd);
690
691
0
    if (is_resp) {
692
      /* completion code */
693
0
      proto_tree_add_uint_format_value(cmd_tree,
694
0
          hf_ipmi_header_completion, tvb, offset++, 1,
695
0
          cc_val, "%s (0x%02x)", cc_str, cc_val);
696
0
    }
697
698
0
    if (siglen) {
699
      /* command prefix (if present) */
700
0
      ti = proto_tree_add_item(cmd_tree, hf_ipmi_header_sig, tvb,
701
0
          offset, siglen, ENC_NA);
702
0
      proto_item_append_text(ti, " (%s)", netfn_str);
703
0
    }
704
0
  }
705
706
0
  if (tree || (cmd->flags & CMD_CALLRQ)) {
707
    /* calculate message data length */
708
0
    unsigned data_len = tvb_captured_length(tvb)
709
0
        - ctx->hdr_len
710
0
        - siglen
711
0
        - (is_resp ? 1 : 0)
712
0
        - !(ctx->flags & IPMI_D_NO_CKS);
713
714
    /* create data subset */
715
0
    tvbuff_t * data_tvb = tvb_new_subset_length(tvb,
716
0
        ctx->hdr_len + siglen + (is_resp ? 1 : 0), data_len);
717
718
    /* Select sub-handler */
719
0
    ipmi_cmd_handler_t hnd = is_resp ? cmd->parse_resp : cmd->parse_req;
720
721
0
    if (hnd && tvb_captured_length(data_tvb)) {
722
      /* create data field */
723
0
      tmp_tree = proto_tree_add_subtree(cmd_tree, data_tvb, 0, -1, ett_data, NULL, "Data");
724
725
      /* save current command */
726
0
      data->curr_hdr = &ctx->hdr;
727
728
      /* save current completion code */
729
0
      data->curr_ccode = cc_val;
730
731
      /* call command parser */
732
0
      hnd(data_tvb, pinfo, tmp_tree);
733
0
    }
734
0
  }
735
736
  /* check if cks2 is specified */
737
0
  if (tree && !(ctx->flags & IPMI_D_NO_CKS)) {
738
0
    uint8_t cks;
739
740
    /* get cks2 offset */
741
0
    offset = tvb_captured_length(tvb) - 1;
742
743
    /* get cks2 */
744
0
    cks = tvb_get_uint8(tvb, offset);
745
746
    /* Header checksum */
747
0
    if (ctx->cks2) {
748
0
      uint8_t correct = cks - ctx->cks2;
749
750
0
      proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_data_crc,
751
0
          tvb, offset, 1, cks,
752
0
          "0x%02x (incorrect, expected 0x%02x)", cks, correct);
753
0
    } else {
754
0
      proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_data_crc,
755
0
          tvb, offset, 1, cks,
756
0
          "0x%02x (correct)", cks);
757
0
    }
758
0
  }
759
760
  /* decrement next nest level */
761
0
  data->next_level = data->curr_level;
762
763
  /* restore previous nest level */
764
0
  data->curr_level = prev_level;
765
766
0
  return tvb_captured_length(tvb);
767
0
}
768
769
/* Get currently parsed message header */
770
const ipmi_header_t * ipmi_get_hdr(packet_info * pinfo)
771
0
{
772
0
  ipmi_packet_data_t * data = get_packet_data(pinfo);
773
0
  return data->curr_hdr;
774
0
}
775
776
/* Get completion code for currently parsed message */
777
uint8_t ipmi_get_ccode(packet_info * pinfo)
778
0
{
779
0
  ipmi_packet_data_t * data = get_packet_data(pinfo);
780
0
  return data->curr_ccode;
781
0
}
782
783
/* Save request data for later use in response */
784
void ipmi_set_data(packet_info *pinfo, unsigned idx, uint32_t value)
785
0
{
786
0
  ipmi_packet_data_t * data = get_packet_data(pinfo);
787
788
  /* check bounds */
789
0
  if (data->curr_level >= MAX_NEST_LEVEL || idx >= NSAVED_DATA || !data->curr_frame ) {
790
0
    return;
791
0
  }
792
793
  /* save data */
794
0
  data->curr_frame->cmd_data[data->curr_level]->saved_data[idx] = value;
795
0
}
796
797
/* Get saved request data */
798
bool ipmi_get_data(packet_info *pinfo, unsigned idx, uint32_t * value)
799
0
{
800
0
  ipmi_packet_data_t * data = get_packet_data(pinfo);
801
802
  /* check bounds */
803
0
  if (data->curr_level >= MAX_NEST_LEVEL || idx >= NSAVED_DATA || !data->curr_frame ) {
804
0
    return false;
805
0
  }
806
807
  /* get data */
808
0
  *value = data->curr_frame->cmd_data[data->curr_level]->saved_data[idx];
809
0
  return true;
810
0
}
811
812
/* ----------------------------------------------------------------
813
   Support for Type/Length fields parsing.
814
---------------------------------------------------------------- */
815
816
static void
817
get_len_binary(unsigned *clen, unsigned *blen, tvbuff_t *tvb _U_, unsigned offs _U_,
818
    unsigned len, bool len_is_bytes _U_)
819
0
{
820
0
  *clen = len * 3;
821
0
  *blen = len;
822
0
}
823
824
static void
825
parse_binary(char *p, tvbuff_t *tvb, unsigned offs, unsigned len)
826
0
{
827
0
  static const char hex[] = "0123456789ABCDEF";
828
0
  uint8_t v;
829
0
  unsigned i;
830
831
0
  for (i = 0; i < len / 3; i++) {
832
0
    v = tvb_get_uint8(tvb, offs + i);
833
0
    *p++ = hex[v >> 4];
834
0
    *p++ = hex[v & 0xf];
835
0
    *p++ = ' ';
836
0
  }
837
838
0
  if (i) {
839
0
    *--p = '\0';
840
0
  }
841
0
}
842
843
static const struct ipmi_parse_typelen ptl_binary = {
844
  get_len_binary, parse_binary, "Binary"
845
};
846
847
static void
848
get_len_bcdplus(unsigned *clen, unsigned *blen, tvbuff_t *tvb _U_, unsigned offs _U_,
849
    unsigned len, bool len_is_bytes)
850
0
{
851
0
  if (len_is_bytes) {
852
0
    *clen = len * 2;
853
0
    *blen = len;
854
0
  } else {
855
0
    *blen = (len + 1) / 2;
856
0
    *clen = len;
857
0
  }
858
0
}
859
860
static void
861
parse_bcdplus(char *p, tvbuff_t *tvb, unsigned offs, unsigned len)
862
0
{
863
0
  static const char bcd[] = "0123456789 -.:,_";
864
0
  unsigned i, msk = 0xf0, shft = 4;
865
0
  uint8_t v;
866
867
0
  for (i = 0; i < len; i++) {
868
0
    v = (tvb_get_uint8(tvb, offs + i / 2) & msk) >> shft;
869
0
    *p++ = bcd[v];
870
0
    msk ^= 0xff;
871
0
    shft = 4 - shft;
872
0
  }
873
0
}
874
875
static const struct ipmi_parse_typelen ptl_bcdplus = {
876
  get_len_bcdplus, parse_bcdplus, "BCD+"
877
};
878
879
static void
880
get_len_6bit_ascii(unsigned *clen, unsigned *blen, tvbuff_t *tvb _U_, unsigned offs _U_,
881
    unsigned len, bool len_is_bytes)
882
0
{
883
0
  if (len_is_bytes) {
884
0
    *clen = len * 4 / 3;
885
0
    *blen = len;
886
0
  } else {
887
0
    *blen = (len * 3 + 3) / 4;
888
0
    *clen = len;
889
0
  }
890
0
}
891
892
static void
893
parse_6bit_ascii(char *p, tvbuff_t *tvb, unsigned offs, unsigned len)
894
0
{
895
0
  uint32_t v;
896
0
  unsigned i;
897
898
  /* First, handle "full" triplets of bytes, 4 characters each */
899
0
  for (i = 0; i < len / 4; i++) {
900
0
    v = tvb_get_letoh24(tvb, offs + i * 3);
901
0
    p[0] = ' ' + (v & 0x3f);
902
0
    p[1] = ' ' + ((v >> 6) & 0x3f);
903
0
    p[2] = ' ' + ((v >> 12) & 0x3f);
904
0
    p[3] = ' ' + ((v >> 18) & 0x3f);
905
0
    p += 4;
906
0
  }
907
908
  /* Do we have any characters left? */
909
0
  offs += len / 4;
910
0
  len &= 0x3;
911
0
  switch (len) {
912
0
  case 3:
913
0
    v = (tvb_get_uint8(tvb, offs + 2) << 4) | (tvb_get_uint8(tvb, offs + 1) >> 4);
914
0
    p[2] = ' ' + (v & 0x3f);
915
    /* Fall thru */
916
0
  case 2:
917
0
    v = (tvb_get_uint8(tvb, offs + 1) << 2) | (tvb_get_uint8(tvb, offs) >> 6);
918
0
    p[1] = ' ' + (v & 0x3f);
919
    /* Fall thru */
920
0
  case 1:
921
0
    v = tvb_get_uint8(tvb, offs) & 0x3f;
922
0
    p[0] = ' ' + (v & 0x3f);
923
0
  }
924
0
}
925
926
static const struct ipmi_parse_typelen ptl_6bit_ascii = {
927
  get_len_6bit_ascii, parse_6bit_ascii, "6-bit ASCII"
928
};
929
930
static void
931
get_len_8bit_ascii(unsigned *clen, unsigned *blen, tvbuff_t *tvb, unsigned offs,
932
    unsigned len, bool len_is_bytes _U_)
933
0
{
934
0
  unsigned i;
935
0
  uint8_t ch;
936
937
0
  *blen = len;  /* One byte is one character */
938
0
  *clen = 0;
939
0
  for (i = 0; i < len; i++) {
940
0
    ch = tvb_get_uint8(tvb, offs + i);
941
0
    *clen += (ch >= 0x20 && ch <= 0x7f) ? 1 : 4;
942
0
  }
943
0
}
944
945
static void
946
parse_8bit_ascii(char *p, tvbuff_t *tvb, unsigned offs, unsigned len)
947
0
{
948
0
  uint8_t ch;
949
0
  char *pmax;
950
951
0
  pmax = p + len;
952
0
  while (p < pmax) {
953
0
    ch = tvb_get_uint8(tvb, offs++);
954
0
    if (ch >= 0x20 && ch <= 0x7f) {
955
0
      *p++ = ch;
956
0
    } else {
957
0
      snprintf(p, 5, "\\x%02x", ch);
958
0
      p += 4;
959
0
    }
960
0
  }
961
0
}
962
963
static const struct ipmi_parse_typelen ptl_8bit_ascii = {
964
  get_len_8bit_ascii, parse_8bit_ascii, "ASCII+Latin1"
965
};
966
967
static void
968
get_len_unicode(unsigned *clen, unsigned *blen, tvbuff_t *tvb _U_, unsigned offs _U_,
969
    unsigned len _U_, bool len_is_bytes)
970
0
{
971
0
  if (len_is_bytes) {
972
0
    *clen = len * 3; /* Each 2 bytes result in 6 chars printed: \Uxxxx */
973
0
    *blen = len;
974
0
  } else {
975
0
    *clen = len * 6;
976
0
    *blen = len * 2;
977
0
  }
978
0
}
979
980
static void
981
parse_unicode(char *p, tvbuff_t *tvb, unsigned offs, unsigned len)
982
0
{
983
0
  char *pmax = p + len;
984
0
  uint8_t ch0, ch1;
985
986
0
  while (p < pmax) {
987
0
    ch0 = tvb_get_uint8(tvb, offs++);
988
0
    ch1 = tvb_get_uint8(tvb, offs++);
989
0
    snprintf(p, 7, "\\U%02x%02x", ch0, ch1);
990
0
    p += 6;
991
0
  }
992
0
}
993
994
static const struct ipmi_parse_typelen ptl_unicode = {
995
  get_len_unicode, parse_unicode, "Unicode"
996
};
997
998
void
999
ipmi_add_typelen(packet_info *pinfo, proto_tree *tree, int hf_string, int hf_type, int hf_length, tvbuff_t *tvb,
1000
    unsigned offs, bool is_fru)
1001
0
{
1002
0
  static const struct ipmi_parse_typelen * const fru_eng[4] = {
1003
0
    &ptl_binary, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_8bit_ascii
1004
0
  };
1005
0
  static const struct ipmi_parse_typelen * const fru_noneng[4] = {
1006
0
    &ptl_binary, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_unicode
1007
0
  };
1008
0
  static const struct ipmi_parse_typelen * const ipmi[4] = {
1009
0
    &ptl_unicode, &ptl_bcdplus, &ptl_6bit_ascii, &ptl_8bit_ascii
1010
0
  };
1011
0
  const struct ipmi_parse_typelen *ptr;
1012
0
  proto_tree *s_tree;
1013
0
  unsigned type, msk, clen, blen, len;
1014
0
  const char *unit;
1015
0
  char *str;
1016
0
  uint8_t typelen;
1017
1018
0
  typelen = tvb_get_uint8(tvb, offs);
1019
0
  type = typelen >> 6;
1020
0
  if (is_fru) {
1021
0
    msk = 0x3f;
1022
0
    ptr = (fru_langcode_is_english ? fru_eng : fru_noneng)[type];
1023
0
    unit = "bytes";
1024
0
  } else {
1025
0
    msk = 0x1f;
1026
0
    ptr = ipmi[type];
1027
0
    unit = "characters";
1028
0
  }
1029
1030
0
  len = typelen & msk;
1031
0
  ptr->get_len(&clen, &blen, tvb, offs + 1, len, is_fru);
1032
1033
0
  str = (char *)wmem_alloc(pinfo->pool, clen + 1);
1034
0
  ptr->parse(str, tvb, offs + 1, clen);
1035
0
  str[clen] = '\0';
1036
1037
0
  s_tree = proto_tree_add_subtree_format(tree, tvb, offs, 1, ett_typelen, NULL,
1038
0
      "%s Type/Length byte: %s, %d %s", (proto_registrar_get_nth(hf_string))->name, ptr->desc, len, unit);
1039
0
  proto_tree_add_uint_format_value(s_tree, hf_type, tvb, offs, 1, type, "%s (0x%02x)",
1040
0
      ptr->desc, type);
1041
0
  proto_tree_add_uint_format_value(s_tree, hf_length, tvb, offs, 1, len, "%d %s",
1042
0
      len, unit);
1043
1044
0
  proto_tree_add_string_format_value(tree, hf_string, tvb, offs + 1, blen, str,
1045
0
      "[%s] '%s'", ptr->desc, str);
1046
0
}
1047
1048
/* ----------------------------------------------------------------
1049
   Timestamp, IPMI-style.
1050
---------------------------------------------------------------- */
1051
void
1052
ipmi_add_timestamp(packet_info *pinfo, proto_tree *tree, int hf, tvbuff_t *tvb, unsigned offset)
1053
0
{
1054
0
  uint32_t ts = tvb_get_letohl(tvb, offset);
1055
1056
0
  if (ts == 0xffffffff) {
1057
0
    proto_tree_add_uint_format_value(tree, hf, tvb, offset, 4,
1058
0
        ts, "Unspecified/Invalid");
1059
0
  } else if (ts <= 0x20000000) {
1060
0
    proto_tree_add_uint_format_value(tree, hf, tvb, offset, 4,
1061
0
        ts, "%s since SEL device's initialization",
1062
0
        unsigned_time_secs_to_str(pinfo->pool, ts));
1063
0
  } else {
1064
0
    proto_tree_add_uint_format_value(tree, hf, tvb, offset, 4,
1065
0
        ts, "%s", abs_time_secs_to_str(pinfo->pool, ts, ABSOLUTE_TIME_UTC, true));
1066
0
  }
1067
0
}
1068
1069
/* ----------------------------------------------------------------
1070
   GUID, IPMI-style.
1071
---------------------------------------------------------------- */
1072
1073
void
1074
ipmi_add_guid(proto_tree *tree, int hf, tvbuff_t *tvb, unsigned offset)
1075
0
{
1076
0
  e_guid_t guid;
1077
0
  int i;
1078
1079
0
  guid.data1 = tvb_get_letohl(tvb, offset + 12);
1080
0
  guid.data2 = tvb_get_letohs(tvb, offset + 10);
1081
0
  guid.data3 = tvb_get_letohs(tvb, offset + 8);
1082
0
  for (i = 0; i < 8; i++) {
1083
0
    guid.data4[i] = tvb_get_uint8(tvb, offset + 7 - i);
1084
0
  }
1085
0
  proto_tree_add_guid(tree, hf, tvb, offset, 16, &guid);
1086
0
}
1087
1088
/* ----------------------------------------------------------------
1089
   Routines for registering/looking up command parsers.
1090
---------------------------------------------------------------- */
1091
1092
static void
1093
ipmi_netfn_setdesc(uint32_t netfn, const char *desc, uint32_t siglen)
1094
238
{
1095
238
  struct ipmi_netfn_root *inr;
1096
1097
238
  inr = &ipmi_cmd_tab[netfn >> 1];
1098
238
  inr->desc = desc;
1099
238
  inr->siglen = siglen;
1100
238
}
1101
1102
void
1103
ipmi_register_netfn_cmdtab(uint32_t netfn, unsigned oem_selector,
1104
    const uint8_t *sig, uint32_t siglen, const char *desc,
1105
    const ipmi_cmd_t *cmdtab, uint32_t cmdtablen)
1106
154
{
1107
154
  struct ipmi_netfn_root *inr;
1108
154
  ipmi_netfn_t *inh;
1109
1110
154
  netfn >>= 1;  /* Requests and responses grouped together */
1111
154
  if (netfn >= IPMI_NETFN_MAX) {
1112
0
    return;
1113
0
  }
1114
1115
154
  inr = &ipmi_cmd_tab[netfn];
1116
154
  if (inr->siglen != siglen) {
1117
0
    return;
1118
0
  }
1119
1120
154
  inh = wmem_new(wmem_epan_scope(), struct ipmi_netfn_handler);
1121
154
  inh->desc = desc;
1122
154
  inh->oem_selector = oem_selector;
1123
154
  inh->sig = sig;
1124
154
  inh->cmdtab = cmdtab;
1125
154
  inh->cmdtablen = cmdtablen;
1126
1127
154
  inh->next = inr->list;
1128
154
  inr->list = inh;
1129
154
}
1130
1131
uint32_t
1132
ipmi_getsiglen(uint32_t netfn)
1133
0
{
1134
0
  return ipmi_cmd_tab[netfn >> 1].siglen;
1135
0
}
1136
1137
const char *
1138
ipmi_getnetfnname(wmem_allocator_t *pool, uint32_t netfn, ipmi_netfn_t *nf)
1139
0
{
1140
0
  const char *dn, *db;
1141
1142
0
  dn = ipmi_cmd_tab[netfn >> 1].desc ?
1143
0
    ipmi_cmd_tab[netfn >> 1].desc : "Reserved";
1144
0
  db = nf ? nf->desc : NULL;
1145
0
  if (db) {
1146
0
    return wmem_strdup_printf(pool, "%s (%s)", db, dn);
1147
0
  } else {
1148
0
    return dn;
1149
0
  }
1150
0
}
1151
1152
ipmi_netfn_t *
1153
ipmi_getnetfn(uint32_t netfn, const uint8_t *sig)
1154
0
{
1155
0
  struct ipmi_netfn_root *inr;
1156
0
  ipmi_netfn_t *inh;
1157
1158
0
  inr = &ipmi_cmd_tab[netfn >> 1];
1159
0
  for (inh = inr->list; inh; inh = inh->next) {
1160
0
    if ((inh->oem_selector == (unsigned)selected_oem || inh->oem_selector == IPMI_OEM_NONE)
1161
0
        && (!inr->siglen || !memcmp(sig, inh->sig, inr->siglen))) {
1162
0
      return inh;
1163
0
    }
1164
0
  }
1165
1166
  /* Either unknown netFn or signature does not match */
1167
0
  return NULL;
1168
0
}
1169
1170
const ipmi_cmd_t *
1171
ipmi_getcmd(ipmi_netfn_t *nf, uint32_t cmd)
1172
0
{
1173
0
  static const ipmi_cmd_t ipmi_cmd_unknown = {
1174
0
    0x00,   /* Code */
1175
0
    ipmi_notimpl, /* request */
1176
0
    ipmi_notimpl, /* response */
1177
0
    NULL,   /* command codes */
1178
0
    NULL,   /* subfunctions */
1179
0
    "Unknown command",
1180
0
    0   /* flag */
1181
0
  };
1182
0
  const ipmi_cmd_t *ic;
1183
0
  size_t i, len;
1184
1185
0
  if (nf) {
1186
0
    len = nf->cmdtablen;
1187
0
    for (ic = nf->cmdtab, i = 0; i < len; i++, ic++) {
1188
0
      if (ic->cmd == cmd) {
1189
0
        return ic;
1190
0
      }
1191
0
    }
1192
0
  }
1193
1194
0
  return &ipmi_cmd_unknown;
1195
0
}
1196
1197
/* ----------------------------------------------------------------
1198
   Various utility functions.
1199
---------------------------------------------------------------- */
1200
1201
void
1202
ipmi_notimpl(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1203
0
{
1204
0
  proto_tree_add_expert_remaining(tree, pinfo, &ei_impi_parser_not_implemented, tvb, 0);
1205
0
}
1206
1207
void
1208
ipmi_fmt_10ms_1based(char *s, uint32_t v)
1209
0
{
1210
0
  snprintf(s, ITEM_LABEL_LENGTH, "%d.%03d seconds", v / 100, (v % 100) * 10);
1211
0
}
1212
1213
void
1214
ipmi_fmt_500ms_0based(char *s, uint32_t v)
1215
0
{
1216
0
  ipmi_fmt_500ms_1based(s, ++v);
1217
0
}
1218
1219
void
1220
ipmi_fmt_500ms_1based(char *s, uint32_t v)
1221
0
{
1222
0
  snprintf(s, ITEM_LABEL_LENGTH, "%d.%03d seconds", v / 2, (v % 2) * 500);
1223
0
}
1224
1225
void
1226
ipmi_fmt_1s_0based(char *s, uint32_t v)
1227
0
{
1228
0
  ipmi_fmt_1s_1based(s, ++v);
1229
0
}
1230
1231
void
1232
ipmi_fmt_1s_1based(char *s, uint32_t v)
1233
0
{
1234
0
  snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", v);
1235
0
}
1236
1237
void
1238
ipmi_fmt_2s_0based(char *s, uint32_t v)
1239
0
{
1240
0
  snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", (v + 1) * 2);
1241
0
}
1242
1243
void
1244
ipmi_fmt_5s_1based(char *s, uint32_t v)
1245
0
{
1246
0
  snprintf(s, ITEM_LABEL_LENGTH, "%d seconds", v * 5);
1247
0
}
1248
1249
void
1250
ipmi_fmt_version(char *s, uint32_t v)
1251
0
{
1252
0
  snprintf(s, ITEM_LABEL_LENGTH, "%d.%d", v & 0x0f, (v >> 4) & 0x0f);
1253
0
}
1254
1255
void
1256
ipmi_fmt_channel(char *s, uint32_t v)
1257
0
{
1258
0
  static const value_string chan_vals[] = {
1259
0
    { 0x00, "Primary IPMB (IPMB-0)" },
1260
0
    { 0x07, "IPMB-L" },
1261
0
    { 0x0e, "Current channel" },
1262
0
    { 0x0f, "System Interface" },
1263
0
    { 0, NULL }
1264
0
  };
1265
0
  char* tmp_str;
1266
1267
0
  tmp_str = val_to_str(NULL, v, chan_vals, "Channel #%d");
1268
0
  snprintf(s, ITEM_LABEL_LENGTH, "%s (0x%02x)", tmp_str, v);
1269
0
  wmem_free(NULL, tmp_str);
1270
0
}
1271
1272
void
1273
ipmi_fmt_udpport(char *s, uint32_t v)
1274
0
{
1275
0
  char* port_str = udp_port_to_display(NULL, v);
1276
0
  snprintf(s, ITEM_LABEL_LENGTH, "%s (%d)", port_str, v);
1277
0
  wmem_free(NULL, port_str);
1278
0
}
1279
1280
void
1281
ipmi_fmt_percent(char *s, uint32_t v)
1282
0
{
1283
0
  snprintf(s, ITEM_LABEL_LENGTH, "%d%%", v);
1284
0
}
1285
1286
const char *
1287
ipmi_get_completion_code(uint8_t completion, const ipmi_cmd_t *cmd)
1288
0
{
1289
0
  static const value_string std_completion_codes[] = {
1290
0
    { 0x00, "Command Completed Normally" },
1291
0
    { 0xc0, "Node Busy" },
1292
0
    { 0xc1, "Invalid Command" },
1293
0
    { 0xc2, "Command invalid for given LUN" },
1294
0
    { 0xc3, "Timeout while processing command, response unavailable" },
1295
0
    { 0xc4, "Out of space" },
1296
0
    { 0xc5, "Reservation Canceled or Invalid Reservation ID" },
1297
0
    { 0xc6, "Request data truncated" },
1298
0
    { 0xc7, "Request data length invalid" },
1299
0
    { 0xc8, "Request data field length limit exceeded" },
1300
0
    { 0xc9, "Parameter out of range" },
1301
0
    { 0xca, "Cannot return number of requested data bytes" },
1302
0
    { 0xcb, "Requested Sensor, data, or record not present" },
1303
0
    { 0xcc, "Invalid data field in Request" },
1304
0
    { 0xcd, "Command illegal for specified sensor or record type" },
1305
0
    { 0xce, "Command response could not be provided" },
1306
0
    { 0xcf, "Cannot execute duplicated request" },
1307
0
    { 0xd0, "Command response could not be provided: SDR Repository in update mode" },
1308
0
    { 0xd1, "Command response could not be provided: device in firmware update mode" },
1309
0
    { 0xd2, "Command response could not be provided: BMC initialization or initialization agent in progress" },
1310
0
    { 0xd3, "Destination unavailable" },
1311
0
    { 0xd4, "Cannot execute command: insufficient privilege level or other security-based restriction" },
1312
0
    { 0xd5, "Cannot execute command: command, or request parameter(s), not supported in present state" },
1313
0
    { 0xd6, "Cannot execute command: parameter is illegal because subfunction is disabled or unavailable" },
1314
0
    { 0xff, "Unspecified error" },
1315
1316
0
    { 0, NULL }
1317
0
  };
1318
0
  const char *res;
1319
1320
0
  if (completion >= 0x01 && completion <= 0x7e) {
1321
0
    return "Device specific (OEM) completion code";
1322
0
  }
1323
1324
0
  if (completion >= 0x80 && completion <= 0xbe) {
1325
0
    if (cmd && cmd->cs_cc && (res = try_val_to_str(completion, cmd->cs_cc)) != NULL) {
1326
0
      return res;
1327
0
    }
1328
0
    return "Standard command-specific code";
1329
0
  }
1330
1331
0
  return val_to_str_const(completion, std_completion_codes, "Unknown");
1332
0
}
1333
1334
static int
1335
dissect_tmode(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1336
0
{
1337
0
  ipmi_dissect_arg_t * arg = (ipmi_dissect_arg_t *) data;
1338
0
  ipmi_context_t ctx;
1339
0
  unsigned tvb_len = tvb_captured_length(tvb);
1340
0
  uint8_t tmp;
1341
1342
  /* TMode message is at least 3 bytes length */
1343
0
  if (tvb_len < 3) {
1344
0
    return 0;
1345
0
  }
1346
1347
0
  memset(&ctx, 0, sizeof(ctx));
1348
1349
  /* get Net Fn/RS LUN field */
1350
0
  tmp = tvb_get_uint8(tvb, 0);
1351
1352
  /* set Net Fn */
1353
0
  ctx.hdr.netfn = tmp >> 2;
1354
1355
  /*
1356
   * NOTE: request/response matching code swaps RQ LUN with RS LUN
1357
   * fields in IPMB-like manner in order to find corresponding request
1358
   * so, we set both RS LUN and RQ LUN here for correct
1359
   * request/response matching
1360
   */
1361
0
  ctx.hdr.rq_lun = tmp & 3;
1362
0
  ctx.hdr.rs_lun = tmp & 3;
1363
1364
  /* get RQ Seq field */
1365
0
  ctx.hdr.rq_seq = tvb_get_uint8(tvb, 1) >> 2;
1366
1367
  /*
1368
   * NOTE: bridge field is ignored in request/response matching
1369
   */
1370
1371
  /* get command code */
1372
0
  ctx.hdr.cmd = tvb_get_uint8(tvb, 2);
1373
1374
  /* set dissect flags */
1375
0
  ctx.flags = IPMI_D_TMODE|IPMI_D_NO_CKS|IPMI_D_NO_RQ_SA;
1376
1377
  /* set header length */
1378
0
  ctx.hdr_len = 3;
1379
1380
  /* copy channel number and direction */
1381
0
  ctx.hdr.context = arg ? arg->context : IPMI_E_NONE;
1382
0
  ctx.hdr.channel = arg ? arg->channel : 0;
1383
0
  ctx.hdr.dir = arg ? arg->flags >> 7 : ctx.hdr.netfn & 1;
1384
1385
0
  if (ctx.hdr.context == IPMI_E_NONE) {
1386
    /* set source column */
1387
0
    col_set_str(pinfo->cinfo, COL_DEF_SRC,
1388
0
        ctx.hdr.dir ? "Console" : "BMC");
1389
1390
    /* set destination column */
1391
0
    col_set_str(pinfo->cinfo, COL_DEF_DST,
1392
0
        ctx.hdr.dir ? "BMC" : "Console");
1393
0
  }
1394
1395
  /* dissect IPMI command */
1396
0
  return dissect_ipmi_cmd(tvb, pinfo, tree, proto_tmode, ett_ipmi, &ctx);
1397
0
}
1398
1399
static int
1400
dissect_kcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1401
0
{
1402
0
  ipmi_dissect_arg_t * arg = (ipmi_dissect_arg_t *) data;
1403
0
  ipmi_context_t ctx;
1404
0
  unsigned tvb_len = tvb_captured_length(tvb);
1405
0
  uint8_t tmp;
1406
1407
  /* KCS message is at least 2 bytes length */
1408
0
  if (tvb_len < 2) {
1409
0
    return 0;
1410
0
  }
1411
1412
0
  memset(&ctx, 0, sizeof(ctx));
1413
1414
  /* get Net Fn/RS LUN field */
1415
0
  tmp = tvb_get_uint8(tvb, 0);
1416
1417
  /* set Net Fn */
1418
0
  ctx.hdr.netfn = tmp >> 2;
1419
1420
  /*
1421
   * NOTE: request/response matching code swaps RQ LUN with RS LUN
1422
   * fields in IPMB-like manner in order to find corresponding request
1423
   * so, we set both RS LUN and RQ LUN here for correct
1424
   * request/response matching
1425
   */
1426
0
  ctx.hdr.rq_lun = tmp & 3;
1427
0
  ctx.hdr.rs_lun = tmp & 3;
1428
1429
  /* get command code */
1430
0
  ctx.hdr.cmd = tvb_get_uint8(tvb, 1);
1431
1432
  /* set dissect flags */
1433
0
  ctx.flags = IPMI_D_NO_CKS|IPMI_D_NO_RQ_SA|IPMI_D_NO_SEQ;
1434
1435
  /* set header length */
1436
0
  ctx.hdr_len = 2;
1437
1438
  /* copy channel number and direction */
1439
0
  ctx.hdr.context = arg ? arg->context : 0;
1440
0
  ctx.hdr.channel = arg ? arg->channel : 0;
1441
0
  ctx.hdr.dir = arg ? arg->flags >> 7 : ctx.hdr.netfn & 1;
1442
1443
0
  if (ctx.hdr.context == IPMI_E_NONE) {
1444
    /* set source column */
1445
0
    col_set_str(pinfo->cinfo, COL_DEF_SRC, ctx.hdr.dir ? "HOST" : "BMC");
1446
1447
    /* set destination column */
1448
0
    col_set_str(pinfo->cinfo, COL_DEF_DST, ctx.hdr.dir ? "BMC" : "HOST");
1449
0
  }
1450
1451
  /* dissect IPMI command */
1452
0
  return dissect_ipmi_cmd(tvb, pinfo, tree, proto_kcs, ett_ipmi, &ctx);
1453
0
}
1454
1455
static uint8_t calc_cks(uint8_t start, tvbuff_t * tvb, unsigned off, unsigned len)
1456
15
{
1457
631
  while (len--) {
1458
616
    start += tvb_get_uint8(tvb, off++);
1459
616
  }
1460
1461
15
  return start;
1462
15
}
1463
1464
static bool guess_imb_format(tvbuff_t *tvb, uint8_t env,
1465
    uint8_t channel, unsigned * imb_flags, uint8_t * cks1, uint8_t * cks2)
1466
8
{
1467
8
  bool check_bc = false;
1468
8
  bool check_sh = false;
1469
8
  bool check_sa = false;
1470
8
  unsigned tvb_len;
1471
8
  unsigned sh_len;
1472
8
  unsigned sa_len;
1473
8
  unsigned rs_sa;
1474
1475
8
  if (message_format == MSGFMT_NONE) {
1476
0
    return false;
1477
8
  } else if (message_format == MSGFMT_IPMB) {
1478
0
    *imb_flags = IPMI_D_TRG_SA;
1479
8
  } else if (message_format == MSGFMT_LAN) {
1480
0
    *imb_flags = IPMI_D_TRG_SA|IPMI_D_SESSION_HANDLE;
1481
  /* channel 0 is primary IPMB */
1482
8
  } else if (!channel) {
1483
    /* check for broadcast if not in send message command */
1484
8
    if (env == IPMI_E_NONE) {
1485
      /* check broadcast */
1486
8
      check_bc = 1;
1487
1488
      /* slave address must be present */
1489
8
      *imb_flags = IPMI_D_TRG_SA;
1490
    /* check if in send message command */
1491
8
    } else if (env != IPMI_E_GETMSG) {
1492
      /* slave address must be present */
1493
0
      *imb_flags = IPMI_D_TRG_SA;
1494
0
    } else /* IPMI_E_GETMSG */ {
1495
0
      *imb_flags = 0;
1496
0
    }
1497
  /* channel 15 is System Interface */
1498
8
  } else if (channel == 15) {
1499
    /* slave address must be present */
1500
0
    *imb_flags = IPMI_D_TRG_SA;
1501
1502
    /* check if in get message command */
1503
0
    if (env == IPMI_E_GETMSG) {
1504
      /* session handle must be present */
1505
0
      *imb_flags |= IPMI_D_SESSION_HANDLE;
1506
0
    }
1507
  /* for other channels */
1508
0
  } else {
1509
0
    if (env == IPMI_E_NONE) {
1510
      /* check broadcast */
1511
0
      check_bc = 1;
1512
1513
      /* slave address must be present */
1514
0
      *imb_flags = IPMI_D_TRG_SA;
1515
0
    } else if (env == IPMI_E_SENDMSG_RQ) {
1516
      /* check session handle */
1517
0
      check_sh = 1;
1518
1519
      /* slave address must be present */
1520
0
      *imb_flags = IPMI_D_TRG_SA;
1521
0
    } else if (env == IPMI_E_SENDMSG_RS) {
1522
      /* slave address must be present */
1523
0
      *imb_flags = IPMI_D_TRG_SA;
1524
0
    } else /* IPMI_E_GETMSG */ {
1525
      /* check session handle */
1526
0
      check_sh = 1;
1527
1528
      /* check slave address presence */
1529
0
      check_sa = 1;
1530
1531
      /* no pre-requisites */
1532
0
      *imb_flags = 0;
1533
0
    }
1534
0
  }
1535
1536
  /* get message length */
1537
8
  tvb_len = tvb_captured_length(tvb);
1538
1539
  /*
1540
   * broadcast message starts with null,
1541
   * does not contain session handle
1542
   * but contains responder address
1543
   */
1544
8
  if (check_bc
1545
8
      && tvb_len >= 8
1546
5
      && !tvb_get_uint8(tvb, 0)
1547
3
      && !calc_cks(0, tvb, 1, 3)
1548
2
      && !calc_cks(0, tvb, 4, tvb_len - 4)) {
1549
0
    *imb_flags = IPMI_D_BROADCAST|IPMI_D_TRG_SA;
1550
0
    *cks1 = 0;
1551
0
    *cks2 = 0;
1552
0
    return true;
1553
0
  }
1554
1555
  /*
1556
   * message with the starts with session handle
1557
   * and contain responder address
1558
   */
1559
8
  if (check_sh
1560
0
      && tvb_len >= 8
1561
0
      && !calc_cks(0, tvb, 1, 3)
1562
0
      && !calc_cks(0, tvb, 4, tvb_len - 4)) {
1563
0
    *imb_flags = IPMI_D_SESSION_HANDLE|IPMI_D_TRG_SA;
1564
0
    *cks1 = 0;
1565
0
    *cks2 = 0;
1566
0
    return true;
1567
0
  }
1568
1569
  /*
1570
   * message with responder address
1571
   */
1572
8
  if (check_sa
1573
0
      && tvb_len >= 7
1574
0
      && !calc_cks(0, tvb, 0, 3)
1575
0
      && !calc_cks(0, tvb, 3, tvb_len - 3)) {
1576
0
    *imb_flags = IPMI_D_TRG_SA;
1577
0
    *cks1 = 0;
1578
0
    *cks2 = 0;
1579
0
    return true;
1580
0
  }
1581
1582
1583
8
  if (*imb_flags & IPMI_D_SESSION_HANDLE) {
1584
0
    sh_len = 1;
1585
0
    sa_len = 1;
1586
0
    rs_sa = 0;
1587
8
  } else if (*imb_flags & IPMI_D_TRG_SA) {
1588
8
    sh_len = 0;
1589
8
    sa_len = 1;
1590
8
    rs_sa = 0;
1591
8
  } else {
1592
0
    sh_len = 0;
1593
0
    sa_len = 0;
1594
0
    rs_sa = 0x20;
1595
0
  }
1596
1597
  /* check message length */
1598
8
  if (tvb_len < 6 + sh_len + sa_len) {
1599
3
    return false;
1600
3
  }
1601
1602
  /* calculate checksum deltas */
1603
5
  *cks1 = calc_cks(rs_sa, tvb, sh_len, sa_len + 2);
1604
5
  *cks2 = calc_cks(0, tvb, sh_len + sa_len + 2,
1605
5
      tvb_len - sh_len - sa_len - 2);
1606
1607
5
  return true;
1608
8
}
1609
1610
int
1611
do_dissect_ipmb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1612
    int hf_parent_item, int ett_tree, ipmi_dissect_arg_t * arg)
1613
8
{
1614
8
  ipmi_context_t ctx;
1615
8
  unsigned offset = 0;
1616
8
  uint8_t tmp;
1617
1618
8
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPMB");
1619
1620
8
  memset(&ctx, 0, sizeof(ctx));
1621
1622
  /* copy message context and channel */
1623
8
  ctx.hdr.context = arg ? arg->context : 0;
1624
8
  ctx.hdr.channel = arg ? arg->channel : 0;
1625
1626
  /* guess IPMB message format */
1627
8
  if (!guess_imb_format(tvb, ctx.hdr.context, ctx.hdr.channel,
1628
8
      &ctx.flags, &ctx.cks1, &ctx.cks2)) {
1629
3
    return 0;
1630
3
  }
1631
1632
  /* check if message is broadcast */
1633
5
  if (ctx.flags & IPMI_D_BROADCAST) {
1634
    /* skip first byte */
1635
0
    offset++;
1636
0
  }
1637
1638
  /* check is session handle is specified */
1639
5
  if (ctx.flags & IPMI_D_SESSION_HANDLE) {
1640
0
    ctx.hdr.session = tvb_get_uint8(tvb, offset++);
1641
0
  }
1642
1643
  /* check is response address is specified */
1644
5
  if (ctx.flags & IPMI_D_TRG_SA) {
1645
5
    ctx.hdr.rs_sa = tvb_get_uint8(tvb, offset++);
1646
5
  } else {
1647
0
    ctx.hdr.rs_sa = 0x20;
1648
0
  }
1649
1650
  /* get Net Fn/RS LUN field */
1651
5
  tmp = tvb_get_uint8(tvb, offset++);
1652
1653
  /* set Net Fn  and RS LUN */
1654
5
  ctx.hdr.netfn = tmp >> 2;
1655
5
  ctx.hdr.rs_lun = tmp & 3;
1656
1657
  /* skip cks1 */
1658
5
  offset++;
1659
1660
  /* get RQ SA */
1661
5
  ctx.hdr.rq_sa = tvb_get_uint8(tvb, offset++);
1662
1663
  /* get RQ Seq/RQ LUN field */
1664
5
  tmp = tvb_get_uint8(tvb, offset++);
1665
1666
  /* set RQ Seq  and RQ LUN */
1667
5
  ctx.hdr.rq_seq = tmp >> 2;
1668
5
  ctx.hdr.rq_lun = tmp & 3;
1669
1670
  /* get command code */
1671
5
  ctx.hdr.cmd = tvb_get_uint8(tvb, offset++);
1672
1673
  /* set header length */
1674
5
  ctx.hdr_len = offset;
1675
1676
  /* copy direction */
1677
5
  ctx.hdr.dir = arg ? arg->flags >> 7 : ctx.hdr.netfn & 1;
1678
1679
5
  if (ctx.hdr.context == IPMI_E_NONE) {
1680
5
    unsigned red = arg ? (arg->flags & 0x40) : 0;
1681
1682
5
    if (!ctx.hdr.channel) {
1683
5
      col_add_fstr(pinfo->cinfo, COL_DEF_SRC,
1684
5
          "0x%02x(%s)", ctx.hdr.rq_sa, red ? "IPMB-B" : "IPMB-A");
1685
5
    } else {
1686
0
      col_add_fstr(pinfo->cinfo, COL_DEF_SRC,
1687
0
          "0x%02x", ctx.hdr.rq_sa);
1688
0
    }
1689
1690
5
    col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%02x", ctx.hdr.rs_sa);
1691
5
  }
1692
1693
  /* dissect IPMI command */
1694
5
  return dissect_ipmi_cmd(tvb, pinfo, tree, hf_parent_item, ett_tree, &ctx);
1695
8
}
1696
1697
static int
1698
dissect_ipmi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1699
8
{
1700
8
  return do_dissect_ipmb(tvb, pinfo, tree, proto_ipmb, ett_ipmi,
1701
8
      (ipmi_dissect_arg_t *) data);
1702
8
}
1703
1704
static int
1705
dissect_i2c_ipmi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1706
0
{
1707
0
  if (pinfo->pseudo_header->i2c.flags & 0x00000001) {
1708
    /* Master-receive transactions are not possible on IPMB */
1709
0
    return 0;
1710
0
  }
1711
1712
0
  return do_dissect_ipmb(tvb, pinfo, tree, proto_ipmb, ett_ipmi,
1713
0
      (ipmi_dissect_arg_t *) data);
1714
0
}
1715
1716
1717
/* Register IPMB protocol.
1718
 */
1719
void
1720
proto_register_ipmi(void)
1721
14
{
1722
14
  static hf_register_info hf[] = {
1723
14
    { &hf_ipmi_command_data, { "Bus command data", "ipmi.bus_command_data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
1724
14
    { &hf_ipmi_session_handle, { "Session handle", "ipmi.session_handle", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1725
14
    { &hf_ipmi_header_trg, { "Target Address", "ipmi.header.target", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1726
14
    { &hf_ipmi_header_trg_lun, { "Target LUN", "ipmi.header.trg_lun", FT_UINT8, BASE_HEX, NULL, 0x03, NULL, HFILL }},
1727
14
    { &hf_ipmi_header_netfn, { "NetFN", "ipmi.header.netfn", FT_UINT8, BASE_HEX, NULL, 0xfc, NULL, HFILL }},
1728
14
    { &hf_ipmi_header_crc, { "Header Checksum", "ipmi.header.crc", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1729
14
    { &hf_ipmi_header_src, { "Source Address", "ipmi.header.source", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1730
14
    { &hf_ipmi_header_src_lun, { "Source LUN", "ipmi.header.src_lun", FT_UINT8, BASE_HEX, NULL, 0x03, NULL, HFILL }},
1731
14
    { &hf_ipmi_header_bridged, { "Bridged", "ipmi.header.bridged", FT_UINT8, BASE_HEX, NULL, 0x03, NULL, HFILL }},
1732
14
    { &hf_ipmi_header_sequence, { "Sequence Number", "ipmi.header.sequence", FT_UINT8, BASE_HEX, NULL, 0xfc, NULL, HFILL }},
1733
14
    { &hf_ipmi_header_command, { "Command", "ipmi.header.command", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1734
14
    { &hf_ipmi_header_completion, { "Completion Code", "ipmi.header.completion", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1735
14
    { &hf_ipmi_header_sig, { "Signature", "ipmi.header.signature", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
1736
14
    { &hf_ipmi_data_crc, { "Data checksum", "ipmi.data.crc", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
1737
14
    { &hf_ipmi_response_to, { "Response to", "ipmi.response_to", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0, NULL, HFILL }},
1738
14
    { &hf_ipmi_response_in, { "Response in", "ipmi.response_in", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0, NULL, HFILL }},
1739
14
    { &hf_ipmi_response_time, { "Responded in", "ipmi.response_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, NULL, HFILL }}
1740
14
  };
1741
14
  static int *ett[] = {
1742
14
    &ett_ipmi,
1743
14
    &ett_header,
1744
14
    &ett_header_byte_1,
1745
14
    &ett_header_byte_4,
1746
14
    &ett_data,
1747
14
    &ett_typelen
1748
14
  };
1749
14
  static const enum_val_t msgfmt_vals[] = {
1750
14
    { "none", "None", MSGFMT_NONE },
1751
14
    { "ipmb", "IPMB", MSGFMT_IPMB },
1752
14
    { "lan", "Session-based (LAN, ...)", MSGFMT_LAN },
1753
14
    { "guess", "Use heuristics", MSGFMT_GUESS },
1754
14
    { NULL, NULL, 0 }
1755
14
  };
1756
14
  static const enum_val_t oemsel_vals[] = {
1757
14
    { "none", "None", IPMI_OEM_NONE },
1758
14
    { "pps", "Pigeon Point Systems", IPMI_OEM_PPS },
1759
14
    { NULL, NULL, 0 }
1760
14
  };
1761
1762
14
  static ei_register_info ei[] = {
1763
14
    { &ei_impi_parser_not_implemented, { "ipmi.parser_not_implemented", PI_UNDECODED, PI_WARN, "[PARSER NOT IMPLEMENTED]", EXPFILL }},
1764
14
  };
1765
1766
14
  module_t *module;
1767
14
  expert_module_t* expert_ipmi;
1768
14
  uint32_t i;
1769
1770
14
  proto_ipmi = proto_register_protocol("Intelligent Platform Management Interface",
1771
14
                          "IPMI",
1772
14
                          "ipmi");
1773
1774
14
  proto_ipmb = proto_register_protocol("Intelligent Platform Management Bus",
1775
14
                          "IPMB",
1776
14
                          "ipmb");
1777
14
  proto_kcs = proto_register_protocol("Keyboard Controller Style Interface",
1778
14
                          "KCS",
1779
14
                          "kcs");
1780
14
  proto_tmode = proto_register_protocol("Serial Terminal Mode Interface",
1781
14
                          "TMode",
1782
14
                          "tmode");
1783
1784
14
  proto_register_field_array(proto_ipmi, hf, array_length(hf));
1785
14
  proto_register_subtree_array(ett, array_length(ett));
1786
1787
14
  expert_ipmi = expert_register_protocol(proto_ipmi);
1788
14
  expert_register_field_array(expert_ipmi, ei, array_length(ei));
1789
1790
14
  ipmi_netfn_setdesc(IPMI_CHASSIS_REQ, "Chassis", 0);
1791
14
  ipmi_netfn_setdesc(IPMI_BRIDGE_REQ, "Bridge", 0);
1792
14
  ipmi_netfn_setdesc(IPMI_SE_REQ, "Sensor/Event", 0);
1793
14
  ipmi_netfn_setdesc(IPMI_APP_REQ, "Application", 0);
1794
14
  ipmi_netfn_setdesc(IPMI_UPDATE_REQ, "Firmware Update", 0);
1795
14
  ipmi_netfn_setdesc(IPMI_STORAGE_REQ, "Storage", 0);
1796
14
  ipmi_netfn_setdesc(IPMI_TRANSPORT_REQ, "Transport", 0);
1797
14
  ipmi_netfn_setdesc(IPMI_GROUP_REQ, "Group", 1);
1798
14
  ipmi_netfn_setdesc(IPMI_OEM_REQ, "OEM/Group", 3);
1799
126
  for (i = 0x30; i < 0x40; i += 2) {
1800
112
    ipmi_netfn_setdesc(i, "OEM", 0);
1801
112
  }
1802
1803
14
  register_dissector("ipmi", dissect_ipmi, proto_ipmi);
1804
14
  ipmi_i2c_handle = register_dissector("ipmi.i2c",  dissect_i2c_ipmi, proto_ipmi );
1805
14
  register_dissector("ipmb", dissect_ipmi, proto_ipmb);
1806
14
  register_dissector("kcs", dissect_kcs, proto_kcs);
1807
14
  register_dissector("tmode", dissect_tmode, proto_tmode);
1808
1809
14
  module = prefs_register_protocol(proto_ipmi, NULL);
1810
14
  prefs_register_bool_preference(module, "dissect_bus_commands", "Dissect bus commands",
1811
14
      "Dissect IPMB commands",
1812
14
      &dissect_bus_commands);
1813
14
  prefs_register_bool_preference(module, "fru_langcode_is_english", "FRU Language Code is English",
1814
14
      "FRU Language Code is English; strings are ASCII+LATIN1 (vs. Unicode)",
1815
14
      &fru_langcode_is_english);
1816
14
  prefs_register_uint_preference(module, "response_after_req", "Maximum delay of response message",
1817
14
      "Do not search for responses coming after this timeout (milliseconds)",
1818
14
      10, &response_after_req);
1819
14
  prefs_register_uint_preference(module, "response_before_req", "Response ahead of request",
1820
14
      "Allow for responses before requests (milliseconds)",
1821
14
      10, &response_before_req);
1822
14
  prefs_register_enum_preference(module, "msgfmt", "Format of embedded messages",
1823
14
      "Format of messages embedded into Send/Get/Forward Message",
1824
14
      &message_format, msgfmt_vals, false);
1825
14
  prefs_register_enum_preference(module, "selected_oem", "OEM commands parsed as",
1826
14
      "Selects which OEM format is used for commands that IPMI does not define",
1827
14
      &selected_oem, oemsel_vals, false);
1828
14
}
1829
1830
void proto_reg_handoff_ipmi(void)
1831
14
{
1832
14
  dissector_add_for_decode_as("i2c.message", ipmi_i2c_handle );
1833
14
}
1834
1835
/*
1836
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1837
 *
1838
 * Local variables:
1839
 * c-basic-offset: 8
1840
 * tab-width: 8
1841
 * indent-tabs-mode: t
1842
 * End:
1843
 *
1844
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1845
 * :indentSize=8:tabSize=8:noTabs=false:
1846
 */