summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEddie James <eajames@linux.vnet.ibm.com>2018-05-01 17:51:25 +0300
committerJoel Stanley <joel@jms.id.au>2018-05-07 14:34:09 +0300
commitf7123755b3e103339a5adb81213e7fd8115966dc (patch)
tree199f6bbe4e9ef623c8cef4985f066fac8e4f32fd
parent09429135c15ee7dc975fb8af33ad250d819d28ef (diff)
downloadlinux-f7123755b3e103339a5adb81213e7fd8115966dc.tar.xz
fsi: occ: Add check for OCC response checksum
The OCC specification indicates that it is an error scenario if the response checksum doesn't match the sum of the bytes of the response. The driver needs to perform this calculation and check, and return an error if it's a mismatch. OpenBMC-Staging-Count: 1 Signed-off-by: Eddie James <eajames@linux.vnet.ibm.com> Acked-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Joel Stanley <joel@jms.id.au>
-rw-r--r--drivers/fsi/fsi-occ.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c
index 938601fd7347..d368b62e5471 100644
--- a/drivers/fsi/fsi-occ.c
+++ b/drivers/fsi/fsi-occ.c
@@ -58,8 +58,7 @@ struct occ_response {
u8 cmd_type;
u8 return_status;
__be16 data_length;
- u8 data[OCC_RESP_DATA_BYTES];
- __be16 checksum;
+ u8 data[OCC_RESP_DATA_BYTES + 2]; /* two bytes checksum */
} __packed;
/*
@@ -427,6 +426,27 @@ static const struct file_operations occ_fops = {
.release = occ_release,
};
+static int occ_verify_checksum(struct occ_response *resp, u16 data_length)
+{
+ u16 i;
+ u16 checksum;
+ /* Fetch the two bytes after the data for the checksum. */
+ u16 checksum_resp = get_unaligned_be16(&resp->data[data_length]);
+
+ checksum = resp->seq_no;
+ checksum += resp->cmd_type;
+ checksum += resp->return_status;
+ checksum += (data_length >> 8) + (data_length & 0xFF);
+
+ for (i = 0; i < data_length; ++i)
+ checksum += resp->data[i];
+
+ if (checksum != checksum_resp)
+ return -EBADMSG;
+
+ return 0;
+}
+
static int occ_write_sbefifo(struct sbefifo_client *client, const char *buf,
ssize_t len)
{
@@ -688,6 +708,8 @@ again:
xfr->resp_data_length = resp_data_length + 7;
+ rc = occ_verify_checksum(resp, resp_data_length);
+
done:
mutex_unlock(&occ->occ_lock);