blob: d759885bd69067bae47a5bd6af4bf9570c92f2f2 [file] [log] [blame]
Karthikeyan Ramasubramaniand9522582012-07-18 19:25:37 -06001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/slab.h>
15#include <linux/uaccess.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/io.h>
20#include <linux/string.h>
21#include <linux/qmi_encdec.h>
22
23#include "qmi_encdec_priv.h"
24
25#define TLV_LEN_SIZE sizeof(uint16_t)
26#define TLV_TYPE_SIZE sizeof(uint8_t)
27
28static int _qmi_kernel_encode(struct elem_info *ei_array,
29 void *out_buf, void *in_c_struct,
30 int enc_level);
31
32static int _qmi_kernel_decode(struct elem_info *ei_array,
33 void *out_c_struct,
34 void *in_buf, uint32_t in_buf_len,
35 int dec_level);
36
37/**
38 * qmi_kernel_encode() - Encode to QMI message wire format
39 * @desc: Pointer to structure descriptor.
40 * @out_buf: Buffer to hold the encoded QMI message.
41 * @out_buf_len: Length of the out buffer.
42 * @in_c_struct: C Structure to be encoded.
43 *
44 * @return: size of encoded message on success, < 0 for error.
45 */
46int qmi_kernel_encode(struct msg_desc *desc,
47 void *out_buf, uint32_t out_buf_len,
48 void *in_c_struct)
49{
50 int enc_level = 1;
51
52 if (!desc || !desc->ei_array)
53 return -EINVAL;
54
55 if (!out_buf || !in_c_struct)
56 return -EINVAL;
57
58 if (desc->max_msg_len < out_buf_len)
59 return -ETOOSMALL;
60
61 return _qmi_kernel_encode(desc->ei_array, out_buf,
62 in_c_struct, enc_level);
63}
64EXPORT_SYMBOL(qmi_kernel_encode);
65
66/**
67 * qmi_encode_basic_elem() - Encodes elements of basic/primary data type
68 * @buf_dst: Buffer to store the encoded information.
69 * @buf_src: Buffer containing the elements to be encoded.
70 * @elem_len: Number of elements, in the buf_src, to be encoded.
71 * @elem_size: Size of a single instance of the element to be encoded.
72 *
73 * @return: number of bytes of encoded information.
74 *
75 * This function encodes the "elem_len" number of data elements, each of
76 * size "elem_size" bytes from the source buffer "buf_src" and stores the
77 * encoded information in the destination buffer "buf_dst". The elements are
78 * of primary data type which include uint8_t - uint64_t or similar. This
79 * function returns the number of bytes of encoded information.
80 */
81static int qmi_encode_basic_elem(void *buf_dst, void *buf_src,
82 uint32_t elem_len, uint32_t elem_size)
83{
84 uint32_t i, rc = 0;
85
86 for (i = 0; i < elem_len; i++) {
87 QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, elem_size);
88 rc += elem_size;
89 }
90
91 return rc;
92}
93
94/**
95 * qmi_encode_struct_elem() - Encodes elements of struct data type
96 * @ei_array: Struct info array descibing the struct element.
97 * @buf_dst: Buffer to store the encoded information.
98 * @buf_src: Buffer containing the elements to be encoded.
99 * @elem_len: Number of elements, in the buf_src, to be encoded.
100 * @enc_level: Depth of the nested structure from the main structure.
101 *
102 * @return: Mumber of bytes of encoded information, on success.
103 * < 0 on error.
104 *
105 * This function encodes the "elem_len" number of struct elements, each of
106 * size "ei_array->elem_size" bytes from the source buffer "buf_src" and
107 * stores the encoded information in the destination buffer "buf_dst". The
108 * elements are of struct data type which includes any C structure. This
109 * function returns the number of bytes of encoded information.
110 */
111static int qmi_encode_struct_elem(struct elem_info *ei_array,
112 void *buf_dst, void *buf_src,
113 uint32_t elem_len, int enc_level)
114{
115 int i, rc, encoded_bytes = 0;
116 struct elem_info *temp_ei = ei_array;
117
118 for (i = 0; i < elem_len; i++) {
119 rc = _qmi_kernel_encode(temp_ei->ei_array,
120 buf_dst, buf_src, enc_level);
121 if (rc < 0) {
122 pr_err("%s: STRUCT Encode failure\n", __func__);
123 return rc;
124 }
125 buf_dst = buf_dst + rc;
126 buf_src = buf_src + temp_ei->elem_size;
127 encoded_bytes += rc;
128 }
129
130 return encoded_bytes;
131}
132
133/**
134 * skip_to_next_elem() - Skip to next element in the structure to be encoded
135 * @ei_array: Struct info describing the element to be skipped.
136 *
137 * @return: Struct info of the next element that can be encoded.
138 *
139 * This function is used while encoding optional elements. If the flag
140 * corresponding to an optional element is not set, then encoding the
141 * optional element can be skipped. This function can be used to perform
142 * that operation.
143 */
144static struct elem_info *skip_to_next_elem(struct elem_info *ei_array)
145{
146 struct elem_info *temp_ei = ei_array;
147 uint8_t tlv_type;
148
149 do {
150 tlv_type = temp_ei->tlv_type;
151 temp_ei = temp_ei + 1;
152 } while (tlv_type == temp_ei->tlv_type);
153
154 return temp_ei;
155}
156
157/**
158 * _qmi_kernel_encode() - Core Encode Function
159 * @ei_array: Struct info array describing the structure to be encoded.
160 * @out_buf: Buffer to hold the encoded QMI message.
161 * @in_c_struct: Pointer to the C structure to be encoded.
162 * @enc_level: Encode level to indicate the depth of the nested structure,
163 * within the main structure, being encoded.
164 *
165 * @return: Number of bytes of encoded information, on success.
166 * < 0 on error.
167 */
168static int _qmi_kernel_encode(struct elem_info *ei_array,
169 void *out_buf, void *in_c_struct,
170 int enc_level)
171{
172 struct elem_info *temp_ei = ei_array;
173 uint8_t opt_flag_value = 0;
174 uint32_t data_len_value = 0, data_len_sz;
175 uint8_t *buf_dst = (uint8_t *)out_buf;
176 uint8_t *tlv_pointer;
177 uint32_t tlv_len;
178 uint8_t tlv_type;
179 uint32_t encoded_bytes = 0;
180 void *buf_src;
181 int encode_tlv = 0;
182 int rc;
183
184 tlv_pointer = buf_dst;
185 tlv_len = 0;
186 buf_dst = buf_dst + (TLV_LEN_SIZE + TLV_TYPE_SIZE);
187
188 while (temp_ei->data_type != QMI_EOTI) {
189 buf_src = in_c_struct + temp_ei->offset;
190 tlv_type = temp_ei->tlv_type;
191
192 if (temp_ei->is_array == NO_ARRAY) {
193 data_len_value = 1;
194 } else if (temp_ei->is_array == STATIC_ARRAY) {
195 data_len_value = temp_ei->elem_len;
196 } else if (data_len_value <= 0 ||
197 temp_ei->elem_len < data_len_value) {
198 pr_err("%s: Invalid data length\n", __func__);
199 return -EINVAL;
200 }
201
202 switch (temp_ei->data_type) {
203 case QMI_OPT_FLAG:
204 rc = qmi_encode_basic_elem(&opt_flag_value, buf_src,
205 1, sizeof(uint8_t));
206 if (opt_flag_value)
207 temp_ei = temp_ei + 1;
208 else
209 temp_ei = skip_to_next_elem(temp_ei);
210 break;
211
212 case QMI_DATA_LEN:
213 memcpy(&data_len_value, buf_src, temp_ei->elem_size);
214 data_len_sz = temp_ei->elem_size == sizeof(uint8_t) ?
215 sizeof(uint8_t) : sizeof(uint16_t);
216 rc = qmi_encode_basic_elem(buf_dst, &data_len_value,
217 1, data_len_sz);
218 if (data_len_value) {
219 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
220 encoded_bytes, tlv_len, encode_tlv, rc);
221 encode_tlv = 0;
222 } else {
223 temp_ei = skip_to_next_elem(temp_ei);
224 }
225 break;
226
227 case QMI_UNSIGNED_1_BYTE:
228 case QMI_UNSIGNED_2_BYTE:
229 case QMI_UNSIGNED_4_BYTE:
230 case QMI_UNSIGNED_8_BYTE:
231 case QMI_SIGNED_2_BYTE_ENUM:
232 case QMI_SIGNED_4_BYTE_ENUM:
233 rc = qmi_encode_basic_elem(buf_dst, buf_src,
234 data_len_value, temp_ei->elem_size);
235 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
236 encoded_bytes, tlv_len, encode_tlv, rc);
237 break;
238
239 case QMI_STRUCT:
240 rc = qmi_encode_struct_elem(temp_ei, buf_dst, buf_src,
241 data_len_value, (enc_level + 1));
242 if (rc < 0)
243 return rc;
244 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
245 encoded_bytes, tlv_len, encode_tlv, rc);
246 break;
247
248 default:
249 pr_err("%s: Unrecognized data type\n", __func__);
250 return -EINVAL;
251
252 }
253
254 if (encode_tlv && enc_level == 1) {
255 QMI_ENCDEC_ENCODE_TLV(tlv_type, tlv_len, tlv_pointer);
256 encoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
257 tlv_pointer = buf_dst;
258 tlv_len = 0;
259 buf_dst = buf_dst + TLV_LEN_SIZE + TLV_TYPE_SIZE;
260 encode_tlv = 0;
261 }
262 }
263 return encoded_bytes;
264}
265
266/**
267 * qmi_kernel_decode() - Decode to C Structure format
268 * @desc: Pointer to structure descriptor.
269 * @out_c_struct: Buffer to hold the decoded C structure.
270 * @in_buf: Buffer containg the QMI message to be decoded.
271 * @in_buf_len: Length of the incoming QMI message.
272 *
273 * @return: 0 on success, < 0 on error.
274 */
275int qmi_kernel_decode(struct msg_desc *desc, void *out_c_struct,
276 void *in_buf, uint32_t in_buf_len)
277{
278 int dec_level = 1;
279 int rc = 0;
280
281 if (!desc || !desc->ei_array)
282 return -EINVAL;
283
284 if (!out_c_struct || !in_buf || !in_buf_len)
285 return -EINVAL;
286
287 if (desc->max_msg_len < in_buf_len)
288 return -EINVAL;
289
290 rc = _qmi_kernel_decode(desc->ei_array, out_c_struct,
291 in_buf, in_buf_len, dec_level);
292 if (rc < 0)
293 return rc;
294 else
295 return 0;
296}
297EXPORT_SYMBOL(qmi_kernel_decode);
298
299/**
300 * qmi_decode_basic_elem() - Decodes elements of basic/primary data type
301 * @buf_dst: Buffer to store the decoded element.
302 * @buf_src: Buffer containing the elements in QMI wire format.
303 * @elem_len: Number of elements to be decoded.
304 * @elem_size: Size of a single instance of the element to be decoded.
305 *
306 * @return: Total size of the decoded data elements, in bytes.
307 *
308 * This function decodes the "elem_len" number of elements in QMI wire format,
309 * each of size "elem_size" bytes from the source buffer "buf_src" and stores
310 * the decoded elements in the destination buffer "buf_dst". The elements are
311 * of primary data type which include uint8_t - uint64_t or similar. This
312 * function returns the number of bytes of decoded information.
313 */
314static int qmi_decode_basic_elem(void *buf_dst, void *buf_src,
315 uint32_t elem_len, uint32_t elem_size)
316{
317 uint32_t i, rc = 0;
318
319 for (i = 0; i < elem_len; i++) {
320 QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, elem_size);
321 rc += elem_size;
322 }
323
324 return rc;
325}
326
327/**
328 * qmi_decode_struct_elem() - Decodes elements of struct data type
329 * @ei_array: Struct info array descibing the struct element.
330 * @buf_dst: Buffer to store the decoded element.
331 * @buf_src: Buffer containing the elements in QMI wire format.
332 * @elem_len: Number of elements to be decoded.
333 * @tlv_len: Total size of the encoded inforation corresponding to
334 * this struct element.
335 * @dec_level: Depth of the nested structure from the main structure.
336 *
337 * @return: Total size of the decoded data elements, on success.
338 * < 0 on error.
339 *
340 * This function decodes the "elem_len" number of elements in QMI wire format,
341 * each of size "(tlv_len/elem_len)" bytes from the source buffer "buf_src"
342 * and stores the decoded elements in the destination buffer "buf_dst". The
343 * elements are of struct data type which includes any C structure. This
344 * function returns the number of bytes of decoded information.
345 */
346static int qmi_decode_struct_elem(struct elem_info *ei_array, void *buf_dst,
347 void *buf_src, uint32_t elem_len,
348 uint32_t tlv_len, int dec_level)
349{
350 int i, rc, decoded_bytes = 0;
351 struct elem_info *temp_ei = ei_array;
352
353 for (i = 0; i < elem_len; i++) {
354 rc = _qmi_kernel_decode(temp_ei->ei_array, buf_dst, buf_src,
355 (tlv_len/elem_len), dec_level);
356 if (rc < 0)
357 return rc;
358 if (rc != (tlv_len/elem_len)) {
359 pr_err("%s: Fault in decoding\n", __func__);
360 return -EFAULT;
361 }
362 buf_src = buf_src + rc;
363 buf_dst = buf_dst + temp_ei->elem_size;
364 decoded_bytes += rc;
365 }
366
367 return decoded_bytes;
368}
369
370/**
371 * find_ei() - Find element info corresponding to TLV Type
372 * @ei_array: Struct info array of the message being decoded.
373 * @type: TLV Type of the element being searched.
374 *
375 * @return: Pointer to struct info, if found
376 *
377 * Every element that got encoded in the QMI message will have a type
378 * information associated with it. While decoding the QMI message,
379 * this function is used to find the struct info regarding the element
380 * that corresponds to the type being decoded.
381 */
382static struct elem_info *find_ei(struct elem_info *ei_array,
383 uint32_t type)
384{
385 struct elem_info *temp_ei = ei_array;
386 while (temp_ei->data_type != QMI_EOTI) {
387 if (temp_ei->tlv_type == (uint8_t)type)
388 return temp_ei;
389 temp_ei = temp_ei + 1;
390 }
391 return NULL;
392}
393
394/**
395 * _qmi_kernel_decode() - Core Decode Function
396 * @ei_array: Struct info array describing the structure to be decoded.
397 * @out_c_struct: Buffer to hold the decoded C struct
398 * @in_buf: Buffer containing the QMI message to be decoded
399 * @in_buf_len: Length of the QMI message to be decoded
400 * @dec_level: Decode level to indicate the depth of the nested structure,
401 * within the main structure, being decoded
402 *
403 * @return: Number of bytes of decoded information, on success
404 * < 0 on error.
405 */
406static int _qmi_kernel_decode(struct elem_info *ei_array,
407 void *out_c_struct,
408 void *in_buf, uint32_t in_buf_len,
409 int dec_level)
410{
411 struct elem_info *temp_ei = ei_array;
412 uint8_t opt_flag_value = 1;
413 uint32_t data_len_value = 0, data_len_sz = 0;
414 uint8_t *buf_dst = out_c_struct;
415 uint8_t *tlv_pointer;
416 uint32_t tlv_len = 0;
417 uint32_t tlv_type;
418 uint32_t decoded_bytes = 0;
419 void *buf_src = in_buf;
420 int rc;
421
422 while (decoded_bytes < in_buf_len) {
423 if (dec_level == 1) {
424 tlv_pointer = buf_src;
425 QMI_ENCDEC_DECODE_TLV(&tlv_type,
426 &tlv_len, tlv_pointer);
427 buf_src += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
428 decoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
429 temp_ei = find_ei(ei_array, tlv_type);
430 if (!temp_ei) {
431 pr_err("%s: Inval element info\n", __func__);
432 return -EINVAL;
433 }
434 }
435
436 buf_dst = out_c_struct + temp_ei->offset;
437 if (temp_ei->data_type == QMI_OPT_FLAG) {
438 memcpy(buf_dst, &opt_flag_value, sizeof(uint8_t));
439 temp_ei = temp_ei + 1;
440 buf_dst = out_c_struct + temp_ei->offset;
441 }
442
443 if (temp_ei->data_type == QMI_DATA_LEN) {
444 data_len_sz = temp_ei->elem_size == sizeof(uint8_t) ?
445 sizeof(uint8_t) : sizeof(uint16_t);
446 rc = qmi_decode_basic_elem(&data_len_value, buf_src,
447 1, data_len_sz);
448 memcpy(buf_dst, &data_len_value, sizeof(uint32_t));
449 temp_ei = temp_ei + 1;
450 buf_dst = out_c_struct + temp_ei->offset;
451 UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
452 }
453
454 if (temp_ei->is_array == NO_ARRAY) {
455 data_len_value = 1;
456 } else if (temp_ei->is_array == STATIC_ARRAY) {
457 data_len_value = temp_ei->elem_len;
458 } else if (data_len_value > temp_ei->elem_len) {
459 pr_err("%s: Data len %d > max spec %d\n",
460 __func__, data_len_value, temp_ei->elem_len);
461 return -ETOOSMALL;
462 }
463
464 switch (temp_ei->data_type) {
465 case QMI_UNSIGNED_1_BYTE:
466 case QMI_UNSIGNED_2_BYTE:
467 case QMI_UNSIGNED_4_BYTE:
468 case QMI_UNSIGNED_8_BYTE:
469 case QMI_SIGNED_2_BYTE_ENUM:
470 case QMI_SIGNED_4_BYTE_ENUM:
471 rc = qmi_decode_basic_elem(buf_dst, buf_src,
472 data_len_value, temp_ei->elem_size);
473 UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
474 break;
475
476 case QMI_STRUCT:
477 rc = qmi_decode_struct_elem(temp_ei, buf_dst, buf_src,
478 data_len_value, tlv_len, (dec_level + 1));
479 if (rc < 0)
480 return rc;
481 UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
482 break;
483 default:
484 pr_err("%s: Unrecognized data type\n", __func__);
485 return -EINVAL;
486 }
487 temp_ei = temp_ei + 1;
488 }
489 return decoded_bytes;
490}
491MODULE_DESCRIPTION("QMI kernel enc/dec");
492MODULE_LICENSE("GPL v2");