Blame src/plugins/lanplus/lanplus.c

Packit Service ed0f68
/*
Packit Service ed0f68
 * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
Packit Service ed0f68
 * 
Packit Service ed0f68
 * Redistribution and use in source and binary forms, with or without
Packit Service ed0f68
 * modification, are permitted provided that the following conditions
Packit Service ed0f68
 * are met:
Packit Service ed0f68
 * 
Packit Service ed0f68
 * Redistribution of source code must retain the above copyright
Packit Service ed0f68
 * notice, this list of conditions and the following disclaimer.
Packit Service ed0f68
 * 
Packit Service ed0f68
 * Redistribution in binary form must reproduce the above copyright
Packit Service ed0f68
 * notice, this list of conditions and the following disclaimer in the
Packit Service ed0f68
 * documentation and/or other materials provided with the distribution.
Packit Service ed0f68
 * 
Packit Service ed0f68
 * Neither the name of Sun Microsystems, Inc. or the names of
Packit Service ed0f68
 * contributors may be used to endorse or promote products derived
Packit Service ed0f68
 * from this software without specific prior written permission.
Packit Service ed0f68
 * 
Packit Service ed0f68
 * This software is provided "AS IS," without a warranty of any kind.
Packit Service ed0f68
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
Packit Service ed0f68
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
Packit Service ed0f68
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
Packit Service ed0f68
 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
Packit Service ed0f68
 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
Packit Service ed0f68
 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
Packit Service ed0f68
 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
Packit Service ed0f68
 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
Packit Service ed0f68
 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
Packit Service ed0f68
 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
Packit Service ed0f68
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
Packit Service ed0f68
 */
Packit Service ed0f68
#define _GNU_SOURCE
Packit Service ed0f68
Packit Service ed0f68
#include <stdlib.h>
Packit Service ed0f68
#include <stdio.h>
Packit Service ed0f68
#include <inttypes.h>
Packit Service ed0f68
#include <string.h>
Packit Service ed0f68
#include <sys/time.h>
Packit Service ed0f68
#include <sys/types.h>
Packit Service ed0f68
#include <sys/select.h>
Packit Service ed0f68
#include <sys/socket.h>
Packit Service ed0f68
#include <netinet/in.h>
Packit Service ed0f68
#include <arpa/inet.h>
Packit Service ed0f68
#include <errno.h>
Packit Service ed0f68
#include <unistd.h>
Packit Service ed0f68
#include <netdb.h>
Packit Service ed0f68
#include <time.h>
Packit Service ed0f68
#include <fcntl.h>
Packit Service ed0f68
#include <assert.h>
Packit Service ed0f68
Packit Service ed0f68
#ifdef HAVE_CONFIG_H
Packit Service ed0f68
# include <config.h>
Packit Service ed0f68
#endif
Packit Service ed0f68
#include <ipmitool/helper.h>
Packit Service ed0f68
#include <ipmitool/log.h>
Packit Service ed0f68
#include <ipmitool/ipmi.h>
Packit Service ed0f68
#include <ipmitool/ipmi_lanp.h>
Packit Service ed0f68
#include <ipmitool/ipmi_channel.h>
Packit Service ed0f68
#include <ipmitool/ipmi_intf.h>
Packit Service ed0f68
#include <ipmitool/ipmi_sel.h>
Packit Service ed0f68
#include <ipmitool/ipmi_strings.h>
Packit Service ed0f68
#include <ipmitool/hpm2.h>
Packit Service ed0f68
#include <ipmitool/bswap.h>
Packit Service ed0f68
#include <openssl/rand.h>
Packit Service ed0f68
Packit Service ed0f68
#include "lanplus.h"
Packit Service ed0f68
#include "lanplus_crypt.h"
Packit Service ed0f68
#include "lanplus_crypt_impl.h"
Packit Service ed0f68
#include "lanplus_dump.h"
Packit Service ed0f68
#include "rmcp.h"
Packit Service ed0f68
#include "asf.h"
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * LAN interface is required to support 45 byte request transactions and
Packit Service ed0f68
 * 42 byte response transactions.
Packit Service ed0f68
 */
Packit Service ed0f68
#define IPMI_LAN_MAX_REQUEST_SIZE	38	/* 45 - 7 */
Packit Service ed0f68
#define IPMI_LAN_MAX_RESPONSE_SIZE	34	/* 42 - 8 */
Packit Service ed0f68
Packit Service ed0f68
extern const struct valstr ipmi_rakp_return_codes[];
Packit Service ed0f68
extern const struct valstr ipmi_priv_levels[];
Packit Service ed0f68
extern const struct valstr ipmi_auth_algorithms[];
Packit Service ed0f68
extern const struct valstr ipmi_integrity_algorithms[];
Packit Service ed0f68
extern const struct valstr ipmi_encryption_algorithms[];
Packit Service ed0f68
Packit Service ed0f68
static struct ipmi_rq_entry * ipmi_req_entries;
Packit Service ed0f68
static struct ipmi_rq_entry * ipmi_req_entries_tail;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
static int ipmi_lanplus_setup(struct ipmi_intf * intf);
Packit Service ed0f68
static int ipmi_lanplus_keepalive(struct ipmi_intf * intf);
Packit Service ed0f68
static int ipmi_lan_send_packet(struct ipmi_intf * intf, uint8_t * data, int data_len);
Packit Service ed0f68
static struct ipmi_rs * ipmi_lan_recv_packet(struct ipmi_intf * intf);
Packit Service ed0f68
static struct ipmi_rs * ipmi_lan_poll_recv(struct ipmi_intf * intf);
Packit Service ed0f68
static struct ipmi_rs * ipmi_lanplus_send_ipmi_cmd(struct ipmi_intf * intf, struct ipmi_rq * req);
Packit Service ed0f68
static struct ipmi_rs * ipmi_lanplus_send_payload(struct ipmi_intf * intf,
Packit Service ed0f68
												  struct ipmi_v2_payload * payload);
Packit Service ed0f68
static void getIpmiPayloadWireRep(
Packit Service ed0f68
								  struct ipmi_intf       * intf,
Packit Service ed0f68
								  struct ipmi_v2_payload * payload,  /* in  */
Packit Service ed0f68
								  uint8_t  * out,
Packit Service ed0f68
								  struct ipmi_rq * req,
Packit Service ed0f68
								  uint8_t    rq_seq,
Packit Service ed0f68
								  uint8_t curr_seq);
Packit Service ed0f68
static void getSolPayloadWireRep(
Packit Service ed0f68
								  struct ipmi_intf       * intf,
Packit Service ed0f68
								 uint8_t          * msg,
Packit Service ed0f68
								 struct ipmi_v2_payload * payload);
Packit Service ed0f68
static void read_open_session_response(struct ipmi_rs * rsp, int offset);
Packit Service ed0f68
static void read_rakp2_message(struct ipmi_rs * rsp, int offset, uint8_t alg);
Packit Service ed0f68
static void read_rakp4_message(struct ipmi_rs * rsp, int offset, uint8_t alg);
Packit Service ed0f68
static void read_session_data(struct ipmi_rs * rsp, int * offset, struct ipmi_session *s);
Packit Service ed0f68
static void read_session_data_v15(struct ipmi_rs * rsp, int * offset, struct ipmi_session *s);
Packit Service ed0f68
static void read_session_data_v2x(struct ipmi_rs * rsp, int * offset, struct ipmi_session *s);
Packit Service ed0f68
static void read_ipmi_response(struct ipmi_rs * rsp, int * offset);
Packit Service ed0f68
static void read_sol_packet(struct ipmi_rs * rsp, int * offset);
Packit Service ed0f68
static struct ipmi_rs * ipmi_lanplus_recv_sol(struct ipmi_intf * intf);
Packit Service ed0f68
static struct ipmi_rs * ipmi_lanplus_send_sol(
Packit Service ed0f68
											  struct ipmi_intf * intf,
Packit Service ed0f68
											  struct ipmi_v2_payload * payload);
Packit Service ed0f68
static int check_sol_packet_for_new_data(
Packit Service ed0f68
									 struct ipmi_intf * intf,
Packit Service ed0f68
									 struct ipmi_rs *rsp);
Packit Service ed0f68
static void ack_sol_packet(
Packit Service ed0f68
							struct ipmi_intf * intf,
Packit Service ed0f68
							struct ipmi_rs * rsp);
Packit Service ed0f68
static void ipmi_lanp_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size);
Packit Service ed0f68
static void ipmi_lanp_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size);
Packit Service ed0f68
Packit Service ed0f68
static uint8_t bridgePossible = 0;
Packit Service ed0f68
Packit Service ed0f68
struct ipmi_intf ipmi_lanplus_intf = {
Packit Service ed0f68
	.name = "lanplus",
Packit Service ed0f68
	.desc = "IPMI v2.0 RMCP+ LAN Interface",
Packit Service ed0f68
	.setup = ipmi_lanplus_setup,
Packit Service ed0f68
	.open = ipmi_lanplus_open,
Packit Service ed0f68
	.close = ipmi_lanplus_close,
Packit Service ed0f68
	.sendrecv = ipmi_lanplus_send_ipmi_cmd,
Packit Service ed0f68
	.recv_sol = ipmi_lanplus_recv_sol,
Packit Service ed0f68
	.send_sol = ipmi_lanplus_send_sol,
Packit Service ed0f68
	.keepalive = ipmi_lanplus_keepalive,
Packit Service ed0f68
	.set_max_request_data_size = ipmi_lanp_set_max_rq_data_size,
Packit Service ed0f68
	.set_max_response_data_size = ipmi_lanp_set_max_rp_data_size,
Packit Service ed0f68
	.target_addr = IPMI_BMC_SLAVE_ADDR,
Packit Service ed0f68
};
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
extern int verbose;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * lanplus_get_requested_ciphers
Packit Service ed0f68
 *
Packit Service ed0f68
 * Set the authentication, integrity and encryption algorithms based
Packit Service ed0f68
 * on the cipher suite ID.  See table 22-19 in the IPMIv2 spec for the
Packit Service ed0f68
 * source of this information.
Packit Service ed0f68
 *
Packit Service ed0f68
 * param cipher_suite_id [in]
Packit Service ed0f68
 * param auth_alg        [out]
Packit Service ed0f68
 * param integrity_alg   [out]
Packit Service ed0f68
 * param crypt_alg       [out]
Packit Service ed0f68
 *
Packit Service ed0f68
 * returns 0 on success
Packit Service ed0f68
 *         1 on failure
Packit Service ed0f68
 */
Packit Service 9e6181
int lanplus_get_requested_ciphers(enum cipher_suite_ids cipher_suite_id,
Packit Service ed0f68
								  uint8_t * auth_alg,
Packit Service ed0f68
								  uint8_t * integrity_alg,
Packit Service ed0f68
								  uint8_t * crypt_alg)
