ID:369 - Fix lanplus interface bridging and response matching

Request/response matching for bridged and double-bridged requests is broken.
This patch reworks the sending and command construction code, and fixes the
response matching problems.
Since the polling code is retried several times, it was moved into a separate
function in order to make the code more readable.

Commit for: Dmitry Bazhenov
This commit is contained in:
Zdenek Styblik 2015-07-25 13:15:41 +02:00
parent c87aa0b96a
commit 6dec83ff5d

View File

@ -601,7 +601,7 @@ ipmiv2_lan_ping(struct ipmi_intf * intf)
/**
*
* ipmi_lan_poll_recv
* ipmi_lan_poll_single
*
* Receive whatever comes back. Ignore received packets that don't correspond
* to a request we've sent.
@ -609,50 +609,42 @@ ipmiv2_lan_ping(struct ipmi_intf * intf)
* Returns: the ipmi_rs packet describing the/a reponse we expect.
*/
static struct ipmi_rs *
ipmi_lan_poll_recv(struct ipmi_intf * intf)
ipmi_lan_poll_single(struct ipmi_intf * intf)
{
struct rmcp_hdr rmcp_rsp;
struct rmcp_hdr * rmcp_rsp;
struct ipmi_rs * rsp;
struct ipmi_session * session = intf->session;
int offset, rv;
uint16_t payload_size;
uint8_t ourAddress = intf->my_addr;
if (ourAddress == 0) {
ourAddress = IPMI_BMC_SLAVE_ADDR;
}
/* receive packet */
rsp = ipmi_lan_recv_packet(intf);
/*
* Not positive why we're looping. Do we sometimes get stuff we don't
* expect?
*/
while (rsp != NULL) {
/* check if no packet has come */
if (rsp == NULL) {
return NULL;
}
/* parse response headers */
memcpy(&rmcp_rsp, rsp->data, 4);
rmcp_rsp = (struct rmcp_hdr *)rsp->data;
if (rmcp_rsp.class == RMCP_CLASS_ASF) {
if (rmcp_rsp->class == RMCP_CLASS_ASF) {
/* might be ping response packet */
rv = ipmi_handle_pong(intf, rsp);
return (rv <= 0) ? NULL : rsp;
}
if (rmcp_rsp.class != RMCP_CLASS_IPMI) {
lprintf(LOG_DEBUG, "Invalid RMCP class: %x",
rmcp_rsp.class);
rsp = ipmi_lan_recv_packet(intf);
continue;
if (rmcp_rsp->class != RMCP_CLASS_IPMI) {
lprintf(LOG_DEBUG, "Invalid RMCP class: %x", rmcp_rsp->class);
/* read one more packet */
return (struct ipmi_rs *)1;
}
/*
* The authtype / payload type determines what we are receiving
*/
offset = 4;
/*--------------------------------------------------------------------
*
* The current packet could be one of several things:
@ -670,38 +662,35 @@ ipmi_lan_poll_recv(struct ipmi_intf * intf)
read_session_data(rsp, &offset, intf->session);
if (lanplus_has_valid_auth_code(rsp, intf->session) == 0)
{
if (lanplus_has_valid_auth_code(rsp, intf->session) == 0) {
lprintf(LOG_ERR, "ERROR: Received message with invalid authcode!");
rsp = ipmi_lan_recv_packet(intf);
assert(0);
//continue;
return NULL;
}
if ((session->v2_data.session_state == LANPLUS_STATE_ACTIVE) &&
(rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
(rsp->session.bEncrypted))
{
(rsp->session.bEncrypted)) {
lanplus_decrypt_payload(session->v2_data.crypt_alg,
session->v2_data.k2,
rsp->data + offset,
rsp->session.msglen,
rsp->data + offset,
&payload_size);
}
else
} else {
payload_size = rsp->session.msglen;
}
/*
* Handle IPMI responses (case #1 and #2) -- all IPMI reponses
*/
if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_IPMI)
{
if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_IPMI) {
struct ipmi_rq_entry * entry;
int payload_start = offset;
int extra_data_length;
int loop = 1;
while (loop--) {
/* fill-in response data */
read_ipmi_response(rsp, &offset);
lprintf(LOG_DEBUG+1, "<< IPMI Response Session Header");
@ -737,51 +726,54 @@ ipmi_lan_poll_recv(struct ipmi_intf * intf)
entry = ipmi_req_lookup_entry(rsp->payload.ipmi_response.rq_seq,
rsp->payload.ipmi_response.cmd);
if (entry != NULL) {
if (entry == NULL) {
lprintf(LOG_INFO, "IPMI Request Match NOT FOUND");
/* read one more packet */
return (struct ipmi_rs *)1;
};
uint8_t target_cmd = entry->req.msg.target_cmd;
lprintf(LOG_DEBUG+2, "IPMI Request Match found");
if ( intf->target_addr != intf->my_addr &&
bridgePossible &&
rsp->data_len &&
rsp->payload.ipmi_response.cmd == 0x34 &&
(rsp->payload.ipmi_response.netfn == 0x06 ||
rsp->payload.ipmi_response.netfn == 0x07) &&
rsp->payload.ipmi_response.rs_lun == 0 )
{
if (entry->bridging_level) {
/* Check completion code */
if (rsp->data[offset-1] == 0)
{
if (rsp->ccode) {
lprintf(LOG_DEBUG, "WARNING: Bridged "
"cmd ccode = 0x%02x", rsp->ccode);
} else {
/* decrement bridging level */
entry->bridging_level--;
if (!entry->bridging_level) {
entry->req.msg.cmd = entry->req.msg.target_cmd;
}
/* check if bridged response is embedded */
if (payload_size > 8) {
printbuf(&rsp->data[offset], (rsp->data_len-offset-1),
"bridge command response");
/*
* decrement payload size
* (cks2 for outer Send Message)
*/
payload_size--;
/*
* need to make a loop for embedded bridged response
*/
loop++;
} else {
lprintf(LOG_DEBUG, "Bridged command answer,"
" waiting for next answer... ");
ipmi_req_remove_entry(
rsp->payload.ipmi_response.rq_seq,
rsp->payload.ipmi_response.cmd);
return ipmi_lan_poll_recv(intf);
/* read one more packet */
return (struct ipmi_rs *)1;
}
else
{
lprintf(LOG_DEBUG, "WARNING: Bridged "
"cmd ccode = 0x%02x",
rsp->data[offset-1]);
}
if (rsp->data_len &&
rsp->payload.ipmi_response.cmd == 0x34) {
memcpy(rsp->data, &rsp->data[offset],
(rsp->data_len-offset));
if (verbose > 2)
printbuf( &rsp->data[offset],
(rsp->data_len-offset),
"bridge command response");
}
}
/* Remove request entry */
ipmi_req_remove_entry(rsp->payload.ipmi_response.rq_seq,
rsp->payload.ipmi_response.cmd);
} else {
lprintf(LOG_INFO, "IPMI Request Match NOT FOUND");
rsp = ipmi_lan_recv_packet(intf);
continue;
}
/*
* Good packet. Shift response data to start of array.
@ -789,108 +781,100 @@ ipmi_lan_poll_recv(struct ipmi_intf * intf)
* rsp->data_len becomes the length of that data
*/
extra_data_length = payload_size - (offset - payload_start) - 1;
if (rsp != NULL && extra_data_length)
{
if (extra_data_length) {
rsp->data_len = extra_data_length;
memmove(rsp->data, rsp->data + offset, extra_data_length);
}
else
} else {
rsp->data_len = 0;
break;
}
}
/*
* Open Response
*/
else if (rsp->session.payloadtype ==
IPMI_PAYLOAD_TYPE_RMCP_OPEN_RESPONSE)
{
} else if (rsp->session.payloadtype ==
IPMI_PAYLOAD_TYPE_RMCP_OPEN_RESPONSE) {
if (session->v2_data.session_state !=
LANPLUS_STATE_OPEN_SESSION_SENT)
{
LANPLUS_STATE_OPEN_SESSION_SENT) {
lprintf(LOG_ERR, "Error: Received an Unexpected Open Session "
"Response");
rsp = ipmi_lan_recv_packet(intf);
continue;
/* read one more packet */
return (struct ipmi_rs *)1;
}
read_open_session_response(rsp, offset);
break;
}
/*
* RAKP 2
*/
else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_2)
{
if (session->v2_data.session_state != LANPLUS_STATE_RAKP_1_SENT)
{
} else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_2) {
if (session->v2_data.session_state != LANPLUS_STATE_RAKP_1_SENT) {
lprintf(LOG_ERR, "Error: Received an Unexpected RAKP 2 message");
rsp = ipmi_lan_recv_packet(intf);
continue;
/* read one more packet */
return (struct ipmi_rs *)1;
}
read_rakp2_message(rsp, offset, session->v2_data.auth_alg);
break;
}
/*
* RAKP 4
*/
else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_4)
{
if (session->v2_data.session_state != LANPLUS_STATE_RAKP_3_SENT)
{
} else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_4) {
if (session->v2_data.session_state != LANPLUS_STATE_RAKP_3_SENT) {
lprintf(LOG_ERR, "Error: Received an Unexpected RAKP 4 message");
rsp = ipmi_lan_recv_packet(intf);
continue;
/* read one more packet */
return (struct ipmi_rs *)1;
}
read_rakp4_message(rsp, offset, session->v2_data.auth_alg);
break;
}
/*
* SOL
*/
else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)
{
} else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) {
int payload_start = offset;
int extra_data_length;
if (session->v2_data.session_state != LANPLUS_STATE_ACTIVE)
{
if (session->v2_data.session_state != LANPLUS_STATE_ACTIVE) {
lprintf(LOG_ERR, "Error: Received an Unexpected SOL packet");
rsp = ipmi_lan_recv_packet(intf);
continue;
/* read one more packet */
return (struct ipmi_rs *)1;
}
read_sol_packet(rsp, &offset);
extra_data_length = payload_size - (offset - payload_start);
if (rsp && extra_data_length)
{
if (rsp && extra_data_length) {
rsp->data_len = extra_data_length;
memmove(rsp->data, rsp->data + offset, extra_data_length);
}
else
} else {
rsp->data_len = 0;
break;
}
else
{
/*
* Unknown Payload type
*/
} else {
lprintf(LOG_ERR, "Invalid RMCP+ payload type : 0x%x",
rsp->session.payloadtype);
assert(0);
/* read one more packet */
return (struct ipmi_rs *)1;
}
return rsp;
}
/**
*
* ipmi_lan_poll_recv
*
* Receive whatever comes back. Ignore received packets that don't correspond
* to a request we've sent.
*
* Returns: the ipmi_rs packet describing the/a reponse we expect.
*/
static struct ipmi_rs *
ipmi_lan_poll_recv(struct ipmi_intf * intf)
{
struct ipmi_rs * rsp;
do {
/* poll single packet */
rsp = ipmi_lan_poll_single(intf);
} while (rsp == (struct ipmi_rs *) 1);
return rsp;
}
@ -1412,7 +1396,7 @@ void getIpmiPayloadWireRep(
tmp = len - cs;
msg[len++] = ipmi_csum(msg+cs, tmp);
cs3 = len;
msg[len++] = intf->my_addr;
msg[len++] = IPMI_REMOTE_SWID;
msg[len++] = curr_seq << 2;
msg[len++] = 0x34; /* Send Message rqst */
#if 0 /* From lan.c example */
@ -1435,7 +1419,10 @@ void getIpmiPayloadWireRep(
bridgePossible);
/* rsAddr */
msg[len++] = intf->target_addr; /* IPMI_BMC_SLAVE_ADDR; */
if (bridgedRequest)
msg[len++] = intf->target_addr;
else
msg[len++] = IPMI_BMC_SLAVE_ADDR;
/* net Fn */
msg[len++] = req->msg.netfn << 2 | (req->msg.lun & 3);
@ -1446,7 +1433,7 @@ void getIpmiPayloadWireRep(
cs = len;
/* rqAddr */
if (!bridgedRequest)
if (bridgedRequest < 2)
msg[len++] = IPMI_REMOTE_SWID;
else /* Bridged message */
msg[len++] = intf->my_addr;
@ -1896,24 +1883,24 @@ ipmi_lanplus_build_v2x_ipmi_cmd(
/* IPMI Message Header -- Figure 13-4 of the IPMI v2.0 spec */
if ((intf->target_addr == intf->my_addr) || (!bridgePossible))
{
if ((intf->target_addr == intf->my_addr) || (!bridgePossible)) {
entry = ipmi_req_add_entry(intf, req, curr_seq);
}
else /* it's a bridge command */
{
/* it's a bridge command */
} else {
unsigned char backup_cmd;
/* Add entry for cmd */
entry = ipmi_req_add_entry(intf, req, curr_seq);
if(entry)
{
/* Add entry for bridge cmd */
backup_cmd = req->msg.cmd;
req->msg.cmd = 0x34;
entry = ipmi_req_add_entry(intf, req, curr_seq);
req->msg.cmd = backup_cmd;
if (entry) {
entry->req.msg.target_cmd = entry->req.msg.cmd;
entry->req.msg.cmd = 0x34;
if (intf->transit_addr &&
intf->transit_addr != intf->my_addr)
entry->bridging_level = 2;
else
entry->bridging_level = 1;
}
}