Commit 7d6380cd authored by Corey Minyard's avatar Corey Minyard

ipmi:ssif: Fix handling of multi-part return messages

The block number was not being compared right, it was off by one
when checking the response.

Some statistics wouldn't be incremented properly in some cases.

Check to see if that middle-part messages always have 31 bytes of
data.
Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
Cc: stable@vger.kernel.org # 4.4
parent 7b558513
...@@ -632,8 +632,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ...@@ -632,8 +632,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
/* Remove the multi-part read marker. */ /* Remove the multi-part read marker. */
len -= 2; len -= 2;
data += 2;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
ssif_info->data[i] = data[i+2]; ssif_info->data[i] = data[i];
ssif_info->multi_len = len; ssif_info->multi_len = len;
ssif_info->multi_pos = 1; ssif_info->multi_pos = 1;
...@@ -661,8 +662,19 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ...@@ -661,8 +662,19 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
} }
blocknum = data[0]; blocknum = data[0];
len--;
data++;
if (blocknum != 0xff && len != 31) {
/* All blocks but the last must have 31 data bytes. */
result = -EIO;
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("Received middle message <31\n");
if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) { goto continue_op;
}
if (ssif_info->multi_len + len > IPMI_MAX_MSG_LENGTH) {
/* Received message too big, abort the operation. */ /* Received message too big, abort the operation. */
result = -E2BIG; result = -E2BIG;
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
...@@ -671,16 +683,14 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ...@@ -671,16 +683,14 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
goto continue_op; goto continue_op;
} }
/* Remove the blocknum from the data. */
len--;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
ssif_info->data[i + ssif_info->multi_len] = data[i + 1]; ssif_info->data[i + ssif_info->multi_len] = data[i];
ssif_info->multi_len += len; ssif_info->multi_len += len;
if (blocknum == 0xff) { if (blocknum == 0xff) {
/* End of read */ /* End of read */
len = ssif_info->multi_len; len = ssif_info->multi_len;
data = ssif_info->data; data = ssif_info->data;
} else if (blocknum + 1 != ssif_info->multi_pos) { } else if (blocknum != ssif_info->multi_pos) {
/* /*
* Out of sequence block, just abort. Block * Out of sequence block, just abort. Block
* numbers start at zero for the second block, * numbers start at zero for the second block,
...@@ -707,6 +717,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ...@@ -707,6 +717,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
} }
} }
continue_op:
if (result < 0) { if (result < 0) {
ssif_inc_stat(ssif_info, receive_errors); ssif_inc_stat(ssif_info, receive_errors);
} else { } else {
...@@ -714,8 +725,6 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ...@@ -714,8 +725,6 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ssif_inc_stat(ssif_info, received_message_parts); ssif_inc_stat(ssif_info, received_message_parts);
} }
continue_op:
if (ssif_info->ssif_debug & SSIF_DEBUG_STATE) if (ssif_info->ssif_debug & SSIF_DEBUG_STATE)
pr_info("DONE 1: state = %d, result=%d\n", pr_info("DONE 1: state = %d, result=%d\n",
ssif_info->ssif_state, result); ssif_info->ssif_state, result);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment