Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be8e8e1b authored by Ravi Aravamudhan's avatar Ravi Aravamudhan Committed by Stephen Boyd
Browse files

diag: Perform CRC check on incoming HDLC encoded packet



Diag driver receives HDLC encoded data from the tools and decodes
them. This patch adds checks to the received data. It discards the
packet if the CRC is not correct.

Change-Id: Ie53056844d6d1e6777d15a339896bf6842cfae64
CRs-Fixed: 519902
Signed-off-by: default avatarRavi Aravamudhan <aravamud@codeaurora.org>
parent 278cf141
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/ratelimit.h>
#include <linux/crc-ccitt.h>
#include "diagchar_hdlc.h"
#include "diagchar.h"
@@ -234,3 +235,37 @@ int diag_hdlc_decode(struct diag_hdlc_decode_type *hdlc)

	return pkt_bnd;
}

int crc_check(uint8_t *buf, uint16_t len)
{
	uint16_t crc = CRC_16_L_SEED;
	uint8_t sent_crc[2] = {0, 0};

	/*
	 * The minimum length of a valid incoming packet is 4. 1 byte
	 * of data and 3 bytes for CRC
	 */
	if (!buf || len < 4) {
		pr_err_ratelimited("diag: In %s, invalid packet or length, buf: 0x%x, len: %d",
				   __func__, (int)buf, len);
		return -EIO;
	}

	/*
	 * Run CRC check for the original input. Skip the last 3 CRC
	 * bytes
	 */
	crc = crc_ccitt(crc, buf, len-3);
	crc ^= CRC_16_L_SEED;

	/* Check the computed CRC against the original CRC bytes. */
	sent_crc[0] = buf[len-3];
	sent_crc[1] = buf[len-2];
	if (crc != *((uint16_t *)sent_crc)) {
		pr_debug("diag: In %s, crc mismatch. expected: %x, sent %x.\n",
				__func__, crc, *((uint16_t *)sent_crc));
		return -EIO;
	}

	return 0;
}
+3 −1
Original line number Diff line number Diff line
/* Copyright (c) 2008-2009, 2012, The Linux Foundation. All rights reserved.
/* Copyright (c) 2008-2009, 2012-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -53,6 +53,8 @@ void diag_hdlc_encode(struct diag_send_desc_type *src_desc,

int diag_hdlc_decode(struct diag_hdlc_decode_type *hdlc);

int crc_check(uint8_t *buf, uint16_t len);

#define ESC_CHAR     0x7D
#define ESC_MASK     0x20

+13 −4
Original line number Diff line number Diff line
@@ -1514,7 +1514,7 @@ static inline void diag_send_error_rsp(int index) {}
void diag_process_hdlc(void *data, unsigned len)
{
	struct diag_hdlc_decode_type hdlc;
	int ret, type = 0;
	int ret, type = 0, crc_chk = 0;

	mutex_lock(&driver->diag_hdlc_mutex);

@@ -1528,6 +1528,16 @@ void diag_process_hdlc(void *data, unsigned len)
	hdlc.escaping = 0;

	ret = diag_hdlc_decode(&hdlc);
	if (ret) {
		crc_chk = crc_check(hdlc.dest_ptr, hdlc.dest_idx);
		if (crc_chk) {
			/* CRC check failed. */
			pr_err_ratelimited("diag: In %s, bad CRC. Dropping packet\n",
								__func__);
			mutex_unlock(&driver->diag_hdlc_mutex);
			return;
		}
	}

	/*
	 * If the message is 3 bytes or less in length then the message is
@@ -1550,9 +1560,8 @@ void diag_process_hdlc(void *data, unsigned len)
			return;
		}
	} else if (driver->debug_flag) {
		printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
				" errors or partial packet received, packet"
				" length = %d\n", len);
		pr_err("diag: In %s, partial packet received, dropping packet, len: %d\n",
								__func__, len);
		print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
					   DUMP_PREFIX_ADDRESS, data, len, 1);
		driver->debug_flag = 0;