1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
4*4882a593Smuzhiyun * Copyright (C) 2017 Linaro Ltd.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun #include <linux/slab.h>
7*4882a593Smuzhiyun #include <linux/uaccess.h>
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/errno.h>
11*4882a593Smuzhiyun #include <linux/string.h>
12*4882a593Smuzhiyun #include <linux/soc/qcom/qmi.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define QMI_ENCDEC_ENCODE_TLV(type, length, p_dst) do { \
15*4882a593Smuzhiyun *p_dst++ = type; \
16*4882a593Smuzhiyun *p_dst++ = ((u8)((length) & 0xFF)); \
17*4882a593Smuzhiyun *p_dst++ = ((u8)(((length) >> 8) & 0xFF)); \
18*4882a593Smuzhiyun } while (0)
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define QMI_ENCDEC_DECODE_TLV(p_type, p_length, p_src) do { \
21*4882a593Smuzhiyun *p_type = (u8)*p_src++; \
22*4882a593Smuzhiyun *p_length = (u8)*p_src++; \
23*4882a593Smuzhiyun *p_length |= ((u8)*p_src) << 8; \
24*4882a593Smuzhiyun } while (0)
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define QMI_ENCDEC_ENCODE_N_BYTES(p_dst, p_src, size) \
27*4882a593Smuzhiyun do { \
28*4882a593Smuzhiyun memcpy(p_dst, p_src, size); \
29*4882a593Smuzhiyun p_dst = (u8 *)p_dst + size; \
30*4882a593Smuzhiyun p_src = (u8 *)p_src + size; \
31*4882a593Smuzhiyun } while (0)
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define QMI_ENCDEC_DECODE_N_BYTES(p_dst, p_src, size) \
34*4882a593Smuzhiyun do { \
35*4882a593Smuzhiyun memcpy(p_dst, p_src, size); \
36*4882a593Smuzhiyun p_dst = (u8 *)p_dst + size; \
37*4882a593Smuzhiyun p_src = (u8 *)p_src + size; \
38*4882a593Smuzhiyun } while (0)
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #define UPDATE_ENCODE_VARIABLES(temp_si, buf_dst, \
41*4882a593Smuzhiyun encoded_bytes, tlv_len, encode_tlv, rc) \
42*4882a593Smuzhiyun do { \
43*4882a593Smuzhiyun buf_dst = (u8 *)buf_dst + rc; \
44*4882a593Smuzhiyun encoded_bytes += rc; \
45*4882a593Smuzhiyun tlv_len += rc; \
46*4882a593Smuzhiyun temp_si = temp_si + 1; \
47*4882a593Smuzhiyun encode_tlv = 1; \
48*4882a593Smuzhiyun } while (0)
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun #define UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc) \
51*4882a593Smuzhiyun do { \
52*4882a593Smuzhiyun buf_src = (u8 *)buf_src + rc; \
53*4882a593Smuzhiyun decoded_bytes += rc; \
54*4882a593Smuzhiyun } while (0)
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun #define TLV_LEN_SIZE sizeof(u16)
57*4882a593Smuzhiyun #define TLV_TYPE_SIZE sizeof(u8)
58*4882a593Smuzhiyun #define OPTIONAL_TLV_TYPE_START 0x10
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun static int qmi_encode(struct qmi_elem_info *ei_array, void *out_buf,
61*4882a593Smuzhiyun const void *in_c_struct, u32 out_buf_len,
62*4882a593Smuzhiyun int enc_level);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
65*4882a593Smuzhiyun const void *in_buf, u32 in_buf_len, int dec_level);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /**
68*4882a593Smuzhiyun * skip_to_next_elem() - Skip to next element in the structure to be encoded
69*4882a593Smuzhiyun * @ei_array: Struct info describing the element to be skipped.
70*4882a593Smuzhiyun * @level: Depth level of encoding/decoding to identify nested structures.
71*4882a593Smuzhiyun *
72*4882a593Smuzhiyun * This function is used while encoding optional elements. If the flag
73*4882a593Smuzhiyun * corresponding to an optional element is not set, then encoding the
74*4882a593Smuzhiyun * optional element can be skipped. This function can be used to perform
75*4882a593Smuzhiyun * that operation.
76*4882a593Smuzhiyun *
77*4882a593Smuzhiyun * Return: struct info of the next element that can be encoded.
78*4882a593Smuzhiyun */
skip_to_next_elem(struct qmi_elem_info * ei_array,int level)79*4882a593Smuzhiyun static struct qmi_elem_info *skip_to_next_elem(struct qmi_elem_info *ei_array,
80*4882a593Smuzhiyun int level)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun struct qmi_elem_info *temp_ei = ei_array;
83*4882a593Smuzhiyun u8 tlv_type;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (level > 1) {
86*4882a593Smuzhiyun temp_ei = temp_ei + 1;
87*4882a593Smuzhiyun } else {
88*4882a593Smuzhiyun do {
89*4882a593Smuzhiyun tlv_type = temp_ei->tlv_type;
90*4882a593Smuzhiyun temp_ei = temp_ei + 1;
91*4882a593Smuzhiyun } while (tlv_type == temp_ei->tlv_type);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun return temp_ei;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /**
98*4882a593Smuzhiyun * qmi_calc_min_msg_len() - Calculate the minimum length of a QMI message
99*4882a593Smuzhiyun * @ei_array: Struct info array describing the structure.
100*4882a593Smuzhiyun * @level: Level to identify the depth of the nested structures.
101*4882a593Smuzhiyun *
102*4882a593Smuzhiyun * Return: Expected minimum length of the QMI message or 0 on error.
103*4882a593Smuzhiyun */
qmi_calc_min_msg_len(struct qmi_elem_info * ei_array,int level)104*4882a593Smuzhiyun static int qmi_calc_min_msg_len(struct qmi_elem_info *ei_array,
105*4882a593Smuzhiyun int level)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun int min_msg_len = 0;
108*4882a593Smuzhiyun struct qmi_elem_info *temp_ei = ei_array;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun if (!ei_array)
111*4882a593Smuzhiyun return min_msg_len;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun while (temp_ei->data_type != QMI_EOTI) {
114*4882a593Smuzhiyun /* Optional elements do not count in minimum length */
115*4882a593Smuzhiyun if (temp_ei->data_type == QMI_OPT_FLAG) {
116*4882a593Smuzhiyun temp_ei = skip_to_next_elem(temp_ei, level);
117*4882a593Smuzhiyun continue;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun if (temp_ei->data_type == QMI_DATA_LEN) {
121*4882a593Smuzhiyun min_msg_len += (temp_ei->elem_size == sizeof(u8) ?
122*4882a593Smuzhiyun sizeof(u8) : sizeof(u16));
123*4882a593Smuzhiyun temp_ei++;
124*4882a593Smuzhiyun continue;
125*4882a593Smuzhiyun } else if (temp_ei->data_type == QMI_STRUCT) {
126*4882a593Smuzhiyun min_msg_len += qmi_calc_min_msg_len(temp_ei->ei_array,
127*4882a593Smuzhiyun (level + 1));
128*4882a593Smuzhiyun temp_ei++;
129*4882a593Smuzhiyun } else if (temp_ei->data_type == QMI_STRING) {
130*4882a593Smuzhiyun if (level > 1)
131*4882a593Smuzhiyun min_msg_len += temp_ei->elem_len <= U8_MAX ?
132*4882a593Smuzhiyun sizeof(u8) : sizeof(u16);
133*4882a593Smuzhiyun min_msg_len += temp_ei->elem_len * temp_ei->elem_size;
134*4882a593Smuzhiyun temp_ei++;
135*4882a593Smuzhiyun } else {
136*4882a593Smuzhiyun min_msg_len += (temp_ei->elem_len * temp_ei->elem_size);
137*4882a593Smuzhiyun temp_ei++;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /*
141*4882a593Smuzhiyun * Type & Length info. not prepended for elements in the
142*4882a593Smuzhiyun * nested structure.
143*4882a593Smuzhiyun */
144*4882a593Smuzhiyun if (level == 1)
145*4882a593Smuzhiyun min_msg_len += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun return min_msg_len;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun /**
152*4882a593Smuzhiyun * qmi_encode_basic_elem() - Encodes elements of basic/primary data type
153*4882a593Smuzhiyun * @buf_dst: Buffer to store the encoded information.
154*4882a593Smuzhiyun * @buf_src: Buffer containing the elements to be encoded.
155*4882a593Smuzhiyun * @elem_len: Number of elements, in the buf_src, to be encoded.
156*4882a593Smuzhiyun * @elem_size: Size of a single instance of the element to be encoded.
157*4882a593Smuzhiyun *
158*4882a593Smuzhiyun * This function encodes the "elem_len" number of data elements, each of
159*4882a593Smuzhiyun * size "elem_size" bytes from the source buffer "buf_src" and stores the
160*4882a593Smuzhiyun * encoded information in the destination buffer "buf_dst". The elements are
161*4882a593Smuzhiyun * of primary data type which include u8 - u64 or similar. This
162*4882a593Smuzhiyun * function returns the number of bytes of encoded information.
163*4882a593Smuzhiyun *
164*4882a593Smuzhiyun * Return: The number of bytes of encoded information.
165*4882a593Smuzhiyun */
qmi_encode_basic_elem(void * buf_dst,const void * buf_src,u32 elem_len,u32 elem_size)166*4882a593Smuzhiyun static int qmi_encode_basic_elem(void *buf_dst, const void *buf_src,
167*4882a593Smuzhiyun u32 elem_len, u32 elem_size)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun u32 i, rc = 0;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun for (i = 0; i < elem_len; i++) {
172*4882a593Smuzhiyun QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, elem_size);
173*4882a593Smuzhiyun rc += elem_size;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun return rc;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /**
180*4882a593Smuzhiyun * qmi_encode_struct_elem() - Encodes elements of struct data type
181*4882a593Smuzhiyun * @ei_array: Struct info array descibing the struct element.
182*4882a593Smuzhiyun * @buf_dst: Buffer to store the encoded information.
183*4882a593Smuzhiyun * @buf_src: Buffer containing the elements to be encoded.
184*4882a593Smuzhiyun * @elem_len: Number of elements, in the buf_src, to be encoded.
185*4882a593Smuzhiyun * @out_buf_len: Available space in the encode buffer.
186*4882a593Smuzhiyun * @enc_level: Depth of the nested structure from the main structure.
187*4882a593Smuzhiyun *
188*4882a593Smuzhiyun * This function encodes the "elem_len" number of struct elements, each of
189*4882a593Smuzhiyun * size "ei_array->elem_size" bytes from the source buffer "buf_src" and
190*4882a593Smuzhiyun * stores the encoded information in the destination buffer "buf_dst". The
191*4882a593Smuzhiyun * elements are of struct data type which includes any C structure. This
192*4882a593Smuzhiyun * function returns the number of bytes of encoded information.
193*4882a593Smuzhiyun *
194*4882a593Smuzhiyun * Return: The number of bytes of encoded information on success or negative
195*4882a593Smuzhiyun * errno on error.
196*4882a593Smuzhiyun */
qmi_encode_struct_elem(struct qmi_elem_info * ei_array,void * buf_dst,const void * buf_src,u32 elem_len,u32 out_buf_len,int enc_level)197*4882a593Smuzhiyun static int qmi_encode_struct_elem(struct qmi_elem_info *ei_array,
198*4882a593Smuzhiyun void *buf_dst, const void *buf_src,
199*4882a593Smuzhiyun u32 elem_len, u32 out_buf_len,
200*4882a593Smuzhiyun int enc_level)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun int i, rc, encoded_bytes = 0;
203*4882a593Smuzhiyun struct qmi_elem_info *temp_ei = ei_array;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun for (i = 0; i < elem_len; i++) {
206*4882a593Smuzhiyun rc = qmi_encode(temp_ei->ei_array, buf_dst, buf_src,
207*4882a593Smuzhiyun out_buf_len - encoded_bytes, enc_level);
208*4882a593Smuzhiyun if (rc < 0) {
209*4882a593Smuzhiyun pr_err("%s: STRUCT Encode failure\n", __func__);
210*4882a593Smuzhiyun return rc;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun buf_dst = buf_dst + rc;
213*4882a593Smuzhiyun buf_src = buf_src + temp_ei->elem_size;
214*4882a593Smuzhiyun encoded_bytes += rc;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun return encoded_bytes;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun /**
221*4882a593Smuzhiyun * qmi_encode_string_elem() - Encodes elements of string data type
222*4882a593Smuzhiyun * @ei_array: Struct info array descibing the string element.
223*4882a593Smuzhiyun * @buf_dst: Buffer to store the encoded information.
224*4882a593Smuzhiyun * @buf_src: Buffer containing the elements to be encoded.
225*4882a593Smuzhiyun * @out_buf_len: Available space in the encode buffer.
226*4882a593Smuzhiyun * @enc_level: Depth of the string element from the main structure.
227*4882a593Smuzhiyun *
228*4882a593Smuzhiyun * This function encodes a string element of maximum length "ei_array->elem_len"
229*4882a593Smuzhiyun * bytes from the source buffer "buf_src" and stores the encoded information in
230*4882a593Smuzhiyun * the destination buffer "buf_dst". This function returns the number of bytes
231*4882a593Smuzhiyun * of encoded information.
232*4882a593Smuzhiyun *
233*4882a593Smuzhiyun * Return: The number of bytes of encoded information on success or negative
234*4882a593Smuzhiyun * errno on error.
235*4882a593Smuzhiyun */
qmi_encode_string_elem(struct qmi_elem_info * ei_array,void * buf_dst,const void * buf_src,u32 out_buf_len,int enc_level)236*4882a593Smuzhiyun static int qmi_encode_string_elem(struct qmi_elem_info *ei_array,
237*4882a593Smuzhiyun void *buf_dst, const void *buf_src,
238*4882a593Smuzhiyun u32 out_buf_len, int enc_level)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun int rc;
241*4882a593Smuzhiyun int encoded_bytes = 0;
242*4882a593Smuzhiyun struct qmi_elem_info *temp_ei = ei_array;
243*4882a593Smuzhiyun u32 string_len = 0;
244*4882a593Smuzhiyun u32 string_len_sz = 0;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun string_len = strlen(buf_src);
247*4882a593Smuzhiyun string_len_sz = temp_ei->elem_len <= U8_MAX ?
248*4882a593Smuzhiyun sizeof(u8) : sizeof(u16);
249*4882a593Smuzhiyun if (string_len > temp_ei->elem_len) {
250*4882a593Smuzhiyun pr_err("%s: String to be encoded is longer - %d > %d\n",
251*4882a593Smuzhiyun __func__, string_len, temp_ei->elem_len);
252*4882a593Smuzhiyun return -EINVAL;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun if (enc_level == 1) {
256*4882a593Smuzhiyun if (string_len + TLV_LEN_SIZE + TLV_TYPE_SIZE >
257*4882a593Smuzhiyun out_buf_len) {
258*4882a593Smuzhiyun pr_err("%s: Output len %d > Out Buf len %d\n",
259*4882a593Smuzhiyun __func__, string_len, out_buf_len);
260*4882a593Smuzhiyun return -ETOOSMALL;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun } else {
263*4882a593Smuzhiyun if (string_len + string_len_sz > out_buf_len) {
264*4882a593Smuzhiyun pr_err("%s: Output len %d > Out Buf len %d\n",
265*4882a593Smuzhiyun __func__, string_len, out_buf_len);
266*4882a593Smuzhiyun return -ETOOSMALL;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun rc = qmi_encode_basic_elem(buf_dst, &string_len,
269*4882a593Smuzhiyun 1, string_len_sz);
270*4882a593Smuzhiyun encoded_bytes += rc;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun rc = qmi_encode_basic_elem(buf_dst + encoded_bytes, buf_src,
274*4882a593Smuzhiyun string_len, temp_ei->elem_size);
275*4882a593Smuzhiyun encoded_bytes += rc;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun return encoded_bytes;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun /**
281*4882a593Smuzhiyun * qmi_encode() - Core Encode Function
282*4882a593Smuzhiyun * @ei_array: Struct info array describing the structure to be encoded.
283*4882a593Smuzhiyun * @out_buf: Buffer to hold the encoded QMI message.
284*4882a593Smuzhiyun * @in_c_struct: Pointer to the C structure to be encoded.
285*4882a593Smuzhiyun * @out_buf_len: Available space in the encode buffer.
286*4882a593Smuzhiyun * @enc_level: Encode level to indicate the depth of the nested structure,
287*4882a593Smuzhiyun * within the main structure, being encoded.
288*4882a593Smuzhiyun *
289*4882a593Smuzhiyun * Return: The number of bytes of encoded information on success or negative
290*4882a593Smuzhiyun * errno on error.
291*4882a593Smuzhiyun */
qmi_encode(struct qmi_elem_info * ei_array,void * out_buf,const void * in_c_struct,u32 out_buf_len,int enc_level)292*4882a593Smuzhiyun static int qmi_encode(struct qmi_elem_info *ei_array, void *out_buf,
293*4882a593Smuzhiyun const void *in_c_struct, u32 out_buf_len,
294*4882a593Smuzhiyun int enc_level)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun struct qmi_elem_info *temp_ei = ei_array;
297*4882a593Smuzhiyun u8 opt_flag_value = 0;
298*4882a593Smuzhiyun u32 data_len_value = 0, data_len_sz;
299*4882a593Smuzhiyun u8 *buf_dst = (u8 *)out_buf;
300*4882a593Smuzhiyun u8 *tlv_pointer;
301*4882a593Smuzhiyun u32 tlv_len;
302*4882a593Smuzhiyun u8 tlv_type;
303*4882a593Smuzhiyun u32 encoded_bytes = 0;
304*4882a593Smuzhiyun const void *buf_src;
305*4882a593Smuzhiyun int encode_tlv = 0;
306*4882a593Smuzhiyun int rc;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun if (!ei_array)
309*4882a593Smuzhiyun return 0;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun tlv_pointer = buf_dst;
312*4882a593Smuzhiyun tlv_len = 0;
313*4882a593Smuzhiyun if (enc_level == 1)
314*4882a593Smuzhiyun buf_dst = buf_dst + (TLV_LEN_SIZE + TLV_TYPE_SIZE);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun while (temp_ei->data_type != QMI_EOTI) {
317*4882a593Smuzhiyun buf_src = in_c_struct + temp_ei->offset;
318*4882a593Smuzhiyun tlv_type = temp_ei->tlv_type;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (temp_ei->array_type == NO_ARRAY) {
321*4882a593Smuzhiyun data_len_value = 1;
322*4882a593Smuzhiyun } else if (temp_ei->array_type == STATIC_ARRAY) {
323*4882a593Smuzhiyun data_len_value = temp_ei->elem_len;
324*4882a593Smuzhiyun } else if (data_len_value <= 0 ||
325*4882a593Smuzhiyun temp_ei->elem_len < data_len_value) {
326*4882a593Smuzhiyun pr_err("%s: Invalid data length\n", __func__);
327*4882a593Smuzhiyun return -EINVAL;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun switch (temp_ei->data_type) {
331*4882a593Smuzhiyun case QMI_OPT_FLAG:
332*4882a593Smuzhiyun rc = qmi_encode_basic_elem(&opt_flag_value, buf_src,
333*4882a593Smuzhiyun 1, sizeof(u8));
334*4882a593Smuzhiyun if (opt_flag_value)
335*4882a593Smuzhiyun temp_ei = temp_ei + 1;
336*4882a593Smuzhiyun else
337*4882a593Smuzhiyun temp_ei = skip_to_next_elem(temp_ei, enc_level);
338*4882a593Smuzhiyun break;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun case QMI_DATA_LEN:
341*4882a593Smuzhiyun memcpy(&data_len_value, buf_src, temp_ei->elem_size);
342*4882a593Smuzhiyun data_len_sz = temp_ei->elem_size == sizeof(u8) ?
343*4882a593Smuzhiyun sizeof(u8) : sizeof(u16);
344*4882a593Smuzhiyun /* Check to avoid out of range buffer access */
345*4882a593Smuzhiyun if ((data_len_sz + encoded_bytes + TLV_LEN_SIZE +
346*4882a593Smuzhiyun TLV_TYPE_SIZE) > out_buf_len) {
347*4882a593Smuzhiyun pr_err("%s: Too Small Buffer @DATA_LEN\n",
348*4882a593Smuzhiyun __func__);
349*4882a593Smuzhiyun return -ETOOSMALL;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun rc = qmi_encode_basic_elem(buf_dst, &data_len_value,
352*4882a593Smuzhiyun 1, data_len_sz);
353*4882a593Smuzhiyun UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
354*4882a593Smuzhiyun encoded_bytes, tlv_len,
355*4882a593Smuzhiyun encode_tlv, rc);
356*4882a593Smuzhiyun if (!data_len_value)
357*4882a593Smuzhiyun temp_ei = skip_to_next_elem(temp_ei, enc_level);
358*4882a593Smuzhiyun else
359*4882a593Smuzhiyun encode_tlv = 0;
360*4882a593Smuzhiyun break;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun case QMI_UNSIGNED_1_BYTE:
363*4882a593Smuzhiyun case QMI_UNSIGNED_2_BYTE:
364*4882a593Smuzhiyun case QMI_UNSIGNED_4_BYTE:
365*4882a593Smuzhiyun case QMI_UNSIGNED_8_BYTE:
366*4882a593Smuzhiyun case QMI_SIGNED_2_BYTE_ENUM:
367*4882a593Smuzhiyun case QMI_SIGNED_4_BYTE_ENUM:
368*4882a593Smuzhiyun /* Check to avoid out of range buffer access */
369*4882a593Smuzhiyun if (((data_len_value * temp_ei->elem_size) +
370*4882a593Smuzhiyun encoded_bytes + TLV_LEN_SIZE + TLV_TYPE_SIZE) >
371*4882a593Smuzhiyun out_buf_len) {
372*4882a593Smuzhiyun pr_err("%s: Too Small Buffer @data_type:%d\n",
373*4882a593Smuzhiyun __func__, temp_ei->data_type);
374*4882a593Smuzhiyun return -ETOOSMALL;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun rc = qmi_encode_basic_elem(buf_dst, buf_src,
377*4882a593Smuzhiyun data_len_value,
378*4882a593Smuzhiyun temp_ei->elem_size);
379*4882a593Smuzhiyun UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
380*4882a593Smuzhiyun encoded_bytes, tlv_len,
381*4882a593Smuzhiyun encode_tlv, rc);
382*4882a593Smuzhiyun break;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun case QMI_STRUCT:
385*4882a593Smuzhiyun rc = qmi_encode_struct_elem(temp_ei, buf_dst, buf_src,
386*4882a593Smuzhiyun data_len_value,
387*4882a593Smuzhiyun out_buf_len - encoded_bytes,
388*4882a593Smuzhiyun enc_level + 1);
389*4882a593Smuzhiyun if (rc < 0)
390*4882a593Smuzhiyun return rc;
391*4882a593Smuzhiyun UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
392*4882a593Smuzhiyun encoded_bytes, tlv_len,
393*4882a593Smuzhiyun encode_tlv, rc);
394*4882a593Smuzhiyun break;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun case QMI_STRING:
397*4882a593Smuzhiyun rc = qmi_encode_string_elem(temp_ei, buf_dst, buf_src,
398*4882a593Smuzhiyun out_buf_len - encoded_bytes,
399*4882a593Smuzhiyun enc_level);
400*4882a593Smuzhiyun if (rc < 0)
401*4882a593Smuzhiyun return rc;
402*4882a593Smuzhiyun UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
403*4882a593Smuzhiyun encoded_bytes, tlv_len,
404*4882a593Smuzhiyun encode_tlv, rc);
405*4882a593Smuzhiyun break;
406*4882a593Smuzhiyun default:
407*4882a593Smuzhiyun pr_err("%s: Unrecognized data type\n", __func__);
408*4882a593Smuzhiyun return -EINVAL;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun if (encode_tlv && enc_level == 1) {
412*4882a593Smuzhiyun QMI_ENCDEC_ENCODE_TLV(tlv_type, tlv_len, tlv_pointer);
413*4882a593Smuzhiyun encoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
414*4882a593Smuzhiyun tlv_pointer = buf_dst;
415*4882a593Smuzhiyun tlv_len = 0;
416*4882a593Smuzhiyun buf_dst = buf_dst + TLV_LEN_SIZE + TLV_TYPE_SIZE;
417*4882a593Smuzhiyun encode_tlv = 0;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun return encoded_bytes;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun /**
425*4882a593Smuzhiyun * qmi_decode_basic_elem() - Decodes elements of basic/primary data type
426*4882a593Smuzhiyun * @buf_dst: Buffer to store the decoded element.
427*4882a593Smuzhiyun * @buf_src: Buffer containing the elements in QMI wire format.
428*4882a593Smuzhiyun * @elem_len: Number of elements to be decoded.
429*4882a593Smuzhiyun * @elem_size: Size of a single instance of the element to be decoded.
430*4882a593Smuzhiyun *
431*4882a593Smuzhiyun * This function decodes the "elem_len" number of elements in QMI wire format,
432*4882a593Smuzhiyun * each of size "elem_size" bytes from the source buffer "buf_src" and stores
433*4882a593Smuzhiyun * the decoded elements in the destination buffer "buf_dst". The elements are
434*4882a593Smuzhiyun * of primary data type which include u8 - u64 or similar. This
435*4882a593Smuzhiyun * function returns the number of bytes of decoded information.
436*4882a593Smuzhiyun *
437*4882a593Smuzhiyun * Return: The total size of the decoded data elements, in bytes.
438*4882a593Smuzhiyun */
qmi_decode_basic_elem(void * buf_dst,const void * buf_src,u32 elem_len,u32 elem_size)439*4882a593Smuzhiyun static int qmi_decode_basic_elem(void *buf_dst, const void *buf_src,
440*4882a593Smuzhiyun u32 elem_len, u32 elem_size)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun u32 i, rc = 0;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun for (i = 0; i < elem_len; i++) {
445*4882a593Smuzhiyun QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, elem_size);
446*4882a593Smuzhiyun rc += elem_size;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun return rc;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /**
453*4882a593Smuzhiyun * qmi_decode_struct_elem() - Decodes elements of struct data type
454*4882a593Smuzhiyun * @ei_array: Struct info array descibing the struct element.
455*4882a593Smuzhiyun * @buf_dst: Buffer to store the decoded element.
456*4882a593Smuzhiyun * @buf_src: Buffer containing the elements in QMI wire format.
457*4882a593Smuzhiyun * @elem_len: Number of elements to be decoded.
458*4882a593Smuzhiyun * @tlv_len: Total size of the encoded inforation corresponding to
459*4882a593Smuzhiyun * this struct element.
460*4882a593Smuzhiyun * @dec_level: Depth of the nested structure from the main structure.
461*4882a593Smuzhiyun *
462*4882a593Smuzhiyun * This function decodes the "elem_len" number of elements in QMI wire format,
463*4882a593Smuzhiyun * each of size "(tlv_len/elem_len)" bytes from the source buffer "buf_src"
464*4882a593Smuzhiyun * and stores the decoded elements in the destination buffer "buf_dst". The
465*4882a593Smuzhiyun * elements are of struct data type which includes any C structure. This
466*4882a593Smuzhiyun * function returns the number of bytes of decoded information.
467*4882a593Smuzhiyun *
468*4882a593Smuzhiyun * Return: The total size of the decoded data elements on success, negative
469*4882a593Smuzhiyun * errno on error.
470*4882a593Smuzhiyun */
qmi_decode_struct_elem(struct qmi_elem_info * ei_array,void * buf_dst,const void * buf_src,u32 elem_len,u32 tlv_len,int dec_level)471*4882a593Smuzhiyun static int qmi_decode_struct_elem(struct qmi_elem_info *ei_array,
472*4882a593Smuzhiyun void *buf_dst, const void *buf_src,
473*4882a593Smuzhiyun u32 elem_len, u32 tlv_len,
474*4882a593Smuzhiyun int dec_level)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun int i, rc, decoded_bytes = 0;
477*4882a593Smuzhiyun struct qmi_elem_info *temp_ei = ei_array;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun for (i = 0; i < elem_len && decoded_bytes < tlv_len; i++) {
480*4882a593Smuzhiyun rc = qmi_decode(temp_ei->ei_array, buf_dst, buf_src,
481*4882a593Smuzhiyun tlv_len - decoded_bytes, dec_level);
482*4882a593Smuzhiyun if (rc < 0)
483*4882a593Smuzhiyun return rc;
484*4882a593Smuzhiyun buf_src = buf_src + rc;
485*4882a593Smuzhiyun buf_dst = buf_dst + temp_ei->elem_size;
486*4882a593Smuzhiyun decoded_bytes += rc;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun if ((dec_level <= 2 && decoded_bytes != tlv_len) ||
490*4882a593Smuzhiyun (dec_level > 2 && (i < elem_len || decoded_bytes > tlv_len))) {
491*4882a593Smuzhiyun pr_err("%s: Fault in decoding: dl(%d), db(%d), tl(%d), i(%d), el(%d)\n",
492*4882a593Smuzhiyun __func__, dec_level, decoded_bytes, tlv_len,
493*4882a593Smuzhiyun i, elem_len);
494*4882a593Smuzhiyun return -EFAULT;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun return decoded_bytes;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun /**
501*4882a593Smuzhiyun * qmi_decode_string_elem() - Decodes elements of string data type
502*4882a593Smuzhiyun * @ei_array: Struct info array descibing the string element.
503*4882a593Smuzhiyun * @buf_dst: Buffer to store the decoded element.
504*4882a593Smuzhiyun * @buf_src: Buffer containing the elements in QMI wire format.
505*4882a593Smuzhiyun * @tlv_len: Total size of the encoded inforation corresponding to
506*4882a593Smuzhiyun * this string element.
507*4882a593Smuzhiyun * @dec_level: Depth of the string element from the main structure.
508*4882a593Smuzhiyun *
509*4882a593Smuzhiyun * This function decodes the string element of maximum length
510*4882a593Smuzhiyun * "ei_array->elem_len" from the source buffer "buf_src" and puts it into
511*4882a593Smuzhiyun * the destination buffer "buf_dst". This function returns number of bytes
512*4882a593Smuzhiyun * decoded from the input buffer.
513*4882a593Smuzhiyun *
514*4882a593Smuzhiyun * Return: The total size of the decoded data elements on success, negative
515*4882a593Smuzhiyun * errno on error.
516*4882a593Smuzhiyun */
qmi_decode_string_elem(struct qmi_elem_info * ei_array,void * buf_dst,const void * buf_src,u32 tlv_len,int dec_level)517*4882a593Smuzhiyun static int qmi_decode_string_elem(struct qmi_elem_info *ei_array,
518*4882a593Smuzhiyun void *buf_dst, const void *buf_src,
519*4882a593Smuzhiyun u32 tlv_len, int dec_level)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun int rc;
522*4882a593Smuzhiyun int decoded_bytes = 0;
523*4882a593Smuzhiyun u32 string_len = 0;
524*4882a593Smuzhiyun u32 string_len_sz = 0;
525*4882a593Smuzhiyun struct qmi_elem_info *temp_ei = ei_array;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if (dec_level == 1) {
528*4882a593Smuzhiyun string_len = tlv_len;
529*4882a593Smuzhiyun } else {
530*4882a593Smuzhiyun string_len_sz = temp_ei->elem_len <= U8_MAX ?
531*4882a593Smuzhiyun sizeof(u8) : sizeof(u16);
532*4882a593Smuzhiyun rc = qmi_decode_basic_elem(&string_len, buf_src,
533*4882a593Smuzhiyun 1, string_len_sz);
534*4882a593Smuzhiyun decoded_bytes += rc;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun if (string_len > temp_ei->elem_len) {
538*4882a593Smuzhiyun pr_err("%s: String len %d > Max Len %d\n",
539*4882a593Smuzhiyun __func__, string_len, temp_ei->elem_len);
540*4882a593Smuzhiyun return -ETOOSMALL;
541*4882a593Smuzhiyun } else if (string_len > tlv_len) {
542*4882a593Smuzhiyun pr_err("%s: String len %d > Input Buffer Len %d\n",
543*4882a593Smuzhiyun __func__, string_len, tlv_len);
544*4882a593Smuzhiyun return -EFAULT;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun rc = qmi_decode_basic_elem(buf_dst, buf_src + decoded_bytes,
548*4882a593Smuzhiyun string_len, temp_ei->elem_size);
549*4882a593Smuzhiyun *((char *)buf_dst + string_len) = '\0';
550*4882a593Smuzhiyun decoded_bytes += rc;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun return decoded_bytes;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun /**
556*4882a593Smuzhiyun * find_ei() - Find element info corresponding to TLV Type
557*4882a593Smuzhiyun * @ei_array: Struct info array of the message being decoded.
558*4882a593Smuzhiyun * @type: TLV Type of the element being searched.
559*4882a593Smuzhiyun *
560*4882a593Smuzhiyun * Every element that got encoded in the QMI message will have a type
561*4882a593Smuzhiyun * information associated with it. While decoding the QMI message,
562*4882a593Smuzhiyun * this function is used to find the struct info regarding the element
563*4882a593Smuzhiyun * that corresponds to the type being decoded.
564*4882a593Smuzhiyun *
565*4882a593Smuzhiyun * Return: Pointer to struct info, if found
566*4882a593Smuzhiyun */
find_ei(struct qmi_elem_info * ei_array,u32 type)567*4882a593Smuzhiyun static struct qmi_elem_info *find_ei(struct qmi_elem_info *ei_array,
568*4882a593Smuzhiyun u32 type)
569*4882a593Smuzhiyun {
570*4882a593Smuzhiyun struct qmi_elem_info *temp_ei = ei_array;
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun while (temp_ei->data_type != QMI_EOTI) {
573*4882a593Smuzhiyun if (temp_ei->tlv_type == (u8)type)
574*4882a593Smuzhiyun return temp_ei;
575*4882a593Smuzhiyun temp_ei = temp_ei + 1;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun return NULL;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun /**
582*4882a593Smuzhiyun * qmi_decode() - Core Decode Function
583*4882a593Smuzhiyun * @ei_array: Struct info array describing the structure to be decoded.
584*4882a593Smuzhiyun * @out_c_struct: Buffer to hold the decoded C struct
585*4882a593Smuzhiyun * @in_buf: Buffer containing the QMI message to be decoded
586*4882a593Smuzhiyun * @in_buf_len: Length of the QMI message to be decoded
587*4882a593Smuzhiyun * @dec_level: Decode level to indicate the depth of the nested structure,
588*4882a593Smuzhiyun * within the main structure, being decoded
589*4882a593Smuzhiyun *
590*4882a593Smuzhiyun * Return: The number of bytes of decoded information on success, negative
591*4882a593Smuzhiyun * errno on error.
592*4882a593Smuzhiyun */
qmi_decode(struct qmi_elem_info * ei_array,void * out_c_struct,const void * in_buf,u32 in_buf_len,int dec_level)593*4882a593Smuzhiyun static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
594*4882a593Smuzhiyun const void *in_buf, u32 in_buf_len,
595*4882a593Smuzhiyun int dec_level)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun struct qmi_elem_info *temp_ei = ei_array;
598*4882a593Smuzhiyun u8 opt_flag_value = 1;
599*4882a593Smuzhiyun u32 data_len_value = 0, data_len_sz = 0;
600*4882a593Smuzhiyun u8 *buf_dst = out_c_struct;
601*4882a593Smuzhiyun const u8 *tlv_pointer;
602*4882a593Smuzhiyun u32 tlv_len = 0;
603*4882a593Smuzhiyun u32 tlv_type;
604*4882a593Smuzhiyun u32 decoded_bytes = 0;
605*4882a593Smuzhiyun const void *buf_src = in_buf;
606*4882a593Smuzhiyun int rc;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun while (decoded_bytes < in_buf_len) {
609*4882a593Smuzhiyun if (dec_level >= 2 && temp_ei->data_type == QMI_EOTI)
610*4882a593Smuzhiyun return decoded_bytes;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun if (dec_level == 1) {
613*4882a593Smuzhiyun tlv_pointer = buf_src;
614*4882a593Smuzhiyun QMI_ENCDEC_DECODE_TLV(&tlv_type,
615*4882a593Smuzhiyun &tlv_len, tlv_pointer);
616*4882a593Smuzhiyun buf_src += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
617*4882a593Smuzhiyun decoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
618*4882a593Smuzhiyun temp_ei = find_ei(ei_array, tlv_type);
619*4882a593Smuzhiyun if (!temp_ei && tlv_type < OPTIONAL_TLV_TYPE_START) {
620*4882a593Smuzhiyun pr_err("%s: Inval element info\n", __func__);
621*4882a593Smuzhiyun return -EINVAL;
622*4882a593Smuzhiyun } else if (!temp_ei) {
623*4882a593Smuzhiyun UPDATE_DECODE_VARIABLES(buf_src,
624*4882a593Smuzhiyun decoded_bytes, tlv_len);
625*4882a593Smuzhiyun continue;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun } else {
628*4882a593Smuzhiyun /*
629*4882a593Smuzhiyun * No length information for elements in nested
630*4882a593Smuzhiyun * structures. So use remaining decodable buffer space.
631*4882a593Smuzhiyun */
632*4882a593Smuzhiyun tlv_len = in_buf_len - decoded_bytes;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun buf_dst = out_c_struct + temp_ei->offset;
636*4882a593Smuzhiyun if (temp_ei->data_type == QMI_OPT_FLAG) {
637*4882a593Smuzhiyun memcpy(buf_dst, &opt_flag_value, sizeof(u8));
638*4882a593Smuzhiyun temp_ei = temp_ei + 1;
639*4882a593Smuzhiyun buf_dst = out_c_struct + temp_ei->offset;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun if (temp_ei->data_type == QMI_DATA_LEN) {
643*4882a593Smuzhiyun data_len_sz = temp_ei->elem_size == sizeof(u8) ?
644*4882a593Smuzhiyun sizeof(u8) : sizeof(u16);
645*4882a593Smuzhiyun rc = qmi_decode_basic_elem(&data_len_value, buf_src,
646*4882a593Smuzhiyun 1, data_len_sz);
647*4882a593Smuzhiyun memcpy(buf_dst, &data_len_value, sizeof(u32));
648*4882a593Smuzhiyun temp_ei = temp_ei + 1;
649*4882a593Smuzhiyun buf_dst = out_c_struct + temp_ei->offset;
650*4882a593Smuzhiyun tlv_len -= data_len_sz;
651*4882a593Smuzhiyun UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun if (temp_ei->array_type == NO_ARRAY) {
655*4882a593Smuzhiyun data_len_value = 1;
656*4882a593Smuzhiyun } else if (temp_ei->array_type == STATIC_ARRAY) {
657*4882a593Smuzhiyun data_len_value = temp_ei->elem_len;
658*4882a593Smuzhiyun } else if (data_len_value > temp_ei->elem_len) {
659*4882a593Smuzhiyun pr_err("%s: Data len %d > max spec %d\n",
660*4882a593Smuzhiyun __func__, data_len_value, temp_ei->elem_len);
661*4882a593Smuzhiyun return -ETOOSMALL;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun switch (temp_ei->data_type) {
665*4882a593Smuzhiyun case QMI_UNSIGNED_1_BYTE:
666*4882a593Smuzhiyun case QMI_UNSIGNED_2_BYTE:
667*4882a593Smuzhiyun case QMI_UNSIGNED_4_BYTE:
668*4882a593Smuzhiyun case QMI_UNSIGNED_8_BYTE:
669*4882a593Smuzhiyun case QMI_SIGNED_2_BYTE_ENUM:
670*4882a593Smuzhiyun case QMI_SIGNED_4_BYTE_ENUM:
671*4882a593Smuzhiyun rc = qmi_decode_basic_elem(buf_dst, buf_src,
672*4882a593Smuzhiyun data_len_value,
673*4882a593Smuzhiyun temp_ei->elem_size);
674*4882a593Smuzhiyun UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
675*4882a593Smuzhiyun break;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun case QMI_STRUCT:
678*4882a593Smuzhiyun rc = qmi_decode_struct_elem(temp_ei, buf_dst, buf_src,
679*4882a593Smuzhiyun data_len_value, tlv_len,
680*4882a593Smuzhiyun dec_level + 1);
681*4882a593Smuzhiyun if (rc < 0)
682*4882a593Smuzhiyun return rc;
683*4882a593Smuzhiyun UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
684*4882a593Smuzhiyun break;
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun case QMI_STRING:
687*4882a593Smuzhiyun rc = qmi_decode_string_elem(temp_ei, buf_dst, buf_src,
688*4882a593Smuzhiyun tlv_len, dec_level);
689*4882a593Smuzhiyun if (rc < 0)
690*4882a593Smuzhiyun return rc;
691*4882a593Smuzhiyun UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
692*4882a593Smuzhiyun break;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun default:
695*4882a593Smuzhiyun pr_err("%s: Unrecognized data type\n", __func__);
696*4882a593Smuzhiyun return -EINVAL;
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun temp_ei = temp_ei + 1;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun return decoded_bytes;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun /**
705*4882a593Smuzhiyun * qmi_encode_message() - Encode C structure as QMI encoded message
706*4882a593Smuzhiyun * @type: Type of QMI message
707*4882a593Smuzhiyun * @msg_id: Message ID of the message
708*4882a593Smuzhiyun * @len: Passed as max length of the message, updated to actual size
709*4882a593Smuzhiyun * @txn_id: Transaction ID
710*4882a593Smuzhiyun * @ei: QMI message descriptor
711*4882a593Smuzhiyun * @c_struct: Reference to structure to encode
712*4882a593Smuzhiyun *
713*4882a593Smuzhiyun * Return: Buffer with encoded message, or negative ERR_PTR() on error
714*4882a593Smuzhiyun */
qmi_encode_message(int type,unsigned int msg_id,size_t * len,unsigned int txn_id,struct qmi_elem_info * ei,const void * c_struct)715*4882a593Smuzhiyun void *qmi_encode_message(int type, unsigned int msg_id, size_t *len,
716*4882a593Smuzhiyun unsigned int txn_id, struct qmi_elem_info *ei,
717*4882a593Smuzhiyun const void *c_struct)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun struct qmi_header *hdr;
720*4882a593Smuzhiyun ssize_t msglen = 0;
721*4882a593Smuzhiyun void *msg;
722*4882a593Smuzhiyun int ret;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun /* Check the possibility of a zero length QMI message */
725*4882a593Smuzhiyun if (!c_struct) {
726*4882a593Smuzhiyun ret = qmi_calc_min_msg_len(ei, 1);
727*4882a593Smuzhiyun if (ret) {
728*4882a593Smuzhiyun pr_err("%s: Calc. len %d != 0, but NULL c_struct\n",
729*4882a593Smuzhiyun __func__, ret);
730*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun msg = kzalloc(sizeof(*hdr) + *len, GFP_KERNEL);
735*4882a593Smuzhiyun if (!msg)
736*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun /* Encode message, if we have a message */
739*4882a593Smuzhiyun if (c_struct) {
740*4882a593Smuzhiyun msglen = qmi_encode(ei, msg + sizeof(*hdr), c_struct, *len, 1);
741*4882a593Smuzhiyun if (msglen < 0) {
742*4882a593Smuzhiyun kfree(msg);
743*4882a593Smuzhiyun return ERR_PTR(msglen);
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun hdr = msg;
748*4882a593Smuzhiyun hdr->type = type;
749*4882a593Smuzhiyun hdr->txn_id = txn_id;
750*4882a593Smuzhiyun hdr->msg_id = msg_id;
751*4882a593Smuzhiyun hdr->msg_len = msglen;
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun *len = sizeof(*hdr) + msglen;
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun return msg;
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun EXPORT_SYMBOL(qmi_encode_message);
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun /**
760*4882a593Smuzhiyun * qmi_decode_message() - Decode QMI encoded message to C structure
761*4882a593Smuzhiyun * @buf: Buffer with encoded message
762*4882a593Smuzhiyun * @len: Amount of data in @buf
763*4882a593Smuzhiyun * @ei: QMI message descriptor
764*4882a593Smuzhiyun * @c_struct: Reference to structure to decode into
765*4882a593Smuzhiyun *
766*4882a593Smuzhiyun * Return: The number of bytes of decoded information on success, negative
767*4882a593Smuzhiyun * errno on error.
768*4882a593Smuzhiyun */
qmi_decode_message(const void * buf,size_t len,struct qmi_elem_info * ei,void * c_struct)769*4882a593Smuzhiyun int qmi_decode_message(const void *buf, size_t len,
770*4882a593Smuzhiyun struct qmi_elem_info *ei, void *c_struct)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun if (!ei)
773*4882a593Smuzhiyun return -EINVAL;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun if (!c_struct || !buf || !len)
776*4882a593Smuzhiyun return -EINVAL;
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun return qmi_decode(ei, c_struct, buf + sizeof(struct qmi_header),
779*4882a593Smuzhiyun len - sizeof(struct qmi_header), 1);
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun EXPORT_SYMBOL(qmi_decode_message);
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun /* Common header in all QMI responses */
784*4882a593Smuzhiyun struct qmi_elem_info qmi_response_type_v01_ei[] = {
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun .data_type = QMI_SIGNED_2_BYTE_ENUM,
787*4882a593Smuzhiyun .elem_len = 1,
788*4882a593Smuzhiyun .elem_size = sizeof(u16),
789*4882a593Smuzhiyun .array_type = NO_ARRAY,
790*4882a593Smuzhiyun .tlv_type = QMI_COMMON_TLV_TYPE,
791*4882a593Smuzhiyun .offset = offsetof(struct qmi_response_type_v01, result),
792*4882a593Smuzhiyun .ei_array = NULL,
793*4882a593Smuzhiyun },
794*4882a593Smuzhiyun {
795*4882a593Smuzhiyun .data_type = QMI_SIGNED_2_BYTE_ENUM,
796*4882a593Smuzhiyun .elem_len = 1,
797*4882a593Smuzhiyun .elem_size = sizeof(u16),
798*4882a593Smuzhiyun .array_type = NO_ARRAY,
799*4882a593Smuzhiyun .tlv_type = QMI_COMMON_TLV_TYPE,
800*4882a593Smuzhiyun .offset = offsetof(struct qmi_response_type_v01, error),
801*4882a593Smuzhiyun .ei_array = NULL,
802*4882a593Smuzhiyun },
803*4882a593Smuzhiyun {
804*4882a593Smuzhiyun .data_type = QMI_EOTI,
805*4882a593Smuzhiyun .elem_len = 0,
806*4882a593Smuzhiyun .elem_size = 0,
807*4882a593Smuzhiyun .array_type = NO_ARRAY,
808*4882a593Smuzhiyun .tlv_type = QMI_COMMON_TLV_TYPE,
809*4882a593Smuzhiyun .offset = 0,
810*4882a593Smuzhiyun .ei_array = NULL,
811*4882a593Smuzhiyun },
812*4882a593Smuzhiyun };
813*4882a593Smuzhiyun EXPORT_SYMBOL(qmi_response_type_v01_ei);
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun MODULE_DESCRIPTION("QMI encoder/decoder helper");
816*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
817