ID: 3611254 - OEM handle for Intel 82751 in SPT mode

Intel 82751 MAC has several deviations in its RMCP+ implementation while working
in the super pass-through mode.
This patch adds a OEM handle which allows IPMItool succesfully interract with
boards equipped with this NIC.

Commit for Dmitry Bazhenov
This commit is contained in:
Zdenek Styblik 2013-05-28 04:18:22 +00:00
parent 38d71179e9
commit 0cea01e42f
5 changed files with 112 additions and 73 deletions

View File

@ -63,6 +63,10 @@ static struct ipmi_oem_handle ipmi_oem_list[] = {
desc: "IBM OEM support", desc: "IBM OEM support",
setup: ipmi_oem_ibm, setup: ipmi_oem_ibm,
}, },
{
name: "i82571spt",
desc: "Intel 82571 MAC with integrated RMCP+ support in super pass-through mode",
},
{ 0 } { 0 }
}; };

View File

@ -1568,43 +1568,45 @@ ipmi_sol_red_pill(struct ipmi_intf * intf, int instance)
FD_SET(0, &read_fds); FD_SET(0, &read_fds);
FD_SET(intf->fd, &read_fds); FD_SET(intf->fd, &read_fds);
/* Send periodic keepalive packet */ if (!ipmi_oem_active(intf,"i82571spt"))
if(_use_sol_for_keepalive == 0)
{ {
keepAliveRet = ipmi_sol_keepalive_using_getdeviceid(intf); /* Send periodic keepalive packet */
} if(_use_sol_for_keepalive == 0)
else
{
keepAliveRet = ipmi_sol_keepalive_using_sol(intf);
}
if (keepAliveRet != 0)
{
/*
* Retrying the keep Alive before declaring a communication
* lost state with the IPMC. Helpful when the payload is
* reset and brings down the connection temporarily. Otherwise,
* if we send getDevice Id to check the status of IPMC during
* this down time when the connection is restarting, SOL will
* exit even though the IPMC is available and the session is open.
*/
if (retrySol == MAX_SOL_RETRY)
{ {
/* no response to Get Device ID keepalive message */ keepAliveRet = ipmi_sol_keepalive_using_getdeviceid(intf);
bShouldExit = 1;
continue;
} }
else else
{ {
retrySol++; keepAliveRet = ipmi_sol_keepalive_using_sol(intf);
} }
}
else if (keepAliveRet != 0)
{ {
/* if the keep Alive is successful reset retries to zero */ /*
retrySol = 0; * Retrying the keep Alive before declaring a communication
} * lost state with the IPMC. Helpful when the payload is
* reset and brings down the connection temporarily. Otherwise,
* if we send getDevice Id to check the status of IPMC during
* this down time when the connection is restarting, SOL will
* exit even though the IPMC is available and the session is open.
*/
if (retrySol == MAX_SOL_RETRY)
{
/* no response to Get Device ID keepalive message */
bShouldExit = 1;
continue;
}
else
{
retrySol++;
}
}
else
{
/* if the keep Alive is successful reset retries to zero */
retrySol = 0;
}
} /* !oem="i82571spt" */
/* Wait up to half a second */ /* Wait up to half a second */
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 500000; tv.tv_usec = 500000;
@ -1757,6 +1759,20 @@ ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval,
if (ipmi_oem_active(intf, "intelplus")) { if (ipmi_oem_active(intf, "intelplus")) {
data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_TRUE; data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_TRUE;
} else if (ipmi_oem_active(intf, "i82571spt")) {
/*
* A quote from Intel: "Engineering believes the problem
* lies within the Auxiliary data being sent with the
* 'Activate Payload' command from IPMITool. IPMITool
* sends a C6h which sets some bits having to do with
* encryption and some behavior dealing with CTS DCD/DSR.
* I recommend that the customer modify this request
* to send 08h instead. This is what our internal utility
* sends and it works without issue. I will work with
* engineering to ensure the settings that IPMITool uses
* (C6h) are supported in the future.
*/
data[2] = 0x08;
} else { } else {
data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_FALSE; data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_FALSE;
} }

View File

@ -3164,7 +3164,7 @@ ipmi_lanplus_rakp3(struct ipmi_intf * intf)
} }
/* Generate our Session Integrity Key, K1, and K2 */ /* Generate our Session Integrity Key, K1, and K2 */
if (lanplus_generate_sik(session)) if (lanplus_generate_sik(session, intf))
{ {
/* Error */ /* Error */
lprintf(LOG_INFO, "> Error generating session integrity key"); lprintf(LOG_INFO, "> Error generating session integrity key");
@ -3417,7 +3417,8 @@ ipmi_lanplus_open(struct ipmi_intf * intf)
* *
* I'm not sure why we accept a failure for the first call * I'm not sure why we accept a failure for the first call
*/ */
if (ipmi_get_auth_capabilities_cmd(intf, &auth_cap)) { if (!ipmi_oem_active(intf, "i82571spt") &&
ipmi_get_auth_capabilities_cmd(intf, &auth_cap)) {
sleep(1); sleep(1);
if (ipmi_get_auth_capabilities_cmd(intf, &auth_cap)); if (ipmi_get_auth_capabilities_cmd(intf, &auth_cap));
{ {
@ -3427,7 +3428,7 @@ ipmi_lanplus_open(struct ipmi_intf * intf)
} }
} }
if (! auth_cap.v20_data_available) if (!ipmi_oem_active(intf, "i82571spt") && ! auth_cap.v20_data_available)
{ {
lprintf(LOG_INFO, "This BMC does not support IPMI v2 / RMCP+"); lprintf(LOG_INFO, "This BMC does not support IPMI v2 / RMCP+");
goto fail; goto fail;
@ -3462,11 +3463,11 @@ ipmi_lanplus_open(struct ipmi_intf * intf)
lprintf(LOG_DEBUG, "IPMIv2 / RMCP+ SESSION OPENED SUCCESSFULLY\n"); lprintf(LOG_DEBUG, "IPMIv2 / RMCP+ SESSION OPENED SUCCESSFULLY\n");
rc = ipmi_set_session_privlvl_cmd(intf); if (!ipmi_oem_active(intf, "i82571spt")) {
rc = ipmi_set_session_privlvl_cmd(intf);
if (rc < 0) if (rc < 0)
goto fail; goto fail;
}
intf->manufacturer_id = ipmi_get_oem(intf); intf->manufacturer_id = ipmi_get_oem(intf);
bridgePossible = 1; bridgePossible = 1;

View File

@ -68,9 +68,9 @@
* return 0 on success (the authcode matches) * return 0 on success (the authcode matches)
* 1 on failure (the authcode does not match) * 1 on failure (the authcode does not match)
*/ */
int lanplus_rakp2_hmac_matches(const struct ipmi_session * session, int
const uint8_t * bmc_mac, lanplus_rakp2_hmac_matches(const struct ipmi_session * session,
struct ipmi_intf * intf) const uint8_t * bmc_mac, struct ipmi_intf * intf)
{ {
uint8_t * buffer; uint8_t * buffer;
int bufferLength, i; int bufferLength, i;
@ -153,6 +153,15 @@ int lanplus_rakp2_hmac_matches(const struct ipmi_session * session,
/* ROLEm */ /* ROLEm */
buffer[56] = session->v2_data.requested_role; buffer[56] = session->v2_data.requested_role;
if (ipmi_oem_active(intf, "i82571spt")) {
/*
* The HMAC calculation code in the Intel 82571 GbE
* skips this bit! Looks like a GbE bug, but we need
* to work around it here anyway...
*/
buffer[56] &= ~0x10;
}
/* ULENGTHm */ /* ULENGTHm */
buffer[57] = strlen((const char *)session->username); buffer[57] = strlen((const char *)session->username);
@ -213,9 +222,9 @@ int lanplus_rakp2_hmac_matches(const struct ipmi_session * session,
* 0 on failure (the authcode does not match) * 0 on failure (the authcode does not match)
* *
*/ */
int lanplus_rakp4_hmac_matches(const struct ipmi_session * session, int
const uint8_t * bmc_mac, lanplus_rakp4_hmac_matches(const struct ipmi_session * session,
struct ipmi_intf * intf) const uint8_t * bmc_mac, struct ipmi_intf * intf)
{ {
uint8_t * buffer; uint8_t * buffer;
int bufferLength, i; int bufferLength, i;
@ -341,10 +350,10 @@ int lanplus_rakp4_hmac_matches(const struct ipmi_session * session,
* returns 0 on success * returns 0 on success
* 1 on failure * 1 on failure
*/ */
int lanplus_generate_rakp3_authcode(uint8_t * output_buffer, int
const struct ipmi_session * session, lanplus_generate_rakp3_authcode(uint8_t * output_buffer,
uint32_t * mac_length, const struct ipmi_session * session,
struct ipmi_intf * intf) uint32_t * mac_length, struct ipmi_intf * intf)
{ {
int ret = 0; int ret = 0;
int input_buffer_length, i; int input_buffer_length, i;
@ -396,7 +405,7 @@ int lanplus_generate_rakp3_authcode(uint8_t * output_buffer
memcpy(input_buffer + 16, &SIDm_lsbf, 4); memcpy(input_buffer + 16, &SIDm_lsbf, 4);
/* ROLEm */ /* ROLEm */
if (ipmi_oem_active(intf, "intelplus")) if (ipmi_oem_active(intf, "intelplus") || ipmi_oem_active(intf, "i82571spt"))
input_buffer[20] = session->privlvl; input_buffer[20] = session->privlvl;
else else
input_buffer[20] = session->v2_data.requested_role; input_buffer[20] = session->v2_data.requested_role;
@ -460,7 +469,8 @@ int lanplus_generate_rakp3_authcode(uint8_t * output_buffer
* returns 0 on success * returns 0 on success
* 1 on failure * 1 on failure
*/ */
int lanplus_generate_sik(struct ipmi_session * session) int
lanplus_generate_sik(struct ipmi_session * session, struct ipmi_intf * intf)
{ {
uint8_t * input_buffer; uint8_t * input_buffer;
int input_buffer_length, i; int input_buffer_length, i;
@ -516,6 +526,15 @@ int lanplus_generate_sik(struct ipmi_session * session)
/* ROLEm */ /* ROLEm */
input_buffer[32] = session->v2_data.requested_role; input_buffer[32] = session->v2_data.requested_role;
if (ipmi_oem_active(intf, "i82571spt")) {
/*
* The HMAC calculation code in the Intel 82571 GbE
* skips this bit! Looks like a GbE bug, but we need
* to work around it here anyway...
*/
input_buffer[32] &= ~0x10;
}
/* ULENGTHm */ /* ULENGTHm */
input_buffer[33] = strlen((const char *)session->username); input_buffer[33] = strlen((const char *)session->username);
@ -580,7 +599,8 @@ int lanplus_generate_sik(struct ipmi_session * session)
* returns 0 on success * returns 0 on success
* 1 on failure * 1 on failure
*/ */
int lanplus_generate_k1(struct ipmi_session * session) int
lanplus_generate_k1(struct ipmi_session * session)
{ {
uint32_t mac_length; uint32_t mac_length;
@ -623,7 +643,8 @@ int lanplus_generate_k1(struct ipmi_session * session)
* returns 0 on success * returns 0 on success
* 1 on failure * 1 on failure
*/ */
int lanplus_generate_k2(struct ipmi_session * session) int
lanplus_generate_k2(struct ipmi_session * session)
{ {
uint32_t mac_length; uint32_t mac_length;
@ -673,12 +694,11 @@ int lanplus_generate_k2(struct ipmi_session * session)
* returns 0 on success * returns 0 on success
* 1 on failure * 1 on failure
*/ */
int lanplus_encrypt_payload(uint8_t crypt_alg, int
const uint8_t * key, lanplus_encrypt_payload(uint8_t crypt_alg,
const uint8_t * input, const uint8_t * key, const uint8_t * input,
uint32_t input_length, uint32_t input_length, uint8_t * output,
uint8_t * output, uint16_t * bytes_written)
uint16_t * bytes_written)
{ {
uint8_t * padded_input; uint8_t * padded_input;
uint32_t mod, i, bytes_encrypted; uint32_t mod, i, bytes_encrypted;
@ -777,12 +797,12 @@ int lanplus_encrypt_payload(uint8_t crypt_alg,
* returns 1 on success (authcode is valid) * returns 1 on success (authcode is valid)
* 0 on failure (autchode integrity check failed) * 0 on failure (autchode integrity check failed)
*/ */
int lanplus_has_valid_auth_code(struct ipmi_rs * rs, int
struct ipmi_session * session) lanplus_has_valid_auth_code(struct ipmi_rs * rs, struct ipmi_session * session)
{ {
uint8_t * bmc_authcode; uint8_t * bmc_authcode;
uint8_t generated_authcode[IPMI_MAX_MAC_SIZE]; uint8_t generated_authcode[IPMI_MAX_MAC_SIZE];
uint32_t generated_authcode_length; uint32_t generated_authcode_length;
if ((rs->session.authtype != IPMI_SESSION_AUTHTYPE_RMCP_PLUS) || if ((rs->session.authtype != IPMI_SESSION_AUTHTYPE_RMCP_PLUS) ||
@ -837,12 +857,10 @@ int lanplus_has_valid_auth_code(struct ipmi_rs * rs,
* returns 0 on success (we were able to successfully decrypt the packet) * returns 0 on success (we were able to successfully decrypt the packet)
* 1 on failure (we were unable to successfully decrypt the packet) * 1 on failure (we were unable to successfully decrypt the packet)
*/ */
int lanplus_decrypt_payload(uint8_t crypt_alg, int
const uint8_t * key, lanplus_decrypt_payload(uint8_t crypt_alg, const uint8_t * key,
const uint8_t * input, const uint8_t * input, uint32_t input_length,
uint32_t input_length, uint8_t * output, uint16_t * payload_size)
uint8_t * output,
uint16_t * payload_size)
{ {
uint8_t * decrypted_payload; uint8_t * decrypted_payload;
uint32_t bytes_decrypted; uint32_t bytes_decrypted;
@ -897,7 +915,7 @@ int lanplus_decrypt_payload(uint8_t crypt_alg,
*/ */
for (i = 0; i < conf_pad_length; ++i) for (i = 0; i < conf_pad_length; ++i)
{ {
if (decrypted_payload[*payload_size + i] == i) if (decrypted_payload[*payload_size + i] != (i + 1))
{ {
lprintf(LOG_ERR, "Malformed payload padding"); lprintf(LOG_ERR, "Malformed payload padding");
assert(0); assert(0);

View File

@ -51,7 +51,7 @@ int lanplus_generate_rakp3_authcode(uint8_t * buffer,
const struct ipmi_session * session, const struct ipmi_session * session,
uint32_t * auth_length, uint32_t * auth_length,
struct ipmi_intf * intf); struct ipmi_intf * intf);
int lanplus_generate_sik(struct ipmi_session * session); int lanplus_generate_sik(struct ipmi_session * session, struct ipmi_intf * intf);
int lanplus_generate_k1(struct ipmi_session * session); int lanplus_generate_k1(struct ipmi_session * session);
int lanplus_generate_k2(struct ipmi_session * session); int lanplus_generate_k2(struct ipmi_session * session);
int lanplus_encrypt_payload(uint8_t crypt_alg, int lanplus_encrypt_payload(uint8_t crypt_alg,