1 /* packet-ipmi-session.c
2 * Routines for dissection of IPMI session wrapper (v1.5 and v2.0)
3 * Copyright 2007-2008, Alexey Neyman, Pigeon Point Systems <avn@pigeonpoint.com>
4 * Copyright Duncan Laurie <duncan@sun.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * Partially copied from packet-ipmi.c.
12 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/packet.h>
19 #include <wsutil/array.h>
21 void proto_register_ipmi_session(void);
22 void proto_reg_handoff_ipmi_session(void);
24 static dissector_handle_t ipmi_session_handle
;
26 #define RMCP_CLASS_IPMI 0x07
28 static int proto_ipmi_session
;
30 static int ett_ipmi_session
;
31 static int ett_ipmi_session_payloadtype
;
33 /* IPMI session header */
34 static int hf_ipmi_session_id
;
35 static int hf_ipmi_session_authtype
;
36 static int hf_ipmi_session_payloadtype
;
37 static int hf_ipmi_session_payloadtype_auth
;
38 static int hf_ipmi_session_payloadtype_enc
;
39 static int hf_ipmi_session_oem_iana
;
40 static int hf_ipmi_session_oem_payload_id
;
41 static int hf_ipmi_session_sequence
;
42 static int hf_ipmi_session_authcode
;
43 static int hf_ipmi_session_msg_len_1b
;
44 static int hf_ipmi_session_msg_len_2b
;
45 static int hf_ipmi_session_trailer
;
47 static dissector_handle_t ipmi_handle
;
49 #define IPMI_AUTH_NONE 0x00
50 #define IPMI_AUTH_MD2 0x01
51 #define IPMI_AUTH_MD5 0x02
52 #define IPMI_AUTH_PASSWORD 0x04
53 #define IPMI_AUTH_OEM 0x05
54 #define IPMI_AUTH_RMCPP 0x06
56 static const value_string ipmi_authtype_vals
[] = {
57 { IPMI_AUTH_NONE
, "NONE" },
58 { IPMI_AUTH_MD2
, "MD2" },
59 { IPMI_AUTH_MD5
, "MD5" },
60 { IPMI_AUTH_PASSWORD
, "PASSWORD" },
61 { IPMI_AUTH_OEM
, "OEM" },
62 { IPMI_AUTH_RMCPP
, "RMCP+"},
66 #define IPMI_IPMI_MESSAGE 0
67 #define IPMI_OEM_EXPLICIT 2
69 static const value_string ipmi_payload_vals
[] = {
70 { IPMI_IPMI_MESSAGE
, "IPMI Message" },
71 { 0x01, "SOL (serial over LAN)" },
72 { IPMI_OEM_EXPLICIT
, "OEM Explicit" },
73 /* Session Setup Payload Types */
74 { 0x10, "RMCP+ Open Session Request" },
75 { 0x11, "RMCP+ Open Session Response" },
76 { 0x12, "RAKP Message 1" },
77 { 0x13, "RAKP Message 2" },
78 { 0x14, "RAKP Message 3" },
79 { 0x15, "RAKP Message 4" },
80 /* OEM Payload Type Handles */
81 { 0x20, "OEM0 (OEM Payload)" },
82 { 0x21, "OEM1 (OEM Payload)" },
83 { 0x22, "OEM2 (OEM Payload)" },
84 { 0x23, "OEM3 (OEM Payload)" },
85 { 0x24, "OEM4 (OEM Payload)" },
86 { 0x25, "OEM5 (OEM Payload)" },
87 { 0x26, "OEM6 (OEM Payload)" },
88 { 0x27, "OEM7 (OEM Payload)" },
92 static const true_false_string ipmi_payload_aut_val
= {
93 "Payload is authenticated",
94 "Payload is unauthenticated"
97 static const true_false_string ipmi_payload_enc_val
= {
98 "Payload is encrypted",
99 "Payload is unencrypted"
103 dissect_ipmi_session(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
105 proto_tree
*sess_tree
= NULL
, *s_tree
;
109 uint8_t authtype
, payloadtype
= 0;
110 uint32_t msg_start
, msg_len
, offset
= 0;
111 bool payloadtype_auth
= 0, payloadtype_enc
= 0;
113 /* session authtype, 0=no authcode present, 6=RMCP+ */
114 authtype
= tvb_get_uint8(tvb
, 0);
115 if (authtype
== IPMI_AUTH_RMCPP
) {
116 /* Fetch additional info before trying to interpret
117 the packet. It may not be IPMI at all! */
118 payloadtype
= tvb_get_uint8(tvb
, 1);
119 payloadtype_auth
= (payloadtype
>> 6) & 1;
120 payloadtype_enc
= (payloadtype
>> 7);
123 /* IPMI v2.0 packets have session ID BEFORE the session
124 sequence number; just after authentication and payload
125 types. The OEM Explicit payload type has 6 more bytes
126 (IANA + Payload ID) before the session ID. */
127 if (payloadtype
== IPMI_OEM_EXPLICIT
) {
128 session_id
= tvb_get_letohl(tvb
, 8);
130 msg_len
= tvb_get_letohs(tvb
, 16);
132 session_id
= tvb_get_letohl(tvb
, 2);
134 msg_len
= tvb_get_letohs(tvb
, 10);
137 /* IPMI v1.5 packets have session ID AFTER the session
138 sequence number. They also have 1 byte for payload
140 session_id
= tvb_get_letohl(tvb
, 5);
141 if (authtype
== IPMI_AUTH_NONE
) {
143 msg_len
= tvb_get_uint8(tvb
, 9);
146 msg_len
= tvb_get_uint8(tvb
, 25);
150 /* Later it will be overridden with sub-dissector, if any */
151 if (authtype
== IPMI_AUTH_RMCPP
) {
152 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RMCP+");
154 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IPMI");
157 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Session ID 0x%x", session_id
);
158 if (authtype
== IPMI_AUTH_RMCPP
) {
159 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", payload type: %s",
160 val_to_str_const(payloadtype
, ipmi_payload_vals
, "Unknown"));
165 ti
= proto_tree_add_protocol_format(tree
, proto_ipmi_session
,
167 "IPMI v%s Session Wrapper, session ID 0x%x",
168 authtype
== IPMI_AUTH_RMCPP
? "2.0+" : "1.5",
170 sess_tree
= proto_item_add_subtree(ti
, ett_ipmi_session
);
171 proto_tree_add_item(sess_tree
, hf_ipmi_session_authtype
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
174 if (authtype
== IPMI_AUTH_RMCPP
) {
176 s_tree
= proto_tree_add_subtree_format(sess_tree
, tvb
, offset
, 1,
177 ett_ipmi_session_payloadtype
, NULL
,
178 "Payload type: %s (0x%02x), %sencrypted, %sauthenticated",
179 val_to_str_const(payloadtype
, ipmi_payload_vals
, "Unknown"),
181 payloadtype_enc
? "" : "not ",
182 payloadtype_auth
? "" : "not ");
183 proto_tree_add_item(s_tree
, hf_ipmi_session_payloadtype_enc
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
184 proto_tree_add_item(s_tree
, hf_ipmi_session_payloadtype_auth
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
185 proto_tree_add_item(s_tree
, hf_ipmi_session_payloadtype
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
188 if (payloadtype
== IPMI_OEM_EXPLICIT
) {
189 proto_tree_add_item(sess_tree
, hf_ipmi_session_oem_iana
, tvb
, offset
, 4, ENC_NA
);
191 proto_tree_add_item(sess_tree
, hf_ipmi_session_oem_payload_id
, tvb
, offset
, 2, ENC_NA
);
194 proto_tree_add_item(sess_tree
, hf_ipmi_session_id
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
196 proto_tree_add_item(sess_tree
, hf_ipmi_session_sequence
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
198 proto_tree_add_item(sess_tree
, hf_ipmi_session_msg_len_2b
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
202 proto_tree_add_item(sess_tree
, hf_ipmi_session_sequence
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
204 proto_tree_add_item(sess_tree
, hf_ipmi_session_id
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
206 if (authtype
!= IPMI_AUTH_NONE
) {
207 proto_tree_add_item(sess_tree
, hf_ipmi_session_authcode
,
208 tvb
, offset
, 16, ENC_NA
);
211 proto_tree_add_item(sess_tree
, hf_ipmi_session_msg_len_1b
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
216 /* If we can parse the embedded message, do so */
217 next_tvb
= tvb_new_subset_length_caplen(tvb
, msg_start
, msg_len
, -1);
218 if (payloadtype_enc
) {
219 /* This is RMCP+, and payload is encrypted. In this case,
220 there is a 'confidentiality header/trailer', whose lengths
221 are unknown to us. These lengths are negotiated during
222 session open process and are retained over a session.
223 Since we are stateless (and more, we may have no session
224 open packet in the capture we parse), we cannot even
225 decipher where a message starts. Just print them as data.
227 call_data_dissector(next_tvb
, pinfo
, tree
);
228 } else if (authtype
!= IPMI_AUTH_RMCPP
|| payloadtype
== IPMI_IPMI_MESSAGE
) {
229 /* This is an IPMI message, either v1.5 or v2.0+. For now,
230 we don't need to distinguish these kinds. */
231 call_dissector(ipmi_handle
, next_tvb
, pinfo
, tree
);
233 /* All other RMCP+ payload types fall here: session open/close
234 requests, RAKP messages, SOL. We cannot parse them yet, thus
235 just output as data. */
236 call_data_dissector(next_tvb
, pinfo
, tree
);
240 /* Account for the message we just parsed. */
243 /* Show the rest of the session wrapper as binary data */
244 if (offset
< tvb_captured_length(tvb
)) {
245 proto_tree_add_item(sess_tree
, hf_ipmi_session_trailer
,
246 tvb
, offset
, -1, ENC_NA
);
249 return tvb_captured_length(tvb
);
253 proto_register_ipmi_session(void)
255 static hf_register_info hf
[] = {
256 { &hf_ipmi_session_authtype
, {
257 "Authentication Type", "ipmi_session.authtype",
258 FT_UINT8
, BASE_HEX
, VALS(ipmi_authtype_vals
), 0, NULL
, HFILL
}},
259 { &hf_ipmi_session_payloadtype
,{
260 "Payload Type", "ipmi_session.payloadtype",
261 FT_UINT8
, BASE_HEX
, VALS(ipmi_payload_vals
), 0x3f, NULL
, HFILL
}},
262 { &hf_ipmi_session_payloadtype_auth
,{
263 "Authenticated","ipmi_session.payloadtype.auth",
264 FT_BOOLEAN
,8, TFS(&ipmi_payload_aut_val
), 0x40, NULL
, HFILL
}},
265 { &hf_ipmi_session_payloadtype_enc
,{
266 "Encryption","ipmi_session.payloadtype.enc",
267 FT_BOOLEAN
,8, TFS(&ipmi_payload_enc_val
), 0x80, NULL
, HFILL
}},
268 { &hf_ipmi_session_oem_iana
, {
269 "OEM IANA", "ipmi_session.oem.iana",
270 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
271 { &hf_ipmi_session_oem_payload_id
, {
272 "OEM Payload ID", "ipmi_session.oem.payloadid",
273 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
274 { &hf_ipmi_session_sequence
, {
275 "Session Sequence Number", "ipmi_session.sequence",
276 FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
277 { &hf_ipmi_session_id
, {
278 "Session ID", "ipmi_session.id",
279 FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}},
280 { &hf_ipmi_session_authcode
, {
281 "Authentication Code", "ipmi_session.authcode",
282 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
283 { &hf_ipmi_session_msg_len_1b
, {
284 "Message Length", "ipmi_session.msg.len",
285 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
286 { &hf_ipmi_session_msg_len_2b
, {
287 "Message Length", "ipmi_session.msg.len",
288 FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}},
289 { &hf_ipmi_session_trailer
, {
290 "IPMI Session Wrapper (trailer)", "ipmi_session.trailer",
291 FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}},
294 static int *ett
[] = { &ett_ipmi_session
, &ett_ipmi_session_payloadtype
};
296 proto_ipmi_session
= proto_register_protocol("Intelligent Platform Management Interface (Session Wrapper)", "IPMI Session", "ipmi_session");
297 proto_register_field_array(proto_ipmi_session
, hf
, array_length(hf
));
298 proto_register_subtree_array(ett
, array_length(ett
));
300 ipmi_session_handle
= register_dissector("ipmi_session", dissect_ipmi_session
, proto_ipmi_session
);
304 proto_reg_handoff_ipmi_session(void)
306 dissector_add_uint("rmcp.class", RMCP_CLASS_IPMI
, ipmi_session_handle
);
308 ipmi_handle
= find_dissector_add_dependency("ipmi", proto_ipmi_session
);
312 * Editor modelines - https://www.wireshark.org/tools/modelines.html
317 * indent-tabs-mode: t
320 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
321 * :indentSize=8:tabSize=8:noTabs=false: