From 5554a12b7bce3ff6b9e18c6174f39f79ee87c20a Mon Sep 17 00:00:00 2001 From: Karthikeyan Ramasubramanian Date: Tue, 8 Jan 2013 17:21:53 -0700 Subject: [PATCH] lib: qmi: Add api to verify maximum length of a QMI message The new API is added to verify the maximum length of a QMI message embedded inside the message descriptor matches the expected maximum length of the concerned QMI message. The expected maximum length of the QMI message is calculated using the message descriptor which describes all the elements in the structure. Change-Id: I09602df410d9891d60f1502245ad055653f8f0f7 Signed-off-by: Karthikeyan Ramasubramanian --- include/linux/qmi_encdec.h | 16 +++++++- lib/qmi_encdec.c | 76 +++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/include/linux/qmi_encdec.h b/include/linux/qmi_encdec.h index 4c5f6d308fde..b1fd2173b917 100644 --- a/include/linux/qmi_encdec.h +++ b/include/linux/qmi_encdec.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -150,6 +150,15 @@ int qmi_kernel_encode(struct msg_desc *desc, int qmi_kernel_decode(struct msg_desc *desc, void *out_c_struct, void *in_buf, uint32_t in_buf_len); +/** + * qmi_verify_max_msg_len() - Verify the maximum length of a QMI message + * @desc: Pointer to structure descriptor. + * + * @return: true if the maximum message length embedded in structure + * descriptor matches the calculated value, else false. + */ +bool qmi_verify_max_msg_len(struct msg_desc *desc); + #else static inline int qmi_kernel_encode(struct msg_desc *desc, void *out_buf, uint32_t out_buf_len, @@ -164,6 +173,11 @@ static inline int qmi_kernel_decode(struct msg_desc *desc, { return -EOPNOTSUPP; } + +static inline bool qmi_verify_max_msg_len(struct msg_desc *desc) +{ + return false; +} #endif #endif diff --git a/lib/qmi_encdec.c b/lib/qmi_encdec.c index 5c489cf0f9b6..3f618cb3f02b 100644 --- a/lib/qmi_encdec.c +++ b/lib/qmi_encdec.c @@ -89,6 +89,71 @@ static int _qmi_kernel_decode(struct elem_info *ei_array, void *in_buf, uint32_t in_buf_len, int dec_level); +/** + * qmi_calc_max_msg_len() - Calculate the maximum length of a QMI message + * @ei_array: Struct info array describing the structure. + * @level: Level to identify the depth of the nested structures. + * + * @return: expected maximum length of the QMI message or 0 on failure. + */ +static int qmi_calc_max_msg_len(struct elem_info *ei_array, + int level) +{ + int max_msg_len = 0; + struct elem_info *temp_ei; + + if (!ei_array) + return max_msg_len; + + for (temp_ei = ei_array; temp_ei->data_type != QMI_EOTI; temp_ei++) { + /* Flag to identify the optional element is not encoded */ + if (temp_ei->data_type == QMI_OPT_FLAG) + continue; + + if (temp_ei->data_type == QMI_DATA_LEN) { + max_msg_len += (temp_ei->elem_size == sizeof(uint8_t) ? + sizeof(uint8_t) : sizeof(uint16_t)); + continue; + } else if (temp_ei->data_type == QMI_STRUCT) { + max_msg_len += qmi_calc_max_msg_len(temp_ei->ei_array, + (level + 1)); + } else { + max_msg_len += (temp_ei->elem_len * temp_ei->elem_size); + } + + /* + * Type & Length info. not prepended for elements in the + * nested structure. + */ + if (level == 1) + max_msg_len += (TLV_TYPE_SIZE + TLV_LEN_SIZE); + } + return max_msg_len; +} + +/** + * qmi_verify_max_msg_len() - Verify the maximum length of a QMI message + * @desc: Pointer to structure descriptor. + * + * @return: true if the maximum message length embedded in structure + * descriptor matches the calculated value, else false. + */ +bool qmi_verify_max_msg_len(struct msg_desc *desc) +{ + int calc_max_msg_len; + + if (!desc) + return false; + + calc_max_msg_len = qmi_calc_max_msg_len(desc->ei_array, 1); + if (calc_max_msg_len != desc->max_msg_len) { + pr_err("%s: Calc. len %d != Passed len %d\n", + __func__, calc_max_msg_len, desc->max_msg_len); + return false; + } + return true; +} + /** * qmi_kernel_encode() - Encode to QMI message wire format * @desc: Pointer to structure descriptor. @@ -103,6 +168,7 @@ int qmi_kernel_encode(struct msg_desc *desc, void *in_c_struct) { int enc_level = 1; + int ret, calc_max_msg_len; if (!desc || !desc->ei_array) return -EINVAL; @@ -113,8 +179,14 @@ int qmi_kernel_encode(struct msg_desc *desc, if (desc->max_msg_len < out_buf_len) return -ETOOSMALL; - return _qmi_kernel_encode(desc->ei_array, out_buf, - in_c_struct, out_buf_len, enc_level); + ret = _qmi_kernel_encode(desc->ei_array, out_buf, + in_c_struct, out_buf_len, enc_level); + if (ret == -ETOOSMALL) { + calc_max_msg_len = qmi_calc_max_msg_len(desc->ei_array, 1); + pr_err("%s: Calc. len %d != Out buf len %d\n", + __func__, calc_max_msg_len, out_buf_len); + } + return ret; } EXPORT_SYMBOL(qmi_kernel_encode);