Packit Service ed0f68
{
Packit Service ed0f68
		/* See table 22-19 for the source of the statement */
Packit Service ed0f68
	switch (cipher_suite_id)
Packit Service ed0f68
	{
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_0:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_NONE;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_NONE;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_NONE;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_1:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA1;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_NONE;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_NONE;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_2:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA1;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_NONE;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_3:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA1;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_AES_CBC_128;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_4:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA1;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_XRC4_128;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_5:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA1;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_XRC4_40;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_6:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_NONE;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_NONE;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_7:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_NONE;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_8:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_AES_CBC_128;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_9:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_XRC4_128;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_10:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_XRC4_40;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_11:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_MD5_128;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_NONE;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_12:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_MD5_128;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_AES_CBC_128;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_13:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_MD5_128;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_XRC4_128;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_14:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_MD5;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_MD5_128;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_XRC4_40;
Packit Service ed0f68
		break;
Packit Service ed0f68
#ifdef HAVE_CRYPTO_SHA256
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_15:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA256;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_NONE;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_NONE;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_16:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA256;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_HMAC_SHA256_128;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_NONE;
Packit Service ed0f68
		break;
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_17:
Packit Service ed0f68
		*auth_alg      = IPMI_AUTH_RAKP_HMAC_SHA256;
Packit Service ed0f68
		*integrity_alg = IPMI_INTEGRITY_HMAC_SHA256_128;
Packit Service ed0f68
		*crypt_alg     = IPMI_CRYPT_AES_CBC_128;
Packit Service ed0f68
		break;
Packit Service ed0f68
#endif /* HAVE_CRYPTO_SHA256 */
Packit Service 9e6181
	case IPMI_LANPLUS_CIPHER_SUITE_RESERVED:
Packit Service 9e6181
	default:
Packit Service 9e6181
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * Reverse the order of arbitrarily long strings of bytes
Packit Service ed0f68
 */
Packit Service ed0f68
void lanplus_swap(
Packit Service ed0f68
				  uint8_t * buffer,
Packit Service ed0f68
						int             length)
Packit Service ed0f68
{
Packit Service ed0f68
	int i;
Packit Service ed0f68
	uint8_t temp;
Packit Service ed0f68
Packit Service ed0f68
	for (i =0; i < length/2; ++i)
Packit Service ed0f68
	{
Packit Service ed0f68
		temp = buffer[i];
Packit Service ed0f68
		buffer[i] = buffer[length - 1 - i];
Packit Service ed0f68
		buffer[length - 1 - i] = temp;
Packit Service ed0f68
	}
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
static const struct valstr plus_payload_types_vals[] = {
Packit Service ed0f68
	 { IPMI_PAYLOAD_TYPE_IPMI,              "IPMI (0)" },	// IPMI Message
Packit Service ed0f68
	 { IPMI_PAYLOAD_TYPE_SOL,               "SOL  (1)" },	// SOL (Serial over LAN)
Packit Service ed0f68
	 { IPMI_PAYLOAD_TYPE_OEM,               "OEM  (2)" },	// OEM Explicid
Packit Service ed0f68
Packit Service ed0f68
	 { IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST, "OpenSession Req (0x10)" },
Packit Service ed0f68
	 { IPMI_PAYLOAD_TYPE_RMCP_OPEN_RESPONSE,"OpenSession Resp (0x11)" },
Packit Service ed0f68
	 { IPMI_PAYLOAD_TYPE_RAKP_1,            "RAKP1 (0x12)" },
Packit Service ed0f68
	 { IPMI_PAYLOAD_TYPE_RAKP_2,            "RAKP2 (0x13)" },
Packit Service ed0f68
	 { IPMI_PAYLOAD_TYPE_RAKP_3,            "RAKP3 (0x14)" },
Packit Service ed0f68
	 { IPMI_PAYLOAD_TYPE_RAKP_4,            "RAKP4 (0x15)" },
Packit Service ed0f68
	{ 0x00, NULL },
Packit Service ed0f68
};
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
static struct ipmi_rq_entry *
Packit Service ed0f68
ipmi_req_add_entry(struct ipmi_intf * intf, struct ipmi_rq * req, uint8_t req_seq)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rq_entry * e;
Packit Service ed0f68
Packit Service ed0f68
	e = malloc(sizeof(struct ipmi_rq_entry));
Packit Service ed0f68
	if (e == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit Service ed0f68
		return NULL;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	memset(e, 0, sizeof(struct ipmi_rq_entry));
Packit Service ed0f68
	memcpy(&e->req, req, sizeof(struct ipmi_rq));
Packit Service ed0f68
Packit Service ed0f68
	e->intf = intf;
Packit Service ed0f68
	e->rq_seq = req_seq;
Packit Service ed0f68
Packit Service ed0f68
	if (ipmi_req_entries == NULL)
Packit Service ed0f68
		ipmi_req_entries = e;
Packit Service ed0f68
	else
Packit Service ed0f68
		ipmi_req_entries_tail->next = e;
Packit Service ed0f68
Packit Service ed0f68
	ipmi_req_entries_tail = e;
Packit Service ed0f68
	lprintf(LOG_DEBUG+3, "added list entry seq=0x%02x cmd=0x%02x",
Packit Service ed0f68
		e->rq_seq, e->req.msg.cmd);     
Packit Service ed0f68
	return e;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
static struct ipmi_rq_entry *
Packit Service ed0f68
ipmi_req_lookup_entry(uint8_t seq, uint8_t cmd)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rq_entry * e = ipmi_req_entries;
Packit Service ed0f68
Packit Service ed0f68
	while (e && (e->rq_seq != seq || e->req.msg.cmd != cmd)) {
Packit Service ed0f68
		if (e == e->next)
Packit Service ed0f68
			return NULL;
Packit Service ed0f68
		e = e->next;
Packit Service ed0f68
	}
Packit Service ed0f68
	return e;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static void
Packit Service ed0f68
ipmi_req_remove_entry(uint8_t seq, uint8_t cmd)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rq_entry * p, * e, * saved_next_entry;
Packit Service ed0f68
Packit Service ed0f68
	e = p = ipmi_req_entries;
Packit Service ed0f68
Packit Service ed0f68
	while (e && (e->rq_seq != seq || e->req.msg.cmd != cmd)) {
Packit Service ed0f68
		p = e;
Packit Service ed0f68
		e = e->next;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (e) {
Packit Service ed0f68
		lprintf(LOG_DEBUG+3, "removed list entry seq=0x%02x cmd=0x%02x",
Packit Service ed0f68
			seq, cmd);
Packit Service ed0f68
		saved_next_entry = e->next;
Packit Service ed0f68
		p->next = (p->next == e->next) ? NULL : e->next;
Packit Service ed0f68
		/* If entry being removed is first in list, fix up list head */
Packit Service ed0f68
		if (ipmi_req_entries == e) {
Packit Service ed0f68
			if (ipmi_req_entries != p)
Packit Service ed0f68
				ipmi_req_entries = p;
Packit Service ed0f68
			else
Packit Service ed0f68
				ipmi_req_entries = saved_next_entry;
Packit Service ed0f68
		}
Packit Service ed0f68
		/* If entry being removed is last in list, fix up list tail */
Packit Service ed0f68
		if (ipmi_req_entries_tail == e) {
Packit Service ed0f68
			if (ipmi_req_entries_tail != p)
Packit Service ed0f68
				ipmi_req_entries_tail = p;
Packit Service ed0f68
			else
Packit Service ed0f68
				ipmi_req_entries_tail = NULL;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		if (e->msg_data) {
Packit Service ed0f68
			free(e->msg_data);
Packit Service ed0f68
			e->msg_data = NULL;
Packit Service ed0f68
		}
Packit Service ed0f68
		free(e);
Packit Service ed0f68
		e = NULL;
Packit Service ed0f68
	}
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static void
Packit Service ed0f68
ipmi_req_clear_entries(void)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rq_entry * p, * e;
Packit Service ed0f68
Packit Service ed0f68
	e = ipmi_req_entries;
Packit Service ed0f68
	while (e) {
Packit Service ed0f68
		lprintf(LOG_DEBUG+3, "cleared list entry seq=0x%02x cmd=0x%02x",
Packit Service ed0f68
			e->rq_seq, e->req.msg.cmd);
Packit Service ed0f68
		p = e->next;
Packit Service ed0f68
		free(e);
Packit Service ed0f68
		e = p;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	ipmi_req_entries = NULL;
Packit Service ed0f68
	ipmi_req_entries_tail = NULL;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
ipmi_lan_send_packet(
Packit Service ed0f68
					 struct ipmi_intf * intf,
Packit Service ed0f68
					 uint8_t * data, int
Packit Service ed0f68
					 data_len)
Packit Service ed0f68
{
Packit Service ed0f68
	if (verbose >= 5)
Packit Service ed0f68
		printbuf(data, data_len, ">> sending packet");
Packit Service ed0f68
Packit Service ed0f68
	return send(intf->fd, data, data_len, 0);
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
struct ipmi_rs *
Packit Service ed0f68
ipmi_lan_recv_packet(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	static struct ipmi_rs rsp;
Packit Service ed0f68
	fd_set read_set, err_set;
Packit Service ed0f68
	struct timeval tmout;
Packit Service ed0f68
	int ret;
Packit Service ed0f68
Packit Service ed0f68
	FD_ZERO(&read_set);
Packit Service ed0f68
	FD_SET(intf->fd, &read_set);
Packit Service ed0f68
Packit Service ed0f68
	FD_ZERO(&err_set);
Packit Service ed0f68
	FD_SET(intf->fd, &err_set);
Packit Service ed0f68
Packit Service ed0f68
	tmout.tv_sec = intf->session->timeout;
Packit Service ed0f68
	tmout.tv_usec = 0;
Packit Service ed0f68
Packit Service ed0f68
	ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout);
Packit Service ed0f68
	if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set))
Packit Service ed0f68
		return NULL;
Packit Service ed0f68
Packit Service ed0f68
	/* the first read may return ECONNREFUSED because the rmcp ping
Packit Service ed0f68
	 * packet--sent to UDP port 623--will be processed by both the
Packit Service ed0f68
	 * BMC and the OS.
Packit Service ed0f68
	 *
Packit Service ed0f68
	 * The problem with this is that the ECONNREFUSED takes
Packit Service ed0f68
	 * priority over any other received datagram; that means that
Packit Service ed0f68
	 * the Connection Refused shows up _before_ the response packet,
Packit Service ed0f68
	 * regardless of the order they were sent out.  (unless the
Packit Service ed0f68
	 * response is read before the connection refused is returned)
Packit Service ed0f68
	 */
Packit Service ed0f68
	ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0);
Packit Service ed0f68
Packit Service ed0f68
	if (ret < 0) {
Packit Service ed0f68
		FD_ZERO(&read_set);
Packit Service ed0f68
		FD_SET(intf->fd, &read_set);
Packit Service ed0f68
Packit Service ed0f68
		FD_ZERO(&err_set);
Packit Service ed0f68
		FD_SET(intf->fd, &err_set);
Packit Service ed0f68
Packit Service ed0f68
		tmout.tv_sec = intf->session->timeout;
Packit Service ed0f68
		tmout.tv_usec = 0;
Packit Service ed0f68
Packit Service ed0f68
		ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout);
Packit Service ed0f68
		if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set))
Packit Service ed0f68
			return NULL;
Packit Service ed0f68
Packit Service ed0f68
		ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0);
Packit Service ed0f68
		if (ret < 0)
Packit Service ed0f68
			return NULL;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (ret == 0)
Packit Service ed0f68
		return NULL;
Packit Service ed0f68
Packit Service ed0f68
	rsp.data[ret] = '\0';
Packit Service ed0f68
	rsp.data_len = ret;
Packit Service ed0f68
Packit Service ed0f68
	if (verbose >= 5)
Packit Service ed0f68
		printbuf(rsp.data, rsp.data_len, "<< received packet");
Packit Service ed0f68
Packit Service ed0f68
	return &rsp;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * parse response RMCP "pong" packet
Packit Service ed0f68
 *
Packit Service ed0f68
 * return -1 if ping response not received
Packit Service ed0f68
 * returns 0 if IPMI is NOT supported
Packit Service ed0f68
 * returns 1 if IPMI is supported
Packit Service ed0f68
 *
Packit Service ed0f68
 * udp.source	= 0x026f	// RMCP_UDP_PORT
Packit Service ed0f68
 * udp.dest	= ?		// udp.source from rmcp-ping
Packit Service ed0f68
 * udp.len	= ?
Packit Service ed0f68
 * udp.check	= ?
Packit Service ed0f68
 * rmcp.ver	= 0x06		// RMCP Version 1.0
Packit Service ed0f68
 * rmcp.__res	= 0x00		// RESERVED
Packit Service ed0f68
 * rmcp.seq	= 0xff		// no RMCP ACK
Packit Service ed0f68
 * rmcp.class	= 0x06		// RMCP_CLASS_ASF
Packit Service ed0f68
 * asf.iana	= 0x000011be	// ASF_RMCP_IANA
Packit Service ed0f68
 * asf.type	= 0x40		// ASF_TYPE_PONG
Packit Service ed0f68
 * asf.tag	= ?		// asf.tag from rmcp-ping
Packit Service ed0f68
 * asf.__res	= 0x00		// RESERVED
Packit Service ed0f68
 * asf.len	= 0x10		// 16 bytes
Packit Service ed0f68
 * asf.data[3:0]= 0x000011be	// IANA# = RMCP_ASF_IANA if no OEM
Packit Service ed0f68
 * asf.data[7:4]= 0x00000000	// OEM-defined (not for IPMI)
Packit Service ed0f68
 * asf.data[8]	= 0x81		// supported entities
Packit Service ed0f68
 * 				// [7]=IPMI [6:4]=RES [3:0]=ASF_1.0
Packit Service ed0f68
 * asf.data[9]	= 0x00		// supported interactions (reserved)
Packit Service ed0f68
 * asf.data[f:a]= 0x000000000000
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_handle_pong(struct ipmi_intf * intf, struct ipmi_rs * rsp)
Packit Service ed0f68
{
Packit Service ed0f68
	struct rmcp_pong {
Packit Service ed0f68
		struct rmcp_hdr rmcp;
Packit Service ed0f68
		struct asf_hdr asf;
Packit Service ed0f68
		uint32_t iana;
Packit Service ed0f68
		uint32_t oem;
Packit Service ed0f68
		uint8_t sup_entities;
Packit Service ed0f68
		uint8_t sup_interact;
Packit Service ed0f68
		uint8_t reserved[6];
Packit Service ed0f68
	} * pong;
Packit Service ed0f68
Packit Service ed0f68
	if (!rsp)
Packit Service ed0f68
		return -1;
Packit Service ed0f68
Packit Service ed0f68
	pong = (struct rmcp_pong *)rsp->data;
Packit Service ed0f68
Packit Service ed0f68
	if (verbose)
Packit Service ed0f68
		printf("Received IPMI/RMCP response packet: "
Packit Service ed0f68
				"IPMI%s Supported\n",
Packit Service ed0f68
				(pong->sup_entities & 0x80) ? "" : " NOT");
Packit Service ed0f68
Packit Service ed0f68
	if (verbose > 1)
Packit Service ed0f68
		printf("  ASF Version %s\n"
Packit Service ed0f68
				"  RMCP Version %s\n"
Packit Service ed0f68
				"  RMCP Sequence %d\n"
Packit Service ed0f68
				"  IANA Enterprise %lu\n\n",
Packit Service ed0f68
				(pong->sup_entities & 0x01) ? "1.0" : "unknown",
Packit Service ed0f68
				(pong->rmcp.ver == 6) ? "1.0" : "unknown",
Packit Service ed0f68
				pong->rmcp.seq,
Packit Service ed0f68
				(unsigned long)ntohl(pong->iana));
Packit Service ed0f68
Packit Service ed0f68
	return (pong->sup_entities & 0x80) ? 1 : 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/* build and send RMCP presence ping packet
Packit Service ed0f68
 *
Packit Service ed0f68
 * RMCP ping
Packit Service ed0f68
 *
Packit Service ed0f68
 * udp.source	= ?
Packit Service ed0f68
 * udp.dest	= 0x026f	// RMCP_UDP_PORT
Packit Service ed0f68
 * udp.len	= ?
Packit Service ed0f68
 * udp.check	= ?
Packit Service ed0f68
 * rmcp.ver	= 0x06		// RMCP Version 1.0
Packit Service ed0f68
 * rmcp.__res	= 0x00		// RESERVED
Packit Service ed0f68
 * rmcp.seq	= 0xff		// no RMCP ACK
Packit Service ed0f68
 * rmcp.class	= 0x06		// RMCP_CLASS_ASF
Packit Service ed0f68
 * asf.iana	= 0x000011be	// ASF_RMCP_IANA
Packit Service ed0f68
 * asf.type	= 0x80		// ASF_TYPE_PING
Packit Service ed0f68
 * asf.tag	= ?		// ASF sequence number
Packit Service ed0f68
 * asf.__res	= 0x00		// RESERVED
Packit Service ed0f68
 * asf.len	= 0x00
Packit Service ed0f68
 *
Packit Service ed0f68
 */
Packit Service ed0f68
int
Packit Service ed0f68
ipmiv2_lan_ping(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct asf_hdr asf_ping = {
Packit Service ed0f68
		.iana	= htonl(ASF_RMCP_IANA),
Packit Service ed0f68
		.type	= ASF_TYPE_PING,
Packit Service ed0f68
	};
Packit Service ed0f68
	struct rmcp_hdr rmcp_ping = {
Packit Service ed0f68
		.ver	= RMCP_VERSION_1,
Packit Service ed0f68
		.class	= RMCP_CLASS_ASF,
Packit Service ed0f68
		.seq	= 0xff,
Packit Service ed0f68
	};
Packit Service ed0f68
	uint8_t * data;
Packit Service ed0f68
	int len = sizeof(rmcp_ping) + sizeof(asf_ping);
Packit Service ed0f68
	int rv;
Packit Service ed0f68
Packit Service ed0f68
	data = malloc(len);
Packit Service ed0f68
	if (data == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	memset(data, 0, len);
Packit Service ed0f68
	memcpy(data, &rmcp_ping, sizeof(rmcp_ping));
Packit Service ed0f68
	memcpy(data+sizeof(rmcp_ping), &asf_ping, sizeof(asf_ping));
Packit Service ed0f68
Packit Service ed0f68
	lprintf(LOG_DEBUG, "Sending IPMI/RMCP presence ping packet");
Packit Service ed0f68
Packit Service ed0f68
	rv = ipmi_lan_send_packet(intf, data, len);
Packit Service ed0f68
Packit Service ed0f68
	free(data);
Packit Service ed0f68
	data = NULL;
Packit Service ed0f68
Packit Service ed0f68
	if (rv < 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Unable to send IPMI presence ping packet");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (ipmi_lan_poll_recv(intf) == 0)
Packit Service ed0f68
		return 0;
Packit Service ed0f68
Packit Service ed0f68
	return 1;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/**
Packit Service ed0f68
 *
Packit Service ed0f68
 * ipmi_lan_poll_single
Packit Service ed0f68
 *
Packit Service ed0f68
 * Receive whatever comes back.  Ignore received packets that don't correspond
Packit Service ed0f68
 * to a request we've sent.
Packit Service ed0f68
 *
Packit Service ed0f68
 * Returns: the ipmi_rs packet describing the/a response we expect.
Packit Service ed0f68
 */
Packit Service ed0f68
static struct ipmi_rs *
Packit Service ed0f68
ipmi_lan_poll_single(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct rmcp_hdr * rmcp_rsp;
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	struct ipmi_session * session = intf->session;
Packit Service ed0f68
	int offset, rv;
Packit Service ed0f68
	uint16_t payload_size;
Packit Service ed0f68
Packit Service ed0f68
	/* receive packet */
Packit Service ed0f68
	rsp = ipmi_lan_recv_packet(intf);
Packit Service ed0f68
Packit Service ed0f68
	/* check if no packet has come */
Packit Service ed0f68
	if (rsp == NULL) {
Packit Service ed0f68
		return NULL;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/* parse response headers */
Packit Service ed0f68
	rmcp_rsp = (struct rmcp_hdr *)rsp->data;
Packit Service ed0f68
Packit Service ed0f68
	if (rmcp_rsp->class == RMCP_CLASS_ASF) {
Packit Service ed0f68
		/* might be ping response packet */
Packit Service ed0f68
		rv = ipmi_handle_pong(intf, rsp);
Packit Service ed0f68
		return (rv <= 0) ? NULL : rsp;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (rmcp_rsp->class != RMCP_CLASS_IPMI) {
Packit Service ed0f68
		lprintf(LOG_DEBUG, "Invalid RMCP class: %x", rmcp_rsp->class);
Packit Service ed0f68
		/* read one more packet */
Packit Service ed0f68
		return (struct ipmi_rs *)1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * The authtype / payload type determines what we are receiving
Packit Service ed0f68
	 */
Packit Service ed0f68
	offset = 4;
Packit Service ed0f68
Packit Service ed0f68
	/*--------------------------------------------------------------------
Packit Service ed0f68
	 *
Packit Service ed0f68
	 * The current packet could be one of several things:
Packit Service ed0f68
	 *
Packit Service ed0f68
	 * 1) An IPMI 1.5 packet (the response to our GET CHANNEL
Packit Service ed0f68
	 *    AUTHENTICATION CAPABILITIES request)
Packit Service ed0f68
	 * 2) An RMCP+ message with an IPMI response payload
Packit Service ed0f68
	 * 3) AN RMCP+ open session response
Packit Service ed0f68
	 * 4) An RAKP-2 message (response to an RAKP 1 message)
Packit Service ed0f68
	 * 5) An RAKP-4 message (response to an RAKP 3 message)
Packit Service ed0f68
	 * 6) A Serial Over LAN packet
Packit Service ed0f68
	 * 7) An Invalid packet (one that doesn't match a request)
Packit Service ed0f68
	 * -------------------------------------------------------------------
Packit Service ed0f68
	 */
Packit Service ed0f68
Packit Service ed0f68
	read_session_data(rsp, &offset, intf->session);
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Skip packets that are not intended for this session
Packit Service ed0f68
	 */
Packit Service ed0f68
	if ((session->v2_data.session_state == LANPLUS_STATE_ACTIVE)    &&
Packit Service ed0f68
		 (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
Packit Service ed0f68
		 (rsp->session.id != intf->session->v2_data.console_id))
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_INFO, "packet session id 0x%x does not "
Packit Service ed0f68
			"match active session 0x%0x",
Packit Service ed0f68
			rsp->session.id, intf->session->v2_data.console_id);
Packit Service ed0f68
		lprintf(LOG_ERR, "ERROR: Received an Unexpected message ID");
Packit Service ed0f68
		/* read one more packet */
Packit Service ed0f68
		return (struct ipmi_rs *)1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (lanplus_has_valid_auth_code(rsp, intf->session) == 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ERROR: Received message with invalid authcode!");
Packit Service ed0f68
		return NULL;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if ((session->v2_data.session_state == LANPLUS_STATE_ACTIVE)    &&
Packit Service ed0f68
			(rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
Packit Service ed0f68
			(rsp->session.bEncrypted)) {
Packit Service ed0f68
		lanplus_decrypt_payload(session->v2_data.crypt_alg,
Packit Service ed0f68
				session->v2_data.k2,
Packit Service ed0f68
				rsp->data + offset,
Packit Service ed0f68
				rsp->session.msglen,
Packit Service ed0f68
				rsp->data + offset,
Packit Service ed0f68
				&payload_size);
Packit Service ed0f68
	} else {
Packit Service ed0f68
		payload_size = rsp->session.msglen;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Handle IPMI responses (case #1 and #2) -- all IPMI responses
Packit Service ed0f68
	 */
Packit Service ed0f68
	if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_IPMI) {
Packit Service ed0f68
		struct ipmi_rq_entry * entry;
Packit Service ed0f68
		int payload_start = offset;
Packit Service ed0f68
		int extra_data_length;
Packit Service ed0f68
		int loop = 1;
Packit Service ed0f68
Packit Service ed0f68
		while (loop--) {
Packit Service ed0f68
			/* fill-in response data */
Packit Service ed0f68
			read_ipmi_response(rsp, &offset);
Packit Service ed0f68
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<< IPMI Response Session Header");
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Authtype                : %s",
Packit Service ed0f68
				val2str(rsp->session.authtype, ipmi_authtype_session_vals));
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Payload type            : %s",
Packit Service ed0f68
				val2str(rsp->session.payloadtype, plus_payload_types_vals));
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Session ID              : 0x%08lx",
Packit Service ed0f68
				(long)rsp->session.id);
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Sequence                : 0x%08lx",
Packit Service ed0f68
				(long)rsp->session.seq);
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   IPMI Msg/Payload Length : %d",
Packit Service ed0f68
				rsp->session.msglen);
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<< IPMI Response Message Header");
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Rq Addr    : %02x",
Packit Service ed0f68
				rsp->payload.ipmi_response.rq_addr);
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   NetFn      : %02x",
Packit Service ed0f68
				rsp->payload.ipmi_response.netfn);
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Rq LUN     : %01x",
Packit Service ed0f68
				rsp->payload.ipmi_response.rq_lun);
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Rs Addr    : %02x",
Packit Service ed0f68
				rsp->payload.ipmi_response.rs_addr);
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Rq Seq     : %02x",
Packit Service ed0f68
				rsp->payload.ipmi_response.rq_seq);
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Rs Lun     : %01x",
Packit Service ed0f68
				rsp->payload.ipmi_response.rs_lun);
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Command    : %02x",
Packit Service ed0f68
				rsp->payload.ipmi_response.cmd);
Packit Service ed0f68
			lprintf(LOG_DEBUG+1, "<<   Compl Code : 0x%02x",
Packit Service ed0f68
				rsp->ccode);
Packit Service ed0f68
Packit Service ed0f68
			/* Are we expecting this packet? */
Packit Service ed0f68
			entry = ipmi_req_lookup_entry(rsp->payload.ipmi_response.rq_seq,
Packit Service ed0f68
								rsp->payload.ipmi_response.cmd);
Packit Service ed0f68
Packit Service ed0f68
			if (entry == NULL) {
Packit Service ed0f68
				lprintf(LOG_INFO, "IPMI Request Match NOT FOUND");
Packit Service ed0f68
				/* read one more packet */
Packit Service ed0f68
				return (struct ipmi_rs *)1;
Packit Service ed0f68
			};
Packit Service ed0f68
Packit Service ed0f68
			uint8_t target_cmd = entry->req.msg.target_cmd;
Packit Service ed0f68
Packit Service ed0f68
			lprintf(LOG_DEBUG+2, "IPMI Request Match found");
Packit Service ed0f68
Packit Service ed0f68
			if (entry->bridging_level) {
Packit Service ed0f68
				/* Check completion code */
Packit Service ed0f68
				if (rsp->ccode) {
Packit Service ed0f68
					lprintf(LOG_DEBUG, "WARNING: Bridged "
Packit Service ed0f68
							"cmd ccode = 0x%02x", rsp->ccode);
Packit Service ed0f68
				} else {
Packit Service ed0f68
					/* decrement bridging level */
Packit Service ed0f68
					entry->bridging_level--;
Packit Service ed0f68
					if (!entry->bridging_level) {
Packit Service ed0f68
						entry->req.msg.cmd = entry->req.msg.target_cmd;
Packit Service ed0f68
					}
Packit Service ed0f68
Packit Service ed0f68
					/* check if bridged response is embedded */
Packit Service ed0f68
					if (payload_size > 8) {
Packit Service ed0f68
						printbuf(&rsp->data[offset], (rsp->data_len-offset-1),
Packit Service ed0f68
								"bridge command response");
Packit Service ed0f68
						/*
Packit Service ed0f68
						 * decrement payload size
Packit Service ed0f68
						 * (cks2 for outer Send Message)
Packit Service ed0f68
						 */
Packit Service ed0f68
						payload_size--;
Packit Service ed0f68
Packit Service ed0f68
						/*
Packit Service ed0f68
						 * need to make a loop for embedded bridged response
Packit Service ed0f68
						 */
Packit Service ed0f68
						loop++;
Packit Service ed0f68
					} else {
Packit Service ed0f68
						lprintf(LOG_DEBUG, "Bridged command answer,"
Packit Service ed0f68
								" waiting for next answer... ");
Packit Service ed0f68
						/* read one more packet */
Packit Service ed0f68
						return (struct ipmi_rs *)1;
Packit Service ed0f68
					}
Packit Service ed0f68
				}
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			/* Remove request entry */
Packit Service ed0f68
			ipmi_req_remove_entry(rsp->payload.ipmi_response.rq_seq,
Packit Service ed0f68
					rsp->payload.ipmi_response.cmd);
Packit Service ed0f68
Packit Service ed0f68
			/*
Packit Service ed0f68
			 * Good packet.  Shift response data to start of array.
Packit Service ed0f68
			 * rsp->data becomes the variable length IPMI response data
Packit Service ed0f68
			 * rsp->data_len becomes the length of that data
Packit Service ed0f68
			 */
Packit Service ed0f68
			extra_data_length = payload_size - (offset - payload_start) - 1;
Packit Service ed0f68
			if (extra_data_length) {
Packit Service ed0f68
				rsp->data_len = extra_data_length;
Packit Service ed0f68
				memmove(rsp->data, rsp->data + offset, extra_data_length);
Packit Service ed0f68
			} else {
Packit Service ed0f68
				rsp->data_len = 0;
Packit Service ed0f68
			}
Packit Service ed0f68
		}
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Open Response
Packit Service ed0f68
	 */
Packit Service ed0f68
	} else if (rsp->session.payloadtype ==
Packit Service ed0f68
			IPMI_PAYLOAD_TYPE_RMCP_OPEN_RESPONSE) {
Packit Service ed0f68
		if (session->v2_data.session_state !=
Packit Service ed0f68
				LANPLUS_STATE_OPEN_SESSION_SENT) {
Packit Service ed0f68
			lprintf(LOG_ERR, "Error: Received an Unexpected Open Session "
Packit Service ed0f68
					"Response");
Packit Service ed0f68
			/* read one more packet */
Packit Service ed0f68
			return (struct ipmi_rs *)1;
Packit Service ed0f68
		}
Packit Service ed0f68
		read_open_session_response(rsp, offset);
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * RAKP 2
Packit Service ed0f68
	 */
Packit Service ed0f68
	} else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_2) {
Packit Service ed0f68
		if (session->v2_data.session_state != LANPLUS_STATE_RAKP_1_SENT) {
Packit Service ed0f68
			lprintf(LOG_ERR, "Error: Received an Unexpected RAKP 2 message");
Packit Service ed0f68
			/* read one more packet */
Packit Service ed0f68
			return (struct ipmi_rs *)1;
Packit Service ed0f68
		}
Packit Service ed0f68
		read_rakp2_message(rsp, offset, session->v2_data.auth_alg);
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * RAKP 4
Packit Service ed0f68
	 */
Packit Service ed0f68
	} else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_4) {
Packit Service ed0f68
		if (session->v2_data.session_state != LANPLUS_STATE_RAKP_3_SENT) {
Packit Service ed0f68
			lprintf(LOG_ERR, "Error: Received an Unexpected RAKP 4 message");
Packit Service ed0f68
			/* read one more packet */
Packit Service ed0f68
			return (struct ipmi_rs *)1;
Packit Service ed0f68
		}
Packit Service ed0f68
		read_rakp4_message(rsp, offset, session->v2_data.auth_alg);
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * SOL
Packit Service ed0f68
	 */
Packit Service ed0f68
	} else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) {
Packit Service ed0f68
		int payload_start = offset;
Packit Service ed0f68
		int extra_data_length;
Packit Service ed0f68
Packit Service ed0f68
		if (session->v2_data.session_state != LANPLUS_STATE_ACTIVE) {
Packit Service ed0f68
			lprintf(LOG_ERR, "Error: Received an Unexpected SOL packet");
Packit Service ed0f68
			/* read one more packet */
Packit Service ed0f68
			return (struct ipmi_rs *)1;
Packit Service ed0f68
		}
Packit Service ed0f68
		read_sol_packet(rsp, &offset);
Packit Service ed0f68
		extra_data_length = payload_size - (offset - payload_start);
Packit Service ed0f68
		if (rsp && extra_data_length) {
Packit Service ed0f68
			rsp->data_len = extra_data_length;
Packit Service ed0f68
			memmove(rsp->data, rsp->data + offset, extra_data_length);
Packit Service ed0f68
		} else {
Packit Service ed0f68
			rsp->data_len = 0;
Packit Service ed0f68
		}
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Unknown Payload type
Packit Service ed0f68
	 */
Packit Service ed0f68
	} else {
Packit Service ed0f68
		lprintf(LOG_ERR, "Invalid RMCP+ payload type : 0x%x",
Packit Service ed0f68
				rsp->session.payloadtype);
Packit Service ed0f68
		/* read one more packet */
Packit Service ed0f68
		return (struct ipmi_rs *)1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return rsp;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/**
Packit Service ed0f68
 *
Packit Service ed0f68
 * ipmi_lan_poll_recv
Packit Service ed0f68
 *
Packit Service ed0f68
 * Receive whatever comes back.  Ignore received packets that don't correspond
Packit Service ed0f68
 * to a request we've sent.
Packit Service ed0f68
 *
Packit Service ed0f68
 * Returns: the ipmi_rs packet describing the/a response we expect.
Packit Service ed0f68
 */
Packit Service ed0f68
static struct ipmi_rs *
Packit Service ed0f68
ipmi_lan_poll_recv(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
Packit Service ed0f68
	do {
Packit Service ed0f68
		/* poll single packet */
Packit Service ed0f68
		rsp = ipmi_lan_poll_single(intf);
Packit Service ed0f68
	} while (rsp == (struct ipmi_rs *) 1);
Packit Service ed0f68
Packit Service ed0f68
	return rsp;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * read_open_session_response
Packit Service ed0f68
 *
Packit Service ed0f68
 * Initialize the ipmi_rs from the IPMI 2.x open session response data.
Packit Service ed0f68
 *
Packit Service ed0f68
 * The offset should point to the first byte of the the Open Session Response
Packit Service ed0f68
 * payload when this function is called.
Packit Service ed0f68
 *
Packit Service ed0f68
 * param rsp    [in/out] reading from the data and writing to the open_session_response
Packit Service ed0f68
 *              section
Packit Service ed0f68
 * param offset [in] tells us where the Open Session Response payload starts
Packit Service ed0f68
 *
Packit Service ed0f68
 * returns 0 on success, 1 on error
Packit Service ed0f68
 */
Packit Service ed0f68
void
Packit Service ed0f68
read_open_session_response(struct ipmi_rs * rsp, int offset)
Packit Service ed0f68
{
Packit Service ed0f68
	memset(&rsp->payload.open_session_response, 0,
Packit Service ed0f68
			 sizeof(rsp->payload.open_session_response));
Packit Service ed0f68
Packit Service ed0f68
	 /*  Message tag */
Packit Service ed0f68
	 rsp->payload.open_session_response.message_tag = rsp->data[offset];
Packit Service ed0f68
Packit Service ed0f68
	 /* RAKP response code */
Packit Service ed0f68
	 rsp->payload.open_session_response.rakp_return_code = rsp->data[offset + 1];
Packit Service ed0f68
Packit Service ed0f68
	 /* Maximum privilege level */
Packit Service ed0f68
	 rsp->payload.open_session_response.max_priv_level = rsp->data[offset + 2];
Packit Service ed0f68
Packit Service ed0f68
	 /*** offset + 3 is reserved ***/
Packit Service ed0f68
Packit Service ed0f68
	 /* Remote console session ID */
Packit Service ed0f68
	 memcpy(&(rsp->payload.open_session_response.console_id),
Packit Service ed0f68
			rsp->data + offset + 4,
Packit Service ed0f68
			4);
Packit Service ed0f68
	 #if WORDS_BIGENDIAN
Packit Service ed0f68
	 rsp->payload.open_session_response.console_id =
Packit Service ed0f68
		 BSWAP_32(rsp->payload.open_session_response.console_id);
Packit Service ed0f68
	 #endif
Packit Service ed0f68
Packit Service ed0f68
	/* only tag, status, privlvl, and console id are returned if error */
Packit Service ed0f68
	 if (rsp->payload.open_session_response.rakp_return_code !=
Packit Service ed0f68
		  IPMI_RAKP_STATUS_NO_ERRORS)
Packit Service ed0f68
		 return;
Packit Service ed0f68
Packit Service ed0f68
	 /* BMC session ID */
Packit Service ed0f68
	 memcpy(&(rsp->payload.open_session_response.bmc_id),
Packit Service ed0f68
			rsp->data + offset + 8,
Packit Service ed0f68
			4);
Packit Service ed0f68
	 #if WORDS_BIGENDIAN
Packit Service ed0f68
	 rsp->payload.open_session_response.bmc_id =
Packit Service ed0f68
		 BSWAP_32(rsp->payload.open_session_response.bmc_id);
Packit Service ed0f68
	 #endif
Packit Service ed0f68
Packit Service ed0f68
	 /* And of course, our negotiated algorithms */
Packit Service ed0f68
	 rsp->payload.open_session_response.auth_alg      = rsp->data[offset + 16];
Packit Service ed0f68
	 rsp->payload.open_session_response.integrity_alg = rsp->data[offset + 24];
Packit Service ed0f68
	 rsp->payload.open_session_response.crypt_alg     = rsp->data[offset + 32];
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * read_rakp2_message
Packit Service ed0f68
 *
Packit Service ed0f68
 * Initialize the ipmi_rs from the IPMI 2.x RAKP 2 message
Packit Service ed0f68
 *
Packit Service ed0f68
 * The offset should point the first byte of the the RAKP 2 payload when this
Packit Service ed0f68
 * function is called.
Packit Service ed0f68
 *
Packit Service ed0f68
 * param rsp [in/out] reading from the data variable and writing to the rakp 2
Packit Service ed0f68
 *       section
Packit Service ed0f68
 * param offset [in] tells us where hte rakp2 payload starts
Packit Service ed0f68
 * param auth_alg [in] describes the authentication algorithm was agreed upon in
Packit Service ed0f68
 *       the open session request/response phase.  We need to know that here so
Packit Service ed0f68
 *       that we know how many bytes (if any) to read fromt the packet.
Packit Service ed0f68
 *
Packit Service ed0f68
 * returns 0 on success, 1 on error
Packit Service ed0f68
 */
Packit Service ed0f68
void
Packit Service ed0f68
read_rakp2_message(
Packit Service ed0f68
					struct ipmi_rs * rsp,
Packit Service ed0f68
					int offset,
Packit Service ed0f68
					uint8_t auth_alg)
Packit Service ed0f68
{
Packit Service ed0f68
	 int i;
Packit Service ed0f68
Packit Service ed0f68
	 /*  Message tag */
Packit Service ed0f68
	 rsp->payload.rakp2_message.message_tag = rsp->data[offset];
Packit Service ed0f68
Packit Service ed0f68
	 /* RAKP response code */
Packit Service ed0f68
	 rsp->payload.rakp2_message.rakp_return_code = rsp->data[offset + 1];
Packit Service ed0f68
Packit Service ed0f68
	 /* Console session ID */
Packit Service ed0f68
	 memcpy(&(rsp->payload.rakp2_message.console_id),
Packit Service ed0f68
			rsp->data + offset + 4,
Packit Service ed0f68
			4);
Packit Service ed0f68
	 #if WORDS_BIGENDIAN
Packit Service ed0f68
	 rsp->payload.rakp2_message.console_id =
Packit Service ed0f68
		 BSWAP_32(rsp->payload.rakp2_message.console_id);
Packit Service ed0f68
	 #endif
Packit Service ed0f68
Packit Service ed0f68
	 /* BMC random number */
Packit Service ed0f68
	 memcpy(&(rsp->payload.rakp2_message.bmc_rand),
Packit Service ed0f68
			rsp->data + offset + 8,
Packit Service ed0f68
			16);
Packit Service ed0f68
	 #if WORDS_BIGENDIAN
Packit Service ed0f68
	 lanplus_swap(rsp->payload.rakp2_message.bmc_rand, 16);
Packit Service ed0f68
	 #endif
Packit Service ed0f68
Packit Service ed0f68
	 /* BMC GUID */
Packit Service ed0f68
	 memcpy(&(rsp->payload.rakp2_message.bmc_guid),
Packit Service ed0f68
			rsp->data + offset + 24,
Packit Service ed0f68
			16);
Packit Service ed0f68
	 #if WORDS_BIGENDIAN
Packit Service ed0f68
	 lanplus_swap(rsp->payload.rakp2_message.bmc_guid, 16);
Packit Service ed0f68
	 #endif
Packit Service ed0f68
	 
Packit Service ed0f68
	 /* Key exchange authentication code */
Packit Service ed0f68
	 switch (auth_alg)
Packit Service ed0f68
	 {
Packit Service ed0f68
	 case  IPMI_AUTH_RAKP_NONE:
Packit Service ed0f68
		 /* Nothing to do here */
Packit Service ed0f68
		 break;
Packit Service ed0f68
Packit Service ed0f68
	 case IPMI_AUTH_RAKP_HMAC_SHA1:
Packit Service ed0f68
		/* We need to copy 20 bytes */
Packit Service ed0f68
		for (i = 0; i < IPMI_SHA_DIGEST_LENGTH; ++i) {
Packit Service ed0f68
			rsp->payload.rakp2_message.key_exchange_auth_code[i] =
Packit Service ed0f68
				rsp->data[offset + 40 + i];
Packit Service ed0f68
		}
Packit Service ed0f68
		break;
Packit Service ed0f68
Packit Service ed0f68
	 case IPMI_AUTH_RAKP_HMAC_MD5:
Packit Service ed0f68
		/* We need to copy 16 bytes */
Packit Service ed0f68
		for (i = 0; i < IPMI_MD5_DIGEST_LENGTH; ++i) {
Packit Service ed0f68
			rsp->payload.rakp2_message.key_exchange_auth_code[i] =
Packit Service ed0f68
				rsp->data[offset + 40 + i];
Packit Service ed0f68
		}
Packit Service ed0f68
		break;
Packit Service ed0f68
Packit Service ed0f68
#ifdef HAVE_CRYPTO_SHA256
Packit Service ed0f68
	 case IPMI_AUTH_RAKP_HMAC_SHA256:
Packit Service ed0f68
		/* We need to copy 32 bytes */
Packit Service ed0f68
		for (i = 0; i < IPMI_SHA256_DIGEST_LENGTH; ++i) {
Packit Service ed0f68
			rsp->payload.rakp2_message.key_exchange_auth_code[i] =
Packit Service ed0f68
				rsp->data[offset + 40 + i];
Packit Service ed0f68
		}
Packit Service ed0f68
		break;
Packit Service ed0f68
#endif /* HAVE_CRYPTO_SHA256 */
Packit Service ed0f68
Packit Service ed0f68
	 default:
Packit Service ed0f68
		lprintf(LOG_ERR, "read_rakp2_message: no support "
Packit Service ed0f68
			"for authentication algorithm 0x%x", auth_alg);
Packit Service ed0f68
		 assert(0);
Packit Service ed0f68
		 break;
Packit Service ed0f68
	 }
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * read_rakp4_message
Packit Service ed0f68
 *
Packit Service ed0f68
 * Initialize the ipmi_rs from the IPMI 2.x RAKP 4 message
Packit Service ed0f68
 *
Packit Service ed0f68
 * The offset should point the first byte of the the RAKP 4 payload when this
Packit Service ed0f68
 * function is called.
Packit Service ed0f68
 *
Packit Service ed0f68
 * param rsp [in/out] reading from the data variable and writing to the rakp
Packit Service ed0f68
 *       4 section
Packit Service ed0f68
 * param offset [in] tells us where hte rakp4 payload starts
Packit Service ed0f68
 * param integrity_alg [in] describes the authentication algorithm was
Packit Service ed0f68
 *       agreed upon in the open session request/response phase.  We need
Packit Service ed0f68
 *       to know that here so that we know how many bytes (if any) to read
Packit Service ed0f68
 *       from the packet.
Packit Service ed0f68
 *
Packit Service ed0f68
 * returns 0 on success, 1 on error
Packit Service ed0f68
 */
Packit Service ed0f68
void
Packit Service ed0f68
read_rakp4_message(
Packit Service ed0f68
					struct ipmi_rs * rsp,
Packit Service ed0f68
					int offset,
Packit Service ed0f68
					uint8_t auth_alg)
Packit Service ed0f68
{
Packit Service ed0f68
	 int i;
Packit Service ed0f68
Packit Service ed0f68
	 /*  Message tag */
Packit Service ed0f68
	 rsp->payload.rakp4_message.message_tag = rsp->data[offset];
Packit Service ed0f68
Packit Service ed0f68
	 /* RAKP response code */
Packit Service ed0f68
	 rsp->payload.rakp4_message.rakp_return_code = rsp->data[offset + 1];
Packit Service ed0f68
Packit Service ed0f68
	 /* Console session ID */
Packit Service ed0f68
	 memcpy(&(rsp->payload.rakp4_message.console_id),
Packit Service ed0f68
			rsp->data + offset + 4,
Packit Service ed0f68
			4);
Packit Service ed0f68
	 #if WORDS_BIGENDIAN
Packit Service ed0f68
	 rsp->payload.rakp4_message.console_id =
Packit Service ed0f68
		 BSWAP_32(rsp->payload.rakp4_message.console_id);
Packit Service ed0f68
	 #endif
Packit Service ed0f68
Packit Service ed0f68
	 
Packit Service ed0f68
	 /* Integrity check value */
Packit Service ed0f68
	 switch (auth_alg)
Packit Service ed0f68
	 {
Packit Service ed0f68
	 case  IPMI_AUTH_RAKP_NONE:
Packit Service ed0f68
		 /* Nothing to do here */
Packit Service ed0f68
		 break;
Packit Service ed0f68
Packit Service ed0f68
	 case IPMI_AUTH_RAKP_HMAC_SHA1:
Packit Service ed0f68
		/* We need to copy 12 bytes */
Packit Service ed0f68
		for (i = 0; i < IPMI_SHA1_AUTHCODE_SIZE; ++i) {
Packit Service ed0f68
			rsp->payload.rakp4_message.integrity_check_value[i] =
Packit Service ed0f68
				rsp->data[offset + 8 + i];
Packit Service ed0f68
		}
Packit Service ed0f68
		break;
Packit Service ed0f68
Packit Service ed0f68
	 case IPMI_AUTH_RAKP_HMAC_MD5:
Packit Service ed0f68
		/* We need to copy 16 bytes */
Packit Service ed0f68
		for (i = 0; i < IPMI_HMAC_MD5_AUTHCODE_SIZE; ++i) {
Packit Service ed0f68
			rsp->payload.rakp4_message.integrity_check_value[i] =
Packit Service ed0f68
				rsp->data[offset + 8 + i];
Packit Service ed0f68
		}
Packit Service ed0f68
		break;
Packit Service ed0f68
Packit Service ed0f68
#ifdef HAVE_CRYPTO_SHA256
Packit Service ed0f68
	 case IPMI_AUTH_RAKP_HMAC_SHA256:
Packit Service ed0f68
		/* We need to copy 16 bytes */
Packit Service ed0f68
		for (i = 0; i < IPMI_HMAC_SHA256_AUTHCODE_SIZE; ++i) {
Packit Service ed0f68
			rsp->payload.rakp4_message.integrity_check_value[i] =
Packit Service ed0f68
				rsp->data[offset + 8 + i];
Packit Service ed0f68
		}
Packit Service ed0f68
		break;
Packit Service ed0f68
#endif /* HAVE_CRYPTO_SHA256 */
Packit Service ed0f68
Packit Service ed0f68
	 default:
Packit Service ed0f68
		 lprintf(LOG_ERR, "read_rakp4_message: no support "
Packit Service ed0f68
			 "for authentication algorithm 0x%x", auth_alg);
Packit Service ed0f68
		 assert(0);
Packit Service ed0f68
		 break;	 
Packit Service ed0f68
	 }
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * read_session_data
Packit Service ed0f68
 *
Packit Service ed0f68
 * Initialize the ipmi_rsp from the session data in the packet
Packit Service ed0f68
 *
Packit Service ed0f68
 * The offset should point the first byte of the the IPMI session when this
Packit Service ed0f68
 * function is called.
Packit Service ed0f68
 *
Packit Service ed0f68
 * param rsp     [in/out] we read from the data buffer and populate the session
Packit Service ed0f68
 *               specific fields.
Packit Service ed0f68
 * param offset  [in/out] should point to the beginning of the session when
Packit Service ed0f68
 *               this function is called.  The offset will be adjusted to
Packit Service ed0f68
 *               point to the end of the session when this function exits.
Packit Service ed0f68
 * param session holds our session state
Packit Service ed0f68
 */
Packit Service ed0f68
void
Packit Service ed0f68
read_session_data(
Packit Service ed0f68
				  struct ipmi_rs * rsp,
Packit Service ed0f68
				  int * offset,
Packit Service ed0f68
				  struct ipmi_session * s)
Packit Service ed0f68
{
Packit Service ed0f68
	/* We expect to read different stuff depending on the authtype */
Packit Service ed0f68
	rsp->session.authtype = rsp->data[*offset];
Packit Service ed0f68
Packit Service ed0f68
	if (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS)
Packit Service ed0f68
		read_session_data_v2x(rsp, offset, s);
Packit Service ed0f68
	else
Packit Service ed0f68
		read_session_data_v15(rsp, offset, s);
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * read_session_data_v2x
Packit Service ed0f68
 *
Packit Service ed0f68
 * Initialize the ipmi_rsp from the v2.x session header of the packet.
Packit Service ed0f68
 *
Packit Service ed0f68
 * The offset should point to the first byte of the the IPMI session when this
Packit Service ed0f68
 * function is called.  When this function exits, offset will point to the
Packit Service ed0f68
 * start of payload.
Packit Service ed0f68
 *
Packit Service ed0f68
 * Should decrypt and perform integrity checking here?
Packit Service ed0f68
 *
Packit Service ed0f68
 * param rsp    [in/out] we read from the data buffer and populate the session
Packit Service ed0f68
 *              specific fields.
Packit Service ed0f68
 * param offset [in/out] should point to the beginning of the session when this
Packit Service ed0f68
 *              function is called.  The offset will be adjusted to point to
Packit Service ed0f68
 *              the end of the session when this function exits.
Packit Service ed0f68
 *  param s      holds our session state
Packit Service ed0f68
 */
Packit Service ed0f68
void
Packit Service ed0f68
read_session_data_v2x(
Packit Service ed0f68
					  struct ipmi_rs      * rsp,
Packit Service ed0f68
					  int                 * offset,
Packit Service ed0f68
					  struct ipmi_session * s)
Packit Service ed0f68
{
Packit Service ed0f68
	rsp->session.authtype = rsp->data[(*offset)++];
Packit Service ed0f68
Packit Service ed0f68
	rsp->session.bEncrypted     = (rsp->data[*offset] & 0x80 ? 1 : 0);
Packit Service ed0f68
	rsp->session.bAuthenticated = (rsp->data[*offset] & 0x40 ? 1 : 0);
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/* Payload type */
Packit Service ed0f68
	rsp->session.payloadtype = rsp->data[(*offset)++] & 0x3F;
Packit Service ed0f68
Packit Service ed0f68
	/* Session ID */
Packit Service ed0f68
	memcpy(&rsp->session.id, rsp->data + *offset, 4);
Packit Service ed0f68
	*offset += 4;
Packit Service ed0f68
	#if WORDS_BIGENDIAN
Packit Service ed0f68
	rsp->session.id = BSWAP_32(rsp->session.id);
Packit Service ed0f68
	#endif
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/* Ignored, so far */
Packit Service ed0f68
	memcpy(&rsp->session.seq, rsp->data + *offset, 4);
Packit Service ed0f68
	*offset += 4;
Packit Service ed0f68
	#if WORDS_BIGENDIAN
Packit Service ed0f68
	rsp->session.seq = BSWAP_32(rsp->session.seq);
Packit Service ed0f68
	#endif		
Packit Service ed0f68
Packit Service ed0f68
	memcpy(&rsp->session.msglen, rsp->data + *offset, 2);
Packit Service ed0f68
	*offset += 2;
Packit Service ed0f68
	#if WORDS_BIGENDIAN
Packit Service ed0f68
	rsp->session.msglen = BSWAP_16(rsp->session.msglen);
Packit Service ed0f68
	#endif
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * read_session_data_v15
Packit Service ed0f68
 *
Packit Service ed0f68
 * Initialize the ipmi_rsp from the session header of the packet. 
Packit Service ed0f68
 *
Packit Service ed0f68
 * The offset should point the first byte of the the IPMI session when this
Packit Service ed0f68
 * function is called.  When this function exits, the offset will point to
Packit Service ed0f68
 * the start of the IPMI message.
Packit Service ed0f68
 *
Packit Service ed0f68
 * param rsp    [in/out] we read from the data buffer and populate the session
Packit Service ed0f68
 *              specific fields.
Packit Service ed0f68
 * param offset [in/out] should point to the beginning of the session when this
Packit Service ed0f68
 *              function is called.  The offset will be adjusted to point to the
Packit Service ed0f68
 *              end of the session when this function exits.
Packit Service ed0f68
 * param s      holds our session state
Packit Service ed0f68
 */
Packit Service ed0f68
void read_session_data_v15(
Packit Service ed0f68
							struct ipmi_rs * rsp,
Packit Service ed0f68
							int * offset,
Packit Service ed0f68
							struct ipmi_session * s)
Packit Service ed0f68
{
Packit Service ed0f68
	/* All v15 messages are IPMI messages */
Packit Service ed0f68
	rsp->session.payloadtype = IPMI_PAYLOAD_TYPE_IPMI;
Packit Service ed0f68
Packit Service ed0f68
	rsp->session.authtype = rsp->data[(*offset)++];
Packit Service ed0f68
Packit Service ed0f68
	/* All v15 messages that we will receive are unencrypted/unauthenticated */
Packit Service ed0f68
	rsp->session.bEncrypted     = 0;
Packit Service ed0f68
	rsp->session.bAuthenticated = 0;
Packit Service ed0f68
Packit Service ed0f68
	/* skip the session id and sequence number fields */
Packit Service ed0f68
	*offset += 8;
Packit Service ed0f68
Packit Service ed0f68
	/* This is the size of the whole payload */
Packit Service ed0f68
	rsp->session.msglen = rsp->data[(*offset)++];
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * read_ipmi_response
Packit Service ed0f68
 *
Packit Service ed0f68
 * Initialize the ipmi_rs from with the IPMI response specific data
Packit Service ed0f68
 *
Packit Service ed0f68
 * The offset should point the first byte of the the IPMI payload when this
Packit Service ed0f68
 * function is called. 
Packit Service ed0f68
 *
Packit Service ed0f68
 * param rsp    [in/out] we read from the data buffer and populate the IPMI
Packit Service ed0f68
 *              specific fields.
Packit Service ed0f68
 * param offset [in/out] should point to the beginning of the IPMI payload when
Packit Service ed0f68
 *              this function is called.
Packit Service ed0f68
 */
Packit Service ed0f68
void read_ipmi_response(struct ipmi_rs * rsp, int * offset)
Packit Service ed0f68
{
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * The data here should be decrypted by now.
Packit Service ed0f68
	 */
Packit Service ed0f68
	rsp->payload.ipmi_response.rq_addr = rsp->data[(*offset)++];
Packit Service ed0f68
	rsp->payload.ipmi_response.netfn   = rsp->data[*offset] >> 2;
Packit Service ed0f68
	rsp->payload.ipmi_response.rq_lun  = rsp->data[(*offset)++] & 0x3;
Packit Service ed0f68
	(*offset)++;		/* checksum */
Packit Service ed0f68
	rsp->payload.ipmi_response.rs_addr = rsp->data[(*offset)++];
Packit Service ed0f68
	rsp->payload.ipmi_response.rq_seq  = rsp->data[*offset] >> 2;
Packit Service ed0f68
	rsp->payload.ipmi_response.rs_lun  = rsp->data[(*offset)++] & 0x3;
Packit Service ed0f68
	rsp->payload.ipmi_response.cmd     = rsp->data[(*offset)++]; 
Packit Service ed0f68
	rsp->ccode                         = rsp->data[(*offset)++];
Packit Service ed0f68
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * read_sol_packet
Packit Service ed0f68
 *
Packit Service ed0f68
 * Initialize the ipmi_rs with the SOL response data
Packit Service ed0f68
 *
Packit Service ed0f68
 * The offset should point the first byte of the the SOL payload when this
Packit Service ed0f68
 * function is called. 
Packit Service ed0f68
 *
Packit Service ed0f68
 * param rsp    [in/out] we read from the data buffer and populate the
Packit Service ed0f68
 *              SOL specific fields.
Packit Service ed0f68
 * param offset [in/out] should point to the beginning of the SOL payload
Packit Service ed0f68
 *              when this function is called.
Packit Service ed0f68
 */
Packit Service ed0f68
void read_sol_packet(struct ipmi_rs * rsp, int * offset)
Packit Service ed0f68
{
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * The data here should be decrypted by now.
Packit Service ed0f68
	 */
Packit Service ed0f68
	rsp->payload.sol_packet.packet_sequence_number =
Packit Service ed0f68
		rsp->data[(*offset)++] & 0x0F;
Packit Service ed0f68
Packit Service ed0f68
	rsp->payload.sol_packet.acked_packet_number =
Packit Service ed0f68
		rsp->data[(*offset)++] & 0x0F;
Packit Service ed0f68
Packit Service ed0f68
	rsp->payload.sol_packet.accepted_character_count =
Packit Service ed0f68
		rsp->data[(*offset)++];
Packit Service ed0f68
Packit Service ed0f68
	rsp->payload.sol_packet.is_nack =
Packit Service ed0f68
		rsp->data[*offset] & 0x40;
Packit Service ed0f68
Packit Service ed0f68
	rsp->payload.sol_packet.transfer_unavailable =
Packit Service ed0f68
		rsp->data[*offset] & 0x20;
Packit Service ed0f68
Packit Service ed0f68
	rsp->payload.sol_packet.sol_inactive =
Packit Service ed0f68
		rsp->data[*offset] & 0x10;
Packit Service ed0f68
Packit Service ed0f68
	rsp->payload.sol_packet.transmit_overrun =
Packit Service ed0f68
		rsp->data[*offset] & 0x08;
Packit Service ed0f68
Packit Service ed0f68
	rsp->payload.sol_packet.break_detected =
Packit Service ed0f68
		rsp->data[(*offset)++] & 0x04;
Packit Service ed0f68
Packit Service ed0f68
	lprintf(LOG_DEBUG, "<<<<<<<<<< RECV FROM BMC <<<<<<<<<<<");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "< SOL sequence number     : 0x%02x",
Packit Service ed0f68
		rsp->payload.sol_packet.packet_sequence_number);
Packit Service ed0f68
	lprintf(LOG_DEBUG, "< SOL acked packet        : 0x%02x",
Packit Service ed0f68
		rsp->payload.sol_packet.acked_packet_number);
Packit Service ed0f68
	lprintf(LOG_DEBUG, "< SOL accepted char count : 0x%02x",
Packit Service ed0f68
		rsp->payload.sol_packet.accepted_character_count);
Packit Service ed0f68
	lprintf(LOG_DEBUG, "< SOL is nack             : %s",
Packit Service ed0f68
		rsp->payload.sol_packet.is_nack? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "< SOL xfer unavailable    : %s",
Packit Service ed0f68
		rsp->payload.sol_packet.transfer_unavailable? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "< SOL inactive            : %s",
Packit Service ed0f68
		rsp->payload.sol_packet.sol_inactive? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "< SOL transmit overrun    : %s",
Packit Service ed0f68
		rsp->payload.sol_packet.transmit_overrun? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "< SOL break detected      : %s",
Packit Service ed0f68
		rsp->payload.sol_packet.break_detected? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
Packit Service ed0f68
Packit Service ed0f68
	if (verbose >= 5)
Packit Service ed0f68
		printbuf(rsp->data + *offset - 4, 4, "SOL MSG FROM BMC");
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * getIpmiPayloadWireRep
Packit Service ed0f68
 *
Packit Service ed0f68
 * param out [out] will contain our wire representation
Packit Service ed0f68
 * param req [in] is the IPMI request to be written
Packit Service ed0f68
 * param crypt_alg [in] specifies the encryption to use
Packit Service ed0f68
 * param rq_seq [in] is the IPMI command sequence number.
Packit Service ed0f68
 */
Packit Service ed0f68
void getIpmiPayloadWireRep(
Packit Service ed0f68
							struct ipmi_intf       * intf,  /* in out */
Packit Service ed0f68
							struct ipmi_v2_payload * payload,  /* in  */
Packit Service ed0f68
							uint8_t  * msg,
Packit Service ed0f68
							struct ipmi_rq * req,
Packit Service ed0f68
							uint8_t    rq_seq,
Packit Service ed0f68
							uint8_t curr_seq)
Packit Service ed0f68
{
Packit Service ed0f68
	int cs, tmp, len;
Packit Service ed0f68
	int cs2 = 0;
Packit Service ed0f68
	int cs3 = 0;
Packit Service ed0f68
	uint8_t ourAddress = intf->my_addr;
Packit Service ed0f68
	uint8_t bridgedRequest = 0;
Packit Service ed0f68
Packit Service ed0f68
	if (ourAddress == 0)
Packit Service ed0f68
		ourAddress = IPMI_BMC_SLAVE_ADDR;
Packit Service ed0f68
Packit Service ed0f68
	len = 0;
Packit Service ed0f68
Packit Service ed0f68
	/* IPMI Message Header -- Figure 13-4 of the IPMI v2.0 spec */
Packit Service ed0f68
	if ((intf->target_addr == ourAddress) || (!bridgePossible)) {
Packit Service ed0f68
		cs = len;
Packit Service ed0f68
	} else {
Packit Service ed0f68
		bridgedRequest = 1;
Packit Service ed0f68
Packit Service ed0f68
		if(intf->transit_addr != ourAddress && intf->transit_addr != 0)
Packit Service ed0f68
		{
Packit Service ed0f68
			bridgedRequest++;
Packit Service ed0f68
		}
Packit Service ed0f68
		/* bridged request: encapsulate w/in Send Message */
Packit Service ed0f68
		cs = len;
Packit Service ed0f68
		msg[len++] = IPMI_BMC_SLAVE_ADDR;
Packit Service ed0f68
		msg[len++] = IPMI_NETFN_APP << 2;
Packit Service ed0f68
		tmp = len - cs;
Packit Service ed0f68
		msg[len++] = ipmi_csum(msg+cs, tmp);
Packit Service ed0f68
		cs2 = len;
Packit Service ed0f68
		msg[len++] = IPMI_REMOTE_SWID;
Packit Service ed0f68
		msg[len++] = curr_seq << 2;
Packit Service ed0f68
Packit Service ed0f68
		
Packit Service ed0f68
		msg[len++] = 0x34;			/* Send Message rqst */
Packit Service ed0f68
		if(bridgedRequest == 2)
Packit Service ed0f68
			msg[len++] = (0x40|intf->transit_channel); /* Track request*/
Packit Service ed0f68
		else
Packit Service ed0f68
			msg[len++] = (0x40|intf->target_channel);    /* Track request*/
Packit Service ed0f68
			
Packit Service ed0f68
		payload->payload_length += 7;
Packit Service ed0f68
		cs = len;
Packit Service ed0f68
		
Packit Service ed0f68
		if(bridgedRequest == 2)
Packit Service ed0f68
		{
Packit Service ed0f68
			/* bridged request: encapsulate w/in Send Message */
Packit Service ed0f68
			cs = len;
Packit Service ed0f68
			msg[len++] = intf->transit_addr;
Packit Service ed0f68
			msg[len++] = IPMI_NETFN_APP << 2;
Packit Service ed0f68
			tmp = len - cs;
Packit Service ed0f68
			msg[len++] = ipmi_csum(msg+cs, tmp);
Packit Service ed0f68
			cs3 = len;
Packit Service ed0f68
			msg[len++] = IPMI_REMOTE_SWID;
Packit Service ed0f68
			msg[len++] = curr_seq << 2;
Packit Service ed0f68
			msg[len++] = 0x34;			/* Send Message rqst */
Packit Service ed0f68
			msg[len++] = (0x40|intf->target_channel); /* Track request*/
Packit Service ed0f68
Packit Service ed0f68
			payload->payload_length += 7;
Packit Service ed0f68
Packit Service ed0f68
			cs = len;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
        lprintf(LOG_DEBUG,"%s RqAddr %#x transit %#x:%#x target %#x:%#x "
Packit Service ed0f68
		"bridgePossible %d",
Packit Service ed0f68
		bridgedRequest ? "Bridging" : "Local",
Packit Service ed0f68
		intf->my_addr, intf->transit_addr, intf->transit_channel,
Packit Service ed0f68
		intf->target_addr, intf->target_channel,
Packit Service ed0f68
		bridgePossible);
Packit Service ed0f68
Packit Service ed0f68
	/* rsAddr */
Packit Service ed0f68
	if (bridgedRequest)
Packit Service ed0f68
		msg[len++] = intf->target_addr;
Packit Service ed0f68
	else
Packit Service ed0f68
		msg[len++] = IPMI_BMC_SLAVE_ADDR;
Packit Service ed0f68
Packit Service ed0f68
	/* net Fn */
Packit Service ed0f68
	msg[len++] = req->msg.netfn << 2 | (req->msg.lun & 3);
Packit Service ed0f68
	tmp = len - cs;
Packit Service ed0f68
Packit Service ed0f68
	/* checkSum */
Packit Service ed0f68
	msg[len++] = ipmi_csum(msg+cs, tmp);
Packit Service ed0f68
	cs = len;
Packit Service ed0f68
Packit Service ed0f68
	/* rqAddr */
Packit Service ed0f68
	if (bridgedRequest < 2)
Packit Service ed0f68
		msg[len++] = IPMI_REMOTE_SWID;
Packit Service ed0f68
	else  /* Bridged message */
Packit Service ed0f68
		msg[len++] = intf->my_addr;
Packit Service ed0f68
Packit Service ed0f68
	/* rqSeq / rqLUN */
Packit Service ed0f68
	msg[len++] = rq_seq << 2;
Packit Service ed0f68
Packit Service ed0f68
	/* cmd */
Packit Service ed0f68
	msg[len++] = req->msg.cmd;
Packit Service ed0f68
Packit Service ed0f68
	/* message data */
Packit Service ed0f68
	if (req->msg.data_len) {
Packit Service ed0f68
		memcpy(msg + len, req->msg.data, req->msg.data_len);
Packit Service ed0f68
		len += req->msg.data_len;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/* second checksum */
Packit Service ed0f68
	tmp = len - cs;
Packit Service ed0f68
	msg[len++] = ipmi_csum(msg+cs, tmp);
Packit Service ed0f68
Packit Service ed0f68
	/* Dual bridged request: 2nd checksum */
Packit Service ed0f68
	if (bridgedRequest == 2) {
Packit Service ed0f68
		tmp = len - cs3;
Packit Service ed0f68
		msg[len++] = ipmi_csum(msg+cs3, tmp);
Packit Service ed0f68
		payload->payload_length += 1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/* bridged request: 2nd checksum */
Packit Service ed0f68
	if (bridgedRequest) {
Packit Service ed0f68
		tmp = len - cs2;
Packit Service ed0f68
		msg[len++] = ipmi_csum(msg+cs2, tmp);
Packit Service ed0f68
		payload->payload_length += 1;
Packit Service ed0f68
	}
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * getSolPayloadWireRep
Packit Service ed0f68
 *
Packit Service ed0f68
 * param msg [out] will contain our wire representation
Packit Service ed0f68
 * param payload [in] holds the v2 payload with our SOL data
Packit Service ed0f68
 */
Packit Service ed0f68
void getSolPayloadWireRep(
Packit Service ed0f68
						  struct ipmi_intf       * intf,  /* in out */
Packit Service ed0f68
						  uint8_t          * msg,     /* output */
Packit Service ed0f68
						  struct ipmi_v2_payload * payload) /* input */
Packit Service ed0f68
{
Packit Service ed0f68
	int i = 0;
Packit Service ed0f68
Packit Service ed0f68
	lprintf(LOG_DEBUG, ">>>>>>>>>> SENDING TO BMC >>>>>>>>>>");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL sequence number     : 0x%02x",
Packit Service ed0f68
		payload->payload.sol_packet.packet_sequence_number);
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL acked packet        : 0x%02x",
Packit Service ed0f68
		payload->payload.sol_packet.acked_packet_number);
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL accepted char count : 0x%02x",
Packit Service ed0f68
		payload->payload.sol_packet.accepted_character_count);
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL is nack             : %s",
Packit Service ed0f68
		payload->payload.sol_packet.is_nack ? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL assert ring wor     : %s",
Packit Service ed0f68
		payload->payload.sol_packet.assert_ring_wor ? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL generate break      : %s",
Packit Service ed0f68
		payload->payload.sol_packet.generate_break ? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL deassert cts        : %s",
Packit Service ed0f68
		payload->payload.sol_packet.deassert_cts ? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL deassert dcd dsr    : %s",
Packit Service ed0f68
		payload->payload.sol_packet.deassert_dcd_dsr ? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL flush inbound       : %s",
Packit Service ed0f68
		payload->payload.sol_packet.flush_inbound ? "true" : "false");
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL flush outbound      : %s",
Packit Service ed0f68
		payload->payload.sol_packet.flush_outbound ? "true" : "false");
Packit Service ed0f68
Packit Service ed0f68
	msg[i++] = payload->payload.sol_packet.packet_sequence_number;
Packit Service ed0f68
	msg[i++] = payload->payload.sol_packet.acked_packet_number;
Packit Service ed0f68
	msg[i++] = payload->payload.sol_packet.accepted_character_count;
Packit Service ed0f68
Packit Service ed0f68
	msg[i]    = payload->payload.sol_packet.is_nack           ? 0x40 : 0;
Packit Service ed0f68
	msg[i]   |= payload->payload.sol_packet.assert_ring_wor   ? 0x20 : 0;
Packit Service ed0f68
	msg[i]   |= payload->payload.sol_packet.generate_break    ? 0x10 : 0;
Packit Service ed0f68
	msg[i]   |= payload->payload.sol_packet.deassert_cts      ? 0x08 : 0;
Packit Service ed0f68
	msg[i]   |= payload->payload.sol_packet.deassert_dcd_dsr  ? 0x04 : 0;
Packit Service ed0f68
	msg[i]   |= payload->payload.sol_packet.flush_inbound     ? 0x02 : 0;
Packit Service ed0f68
	msg[i++] |= payload->payload.sol_packet.flush_outbound    ? 0x01 : 0;
Packit Service ed0f68
Packit Service ed0f68
	/* We may have data to add */
Packit Service ed0f68
	memcpy(msg + i,
Packit Service ed0f68
			payload->payload.sol_packet.data,
Packit Service ed0f68
			payload->payload.sol_packet.character_count);
Packit Service ed0f68
Packit Service ed0f68
	lprintf(LOG_DEBUG, "> SOL character count     : %d",
Packit Service ed0f68
		payload->payload.sol_packet.character_count);
Packit Service ed0f68
	lprintf(LOG_DEBUG, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
Packit Service ed0f68
Packit Service ed0f68
	if (verbose >= 5 && payload->payload.sol_packet.character_count)
Packit Service ed0f68
		printbuf(payload->payload.sol_packet.data, payload->payload.sol_packet.character_count, "SOL SEND DATA");
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * At this point, the payload length becomes the whole payload
Packit Service ed0f68
	 * length, including the 4 bytes at the beginning of the SOL
Packit Service ed0f68
	 * packet
Packit Service ed0f68
	 */
Packit Service ed0f68
	payload->payload_length = payload->payload.sol_packet.character_count + 4;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_lanplus_build_v2x_msg
Packit Service ed0f68
 *
Packit Service ed0f68
 * Encapsulates the payload data to create the IPMI v2.0 / RMCP+ packet.
Packit Service ed0f68
 * 
Packit Service ed0f68
 *
Packit Service ed0f68
 * IPMI v2.0 LAN Request Message Format
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 * |  rmcp.ver            | 4 bytes
Packit Service ed0f68
 * |  rmcp.__reserved     |
Packit Service ed0f68
 * |  rmcp.seq            |
Packit Service ed0f68
 * |  rmcp.class          |
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 * |  session.authtype    | 10 bytes
Packit Service ed0f68
 * |  session.payloadtype |
Packit Service ed0f68
 * |  session.id          |
Packit Service ed0f68
 * |  session.seq         |
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 * |  message length      | 2 bytes
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 * | Confidentiality Hdr  | var (possibly absent)
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 * |  Paylod              | var Payload
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 * | Confidentiality Trlr | var (possibly absent)
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 * | Integrity pad        | var (possibly absent)
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 * | Pad length           | 1 byte (WTF?)
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 * | Next Header          | 1 byte (WTF?)
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 * | Authcode             | var (possibly absent)
Packit Service ed0f68
 * +----------------------+
Packit Service ed0f68
 */
Packit Service ed0f68
void
Packit Service ed0f68
ipmi_lanplus_build_v2x_msg(
Packit Service ed0f68
							struct ipmi_intf       * intf,     /* in  */
Packit Service ed0f68
							struct ipmi_v2_payload * payload,  /* in  */
Packit Service ed0f68
							int                    * msg_len,  /* out */
Packit Service ed0f68
							uint8_t         ** msg_data, /* out */
Packit Service ed0f68
							uint8_t curr_seq)
Packit Service ed0f68
{
Packit Service ed0f68
	uint32_t session_trailer_length = 0;
Packit Service ed0f68
	struct ipmi_session * session = intf->session;
Packit Service ed0f68
	struct rmcp_hdr rmcp = {
Packit Service ed0f68
		.ver		= RMCP_VERSION_1,
Packit Service ed0f68
		.class		= RMCP_CLASS_IPMI,
Packit Service ed0f68
		.seq		= 0xff,
Packit Service ed0f68
	};
Packit Service ed0f68
Packit Service ed0f68
	/* msg will hold the entire message to be sent */
Packit Service ed0f68
	uint8_t * msg;
Packit Service ed0f68
	int len = 0;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	len =
Packit Service ed0f68
		sizeof(rmcp)                +  // RMCP Header (4)
Packit Service ed0f68
		10                          +  // IPMI Session Header
Packit Service ed0f68
		2                           +  // Message length
Packit Service ed0f68
		payload->payload_length     +  // The actual payload
Packit Service ed0f68
		IPMI_MAX_INTEGRITY_PAD_SIZE +  // Integrity Pad
Packit Service ed0f68
		1                           +  // Pad Length
Packit Service ed0f68
		1                           +  // Next Header
Packit Service ed0f68
		IPMI_MAX_AUTH_CODE_SIZE;       // Authcode
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	msg = malloc(len);
Packit Service ed0f68
	if (msg == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit Service ed0f68
		return;
Packit Service ed0f68
	}
Packit Service ed0f68
	memset(msg, 0, len);
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 *------------------------------------------
Packit Service ed0f68
	 * RMCP HEADER
Packit Service ed0f68
	 *------------------------------------------
Packit Service ed0f68
	 */
Packit Service ed0f68
	memcpy(msg, &rmcp, sizeof(rmcp));
Packit Service ed0f68
	len = sizeof(rmcp);
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 *------------------------------------------
Packit Service ed0f68
	 * IPMI SESSION HEADER
Packit Service ed0f68
	 *------------------------------------------
Packit Service ed0f68
	 */
Packit Service ed0f68
	/* ipmi session Auth Type / Format is always 0x06 for IPMI v2 */
Packit Service ed0f68
	msg[IPMI_LANPLUS_OFFSET_AUTHTYPE] = 0x06;
Packit Service ed0f68
Packit Service ed0f68
	/* Payload Type -- also specifies whether were authenticated/encyrpted */
Packit Service ed0f68
	msg[IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE] = payload->payload_type;
Packit Service ed0f68
Packit Service ed0f68
	if (session->v2_data.session_state == LANPLUS_STATE_ACTIVE)
Packit Service ed0f68
	{
Packit Service ed0f68
		msg[IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE] |=
Packit Service ed0f68
			((session->v2_data.crypt_alg != IPMI_CRYPT_NONE	)? 0x80 : 0x00);
Packit Service ed0f68
		msg[IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE] |=
Packit Service ed0f68
			((session->v2_data.integrity_alg  != IPMI_INTEGRITY_NONE)? 0x40 : 0x00);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (session->v2_data.session_state == LANPLUS_STATE_ACTIVE)
Packit Service ed0f68
	{
Packit Service ed0f68
		/* Session ID  -- making it LSB */
Packit Service ed0f68
		msg[IPMI_LANPLUS_OFFSET_SESSION_ID    ] = session->v2_data.bmc_id         & 0xff;
Packit Service ed0f68
		msg[IPMI_LANPLUS_OFFSET_SESSION_ID + 1] = (session->v2_data.bmc_id >> 8)  & 0xff;
Packit Service ed0f68
		msg[IPMI_LANPLUS_OFFSET_SESSION_ID + 2] = (session->v2_data.bmc_id >> 16) & 0xff;
Packit Service ed0f68
		msg[IPMI_LANPLUS_OFFSET_SESSION_ID + 3] = (session->v2_data.bmc_id >> 24) & 0xff;
Packit Service ed0f68
Packit Service ed0f68
		/* Sequence Number -- making it LSB */
Packit Service ed0f68
		msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM    ] = session->out_seq         & 0xff;
Packit Service ed0f68
		msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM + 1] = (session->out_seq >> 8)  & 0xff;
Packit Service ed0f68
		msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM + 2] = (session->out_seq >> 16) & 0xff;
Packit Service ed0f68
		msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM + 3] = (session->out_seq >> 24) & 0xff;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Payload Length is set below (we don't know how big the payload is until after
Packit Service ed0f68
	 * encryption).
Packit Service ed0f68
	 */
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Payload
Packit Service ed0f68
	 *
Packit Service ed0f68
	 * At this point we are ready to slam the payload in.
Packit Service ed0f68
	 * This includes:
Packit Service ed0f68
	 * 1) The confidentiality header
Packit Service ed0f68
	 * 2) The payload proper (possibly encrypted)
Packit Service ed0f68
	 * 3) The confidentiality trailer
Packit Service ed0f68
	 *
Packit Service ed0f68
	 */
Packit Service ed0f68
	switch (payload->payload_type)
Packit Service ed0f68
	{
Packit Service ed0f68
	case IPMI_PAYLOAD_TYPE_IPMI:
Packit Service ed0f68
		getIpmiPayloadWireRep(intf,
Packit Service ed0f68
							  payload,  /* in  */
Packit Service ed0f68
							  msg + IPMI_LANPLUS_OFFSET_PAYLOAD,
Packit Service ed0f68
							  payload->payload.ipmi_request.request,
Packit Service ed0f68
							  payload->payload.ipmi_request.rq_seq,
Packit Service ed0f68
							  curr_seq);
Packit Service ed0f68
		break;
Packit Service ed0f68
Packit Service ed0f68
	case IPMI_PAYLOAD_TYPE_SOL:
Packit Service ed0f68
		getSolPayloadWireRep(intf,
Packit Service ed0f68
							 msg + IPMI_LANPLUS_OFFSET_PAYLOAD,
Packit Service ed0f68
							 payload);
Packit Service ed0f68
Packit Service ed0f68
		if (verbose >= 5)
Packit Service ed0f68
			printbuf(msg + IPMI_LANPLUS_OFFSET_PAYLOAD, 4, "SOL MSG TO BMC");
Packit Service ed0f68
Packit Service ed0f68
		len += payload->payload_length;
Packit Service ed0f68
Packit Service ed0f68
		break;
Packit Service ed0f68
Packit Service ed0f68
	case IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST:
Packit Service ed0f68
		/* never encrypted, so our job is easy */
Packit Service ed0f68
		memcpy(msg + IPMI_LANPLUS_OFFSET_PAYLOAD,
Packit Service ed0f68
				payload->payload.open_session_request.request,
Packit Service ed0f68
				payload->payload_length);
Packit Service ed0f68
		len += payload->payload_length;
Packit Service ed0f68
		break;
Packit Service ed0f68
Packit Service ed0f68
	case IPMI_PAYLOAD_TYPE_RAKP_1:
Packit Service ed0f68
		/* never encrypted, so our job is easy */
Packit Service ed0f68
		memcpy(msg + IPMI_LANPLUS_OFFSET_PAYLOAD,
Packit Service ed0f68
				payload->payload.rakp_1_message.message,
Packit Service ed0f68
				payload->payload_length);
Packit Service ed0f68
		len += payload->payload_length;
Packit Service ed0f68
		break;
Packit Service ed0f68
Packit Service ed0f68
	case IPMI_PAYLOAD_TYPE_RAKP_3:
Packit Service ed0f68
		/* never encrypted, so our job is easy */
Packit Service ed0f68
		memcpy(msg + IPMI_LANPLUS_OFFSET_PAYLOAD,
Packit Service ed0f68
				payload->payload.rakp_3_message.message,
Packit Service ed0f68
				payload->payload_length);
Packit Service ed0f68
		len += payload->payload_length;
Packit Service ed0f68
		break;
Packit Service ed0f68
Packit Service ed0f68
	default:
Packit Service ed0f68
		lprintf(LOG_ERR, "unsupported payload type 0x%x",
Packit Service ed0f68
			payload->payload_type);
Packit Service ed0f68
		free(msg);
Packit Service ed0f68
		msg = NULL;
Packit Service ed0f68
		assert(0);
Packit Service ed0f68
		break;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 *------------------------------------------
Packit Service ed0f68
	 * ENCRYPT THE PAYLOAD IF NECESSARY
Packit Service ed0f68
	 *------------------------------------------
Packit Service ed0f68
	 */
Packit Service ed0f68
	if (session->v2_data.session_state == LANPLUS_STATE_ACTIVE)
Packit Service ed0f68
	{
Packit Service ed0f68
		/* Payload len is adjusted as necessary by lanplus_encrypt_payload */
Packit Service ed0f68
		lanplus_encrypt_payload(session->v2_data.crypt_alg,        /* input  */
Packit Service ed0f68
								session->v2_data.k2,               /* input  */
Packit Service ed0f68
								msg + IPMI_LANPLUS_OFFSET_PAYLOAD, /* input  */
Packit Service ed0f68
								payload->payload_length,           /* input  */
Packit Service ed0f68
								msg + IPMI_LANPLUS_OFFSET_PAYLOAD, /* output */
Packit Service ed0f68
								&(payload->payload_length));       /* output */
Packit Service ed0f68
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/* Now we know the payload length */
Packit Service ed0f68
	msg[IPMI_LANPLUS_OFFSET_PAYLOAD_SIZE    ] =
Packit Service ed0f68
		payload->payload_length        & 0xff;
Packit Service ed0f68
	msg[IPMI_LANPLUS_OFFSET_PAYLOAD_SIZE + 1] =
Packit Service ed0f68
		(payload->payload_length >> 8) & 0xff;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 *------------------------------------------
Packit Service ed0f68
	 * SESSION TRAILER
Packit Service ed0f68
	 *------------------------------------------
Packit Service ed0f68
	 */
Packit Service ed0f68
	if ((session->v2_data.session_state == LANPLUS_STATE_ACTIVE) &&
Packit Service ed0f68
		(session->v2_data.integrity_alg != IPMI_INTEGRITY_NONE))
Packit Service ed0f68
	{
Packit Service ed0f68
		uint32_t i;
Packit Service ed0f68
		uint32_t hmac_length;
Packit Service ed0f68
		uint32_t auth_length = 0;
Packit Service ed0f68
		uint32_t integrity_pad_size = 0;
Packit Service ed0f68
		uint32_t hmac_input_size;
Packit Service ed0f68
		uint8_t * hmac_output;
Packit Service ed0f68
		uint32_t start_of_session_trailer =
Packit Service ed0f68
			IPMI_LANPLUS_OFFSET_PAYLOAD +
Packit Service ed0f68
			payload->payload_length;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * Determine the required integrity pad length.  We have to make the
Packit Service ed0f68
		 * data range covered by the authcode a multiple of 4.
Packit Service ed0f68
		 */
Packit Service ed0f68
		uint32_t length_before_authcode;
Packit Service ed0f68
Packit Service ed0f68
		if (ipmi_oem_active(intf, "icts")) {
Packit Service ed0f68
			length_before_authcode =
Packit Service ed0f68
				12                          + /* the stuff before the payload */
Packit Service ed0f68
				payload->payload_length;
Packit Service ed0f68
		} else {
Packit Service ed0f68
			length_before_authcode =
Packit Service ed0f68
				12                          + /* the stuff before the payload */
Packit Service ed0f68
				payload->payload_length     +
Packit Service ed0f68
				1                           + /* pad length field  */
Packit Service ed0f68
				1;                            /* next header field */
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		if (length_before_authcode % 4)
Packit Service ed0f68
			integrity_pad_size = 4 - (length_before_authcode % 4);
Packit Service ed0f68
Packit Service ed0f68
		for (i = 0; i < integrity_pad_size; ++i)
Packit Service ed0f68
			msg[start_of_session_trailer + i] = 0xFF;
Packit Service ed0f68
Packit Service ed0f68
		/* Pad length */
Packit Service ed0f68
		msg[start_of_session_trailer + integrity_pad_size] = integrity_pad_size;
Packit Service ed0f68
Packit Service ed0f68
		/* Next Header */
Packit Service ed0f68
		msg[start_of_session_trailer + integrity_pad_size + 1] =
Packit Service ed0f68
			0x07; /* Hardcoded per the spec, table 13-8 */
Packit Service ed0f68
Packit Service ed0f68
		hmac_input_size =
Packit Service ed0f68
			12                      +
Packit Service ed0f68
			payload->payload_length +
Packit Service ed0f68
			integrity_pad_size      +
Packit Service ed0f68
			2;
Packit Service ed0f68
Packit Service ed0f68
		hmac_output =
Packit Service ed0f68
			msg                         +
Packit Service ed0f68
			IPMI_LANPLUS_OFFSET_PAYLOAD +
Packit Service ed0f68
			payload->payload_length     +
Packit Service ed0f68
			integrity_pad_size          +
Packit Service ed0f68
			2;
Packit Service ed0f68
Packit Service ed0f68
		if (verbose > 2)
Packit Service ed0f68
			printbuf(msg + IPMI_LANPLUS_OFFSET_AUTHTYPE, hmac_input_size, "authcode input");
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
		/* Auth Code */
Packit Service ed0f68
		lanplus_HMAC(session->v2_data.integrity_alg,
Packit Service ed0f68
					 session->v2_data.k1,                /* key        */
Packit Service ed0f68
					 session->v2_data.k1_len,            /* key length */
Packit Service ed0f68
					 msg + IPMI_LANPLUS_OFFSET_AUTHTYPE, /* hmac input */
Packit Service ed0f68
					 hmac_input_size,
Packit Service ed0f68
					 hmac_output,
Packit Service ed0f68
					 &hmac_length);
Packit Service ed0f68
Packit Service ed0f68
		switch(session->v2_data.integrity_alg) {
Packit Service ed0f68
			case IPMI_INTEGRITY_HMAC_SHA1_96:
Packit Service ed0f68
				assert(hmac_length == IPMI_SHA_DIGEST_LENGTH);
Packit Service ed0f68
				auth_length = IPMI_SHA1_AUTHCODE_SIZE;
Packit Service ed0f68
				break;
Packit Service ed0f68
			case IPMI_INTEGRITY_HMAC_MD5_128 :
Packit Service ed0f68
				assert(hmac_length == IPMI_MD5_DIGEST_LENGTH);
Packit Service ed0f68
				auth_length = IPMI_HMAC_MD5_AUTHCODE_SIZE;
Packit Service ed0f68
				break;
Packit Service ed0f68
#ifdef HAVE_CRYPTO_SHA256
Packit Service ed0f68
			case IPMI_INTEGRITY_HMAC_SHA256_128:
Packit Service ed0f68
				assert(hmac_length == IPMI_SHA256_DIGEST_LENGTH);
Packit Service ed0f68
				auth_length = IPMI_HMAC_SHA256_AUTHCODE_SIZE;
Packit Service ed0f68
				break;
Packit Service ed0f68
#endif /* HAVE_CRYPTO_SHA256 */
Packit Service ed0f68
			default:
Packit Service ed0f68
				assert(0);
Packit Service ed0f68
				break;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		if (verbose > 2)
Packit Service ed0f68
			printbuf(hmac_output, auth_length, "authcode output");
Packit Service ed0f68
Packit Service ed0f68
		/* Set session_trailer_length appropriately */
Packit Service ed0f68
		session_trailer_length =
Packit Service ed0f68
			integrity_pad_size +
Packit Service ed0f68
			2                  + /* pad length + next header */
Packit Service ed0f68
			auth_length;         /* Size of the authcode. We only
Packit Service ed0f68
			                      * use the first 12(SHA1) or
Packit Service ed0f68
			                      * 16(MD5/SHA256) bytes.
Packit Service ed0f68
			                      */
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	++(session->out_seq);
Packit Service ed0f68
	if (!session->out_seq)
Packit Service ed0f68
		++(session->out_seq);
Packit Service ed0f68
Packit Service ed0f68
	*msg_len =
Packit Service ed0f68
		IPMI_LANPLUS_OFFSET_PAYLOAD +
Packit Service ed0f68
		payload->payload_length     +
Packit Service ed0f68
		session_trailer_length;
Packit Service ed0f68
	*msg_data = msg;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_lanplus_build_v2x_ipmi_cmd
Packit Service ed0f68
 *
Packit Service ed0f68
 * Wraps ipmi_lanplus_build_v2x_msg and returns a new entry object for the
Packit Service ed0f68
 * command
Packit Service ed0f68
 *
Packit Service ed0f68
 */
Packit Service ed0f68
static struct ipmi_rq_entry *
Packit Service ed0f68
ipmi_lanplus_build_v2x_ipmi_cmd(
Packit Service ed0f68
								struct ipmi_intf * intf,
Packit Service ed0f68
								struct ipmi_rq * req,
Packit Service ed0f68
								int isRetry)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_v2_payload v2_payload;
Packit Service ed0f68
	struct ipmi_rq_entry * entry;
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * We have a problem.  we need to know the sequence number here,
Packit Service ed0f68
	 * because we use it in our stored entry.  But we also need to
Packit Service ed0f68
	 * know the sequence number when we generate our IPMI
Packit Service ed0f68
	 * representation far below.
Packit Service ed0f68
	 */
Packit Service ed0f68
	static uint8_t curr_seq = 0;
Packit Service ed0f68
Packit Service ed0f68
	if( isRetry == 0 )
Packit Service ed0f68
		curr_seq += 1;
Packit Service ed0f68
Packit Service ed0f68
	if (curr_seq >= 64)
Packit Service ed0f68
		curr_seq = 0;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/* IPMI Message Header -- Figure 13-4 of the IPMI v2.0 spec */
Packit Service ed0f68
	if ((intf->target_addr == intf->my_addr) || (!bridgePossible)) {
Packit Service ed0f68
		entry = ipmi_req_add_entry(intf, req, curr_seq);
Packit Service ed0f68
	/* it's a bridge command */
Packit Service ed0f68
	} else {
Packit Service ed0f68
		unsigned char backup_cmd;
Packit Service ed0f68
Packit Service ed0f68
		/* Add entry for cmd */
Packit Service ed0f68
		entry = ipmi_req_add_entry(intf, req, curr_seq);
Packit Service ed0f68
Packit Service ed0f68
		if (entry) {
Packit Service ed0f68
			entry->req.msg.target_cmd = entry->req.msg.cmd;
Packit Service ed0f68
			entry->req.msg.cmd = 0x34;
Packit Service ed0f68
Packit Service ed0f68
			if (intf->transit_addr &&
Packit Service ed0f68
					intf->transit_addr != intf->my_addr)
Packit Service ed0f68
				entry->bridging_level = 2;
Packit Service ed0f68
			else
Packit Service ed0f68
				entry->bridging_level = 1;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (entry == NULL)
Packit Service ed0f68
		return NULL;
Packit Service ed0f68
Packit Service ed0f68
	// Build our payload
Packit Service ed0f68
	v2_payload.payload_type                 = IPMI_PAYLOAD_TYPE_IPMI;
Packit Service ed0f68
	v2_payload.payload_length               = req->msg.data_len + 7;
Packit Service ed0f68
	v2_payload.payload.ipmi_request.request = req;
Packit Service ed0f68
	v2_payload.payload.ipmi_request.rq_seq  = curr_seq;
Packit Service ed0f68
Packit Service ed0f68
	ipmi_lanplus_build_v2x_msg(intf,                // in
Packit Service ed0f68
					&v2_payload,         // in
Packit Service ed0f68
					&(entry->msg_len),   // out
Packit Service ed0f68
					&(entry->msg_data),  // out
Packit Service ed0f68
					curr_seq); 		// in
Packit Service ed0f68
Packit Service ed0f68
	return entry;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * IPMI LAN Request Message Format
Packit Service ed0f68
 * +--------------------+
Packit Service ed0f68
 * |  rmcp.ver          | 4 bytes
Packit Service ed0f68
 * |  rmcp.__reserved   |
Packit Service ed0f68
 * |  rmcp.seq          |
Packit Service ed0f68
 * |  rmcp.class        |
Packit Service ed0f68
 * +--------------------+
Packit Service ed0f68
 * |  session.authtype  | 9 bytes
Packit Service ed0f68
 * |  session.seq       |
Packit Service ed0f68
 * |  session.id        |
Packit Service ed0f68
 * +--------------------+
Packit Service ed0f68
 * | [session.authcode] | 16 bytes (AUTHTYPE != none)
Packit Service ed0f68
 * +--------------------+
Packit Service ed0f68
 * |  message length    | 1 byte
Packit Service ed0f68
 * +--------------------+
Packit Service ed0f68
 * |  message.rs_addr   | 6 bytes
Packit Service ed0f68
 * |  message.netfn_lun |
Packit Service ed0f68
 * |  message.checksum  |
Packit Service ed0f68
 * |  message.rq_addr   |
Packit Service ed0f68
 * |  message.rq_seq    |
Packit Service ed0f68
 * |  message.cmd       |
Packit Service ed0f68
 * +--------------------+
Packit Service ed0f68
 * | [request data]     | data_len bytes
Packit Service ed0f68
 * +--------------------+
Packit Service ed0f68
 * |  checksum          | 1 byte
Packit Service ed0f68
 * +--------------------+
Packit Service ed0f68
 */
Packit Service ed0f68
static struct ipmi_rq_entry *
Packit Service ed0f68
ipmi_lanplus_build_v15_ipmi_cmd(
Packit Service ed0f68
								struct ipmi_intf * intf,
Packit Service ed0f68
								struct ipmi_rq * req)
Packit Service ed0f68
{
Packit Service ed0f68
	struct rmcp_hdr rmcp = {
Packit Service ed0f68
		.ver		= RMCP_VERSION_1,
Packit Service ed0f68
		.class		= RMCP_CLASS_IPMI,
Packit Service ed0f68
		.seq		= 0xff,
Packit Service ed0f68
	};
Packit Service ed0f68
	uint8_t * msg;
Packit Service ed0f68
	int cs, mp, len = 0, tmp;
Packit Service ed0f68
	struct ipmi_session  * session = intf->session;
Packit Service ed0f68
	struct ipmi_rq_entry * entry;
Packit Service ed0f68
Packit Service ed0f68
	entry = ipmi_req_add_entry(intf, req, 0);
Packit Service ed0f68
	if (entry == NULL)
Packit Service ed0f68
		return NULL;
Packit Service ed0f68
Packit Service ed0f68
	len = req->msg.data_len + 21;
Packit Service ed0f68
Packit Service ed0f68
	msg = malloc(len);
Packit Service ed0f68
	if (msg == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit Service ed0f68
		return NULL;
Packit Service ed0f68
	}
Packit Service ed0f68
	memset(msg, 0, len);
Packit Service ed0f68
Packit Service ed0f68
	/* rmcp header */
Packit Service ed0f68
	memcpy(msg, &rmcp, sizeof(rmcp));
Packit Service ed0f68
	len = sizeof(rmcp);
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * ipmi session header
Packit Service ed0f68
	 */
Packit Service ed0f68
	/* Authtype should always be none for 1.5 packets sent from this
Packit Service ed0f68
	 * interface
Packit Service ed0f68
	 */
Packit Service ed0f68
	msg[len++] = IPMI_SESSION_AUTHTYPE_NONE;
Packit Service ed0f68
Packit Service ed0f68
	msg[len++] = session->out_seq & 0xff;
Packit Service ed0f68
	msg[len++] = (session->out_seq >> 8) & 0xff;
Packit Service ed0f68
	msg[len++] = (session->out_seq >> 16) & 0xff;
Packit Service ed0f68
	msg[len++] = (session->out_seq >> 24) & 0xff;
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * The session ID should be all zeroes for pre-session commands.  We
Packit Service ed0f68
	 * should only be using the 1.5 interface for the pre-session Get
Packit Service ed0f68
	 * Channel Authentication Capabilities command
Packit Service ed0f68
	 */
Packit Service ed0f68
	msg[len++] = 0;
Packit Service ed0f68
	msg[len++] = 0;
Packit Service ed0f68
	msg[len++] = 0;
Packit Service ed0f68
	msg[len++] = 0;
Packit Service ed0f68
Packit Service ed0f68
	/* message length */
Packit Service ed0f68
	msg[len++] = req->msg.data_len + 7;
Packit Service ed0f68
Packit Service ed0f68
	/* ipmi message header */
Packit Service ed0f68
	cs = mp = len;
Packit Service ed0f68
	msg[len++] = IPMI_BMC_SLAVE_ADDR;
Packit Service ed0f68
	msg[len++] = req->msg.netfn << 2;
Packit Service ed0f68
	tmp = len - cs;
Packit Service ed0f68
	msg[len++] = ipmi_csum(msg+cs, tmp);
Packit Service ed0f68
	cs = len;
Packit Service ed0f68
	msg[len++] = IPMI_REMOTE_SWID;
Packit Service ed0f68
Packit Service ed0f68
	entry->rq_seq = 0;
Packit Service ed0f68
Packit Service ed0f68
	msg[len++] = entry->rq_seq << 2;
Packit Service ed0f68
	msg[len++] = req->msg.cmd;
Packit Service ed0f68
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">> IPMI Request Session Header");
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">>   Authtype   : %s",
Packit Service ed0f68
		val2str(IPMI_SESSION_AUTHTYPE_NONE, ipmi_authtype_session_vals));
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">>   Sequence   : 0x%08lx",
Packit Service ed0f68
		(long)session->out_seq);
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">>   Session ID : 0x%08lx",
Packit Service ed0f68
		(long)0);
Packit Service ed0f68
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">> IPMI Request Message Header");
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">>   Rs Addr    : %02x", IPMI_BMC_SLAVE_ADDR);
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">>   NetFn      : %02x", req->msg.netfn);
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">>   Rs LUN     : %01x", 0);
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">>   Rq Addr    : %02x", IPMI_REMOTE_SWID);
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">>   Rq Seq     : %02x", entry->rq_seq);
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">>   Rq Lun     : %01x", 0);
Packit Service ed0f68
	lprintf(LOG_DEBUG+1, ">>   Command    : %02x", req->msg.cmd);
Packit Service ed0f68
Packit Service ed0f68
	/* message data */
Packit Service ed0f68
	if (req->msg.data_len) {
Packit Service ed0f68
		memcpy(msg+len, req->msg.data, req->msg.data_len);
Packit Service ed0f68
		len += req->msg.data_len;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/* second checksum */
Packit Service ed0f68
	tmp = len - cs;
Packit Service ed0f68
	msg[len++] = ipmi_csum(msg+cs, tmp);
Packit Service ed0f68
Packit Service ed0f68
	entry->msg_len = len;
Packit Service ed0f68
	entry->msg_data = msg;
Packit Service ed0f68
Packit Service ed0f68
	return entry;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * is_sol_packet
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
is_sol_packet(struct ipmi_rs * rsp)
Packit Service ed0f68
{
Packit Service ed0f68
	return (rsp                                                           &&
Packit Service ed0f68
			(rsp->session.authtype    == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
Packit Service ed0f68
			(rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL));
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * sol_response_acks_packet
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
sol_response_acks_packet(
Packit Service ed0f68
						 struct ipmi_rs         * rsp,
Packit Service ed0f68
						 struct ipmi_v2_payload * payload)
Packit Service ed0f68
{
Packit Service ed0f68
	return (is_sol_packet(rsp)                                            &&
Packit Service ed0f68
			payload                                                       &&
Packit Service ed0f68
			(payload->payload_type    == IPMI_PAYLOAD_TYPE_SOL)           && 
Packit Service ed0f68
			(rsp->payload.sol_packet.acked_packet_number ==
Packit Service ed0f68
			 payload->payload.sol_packet.packet_sequence_number));
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_lanplus_send_payload
Packit Service ed0f68
 *
Packit Service ed0f68
 */
Packit Service ed0f68
struct ipmi_rs *
Packit Service ed0f68
ipmi_lanplus_send_payload(
Packit Service ed0f68
						  struct ipmi_intf * intf,
Packit Service ed0f68
						  struct ipmi_v2_payload * payload)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs      * rsp = NULL;
Packit Service ed0f68
	uint8_t             * msg_data = NULL;
Packit Service ed0f68
	int                   msg_length;
Packit Service ed0f68
	struct ipmi_session * session = intf->session;
Packit Service ed0f68
	struct ipmi_rq_entry * entry = NULL;
Packit Service ed0f68
	int                   try = 0;
Packit Service ed0f68
	int                   xmit = 1;
Packit Service ed0f68
	time_t                ltime;
Packit Service ed0f68
	uint32_t	      saved_timeout;
Packit Service ed0f68
Packit Service ed0f68
	if (!intf->opened && intf->open && intf->open(intf) < 0)
Packit Service ed0f68
		return NULL;
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * The session timeout is initialized in the above interface open,
Packit Service ed0f68
	 * so it will only be valid after the open completes.
Packit Service ed0f68
	 */
Packit Service ed0f68
	saved_timeout = session->timeout;
Packit Service ed0f68
	while (try < intf->ssn_params.retry) {
Packit Service ed0f68
		//ltime = time(NULL);
Packit Service ed0f68
Packit Service ed0f68
		if (xmit) {
Packit Service ed0f68
			ltime = time(NULL);
Packit Service ed0f68
Packit Service ed0f68
			if (payload->payload_type == IPMI_PAYLOAD_TYPE_IPMI)
Packit Service ed0f68
			{
Packit Service ed0f68
				/*
Packit Service ed0f68
				 * Build an IPMI v1.5 or v2 command
Packit Service ed0f68
				 */
Packit Service ed0f68
				struct ipmi_rq * ipmi_request = payload->payload.ipmi_request.request;
Packit Service ed0f68
Packit Service ed0f68
				lprintf(LOG_DEBUG, "");
Packit Service ed0f68
				lprintf(LOG_DEBUG, ">> Sending IPMI command payload");
Packit Service ed0f68
				lprintf(LOG_DEBUG, ">>    netfn   : 0x%02x", ipmi_request->msg.netfn);
Packit Service ed0f68
				lprintf(LOG_DEBUG, ">>    command : 0x%02x", ipmi_request->msg.cmd);
Packit Service ed0f68
Packit Service ed0f68
				if (verbose > 1)
Packit Service ed0f68
				{
Packit Service ed0f68
					uint16_t i;
Packit Service ed0f68
					fprintf(stderr, ">>    data    : ");
Packit Service ed0f68
					for (i = 0; i < ipmi_request->msg.data_len; ++i)
Packit Service ed0f68
						fprintf(stderr, "0x%02x ", ipmi_request->msg.data[i]);
Packit Service ed0f68
					fprintf(stderr, "\n\n");
Packit Service ed0f68
				}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
				/*
Packit Service ed0f68
				 * If we are presession, and the command is GET CHANNEL AUTHENTICATION
Packit Service ed0f68
				 * CAPABILITIES, we will build the command in v1.5 format.  This is so
Packit Service ed0f68
				 * that we can ask any server whether it supports IPMI v2 / RMCP+
Packit Service ed0f68
				 * before we attempt to open a v2.x session.
Packit Service ed0f68
				 */
Packit Service ed0f68
				if ((ipmi_request->msg.netfn == IPMI_NETFN_APP) &&
Packit Service ed0f68
					 (ipmi_request->msg.cmd   == IPMI_GET_CHANNEL_AUTH_CAP) &&
Packit Service ed0f68
					 (session->v2_data.bmc_id  == 0)) // jme - check
Packit Service ed0f68
				{
Packit Service ed0f68
					lprintf(LOG_DEBUG+1, "BUILDING A v1.5 COMMAND");
Packit Service ed0f68
					entry = ipmi_lanplus_build_v15_ipmi_cmd(intf, ipmi_request);
Packit Service ed0f68
				}
Packit Service ed0f68
				else
Packit Service ed0f68
				{
Packit Service ed0f68
					int isRetry = ( try > 0 ? 1 : 0 );
Packit Service ed0f68
Packit Service ed0f68
					lprintf(LOG_DEBUG+1, "BUILDING A v2 COMMAND");
Packit Service ed0f68
					entry = ipmi_lanplus_build_v2x_ipmi_cmd(intf, ipmi_request, isRetry);
Packit Service ed0f68
				}
Packit Service ed0f68
Packit Service ed0f68
				if (entry == NULL) {
Packit Service ed0f68
					lprintf(LOG_ERR, "Aborting send command, unable to build");
Packit Service ed0f68
					return NULL;
Packit Service ed0f68
				}
Packit Service ed0f68
Packit Service ed0f68
				msg_data   = entry->msg_data;
Packit Service ed0f68
				msg_length = entry->msg_len;
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST)
Packit Service ed0f68
			{
Packit Service ed0f68
				lprintf(LOG_DEBUG, ">> SENDING AN OPEN SESSION REQUEST\n");
Packit Service ed0f68
				assert(session->v2_data.session_state == LANPLUS_STATE_PRESESSION
Packit Service ed0f68
						|| session->v2_data.session_state == LANPLUS_STATE_OPEN_SESSION_SENT);
Packit Service ed0f68
Packit Service ed0f68
				ipmi_lanplus_build_v2x_msg(intf,        /* in  */
Packit Service ed0f68
								payload,     /* in  */
Packit Service ed0f68
								&msg_length, /* out */
Packit Service ed0f68
								&msg_data,   /* out */
Packit Service ed0f68
								0);  /* irrelevant for this msg*/
Packit Service ed0f68
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RAKP_1)
Packit Service ed0f68
			{
Packit Service ed0f68
				lprintf(LOG_DEBUG, ">> SENDING A RAKP 1 MESSAGE\n");
Packit Service ed0f68
				assert(session->v2_data.session_state ==
Packit Service ed0f68
						 LANPLUS_STATE_OPEN_SESSION_RECEIEVED);
Packit Service ed0f68
Packit Service ed0f68
				ipmi_lanplus_build_v2x_msg(intf,        /* in  */
Packit Service ed0f68
								payload,     /* in  */
Packit Service ed0f68
								&msg_length, /* out */
Packit Service ed0f68
								&msg_data,   /* out */
Packit Service ed0f68
								0);  /* irrelevant for this msg*/
Packit Service ed0f68
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RAKP_3)
Packit Service ed0f68
			{
Packit Service ed0f68
				lprintf(LOG_DEBUG, ">> SENDING A RAKP 3 MESSAGE\n");
Packit Service ed0f68
				assert(session->v2_data.session_state ==
Packit Service ed0f68
						 LANPLUS_STATE_RAKP_2_RECEIVED);
Packit Service ed0f68
Packit Service ed0f68
				ipmi_lanplus_build_v2x_msg(intf,        /* in  */
Packit Service ed0f68
								payload,     /* in  */
Packit Service ed0f68
								&msg_length, /* out */
Packit Service ed0f68
								&msg_data,   /* out */
Packit Service ed0f68
								0);  /* irrelevant for this msg*/
Packit Service ed0f68
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			else if (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL)
Packit Service ed0f68
			{
Packit Service ed0f68
				lprintf(LOG_DEBUG, ">> SENDING A SOL MESSAGE\n");
Packit Service ed0f68
				assert(session->v2_data.session_state == LANPLUS_STATE_ACTIVE);
Packit Service ed0f68
Packit Service ed0f68
				ipmi_lanplus_build_v2x_msg(intf,        /* in  */
Packit Service ed0f68
								payload,     /* in  */
Packit Service ed0f68
								&msg_length, /* out */
Packit Service ed0f68
								&msg_data,   /* out */
Packit Service ed0f68
								0);  /* irrelevant for this msg*/
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			else
Packit Service ed0f68
			{
Packit Service ed0f68
				lprintf(LOG_ERR, "Payload type 0x%0x is unsupported!",
Packit Service ed0f68
					payload->payload_type);
Packit Service ed0f68
				assert(0);
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
			if (ipmi_lan_send_packet(intf, msg_data, msg_length) < 0) {
Packit Service ed0f68
				lprintf(LOG_ERR, "IPMI LAN send command failed");
Packit Service ed0f68
				return NULL;
Packit Service ed0f68
			}
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		/* if we are set to noanswer we do not expect response */
Packit Service ed0f68
		if (intf->noanswer)
Packit Service ed0f68
			break;
Packit Service ed0f68
Packit Service ed0f68
		usleep(100); 			/* Not sure what this is for */
Packit Service ed0f68
Packit Service ed0f68
		/* Remember our connection state */
Packit Service ed0f68
		switch (payload->payload_type)
Packit Service ed0f68
		{
Packit Service ed0f68
		case IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST:
Packit Service ed0f68
			session->v2_data.session_state = LANPLUS_STATE_OPEN_SESSION_SENT;
Packit Service ed0f68
			/* not retryable for timeouts, force no retry */
Packit Service ed0f68
			try = intf->ssn_params.retry;
Packit Service ed0f68
			break;
Packit Service ed0f68
		case IPMI_PAYLOAD_TYPE_RAKP_1:
Packit Service ed0f68
			session->v2_data.session_state = LANPLUS_STATE_RAKP_1_SENT;
Packit Service ed0f68
			/* not retryable for timeouts, force no retry */
Packit Service ed0f68
			try = intf->ssn_params.retry;
Packit Service ed0f68
			break;
Packit Service ed0f68
		case IPMI_PAYLOAD_TYPE_RAKP_3:
Packit Service ed0f68
			/* not retryable for timeouts, force no retry */
Packit Service ed0f68
			try = intf->ssn_params.retry;
Packit Service ed0f68
			session->v2_data.session_state = LANPLUS_STATE_RAKP_3_SENT;
Packit Service ed0f68
			break;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * Special case for SOL outbound packets.
Packit Service ed0f68
		 */
Packit Service ed0f68
		if (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL)
Packit Service ed0f68
		{
Packit Service ed0f68
			if (! payload->payload.sol_packet.packet_sequence_number)
Packit Service ed0f68
			{
Packit Service ed0f68
				/* We're just sending an ACK.  No need to retry. */
Packit Service ed0f68
				break;
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
			rsp = ipmi_lanplus_recv_sol(intf); /* Grab the next packet */
Packit Service ed0f68
Packit Service ed0f68
			if (!is_sol_packet(rsp)) {
Packit Service ed0f68
				break;
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			if (sol_response_acks_packet(rsp, payload))
Packit Service ed0f68
				break;
Packit Service ed0f68
Packit Service ed0f68
			else if (is_sol_packet(rsp) && rsp->data_len)
Packit Service ed0f68
			{
Packit Service ed0f68
				/*
Packit Service ed0f68
				 * We're still waiting for our ACK, but we more data from
Packit Service ed0f68
				 * the BMC
Packit Service ed0f68
				 */
Packit Service ed0f68
				intf->session->sol_data.sol_input_handler(rsp);
Packit Service ed0f68
				/* In order to avoid duplicate output, just set data_len to 0 */
Packit Service ed0f68
				rsp->data_len = 0;
Packit Service ed0f68
				break;
Packit Service ed0f68
			}
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
		/* Non-SOL processing */
Packit Service ed0f68
		else
Packit Service ed0f68
		{
Packit Service ed0f68
			rsp = ipmi_lan_poll_recv(intf);
Packit Service ed0f68
Packit Service ed0f68
			/* Duplicate Request ccode most likely indicates a response to
Packit Service ed0f68
			   a previous retry. Ignore and keep polling. */
Packit Service ed0f68
			while ((rsp != NULL) && (rsp->ccode == 0xcf))
Packit Service ed0f68
			{
Packit Service ed0f68
				rsp = NULL;
Packit Service ed0f68
				rsp = ipmi_lan_poll_recv(intf);
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			if (rsp)
Packit Service ed0f68
				break;
Packit Service ed0f68
			/* This payload type is retryable for timeouts. */
Packit Service ed0f68
			if ((payload->payload_type == IPMI_PAYLOAD_TYPE_IPMI) && entry) {
Packit Service ed0f68
				ipmi_req_remove_entry( entry->rq_seq, entry->req.msg.cmd);
Packit Service ed0f68
			}
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		/* only timeout if time exceeds the timeout value */
Packit Service ed0f68
		xmit = ((time(NULL) - ltime) >= session->timeout);
Packit Service ed0f68
Packit Service ed0f68
		usleep(5000);
Packit Service ed0f68
Packit Service ed0f68
		if (xmit) {
Packit Service ed0f68
			/* increment session timeout by 1 second each retry */
Packit Service ed0f68
			session->timeout++;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		try++;
Packit Service ed0f68
	}
Packit Service ed0f68
	session->timeout = saved_timeout;
Packit Service ed0f68
Packit Service ed0f68
	/* IPMI messages are deleted under ipmi_lan_poll_recv() */
Packit Service ed0f68
	switch (payload->payload_type) {
Packit Service ed0f68
	case IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST:
Packit Service ed0f68
	case IPMI_PAYLOAD_TYPE_RAKP_1:
Packit Service ed0f68
	case IPMI_PAYLOAD_TYPE_RAKP_3:
Packit Service ed0f68
	case IPMI_PAYLOAD_TYPE_SOL:
Packit Service ed0f68
		free(msg_data);
Packit Service ed0f68
		msg_data = NULL;
Packit Service ed0f68
		break;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return rsp;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * is_sol_partial_ack
Packit Service ed0f68
 *
Packit Service ed0f68
 * Determine if the response is a partial ACK/NACK that indicates
Packit Service ed0f68
 * we need to resend part of our packet.
Packit Service ed0f68
 *
Packit Service ed0f68
 * returns the number of characters we need to resend, or
Packit Service ed0f68
 *         0 if this isn't an ACK or we don't need to resend anything
Packit Service ed0f68
 */
Packit Service ed0f68
int is_sol_partial_ack(
Packit Service ed0f68
						struct ipmi_intf       * intf,
Packit Service ed0f68
						struct ipmi_v2_payload * v2_payload,
Packit Service ed0f68
						struct ipmi_rs         * rs)
Packit Service ed0f68
{
Packit Service ed0f68
	int chars_to_resend = 0;
Packit Service ed0f68
Packit Service ed0f68
	if (v2_payload                               &&
Packit Service ed0f68
		rs                                       &&
Packit Service ed0f68
		is_sol_packet(rs)                        &&
Packit Service ed0f68
		sol_response_acks_packet(rs, v2_payload) &&
Packit Service ed0f68
		(rs->payload.sol_packet.accepted_character_count <
Packit Service ed0f68
		 v2_payload->payload.sol_packet.character_count))
Packit Service ed0f68
	{
Packit Service ed0f68
		if (ipmi_oem_active(intf, "intelplus") &&
Packit Service ed0f68
			 rs->payload.sol_packet.accepted_character_count == 0)
Packit Service ed0f68
			return 0;
Packit Service ed0f68
Packit Service ed0f68
		chars_to_resend =
Packit Service ed0f68
			v2_payload->payload.sol_packet.character_count -
Packit Service ed0f68
			rs->payload.sol_packet.accepted_character_count;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return chars_to_resend;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * set_sol_packet_sequence_number
Packit Service ed0f68
 */
Packit Service ed0f68
static void set_sol_packet_sequence_number(
Packit Service ed0f68
											struct ipmi_intf * intf,
Packit Service ed0f68
											struct ipmi_v2_payload * v2_payload)
Packit Service ed0f68
{
Packit Service ed0f68
	/* Keep our sequence number sane */
Packit Service ed0f68
	if (intf->session->sol_data.sequence_number > 0x0F)
Packit Service ed0f68
		intf->session->sol_data.sequence_number = 1;
Packit Service ed0f68
Packit Service ed0f68
	v2_payload->payload.sol_packet.packet_sequence_number =
Packit Service ed0f68
		intf->session->sol_data.sequence_number++;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_lanplus_send_sol
Packit Service ed0f68
 *
Packit Service ed0f68
 * Sends a SOL packet..  We handle partial ACK/NACKs from the BMC here.
Packit Service ed0f68
 *
Packit Service ed0f68
 * Returns a pointer to the SOL ACK we received, or
Packit Service ed0f68
 *         0 on failure
Packit Service ed0f68
 * 
Packit Service ed0f68
 */
Packit Service ed0f68
struct ipmi_rs *
Packit Service ed0f68
ipmi_lanplus_send_sol(
Packit Service ed0f68
					  struct ipmi_intf * intf,
Packit Service ed0f68
					  struct ipmi_v2_payload * v2_payload)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rs;
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * chars_to_resend indicates either that we got a NACK telling us
Packit Service ed0f68
	 * that we need to resend some part of our data.
Packit Service ed0f68
	 */
Packit Service ed0f68
	int chars_to_resend = 0;
Packit Service ed0f68
Packit Service ed0f68
	v2_payload->payload_type   = IPMI_PAYLOAD_TYPE_SOL;
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Payload length is just the length of the character
Packit Service ed0f68
	 * data here.
Packit Service ed0f68
	 */
Packit Service ed0f68
	v2_payload->payload_length = v2_payload->payload.sol_packet.character_count;
Packit Service ed0f68
Packit Service ed0f68
	v2_payload->payload.sol_packet.acked_packet_number = 0; /* NA */
Packit Service ed0f68
Packit Service ed0f68
	set_sol_packet_sequence_number(intf, v2_payload);
Packit Service ed0f68
Packit Service ed0f68
	v2_payload->payload.sol_packet.accepted_character_count = 0; /* NA */
Packit Service ed0f68
Packit Service ed0f68
	rs = ipmi_lanplus_send_payload(intf, v2_payload);
Packit Service ed0f68
Packit Service ed0f68
	/* Determine if we need to resend some of our data */
Packit Service ed0f68
	chars_to_resend = is_sol_partial_ack(intf, v2_payload, rs);
Packit Service ed0f68
Packit Service ed0f68
	while (rs && !rs->payload.sol_packet.transfer_unavailable &&
Packit Service ed0f68
			 !rs->payload.sol_packet.is_nack &&
Packit Service ed0f68
			 chars_to_resend)
Packit Service ed0f68
	{
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * We first need to handle any new data we might have
Packit Service ed0f68
		 * received in our NACK
Packit Service ed0f68
		 */
Packit Service ed0f68
		if (rs->data_len)
Packit Service ed0f68
			intf->session->sol_data.sol_input_handler(rs);
Packit Service ed0f68
Packit Service ed0f68
		set_sol_packet_sequence_number(intf, v2_payload);
Packit Service ed0f68
Packit Service ed0f68
		/* Just send the required data */
Packit Service ed0f68
		memmove(v2_payload->payload.sol_packet.data,
Packit Service ed0f68
				v2_payload->payload.sol_packet.data +
Packit Service ed0f68
				rs->payload.sol_packet.accepted_character_count,
Packit Service ed0f68
				chars_to_resend);
Packit Service ed0f68
Packit Service ed0f68
		v2_payload->payload.sol_packet.character_count = chars_to_resend;
Packit Service ed0f68
Packit Service ed0f68
		v2_payload->payload_length = v2_payload->payload.sol_packet.character_count;
Packit Service ed0f68
Packit Service ed0f68
		rs = ipmi_lanplus_send_payload(intf, v2_payload);
Packit Service ed0f68
Packit Service ed0f68
		chars_to_resend = is_sol_partial_ack(intf, v2_payload, rs);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return rs;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * check_sol_packet_for_new_data
Packit Service ed0f68
 *
Packit Service ed0f68
 * Determine whether the SOL packet has already been seen
Packit Service ed0f68
 * and whether the packet has new data for us.
Packit Service ed0f68
 *
Packit Service ed0f68
 * This function has the side effect of removing an previously
Packit Service ed0f68
 * seen data, and moving new data to the front.
Packit Service ed0f68
 *
Packit Service ed0f68
 * It also "Remembers" the data so we don't get repeats.
Packit Service ed0f68
 *
Packit Service ed0f68
 * returns the number of new bytes in the SOL packet
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
check_sol_packet_for_new_data(
Packit Service ed0f68
							  struct ipmi_intf * intf,
Packit Service ed0f68
							  struct ipmi_rs *rsp)
Packit Service ed0f68
{
Packit Service ed0f68
	static uint8_t last_received_sequence_number = 0;
Packit Service ed0f68
	static uint8_t last_received_byte_count      = 0;
Packit Service ed0f68
	int new_data_size                                  = 0;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	if (rsp &&
Packit Service ed0f68
		(rsp->session.authtype    == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
Packit Service ed0f68
		(rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL))
Packit Service ed0f68
	{
Packit Service ed0f68
		/* Store the data length before we mod it */
Packit Service ed0f68
		uint8_t unaltered_data_len = rsp->data_len;
Packit Service ed0f68
Packit Service ed0f68
		if (rsp->payload.sol_packet.packet_sequence_number ==
Packit Service ed0f68
			last_received_sequence_number)
Packit Service ed0f68
		{
Packit Service ed0f68
Packit Service ed0f68
			/*
Packit Service ed0f68
			 * This is the same as the last packet, but may include
Packit Service ed0f68
			 * extra data
Packit Service ed0f68
			 */
Packit Service ed0f68
			new_data_size = rsp->data_len - last_received_byte_count;
Packit Service ed0f68
Packit Service ed0f68
			if (new_data_size > 0)
Packit Service ed0f68
			{
Packit Service ed0f68
				/* We have more data to process */
Packit Service ed0f68
				memmove(rsp->data,
Packit Service ed0f68
						rsp->data +
Packit Service ed0f68
						rsp->data_len - new_data_size,
Packit Service ed0f68
						new_data_size);
Packit Service ed0f68
			}
Packit Service ed0f68
Packit Service ed0f68
			rsp->data_len = new_data_size;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
		/*
Packit Service ed0f68
		 *Rember the data for next round
Packit Service ed0f68
		 */
Packit Service ed0f68
		if (rsp->payload.sol_packet.packet_sequence_number)
Packit Service ed0f68
		{
Packit Service ed0f68
			last_received_sequence_number =
Packit Service ed0f68
				rsp->payload.sol_packet.packet_sequence_number;
Packit Service ed0f68
Packit Service ed0f68
			last_received_byte_count = unaltered_data_len;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	return new_data_size;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ack_sol_packet
Packit Service ed0f68
 *
Packit Service ed0f68
 * Provided the specified packet looks reasonable, ACK it.
Packit Service ed0f68
 */
Packit Service ed0f68
static void
Packit Service ed0f68
ack_sol_packet(
Packit Service ed0f68
				struct ipmi_intf * intf,
Packit Service ed0f68
				struct ipmi_rs * rsp)
Packit Service ed0f68
{
Packit Service ed0f68
	if (rsp                                                           &&
Packit Service ed0f68
		(rsp->session.authtype    == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
Packit Service ed0f68
		(rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)           &&
Packit Service ed0f68
		(rsp->payload.sol_packet.packet_sequence_number))
Packit Service ed0f68
	{
Packit Service ed0f68
		struct ipmi_v2_payload ack;
Packit Service ed0f68
Packit Service ed0f68
		memset(&ack, 0, sizeof(struct ipmi_v2_payload));
Packit Service ed0f68
Packit Service ed0f68
		ack.payload_type   = IPMI_PAYLOAD_TYPE_SOL;
Packit Service ed0f68
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * Payload length is just the length of the character
Packit Service ed0f68
		 * data here.
Packit Service ed0f68
		 */
Packit Service ed0f68
		ack.payload_length = 0;
Packit Service ed0f68
Packit Service ed0f68
		/* ACK packets have sequence numbers of 0 */
Packit Service ed0f68
		ack.payload.sol_packet.packet_sequence_number = 0;
Packit Service ed0f68
Packit Service ed0f68
		ack.payload.sol_packet.acked_packet_number =
Packit Service ed0f68
			rsp->payload.sol_packet.packet_sequence_number;
Packit Service ed0f68
Packit Service ed0f68
		ack.payload.sol_packet.accepted_character_count = rsp->data_len;
Packit Service ed0f68
Packit Service ed0f68
		ipmi_lanplus_send_payload(intf, &ack;;
Packit Service ed0f68
	}
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_lanplus_recv_sol
Packit Service ed0f68
 *
Packit Service ed0f68
 * Receive a SOL packet and send an ACK in response.
Packit Service ed0f68
 *
Packit Service ed0f68
 */
Packit Service ed0f68
struct ipmi_rs *
Packit Service ed0f68
ipmi_lanplus_recv_sol(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rsp = ipmi_lan_poll_recv(intf);
Packit Service ed0f68
Packit Service ed0f68
	if (rsp && rsp->session.authtype != 0)
Packit Service ed0f68
	{
Packit Service ed0f68
		ack_sol_packet(intf, rsp);
Packit Service ed0f68
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * Remembers the data sent, and alters the data to just
Packit Service ed0f68
		 * include the new stuff.
Packit Service ed0f68
		 */
Packit Service ed0f68
		check_sol_packet_for_new_data(intf, rsp);
Packit Service ed0f68
	}
Packit Service ed0f68
	return rsp;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/**
Packit Service ed0f68
 * ipmi_lanplus_send_ipmi_cmd
Packit Service ed0f68
 *
Packit Service ed0f68
 * Build a payload request and dispatch it.
Packit Service ed0f68
 */
Packit Service ed0f68
struct ipmi_rs *
Packit Service ed0f68
ipmi_lanplus_send_ipmi_cmd(
Packit Service ed0f68
							struct ipmi_intf * intf,
Packit Service ed0f68
							struct ipmi_rq * req)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_v2_payload v2_payload;
Packit Service ed0f68
Packit Service ed0f68
	v2_payload.payload_type = IPMI_PAYLOAD_TYPE_IPMI;
Packit Service ed0f68
	v2_payload.payload.ipmi_request.request = req;
Packit Service ed0f68
Packit Service ed0f68
	return ipmi_lanplus_send_payload(intf, &v2_payload);
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_get_auth_capabilities_cmd
Packit Service ed0f68
 *
Packit Service ed0f68
 * This command may have to be sent twice.  We first ask for the
Packit Service ed0f68
 * authentication capabilities with the "request IPMI v2 data bit"
Packit Service ed0f68
 * set.  If this fails, we send the same command without that bit
Packit Service ed0f68
 * set.
Packit Service ed0f68
 *
Packit Service ed0f68
 * param intf is the initialized (but possibly) pre-session interface
Packit Service ed0f68
 *       on which we will send the command
Packit Service ed0f68
 * param auth_cap [out] will be initialized to hold the Get Channel
Packit Service ed0f68
 *       Authentication Capabilities return data on success.  Its
Packit Service ed0f68
 *       contents will be undefined on error.
Packit Service ed0f68
 * 
Packit Service ed0f68
 * returns 0 on success
Packit Service ed0f68
 *         non-zero if we were unable to contact the BMC, or we cannot
Packit Service ed0f68
 *         get a successful response
Packit Service ed0f68
 *
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_get_auth_capabilities_cmd(
Packit Service ed0f68
								struct ipmi_intf * intf,
Packit Service ed0f68
								struct get_channel_auth_cap_rsp * auth_cap)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	struct ipmi_rq req;
Packit Service ed0f68
	uint8_t msg_data[2];
Packit Service ed0f68
	uint8_t backupBridgePossible;
Packit Service ed0f68
Packit Service ed0f68
	backupBridgePossible = bridgePossible;
Packit Service ed0f68
Packit Service ed0f68
	bridgePossible = 0;
Packit Service ed0f68
Packit Service ed0f68
	msg_data[0] = IPMI_LAN_CHANNEL_E | 0x80; // Ask for IPMI v2 data as well
Packit Service ed0f68
	msg_data[1] = intf->ssn_params.privlvl;
Packit Service ed0f68
Packit Service ed0f68
	memset(&req, 0, sizeof(req));
Packit Service ed0f68
	req.msg.netfn    = IPMI_NETFN_APP;            // 0x06
Packit Service ed0f68
	req.msg.cmd      = IPMI_GET_CHANNEL_AUTH_CAP; // 0x38
Packit Service ed0f68
	req.msg.data     = msg_data;
Packit Service ed0f68
	req.msg.data_len = 2;
Packit Service ed0f68
Packit Service ed0f68
	rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
Packit Service ed0f68
	if (rsp == NULL || rsp->ccode > 0) {
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * It's very possible that this failed because we asked for IPMI
Packit Service ed0f68
		 * v2 data. Ask again, without requesting IPMI v2 data.
Packit Service ed0f68
		 */
Packit Service ed0f68
		msg_data[0] &= 0x7F;
Packit Service ed0f68
Packit Service ed0f68
		rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
Packit Service ed0f68
		if (rsp == NULL) {
Packit Service ed0f68
			lprintf(LOG_INFO, "Get Auth Capabilities error");
Packit Service ed0f68
			return 1;
Packit Service ed0f68
		}
Packit Service ed0f68
		if (rsp->ccode > 0) {
Packit Service ed0f68
			lprintf(LOG_INFO, "Get Auth Capabilities error: %s",
Packit Service ed0f68
				val2str(rsp->ccode, completion_code_vals));
Packit Service ed0f68
			return 1;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	memcpy(auth_cap,
Packit Service ed0f68
			rsp->data,
Packit Service ed0f68
			sizeof(struct get_channel_auth_cap_rsp));
Packit Service ed0f68
Packit Service ed0f68
	bridgePossible = backupBridgePossible;
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_close_session_cmd(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	struct ipmi_rq req;
Packit Service ed0f68
	uint8_t msg_data[4];
Packit Service ed0f68
	uint32_t bmc_session_lsbf;
Packit Service ed0f68
	uint8_t backupBridgePossible;
Packit Service ed0f68
Packit Service ed0f68
	if (intf->session == NULL
Packit Service ed0f68
			|| intf->session->v2_data.session_state != LANPLUS_STATE_ACTIVE)
Packit Service ed0f68
		return -1;
Packit Service ed0f68
Packit Service ed0f68
	backupBridgePossible = bridgePossible;
Packit Service ed0f68
Packit Service ed0f68
	intf->target_addr = IPMI_BMC_SLAVE_ADDR;
Packit Service ed0f68
	bridgePossible = 0;
Packit Service ed0f68
Packit Service ed0f68
	bmc_session_lsbf = intf->session->v2_data.bmc_id;
Packit Service ed0f68
#if WORDS_BIGENDIAN
Packit Service ed0f68
	bmc_session_lsbf = BSWAP_32(bmc_session_lsbf);
Packit Service ed0f68
#endif
Packit Service ed0f68
Packit Service ed0f68
	memcpy(&msg_data, &bmc_session_lsbf, 4);
Packit Service ed0f68
Packit Service ed0f68
	memset(&req, 0, sizeof(req));
Packit Service ed0f68
	req.msg.netfn		= IPMI_NETFN_APP;
Packit Service ed0f68
	req.msg.cmd		    = 0x3c;
Packit Service ed0f68
	req.msg.data		= msg_data;
Packit Service ed0f68
	req.msg.data_len	= 4;
Packit Service ed0f68
Packit Service ed0f68
	rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
	if (rsp == NULL) {
Packit Service ed0f68
		/* Looks like the session was closed */
Packit Service ed0f68
		lprintf(LOG_ERR, "Close Session command failed");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (verbose > 2)
Packit Service ed0f68
		printbuf(rsp->data, rsp->data_len, "close_session");
Packit Service ed0f68
Packit Service ed0f68
	if (rsp->ccode == 0x87) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Failed to Close Session: invalid "
Packit Service ed0f68
			"session ID %08lx",
Packit Service ed0f68
			(long)intf->session->v2_data.bmc_id);
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (rsp->ccode > 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Close Session command failed: %s",
Packit Service ed0f68
			val2str(rsp->ccode, completion_code_vals));
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	lprintf(LOG_DEBUG, "Closed Session %08lx\n",
Packit Service ed0f68
		(long)intf->session->v2_data.bmc_id);
Packit Service ed0f68
Packit Service ed0f68
	bridgePossible = backupBridgePossible;
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_lanplus_open_session
Packit Service ed0f68
 *
Packit Service ed0f68
 * Build and send the open session command.  See section 13.17 of the IPMI
Packit Service ed0f68
 * v2 specification for details.
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_lanplus_open_session(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_v2_payload v2_payload;
Packit Service ed0f68
	struct ipmi_session * session = intf->session;
Packit Service ed0f68
	uint8_t * msg;
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	/* 0 = success, 1 = error, 2 = timeout */
Packit Service ed0f68
	int rc = 0;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Build an Open Session Request Payload
Packit Service ed0f68
	 */
Packit Service ed0f68
	msg = (uint8_t*)malloc(IPMI_OPEN_SESSION_REQUEST_SIZE);
Packit Service ed0f68
	if (msg == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	memset(msg, 0, IPMI_OPEN_SESSION_REQUEST_SIZE);
Packit Service ed0f68
Packit Service ed0f68
	msg[0] = 0; /* Message tag */
Packit Service ed0f68
	if (ipmi_oem_active(intf, "intelplus") || intf->ssn_params.privlvl != IPMI_SESSION_PRIV_ADMIN)
Packit Service ed0f68
		msg[1] = intf->ssn_params.privlvl;
Packit Service ed0f68
	else
Packit Service ed0f68
		msg[1] = 0; /* Give us highest privlg level based on supported algorithms */
Packit Service ed0f68
	msg[2] = 0; /* reserved */
Packit Service ed0f68
	msg[3] = 0; /* reserved */
Packit Service ed0f68
Packit Service ed0f68
	/* Choose our session ID for easy recognition in the packet dump */
Packit Service ed0f68
	session->v2_data.console_id = 0xA0A2A3A4;
Packit Service ed0f68
	msg[4] = session->v2_data.console_id & 0xff;
Packit Service ed0f68
	msg[5] = (session->v2_data.console_id >> 8)  & 0xff;
Packit Service ed0f68
	msg[6] = (session->v2_data.console_id >> 16) & 0xff;
Packit Service ed0f68
	msg[7] = (session->v2_data.console_id >> 24) & 0xff;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	if (lanplus_get_requested_ciphers(intf->ssn_params.cipher_suite_id,
Packit Service ed0f68
									  &(session->v2_data.requested_auth_alg),
Packit Service ed0f68
									  &(session->v2_data.requested_integrity_alg),
Packit Service ed0f68
									  &(session->v2_data.requested_crypt_alg)))
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_WARNING, "Unsupported cipher suite ID : %d\n",
Packit Service ed0f68
				intf->ssn_params.cipher_suite_id);
Packit Service ed0f68
		free(msg);
Packit Service ed0f68
		msg = NULL;
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Authentication payload
Packit Service ed0f68
	 */
Packit Service ed0f68
	msg[8]  = 0; /* specifies authentication payload */
Packit Service ed0f68
	msg[9]  = 0; /* reserved */
Packit Service ed0f68
	msg[10] = 0; /* reserved */
Packit Service ed0f68
	msg[11] = 8; /* payload length */
Packit Service ed0f68
	msg[12] = session->v2_data.requested_auth_alg;
Packit Service ed0f68
	msg[13] = 0; /* reserved */	
Packit Service ed0f68
	msg[14] = 0; /* reserved */
Packit Service ed0f68
	msg[15] = 0; /* reserved */	
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Integrity payload
Packit Service ed0f68
	 */
Packit Service ed0f68
	msg[16] = 1; /* specifies integrity payload */
Packit Service ed0f68
	msg[17] = 0; /* reserved */
Packit Service ed0f68
	msg[18] = 0; /* reserved */
Packit Service ed0f68
	msg[19] = 8; /* payload length */
Packit Service ed0f68
	msg[20] = session->v2_data.requested_integrity_alg;
Packit Service ed0f68
	msg[21] = 0; /* reserved */	
Packit Service ed0f68
	msg[22] = 0; /* reserved */
Packit Service ed0f68
	msg[23] = 0; /* reserved */
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Confidentiality/Encryption payload
Packit Service ed0f68
	 */
Packit Service ed0f68
	msg[24] = 2; /* specifies confidentiality payload */
Packit Service ed0f68
	msg[25] = 0; /* reserved */
Packit Service ed0f68
	msg[26] = 0; /* reserved */
Packit Service ed0f68
	msg[27] = 8; /* payload length */
Packit Service ed0f68
	msg[28] = session->v2_data.requested_crypt_alg;
Packit Service ed0f68
	msg[29] = 0; /* reserved */	
Packit Service ed0f68
	msg[30] = 0; /* reserved */
Packit Service ed0f68
	msg[31] = 0; /* reserved */
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	v2_payload.payload_type   = IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST;
Packit Service ed0f68
	v2_payload.payload_length = IPMI_OPEN_SESSION_REQUEST_SIZE;
Packit Service ed0f68
	v2_payload.payload.open_session_request.request = msg;
Packit Service ed0f68
Packit Service ed0f68
	rsp = ipmi_lanplus_send_payload(intf, &v2_payload);
Packit Service ed0f68
Packit Service ed0f68
	free(msg);
Packit Service ed0f68
	msg = NULL;
Packit Service ed0f68
	if (rsp == NULL ) {
Packit Service ed0f68
		lprintf(LOG_DEBUG, "Timeout in open session response message.");
Packit Service ed0f68
		return 2;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (verbose)
Packit Service ed0f68
		lanplus_dump_open_session_response(rsp);
Packit Service ed0f68
Packit Service ed0f68
	if (rsp->payload.open_session_response.rakp_return_code !=
Packit Service ed0f68
		IPMI_RAKP_STATUS_NO_ERRORS)
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_WARNING, "Error in open session response message : %s\n",
Packit Service ed0f68
			val2str(rsp->payload.open_session_response.rakp_return_code,
Packit Service ed0f68
				ipmi_rakp_return_codes));
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
	else
Packit Service ed0f68
	{
Packit Service ed0f68
		if (rsp->payload.open_session_response.console_id !=
Packit Service ed0f68
			 session->v2_data.console_id) {
Packit Service ed0f68
			lprintf(LOG_WARNING, "Warning: Console session ID is not "
Packit Service ed0f68
				"what we requested");
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		session->v2_data.max_priv_level =
Packit Service ed0f68
			rsp->payload.open_session_response.max_priv_level;
Packit Service ed0f68
		session->v2_data.bmc_id         =
Packit Service ed0f68
			rsp->payload.open_session_response.bmc_id;
Packit Service ed0f68
		session->v2_data.auth_alg       =
Packit Service ed0f68
			rsp->payload.open_session_response.auth_alg;
Packit Service ed0f68
		session->v2_data.integrity_alg  =
Packit Service ed0f68
			rsp->payload.open_session_response.integrity_alg;
Packit Service ed0f68
		session->v2_data.crypt_alg      =
Packit Service ed0f68
			rsp->payload.open_session_response.crypt_alg;
Packit Service ed0f68
		session->v2_data.session_state  =
Packit Service ed0f68
			LANPLUS_STATE_OPEN_SESSION_RECEIEVED;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * Verify that we have agreed on a cipher suite
Packit Service ed0f68
		 */
Packit Service ed0f68
		if (rsp->payload.open_session_response.auth_alg !=
Packit Service ed0f68
			session->v2_data.requested_auth_alg)
Packit Service ed0f68
		{
Packit Service ed0f68
			lprintf(LOG_WARNING, "Authentication algorithm 0x%02x is "
Packit Service ed0f68
					"not what we requested 0x%02x\n",
Packit Service ed0f68
					rsp->payload.open_session_response.auth_alg,
Packit Service ed0f68
					session->v2_data.requested_auth_alg);
Packit Service ed0f68
			rc = 1;
Packit Service ed0f68
		}
Packit Service ed0f68
		else if (rsp->payload.open_session_response.integrity_alg !=
Packit Service ed0f68
				 session->v2_data.requested_integrity_alg)
Packit Service ed0f68
		{
Packit Service ed0f68
			lprintf(LOG_WARNING, "Integrity algorithm 0x%02x is "
Packit Service ed0f68
					"not what we requested 0x%02x\n",
Packit Service ed0f68
					rsp->payload.open_session_response.integrity_alg,
Packit Service ed0f68
					session->v2_data.requested_integrity_alg);
Packit Service ed0f68
			rc = 1;
Packit Service ed0f68
		}
Packit Service ed0f68
		else if (rsp->payload.open_session_response.crypt_alg !=
Packit Service ed0f68
				 session->v2_data.requested_crypt_alg)
Packit Service ed0f68
		{
Packit Service ed0f68
			lprintf(LOG_WARNING, "Encryption algorithm 0x%02x is "
Packit Service ed0f68
					"not what we requested 0x%02x\n",
Packit Service ed0f68
					rsp->payload.open_session_response.crypt_alg,
Packit Service ed0f68
					session->v2_data.requested_crypt_alg);
Packit Service ed0f68
			rc = 1;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return rc;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_lanplus_rakp1
Packit Service ed0f68
 *
Packit Service ed0f68
 * Build and send the RAKP 1 message as part of the IPMI v2 / RMCP+ session
Packit Service ed0f68
 * negotiation protocol.  We also read and validate the RAKP 2 message received
Packit Service ed0f68
 * from the BMC, here.  See section 13.20 of the IPMI v2 specification for
Packit Service ed0f68
 * details.
Packit Service ed0f68
 *
Packit Service ed0f68
 * returns 0 on success
Packit Service ed0f68
 *         1 on failure
Packit Service ed0f68
 *
Packit Service ed0f68
 * Note that failure is only indicated if we have an internal error of
Packit Service ed0f68
 * some kind. If we actually get a RAKP 2 message in response to our
Packit Service ed0f68
 * RAKP 1 message, any errors will be stored in
Packit Service ed0f68
 * session->v2_data.rakp2_return_code and sent to the BMC in the RAKP
Packit Service ed0f68
 * 3 message.
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_lanplus_rakp1(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_v2_payload v2_payload;
Packit Service ed0f68
	struct ipmi_session * session = intf->session;
Packit Service ed0f68
	uint8_t * msg;
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	int rc = 0;    /* 0 = success, 1 = error, 2 = timeout */
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Build a RAKP 1 message
Packit Service ed0f68
	 */
Packit Service ed0f68
	msg = (uint8_t*)malloc(IPMI_RAKP1_MESSAGE_SIZE);
Packit Service ed0f68
	if (msg == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
	memset(msg, 0, IPMI_RAKP1_MESSAGE_SIZE);
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	msg[0] = 0; /* Message tag */
Packit Service ed0f68
Packit Service ed0f68
	msg[1] = 0; /* reserved */
Packit Service ed0f68
	msg[2] = 0; /* reserved */
Packit Service ed0f68
	msg[3] = 0; /* reserved */
Packit Service ed0f68
Packit Service ed0f68
	/* BMC session ID */
Packit Service ed0f68
	msg[4] = session->v2_data.bmc_id & 0xff;
Packit Service ed0f68
	msg[5] = (session->v2_data.bmc_id >> 8)  & 0xff;
Packit Service ed0f68
	msg[6] = (session->v2_data.bmc_id >> 16) & 0xff;
Packit Service ed0f68
	msg[7] = (session->v2_data.bmc_id >> 24) & 0xff;
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/* We need a 16 byte random number */
Packit Service ed0f68
	if (lanplus_rand(session->v2_data.console_rand, 16))
Packit Service ed0f68
	{
Packit Service ed0f68
		// ERROR;
Packit Service ed0f68
		lprintf(LOG_ERR, "ERROR generating random number "
Packit Service ed0f68
			"in ipmi_lanplus_rakp1");
Packit Service ed0f68
		free(msg);
Packit Service ed0f68
		msg = NULL;
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
	memcpy(msg + 8, session->v2_data.console_rand, 16);
Packit Service ed0f68
	#if WORDS_BIGENDIAN
Packit Service ed0f68
	lanplus_swap(msg + 8, 16);
Packit Service ed0f68
	#endif
Packit Service ed0f68
Packit Service ed0f68
	if (verbose > 1)
Packit Service ed0f68
		printbuf(session->v2_data.console_rand, 16,
Packit Service ed0f68
				 ">> Console generated random number");
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Requested maximum privilege level.
Packit Service ed0f68
	 */
Packit Service ed0f68
	msg[24] = intf->ssn_params.privlvl | intf->ssn_params.lookupbit;
Packit Service ed0f68
	session->v2_data.requested_role = msg[24];
Packit Service ed0f68
	msg[25] = 0; /* reserved */
Packit Service ed0f68
	msg[26] = 0; /* reserved */
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/* Username specification */
Packit Service ed0f68
	msg[27] = strlen((const char *)intf->ssn_params.username);
Packit Service ed0f68
	if (msg[27] > IPMI_MAX_USER_NAME_LENGTH)
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_ERR, "ERROR: user name too long.  "
Packit Service ed0f68
			"(Exceeds %d characters)",
Packit Service ed0f68
			IPMI_MAX_USER_NAME_LENGTH);
Packit Service ed0f68
		free(msg);
Packit Service ed0f68
		msg = NULL;
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
	memcpy(msg + 28, intf->ssn_params.username, msg[27]);
Packit Service ed0f68
Packit Service ed0f68
	v2_payload.payload_type = IPMI_PAYLOAD_TYPE_RAKP_1;
Packit Service ed0f68
	if (ipmi_oem_active(intf, "i82571spt")) {
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * The IPMI v2.0 spec hints on that all user name bytes
Packit Service ed0f68
		 * must be occupied (29:44).  The Intel 82571 GbE refuses
Packit Service ed0f68
		 * to establish a session if this field is shorter.
Packit Service ed0f68
		 */
Packit Service ed0f68
		v2_payload.payload_length = IPMI_RAKP1_MESSAGE_SIZE;
Packit Service ed0f68
	} else {
Packit Service ed0f68
		v2_payload.payload_length =
Packit Service ed0f68
			IPMI_RAKP1_MESSAGE_SIZE - (16 - msg[27]);
Packit Service ed0f68
	}
Packit Service ed0f68
	v2_payload.payload.rakp_1_message.message = msg;
Packit Service ed0f68
Packit Service ed0f68
	rsp = ipmi_lanplus_send_payload(intf, &v2_payload);
Packit Service ed0f68
Packit Service ed0f68
	free(msg);
Packit Service ed0f68
	msg = NULL;
Packit Service ed0f68
Packit Service ed0f68
	if (rsp == NULL)
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_WARNING, "> Error: no response from RAKP 1 message");
Packit Service ed0f68
		return 2;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	session->v2_data.session_state = LANPLUS_STATE_RAKP_2_RECEIVED;
Packit Service ed0f68
Packit Service ed0f68
	if (verbose)
Packit Service ed0f68
		lanplus_dump_rakp2_message(rsp, session->v2_data.auth_alg);
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	if (rsp->payload.rakp2_message.rakp_return_code != IPMI_RAKP_STATUS_NO_ERRORS)
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_INFO, "RAKP 2 message indicates an error : %s",
Packit Service ed0f68
			val2str(rsp->payload.rakp2_message.rakp_return_code,
Packit Service ed0f68
				ipmi_rakp_return_codes));
Packit Service ed0f68
		rc = 1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	else
Packit Service ed0f68
	{
Packit Service ed0f68
		memcpy(session->v2_data.bmc_rand, rsp->payload.rakp2_message.bmc_rand, 16);
Packit Service ed0f68
		memcpy(session->v2_data.bmc_guid, rsp->payload.rakp2_message.bmc_guid, 16);
Packit Service ed0f68
Packit Service ed0f68
		if (verbose > 2)
Packit Service ed0f68
			printbuf(session->v2_data.bmc_rand, 16, "bmc_rand");
Packit Service ed0f68
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * It is at this point that we have to decode the random number and determine
Packit Service ed0f68
		 * whether the BMC has authenticated.
Packit Service ed0f68
		 */
Packit Service ed0f68
		if (! lanplus_rakp2_hmac_matches(session,
Packit Service ed0f68
										 rsp->payload.rakp2_message.key_exchange_auth_code, 
Packit Service ed0f68
										 intf))
Packit Service ed0f68
		{
Packit Service ed0f68
			/* Error */
Packit Service ed0f68
			lprintf(LOG_INFO, "> RAKP 2 HMAC is invalid");
Packit Service ed0f68
			session->v2_data.rakp2_return_code = IPMI_RAKP_STATUS_INVALID_INTEGRITY_CHECK_VALUE;
Packit Service ed0f68
								rc = 1;
Packit Service ed0f68
		}
Packit Service ed0f68
		else
Packit Service ed0f68
		{
Packit Service ed0f68
			/* Success */
Packit Service ed0f68
			session->v2_data.rakp2_return_code = IPMI_RAKP_STATUS_NO_ERRORS;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return rc;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/*
Packit Service ed0f68
 * ipmi_lanplus_rakp3
Packit Service ed0f68
 *
Packit Service ed0f68
 * Build and send the RAKP 3 message as part of the IPMI v2 / RMCP+ session
Packit Service ed0f68
 * negotiation protocol.  We also read and validate the RAKP 4 message received
Packit Service ed0f68
 * from the BMC, here.  See section 13.20 of the IPMI v2 specification for
Packit Service ed0f68
 * details.
Packit Service ed0f68
 *
Packit Service ed0f68
 * If the RAKP 2 return code is not IPMI_RAKP_STATUS_NO_ERRORS, we will
Packit Service ed0f68
 * exit with an error code immediately after sendint the RAKP 3 message.
Packit Service ed0f68
 *
Packit Service ed0f68
 * param intf is the intf that holds all the state we are concerned with
Packit Service ed0f68
 *
Packit Service ed0f68
 * returns 0 on success
Packit Service ed0f68
 *         1 on failure
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_lanplus_rakp3(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_v2_payload v2_payload;
Packit Service ed0f68
	struct ipmi_session * session = intf->session;
Packit Service ed0f68
	uint8_t * msg;
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
Packit Service ed0f68
	assert(session->v2_data.session_state == LANPLUS_STATE_RAKP_2_RECEIVED);
Packit Service ed0f68
	
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * Build a RAKP 3 message
Packit Service ed0f68
	 */
Packit Service ed0f68
	msg = (uint8_t*)malloc(IPMI_RAKP3_MESSAGE_MAX_SIZE);
Packit Service ed0f68
	if (msg == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
	memset(msg, 0, IPMI_RAKP3_MESSAGE_MAX_SIZE);
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	msg[0] = 0; /* Message tag */
Packit Service ed0f68
	msg[1] = session->v2_data.rakp2_return_code;
Packit Service ed0f68
	
Packit Service ed0f68
	msg[2] = 0; /* reserved */
Packit Service ed0f68
	msg[3] = 0; /* reserved */
Packit Service ed0f68
Packit Service ed0f68
	/* BMC session ID */
Packit Service ed0f68
	msg[4] = session->v2_data.bmc_id & 0xff;
Packit Service ed0f68
	msg[5] = (session->v2_data.bmc_id >> 8)  & 0xff;
Packit Service ed0f68
	msg[6] = (session->v2_data.bmc_id >> 16) & 0xff;
Packit Service ed0f68
	msg[7] = (session->v2_data.bmc_id >> 24) & 0xff;
Packit Service ed0f68
Packit Service ed0f68
	v2_payload.payload_type                   = IPMI_PAYLOAD_TYPE_RAKP_3;
Packit Service ed0f68
	v2_payload.payload_length                 = 8;
Packit Service ed0f68
	v2_payload.payload.rakp_3_message.message = msg;
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * If the rakp2 return code indicates and error, we don't have to
Packit Service ed0f68
	 * generate an authcode or session integrity key.  In that case, we
Packit Service ed0f68
	 * are simply sending a RAKP 3 message to indicate to the BMC that the
Packit Service ed0f68
	 * RAKP 2 message caused an error.
Packit Service ed0f68
	 */
Packit Service ed0f68
	if (session->v2_data.rakp2_return_code == IPMI_RAKP_STATUS_NO_ERRORS)
Packit Service ed0f68
	{
Packit Service ed0f68
		uint32_t auth_length;
Packit Service ed0f68
		
Packit Service ed0f68
		if (lanplus_generate_rakp3_authcode(msg + 8, session, &auth_length, intf))
Packit Service ed0f68
		{
Packit Service ed0f68
			/* Error */
Packit Service ed0f68
			lprintf(LOG_INFO, "> Error generating RAKP 3 authcode");
Packit Service ed0f68
			free(msg);
Packit Service ed0f68
			msg = NULL;
Packit Service ed0f68
			return 1;
Packit Service ed0f68
		}
Packit Service ed0f68
		else
Packit Service ed0f68
		{
Packit Service ed0f68
			/* Success */
Packit Service ed0f68
			v2_payload.payload_length += auth_length;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		/* Generate our Session Integrity Key, K1, and K2 */
Packit Service ed0f68
		if (lanplus_generate_sik(session, intf))
Packit Service ed0f68
		{
Packit Service ed0f68
			/* Error */
Packit Service ed0f68
			lprintf(LOG_INFO, "> Error generating session integrity key");
Packit Service ed0f68
			free(msg);
Packit Service ed0f68
			msg = NULL;
Packit Service ed0f68
			return 1;
Packit Service ed0f68
		}
Packit Service ed0f68
		else if (lanplus_generate_k1(session))
Packit Service ed0f68
		{
Packit Service ed0f68
			/* Error */
Packit Service ed0f68
			lprintf(LOG_INFO, "> Error generating K1 key");
Packit Service ed0f68
			free(msg);
Packit Service ed0f68
			msg = NULL;
Packit Service ed0f68
			return 1;
Packit Service ed0f68
		}
Packit Service ed0f68
		else if (lanplus_generate_k2(session))
Packit Service ed0f68
		{
Packit Service ed0f68
			/* Error */
Packit Service ed0f68
			lprintf(LOG_INFO, "> Error generating K1 key");
Packit Service ed0f68
			free(msg);
Packit Service ed0f68
			msg = NULL;
Packit Service ed0f68
			return 1;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
	
Packit Service ed0f68
Packit Service ed0f68
	rsp = ipmi_lanplus_send_payload(intf, &v2_payload);
Packit Service ed0f68
Packit Service ed0f68
	free(msg);
Packit Service ed0f68
	msg = NULL;
Packit Service ed0f68
Packit Service ed0f68
	if (session->v2_data.rakp2_return_code != IPMI_RAKP_STATUS_NO_ERRORS)
Packit Service ed0f68
	{
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * If the previous RAKP 2 message received was deemed erroneous,
Packit Service ed0f68
		 * we have nothing else to do here.  We only sent the RAKP 3 message
Packit Service ed0f68
		 * to indicate to the BMC that the RAKP 2 message failed.
Packit Service ed0f68
		 */
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
	else if (rsp == NULL)
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_WARNING, "> Error: no response from RAKP 3 message");
Packit Service ed0f68
		return 2;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * We have a RAKP 4 message to chew on.
Packit Service ed0f68
	 */
Packit Service ed0f68
	if (verbose)
Packit Service ed0f68
		lanplus_dump_rakp4_message(rsp, session->v2_data.auth_alg);
Packit Service ed0f68
	
Packit Service ed0f68
Packit Service ed0f68
	if (rsp->payload.open_session_response.rakp_return_code != IPMI_RAKP_STATUS_NO_ERRORS)
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_INFO, "RAKP 4 message indicates an error : %s",
Packit Service ed0f68
			val2str(rsp->payload.rakp4_message.rakp_return_code,
Packit Service ed0f68
				ipmi_rakp_return_codes));
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	else
Packit Service ed0f68
	{
Packit Service ed0f68
		/* Validate the authcode */
Packit Service ed0f68
		if (lanplus_rakp4_hmac_matches(session,
Packit Service ed0f68
										rsp->payload.rakp4_message.integrity_check_value,
Packit Service ed0f68
										intf))
Packit Service ed0f68
		{
Packit Service ed0f68
			/* Success */
Packit Service ed0f68
			session->v2_data.session_state = LANPLUS_STATE_ACTIVE;
Packit Service ed0f68
		}
Packit Service ed0f68
		else
Packit Service ed0f68
		{
Packit Service ed0f68
			/* Error */
Packit Service ed0f68
			lprintf(LOG_INFO, "> RAKP 4 message has invalid integrity check value");
Packit Service ed0f68
			return 1;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	intf->abort = 0;
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/**
Packit Service ed0f68
 * ipmi_lan_close
Packit Service ed0f68
 */
Packit Service ed0f68
void
Packit Service ed0f68
ipmi_lanplus_close(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	if (!intf->abort && intf->session)
Packit Service ed0f68
		ipmi_close_session_cmd(intf);
Packit Service ed0f68
Packit Service ed0f68
	if (intf->fd >= 0) {
Packit Service ed0f68
		close(intf->fd);
Packit Service ed0f68
		intf->fd = -1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	ipmi_req_clear_entries();
Packit Service ed0f68
	ipmi_intf_session_cleanup(intf);
Packit Service ed0f68
	intf->opened = 0;
Packit Service ed0f68
	intf->manufacturer_id = IPMI_OEM_UNKNOWN;
Packit Service ed0f68
	intf = NULL;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_set_session_privlvl_cmd(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	struct ipmi_rq req;
Packit Service ed0f68
	uint8_t backupBridgePossible;
Packit Service ed0f68
	uint8_t privlvl = intf->ssn_params.privlvl;
Packit Service ed0f68
Packit Service ed0f68
	if (privlvl <= IPMI_SESSION_PRIV_USER)
Packit Service ed0f68
		return 0;	/* no need to set higher */
Packit Service ed0f68
Packit Service ed0f68
	backupBridgePossible = bridgePossible;
Packit Service ed0f68
Packit Service ed0f68
	bridgePossible = 0;
Packit Service ed0f68
Packit Service ed0f68
	memset(&req, 0, sizeof(req));
Packit Service ed0f68
	req.msg.netfn		= IPMI_NETFN_APP;
Packit Service ed0f68
	req.msg.cmd		= 0x3b;
Packit Service ed0f68
	req.msg.data		= &privlvl;
Packit Service ed0f68
	req.msg.data_len	= 1;
Packit Service ed0f68
Packit Service ed0f68
	rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
	if (rsp == NULL) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Set Session Privilege Level to %s failed",
Packit Service ed0f68
			val2str(privlvl, ipmi_privlvl_vals));
Packit Service ed0f68
		bridgePossible = backupBridgePossible;
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
	if (verbose > 2)
Packit Service ed0f68
		printbuf(rsp->data, rsp->data_len, "set_session_privlvl");
Packit Service ed0f68
Packit Service ed0f68
	if (rsp->ccode > 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Set Session Privilege Level to %s failed: %s",
Packit Service ed0f68
			val2str(privlvl, ipmi_privlvl_vals),
Packit Service ed0f68
			val2str(rsp->ccode, completion_code_vals));
Packit Service ed0f68
		bridgePossible = backupBridgePossible;
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	lprintf(LOG_DEBUG, "Set Session Privilege Level to %s\n",
Packit Service ed0f68
		val2str(rsp->data[0], ipmi_privlvl_vals));
Packit Service ed0f68
Packit Service ed0f68
	bridgePossible = backupBridgePossible;
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service 9e6181
static uint8_t
Packit Service 9e6181
ipmi_find_best_cipher_suite(struct ipmi_intf *intf)
Packit Service 9e6181
{
Packit Service 9e6181
	enum cipher_suite_ids best_suite = IPMI_LANPLUS_CIPHER_SUITE_RESERVED;
Packit Service 9e6181
#ifdef HAVE_CRYPTO_SHA256
Packit Service 9e6181
	struct cipher_suite_info suites[MAX_CIPHER_SUITE_COUNT];
Packit Service 9e6181
	size_t nr_suites = ARRAY_SIZE(suites);
Packit Service 9e6181
	/* cipher suite best order is chosen with this criteria:
Packit Service 9e6181
	 * HMAC-MD5 and MD5 are BAD; xRC4 is bad; AES128 is required
Packit Service 9e6181
	 * HMAC-SHA256 > HMAC-SHA1
Packit Service 9e6181
	 * secure authentication > encrypted content
Packit Service 9e6181
	 *
Packit Service 9e6181
	 * With xRC4 out, all cipher suites with MD5 out, and cipher suite 3 being
Packit Service 9e6181
	 * required by the spec, the only better defined standard cipher suite is
Packit Service 9e6181
	 * 17. So if SHA256 is available, we should try to use that, otherwise,
Packit Service 9e6181
	 * fall back to 3.
Packit Service 9e6181
	 */
Packit Service 9e6181
	const enum cipher_suite_ids cipher_order_preferred[] = {
Packit Service 9e6181
		IPMI_LANPLUS_CIPHER_SUITE_17,
Packit Service 9e6181
		IPMI_LANPLUS_CIPHER_SUITE_3,
Packit Service 9e6181
	};
Packit Service 9e6181
	const size_t nr_preferred = ARRAY_SIZE(cipher_order_preferred);
Packit Service 9e6181
	size_t ipref, i;
Packit Service 866787
	int rc;
Packit Service 866787
	int retry_old = intf->ssn_params.retry;
Packit Service 9e6181
Packit Service 866787
	ipmi_intf_session_set_retry(intf, 1);
Packit Service 866787
	rc = ipmi_get_channel_cipher_suites(intf, "ipmi", IPMI_LAN_CHANNEL_E, suites, &nr_suites);
Packit Service 866787
	ipmi_intf_session_set_retry(intf, retry_old);
Packit Service 866787
	if (rc < 0)
Packit Service 9e6181
	{
Packit Service 9e6181
		/* default legacy behavior - cipher suite 3 if none is requested */
Packit Service 9e6181
		return IPMI_LANPLUS_CIPHER_SUITE_3;
Packit Service 9e6181
	}
Packit Service 9e6181
	for (ipref = 0; ipref < nr_preferred &&
Packit Service 9e6181
	                IPMI_LANPLUS_CIPHER_SUITE_RESERVED == best_suite; ipref++)
Packit Service 9e6181
	{
Packit Service 9e6181
		for (i = 0; i < nr_suites; i++) {
Packit Service 9e6181
			if (cipher_order_preferred[ipref] == suites[i].cipher_suite_id) {
Packit Service 9e6181
				best_suite = cipher_order_preferred[ipref];
Packit Service 9e6181
				break;
Packit Service 9e6181
			}
Packit Service 9e6181
		}
Packit Service 9e6181
	}
Packit Service 9e6181
#endif /* HAVE_CRYPTO_SHA256 */
Packit Service 9e6181
	if (IPMI_LANPLUS_CIPHER_SUITE_RESERVED == best_suite) {
Packit Service 9e6181
		/* IPMI 2.0 spec requires that cipher suite 3 is implemented
Packit Service 9e6181
		 * so we should always be able to fall back to that if better
Packit Service 9e6181
		 * options are not available. */
Packit Service 9e6181
		best_suite = IPMI_LANPLUS_CIPHER_SUITE_3;
Packit Service 9e6181
	}
Packit Service 9e6181
	lprintf(LOG_INFO, "Using best available cipher suite %d\n", best_suite);
Packit Service 9e6181
	return best_suite;
Packit Service 9e6181
}
Packit Service 9e6181
Packit Service ed0f68
/**
Packit Service ed0f68
 * ipmi_lanplus_open
Packit Service ed0f68
 */
Packit Service ed0f68
int
Packit Service ed0f68
ipmi_lanplus_open(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	int rc;
Packit Service ed0f68
	int retry;
Packit Service ed0f68
	struct get_channel_auth_cap_rsp auth_cap;
Packit Service ed0f68
	struct ipmi_session_params *params;
Packit Service ed0f68
	struct ipmi_session *session;
Packit Service ed0f68
Packit Service ed0f68
	if (!intf)
Packit Service ed0f68
		return -1;
Packit Service ed0f68
Packit Service ed0f68
	if (intf->opened)
Packit Service ed0f68
		return intf->fd;
Packit Service ed0f68
Packit Service ed0f68
	params = &intf->ssn_params;
Packit Service ed0f68
Packit Service ed0f68
	if (!params->port)
Packit Service ed0f68
		params->port = IPMI_LANPLUS_PORT;
Packit Service ed0f68
	if (!params->privlvl)
Packit Service ed0f68
		params->privlvl = IPMI_SESSION_PRIV_ADMIN;
Packit Service ed0f68
	if (!params->timeout)
Packit Service ed0f68
		params->timeout = IPMI_LAN_TIMEOUT;
Packit Service ed0f68
	if (!params->retry)
Packit Service ed0f68
		params->retry = IPMI_LAN_RETRY;
Packit Service ed0f68
Packit Service ed0f68
	if (params->hostname == NULL || strlen((const char *)params->hostname) == 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "No hostname specified!");
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (ipmi_intf_socket_connect(intf) == -1) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Could not open socket!");
Packit Service ed0f68
		goto fail;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	session = (struct ipmi_session *)malloc(sizeof (struct ipmi_session));
Packit Service ed0f68
	if (!session) {
Packit Service ed0f68
		lprintf(LOG_ERR, "ipmitool: malloc failure");
Packit Service ed0f68
		goto fail;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	intf->session = session;
Packit Service ed0f68
Packit Service ed0f68
	/* Setup our lanplus session state */
Packit Service ed0f68
	memset(session, 0, sizeof(struct ipmi_session));
Packit Service ed0f68
	session->timeout = params->timeout;
Packit Service ed0f68
	memcpy(&session->authcode, &params->authcode_set, sizeof(session->authcode));
Packit Service ed0f68
	session->v2_data.auth_alg         = IPMI_AUTH_RAKP_NONE;
Packit Service ed0f68
	session->v2_data.crypt_alg        = IPMI_CRYPT_NONE;
Packit Service ed0f68
	session->sol_data.sequence_number = 1;
Packit Service ed0f68
Packit Service ed0f68
	intf->opened = 1;
Packit Service ed0f68
	intf->abort = 1;
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 *
Packit Service ed0f68
	 * Make sure the BMC supports IPMI v2 / RMCP+
Packit Service ed0f68
	 */
Packit Service ed0f68
	if (!ipmi_oem_active(intf, "i82571spt") &&
Packit Service ed0f68
			ipmi_get_auth_capabilities_cmd(intf, &auth_cap)) {
Packit Service ed0f68
		lprintf(LOG_INFO, "Error issuing Get Channel "
Packit Service ed0f68
			"Authentication Capabilities request");
Packit Service ed0f68
		goto fail;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (!ipmi_oem_active(intf, "i82571spt") && ! auth_cap.v20_data_available) {
Packit Service ed0f68
		lprintf(LOG_INFO, "This BMC does not support IPMI v2 / RMCP+");
Packit Service ed0f68
		goto fail;
Packit Service ed0f68
	}
Packit Service 9e6181
	/*
Packit Service 9e6181
	 * If no cipher suite was provided, query the channel cipher suite list and
Packit Service 9e6181
	 * pick the best one available
Packit Service 9e6181
	 */
Packit Service 9e6181
	if (IPMI_LANPLUS_CIPHER_SUITE_RESERVED ==
Packit Service 9e6181
	    intf->ssn_params.cipher_suite_id)
Packit Service 9e6181
	{
Packit Service 9e6181
		ipmi_intf_session_set_cipher_suite_id(intf,
Packit Service 9e6181
			ipmi_find_best_cipher_suite(intf));
Packit Service 9e6181
	}
Packit Service ed0f68
Packit Service ed0f68
	/*
Packit Service ed0f68
	 * If the open/rakp1/rakp3 sequence encounters a timeout, the whole sequence
Packit Service ed0f68
	 * needs to restart. The individual messages are not individually retryable,
Packit Service ed0f68
	 * as the session state is advancing.
Packit Service ed0f68
	 */
Packit Service ed0f68
	for (retry = 0; retry < IPMI_LAN_RETRY; retry++) {
Packit Service ed0f68
		session->v2_data.session_state = LANPLUS_STATE_PRESESSION;
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * Open session
Packit Service ed0f68
		 */
Packit Service ed0f68
		if ((rc = ipmi_lanplus_open_session(intf)) == 1) {
Packit Service ed0f68
			goto fail;
Packit Service ed0f68
		}
Packit Service ed0f68
		if (rc == 2) {
Packit Service ed0f68
			lprintf(LOG_DEBUG, "Retry lanplus open session, %d", retry);
Packit Service ed0f68
			continue;
Packit Service ed0f68
		}
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * RAKP 1
Packit Service ed0f68
		 */
Packit Service ed0f68
		if ((rc = ipmi_lanplus_rakp1(intf)) == 1) {
Packit Service ed0f68
			goto fail;
Packit Service ed0f68
		}
Packit Service ed0f68
		if (rc == 2) {
Packit Service ed0f68
			lprintf(LOG_DEBUG, "Retry lanplus rakp1, %d", retry);
Packit Service ed0f68
			continue;
Packit Service ed0f68
		}
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * RAKP 3
Packit Service ed0f68
		 */
Packit Service ed0f68
		if ((rc = ipmi_lanplus_rakp3(intf)) == 1) {
Packit Service ed0f68
			goto fail;
Packit Service ed0f68
		}
Packit Service ed0f68
		if (rc == 0) break;
Packit Service ed0f68
		lprintf(LOG_DEBUG,"Retry lanplus rakp3, %d", retry);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	lprintf(LOG_DEBUG, "IPMIv2 / RMCP+ SESSION OPENED SUCCESSFULLY\n");
Packit Service ed0f68
Packit Service ed0f68
	intf->abort = 0;
Packit Service ed0f68
Packit Service ed0f68
	if (!ipmi_oem_active(intf, "i82571spt")) {
Packit Service ed0f68
		rc = ipmi_set_session_privlvl_cmd(intf);
Packit Service ed0f68
		if (rc < 0) {
Packit Service ed0f68
			goto fail;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		/* automatically detect interface request and response sizes */
Packit Service ed0f68
		hpm2_detect_max_payload_size(intf);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	bridgePossible = 1;
Packit Service ed0f68
Packit Service ed0f68
	if (!ipmi_oem_active(intf, "i82571spt")) {
Packit Service ed0f68
		intf->manufacturer_id = ipmi_get_oem(intf);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return intf->fd;
Packit Service ed0f68
Packit Service ed0f68
 fail:
Packit Service ed0f68
	lprintf(LOG_ERR, "Error: Unable to establish IPMI v2 / RMCP+ session");
Packit Service ed0f68
	intf->close(intf);
Packit Service ed0f68
	return -1;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
void test_crypt1(void)
Packit Service ed0f68
{
Packit Service ed0f68
	uint8_t key[]  =
Packit Service ed0f68
		{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
Packit Service ed0f68
		 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14};
Packit Service ed0f68
Packit Service ed0f68
	uint16_t  bytes_encrypted;
Packit Service ed0f68
	uint16_t  bytes_decrypted;
Packit Service ed0f68
	uint8_t   decrypt_buffer[1000];
Packit Service ed0f68
	uint8_t   encrypt_buffer[1000];
Packit Service ed0f68
Packit Service ed0f68
	uint8_t data[] =
Packit Service ed0f68
		{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
Packit Service ed0f68
		 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
Packit Service ed0f68
		 0x11, 0x12};
Packit Service ed0f68
Packit Service ed0f68
	printbuf(data, sizeof(data), "original data");
Packit Service ed0f68
Packit Service ed0f68
	if (lanplus_encrypt_payload(IPMI_CRYPT_AES_CBC_128,
Packit Service ed0f68
								key,
Packit Service ed0f68
								data,
Packit Service ed0f68
								sizeof(data),
Packit Service ed0f68
								encrypt_buffer,
Packit Service ed0f68
								&bytes_encrypted))
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_ERR, "Encrypt test failed");
Packit Service ed0f68
		assert(0);
Packit Service ed0f68
	}
Packit Service ed0f68
	printbuf(encrypt_buffer, bytes_encrypted, "encrypted payload");
Packit Service ed0f68
	
Packit Service ed0f68
Packit Service ed0f68
	if (lanplus_decrypt_payload(IPMI_CRYPT_AES_CBC_128,
Packit Service ed0f68
								key,
Packit Service ed0f68
								encrypt_buffer,
Packit Service ed0f68
								bytes_encrypted,
Packit Service ed0f68
								decrypt_buffer,
Packit Service ed0f68
								&bytes_decrypted))
Packit Service ed0f68
	{
Packit Service ed0f68
		lprintf(LOG_ERR, "Decrypt test failed\n");
Packit Service ed0f68
		assert(0);
Packit Service ed0f68
	}	
Packit Service ed0f68
	printbuf(decrypt_buffer, bytes_decrypted, "decrypted payload");
Packit Service ed0f68
	
Packit Service ed0f68
	lprintf(LOG_DEBUG, "\nDone testing the encrypt/decyrpt methods!\n");
Packit Service ed0f68
	exit(0);
Packit Service ed0f68
}	
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
void test_crypt2(void)
Packit Service ed0f68
{
Packit Service ed0f68
	uint8_t key[]  =
Packit Service ed0f68
		{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
Packit Service ed0f68
		 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14};
Packit Service ed0f68
	uint8_t iv[]  =
Packit Service ed0f68
		  {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
Packit Service ed0f68
			0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14};
Packit Service ed0f68
	uint8_t data[8] = "12345678";
Packit Service ed0f68
Packit Service ed0f68
	uint8_t encrypt_buffer[1000];
Packit Service ed0f68
	uint8_t decrypt_buffer[1000];
Packit Service ed0f68
	uint32_t bytes_encrypted;
Packit Service ed0f68
	uint32_t bytes_decrypted;
Packit Service ed0f68
Packit Service ed0f68
	printbuf((const uint8_t *)data, strlen((const char *)data), "input data");
Packit Service ed0f68
Packit Service ed0f68
	lanplus_encrypt_aes_cbc_128(iv,
Packit Service ed0f68
								key,
Packit Service ed0f68
								data,
Packit Service ed0f68
								strlen((const char *)data),
Packit Service ed0f68
								encrypt_buffer,
Packit Service ed0f68
								&bytes_encrypted);
Packit Service ed0f68
	printbuf((const uint8_t *)encrypt_buffer, bytes_encrypted, "encrypt_buffer");
Packit Service ed0f68
Packit Service ed0f68
	lanplus_decrypt_aes_cbc_128(iv,
Packit Service ed0f68
								key,
Packit Service ed0f68
								encrypt_buffer,
Packit Service ed0f68
								bytes_encrypted,
Packit Service ed0f68
								decrypt_buffer,
Packit Service ed0f68
								&bytes_decrypted);
Packit Service ed0f68
	printbuf((const uint8_t *)decrypt_buffer, bytes_decrypted, "decrypt_buffer");
Packit Service ed0f68
Packit Service ed0f68
	lprintf(LOG_INFO, "\nDone testing the encrypt/decyrpt methods!\n");
Packit Service ed0f68
	exit(0);
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/**
Packit Service ed0f68
 * send a get device id command to keep session active
Packit Service ed0f68
 */
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_lanplus_keepalive(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	struct ipmi_rs * rsp;
Packit Service ed0f68
	struct ipmi_rq req = {
Packit Service ed0f68
		.msg = {
Packit Service ed0f68
			.netfn = IPMI_NETFN_APP,
Packit Service ed0f68
			.cmd = 1,
Packit Service ed0f68
		}
Packit Service ed0f68
	};
Packit Service ed0f68
Packit Service ed0f68
	if (!intf->opened)
Packit Service ed0f68
		return 0;
Packit Service ed0f68
Packit Service ed0f68
	rsp = intf->sendrecv(intf, &req;;
Packit Service ed0f68
	while (rsp != NULL && is_sol_packet(rsp)) {
Packit Service ed0f68
					 /* rsp was SOL data instead of our answer */
Packit Service ed0f68
					 /* since it didn't go through the sol recv, do sol recv stuff here */
Packit Service ed0f68
					 ack_sol_packet(intf, rsp);
Packit Service ed0f68
					 check_sol_packet_for_new_data(intf, rsp);
Packit Service ed0f68
					 if (rsp->data_len)
Packit Service ed0f68
								intf->session->sol_data.sol_input_handler(rsp);
Packit Service ed0f68
		rsp = ipmi_lan_poll_recv(intf);
Packit Service ed0f68
		if (rsp == NULL) /* the get device id answer never got back, but retry mechanism was bypassed by SOL data */
Packit Service ed0f68
			return 0; /* so get device id command never returned, the connection is still alive */
Packit Service ed0f68
		  }
Packit Service ed0f68
Packit Service ed0f68
	if (rsp == NULL)
Packit Service ed0f68
		return -1;
Packit Service ed0f68
	if (rsp->ccode > 0)
Packit Service ed0f68
		return -1;
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
Packit Service ed0f68
/**
Packit Service ed0f68
 * ipmi_lanplus_setup
Packit Service ed0f68
 */
Packit Service ed0f68
static int ipmi_lanplus_setup(struct ipmi_intf * intf)
Packit Service ed0f68
{
Packit Service ed0f68
	//test_crypt1();
Packit Service ed0f68
	assert("ipmi_lanplus_setup");
Packit Service ed0f68
Packit Service ed0f68
	if (lanplus_seed_prng(16))
Packit Service ed0f68
		return -1;
Packit Service ed0f68
Packit Service ed0f68
    /* setup default LAN maximum request and response sizes */
Packit Service ed0f68
    intf->max_request_data_size = IPMI_LAN_MAX_REQUEST_SIZE;
Packit Service ed0f68
    intf->max_response_data_size = IPMI_LAN_MAX_RESPONSE_SIZE;
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static void ipmi_lanp_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size)
Packit Service ed0f68
{
Packit Service 9e6181
	if (intf->ssn_params.cipher_suite_id == IPMI_LANPLUS_CIPHER_SUITE_3) {
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * encrypted payload can only be multiple of 16 bytes
Packit Service ed0f68
		 */
Packit Service ed0f68
		size &= ~15;
Packit Service ed0f68
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * decrement payload size on confidentiality header size
Packit Service ed0f68
		 * plus minimal confidentiality trailer size
Packit Service ed0f68
		 */
Packit Service ed0f68
		size -= (16 + 1);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	intf->max_request_data_size = size;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static void ipmi_lanp_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size)
Packit Service ed0f68
{
Packit Service 9e6181
	if (intf->ssn_params.cipher_suite_id == IPMI_LANPLUS_CIPHER_SUITE_3) {
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * encrypted payload can only be multiple of 16 bytes
Packit Service ed0f68
		 */
Packit Service ed0f68
		size &= ~15;
Packit Service ed0f68
Packit Service ed0f68
		/*
Packit Service ed0f68
		 * decrement payload size on confidentiality header size
Packit Service ed0f68
		 * plus minimal confidentiality trailer size
Packit Service ed0f68
		 */
Packit Service ed0f68
		size -= (16 + 1);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	intf->max_response_data_size = size;
Packit Service ed0f68
}