From 0cea01e42f42175b2199ec3efd0bcd53bb232847 Mon Sep 17 00:00:00 2001 From: Zdenek Styblik Date: Tue, 28 May 2013 04:18:22 +0000 Subject: [PATCH] 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 --- ipmitool/lib/ipmi_oem.c | 4 + ipmitool/lib/ipmi_sol.c | 82 ++++++++++++-------- ipmitool/src/plugins/lanplus/lanplus.c | 17 ++-- ipmitool/src/plugins/lanplus/lanplus_crypt.c | 80 +++++++++++-------- ipmitool/src/plugins/lanplus/lanplus_crypt.h | 2 +- 5 files changed, 112 insertions(+), 73 deletions(-) diff --git a/ipmitool/lib/ipmi_oem.c b/ipmitool/lib/ipmi_oem.c index de4a1a9..f0fd598 100644 --- a/ipmitool/lib/ipmi_oem.c +++ b/ipmitool/lib/ipmi_oem.c @@ -63,6 +63,10 @@ static struct ipmi_oem_handle ipmi_oem_list[] = { desc: "IBM OEM support", setup: ipmi_oem_ibm, }, + { + name: "i82571spt", + desc: "Intel 82571 MAC with integrated RMCP+ support in super pass-through mode", + }, { 0 } }; diff --git a/ipmitool/lib/ipmi_sol.c b/ipmitool/lib/ipmi_sol.c index d0fadcf..e9ef4f0 100644 --- a/ipmitool/lib/ipmi_sol.c +++ b/ipmitool/lib/ipmi_sol.c @@ -1568,43 +1568,45 @@ ipmi_sol_red_pill(struct ipmi_intf * intf, int instance) FD_SET(0, &read_fds); FD_SET(intf->fd, &read_fds); - /* Send periodic keepalive packet */ - if(_use_sol_for_keepalive == 0) + if (!ipmi_oem_active(intf,"i82571spt")) { - keepAliveRet = ipmi_sol_keepalive_using_getdeviceid(intf); - } - 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) + /* Send periodic keepalive packet */ + if(_use_sol_for_keepalive == 0) { - /* no response to Get Device ID keepalive message */ - bShouldExit = 1; - continue; + keepAliveRet = ipmi_sol_keepalive_using_getdeviceid(intf); } - else - { - retrySol++; + else + { + keepAliveRet = ipmi_sol_keepalive_using_sol(intf); } - } - else - { - /* if the keep Alive is successful reset retries to zero */ - retrySol = 0; - } - + + 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 */ + 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 */ tv.tv_sec = 0; 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")) { 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 { data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_FALSE; } diff --git a/ipmitool/src/plugins/lanplus/lanplus.c b/ipmitool/src/plugins/lanplus/lanplus.c index d2aca7f..2abbdc4 100644 --- a/ipmitool/src/plugins/lanplus/lanplus.c +++ b/ipmitool/src/plugins/lanplus/lanplus.c @@ -3164,7 +3164,7 @@ ipmi_lanplus_rakp3(struct ipmi_intf * intf) } /* Generate our Session Integrity Key, K1, and K2 */ - if (lanplus_generate_sik(session)) + if (lanplus_generate_sik(session, intf)) { /* Error */ 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 */ - 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); 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+"); goto fail; @@ -3462,11 +3463,11 @@ ipmi_lanplus_open(struct ipmi_intf * intf) lprintf(LOG_DEBUG, "IPMIv2 / RMCP+ SESSION OPENED SUCCESSFULLY\n"); - rc = ipmi_set_session_privlvl_cmd(intf); - - if (rc < 0) - goto fail; - + if (!ipmi_oem_active(intf, "i82571spt")) { + rc = ipmi_set_session_privlvl_cmd(intf); + if (rc < 0) + goto fail; + } intf->manufacturer_id = ipmi_get_oem(intf); bridgePossible = 1; diff --git a/ipmitool/src/plugins/lanplus/lanplus_crypt.c b/ipmitool/src/plugins/lanplus/lanplus_crypt.c index 16a5849..54fd5cb 100644 --- a/ipmitool/src/plugins/lanplus/lanplus_crypt.c +++ b/ipmitool/src/plugins/lanplus/lanplus_crypt.c @@ -68,9 +68,9 @@ * return 0 on success (the authcode matches) * 1 on failure (the authcode does not match) */ -int lanplus_rakp2_hmac_matches(const struct ipmi_session * session, - const uint8_t * bmc_mac, - struct ipmi_intf * intf) +int +lanplus_rakp2_hmac_matches(const struct ipmi_session * session, + const uint8_t * bmc_mac, struct ipmi_intf * intf) { uint8_t * buffer; int bufferLength, i; @@ -153,6 +153,15 @@ int lanplus_rakp2_hmac_matches(const struct ipmi_session * session, /* ROLEm */ 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 */ 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) * */ -int lanplus_rakp4_hmac_matches(const struct ipmi_session * session, - const uint8_t * bmc_mac, - struct ipmi_intf * intf) +int +lanplus_rakp4_hmac_matches(const struct ipmi_session * session, + const uint8_t * bmc_mac, struct ipmi_intf * intf) { uint8_t * buffer; int bufferLength, i; @@ -341,10 +350,10 @@ int lanplus_rakp4_hmac_matches(const struct ipmi_session * session, * returns 0 on success * 1 on failure */ -int lanplus_generate_rakp3_authcode(uint8_t * output_buffer, - const struct ipmi_session * session, - uint32_t * mac_length, - struct ipmi_intf * intf) +int +lanplus_generate_rakp3_authcode(uint8_t * output_buffer, + const struct ipmi_session * session, + uint32_t * mac_length, struct ipmi_intf * intf) { int ret = 0; 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); /* ROLEm */ - if (ipmi_oem_active(intf, "intelplus")) + if (ipmi_oem_active(intf, "intelplus") || ipmi_oem_active(intf, "i82571spt")) input_buffer[20] = session->privlvl; else 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 * 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; int input_buffer_length, i; @@ -516,6 +526,15 @@ int lanplus_generate_sik(struct ipmi_session * session) /* ROLEm */ 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 */ input_buffer[33] = strlen((const char *)session->username); @@ -580,7 +599,8 @@ int lanplus_generate_sik(struct ipmi_session * session) * returns 0 on success * 1 on failure */ -int lanplus_generate_k1(struct ipmi_session * session) +int +lanplus_generate_k1(struct ipmi_session * session) { uint32_t mac_length; @@ -623,7 +643,8 @@ int lanplus_generate_k1(struct ipmi_session * session) * returns 0 on success * 1 on failure */ -int lanplus_generate_k2(struct ipmi_session * session) +int +lanplus_generate_k2(struct ipmi_session * session) { uint32_t mac_length; @@ -673,12 +694,11 @@ int lanplus_generate_k2(struct ipmi_session * session) * returns 0 on success * 1 on failure */ -int lanplus_encrypt_payload(uint8_t crypt_alg, - const uint8_t * key, - const uint8_t * input, - uint32_t input_length, - uint8_t * output, - uint16_t * bytes_written) +int +lanplus_encrypt_payload(uint8_t crypt_alg, + const uint8_t * key, const uint8_t * input, + uint32_t input_length, uint8_t * output, + uint16_t * bytes_written) { uint8_t * padded_input; 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) * 0 on failure (autchode integrity check failed) */ -int lanplus_has_valid_auth_code(struct ipmi_rs * rs, - struct ipmi_session * session) +int +lanplus_has_valid_auth_code(struct ipmi_rs * rs, struct ipmi_session * session) { uint8_t * bmc_authcode; - uint8_t generated_authcode[IPMI_MAX_MAC_SIZE]; - uint32_t generated_authcode_length; + uint8_t generated_authcode[IPMI_MAX_MAC_SIZE]; + uint32_t generated_authcode_length; 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) * 1 on failure (we were unable to successfully decrypt the packet) */ -int lanplus_decrypt_payload(uint8_t crypt_alg, - const uint8_t * key, - const uint8_t * input, - uint32_t input_length, - uint8_t * output, - uint16_t * payload_size) +int +lanplus_decrypt_payload(uint8_t crypt_alg, const uint8_t * key, + const uint8_t * input, uint32_t input_length, + uint8_t * output, uint16_t * payload_size) { uint8_t * decrypted_payload; uint32_t bytes_decrypted; @@ -897,7 +915,7 @@ int lanplus_decrypt_payload(uint8_t crypt_alg, */ 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"); assert(0); diff --git a/ipmitool/src/plugins/lanplus/lanplus_crypt.h b/ipmitool/src/plugins/lanplus/lanplus_crypt.h index 9b7f0d4..d69cc9b 100644 --- a/ipmitool/src/plugins/lanplus/lanplus_crypt.h +++ b/ipmitool/src/plugins/lanplus/lanplus_crypt.h @@ -51,7 +51,7 @@ int lanplus_generate_rakp3_authcode(uint8_t * buffer, const struct ipmi_session * session, uint32_t * auth_length, 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_k2(struct ipmi_session * session); int lanplus_encrypt_payload(uint8_t crypt_alg,