/* packet-ipmi-se.c
 * Sub-dissectors for IPMI messages (netFn=Sensor/Event)
 * Copyright 2007-2008, Alexey Neyman, Pigeon Point Systems <avn@pigeonpoint.com>
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "config.h"

#include <epan/packet.h>
#include <epan/tfs.h>
#include <wsutil/array.h>
#include "packet-ipmi.h"

void proto_register_ipmi_se(void);

/* Data types for sensor-specific info */
struct sensor_info;
typedef bool (*intrp_t)(proto_tree *, tvbuff_t *, const struct sensor_info *,
		uint32_t, uint32_t, uint32_t);

struct sensor_info {
	const value_string *offsets;
	intrp_t intrp2;
	intrp_t intrp3;
	const char *desc;
};

struct evtype_info {
	const value_string *byte2;
	const value_string *byte3;
	const value_string *offsets;
	intrp_t intrp2;
	intrp_t intrp3;
};

static int ett_ipmi_se_evt_byte3;
static int ett_ipmi_se_evt_evd_byte1;
static int ett_ipmi_se_evt_evd_byte2;
static int ett_ipmi_se_evt_evd_byte3;

static int ett_ipmi_se_cp06_byte1;
static int ett_ipmi_se_cp07_byte1;
static int ett_ipmi_se_cp09_byte1;
static int ett_ipmi_se_cp10_byte1;
static int ett_ipmi_se_cp12_byte1;
static int ett_ipmi_se_cp12_byte2;
static int ett_ipmi_se_cp12_byte3;
static int ett_ipmi_se_cp13_byte1;
static int ett_ipmi_se_cp15_byte1;
static int ett_ipmi_se_cp15_byte2;
static int ett_ipmi_se_cp15_member;
static int ett_ipmi_se_cp15_byte11;

static int ett_ipmi_se_00_byte2;
static int ett_ipmi_se_01_byte2;
static int ett_ipmi_se_10_action;
static int ett_ipmi_se_12_byte1;
static int ett_ipmi_se_13_byte1;
static int ett_ipmi_se_13_rev;
static int ett_ipmi_se_14_byte1;
static int ett_ipmi_se_16_byte1;
static int ett_ipmi_se_16_byte2;
static int ett_ipmi_se_16_byte3;
static int ett_ipmi_se_20_rq_byte1;
static int ett_ipmi_se_20_rs_byte2;
static int ett_ipmi_se_23_readingfactors;
static int ett_ipmi_se_23_byte1;
static int ett_ipmi_se_23_byte2;
static int ett_ipmi_se_23_byte3;
static int ett_ipmi_se_23_byte4;
static int ett_ipmi_se_23_byte5;
static int ett_ipmi_se_23_byte6;
static int ett_ipmi_se_XX_mask;
static int ett_ipmi_se_XX_b1;
static int ett_ipmi_se_XX_b2;
static int ett_ipmi_se_XX_b3;
static int ett_ipmi_se_XX_b4;
static int ett_ipmi_se_28_byte2;
static int ett_ipmi_se_29_byte1;
static int ett_ipmi_se_2a_byte2;
static int ett_ipmi_se_2b_byte1;
static int ett_ipmi_se_2d_byte2;
static int ett_ipmi_se_2d_b1;
static int ett_ipmi_se_2d_b2;

static expert_field ei_ipmi_se_13_request_param_rev;
static expert_field ei_ipmi_se_13_request_param_data;

static int hf_ipmi_se_evt_rev;
static int hf_ipmi_se_evt_sensor_type;
static int hf_ipmi_se_evt_sensor_num;
static int hf_ipmi_se_evt_byte3;
static int hf_ipmi_se_evt_dir;
static int hf_ipmi_se_evt_type;
static int hf_ipmi_se_evt_data1;
static int hf_ipmi_se_evt_data1_b2;
static int hf_ipmi_se_evt_data1_b3;
static int hf_ipmi_se_evt_data1_offs;
static int hf_ipmi_se_evt_data2;
static int hf_ipmi_se_evt_data3;

static int hf_ipmi_se_cp00_sip;
static int hf_ipmi_se_cp01_alert_startup;
static int hf_ipmi_se_cp01_startup;
static int hf_ipmi_se_cp01_event_msg;
static int hf_ipmi_se_cp01_pef;
static int hf_ipmi_se_cp02_diag_intr;
static int hf_ipmi_se_cp02_oem_action;
static int hf_ipmi_se_cp02_pwr_cycle;
static int hf_ipmi_se_cp02_reset;
static int hf_ipmi_se_cp02_pwr_down;
static int hf_ipmi_se_cp02_alert;
static int hf_ipmi_se_cp03_startup;
static int hf_ipmi_se_cp04_alert_startup;
static int hf_ipmi_se_cp05_num_evfilters;
static int hf_ipmi_se_cp06_filter;
static int hf_ipmi_se_cp06_data;
static int hf_ipmi_se_cp07_filter;
/* static int hf_ipmi_se_cp07_data; */
static int hf_ipmi_se_cp08_policies;
static int hf_ipmi_se_cp09_entry;
static int hf_ipmi_se_cp09_data;
static int hf_ipmi_se_cp10_useval;
static int hf_ipmi_se_cp10_guid;
static int hf_ipmi_se_cp11_num_alertstr;
static int hf_ipmi_se_cp12_byte1;
static int hf_ipmi_se_cp12_alert_stringsel;
static int hf_ipmi_se_cp12_evfilter;
static int hf_ipmi_se_cp12_alert_stringset;
static int hf_ipmi_se_cp13_stringsel;
static int hf_ipmi_se_cp13_blocksel;
static int hf_ipmi_se_cp13_string;
static int hf_ipmi_se_cp14_num_gct;
static int hf_ipmi_se_cp15_gctsel;
static int hf_ipmi_se_cp15_force;
static int hf_ipmi_se_cp15_delayed;
static int hf_ipmi_se_cp15_channel;
static int hf_ipmi_se_cp15_group;
static int hf_ipmi_se_cp15_member_check;
static int hf_ipmi_se_cp15_member_id;
static int hf_ipmi_se_cp15_retries;
static int hf_ipmi_se_cp15_operation;

static int hf_ipmi_se_00_addr;
static int hf_ipmi_se_00_lun;

static int hf_ipmi_se_01_addr;
static int hf_ipmi_se_01_lun;

static int hf_ipmi_se_10_pef_version;
static int hf_ipmi_se_10_action_oem_filter;
static int hf_ipmi_se_10_action_diag_intr;
static int hf_ipmi_se_10_action_oem_action;
static int hf_ipmi_se_10_action_pwr_cycle;
static int hf_ipmi_se_10_action_reset;
static int hf_ipmi_se_10_action_pwr_down;
static int hf_ipmi_se_10_action_alert;
static int hf_ipmi_se_10_entries;
static int hf_ipmi_se_10_evtype;

static int hf_ipmi_se_11_rq_timeout;
static int hf_ipmi_se_11_rs_timeout;

static int hf_ipmi_se_12_byte1;
static int hf_ipmi_se_12_param;
static int hf_ipmi_se_12_data;

static int hf_ipmi_se_13_byte1;
static int hf_ipmi_se_13_getrev;
static int hf_ipmi_se_13_param;
static int hf_ipmi_se_13_set;
static int hf_ipmi_se_13_block;
static int hf_ipmi_se_13_rev_present;
static int hf_ipmi_se_13_rev_compat;
static int hf_ipmi_se_13_data;

static int hf_ipmi_se_14_processed_by;
static int hf_ipmi_se_14_rid;

static int hf_ipmi_se_15_tstamp;
static int hf_ipmi_se_15_lastrec;
static int hf_ipmi_se_15_proc_sw;
static int hf_ipmi_se_15_proc_bmc;

static int hf_ipmi_se_16_chan;
static int hf_ipmi_se_16_op;
static int hf_ipmi_se_16_dst;
static int hf_ipmi_se_16_send_string;
static int hf_ipmi_se_16_string_sel;
static int hf_ipmi_se_16_gen;
static int hf_ipmi_se_16_status;

static int hf_ipmi_se_17_seq;
static int hf_ipmi_se_17_tstamp;
static int hf_ipmi_se_17_evsrc;
static int hf_ipmi_se_17_sensor_dev;
static int hf_ipmi_se_17_sensor_num;
static int hf_ipmi_se_17_evdata1;
static int hf_ipmi_se_17_evdata2;
static int hf_ipmi_se_17_evdata3;

static int hf_ipmi_se_20_rq_op;
static int hf_ipmi_se_20_rs_num;
static int hf_ipmi_se_20_rs_sdr;
static int hf_ipmi_se_20_rs_population;
static int hf_ipmi_se_20_rs_lun3;
static int hf_ipmi_se_20_rs_lun2;
static int hf_ipmi_se_20_rs_lun1;
static int hf_ipmi_se_20_rs_lun0;
static int hf_ipmi_se_20_rs_change;

static int hf_ipmi_se_21_rid;
static int hf_ipmi_se_21_record;
static int hf_ipmi_se_21_offset;
static int hf_ipmi_se_21_len;
static int hf_ipmi_se_21_next;
static int hf_ipmi_se_21_recdata;

static int hf_ipmi_se_22_resid;

static int hf_ipmi_se_23_rq_sensor;
static int hf_ipmi_se_23_rq_reading;
static int hf_ipmi_se_23_rs_next_reading;

static int hf_ipmi_se_24_sensor;
static int hf_ipmi_se_24_mask;
static int hf_ipmi_se_24_hyst_pos;
static int hf_ipmi_se_24_hyst_neg;

static int hf_ipmi_se_25_sensor;
static int hf_ipmi_se_25_mask;
static int hf_ipmi_se_25_hyst_pos;
static int hf_ipmi_se_25_hyst_neg;

static int hf_ipmi_se_26_sensor;
static int hf_ipmi_se_XX_m_unr;
static int hf_ipmi_se_XX_m_uc;
static int hf_ipmi_se_XX_m_unc;
static int hf_ipmi_se_XX_m_lnr;
static int hf_ipmi_se_XX_m_lc;
static int hf_ipmi_se_XX_m_lnc;
static int hf_ipmi_se_XX_thr_lnc;
static int hf_ipmi_se_XX_thr_lc;
static int hf_ipmi_se_XX_thr_lnr;
static int hf_ipmi_se_XX_thr_unc;
static int hf_ipmi_se_XX_thr_uc;
static int hf_ipmi_se_XX_thr_unr;

static int hf_ipmi_se_27_sensor;

static int hf_ipmi_se_XX_b1_7;
static int hf_ipmi_se_XX_b1_6;
static int hf_ipmi_se_XX_b1_5;
static int hf_ipmi_se_XX_b1_4;
static int hf_ipmi_se_XX_b1_3;
static int hf_ipmi_se_XX_b1_2;
static int hf_ipmi_se_XX_b1_1;
static int hf_ipmi_se_XX_b1_0;
static int hf_ipmi_se_XX_b2_6;
static int hf_ipmi_se_XX_b2_5;
static int hf_ipmi_se_XX_b2_4;
static int hf_ipmi_se_XX_b2_3;
static int hf_ipmi_se_XX_b2_2;
static int hf_ipmi_se_XX_b2_1;
static int hf_ipmi_se_XX_b2_0;
static int hf_ipmi_se_XX_b3_7;
static int hf_ipmi_se_XX_b3_6;
static int hf_ipmi_se_XX_b3_5;
static int hf_ipmi_se_XX_b3_4;
static int hf_ipmi_se_XX_b3_3;
static int hf_ipmi_se_XX_b3_2;
static int hf_ipmi_se_XX_b3_1;
static int hf_ipmi_se_XX_b3_0;
static int hf_ipmi_se_XX_b4_6;
static int hf_ipmi_se_XX_b4_5;
static int hf_ipmi_se_XX_b4_4;
static int hf_ipmi_se_XX_b4_3;
static int hf_ipmi_se_XX_b4_2;
static int hf_ipmi_se_XX_b4_1;
static int hf_ipmi_se_XX_b4_0;

static int hf_ipmi_se_28_sensor;
static int hf_ipmi_se_28_fl_evm;
static int hf_ipmi_se_28_fl_scan;
static int hf_ipmi_se_28_fl_action;

static int hf_ipmi_se_29_sensor;
static int hf_ipmi_se_29_fl_evm;
static int hf_ipmi_se_29_fl_scan;

static int hf_ipmi_se_2a_sensor;
static int hf_ipmi_se_2a_fl_sel;

static int hf_ipmi_se_2b_sensor;
static int hf_ipmi_se_2b_fl_evm;
static int hf_ipmi_se_2b_fl_scan;
static int hf_ipmi_se_2b_fl_unavail;

static int hf_ipmi_se_2d_sensor;
static int hf_ipmi_se_2d_reading;
static int hf_ipmi_se_2d_b1_7;
static int hf_ipmi_se_2d_b1_6;
static int hf_ipmi_se_2d_b1_5;
static int hf_ipmi_se_2d_b1_4;
static int hf_ipmi_se_2d_b1_3;
static int hf_ipmi_se_2d_b1_2;
static int hf_ipmi_se_2d_b1_1;
static int hf_ipmi_se_2d_b1_0;
static int hf_ipmi_se_2d_b2_6;
static int hf_ipmi_se_2d_b2_5;
static int hf_ipmi_se_2d_b2_4;
static int hf_ipmi_se_2d_b2_3;
static int hf_ipmi_se_2d_b2_2;
static int hf_ipmi_se_2d_b2_1;
static int hf_ipmi_se_2d_b2_0;

static int hf_ipmi_se_2e_sensor;
static int hf_ipmi_se_2e_stype;
static int hf_ipmi_se_2e_evtype;

static int hf_ipmi_se_2f_sensor;
static int hf_ipmi_se_2f_stype;
static int hf_ipmi_se_2f_evtype;

/* Generated from convert_proto_tree_add_text.pl */
static int hf_ipmi_se_f3_gs_management_power;
static int hf_ipmi_se_f0_cause;
static int hf_ipmi_se_28_logical_fru_device;
static int hf_ipmi_se_evt_trigger_threshold;
static int hf_ipmi_se_10_logging_disable;
static int hf_ipmi_se_28_sensor_number;
static int hf_ipmi_se_23_interrupt_type;
static int hf_ipmi_se_23_accuracy_exponent;
static int hf_ipmi_se_2a_session_deactivated_by;
static int hf_ipmi_se_0c_memory_module;
static int hf_ipmi_se_f1_ipmb_a_override_state;
static int hf_ipmi_se_12_reset;
static int hf_ipmi_se_f1_ipmb_b_local_status;
static int hf_ipmi_se_f1_ipmb_a_local_status;
static int hf_ipmi_se_1d_restart_cause;
static int hf_ipmi_se_12_power_off;
static int hf_ipmi_se_f3_management_power_overcurrent;
static int hf_ipmi_se_2a_user_id;
static int hf_ipmi_se_12_event;
static int hf_ipmi_se_2c_previous_state;
static int hf_ipmi_se_1d_channel;
static int hf_ipmi_se_f3_channel_management_power;
static int hf_ipmi_se_12_power_cycle;
static int hf_ipmi_se_f1_ipmb_b_override_state;
static int hf_ipmi_se_19_requested_power_state;
static int hf_ipmi_se_f3_payload_power_overcurrent;
static int hf_ipmi_se_f0_previous_state;
static int hf_ipmi_se_f3_ps1;
static int hf_ipmi_se_13_parameter;
static int hf_ipmi_se_28_i2c_slave_address;
static int hf_ipmi_se_0f_extension_code_err;
static int hf_ipmi_se_28_lun_for_master_read_write_command;
static int hf_ipmi_se_evt_trigger_reading;
static int hf_ipmi_se_21_slot_connector_type;
static int hf_ipmi_se_f3_pwr_on;
static int hf_ipmi_se_28_fru_device_id_within_controller;
static int hf_ipmi_se_12_log_entry_action;
static int hf_ipmi_se_12_log_type;
static int hf_ipmi_se_23_accuracy;
static int hf_ipmi_se_f3_role;
static int hf_ipmi_se_f3_channel_payload_power;
static int hf_ipmi_se_23_m;
static int hf_ipmi_se_f1_channel;
static int hf_ipmi_se_10_event_offset;
static int hf_ipmi_se_f3_gs_payload_power;
static int hf_ipmi_se_pst_severity;
static int hf_ipmi_se_f3_global_status;
static int hf_ipmi_se_f3_channel_status;
static int hf_ipmi_se_12_alert;
static int hf_ipmi_se_23_timer_use_at_expiration;
static int hf_ipmi_se_12_oem_action;
static int hf_ipmi_se_f0_fru_id;
static int hf_ipmi_se_pst_previous_state;
static int hf_ipmi_se_23_tolerance;
static int hf_ipmi_se_21_slot_connector;
static int hf_ipmi_se_12_diagnostic_interrupt;
static int hf_ipmi_se_2c_cause;
static int hf_ipmi_se_f3_enable;
static int hf_ipmi_se_10_sel_filled;
static int hf_ipmi_se_23_b_exponent;
static int hf_ipmi_se_0f_extension_code_progress;
static int hf_ipmi_se_05_network_controller;
static int hf_ipmi_se_28_private_bus_id;
static int hf_ipmi_se_10_event;
static int hf_ipmi_se_23_r_exponent;
static int hf_ipmi_se_f3_power_channel_number;
static int hf_ipmi_se_2a_channel;
static int hf_ipmi_se_2b_version_change_type;
static int hf_ipmi_se_f3_redundant_pm;
static int hf_ipmi_se_19_power_state;
static int hf_ipmi_se_08_error_type;
static int hf_ipmi_se_23_b;
static int hf_ipmi_se_12_timestamp_clock_type;
static int hf_ipmi_se_10_memory_module;


/* Platform Event parsing. Common for Platform Event and Alert Immediate.
 */
static const value_string evt_evm_rev_vals[] = {
	{ 0x03, "IPMI 1.0" },
	{ 0x04, "IPMI 1.5+" },
	{ 0, NULL },
};

static const struct true_false_string evt_evdir_tfs = {
	"Deassertion event",
	"Assertion event"
};

static const value_string et_empty[] = {
	{ 0, NULL }
};

static const value_string etb2_thr[] = {
	{ 0x00, "Unspecified" },
	{ 0x01, "Trigger reading" },
	{ 0x02, "OEM code" },
	{ 0x03, "Sensor-specific" },
	{ 0, NULL }
};

static const value_string etb3_thr[] = {
	{ 0x00, "Unspecified" },
	{ 0x01, "Trigger threshold" },
	{ 0x02, "OEM code" },
	{ 0x03, "Sensor-specific" },
	{ 0, NULL }
};

static const value_string etb2_dscr[] = {
	{ 0x00, "Unspecified" },
	{ 0x01, "Previous state and/or severity" },
	{ 0x02, "OEM code" },
	{ 0x03, "Sensor-specific" },
	{ 0, NULL }
};

static const value_string etb3_dscr[] = {
	{ 0x00, "Unspecified" },
	{ 0x02, "OEM code" },
	{ 0x03, "Sensor-specific" },
	{ 0, NULL }
};

static const value_string etb2_oem[] = {
	{ 0x00, "Unspecified" },
	{ 0x01, "Previous state and/or severity" },
	{ 0x02, "OEM code" },
	{ 0, NULL }
};

static const value_string etb3_oem[] = {
	{ 0x00, "Unspecified" },
	{ 0x02, "OEM code" },
	{ 0, NULL }
};

static const value_string etoff_01[] = {
	{ 0x00, "Lower Non-Critical: going low" },
	{ 0x01, "Lower Non-Critical: going high" },
	{ 0x02, "Lower Critical: going low" },
	{ 0x03, "Lower Critical: going high" },
	{ 0x04, "Lower Non-Recoverable: going low" },
	{ 0x05, "Lower Non-Recoverable: going high" },
	{ 0x06, "Upper Non-Critical: going low" },
	{ 0x07, "Upper Non-Critical: going high" },
	{ 0x08, "Upper Critical: going low" },
	{ 0x09, "Upper Critical: going high" },
	{ 0x0a, "Upper Non-Recoverable: going low" },
	{ 0x0b, "Upper Non-Recoverable: going high" },
	{ 0, NULL }
};

static const value_string etoff_02[] = {
	{ 0x00, "Transition to Idle" },
	{ 0x01, "Transition to Active" },
	{ 0x02, "Transition to Busy" },
	{ 0, NULL }
};

static const value_string etoff_03[] = {
	{ 0x00, "State Deasserted" },
	{ 0x01, "State Asserted" },
	{ 0, NULL }
};

static const value_string etoff_04[] = {
	{ 0x00, "Predictive Failure Deasserted" },
	{ 0x01, "Predictive Failure Asserted" },
	{ 0, NULL }
};

static const value_string etoff_05[] = {
	{ 0x00, "Limit Not Exceeded" },
	{ 0x01, "Limit Exceeded" },
	{ 0, NULL }
};

static const value_string etoff_06[] = {
	{ 0x00, "Performance Met" },
	{ 0x01, "Performance Lags" },
	{ 0, NULL }
};

static const value_string etoff_07[] = {
	{ 0x00, "Transition to OK" },
	{ 0x01, "Transition to Non-Critical from OK" },
	{ 0x02, "Transition to Critical from less severe" },
	{ 0x03, "Transition to Non-Recoverable from less severe" },
	{ 0x04, "Transition to Non-Critical from more severe" },
	{ 0x05, "Transition to Critical from Non-Recoverable" },
	{ 0x06, "Transition to Non-Recoverable" },
	{ 0x07, "Monitor" },
	{ 0x08, "Informational" },
	{ 0x0F, "Unspecified" },
	{ 0, NULL }
};

static const value_string etoff_08[] = {
	{ 0x00, "Device Removed/Absent" },
	{ 0x01, "Device Inserted/Present" },
	{ 0, NULL }
};

static const value_string etoff_09[] = {
	{ 0x00, "Device Disabled" },
	{ 0x01, "Device Enabled" },
	{ 0, NULL }
};

static const value_string etoff_0a[] = {
	{ 0x00, "Transition to Running" },
	{ 0x01, "Transition to In Test" },
	{ 0x02, "Transition to Power Off" },
	{ 0x03, "Transition to On Line" },
	{ 0x04, "Transition to Off Line" },
	{ 0x05, "Transition to Off Duty" },
	{ 0x06, "Transition to Degraded" },
	{ 0x07, "Transition to Power Save" },
	{ 0x08, "Install Error" },
	{ 0, NULL }
};

static const value_string etoff_0b[] = {
	{ 0x00, "Fully Redundant" },
	{ 0x01, "Redundancy Lost" },
	{ 0x02, "Redundancy Degraded" },
	{ 0x03, "Non-Redundant: Sufficient Resources from Redundant" },
	{ 0x04, "Non-Redundant: Sufficient Resources from Insufficient Resources" },
	{ 0x05, "Non-Redundant: Insufficient Resources" },
	{ 0x06, "Redundancy Degraded from Fully Redundant" },
	{ 0x07, "Redundancy Degraded from Non-Redundant" },
	{ 0, NULL }
};

static const value_string etoff_0c[] = {
	{ 0x00, "D0 Power State" },
	{ 0x01, "D1 Power State" },
	{ 0x02, "D2 Power State" },
	{ 0x03, "D3 Power State" },
	{ 0, NULL }
};

