xref: /openbmc/ipmitool/src/plugins/lanplus/lanplus.c (revision d9f89a8d)
1c18ec02fSPetter Reinholdtsen /*
2c18ec02fSPetter Reinholdtsen  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
3c18ec02fSPetter Reinholdtsen  *
4c18ec02fSPetter Reinholdtsen  * Redistribution and use in source and binary forms, with or without
5c18ec02fSPetter Reinholdtsen  * modification, are permitted provided that the following conditions
6c18ec02fSPetter Reinholdtsen  * are met:
7c18ec02fSPetter Reinholdtsen  *
8c18ec02fSPetter Reinholdtsen  * Redistribution of source code must retain the above copyright
9c18ec02fSPetter Reinholdtsen  * notice, this list of conditions and the following disclaimer.
10c18ec02fSPetter Reinholdtsen  *
11c18ec02fSPetter Reinholdtsen  * Redistribution in binary form must reproduce the above copyright
12c18ec02fSPetter Reinholdtsen  * notice, this list of conditions and the following disclaimer in the
13c18ec02fSPetter Reinholdtsen  * documentation and/or other materials provided with the distribution.
14c18ec02fSPetter Reinholdtsen  *
15c18ec02fSPetter Reinholdtsen  * Neither the name of Sun Microsystems, Inc. or the names of
16c18ec02fSPetter Reinholdtsen  * contributors may be used to endorse or promote products derived
17c18ec02fSPetter Reinholdtsen  * from this software without specific prior written permission.
18c18ec02fSPetter Reinholdtsen  *
19c18ec02fSPetter Reinholdtsen  * This software is provided "AS IS," without a warranty of any kind.
20c18ec02fSPetter Reinholdtsen  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21c18ec02fSPetter Reinholdtsen  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22c18ec02fSPetter Reinholdtsen  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23c18ec02fSPetter Reinholdtsen  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24c18ec02fSPetter Reinholdtsen  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25c18ec02fSPetter Reinholdtsen  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26c18ec02fSPetter Reinholdtsen  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27c18ec02fSPetter Reinholdtsen  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28c18ec02fSPetter Reinholdtsen  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29c18ec02fSPetter Reinholdtsen  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30c18ec02fSPetter Reinholdtsen  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31c18ec02fSPetter Reinholdtsen  */
32c18ec02fSPetter Reinholdtsen 
33c18ec02fSPetter Reinholdtsen #include <stdlib.h>
34c18ec02fSPetter Reinholdtsen #include <stdio.h>
35c18ec02fSPetter Reinholdtsen #include <inttypes.h>
36c18ec02fSPetter Reinholdtsen #include <string.h>
37c18ec02fSPetter Reinholdtsen #include <sys/types.h>
38c18ec02fSPetter Reinholdtsen #include <sys/socket.h>
39c18ec02fSPetter Reinholdtsen #include <netinet/in.h>
40c18ec02fSPetter Reinholdtsen #include <arpa/inet.h>
41c18ec02fSPetter Reinholdtsen #include <errno.h>
42c18ec02fSPetter Reinholdtsen #include <unistd.h>
43c18ec02fSPetter Reinholdtsen #include <netdb.h>
44c18ec02fSPetter Reinholdtsen #include <time.h>
45c18ec02fSPetter Reinholdtsen #include <fcntl.h>
46c18ec02fSPetter Reinholdtsen #include <assert.h>
47c18ec02fSPetter Reinholdtsen 
48c18ec02fSPetter Reinholdtsen #ifdef HAVE_CONFIG_H
49c18ec02fSPetter Reinholdtsen # include <config.h>
50c18ec02fSPetter Reinholdtsen #endif
51c18ec02fSPetter Reinholdtsen #include <ipmitool/helper.h>
52c18ec02fSPetter Reinholdtsen #include <ipmitool/log.h>
53c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi.h>
54c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_lanp.h>
55c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_channel.h>
56c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_intf.h>
57c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_strings.h>
5823e9340bSZdenek Styblik #include <ipmitool/hpm2.h>
59c18ec02fSPetter Reinholdtsen #include <ipmitool/bswap.h>
60c18ec02fSPetter Reinholdtsen #include <openssl/rand.h>
61c18ec02fSPetter Reinholdtsen 
62c18ec02fSPetter Reinholdtsen #include "lanplus.h"
63c18ec02fSPetter Reinholdtsen #include "lanplus_crypt.h"
64c18ec02fSPetter Reinholdtsen #include "lanplus_crypt_impl.h"
65c18ec02fSPetter Reinholdtsen #include "lanplus_dump.h"
66c18ec02fSPetter Reinholdtsen #include "rmcp.h"
67c18ec02fSPetter Reinholdtsen #include "asf.h"
68c18ec02fSPetter Reinholdtsen 
6923e9340bSZdenek Styblik /*
7023e9340bSZdenek Styblik  * LAN interface is required to support 45 byte request transactions and
7123e9340bSZdenek Styblik  * 42 byte response transactions.
7223e9340bSZdenek Styblik  */
7323e9340bSZdenek Styblik #define IPMI_LAN_MAX_REQUEST_SIZE	38	/* 45 - 7 */
7423e9340bSZdenek Styblik #define IPMI_LAN_MAX_RESPONSE_SIZE	34	/* 42 - 8 */
7523e9340bSZdenek Styblik 
76c18ec02fSPetter Reinholdtsen extern const struct valstr ipmi_rakp_return_codes[];
77c18ec02fSPetter Reinholdtsen extern const struct valstr ipmi_priv_levels[];
78c18ec02fSPetter Reinholdtsen extern const struct valstr ipmi_auth_algorithms[];
79c18ec02fSPetter Reinholdtsen extern const struct valstr ipmi_integrity_algorithms[];
80c18ec02fSPetter Reinholdtsen extern const struct valstr ipmi_encryption_algorithms[];
81c18ec02fSPetter Reinholdtsen 
82c18ec02fSPetter Reinholdtsen static struct ipmi_rq_entry * ipmi_req_entries;
83c18ec02fSPetter Reinholdtsen static struct ipmi_rq_entry * ipmi_req_entries_tail;
84c18ec02fSPetter Reinholdtsen 
85c18ec02fSPetter Reinholdtsen 
86c18ec02fSPetter Reinholdtsen static int ipmi_lanplus_setup(struct ipmi_intf * intf);
87c18ec02fSPetter Reinholdtsen static int ipmi_lanplus_keepalive(struct ipmi_intf * intf);
88c18ec02fSPetter Reinholdtsen static int ipmi_lan_send_packet(struct ipmi_intf * intf, uint8_t * data, int data_len);
89c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lan_recv_packet(struct ipmi_intf * intf);
90c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lan_poll_recv(struct ipmi_intf * intf);
91c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lanplus_send_ipmi_cmd(struct ipmi_intf * intf, struct ipmi_rq * req);
92c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lanplus_send_payload(struct ipmi_intf * intf,
93c18ec02fSPetter Reinholdtsen 												  struct ipmi_v2_payload * payload);
94c18ec02fSPetter Reinholdtsen static void getIpmiPayloadWireRep(
95c18ec02fSPetter Reinholdtsen 								  struct ipmi_intf       * intf,
96c18ec02fSPetter Reinholdtsen 								  struct ipmi_v2_payload * payload,  /* in  */
97c18ec02fSPetter Reinholdtsen 								  uint8_t  * out,
98c18ec02fSPetter Reinholdtsen 								  struct ipmi_rq * req,
99c18ec02fSPetter Reinholdtsen 								  uint8_t    rq_seq,
100c18ec02fSPetter Reinholdtsen 								  uint8_t curr_seq);
101c18ec02fSPetter Reinholdtsen static void getSolPayloadWireRep(
102c18ec02fSPetter Reinholdtsen 								  struct ipmi_intf       * intf,
103c18ec02fSPetter Reinholdtsen 								 uint8_t          * msg,
104c18ec02fSPetter Reinholdtsen 								 struct ipmi_v2_payload * payload);
105c18ec02fSPetter Reinholdtsen static void read_open_session_response(struct ipmi_rs * rsp, int offset);
106c18ec02fSPetter Reinholdtsen static void read_rakp2_message(struct ipmi_rs * rsp, int offset, uint8_t alg);
107c18ec02fSPetter Reinholdtsen static void read_rakp4_message(struct ipmi_rs * rsp, int offset, uint8_t alg);
108c18ec02fSPetter Reinholdtsen static void read_session_data(struct ipmi_rs * rsp, int * offset, struct ipmi_session *s);
109c18ec02fSPetter Reinholdtsen static void read_session_data_v15(struct ipmi_rs * rsp, int * offset, struct ipmi_session *s);
110c18ec02fSPetter Reinholdtsen static void read_session_data_v2x(struct ipmi_rs * rsp, int * offset, struct ipmi_session *s);
111c18ec02fSPetter Reinholdtsen static void read_ipmi_response(struct ipmi_rs * rsp, int * offset);
112c18ec02fSPetter Reinholdtsen static void read_sol_packet(struct ipmi_rs * rsp, int * offset);
113c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lanplus_recv_sol(struct ipmi_intf * intf);
114c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lanplus_send_sol(
115c18ec02fSPetter Reinholdtsen 											  struct ipmi_intf * intf,
116c18ec02fSPetter Reinholdtsen 											  struct ipmi_v2_payload * payload);
117c18ec02fSPetter Reinholdtsen static int check_sol_packet_for_new_data(
118c18ec02fSPetter Reinholdtsen 									 struct ipmi_intf * intf,
119c18ec02fSPetter Reinholdtsen 									 struct ipmi_rs *rsp);
120c18ec02fSPetter Reinholdtsen static void ack_sol_packet(
121c18ec02fSPetter Reinholdtsen 							struct ipmi_intf * intf,
122c18ec02fSPetter Reinholdtsen 							struct ipmi_rs * rsp);
12323e9340bSZdenek Styblik static void ipmi_lanp_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size);
12423e9340bSZdenek Styblik static void ipmi_lanp_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size);
125c18ec02fSPetter Reinholdtsen 
126c18ec02fSPetter Reinholdtsen static uint8_t bridgePossible = 0;
127c18ec02fSPetter Reinholdtsen 
128c18ec02fSPetter Reinholdtsen struct ipmi_intf ipmi_lanplus_intf = {
129c18ec02fSPetter Reinholdtsen 	name:		"lanplus",
130c18ec02fSPetter Reinholdtsen 	desc:		"IPMI v2.0 RMCP+ LAN Interface",
131c18ec02fSPetter Reinholdtsen 	setup:		ipmi_lanplus_setup,
132c18ec02fSPetter Reinholdtsen 	open:		ipmi_lanplus_open,
133c18ec02fSPetter Reinholdtsen 	close:		ipmi_lanplus_close,
134c18ec02fSPetter Reinholdtsen 	sendrecv:	ipmi_lanplus_send_ipmi_cmd,
135c18ec02fSPetter Reinholdtsen 	recv_sol:	ipmi_lanplus_recv_sol,
136c18ec02fSPetter Reinholdtsen 	send_sol:	ipmi_lanplus_send_sol,
137c18ec02fSPetter Reinholdtsen 	keepalive:	ipmi_lanplus_keepalive,
13823e9340bSZdenek Styblik 	set_max_request_data_size: ipmi_lanp_set_max_rq_data_size,
13923e9340bSZdenek Styblik 	set_max_response_data_size: ipmi_lanp_set_max_rp_data_size,
140c18ec02fSPetter Reinholdtsen 	target_addr:	IPMI_BMC_SLAVE_ADDR,
141c18ec02fSPetter Reinholdtsen };
142c18ec02fSPetter Reinholdtsen 
143c18ec02fSPetter Reinholdtsen 
144c18ec02fSPetter Reinholdtsen extern int verbose;
145c18ec02fSPetter Reinholdtsen 
146c18ec02fSPetter Reinholdtsen 
147c18ec02fSPetter Reinholdtsen 
148c18ec02fSPetter Reinholdtsen /*
149c18ec02fSPetter Reinholdtsen  * lanplus_get_requested_ciphers
150c18ec02fSPetter Reinholdtsen  *
151c18ec02fSPetter Reinholdtsen  * Set the authentication, integrity and encryption algorithms based
152c18ec02fSPetter Reinholdtsen  * on the cipher suite ID.  See table 22-19 in the IPMIv2 spec for the
153c18ec02fSPetter Reinholdtsen  * source of this information.
154c18ec02fSPetter Reinholdtsen  *
155c18ec02fSPetter Reinholdtsen  * param cipher_suite_id [in]
156c18ec02fSPetter Reinholdtsen  * param auth_alg        [out]
157c18ec02fSPetter Reinholdtsen  * param integrity_alg   [out]
158c18ec02fSPetter Reinholdtsen  * param crypt_alg       [out]
159c18ec02fSPetter Reinholdtsen  *
160c18ec02fSPetter Reinholdtsen  * returns 0 on success
161c18ec02fSPetter Reinholdtsen  *         1 on failure
162c18ec02fSPetter Reinholdtsen  */
163c18ec02fSPetter Reinholdtsen int lanplus_get_requested_ciphers(int       cipher_suite_id,
164c18ec02fSPetter Reinholdtsen 								  uint8_t * auth_alg,
165c18ec02fSPetter Reinholdtsen 								  uint8_t * integrity_alg,
166c18ec02fSPetter Reinholdtsen 								  uint8_t * crypt_alg)
167c18ec02fSPetter Reinholdtsen {
168c18ec02fSPetter Reinholdtsen 	if ((cipher_suite_id < 0) || (cipher_suite_id > 14))
169c18ec02fSPetter Reinholdtsen 		return 1;
170c18ec02fSPetter Reinholdtsen 
171c18ec02fSPetter Reinholdtsen 		/* See table 22-19 for the source of the statement */
172c18ec02fSPetter Reinholdtsen 	switch (cipher_suite_id)
173c18ec02fSPetter Reinholdtsen 	{
174c18ec02fSPetter Reinholdtsen 	case 0:
175c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_NONE;
176c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_NONE;
177c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_NONE;
178c18ec02fSPetter Reinholdtsen 		break;
179c18ec02fSPetter Reinholdtsen 	case 1:
180c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA1;
181c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_NONE;
182c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_NONE;
183c18ec02fSPetter Reinholdtsen 		break;
184c18ec02fSPetter Reinholdtsen 	case 2:
185c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA1;
186c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96;
187c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_NONE;
188c18ec02fSPetter Reinholdtsen 		break;
189c18ec02fSPetter Reinholdtsen 	case 3:
190c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA1;
191c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96;
192c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_AES_CBC_128;
193c18ec02fSPetter Reinholdtsen 		break;
194c18ec02fSPetter Reinholdtsen 	case 4:
195c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA1;
196c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96;
197c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_XRC4_128;
198c18ec02fSPetter Reinholdtsen 		break;
199c18ec02fSPetter Reinholdtsen 	case 5:
200c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA1;
201c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96;
202c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_XRC4_40;
203c18ec02fSPetter Reinholdtsen 		break;
204c18ec02fSPetter Reinholdtsen 	case 6:
205c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
206c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_NONE;
207c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_NONE;
208c18ec02fSPetter Reinholdtsen 		break;
209c18ec02fSPetter Reinholdtsen 	case 7:
210c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
211c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128;
212c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_NONE;
213c18ec02fSPetter Reinholdtsen 		break;
214c18ec02fSPetter Reinholdtsen 	case 8:
215c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
216c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128;
217c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_AES_CBC_128;
218c18ec02fSPetter Reinholdtsen 		break;
219c18ec02fSPetter Reinholdtsen 	case 9:
220c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
221c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128;
222c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_XRC4_128;
223c18ec02fSPetter Reinholdtsen 		break;
224c18ec02fSPetter Reinholdtsen 	case 10:
225c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
226c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128;
227c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_XRC4_40;
228c18ec02fSPetter Reinholdtsen 		break;
229c18ec02fSPetter Reinholdtsen 	case 11:
230c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
231c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_MD5_128;
232c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_NONE;
233c18ec02fSPetter Reinholdtsen 		break;
234c18ec02fSPetter Reinholdtsen 	case 12:
235c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
236c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_MD5_128;
237c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_AES_CBC_128;
238c18ec02fSPetter Reinholdtsen 		break;
239c18ec02fSPetter Reinholdtsen 	case 13:
240c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
241c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_MD5_128;
242c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_XRC4_128;
243c18ec02fSPetter Reinholdtsen 		break;
244c18ec02fSPetter Reinholdtsen 	case 14:
245c18ec02fSPetter Reinholdtsen 		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
246c18ec02fSPetter Reinholdtsen 		*integrity_alg = IPMI_INTEGRITY_MD5_128;
247c18ec02fSPetter Reinholdtsen 		*crypt_alg     = IPMI_CRYPT_XRC4_40;
248c18ec02fSPetter Reinholdtsen 		break;
249c18ec02fSPetter Reinholdtsen 	}
250c18ec02fSPetter Reinholdtsen 
251c18ec02fSPetter Reinholdtsen 	return 0;
252c18ec02fSPetter Reinholdtsen }
253c18ec02fSPetter Reinholdtsen 
254c18ec02fSPetter Reinholdtsen 
255c18ec02fSPetter Reinholdtsen 
256c18ec02fSPetter Reinholdtsen /*
257c18ec02fSPetter Reinholdtsen  * Reverse the order of arbitrarily long strings of bytes
258c18ec02fSPetter Reinholdtsen  */
259c18ec02fSPetter Reinholdtsen void lanplus_swap(
260c18ec02fSPetter Reinholdtsen 				  uint8_t * buffer,
261c18ec02fSPetter Reinholdtsen 						int             length)
262c18ec02fSPetter Reinholdtsen {
263c18ec02fSPetter Reinholdtsen 	int i;
264c18ec02fSPetter Reinholdtsen 	uint8_t temp;
265c18ec02fSPetter Reinholdtsen 
266c18ec02fSPetter Reinholdtsen 	for (i =0; i < length/2; ++i)
267c18ec02fSPetter Reinholdtsen 	{
268c18ec02fSPetter Reinholdtsen 		temp = buffer[i];
269c18ec02fSPetter Reinholdtsen 		buffer[i] = buffer[length - 1 - i];
270c18ec02fSPetter Reinholdtsen 		buffer[length - 1 - i] = temp;
271c18ec02fSPetter Reinholdtsen 	}
272c18ec02fSPetter Reinholdtsen }
273c18ec02fSPetter Reinholdtsen 
274c18ec02fSPetter Reinholdtsen 
275c18ec02fSPetter Reinholdtsen 
276c18ec02fSPetter Reinholdtsen static const struct valstr plus_payload_types_vals[] = {
277c18ec02fSPetter Reinholdtsen 	 { IPMI_PAYLOAD_TYPE_IPMI,              "IPMI (0)" },	// IPMI Message
278c18ec02fSPetter Reinholdtsen 	 { IPMI_PAYLOAD_TYPE_SOL,               "SOL  (1)" },	// SOL (Serial over LAN)
279c18ec02fSPetter Reinholdtsen 	 { IPMI_PAYLOAD_TYPE_OEM,               "OEM  (2)" },	// OEM Explicid
280c18ec02fSPetter Reinholdtsen 
281c18ec02fSPetter Reinholdtsen 	 { IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST, "OpenSession Req (0x10)" },
282c18ec02fSPetter Reinholdtsen 	 { IPMI_PAYLOAD_TYPE_RMCP_OPEN_RESPONSE,"OpenSession Resp (0x11)" },
283c18ec02fSPetter Reinholdtsen 	 { IPMI_PAYLOAD_TYPE_RAKP_1,            "RAKP1 (0x12)" },
284c18ec02fSPetter Reinholdtsen 	 { IPMI_PAYLOAD_TYPE_RAKP_2,            "RAKP2 (0x13)" },
285c18ec02fSPetter Reinholdtsen 	 { IPMI_PAYLOAD_TYPE_RAKP_3,            "RAKP3 (0x14)" },
286c18ec02fSPetter Reinholdtsen 	 { IPMI_PAYLOAD_TYPE_RAKP_4,            "RAKP4 (0x15)" },
287c18ec02fSPetter Reinholdtsen 	{ 0x00, NULL },
288c18ec02fSPetter Reinholdtsen };
289c18ec02fSPetter Reinholdtsen 
290c18ec02fSPetter Reinholdtsen 
291c18ec02fSPetter Reinholdtsen static struct ipmi_rq_entry *
292c18ec02fSPetter Reinholdtsen ipmi_req_add_entry(struct ipmi_intf * intf, struct ipmi_rq * req, uint8_t req_seq)
293c18ec02fSPetter Reinholdtsen {
294c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * e;
295c18ec02fSPetter Reinholdtsen 
296c18ec02fSPetter Reinholdtsen 	e = malloc(sizeof(struct ipmi_rq_entry));
297c18ec02fSPetter Reinholdtsen 	if (e == NULL) {
298c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
299c18ec02fSPetter Reinholdtsen 		return NULL;
300c18ec02fSPetter Reinholdtsen 	}
301c18ec02fSPetter Reinholdtsen 
302c18ec02fSPetter Reinholdtsen 	memset(e, 0, sizeof(struct ipmi_rq_entry));
303c18ec02fSPetter Reinholdtsen 	memcpy(&e->req, req, sizeof(struct ipmi_rq));
304c18ec02fSPetter Reinholdtsen 
305c18ec02fSPetter Reinholdtsen 	e->intf = intf;
306c18ec02fSPetter Reinholdtsen 	e->rq_seq = req_seq;
307c18ec02fSPetter Reinholdtsen 
308c18ec02fSPetter Reinholdtsen 	if (ipmi_req_entries == NULL)
309c18ec02fSPetter Reinholdtsen 		ipmi_req_entries = e;
310c18ec02fSPetter Reinholdtsen 	else
311c18ec02fSPetter Reinholdtsen 		ipmi_req_entries_tail->next = e;
312c18ec02fSPetter Reinholdtsen 
313c18ec02fSPetter Reinholdtsen 	ipmi_req_entries_tail = e;
314c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+3, "added list entry seq=0x%02x cmd=0x%02x",
315c18ec02fSPetter Reinholdtsen 		e->rq_seq, e->req.msg.cmd);
316c18ec02fSPetter Reinholdtsen 	return e;
317c18ec02fSPetter Reinholdtsen }
318c18ec02fSPetter Reinholdtsen 
319c18ec02fSPetter Reinholdtsen 
320c18ec02fSPetter Reinholdtsen static struct ipmi_rq_entry *
321c18ec02fSPetter Reinholdtsen ipmi_req_lookup_entry(uint8_t seq, uint8_t cmd)
322c18ec02fSPetter Reinholdtsen {
323c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * e = ipmi_req_entries;
324c18ec02fSPetter Reinholdtsen 
325c18ec02fSPetter Reinholdtsen 	while (e && (e->rq_seq != seq || e->req.msg.cmd != cmd)) {
326c18ec02fSPetter Reinholdtsen 		if (e == e->next)
327c18ec02fSPetter Reinholdtsen 			return NULL;
328c18ec02fSPetter Reinholdtsen 		e = e->next;
329c18ec02fSPetter Reinholdtsen 	}
330c18ec02fSPetter Reinholdtsen 	return e;
331c18ec02fSPetter Reinholdtsen }
332c18ec02fSPetter Reinholdtsen 
333c18ec02fSPetter Reinholdtsen static void
334c18ec02fSPetter Reinholdtsen ipmi_req_remove_entry(uint8_t seq, uint8_t cmd)
335c18ec02fSPetter Reinholdtsen {
336c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * p, * e, * saved_next_entry;
337c18ec02fSPetter Reinholdtsen 
338c18ec02fSPetter Reinholdtsen 	e = p = ipmi_req_entries;
339c18ec02fSPetter Reinholdtsen 
340c18ec02fSPetter Reinholdtsen 	while (e && (e->rq_seq != seq || e->req.msg.cmd != cmd)) {
341c18ec02fSPetter Reinholdtsen 		p = e;
342c18ec02fSPetter Reinholdtsen 		e = e->next;
343c18ec02fSPetter Reinholdtsen 	}
344c18ec02fSPetter Reinholdtsen 	if (e) {
345c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG+3, "removed list entry seq=0x%02x cmd=0x%02x",
346c18ec02fSPetter Reinholdtsen 			seq, cmd);
347c18ec02fSPetter Reinholdtsen 		saved_next_entry = e->next;
348c18ec02fSPetter Reinholdtsen 		p->next = (p->next == e->next) ? NULL : e->next;
349c18ec02fSPetter Reinholdtsen 		/* If entry being removed is first in list, fix up list head */
350c18ec02fSPetter Reinholdtsen 		if (ipmi_req_entries == e) {
351c18ec02fSPetter Reinholdtsen 			if (ipmi_req_entries != p)
352c18ec02fSPetter Reinholdtsen 				ipmi_req_entries = p;
353c18ec02fSPetter Reinholdtsen 			else
354c18ec02fSPetter Reinholdtsen 				ipmi_req_entries = saved_next_entry;
355c18ec02fSPetter Reinholdtsen 		}
356c18ec02fSPetter Reinholdtsen 		/* If entry being removed is last in list, fix up list tail */
357c18ec02fSPetter Reinholdtsen 		if (ipmi_req_entries_tail == e) {
358c18ec02fSPetter Reinholdtsen 			if (ipmi_req_entries_tail != p)
359c18ec02fSPetter Reinholdtsen 				ipmi_req_entries_tail = p;
360c18ec02fSPetter Reinholdtsen 			else
361c18ec02fSPetter Reinholdtsen 				ipmi_req_entries_tail = NULL;
362c18ec02fSPetter Reinholdtsen 		}
363c18ec02fSPetter Reinholdtsen 
364c18ec02fSPetter Reinholdtsen 		if (e->msg_data) {
365c18ec02fSPetter Reinholdtsen 			free(e->msg_data);
366c18ec02fSPetter Reinholdtsen 			e->msg_data = NULL;
367c18ec02fSPetter Reinholdtsen 		}
368c18ec02fSPetter Reinholdtsen 		free(e);
369c18ec02fSPetter Reinholdtsen 		e = NULL;
370c18ec02fSPetter Reinholdtsen 	}
371c18ec02fSPetter Reinholdtsen }
372c18ec02fSPetter Reinholdtsen 
373c18ec02fSPetter Reinholdtsen static void
374c18ec02fSPetter Reinholdtsen ipmi_req_clear_entries(void)
375c18ec02fSPetter Reinholdtsen {
376c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * p, * e;
377c18ec02fSPetter Reinholdtsen 
378c18ec02fSPetter Reinholdtsen 	e = ipmi_req_entries;
379c18ec02fSPetter Reinholdtsen 	while (e) {
380c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG+3, "cleared list entry seq=0x%02x cmd=0x%02x",
381c18ec02fSPetter Reinholdtsen 			e->rq_seq, e->req.msg.cmd);
382c18ec02fSPetter Reinholdtsen 		p = e->next;
383c18ec02fSPetter Reinholdtsen 		free(e);
384c18ec02fSPetter Reinholdtsen 		e = p;
385c18ec02fSPetter Reinholdtsen 	}
386c18ec02fSPetter Reinholdtsen }
387c18ec02fSPetter Reinholdtsen 
388c18ec02fSPetter Reinholdtsen 
389c18ec02fSPetter Reinholdtsen int
390c18ec02fSPetter Reinholdtsen ipmi_lan_send_packet(
391c18ec02fSPetter Reinholdtsen 					 struct ipmi_intf * intf,
392c18ec02fSPetter Reinholdtsen 					 uint8_t * data, int
393c18ec02fSPetter Reinholdtsen 					 data_len)
394c18ec02fSPetter Reinholdtsen {
395c18ec02fSPetter Reinholdtsen 	if (verbose >= 5)
396c18ec02fSPetter Reinholdtsen 		printbuf(data, data_len, ">> sending packet");
397c18ec02fSPetter Reinholdtsen 
398c18ec02fSPetter Reinholdtsen 	return send(intf->fd, data, data_len, 0);
399c18ec02fSPetter Reinholdtsen }
400c18ec02fSPetter Reinholdtsen 
401c18ec02fSPetter Reinholdtsen 
402c18ec02fSPetter Reinholdtsen 
403c18ec02fSPetter Reinholdtsen struct ipmi_rs *
404c18ec02fSPetter Reinholdtsen ipmi_lan_recv_packet(struct ipmi_intf * intf)
405c18ec02fSPetter Reinholdtsen {
406c18ec02fSPetter Reinholdtsen 	static struct ipmi_rs rsp;
407c18ec02fSPetter Reinholdtsen 	fd_set read_set, err_set;
408c18ec02fSPetter Reinholdtsen 	struct timeval tmout;
409c18ec02fSPetter Reinholdtsen 	int ret;
410c18ec02fSPetter Reinholdtsen 
411c18ec02fSPetter Reinholdtsen 	FD_ZERO(&read_set);
412c18ec02fSPetter Reinholdtsen 	FD_SET(intf->fd, &read_set);
413c18ec02fSPetter Reinholdtsen 
414c18ec02fSPetter Reinholdtsen 	FD_ZERO(&err_set);
415c18ec02fSPetter Reinholdtsen 	FD_SET(intf->fd, &err_set);
416c18ec02fSPetter Reinholdtsen 
417c18ec02fSPetter Reinholdtsen 	tmout.tv_sec = intf->session->timeout;
418c18ec02fSPetter Reinholdtsen 	tmout.tv_usec = 0;
419c18ec02fSPetter Reinholdtsen 
420c18ec02fSPetter Reinholdtsen 	ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout);
421c18ec02fSPetter Reinholdtsen 	if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set))
422c18ec02fSPetter Reinholdtsen 		return NULL;
423c18ec02fSPetter Reinholdtsen 
424c18ec02fSPetter Reinholdtsen 	/* the first read may return ECONNREFUSED because the rmcp ping
425c18ec02fSPetter Reinholdtsen 	 * packet--sent to UDP port 623--will be processed by both the
426c18ec02fSPetter Reinholdtsen 	 * BMC and the OS.
427c18ec02fSPetter Reinholdtsen 	 *
428c18ec02fSPetter Reinholdtsen 	 * The problem with this is that the ECONNREFUSED takes
429c18ec02fSPetter Reinholdtsen 	 * priority over any other received datagram; that means that
430c18ec02fSPetter Reinholdtsen 	 * the Connection Refused shows up _before_ the response packet,
431c18ec02fSPetter Reinholdtsen 	 * regardless of the order they were sent out.  (unless the
432c18ec02fSPetter Reinholdtsen 	 * response is read before the connection refused is returned)
433c18ec02fSPetter Reinholdtsen 	 */
434c18ec02fSPetter Reinholdtsen 	ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0);
435c18ec02fSPetter Reinholdtsen 
436c18ec02fSPetter Reinholdtsen 	if (ret < 0) {
437c18ec02fSPetter Reinholdtsen 		FD_ZERO(&read_set);
438c18ec02fSPetter Reinholdtsen 		FD_SET(intf->fd, &read_set);
439c18ec02fSPetter Reinholdtsen 
440c18ec02fSPetter Reinholdtsen 		FD_ZERO(&err_set);
441c18ec02fSPetter Reinholdtsen 		FD_SET(intf->fd, &err_set);
442c18ec02fSPetter Reinholdtsen 
443c18ec02fSPetter Reinholdtsen 		tmout.tv_sec = intf->session->timeout;
444c18ec02fSPetter Reinholdtsen 		tmout.tv_usec = 0;
445c18ec02fSPetter Reinholdtsen 
446c18ec02fSPetter Reinholdtsen 		ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout);
447c18ec02fSPetter Reinholdtsen 		if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set))
448c18ec02fSPetter Reinholdtsen 			return NULL;
449c18ec02fSPetter Reinholdtsen 
450c18ec02fSPetter Reinholdtsen 		ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0);
451c18ec02fSPetter Reinholdtsen 		if (ret < 0)
452c18ec02fSPetter Reinholdtsen 			return NULL;
453c18ec02fSPetter Reinholdtsen 	}
454c18ec02fSPetter Reinholdtsen 
455c18ec02fSPetter Reinholdtsen 	if (ret == 0)
456c18ec02fSPetter Reinholdtsen 		return NULL;
457c18ec02fSPetter Reinholdtsen 
458c18ec02fSPetter Reinholdtsen 	rsp.data[ret] = '\0';
459c18ec02fSPetter Reinholdtsen 	rsp.data_len = ret;
460c18ec02fSPetter Reinholdtsen 
461c18ec02fSPetter Reinholdtsen 	if (verbose >= 5)
462c18ec02fSPetter Reinholdtsen 		printbuf(rsp.data, rsp.data_len, "<< received packet");
463c18ec02fSPetter Reinholdtsen 
464c18ec02fSPetter Reinholdtsen 	return &rsp;
465c18ec02fSPetter Reinholdtsen }
466c18ec02fSPetter Reinholdtsen 
467c18ec02fSPetter Reinholdtsen 
468c18ec02fSPetter Reinholdtsen 
469c18ec02fSPetter Reinholdtsen /*
470c18ec02fSPetter Reinholdtsen  * parse response RMCP "pong" packet
471c18ec02fSPetter Reinholdtsen  *
472c18ec02fSPetter Reinholdtsen  * return -1 if ping response not received
473c18ec02fSPetter Reinholdtsen  * returns 0 if IPMI is NOT supported
474c18ec02fSPetter Reinholdtsen  * returns 1 if IPMI is supported
475c18ec02fSPetter Reinholdtsen  *
476c18ec02fSPetter Reinholdtsen  * udp.source	= 0x026f	// RMCP_UDP_PORT
477c18ec02fSPetter Reinholdtsen  * udp.dest	= ?		// udp.source from rmcp-ping
478c18ec02fSPetter Reinholdtsen  * udp.len	= ?
479c18ec02fSPetter Reinholdtsen  * udp.check	= ?
480c18ec02fSPetter Reinholdtsen  * rmcp.ver	= 0x06		// RMCP Version 1.0
481c18ec02fSPetter Reinholdtsen  * rmcp.__res	= 0x00		// RESERVED
482c18ec02fSPetter Reinholdtsen  * rmcp.seq	= 0xff		// no RMCP ACK
483c18ec02fSPetter Reinholdtsen  * rmcp.class	= 0x06		// RMCP_CLASS_ASF
484c18ec02fSPetter Reinholdtsen  * asf.iana	= 0x000011be	// ASF_RMCP_IANA
485c18ec02fSPetter Reinholdtsen  * asf.type	= 0x40		// ASF_TYPE_PONG
486c18ec02fSPetter Reinholdtsen  * asf.tag	= ?		// asf.tag from rmcp-ping
487c18ec02fSPetter Reinholdtsen  * asf.__res	= 0x00		// RESERVED
488c18ec02fSPetter Reinholdtsen  * asf.len	= 0x10		// 16 bytes
489c18ec02fSPetter Reinholdtsen  * asf.data[3:0]= 0x000011be	// IANA# = RMCP_ASF_IANA if no OEM
490c18ec02fSPetter Reinholdtsen  * asf.data[7:4]= 0x00000000	// OEM-defined (not for IPMI)
491c18ec02fSPetter Reinholdtsen  * asf.data[8]	= 0x81		// supported entities
492c18ec02fSPetter Reinholdtsen  * 				// [7]=IPMI [6:4]=RES [3:0]=ASF_1.0
493c18ec02fSPetter Reinholdtsen  * asf.data[9]	= 0x00		// supported interactions (reserved)
494c18ec02fSPetter Reinholdtsen  * asf.data[f:a]= 0x000000000000
495c18ec02fSPetter Reinholdtsen  */
496c18ec02fSPetter Reinholdtsen static int
497c18ec02fSPetter Reinholdtsen ipmi_handle_pong(struct ipmi_intf * intf, struct ipmi_rs * rsp)
498c18ec02fSPetter Reinholdtsen {
499c18ec02fSPetter Reinholdtsen 	struct rmcp_pong {
500c18ec02fSPetter Reinholdtsen 		struct rmcp_hdr rmcp;
501c18ec02fSPetter Reinholdtsen 		struct asf_hdr asf;
502c18ec02fSPetter Reinholdtsen 		uint32_t iana;
503c18ec02fSPetter Reinholdtsen 		uint32_t oem;
504c18ec02fSPetter Reinholdtsen 		uint8_t sup_entities;
505c18ec02fSPetter Reinholdtsen 		uint8_t sup_interact;
506c18ec02fSPetter Reinholdtsen 		uint8_t reserved[6];
507c18ec02fSPetter Reinholdtsen 	} * pong;
508c18ec02fSPetter Reinholdtsen 
509c18ec02fSPetter Reinholdtsen 	if (!rsp)
510c18ec02fSPetter Reinholdtsen 		return -1;
511c18ec02fSPetter Reinholdtsen 
512c18ec02fSPetter Reinholdtsen 	pong = (struct rmcp_pong *)rsp->data;
513c18ec02fSPetter Reinholdtsen 
514c18ec02fSPetter Reinholdtsen 	if (verbose)
515c18ec02fSPetter Reinholdtsen 		printf("Received IPMI/RMCP response packet: "
516c18ec02fSPetter Reinholdtsen 				"IPMI%s Supported\n",
517c18ec02fSPetter Reinholdtsen 				(pong->sup_entities & 0x80) ? "" : " NOT");
518c18ec02fSPetter Reinholdtsen 
519c18ec02fSPetter Reinholdtsen 	if (verbose > 1)
520c18ec02fSPetter Reinholdtsen 		printf("  ASF Version %s\n"
521c18ec02fSPetter Reinholdtsen 				"  RMCP Version %s\n"
522c18ec02fSPetter Reinholdtsen 				"  RMCP Sequence %d\n"
523c18ec02fSPetter Reinholdtsen 				"  IANA Enterprise %lu\n\n",
524c18ec02fSPetter Reinholdtsen 				(pong->sup_entities & 0x01) ? "1.0" : "unknown",
525c18ec02fSPetter Reinholdtsen 				(pong->rmcp.ver == 6) ? "1.0" : "unknown",
526c18ec02fSPetter Reinholdtsen 				pong->rmcp.seq,
527c18ec02fSPetter Reinholdtsen 				(unsigned long)ntohl(pong->iana));
528c18ec02fSPetter Reinholdtsen 
529c18ec02fSPetter Reinholdtsen 	return (pong->sup_entities & 0x80) ? 1 : 0;
530c18ec02fSPetter Reinholdtsen }
531c18ec02fSPetter Reinholdtsen 
532c18ec02fSPetter Reinholdtsen 
533c18ec02fSPetter Reinholdtsen /* build and send RMCP presence ping packet
534c18ec02fSPetter Reinholdtsen  *
535c18ec02fSPetter Reinholdtsen  * RMCP ping
536c18ec02fSPetter Reinholdtsen  *
537c18ec02fSPetter Reinholdtsen  * udp.source	= ?
538c18ec02fSPetter Reinholdtsen  * udp.dest	= 0x026f	// RMCP_UDP_PORT
539c18ec02fSPetter Reinholdtsen  * udp.len	= ?
540c18ec02fSPetter Reinholdtsen  * udp.check	= ?
541c18ec02fSPetter Reinholdtsen  * rmcp.ver	= 0x06		// RMCP Version 1.0
542c18ec02fSPetter Reinholdtsen  * rmcp.__res	= 0x00		// RESERVED
543c18ec02fSPetter Reinholdtsen  * rmcp.seq	= 0xff		// no RMCP ACK
544c18ec02fSPetter Reinholdtsen  * rmcp.class	= 0x06		// RMCP_CLASS_ASF
545c18ec02fSPetter Reinholdtsen  * asf.iana	= 0x000011be	// ASF_RMCP_IANA
546c18ec02fSPetter Reinholdtsen  * asf.type	= 0x80		// ASF_TYPE_PING
547c18ec02fSPetter Reinholdtsen  * asf.tag	= ?		// ASF sequence number
548c18ec02fSPetter Reinholdtsen  * asf.__res	= 0x00		// RESERVED
549c18ec02fSPetter Reinholdtsen  * asf.len	= 0x00
550c18ec02fSPetter Reinholdtsen  *
551c18ec02fSPetter Reinholdtsen  */
552c18ec02fSPetter Reinholdtsen int
553c18ec02fSPetter Reinholdtsen ipmiv2_lan_ping(struct ipmi_intf * intf)
554c18ec02fSPetter Reinholdtsen {
555c18ec02fSPetter Reinholdtsen 	struct asf_hdr asf_ping = {
556c18ec02fSPetter Reinholdtsen 		.iana	= htonl(ASF_RMCP_IANA),
557c18ec02fSPetter Reinholdtsen 		.type	= ASF_TYPE_PING,
558c18ec02fSPetter Reinholdtsen 	};
559c18ec02fSPetter Reinholdtsen 	struct rmcp_hdr rmcp_ping = {
560c18ec02fSPetter Reinholdtsen 		.ver	= RMCP_VERSION_1,
561c18ec02fSPetter Reinholdtsen 		.class	= RMCP_CLASS_ASF,
562c18ec02fSPetter Reinholdtsen 		.seq	= 0xff,
563c18ec02fSPetter Reinholdtsen 	};
564c18ec02fSPetter Reinholdtsen 	uint8_t * data;
565c18ec02fSPetter Reinholdtsen 	int len = sizeof(rmcp_ping) + sizeof(asf_ping);
566c18ec02fSPetter Reinholdtsen 	int rv;
567c18ec02fSPetter Reinholdtsen 
568c18ec02fSPetter Reinholdtsen 	data = malloc(len);
569c18ec02fSPetter Reinholdtsen 	if (data == NULL) {
570c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
571c18ec02fSPetter Reinholdtsen 		return -1;
572c18ec02fSPetter Reinholdtsen 	}
573c18ec02fSPetter Reinholdtsen 	memset(data, 0, len);
574c18ec02fSPetter Reinholdtsen 	memcpy(data, &rmcp_ping, sizeof(rmcp_ping));
575c18ec02fSPetter Reinholdtsen 	memcpy(data+sizeof(rmcp_ping), &asf_ping, sizeof(asf_ping));
576c18ec02fSPetter Reinholdtsen 
577c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Sending IPMI/RMCP presence ping packet");
578c18ec02fSPetter Reinholdtsen 
579c18ec02fSPetter Reinholdtsen 	rv = ipmi_lan_send_packet(intf, data, len);
580c18ec02fSPetter Reinholdtsen 
581c18ec02fSPetter Reinholdtsen 	free(data);
582c18ec02fSPetter Reinholdtsen 	data = NULL;
583c18ec02fSPetter Reinholdtsen 
584c18ec02fSPetter Reinholdtsen 	if (rv < 0) {
585c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Unable to send IPMI presence ping packet");
586c18ec02fSPetter Reinholdtsen 		return -1;
587c18ec02fSPetter Reinholdtsen 	}
588c18ec02fSPetter Reinholdtsen 
589c18ec02fSPetter Reinholdtsen 	if (ipmi_lan_poll_recv(intf) == 0)
590c18ec02fSPetter Reinholdtsen 		return 0;
591c18ec02fSPetter Reinholdtsen 
592c18ec02fSPetter Reinholdtsen 	return 1;
593c18ec02fSPetter Reinholdtsen }
594c18ec02fSPetter Reinholdtsen 
595c18ec02fSPetter Reinholdtsen 
596c18ec02fSPetter Reinholdtsen /**
597c18ec02fSPetter Reinholdtsen  *
598c18ec02fSPetter Reinholdtsen  * ipmi_lan_poll_recv
599c18ec02fSPetter Reinholdtsen  *
600c18ec02fSPetter Reinholdtsen  * Receive whatever comes back.  Ignore received packets that don't correspond
601c18ec02fSPetter Reinholdtsen  * to a request we've sent.
602c18ec02fSPetter Reinholdtsen  *
603c18ec02fSPetter Reinholdtsen  * Returns: the ipmi_rs packet describing the/a reponse we expect.
604c18ec02fSPetter Reinholdtsen  */
605c18ec02fSPetter Reinholdtsen static struct ipmi_rs *
606c18ec02fSPetter Reinholdtsen ipmi_lan_poll_recv(struct ipmi_intf * intf)
607c18ec02fSPetter Reinholdtsen {
608c18ec02fSPetter Reinholdtsen 	struct rmcp_hdr rmcp_rsp;
609c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
610c18ec02fSPetter Reinholdtsen 	struct ipmi_session * session = intf->session;
611c18ec02fSPetter Reinholdtsen 	int offset, rv;
612c18ec02fSPetter Reinholdtsen 	uint16_t payload_size;
613c18ec02fSPetter Reinholdtsen 	uint8_t ourAddress = intf->my_addr;
614c18ec02fSPetter Reinholdtsen 
615c18ec02fSPetter Reinholdtsen 	if (ourAddress == 0) {
616c18ec02fSPetter Reinholdtsen 		ourAddress = IPMI_BMC_SLAVE_ADDR;
617c18ec02fSPetter Reinholdtsen 	}
618c18ec02fSPetter Reinholdtsen 
619c18ec02fSPetter Reinholdtsen 	rsp = ipmi_lan_recv_packet(intf);
620c18ec02fSPetter Reinholdtsen 
621c18ec02fSPetter Reinholdtsen 	/*
622c18ec02fSPetter Reinholdtsen 	 * Not positive why we're looping.  Do we sometimes get stuff we don't
623c18ec02fSPetter Reinholdtsen 	 * expect?
624c18ec02fSPetter Reinholdtsen 	 */
625c18ec02fSPetter Reinholdtsen 	while (rsp != NULL) {
626c18ec02fSPetter Reinholdtsen 
627c18ec02fSPetter Reinholdtsen 		/* parse response headers */
628c18ec02fSPetter Reinholdtsen 		memcpy(&rmcp_rsp, rsp->data, 4);
629c18ec02fSPetter Reinholdtsen 
630c18ec02fSPetter Reinholdtsen 		if (rmcp_rsp.class == RMCP_CLASS_ASF) {
631c18ec02fSPetter Reinholdtsen 			/* might be ping response packet */
632c18ec02fSPetter Reinholdtsen 			rv = ipmi_handle_pong(intf, rsp);
633c18ec02fSPetter Reinholdtsen 			return (rv <= 0) ? NULL : rsp;
634c18ec02fSPetter Reinholdtsen 		}
635c18ec02fSPetter Reinholdtsen 
636c18ec02fSPetter Reinholdtsen 		if (rmcp_rsp.class != RMCP_CLASS_IPMI) {
637c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "Invalid RMCP class: %x",
638c18ec02fSPetter Reinholdtsen 				rmcp_rsp.class);
639c18ec02fSPetter Reinholdtsen 			rsp = ipmi_lan_recv_packet(intf);
640c18ec02fSPetter Reinholdtsen 			continue;
641c18ec02fSPetter Reinholdtsen 		}
642c18ec02fSPetter Reinholdtsen 
643c18ec02fSPetter Reinholdtsen 
644c18ec02fSPetter Reinholdtsen 		/*
645c18ec02fSPetter Reinholdtsen 		 * The authtype / payload type determines what we are receiving
646c18ec02fSPetter Reinholdtsen 		 */
647c18ec02fSPetter Reinholdtsen 		offset = 4;
648c18ec02fSPetter Reinholdtsen 
649c18ec02fSPetter Reinholdtsen 
650c18ec02fSPetter Reinholdtsen 		/*--------------------------------------------------------------------
651c18ec02fSPetter Reinholdtsen 		 *
652c18ec02fSPetter Reinholdtsen 		 * The current packet could be one of several things:
653c18ec02fSPetter Reinholdtsen 		 *
654c18ec02fSPetter Reinholdtsen 		 * 1) An IPMI 1.5 packet (the response to our GET CHANNEL
655c18ec02fSPetter Reinholdtsen 		 *    AUTHENTICATION CAPABILITIES request)
656c18ec02fSPetter Reinholdtsen 		 * 2) An RMCP+ message with an IPMI reponse payload
657c18ec02fSPetter Reinholdtsen 		 * 3) AN RMCP+ open session response
658c18ec02fSPetter Reinholdtsen 		 * 4) An RAKP-2 message (response to an RAKP 1 message)
659c18ec02fSPetter Reinholdtsen 		 * 5) An RAKP-4 message (response to an RAKP 3 message)
660c18ec02fSPetter Reinholdtsen 		 * 6) A Serial Over LAN packet
661c18ec02fSPetter Reinholdtsen 		 * 7) An Invalid packet (one that doesn't match a request)
662c18ec02fSPetter Reinholdtsen 		 * -------------------------------------------------------------------
663c18ec02fSPetter Reinholdtsen 		 */
664c18ec02fSPetter Reinholdtsen 
665c18ec02fSPetter Reinholdtsen 		read_session_data(rsp, &offset, intf->session);
666c18ec02fSPetter Reinholdtsen 
667c18ec02fSPetter Reinholdtsen 		if (lanplus_has_valid_auth_code(rsp, intf->session) == 0)
668c18ec02fSPetter Reinholdtsen 		{
669c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "ERROR: Received message with invalid authcode!");
670c18ec02fSPetter Reinholdtsen 			rsp = ipmi_lan_recv_packet(intf);
671c18ec02fSPetter Reinholdtsen 			assert(0);
672c18ec02fSPetter Reinholdtsen 			//continue;
673c18ec02fSPetter Reinholdtsen 		}
674c18ec02fSPetter Reinholdtsen 
675c18ec02fSPetter Reinholdtsen 		if ((session->v2_data.session_state == LANPLUS_STATE_ACTIVE)    &&
676c18ec02fSPetter Reinholdtsen 			 (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
677c18ec02fSPetter Reinholdtsen 			 (rsp->session.bEncrypted))
678c18ec02fSPetter Reinholdtsen 
679c18ec02fSPetter Reinholdtsen 		{
680c18ec02fSPetter Reinholdtsen 			lanplus_decrypt_payload(session->v2_data.crypt_alg,
681c18ec02fSPetter Reinholdtsen 						session->v2_data.k2,
682c18ec02fSPetter Reinholdtsen 						rsp->data + offset,
683c18ec02fSPetter Reinholdtsen 						rsp->session.msglen,
684c18ec02fSPetter Reinholdtsen 						rsp->data + offset,
685c18ec02fSPetter Reinholdtsen 						&payload_size);
686c18ec02fSPetter Reinholdtsen 		}
687c18ec02fSPetter Reinholdtsen 		else
688c18ec02fSPetter Reinholdtsen 			payload_size = rsp->session.msglen;
689c18ec02fSPetter Reinholdtsen 
690c18ec02fSPetter Reinholdtsen 
691c18ec02fSPetter Reinholdtsen 		/*
692c18ec02fSPetter Reinholdtsen 		 * Handle IPMI responses (case #1 and #2) -- all IPMI reponses
693c18ec02fSPetter Reinholdtsen 		 */
694c18ec02fSPetter Reinholdtsen 		if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_IPMI)
695c18ec02fSPetter Reinholdtsen 		{
696c18ec02fSPetter Reinholdtsen 			struct ipmi_rq_entry * entry;
697c18ec02fSPetter Reinholdtsen 			int payload_start = offset;
698c18ec02fSPetter Reinholdtsen 			int extra_data_length;
699c18ec02fSPetter Reinholdtsen 			read_ipmi_response(rsp, &offset);
700c18ec02fSPetter Reinholdtsen 
701c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<< IPMI Response Session Header");
702c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Authtype                : %s",
703c18ec02fSPetter Reinholdtsen 				val2str(rsp->session.authtype, ipmi_authtype_session_vals));
704c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Payload type            : %s",
705c18ec02fSPetter Reinholdtsen 				val2str(rsp->session.payloadtype, plus_payload_types_vals));
706c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Session ID              : 0x%08lx",
707c18ec02fSPetter Reinholdtsen 				(long)rsp->session.id);
708c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Sequence                : 0x%08lx",
709c18ec02fSPetter Reinholdtsen 				(long)rsp->session.seq);
710c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   IPMI Msg/Payload Length : %d",
711c18ec02fSPetter Reinholdtsen 				rsp->session.msglen);
712c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<< IPMI Response Message Header");
713c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Rq Addr    : %02x",
714c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.rq_addr);
715c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   NetFn      : %02x",
716c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.netfn);
717c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Rq LUN     : %01x",
718c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.rq_lun);
719c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Rs Addr    : %02x",
720c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.rs_addr);
721c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Rq Seq     : %02x",
722c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.rq_seq);
723c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Rs Lun     : %01x",
724c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.rs_lun);
725c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Command    : %02x",
726c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.cmd);
727c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Compl Code : 0x%02x",
728c18ec02fSPetter Reinholdtsen 				rsp->ccode);
729c18ec02fSPetter Reinholdtsen 
730c18ec02fSPetter Reinholdtsen 			/* Are we expecting this packet? */
731c18ec02fSPetter Reinholdtsen 			entry = ipmi_req_lookup_entry(rsp->payload.ipmi_response.rq_seq,
732c18ec02fSPetter Reinholdtsen 								rsp->payload.ipmi_response.cmd);
733c18ec02fSPetter Reinholdtsen 
734c18ec02fSPetter Reinholdtsen 			if (entry != NULL) {
735c18ec02fSPetter Reinholdtsen 				lprintf(LOG_DEBUG+2, "IPMI Request Match found");
736c18ec02fSPetter Reinholdtsen 				if ( intf->target_addr != intf->my_addr &&
737c18ec02fSPetter Reinholdtsen 				     bridgePossible &&
738c18ec02fSPetter Reinholdtsen 				     rsp->data_len &&
739c18ec02fSPetter Reinholdtsen 				     rsp->payload.ipmi_response.cmd == 0x34 &&
740c18ec02fSPetter Reinholdtsen 				     (rsp->payload.ipmi_response.netfn == 0x06 ||
741c18ec02fSPetter Reinholdtsen 				     rsp->payload.ipmi_response.netfn == 0x07) &&
742c18ec02fSPetter Reinholdtsen 				     rsp->payload.ipmi_response.rs_lun == 0 )
743c18ec02fSPetter Reinholdtsen 				{
744c18ec02fSPetter Reinholdtsen 					/* Check completion code */
745c18ec02fSPetter Reinholdtsen 					if (rsp->data[offset-1] == 0)
746c18ec02fSPetter Reinholdtsen 					{
747c18ec02fSPetter Reinholdtsen 						lprintf(LOG_DEBUG, "Bridged command answer,"
748c18ec02fSPetter Reinholdtsen 						     " waiting for next answer... ");
749c18ec02fSPetter Reinholdtsen 						ipmi_req_remove_entry(
750c18ec02fSPetter Reinholdtsen 							rsp->payload.ipmi_response.rq_seq,
751c18ec02fSPetter Reinholdtsen 							rsp->payload.ipmi_response.cmd);
752c18ec02fSPetter Reinholdtsen 						return ipmi_lan_poll_recv(intf);
753c18ec02fSPetter Reinholdtsen 					}
754c18ec02fSPetter Reinholdtsen 					else
755c18ec02fSPetter Reinholdtsen 					{
756c18ec02fSPetter Reinholdtsen 						lprintf(LOG_DEBUG, "WARNING: Bridged "
757c18ec02fSPetter Reinholdtsen 								   "cmd ccode = 0x%02x",
758c18ec02fSPetter Reinholdtsen 								   rsp->data[offset-1]);
759c18ec02fSPetter Reinholdtsen 					}
760c18ec02fSPetter Reinholdtsen 
761c18ec02fSPetter Reinholdtsen 					if (rsp->data_len &&
762c18ec02fSPetter Reinholdtsen 					    rsp->payload.ipmi_response.cmd == 0x34) {
763c18ec02fSPetter Reinholdtsen 						memcpy(rsp->data, &rsp->data[offset],
764c18ec02fSPetter Reinholdtsen 							(rsp->data_len-offset));
765c18ec02fSPetter Reinholdtsen 						if (verbose > 2)
766c18ec02fSPetter Reinholdtsen 							printbuf( &rsp->data[offset],
767c18ec02fSPetter Reinholdtsen 							(rsp->data_len-offset),
768c18ec02fSPetter Reinholdtsen 							"bridge command response");
769c18ec02fSPetter Reinholdtsen 					}
770c18ec02fSPetter Reinholdtsen 				}
771c18ec02fSPetter Reinholdtsen 
772c18ec02fSPetter Reinholdtsen 				ipmi_req_remove_entry(rsp->payload.ipmi_response.rq_seq,
773c18ec02fSPetter Reinholdtsen 								rsp->payload.ipmi_response.cmd);
774c18ec02fSPetter Reinholdtsen 			} else {
775c18ec02fSPetter Reinholdtsen 				lprintf(LOG_INFO, "IPMI Request Match NOT FOUND");
776c18ec02fSPetter Reinholdtsen 				rsp = ipmi_lan_recv_packet(intf);
777c18ec02fSPetter Reinholdtsen 				continue;
778c18ec02fSPetter Reinholdtsen 			}
779c18ec02fSPetter Reinholdtsen 
780c18ec02fSPetter Reinholdtsen 			/*
781c18ec02fSPetter Reinholdtsen 			 * Good packet.  Shift response data to start of array.
782c18ec02fSPetter Reinholdtsen 			 * rsp->data becomes the variable length IPMI response data
783c18ec02fSPetter Reinholdtsen 			 * rsp->data_len becomes the length of that data
784c18ec02fSPetter Reinholdtsen 			 */
785c18ec02fSPetter Reinholdtsen 			extra_data_length = payload_size - (offset - payload_start) - 1;
786c18ec02fSPetter Reinholdtsen 			if (rsp != NULL && extra_data_length)
787c18ec02fSPetter Reinholdtsen 			{
788c18ec02fSPetter Reinholdtsen 				rsp->data_len = extra_data_length;
789c18ec02fSPetter Reinholdtsen 				memmove(rsp->data, rsp->data + offset, extra_data_length);
790c18ec02fSPetter Reinholdtsen 			}
791c18ec02fSPetter Reinholdtsen 			else
792c18ec02fSPetter Reinholdtsen 				rsp->data_len = 0;
793c18ec02fSPetter Reinholdtsen 
794c18ec02fSPetter Reinholdtsen 			break;
795c18ec02fSPetter Reinholdtsen 		}
796c18ec02fSPetter Reinholdtsen 
797c18ec02fSPetter Reinholdtsen 
798c18ec02fSPetter Reinholdtsen 		/*
799c18ec02fSPetter Reinholdtsen 		 * Open Response
800c18ec02fSPetter Reinholdtsen 		 */
801c18ec02fSPetter Reinholdtsen 		else if (rsp->session.payloadtype ==
802c18ec02fSPetter Reinholdtsen 			 IPMI_PAYLOAD_TYPE_RMCP_OPEN_RESPONSE)
803c18ec02fSPetter Reinholdtsen 		{
804c18ec02fSPetter Reinholdtsen 			if (session->v2_data.session_state !=
805c18ec02fSPetter Reinholdtsen 				 LANPLUS_STATE_OPEN_SESSION_SENT)
806c18ec02fSPetter Reinholdtsen 			{
807c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "Error: Received an Unexpected Open Session "
808c18ec02fSPetter Reinholdtsen 					"Response");
809c18ec02fSPetter Reinholdtsen 				rsp = ipmi_lan_recv_packet(intf);
810c18ec02fSPetter Reinholdtsen 				continue;
811c18ec02fSPetter Reinholdtsen 			}
812c18ec02fSPetter Reinholdtsen 
813c18ec02fSPetter Reinholdtsen 			read_open_session_response(rsp, offset);
814c18ec02fSPetter Reinholdtsen 			break;
815c18ec02fSPetter Reinholdtsen 		}
816c18ec02fSPetter Reinholdtsen 
817c18ec02fSPetter Reinholdtsen 
818c18ec02fSPetter Reinholdtsen 		/*
819c18ec02fSPetter Reinholdtsen 		 * RAKP 2
820c18ec02fSPetter Reinholdtsen 		 */
821c18ec02fSPetter Reinholdtsen 		else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_2)
822c18ec02fSPetter Reinholdtsen 		{
823c18ec02fSPetter Reinholdtsen 			if (session->v2_data.session_state != LANPLUS_STATE_RAKP_1_SENT)
824c18ec02fSPetter Reinholdtsen 			{
825c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "Error: Received an Unexpected RAKP 2 message");
826c18ec02fSPetter Reinholdtsen 				rsp = ipmi_lan_recv_packet(intf);
827c18ec02fSPetter Reinholdtsen 				continue;
828c18ec02fSPetter Reinholdtsen 			}
829c18ec02fSPetter Reinholdtsen 
830c18ec02fSPetter Reinholdtsen 			read_rakp2_message(rsp, offset, session->v2_data.auth_alg);
831c18ec02fSPetter Reinholdtsen 			break;
832c18ec02fSPetter Reinholdtsen 		}
833c18ec02fSPetter Reinholdtsen 
834c18ec02fSPetter Reinholdtsen 
835c18ec02fSPetter Reinholdtsen 		/*
836c18ec02fSPetter Reinholdtsen 		 * RAKP 4
837c18ec02fSPetter Reinholdtsen 		 */
838c18ec02fSPetter Reinholdtsen 		else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_4)
839c18ec02fSPetter Reinholdtsen 		{
840c18ec02fSPetter Reinholdtsen 			if (session->v2_data.session_state != LANPLUS_STATE_RAKP_3_SENT)
841c18ec02fSPetter Reinholdtsen 			{
842c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "Error: Received an Unexpected RAKP 4 message");
843c18ec02fSPetter Reinholdtsen 				rsp = ipmi_lan_recv_packet(intf);
844c18ec02fSPetter Reinholdtsen 				continue;
845c18ec02fSPetter Reinholdtsen 			}
846c18ec02fSPetter Reinholdtsen 
847c18ec02fSPetter Reinholdtsen 			read_rakp4_message(rsp, offset, session->v2_data.auth_alg);
848c18ec02fSPetter Reinholdtsen 			break;
849c18ec02fSPetter Reinholdtsen 		}
850c18ec02fSPetter Reinholdtsen 
851c18ec02fSPetter Reinholdtsen 
852c18ec02fSPetter Reinholdtsen 		/*
853c18ec02fSPetter Reinholdtsen 		 * SOL
854c18ec02fSPetter Reinholdtsen 		 */
855c18ec02fSPetter Reinholdtsen 		else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)
856c18ec02fSPetter Reinholdtsen 		{
857c18ec02fSPetter Reinholdtsen 			int payload_start = offset;
858c18ec02fSPetter Reinholdtsen 			int extra_data_length;
859c18ec02fSPetter Reinholdtsen 
860c18ec02fSPetter Reinholdtsen 			if (session->v2_data.session_state != LANPLUS_STATE_ACTIVE)
861c18ec02fSPetter Reinholdtsen 			{
862c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "Error: Received an Unexpected SOL packet");
863c18ec02fSPetter Reinholdtsen 				rsp = ipmi_lan_recv_packet(intf);
864c18ec02fSPetter Reinholdtsen 				continue;
865c18ec02fSPetter Reinholdtsen 			}
866c18ec02fSPetter Reinholdtsen 
867c18ec02fSPetter Reinholdtsen 			read_sol_packet(rsp, &offset);
868c18ec02fSPetter Reinholdtsen 			extra_data_length = payload_size - (offset - payload_start);
869c18ec02fSPetter Reinholdtsen 			if (rsp && extra_data_length)
870c18ec02fSPetter Reinholdtsen 			{
871c18ec02fSPetter Reinholdtsen 				rsp->data_len = extra_data_length;
872c18ec02fSPetter Reinholdtsen 				memmove(rsp->data, rsp->data + offset, extra_data_length);
873c18ec02fSPetter Reinholdtsen 			}
874c18ec02fSPetter Reinholdtsen 			else
875c18ec02fSPetter Reinholdtsen 				rsp->data_len = 0;
876c18ec02fSPetter Reinholdtsen 
877c18ec02fSPetter Reinholdtsen 			break;
878c18ec02fSPetter Reinholdtsen 		}
879c18ec02fSPetter Reinholdtsen 
880c18ec02fSPetter Reinholdtsen 		else
881c18ec02fSPetter Reinholdtsen 		{
882c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Invalid RMCP+ payload type : 0x%x",
883c18ec02fSPetter Reinholdtsen 				rsp->session.payloadtype);
884c18ec02fSPetter Reinholdtsen 			assert(0);
885c18ec02fSPetter Reinholdtsen 		}
886c18ec02fSPetter Reinholdtsen 	}
887c18ec02fSPetter Reinholdtsen 
888c18ec02fSPetter Reinholdtsen 	return rsp;
889c18ec02fSPetter Reinholdtsen }
890c18ec02fSPetter Reinholdtsen 
891c18ec02fSPetter Reinholdtsen 
892c18ec02fSPetter Reinholdtsen 
893c18ec02fSPetter Reinholdtsen /*
894c18ec02fSPetter Reinholdtsen  * read_open_session_reponse
895c18ec02fSPetter Reinholdtsen  *
896c18ec02fSPetter Reinholdtsen  * Initialize the ipmi_rs from the IPMI 2.x open session response data.
897c18ec02fSPetter Reinholdtsen  *
898c18ec02fSPetter Reinholdtsen  * The offset should point to the first byte of the the Open Session Response
899c18ec02fSPetter Reinholdtsen  * payload when this function is called.
900c18ec02fSPetter Reinholdtsen  *
901c18ec02fSPetter Reinholdtsen  * param rsp    [in/out] reading from the data and writing to the open_session_response
902c18ec02fSPetter Reinholdtsen  *              section
903c18ec02fSPetter Reinholdtsen  * param offset [in] tells us where the Open Session Response payload starts
904c18ec02fSPetter Reinholdtsen  *
905c18ec02fSPetter Reinholdtsen  * returns 0 on success, 1 on error
906c18ec02fSPetter Reinholdtsen  */
907c18ec02fSPetter Reinholdtsen void
908c18ec02fSPetter Reinholdtsen read_open_session_response(struct ipmi_rs * rsp, int offset)
909c18ec02fSPetter Reinholdtsen {
910c18ec02fSPetter Reinholdtsen 	memset(&rsp->payload.open_session_response, 0,
911c18ec02fSPetter Reinholdtsen 			 sizeof(rsp->payload.open_session_response));
912c18ec02fSPetter Reinholdtsen 
913c18ec02fSPetter Reinholdtsen 	 /*  Message tag */
914c18ec02fSPetter Reinholdtsen 	 rsp->payload.open_session_response.message_tag = rsp->data[offset];
915c18ec02fSPetter Reinholdtsen 
916c18ec02fSPetter Reinholdtsen 	 /* RAKP reponse code */
917c18ec02fSPetter Reinholdtsen 	 rsp->payload.open_session_response.rakp_return_code = rsp->data[offset + 1];
918c18ec02fSPetter Reinholdtsen 
919c18ec02fSPetter Reinholdtsen 	 /* Maximum privilege level */
920c18ec02fSPetter Reinholdtsen 	 rsp->payload.open_session_response.max_priv_level = rsp->data[offset + 2];
921c18ec02fSPetter Reinholdtsen 
922c18ec02fSPetter Reinholdtsen 	 /*** offset + 3 is reserved ***/
923c18ec02fSPetter Reinholdtsen 
924c18ec02fSPetter Reinholdtsen 	 /* Remote console session ID */
925c18ec02fSPetter Reinholdtsen 	 memcpy(&(rsp->payload.open_session_response.console_id),
926c18ec02fSPetter Reinholdtsen 			rsp->data + offset + 4,
927c18ec02fSPetter Reinholdtsen 			4);
928c18ec02fSPetter Reinholdtsen 	 #if WORDS_BIGENDIAN
929c18ec02fSPetter Reinholdtsen 	 rsp->payload.open_session_response.console_id =
930c18ec02fSPetter Reinholdtsen 		 BSWAP_32(rsp->payload.open_session_response.console_id);
931c18ec02fSPetter Reinholdtsen 	 #endif
932c18ec02fSPetter Reinholdtsen 
933c18ec02fSPetter Reinholdtsen 	/* only tag, status, privlvl, and console id are returned if error */
934c18ec02fSPetter Reinholdtsen 	 if (rsp->payload.open_session_response.rakp_return_code !=
935c18ec02fSPetter Reinholdtsen 		  IPMI_RAKP_STATUS_NO_ERRORS)
936c18ec02fSPetter Reinholdtsen 		 return;
937c18ec02fSPetter Reinholdtsen 
938c18ec02fSPetter Reinholdtsen 	 /* BMC session ID */
939c18ec02fSPetter Reinholdtsen 	 memcpy(&(rsp->payload.open_session_response.bmc_id),
940c18ec02fSPetter Reinholdtsen 			rsp->data + offset + 8,
941c18ec02fSPetter Reinholdtsen 			4);
942c18ec02fSPetter Reinholdtsen 	 #if WORDS_BIGENDIAN
943c18ec02fSPetter Reinholdtsen 	 rsp->payload.open_session_response.bmc_id =
944c18ec02fSPetter Reinholdtsen 		 BSWAP_32(rsp->payload.open_session_response.bmc_id);
945c18ec02fSPetter Reinholdtsen 	 #endif
946c18ec02fSPetter Reinholdtsen 
947c18ec02fSPetter Reinholdtsen 	 /* And of course, our negotiated algorithms */
948c18ec02fSPetter Reinholdtsen 	 rsp->payload.open_session_response.auth_alg      = rsp->data[offset + 16];
949c18ec02fSPetter Reinholdtsen 	 rsp->payload.open_session_response.integrity_alg = rsp->data[offset + 24];
950c18ec02fSPetter Reinholdtsen 	 rsp->payload.open_session_response.crypt_alg     = rsp->data[offset + 32];
951c18ec02fSPetter Reinholdtsen }
952c18ec02fSPetter Reinholdtsen 
953c18ec02fSPetter Reinholdtsen 
954c18ec02fSPetter Reinholdtsen 
955c18ec02fSPetter Reinholdtsen /*
956c18ec02fSPetter Reinholdtsen  * read_rakp2_message
957c18ec02fSPetter Reinholdtsen  *
958c18ec02fSPetter Reinholdtsen  * Initialize the ipmi_rs from the IPMI 2.x RAKP 2 message
959c18ec02fSPetter Reinholdtsen  *
960c18ec02fSPetter Reinholdtsen  * The offset should point the first byte of the the RAKP 2 payload when this
961c18ec02fSPetter Reinholdtsen  * function is called.
962c18ec02fSPetter Reinholdtsen  *
963c18ec02fSPetter Reinholdtsen  * param rsp [in/out] reading from the data variable and writing to the rakp 2
964c18ec02fSPetter Reinholdtsen  *       section
965c18ec02fSPetter Reinholdtsen  * param offset [in] tells us where hte rakp2 payload starts
966c18ec02fSPetter Reinholdtsen  * param auth_alg [in] describes the authentication algorithm was agreed upon in
967c18ec02fSPetter Reinholdtsen  *       the open session request/response phase.  We need to know that here so
968c18ec02fSPetter Reinholdtsen  *       that we know how many bytes (if any) to read fromt the packet.
969c18ec02fSPetter Reinholdtsen  *
970c18ec02fSPetter Reinholdtsen  * returns 0 on success, 1 on error
971c18ec02fSPetter Reinholdtsen  */
972c18ec02fSPetter Reinholdtsen void
973c18ec02fSPetter Reinholdtsen read_rakp2_message(
974c18ec02fSPetter Reinholdtsen 					struct ipmi_rs * rsp,
975c18ec02fSPetter Reinholdtsen 					int offset,
976c18ec02fSPetter Reinholdtsen 					uint8_t auth_alg)
977c18ec02fSPetter Reinholdtsen {
978c18ec02fSPetter Reinholdtsen 	 int i;
979c18ec02fSPetter Reinholdtsen 
980c18ec02fSPetter Reinholdtsen 	 /*  Message tag */
981c18ec02fSPetter Reinholdtsen 	 rsp->payload.rakp2_message.message_tag = rsp->data[offset];
982c18ec02fSPetter Reinholdtsen 
983c18ec02fSPetter Reinholdtsen 	 /* RAKP reponse code */
984c18ec02fSPetter Reinholdtsen 	 rsp->payload.rakp2_message.rakp_return_code = rsp->data[offset + 1];
985c18ec02fSPetter Reinholdtsen 
986c18ec02fSPetter Reinholdtsen 	 /* Console session ID */
987c18ec02fSPetter Reinholdtsen 	 memcpy(&(rsp->payload.rakp2_message.console_id),
988c18ec02fSPetter Reinholdtsen 			rsp->data + offset + 4,
989c18ec02fSPetter Reinholdtsen 			4);
990c18ec02fSPetter Reinholdtsen 	 #if WORDS_BIGENDIAN
991c18ec02fSPetter Reinholdtsen 	 rsp->payload.rakp2_message.console_id =
992c18ec02fSPetter Reinholdtsen 		 BSWAP_32(rsp->payload.rakp2_message.console_id);
993c18ec02fSPetter Reinholdtsen 	 #endif
994c18ec02fSPetter Reinholdtsen 
995c18ec02fSPetter Reinholdtsen 	 /* BMC random number */
996c18ec02fSPetter Reinholdtsen 	 memcpy(&(rsp->payload.rakp2_message.bmc_rand),
997c18ec02fSPetter Reinholdtsen 			rsp->data + offset + 8,
998c18ec02fSPetter Reinholdtsen 			16);
999c18ec02fSPetter Reinholdtsen 	 #if WORDS_BIGENDIAN
1000c18ec02fSPetter Reinholdtsen 	 lanplus_swap(rsp->payload.rakp2_message.bmc_rand, 16);
1001c18ec02fSPetter Reinholdtsen 	 #endif
1002c18ec02fSPetter Reinholdtsen 
1003c18ec02fSPetter Reinholdtsen 	 /* BMC GUID */
1004c18ec02fSPetter Reinholdtsen 	 memcpy(&(rsp->payload.rakp2_message.bmc_guid),
1005c18ec02fSPetter Reinholdtsen 			rsp->data + offset + 24,
1006c18ec02fSPetter Reinholdtsen 			16);
1007c18ec02fSPetter Reinholdtsen 	 #if WORDS_BIGENDIAN
1008c18ec02fSPetter Reinholdtsen 	 lanplus_swap(rsp->payload.rakp2_message.bmc_guid, 16);
1009c18ec02fSPetter Reinholdtsen 	 #endif
1010c18ec02fSPetter Reinholdtsen 
1011c18ec02fSPetter Reinholdtsen 	 /* Key exchange authentication code */
1012c18ec02fSPetter Reinholdtsen 	 switch (auth_alg)
1013c18ec02fSPetter Reinholdtsen 	 {
1014c18ec02fSPetter Reinholdtsen 	 case  IPMI_AUTH_RAKP_NONE:
1015c18ec02fSPetter Reinholdtsen 		 /* Nothing to do here */
1016c18ec02fSPetter Reinholdtsen 		 break;
1017c18ec02fSPetter Reinholdtsen 
1018c18ec02fSPetter Reinholdtsen 	 case IPMI_AUTH_RAKP_HMAC_SHA1:
1019c18ec02fSPetter Reinholdtsen 		 /* We need to copy 20 bytes */
1020c18ec02fSPetter Reinholdtsen 		 for (i = 0; i < 20; ++i)
1021c18ec02fSPetter Reinholdtsen 			 rsp->payload.rakp2_message.key_exchange_auth_code[i] =
1022c18ec02fSPetter Reinholdtsen 				 rsp->data[offset + 40 + i];
1023c18ec02fSPetter Reinholdtsen 		 break;
1024c18ec02fSPetter Reinholdtsen 
1025c18ec02fSPetter Reinholdtsen 	 case IPMI_AUTH_RAKP_HMAC_MD5:
1026c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "read_rakp2_message: no support for "
1027c18ec02fSPetter Reinholdtsen 				"IPMI_AUTH_RAKP_HMAC_MD5");
1028c18ec02fSPetter Reinholdtsen 		 assert(0);
1029c18ec02fSPetter Reinholdtsen 		 break;
1030c18ec02fSPetter Reinholdtsen 	 }
1031c18ec02fSPetter Reinholdtsen }
1032c18ec02fSPetter Reinholdtsen 
1033c18ec02fSPetter Reinholdtsen 
1034c18ec02fSPetter Reinholdtsen 
1035c18ec02fSPetter Reinholdtsen /*
1036c18ec02fSPetter Reinholdtsen  * read_rakp4_message
1037c18ec02fSPetter Reinholdtsen  *
1038c18ec02fSPetter Reinholdtsen  * Initialize the ipmi_rs from the IPMI 2.x RAKP 4 message
1039c18ec02fSPetter Reinholdtsen  *
1040c18ec02fSPetter Reinholdtsen  * The offset should point the first byte of the the RAKP 4 payload when this
1041c18ec02fSPetter Reinholdtsen  * function is called.
1042c18ec02fSPetter Reinholdtsen  *
1043c18ec02fSPetter Reinholdtsen  * param rsp [in/out] reading from the data variable and writing to the rakp
1044c18ec02fSPetter Reinholdtsen  *       4 section
1045c18ec02fSPetter Reinholdtsen  * param offset [in] tells us where hte rakp4 payload starts
1046c18ec02fSPetter Reinholdtsen  * param integrity_alg [in] describes the authentication algorithm was
1047c18ec02fSPetter Reinholdtsen  *       agreed upon in the open session request/response phase.  We need
1048c18ec02fSPetter Reinholdtsen  *       to know that here so that we know how many bytes (if any) to read
1049c18ec02fSPetter Reinholdtsen  *       from the packet.
1050c18ec02fSPetter Reinholdtsen  *
1051c18ec02fSPetter Reinholdtsen  * returns 0 on success, 1 on error
1052c18ec02fSPetter Reinholdtsen  */
1053c18ec02fSPetter Reinholdtsen void
1054c18ec02fSPetter Reinholdtsen read_rakp4_message(
1055c18ec02fSPetter Reinholdtsen 					struct ipmi_rs * rsp,
1056c18ec02fSPetter Reinholdtsen 					int offset,
1057c18ec02fSPetter Reinholdtsen 					uint8_t auth_alg)
1058c18ec02fSPetter Reinholdtsen {
1059c18ec02fSPetter Reinholdtsen 	 int i;
1060c18ec02fSPetter Reinholdtsen 
1061c18ec02fSPetter Reinholdtsen 	 /*  Message tag */
1062c18ec02fSPetter Reinholdtsen 	 rsp->payload.rakp4_message.message_tag = rsp->data[offset];
1063c18ec02fSPetter Reinholdtsen 
1064c18ec02fSPetter Reinholdtsen 	 /* RAKP reponse code */
1065c18ec02fSPetter Reinholdtsen 	 rsp->payload.rakp4_message.rakp_return_code = rsp->data[offset + 1];
1066c18ec02fSPetter Reinholdtsen 
1067c18ec02fSPetter Reinholdtsen 	 /* Console session ID */
1068c18ec02fSPetter Reinholdtsen 	 memcpy(&(rsp->payload.rakp4_message.console_id),
1069c18ec02fSPetter Reinholdtsen 			rsp->data + offset + 4,
1070c18ec02fSPetter Reinholdtsen 			4);
1071c18ec02fSPetter Reinholdtsen 	 #if WORDS_BIGENDIAN
1072c18ec02fSPetter Reinholdtsen 	 rsp->payload.rakp4_message.console_id =
1073c18ec02fSPetter Reinholdtsen 		 BSWAP_32(rsp->payload.rakp4_message.console_id);
1074c18ec02fSPetter Reinholdtsen 	 #endif
1075c18ec02fSPetter Reinholdtsen 
1076c18ec02fSPetter Reinholdtsen 
1077c18ec02fSPetter Reinholdtsen 	 /* Integrity check value */
1078c18ec02fSPetter Reinholdtsen 	 switch (auth_alg)
1079c18ec02fSPetter Reinholdtsen 	 {
1080c18ec02fSPetter Reinholdtsen 	 case  IPMI_AUTH_RAKP_NONE:
1081c18ec02fSPetter Reinholdtsen 		 /* Nothing to do here */
1082c18ec02fSPetter Reinholdtsen 		 break;
1083c18ec02fSPetter Reinholdtsen 
1084c18ec02fSPetter Reinholdtsen 	 case IPMI_AUTH_RAKP_HMAC_SHA1:
1085c18ec02fSPetter Reinholdtsen 		 /* We need to copy 12 bytes */
1086c18ec02fSPetter Reinholdtsen 		 for (i = 0; i < 12; ++i)
1087c18ec02fSPetter Reinholdtsen 			 rsp->payload.rakp4_message.integrity_check_value[i] =
1088c18ec02fSPetter Reinholdtsen 				 rsp->data[offset + 8 + i];
1089c18ec02fSPetter Reinholdtsen 		 break;
1090c18ec02fSPetter Reinholdtsen 
1091c18ec02fSPetter Reinholdtsen 	 case IPMI_AUTH_RAKP_HMAC_MD5:
1092c18ec02fSPetter Reinholdtsen 		 lprintf(LOG_ERR, "read_rakp4_message: no support "
1093c18ec02fSPetter Reinholdtsen 			 "for authentication algorithm 0x%x", auth_alg);
1094c18ec02fSPetter Reinholdtsen 		 assert(0);
1095c18ec02fSPetter Reinholdtsen 		 break;
1096c18ec02fSPetter Reinholdtsen 	 }
1097c18ec02fSPetter Reinholdtsen }
1098c18ec02fSPetter Reinholdtsen 
1099c18ec02fSPetter Reinholdtsen 
1100c18ec02fSPetter Reinholdtsen 
1101c18ec02fSPetter Reinholdtsen 
1102c18ec02fSPetter Reinholdtsen /*
1103c18ec02fSPetter Reinholdtsen  * read_session_data
1104c18ec02fSPetter Reinholdtsen  *
1105c18ec02fSPetter Reinholdtsen  * Initialize the ipmi_rsp from the session data in the packet
1106c18ec02fSPetter Reinholdtsen  *
1107c18ec02fSPetter Reinholdtsen  * The offset should point the first byte of the the IPMI session when this
1108c18ec02fSPetter Reinholdtsen  * function is called.
1109c18ec02fSPetter Reinholdtsen  *
1110c18ec02fSPetter Reinholdtsen  * param rsp     [in/out] we read from the data buffer and populate the session
1111c18ec02fSPetter Reinholdtsen  *               specific fields.
1112c18ec02fSPetter Reinholdtsen  * param offset  [in/out] should point to the beginning of the session when
1113c18ec02fSPetter Reinholdtsen  *               this function is called.  The offset will be adjusted to
1114c18ec02fSPetter Reinholdtsen  *               point to the end of the session when this function exits.
1115c18ec02fSPetter Reinholdtsen  * param session holds our session state
1116c18ec02fSPetter Reinholdtsen  */
1117c18ec02fSPetter Reinholdtsen void
1118c18ec02fSPetter Reinholdtsen read_session_data(
1119c18ec02fSPetter Reinholdtsen 				  struct ipmi_rs * rsp,
1120c18ec02fSPetter Reinholdtsen 				  int * offset,
1121c18ec02fSPetter Reinholdtsen 				  struct ipmi_session * s)
1122c18ec02fSPetter Reinholdtsen {
1123c18ec02fSPetter Reinholdtsen 	/* We expect to read different stuff depending on the authtype */
1124c18ec02fSPetter Reinholdtsen 	rsp->session.authtype = rsp->data[*offset];
1125c18ec02fSPetter Reinholdtsen 
1126c18ec02fSPetter Reinholdtsen 	if (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS)
1127c18ec02fSPetter Reinholdtsen 		read_session_data_v2x(rsp, offset, s);
1128c18ec02fSPetter Reinholdtsen 	else
1129c18ec02fSPetter Reinholdtsen 		read_session_data_v15(rsp, offset, s);
1130c18ec02fSPetter Reinholdtsen }
1131c18ec02fSPetter Reinholdtsen 
1132c18ec02fSPetter Reinholdtsen 
1133c18ec02fSPetter Reinholdtsen 
1134c18ec02fSPetter Reinholdtsen /*
1135c18ec02fSPetter Reinholdtsen  * read_session_data_v2x
1136c18ec02fSPetter Reinholdtsen  *
1137c18ec02fSPetter Reinholdtsen  * Initialize the ipmi_rsp from the v2.x session header of the packet.
1138c18ec02fSPetter Reinholdtsen  *
1139c18ec02fSPetter Reinholdtsen  * The offset should point to the first byte of the the IPMI session when this
1140c18ec02fSPetter Reinholdtsen  * function is called.  When this function exits, offset will point to the
1141c18ec02fSPetter Reinholdtsen  * start of payload.
1142c18ec02fSPetter Reinholdtsen  *
1143c18ec02fSPetter Reinholdtsen  * Should decrypt and perform integrity checking here?
1144c18ec02fSPetter Reinholdtsen  *
1145c18ec02fSPetter Reinholdtsen  * param rsp    [in/out] we read from the data buffer and populate the session
1146c18ec02fSPetter Reinholdtsen  *              specific fields.
1147c18ec02fSPetter Reinholdtsen  * param offset [in/out] should point to the beginning of the session when this
1148c18ec02fSPetter Reinholdtsen  *              function is called.  The offset will be adjusted to point to
1149c18ec02fSPetter Reinholdtsen  *              the end of the session when this function exits.
1150c18ec02fSPetter Reinholdtsen  *  param s      holds our session state
1151c18ec02fSPetter Reinholdtsen  */
1152c18ec02fSPetter Reinholdtsen void
1153c18ec02fSPetter Reinholdtsen read_session_data_v2x(
1154c18ec02fSPetter Reinholdtsen 					  struct ipmi_rs      * rsp,
1155c18ec02fSPetter Reinholdtsen 					  int                 * offset,
1156c18ec02fSPetter Reinholdtsen 					  struct ipmi_session * s)
1157c18ec02fSPetter Reinholdtsen {
1158c18ec02fSPetter Reinholdtsen 	rsp->session.authtype = rsp->data[(*offset)++];
1159c18ec02fSPetter Reinholdtsen 
1160c18ec02fSPetter Reinholdtsen 	rsp->session.bEncrypted     = (rsp->data[*offset] & 0x80 ? 1 : 0);
1161c18ec02fSPetter Reinholdtsen 	rsp->session.bAuthenticated = (rsp->data[*offset] & 0x40 ? 1 : 0);
1162c18ec02fSPetter Reinholdtsen 
1163c18ec02fSPetter Reinholdtsen 
1164c18ec02fSPetter Reinholdtsen 	/* Payload type */
1165c18ec02fSPetter Reinholdtsen 	rsp->session.payloadtype = rsp->data[(*offset)++] & 0x3F;
1166c18ec02fSPetter Reinholdtsen 
1167c18ec02fSPetter Reinholdtsen 	/* Session ID */
1168c18ec02fSPetter Reinholdtsen 	memcpy(&rsp->session.id, rsp->data + *offset, 4);
1169c18ec02fSPetter Reinholdtsen 	*offset += 4;
1170c18ec02fSPetter Reinholdtsen 	#if WORDS_BIGENDIAN
1171c18ec02fSPetter Reinholdtsen 	rsp->session.id = BSWAP_32(rsp->session.id);
1172c18ec02fSPetter Reinholdtsen 	#endif
1173c18ec02fSPetter Reinholdtsen 
1174c18ec02fSPetter Reinholdtsen 
1175c18ec02fSPetter Reinholdtsen 	/*
1176c18ec02fSPetter Reinholdtsen 	 * Verify that the session ID is what we think it should be
1177c18ec02fSPetter Reinholdtsen 	 */
1178c18ec02fSPetter Reinholdtsen 	if ((s->v2_data.session_state == LANPLUS_STATE_ACTIVE) &&
1179c18ec02fSPetter Reinholdtsen 		(rsp->session.id != s->v2_data.console_id))
1180c18ec02fSPetter Reinholdtsen 	{
1181c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "packet session id 0x%x does not "
1182c18ec02fSPetter Reinholdtsen 			"match active session 0x%0x",
1183c18ec02fSPetter Reinholdtsen 			rsp->session.id, s->v2_data.console_id);
1184c18ec02fSPetter Reinholdtsen 		assert(0);
1185c18ec02fSPetter Reinholdtsen 	}
1186c18ec02fSPetter Reinholdtsen 
1187c18ec02fSPetter Reinholdtsen 
1188c18ec02fSPetter Reinholdtsen 	/* Ignored, so far */
1189c18ec02fSPetter Reinholdtsen 	memcpy(&rsp->session.seq, rsp->data + *offset, 4);
1190c18ec02fSPetter Reinholdtsen 	*offset += 4;
1191c18ec02fSPetter Reinholdtsen 	#if WORDS_BIGENDIAN
1192c18ec02fSPetter Reinholdtsen 	rsp->session.seq = BSWAP_32(rsp->session.seq);
1193c18ec02fSPetter Reinholdtsen 	#endif
1194c18ec02fSPetter Reinholdtsen 
1195c18ec02fSPetter Reinholdtsen 	memcpy(&rsp->session.msglen, rsp->data + *offset, 2);
1196c18ec02fSPetter Reinholdtsen 	*offset += 2;
1197c18ec02fSPetter Reinholdtsen 	#if WORDS_BIGENDIAN
1198c18ec02fSPetter Reinholdtsen 	rsp->session.msglen = BSWAP_16(rsp->session.msglen);
1199c18ec02fSPetter Reinholdtsen 	#endif
1200c18ec02fSPetter Reinholdtsen }
1201c18ec02fSPetter Reinholdtsen 
1202c18ec02fSPetter Reinholdtsen 
1203c18ec02fSPetter Reinholdtsen 
1204c18ec02fSPetter Reinholdtsen /*
1205c18ec02fSPetter Reinholdtsen  * read_session_data_v15
1206c18ec02fSPetter Reinholdtsen  *
1207c18ec02fSPetter Reinholdtsen  * Initialize the ipmi_rsp from the session header of the packet.
1208c18ec02fSPetter Reinholdtsen  *
1209c18ec02fSPetter Reinholdtsen  * The offset should point the first byte of the the IPMI session when this
1210c18ec02fSPetter Reinholdtsen  * function is called.  When this function exits, the offset will point to
1211c18ec02fSPetter Reinholdtsen  * the start of the IPMI message.
1212c18ec02fSPetter Reinholdtsen  *
1213c18ec02fSPetter Reinholdtsen  * param rsp    [in/out] we read from the data buffer and populate the session
1214c18ec02fSPetter Reinholdtsen  *              specific fields.
1215c18ec02fSPetter Reinholdtsen  * param offset [in/out] should point to the beginning of the session when this
1216c18ec02fSPetter Reinholdtsen  *              function is called.  The offset will be adjusted to point to the
1217c18ec02fSPetter Reinholdtsen  *              end of the session when this function exits.
1218c18ec02fSPetter Reinholdtsen  * param s      holds our session state
1219c18ec02fSPetter Reinholdtsen  */
1220c18ec02fSPetter Reinholdtsen void read_session_data_v15(
1221c18ec02fSPetter Reinholdtsen 							struct ipmi_rs * rsp,
1222c18ec02fSPetter Reinholdtsen 							int * offset,
1223c18ec02fSPetter Reinholdtsen 							struct ipmi_session * s)
1224c18ec02fSPetter Reinholdtsen {
1225c18ec02fSPetter Reinholdtsen 	/* All v15 messages are IPMI messages */
1226c18ec02fSPetter Reinholdtsen 	rsp->session.payloadtype = IPMI_PAYLOAD_TYPE_IPMI;
1227c18ec02fSPetter Reinholdtsen 
1228c18ec02fSPetter Reinholdtsen 	rsp->session.authtype = rsp->data[(*offset)++];
1229c18ec02fSPetter Reinholdtsen 
1230c18ec02fSPetter Reinholdtsen 	/* All v15 messages that we will receive are unencrypted/unauthenticated */
1231c18ec02fSPetter Reinholdtsen 	rsp->session.bEncrypted     = 0;
1232c18ec02fSPetter Reinholdtsen 	rsp->session.bAuthenticated = 0;
1233c18ec02fSPetter Reinholdtsen 
1234c18ec02fSPetter Reinholdtsen 	/* skip the session id and sequence number fields */
1235c18ec02fSPetter Reinholdtsen 	*offset += 8;
1236c18ec02fSPetter Reinholdtsen 
1237c18ec02fSPetter Reinholdtsen 	/* This is the size of the whole payload */
1238c18ec02fSPetter Reinholdtsen 	rsp->session.msglen = rsp->data[(*offset)++];
1239c18ec02fSPetter Reinholdtsen }
1240c18ec02fSPetter Reinholdtsen 
1241c18ec02fSPetter Reinholdtsen 
1242c18ec02fSPetter Reinholdtsen 
1243c18ec02fSPetter Reinholdtsen /*
1244c18ec02fSPetter Reinholdtsen  * read_ipmi_response
1245c18ec02fSPetter Reinholdtsen  *
1246c18ec02fSPetter Reinholdtsen  * Initialize the ipmi_rs from with the IPMI response specific data
1247c18ec02fSPetter Reinholdtsen  *
1248c18ec02fSPetter Reinholdtsen  * The offset should point the first byte of the the IPMI payload when this
1249c18ec02fSPetter Reinholdtsen  * function is called.
1250c18ec02fSPetter Reinholdtsen  *
1251c18ec02fSPetter Reinholdtsen  * param rsp    [in/out] we read from the data buffer and populate the IPMI
1252c18ec02fSPetter Reinholdtsen  *              specific fields.
1253c18ec02fSPetter Reinholdtsen  * param offset [in/out] should point to the beginning of the IPMI payload when
1254c18ec02fSPetter Reinholdtsen  *              this function is called.
1255c18ec02fSPetter Reinholdtsen  */
1256c18ec02fSPetter Reinholdtsen void read_ipmi_response(struct ipmi_rs * rsp, int * offset)
1257c18ec02fSPetter Reinholdtsen {
1258c18ec02fSPetter Reinholdtsen 	/*
1259c18ec02fSPetter Reinholdtsen 	 * The data here should be decrypted by now.
1260c18ec02fSPetter Reinholdtsen 	 */
1261c18ec02fSPetter Reinholdtsen 	rsp->payload.ipmi_response.rq_addr = rsp->data[(*offset)++];
1262c18ec02fSPetter Reinholdtsen 	rsp->payload.ipmi_response.netfn   = rsp->data[*offset] >> 2;
1263c18ec02fSPetter Reinholdtsen 	rsp->payload.ipmi_response.rq_lun  = rsp->data[(*offset)++] & 0x3;
1264c18ec02fSPetter Reinholdtsen 	(*offset)++;		/* checksum */
1265c18ec02fSPetter Reinholdtsen 	rsp->payload.ipmi_response.rs_addr = rsp->data[(*offset)++];
1266c18ec02fSPetter Reinholdtsen 	rsp->payload.ipmi_response.rq_seq  = rsp->data[*offset] >> 2;
1267c18ec02fSPetter Reinholdtsen 	rsp->payload.ipmi_response.rs_lun  = rsp->data[(*offset)++] & 0x3;
1268c18ec02fSPetter Reinholdtsen 	rsp->payload.ipmi_response.cmd     = rsp->data[(*offset)++];
1269c18ec02fSPetter Reinholdtsen 	rsp->ccode                         = rsp->data[(*offset)++];
1270c18ec02fSPetter Reinholdtsen 
1271c18ec02fSPetter Reinholdtsen }
1272c18ec02fSPetter Reinholdtsen 
1273c18ec02fSPetter Reinholdtsen 
1274c18ec02fSPetter Reinholdtsen 
1275c18ec02fSPetter Reinholdtsen /*
1276c18ec02fSPetter Reinholdtsen  * read_sol_packet
1277c18ec02fSPetter Reinholdtsen  *
1278c18ec02fSPetter Reinholdtsen  * Initialize the ipmi_rs with the SOL response data
1279c18ec02fSPetter Reinholdtsen  *
1280c18ec02fSPetter Reinholdtsen  * The offset should point the first byte of the the SOL payload when this
1281c18ec02fSPetter Reinholdtsen  * function is called.
1282c18ec02fSPetter Reinholdtsen  *
1283c18ec02fSPetter Reinholdtsen  * param rsp    [in/out] we read from the data buffer and populate the
1284c18ec02fSPetter Reinholdtsen  *              SOL specific fields.
1285c18ec02fSPetter Reinholdtsen  * param offset [in/out] should point to the beginning of the SOL payload
1286c18ec02fSPetter Reinholdtsen  *              when this function is called.
1287c18ec02fSPetter Reinholdtsen  */
1288c18ec02fSPetter Reinholdtsen void read_sol_packet(struct ipmi_rs * rsp, int * offset)
1289c18ec02fSPetter Reinholdtsen {
1290c18ec02fSPetter Reinholdtsen 
1291c18ec02fSPetter Reinholdtsen 	/*
1292c18ec02fSPetter Reinholdtsen 	 * The data here should be decrypted by now.
1293c18ec02fSPetter Reinholdtsen 	 */
1294c18ec02fSPetter Reinholdtsen 	rsp->payload.sol_packet.packet_sequence_number =
1295c18ec02fSPetter Reinholdtsen 		rsp->data[(*offset)++] & 0x0F;
1296c18ec02fSPetter Reinholdtsen 
1297c18ec02fSPetter Reinholdtsen 	rsp->payload.sol_packet.acked_packet_number =
1298c18ec02fSPetter Reinholdtsen 		rsp->data[(*offset)++] & 0x0F;
1299c18ec02fSPetter Reinholdtsen 
1300c18ec02fSPetter Reinholdtsen 	rsp->payload.sol_packet.accepted_character_count =
1301c18ec02fSPetter Reinholdtsen 		rsp->data[(*offset)++];
1302c18ec02fSPetter Reinholdtsen 
1303c18ec02fSPetter Reinholdtsen 	rsp->payload.sol_packet.is_nack =
1304c18ec02fSPetter Reinholdtsen 		rsp->data[*offset] & 0x40;
1305c18ec02fSPetter Reinholdtsen 
1306c18ec02fSPetter Reinholdtsen 	rsp->payload.sol_packet.transfer_unavailable =
1307c18ec02fSPetter Reinholdtsen 		rsp->data[*offset] & 0x20;
1308c18ec02fSPetter Reinholdtsen 
1309c18ec02fSPetter Reinholdtsen 	rsp->payload.sol_packet.sol_inactive =
1310c18ec02fSPetter Reinholdtsen 		rsp->data[*offset] & 0x10;
1311c18ec02fSPetter Reinholdtsen 
1312c18ec02fSPetter Reinholdtsen 	rsp->payload.sol_packet.transmit_overrun =
1313c18ec02fSPetter Reinholdtsen 		rsp->data[*offset] & 0x08;
1314c18ec02fSPetter Reinholdtsen 
1315c18ec02fSPetter Reinholdtsen 	rsp->payload.sol_packet.break_detected =
1316c18ec02fSPetter Reinholdtsen 		rsp->data[(*offset)++] & 0x04;
1317c18ec02fSPetter Reinholdtsen 
1318c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "<<<<<<<<<< RECV FROM BMC <<<<<<<<<<<");
1319c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "< SOL sequence number     : 0x%02x",
1320c18ec02fSPetter Reinholdtsen 		rsp->payload.sol_packet.packet_sequence_number);
1321c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "< SOL acked packet        : 0x%02x",
1322c18ec02fSPetter Reinholdtsen 		rsp->payload.sol_packet.acked_packet_number);
1323c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "< SOL accepted char count : 0x%02x",
1324c18ec02fSPetter Reinholdtsen 		rsp->payload.sol_packet.accepted_character_count);
1325c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "< SOL is nack             : %s",
1326c18ec02fSPetter Reinholdtsen 		rsp->payload.sol_packet.is_nack? "true" : "false");
1327c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "< SOL xfer unavailable    : %s",
1328c18ec02fSPetter Reinholdtsen 		rsp->payload.sol_packet.transfer_unavailable? "true" : "false");
1329c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "< SOL inactive            : %s",
1330c18ec02fSPetter Reinholdtsen 		rsp->payload.sol_packet.sol_inactive? "true" : "false");
1331c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "< SOL transmit overrun    : %s",
1332c18ec02fSPetter Reinholdtsen 		rsp->payload.sol_packet.transmit_overrun? "true" : "false");
1333c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "< SOL break detected      : %s",
1334c18ec02fSPetter Reinholdtsen 		rsp->payload.sol_packet.break_detected? "true" : "false");
1335c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
1336c18ec02fSPetter Reinholdtsen 
1337c18ec02fSPetter Reinholdtsen 	if (verbose >= 5)
1338c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data + *offset - 4, 4, "SOL MSG FROM BMC");
1339c18ec02fSPetter Reinholdtsen }
1340c18ec02fSPetter Reinholdtsen 
1341c18ec02fSPetter Reinholdtsen 
1342c18ec02fSPetter Reinholdtsen 
1343c18ec02fSPetter Reinholdtsen /*
1344c18ec02fSPetter Reinholdtsen  * getIpmiPayloadWireRep
1345c18ec02fSPetter Reinholdtsen  *
1346c18ec02fSPetter Reinholdtsen  * param out [out] will contain our wire representation
1347c18ec02fSPetter Reinholdtsen  * param req [in] is the IPMI request to be written
1348c18ec02fSPetter Reinholdtsen  * param crypt_alg [in] specifies the encryption to use
1349c18ec02fSPetter Reinholdtsen  * param rq_seq [in] is the IPMI command sequence number.
1350c18ec02fSPetter Reinholdtsen  */
1351c18ec02fSPetter Reinholdtsen void getIpmiPayloadWireRep(
1352c18ec02fSPetter Reinholdtsen 							struct ipmi_intf       * intf,  /* in out */
1353c18ec02fSPetter Reinholdtsen 							struct ipmi_v2_payload * payload,  /* in  */
1354c18ec02fSPetter Reinholdtsen 							uint8_t  * msg,
1355c18ec02fSPetter Reinholdtsen 							struct ipmi_rq * req,
1356c18ec02fSPetter Reinholdtsen 							uint8_t    rq_seq,
1357c18ec02fSPetter Reinholdtsen 							uint8_t curr_seq)
1358c18ec02fSPetter Reinholdtsen {
1359c18ec02fSPetter Reinholdtsen 	int cs, tmp, len;
1360c18ec02fSPetter Reinholdtsen 	int cs2 = 0;
1361c18ec02fSPetter Reinholdtsen 	int cs3 = 0;
1362c18ec02fSPetter Reinholdtsen 	uint8_t ourAddress = intf->my_addr;
1363c18ec02fSPetter Reinholdtsen 	uint8_t bridgedRequest = 0;
1364c18ec02fSPetter Reinholdtsen 
1365c18ec02fSPetter Reinholdtsen 	if (ourAddress == 0)
1366c18ec02fSPetter Reinholdtsen 		ourAddress = IPMI_BMC_SLAVE_ADDR;
1367c18ec02fSPetter Reinholdtsen 
1368c18ec02fSPetter Reinholdtsen 	len = 0;
1369c18ec02fSPetter Reinholdtsen 
1370c18ec02fSPetter Reinholdtsen 	/* IPMI Message Header -- Figure 13-4 of the IPMI v2.0 spec */
1371c18ec02fSPetter Reinholdtsen 	if ((intf->target_addr == ourAddress) || (!bridgePossible)) {
1372c18ec02fSPetter Reinholdtsen 		cs = len;
1373c18ec02fSPetter Reinholdtsen 	} else {
1374c18ec02fSPetter Reinholdtsen 		bridgedRequest = 1;
1375c18ec02fSPetter Reinholdtsen 
1376c18ec02fSPetter Reinholdtsen 		if(intf->transit_addr != ourAddress && intf->transit_addr != 0)
1377c18ec02fSPetter Reinholdtsen 		{
1378c18ec02fSPetter Reinholdtsen 			bridgedRequest++;
1379c18ec02fSPetter Reinholdtsen 		}
1380c18ec02fSPetter Reinholdtsen 		/* bridged request: encapsulate w/in Send Message */
1381c18ec02fSPetter Reinholdtsen 		cs = len;
1382c18ec02fSPetter Reinholdtsen 		msg[len++] = IPMI_BMC_SLAVE_ADDR;
1383c18ec02fSPetter Reinholdtsen 		msg[len++] = IPMI_NETFN_APP << 2;
1384c18ec02fSPetter Reinholdtsen 		tmp = len - cs;
1385c18ec02fSPetter Reinholdtsen 		msg[len++] = ipmi_csum(msg+cs, tmp);
1386c18ec02fSPetter Reinholdtsen 		cs2 = len;
1387c18ec02fSPetter Reinholdtsen 		msg[len++] = IPMI_REMOTE_SWID;
1388c18ec02fSPetter Reinholdtsen 		msg[len++] = curr_seq << 2;
1389c18ec02fSPetter Reinholdtsen 
1390c18ec02fSPetter Reinholdtsen 
1391c18ec02fSPetter Reinholdtsen 		msg[len++] = 0x34;			/* Send Message rqst */
1392c18ec02fSPetter Reinholdtsen 		if(bridgedRequest == 2)
1393c18ec02fSPetter Reinholdtsen 			msg[len++] = (0x40|intf->transit_channel); /* Track request*/
1394c18ec02fSPetter Reinholdtsen 		else
1395c18ec02fSPetter Reinholdtsen 			msg[len++] = (0x40|intf->target_channel);    /* Track request*/
1396c18ec02fSPetter Reinholdtsen 
1397c18ec02fSPetter Reinholdtsen 		payload->payload_length += 7;
1398c18ec02fSPetter Reinholdtsen 		cs = len;
1399c18ec02fSPetter Reinholdtsen 
1400c18ec02fSPetter Reinholdtsen 		if(bridgedRequest == 2)
1401c18ec02fSPetter Reinholdtsen 		{
1402c18ec02fSPetter Reinholdtsen 			/* bridged request: encapsulate w/in Send Message */
1403c18ec02fSPetter Reinholdtsen 			cs = len;
1404c18ec02fSPetter Reinholdtsen 			msg[len++] = intf->transit_addr;
1405c18ec02fSPetter Reinholdtsen 			msg[len++] = IPMI_NETFN_APP << 2;
1406c18ec02fSPetter Reinholdtsen 			tmp = len - cs;
1407c18ec02fSPetter Reinholdtsen 			msg[len++] = ipmi_csum(msg+cs, tmp);
1408c18ec02fSPetter Reinholdtsen 			cs3 = len;
1409c18ec02fSPetter Reinholdtsen 			msg[len++] = intf->my_addr;
1410c18ec02fSPetter Reinholdtsen 			msg[len++] = curr_seq << 2;
1411c18ec02fSPetter Reinholdtsen 			msg[len++] = 0x34;			/* Send Message rqst */
1412c18ec02fSPetter Reinholdtsen 	#if 0  /* From lan.c example */
1413c18ec02fSPetter Reinholdtsen 			entry->req.msg.target_cmd = entry->req.msg.cmd;	/* Save target command */
1414c18ec02fSPetter Reinholdtsen 			entry->req.msg.cmd = 0x34;		/* (fixup request entry) */
1415c18ec02fSPetter Reinholdtsen 	#endif
1416c18ec02fSPetter Reinholdtsen 			msg[len++] = (0x40|intf->target_channel); /* Track request*/
1417c18ec02fSPetter Reinholdtsen 
1418c18ec02fSPetter Reinholdtsen 			payload->payload_length += 7;
1419c18ec02fSPetter Reinholdtsen 
1420c18ec02fSPetter Reinholdtsen 			cs = len;
1421c18ec02fSPetter Reinholdtsen 		}
1422c18ec02fSPetter Reinholdtsen 	}
1423c18ec02fSPetter Reinholdtsen 
1424c18ec02fSPetter Reinholdtsen         lprintf(LOG_DEBUG,"%s RqAddr %#x transit %#x:%#x target %#x:%#x "
1425c18ec02fSPetter Reinholdtsen 		"bridgePossible %d",
1426c18ec02fSPetter Reinholdtsen 		bridgedRequest ? "Bridging" : "Local",
1427c18ec02fSPetter Reinholdtsen 		intf->my_addr, intf->transit_addr, intf->transit_channel,
1428c18ec02fSPetter Reinholdtsen 		intf->target_addr, intf->target_channel,
1429c18ec02fSPetter Reinholdtsen 		bridgePossible);
1430c18ec02fSPetter Reinholdtsen 
1431c18ec02fSPetter Reinholdtsen 	/* rsAddr */
1432c18ec02fSPetter Reinholdtsen 	msg[len++] = intf->target_addr; /* IPMI_BMC_SLAVE_ADDR; */
1433c18ec02fSPetter Reinholdtsen 
1434c18ec02fSPetter Reinholdtsen 	/* net Fn */
1435c18ec02fSPetter Reinholdtsen 	msg[len++] = req->msg.netfn << 2 | (req->msg.lun & 3);
1436c18ec02fSPetter Reinholdtsen 	tmp = len - cs;
1437c18ec02fSPetter Reinholdtsen 
1438c18ec02fSPetter Reinholdtsen 	/* checkSum */
1439c18ec02fSPetter Reinholdtsen 	msg[len++] = ipmi_csum(msg+cs, tmp);
1440c18ec02fSPetter Reinholdtsen 	cs = len;
1441c18ec02fSPetter Reinholdtsen 
1442c18ec02fSPetter Reinholdtsen 	/* rqAddr */
1443c18ec02fSPetter Reinholdtsen 	if (!bridgedRequest)
1444c18ec02fSPetter Reinholdtsen 		msg[len++] = IPMI_REMOTE_SWID;
1445c18ec02fSPetter Reinholdtsen 	else  /* Bridged message */
1446c18ec02fSPetter Reinholdtsen 		msg[len++] = intf->my_addr;
1447c18ec02fSPetter Reinholdtsen 
1448c18ec02fSPetter Reinholdtsen 	/* rqSeq / rqLUN */
1449c18ec02fSPetter Reinholdtsen 	msg[len++] = rq_seq << 2;
1450c18ec02fSPetter Reinholdtsen 
1451c18ec02fSPetter Reinholdtsen 	/* cmd */
1452c18ec02fSPetter Reinholdtsen 	msg[len++] = req->msg.cmd;
1453c18ec02fSPetter Reinholdtsen 
1454c18ec02fSPetter Reinholdtsen 	/* message data */
1455c18ec02fSPetter Reinholdtsen 	if (req->msg.data_len) {
1456c18ec02fSPetter Reinholdtsen 		memcpy(msg + len, req->msg.data, req->msg.data_len);
1457c18ec02fSPetter Reinholdtsen 		len += req->msg.data_len;
1458c18ec02fSPetter Reinholdtsen 	}
1459c18ec02fSPetter Reinholdtsen 
1460c18ec02fSPetter Reinholdtsen 	/* second checksum */
1461c18ec02fSPetter Reinholdtsen 	tmp = len - cs;
1462c18ec02fSPetter Reinholdtsen 	msg[len++] = ipmi_csum(msg+cs, tmp);
1463c18ec02fSPetter Reinholdtsen 
1464c18ec02fSPetter Reinholdtsen 	/* Dual bridged request: 2nd checksum */
1465c18ec02fSPetter Reinholdtsen 	if (bridgedRequest == 2) {
1466c18ec02fSPetter Reinholdtsen 		tmp = len - cs3;
1467c18ec02fSPetter Reinholdtsen 		msg[len++] = ipmi_csum(msg+cs3, tmp);
1468c18ec02fSPetter Reinholdtsen 		payload->payload_length += 1;
1469c18ec02fSPetter Reinholdtsen 	}
1470c18ec02fSPetter Reinholdtsen 
1471c18ec02fSPetter Reinholdtsen 	/* bridged request: 2nd checksum */
1472c18ec02fSPetter Reinholdtsen 	if (bridgedRequest) {
1473c18ec02fSPetter Reinholdtsen 		tmp = len - cs2;
1474c18ec02fSPetter Reinholdtsen 		msg[len++] = ipmi_csum(msg+cs2, tmp);
1475c18ec02fSPetter Reinholdtsen 		payload->payload_length += 1;
1476c18ec02fSPetter Reinholdtsen 	}
1477c18ec02fSPetter Reinholdtsen }
1478c18ec02fSPetter Reinholdtsen 
1479c18ec02fSPetter Reinholdtsen 
1480c18ec02fSPetter Reinholdtsen 
1481c18ec02fSPetter Reinholdtsen /*
1482c18ec02fSPetter Reinholdtsen  * getSolPayloadWireRep
1483c18ec02fSPetter Reinholdtsen  *
1484c18ec02fSPetter Reinholdtsen  * param msg [out] will contain our wire representation
1485c18ec02fSPetter Reinholdtsen  * param payload [in] holds the v2 payload with our SOL data
1486c18ec02fSPetter Reinholdtsen  */
1487c18ec02fSPetter Reinholdtsen void getSolPayloadWireRep(
1488c18ec02fSPetter Reinholdtsen 						  struct ipmi_intf       * intf,  /* in out */
1489c18ec02fSPetter Reinholdtsen 						  uint8_t          * msg,     /* output */
1490c18ec02fSPetter Reinholdtsen 						  struct ipmi_v2_payload * payload) /* input */
1491c18ec02fSPetter Reinholdtsen {
1492c18ec02fSPetter Reinholdtsen 	int i = 0;
1493c18ec02fSPetter Reinholdtsen 
1494c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, ">>>>>>>>>> SENDING TO BMC >>>>>>>>>>");
1495c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL sequence number     : 0x%02x",
1496c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.packet_sequence_number);
1497c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL acked packet        : 0x%02x",
1498c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.acked_packet_number);
1499c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL accepted char count : 0x%02x",
1500c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.accepted_character_count);
1501c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL is nack             : %s",
1502c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.is_nack ? "true" : "false");
1503c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL assert ring wor     : %s",
1504c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.assert_ring_wor ? "true" : "false");
1505c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL generate break      : %s",
1506c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.generate_break ? "true" : "false");
1507c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL deassert cts        : %s",
1508c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.deassert_cts ? "true" : "false");
1509c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL deassert dcd dsr    : %s",
1510c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.deassert_dcd_dsr ? "true" : "false");
1511c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL flush inbound       : %s",
1512c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.flush_inbound ? "true" : "false");
1513c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL flush outbound      : %s",
1514c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.flush_outbound ? "true" : "false");
1515c18ec02fSPetter Reinholdtsen 
1516c18ec02fSPetter Reinholdtsen 	msg[i++] = payload->payload.sol_packet.packet_sequence_number;
1517c18ec02fSPetter Reinholdtsen 	msg[i++] = payload->payload.sol_packet.acked_packet_number;
1518c18ec02fSPetter Reinholdtsen 	msg[i++] = payload->payload.sol_packet.accepted_character_count;
1519c18ec02fSPetter Reinholdtsen 
1520c18ec02fSPetter Reinholdtsen 	msg[i]    = payload->payload.sol_packet.is_nack           ? 0x40 : 0;
1521c18ec02fSPetter Reinholdtsen 	msg[i]   |= payload->payload.sol_packet.assert_ring_wor   ? 0x20 : 0;
1522c18ec02fSPetter Reinholdtsen 	msg[i]   |= payload->payload.sol_packet.generate_break    ? 0x10 : 0;
1523c18ec02fSPetter Reinholdtsen 	msg[i]   |= payload->payload.sol_packet.deassert_cts      ? 0x08 : 0;
1524c18ec02fSPetter Reinholdtsen 	msg[i]   |= payload->payload.sol_packet.deassert_dcd_dsr  ? 0x04 : 0;
1525c18ec02fSPetter Reinholdtsen 	msg[i]   |= payload->payload.sol_packet.flush_inbound     ? 0x02 : 0;
1526c18ec02fSPetter Reinholdtsen 	msg[i++] |= payload->payload.sol_packet.flush_outbound    ? 0x01 : 0;
1527c18ec02fSPetter Reinholdtsen 
1528c18ec02fSPetter Reinholdtsen 	/* We may have data to add */
1529c18ec02fSPetter Reinholdtsen 	memcpy(msg + i,
1530c18ec02fSPetter Reinholdtsen 			payload->payload.sol_packet.data,
1531c18ec02fSPetter Reinholdtsen 			payload->payload.sol_packet.character_count);
1532c18ec02fSPetter Reinholdtsen 
1533c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "> SOL character count     : %d",
1534c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.character_count);
1535c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
1536c18ec02fSPetter Reinholdtsen 
1537c18ec02fSPetter Reinholdtsen 	if (verbose >= 5 && payload->payload.sol_packet.character_count)
1538c18ec02fSPetter Reinholdtsen 		printbuf(payload->payload.sol_packet.data, payload->payload.sol_packet.character_count, "SOL SEND DATA");
1539c18ec02fSPetter Reinholdtsen 
1540c18ec02fSPetter Reinholdtsen 	/*
1541c18ec02fSPetter Reinholdtsen 	 * At this point, the payload length becomes the whole payload
1542c18ec02fSPetter Reinholdtsen 	 * length, including the 4 bytes at the beginning of the SOL
1543c18ec02fSPetter Reinholdtsen 	 * packet
1544c18ec02fSPetter Reinholdtsen 	 */
1545c18ec02fSPetter Reinholdtsen 	payload->payload_length = payload->payload.sol_packet.character_count + 4;
1546c18ec02fSPetter Reinholdtsen }
1547c18ec02fSPetter Reinholdtsen 
1548c18ec02fSPetter Reinholdtsen 
1549c18ec02fSPetter Reinholdtsen 
1550c18ec02fSPetter Reinholdtsen /*
1551c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_build_v2x_msg
1552c18ec02fSPetter Reinholdtsen  *
1553c18ec02fSPetter Reinholdtsen  * Encapsulates the payload data to create the IPMI v2.0 / RMCP+ packet.
1554c18ec02fSPetter Reinholdtsen  *
1555c18ec02fSPetter Reinholdtsen  *
1556c18ec02fSPetter Reinholdtsen  * IPMI v2.0 LAN Request Message Format
1557c18ec02fSPetter Reinholdtsen  * +----------------------+
1558c18ec02fSPetter Reinholdtsen  * |  rmcp.ver            | 4 bytes
1559c18ec02fSPetter Reinholdtsen  * |  rmcp.__reserved     |
1560c18ec02fSPetter Reinholdtsen  * |  rmcp.seq            |
1561c18ec02fSPetter Reinholdtsen  * |  rmcp.class          |
1562c18ec02fSPetter Reinholdtsen  * +----------------------+
1563c18ec02fSPetter Reinholdtsen  * |  session.authtype    | 10 bytes
1564c18ec02fSPetter Reinholdtsen  * |  session.payloadtype |
1565c18ec02fSPetter Reinholdtsen  * |  session.id          |
1566c18ec02fSPetter Reinholdtsen  * |  session.seq         |
1567c18ec02fSPetter Reinholdtsen  * +----------------------+
1568c18ec02fSPetter Reinholdtsen  * |  message length      | 2 bytes
1569c18ec02fSPetter Reinholdtsen  * +----------------------+
1570c18ec02fSPetter Reinholdtsen  * | Confidentiality Hdr  | var (possibly absent)
1571c18ec02fSPetter Reinholdtsen  * +----------------------+
1572c18ec02fSPetter Reinholdtsen  * |  Paylod              | var Payload
1573c18ec02fSPetter Reinholdtsen  * +----------------------+
1574c18ec02fSPetter Reinholdtsen  * | Confidentiality Trlr | var (possibly absent)
1575c18ec02fSPetter Reinholdtsen  * +----------------------+
1576c18ec02fSPetter Reinholdtsen  * | Integrity pad        | var (possibly absent)
1577c18ec02fSPetter Reinholdtsen  * +----------------------+
1578c18ec02fSPetter Reinholdtsen  * | Pad length           | 1 byte (WTF?)
1579c18ec02fSPetter Reinholdtsen  * +----------------------+
1580c18ec02fSPetter Reinholdtsen  * | Next Header          | 1 byte (WTF?)
1581c18ec02fSPetter Reinholdtsen  * +----------------------+
1582c18ec02fSPetter Reinholdtsen  * | Authcode             | var (possibly absent)
1583c18ec02fSPetter Reinholdtsen  * +----------------------+
1584c18ec02fSPetter Reinholdtsen  */
1585c18ec02fSPetter Reinholdtsen void
1586c18ec02fSPetter Reinholdtsen ipmi_lanplus_build_v2x_msg(
1587c18ec02fSPetter Reinholdtsen 							struct ipmi_intf       * intf,     /* in  */
1588c18ec02fSPetter Reinholdtsen 							struct ipmi_v2_payload * payload,  /* in  */
1589c18ec02fSPetter Reinholdtsen 							int                    * msg_len,  /* out */
1590c18ec02fSPetter Reinholdtsen 							uint8_t         ** msg_data, /* out */
1591c18ec02fSPetter Reinholdtsen 							uint8_t curr_seq)
1592c18ec02fSPetter Reinholdtsen {
1593c18ec02fSPetter Reinholdtsen 	uint32_t session_trailer_length = 0;
1594c18ec02fSPetter Reinholdtsen 	struct ipmi_session * session = intf->session;
1595c18ec02fSPetter Reinholdtsen 	struct rmcp_hdr rmcp = {
1596c18ec02fSPetter Reinholdtsen 		.ver		= RMCP_VERSION_1,
1597c18ec02fSPetter Reinholdtsen 		.class		= RMCP_CLASS_IPMI,
1598c18ec02fSPetter Reinholdtsen 		.seq		= 0xff,
1599c18ec02fSPetter Reinholdtsen 	};
1600c18ec02fSPetter Reinholdtsen 
1601c18ec02fSPetter Reinholdtsen 	/* msg will hold the entire message to be sent */
1602c18ec02fSPetter Reinholdtsen 	uint8_t * msg;
1603c18ec02fSPetter Reinholdtsen 	int len = 0;
1604c18ec02fSPetter Reinholdtsen 
1605c18ec02fSPetter Reinholdtsen 
1606c18ec02fSPetter Reinholdtsen 	len =
1607c18ec02fSPetter Reinholdtsen 		sizeof(rmcp)                +  // RMCP Header (4)
1608c18ec02fSPetter Reinholdtsen 		10                          +  // IPMI Session Header
1609c18ec02fSPetter Reinholdtsen 		2                           +  // Message length
1610c18ec02fSPetter Reinholdtsen 		payload->payload_length     +  // The actual payload
1611c18ec02fSPetter Reinholdtsen 		IPMI_MAX_INTEGRITY_PAD_SIZE +  // Integrity Pad
1612c18ec02fSPetter Reinholdtsen 		1                           +  // Pad Length
1613c18ec02fSPetter Reinholdtsen 		1                           +  // Next Header
1614c18ec02fSPetter Reinholdtsen 		IPMI_MAX_AUTH_CODE_SIZE;       // Authcode
1615c18ec02fSPetter Reinholdtsen 
1616c18ec02fSPetter Reinholdtsen 
1617c18ec02fSPetter Reinholdtsen 	msg = malloc(len);
1618c18ec02fSPetter Reinholdtsen 	if (msg == NULL) {
1619c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
1620c18ec02fSPetter Reinholdtsen 		return;
1621c18ec02fSPetter Reinholdtsen 	}
1622c18ec02fSPetter Reinholdtsen 	memset(msg, 0, len);
1623c18ec02fSPetter Reinholdtsen 
1624c18ec02fSPetter Reinholdtsen 	/*
1625c18ec02fSPetter Reinholdtsen 	 *------------------------------------------
1626c18ec02fSPetter Reinholdtsen 	 * RMCP HEADER
1627c18ec02fSPetter Reinholdtsen 	 *------------------------------------------
1628c18ec02fSPetter Reinholdtsen 	 */
1629c18ec02fSPetter Reinholdtsen 	memcpy(msg, &rmcp, sizeof(rmcp));
1630c18ec02fSPetter Reinholdtsen 	len = sizeof(rmcp);
1631c18ec02fSPetter Reinholdtsen 
1632c18ec02fSPetter Reinholdtsen 
1633c18ec02fSPetter Reinholdtsen 	/*
1634c18ec02fSPetter Reinholdtsen 	 *------------------------------------------
1635c18ec02fSPetter Reinholdtsen 	 * IPMI SESSION HEADER
1636c18ec02fSPetter Reinholdtsen 	 *------------------------------------------
1637c18ec02fSPetter Reinholdtsen 	 */
1638c18ec02fSPetter Reinholdtsen 	/* ipmi session Auth Type / Format is always 0x06 for IPMI v2 */
1639c18ec02fSPetter Reinholdtsen 	msg[IPMI_LANPLUS_OFFSET_AUTHTYPE] = 0x06;
1640c18ec02fSPetter Reinholdtsen 
1641c18ec02fSPetter Reinholdtsen 	/* Payload Type -- also specifies whether were authenticated/encyrpted */
1642c18ec02fSPetter Reinholdtsen 	msg[IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE] = payload->payload_type;
1643c18ec02fSPetter Reinholdtsen 
1644c18ec02fSPetter Reinholdtsen 	if (session->v2_data.session_state == LANPLUS_STATE_ACTIVE)
1645c18ec02fSPetter Reinholdtsen 	{
1646c18ec02fSPetter Reinholdtsen 		msg[IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE] |=
1647c18ec02fSPetter Reinholdtsen 			((session->v2_data.crypt_alg != IPMI_CRYPT_NONE	)? 0x80 : 0x00);
1648c18ec02fSPetter Reinholdtsen 		msg[IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE] |=
1649c18ec02fSPetter Reinholdtsen 			((session->v2_data.integrity_alg  != IPMI_INTEGRITY_NONE)? 0x40 : 0x00);
1650c18ec02fSPetter Reinholdtsen 	}
1651c18ec02fSPetter Reinholdtsen 
1652c18ec02fSPetter Reinholdtsen 	if (session->v2_data.session_state == LANPLUS_STATE_ACTIVE)
1653c18ec02fSPetter Reinholdtsen 	{
1654c18ec02fSPetter Reinholdtsen 		/* Session ID  -- making it LSB */
1655c18ec02fSPetter Reinholdtsen 		msg[IPMI_LANPLUS_OFFSET_SESSION_ID    ] = session->v2_data.bmc_id         & 0xff;
1656c18ec02fSPetter Reinholdtsen 		msg[IPMI_LANPLUS_OFFSET_SESSION_ID + 1] = (session->v2_data.bmc_id >> 8)  & 0xff;
1657c18ec02fSPetter Reinholdtsen 		msg[IPMI_LANPLUS_OFFSET_SESSION_ID + 2] = (session->v2_data.bmc_id >> 16) & 0xff;
1658c18ec02fSPetter Reinholdtsen 		msg[IPMI_LANPLUS_OFFSET_SESSION_ID + 3] = (session->v2_data.bmc_id >> 24) & 0xff;
1659c18ec02fSPetter Reinholdtsen 
1660c18ec02fSPetter Reinholdtsen 		/* Sequence Number -- making it LSB */
1661c18ec02fSPetter Reinholdtsen 		msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM    ] = session->out_seq         & 0xff;
1662c18ec02fSPetter Reinholdtsen 		msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM + 1] = (session->out_seq >> 8)  & 0xff;
1663c18ec02fSPetter Reinholdtsen 		msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM + 2] = (session->out_seq >> 16) & 0xff;
1664c18ec02fSPetter Reinholdtsen 		msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM + 3] = (session->out_seq >> 24) & 0xff;
1665c18ec02fSPetter Reinholdtsen 	}
1666c18ec02fSPetter Reinholdtsen 
1667c18ec02fSPetter Reinholdtsen 	/*
1668c18ec02fSPetter Reinholdtsen 	 * Payload Length is set below (we don't know how big the payload is until after
1669c18ec02fSPetter Reinholdtsen 	 * encryption).
1670c18ec02fSPetter Reinholdtsen 	 */
1671c18ec02fSPetter Reinholdtsen 
1672c18ec02fSPetter Reinholdtsen 	/*
1673c18ec02fSPetter Reinholdtsen 	 * Payload
1674c18ec02fSPetter Reinholdtsen 	 *
1675c18ec02fSPetter Reinholdtsen 	 * At this point we are ready to slam the payload in.
1676c18ec02fSPetter Reinholdtsen 	 * This includes:
1677c18ec02fSPetter Reinholdtsen 	 * 1) The confidentiality header
1678c18ec02fSPetter Reinholdtsen 	 * 2) The payload proper (possibly encrypted)
1679c18ec02fSPetter Reinholdtsen 	 * 3) The confidentiality trailer
1680c18ec02fSPetter Reinholdtsen 	 *
1681c18ec02fSPetter Reinholdtsen 	 */
1682c18ec02fSPetter Reinholdtsen 	switch (payload->payload_type)
1683c18ec02fSPetter Reinholdtsen 	{
1684c18ec02fSPetter Reinholdtsen 	case IPMI_PAYLOAD_TYPE_IPMI:
1685c18ec02fSPetter Reinholdtsen 		getIpmiPayloadWireRep(intf,
1686c18ec02fSPetter Reinholdtsen 							  payload,  /* in  */
1687c18ec02fSPetter Reinholdtsen 							  msg + IPMI_LANPLUS_OFFSET_PAYLOAD,
1688c18ec02fSPetter Reinholdtsen 							  payload->payload.ipmi_request.request,
1689c18ec02fSPetter Reinholdtsen 							  payload->payload.ipmi_request.rq_seq,
1690c18ec02fSPetter Reinholdtsen 							  curr_seq);
1691c18ec02fSPetter Reinholdtsen 		break;
1692c18ec02fSPetter Reinholdtsen 
1693c18ec02fSPetter Reinholdtsen 	case IPMI_PAYLOAD_TYPE_SOL:
1694c18ec02fSPetter Reinholdtsen 		getSolPayloadWireRep(intf,
1695c18ec02fSPetter Reinholdtsen 							 msg + IPMI_LANPLUS_OFFSET_PAYLOAD,
1696c18ec02fSPetter Reinholdtsen 							 payload);
1697c18ec02fSPetter Reinholdtsen 
1698c18ec02fSPetter Reinholdtsen 		if (verbose >= 5)
1699c18ec02fSPetter Reinholdtsen 			printbuf(msg + IPMI_LANPLUS_OFFSET_PAYLOAD, 4, "SOL MSG TO BMC");
1700c18ec02fSPetter Reinholdtsen 
1701c18ec02fSPetter Reinholdtsen 		len += payload->payload_length;
1702c18ec02fSPetter Reinholdtsen 
1703c18ec02fSPetter Reinholdtsen 		break;
1704c18ec02fSPetter Reinholdtsen 
1705c18ec02fSPetter Reinholdtsen 	case IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST:
1706c18ec02fSPetter Reinholdtsen 		/* never encrypted, so our job is easy */
1707c18ec02fSPetter Reinholdtsen 		memcpy(msg + IPMI_LANPLUS_OFFSET_PAYLOAD,
1708c18ec02fSPetter Reinholdtsen 				payload->payload.open_session_request.request,
1709c18ec02fSPetter Reinholdtsen 				payload->payload_length);
1710c18ec02fSPetter Reinholdtsen 		len += payload->payload_length;
1711c18ec02fSPetter Reinholdtsen 		break;
1712c18ec02fSPetter Reinholdtsen 
1713c18ec02fSPetter Reinholdtsen 	case IPMI_PAYLOAD_TYPE_RAKP_1:
1714c18ec02fSPetter Reinholdtsen 		/* never encrypted, so our job is easy */
1715c18ec02fSPetter Reinholdtsen 		memcpy(msg + IPMI_LANPLUS_OFFSET_PAYLOAD,
1716c18ec02fSPetter Reinholdtsen 				payload->payload.rakp_1_message.message,
1717c18ec02fSPetter Reinholdtsen 				payload->payload_length);
1718c18ec02fSPetter Reinholdtsen 		len += payload->payload_length;
1719c18ec02fSPetter Reinholdtsen 		break;
1720c18ec02fSPetter Reinholdtsen 
1721c18ec02fSPetter Reinholdtsen 	case IPMI_PAYLOAD_TYPE_RAKP_3:
1722c18ec02fSPetter Reinholdtsen 		/* never encrypted, so our job is easy */
1723c18ec02fSPetter Reinholdtsen 		memcpy(msg + IPMI_LANPLUS_OFFSET_PAYLOAD,
1724c18ec02fSPetter Reinholdtsen 				payload->payload.rakp_3_message.message,
1725c18ec02fSPetter Reinholdtsen 				payload->payload_length);
1726c18ec02fSPetter Reinholdtsen 		len += payload->payload_length;
1727c18ec02fSPetter Reinholdtsen 		break;
1728c18ec02fSPetter Reinholdtsen 
1729c18ec02fSPetter Reinholdtsen 	default:
1730c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "unsupported payload type 0x%x",
1731c18ec02fSPetter Reinholdtsen 			payload->payload_type);
1732c18ec02fSPetter Reinholdtsen 		free(msg);
1733c18ec02fSPetter Reinholdtsen 		msg = NULL;
1734c18ec02fSPetter Reinholdtsen 		assert(0);
1735c18ec02fSPetter Reinholdtsen 		break;
1736c18ec02fSPetter Reinholdtsen 	}
1737c18ec02fSPetter Reinholdtsen 
1738c18ec02fSPetter Reinholdtsen 
1739c18ec02fSPetter Reinholdtsen 	/*
1740c18ec02fSPetter Reinholdtsen 	 *------------------------------------------
1741c18ec02fSPetter Reinholdtsen 	 * ENCRYPT THE PAYLOAD IF NECESSARY
1742c18ec02fSPetter Reinholdtsen 	 *------------------------------------------
1743c18ec02fSPetter Reinholdtsen 	 */
1744c18ec02fSPetter Reinholdtsen 	if (session->v2_data.session_state == LANPLUS_STATE_ACTIVE)
1745c18ec02fSPetter Reinholdtsen 	{
1746c18ec02fSPetter Reinholdtsen 		/* Payload len is adjusted as necessary by lanplus_encrypt_payload */
1747c18ec02fSPetter Reinholdtsen 		lanplus_encrypt_payload(session->v2_data.crypt_alg,        /* input  */
1748c18ec02fSPetter Reinholdtsen 								session->v2_data.k2,               /* input  */
1749c18ec02fSPetter Reinholdtsen 								msg + IPMI_LANPLUS_OFFSET_PAYLOAD, /* input  */
1750c18ec02fSPetter Reinholdtsen 								payload->payload_length,           /* input  */
1751c18ec02fSPetter Reinholdtsen 								msg + IPMI_LANPLUS_OFFSET_PAYLOAD, /* output */
1752c18ec02fSPetter Reinholdtsen 								&(payload->payload_length));       /* output */
1753c18ec02fSPetter Reinholdtsen 
1754c18ec02fSPetter Reinholdtsen 	}
1755c18ec02fSPetter Reinholdtsen 
1756c18ec02fSPetter Reinholdtsen 	/* Now we know the payload length */
1757c18ec02fSPetter Reinholdtsen 	msg[IPMI_LANPLUS_OFFSET_PAYLOAD_SIZE    ] =
1758c18ec02fSPetter Reinholdtsen 		payload->payload_length        & 0xff;
1759c18ec02fSPetter Reinholdtsen 	msg[IPMI_LANPLUS_OFFSET_PAYLOAD_SIZE + 1] =
1760c18ec02fSPetter Reinholdtsen 		(payload->payload_length >> 8) & 0xff;
1761c18ec02fSPetter Reinholdtsen 
1762c18ec02fSPetter Reinholdtsen 
1763c18ec02fSPetter Reinholdtsen 	/*
1764c18ec02fSPetter Reinholdtsen 	 *------------------------------------------
1765c18ec02fSPetter Reinholdtsen 	 * SESSION TRAILER
1766c18ec02fSPetter Reinholdtsen 	 *------------------------------------------
1767c18ec02fSPetter Reinholdtsen 	 */
1768c18ec02fSPetter Reinholdtsen 	if ((session->v2_data.session_state == LANPLUS_STATE_ACTIVE) &&
1769c18ec02fSPetter Reinholdtsen 		(session->v2_data.integrity_alg != IPMI_INTEGRITY_NONE))
1770c18ec02fSPetter Reinholdtsen 	{
1771c18ec02fSPetter Reinholdtsen 		uint32_t i, hmac_length, integrity_pad_size = 0, hmac_input_size;
1772c18ec02fSPetter Reinholdtsen 		uint8_t * hmac_output;
1773c18ec02fSPetter Reinholdtsen 		uint32_t start_of_session_trailer =
1774c18ec02fSPetter Reinholdtsen 			IPMI_LANPLUS_OFFSET_PAYLOAD +
1775c18ec02fSPetter Reinholdtsen 			payload->payload_length;
1776c18ec02fSPetter Reinholdtsen 
1777c18ec02fSPetter Reinholdtsen 
1778c18ec02fSPetter Reinholdtsen 		/*
1779c18ec02fSPetter Reinholdtsen 		 * Determine the required integrity pad length.  We have to make the
1780c18ec02fSPetter Reinholdtsen 		 * data range covered by the authcode a multiple of 4.
1781c18ec02fSPetter Reinholdtsen 		 */
1782c18ec02fSPetter Reinholdtsen 		uint32_t length_before_authcode;
1783c18ec02fSPetter Reinholdtsen 
1784c18ec02fSPetter Reinholdtsen 		if (ipmi_oem_active(intf, "icts")) {
1785c18ec02fSPetter Reinholdtsen 			length_before_authcode =
1786c18ec02fSPetter Reinholdtsen 				12                          + /* the stuff before the payload */
1787c18ec02fSPetter Reinholdtsen 				payload->payload_length;
1788c18ec02fSPetter Reinholdtsen 		} else {
1789c18ec02fSPetter Reinholdtsen 			length_before_authcode =
1790c18ec02fSPetter Reinholdtsen 				12                          + /* the stuff before the payload */
1791c18ec02fSPetter Reinholdtsen 				payload->payload_length     +
1792c18ec02fSPetter Reinholdtsen 				1                           + /* pad length field  */
1793c18ec02fSPetter Reinholdtsen 				1;                            /* next header field */
1794c18ec02fSPetter Reinholdtsen 		}
1795c18ec02fSPetter Reinholdtsen 
1796c18ec02fSPetter Reinholdtsen 		if (length_before_authcode % 4)
1797c18ec02fSPetter Reinholdtsen 			integrity_pad_size = 4 - (length_before_authcode % 4);
1798c18ec02fSPetter Reinholdtsen 
1799c18ec02fSPetter Reinholdtsen 		for (i = 0; i < integrity_pad_size; ++i)
1800c18ec02fSPetter Reinholdtsen 			msg[start_of_session_trailer + i] = 0xFF;
1801c18ec02fSPetter Reinholdtsen 
1802c18ec02fSPetter Reinholdtsen 		/* Pad length */
1803c18ec02fSPetter Reinholdtsen 		msg[start_of_session_trailer + integrity_pad_size] = integrity_pad_size;
1804c18ec02fSPetter Reinholdtsen 
1805c18ec02fSPetter Reinholdtsen 		/* Next Header */
1806c18ec02fSPetter Reinholdtsen 		msg[start_of_session_trailer + integrity_pad_size + 1] =
1807c18ec02fSPetter Reinholdtsen 			0x07; /* Hardcoded per the spec, table 13-8 */
1808c18ec02fSPetter Reinholdtsen 
1809c18ec02fSPetter Reinholdtsen 		hmac_input_size =
1810c18ec02fSPetter Reinholdtsen 			12                      +
1811c18ec02fSPetter Reinholdtsen 			payload->payload_length +
1812c18ec02fSPetter Reinholdtsen 			integrity_pad_size      +
1813c18ec02fSPetter Reinholdtsen 			2;
1814c18ec02fSPetter Reinholdtsen 
1815c18ec02fSPetter Reinholdtsen 		hmac_output =
1816c18ec02fSPetter Reinholdtsen 			msg                         +
1817c18ec02fSPetter Reinholdtsen 			IPMI_LANPLUS_OFFSET_PAYLOAD +
1818c18ec02fSPetter Reinholdtsen 			payload->payload_length     +
1819c18ec02fSPetter Reinholdtsen 			integrity_pad_size          +
1820c18ec02fSPetter Reinholdtsen 			2;
1821c18ec02fSPetter Reinholdtsen 
1822c18ec02fSPetter Reinholdtsen 		if (verbose > 2)
1823c18ec02fSPetter Reinholdtsen 			printbuf(msg + IPMI_LANPLUS_OFFSET_AUTHTYPE, hmac_input_size, "authcode input");
1824c18ec02fSPetter Reinholdtsen 
1825c18ec02fSPetter Reinholdtsen 
1826c18ec02fSPetter Reinholdtsen 		/* Auth Code */
1827c18ec02fSPetter Reinholdtsen 		lanplus_HMAC(session->v2_data.integrity_alg,
1828c18ec02fSPetter Reinholdtsen 					 session->v2_data.k1,                /* key        */
1829c18ec02fSPetter Reinholdtsen 					 20,                                 /* key length */
1830c18ec02fSPetter Reinholdtsen 					 msg + IPMI_LANPLUS_OFFSET_AUTHTYPE, /* hmac input */
1831c18ec02fSPetter Reinholdtsen 					 hmac_input_size,
1832c18ec02fSPetter Reinholdtsen 					 hmac_output,
1833c18ec02fSPetter Reinholdtsen 					 &hmac_length);
1834c18ec02fSPetter Reinholdtsen 
1835c18ec02fSPetter Reinholdtsen 		assert(hmac_length == 20);
1836c18ec02fSPetter Reinholdtsen 
1837c18ec02fSPetter Reinholdtsen 		if (verbose > 2)
1838c18ec02fSPetter Reinholdtsen 			printbuf(hmac_output, 12, "authcode output");
1839c18ec02fSPetter Reinholdtsen 
1840c18ec02fSPetter Reinholdtsen 		/* Set session_trailer_length appropriately */
1841c18ec02fSPetter Reinholdtsen 		session_trailer_length =
1842c18ec02fSPetter Reinholdtsen 			integrity_pad_size +
1843c18ec02fSPetter Reinholdtsen 			2                  + /* pad length + next header */
1844c18ec02fSPetter Reinholdtsen 			12;                  /* Size of the authcode (we only use the first 12 bytes) */
1845c18ec02fSPetter Reinholdtsen 	}
1846c18ec02fSPetter Reinholdtsen 
1847c18ec02fSPetter Reinholdtsen 
1848c18ec02fSPetter Reinholdtsen 	++(session->out_seq);
1849c18ec02fSPetter Reinholdtsen 	if (!session->out_seq)
1850c18ec02fSPetter Reinholdtsen 		++(session->out_seq);
1851c18ec02fSPetter Reinholdtsen 
1852c18ec02fSPetter Reinholdtsen 	*msg_len =
1853c18ec02fSPetter Reinholdtsen 		IPMI_LANPLUS_OFFSET_PAYLOAD +
1854c18ec02fSPetter Reinholdtsen 		payload->payload_length     +
1855c18ec02fSPetter Reinholdtsen 		session_trailer_length;
1856c18ec02fSPetter Reinholdtsen 	*msg_data = msg;
1857c18ec02fSPetter Reinholdtsen }
1858c18ec02fSPetter Reinholdtsen 
1859c18ec02fSPetter Reinholdtsen 
1860c18ec02fSPetter Reinholdtsen 
1861c18ec02fSPetter Reinholdtsen /*
1862c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_build_v2x_ipmi_cmd
1863c18ec02fSPetter Reinholdtsen  *
1864c18ec02fSPetter Reinholdtsen  * Wraps ipmi_lanplus_build_v2x_msg and returns a new entry object for the
1865c18ec02fSPetter Reinholdtsen  * command
1866c18ec02fSPetter Reinholdtsen  *
1867c18ec02fSPetter Reinholdtsen  */
1868c18ec02fSPetter Reinholdtsen static struct ipmi_rq_entry *
1869c18ec02fSPetter Reinholdtsen ipmi_lanplus_build_v2x_ipmi_cmd(
1870c18ec02fSPetter Reinholdtsen 								struct ipmi_intf * intf,
1871c18ec02fSPetter Reinholdtsen 								struct ipmi_rq * req,
1872c18ec02fSPetter Reinholdtsen 								int isRetry)
1873c18ec02fSPetter Reinholdtsen {
1874c18ec02fSPetter Reinholdtsen 	struct ipmi_v2_payload v2_payload;
1875c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * entry;
1876c18ec02fSPetter Reinholdtsen 
1877c18ec02fSPetter Reinholdtsen 	/*
1878c18ec02fSPetter Reinholdtsen 	 * We have a problem.  we need to know the sequence number here,
1879c18ec02fSPetter Reinholdtsen 	 * because we use it in our stored entry.  But we also need to
1880c18ec02fSPetter Reinholdtsen 	 * know the sequence number when we generate our IPMI
1881c18ec02fSPetter Reinholdtsen 	 * representation far below.
1882c18ec02fSPetter Reinholdtsen 	 */
1883c18ec02fSPetter Reinholdtsen 	static uint8_t curr_seq = 0;
1884c18ec02fSPetter Reinholdtsen 
1885c18ec02fSPetter Reinholdtsen 	if( isRetry == 0 )
1886c18ec02fSPetter Reinholdtsen 		curr_seq += 1;
1887c18ec02fSPetter Reinholdtsen 
1888c18ec02fSPetter Reinholdtsen 	if (curr_seq >= 64)
1889c18ec02fSPetter Reinholdtsen 		curr_seq = 0;
1890c18ec02fSPetter Reinholdtsen 
1891c18ec02fSPetter Reinholdtsen 
1892c18ec02fSPetter Reinholdtsen 	/* IPMI Message Header -- Figure 13-4 of the IPMI v2.0 spec */
1893c18ec02fSPetter Reinholdtsen 	if ((intf->target_addr == intf->my_addr) || (!bridgePossible))
1894c18ec02fSPetter Reinholdtsen    {
1895c18ec02fSPetter Reinholdtsen 	entry = ipmi_req_add_entry(intf, req, curr_seq);
1896c18ec02fSPetter Reinholdtsen    }
1897c18ec02fSPetter Reinholdtsen    else /* it's a bridge command */
1898c18ec02fSPetter Reinholdtsen    {
1899c18ec02fSPetter Reinholdtsen       unsigned char backup_cmd;
1900c18ec02fSPetter Reinholdtsen 
1901c18ec02fSPetter Reinholdtsen       /* Add entry for cmd */
1902c18ec02fSPetter Reinholdtsen    	entry = ipmi_req_add_entry(intf, req, curr_seq);
1903c18ec02fSPetter Reinholdtsen 
1904c18ec02fSPetter Reinholdtsen       if(entry)
1905c18ec02fSPetter Reinholdtsen       {
1906c18ec02fSPetter Reinholdtsen          /* Add entry for bridge cmd */
1907c18ec02fSPetter Reinholdtsen          backup_cmd = req->msg.cmd;
1908c18ec02fSPetter Reinholdtsen          req->msg.cmd = 0x34;
1909c18ec02fSPetter Reinholdtsen    	   entry = ipmi_req_add_entry(intf, req, curr_seq);
1910c18ec02fSPetter Reinholdtsen          req->msg.cmd = backup_cmd;
1911c18ec02fSPetter Reinholdtsen       }
1912c18ec02fSPetter Reinholdtsen    }
1913c18ec02fSPetter Reinholdtsen 
1914c18ec02fSPetter Reinholdtsen 	if (entry == NULL)
1915c18ec02fSPetter Reinholdtsen 		return NULL;
1916c18ec02fSPetter Reinholdtsen 
1917c18ec02fSPetter Reinholdtsen 	// Build our payload
1918c18ec02fSPetter Reinholdtsen 	v2_payload.payload_type                 = IPMI_PAYLOAD_TYPE_IPMI;
1919c18ec02fSPetter Reinholdtsen 	v2_payload.payload_length               = req->msg.data_len + 7;
1920c18ec02fSPetter Reinholdtsen 	v2_payload.payload.ipmi_request.request = req;
1921c18ec02fSPetter Reinholdtsen 	v2_payload.payload.ipmi_request.rq_seq  = curr_seq;
1922c18ec02fSPetter Reinholdtsen 
1923c18ec02fSPetter Reinholdtsen 	ipmi_lanplus_build_v2x_msg(intf,                // in
1924c18ec02fSPetter Reinholdtsen 					&v2_payload,         // in
1925c18ec02fSPetter Reinholdtsen 					&(entry->msg_len),   // out
1926c18ec02fSPetter Reinholdtsen 					&(entry->msg_data),  // out
1927c18ec02fSPetter Reinholdtsen 					curr_seq); 		// in
1928c18ec02fSPetter Reinholdtsen 
1929c18ec02fSPetter Reinholdtsen 	return entry;
1930c18ec02fSPetter Reinholdtsen }
1931c18ec02fSPetter Reinholdtsen 
1932c18ec02fSPetter Reinholdtsen 
1933c18ec02fSPetter Reinholdtsen 
1934c18ec02fSPetter Reinholdtsen 
1935c18ec02fSPetter Reinholdtsen 
1936c18ec02fSPetter Reinholdtsen /*
1937c18ec02fSPetter Reinholdtsen  * IPMI LAN Request Message Format
1938c18ec02fSPetter Reinholdtsen  * +--------------------+
1939c18ec02fSPetter Reinholdtsen  * |  rmcp.ver          | 4 bytes
1940c18ec02fSPetter Reinholdtsen  * |  rmcp.__reserved   |
1941c18ec02fSPetter Reinholdtsen  * |  rmcp.seq          |
1942c18ec02fSPetter Reinholdtsen  * |  rmcp.class        |
1943c18ec02fSPetter Reinholdtsen  * +--------------------+
1944c18ec02fSPetter Reinholdtsen  * |  session.authtype  | 9 bytes
1945c18ec02fSPetter Reinholdtsen  * |  session.seq       |
1946c18ec02fSPetter Reinholdtsen  * |  session.id        |
1947c18ec02fSPetter Reinholdtsen  * +--------------------+
1948c18ec02fSPetter Reinholdtsen  * | [session.authcode] | 16 bytes (AUTHTYPE != none)
1949c18ec02fSPetter Reinholdtsen  * +--------------------+
1950c18ec02fSPetter Reinholdtsen  * |  message length    | 1 byte
1951c18ec02fSPetter Reinholdtsen  * +--------------------+
1952c18ec02fSPetter Reinholdtsen  * |  message.rs_addr   | 6 bytes
1953c18ec02fSPetter Reinholdtsen  * |  message.netfn_lun |
1954c18ec02fSPetter Reinholdtsen  * |  message.checksum  |
1955c18ec02fSPetter Reinholdtsen  * |  message.rq_addr   |
1956c18ec02fSPetter Reinholdtsen  * |  message.rq_seq    |
1957c18ec02fSPetter Reinholdtsen  * |  message.cmd       |
1958c18ec02fSPetter Reinholdtsen  * +--------------------+
1959c18ec02fSPetter Reinholdtsen  * | [request data]     | data_len bytes
1960c18ec02fSPetter Reinholdtsen  * +--------------------+
1961c18ec02fSPetter Reinholdtsen  * |  checksum          | 1 byte
1962c18ec02fSPetter Reinholdtsen  * +--------------------+
1963c18ec02fSPetter Reinholdtsen  */
1964c18ec02fSPetter Reinholdtsen static struct ipmi_rq_entry *
1965c18ec02fSPetter Reinholdtsen ipmi_lanplus_build_v15_ipmi_cmd(
1966c18ec02fSPetter Reinholdtsen 								struct ipmi_intf * intf,
1967c18ec02fSPetter Reinholdtsen 								struct ipmi_rq * req)
1968c18ec02fSPetter Reinholdtsen {
1969c18ec02fSPetter Reinholdtsen 	struct rmcp_hdr rmcp = {
1970c18ec02fSPetter Reinholdtsen 		.ver		= RMCP_VERSION_1,
1971c18ec02fSPetter Reinholdtsen 		.class		= RMCP_CLASS_IPMI,
1972c18ec02fSPetter Reinholdtsen 		.seq		= 0xff,
1973c18ec02fSPetter Reinholdtsen 	};
1974c18ec02fSPetter Reinholdtsen 	uint8_t * msg;
1975c18ec02fSPetter Reinholdtsen 	int cs, mp, len = 0, tmp;
1976c18ec02fSPetter Reinholdtsen 	struct ipmi_session  * session = intf->session;
1977c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * entry;
1978c18ec02fSPetter Reinholdtsen 
1979c18ec02fSPetter Reinholdtsen 	entry = ipmi_req_add_entry(intf, req, 0);
1980c18ec02fSPetter Reinholdtsen 	if (entry == NULL)
1981c18ec02fSPetter Reinholdtsen 		return NULL;
1982c18ec02fSPetter Reinholdtsen 
1983c18ec02fSPetter Reinholdtsen 	len = req->msg.data_len + 21;
1984c18ec02fSPetter Reinholdtsen 
1985c18ec02fSPetter Reinholdtsen 	msg = malloc(len);
1986c18ec02fSPetter Reinholdtsen 	if (msg == NULL) {
1987c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
1988c18ec02fSPetter Reinholdtsen 		return NULL;
1989c18ec02fSPetter Reinholdtsen 	}
1990c18ec02fSPetter Reinholdtsen 	memset(msg, 0, len);
1991c18ec02fSPetter Reinholdtsen 
1992c18ec02fSPetter Reinholdtsen 	/* rmcp header */
1993c18ec02fSPetter Reinholdtsen 	memcpy(msg, &rmcp, sizeof(rmcp));
1994c18ec02fSPetter Reinholdtsen 	len = sizeof(rmcp);
1995c18ec02fSPetter Reinholdtsen 
1996c18ec02fSPetter Reinholdtsen 	/*
1997c18ec02fSPetter Reinholdtsen 	 * ipmi session header
1998c18ec02fSPetter Reinholdtsen 	 */
1999c18ec02fSPetter Reinholdtsen 	/* Authtype should always be none for 1.5 packets sent from this
2000c18ec02fSPetter Reinholdtsen 	 * interface
2001c18ec02fSPetter Reinholdtsen 	 */
2002c18ec02fSPetter Reinholdtsen 	msg[len++] = IPMI_SESSION_AUTHTYPE_NONE;
2003c18ec02fSPetter Reinholdtsen 
2004c18ec02fSPetter Reinholdtsen 	msg[len++] = session->out_seq & 0xff;
2005c18ec02fSPetter Reinholdtsen 	msg[len++] = (session->out_seq >> 8) & 0xff;
2006c18ec02fSPetter Reinholdtsen 	msg[len++] = (session->out_seq >> 16) & 0xff;
2007c18ec02fSPetter Reinholdtsen 	msg[len++] = (session->out_seq >> 24) & 0xff;
2008c18ec02fSPetter Reinholdtsen 
2009c18ec02fSPetter Reinholdtsen 	/*
2010c18ec02fSPetter Reinholdtsen 	 * The session ID should be all zeroes for pre-session commands.  We
2011c18ec02fSPetter Reinholdtsen 	 * should only be using the 1.5 interface for the pre-session Get
2012c18ec02fSPetter Reinholdtsen 	 * Channel Authentication Capabilities command
2013c18ec02fSPetter Reinholdtsen 	 */
2014c18ec02fSPetter Reinholdtsen 	msg[len++] = 0;
2015c18ec02fSPetter Reinholdtsen 	msg[len++] = 0;
2016c18ec02fSPetter Reinholdtsen 	msg[len++] = 0;
2017c18ec02fSPetter Reinholdtsen 	msg[len++] = 0;
2018c18ec02fSPetter Reinholdtsen 
2019c18ec02fSPetter Reinholdtsen 	/* message length */
2020c18ec02fSPetter Reinholdtsen 	msg[len++] = req->msg.data_len + 7;
2021c18ec02fSPetter Reinholdtsen 
2022c18ec02fSPetter Reinholdtsen 	/* ipmi message header */
2023c18ec02fSPetter Reinholdtsen 	cs = mp = len;
2024c18ec02fSPetter Reinholdtsen 	msg[len++] = IPMI_BMC_SLAVE_ADDR;
2025c18ec02fSPetter Reinholdtsen 	msg[len++] = req->msg.netfn << 2;
2026c18ec02fSPetter Reinholdtsen 	tmp = len - cs;
2027c18ec02fSPetter Reinholdtsen 	msg[len++] = ipmi_csum(msg+cs, tmp);
2028c18ec02fSPetter Reinholdtsen 	cs = len;
2029c18ec02fSPetter Reinholdtsen 	msg[len++] = IPMI_REMOTE_SWID;
2030c18ec02fSPetter Reinholdtsen 
2031c18ec02fSPetter Reinholdtsen 	entry->rq_seq = 0;
2032c18ec02fSPetter Reinholdtsen 
2033c18ec02fSPetter Reinholdtsen 	msg[len++] = entry->rq_seq << 2;
2034c18ec02fSPetter Reinholdtsen 	msg[len++] = req->msg.cmd;
2035c18ec02fSPetter Reinholdtsen 
2036c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">> IPMI Request Session Header");
2037c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Authtype   : %s",
2038c18ec02fSPetter Reinholdtsen 		val2str(IPMI_SESSION_AUTHTYPE_NONE, ipmi_authtype_session_vals));
2039c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Sequence   : 0x%08lx",
2040c18ec02fSPetter Reinholdtsen 		(long)session->out_seq);
2041c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Session ID : 0x%08lx",
2042c18ec02fSPetter Reinholdtsen 		(long)0);
2043c18ec02fSPetter Reinholdtsen 
2044c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">> IPMI Request Message Header");
2045c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Rs Addr    : %02x", IPMI_BMC_SLAVE_ADDR);
2046c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   NetFn      : %02x", req->msg.netfn);
2047c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Rs LUN     : %01x", 0);
2048c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Rq Addr    : %02x", IPMI_REMOTE_SWID);
2049c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Rq Seq     : %02x", entry->rq_seq);
2050c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Rq Lun     : %01x", 0);
2051c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Command    : %02x", req->msg.cmd);
2052c18ec02fSPetter Reinholdtsen 
2053c18ec02fSPetter Reinholdtsen 	/* message data */
2054c18ec02fSPetter Reinholdtsen 	if (req->msg.data_len) {
2055c18ec02fSPetter Reinholdtsen 		memcpy(msg+len, req->msg.data, req->msg.data_len);
2056c18ec02fSPetter Reinholdtsen 		len += req->msg.data_len;
2057c18ec02fSPetter Reinholdtsen 	}
2058c18ec02fSPetter Reinholdtsen 
2059c18ec02fSPetter Reinholdtsen 	/* second checksum */
2060c18ec02fSPetter Reinholdtsen 	tmp = len - cs;
2061c18ec02fSPetter Reinholdtsen 	msg[len++] = ipmi_csum(msg+cs, tmp);
2062c18ec02fSPetter Reinholdtsen 
2063c18ec02fSPetter Reinholdtsen 	entry->msg_len = len;
2064c18ec02fSPetter Reinholdtsen 	entry->msg_data = msg;
2065c18ec02fSPetter Reinholdtsen 
2066c18ec02fSPetter Reinholdtsen 	return entry;
2067c18ec02fSPetter Reinholdtsen }
2068c18ec02fSPetter Reinholdtsen 
2069c18ec02fSPetter Reinholdtsen 
2070c18ec02fSPetter Reinholdtsen 
2071c18ec02fSPetter Reinholdtsen /*
2072c18ec02fSPetter Reinholdtsen  * is_sol_packet
2073c18ec02fSPetter Reinholdtsen  */
2074c18ec02fSPetter Reinholdtsen static int
2075c18ec02fSPetter Reinholdtsen is_sol_packet(struct ipmi_rs * rsp)
2076c18ec02fSPetter Reinholdtsen {
2077c18ec02fSPetter Reinholdtsen 	return (rsp                                                           &&
2078c18ec02fSPetter Reinholdtsen 			(rsp->session.authtype    == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
2079c18ec02fSPetter Reinholdtsen 			(rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL));
2080c18ec02fSPetter Reinholdtsen }
2081c18ec02fSPetter Reinholdtsen 
2082c18ec02fSPetter Reinholdtsen 
2083c18ec02fSPetter Reinholdtsen 
2084c18ec02fSPetter Reinholdtsen /*
2085c18ec02fSPetter Reinholdtsen  * sol_response_acks_packet
2086c18ec02fSPetter Reinholdtsen  */
2087c18ec02fSPetter Reinholdtsen static int
2088c18ec02fSPetter Reinholdtsen sol_response_acks_packet(
2089c18ec02fSPetter Reinholdtsen 						 struct ipmi_rs         * rsp,
2090c18ec02fSPetter Reinholdtsen 						 struct ipmi_v2_payload * payload)
2091c18ec02fSPetter Reinholdtsen {
2092c18ec02fSPetter Reinholdtsen 	return (is_sol_packet(rsp)                                            &&
2093c18ec02fSPetter Reinholdtsen 			payload                                                       &&
2094c18ec02fSPetter Reinholdtsen 			(payload->payload_type    == IPMI_PAYLOAD_TYPE_SOL)           &&
2095c18ec02fSPetter Reinholdtsen 			(rsp->payload.sol_packet.acked_packet_number ==
2096c18ec02fSPetter Reinholdtsen 			 payload->payload.sol_packet.packet_sequence_number));
2097c18ec02fSPetter Reinholdtsen }
2098c18ec02fSPetter Reinholdtsen 
2099c18ec02fSPetter Reinholdtsen 
2100c18ec02fSPetter Reinholdtsen 
2101c18ec02fSPetter Reinholdtsen /*
2102c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_send_payload
2103c18ec02fSPetter Reinholdtsen  *
2104c18ec02fSPetter Reinholdtsen  */
2105c18ec02fSPetter Reinholdtsen struct ipmi_rs *
2106c18ec02fSPetter Reinholdtsen ipmi_lanplus_send_payload(
2107c18ec02fSPetter Reinholdtsen 						  struct ipmi_intf * intf,
2108c18ec02fSPetter Reinholdtsen 						  struct ipmi_v2_payload * payload)
2109c18ec02fSPetter Reinholdtsen {
2110c18ec02fSPetter Reinholdtsen 	struct ipmi_rs      * rsp = NULL;
2111c18ec02fSPetter Reinholdtsen 	uint8_t             * msg_data;
2112c18ec02fSPetter Reinholdtsen 	int                   msg_length;
2113c18ec02fSPetter Reinholdtsen 	struct ipmi_session * session = intf->session;
2114176774cfSZdenek Styblik 	struct ipmi_rq_entry * entry = NULL;
2115c18ec02fSPetter Reinholdtsen 	int                   try = 0;
2116c18ec02fSPetter Reinholdtsen 	int                   xmit = 1;
2117c18ec02fSPetter Reinholdtsen 	time_t                ltime;
2118c18ec02fSPetter Reinholdtsen 	uint32_t	      saved_timeout;
2119c18ec02fSPetter Reinholdtsen 
2120c18ec02fSPetter Reinholdtsen 	if (!intf->opened && intf->open && intf->open(intf) < 0)
2121c18ec02fSPetter Reinholdtsen 		return NULL;
2122c18ec02fSPetter Reinholdtsen 
2123c18ec02fSPetter Reinholdtsen 	/*
2124c18ec02fSPetter Reinholdtsen 	 * The session timeout is initialized in the above interface open,
2125c18ec02fSPetter Reinholdtsen 	 * so it will only be valid after the open completes.
2126c18ec02fSPetter Reinholdtsen 	 */
2127c18ec02fSPetter Reinholdtsen 	saved_timeout = session->timeout;
2128c18ec02fSPetter Reinholdtsen 	while (try < session->retry) {
2129c18ec02fSPetter Reinholdtsen 		//ltime = time(NULL);
2130c18ec02fSPetter Reinholdtsen 
2131c18ec02fSPetter Reinholdtsen 		if (xmit) {
2132c18ec02fSPetter Reinholdtsen 			ltime = time(NULL);
2133c18ec02fSPetter Reinholdtsen 
2134c18ec02fSPetter Reinholdtsen 			if (payload->payload_type == IPMI_PAYLOAD_TYPE_IPMI)
2135c18ec02fSPetter Reinholdtsen 			{
2136c18ec02fSPetter Reinholdtsen 				/*
2137c18ec02fSPetter Reinholdtsen 				 * Build an IPMI v1.5 or v2 command
2138c18ec02fSPetter Reinholdtsen 				 */
2139c18ec02fSPetter Reinholdtsen 				struct ipmi_rq * ipmi_request = payload->payload.ipmi_request.request;
2140c18ec02fSPetter Reinholdtsen 
2141c18ec02fSPetter Reinholdtsen 				lprintf(LOG_DEBUG, "");
2142c18ec02fSPetter Reinholdtsen 				lprintf(LOG_DEBUG, ">> Sending IPMI command payload");
2143c18ec02fSPetter Reinholdtsen 				lprintf(LOG_DEBUG, ">>    netfn   : 0x%02x", ipmi_request->msg.netfn);
2144c18ec02fSPetter Reinholdtsen 				lprintf(LOG_DEBUG, ">>    command : 0x%02x", ipmi_request->msg.cmd);
2145c18ec02fSPetter Reinholdtsen 
2146c18ec02fSPetter Reinholdtsen 				if (verbose > 1)
2147c18ec02fSPetter Reinholdtsen 				{
2148c18ec02fSPetter Reinholdtsen 					uint16_t i;
2149c18ec02fSPetter Reinholdtsen 					fprintf(stderr, ">>    data    : ");
2150c18ec02fSPetter Reinholdtsen 					for (i = 0; i < ipmi_request->msg.data_len; ++i)
2151c18ec02fSPetter Reinholdtsen 						fprintf(stderr, "0x%02x ", ipmi_request->msg.data[i]);
2152c18ec02fSPetter Reinholdtsen 					fprintf(stderr, "\n\n");
2153c18ec02fSPetter Reinholdtsen 				}
2154c18ec02fSPetter Reinholdtsen 
2155c18ec02fSPetter Reinholdtsen 
2156c18ec02fSPetter Reinholdtsen 				/*
2157c18ec02fSPetter Reinholdtsen 				 * If we are presession, and the command is GET CHANNEL AUTHENTICATION
2158c18ec02fSPetter Reinholdtsen 				 * CAPABILITIES, we will build the command in v1.5 format.  This is so
2159c18ec02fSPetter Reinholdtsen 				 * that we can ask any server whether it supports IPMI v2 / RMCP+
2160c18ec02fSPetter Reinholdtsen 				 * before we attempt to open a v2.x session.
2161c18ec02fSPetter Reinholdtsen 				 */
2162c18ec02fSPetter Reinholdtsen 				if ((ipmi_request->msg.netfn == IPMI_NETFN_APP) &&
2163c18ec02fSPetter Reinholdtsen 					 (ipmi_request->msg.cmd   == IPMI_GET_CHANNEL_AUTH_CAP) &&
2164c18ec02fSPetter Reinholdtsen 					 (session->v2_data.bmc_id  == 0)) // jme - check
2165c18ec02fSPetter Reinholdtsen 				{
2166c18ec02fSPetter Reinholdtsen 					lprintf(LOG_DEBUG+1, "BUILDING A v1.5 COMMAND");
2167c18ec02fSPetter Reinholdtsen 					entry = ipmi_lanplus_build_v15_ipmi_cmd(intf, ipmi_request);
2168c18ec02fSPetter Reinholdtsen 				}
2169c18ec02fSPetter Reinholdtsen 				else
2170c18ec02fSPetter Reinholdtsen 				{
2171c18ec02fSPetter Reinholdtsen 					int isRetry = ( try > 0 ? 1 : 0 );
2172c18ec02fSPetter Reinholdtsen 
2173c18ec02fSPetter Reinholdtsen 					lprintf(LOG_DEBUG+1, "BUILDING A v2 COMMAND");
2174c18ec02fSPetter Reinholdtsen 					entry = ipmi_lanplus_build_v2x_ipmi_cmd(intf, ipmi_request, isRetry);
2175c18ec02fSPetter Reinholdtsen 				}
2176c18ec02fSPetter Reinholdtsen 
2177c18ec02fSPetter Reinholdtsen 				if (entry == NULL) {
2178c18ec02fSPetter Reinholdtsen 					lprintf(LOG_ERR, "Aborting send command, unable to build");
2179c18ec02fSPetter Reinholdtsen 					return NULL;
2180c18ec02fSPetter Reinholdtsen 				}
2181c18ec02fSPetter Reinholdtsen 
2182c18ec02fSPetter Reinholdtsen 				msg_data   = entry->msg_data;
2183c18ec02fSPetter Reinholdtsen 				msg_length = entry->msg_len;
2184c18ec02fSPetter Reinholdtsen 			}
2185c18ec02fSPetter Reinholdtsen 
2186c18ec02fSPetter Reinholdtsen 			else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST)
2187c18ec02fSPetter Reinholdtsen 			{
2188c18ec02fSPetter Reinholdtsen 				lprintf(LOG_DEBUG, ">> SENDING AN OPEN SESSION REQUEST\n");
2189c18ec02fSPetter Reinholdtsen 				assert(session->v2_data.session_state == LANPLUS_STATE_PRESESSION
2190c18ec02fSPetter Reinholdtsen 						|| session->v2_data.session_state == LANPLUS_STATE_OPEN_SESSION_SENT);
2191c18ec02fSPetter Reinholdtsen 
2192c18ec02fSPetter Reinholdtsen 				ipmi_lanplus_build_v2x_msg(intf,        /* in  */
2193c18ec02fSPetter Reinholdtsen 								payload,     /* in  */
2194c18ec02fSPetter Reinholdtsen 								&msg_length, /* out */
2195c18ec02fSPetter Reinholdtsen 								&msg_data,   /* out */
2196c18ec02fSPetter Reinholdtsen 								0);  /* irrelevant for this msg*/
2197c18ec02fSPetter Reinholdtsen 
2198c18ec02fSPetter Reinholdtsen 			}
2199c18ec02fSPetter Reinholdtsen 
2200c18ec02fSPetter Reinholdtsen 			else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RAKP_1)
2201c18ec02fSPetter Reinholdtsen 			{
2202c18ec02fSPetter Reinholdtsen 				lprintf(LOG_DEBUG, ">> SENDING A RAKP 1 MESSAGE\n");
2203c18ec02fSPetter Reinholdtsen 				assert(session->v2_data.session_state ==
2204c18ec02fSPetter Reinholdtsen 						 LANPLUS_STATE_OPEN_SESSION_RECEIEVED);
2205c18ec02fSPetter Reinholdtsen 
2206c18ec02fSPetter Reinholdtsen 				ipmi_lanplus_build_v2x_msg(intf,        /* in  */
2207c18ec02fSPetter Reinholdtsen 								payload,     /* in  */
2208c18ec02fSPetter Reinholdtsen 								&msg_length, /* out */
2209c18ec02fSPetter Reinholdtsen 								&msg_data,   /* out */
2210c18ec02fSPetter Reinholdtsen 								0);  /* irrelevant for this msg*/
2211c18ec02fSPetter Reinholdtsen 
2212c18ec02fSPetter Reinholdtsen 			}
2213c18ec02fSPetter Reinholdtsen 
2214c18ec02fSPetter Reinholdtsen 			else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RAKP_3)
2215c18ec02fSPetter Reinholdtsen 			{
2216c18ec02fSPetter Reinholdtsen 				lprintf(LOG_DEBUG, ">> SENDING A RAKP 3 MESSAGE\n");
2217c18ec02fSPetter Reinholdtsen 				assert(session->v2_data.session_state ==
2218c18ec02fSPetter Reinholdtsen 						 LANPLUS_STATE_RAKP_2_RECEIVED);
2219c18ec02fSPetter Reinholdtsen 
2220c18ec02fSPetter Reinholdtsen 				ipmi_lanplus_build_v2x_msg(intf,        /* in  */
2221c18ec02fSPetter Reinholdtsen 								payload,     /* in  */
2222c18ec02fSPetter Reinholdtsen 								&msg_length, /* out */
2223c18ec02fSPetter Reinholdtsen 								&msg_data,   /* out */
2224c18ec02fSPetter Reinholdtsen 								0);  /* irrelevant for this msg*/
2225c18ec02fSPetter Reinholdtsen 
2226c18ec02fSPetter Reinholdtsen 			}
2227c18ec02fSPetter Reinholdtsen 
2228c18ec02fSPetter Reinholdtsen 			else if (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL)
2229c18ec02fSPetter Reinholdtsen 			{
2230c18ec02fSPetter Reinholdtsen 				lprintf(LOG_DEBUG, ">> SENDING A SOL MESSAGE\n");
2231c18ec02fSPetter Reinholdtsen 				assert(session->v2_data.session_state == LANPLUS_STATE_ACTIVE);
2232c18ec02fSPetter Reinholdtsen 
2233c18ec02fSPetter Reinholdtsen 				ipmi_lanplus_build_v2x_msg(intf,        /* in  */
2234c18ec02fSPetter Reinholdtsen 								payload,     /* in  */
2235c18ec02fSPetter Reinholdtsen 								&msg_length, /* out */
2236c18ec02fSPetter Reinholdtsen 								&msg_data,   /* out */
2237c18ec02fSPetter Reinholdtsen 								0);  /* irrelevant for this msg*/
2238c18ec02fSPetter Reinholdtsen 			}
2239c18ec02fSPetter Reinholdtsen 
2240c18ec02fSPetter Reinholdtsen 			else
2241c18ec02fSPetter Reinholdtsen 			{
2242c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "Payload type 0x%0x is unsupported!",
2243c18ec02fSPetter Reinholdtsen 					payload->payload_type);
2244c18ec02fSPetter Reinholdtsen 				assert(0);
2245c18ec02fSPetter Reinholdtsen 			}
2246c18ec02fSPetter Reinholdtsen 
2247c18ec02fSPetter Reinholdtsen 
2248c18ec02fSPetter Reinholdtsen 			if (ipmi_lan_send_packet(intf, msg_data, msg_length) < 0) {
2249c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "IPMI LAN send command failed");
2250c18ec02fSPetter Reinholdtsen 				return NULL;
2251c18ec02fSPetter Reinholdtsen 			}
2252c18ec02fSPetter Reinholdtsen 		}
2253c18ec02fSPetter Reinholdtsen 
2254c18ec02fSPetter Reinholdtsen 		/* if we are set to noanswer we do not expect response */
2255c18ec02fSPetter Reinholdtsen 		if (intf->noanswer)
2256c18ec02fSPetter Reinholdtsen 			break;
2257c18ec02fSPetter Reinholdtsen 
2258c18ec02fSPetter Reinholdtsen 		usleep(100); 			/* Not sure what this is for */
2259c18ec02fSPetter Reinholdtsen 
2260c18ec02fSPetter Reinholdtsen 		/* Remember our connection state */
2261c18ec02fSPetter Reinholdtsen 		switch (payload->payload_type)
2262c18ec02fSPetter Reinholdtsen 		{
2263c18ec02fSPetter Reinholdtsen 		case IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST:
2264c18ec02fSPetter Reinholdtsen 			session->v2_data.session_state = LANPLUS_STATE_OPEN_SESSION_SENT;
2265176774cfSZdenek Styblik 			/* not retryable for timeouts, force no retry */
2266176774cfSZdenek Styblik 			try = session->retry;
2267c18ec02fSPetter Reinholdtsen 			break;
2268c18ec02fSPetter Reinholdtsen 		case IPMI_PAYLOAD_TYPE_RAKP_1:
2269c18ec02fSPetter Reinholdtsen 			session->v2_data.session_state = LANPLUS_STATE_RAKP_1_SENT;
2270176774cfSZdenek Styblik 			/* not retryable for timeouts, force no retry */
2271176774cfSZdenek Styblik 			try = session->retry;
2272c18ec02fSPetter Reinholdtsen 			break;
2273c18ec02fSPetter Reinholdtsen 		case IPMI_PAYLOAD_TYPE_RAKP_3:
2274176774cfSZdenek Styblik 			/* not retryable for timeouts, force no retry */
2275176774cfSZdenek Styblik 			try = session->retry;
2276c18ec02fSPetter Reinholdtsen 			session->v2_data.session_state = LANPLUS_STATE_RAKP_3_SENT;
2277c18ec02fSPetter Reinholdtsen 			break;
2278c18ec02fSPetter Reinholdtsen 		}
2279c18ec02fSPetter Reinholdtsen 
2280c18ec02fSPetter Reinholdtsen 
2281c18ec02fSPetter Reinholdtsen 		/*
2282c18ec02fSPetter Reinholdtsen 		 * Special case for SOL outbound packets.
2283c18ec02fSPetter Reinholdtsen 		 */
2284c18ec02fSPetter Reinholdtsen 		if (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL)
2285c18ec02fSPetter Reinholdtsen 		{
2286c18ec02fSPetter Reinholdtsen 			if (! payload->payload.sol_packet.packet_sequence_number)
2287c18ec02fSPetter Reinholdtsen 			{
2288c18ec02fSPetter Reinholdtsen 				/* We're just sending an ACK.  No need to retry. */
2289c18ec02fSPetter Reinholdtsen 				break;
2290c18ec02fSPetter Reinholdtsen 			}
2291c18ec02fSPetter Reinholdtsen 
2292c18ec02fSPetter Reinholdtsen 
2293c18ec02fSPetter Reinholdtsen 			rsp = ipmi_lanplus_recv_sol(intf); /* Grab the next packet */
2294c18ec02fSPetter Reinholdtsen 
2295c18ec02fSPetter Reinholdtsen 			if (sol_response_acks_packet(rsp, payload))
2296c18ec02fSPetter Reinholdtsen 				break;
2297c18ec02fSPetter Reinholdtsen 
2298c18ec02fSPetter Reinholdtsen 			else if (is_sol_packet(rsp) && rsp->data_len)
2299c18ec02fSPetter Reinholdtsen 			{
2300c18ec02fSPetter Reinholdtsen 				/*
2301c18ec02fSPetter Reinholdtsen 				 * We're still waiting for our ACK, but we more data from
2302c18ec02fSPetter Reinholdtsen 				 * the BMC
2303c18ec02fSPetter Reinholdtsen 				 */
2304c18ec02fSPetter Reinholdtsen 				intf->session->sol_data.sol_input_handler(rsp);
2305c18ec02fSPetter Reinholdtsen 				/* In order to avoid duplicate output, just set data_len to 0 */
2306c18ec02fSPetter Reinholdtsen 				rsp->data_len = 0;
2307c18ec02fSPetter Reinholdtsen 			}
2308c18ec02fSPetter Reinholdtsen 		}
2309c18ec02fSPetter Reinholdtsen 
2310c18ec02fSPetter Reinholdtsen 
2311c18ec02fSPetter Reinholdtsen 		/* Non-SOL processing */
2312c18ec02fSPetter Reinholdtsen 		else
2313c18ec02fSPetter Reinholdtsen 		{
2314c18ec02fSPetter Reinholdtsen 			rsp = ipmi_lan_poll_recv(intf);
2315c18ec02fSPetter Reinholdtsen 
2316c18ec02fSPetter Reinholdtsen 			/* Duplicate Request ccode most likely indicates a response to
2317c18ec02fSPetter Reinholdtsen 			   a previous retry. Ignore and keep polling. */
2318c18ec02fSPetter Reinholdtsen 			while ((rsp != NULL) && (rsp->ccode == 0xcf))
2319c18ec02fSPetter Reinholdtsen 			{
2320c18ec02fSPetter Reinholdtsen 				rsp = NULL;
2321c18ec02fSPetter Reinholdtsen 				rsp = ipmi_lan_poll_recv(intf);
2322c18ec02fSPetter Reinholdtsen 			}
2323c18ec02fSPetter Reinholdtsen 
2324c18ec02fSPetter Reinholdtsen 			if (rsp)
2325c18ec02fSPetter Reinholdtsen 				break;
2326176774cfSZdenek Styblik 			/* This payload type is retryable for timeouts. */
2327176774cfSZdenek Styblik 			if ((payload->payload_type == IPMI_PAYLOAD_TYPE_IPMI) && entry) {
2328176774cfSZdenek Styblik 				ipmi_req_remove_entry( entry->rq_seq, entry->req.msg.cmd);
2329176774cfSZdenek Styblik 			}
2330c18ec02fSPetter Reinholdtsen 		}
2331c18ec02fSPetter Reinholdtsen 
2332c18ec02fSPetter Reinholdtsen 		/* only timeout if time exceeds the timeout value */
2333c18ec02fSPetter Reinholdtsen 		xmit = ((time(NULL) - ltime) >= session->timeout);
2334c18ec02fSPetter Reinholdtsen 
2335c18ec02fSPetter Reinholdtsen 		usleep(5000);
2336c18ec02fSPetter Reinholdtsen 
2337c18ec02fSPetter Reinholdtsen 		if (xmit) {
2338c18ec02fSPetter Reinholdtsen 			/* increment session timeout by 1 second each retry */
2339c18ec02fSPetter Reinholdtsen 			session->timeout++;
2340c18ec02fSPetter Reinholdtsen 		}
2341c18ec02fSPetter Reinholdtsen 
2342c18ec02fSPetter Reinholdtsen 		try++;
2343c18ec02fSPetter Reinholdtsen 	}
2344c18ec02fSPetter Reinholdtsen 	session->timeout = saved_timeout;
2345c18ec02fSPetter Reinholdtsen 
2346c18ec02fSPetter Reinholdtsen 	/* IPMI messages are deleted under ipmi_lan_poll_recv() */
2347c18ec02fSPetter Reinholdtsen 	switch (payload->payload_type) {
2348c18ec02fSPetter Reinholdtsen 	case IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST:
2349c18ec02fSPetter Reinholdtsen 	case IPMI_PAYLOAD_TYPE_RAKP_1:
2350c18ec02fSPetter Reinholdtsen 	case IPMI_PAYLOAD_TYPE_RAKP_3:
2351c18ec02fSPetter Reinholdtsen 		free(msg_data);
2352c18ec02fSPetter Reinholdtsen 		msg_data = NULL;
2353c18ec02fSPetter Reinholdtsen 		break;
2354c18ec02fSPetter Reinholdtsen 	}
2355c18ec02fSPetter Reinholdtsen 
2356c18ec02fSPetter Reinholdtsen 	return rsp;
2357c18ec02fSPetter Reinholdtsen }
2358c18ec02fSPetter Reinholdtsen 
2359c18ec02fSPetter Reinholdtsen 
2360c18ec02fSPetter Reinholdtsen 
2361c18ec02fSPetter Reinholdtsen /*
2362c18ec02fSPetter Reinholdtsen  * is_sol_partial_ack
2363c18ec02fSPetter Reinholdtsen  *
2364c18ec02fSPetter Reinholdtsen  * Determine if the response is a partial ACK/NACK that indicates
2365c18ec02fSPetter Reinholdtsen  * we need to resend part of our packet.
2366c18ec02fSPetter Reinholdtsen  *
2367c18ec02fSPetter Reinholdtsen  * returns the number of characters we need to resend, or
2368c18ec02fSPetter Reinholdtsen  *         0 if this isn't an ACK or we don't need to resend anything
2369c18ec02fSPetter Reinholdtsen  */
2370c18ec02fSPetter Reinholdtsen int is_sol_partial_ack(
2371c18ec02fSPetter Reinholdtsen 						struct ipmi_intf       * intf,
2372c18ec02fSPetter Reinholdtsen 						struct ipmi_v2_payload * v2_payload,
2373c18ec02fSPetter Reinholdtsen 						struct ipmi_rs         * rs)
2374c18ec02fSPetter Reinholdtsen {
2375c18ec02fSPetter Reinholdtsen 	int chars_to_resend = 0;
2376c18ec02fSPetter Reinholdtsen 
2377c18ec02fSPetter Reinholdtsen 	if (v2_payload                               &&
2378c18ec02fSPetter Reinholdtsen 		rs                                       &&
2379c18ec02fSPetter Reinholdtsen 		is_sol_packet(rs)                        &&
2380c18ec02fSPetter Reinholdtsen 		sol_response_acks_packet(rs, v2_payload) &&
2381c18ec02fSPetter Reinholdtsen 		(rs->payload.sol_packet.accepted_character_count <
2382c18ec02fSPetter Reinholdtsen 		 v2_payload->payload.sol_packet.character_count))
2383c18ec02fSPetter Reinholdtsen 	{
2384c18ec02fSPetter Reinholdtsen 		if (ipmi_oem_active(intf, "intelplus") &&
2385c18ec02fSPetter Reinholdtsen 			 rs->payload.sol_packet.accepted_character_count == 0)
2386c18ec02fSPetter Reinholdtsen 			return 0;
2387c18ec02fSPetter Reinholdtsen 
2388c18ec02fSPetter Reinholdtsen 		chars_to_resend =
2389c18ec02fSPetter Reinholdtsen 			v2_payload->payload.sol_packet.character_count -
2390c18ec02fSPetter Reinholdtsen 			rs->payload.sol_packet.accepted_character_count;
2391c18ec02fSPetter Reinholdtsen 	}
2392c18ec02fSPetter Reinholdtsen 
2393c18ec02fSPetter Reinholdtsen 	return chars_to_resend;
2394c18ec02fSPetter Reinholdtsen }
2395c18ec02fSPetter Reinholdtsen 
2396c18ec02fSPetter Reinholdtsen 
2397c18ec02fSPetter Reinholdtsen 
2398c18ec02fSPetter Reinholdtsen /*
2399c18ec02fSPetter Reinholdtsen  * set_sol_packet_sequence_number
2400c18ec02fSPetter Reinholdtsen  */
2401c18ec02fSPetter Reinholdtsen static void set_sol_packet_sequence_number(
2402c18ec02fSPetter Reinholdtsen 											struct ipmi_intf * intf,
2403c18ec02fSPetter Reinholdtsen 											struct ipmi_v2_payload * v2_payload)
2404c18ec02fSPetter Reinholdtsen {
2405c18ec02fSPetter Reinholdtsen 	/* Keep our sequence number sane */
2406c18ec02fSPetter Reinholdtsen 	if (intf->session->sol_data.sequence_number > 0x0F)
2407c18ec02fSPetter Reinholdtsen 		intf->session->sol_data.sequence_number = 1;
2408c18ec02fSPetter Reinholdtsen 
2409c18ec02fSPetter Reinholdtsen 	v2_payload->payload.sol_packet.packet_sequence_number =
2410c18ec02fSPetter Reinholdtsen 		intf->session->sol_data.sequence_number++;
2411c18ec02fSPetter Reinholdtsen }
2412c18ec02fSPetter Reinholdtsen 
2413c18ec02fSPetter Reinholdtsen 
2414c18ec02fSPetter Reinholdtsen 
2415c18ec02fSPetter Reinholdtsen /*
2416c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_send_sol
2417c18ec02fSPetter Reinholdtsen  *
2418c18ec02fSPetter Reinholdtsen  * Sends a SOL packet..  We handle partial ACK/NACKs from the BMC here.
2419c18ec02fSPetter Reinholdtsen  *
2420c18ec02fSPetter Reinholdtsen  * Returns a pointer to the SOL ACK we received, or
2421c18ec02fSPetter Reinholdtsen  *         0 on failure
2422c18ec02fSPetter Reinholdtsen  *
2423c18ec02fSPetter Reinholdtsen  */
2424c18ec02fSPetter Reinholdtsen struct ipmi_rs *
2425c18ec02fSPetter Reinholdtsen ipmi_lanplus_send_sol(
2426c18ec02fSPetter Reinholdtsen 					  struct ipmi_intf * intf,
2427c18ec02fSPetter Reinholdtsen 					  struct ipmi_v2_payload * v2_payload)
2428c18ec02fSPetter Reinholdtsen {
2429c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rs;
2430c18ec02fSPetter Reinholdtsen 
2431c18ec02fSPetter Reinholdtsen 	/*
2432c18ec02fSPetter Reinholdtsen 	 * chars_to_resend indicates either that we got a NACK telling us
2433c18ec02fSPetter Reinholdtsen 	 * that we need to resend some part of our data.
2434c18ec02fSPetter Reinholdtsen 	 */
2435c18ec02fSPetter Reinholdtsen 	int chars_to_resend = 0;
2436c18ec02fSPetter Reinholdtsen 
2437c18ec02fSPetter Reinholdtsen 	v2_payload->payload_type   = IPMI_PAYLOAD_TYPE_SOL;
2438c18ec02fSPetter Reinholdtsen 
2439c18ec02fSPetter Reinholdtsen 	/*
2440c18ec02fSPetter Reinholdtsen 	 * Payload length is just the length of the character
2441c18ec02fSPetter Reinholdtsen 	 * data here.
2442c18ec02fSPetter Reinholdtsen 	 */
2443c18ec02fSPetter Reinholdtsen 	v2_payload->payload_length = v2_payload->payload.sol_packet.character_count;
2444c18ec02fSPetter Reinholdtsen 
2445c18ec02fSPetter Reinholdtsen 	v2_payload->payload.sol_packet.acked_packet_number = 0; /* NA */
2446c18ec02fSPetter Reinholdtsen 
2447c18ec02fSPetter Reinholdtsen 	set_sol_packet_sequence_number(intf, v2_payload);
2448c18ec02fSPetter Reinholdtsen 
2449c18ec02fSPetter Reinholdtsen 	v2_payload->payload.sol_packet.accepted_character_count = 0; /* NA */
2450c18ec02fSPetter Reinholdtsen 
2451c18ec02fSPetter Reinholdtsen 	rs = ipmi_lanplus_send_payload(intf, v2_payload);
2452c18ec02fSPetter Reinholdtsen 
2453c18ec02fSPetter Reinholdtsen 	/* Determine if we need to resend some of our data */
2454c18ec02fSPetter Reinholdtsen 	chars_to_resend = is_sol_partial_ack(intf, v2_payload, rs);
2455c18ec02fSPetter Reinholdtsen 
2456c18ec02fSPetter Reinholdtsen 	while (rs && !rs->payload.sol_packet.transfer_unavailable &&
2457c18ec02fSPetter Reinholdtsen 			 !rs->payload.sol_packet.is_nack &&
2458c18ec02fSPetter Reinholdtsen 			 chars_to_resend)
2459c18ec02fSPetter Reinholdtsen 	{
2460c18ec02fSPetter Reinholdtsen 		/*
2461c18ec02fSPetter Reinholdtsen 		 * We first need to handle any new data we might have
2462c18ec02fSPetter Reinholdtsen 		 * received in our NACK
2463c18ec02fSPetter Reinholdtsen 		 */
2464c18ec02fSPetter Reinholdtsen 		if (rs->data_len)
2465c18ec02fSPetter Reinholdtsen 			intf->session->sol_data.sol_input_handler(rs);
2466c18ec02fSPetter Reinholdtsen 
2467c18ec02fSPetter Reinholdtsen 		set_sol_packet_sequence_number(intf, v2_payload);
2468c18ec02fSPetter Reinholdtsen 
2469c18ec02fSPetter Reinholdtsen 		/* Just send the required data */
2470c18ec02fSPetter Reinholdtsen 		memmove(v2_payload->payload.sol_packet.data,
2471c18ec02fSPetter Reinholdtsen 				v2_payload->payload.sol_packet.data +
2472c18ec02fSPetter Reinholdtsen 				rs->payload.sol_packet.accepted_character_count,
2473c18ec02fSPetter Reinholdtsen 				chars_to_resend);
2474c18ec02fSPetter Reinholdtsen 
2475c18ec02fSPetter Reinholdtsen 		v2_payload->payload.sol_packet.character_count = chars_to_resend;
2476c18ec02fSPetter Reinholdtsen 
2477c18ec02fSPetter Reinholdtsen 		v2_payload->payload_length = v2_payload->payload.sol_packet.character_count;
2478c18ec02fSPetter Reinholdtsen 
2479c18ec02fSPetter Reinholdtsen 		rs = ipmi_lanplus_send_payload(intf, v2_payload);
2480c18ec02fSPetter Reinholdtsen 
2481c18ec02fSPetter Reinholdtsen 		chars_to_resend = is_sol_partial_ack(intf, v2_payload, rs);
2482c18ec02fSPetter Reinholdtsen 	}
2483c18ec02fSPetter Reinholdtsen 
2484c18ec02fSPetter Reinholdtsen 	return rs;
2485c18ec02fSPetter Reinholdtsen }
2486c18ec02fSPetter Reinholdtsen 
2487c18ec02fSPetter Reinholdtsen 
2488c18ec02fSPetter Reinholdtsen 
2489c18ec02fSPetter Reinholdtsen /*
2490c18ec02fSPetter Reinholdtsen  * check_sol_packet_for_new_data
2491c18ec02fSPetter Reinholdtsen  *
2492c18ec02fSPetter Reinholdtsen  * Determine whether the SOL packet has already been seen
2493c18ec02fSPetter Reinholdtsen  * and whether the packet has new data for us.
2494c18ec02fSPetter Reinholdtsen  *
2495c18ec02fSPetter Reinholdtsen  * This function has the side effect of removing an previously
2496c18ec02fSPetter Reinholdtsen  * seen data, and moving new data to the front.
2497c18ec02fSPetter Reinholdtsen  *
2498c18ec02fSPetter Reinholdtsen  * It also "Remembers" the data so we don't get repeats.
2499c18ec02fSPetter Reinholdtsen  *
2500c18ec02fSPetter Reinholdtsen  * returns the number of new bytes in the SOL packet
2501c18ec02fSPetter Reinholdtsen  */
2502c18ec02fSPetter Reinholdtsen static int
2503c18ec02fSPetter Reinholdtsen check_sol_packet_for_new_data(
2504c18ec02fSPetter Reinholdtsen 							  struct ipmi_intf * intf,
2505c18ec02fSPetter Reinholdtsen 							  struct ipmi_rs *rsp)
2506c18ec02fSPetter Reinholdtsen {
2507c18ec02fSPetter Reinholdtsen 	static uint8_t last_received_sequence_number = 0;
2508c18ec02fSPetter Reinholdtsen 	static uint8_t last_received_byte_count      = 0;
2509c18ec02fSPetter Reinholdtsen 	int new_data_size                                  = 0;
2510c18ec02fSPetter Reinholdtsen 
2511c18ec02fSPetter Reinholdtsen 
2512c18ec02fSPetter Reinholdtsen 	if (rsp &&
2513c18ec02fSPetter Reinholdtsen 		(rsp->session.authtype    == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
2514c18ec02fSPetter Reinholdtsen 		(rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL))
2515c18ec02fSPetter Reinholdtsen 	{
2516c18ec02fSPetter Reinholdtsen 		/* Store the data length before we mod it */
2517c18ec02fSPetter Reinholdtsen 		uint8_t unaltered_data_len = rsp->data_len;
2518c18ec02fSPetter Reinholdtsen 
2519c18ec02fSPetter Reinholdtsen 		if (rsp->payload.sol_packet.packet_sequence_number ==
2520c18ec02fSPetter Reinholdtsen 			last_received_sequence_number)
2521c18ec02fSPetter Reinholdtsen 		{
2522c18ec02fSPetter Reinholdtsen 
2523c18ec02fSPetter Reinholdtsen 			/*
2524c18ec02fSPetter Reinholdtsen 			 * This is the same as the last packet, but may include
2525c18ec02fSPetter Reinholdtsen 			 * extra data
2526c18ec02fSPetter Reinholdtsen 			 */
2527c18ec02fSPetter Reinholdtsen 			new_data_size = rsp->data_len - last_received_byte_count;
2528c18ec02fSPetter Reinholdtsen 
2529c18ec02fSPetter Reinholdtsen 			if (new_data_size > 0)
2530c18ec02fSPetter Reinholdtsen 			{
2531c18ec02fSPetter Reinholdtsen 				/* We have more data to process */
2532c18ec02fSPetter Reinholdtsen 				memmove(rsp->data,
2533c18ec02fSPetter Reinholdtsen 						rsp->data +
2534c18ec02fSPetter Reinholdtsen 						rsp->data_len - new_data_size,
2535c18ec02fSPetter Reinholdtsen 						new_data_size);
2536c18ec02fSPetter Reinholdtsen 			}
2537c18ec02fSPetter Reinholdtsen 
2538c18ec02fSPetter Reinholdtsen 			rsp->data_len = new_data_size;
2539c18ec02fSPetter Reinholdtsen 		}
2540c18ec02fSPetter Reinholdtsen 
2541c18ec02fSPetter Reinholdtsen 
2542c18ec02fSPetter Reinholdtsen 		/*
2543c18ec02fSPetter Reinholdtsen 		 *Rember the data for next round
2544c18ec02fSPetter Reinholdtsen 		 */
2545c18ec02fSPetter Reinholdtsen 		if (rsp->payload.sol_packet.packet_sequence_number)
2546c18ec02fSPetter Reinholdtsen 		{
2547c18ec02fSPetter Reinholdtsen 			last_received_sequence_number =
2548c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.packet_sequence_number;
2549c18ec02fSPetter Reinholdtsen 
2550c18ec02fSPetter Reinholdtsen 			last_received_byte_count = unaltered_data_len;
2551c18ec02fSPetter Reinholdtsen 		}
2552c18ec02fSPetter Reinholdtsen 	}
2553c18ec02fSPetter Reinholdtsen 
2554c18ec02fSPetter Reinholdtsen 
2555c18ec02fSPetter Reinholdtsen 	return new_data_size;
2556c18ec02fSPetter Reinholdtsen }
2557c18ec02fSPetter Reinholdtsen 
2558c18ec02fSPetter Reinholdtsen 
2559c18ec02fSPetter Reinholdtsen 
2560c18ec02fSPetter Reinholdtsen /*
2561c18ec02fSPetter Reinholdtsen  * ack_sol_packet
2562c18ec02fSPetter Reinholdtsen  *
2563c18ec02fSPetter Reinholdtsen  * Provided the specified packet looks reasonable, ACK it.
2564c18ec02fSPetter Reinholdtsen  */
2565c18ec02fSPetter Reinholdtsen static void
2566c18ec02fSPetter Reinholdtsen ack_sol_packet(
2567c18ec02fSPetter Reinholdtsen 				struct ipmi_intf * intf,
2568c18ec02fSPetter Reinholdtsen 				struct ipmi_rs * rsp)
2569c18ec02fSPetter Reinholdtsen {
2570c18ec02fSPetter Reinholdtsen 	if (rsp                                                           &&
2571c18ec02fSPetter Reinholdtsen 		(rsp->session.authtype    == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
2572c18ec02fSPetter Reinholdtsen 		(rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)           &&
2573c18ec02fSPetter Reinholdtsen 		(rsp->payload.sol_packet.packet_sequence_number))
2574c18ec02fSPetter Reinholdtsen 	{
2575c18ec02fSPetter Reinholdtsen 		struct ipmi_v2_payload ack;
2576c18ec02fSPetter Reinholdtsen 
2577*d9f89a8dSZdenek Styblik 		memset(&ack, 0, sizeof(struct ipmi_v2_payload));
2578c18ec02fSPetter Reinholdtsen 
2579c18ec02fSPetter Reinholdtsen 		ack.payload_type   = IPMI_PAYLOAD_TYPE_SOL;
2580c18ec02fSPetter Reinholdtsen 
2581c18ec02fSPetter Reinholdtsen 		/*
2582c18ec02fSPetter Reinholdtsen 		 * Payload length is just the length of the character
2583c18ec02fSPetter Reinholdtsen 		 * data here.
2584c18ec02fSPetter Reinholdtsen 		 */
2585c18ec02fSPetter Reinholdtsen 		ack.payload_length = 0;
2586c18ec02fSPetter Reinholdtsen 
2587c18ec02fSPetter Reinholdtsen 		/* ACK packets have sequence numbers of 0 */
2588c18ec02fSPetter Reinholdtsen 		ack.payload.sol_packet.packet_sequence_number = 0;
2589c18ec02fSPetter Reinholdtsen 
2590c18ec02fSPetter Reinholdtsen 		ack.payload.sol_packet.acked_packet_number =
2591c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.packet_sequence_number;
2592c18ec02fSPetter Reinholdtsen 
2593c18ec02fSPetter Reinholdtsen 		ack.payload.sol_packet.accepted_character_count = rsp->data_len;
2594c18ec02fSPetter Reinholdtsen 
2595c18ec02fSPetter Reinholdtsen 		ipmi_lanplus_send_payload(intf, &ack);
2596c18ec02fSPetter Reinholdtsen 	}
2597c18ec02fSPetter Reinholdtsen }
2598c18ec02fSPetter Reinholdtsen 
2599c18ec02fSPetter Reinholdtsen 
2600c18ec02fSPetter Reinholdtsen 
2601c18ec02fSPetter Reinholdtsen /*
2602c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_recv_sol
2603c18ec02fSPetter Reinholdtsen  *
2604c18ec02fSPetter Reinholdtsen  * Receive a SOL packet and send an ACK in response.
2605c18ec02fSPetter Reinholdtsen  *
2606c18ec02fSPetter Reinholdtsen  */
2607c18ec02fSPetter Reinholdtsen struct ipmi_rs *
2608c18ec02fSPetter Reinholdtsen ipmi_lanplus_recv_sol(struct ipmi_intf * intf)
2609c18ec02fSPetter Reinholdtsen {
2610c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp = ipmi_lan_poll_recv(intf);
2611c18ec02fSPetter Reinholdtsen 
2612c18ec02fSPetter Reinholdtsen 	if (rsp && rsp->session.authtype != 0)
2613c18ec02fSPetter Reinholdtsen 	{
2614c18ec02fSPetter Reinholdtsen 		ack_sol_packet(intf, rsp);
2615c18ec02fSPetter Reinholdtsen 
2616c18ec02fSPetter Reinholdtsen 		/*
2617c18ec02fSPetter Reinholdtsen 		 * Remembers the data sent, and alters the data to just
2618c18ec02fSPetter Reinholdtsen 		 * include the new stuff.
2619c18ec02fSPetter Reinholdtsen 		 */
2620c18ec02fSPetter Reinholdtsen 		check_sol_packet_for_new_data(intf, rsp);
2621c18ec02fSPetter Reinholdtsen 	}
2622c18ec02fSPetter Reinholdtsen 	return rsp;
2623c18ec02fSPetter Reinholdtsen }
2624c18ec02fSPetter Reinholdtsen 
2625c18ec02fSPetter Reinholdtsen 
2626c18ec02fSPetter Reinholdtsen 
2627c18ec02fSPetter Reinholdtsen /**
2628c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_send_ipmi_cmd
2629c18ec02fSPetter Reinholdtsen  *
2630c18ec02fSPetter Reinholdtsen  * Build a payload request and dispatch it.
2631c18ec02fSPetter Reinholdtsen  */
2632c18ec02fSPetter Reinholdtsen struct ipmi_rs *
2633c18ec02fSPetter Reinholdtsen ipmi_lanplus_send_ipmi_cmd(
2634c18ec02fSPetter Reinholdtsen 							struct ipmi_intf * intf,
2635c18ec02fSPetter Reinholdtsen 							struct ipmi_rq * req)
2636c18ec02fSPetter Reinholdtsen {
2637c18ec02fSPetter Reinholdtsen 	struct ipmi_v2_payload v2_payload;
2638c18ec02fSPetter Reinholdtsen 
2639c18ec02fSPetter Reinholdtsen 	v2_payload.payload_type = IPMI_PAYLOAD_TYPE_IPMI;
2640c18ec02fSPetter Reinholdtsen 	v2_payload.payload.ipmi_request.request = req;
2641c18ec02fSPetter Reinholdtsen 
2642c18ec02fSPetter Reinholdtsen 	return ipmi_lanplus_send_payload(intf, &v2_payload);
2643c18ec02fSPetter Reinholdtsen }
2644c18ec02fSPetter Reinholdtsen 
2645c18ec02fSPetter Reinholdtsen 
2646c18ec02fSPetter Reinholdtsen /*
2647c18ec02fSPetter Reinholdtsen  * ipmi_get_auth_capabilities_cmd
2648c18ec02fSPetter Reinholdtsen  *
2649c18ec02fSPetter Reinholdtsen  * This command may have to be sent twice.  We first ask for the
2650c18ec02fSPetter Reinholdtsen  * authentication capabilities with the "request IPMI v2 data bit"
2651c18ec02fSPetter Reinholdtsen  * set.  If this fails, we send the same command without that bit
2652c18ec02fSPetter Reinholdtsen  * set.
2653c18ec02fSPetter Reinholdtsen  *
2654c18ec02fSPetter Reinholdtsen  * param intf is the initialized (but possibly) pre-session interface
2655c18ec02fSPetter Reinholdtsen  *       on which we will send the command
2656c18ec02fSPetter Reinholdtsen  * param auth_cap [out] will be initialized to hold the Get Channel
2657c18ec02fSPetter Reinholdtsen  *       Authentication Capabilities return data on success.  Its
2658c18ec02fSPetter Reinholdtsen  *       contents will be undefined on error.
2659c18ec02fSPetter Reinholdtsen  *
2660c18ec02fSPetter Reinholdtsen  * returns 0 on success
2661c18ec02fSPetter Reinholdtsen  *         non-zero if we were unable to contact the BMC, or we cannot
2662c18ec02fSPetter Reinholdtsen  *         get a successful response
2663c18ec02fSPetter Reinholdtsen  *
2664c18ec02fSPetter Reinholdtsen  */
2665c18ec02fSPetter Reinholdtsen static int
2666c18ec02fSPetter Reinholdtsen ipmi_get_auth_capabilities_cmd(
2667c18ec02fSPetter Reinholdtsen 								struct ipmi_intf * intf,
2668c18ec02fSPetter Reinholdtsen 								struct get_channel_auth_cap_rsp * auth_cap)
2669c18ec02fSPetter Reinholdtsen {
2670c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
2671c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
2672c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[2];
2673c18ec02fSPetter Reinholdtsen 	uint8_t backupBridgePossible;
2674c18ec02fSPetter Reinholdtsen 
2675c18ec02fSPetter Reinholdtsen 	backupBridgePossible = bridgePossible;
2676c18ec02fSPetter Reinholdtsen 
2677c18ec02fSPetter Reinholdtsen 	bridgePossible = 0;
2678c18ec02fSPetter Reinholdtsen 
2679c18ec02fSPetter Reinholdtsen 	msg_data[0] = IPMI_LAN_CHANNEL_E | 0x80; // Ask for IPMI v2 data as well
2680c18ec02fSPetter Reinholdtsen 	msg_data[1] = intf->session->privlvl;
2681c18ec02fSPetter Reinholdtsen 
2682c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
2683c18ec02fSPetter Reinholdtsen 	req.msg.netfn    = IPMI_NETFN_APP;            // 0x06
2684c18ec02fSPetter Reinholdtsen 	req.msg.cmd      = IPMI_GET_CHANNEL_AUTH_CAP; // 0x38
2685c18ec02fSPetter Reinholdtsen 	req.msg.data     = msg_data;
2686c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 2;
2687c18ec02fSPetter Reinholdtsen 
2688c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
2689c18ec02fSPetter Reinholdtsen 
2690c18ec02fSPetter Reinholdtsen 	if (rsp == NULL || rsp->ccode > 0) {
2691c18ec02fSPetter Reinholdtsen 		/*
2692c18ec02fSPetter Reinholdtsen 		 * It's very possible that this failed because we asked for IPMI
2693c18ec02fSPetter Reinholdtsen 		 * v2 data. Ask again, without requesting IPMI v2 data.
2694c18ec02fSPetter Reinholdtsen 		 */
2695c18ec02fSPetter Reinholdtsen 		msg_data[0] &= 0x7F;
2696c18ec02fSPetter Reinholdtsen 
2697c18ec02fSPetter Reinholdtsen 		rsp = intf->sendrecv(intf, &req);
2698c18ec02fSPetter Reinholdtsen 
2699c18ec02fSPetter Reinholdtsen 		if (rsp == NULL) {
2700c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO, "Get Auth Capabilities error");
2701c18ec02fSPetter Reinholdtsen 			return 1;
2702c18ec02fSPetter Reinholdtsen 		}
2703c18ec02fSPetter Reinholdtsen 		if (rsp->ccode > 0) {
2704c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO, "Get Auth Capabilities error: %s",
2705c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
2706c18ec02fSPetter Reinholdtsen 			return 1;
2707c18ec02fSPetter Reinholdtsen 		}
2708c18ec02fSPetter Reinholdtsen 	}
2709c18ec02fSPetter Reinholdtsen 
2710c18ec02fSPetter Reinholdtsen 
2711c18ec02fSPetter Reinholdtsen 	memcpy(auth_cap,
2712c18ec02fSPetter Reinholdtsen 			rsp->data,
2713c18ec02fSPetter Reinholdtsen 			sizeof(struct get_channel_auth_cap_rsp));
2714c18ec02fSPetter Reinholdtsen 
2715c18ec02fSPetter Reinholdtsen 	bridgePossible = backupBridgePossible;
2716c18ec02fSPetter Reinholdtsen 
2717c18ec02fSPetter Reinholdtsen 	return 0;
2718c18ec02fSPetter Reinholdtsen }
2719c18ec02fSPetter Reinholdtsen 
2720c18ec02fSPetter Reinholdtsen 
2721c18ec02fSPetter Reinholdtsen 
2722c18ec02fSPetter Reinholdtsen static int
2723c18ec02fSPetter Reinholdtsen ipmi_close_session_cmd(struct ipmi_intf * intf)
2724c18ec02fSPetter Reinholdtsen {
2725c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
2726c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
2727c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
2728c18ec02fSPetter Reinholdtsen 	uint32_t bmc_session_lsbf;
2729c18ec02fSPetter Reinholdtsen 	uint8_t backupBridgePossible;
2730c18ec02fSPetter Reinholdtsen 
2731c18ec02fSPetter Reinholdtsen 	if (intf->session->v2_data.session_state != LANPLUS_STATE_ACTIVE)
2732c18ec02fSPetter Reinholdtsen 		return -1;
2733c18ec02fSPetter Reinholdtsen 
2734c18ec02fSPetter Reinholdtsen 	backupBridgePossible = bridgePossible;
2735c18ec02fSPetter Reinholdtsen 
2736c18ec02fSPetter Reinholdtsen 	intf->target_addr = IPMI_BMC_SLAVE_ADDR;
2737c18ec02fSPetter Reinholdtsen 	bridgePossible = 0;
2738c18ec02fSPetter Reinholdtsen 
2739c18ec02fSPetter Reinholdtsen 	bmc_session_lsbf = intf->session->v2_data.bmc_id;
2740c18ec02fSPetter Reinholdtsen #if WORDS_BIGENDIAN
2741c18ec02fSPetter Reinholdtsen 	bmc_session_lsbf = BSWAP_32(bmc_session_lsbf);
2742c18ec02fSPetter Reinholdtsen #endif
2743c18ec02fSPetter Reinholdtsen 
2744c18ec02fSPetter Reinholdtsen 	memcpy(&msg_data, &bmc_session_lsbf, 4);
2745c18ec02fSPetter Reinholdtsen 
2746c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
2747c18ec02fSPetter Reinholdtsen 	req.msg.netfn		= IPMI_NETFN_APP;
2748c18ec02fSPetter Reinholdtsen 	req.msg.cmd		    = 0x3c;
2749c18ec02fSPetter Reinholdtsen 	req.msg.data		= msg_data;
2750c18ec02fSPetter Reinholdtsen 	req.msg.data_len	= 4;
2751c18ec02fSPetter Reinholdtsen 
2752c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
2753c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
2754c18ec02fSPetter Reinholdtsen 		/* Looks like the session was closed */
2755c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Close Session command failed");
2756c18ec02fSPetter Reinholdtsen 		return -1;
2757c18ec02fSPetter Reinholdtsen 	}
2758c18ec02fSPetter Reinholdtsen 	if (verbose > 2)
2759c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "close_session");
2760c18ec02fSPetter Reinholdtsen 
2761c18ec02fSPetter Reinholdtsen 	if (rsp->ccode == 0x87) {
2762c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Failed to Close Session: invalid "
2763c18ec02fSPetter Reinholdtsen 			"session ID %08lx",
2764c18ec02fSPetter Reinholdtsen 			(long)intf->session->v2_data.bmc_id);
2765c18ec02fSPetter Reinholdtsen 		return -1;
2766c18ec02fSPetter Reinholdtsen 	}
2767c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
2768c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Close Session command failed: %s",
2769c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
2770c18ec02fSPetter Reinholdtsen 		return -1;
2771c18ec02fSPetter Reinholdtsen 	}
2772c18ec02fSPetter Reinholdtsen 
2773c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Closed Session %08lx\n",
2774c18ec02fSPetter Reinholdtsen 		(long)intf->session->v2_data.bmc_id);
2775c18ec02fSPetter Reinholdtsen 
2776c18ec02fSPetter Reinholdtsen 	bridgePossible = backupBridgePossible;
2777c18ec02fSPetter Reinholdtsen 
2778c18ec02fSPetter Reinholdtsen 	return 0;
2779c18ec02fSPetter Reinholdtsen }
2780c18ec02fSPetter Reinholdtsen 
2781c18ec02fSPetter Reinholdtsen 
2782c18ec02fSPetter Reinholdtsen 
2783c18ec02fSPetter Reinholdtsen /*
2784c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_open_session
2785c18ec02fSPetter Reinholdtsen  *
2786c18ec02fSPetter Reinholdtsen  * Build and send the open session command.  See section 13.17 of the IPMI
2787c18ec02fSPetter Reinholdtsen  * v2 specification for details.
2788c18ec02fSPetter Reinholdtsen  */
2789c18ec02fSPetter Reinholdtsen static int
2790c18ec02fSPetter Reinholdtsen ipmi_lanplus_open_session(struct ipmi_intf * intf)
2791c18ec02fSPetter Reinholdtsen {
2792c18ec02fSPetter Reinholdtsen 	struct ipmi_v2_payload v2_payload;
2793c18ec02fSPetter Reinholdtsen 	struct ipmi_session * session = intf->session;
2794c18ec02fSPetter Reinholdtsen 	uint8_t * msg;
2795c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
2796176774cfSZdenek Styblik 	/* 0 = success, 1 = error, 2 = timeout */
2797c18ec02fSPetter Reinholdtsen 	int rc = 0;
2798c18ec02fSPetter Reinholdtsen 
2799c18ec02fSPetter Reinholdtsen 
2800c18ec02fSPetter Reinholdtsen 	/*
2801c18ec02fSPetter Reinholdtsen 	 * Build an Open Session Request Payload
2802c18ec02fSPetter Reinholdtsen 	 */
2803c18ec02fSPetter Reinholdtsen 	msg = (uint8_t*)malloc(IPMI_OPEN_SESSION_REQUEST_SIZE);
2804c18ec02fSPetter Reinholdtsen 	if (msg == NULL) {
2805c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
2806176774cfSZdenek Styblik 		return 1;
2807c18ec02fSPetter Reinholdtsen 	}
2808c18ec02fSPetter Reinholdtsen 
2809c18ec02fSPetter Reinholdtsen 	memset(msg, 0, IPMI_OPEN_SESSION_REQUEST_SIZE);
2810c18ec02fSPetter Reinholdtsen 
2811c18ec02fSPetter Reinholdtsen 	msg[0] = 0; /* Message tag */
2812c18ec02fSPetter Reinholdtsen 	if (ipmi_oem_active(intf, "intelplus") || session->privlvl != IPMI_SESSION_PRIV_ADMIN)
2813c18ec02fSPetter Reinholdtsen 		msg[1] = session->privlvl;
2814c18ec02fSPetter Reinholdtsen 	else
2815c18ec02fSPetter Reinholdtsen 		msg[1] = 0; /* Give us highest privlg level based on supported algorithms */
2816c18ec02fSPetter Reinholdtsen 	msg[2] = 0; /* reserved */
2817c18ec02fSPetter Reinholdtsen 	msg[3] = 0; /* reserved */
2818c18ec02fSPetter Reinholdtsen 
2819c18ec02fSPetter Reinholdtsen 	/* Choose our session ID for easy recognition in the packet dump */
2820c18ec02fSPetter Reinholdtsen 	session->v2_data.console_id = 0xA0A2A3A4;
2821c18ec02fSPetter Reinholdtsen 	msg[4] = session->v2_data.console_id & 0xff;
2822c18ec02fSPetter Reinholdtsen 	msg[5] = (session->v2_data.console_id >> 8)  & 0xff;
2823c18ec02fSPetter Reinholdtsen 	msg[6] = (session->v2_data.console_id >> 16) & 0xff;
2824c18ec02fSPetter Reinholdtsen 	msg[7] = (session->v2_data.console_id >> 24) & 0xff;
2825c18ec02fSPetter Reinholdtsen 
2826c18ec02fSPetter Reinholdtsen 
2827c18ec02fSPetter Reinholdtsen 	if (lanplus_get_requested_ciphers(session->cipher_suite_id,
2828c18ec02fSPetter Reinholdtsen 									  &(session->v2_data.requested_auth_alg),
2829c18ec02fSPetter Reinholdtsen 									  &(session->v2_data.requested_integrity_alg),
2830c18ec02fSPetter Reinholdtsen 									  &(session->v2_data.requested_crypt_alg)))
2831c18ec02fSPetter Reinholdtsen 	{
2832c18ec02fSPetter Reinholdtsen 		lprintf(LOG_WARNING, "Unsupported cipher suite ID : %d\n",
2833c18ec02fSPetter Reinholdtsen 				session->cipher_suite_id);
2834c18ec02fSPetter Reinholdtsen 		free(msg);
2835c18ec02fSPetter Reinholdtsen 		msg = NULL;
2836176774cfSZdenek Styblik 		return 1;
2837c18ec02fSPetter Reinholdtsen 	}
2838c18ec02fSPetter Reinholdtsen 
2839c18ec02fSPetter Reinholdtsen 
2840c18ec02fSPetter Reinholdtsen 	/*
2841c18ec02fSPetter Reinholdtsen 	 * Authentication payload
2842c18ec02fSPetter Reinholdtsen 	 */
2843c18ec02fSPetter Reinholdtsen 	msg[8]  = 0; /* specifies authentication payload */
2844c18ec02fSPetter Reinholdtsen 	msg[9]  = 0; /* reserved */
2845c18ec02fSPetter Reinholdtsen 	msg[10] = 0; /* reserved */
2846c18ec02fSPetter Reinholdtsen 	msg[11] = 8; /* payload length */
2847c18ec02fSPetter Reinholdtsen 	msg[12] = session->v2_data.requested_auth_alg;
2848c18ec02fSPetter Reinholdtsen 	msg[13] = 0; /* reserved */
2849c18ec02fSPetter Reinholdtsen 	msg[14] = 0; /* reserved */
2850c18ec02fSPetter Reinholdtsen 	msg[15] = 0; /* reserved */
2851c18ec02fSPetter Reinholdtsen 
2852c18ec02fSPetter Reinholdtsen 	/*
2853c18ec02fSPetter Reinholdtsen 	 * Integrity payload
2854c18ec02fSPetter Reinholdtsen 	 */
2855c18ec02fSPetter Reinholdtsen 	msg[16] = 1; /* specifies integrity payload */
2856c18ec02fSPetter Reinholdtsen 	msg[17] = 0; /* reserved */
2857c18ec02fSPetter Reinholdtsen 	msg[18] = 0; /* reserved */
2858c18ec02fSPetter Reinholdtsen 	msg[19] = 8; /* payload length */
2859c18ec02fSPetter Reinholdtsen 	msg[20] = session->v2_data.requested_integrity_alg;
2860c18ec02fSPetter Reinholdtsen 	msg[21] = 0; /* reserved */
2861c18ec02fSPetter Reinholdtsen 	msg[22] = 0; /* reserved */
2862c18ec02fSPetter Reinholdtsen 	msg[23] = 0; /* reserved */
2863c18ec02fSPetter Reinholdtsen 
2864c18ec02fSPetter Reinholdtsen 	/*
2865c18ec02fSPetter Reinholdtsen 	 * Confidentiality/Encryption payload
2866c18ec02fSPetter Reinholdtsen 	 */
2867c18ec02fSPetter Reinholdtsen 	msg[24] = 2; /* specifies confidentiality payload */
2868c18ec02fSPetter Reinholdtsen 	msg[25] = 0; /* reserved */
2869c18ec02fSPetter Reinholdtsen 	msg[26] = 0; /* reserved */
2870c18ec02fSPetter Reinholdtsen 	msg[27] = 8; /* payload length */
2871c18ec02fSPetter Reinholdtsen 	msg[28] = session->v2_data.requested_crypt_alg;
2872c18ec02fSPetter Reinholdtsen 	msg[29] = 0; /* reserved */
2873c18ec02fSPetter Reinholdtsen 	msg[30] = 0; /* reserved */
2874c18ec02fSPetter Reinholdtsen 	msg[31] = 0; /* reserved */
2875c18ec02fSPetter Reinholdtsen 
2876c18ec02fSPetter Reinholdtsen 
2877c18ec02fSPetter Reinholdtsen 	v2_payload.payload_type   = IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST;
2878c18ec02fSPetter Reinholdtsen 	v2_payload.payload_length = IPMI_OPEN_SESSION_REQUEST_SIZE;
2879c18ec02fSPetter Reinholdtsen 	v2_payload.payload.open_session_request.request = msg;
2880c18ec02fSPetter Reinholdtsen 
2881c18ec02fSPetter Reinholdtsen 	rsp = ipmi_lanplus_send_payload(intf, &v2_payload);
2882c18ec02fSPetter Reinholdtsen 
2883c18ec02fSPetter Reinholdtsen 	free(msg);
2884c18ec02fSPetter Reinholdtsen 	msg = NULL;
2885176774cfSZdenek Styblik 	if (rsp == NULL ) {
2886176774cfSZdenek Styblik 		lprintf(LOG_DEBUG, "Timeout in open session response message.");
2887176774cfSZdenek Styblik 		return 2;
2888176774cfSZdenek Styblik 	}
28894f096777SZdenek Styblik 	if (verbose)
28904f096777SZdenek Styblik 		lanplus_dump_open_session_response(rsp);
28914f096777SZdenek Styblik 
2892c18ec02fSPetter Reinholdtsen 	if (rsp->payload.open_session_response.rakp_return_code !=
2893c18ec02fSPetter Reinholdtsen 		IPMI_RAKP_STATUS_NO_ERRORS)
2894c18ec02fSPetter Reinholdtsen 	{
2895c18ec02fSPetter Reinholdtsen 		lprintf(LOG_WARNING, "Error in open session response message : %s\n",
2896c18ec02fSPetter Reinholdtsen 			val2str(rsp->payload.open_session_response.rakp_return_code,
2897c18ec02fSPetter Reinholdtsen 				ipmi_rakp_return_codes));
2898176774cfSZdenek Styblik 		return 1;
2899c18ec02fSPetter Reinholdtsen 	}
2900c18ec02fSPetter Reinholdtsen 	else
2901c18ec02fSPetter Reinholdtsen 	{
2902c18ec02fSPetter Reinholdtsen 		if (rsp->payload.open_session_response.console_id !=
2903c18ec02fSPetter Reinholdtsen 			 session->v2_data.console_id) {
2904c18ec02fSPetter Reinholdtsen 			lprintf(LOG_WARNING, "Warning: Console session ID is not "
2905c18ec02fSPetter Reinholdtsen 				"what we requested");
2906c18ec02fSPetter Reinholdtsen 		}
2907c18ec02fSPetter Reinholdtsen 
2908c18ec02fSPetter Reinholdtsen 		session->v2_data.max_priv_level =
2909c18ec02fSPetter Reinholdtsen 			rsp->payload.open_session_response.max_priv_level;
2910c18ec02fSPetter Reinholdtsen 		session->v2_data.bmc_id         =
2911c18ec02fSPetter Reinholdtsen 			rsp->payload.open_session_response.bmc_id;
2912c18ec02fSPetter Reinholdtsen 		session->v2_data.auth_alg       =
2913c18ec02fSPetter Reinholdtsen 			rsp->payload.open_session_response.auth_alg;
2914c18ec02fSPetter Reinholdtsen 		session->v2_data.integrity_alg  =
2915c18ec02fSPetter Reinholdtsen 			rsp->payload.open_session_response.integrity_alg;
2916c18ec02fSPetter Reinholdtsen 		session->v2_data.crypt_alg      =
2917c18ec02fSPetter Reinholdtsen 			rsp->payload.open_session_response.crypt_alg;
2918c18ec02fSPetter Reinholdtsen 		session->v2_data.session_state  =
2919c18ec02fSPetter Reinholdtsen 			LANPLUS_STATE_OPEN_SESSION_RECEIEVED;
2920c18ec02fSPetter Reinholdtsen 
2921c18ec02fSPetter Reinholdtsen 
2922c18ec02fSPetter Reinholdtsen 		/*
2923c18ec02fSPetter Reinholdtsen 		 * Verify that we have agreed on a cipher suite
2924c18ec02fSPetter Reinholdtsen 		 */
2925c18ec02fSPetter Reinholdtsen 		if (rsp->payload.open_session_response.auth_alg !=
2926c18ec02fSPetter Reinholdtsen 			session->v2_data.requested_auth_alg)
2927c18ec02fSPetter Reinholdtsen 		{
2928c18ec02fSPetter Reinholdtsen 			lprintf(LOG_WARNING, "Authentication algorithm 0x%02x is "
2929c18ec02fSPetter Reinholdtsen 					"not what we requested 0x%02x\n",
2930c18ec02fSPetter Reinholdtsen 					rsp->payload.open_session_response.auth_alg,
2931c18ec02fSPetter Reinholdtsen 					session->v2_data.requested_auth_alg);
2932176774cfSZdenek Styblik 			rc = 1;
2933c18ec02fSPetter Reinholdtsen 		}
2934c18ec02fSPetter Reinholdtsen 		else if (rsp->payload.open_session_response.integrity_alg !=
2935c18ec02fSPetter Reinholdtsen 				 session->v2_data.requested_integrity_alg)
2936c18ec02fSPetter Reinholdtsen 		{
2937c18ec02fSPetter Reinholdtsen 			lprintf(LOG_WARNING, "Integrity algorithm 0x%02x is "
2938c18ec02fSPetter Reinholdtsen 					"not what we requested 0x%02x\n",
2939c18ec02fSPetter Reinholdtsen 					rsp->payload.open_session_response.integrity_alg,
2940c18ec02fSPetter Reinholdtsen 					session->v2_data.requested_integrity_alg);
2941176774cfSZdenek Styblik 			rc = 1;
2942c18ec02fSPetter Reinholdtsen 		}
2943c18ec02fSPetter Reinholdtsen 		else if (rsp->payload.open_session_response.crypt_alg !=
2944c18ec02fSPetter Reinholdtsen 				 session->v2_data.requested_crypt_alg)
2945c18ec02fSPetter Reinholdtsen 		{
2946c18ec02fSPetter Reinholdtsen 			lprintf(LOG_WARNING, "Encryption algorithm 0x%02x is "
2947c18ec02fSPetter Reinholdtsen 					"not what we requested 0x%02x\n",
2948c18ec02fSPetter Reinholdtsen 					rsp->payload.open_session_response.crypt_alg,
2949c18ec02fSPetter Reinholdtsen 					session->v2_data.requested_crypt_alg);
2950176774cfSZdenek Styblik 			rc = 1;
2951c18ec02fSPetter Reinholdtsen 		}
2952c18ec02fSPetter Reinholdtsen 
2953c18ec02fSPetter Reinholdtsen 	}
2954c18ec02fSPetter Reinholdtsen 
2955c18ec02fSPetter Reinholdtsen 	return rc;
2956c18ec02fSPetter Reinholdtsen }
2957c18ec02fSPetter Reinholdtsen 
2958c18ec02fSPetter Reinholdtsen 
2959c18ec02fSPetter Reinholdtsen 
2960c18ec02fSPetter Reinholdtsen /*
2961c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_rakp1
2962c18ec02fSPetter Reinholdtsen  *
2963c18ec02fSPetter Reinholdtsen  * Build and send the RAKP 1 message as part of the IPMI v2 / RMCP+ session
2964c18ec02fSPetter Reinholdtsen  * negotiation protocol.  We also read and validate the RAKP 2 message received
2965c18ec02fSPetter Reinholdtsen  * from the BMC, here.  See section 13.20 of the IPMI v2 specification for
2966c18ec02fSPetter Reinholdtsen  * details.
2967c18ec02fSPetter Reinholdtsen  *
2968c18ec02fSPetter Reinholdtsen  * returns 0 on success
2969c18ec02fSPetter Reinholdtsen  *         1 on failure
2970c18ec02fSPetter Reinholdtsen  *
2971c18ec02fSPetter Reinholdtsen  * Note that failure is only indicated if we have an internal error of
2972c18ec02fSPetter Reinholdtsen  * some kind. If we actually get a RAKP 2 message in response to our
2973c18ec02fSPetter Reinholdtsen  * RAKP 1 message, any errors will be stored in
2974c18ec02fSPetter Reinholdtsen  * session->v2_data.rakp2_return_code and sent to the BMC in the RAKP
2975c18ec02fSPetter Reinholdtsen  * 3 message.
2976c18ec02fSPetter Reinholdtsen  */
2977c18ec02fSPetter Reinholdtsen static int
2978c18ec02fSPetter Reinholdtsen ipmi_lanplus_rakp1(struct ipmi_intf * intf)
2979c18ec02fSPetter Reinholdtsen {
2980c18ec02fSPetter Reinholdtsen 	struct ipmi_v2_payload v2_payload;
2981c18ec02fSPetter Reinholdtsen 	struct ipmi_session * session = intf->session;
2982c18ec02fSPetter Reinholdtsen 	uint8_t * msg;
2983c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
2984176774cfSZdenek Styblik 	int rc = 0;    /* 0 = success, 1 = error, 2 = timeout */
2985c18ec02fSPetter Reinholdtsen 
2986c18ec02fSPetter Reinholdtsen 	/*
2987c18ec02fSPetter Reinholdtsen 	 * Build a RAKP 1 message
2988c18ec02fSPetter Reinholdtsen 	 */
2989c18ec02fSPetter Reinholdtsen 	msg = (uint8_t*)malloc(IPMI_RAKP1_MESSAGE_SIZE);
2990c18ec02fSPetter Reinholdtsen 	if (msg == NULL) {
2991c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
2992c18ec02fSPetter Reinholdtsen 		return 1;
2993c18ec02fSPetter Reinholdtsen 	}
2994c18ec02fSPetter Reinholdtsen 	memset(msg, 0, IPMI_RAKP1_MESSAGE_SIZE);
2995c18ec02fSPetter Reinholdtsen 
2996c18ec02fSPetter Reinholdtsen 
2997c18ec02fSPetter Reinholdtsen 	msg[0] = 0; /* Message tag */
2998c18ec02fSPetter Reinholdtsen 
2999c18ec02fSPetter Reinholdtsen 	msg[1] = 0; /* reserved */
3000c18ec02fSPetter Reinholdtsen 	msg[2] = 0; /* reserved */
3001c18ec02fSPetter Reinholdtsen 	msg[3] = 0; /* reserved */
3002c18ec02fSPetter Reinholdtsen 
3003c18ec02fSPetter Reinholdtsen 	/* BMC session ID */
3004c18ec02fSPetter Reinholdtsen 	msg[4] = session->v2_data.bmc_id & 0xff;
3005c18ec02fSPetter Reinholdtsen 	msg[5] = (session->v2_data.bmc_id >> 8)  & 0xff;
3006c18ec02fSPetter Reinholdtsen 	msg[6] = (session->v2_data.bmc_id >> 16) & 0xff;
3007c18ec02fSPetter Reinholdtsen 	msg[7] = (session->v2_data.bmc_id >> 24) & 0xff;
3008c18ec02fSPetter Reinholdtsen 
3009c18ec02fSPetter Reinholdtsen 
3010c18ec02fSPetter Reinholdtsen 	/* We need a 16 byte random number */
3011c18ec02fSPetter Reinholdtsen 	if (lanplus_rand(session->v2_data.console_rand, 16))
3012c18ec02fSPetter Reinholdtsen 	{
3013c18ec02fSPetter Reinholdtsen 		// ERROR;
3014c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ERROR generating random number "
3015c18ec02fSPetter Reinholdtsen 			"in ipmi_lanplus_rakp1");
3016c18ec02fSPetter Reinholdtsen 		free(msg);
3017c18ec02fSPetter Reinholdtsen 		msg = NULL;
3018c18ec02fSPetter Reinholdtsen 		return 1;
3019c18ec02fSPetter Reinholdtsen 	}
3020c18ec02fSPetter Reinholdtsen 	memcpy(msg + 8, session->v2_data.console_rand, 16);
3021c18ec02fSPetter Reinholdtsen 	#if WORDS_BIGENDIAN
3022c18ec02fSPetter Reinholdtsen 	lanplus_swap(msg + 8, 16);
3023c18ec02fSPetter Reinholdtsen 	#endif
3024c18ec02fSPetter Reinholdtsen 
3025c18ec02fSPetter Reinholdtsen 	if (verbose > 1)
3026c18ec02fSPetter Reinholdtsen 		printbuf(session->v2_data.console_rand, 16,
3027c18ec02fSPetter Reinholdtsen 				 ">> Console generated random number");
3028c18ec02fSPetter Reinholdtsen 
3029c18ec02fSPetter Reinholdtsen 
3030c18ec02fSPetter Reinholdtsen 	/*
3031c18ec02fSPetter Reinholdtsen 	 * Requested maximum privilege level.
3032c18ec02fSPetter Reinholdtsen 	 */
3033c18ec02fSPetter Reinholdtsen 	msg[24] = session->privlvl | session->v2_data.lookupbit;
3034c18ec02fSPetter Reinholdtsen 	session->v2_data.requested_role = msg[24];
3035c18ec02fSPetter Reinholdtsen 	msg[25] = 0; /* reserved */
3036c18ec02fSPetter Reinholdtsen 	msg[26] = 0; /* reserved */
3037c18ec02fSPetter Reinholdtsen 
3038c18ec02fSPetter Reinholdtsen 
3039c18ec02fSPetter Reinholdtsen 	/* Username specification */
3040c18ec02fSPetter Reinholdtsen 	msg[27] = strlen((const char *)session->username);
3041c18ec02fSPetter Reinholdtsen 	if (msg[27] > IPMI_MAX_USER_NAME_LENGTH)
3042c18ec02fSPetter Reinholdtsen 	{
3043c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ERROR: user name too long.  "
3044c18ec02fSPetter Reinholdtsen 			"(Exceeds %d characters)",
3045c18ec02fSPetter Reinholdtsen 			IPMI_MAX_USER_NAME_LENGTH);
3046c18ec02fSPetter Reinholdtsen 		free(msg);
3047c18ec02fSPetter Reinholdtsen 		msg = NULL;
3048c18ec02fSPetter Reinholdtsen 		return 1;
3049c18ec02fSPetter Reinholdtsen 	}
3050c18ec02fSPetter Reinholdtsen 	memcpy(msg + 28, session->username, msg[27]);
3051c18ec02fSPetter Reinholdtsen 
3052c18ec02fSPetter Reinholdtsen 	v2_payload.payload_type = IPMI_PAYLOAD_TYPE_RAKP_1;
3053f56d740dSZdenek Styblik 	if (ipmi_oem_active(intf, "i82571spt")) {
3054f56d740dSZdenek Styblik 		/*
3055f56d740dSZdenek Styblik 		 * The IPMI v2.0 spec hints on that all user name bytes
3056f56d740dSZdenek Styblik 		 * must be occupied (29:44).  The Intel 82571 GbE refuses
3057f56d740dSZdenek Styblik 		 * to establish a session if this field is shorter.
3058f56d740dSZdenek Styblik 		 */
3059f56d740dSZdenek Styblik 		v2_payload.payload_length = IPMI_RAKP1_MESSAGE_SIZE;
3060f56d740dSZdenek Styblik 	} else {
3061c18ec02fSPetter Reinholdtsen 		v2_payload.payload_length =
3062c18ec02fSPetter Reinholdtsen 			IPMI_RAKP1_MESSAGE_SIZE - (16 - msg[27]);
3063f56d740dSZdenek Styblik 	}
3064c18ec02fSPetter Reinholdtsen 	v2_payload.payload.rakp_1_message.message = msg;
3065c18ec02fSPetter Reinholdtsen 
3066c18ec02fSPetter Reinholdtsen 	rsp = ipmi_lanplus_send_payload(intf, &v2_payload);
3067c18ec02fSPetter Reinholdtsen 
3068c18ec02fSPetter Reinholdtsen 	free(msg);
3069c18ec02fSPetter Reinholdtsen 	msg = NULL;
3070c18ec02fSPetter Reinholdtsen 
3071c18ec02fSPetter Reinholdtsen 	if (rsp == NULL)
3072c18ec02fSPetter Reinholdtsen 	{
3073176774cfSZdenek Styblik 		lprintf(LOG_WARNING, "> Error: no response from RAKP 1 message");
3074176774cfSZdenek Styblik 		return 2;
3075c18ec02fSPetter Reinholdtsen 	}
3076c18ec02fSPetter Reinholdtsen 
3077c18ec02fSPetter Reinholdtsen 	session->v2_data.session_state = LANPLUS_STATE_RAKP_2_RECEIVED;
3078c18ec02fSPetter Reinholdtsen 
3079c18ec02fSPetter Reinholdtsen 	if (verbose)
3080c18ec02fSPetter Reinholdtsen 		lanplus_dump_rakp2_message(rsp, session->v2_data.auth_alg);
3081c18ec02fSPetter Reinholdtsen 
3082c18ec02fSPetter Reinholdtsen 
3083c18ec02fSPetter Reinholdtsen 
3084c18ec02fSPetter Reinholdtsen 	if (rsp->payload.rakp2_message.rakp_return_code != IPMI_RAKP_STATUS_NO_ERRORS)
3085c18ec02fSPetter Reinholdtsen 	{
3086c18ec02fSPetter Reinholdtsen 		lprintf(LOG_INFO, "RAKP 2 message indicates an error : %s",
3087c18ec02fSPetter Reinholdtsen 			val2str(rsp->payload.rakp2_message.rakp_return_code,
3088c18ec02fSPetter Reinholdtsen 				ipmi_rakp_return_codes));
3089c18ec02fSPetter Reinholdtsen 		rc = 1;
3090c18ec02fSPetter Reinholdtsen 	}
3091c18ec02fSPetter Reinholdtsen 
3092c18ec02fSPetter Reinholdtsen 	else
3093c18ec02fSPetter Reinholdtsen 	{
3094c18ec02fSPetter Reinholdtsen 		memcpy(session->v2_data.bmc_rand, rsp->payload.rakp2_message.bmc_rand, 16);
3095c18ec02fSPetter Reinholdtsen 		memcpy(session->v2_data.bmc_guid, rsp->payload.rakp2_message.bmc_guid, 16);
3096c18ec02fSPetter Reinholdtsen 
3097c18ec02fSPetter Reinholdtsen 		if (verbose > 2)
3098c18ec02fSPetter Reinholdtsen 			printbuf(session->v2_data.bmc_rand, 16, "bmc_rand");
3099c18ec02fSPetter Reinholdtsen 
3100c18ec02fSPetter Reinholdtsen 		/*
3101c18ec02fSPetter Reinholdtsen 		 * It is at this point that we have to decode the random number and determine
3102c18ec02fSPetter Reinholdtsen 		 * whether the BMC has authenticated.
3103c18ec02fSPetter Reinholdtsen 		 */
3104c18ec02fSPetter Reinholdtsen 		if (! lanplus_rakp2_hmac_matches(session,
3105c18ec02fSPetter Reinholdtsen 										 rsp->payload.rakp2_message.key_exchange_auth_code,
3106c18ec02fSPetter Reinholdtsen 										 intf))
3107c18ec02fSPetter Reinholdtsen 		{
3108c18ec02fSPetter Reinholdtsen 			/* Error */
3109c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO, "> RAKP 2 HMAC is invalid");
3110c18ec02fSPetter Reinholdtsen 			session->v2_data.rakp2_return_code = IPMI_RAKP_STATUS_INVALID_INTEGRITY_CHECK_VALUE;
3111c18ec02fSPetter Reinholdtsen 								rc = 1;
3112c18ec02fSPetter Reinholdtsen 		}
3113c18ec02fSPetter Reinholdtsen 		else
3114c18ec02fSPetter Reinholdtsen 		{
3115c18ec02fSPetter Reinholdtsen 			/* Success */
3116c18ec02fSPetter Reinholdtsen 			session->v2_data.rakp2_return_code = IPMI_RAKP_STATUS_NO_ERRORS;
3117c18ec02fSPetter Reinholdtsen 		}
3118c18ec02fSPetter Reinholdtsen 	}
3119c18ec02fSPetter Reinholdtsen 
3120c18ec02fSPetter Reinholdtsen 	return rc;
3121c18ec02fSPetter Reinholdtsen }
3122c18ec02fSPetter Reinholdtsen 
3123c18ec02fSPetter Reinholdtsen 
3124c18ec02fSPetter Reinholdtsen 
3125c18ec02fSPetter Reinholdtsen /*
3126c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_rakp3
3127c18ec02fSPetter Reinholdtsen  *
3128c18ec02fSPetter Reinholdtsen  * Build and send the RAKP 3 message as part of the IPMI v2 / RMCP+ session
3129c18ec02fSPetter Reinholdtsen  * negotiation protocol.  We also read and validate the RAKP 4 message received
3130c18ec02fSPetter Reinholdtsen  * from the BMC, here.  See section 13.20 of the IPMI v2 specification for
3131c18ec02fSPetter Reinholdtsen  * details.
3132c18ec02fSPetter Reinholdtsen  *
3133c18ec02fSPetter Reinholdtsen  * If the RAKP 2 return code is not IPMI_RAKP_STATUS_NO_ERRORS, we will
3134c18ec02fSPetter Reinholdtsen  * exit with an error code immediately after sendint the RAKP 3 message.
3135c18ec02fSPetter Reinholdtsen  *
3136c18ec02fSPetter Reinholdtsen  * param intf is the intf that holds all the state we are concerned with
3137c18ec02fSPetter Reinholdtsen  *
3138c18ec02fSPetter Reinholdtsen  * returns 0 on success
3139c18ec02fSPetter Reinholdtsen  *         1 on failure
3140c18ec02fSPetter Reinholdtsen  */
3141c18ec02fSPetter Reinholdtsen static int
3142c18ec02fSPetter Reinholdtsen ipmi_lanplus_rakp3(struct ipmi_intf * intf)
3143c18ec02fSPetter Reinholdtsen {
3144c18ec02fSPetter Reinholdtsen 	struct ipmi_v2_payload v2_payload;
3145c18ec02fSPetter Reinholdtsen 	struct ipmi_session * session = intf->session;
3146c18ec02fSPetter Reinholdtsen 	uint8_t * msg;
3147c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
3148c18ec02fSPetter Reinholdtsen 
3149c18ec02fSPetter Reinholdtsen 	assert(session->v2_data.session_state == LANPLUS_STATE_RAKP_2_RECEIVED);
3150c18ec02fSPetter Reinholdtsen 
3151c18ec02fSPetter Reinholdtsen 	/*
3152c18ec02fSPetter Reinholdtsen 	 * Build a RAKP 3 message
3153c18ec02fSPetter Reinholdtsen 	 */
3154c18ec02fSPetter Reinholdtsen 	msg = (uint8_t*)malloc(IPMI_RAKP3_MESSAGE_MAX_SIZE);
3155c18ec02fSPetter Reinholdtsen 	if (msg == NULL) {
3156c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
3157c18ec02fSPetter Reinholdtsen 		return 1;
3158c18ec02fSPetter Reinholdtsen 	}
3159c18ec02fSPetter Reinholdtsen 	memset(msg, 0, IPMI_RAKP3_MESSAGE_MAX_SIZE);
3160c18ec02fSPetter Reinholdtsen 
3161c18ec02fSPetter Reinholdtsen 
3162c18ec02fSPetter Reinholdtsen 	msg[0] = 0; /* Message tag */
3163c18ec02fSPetter Reinholdtsen 	msg[1] = session->v2_data.rakp2_return_code;
3164c18ec02fSPetter Reinholdtsen 
3165c18ec02fSPetter Reinholdtsen 	msg[2] = 0; /* reserved */
3166c18ec02fSPetter Reinholdtsen 	msg[3] = 0; /* reserved */
3167c18ec02fSPetter Reinholdtsen 
3168c18ec02fSPetter Reinholdtsen 	/* BMC session ID */
3169c18ec02fSPetter Reinholdtsen 	msg[4] = session->v2_data.bmc_id & 0xff;
3170c18ec02fSPetter Reinholdtsen 	msg[5] = (session->v2_data.bmc_id >> 8)  & 0xff;
3171c18ec02fSPetter Reinholdtsen 	msg[6] = (session->v2_data.bmc_id >> 16) & 0xff;
3172c18ec02fSPetter Reinholdtsen 	msg[7] = (session->v2_data.bmc_id >> 24) & 0xff;
3173c18ec02fSPetter Reinholdtsen 
3174c18ec02fSPetter Reinholdtsen 	v2_payload.payload_type                   = IPMI_PAYLOAD_TYPE_RAKP_3;
3175c18ec02fSPetter Reinholdtsen 	v2_payload.payload_length                 = 8;
3176c18ec02fSPetter Reinholdtsen 	v2_payload.payload.rakp_3_message.message = msg;
3177c18ec02fSPetter Reinholdtsen 
3178c18ec02fSPetter Reinholdtsen 	/*
3179c18ec02fSPetter Reinholdtsen 	 * If the rakp2 return code indicates and error, we don't have to
3180c18ec02fSPetter Reinholdtsen 	 * generate an authcode or session integrity key.  In that case, we
3181c18ec02fSPetter Reinholdtsen 	 * are simply sending a RAKP 3 message to indicate to the BMC that the
3182c18ec02fSPetter Reinholdtsen 	 * RAKP 2 message caused an error.
3183c18ec02fSPetter Reinholdtsen 	 */
3184c18ec02fSPetter Reinholdtsen 	if (session->v2_data.rakp2_return_code == IPMI_RAKP_STATUS_NO_ERRORS)
3185c18ec02fSPetter Reinholdtsen 	{
3186c18ec02fSPetter Reinholdtsen 		uint32_t auth_length;
3187c18ec02fSPetter Reinholdtsen 
3188c18ec02fSPetter Reinholdtsen 		if (lanplus_generate_rakp3_authcode(msg + 8, session, &auth_length, intf))
3189c18ec02fSPetter Reinholdtsen 		{
3190c18ec02fSPetter Reinholdtsen 			/* Error */
3191c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO, "> Error generating RAKP 3 authcode");
3192c18ec02fSPetter Reinholdtsen 			free(msg);
3193c18ec02fSPetter Reinholdtsen 			msg = NULL;
3194c18ec02fSPetter Reinholdtsen 			return 1;
3195c18ec02fSPetter Reinholdtsen 		}
3196c18ec02fSPetter Reinholdtsen 		else
3197c18ec02fSPetter Reinholdtsen 		{
3198c18ec02fSPetter Reinholdtsen 			/* Success */
3199c18ec02fSPetter Reinholdtsen 			v2_payload.payload_length += auth_length;
3200c18ec02fSPetter Reinholdtsen 		}
3201c18ec02fSPetter Reinholdtsen 
3202c18ec02fSPetter Reinholdtsen 		/* Generate our Session Integrity Key, K1, and K2 */
3203c18ec02fSPetter Reinholdtsen 		if (lanplus_generate_sik(session, intf))
3204c18ec02fSPetter Reinholdtsen 		{
3205c18ec02fSPetter Reinholdtsen 			/* Error */
3206c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO, "> Error generating session integrity key");
3207c18ec02fSPetter Reinholdtsen 			free(msg);
3208c18ec02fSPetter Reinholdtsen 			msg = NULL;
3209c18ec02fSPetter Reinholdtsen 			return 1;
3210c18ec02fSPetter Reinholdtsen 		}
3211c18ec02fSPetter Reinholdtsen 		else if (lanplus_generate_k1(session))
3212c18ec02fSPetter Reinholdtsen 		{
3213c18ec02fSPetter Reinholdtsen 			/* Error */
3214c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO, "> Error generating K1 key");
3215c18ec02fSPetter Reinholdtsen 			free(msg);
3216c18ec02fSPetter Reinholdtsen 			msg = NULL;
3217c18ec02fSPetter Reinholdtsen 			return 1;
3218c18ec02fSPetter Reinholdtsen 		}
3219c18ec02fSPetter Reinholdtsen 		else if (lanplus_generate_k2(session))
3220c18ec02fSPetter Reinholdtsen 		{
3221c18ec02fSPetter Reinholdtsen 			/* Error */
3222c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO, "> Error generating K1 key");
3223c18ec02fSPetter Reinholdtsen 			free(msg);
3224c18ec02fSPetter Reinholdtsen 			msg = NULL;
3225c18ec02fSPetter Reinholdtsen 			return 1;
3226c18ec02fSPetter Reinholdtsen 		}
3227c18ec02fSPetter Reinholdtsen 	}
3228c18ec02fSPetter Reinholdtsen 
3229c18ec02fSPetter Reinholdtsen 
3230c18ec02fSPetter Reinholdtsen 	rsp = ipmi_lanplus_send_payload(intf, &v2_payload);
3231c18ec02fSPetter Reinholdtsen 
3232c18ec02fSPetter Reinholdtsen 	free(msg);
3233c18ec02fSPetter Reinholdtsen 	msg = NULL;
3234c18ec02fSPetter Reinholdtsen 
3235c18ec02fSPetter Reinholdtsen 	if (session->v2_data.rakp2_return_code != IPMI_RAKP_STATUS_NO_ERRORS)
3236c18ec02fSPetter Reinholdtsen 	{
3237c18ec02fSPetter Reinholdtsen 		/*
3238c18ec02fSPetter Reinholdtsen 		 * If the previous RAKP 2 message received was deemed erroneous,
3239c18ec02fSPetter Reinholdtsen 		 * we have nothing else to do here.  We only sent the RAKP 3 message
3240c18ec02fSPetter Reinholdtsen 		 * to indicate to the BMC that the RAKP 2 message failed.
3241c18ec02fSPetter Reinholdtsen 		 */
3242c18ec02fSPetter Reinholdtsen 		return 1;
3243c18ec02fSPetter Reinholdtsen 	}
3244c18ec02fSPetter Reinholdtsen 	else if (rsp == NULL)
3245c18ec02fSPetter Reinholdtsen 	{
3246176774cfSZdenek Styblik 		lprintf(LOG_WARNING, "> Error: no response from RAKP 3 message");
3247176774cfSZdenek Styblik 		return 2;
3248c18ec02fSPetter Reinholdtsen 	}
3249c18ec02fSPetter Reinholdtsen 
3250c18ec02fSPetter Reinholdtsen 
3251c18ec02fSPetter Reinholdtsen 	/*
3252c18ec02fSPetter Reinholdtsen 	 * We have a RAKP 4 message to chew on.
3253c18ec02fSPetter Reinholdtsen 	 */
3254c18ec02fSPetter Reinholdtsen 	if (verbose)
3255c18ec02fSPetter Reinholdtsen 		lanplus_dump_rakp4_message(rsp, session->v2_data.auth_alg);
3256c18ec02fSPetter Reinholdtsen 
3257c18ec02fSPetter Reinholdtsen 
3258c18ec02fSPetter Reinholdtsen 	if (rsp->payload.open_session_response.rakp_return_code != IPMI_RAKP_STATUS_NO_ERRORS)
3259c18ec02fSPetter Reinholdtsen 	{
3260c18ec02fSPetter Reinholdtsen 		lprintf(LOG_INFO, "RAKP 4 message indicates an error : %s",
3261c18ec02fSPetter Reinholdtsen 			val2str(rsp->payload.rakp4_message.rakp_return_code,
3262c18ec02fSPetter Reinholdtsen 				ipmi_rakp_return_codes));
3263c18ec02fSPetter Reinholdtsen 		return 1;
3264c18ec02fSPetter Reinholdtsen 	}
3265c18ec02fSPetter Reinholdtsen 
3266c18ec02fSPetter Reinholdtsen 	else
3267c18ec02fSPetter Reinholdtsen 	{
3268c18ec02fSPetter Reinholdtsen 		/* Validate the authcode */
3269c18ec02fSPetter Reinholdtsen 		if (lanplus_rakp4_hmac_matches(session,
3270c18ec02fSPetter Reinholdtsen 										rsp->payload.rakp4_message.integrity_check_value,
3271c18ec02fSPetter Reinholdtsen 										intf))
3272c18ec02fSPetter Reinholdtsen 		{
3273c18ec02fSPetter Reinholdtsen 			/* Success */
3274c18ec02fSPetter Reinholdtsen 			session->v2_data.session_state = LANPLUS_STATE_ACTIVE;
3275c18ec02fSPetter Reinholdtsen 		}
3276c18ec02fSPetter Reinholdtsen 		else
3277c18ec02fSPetter Reinholdtsen 		{
3278c18ec02fSPetter Reinholdtsen 			/* Error */
3279c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO, "> RAKP 4 message has invalid integrity check value");
3280c18ec02fSPetter Reinholdtsen 			return 1;
3281c18ec02fSPetter Reinholdtsen 		}
3282c18ec02fSPetter Reinholdtsen 	}
3283c18ec02fSPetter Reinholdtsen 
3284c18ec02fSPetter Reinholdtsen 	intf->abort = 0;
3285c18ec02fSPetter Reinholdtsen 	return 0;
3286c18ec02fSPetter Reinholdtsen }
3287c18ec02fSPetter Reinholdtsen 
3288c18ec02fSPetter Reinholdtsen 
3289c18ec02fSPetter Reinholdtsen 
3290c18ec02fSPetter Reinholdtsen /**
3291c18ec02fSPetter Reinholdtsen  * ipmi_lan_close
3292c18ec02fSPetter Reinholdtsen  */
3293c18ec02fSPetter Reinholdtsen void
3294c18ec02fSPetter Reinholdtsen ipmi_lanplus_close(struct ipmi_intf * intf)
3295c18ec02fSPetter Reinholdtsen {
3296c18ec02fSPetter Reinholdtsen 	if (!intf->abort)
3297c18ec02fSPetter Reinholdtsen 		ipmi_close_session_cmd(intf);
3298c18ec02fSPetter Reinholdtsen 
3299c18ec02fSPetter Reinholdtsen 	if (intf->fd >= 0)
3300c18ec02fSPetter Reinholdtsen 		close(intf->fd);
3301c18ec02fSPetter Reinholdtsen 
3302c18ec02fSPetter Reinholdtsen 	ipmi_req_clear_entries();
3303deb9a4edSZdenek Styblik 	ipmi_intf_session_cleanup(intf);
3304c18ec02fSPetter Reinholdtsen 	intf->session = NULL;
3305c18ec02fSPetter Reinholdtsen 	intf->opened = 0;
3306c18ec02fSPetter Reinholdtsen 	intf->manufacturer_id = IPMI_OEM_UNKNOWN;
3307c18ec02fSPetter Reinholdtsen 	intf = NULL;
3308c18ec02fSPetter Reinholdtsen }
3309c18ec02fSPetter Reinholdtsen 
3310c18ec02fSPetter Reinholdtsen 
3311c18ec02fSPetter Reinholdtsen 
3312c18ec02fSPetter Reinholdtsen static int
3313c18ec02fSPetter Reinholdtsen ipmi_set_session_privlvl_cmd(struct ipmi_intf * intf)
3314c18ec02fSPetter Reinholdtsen {
3315c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
3316c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
3317c18ec02fSPetter Reinholdtsen 	uint8_t backupBridgePossible;
3318c18ec02fSPetter Reinholdtsen 	uint8_t privlvl = intf->session->privlvl;
3319c18ec02fSPetter Reinholdtsen 
3320c18ec02fSPetter Reinholdtsen 	if (privlvl <= IPMI_SESSION_PRIV_USER)
3321c18ec02fSPetter Reinholdtsen 		return 0;	/* no need to set higher */
3322c18ec02fSPetter Reinholdtsen 
3323c18ec02fSPetter Reinholdtsen 	backupBridgePossible = bridgePossible;
3324c18ec02fSPetter Reinholdtsen 
3325c18ec02fSPetter Reinholdtsen 	bridgePossible = 0;
3326c18ec02fSPetter Reinholdtsen 
3327c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
3328c18ec02fSPetter Reinholdtsen 	req.msg.netfn		= IPMI_NETFN_APP;
3329c18ec02fSPetter Reinholdtsen 	req.msg.cmd		= 0x3b;
3330c18ec02fSPetter Reinholdtsen 	req.msg.data		= &privlvl;
3331c18ec02fSPetter Reinholdtsen 	req.msg.data_len	= 1;
3332c18ec02fSPetter Reinholdtsen 
3333c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
3334c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
3335c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Set Session Privilege Level to %s failed",
3336c18ec02fSPetter Reinholdtsen 			val2str(privlvl, ipmi_privlvl_vals));
3337c18ec02fSPetter Reinholdtsen 		bridgePossible = backupBridgePossible;
3338c18ec02fSPetter Reinholdtsen 		return -1;
3339c18ec02fSPetter Reinholdtsen 	}
3340c18ec02fSPetter Reinholdtsen 	if (verbose > 2)
3341c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "set_session_privlvl");
3342c18ec02fSPetter Reinholdtsen 
3343c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
3344c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Set Session Privilege Level to %s failed: %s",
3345c18ec02fSPetter Reinholdtsen 			val2str(privlvl, ipmi_privlvl_vals),
3346c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
3347c18ec02fSPetter Reinholdtsen 		bridgePossible = backupBridgePossible;
3348c18ec02fSPetter Reinholdtsen 		return -1;
3349c18ec02fSPetter Reinholdtsen 	}
3350c18ec02fSPetter Reinholdtsen 
3351c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Set Session Privilege Level to %s\n",
3352c18ec02fSPetter Reinholdtsen 		val2str(rsp->data[0], ipmi_privlvl_vals));
3353c18ec02fSPetter Reinholdtsen 
3354c18ec02fSPetter Reinholdtsen 	bridgePossible = backupBridgePossible;
3355c18ec02fSPetter Reinholdtsen 
3356c18ec02fSPetter Reinholdtsen 	return 0;
3357c18ec02fSPetter Reinholdtsen }
3358c18ec02fSPetter Reinholdtsen 
3359c18ec02fSPetter Reinholdtsen /**
3360c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_open
3361c18ec02fSPetter Reinholdtsen  */
3362c18ec02fSPetter Reinholdtsen int
3363c18ec02fSPetter Reinholdtsen ipmi_lanplus_open(struct ipmi_intf * intf)
3364c18ec02fSPetter Reinholdtsen {
3365c18ec02fSPetter Reinholdtsen 	int rc;
3366176774cfSZdenek Styblik 	int retry;
3367c18ec02fSPetter Reinholdtsen 	struct get_channel_auth_cap_rsp auth_cap;
3368c18ec02fSPetter Reinholdtsen 	struct ipmi_session *session;
3369c18ec02fSPetter Reinholdtsen 
3370c18ec02fSPetter Reinholdtsen 	if (!intf || !intf->session)
3371c18ec02fSPetter Reinholdtsen 		return -1;
3372c18ec02fSPetter Reinholdtsen 	session = intf->session;
3373c18ec02fSPetter Reinholdtsen 
3374c18ec02fSPetter Reinholdtsen 	if (!session->port)
3375c18ec02fSPetter Reinholdtsen 		session->port = IPMI_LANPLUS_PORT;
3376c18ec02fSPetter Reinholdtsen 	if (!session->privlvl)
3377c18ec02fSPetter Reinholdtsen 		session->privlvl = IPMI_SESSION_PRIV_ADMIN;
3378c18ec02fSPetter Reinholdtsen 	if (!session->timeout)
3379c18ec02fSPetter Reinholdtsen 		session->timeout = IPMI_LAN_TIMEOUT;
3380c18ec02fSPetter Reinholdtsen 	if (!session->retry)
3381c18ec02fSPetter Reinholdtsen 		session->retry = IPMI_LAN_RETRY;
3382c18ec02fSPetter Reinholdtsen 
3383c18ec02fSPetter Reinholdtsen 	if (session->hostname == NULL || strlen((const char *)session->hostname) == 0) {
3384c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "No hostname specified!");
3385c18ec02fSPetter Reinholdtsen 		return -1;
3386c18ec02fSPetter Reinholdtsen 	}
3387c18ec02fSPetter Reinholdtsen 
3388c18ec02fSPetter Reinholdtsen 	intf->abort = 1;
3389c18ec02fSPetter Reinholdtsen 
3390c18ec02fSPetter Reinholdtsen 
3391c18ec02fSPetter Reinholdtsen 	/* Setup our lanplus session state */
3392c18ec02fSPetter Reinholdtsen 	session->v2_data.auth_alg         = IPMI_AUTH_RAKP_NONE;
3393c18ec02fSPetter Reinholdtsen 	session->v2_data.crypt_alg        = IPMI_CRYPT_NONE;
3394c18ec02fSPetter Reinholdtsen 	session->v2_data.console_id       = 0x00;
3395c18ec02fSPetter Reinholdtsen 	session->v2_data.bmc_id           = 0x00;
3396c18ec02fSPetter Reinholdtsen 	session->sol_data.sequence_number = 1;
3397c18ec02fSPetter Reinholdtsen 	//session->sol_data.last_received_sequence_number = 0;
3398c18ec02fSPetter Reinholdtsen 	//session->sol_data.last_received_byte_count      = 0;
3399c18ec02fSPetter Reinholdtsen 	memset(session->v2_data.sik, 0, IPMI_SIK_BUFFER_SIZE);
3400c18ec02fSPetter Reinholdtsen 
3401c18ec02fSPetter Reinholdtsen 	/* Kg is set in ipmi_intf */
3402c18ec02fSPetter Reinholdtsen 	//memset(session->v2_data.kg,  0, IPMI_KG_BUFFER_SIZE);
3403c18ec02fSPetter Reinholdtsen 
3404c18ec02fSPetter Reinholdtsen 	if (ipmi_intf_socket_connect (intf) == -1) {
3405c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Could not open socket!");
3406c18ec02fSPetter Reinholdtsen 		return -1;
3407c18ec02fSPetter Reinholdtsen 	}
3408c18ec02fSPetter Reinholdtsen 
3409c18ec02fSPetter Reinholdtsen 	if (intf->fd < 0) {
3410c18ec02fSPetter Reinholdtsen 		lperror(LOG_ERR, "Connect to %s failed",
3411c18ec02fSPetter Reinholdtsen 			session->hostname);
3412c18ec02fSPetter Reinholdtsen 		intf->close(intf);
3413c18ec02fSPetter Reinholdtsen 		return -1;
3414c18ec02fSPetter Reinholdtsen 	}
3415c18ec02fSPetter Reinholdtsen 
3416c18ec02fSPetter Reinholdtsen 	intf->opened = 1;
3417c18ec02fSPetter Reinholdtsen 
3418c18ec02fSPetter Reinholdtsen 	/*
3419c18ec02fSPetter Reinholdtsen 	 *
3420c18ec02fSPetter Reinholdtsen 	 * Make sure the BMC supports IPMI v2 / RMCP+
3421c18ec02fSPetter Reinholdtsen 	 */
3422c18ec02fSPetter Reinholdtsen 	if (!ipmi_oem_active(intf, "i82571spt") &&
3423c18ec02fSPetter Reinholdtsen 			ipmi_get_auth_capabilities_cmd(intf, &auth_cap)) {
3424c18ec02fSPetter Reinholdtsen 		lprintf(LOG_INFO, "Error issuing Get Channel "
3425c18ec02fSPetter Reinholdtsen 			"Authentication Capabilies request");
3426c18ec02fSPetter Reinholdtsen 		goto fail;
3427c18ec02fSPetter Reinholdtsen 	}
3428c18ec02fSPetter Reinholdtsen 
3429f56d740dSZdenek Styblik 	if (!ipmi_oem_active(intf, "i82571spt") && ! auth_cap.v20_data_available) {
3430c18ec02fSPetter Reinholdtsen 		lprintf(LOG_INFO, "This BMC does not support IPMI v2 / RMCP+");
3431c18ec02fSPetter Reinholdtsen 		goto fail;
3432c18ec02fSPetter Reinholdtsen 	}
3433c18ec02fSPetter Reinholdtsen 
3434176774cfSZdenek Styblik 	/*
3435176774cfSZdenek Styblik 	 * If the open/rakp1/rakp3 sequence encounters a timeout, the whole sequence
3436176774cfSZdenek Styblik 	 * needs to restart. The individual messages are not individually retryable,
3437176774cfSZdenek Styblik 	 * as the session state is advancing.
3438176774cfSZdenek Styblik 	 */
3439176774cfSZdenek Styblik 	for (retry = 0; retry < IPMI_LAN_RETRY; retry++) {
3440176774cfSZdenek Styblik 		session->v2_data.session_state = LANPLUS_STATE_PRESESSION;
3441c18ec02fSPetter Reinholdtsen 		/*
3442c18ec02fSPetter Reinholdtsen 		 * Open session
3443c18ec02fSPetter Reinholdtsen 		 */
3444176774cfSZdenek Styblik 		if ((rc = ipmi_lanplus_open_session(intf)) == 1) {
3445c18ec02fSPetter Reinholdtsen 			intf->close(intf);
3446c18ec02fSPetter Reinholdtsen 			goto fail;
3447c18ec02fSPetter Reinholdtsen 		}
3448176774cfSZdenek Styblik 		if (rc == 2) {
3449176774cfSZdenek Styblik 			lprintf(LOG_DEBUG, "Retry lanplus open session, %d", retry);
3450176774cfSZdenek Styblik 			continue;
3451176774cfSZdenek Styblik 		}
3452c18ec02fSPetter Reinholdtsen 		/*
3453c18ec02fSPetter Reinholdtsen 		 * RAKP 1
3454c18ec02fSPetter Reinholdtsen 		 */
3455176774cfSZdenek Styblik 		if ((rc = ipmi_lanplus_rakp1(intf)) == 1) {
3456c18ec02fSPetter Reinholdtsen 			intf->close(intf);
3457c18ec02fSPetter Reinholdtsen 			goto fail;
3458c18ec02fSPetter Reinholdtsen 		}
3459176774cfSZdenek Styblik 		if (rc == 2) {
3460176774cfSZdenek Styblik 			lprintf(LOG_DEBUG, "Retry lanplus rakp1, %d", retry);
3461176774cfSZdenek Styblik 			continue;
3462176774cfSZdenek Styblik 		}
3463c18ec02fSPetter Reinholdtsen 		/*
3464c18ec02fSPetter Reinholdtsen 		 * RAKP 3
3465c18ec02fSPetter Reinholdtsen 		 */
3466176774cfSZdenek Styblik 		if ((rc = ipmi_lanplus_rakp3(intf)) == 1) {
3467c18ec02fSPetter Reinholdtsen 			intf->close(intf);
3468c18ec02fSPetter Reinholdtsen 			goto fail;
3469c18ec02fSPetter Reinholdtsen 		}
3470176774cfSZdenek Styblik 		if (rc == 0) break;
3471176774cfSZdenek Styblik 		lprintf(LOG_DEBUG,"Retry lanplus rakp3, %d", retry);
3472176774cfSZdenek Styblik 	}
3473c18ec02fSPetter Reinholdtsen 
3474c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "IPMIv2 / RMCP+ SESSION OPENED SUCCESSFULLY\n");
3475c18ec02fSPetter Reinholdtsen 
3476c18ec02fSPetter Reinholdtsen 	if (!ipmi_oem_active(intf, "i82571spt")) {
3477c18ec02fSPetter Reinholdtsen 		rc = ipmi_set_session_privlvl_cmd(intf);
3478176774cfSZdenek Styblik 		if (rc < 0) {
3479176774cfSZdenek Styblik 			intf->close(intf);
3480c18ec02fSPetter Reinholdtsen 			goto fail;
3481c18ec02fSPetter Reinholdtsen 		}
3482176774cfSZdenek Styblik 	}
3483c18ec02fSPetter Reinholdtsen 	intf->manufacturer_id = ipmi_get_oem(intf);
3484c18ec02fSPetter Reinholdtsen 	bridgePossible = 1;
3485c18ec02fSPetter Reinholdtsen 
348623e9340bSZdenek Styblik 	/* automatically detect interface request and response sizes */
348723e9340bSZdenek Styblik 	hpm2_detect_max_payload_size(intf);
348823e9340bSZdenek Styblik 
3489c18ec02fSPetter Reinholdtsen 	return intf->fd;
3490c18ec02fSPetter Reinholdtsen 
3491c18ec02fSPetter Reinholdtsen  fail:
3492c18ec02fSPetter Reinholdtsen 	lprintf(LOG_ERR, "Error: Unable to establish IPMI v2 / RMCP+ session");
3493c18ec02fSPetter Reinholdtsen 	intf->opened = 0;
3494c18ec02fSPetter Reinholdtsen 	return -1;
3495c18ec02fSPetter Reinholdtsen }
3496c18ec02fSPetter Reinholdtsen 
3497c18ec02fSPetter Reinholdtsen 
3498c18ec02fSPetter Reinholdtsen 
3499c18ec02fSPetter Reinholdtsen void test_crypt1(void)
3500c18ec02fSPetter Reinholdtsen {
3501c18ec02fSPetter Reinholdtsen 	uint8_t key[]  =
3502c18ec02fSPetter Reinholdtsen 		{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
3503c18ec02fSPetter Reinholdtsen 		 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14};
3504c18ec02fSPetter Reinholdtsen 
3505c18ec02fSPetter Reinholdtsen 	uint16_t  bytes_encrypted;
3506c18ec02fSPetter Reinholdtsen 	uint16_t  bytes_decrypted;
3507c18ec02fSPetter Reinholdtsen 	uint8_t   decrypt_buffer[1000];
3508c18ec02fSPetter Reinholdtsen 	uint8_t   encrypt_buffer[1000];
3509c18ec02fSPetter Reinholdtsen 
3510c18ec02fSPetter Reinholdtsen 	uint8_t data[] =
3511c18ec02fSPetter Reinholdtsen 		{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
3512c18ec02fSPetter Reinholdtsen 		 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
3513c18ec02fSPetter Reinholdtsen 		 0x11, 0x12};
3514c18ec02fSPetter Reinholdtsen 
3515c18ec02fSPetter Reinholdtsen 	printbuf(data, sizeof(data), "original data");
3516c18ec02fSPetter Reinholdtsen 
3517c18ec02fSPetter Reinholdtsen 	if (lanplus_encrypt_payload(IPMI_CRYPT_AES_CBC_128,
3518c18ec02fSPetter Reinholdtsen 								key,
3519c18ec02fSPetter Reinholdtsen 								data,
3520c18ec02fSPetter Reinholdtsen 								sizeof(data),
3521c18ec02fSPetter Reinholdtsen 								encrypt_buffer,
3522c18ec02fSPetter Reinholdtsen 								&bytes_encrypted))
3523c18ec02fSPetter Reinholdtsen 	{
3524c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Encrypt test failed");
3525c18ec02fSPetter Reinholdtsen 		assert(0);
3526c18ec02fSPetter Reinholdtsen 	}
3527c18ec02fSPetter Reinholdtsen 	printbuf(encrypt_buffer, bytes_encrypted, "encrypted payload");
3528c18ec02fSPetter Reinholdtsen 
3529c18ec02fSPetter Reinholdtsen 
3530c18ec02fSPetter Reinholdtsen 	if (lanplus_decrypt_payload(IPMI_CRYPT_AES_CBC_128,
3531c18ec02fSPetter Reinholdtsen 								key,
3532c18ec02fSPetter Reinholdtsen 								encrypt_buffer,
3533c18ec02fSPetter Reinholdtsen 								bytes_encrypted,
3534c18ec02fSPetter Reinholdtsen 								decrypt_buffer,
3535c18ec02fSPetter Reinholdtsen 								&bytes_decrypted))
3536c18ec02fSPetter Reinholdtsen 	{
3537c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Decrypt test failed\n");
3538c18ec02fSPetter Reinholdtsen 		assert(0);
3539c18ec02fSPetter Reinholdtsen 	}
3540c18ec02fSPetter Reinholdtsen 	printbuf(decrypt_buffer, bytes_decrypted, "decrypted payload");
3541c18ec02fSPetter Reinholdtsen 
3542c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "\nDone testing the encrypt/decyrpt methods!\n");
3543c18ec02fSPetter Reinholdtsen 	exit(0);
3544c18ec02fSPetter Reinholdtsen }
3545c18ec02fSPetter Reinholdtsen 
3546c18ec02fSPetter Reinholdtsen 
3547c18ec02fSPetter Reinholdtsen 
3548c18ec02fSPetter Reinholdtsen void test_crypt2(void)
3549c18ec02fSPetter Reinholdtsen {
3550c18ec02fSPetter Reinholdtsen 	uint8_t key[]  =
3551c18ec02fSPetter Reinholdtsen 		{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
3552c18ec02fSPetter Reinholdtsen 		 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14};
3553c18ec02fSPetter Reinholdtsen 	uint8_t iv[]  =
3554c18ec02fSPetter Reinholdtsen 		  {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
3555c18ec02fSPetter Reinholdtsen 			0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14};
3556c18ec02fSPetter Reinholdtsen 	uint8_t data[8] = "12345678";
3557c18ec02fSPetter Reinholdtsen 
3558c18ec02fSPetter Reinholdtsen 	uint8_t encrypt_buffer[1000];
3559c18ec02fSPetter Reinholdtsen 	uint8_t decrypt_buffer[1000];
3560c18ec02fSPetter Reinholdtsen 	uint32_t bytes_encrypted;
3561c18ec02fSPetter Reinholdtsen 	uint32_t bytes_decrypted;
3562c18ec02fSPetter Reinholdtsen 
3563c18ec02fSPetter Reinholdtsen 	printbuf((const uint8_t *)data, strlen((const char *)data), "input data");
3564c18ec02fSPetter Reinholdtsen 
3565c18ec02fSPetter Reinholdtsen 	lanplus_encrypt_aes_cbc_128(iv,
3566c18ec02fSPetter Reinholdtsen 								key,
3567c18ec02fSPetter Reinholdtsen 								data,
3568c18ec02fSPetter Reinholdtsen 								strlen((const char *)data),
3569c18ec02fSPetter Reinholdtsen 								encrypt_buffer,
3570c18ec02fSPetter Reinholdtsen 								&bytes_encrypted);
3571c18ec02fSPetter Reinholdtsen 	printbuf((const uint8_t *)encrypt_buffer, bytes_encrypted, "encrypt_buffer");
3572c18ec02fSPetter Reinholdtsen 
3573c18ec02fSPetter Reinholdtsen 	lanplus_decrypt_aes_cbc_128(iv,
3574c18ec02fSPetter Reinholdtsen 								key,
3575c18ec02fSPetter Reinholdtsen 								encrypt_buffer,
3576c18ec02fSPetter Reinholdtsen 								bytes_encrypted,
3577c18ec02fSPetter Reinholdtsen 								decrypt_buffer,
3578c18ec02fSPetter Reinholdtsen 								&bytes_decrypted);
3579c18ec02fSPetter Reinholdtsen 	printbuf((const uint8_t *)decrypt_buffer, bytes_decrypted, "decrypt_buffer");
3580c18ec02fSPetter Reinholdtsen 
3581c18ec02fSPetter Reinholdtsen 	lprintf(LOG_INFO, "\nDone testing the encrypt/decyrpt methods!\n");
3582c18ec02fSPetter Reinholdtsen 	exit(0);
3583c18ec02fSPetter Reinholdtsen }
3584c18ec02fSPetter Reinholdtsen 
3585c18ec02fSPetter Reinholdtsen 
3586c18ec02fSPetter Reinholdtsen /**
3587c18ec02fSPetter Reinholdtsen  * send a get device id command to keep session active
3588c18ec02fSPetter Reinholdtsen  */
3589c18ec02fSPetter Reinholdtsen static int
3590c18ec02fSPetter Reinholdtsen ipmi_lanplus_keepalive(struct ipmi_intf * intf)
3591c18ec02fSPetter Reinholdtsen {
3592c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
3593c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req = { msg: {
3594c18ec02fSPetter Reinholdtsen 		netfn: IPMI_NETFN_APP,
3595c18ec02fSPetter Reinholdtsen 		cmd: 1,
3596c18ec02fSPetter Reinholdtsen 	}};
3597c18ec02fSPetter Reinholdtsen 
3598c18ec02fSPetter Reinholdtsen 	if (!intf->opened)
3599c18ec02fSPetter Reinholdtsen 		return 0;
3600c18ec02fSPetter Reinholdtsen 
3601c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
3602c18ec02fSPetter Reinholdtsen 	while (rsp != NULL && is_sol_packet(rsp)) {
3603c18ec02fSPetter Reinholdtsen 					 /* rsp was SOL data instead of our answer */
3604c18ec02fSPetter Reinholdtsen 					 /* since it didn't go through the sol recv, do sol recv stuff here */
3605c18ec02fSPetter Reinholdtsen 					 ack_sol_packet(intf, rsp);
3606c18ec02fSPetter Reinholdtsen 					 check_sol_packet_for_new_data(intf, rsp);
3607c18ec02fSPetter Reinholdtsen 					 if (rsp->data_len)
3608c18ec02fSPetter Reinholdtsen 								intf->session->sol_data.sol_input_handler(rsp);
3609c18ec02fSPetter Reinholdtsen 		rsp = ipmi_lan_poll_recv(intf);
3610c18ec02fSPetter Reinholdtsen 		if (rsp == NULL) /* the get device id answer never got back, but retry mechanism was bypassed by SOL data */
3611c18ec02fSPetter Reinholdtsen 			return 0; /* so get device id command never returned, the connection is still alive */
3612c18ec02fSPetter Reinholdtsen 		  }
3613c18ec02fSPetter Reinholdtsen 
3614c18ec02fSPetter Reinholdtsen 	if (rsp == NULL)
3615c18ec02fSPetter Reinholdtsen 		return -1;
3616c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0)
3617c18ec02fSPetter Reinholdtsen 		return -1;
3618c18ec02fSPetter Reinholdtsen 
3619c18ec02fSPetter Reinholdtsen 	return 0;
3620c18ec02fSPetter Reinholdtsen }
3621c18ec02fSPetter Reinholdtsen 
3622c18ec02fSPetter Reinholdtsen 
3623c18ec02fSPetter Reinholdtsen /**
3624c18ec02fSPetter Reinholdtsen  * ipmi_lanplus_setup
3625c18ec02fSPetter Reinholdtsen  */
3626c18ec02fSPetter Reinholdtsen static int ipmi_lanplus_setup(struct ipmi_intf * intf)
3627c18ec02fSPetter Reinholdtsen {
3628c18ec02fSPetter Reinholdtsen 	//test_crypt1();
3629c18ec02fSPetter Reinholdtsen 	assert("ipmi_lanplus_setup");
3630c18ec02fSPetter Reinholdtsen 
3631c18ec02fSPetter Reinholdtsen 	if (lanplus_seed_prng(16))
3632c18ec02fSPetter Reinholdtsen 		return -1;
3633c18ec02fSPetter Reinholdtsen 
3634c18ec02fSPetter Reinholdtsen 	intf->session = malloc(sizeof(struct ipmi_session));
3635c18ec02fSPetter Reinholdtsen 	if (intf->session == NULL) {
3636c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
3637c18ec02fSPetter Reinholdtsen 		return -1;
3638c18ec02fSPetter Reinholdtsen 	}
3639c18ec02fSPetter Reinholdtsen 	memset(intf->session, 0, sizeof(struct ipmi_session));
364023e9340bSZdenek Styblik 
364123e9340bSZdenek Styblik     /* setup default LAN maximum request and response sizes */
364223e9340bSZdenek Styblik     intf->max_request_data_size = IPMI_LAN_MAX_REQUEST_SIZE;
364323e9340bSZdenek Styblik     intf->max_response_data_size = IPMI_LAN_MAX_RESPONSE_SIZE;
364423e9340bSZdenek Styblik 
3645c18ec02fSPetter Reinholdtsen 	return 0;
3646c18ec02fSPetter Reinholdtsen }
364723e9340bSZdenek Styblik 
364823e9340bSZdenek Styblik static void ipmi_lanp_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size)
364923e9340bSZdenek Styblik {
365023e9340bSZdenek Styblik 	if (intf->session->cipher_suite_id == 3) {
365123e9340bSZdenek Styblik 		/*
365223e9340bSZdenek Styblik 		 * encrypted payload can only be multiple of 16 bytes
365323e9340bSZdenek Styblik 		 */
365423e9340bSZdenek Styblik 		size &= ~15;
365523e9340bSZdenek Styblik 
365623e9340bSZdenek Styblik 		/*
365723e9340bSZdenek Styblik 		 * decrement payload size on confidentiality header size
365823e9340bSZdenek Styblik 		 * plus minimal confidentiality trailer size
365923e9340bSZdenek Styblik 		 */
366023e9340bSZdenek Styblik 		size -= (16 + 1);
366123e9340bSZdenek Styblik 	}
366223e9340bSZdenek Styblik 
366323e9340bSZdenek Styblik 	intf->max_request_data_size = size;
366423e9340bSZdenek Styblik }
366523e9340bSZdenek Styblik 
366623e9340bSZdenek Styblik static void ipmi_lanp_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size)
366723e9340bSZdenek Styblik {
366823e9340bSZdenek Styblik 	if (intf->session->cipher_suite_id == 3) {
366923e9340bSZdenek Styblik 		/*
367023e9340bSZdenek Styblik 		 * encrypted payload can only be multiple of 16 bytes
367123e9340bSZdenek Styblik 		 */
367223e9340bSZdenek Styblik 		size &= ~15;
367323e9340bSZdenek Styblik 
367423e9340bSZdenek Styblik 		/*
367523e9340bSZdenek Styblik 		 * decrement payload size on confidentiality header size
367623e9340bSZdenek Styblik 		 * plus minimal confidentiality trailer size
367723e9340bSZdenek Styblik 		 */
367823e9340bSZdenek Styblik 		size -= (16 + 1);
367923e9340bSZdenek Styblik 	}
368023e9340bSZdenek Styblik 
368123e9340bSZdenek Styblik 	intf->max_response_data_size = size;
368223e9340bSZdenek Styblik }
3683