summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);