static bool
eti_thr_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d)
{
	proto_item* ti;

	if (b == 0x1) {
		ti = proto_tree_add_item(tree, hf_ipmi_se_evt_trigger_reading, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		if (d == 0xff)
			proto_item_append_text(ti, " (unspecified)");
		return true;
	}
	return false;
}

static bool
eti_thr_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d)
{
	proto_item* ti;

	if (b == 0x1) {
		ti = proto_tree_add_item(tree, hf_ipmi_se_evt_trigger_threshold, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		if (d == 0xff)
			proto_item_append_text(ti, " (unspecified)");
		return true;
	}
	return false;
}

static bool
eti_2_pst_sev(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si,
		uint32_t b, uint32_t offs _U_, uint32_t d)
{
	proto_tree *s_tree;
	uint32_t tmp;
	const char *desc;

	if (b == 0x1) {
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte2, NULL, "Previous state/severity");
		proto_tree_add_item(s_tree, hf_ipmi_se_pst_severity, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		tmp = d & 0xf;
		desc = (tmp == 0x0f) ? "Unspecified" : val_to_str_const(tmp, si->offsets, "Unknown");
		proto_tree_add_uint_format_value(s_tree, hf_ipmi_se_pst_previous_state, tvb, 0, 1,
				tmp, "%s (0x%02x)", desc, tmp);
		return true;
	}
	return false;
}

static const range_string evtype_rvals[] = {
	{0x00, 0x00, "Reserved"},
	{0x01, 0x01, "Threshold"},
	{0x02, 0x0C, "Discrete"},
	{0x0D, 0x6E, "Reserved"},
	{0x6F, 0x6F, "Sensor-specific"},
	{0x70, 0x7F, "OEM-specific"},
	{0,0,NULL}
};

static const struct evtype_info *
get_evtype_info(unsigned int evtype)
{
	static const struct {
		unsigned int id;
		struct evtype_info eti;
	} eti_tab[] = {
		{ 0x01, { etb2_thr,  etb3_thr,  etoff_01, eti_thr_2,  eti_thr_3}},
		{ 0x02, { etb2_dscr, etb3_dscr, etoff_02, eti_2_pst_sev, NULL}},
		{ 0x03, { etb2_dscr, etb3_dscr, etoff_03, eti_2_pst_sev, NULL}},
		{ 0x04, { etb2_dscr, etb3_dscr, etoff_04, eti_2_pst_sev, NULL}},
		{ 0x05, { etb2_dscr, etb3_dscr, etoff_05, eti_2_pst_sev, NULL}},
		{ 0x06, { etb2_dscr, etb3_dscr, etoff_06, eti_2_pst_sev, NULL}},
		{ 0x07, { etb2_dscr, etb3_dscr, etoff_07, eti_2_pst_sev, NULL}},
		{ 0x08, { etb2_dscr, etb3_dscr, etoff_08, eti_2_pst_sev, NULL}},
		{ 0x09, { etb2_dscr, etb3_dscr, etoff_09, eti_2_pst_sev, NULL}},
		{ 0x0a, { etb2_dscr, etb3_dscr, etoff_0a, eti_2_pst_sev, NULL}},
		{ 0x0b, { etb2_dscr, etb3_dscr, etoff_0b, eti_2_pst_sev, NULL}},
		{ 0x0c, { etb2_dscr, etb3_dscr, etoff_0c, eti_2_pst_sev, NULL}},
		{ 0x6f, { etb2_dscr, etb3_dscr, NULL,     eti_2_pst_sev, NULL}}
	};
	static const struct evtype_info eti_oem = {
		etb2_oem, etb3_oem, et_empty, eti_2_pst_sev, NULL
	};
	static const struct evtype_info eti_rsrv = {
		et_empty, et_empty, et_empty, NULL, NULL
	};
	unsigned int i;

	/* Look for explicitly specified event/reading type */
	for (i = 0; i < array_length(eti_tab); i++) {
		if (eti_tab[i].id == evtype) {
			return &eti_tab[i].eti;
		}
	}

	/* Falls in OEM range? */
	if (evtype >= 0x70 && evtype <= 0x7f) {
		return &eti_oem;
	}

	return &eti_rsrv;
}

static const value_string ssoff_05[] = {
	{ 0x00, "General Chassis Intrusion" },
	{ 0x01, "Drive Bay Intrusion" },
	{ 0x02, "I/O Card Area Intrusion" },
	{ 0x03, "Processor Area Intrusion" },
	{ 0x04, "LAN Leash Lost" },
	{ 0x05, "Unauthorized dock" },
	{ 0x06, "FAN Area Intrusion" },
	{ 0, NULL }
};

static const value_string ssoff_06[] = {
	{ 0x00, "Secure Mode (Front Panel Lockout) Violation Attempt" },
	{ 0x01, "Pre-boot Password Violation: user password" },
	{ 0x02, "Pre-boot Password Violation: setup password" },
	{ 0x03, "Pre-boot Password Violation: network boot password" },
	{ 0x04, "Other pre-boot password violation" },
	{ 0x05, "Out-of-band password violation" },
	{ 0, NULL }
};

static const value_string ssoff_07[] = {
	{ 0x00, "IERR" },
	{ 0x01, "Thermal Trip" },
	{ 0x02, "FRB1/BIST Failure" },
	{ 0x03, "FRB2/Hang in POST Failure" },
	{ 0x04, "FRB3/Processor Startup/Initialization Failure" },
	{ 0x05, "Configuration Error" },
	{ 0x06, "SM BIOS Uncorrectable CPU-complex error" },
	{ 0x07, "Processor Presence Detected" },
	{ 0x08, "Processor Disabled" },
	{ 0x09, "Terminator Presence Detected" },
	{ 0x0a, "Processor Automatically Throttled" },
	{ 0, NULL }
};

static const value_string ssoff_08[] = {
	{ 0x00, "Presence Detected" },
	{ 0x01, "Power Supply Failure Detected" },
	{ 0x02, "Predictive Failure" },
	{ 0x03, "Power Supply input lost (AC/DC)" },
	{ 0x04, "Power Supply input lost or out-of-range" },
	{ 0x05, "Power Supply out-of-range, but present" },
	{ 0x06, "Configuration error" },
	{ 0, NULL }
};

static const value_string ssoff_09[] = {
	{ 0x00, "Power Off / Power Down" },
	{ 0x01, "Power Cycle" },
	{ 0x02, "240VA Power Down" },
	{ 0x03, "Interlock Power Down" },
	{ 0x04, "AC Lost" },
	{ 0x05, "Soft Power Control Failure" },
	{ 0x06, "Power Unit Failure Detected" },
	{ 0x07, "Predictive Failure" },
	{ 0, NULL }
};

static const value_string ssoff_0c[] = {
	{ 0x00, "Correctable ECC/other correctable memory error" },
	{ 0x01, "Uncorrectable ECC/other uncorrectable memory error" },
	{ 0x02, "Parity" },
	{ 0x03, "Memory Scrub Failed" },
	{ 0x04, "Memory Device Disabled" },
	{ 0x05, "Correctable ECC/other correctable memory error: logging limit reached" },
	{ 0x06, "Presence Detected" },
	{ 0x07, "Configuration Error" },
	{ 0x08, "Spare" },
	{ 0x09, "Memory Automatically Throttled" },
	{ 0x0a, "Critical Overtemperature" },
	{ 0, NULL }
};

static const value_string ssoff_0d[] = {
	{ 0x00, "Drive Presence" },
	{ 0x01, "Drive Fault" },
	{ 0x02, "Predictive Failure" },
	{ 0x03, "Hot Spare" },
	{ 0x04, "Consistency Check / Parity Check in progress" },
	{ 0x05, "In Critical Array" },
	{ 0x06, "In Failed Array" },
	{ 0x07, "Rebuild/Remap in progress" },
	{ 0x08, "Rebuild/Remap aborted" },
	{ 0, NULL }
};

static const value_string ssoff_0f[] = {
	{ 0x00, "System Firmware Error (POST Error)" },
	{ 0x01, "System Firmware Hang" },
	{ 0x02, "System Firmware Progress" },
	{ 0, NULL }
};

static const value_string ssoff_10[] = {
	{ 0x00, "Correctable Memory Error Logging Disabled" },
	{ 0x01, "Event type Logging Disabled" },
	{ 0x02, "Log Area Reset/Cleared" },
	{ 0x03, "All Event Logging Disabled" },
	{ 0x04, "SEL Full" },
	{ 0x05, "SEL Almost Full" },
	{ 0, NULL }
};

static const value_string ssoff_11[] = {
	{ 0x00, "BIOS Watchdog Reset" },
	{ 0x01, "OS Watchdog Reset" },
	{ 0x02, "OS Watchdog Shutdown" },
	{ 0x03, "OS Watchdog Power Down" },
	{ 0x04, "OS Watchdog Power Cycle" },
	{ 0x05, "OS Watchdog NMI/Diagnostic Interrupt" },
	{ 0x06, "OS Watchdog Expired, status only" },
	{ 0x07, "OS Watchdog pre-timeout interrupt, non-NMI" },
	{ 0, NULL }
};

static const value_string ssoff_12[] = {
	{ 0x00, "System Reconfigured" },
	{ 0x01, "OEM System Boot Event" },
	{ 0x02, "Undetermined system hardware failure" },
	{ 0x03, "Entry added to Auxiliary Log" },
	{ 0x04, "PEF Action" },
	{ 0x05, "Timestamp Clock Synch" },
	{ 0, NULL }
};

static const value_string ssoff_13[] = {
	{ 0x00, "Front Panel NMI/Diagnostic Interrupt" },
	{ 0x01, "Bus Timeout" },
	{ 0x02, "I/O Channel Check NMI" },
	{ 0x03, "Software NMI" },
	{ 0x04, "PCI PERR" },
	{ 0x05, "PCI SERR" },
	{ 0x06, "EISA Fail Safe Timeout" },
	{ 0x07, "Bus Correctable Error" },
	{ 0x08, "Bus Uncorrectable Error" },
	{ 0x09, "Fatal NMI" },
	{ 0x0a, "Bus Fatal Error" },
	{ 0x0b, "Bus Degraded" },
	{ 0, NULL }
};

static const value_string ssoff_14[] = {
	{ 0x00, "Power Button Pressed" },
	{ 0x01, "Sleep Button Pressed" },
	{ 0x02, "Reset Button Pressed" },
	{ 0x03, "FRU Latch open" },
	{ 0x04, "FRU Service Request Button Pressed" },
	{ 0, NULL }
};

static const value_string ssoff_19[] = {
	{ 0x00, "Soft Power Control Failure" },
	{ 0, NULL }
};

static const value_string ssoff_1b[] = {
	{ 0x00, "Cable/Interconnect is connected" },
	{ 0x01, "Configuration error - Incorrect cable connected / Incorrect interconnection" },
	{ 0, NULL }
};

static const value_string ssoff_1d[] = {
	{ 0x00, "Initiated by Power Up" },
	{ 0x01, "Initiated by hard reset" },
	{ 0x02, "Initiated by warm reset" },
	{ 0x03, "User requested PXE boot" },
	{ 0x04, "Automatic boot to diagnostic" },
	{ 0x05, "OS / run-time software initiated hard reset" },
	{ 0x06, "OS / run-time software initiated warm reset" },
	{ 0x07, "System Restart" },
	{ 0, NULL }
};

static const value_string ssoff_1e[] = {
	{ 0x00, "No bootable media" },
	{ 0x01, "No bootable diskette left in drive" },
	{ 0x02, "PXE Server not found" },
	{ 0x03, "Invalid boot sector" },
	{ 0x04, "Timeout waiting for user selection of boot source" },
	{ 0, NULL }
};

static const value_string ssoff_1f[] = {
	{ 0x00, "A: boot completed" },
	{ 0x01, "C: boot completed" },
	{ 0x02, "PXE boot completed" },
	{ 0x03, "Diagnostic boot completed" },
	{ 0x04, "CD-ROM boot completed" },
	{ 0x05, "ROM boot completed" },
	{ 0x06, "Boot completed - boot device not specified" },
	{ 0, NULL }
};

static const value_string ssoff_20[] = {
	{ 0x00, "Critical stop during OS load/initialization" },
	{ 0x01, "Run-time critical stop" },
	{ 0x02, "OS Graceful Stop" },
	{ 0x03, "OS Graceful Shutdown" },
	{ 0x04, "Soft Shutdown initiated by PEF" },
	{ 0x05, "Agent Not Responding" },
	{ 0, NULL }
};

static const value_string ssoff_21[] = {
	{ 0x00, "Fault Status asserted" },
	{ 0x01, "Identify Status asserted" },
	{ 0x02, "Slot/Connector Device installed/attached" },
	{ 0x03, "Slot/Connector Ready for Device Installation" },
	{ 0x04, "Slot/Connector Ready for Device Removal" },
	{ 0x05, "Slot Power is Off" },
	{ 0x06, "Slot/Connector Device Removal Request" },
	{ 0x07, "Interlock Asserted" },
	{ 0x08, "Slot is Disabled" },
	{ 0x09, "Slot holds spare device" },
	{ 0, NULL }
};

static const value_string ssoff_22[] = {
	{ 0x00, "S0/G0 'working'" },
	{ 0x01, "S1 'sleeping with system h/w & processor context maintained'" },
	{ 0x02, "S2 'sleeping, processor context lost'" },
	{ 0x03, "S3 'sleeping, processor & h/w, memory retained'" },
	{ 0x04, "S4 'non-volatile sleep / suspend-to-disk'" },
	{ 0x05, "S5/G2 'soft-off'" },
	{ 0x06, "S4/S5 'soft-off', particular S4/S5 state cannot be determined" },
	{ 0x07, "G3 / Mechanical Off" },
	{ 0x08, "Sleeping in S1, S2 or S3 states" },
	{ 0x09, "G1 sleeping" },
	{ 0x0a, "S5 entered by override" },
	{ 0x0b, "Legacy ON state" },
	{ 0x0c, "Legacy OFF state" },
	{ 0x0e, "Unknown" },
	{ 0, NULL }
};

static const value_string ssoff_23[] = {
	{ 0x00, "Timer expired, status only" },
	{ 0x01, "Hard Reset" },
	{ 0x02, "Power Down" },
	{ 0x03, "Power Cycle" },
	{ 0x08, "Timer Interrupt" },
	{ 0, NULL }
};

static const value_string ssoff_24[] = {
	{ 0x00, "Platform Generated Page" },
	{ 0x01, "Platform Generated LAN Event" },
	{ 0x02, "Platform Event Trap generated" },
	{ 0x03, "Platform generated SNMP trap" },
	{ 0, NULL }
};

static const value_string ssoff_25[] = {
	{ 0x00, "Entity Present" },
	{ 0x01, "Entity Absent" },
	{ 0x02, "Entity Disabled" },
	{ 0, NULL }
};

static const value_string ssoff_27[] = {
	{ 0x00, "LAN Heartbeat Lost" },
	{ 0x01, "LAN Heartbeat" },
	{ 0, NULL }
};

static const value_string ssoff_28[] = {
	{ 0x00, "Sensor access degraded or unavailable" },
	{ 0x01, "Controller access degraded or unavailable" },
	{ 0x02, "Management controller off-line" },
	{ 0x03, "Management controller unavailable" },
	{ 0x04, "Sensor failure" },
	{ 0x05, "FRU failure" },
	{ 0, NULL }
};

static const value_string ssoff_29[] = {
	{ 0x00, "Battery low" },
	{ 0x01, "Battery failed" },
	{ 0x02, "Battery presence detected" },
	{ 0, NULL }
};

static const value_string ssoff_2a[] = {
	{ 0x00, "Session Activated" },
	{ 0x01, "Session Deactivated" },
	{ 0, NULL }
};

static const value_string ssoff_2b[] = {
	{ 0x00, "Hardware change detected with associated Entity" },
	{ 0x01, "Firmware or software change detected with associated Entity" },
	{ 0x02, "Hardware incompatibility detected with associated Entity" },
	{ 0x03, "Firmware or software incompatibility detected with associated Entity" },
	{ 0x04, "Entity is of an invalid or unsupported hardware version" },
	{ 0x05, "Entity contains an invalid or unsupported firmware or software version" },
	{ 0x06, "Hardware Change detected with associated Entity was successful" },
	{ 0x07, "Software or Firmware Change detected with associated Entity was successful" },
	{ 0, NULL }
};

static const value_string ssoff_2c[] = {
	{ 0x00, "M0 - FRU Not Installed" },
	{ 0x01, "M1 - FRU Inactive" },
	{ 0x02, "M2 - FRU Activation Requested" },
	{ 0x03, "M3 - FRU Activation In Progress" },
	{ 0x04, "M4 - FRU Active" },
	{ 0x05, "M5 - FRU Deactivation Requested" },
	{ 0x06, "M6 - FRU Deactivation In Progress" },
	{ 0x07, "M7 - FRU Communication Lost" },
	{ 0, NULL }
};

static const value_string ssoff_f0[] = {
	{ 0x00, "M0 - FRU Not Installed" },
	{ 0x01, "M1 - FRU Inactive" },
	{ 0x02, "M2 - FRU Activation Requested" },
	{ 0x03, "M3 - FRU Activation In Progress" },
	{ 0x04, "M4 - FRU Active" },
	{ 0x05, "M5 - FRU Deactivation Requested" },
	{ 0x06, "M6 - FRU Deactivation In Progress" },
	{ 0x07, "M7 - FRU Communication Lost" },
	{ 0, NULL }
};

static const value_string ssoff_f1[] = {
	{ 0x00, "IPMB-A disabled, IPMB-B disabled" },
	{ 0x01, "IPMB-A enabled, IPMB-B disabled" },
	{ 0x02, "IPMB-A disabled, IPMB-B enabled" },
	{ 0x03, "IPMB-A enabled, IPMB-B enabled" },
	{ 0, NULL }
};

static const value_string ssoff_f2[] = {
	{ 0x00, "Module handle closed" },
	{ 0x01, "Module handle open" },
	{ 0x02, "Quiesced" },
	{ 0x03, "Backend Power Failure" },
	{ 0x04, "Backend Power Shut Down" },
	{ 0, NULL }
};

static const value_string ssoff_f3[] = {
	{ 0x00, "Global status change" },
	{ 0x01, "Channel status change" },
	{ 0, NULL }
};

static const value_string ssoff_f4[] = {
	{ 0x00, "Minor Reset" },
	{ 0x01, "Major Reset" },
	{ 0x02, "Alarm Cutoff" },
	{ 0, NULL }
};

static bool
ssi_05_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d _U_)
{
	if (b == 0x3 && offs == 0x04) {
		/* LAN Leash Lost */
		proto_tree_add_item(tree, hf_ipmi_se_05_network_controller, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const value_string ssi_08_3_err_vals[] = {
	{ 0x00, "Vendor mismatch" },
	{ 0x01, "Revision mismatch" },
	{ 0x02, "Processor missing" },
	{ 0, NULL }
};

static bool
ssi_08_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d _U_)
{
	if (b == 0x3 && offs == 0x06) {
		/* Configuration error */
		proto_tree_add_item(tree, hf_ipmi_se_08_error_type, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static bool
ssi_0c_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d _U_)
{
	if (b == 0x3) {
		proto_tree_add_item(tree, hf_ipmi_se_0c_memory_module, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const value_string ssi_0f_2_err_vals[] = {
	{ 0x00, "Unspecified" },
	{ 0x01, "No system memory is physically installed" },
	{ 0x02, "No usable system memory" },
	{ 0x03, "Unrecoverable hard-disk/ATAPI/IDE device failure" },
	{ 0x04, "Unrecoverable system board failure" },
	{ 0x05, "Unrecoverable diskette subsystem failure" },
	{ 0x06, "Unrecoverable hard-disk controller failure" },
	{ 0x07, "Unrecoverable PS/2 or USB keyboard failure" },
	{ 0x08, "Removable boot media not found" },
	{ 0x09, "Unrecoverable video controller failure" },
	{ 0x0a, "No video device detected" },
	{ 0x0b, "Firmware (BIOS) ROM corruption detected" },
	{ 0x0c, "CPU voltage mismatch" },
	{ 0x0d, "CPU speed matching failure" },
	{ 0, NULL }
};
static const value_string ssi_0f_2_progress_vals[] = {
	{ 0x00, "Unspecified" },
	{ 0x01, "Memory initialization" },
	{ 0x02, "Hard-disk initialization" },
	{ 0x03, "Secondary processor(s) initialization" },
	{ 0x04, "User authentication" },
	{ 0x05, "User-initiated system setup" },
	{ 0x06, "USB resource configuration" },
	{ 0x07, "PCI resource configuration" },
	{ 0x08, "Option ROM initialization" },
	{ 0x09, "Video initialization" },
	{ 0x0a, "Cache initialization" },
	{ 0x0b, "SM Bus initialization" },
	{ 0x0c, "Keyboard controller initialization" },
	{ 0x0d, "Embedded controller / management controller initialization" },
	{ 0x0e, "Docking station attachment" },
	{ 0x0f, "Enabling docking station" },
	{ 0x10, "Docking station ejection" },
	{ 0x11, "Disabling docking station" },
	{ 0x12, "Calling operating system wake-up vector" },
	{ 0x13, "Starting operating system boot process" },
	{ 0x14, "Baseboard or motherboard initialization" },
	{ 0x15, "Reserved" },
	{ 0x16, "Floppy initialization" },
	{ 0x17, "Keyboard test" },
	{ 0x18, "Pointing device test" },
	{ 0x19, "Primary processor initialization" },
	{ 0, NULL }
};

static bool
ssi_0f_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d _U_)
{

	if (b == 0x3 && offs == 0x00) {
		proto_tree_add_item(tree, hf_ipmi_se_0f_extension_code_err, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	if (b == 0x3 && (offs == 0x01 || offs == 0x02)) {
		proto_tree_add_item(tree, hf_ipmi_se_0f_extension_code_progress, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const struct evtype_info *ssi_10_saveptr;

static bool
ssi_10_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d)
{
	if (b == 0x3 && offs == 0x00) {
		proto_tree_add_item(tree, hf_ipmi_se_10_memory_module, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	if (b == 0x3 && offs == 0x01) {
		ssi_10_saveptr = get_evtype_info(d);
		proto_tree_add_item(tree, hf_ipmi_se_10_evtype, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const true_false_string tfs_deassertion_assertion = {
	"Deassertion",
	"Assertion"
};

static bool
ssi_10_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d)
{
	proto_tree *s_tree;
	const value_string *off_vals;

	if (b == 0x3 && offs == 0x01) {
		if (!ssi_10_saveptr) {
			return false; /* something went wrong */
		}
		off_vals = ssi_10_saveptr->offsets ? ssi_10_saveptr->offsets : et_empty;
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte3, NULL, "Logging details/Offset");
		proto_tree_add_item(s_tree, hf_ipmi_se_10_logging_disable, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_10_event, tvb, 0, 1, ENC_NA);
		d &= 0x0f;
		proto_tree_add_uint_format_value(s_tree, hf_ipmi_se_10_event_offset, tvb, 0, 1,
				d, "%s (0x%02x)", val_to_str_const(d, off_vals, "Unknown"), d);
		return true;
	}
	if (b == 0x3 && offs == 0x05) {
		proto_tree_add_item(tree, hf_ipmi_se_10_sel_filled, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const value_string ssi_12_2_act_vals[] = {
	{ 0x00, "Entry added" },
	{ 0x01, "Entry added because event did not map to standard IPMI event" },
	{ 0x02, "Entry added along with one or more corresponding SEL entries" },
	{ 0x03, "Log cleared" },
	{ 0x04, "Log disabled" },
	{ 0x05, "Log enabled" },
	{ 0, NULL }
};
static const value_string ssi_12_2_type_vals[] = {
	{ 0x00, "MCA Log" },
	{ 0x01, "OEM 1" },
	{ 0x02, "OEM 2" },
	{ 0, NULL }
};
static const value_string ssi_12_2_clock_vals[] = {
	{ 0x00, "SEL Timestamp Clock updated" },
	{ 0x01, "SDR Timestamp Clock updated" },
	{ 0, NULL }
};

static const true_false_string tfs_second_first_pair = {
	"Second of pair",
	"First of pair"
};

static bool
ssi_12_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d _U_)
{
	proto_tree *s_tree;

	if (b == 0x3 && offs == 0x03) {
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte2, NULL, "Log action/type");
		proto_tree_add_item(s_tree, hf_ipmi_se_12_log_entry_action, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		proto_tree_add_item(s_tree, hf_ipmi_se_12_log_type, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	if (b == 0x3 && offs == 0x04) {
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte2, NULL, "PEF Actions to be taken");
		proto_tree_add_item(s_tree, hf_ipmi_se_12_diagnostic_interrupt, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_12_oem_action, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_12_power_cycle, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_12_reset, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_12_power_off, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_12_alert, tvb, 0, 1, ENC_NA);
		return true;
	}
	if (b == 0x3 && offs == 0x05) {
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte2, NULL, "Details");
		proto_tree_add_item(s_tree, hf_ipmi_se_12_event, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_12_timestamp_clock_type, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	}
	return false;
}

static bool
ssi_19_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d _U_)
{
	if (b == 0x3 && offs == 0x00) {
		proto_tree_add_item(tree, hf_ipmi_se_19_requested_power_state, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static bool
ssi_19_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d _U_)
{
	if (b == 0x3 && offs == 0x00) {
		proto_tree_add_item(tree, hf_ipmi_se_19_power_state, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

/* Copied from ipmi_chassis.c */
static const value_string ssi_1d_2_cause_vals[] = {
	{ 0x00, "Unknown" },
	{ 0x01, "Chassis Control command" },
	{ 0x02, "Reset via pushbutton" },
	{ 0x03, "Power-up via pushbutton" },
	{ 0x04, "Watchdog expiration" },
	{ 0x05, "OEM" },
	{ 0x06, "Automatic power-up on AC being applied due to 'always restore' power restore policy" },
	{ 0x07, "Automatic power-up on AC being applied due to 'restore previous power state' power restore policy" },
	{ 0x08, "Reset via PEF" },
	{ 0x09, "Power-cycle via PEF" },
	{ 0x0a, "Soft reset" },
	{ 0x0b, "Power-up via RTC wakeup" },
	{ 0, NULL }
};

static bool
ssi_1d_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d _U_)
{
	if (b == 0x3 && offs == 0x07) {
		proto_tree_add_item(tree, hf_ipmi_se_1d_restart_cause, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static bool
ssi_1d_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d _U_)
{
	char s[ITEM_LABEL_LENGTH];

	ipmi_fmt_channel(s, d);
	if (b == 0x3 && offs == 0x07) {
		proto_tree_add_item(tree, hf_ipmi_se_1d_channel, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const value_string ssi_21_2_type_vals[] = {
	{ 0x00, "PCI" },
	{ 0x01, "Drive Array" },
	{ 0x02, "External Peripheral Connector" },
	{ 0x03, "Docking" },
	{ 0x04, "Other standard internal expansion slot" },
	{ 0x05, "Slot associated with entity specified by Entity ID for sensor" },
	{ 0x06, "AdvancedTCA" },
	{ 0x07, "DIMM/Memory device" },
	{ 0x08, "FAN" },
	{ 0x09, "PCI Express" },
	{ 0x0a, "SCSI (parallel)" },
	{ 0x0b, "SATA/SAS" },
	{ 0, NULL }
};

static bool
ssi_21_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d _U_)
{
	if (b == 0x3) {
		proto_tree_add_item(tree, hf_ipmi_se_21_slot_connector_type, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static bool
ssi_21_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d _U_)
{
	if (b == 0x3) {
		proto_tree_add_item(tree, hf_ipmi_se_21_slot_connector, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const value_string ssi_23_2_intr_vals[] = {
	{ 0x00, "None" },
	{ 0x01, "SMI" },
	{ 0x02, "NMI" },
	{ 0x03, "Messaging interrupt" },
	{ 0x0f, "Unspecified" },
	{ 0, NULL }
};
static const value_string ssi_23_2_use_vals[] = {
	{ 0x01, "BIOS FRB2" },
	{ 0x02, "BIOS/POST" },
	{ 0x03, "OS Load" },
	{ 0x04, "SMS/OS" },
	{ 0x05, "OEM" },
	{ 0x0f, "Unspecified" },
	{ 0, NULL }
};

static bool
ssi_23_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d _U_)
{
	proto_tree *s_tree;

	if (b == 0x3) {
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte2, NULL, "Timer use/interrupt");
		proto_tree_add_item(s_tree, hf_ipmi_se_23_interrupt_type, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		proto_tree_add_item(s_tree, hf_ipmi_se_23_timer_use_at_expiration, tvb, 0, 1, ENC_LITTLE_ENDIAN);

		return true;
	}
	return false;
}

static int ssi28_is_logical_fru;

static bool
ssi_28_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d)
{
	proto_tree *s_tree;

	if (b == 0x3 && (offs == 0x00 || offs == 0x04)) {
		proto_tree_add_item(tree, hf_ipmi_se_28_sensor_number, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	if (b == 0x3 && offs == 0x05) {
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte2, NULL, "FRU details");
		ssi28_is_logical_fru = (d & 0x80) ? 1 : 0;
		proto_tree_add_item(s_tree, hf_ipmi_se_28_logical_fru_device, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_28_lun_for_master_read_write_command, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		proto_tree_add_item(s_tree, hf_ipmi_se_28_private_bus_id, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static bool
ssi_28_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d _U_)
{
	if (b == 0x3 && offs == 0x05) {
		if (ssi28_is_logical_fru == -1) {
			return false; /* something went wrong */
		}
		if (ssi28_is_logical_fru) {
			proto_tree_add_item(tree, hf_ipmi_se_28_fru_device_id_within_controller, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		} else {
			proto_tree_add_item(tree, hf_ipmi_se_28_i2c_slave_address, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		}
		return true;
	}
	return false;
}

static bool
ssi_2a_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d)
{
	proto_item *ti;

	if (b == 0x3) {
		ti = proto_tree_add_item(tree, hf_ipmi_se_2a_user_id, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		if ((d & 0x3f) == 0)
			proto_item_append_text(ti, " (unspecified)");
	}
	return false;
}

static const value_string ssi_2a_3_deact_vals[] = {
	{ 0x00, "Unspecified cause" },
	{ 0x01, "Close Session command" },
	{ 0x02, "Timeout" },
	{ 0x03, "Configuration change" },
	{ 0, NULL }
};

static bool
ssi_2a_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d _U_)
{
	proto_tree *s_tree;

	if (b == 0x3) {
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte3, NULL, "Deactivation cause/Channel #");
		proto_tree_add_item(s_tree, hf_ipmi_se_2a_session_deactivated_by, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		proto_tree_add_item(s_tree, hf_ipmi_se_2a_channel, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const value_string ssi_2b_2_vctype_vals[] = {
	{ 0x00, "Unspecified" },
	{ 0x01, "Management controller device ID" },
	{ 0x02, "Management controller firmware revision" },
	{ 0x03, "Management controller device revision" },
	{ 0x04, "Management controller manufacturer ID" },
	{ 0x05, "Management controller IPMI version" },
	{ 0x06, "Management controller auxiliary firmware ID" },
	{ 0x07, "Management controller firmware boot block" },
	{ 0x08, "Other management controller firmware" },
	{ 0x09, "System firmware (EFI/BIOS) change" },
	{ 0x0a, "SMBIOS change" },
	{ 0x0b, "Operating system change" },
	{ 0x0c, "Operating system loader change" },
	{ 0x0d, "Service or diagnostic partition change" },
	{ 0x0e, "Management software agent change" },
	{ 0x0f, "Management software application change" },
	{ 0x10, "Management software middleware change" },
	{ 0x11, "Programmable hardware change" },
	{ 0x12, "Board/FRU module change" },
	{ 0x13, "Board/FRU component change" },
	{ 0x14, "Board/FRU replaced with equivalent version" },
	{ 0x15, "Board/FRU replaced with newer version" },
	{ 0x16, "Board/FRU replaced with older version" },
	{ 0x17, "Board/FRU configuration change" },
	{ 0, NULL }
};

static bool
ssi_2b_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d _U_)
{
	if (b == 0x3) {
		proto_tree_add_item(tree, hf_ipmi_se_2b_version_change_type, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const value_string ssi_2c_2_cause_vals[] = {
	{ 0x00, "Normal State Change" },
	{ 0x01, "Change commanded by software external to FRU" },
	{ 0x02, "State Change due to operator changing a handle latch" },
	{ 0x03, "State Change due to operator pressing the hot swap push button" },
	{ 0x04, "State Change due to FRU programmatic action" },
	{ 0x05, "Communication lost" },
	{ 0x06, "Communication lost due to local failure" },
	{ 0x07, "State Change due to unexpected extraction" },
	{ 0x08, "State Change due to operator intervention/update" },
	{ 0x09, "Unable to compute IPMB address" },
	{ 0x0a, "Unexpected Deactivation" },
	{ 0x0f, "State Change, Cause Unknown" },
	{ 0, NULL }
};

static bool
ssi_2c_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si,
		uint32_t b, uint32_t offs _U_, uint32_t d)
{
	proto_tree *s_tree;

	if (b == 0x3) {
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte2, NULL, "Previous state/Cause");
		proto_tree_add_item(s_tree, hf_ipmi_se_2c_cause, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		d &= 0xf;
		proto_tree_add_uint_format_value(s_tree, hf_ipmi_se_2c_previous_state, tvb, 0, 1,
				d, "%s (0x%02x)", val_to_str_const(d, si->offsets, "Reserved"), d);
		return true;
	}
	return false;
}

static const value_string ssi_f0_2_cause_vals[] = {
	{ 0x00, "Normal State Change" },
	{ 0x01, "Change Commanded by Shelf Manager with Set FRU Activation" },
	{ 0x02, "State Change due to operator changing a Handle Switch" },
	{ 0x03, "State Change due to FRU programmatic action" },
	{ 0x04, "Communication Lost or Regained" },
	{ 0x05, "Communication Lost or Regained - locally detected" },
	{ 0x06, "Surprise State Change due to extraction" },
	{ 0x07, "State Change due to provided information" },
	{ 0x08, "Invalid Hardware Address Detected" },
	{ 0x09, "Unexpected Deactivation" },
	{ 0x0f, "State Change, Cause Unknown" },
	{ 0, NULL }
};

static bool
ssi_f0_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si,
		uint32_t b, uint32_t offs _U_, uint32_t d)
{
	proto_tree *s_tree;

	if (b == 0x2) {
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte2, NULL, "Previous state/Cause");
		proto_tree_add_item(s_tree, hf_ipmi_se_f0_cause, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		d &= 0xf;
		proto_tree_add_uint_format_value(s_tree, hf_ipmi_se_f0_previous_state, tvb, 0, 1,
				d, "%s (0x%02x)", val_to_str_const(d, si->offsets, "Reserved"), d);
		return true;
	}
	return false;
}

static bool
ssi_f0_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d _U_)
{
	if (b == 0x2) {
		proto_tree_add_item(tree, hf_ipmi_se_f0_fru_id, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static bool
ssi_f1_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d _U_)
{
	if (b == 0x02) {
		proto_tree_add_item(tree, hf_ipmi_se_f1_channel, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const true_false_string tfs_f1_3_override_state = {
	"Override state, bus isolated",
	"Local control state"
};

static const value_string ssi_f1_3_status_vals[] = {
	{ 0x00, "No failure" },
	{ 0x01, "Unable to drive clock HI" },
	{ 0x02, "Unable to drive data HI" },
	{ 0x03, "Unable to drive clock LO" },
	{ 0x04, "Unable to drive data LO" },
	{ 0x05, "Clock low timeout" },
	{ 0x06, "Under test" },
	{ 0x07, "Undiagnosed communications failure" },
	{ 0, NULL }
};

static bool
ssi_f1_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs _U_, uint32_t d _U_)
{
	proto_tree *s_tree;

	if (b == 0x02) {
		s_tree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ipmi_se_evt_evd_byte3, NULL, "Override state / Local status");
		proto_tree_add_item(s_tree, hf_ipmi_se_f1_ipmb_b_override_state, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f1_ipmb_b_local_status, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		proto_tree_add_item(s_tree, hf_ipmi_se_f1_ipmb_a_override_state, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f1_ipmb_a_local_status, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}
	return false;
}

static const true_false_string tfs_provide_not_provide_payload_current = {
	"providing Payload Current",
	"not providing Payload Current (or this is Primary PM)"
};

static const true_false_string tfs_is_good_not_good = {
	"is good",
	"is not good"
};

static const true_false_string tfs_primary_redundant = {
	"Primary",
	"Redundant"
};

static const true_false_string tfs_asserted_not_asserted = {
	"Asserted",
	"Not asserted"
};

static bool
ssi_f3_2(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d _U_)
{
	proto_tree *s_tree;
	proto_item *ti;

	if (b == 0x02 && offs == 0x00) {
		/* Global status change */
		ti = proto_tree_add_item(tree, hf_ipmi_se_f3_global_status, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		s_tree = proto_item_add_subtree(ti, ett_ipmi_se_evt_evd_byte2);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_redundant_pm, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_gs_payload_power, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_gs_management_power, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_role, tvb, 0, 1, ENC_NA);
		return true;
	} else if (b == 0x02 && offs == 0x01) {
		/* Channel status change */
		ti = proto_tree_add_item(tree, hf_ipmi_se_f3_channel_status, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		s_tree = proto_item_add_subtree(ti, ett_ipmi_se_evt_evd_byte2);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_pwr_on, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_payload_power_overcurrent, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_channel_payload_power, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_enable, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_management_power_overcurrent, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_channel_management_power, tvb, 0, 1, ENC_NA);
		proto_tree_add_item(s_tree, hf_ipmi_se_f3_ps1, tvb, 0, 1, ENC_NA);
		return true;
	}

	return false;
}

static bool
ssi_f3_3(proto_tree *tree, tvbuff_t *tvb, const struct sensor_info *si _U_,
		uint32_t b, uint32_t offs, uint32_t d _U_)
{
	if (b == 0x02 && offs == 0x01) {
		/* Channel status change */
		proto_tree_add_item(tree, hf_ipmi_se_f3_power_channel_number, tvb, 0, 1, ENC_LITTLE_ENDIAN);
		return true;
	}

	return false;
}

static void
reinit_statics(void)
{
	ssi_10_saveptr = NULL;
	ssi28_is_logical_fru = -1;
}

static const struct sensor_info *
get_sensor_info(unsigned int stype)
{
	static const struct {
		unsigned int id;
		struct sensor_info si;
	} si_tab[] = {
		{ 0x01, { NULL,     NULL,     NULL,     "Temperature" }},
		{ 0x02, { NULL,     NULL,     NULL,     "Voltage" }},
		{ 0x03, { NULL,     NULL,     NULL,     "Current" }},
		{ 0x04, { NULL,     NULL,     NULL,     "Fan" }},
		{ 0x05, { ssoff_05, ssi_05_2, NULL,     "Physical Security (Chassis Intrusion)" }},
		{ 0x06, { ssoff_06, NULL,     NULL,     "Platform Security Violation Attempt" }},
		{ 0x07, { ssoff_07, NULL,     NULL,     "Processor" }},
		{ 0x08, { ssoff_08, NULL,     ssi_08_3, "Power Supply" }},
		{ 0x09, { ssoff_09, NULL,     NULL,     "Power Unit" }},
		{ 0x0a, { NULL,     NULL,     NULL,     "Cooling Device" }},
		{ 0x0b, { NULL,     NULL,     NULL,     "Other Units-based Sensor (per units given in SDR)" }},
		{ 0x0c, { ssoff_0c, NULL,     ssi_0c_3, "Memory" }},
		{ 0x0d, { ssoff_0d, NULL,     NULL,     "Drive Slot (Bay)" }},
		{ 0x0e, { NULL,     NULL,     NULL,     "POST Memory Resize" }},
		{ 0x0f, { ssoff_0f, ssi_0f_2, NULL,     "System Firmware Progress (formerly POST Error)" }},
		{ 0x10, { ssoff_10, ssi_10_2, ssi_10_3, "Event Logging Disabled" }},
		{ 0x11, { ssoff_11, NULL,     NULL,     "Watchdog 1" }},
		{ 0x12, { ssoff_12, ssi_12_2, NULL,     "System Event" }},
		{ 0x13, { ssoff_13, NULL,     NULL,     "Critical Interrupt" }},
		{ 0x14, { ssoff_14, NULL,     NULL,     "Button" }},
		{ 0x15, { NULL,     NULL,     NULL,     "Module / Board" }},
		{ 0x16, { NULL,     NULL,     NULL,     "Microcontroller / Coprocessor" }},
		{ 0x17, { NULL,     NULL,     NULL,     "Add-in Card" }},
		{ 0x18, { NULL,     NULL,     NULL,     "Chassis" }},
		{ 0x19, { ssoff_19, ssi_19_2, ssi_19_3, "Chip Set" }},
		{ 0x1a, { NULL,     NULL,     NULL,     "Other FRU" }},
		{ 0x1b, { ssoff_1b, NULL,     NULL,     "Cable / Interconnect" }},
		{ 0x1c, { NULL,     NULL,     NULL,     "Terminator" }},
		{ 0x1d, { ssoff_1d, ssi_1d_2, ssi_1d_3, "System Boot / Restart Initiated" }},
		{ 0x1e, { ssoff_1e, NULL,     NULL,     "Boot Error" }},
		{ 0x1f, { ssoff_1f, NULL,     NULL,     "OS Boot" }},
		{ 0x20, { ssoff_20, NULL,     NULL,     "OS Critical Stop" }},
		{ 0x21, { ssoff_21, ssi_21_2, ssi_21_3, "Slot / Connector" }},
		{ 0x22, { ssoff_22, NULL,     NULL,     "System ACPI Power State" }},
		{ 0x23, { ssoff_23, ssi_23_2, NULL,     "Watchdog 2" }},
		{ 0x24, { ssoff_24, NULL,     NULL,     "Platform Alert" }},
		{ 0x25, { ssoff_25, NULL,     NULL,     "Entity Presence" }},
		{ 0x26, { NULL,     NULL,     NULL,     "Monitor ASIC / IC" }},
		{ 0x27, { ssoff_27, NULL,     NULL,     "LAN" }},
		{ 0x28, { ssoff_28, ssi_28_2, ssi_28_3, "Management Subsystem Health" }},
		{ 0x29, { ssoff_29, NULL,     NULL,     "Battery" }},
		{ 0x2a, { ssoff_2a, ssi_2a_2, ssi_2a_3, "Session Audit" }},
		{ 0x2b, { ssoff_2b, ssi_2b_2, NULL,     "Version Change" }},
		{ 0x2c, { ssoff_2c, ssi_2c_2, NULL,     "FRU State" }},
		{ 0xf0, { ssoff_f0, ssi_f0_2, ssi_f0_3, "Hot Swap (ATCA)" }},
		{ 0xf1, { ssoff_f1, ssi_f1_2, ssi_f1_3, "IPMB Physical State (ATCA)" }},
		{ 0xf2, { ssoff_f2, NULL,     NULL,     "Module Hot Swap (AMC.0)" }},
		{ 0xf3, { ssoff_f3, ssi_f3_2, ssi_f3_3, "Power Channel Notification" }},
		{ 0xf4, { ssoff_f4, NULL,     NULL,     "Telco Alarm Input" }}
	};
	static const struct sensor_info si_oem = {
		NULL, NULL, NULL, "OEM Reserved"
	};
	static const struct sensor_info si_rsrv = {
		NULL, NULL, NULL, "Reserved"
	};
	unsigned int i;

	/* Look for explicitly defined ones */
	for (i = 0; i < array_length(si_tab); i++) {
		if (si_tab[i].id == stype) {
			return &si_tab[i].si;
		}
	}

	if (stype >= 0xc0 && stype <= 0xff) {
		return &si_oem;
	}

	return &si_rsrv;
}

static void
parse_platform_event(tvbuff_t *tvb, proto_tree *tree)
{
	proto_item *ti;
	proto_tree *s_tree;
	tvbuff_t *next_tvb;
	unsigned int stype, evtype;
	const struct sensor_info *si;
	const struct evtype_info *eti;
	unsigned int d, b2, b3, offs;
	const value_string *off_vals;

	stype = tvb_get_uint8(tvb, 1);
	si = get_sensor_info(stype);
	evtype = tvb_get_uint8(tvb, 3) & 0x7f;
	eti = get_evtype_info(evtype);

	proto_tree_add_item(tree, hf_ipmi_se_evt_rev, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_uint_format_value(tree, hf_ipmi_se_evt_sensor_type, tvb, 1, 1, stype,
			"%s (0x%02x)", si->desc, stype);
	proto_tree_add_item(tree, hf_ipmi_se_evt_sensor_num, tvb, 2, 1, ENC_LITTLE_ENDIAN);
	ti = proto_tree_add_item(tree, hf_ipmi_se_evt_byte3, tvb, 3, 1, ENC_LITTLE_ENDIAN);
	s_tree = proto_item_add_subtree(ti, ett_ipmi_se_evt_byte3);
	proto_tree_add_item(s_tree, hf_ipmi_se_evt_dir, tvb, 3, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(s_tree, hf_ipmi_se_evt_type, tvb, 3, 1, ENC_LITTLE_ENDIAN);

	offs = tvb_get_uint8(tvb, 4);
	b2 = offs >> 6;
	b3 = (offs >> 4) & 0x3;
	off_vals = eti->offsets ? eti->offsets : si->offsets ? si->offsets : et_empty;

	ti = proto_tree_add_item(tree, hf_ipmi_se_evt_data1, tvb, 4, 1, ENC_LITTLE_ENDIAN);
	s_tree = proto_item_add_subtree(ti, ett_ipmi_se_evt_evd_byte1);
	proto_tree_add_uint_format_value(s_tree, hf_ipmi_se_evt_data1_b2, tvb, 4, 1, offs,
			"%s (0x%02x)", val_to_str_const(b2, eti->byte2, "Reserved"), b2);
	proto_tree_add_uint_format_value(s_tree, hf_ipmi_se_evt_data1_b3, tvb, 4, 1, offs,
			"%s (0x%02x)", val_to_str_const(b3, eti->byte3, "Reserved"), b3);
	offs &= 0x0f;
	proto_tree_add_uint_format_value(s_tree, hf_ipmi_se_evt_data1_offs, tvb, 4, 1, offs,
			"%s (0x%02x)", val_to_str_const(offs, off_vals, "Reserved"), offs);

	/* This is tricky. First, bytes 2-3 are optional and may be absent.
	   Second, the necessity to interpret them either in a generic way or in
	   sensor-specific way depends on the value in byte 1. And at last,
	   there could be mixture of both ways: the byte 2 can relate to
	   'previous state', which could be sensor-specific.

	   Thus, intrp() methods return whether they actually handled the
	   value. If the 'generic' (related to event/reading type) method fails
	   to handle the value, we call the 'specific' one. If that fails as
	   well, we just output it as a hex value.

	   This is further complicated by the fact that in some events, the
	   interpretation of the byte 3 depends on the 2nd byte - which could
	   be specified as having some generic type. Thus, we check it and
	   fall back to "default" display in such weird cases.
	*/
	reinit_statics();
	if (tvb_captured_length(tvb) <= 5) {
		return;
	}

	next_tvb = tvb_new_subset_length(tvb, 5, 1);
	d = tvb_get_uint8(next_tvb, 0);
	if ((eti->intrp2 && eti->intrp2(tree, next_tvb, si, b2, offs, d))
			|| (si->intrp2 && si->intrp2(tree, next_tvb, si, b2, offs, d))) {
		/* One of them succeeded. */
		ti = proto_tree_add_item(tree, hf_ipmi_se_evt_data2, next_tvb, 0, 1, ENC_LITTLE_ENDIAN);
		proto_item_set_hidden(ti);
	} else {
		/* Just add as hex */
		proto_tree_add_item(tree, hf_ipmi_se_evt_data2, next_tvb, 0, 1, ENC_LITTLE_ENDIAN);
	}

	/* Now the same for byte 3 */
	if (tvb_captured_length(tvb) <= 6) {
		return;
	}

	next_tvb = tvb_new_subset_length(tvb, 6, 1);
	d = tvb_get_uint8(next_tvb, 0);
	if ((eti->intrp3 && eti->intrp3(tree, next_tvb, si, b3, offs, d))
			|| (si->intrp3 && si->intrp3(tree, next_tvb, si, b3, offs, d))) {
		/* One of them succeeded. */
		ti = proto_tree_add_item(tree, hf_ipmi_se_evt_data3, next_tvb, 0, 1, ENC_LITTLE_ENDIAN);
		proto_item_set_hidden(ti);
	} else {
		/* Just add as hex */
		proto_tree_add_item(tree, hf_ipmi_se_evt_data3, next_tvb, 0, 1, ENC_LITTLE_ENDIAN);
	}
}

/* Common for set/get config parameters */
static const value_string cp00_sip_vals[] = {
	{ 0x00, "Set complete" },
	{ 0x01, "Set in progress" },
	{ 0x02, "Commit write" },
	{ 0x03, "Reserved" },
	{ 0, NULL }
};

static const struct true_false_string cp10_use_tfs = {
	"BMC uses the following value",
	"BMC uses the value returned from Get System GUID command"
};

static const struct true_false_string cp15_rq_frc_tfs = {
	"Force control operation",
	"Request control operation"
};

static const struct true_false_string cp15_imm_delay_tfs = {
	"Delayed control",
	"Immediate control"
};

static const value_string cp15_op_vals[] = {
	{ 0x00, "Power down" },
	{ 0x01, "Power up" },
	{ 0x02, "Power cycle" },
	{ 0x03, "Hard reset" },
	{ 0x04, "Pulse diagnostic interrupt" },
	{ 0x05, "Initiate a soft-shutdown of OS via ACPI by emulating a fatal overtemperature" },
	{ 0, NULL }
};

static const value_string unique_selects_volatile_string_parameters[] = {
	{ 0, "Selects volatile string parameters" },
	{ 0, NULL }
};

static const value_string unique_disable_message_generation[] = {
	{ 0xFF, "Disable Message Generation" },
	{ 0, NULL }
};

static const value_string unique_sel_is_empty[] = {
	{ 0xFFFF, "SEL is empty" },
	{ 0, NULL }
};

static const value_string unique_event_processed_not_logged[] = {
	{ 0, "Event processed but cannot be logged" },
	{ 0, NULL }
};

static void
cfgparam_00(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp00_sip, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
cfgparam_01(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp01_alert_startup, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp01_startup, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp01_event_msg, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp01_pef, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
cfgparam_02(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp02_diag_intr, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp02_oem_action, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp02_pwr_cycle, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp02_reset, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp02_pwr_down, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp02_alert, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}


static void
cfgparam_03(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp03_startup, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
cfgparam_04(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp04_alert_startup, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
cfgparam_05(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp05_num_evfilters, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
cfgparam_06(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp06_filter, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp06_data, tvb, 1, 20, ENC_NA);
}

static void
cfgparam_07(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp07_filter, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp06_data, tvb, 1, 1, ENC_NA);
}

static void
cfgparam_08(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp08_policies, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
cfgparam_09(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp09_entry, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp09_data, tvb, 1, 3, ENC_NA);
}

static void
cfgparam_10(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp10_useval, tvb, 0, 1, ENC_NA);
	ipmi_add_guid(tree, hf_ipmi_se_cp10_guid, tvb, 1);
}

static void
cfgparam_11(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp11_num_alertstr, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
cfgparam_12(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_item *ti;
	proto_tree *s_tree;

	ti = proto_tree_add_item(tree, hf_ipmi_se_cp12_byte1, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	s_tree = proto_item_add_subtree(ti, ett_ipmi_se_cp12_byte1);
	proto_tree_add_item(s_tree, hf_ipmi_se_cp12_alert_stringsel, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp12_evfilter, tvb, 1, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp12_alert_stringset, tvb, 2, 1, ENC_LITTLE_ENDIAN);
}

static void
cfgparam_13(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp13_stringsel, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp13_blocksel, tvb, 1, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_cp13_string, tvb, 2, -1, ENC_ASCII);
}

static void
cfgparam_14(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_cp14_num_gct, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
cp15_add_group_and_member(proto_tree *tree, tvbuff_t *tvb, unsigned offs, unsigned num)
{
	static int * const byte2[] = { &hf_ipmi_se_cp15_member_check, &hf_ipmi_se_cp15_member_id, NULL };
	const char *gdesc;
	uint8_t tmp;

	tmp = tvb_get_uint8(tvb, offs);
	if (tmp == 0x00) {
		gdesc = " (unspecified)";
	} else if (tmp == 0xff) {
		gdesc = " (all groups)";
	} else {
		gdesc = "";
	}

	proto_tree_add_uint_format(tree, hf_ipmi_se_cp15_group, tvb, offs, 1, tmp,
			"Group ID %d: %d%s", num, tmp, gdesc);
	proto_tree_add_bitmask_text(tree, tvb, offs + 1, 1, NULL, NULL, ett_ipmi_se_cp15_member, byte2, ENC_LITTLE_ENDIAN, 0);
}

static void
cfgparam_15(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree)
{
	static int * const byte2[] = { &hf_ipmi_se_cp15_force, &hf_ipmi_se_cp15_delayed, &hf_ipmi_se_cp15_channel, NULL };
	static int * const byte11[] = { &hf_ipmi_se_cp15_retries, &hf_ipmi_se_cp15_operation, NULL };

	proto_tree_add_item(tree, hf_ipmi_se_cp15_gctsel, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_bitmask_text(tree, tvb, 1, 1, NULL, NULL, ett_ipmi_se_cp15_byte2, byte2, ENC_LITTLE_ENDIAN, 0);
	cp15_add_group_and_member(tree, tvb, 2, 0);
	cp15_add_group_and_member(tree, tvb, 4, 1);
	cp15_add_group_and_member(tree, tvb, 6, 2);
	cp15_add_group_and_member(tree, tvb, 8, 3);
	proto_tree_add_bitmask_text(tree, tvb, 10, 1, NULL, NULL, ett_ipmi_se_cp15_byte11, byte11, ENC_LITTLE_ENDIAN, 0);
}

static const struct {
	void (*intrp)(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree);
	const char *name;
} conf_params[] = {
	{ cfgparam_00, "Set In Progress" },
	{ cfgparam_01, "PEF Control" },
	{ cfgparam_02, "PEF Action global control" },
	{ cfgparam_03, "PEF Startup Delay" },
	{ cfgparam_04, "PEF Alert Startup Delay" },
	{ cfgparam_05, "Number of Event Filters" },
	{ cfgparam_06, "Event Filter Table" },
	{ cfgparam_07, "Event Filter Table Data 1" },
	{ cfgparam_08, "Number of Alert Policy Entries" },
	{ cfgparam_09, "Alert Policy Table" },
	{ cfgparam_10, "System GUID" },
	{ cfgparam_11, "Number of Alert Strings" },
	{ cfgparam_12, "Alert String Keys" },
	{ cfgparam_13, "Alert Strings" },
	{ cfgparam_14, "Number of Group Control Table Entries" },
	{ cfgparam_15, "Group Control Table" }
};

static const value_string vals_11_pef_timer[] = {
	{ 0x00, "Disable Postpone Timer" },
	{ 0xfe, "Temporary PEF disable" },
	{ 0xff, "Get Present Countdown Value" },
	{ 0, NULL }
};

static const struct true_false_string tfs_14_processed = {
	"BMC",
	"software"
};

static const value_string vals_16_op[] = {
	{ 0x00, "Initiate Alert" },
	{ 0x01, "Get Alert Immediate status" },
	{ 0x02, "Clear Alert Immediate status" },
	{ 0x03, "Reserved" },
	{ 0, NULL }
};

static const value_string vals_16_status[] = {
	{ 0x00, "No status" },
	{ 0x01, "Alert was Normal End" },
	{ 0x02, "`Call Retry' retries failed" },
	{ 0x03, "Alert failed due to timeouts waiting for acknowledge on all retries" },
	{ 0xFF, "Alert by this command is in progress" },
	{ 0, NULL }
};

static const struct true_false_string tfs_20_op = {
	"Get SDR Count", "Get sensor count"
};

static const struct true_false_string tfs_20_pop = {
	"Dynamic", "Static"
};

static const value_string vals_28_act[] = {
	{ 0x00, "Do not change individual enables" },
	{ 0x01, "Enable selected event messages" },
	{ 0x02, "Disable selected event messages" },
	{ 0x03, "Reserved" },
	{ 0, NULL }
};

static const struct true_false_string tfs_28_enable = {
	"Enable", "Disable"
};

static const struct true_false_string tfs_29_enabled = {
	"Enabled", "Disabled"
};

static const struct true_false_string tfs_2a_sel = {
	"Selected", "All"
};

static const struct true_false_string tfs_2b_enabled = {
	"Enabled", "Disabled"
};

/* Set event receiver.
 */
static void
rq00(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_00_addr, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_00_lun, tvb, 1, 1, ENC_LITTLE_ENDIAN);
}

/* Get event receiver.
 */
static void
rs01(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_01_addr, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_01_lun, tvb, 1, 1, ENC_LITTLE_ENDIAN);
}

/* Platform event.
 */
static void
rq02(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	parse_platform_event(tvb, tree);
}

/* Get PEF capabilities.
 */
static void
rs10(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	static int * const byte2[] = { &hf_ipmi_se_10_action_oem_filter, &hf_ipmi_se_10_action_diag_intr,
		&hf_ipmi_se_10_action_oem_action, &hf_ipmi_se_10_action_pwr_cycle, &hf_ipmi_se_10_action_reset,
		&hf_ipmi_se_10_action_pwr_down, &hf_ipmi_se_10_action_alert, NULL };

	proto_tree_add_item(tree, hf_ipmi_se_10_pef_version, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_bitmask_text(tree, tvb, 1, 1, "Action support: ", "None", ett_ipmi_se_10_action,
			byte2, ENC_LITTLE_ENDIAN, 0);
	proto_tree_add_item(tree, hf_ipmi_se_10_entries, tvb, 2, 1, ENC_LITTLE_ENDIAN);
}

/* Arm PEF Postpone Timer.
 */
static void
rq11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	uint8_t val;

	val = tvb_get_uint8(tvb, 0);
	proto_tree_add_uint_format(tree, hf_ipmi_se_11_rq_timeout, tvb, 0, 1,
			val, "%s", val_to_str(pinfo->pool, val, vals_11_pef_timer, "Arm Timer for: %d sec"));
}

static void
rs11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	uint8_t val;

	val = tvb_get_uint8(tvb, 0);
	proto_tree_add_uint_format(tree, hf_ipmi_se_11_rs_timeout, tvb, 0, 1,
			val, "%s", val_to_str(pinfo->pool, val, vals_11_pef_timer, "Present Timer Countdown value: %d sec"));
}

/* Set PEF Configuration Parameters.
 */
static void
rq12(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	proto_item *ti;
	proto_tree *s_tree;
	tvbuff_t *sub;
	uint8_t pno;
	const char *desc;

	pno = tvb_get_uint8(tvb, 0) & 0x7f;
	if (pno < array_length(conf_params)) {
		desc = conf_params[pno].name;
	} else if (pno >= 96 && pno <= 127) {
		desc = "OEM";
	} else {
		desc = "Reserved";
	}
	ti = proto_tree_add_uint_format_value(tree, hf_ipmi_se_12_byte1, tvb, 0, 1,
			pno, "%s (0x%02x)", desc, pno);
	s_tree = proto_item_add_subtree(ti, ett_ipmi_se_12_byte1);
	proto_tree_add_uint_format_value(s_tree, hf_ipmi_se_12_param, tvb, 0, 1,
			pno, "Parameter selector: %s (0x%02x)", desc, pno);

	if (pno < array_length(conf_params)) {
		sub = tvb_new_subset_remaining(tvb, 1);
		conf_params[pno].intrp(sub, pinfo, tree);
	} else {
		proto_tree_add_none_format(tree, hf_ipmi_se_12_data, tvb, 1, -1,
				"Configuration parameter data: %s", desc);
	}
}

static const value_string cc12[] = {
	{ 0x80, "Parameter not supported" },
	{ 0x81, "Attempt to set the 'set in progress' value (in parameter #0) when not in the 'set complete' state" },
	{ 0x82, "Attempt to write read-only parameter" },
	{ 0x83, "Attempt to read write-only parameter" },
	{ 0, NULL }
};

/* Get PEF Configuration Parameters.
 */
static void
rq13(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_item *ti;
	proto_tree *s_tree;
	uint32_t pno;
	const char *desc;

	pno = tvb_get_uint8(tvb, 0);

	ipmi_set_data(pinfo, 0, pno);
	if (!tree) {
		/* Just cache parameter selector */
		return;
	}

	pno &= 0x7f;

	if (pno < array_length(conf_params)) {
		desc = conf_params[pno].name;
	} else if (pno >= 96 && pno <= 127) {
		desc = "OEM";
	} else {
		desc = "Reserved";
	}
	ti = proto_tree_add_uint_format_value(tree, hf_ipmi_se_13_byte1, tvb, 0, 1,
			pno, "%s (0x%02x)", desc, pno);
	s_tree = proto_item_add_subtree(ti, ett_ipmi_se_13_byte1);
	proto_tree_add_item(s_tree, hf_ipmi_se_13_getrev, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_uint_format_value(s_tree, hf_ipmi_se_13_param, tvb, 0, 1,
			pno, "%s (0x%02x)", desc, pno);

	proto_tree_add_item(tree, hf_ipmi_se_13_set, tvb, 1, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_13_block, tvb, 2, 1, ENC_LITTLE_ENDIAN);
}

static void
rs13(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	static int * const byte1[] = { &hf_ipmi_se_13_rev_present, &hf_ipmi_se_13_rev_compat, NULL };
	proto_item *ti;
	tvbuff_t *sub;
	uint32_t pno;
	const char *desc;

	ti = proto_tree_add_bitmask_text(tree, tvb, 0, 1, "Parameter revision", NULL,
			ett_ipmi_se_13_rev, byte1, ENC_LITTLE_ENDIAN, 0);

	if (!ipmi_get_data(pinfo, 0, &pno)) {
		/* No request found - cannot parse further */
		if (tvb_captured_length(tvb) > 1) {
			proto_tree_add_item(tree, hf_ipmi_se_13_data, tvb, 1, -1, ENC_NA);
		}
		return;
	}

	if ((pno & 0x80) && tvb_captured_length(tvb) > 1) {
		expert_add_info(pinfo, ti, &ei_ipmi_se_13_request_param_rev);
	} else if (!(pno & 0x80) && tvb_captured_length(tvb) == 1) {
		expert_add_info(pinfo, ti, &ei_ipmi_se_13_request_param_data);
	}

	pno &= 0x7f;
	if (pno < array_length(conf_params)) {
		desc = conf_params[pno].name;
	} else if (pno >= 96 && pno <= 127) {
		desc = "OEM";
	} else {
		desc = "Reserved";
	}

	ti = proto_tree_add_uint_format_value(tree, hf_ipmi_se_13_parameter, tvb, 0, 0,
		pno, "%s", desc);
	proto_item_set_generated(ti);

	if (tvb_captured_length(tvb) > 1) {
		if (pno < array_length(conf_params)) {
			sub = tvb_new_subset_remaining(tvb, 1);
			conf_params[pno].intrp(sub, pinfo, tree);
		} else {
			proto_tree_add_item(tree, hf_ipmi_se_13_data, tvb, 1, -1, ENC_NA);
		}
	}
}

static const value_string cc13[] = {
	{ 0x80, "Parameter not supported" },
	{ 0, NULL }
};

/* Set Last Processed Event ID Command.
 */
static void
rq14(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_14_processed_by, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_14_rid, tvb, 1, 2, ENC_LITTLE_ENDIAN);
}

static const value_string cc14[] = {
	{ 0x81, "Cannot execute command, SEL erase in progress" },
	{ 0, NULL }
};

/* Get Last Processed Event ID Command.
 */
static void
rs15(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	ipmi_add_timestamp(pinfo, tree, hf_ipmi_se_15_tstamp, tvb, 0);
	proto_tree_add_item(tree, hf_ipmi_se_15_lastrec, tvb, 4, 2, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_15_proc_sw, tvb, 6, 2, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_15_proc_bmc, tvb, 8, 2, ENC_LITTLE_ENDIAN);
}

static const value_string cc15[] = {
	{ 0x81, "Cannot execute command, SEL erase in progress" },
	{ 0, NULL }
};

/* Alert Immediate.
 */
static void
rq16(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	static int * const byte1[] = { &hf_ipmi_se_16_chan, NULL };
	static int * const byte2[] = { &hf_ipmi_se_16_op, &hf_ipmi_se_16_dst, NULL };
	static int * const byte3[] = { &hf_ipmi_se_16_send_string, &hf_ipmi_se_16_string_sel, NULL };
	tvbuff_t *sub;

	ipmi_set_data(pinfo, 0, (tvb_get_uint8(tvb, 1) & 0xc0) >> 6);
	if (!tree) {
		/* Save the operation */
		return;
	}

	proto_tree_add_bitmask_text(tree, tvb, 0, 1, NULL, NULL, ett_ipmi_se_16_byte1, byte1, ENC_LITTLE_ENDIAN, 0);
	proto_tree_add_bitmask_text(tree, tvb, 1, 1, NULL, NULL, ett_ipmi_se_16_byte2, byte2, ENC_LITTLE_ENDIAN, 0);
	proto_tree_add_bitmask_text(tree, tvb, 2, 1, NULL, NULL, ett_ipmi_se_16_byte3, byte3, ENC_LITTLE_ENDIAN, 0);
	if (tvb_captured_length(tvb) > 3) {
		proto_tree_add_item(tree, hf_ipmi_se_16_gen, tvb, 3, 1, ENC_LITTLE_ENDIAN);
		sub = tvb_new_subset_remaining(tvb, 4);
		parse_platform_event(sub, tree);
	}
}

static void
rs16(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	uint32_t val;

	if (ipmi_get_data(pinfo, 0, &val) && val == 0x01) {
		/* Operation == Get Alert Immediate Status */
		proto_tree_add_item(tree, hf_ipmi_se_16_status, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	}
}

static const value_string cc16[] = {
	{ 0x81, "Alert Immediate rejected due to alert already in progress" },
	{ 0x82, "Alert Immediate rejected due to IPMI messaging session active on this channel" },
	{ 0x83, "Platform Event parameters not supported" },
	{ 0, NULL }
};

/* PET Acknowledge.
 */
static void
rq17(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_17_seq, tvb, 0, 2, ENC_LITTLE_ENDIAN);
	ipmi_add_timestamp(pinfo, tree, hf_ipmi_se_17_tstamp, tvb, 2);
	proto_tree_add_item(tree, hf_ipmi_se_17_evsrc, tvb, 6, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_17_sensor_dev, tvb, 7, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_17_sensor_num, tvb, 8, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_17_evdata1, tvb, 9, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_17_evdata2, tvb, 10, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_17_evdata3, tvb, 11, 1, ENC_LITTLE_ENDIAN);
}

/* Get Device SDR Info.
 */
static void
rq20(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	if (tvb_captured_length(tvb) > 0) {
		ipmi_set_data(pinfo, 0, tvb_get_uint8(tvb, 0) & 0x01);

		proto_tree_add_item(tree, hf_ipmi_se_20_rq_op, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	}
}

static void
rs20(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	static int * const byte2[] = { &hf_ipmi_se_20_rs_population, &hf_ipmi_se_20_rs_lun3,
		&hf_ipmi_se_20_rs_lun2, &hf_ipmi_se_20_rs_lun1, &hf_ipmi_se_20_rs_lun0, NULL };
	uint32_t val;

	if (ipmi_get_data(pinfo, 0, &val) && val) {
		proto_tree_add_item(tree, hf_ipmi_se_20_rs_sdr, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	} else {
		proto_tree_add_item(tree, hf_ipmi_se_20_rs_num, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	}
	proto_tree_add_bitmask_text(tree, tvb, 1, 1, NULL, NULL, ett_ipmi_se_20_rs_byte2,
			byte2, ENC_LITTLE_ENDIAN, 0);
	if (tvb_get_uint8(tvb, 1) & 0x80) {
		/* Dynamic sensor population */
		proto_tree_add_item(tree, hf_ipmi_se_20_rs_change, tvb, 2, 4, ENC_LITTLE_ENDIAN);
	}
}


/* Get Device SDR.
 */
static void
rq21(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	uint8_t len;

	len = tvb_get_uint8(tvb, 5);

	proto_tree_add_item(tree, hf_ipmi_se_21_rid, tvb, 0, 2, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_21_record, tvb, 2, 2, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_21_offset, tvb, 4, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_uint_format_value(tree, hf_ipmi_se_21_len, tvb, 5, 1, len,
			"%u%s", len, len == 0xff ? "(entire record)" : "");
}

static void
rs21(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_21_next, tvb, 0, 2, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_21_recdata, tvb, 2, -1, ENC_NA);
}

static const value_string cc21[] = {
	{ 0x80, "Record changed" },
	{ 0, NULL }
};

/* Reserve Device SDR Repository.
 */
static void
rs22(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_22_resid, tvb, 0, 2, ENC_LITTLE_ENDIAN);
}

/* Get Sensor Reading Factors.
 */
static void
rq23(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_23_rq_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_23_rq_reading, tvb, 1, 1, ENC_LITTLE_ENDIAN);
}

static inline int16_t
sign_extend(int16_t v, int bits)
{
	if ((v & (1 << (bits - 1))) == 0) {
		return v;
	}

	return v | (0xffff << bits);
}

static void
rs23(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree *s_tree;
	uint16_t tol, acc, accexp, tmp;
	int16_t m, b, bexp, rexp;

	proto_tree_add_item(tree, hf_ipmi_se_23_rs_next_reading, tvb, 0, 1, ENC_LITTLE_ENDIAN);

	m = tvb_get_uint8(tvb, 1);
	tmp = tvb_get_uint8(tvb, 2);
	m |= (tmp & 0xc0) << 2;
	tol = tmp & 0x3f;
	b = tvb_get_uint8(tvb, 3);
	tmp = tvb_get_uint8(tvb, 4);
	b |= (tmp & 0xc0) << 2;
	acc = tmp & 0x3f;
	tmp = tvb_get_uint8(tvb, 5);
	acc |= (tmp & 0xf0) << 4;
	accexp = (tmp & 0x0c) >> 2;
	tmp = tvb_get_uint8(tvb, 6);
	rexp = (tmp & 0xf0) >> 4;
	bexp = tmp & 0x0f;

	m = sign_extend(m, 10);
	b = sign_extend(b, 10);
	bexp = sign_extend(bexp, 4);
	rexp = sign_extend(rexp, 4);

	s_tree = proto_tree_add_subtree_format(tree, tvb, 1, 6, ett_ipmi_se_23_readingfactors, NULL,
			"Factors: M=%d B=%d K1=%d K2=%d Acc=%u*10^%u Tol=%u",
			m, b, bexp, rexp, acc, accexp, tol);

	proto_tree_add_item(s_tree, hf_ipmi_se_23_m, tvb, 1, 2, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(s_tree, hf_ipmi_se_23_tolerance, tvb, 1, 2, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(s_tree, hf_ipmi_se_23_b, tvb, 3, 2, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(s_tree, hf_ipmi_se_23_accuracy, tvb, 4, 2, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(s_tree, hf_ipmi_se_23_accuracy_exponent, tvb, 5, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(s_tree, hf_ipmi_se_23_r_exponent, tvb, 6, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(s_tree, hf_ipmi_se_23_b_exponent, tvb, 6, 1, ENC_LITTLE_ENDIAN);
}

/* Set Sensor Hysteresis.
 */
static void
rq24(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_24_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_24_mask, tvb, 1, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_24_hyst_pos, tvb, 2, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_24_hyst_neg, tvb, 3, 1, ENC_LITTLE_ENDIAN);
}

/* Get Sensor Hysteresis.
 */
static void
rq25(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_25_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_25_mask, tvb, 1, 1, ENC_LITTLE_ENDIAN);
}

static void
rs25(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_25_hyst_pos, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_25_hyst_neg, tvb, 1, 1, ENC_LITTLE_ENDIAN);
}

/* Common for Get/Set Thresholds */
static void
add_thresholds(tvbuff_t *tvb, int offs, proto_tree *tree, const char *desc)
{
	static int * const threshold_mask[] = { &hf_ipmi_se_XX_m_unr, &hf_ipmi_se_XX_m_uc, &hf_ipmi_se_XX_m_unc,
		&hf_ipmi_se_XX_m_lnr, &hf_ipmi_se_XX_m_lc, &hf_ipmi_se_XX_m_lnc, NULL };

	proto_tree_add_bitmask_text(tree, tvb, offs, 1, desc, "None",
			ett_ipmi_se_XX_mask, threshold_mask, ENC_LITTLE_ENDIAN, 0);
	proto_tree_add_item(tree, hf_ipmi_se_XX_thr_lnc, tvb, offs + 1, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_XX_thr_lc, tvb, offs + 2, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_XX_thr_lnr, tvb, offs + 3, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_XX_thr_unc, tvb, offs + 4, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_XX_thr_uc, tvb, offs + 5, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_XX_thr_unr, tvb, offs + 6, 1, ENC_LITTLE_ENDIAN);
}

/* Set Sensor Thresholds.
 */
static void
rq26(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_26_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	add_thresholds(tvb, 1, tree, "Set thresholds: ");
}

/* Get Sensor Thresholds.
 */
static void
rq27(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_27_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
rs27(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	add_thresholds(tvb, 0, tree, "Readable thresholds: ");
}

/* Common for Get EE/Set EE/Rearm
 */
static void
add_events(tvbuff_t *tvb, int offs, proto_tree *tree, const struct true_false_string *tfs,
		const char *desc)
{
	static int * const bsel[4][8] = {
		{ &hf_ipmi_se_XX_b1_0, &hf_ipmi_se_XX_b1_1, &hf_ipmi_se_XX_b1_2, &hf_ipmi_se_XX_b1_3,
			&hf_ipmi_se_XX_b1_4, &hf_ipmi_se_XX_b1_5, &hf_ipmi_se_XX_b1_6, &hf_ipmi_se_XX_b1_7 },
		{ &hf_ipmi_se_XX_b2_0, &hf_ipmi_se_XX_b2_1, &hf_ipmi_se_XX_b2_2, &hf_ipmi_se_XX_b2_3,
			&hf_ipmi_se_XX_b2_4, &hf_ipmi_se_XX_b2_5, &hf_ipmi_se_XX_b2_6, NULL },
		{ &hf_ipmi_se_XX_b3_0, &hf_ipmi_se_XX_b3_1, &hf_ipmi_se_XX_b3_2, &hf_ipmi_se_XX_b3_3,
			&hf_ipmi_se_XX_b3_4, &hf_ipmi_se_XX_b3_5, &hf_ipmi_se_XX_b3_6, &hf_ipmi_se_XX_b3_7 },
		{ &hf_ipmi_se_XX_b4_0, &hf_ipmi_se_XX_b4_1, &hf_ipmi_se_XX_b4_2, &hf_ipmi_se_XX_b4_3,
			&hf_ipmi_se_XX_b4_4, &hf_ipmi_se_XX_b4_5, &hf_ipmi_se_XX_b4_6, NULL }
	};
	static int * const tsel[] = { &ett_ipmi_se_XX_b1, &ett_ipmi_se_XX_b2, &ett_ipmi_se_XX_b3, &ett_ipmi_se_XX_b4 };
	proto_tree *s_tree;
	int len = tvb_captured_length(tvb);
	int i, j, val, msk;

	for (i = 0; (offs < len) && (i < 4); i++, offs++) {
		val = tvb_get_uint8(tvb, offs);
		s_tree = proto_tree_add_subtree_format(tree, tvb, offs, 1, *tsel[i], NULL, "%s (byte %d)", desc, i);
		for (j = 7; j >= 0; j--) {
			if (!bsel[i][j]) {
				continue;
			}
			msk = 1 << j;
			proto_tree_add_boolean_format_value(s_tree, *bsel[i][j], tvb, offs, 1,
					val & msk, "%s", tfs_get_string(val & msk, tfs));
		}
	}
}


/* Set Sensor Event Enable.
 */
static void
rq28(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	static int * const byte2[] = { &hf_ipmi_se_28_fl_evm, &hf_ipmi_se_28_fl_scan, &hf_ipmi_se_28_fl_action, NULL };
	static const struct true_false_string tfs_lect = { "Select", "Do not select" };

	proto_tree_add_item(tree, hf_ipmi_se_28_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_bitmask_text(tree, tvb, 1, 1, NULL, NULL, ett_ipmi_se_28_byte2, byte2, ENC_LITTLE_ENDIAN, 0);
	add_events(tvb, 2, tree, &tfs_lect, "Selected events");
}

/* Get Sensor Event Enable.
 */
static void
rq29(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_29_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
rs29(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	static int * const byte1[] = { &hf_ipmi_se_29_fl_evm, &hf_ipmi_se_29_fl_scan, NULL };

	proto_tree_add_bitmask_text(tree, tvb, 0, 1, NULL, NULL, ett_ipmi_se_29_byte1, byte1, ENC_LITTLE_ENDIAN, 0);
	add_events(tvb, 1, tree, &tfs_29_enabled, "Enabled events");
}

/* Re-arm Sensor Events.
 */
static void
rq2a(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	static const struct true_false_string rearm_tfs = { "Re-arm", "Do not re-arm" };

	proto_tree_add_item(tree, hf_ipmi_se_2a_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_item(tree, hf_ipmi_se_2a_fl_sel, tvb, 1, 1, ENC_LITTLE_ENDIAN);
	add_events(tvb, 2, tree, &rearm_tfs, "Re-arm Events");
}

/* Get Sensor Event Status.
 */
static void
rq2b(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_2b_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
rs2b(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	static int * const byte1[] = { &hf_ipmi_se_2b_fl_evm, &hf_ipmi_se_2b_fl_scan, &hf_ipmi_se_2b_fl_unavail, NULL };
	static const struct true_false_string occur_tfs = { "Occurred", "Did not occur" };

	proto_tree_add_bitmask_text(tree, tvb, 0, 1, NULL, NULL, ett_ipmi_se_2b_byte1, byte1, ENC_LITTLE_ENDIAN, 0);
	add_events(tvb, 1, tree, &occur_tfs, "Event Status");
}

/* Get Sensor Reading.
 */
static void
rq2d(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_2d_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
rs2d(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	/* Reuse flags from Event Status message */
	static int * const byte2[] = { &hf_ipmi_se_2b_fl_evm, &hf_ipmi_se_2b_fl_scan, &hf_ipmi_se_2b_fl_unavail, NULL };
	static int * const bsel[2][8] = {
		{ &hf_ipmi_se_2d_b1_0, &hf_ipmi_se_2d_b1_1, &hf_ipmi_se_2d_b1_2, &hf_ipmi_se_2d_b1_3,
			&hf_ipmi_se_2d_b1_4, &hf_ipmi_se_2d_b1_5, &hf_ipmi_se_2d_b1_6, &hf_ipmi_se_2d_b1_7 },
		{ &hf_ipmi_se_2d_b2_0, &hf_ipmi_se_2d_b2_1, &hf_ipmi_se_2d_b2_2, &hf_ipmi_se_2d_b2_3,
			&hf_ipmi_se_2d_b2_4, &hf_ipmi_se_2d_b2_5, &hf_ipmi_se_2d_b2_6, NULL }
	};
	static int * const tsel[2] = { &ett_ipmi_se_2d_b1, &ett_ipmi_se_2d_b2 };
	proto_tree *s_tree;
	int i, j, len;

	proto_tree_add_item(tree, hf_ipmi_se_2d_reading, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_bitmask_text(tree, tvb, 1, 1, NULL, NULL, ett_ipmi_se_2d_byte2, byte2, ENC_LITTLE_ENDIAN, 0);
	len = tvb_captured_length(tvb);
	for (i = 0; i < 2 && i < len - 2; i++) {
		s_tree = proto_tree_add_subtree_format(tree, tvb, i + 2, 1, *tsel[i], NULL,
				"Threshold comparisons/assertions (byte %d)", i);
		for (j = 7; j >= 0; j--) {
			if (bsel[i][j]) {
				proto_tree_add_item(s_tree, *bsel[i][j], tvb, i + 2, 1, ENC_LITTLE_ENDIAN);
			}
		}
	}
}

/* Set Sensor Type.
 */
static void
rq2e(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	uint8_t stype;
	const struct sensor_info *si;

	stype = tvb_get_uint8(tvb, 1);
	si = get_sensor_info(stype);

	proto_tree_add_item(tree, hf_ipmi_se_2e_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
	proto_tree_add_uint_format_value(tree, hf_ipmi_se_2e_stype, tvb, 1, 1,
			stype, "%s (0x%02x)", si->desc, stype);

	proto_tree_add_item(tree, hf_ipmi_se_2e_evtype, tvb, 2, 1, ENC_LITTLE_ENDIAN);
}

/* Get Sensor Type.
 */
static void
rq2f(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	proto_tree_add_item(tree, hf_ipmi_se_2f_sensor, tvb, 0, 1, ENC_LITTLE_ENDIAN);
}

static void
rs2f(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
	uint8_t stype;
	const struct sensor_info *si;

	stype = tvb_get_uint8(tvb, 0);
	si = get_sensor_info(stype);

	proto_tree_add_uint_format_value(tree, hf_ipmi_se_2f_stype, tvb, 0, 1,
			stype, "%s (0x%02x)", si->desc, stype);

	proto_tree_add_item(tree, hf_ipmi_se_2f_evtype, tvb, 1, 1, ENC_LITTLE_ENDIAN);
}

static const value_string cc30[] = {
	{ 0x80, "Attempt to change not-settable reading/status bits" },
	{ 0x81, "Setting Event Data Bytes not supported" },
	{ 0, NULL }
};

static const ipmi_cmd_t cmd_se[] = {
	/* Event commands */
	{ 0x00, rq00, NULL, NULL, NULL, "Set Event Receiver", 0 },
	{ 0x01, NULL, rs01, NULL, NULL, "Get Event Receiver", 0 },
	{ 0x02, rq02, NULL, NULL, NULL, "Platform Event", 0 },

	/* PEF and Alerting Commands */
	{ 0x10, NULL, rs10, NULL, NULL, "Get PEF Capabilities", 0 },
	{ 0x11, rq11, rs11, NULL, NULL, "Arm PEF Postpone Timer", 0 },
	{ 0x12, rq12, NULL, cc12, NULL, "Set PEF Configuration Parameters", 0 },
	{ 0x13, rq13, rs13, cc13, NULL, "Get PEF Configuration Parameters", CMD_CALLRQ },
	{ 0x14, rq14, NULL, cc14, NULL, "Set Last Processed Event ID", 0 },
	{ 0x15, NULL, rs15, cc15, NULL, "Get Last Processed Event ID", 0 },
	{ 0x16, rq16, rs16, cc16, NULL, "Alert Immediate", CMD_CALLRQ },
	{ 0x17, rq17, NULL, NULL, NULL, "PET Acknowledge", 0 },

	/* Sensor Device Commands */
	{ 0x20, rq20, rs20, NULL, NULL, "Get Device SDR Info", CMD_CALLRQ },
	{ 0x21, rq21, rs21, cc21, NULL, "Get Device SDR", 0 },
	{ 0x22, NULL, rs22, NULL, NULL, "Reserve Device SDR Repository", 0 },
	{ 0x23, rq23, rs23, NULL, NULL, "Get Sensor Reading Factors", 0 },
	{ 0x24, rq24, NULL, NULL, NULL, "Set Sensor Hysteresis", 0 },
	{ 0x25, rq25, rs25, NULL, NULL, "Get Sensor Hysteresis", 0 },
	{ 0x26, rq26, NULL, NULL, NULL, "Set Sensor Threshold", 0 },
	{ 0x27, rq27, rs27, NULL, NULL, "Get Sensor Threshold", 0 },
	{ 0x28, rq28, NULL, NULL, NULL, "Set Sensor Event Enable", 0 },
	{ 0x29, rq29, rs29, NULL, NULL, "Get Sensor Event Enable", 0 },
	{ 0x2a, rq2a, NULL, NULL, NULL, "Re-arm Sensor Events", 0 },
	{ 0x2b, rq2b, rs2b, NULL, NULL, "Get Sensor Event Status", 0 },
	{ 0x2d, rq2d, rs2d, NULL, NULL, "Get Sensor Reading", 0 },
	{ 0x2e, rq2e, NULL, NULL, NULL, "Set Sensor Type", 0 },
	{ 0x2f, rq2f, rs2f, NULL, NULL, "Get Sensor Type", 0 },
	{ 0x30, IPMI_TBD,   cc30, NULL, "Set Sensor Reading and Event Status", 0 },
};

void
proto_register_ipmi_se(void)
{
	static hf_register_info hf[] = {
		{ &hf_ipmi_se_evt_rev,
			{ "Event Message Revision",
				"ipmi.evt.evmrev", FT_UINT8, BASE_HEX, VALS(evt_evm_rev_vals), 0, NULL, HFILL }},
		{ &hf_ipmi_se_evt_sensor_type,
			{ "Sensor Type",
				"ipmi.evt.sensor_type", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_evt_sensor_num,
			{ "Sensor #",
				"ipmi.evt.sensor_num", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_evt_byte3,
			{ "Event Dir/Type",
				"ipmi.evt.byte3", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_evt_dir,
			{ "Event Direction",
				"ipmi.evt.evdir", FT_BOOLEAN, 8, TFS(&evt_evdir_tfs), 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_evt_type,
			{ "Event/Reading type",
				"ipmi.evt.evtype", FT_UINT8, BASE_HEX|BASE_RANGE_STRING, RVALS(evtype_rvals), 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_evt_data1,
			{ "Event Data 1",
				"ipmi.evt.data1", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_evt_data1_b2,
			{ "Byte 2",
				"ipmi.evt.data1.b2", FT_UINT8, BASE_HEX, NULL, 0xc0, NULL, HFILL }},
		{ &hf_ipmi_se_evt_data1_b3,
			{ "Byte 3",
				"ipmi.evt.data1.b3", FT_UINT8, BASE_HEX, NULL, 0x30, NULL, HFILL }},
		{ &hf_ipmi_se_evt_data1_offs,
			{ "Offset",
				"ipmi.evt.data1.offs", FT_UINT8, BASE_HEX, NULL, 0x0f, NULL, HFILL }},
		{ &hf_ipmi_se_evt_data2,
			{ "Event Data 2",
				"ipmi.evt.data2", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_evt_data3,
			{ "Event Data 3",
				"ipmi.evt.data3", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_cp00_sip,
			{ "Set In Progress",
				"ipmi.cp00.sip", FT_UINT8, BASE_HEX, VALS(cp00_sip_vals), 0x03, NULL, HFILL }},
		{ &hf_ipmi_se_cp01_alert_startup,
			{ "PEF Alert Startup Delay disable",
				"ipmi.cp01.alert_startup", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_cp01_startup,
			{ "PEF Startup Delay disable",
				"ipmi.cp01.startup", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_cp01_event_msg,
			{ "Enable Event Messages for PEF actions",
				"ipmi.cp01.event_msg", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_cp01_pef,
			{ "Enable PEF",
				"ipmi.cp01.pef", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_cp02_diag_intr,
			{ "Enable Diagnostic Interrupt",
				"ipmi.cp02.diag_intr", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_cp02_oem_action,
			{ "Enable OEM action",
				"ipmi.cp02.oem_action", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_cp02_pwr_cycle,
			{ "Enable Power Cycle action",
				"ipmi.cp02.pwr_cycle", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_cp02_reset,
			{ "Enable Reset action",
				"ipmi.cp02.reset", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_cp02_pwr_down,
			{ "Enable Power Down action",
				"ipmi.cp02.pwr_down", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_cp02_alert,
			{ "Enable Alert action",
				"ipmi.cp02.alert", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_cp03_startup,
			{ "PEF Startup delay",
				"ipmi.cp03.startup", FT_UINT8, BASE_CUSTOM, CF_FUNC(ipmi_fmt_1s_1based), 0, NULL, HFILL }},
		{ &hf_ipmi_se_cp04_alert_startup,
			{ "PEF Alert Startup delay",
				"ipmi.cp04.alert_startup", FT_UINT8, BASE_CUSTOM, CF_FUNC(ipmi_fmt_1s_1based), 0, NULL, HFILL }},
		{ &hf_ipmi_se_cp05_num_evfilters,
			{ "Number of Event Filters",
				"ipmi.cp05.num_evfilters", FT_UINT8, BASE_DEC, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_cp06_filter,
			{ "Filter number (set selector)",
				"ipmi.cp06.filter", FT_UINT8, BASE_DEC, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_cp06_data,
			{ "Filter data",
				"ipmi.cp06.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_cp07_filter,
			{ "Filter number (set selector)",
				"ipmi.cp07.filter", FT_UINT8, BASE_DEC, NULL, 0x7f, NULL, HFILL }},
#if 0
		{ &hf_ipmi_se_cp07_data,
			{ "Filter data (byte 1)",
				"ipmi.cp07.data", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
#endif
		{ &hf_ipmi_se_cp08_policies,
			{ "Number of Alert Policy Entries",
				"ipmi.cp08.policies", FT_UINT8, BASE_DEC, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_cp09_entry,
			{ "Entry number (set selector)",
				"ipmi.cp09.entry", FT_UINT8, BASE_DEC, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_cp09_data,
			{ "Entry data",
				"ipmi.cp09.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_cp10_useval,
			{ "Used to fill the GUID field in PET Trap",
				"ipmi.cp10.useval", FT_BOOLEAN, 8, TFS(&cp10_use_tfs), 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_cp10_guid,
			{ "GUID",
				"ipmi.cp10.guid", FT_GUID, BASE_NONE, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_cp11_num_alertstr,
			{ "Number of Alert Strings",
				"ipmi.cp11.num_alertstr", FT_UINT8, BASE_DEC, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_cp12_byte1,
			{ "Alert String Selector",
				"ipmi.cp12.byte1", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_cp12_alert_stringsel,
			{ "Alert String Selector (set selector)",
				"ipmi.cp12.alert_stringsel", FT_UINT8, BASE_HEX|BASE_SPECIAL_VALS, VALS(unique_selects_volatile_string_parameters), 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_cp12_evfilter,
			{ "Filter Number",
				"ipmi.cp12.evfilter", FT_UINT8, BASE_HEX, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_cp12_alert_stringset,
			{ "Set number for string",
				"ipmi.cp12.alert_stringset", FT_UINT8, BASE_HEX, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_cp13_stringsel,
			{ "String selector (set selector)",
				"ipmi.cp13.stringsel", FT_UINT8, BASE_HEX, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_cp13_blocksel,
			{ "Block selector",
				"ipmi.cp13.blocksel", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_cp13_string,
			{ "String data",
				"ipmi.cp13.string", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_cp14_num_gct,
			{ "Number of Group Control Table entries",
				"ipmi.cp14.num_gct", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_cp15_gctsel,
			{ "Group control table entry selector (set selector)",
				"ipmi.cp15.gctsel", FT_UINT8, BASE_HEX, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_cp15_force,
			{ "Request/Force",
				"ipmi.cp15.force", FT_BOOLEAN, 8, TFS(&cp15_rq_frc_tfs), 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_cp15_delayed,
			{ "Immediate/Delayed",
				"ipmi.cp15.delayed", FT_BOOLEAN, 8, TFS(&cp15_imm_delay_tfs), 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_cp15_channel,
			{ "Channel",
				"ipmi.cp15.channel", FT_UINT8, BASE_CUSTOM, CF_FUNC(ipmi_fmt_channel), 0x0f, NULL, HFILL }},
		{ &hf_ipmi_se_cp15_group,
			{ "Group ID",
				"ipmi.cp15.group_id", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_cp15_member_check,
			{ "Member ID check disabled",
				"ipmi.cp15.member_check", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_cp15_member_id,
			{ "Member ID",
				"ipmi.cp15_member_id", FT_UINT8, BASE_DEC, NULL, 0x0f, NULL, HFILL }},
		{ &hf_ipmi_se_cp15_retries,
			{ "Retries",
				"ipmi.cp15.retries", FT_UINT8, BASE_DEC, NULL, 0x70, NULL, HFILL }},
		{ &hf_ipmi_se_cp15_operation,
			{ "Operation",
				"ipmi.cp15.operation", FT_UINT8, BASE_HEX, VALS(cp15_op_vals), 0x0f, NULL, HFILL }},

		{ &hf_ipmi_se_00_addr,
			{ "Event Receiver slave address",
				"ipmi.se00.addr", FT_UINT8, BASE_HEX|BASE_SPECIAL_VALS, VALS(unique_disable_message_generation), 0, NULL, HFILL }},
		{ &hf_ipmi_se_00_lun,
			{ "Event Receiver LUN",
				"ipmi.se00.lun", FT_UINT8, BASE_HEX, NULL, 0x3, NULL, HFILL }},

		{ &hf_ipmi_se_01_addr,
			{ "Event Receiver slave address",
				"ipmi.se01.addr", FT_UINT8, BASE_HEX|BASE_SPECIAL_VALS, VALS(unique_disable_message_generation), 0, NULL, HFILL }},
		{ &hf_ipmi_se_01_lun,
			{ "Event Receiver LUN",
				"ipmi.se01.lun", FT_UINT8, BASE_HEX, NULL, 0x3, NULL, HFILL }},

		{ &hf_ipmi_se_10_pef_version,
			{ "PEF Version",
				"ipmi.se10.pef_version", FT_UINT8, BASE_CUSTOM, CF_FUNC(ipmi_fmt_version), 0, NULL, HFILL }},
		{ &hf_ipmi_se_10_action_oem_filter,
			{ "OEM Event Record Filtering supported",
				"ipmi.se10.action.oem_filter", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_10_action_diag_intr,
			{ "Diagnostic Interrupt",
				"ipmi.se10.action.diag_intr", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_10_action_oem_action,
			{ "OEM Action",
				"ipmi.se10.action.oem_action", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_10_action_pwr_cycle,
			{ "Power Cycle",
				"ipmi.se10.action.pwr_cycle", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_10_action_reset,
			{ "Reset",
				"ipmi.se10.action.reset", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_10_action_pwr_down,
			{ "Power Down",
				"ipmi.se10.action.pwr_down", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_10_action_alert,
			{ "Alert",
				"ipmi.se10.action.alert", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_10_entries,
			{ "Number of event filter table entries",
				"ipmi.se10.entries", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_10_evtype,
			{ "Event/Reading type",
				"ipmi.se10.evtype", FT_UINT8, BASE_HEX|BASE_RANGE_STRING, RVALS(evtype_rvals), 0x7f, NULL, HFILL }},

		{ &hf_ipmi_se_11_rq_timeout,
			{ "Timeout value",
				"ipmi.se11.rq_timeout", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_11_rs_timeout,
			{ "Timeout value",
				"ipmi.se11.rs_timeout", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_12_byte1,
			{ "Parameter selector",
				"ipmi.se12.byte1", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_12_param,
			{ "Parameter selector",
				"ipmi.se12.param", FT_UINT8, BASE_HEX, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_12_data,
			{ "Parameter data",
				"ipmi.se12.data", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_13_byte1,
			{ "Parameter selector",
				"ipmi.se13.byte1", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_13_getrev,
			{ "Get Parameter Revision only",
				"ipmi.se13.getrev", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_13_param,
			{ "Parameter selector",
				"ipmi.se13.param", FT_UINT8, BASE_HEX, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_13_set,
			{ "Set Selector",
				"ipmi.se13.set", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_13_block,
			{ "Block Selector",
				"ipmi.se13.block", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_13_rev_present,
			{ "Present",
				"ipmi.se13.rev.present", FT_UINT8, BASE_DEC, NULL, 0xf0, NULL, HFILL }},
		{ &hf_ipmi_se_13_rev_compat,
			{ "Oldest forward-compatible",
				"ipmi.se13.rev.compat", FT_UINT8, BASE_DEC, NULL, 0x0f, NULL, HFILL }},
		{ &hf_ipmi_se_13_data,
			{ "Parameter data",
				"ipmi.se13.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_14_processed_by,
			{ "Set Record ID for last record processed by",
				"ipmi.se14.processed_by", FT_BOOLEAN, 8, TFS(&tfs_14_processed), 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_14_rid,
			{ "Record ID",
				"ipmi.se14.rid", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_15_tstamp,
			{ "Most recent addition timestamp",
				"ipmi.se15.tstamp", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_15_lastrec,
			{ "Record ID for last record in SEL",
				"ipmi.se15.lastrec", FT_UINT16, BASE_HEX|BASE_SPECIAL_VALS, VALS(unique_sel_is_empty), 0, NULL, HFILL }},
		{ &hf_ipmi_se_15_proc_sw,
			{ "Last SW Processed Event Record ID",
				"ipmi.se15.proc_sw", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_15_proc_bmc,
			{ "Last BMC Processed Event Record ID",
				"ipmi.se15.proc_bmc", FT_UINT16, BASE_HEX|BASE_SPECIAL_VALS, VALS(unique_event_processed_not_logged), 0, NULL, HFILL }},

		{ &hf_ipmi_se_16_chan,
			{ "Channel",
				"ipmi.se16.chan", FT_UINT8, BASE_CUSTOM, CF_FUNC(ipmi_fmt_channel), 0x0f, NULL, HFILL }},
		{ &hf_ipmi_se_16_op,
			{ "Operation",
				"ipmi.se16.op", FT_UINT8, BASE_HEX, VALS(vals_16_op), 0xc0, NULL, HFILL }},
		{ &hf_ipmi_se_16_dst,
			{ "Destination",
				"ipmi.se16.dst", FT_UINT8, BASE_HEX, NULL, 0x0f, NULL, HFILL }},
		{ &hf_ipmi_se_16_send_string,
			{ "Send Alert String",
				"ipmi.se16.send_string", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_16_string_sel,
			{ "String selector",
				"ipmi.se16.string_sel", FT_UINT8, BASE_HEX, NULL, 0x7f, NULL, HFILL }},
		{ &hf_ipmi_se_16_gen,
			{ "Generator ID",
				"ipmi.se16.gen", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_16_status,
			{ "Alert Immediate Status",
				"ipmi.se16.status", FT_UINT8, BASE_HEX, VALS(vals_16_status), 0, NULL, HFILL }},

		{ &hf_ipmi_se_17_seq,
			{ "Sequence Number",
				"ipmi.se17.seq", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_17_tstamp,
			{ "Local Timestamp",
				"ipmi.se17.tstamp", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_17_evsrc,
			{ "Event Source Type",
				"ipmi.se17.evsrc", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_17_sensor_dev,
			{ "Sensor Device",
				"ipmi.se17.sensor_dev", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_17_sensor_num,
			{ "Sensor Number",
				"ipmi.se17.sensor_num", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_17_evdata1,
			{ "Event Data 1",
				"ipmi.se17.evdata1", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_17_evdata2,
			{ "Event Data 2",
				"ipmi.se17.evdata2", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_17_evdata3,
			{ "Event Data 3",
				"ipmi.se17.evdata3", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_20_rq_op,
			{ "Operation",
				"ipmi.se20.rq_op", FT_BOOLEAN, 8, TFS(&tfs_20_op), 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_20_rs_num,
			{ "Number of sensors in device for LUN",
				"ipmi.se20.rs_num", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_20_rs_sdr,
			{ "Total Number of SDRs in the device",
				"ipmi.se20.rs_sdr", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_20_rs_population,
			{ "Sensor population",
				"ipmi.se20.rs_population", FT_BOOLEAN, 8, TFS(&tfs_20_pop), 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_20_rs_lun3,
			{ "LUN3 has sensors",
				"ipmi.se20.rs_lun3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_20_rs_lun2,
			{ "LUN2 has sensors",
				"ipmi.se20.rs_lun2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_20_rs_lun1,
			{ "LUN1 has sensors",
				"ipmi.se20.rs_lun1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_20_rs_lun0,
			{ "LUN0 has sensors",
				"ipmi.se20.rs_lun0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_20_rs_change,
			{ "Sensor Population Change Indicator",
				"ipmi.se20.rs_change", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_21_rid,
			{ "Reservation ID",
				"ipmi.se21.rid", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_21_record,
			{ "Record ID",
				"ipmi.se21.record", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_21_offset,
			{ "Offset into data",
				"ipmi.se21.offset", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_21_len,
			{ "Bytes to read",
				"ipmi.se21.len", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_21_next,
			{ "Next record ID",
				"ipmi.se21.next", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_21_recdata,
			{ "Record data",
				"ipmi.se21.recdata", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_22_resid,
			{ "Reservation ID",
				"ipmi.se22.resid", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_23_rq_sensor,
			{ "Sensor Number",
				"ipmi.se23.rq_sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_23_rq_reading,
			{ "Reading",
				"ipmi.se23.rq_reading", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_23_rs_next_reading,
			{ "Next reading",
				"ipmi.se23.rs_next_reading", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_24_sensor,
			{ "Sensor Number",
				"ipmi.se24.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_24_mask,
			{ "Reserved for future 'hysteresis mask'",
				"ipmi.se24.mask", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_24_hyst_pos,
			{ "Positive-going hysteresis",
				"ipmi.se24.hyst_pos", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_24_hyst_neg,
			{ "Negative-going hysteresis",
				"ipmi.se24.hyst_neg", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_25_sensor,
			{ "Sensor Number",
				"ipmi.se25.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_25_mask,
			{ "Reserved for future 'hysteresis mask'",
				"ipmi.se25.mask", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_25_hyst_pos,
			{ "Positive-going hysteresis",
				"ipmi.se25.hyst_pos", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_25_hyst_neg,
			{ "Negative-going hysteresis",
				"ipmi.se25.hyst_neg", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_26_sensor,
			{ "Sensor Number",
				"ipmi.seXX.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_XX_m_unr,
			{ "Upper Non-Recoverable",
				"ipmi.seXX.mask.unr", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_XX_m_uc,
			{ "Upper Critical",
				"ipmi.seXX.mask.uc", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_XX_m_unc,
			{ "Upper Non-Critical",
				"ipmi.seXX.mask.unc", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_XX_m_lnr,
			{ "Lower Non-Recoverable",
				"ipmi.seXX.mask.lnr", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_XX_m_lc,
			{ "Lower Critical",
				"ipmi.seXX.mask.lc", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_XX_m_lnc,
			{ "Lower Non-Critical",
				"ipmi.seXX.mask.lnc", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_XX_thr_lnc,
			{ "Lower Non-Critical Threshold",
				"ipmi.seXX.lnc", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_XX_thr_lc,
			{ "Lower Critical Threshold",
				"ipmi.seXX.lc", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_XX_thr_lnr,
			{ "Lower Non-Recoverable Threshold",
				"ipmi.seXX.lnr", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_XX_thr_unc,
			{ "Upper Non-Critical Threshold",
				"ipmi.seXX.unc", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_XX_thr_uc,
			{ "Upper Critical Threshold",
				"ipmi.seXX.uc", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_XX_thr_unr,
			{ "Upper Non-Recoverable Threshold",
				"ipmi.seXX.unr", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_27_sensor,
			{ "Sensor Number",
				"ipmi.se27.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},

		{ &hf_ipmi_se_XX_b1_7,
			{ "Assertion for UNC (going high) / state bit 7",
				"ipmi.seXX.a_7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b1_6,
			{ "Assertion for UNC (going low) / state bit 6",
				"ipmi.seXX.a_6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b1_5,
			{ "Assertion for LNR (going high) / state bit 5",
				"ipmi.seXX.a_5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b1_4,
			{ "Assertion for LNR (going low) / state bit 4",
				"ipmi.seXX.a_4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b1_3,
			{ "Assertion for LC (going high) / state bit 3",
				"ipmi.seXX.a_3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b1_2,
			{ "Assertion for LC (going low) / state bit 2",
				"ipmi.seXX.a_2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b1_1,
			{ "Assertion for LNC (going high) / state bit 1",
				"ipmi.seXX.a_1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b1_0,
			{ "Assertion for LNC (going low) / state bit 0",
				"ipmi.seXX.a_0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b2_6,
			{ "Reserved / Assertion for state bit 14",
				"ipmi.seXX.a_14", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b2_5,
			{ "Reserved / Assertion for state bit 13",
				"ipmi.seXX.a_13", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b2_4,
			{ "Reserved / Assertion for state bit 12",
				"ipmi.seXX.a_12", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b2_3,
			{ "Assertion for UNR (going high) / state bit 11",
				"ipmi.seXX.a_11", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b2_2,
			{ "Assertion for UNR (going low) / state bit 10",
				"ipmi.seXX.a_10", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b2_1,
			{ "Assertion for UC (going high) / state bit 9",
				"ipmi.seXX.a_9", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b2_0,
			{ "Assertion for UC (going low) / state bit 8",
				"ipmi.seXX.a_8", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b3_7,
			{ "Deassertion for UNC (going high) / state bit 7",
				"ipmi.seXX.d_7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b3_6,
			{ "Deassertion for UNC (going low) / state bit 6",
				"ipmi.seXX.d_6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b3_5,
			{ "Deassertion for LNR (going high) / state bit 5",
				"ipmi.seXX.d_5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b3_4,
			{ "Deassertion for LNR (going low) / state bit 4",
				"ipmi.seXX.d_4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b3_3,
			{ "Deassertion for LC (going high) / state bit 3",
				"ipmi.seXX.d_3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b3_2,
			{ "Deassertion for LC (going low) / state bit 2",
				"ipmi.seXX.d_2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b3_1,
			{ "Deassertion for LNC (going high) / state bit 1",
				"ipmi.seXX.d_1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b3_0,
			{ "Deassertion for LNC (going low) / state bit 0",
				"ipmi.seXX.d_0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b4_6,
			{ "Reserved / Deassertion for state bit 14",
				"ipmi.seXX.d_14", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b4_5,
			{ "Reserved / Deassertion for state bit 13",
				"ipmi.seXX.d_13", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b4_4,
			{ "Reserved / Deassertion for state bit 12",
				"ipmi.seXX.d_12", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b4_3,
			{ "Deassertion for UNR (going high) / state bit 11",
				"ipmi.seXX.d_11", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b4_2,
			{ "Deassertion for UNR (going low) / state bit 10",
				"ipmi.seXX.d_10", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b4_1,
			{ "Deassertion for UC (going high) / state bit 9",
				"ipmi.seXX.d_9", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_XX_b4_0,
			{ "Deassertion for UC (going low) / state bit 8",
				"ipmi.seXX.d_8", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},

		{ &hf_ipmi_se_28_sensor,
			{ "Sensor Number",
				"ipmi.se28.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_28_fl_evm,
			{ "Event Messages",
				"ipmi.se28.fl_evm", FT_BOOLEAN, 8, TFS(&tfs_28_enable), 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_28_fl_scan,
			{ "Scanning",
				"ipmi.se28.fl_scan", FT_BOOLEAN, 8, TFS(&tfs_28_enable), 0x40, NULL, HFILL }},
		{ &hf_ipmi_se_28_fl_action,
			{ "Action",
				"ipmi.se28.fl_action", FT_UINT8, BASE_HEX, VALS(vals_28_act), 0x30, NULL, HFILL }},

		{ &hf_ipmi_se_29_sensor,
			{ "Sensor Number",
				"ipmi.se29.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_29_fl_evm,
			{ "Event Messages",
				"ipmi.se29.fl_evm", FT_BOOLEAN, 8, TFS(&tfs_29_enabled), 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_29_fl_scan,
			{ "Scanning",
				"ipmi.se29.fl_scan", FT_BOOLEAN, 8, TFS(&tfs_29_enabled), 0x40, NULL, HFILL }},

		{ &hf_ipmi_se_2a_sensor,
			{ "Sensor Number",
				"ipmi.se2a.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_2a_fl_sel,
			{ "Re-arm Events",
				"ipmi.se2a.fl_sel", FT_BOOLEAN, 8, TFS(&tfs_2a_sel), 0x80, NULL, HFILL }},

		{ &hf_ipmi_se_2b_sensor,
			{ "Sensor Number",
				"ipmi.se2b.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_2b_fl_evm,
			{ "Event Messages",
				"ipmi.se2b.fl_evm", FT_BOOLEAN, 8, TFS(&tfs_2b_enabled), 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_2b_fl_scan,
			{ "Sensor scanning",
				"ipmi.se2b.fl_scan", FT_BOOLEAN, 8, TFS(&tfs_2b_enabled), 0x40, NULL, HFILL }},
		{ &hf_ipmi_se_2b_fl_unavail,
			{ "Reading/status unavailable",
				"ipmi.se2b.fl_unavail", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},

		{ &hf_ipmi_se_2d_sensor,
			{ "Sensor Number",
				"ipmi.se2d.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_2d_reading,
			{ "Sensor Reading",
				"ipmi.se2d.reading", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b1_7,
			{ "Reserved / State 7 asserted",
				"ipmi.se2d.b1_7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b1_6,
			{ "Reserved / State 6 asserted",
				"ipmi.se2d.b1_6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b1_5,
			{ "At or above UNR threshold / State 5 asserted",
				"ipmi.se2d.b1_5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b1_4,
			{ "At or above UC threshold / State 4 asserted",
				"ipmi.se2d.b1_4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b1_3,
			{ "At or above UNC threshold / State 3 asserted",
				"ipmi.se2d.b1_3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b1_2,
			{ "At or below LNR threshold / State 2 asserted",
				"ipmi.se2d.b1_2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b1_1,
			{ "At or below LC threshold / State 1 asserted",
				"ipmi.se2d.b1_1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b1_0,
			{ "At or below LNC threshold / State 0 asserted",
				"ipmi.se2d.b1_0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b2_6,
			{ "Reserved / State 14 asserted",
				"ipmi.se2d.b1_6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b2_5,
			{ "Reserved / State 13 asserted",
				"ipmi.se2d.b1_5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b2_4,
			{ "Reserved / State 12 asserted",
				"ipmi.se2d.b1_4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b2_3,
			{ "Reserved / State 11 asserted",
				"ipmi.se2d.b1_3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b2_2,
			{ "Reserved / State 10 asserted",
				"ipmi.se2d.b1_2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b2_1,
			{ "Reserved / State 9 asserted",
				"ipmi.se2d.b1_1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_2d_b2_0,
			{ "Reserved / State 8 asserted",
				"ipmi.se2d.b1_0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},

		{ &hf_ipmi_se_2e_sensor,
			{ "Sensor number",
				"ipmi.se2e.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_2e_stype,
			{ "Sensor type",
				"ipmi.se2e.stype", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_2e_evtype,
			{ "Event/Reading type",
				"ipmi.se2e.evtype", FT_UINT8, BASE_HEX|BASE_RANGE_STRING, RVALS(evtype_rvals), 0x7f, NULL, HFILL }},

		{ &hf_ipmi_se_2f_sensor,
			{ "Sensor number",
				"ipmi.se2f.sensor", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_2f_stype,
			{ "Sensor type",
				"ipmi.se2f.stype", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
		{ &hf_ipmi_se_2f_evtype,
			{ "Event/Reading type",
				"ipmi.se2f.evtype", FT_UINT8, BASE_HEX|BASE_RANGE_STRING, RVALS(evtype_rvals), 0x7f, NULL, HFILL }},

		/* Generated from convert_proto_tree_add_text.pl */
		{ &hf_ipmi_se_evt_trigger_reading, { "Trigger reading", "ipmi.evt.trigger_reading", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_evt_trigger_threshold, { "Trigger threshold", "ipmi.evt.trigger_threshold", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_pst_severity, { "Severity", "ipmi.pst.severity", FT_UINT8, BASE_HEX, VALS(etoff_07), 0xF0, NULL, HFILL }},
		{ &hf_ipmi_se_pst_previous_state, { "Previous state", "ipmi.pst.previous_state", FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL }},
		{ &hf_ipmi_se_05_network_controller, { "Network controller #", "ipmi.se05.network_controller", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_08_error_type, { "Error type", "ipmi.se08.error_type", FT_UINT8, BASE_HEX, VALS(ssi_08_3_err_vals), 0x0F, NULL, HFILL }},
		{ &hf_ipmi_se_0c_memory_module, { "Memory module/device ID", "ipmi.se0c.memory_module", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_0f_extension_code_err, { "Extension code", "ipmi.se0f.extension_code", FT_UINT8, BASE_HEX, VALS(ssi_0f_2_err_vals), 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_0f_extension_code_progress, { "Extension code", "ipmi.se0f.extension_code", FT_UINT8, BASE_HEX, VALS(ssi_0f_2_progress_vals), 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_10_memory_module, { "Memory module/device ID", "ipmi.se10.memory_module", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_10_logging_disable, { "Logging disable for all events of given type", "ipmi.se10.logging_disable", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_10_event, { "Event", "ipmi.se10.event", FT_BOOLEAN, 8, TFS(&tfs_deassertion_assertion), 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_10_event_offset, { "Event Offset", "ipmi.se10.event_offset", FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL }},
		{ &hf_ipmi_se_10_sel_filled, { "SEL filled (%)", "ipmi.se10.sel_filled", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_12_log_entry_action, { "Log entry action", "ipmi.se12.log_entry_action", FT_UINT8, BASE_HEX, VALS(ssi_12_2_act_vals), 0xF0, NULL, HFILL }},
		{ &hf_ipmi_se_12_log_type, { "Log type", "ipmi.se12.log_type", FT_UINT8, BASE_HEX, VALS(ssi_12_2_type_vals), 0x0F, NULL, HFILL }},
		{ &hf_ipmi_se_12_diagnostic_interrupt, { "Diagnostic interrupt (NMI)", "ipmi.se12.diagnostic_interrupt", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_12_oem_action, { "OEM Action", "ipmi.se12.oem_action", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_12_power_cycle, { "Power Cycle", "ipmi.se12.power_cycle", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_12_reset, { "Reset", "ipmi.se12.reset", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_12_power_off, { "Power Off", "ipmi.se12.power_off", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_12_alert, { "Alert", "ipmi.se12.alert", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_12_event, { "Event", "ipmi.se12.event", FT_BOOLEAN, 8, TFS(&tfs_second_first_pair), 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_12_timestamp_clock_type, { "Timestamp clock type", "ipmi.se12.timestamp_clock_type", FT_UINT8, BASE_HEX, VALS(ssi_12_2_clock_vals), 0x0F, NULL, HFILL }},
		{ &hf_ipmi_se_19_requested_power_state, { "Requested power state", "ipmi.se19.requested_power_state", FT_UINT8, BASE_HEX, VALS(ssoff_22), 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_19_power_state, { "Power state at time of request", "ipmi.se19.power_state", FT_UINT8, BASE_HEX, VALS(ssoff_22), 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_1d_restart_cause, { "Restart cause", "ipmi.se1d.restart_cause", FT_UINT8, BASE_HEX, VALS(ssi_1d_2_cause_vals), 0x0F, NULL, HFILL }},
		{ &hf_ipmi_se_1d_channel, { "Channel", "ipmi.se1d.channel", FT_UINT8, BASE_CUSTOM, CF_FUNC(ipmi_fmt_channel), 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_21_slot_connector_type, { "Slot/connector type", "ipmi.se21.slot_connector_type", FT_UINT8, BASE_HEX, VALS(ssi_21_2_type_vals), 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_21_slot_connector, { "Slot/connector #", "ipmi.se21.slot_connector", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_23_interrupt_type, { "Interrupt type", "ipmi.se23.interrupt_type", FT_UINT8, BASE_HEX, VALS(ssi_23_2_intr_vals), 0xF0, NULL, HFILL }},
		{ &hf_ipmi_se_23_timer_use_at_expiration, { "Timer use at expiration", "ipmi.se23.timer_use_at_expiration", FT_UINT8, BASE_HEX, VALS(ssi_23_2_use_vals), 0x0F, NULL, HFILL }},
		{ &hf_ipmi_se_28_sensor_number, { "Sensor number", "ipmi.se28.sensor_number", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_28_logical_fru_device, { "Logical FRU device", "ipmi.se28.logical_fru_device", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_28_lun_for_master_read_write_command, { "LUN for Master Read-Write command", "ipmi.se28.lun_for_master_read_write_command", FT_UINT8, BASE_HEX, NULL, 0x18, NULL, HFILL }},
		{ &hf_ipmi_se_28_private_bus_id, { "Private Bus ID", "ipmi.se28.private_bus_id", FT_UINT8, BASE_HEX, NULL, 0x07, NULL, HFILL }},
		{ &hf_ipmi_se_28_fru_device_id_within_controller, { "FRU Device ID within controller", "ipmi.se28.fru_device_id_within_controller", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_28_i2c_slave_address, { "I2C Slave Address", "ipmi.se28.i2c_slave_address", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_2a_user_id, { "User ID", "ipmi.se2a.user_id", FT_UINT8, BASE_DEC, NULL, 0x3F, NULL, HFILL }},
		{ &hf_ipmi_se_2a_session_deactivated_by, { "Session deactivated by", "ipmi.se2a.session_deactivated_by", FT_UINT8, BASE_HEX, VALS(ssi_2a_3_deact_vals), 0x30, NULL, HFILL }},
		{ &hf_ipmi_se_2a_channel, { "Channel", "ipmi.se2a.channel", FT_UINT8, BASE_CUSTOM, CF_FUNC(ipmi_fmt_channel), 0x0F, NULL, HFILL }},
		{ &hf_ipmi_se_2b_version_change_type, { "Version change type", "ipmi.se2b.version_change_type", FT_UINT8, BASE_DEC, VALS(ssi_2b_2_vctype_vals), 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_2c_cause, { "Cause", "ipmi.se2c.cause", FT_UINT8, BASE_HEX, VALS(ssi_2c_2_cause_vals), 0xF0, NULL, HFILL }},
		{ &hf_ipmi_se_2c_previous_state, { "Previous state", "ipmi.se2c.previous_state", FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL }},
		{ &hf_ipmi_se_f0_cause, { "Cause", "ipmi.sef0.cause", FT_UINT8, BASE_HEX, VALS(ssi_f0_2_cause_vals), 0xF0, NULL, HFILL }},
		{ &hf_ipmi_se_f0_previous_state, { "Previous state", "ipmi.sef0.previous_state", FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL }},
		{ &hf_ipmi_se_f0_fru_id, { "FRU Id", "ipmi.sef0.fru_id", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_f1_channel, { "Channel", "ipmi.sef1.channel", FT_UINT8, BASE_CUSTOM, CF_FUNC(ipmi_fmt_channel), 0xF0, NULL, HFILL }},
		{ &hf_ipmi_se_f1_ipmb_b_override_state, { "IPMB-B Override state", "ipmi.sef1.ipmb_b_override_state", FT_BOOLEAN, 8, TFS(&tfs_f1_3_override_state), 0x80, NULL, HFILL }},
		{ &hf_ipmi_se_f1_ipmb_b_local_status, { "IPMB-B Local status", "ipmi.sef1.ipmb_b_local_status", FT_UINT8, BASE_HEX, VALS(ssi_f1_3_status_vals), 0x70, NULL, HFILL }},
		{ &hf_ipmi_se_f1_ipmb_a_override_state, { "IPMB-A Override state", "ipmi.sef1.ipmb_a_override_state", FT_BOOLEAN, 8, TFS(&tfs_f1_3_override_state), 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_f1_ipmb_a_local_status, { "IPMB-A Local status", "ipmi.sef1.ipmb_a_local_status", FT_UINT8, BASE_HEX, VALS(ssi_f1_3_status_vals), 0x07, NULL, HFILL }},
		{ &hf_ipmi_se_f3_global_status, { "Global Status", "ipmi.sef3.global_status", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_f3_redundant_pm, { "Redundant PM", "ipmi.sef3.redundant_pm", FT_BOOLEAN, 8, TFS(&tfs_provide_not_provide_payload_current), 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_f3_gs_payload_power, { "Payload Power", "ipmi.sef3.payload_power", FT_BOOLEAN, 8, TFS(&tfs_is_good_not_good), 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_f3_gs_management_power, { "Management Power", "ipmi.sef3.management_power", FT_BOOLEAN, 8, TFS(&tfs_is_good_not_good), 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_f3_role, { "Role", "ipmi.sef3.role", FT_BOOLEAN, 8, TFS(&tfs_primary_redundant), 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_f3_channel_status, { "Channel Status", "ipmi.sef3.channel_status", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_f3_pwr_on, { "PWR_ON", "ipmi.sef3.pwr_on", FT_BOOLEAN, 8, TFS(&tfs_asserted_not_asserted), 0x40, NULL, HFILL }},
		{ &hf_ipmi_se_f3_payload_power_overcurrent, { "Payload Power Overcurrent", "ipmi.sef3.payload_power_overcurrent", FT_BOOLEAN, 8, TFS(&tfs_detected_not_detected), 0x20, NULL, HFILL }},
		{ &hf_ipmi_se_f3_channel_payload_power, { "Payload Power", "ipmi.sef3.payload_power", FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x10, NULL, HFILL }},
		{ &hf_ipmi_se_f3_enable, { "ENABLE#", "ipmi.sef3.enable", FT_BOOLEAN, 8, TFS(&tfs_asserted_not_asserted), 0x08, NULL, HFILL }},
		{ &hf_ipmi_se_f3_management_power_overcurrent, { "Management Power Overcurrent", "ipmi.sef3.management_power_overcurrent", FT_BOOLEAN, 8, TFS(&tfs_detected_not_detected), 0x04, NULL, HFILL }},
		{ &hf_ipmi_se_f3_channel_management_power, { "Management Power", "ipmi.sef3.management_power", FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x02, NULL, HFILL }},
		{ &hf_ipmi_se_f3_ps1, { "PS1#", "ipmi.sef3.ps1", FT_BOOLEAN, 8, TFS(&tfs_asserted_not_asserted), 0x01, NULL, HFILL }},
		{ &hf_ipmi_se_f3_power_channel_number, { "Power Channel number", "ipmi.sef3.power_channel_number", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
		{ &hf_ipmi_se_13_parameter, { "Parameter", "ipmi.se13.parameter", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL }},
		{ &hf_ipmi_se_23_m, { "M", "ipmi.se23.m", FT_UINT16, BASE_HEX, NULL, 0xFFC0, NULL, HFILL }},
		{ &hf_ipmi_se_23_tolerance, { "Tolerance", "ipmi.se23.tolerance", FT_UINT16, BASE_DEC, NULL, 0x003F, NULL, HFILL }},
		{ &hf_ipmi_se_23_b, { "B", "ipmi.se23.b", FT_UINT16, BASE_HEX, NULL, 0xFFC0, NULL, HFILL }},
		{ &hf_ipmi_se_23_accuracy, { "Accuracy", "ipmi.se23.accuracy", FT_UINT16, BASE_DEC, NULL, 0x3FF0, NULL, HFILL }},
		{ &hf_ipmi_se_23_accuracy_exponent, { "Accuracy exponent", "ipmi.se23.accuracy_exponent", FT_UINT8, BASE_DEC, NULL, 0x0C, NULL, HFILL }},
		{ &hf_ipmi_se_23_r_exponent, { "R exponent", "ipmi.se23.r_exponent", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }},
		{ &hf_ipmi_se_23_b_exponent, { "B exponent", "ipmi.se23.b_exponent", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }},

	};
	static int *ett[] = {
		&ett_ipmi_se_evt_byte3,
		&ett_ipmi_se_evt_evd_byte1,
		&ett_ipmi_se_evt_evd_byte2,
		&ett_ipmi_se_evt_evd_byte3,
		&ett_ipmi_se_cp06_byte1,
		&ett_ipmi_se_cp07_byte1,
		&ett_ipmi_se_cp09_byte1,
		&ett_ipmi_se_cp10_byte1,
		&ett_ipmi_se_cp12_byte1,
		&ett_ipmi_se_cp12_byte2,
		&ett_ipmi_se_cp12_byte3,
		&ett_ipmi_se_cp13_byte1,
		&ett_ipmi_se_cp15_byte1,
		&ett_ipmi_se_cp15_byte2,
		&ett_ipmi_se_cp15_member,
		&ett_ipmi_se_cp15_byte11,
		&ett_ipmi_se_00_byte2,
		&ett_ipmi_se_01_byte2,
		&ett_ipmi_se_10_action,
		&ett_ipmi_se_12_byte1,
		&ett_ipmi_se_13_byte1,
		&ett_ipmi_se_13_rev,
		&ett_ipmi_se_14_byte1,
		&ett_ipmi_se_16_byte1,
		&ett_ipmi_se_16_byte2,
		&ett_ipmi_se_16_byte3,
		&ett_ipmi_se_20_rq_byte1,
		&ett_ipmi_se_20_rs_byte2,
		&ett_ipmi_se_23_readingfactors,
		&ett_ipmi_se_23_byte1,
		&ett_ipmi_se_23_byte2,
		&ett_ipmi_se_23_byte3,
		&ett_ipmi_se_23_byte4,
		&ett_ipmi_se_23_byte5,
		&ett_ipmi_se_23_byte6,
		&ett_ipmi_se_XX_mask,
		&ett_ipmi_se_XX_b1,
		&ett_ipmi_se_XX_b2,
		&ett_ipmi_se_XX_b3,
		&ett_ipmi_se_XX_b4,
		&ett_ipmi_se_28_byte2,
		&ett_ipmi_se_29_byte1,
		&ett_ipmi_se_2a_byte2,
		&ett_ipmi_se_2b_byte1,
		&ett_ipmi_se_2d_byte2,
		&ett_ipmi_se_2d_b1,
		&ett_ipmi_se_2d_b2,
	};

	static ei_register_info ei[] = {
		{ &ei_ipmi_se_13_request_param_rev, { "ipmi.se13.request_param_rev", PI_PROTOCOL, PI_NOTE, "Requested parameter revision; parameter data returned", EXPFILL }},
		{ &ei_ipmi_se_13_request_param_data, { "ipmi.se13.mrequest_param_data", PI_PROTOCOL, PI_NOTE, "Requested parameter data; only parameter version returned", EXPFILL }},
	};

	expert_module_t* expert_ipmi_se;

	proto_register_field_array(proto_ipmi, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));
	expert_ipmi_se = expert_register_protocol(proto_ipmi);
	expert_register_field_array(expert_ipmi_se, ei, array_length(ei));
	ipmi_register_netfn_cmdtab(IPMI_SE_REQ, IPMI_OEM_NONE, NULL, 0, NULL,
			cmd_se, array_length(cmd_se));


}

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * c-basic-offset: 8
 * tab-width: 8
 * indent-tabs-mode: t
 * End:
 *
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
 * :indentSize=8:tabSize=8:noTabs=false:
 */
