/src/wireshark/epan/dissectors/packet-ipmi-session.c
Line | Count | Source |
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> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * Partially copied from packet-ipmi.c. |
11 | | * |
12 | | * SPDX-License-Identifier: GPL-2.0-or-later |
13 | | */ |
14 | | |
15 | | #include "config.h" |
16 | | |
17 | | #include <epan/packet.h> |
18 | | #include <epan/tfs.h> |
19 | | #include <wsutil/array.h> |
20 | | |
21 | | void proto_register_ipmi_session(void); |
22 | | void proto_reg_handoff_ipmi_session(void); |
23 | | |
24 | | static dissector_handle_t ipmi_session_handle; |
25 | | |
26 | 14 | #define RMCP_CLASS_IPMI 0x07 |
27 | | |
28 | | static int proto_ipmi_session; |
29 | | |
30 | | static int ett_ipmi_session; |
31 | | static int ett_ipmi_session_payloadtype; |
32 | | |
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; |
46 | | |
47 | | static dissector_handle_t ipmi_handle; |
48 | | |
49 | 9 | #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 | 33 | #define IPMI_AUTH_RMCPP 0x06 |
55 | | |
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+"}, |
63 | | { 0x00, NULL } |
64 | | }; |
65 | | |
66 | 0 | #define IPMI_IPMI_MESSAGE 0 |
67 | 0 | #define IPMI_OEM_EXPLICIT 2 |
68 | | |
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)" }, |
89 | | { 0x00, NULL } |
90 | | }; |
91 | | |
92 | | static const true_false_string ipmi_payload_aut_val = { |
93 | | "Payload is authenticated", |
94 | | "Payload is unauthenticated" |
95 | | }; |
96 | | |
97 | | static const true_false_string ipmi_payload_enc_val = { |
98 | | "Payload is encrypted", |
99 | | "Payload is unencrypted" |
100 | | }; |
101 | | |
102 | | static int |
103 | | dissect_ipmi_session(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
104 | 5 | { |
105 | 5 | proto_tree *sess_tree = NULL, *s_tree; |
106 | 5 | proto_item *ti; |
107 | 5 | tvbuff_t *next_tvb; |
108 | 5 | uint32_t session_id; |
109 | 5 | uint8_t authtype, payloadtype = 0; |
110 | 5 | uint32_t msg_start, msg_len, offset = 0; |
111 | 5 | bool payloadtype_auth = 0, payloadtype_enc = 0; |
112 | | |
113 | | /* session authtype, 0=no authcode present, 6=RMCP+ */ |
114 | 5 | authtype = tvb_get_uint8(tvb, 0); |
115 | 5 | if (authtype == IPMI_AUTH_RMCPP) { |
116 | | /* Fetch additional info before trying to interpret |
117 | | the packet. It may not be IPMI at all! */ |
118 | 0 | payloadtype = tvb_get_uint8(tvb, 1); |
119 | 0 | payloadtype_auth = (payloadtype >> 6) & 1; |
120 | 0 | payloadtype_enc = (payloadtype >> 7); |
121 | 0 | payloadtype &= 0x3f; |
122 | | |
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 | 0 | if (payloadtype == IPMI_OEM_EXPLICIT) { |
128 | 0 | session_id = tvb_get_letohl(tvb, 8); |
129 | 0 | msg_start = 18; |
130 | 0 | msg_len = tvb_get_letohs(tvb, 16); |
131 | 0 | } else { |
132 | 0 | session_id = tvb_get_letohl(tvb, 2); |
133 | 0 | msg_start = 12; |
134 | 0 | msg_len = tvb_get_letohs(tvb, 10); |
135 | 0 | } |
136 | 5 | } else { |
137 | | /* IPMI v1.5 packets have session ID AFTER the session |
138 | | sequence number. They also have 1 byte for payload |
139 | | message length. */ |
140 | 5 | session_id = tvb_get_letohl(tvb, 5); |
141 | 5 | if (authtype == IPMI_AUTH_NONE) { |
142 | 3 | msg_start = 10; |
143 | 3 | msg_len = tvb_get_uint8(tvb, 9); |
144 | 3 | } else { |
145 | 2 | msg_start = 26; |
146 | 2 | msg_len = tvb_get_uint8(tvb, 25); |
147 | 2 | } |
148 | 5 | } |
149 | | |
150 | | /* Later it will be overridden with sub-dissector, if any */ |
151 | 5 | if (authtype == IPMI_AUTH_RMCPP) { |
152 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "RMCP+"); |
153 | 5 | } else { |
154 | 5 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPMI"); |
155 | 5 | } |
156 | | |
157 | 5 | col_add_fstr(pinfo->cinfo, COL_INFO, "Session ID 0x%x", session_id); |
158 | 5 | if (authtype == IPMI_AUTH_RMCPP) { |
159 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", payload type: %s", |
160 | 0 | val_to_str_const(payloadtype, ipmi_payload_vals, "Unknown")); |
161 | 0 | } |
162 | | |
163 | 5 | if (tree) { |
164 | 4 | offset = 0; |
165 | 4 | ti = proto_tree_add_protocol_format(tree, proto_ipmi_session, |
166 | 4 | tvb, 0, -1, |
167 | 4 | "IPMI v%s Session Wrapper, session ID 0x%x", |
168 | 4 | authtype == IPMI_AUTH_RMCPP ? "2.0+" : "1.5", |
169 | 4 | session_id); |
170 | 4 | sess_tree = proto_item_add_subtree(ti, ett_ipmi_session); |
171 | 4 | proto_tree_add_item(sess_tree, hf_ipmi_session_authtype, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
172 | 4 | offset++; |
173 | | |
174 | 4 | if (authtype == IPMI_AUTH_RMCPP) { |
175 | | /* IPMI v2.0+ */ |
176 | 0 | s_tree = proto_tree_add_subtree_format(sess_tree, tvb, offset, 1, |
177 | 0 | ett_ipmi_session_payloadtype, NULL, |
178 | 0 | "Payload type: %s (0x%02x), %sencrypted, %sauthenticated", |
179 | 0 | val_to_str_const(payloadtype, ipmi_payload_vals, "Unknown"), |
180 | 0 | payloadtype, |
181 | 0 | payloadtype_enc ? "" : "not ", |
182 | 0 | payloadtype_auth ? "" : "not "); |
183 | 0 | proto_tree_add_item(s_tree, hf_ipmi_session_payloadtype_enc, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
184 | 0 | proto_tree_add_item(s_tree, hf_ipmi_session_payloadtype_auth, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
185 | 0 | proto_tree_add_item(s_tree, hf_ipmi_session_payloadtype, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
186 | 0 | offset++; |
187 | |
|
188 | 0 | if (payloadtype == IPMI_OEM_EXPLICIT) { |
189 | 0 | proto_tree_add_item(sess_tree, hf_ipmi_session_oem_iana, tvb, offset, 4, ENC_NA); |
190 | 0 | offset += 4; |
191 | 0 | proto_tree_add_item(sess_tree, hf_ipmi_session_oem_payload_id, tvb, offset, 2, ENC_NA); |
192 | 0 | offset += 2; |
193 | 0 | } |
194 | 0 | proto_tree_add_item(sess_tree, hf_ipmi_session_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
195 | 0 | offset += 4; |
196 | 0 | proto_tree_add_item(sess_tree, hf_ipmi_session_sequence, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
197 | 0 | offset += 4; |
198 | 0 | proto_tree_add_item(sess_tree, hf_ipmi_session_msg_len_2b, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
199 | 0 | offset += 2; |
200 | 4 | } else { |
201 | | /* IPMI v1.5 */ |
202 | 4 | proto_tree_add_item(sess_tree, hf_ipmi_session_sequence, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
203 | 4 | offset += 4; |
204 | 4 | proto_tree_add_item(sess_tree, hf_ipmi_session_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
205 | 4 | offset += 4; |
206 | 4 | if (authtype != IPMI_AUTH_NONE) { |
207 | 1 | proto_tree_add_item(sess_tree, hf_ipmi_session_authcode, |
208 | 1 | tvb, offset, 16, ENC_NA); |
209 | 1 | offset += 16; |
210 | 1 | } |
211 | 4 | proto_tree_add_item(sess_tree, hf_ipmi_session_msg_len_1b, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
212 | 4 | offset++; |
213 | 4 | } |
214 | 4 | } |
215 | | |
216 | | /* If we can parse the embedded message, do so */ |
217 | 5 | next_tvb = tvb_new_subset_length(tvb, msg_start, msg_len); |
218 | 5 | 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. |
226 | | */ |
227 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
228 | 5 | } 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 | 4 | call_dissector(ipmi_handle, next_tvb, pinfo, tree); |
232 | 4 | } else { |
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 | 1 | call_data_dissector(next_tvb, pinfo, tree); |
237 | 1 | } |
238 | | |
239 | 5 | if (tree) { |
240 | | /* Account for the message we just parsed. */ |
241 | 4 | offset += msg_len; |
242 | | |
243 | | /* Show the rest of the session wrapper as binary data */ |
244 | 4 | if (offset < tvb_captured_length(tvb)) { |
245 | 1 | proto_tree_add_item(sess_tree, hf_ipmi_session_trailer, |
246 | 1 | tvb, offset, -1, ENC_NA); |
247 | 1 | } |
248 | 4 | } |
249 | 5 | return tvb_captured_length(tvb); |
250 | 5 | } |
251 | | |
252 | | void |
253 | | proto_register_ipmi_session(void) |
254 | 14 | { |
255 | 14 | static hf_register_info hf[] = { |
256 | 14 | { &hf_ipmi_session_authtype, { |
257 | 14 | "Authentication Type", "ipmi_session.authtype", |
258 | 14 | FT_UINT8, BASE_HEX, VALS(ipmi_authtype_vals), 0, NULL, HFILL }}, |
259 | 14 | { &hf_ipmi_session_payloadtype,{ |
260 | 14 | "Payload Type", "ipmi_session.payloadtype", |
261 | 14 | FT_UINT8, BASE_HEX, VALS(ipmi_payload_vals), 0x3f, NULL, HFILL }}, |
262 | 14 | { &hf_ipmi_session_payloadtype_auth,{ |
263 | 14 | "Authenticated","ipmi_session.payloadtype.auth", |
264 | 14 | FT_BOOLEAN,8, TFS(&ipmi_payload_aut_val), 0x40, NULL, HFILL }}, |
265 | 14 | { &hf_ipmi_session_payloadtype_enc,{ |
266 | 14 | "Encryption","ipmi_session.payloadtype.enc", |
267 | 14 | FT_BOOLEAN,8, TFS(&ipmi_payload_enc_val), 0x80, NULL, HFILL }}, |
268 | 14 | { &hf_ipmi_session_oem_iana, { |
269 | 14 | "OEM IANA", "ipmi_session.oem.iana", |
270 | 14 | FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}, |
271 | 14 | { &hf_ipmi_session_oem_payload_id, { |
272 | 14 | "OEM Payload ID", "ipmi_session.oem.payloadid", |
273 | 14 | FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}, |
274 | 14 | { &hf_ipmi_session_sequence, { |
275 | 14 | "Session Sequence Number", "ipmi_session.sequence", |
276 | 14 | FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }}, |
277 | 14 | { &hf_ipmi_session_id, { |
278 | 14 | "Session ID", "ipmi_session.id", |
279 | 14 | FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }}, |
280 | 14 | { &hf_ipmi_session_authcode, { |
281 | 14 | "Authentication Code", "ipmi_session.authcode", |
282 | 14 | FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}, |
283 | 14 | { &hf_ipmi_session_msg_len_1b, { |
284 | 14 | "Message Length", "ipmi_session.msg.len", |
285 | 14 | FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, |
286 | 14 | { &hf_ipmi_session_msg_len_2b, { |
287 | 14 | "Message Length", "ipmi_session.msg.len", |
288 | 14 | FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}, |
289 | 14 | { &hf_ipmi_session_trailer, { |
290 | 14 | "IPMI Session Wrapper (trailer)", "ipmi_session.trailer", |
291 | 14 | FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}, |
292 | 14 | }; |
293 | | |
294 | 14 | static int *ett[] = { &ett_ipmi_session, &ett_ipmi_session_payloadtype }; |
295 | | |
296 | 14 | proto_ipmi_session = proto_register_protocol("Intelligent Platform Management Interface (Session Wrapper)", "IPMI Session", "ipmi_session"); |
297 | 14 | proto_register_field_array(proto_ipmi_session, hf, array_length(hf)); |
298 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
299 | | |
300 | 14 | ipmi_session_handle = register_dissector("ipmi_session", dissect_ipmi_session, proto_ipmi_session); |
301 | 14 | } |
302 | | |
303 | | void |
304 | | proto_reg_handoff_ipmi_session(void) |
305 | 14 | { |
306 | 14 | dissector_add_uint("rmcp.class", RMCP_CLASS_IPMI, ipmi_session_handle); |
307 | | |
308 | 14 | ipmi_handle = find_dissector_add_dependency("ipmi", proto_ipmi_session); |
309 | 14 | } |
310 | | |
311 | | /* |
312 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
313 | | * |
314 | | * Local variables: |
315 | | * c-basic-offset: 8 |
316 | | * tab-width: 8 |
317 | | * indent-tabs-mode: t |
318 | | * End: |
319 | | * |
320 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
321 | | * :indentSize=8:tabSize=8:noTabs=false: |
322 | | */ |