Add Management Component Transport Protocol (MCTP) dissector

This change adds a protocol dissector for the Management Component
Transport Protocol (MCTP). This is a failry simple datagram-based
protocol for messaging between components within a single platform,
typically over I2C, serial or PCIe.

This dissector just implements the header fields, and sequence-number
based message reassembly. Inner protocols will be added as follow-up
changes.

Linux has support for AF_MCTP data, so decode from the MCTP SLL ltype.

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
This commit is contained in:
Jeremy Kerr 2021-10-28 09:01:06 +08:00 committed by A Wireshark GitLab Utility
parent b704562c0c
commit e1cbe02cce
11 changed files with 411 additions and 1 deletions

View File

@ -80,6 +80,7 @@ SAP Internet Graphic Server (SAP IGS)
SAP Network Interface (SAPNI)
World of Warcraft World (WOWW) display filters have been changed to be more internally consistent.
Support for almost all WoW 1.12 messages has been added.
Management Component Transport Protocol (MCTP)
--
=== Updated Protocol Support

View File

@ -47,6 +47,7 @@ typedef enum {
AT_AX25, /* AX.25 */
AT_VINES, /* Banyan Vines address */
AT_NUMERIC, /* Numeric address type. */
AT_MCTP, /* MCTP */
AT_END_OF_LIST /* Must be last in list */
} address_type;
@ -363,7 +364,8 @@ typedef enum {
PT_I2C,
PT_IBQP, /* Infiniband QP number */
PT_BLUETOOTH,
PT_IWARP_MPA /* iWarp MPA */
PT_IWARP_MPA, /* iWarp MPA */
PT_MCTP
} port_type;
#ifdef __cplusplus

View File

@ -583,6 +583,28 @@ static int numeric_addr_to_str(const address* addr, gchar *buf, int buf_len)
return ret + 1;
}
/******************************************************************************
* AT_MCTP
******************************************************************************/
static int mctp_addr_to_str(const address* addr, gchar *buf, int buf_len _U_)
{
const guint8 *addr_data = (const guint8 *)addr->data;
gchar *bufp = buf;
return g_snprintf(bufp, 3, "%d", addr_data[0]);
}
static int mctp_addr_str_len(const address* addr _U_)
{
return 3;
}
static int mctp_len(void)
{
return 1;
}
/******************************************************************************
* END OF PROVIDED ADDRESS TYPES
******************************************************************************/
@ -759,6 +781,18 @@ void address_types_initialize(void)
NULL, /* addr_name_res_str */
NULL, /* addr_name_res_len */
};
static address_type_t mctp_address = {
AT_MCTP, /* addr_type */
"AT_MCTP" , /* name */
"MCTP Address", /* pretty_name */
mctp_addr_to_str, /* addr_to_str */
mctp_addr_str_len, /* addr_str_len */
NULL, /* addr_to_byte */
NULL, /* addr_col_filter */
mctp_len, /* addr_fixed_len */
NULL, /* addr_name_res_str */
NULL, /* addr_name_res_len */
};
num_dissector_addr_type = 0;
@ -779,6 +813,7 @@ void address_types_initialize(void)
address_type_register(AT_AX25, &ax25_address );
address_type_register(AT_VINES, &vines_address );
address_type_register(AT_NUMERIC, &numeric_address );
address_type_register(AT_MCTP, &mctp_address );
}
/* Given an address type id, return an address_type_t* */

View File

@ -1912,6 +1912,8 @@ conversation_type conversation_pt_to_conversation_type(port_type pt)
return CONVERSATION_BLUETOOTH;
case PT_IWARP_MPA:
return CONVERSATION_IWARP_MPA;
case PT_MCTP:
return CONVERSATION_MCTP;
}
DISSECTOR_ASSERT(FALSE);
@ -1950,6 +1952,8 @@ endpoint_type conversation_pt_to_endpoint_type(port_type pt)
return ENDPOINT_BLUETOOTH;
case PT_IWARP_MPA:
return ENDPOINT_IWARP_MPA;
case PT_MCTP:
return ENDPOINT_MCTP;
}
DISSECTOR_ASSERT(FALSE);

View File

@ -89,6 +89,7 @@ typedef enum {
CONVERSATION_BT_UTP, /* BitTorrent uTP Connection ID */
CONVERSATION_LOG, /* Logging source */
CONVERSATION_LTP, /* LTP Engine ID and Session Number */
CONVERSATION_MCTP,
} conversation_type;
/*
@ -133,6 +134,7 @@ typedef enum {
#define ENDPOINT_IWARP_MPA CONVERSATION_IWARP_MPA
#define ENDPOINT_BT_UTP CONVERSATION_BT_UTP
#define ENDPOINT_LOG CONVERSATION_LOG
#define ENDPOINT_MCTP CONVERSATION_MCTP
typedef conversation_type endpoint_type;

View File

@ -1439,6 +1439,7 @@ set(DISSECTOR_SRC
${CMAKE_CURRENT_SOURCE_DIR}/packet-mbtcp.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-mc-nmf.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-mcpe.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-mctp.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-mdp.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-mdshdr.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-media.c

View File

@ -0,0 +1,360 @@
/* packet-mctp.c
* Routines for Management Component Transport Protocol (MCTP) packet
* disassembly
* Copyright 2022, Jeremy Kerr <jk@codeconstruct.com.au>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
/*
* MCTP is a datagram-based protocol for intra-platform communication,
* typically between a management controller and system devices.
*
* MCTP is defined by DMTF standard DSP0236: https://www.dmtf.org/dsp/DSP0236
*/
#include <config.h>
#include <epan/packet.h>
#include <epan/reassemble.h>
#include <epan/to_str.h>
#include <epan/dissectors/packet-sll.h>
#define MCTP_MIN_LENGTH 5 /* 4-byte header, plus message type */
void proto_register_mctp(void);
void proto_reg_handoff_mctp(void);
static int proto_mctp = -1;
static int hf_mctp_ver = -1;
static int hf_mctp_dst = -1;
static int hf_mctp_src = -1;
static int hf_mctp_flags = -1;
static int hf_mctp_flags_som = -1;
static int hf_mctp_flags_eom = -1;
static int hf_mctp_seq = -1;
static int hf_mctp_tag = -1;
static int hf_mctp_tag_to = -1;
static int hf_mctp_tag_value = -1;
static gint ett_mctp = -1;
static gint ett_mctp_fst = -1;
static gint ett_mctp_flags = -1;
static gint ett_mctp_tag = -1;
static const true_false_string tfs_tag_to = { "Sender", "Receiver" };
static int hf_mctp_fragments = -1;
static int hf_mctp_fragment = -1;
static int hf_mctp_fragment_overlap = -1;
static int hf_mctp_fragment_overlap_conflicts = -1;
static int hf_mctp_fragment_multiple_tails = -1;
static int hf_mctp_fragment_too_long_fragment = -1;
static int hf_mctp_fragment_error = -1;
static int hf_mctp_fragment_count = -1;
static int hf_mctp_reassembled_in = -1;
static int hf_mctp_reassembled_length = -1;
static int hf_mctp_reassembled_data = -1;
static gint ett_mctp_fragment = -1;
static gint ett_mctp_fragments = -1;
static const fragment_items mctp_frag_items = {
/* Fragment subtrees */
&ett_mctp_fragment,
&ett_mctp_fragments,
/* Fragment fields */
&hf_mctp_fragments,
&hf_mctp_fragment,
&hf_mctp_fragment_overlap,
&hf_mctp_fragment_overlap_conflicts,
&hf_mctp_fragment_multiple_tails,
&hf_mctp_fragment_too_long_fragment,
&hf_mctp_fragment_error,
&hf_mctp_fragment_count,
/* "Reassembled in" field */
&hf_mctp_reassembled_in,
/* Reassembled length field */
&hf_mctp_reassembled_length,
&hf_mctp_reassembled_data,
/* Tag */
"Message fragments"
};
static const value_string flag_vals[] = {
{ 0x00, "none" },
{ 0x01, "EOM" },
{ 0x02, "SOM" },
{ 0x03, "SOM|EOM" },
{ 0x00, NULL },
};
static dissector_table_t mctp_dissector_table;
static reassembly_table mctp_reassembly_table;
static int
dissect_mctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
void *data _U_)
{
proto_tree *mctp_tree, *fst_tree;
guint len, ver, type, seq, fst;
bool save_fragmented;
proto_item *ti, *tti;
tvbuff_t *next_tvb;
guint8 tag;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "MCTP");
col_clear(pinfo->cinfo, COL_INFO);
/* Check that the packet is long enough for it to belong to us. */
len = tvb_reported_length(tvb);
if (len < MCTP_MIN_LENGTH) {
col_add_fstr(pinfo->cinfo, COL_INFO, "Bogus length %u, minimum %u",
len, MCTP_MIN_LENGTH);
return tvb_captured_length(tvb);
}
ver = tvb_get_bits8(tvb, 4, 4);
if (ver != 1) {
col_add_fstr(pinfo->cinfo, COL_INFO, "Invalid version %u", ver);
return tvb_captured_length(tvb);
}
/* Top-level protocol item & tree */
ti = proto_tree_add_item(tree, proto_mctp, tvb, 0, 4, ENC_NA);
mctp_tree = proto_item_add_subtree(ti, ett_mctp);
set_address_tvb(&pinfo->dl_dst, AT_MCTP, 1, tvb, 1);
set_address_tvb(&pinfo->dl_src, AT_MCTP, 1, tvb, 2);
copy_address_shallow(&pinfo->dst, &pinfo->dl_dst);
copy_address_shallow(&pinfo->src, &pinfo->dl_src);
proto_item_append_text(ti, " Dst: %s, Src %s",
address_to_str(pinfo->pool, &pinfo->dst),
address_to_str(pinfo->pool, &pinfo->src));
/* Standard header fields */
proto_tree_add_item(mctp_tree, hf_mctp_ver, tvb, 0, 1, ENC_NA);
proto_tree_add_item(mctp_tree, hf_mctp_dst, tvb, 1, 1, ENC_NA);
proto_tree_add_item(mctp_tree, hf_mctp_src, tvb, 2, 1, ENC_NA);
static int * const mctp_flags[] = {
&hf_mctp_flags_som,
&hf_mctp_flags_eom,
NULL
};
static int * const mctp_tag[] = {
&hf_mctp_tag_to,
&hf_mctp_tag_value,
NULL,
};
fst = tvb_get_guint8(tvb, 3);
tag = fst & 0x0f;
fst_tree = proto_tree_add_subtree_format(mctp_tree, tvb, 3, 1, ett_mctp_fst,
&tti, "Flags %s, seq %d, tag %s%d",
val_to_str_const(fst >> 6, flag_vals, ""),
fst >> 4 & 0x3,
fst & 0x08 ? "TO:" : "",
fst & 0x7);
proto_tree_add_bitmask(fst_tree, tvb, 3, hf_mctp_flags,
ett_mctp_flags, mctp_flags, ENC_NA);
proto_tree_add_item_ret_uint(fst_tree, hf_mctp_seq, tvb, 3, 1, ENC_NA, &seq);
proto_tree_add_bitmask_with_flags(fst_tree, tvb, 3, hf_mctp_tag,
ett_mctp_tag, mctp_tag, ENC_NA, BMT_NO_FLAGS);
/* use the tags as our port numbers */
pinfo->ptype = PT_MCTP;
pinfo->srcport = tag;
pinfo->destport = tag ^ 0x08; /* flip tag-owner bit */
save_fragmented = pinfo->fragmented;
col_set_str(pinfo->cinfo, COL_INFO, "MCTP message");
/* if we're not both the start and end of a message, handle as a
* fragment */
if ((fst & 0xc0) != 0xc0) {
fragment_head *frag_msg = NULL;
tvbuff_t *new_tvb = NULL;
pinfo->fragmented = true;
frag_msg = fragment_add_seq_next(&mctp_reassembly_table,
tvb, 4, pinfo,
fst & 0x7, NULL,
tvb_captured_length_remaining(tvb, 4),
!(fst & 0x40));
new_tvb = process_reassembled_data(tvb, 4, pinfo,
"reassembled Message",
frag_msg, &mctp_frag_items,
NULL, mctp_tree);
if (fst & 0x40)
col_append_str(pinfo->cinfo, COL_INFO, " reassembled");
else
col_append_fstr(pinfo->cinfo, COL_INFO, " frag %u", seq);
next_tvb = new_tvb;
} else {
next_tvb = tvb_new_subset_remaining(tvb, 4);
}
if (next_tvb) {
type = tvb_get_guint8(next_tvb, 0);
dissector_try_uint_new(mctp_dissector_table, type & 0x7f, next_tvb,
pinfo, tree, true, NULL);
}
pinfo->fragmented = save_fragmented;
return tvb_captured_length(tvb);
}
void
proto_register_mctp(void)
{
/* *INDENT-OFF* */
/* Field definitions */
static hf_register_info hf[] = {
{ &hf_mctp_ver,
{ "Version", "mctp.version",
FT_UINT8, BASE_DEC, NULL, 0x0f,
NULL, HFILL },
},
{ &hf_mctp_dst,
{ "Destination", "mctp.dst",
FT_UINT8, BASE_DEC, NULL, 0x00,
NULL, HFILL },
},
{ &hf_mctp_src,
{ "Source", "mctp.src",
FT_UINT8, BASE_DEC, NULL, 0x00,
NULL, HFILL },
},
{ &hf_mctp_flags,
{ "Flags", "mctp.flags",
FT_UINT8, BASE_HEX, NULL, 0xc0,
NULL, HFILL },
},
{ &hf_mctp_flags_som,
{ "Start of message", "mctp.flags.som",
FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x80,
NULL, HFILL },
},
{ &hf_mctp_flags_eom,
{ "End of message", "mctp.flags.eom",
FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x40,
NULL, HFILL },
},
{ &hf_mctp_seq,
{ "Sequence", "mctp.seq",
FT_UINT8, BASE_HEX, NULL, 0x30,
NULL, HFILL },
},
{ &hf_mctp_tag,
{ "Tag", "mctp.tag",
FT_UINT8, BASE_HEX, NULL, 0x0f,
NULL, HFILL },
},
{ &hf_mctp_tag_to,
{ "Tag owner", "mctp.tag.to",
FT_BOOLEAN, 8, TFS(&tfs_tag_to), 0x08,
NULL, HFILL },
},
{ &hf_mctp_tag_value,
{ "Tag value", "mctp.tag.value",
FT_UINT8, BASE_HEX, NULL, 0x07,
NULL, HFILL },
},
/* generic fragmentation */
{&hf_mctp_fragments,
{"Message fragments", "mctp.fragments",
FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
{&hf_mctp_fragment,
{"Message fragment", "mctp.fragment",
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
{&hf_mctp_fragment_overlap,
{"Message fragment overlap", "mctp.fragment.overlap",
FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
{&hf_mctp_fragment_overlap_conflicts,
{"Message fragment overlapping with conflicting data",
"mctp.fragment.overlap.conflicts",
FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
{&hf_mctp_fragment_multiple_tails,
{"Message has multiple tail fragments",
"mctp.fragment.multiple_tails",
FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
{&hf_mctp_fragment_too_long_fragment,
{"Message fragment too long", "mctp.fragment.too_long_fragment",
FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
{&hf_mctp_fragment_error,
{"Message defragmentation error", "mctp.fragment.error",
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
{&hf_mctp_fragment_count,
{"Message fragment count", "mctp.fragment.count",
FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
{&hf_mctp_reassembled_in,
{"Reassembled in", "mctp.reassembled.in",
FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
{&hf_mctp_reassembled_length,
{"Reassembled length", "mctp.reassembled.length",
FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
{&hf_mctp_reassembled_data,
{"Reassembled data", "mctp.reassembled.data",
FT_BYTES, SEP_SPACE, NULL, 0x00, NULL, HFILL } },
};
/* protocol subtree */
static gint *ett[] = {
&ett_mctp,
&ett_mctp_flags,
&ett_mctp_fst,
&ett_mctp_tag,
&ett_mctp_fragment,
&ett_mctp_fragments,
};
/* Register the protocol name and description */
proto_mctp = proto_register_protocol("MCTP", "MCTP", "mctp");
/* Required function calls to register the header fields and subtrees */
proto_register_field_array(proto_mctp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
mctp_dissector_table = register_dissector_table("mctp.type", "MCTP type",
proto_mctp, FT_UINT8,
BASE_HEX);
reassembly_table_register(&mctp_reassembly_table,
&addresses_reassembly_table_functions);
}
void
proto_reg_handoff_mctp(void)
{
dissector_handle_t mctp_handle;
mctp_handle = create_dissector_handle(dissect_mctp, proto_mctp);
dissector_add_uint("sll.ltype", LINUX_SLL_P_MCTP, mctp_handle);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -74,6 +74,7 @@ static const value_string ltype_vals[] = {
{ LINUX_SLL_P_IRDA_LAP, "IrDA LAP" },
{ LINUX_SLL_P_ISI, "ISI" },
{ LINUX_SLL_P_IEEE802154, "IEEE 802.15.4" },
{ LINUX_SLL_P_MCTP, "MCTP" },
{ 0, NULL }
};

View File

@ -25,5 +25,6 @@
#define LINUX_SLL_P_IRDA_LAP 0x0017 /* IrDA Link Access Protocol */
#define LINUX_SLL_P_ISI 0x00F5 /* Intelligent Service Interface */
#define LINUX_SLL_P_IEEE802154 0x00f6 /* 802.15.4 on monitor inteface */
#define LINUX_SLL_P_MCTP 0x00fa /* Management Component Transport Protocol */
#endif

View File

@ -114,6 +114,8 @@ static guint exp_pdu_ws_port_type_to_exp_pdu_port_type(port_type pt)
return EXP_PDU_PT_BLUETOOTH;
case PT_IWARP_MPA:
return EXP_PDU_PT_IWARP_MPA;
case PT_MCTP:
return EXP_PDU_PT_MCTP;
}
DISSECTOR_ASSERT(FALSE);

View File

@ -119,6 +119,7 @@
#define EXP_PDU_PT_BLUETOOTH 15
#define EXP_PDU_PT_TDMOP 16
#define EXP_PDU_PT_IWARP_MPA 17
#define EXP_PDU_PT_MCTP 18
#define EXP_PDU_TAG_PORT_TYPE 24 /**< part type - 4 bytes, EXP_PDU_PT value */
#define EXP_PDU_TAG_SRC_PORT 25 /**< source port - 4 bytes (even for protocols with 2-byte ports) */