blob: 40273d0e6a5ea5121b21f483d15916b3dd1f11ef [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
Karthikeyan Ramasubramaniandc4d5632012-11-07 19:42:25 -070028#ifdef CONFIG_QMI_ENCDEC_DEBUG
29
30#define qmi_encdec_dump(prefix_str, buf, buf_len) do { \
31 const u8 *ptr = buf; \
32 int i, linelen, remaining = buf_len; \
33 int rowsize = 16, groupsize = 1; \
34 unsigned char linebuf[256]; \
35 for (i = 0; i < buf_len; i += rowsize) { \
36 linelen = min(remaining, rowsize); \
37 remaining -= linelen; \
38 hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, \
39 linebuf, sizeof(linebuf), false); \
40 pr_debug("%s: %s\n", prefix_str, linebuf); \
41 } \
42} while (0)
43
44#define QMI_ENCODE_LOG_MSG(buf, buf_len) do { \
45 qmi_encdec_dump("QMI_ENCODE_MSG", buf, buf_len); \
46} while (0)
47
48#define QMI_DECODE_LOG_MSG(buf, buf_len) do { \
49 qmi_encdec_dump("QMI_DECODE_MSG", buf, buf_len); \
50} while (0)
51
52#define QMI_ENCODE_LOG_ELEM(level, elem_len, elem_size, buf) do { \
53 pr_debug("QMI_ENCODE_ELEM lvl: %d, len: %d, size: %d\n", \
54 level, elem_len, elem_size); \
55 qmi_encdec_dump("QMI_ENCODE_ELEM", buf, (elem_len * elem_size)); \
56} while (0)
57
58#define QMI_DECODE_LOG_ELEM(level, elem_len, elem_size, buf) do { \
59 pr_debug("QMI_DECODE_ELEM lvl: %d, len: %d, size: %d\n", \
60 level, elem_len, elem_size); \
61 qmi_encdec_dump("QMI_DECODE_ELEM", buf, (elem_len * elem_size)); \
62} while (0)
63
64#define QMI_ENCODE_LOG_TLV(tlv_type, tlv_len) do { \
65 pr_debug("QMI_ENCODE_TLV type: %d, len: %d\n", tlv_type, tlv_len); \
66} while (0)
67
68#define QMI_DECODE_LOG_TLV(tlv_type, tlv_len) do { \
69 pr_debug("QMI_DECODE_TLV type: %d, len: %d\n", tlv_type, tlv_len); \
70} while (0)
71
72#else
73
74#define QMI_ENCODE_LOG_MSG(buf, buf_len) { }
75#define QMI_DECODE_LOG_MSG(buf, buf_len) { }
76#define QMI_ENCODE_LOG_ELEM(level, elem_len, elem_size, buf) { }
77#define QMI_DECODE_LOG_ELEM(level, elem_len, elem_size, buf) { }
78#define QMI_ENCODE_LOG_TLV(tlv_type, tlv_len) { }
79#define QMI_DECODE_LOG_TLV(tlv_type, tlv_len) { }
80
81#endif
82
Karthikeyan Ramasubramaniand9522582012-07-18 19:25:37 -060083static int _qmi_kernel_encode(struct elem_info *ei_array,
84 void *out_buf, void *in_c_struct,
85 int enc_level);
86
87static int _qmi_kernel_decode(struct elem_info *ei_array,
88 void *out_c_struct,
89 void *in_buf, uint32_t in_buf_len,
90 int dec_level);
91
92/**
93 * qmi_kernel_encode() - Encode to QMI message wire format
94 * @desc: Pointer to structure descriptor.
95 * @out_buf: Buffer to hold the encoded QMI message.
96 * @out_buf_len: Length of the out buffer.
97 * @in_c_struct: C Structure to be encoded.
98 *
99 * @return: size of encoded message on success, < 0 for error.
100 */
101int qmi_kernel_encode(struct msg_desc *desc,
102 void *out_buf, uint32_t out_buf_len,
103 void *in_c_struct)
104{
105 int enc_level = 1;
106
107 if (!desc || !desc->ei_array)
108 return -EINVAL;
109
110 if (!out_buf || !in_c_struct)
111 return -EINVAL;
112
113 if (desc->max_msg_len < out_buf_len)
114 return -ETOOSMALL;
115
116 return _qmi_kernel_encode(desc->ei_array, out_buf,
117 in_c_struct, enc_level);
118}
119EXPORT_SYMBOL(qmi_kernel_encode);
120
121/**
122 * qmi_encode_basic_elem() - Encodes elements of basic/primary data type
123 * @buf_dst: Buffer to store the encoded information.
124 * @buf_src: Buffer containing the elements to be encoded.
125 * @elem_len: Number of elements, in the buf_src, to be encoded.
126 * @elem_size: Size of a single instance of the element to be encoded.
127 *
128 * @return: number of bytes of encoded information.
129 *
130 * This function encodes the "elem_len" number of data elements, each of
131 * size "elem_size" bytes from the source buffer "buf_src" and stores the
132 * encoded information in the destination buffer "buf_dst". The elements are
133 * of primary data type which include uint8_t - uint64_t or similar. This
134 * function returns the number of bytes of encoded information.
135 */
136static int qmi_encode_basic_elem(void *buf_dst, void *buf_src,
137 uint32_t elem_len, uint32_t elem_size)
138{
139 uint32_t i, rc = 0;
140
141 for (i = 0; i < elem_len; i++) {
142 QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, elem_size);
143 rc += elem_size;
144 }
145
146 return rc;
147}
148
149/**
150 * qmi_encode_struct_elem() - Encodes elements of struct data type
151 * @ei_array: Struct info array descibing the struct element.
152 * @buf_dst: Buffer to store the encoded information.
153 * @buf_src: Buffer containing the elements to be encoded.
154 * @elem_len: Number of elements, in the buf_src, to be encoded.
155 * @enc_level: Depth of the nested structure from the main structure.
156 *
157 * @return: Mumber of bytes of encoded information, on success.
158 * < 0 on error.
159 *
160 * This function encodes the "elem_len" number of struct elements, each of
161 * size "ei_array->elem_size" bytes from the source buffer "buf_src" and
162 * stores the encoded information in the destination buffer "buf_dst". The
163 * elements are of struct data type which includes any C structure. This
164 * function returns the number of bytes of encoded information.
165 */
166static int qmi_encode_struct_elem(struct elem_info *ei_array,
167 void *buf_dst, void *buf_src,
168 uint32_t elem_len, int enc_level)
169{
170 int i, rc, encoded_bytes = 0;
171 struct elem_info *temp_ei = ei_array;
172
173 for (i = 0; i < elem_len; i++) {
174 rc = _qmi_kernel_encode(temp_ei->ei_array,
175 buf_dst, buf_src, enc_level);
176 if (rc < 0) {
177 pr_err("%s: STRUCT Encode failure\n", __func__);
178 return rc;
179 }
180 buf_dst = buf_dst + rc;
181 buf_src = buf_src + temp_ei->elem_size;
182 encoded_bytes += rc;
183 }
184
185 return encoded_bytes;
186}
187
188/**
189 * skip_to_next_elem() - Skip to next element in the structure to be encoded
190 * @ei_array: Struct info describing the element to be skipped.
191 *
192 * @return: Struct info of the next element that can be encoded.
193 *
194 * This function is used while encoding optional elements. If the flag
195 * corresponding to an optional element is not set, then encoding the
196 * optional element can be skipped. This function can be used to perform
197 * that operation.
198 */
199static struct elem_info *skip_to_next_elem(struct elem_info *ei_array)
200{
201 struct elem_info *temp_ei = ei_array;
202 uint8_t tlv_type;
203
204 do {
205 tlv_type = temp_ei->tlv_type;
206 temp_ei = temp_ei + 1;
207 } while (tlv_type == temp_ei->tlv_type);
208
209 return temp_ei;
210}
211
212/**
213 * _qmi_kernel_encode() - Core Encode Function
214 * @ei_array: Struct info array describing the structure to be encoded.
215 * @out_buf: Buffer to hold the encoded QMI message.
216 * @in_c_struct: Pointer to the C structure to be encoded.
217 * @enc_level: Encode level to indicate the depth of the nested structure,
218 * within the main structure, being encoded.
219 *
220 * @return: Number of bytes of encoded information, on success.
221 * < 0 on error.
222 */
223static int _qmi_kernel_encode(struct elem_info *ei_array,
224 void *out_buf, void *in_c_struct,
225 int enc_level)
226{
227 struct elem_info *temp_ei = ei_array;
228 uint8_t opt_flag_value = 0;
229 uint32_t data_len_value = 0, data_len_sz;
230 uint8_t *buf_dst = (uint8_t *)out_buf;
231 uint8_t *tlv_pointer;
232 uint32_t tlv_len;
233 uint8_t tlv_type;
234 uint32_t encoded_bytes = 0;
235 void *buf_src;
236 int encode_tlv = 0;
237 int rc;
238
239 tlv_pointer = buf_dst;
240 tlv_len = 0;
241 buf_dst = buf_dst + (TLV_LEN_SIZE + TLV_TYPE_SIZE);
242
243 while (temp_ei->data_type != QMI_EOTI) {
244 buf_src = in_c_struct + temp_ei->offset;
245 tlv_type = temp_ei->tlv_type;
246
247 if (temp_ei->is_array == NO_ARRAY) {
248 data_len_value = 1;
249 } else if (temp_ei->is_array == STATIC_ARRAY) {
250 data_len_value = temp_ei->elem_len;
251 } else if (data_len_value <= 0 ||
252 temp_ei->elem_len < data_len_value) {
253 pr_err("%s: Invalid data length\n", __func__);
254 return -EINVAL;
255 }
256
257 switch (temp_ei->data_type) {
258 case QMI_OPT_FLAG:
259 rc = qmi_encode_basic_elem(&opt_flag_value, buf_src,
260 1, sizeof(uint8_t));
261 if (opt_flag_value)
262 temp_ei = temp_ei + 1;
263 else
264 temp_ei = skip_to_next_elem(temp_ei);
265 break;
266
267 case QMI_DATA_LEN:
268 memcpy(&data_len_value, buf_src, temp_ei->elem_size);
269 data_len_sz = temp_ei->elem_size == sizeof(uint8_t) ?
270 sizeof(uint8_t) : sizeof(uint16_t);
271 rc = qmi_encode_basic_elem(buf_dst, &data_len_value,
272 1, data_len_sz);
273 if (data_len_value) {
274 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
275 encoded_bytes, tlv_len, encode_tlv, rc);
276 encode_tlv = 0;
277 } else {
278 temp_ei = skip_to_next_elem(temp_ei);
279 }
280 break;
281
282 case QMI_UNSIGNED_1_BYTE:
283 case QMI_UNSIGNED_2_BYTE:
284 case QMI_UNSIGNED_4_BYTE:
285 case QMI_UNSIGNED_8_BYTE:
286 case QMI_SIGNED_2_BYTE_ENUM:
287 case QMI_SIGNED_4_BYTE_ENUM:
288 rc = qmi_encode_basic_elem(buf_dst, buf_src,
289 data_len_value, temp_ei->elem_size);
Karthikeyan Ramasubramaniandc4d5632012-11-07 19:42:25 -0700290 QMI_ENCODE_LOG_ELEM(enc_level, data_len_value,
291 temp_ei->elem_size, buf_src);
Karthikeyan Ramasubramaniand9522582012-07-18 19:25:37 -0600292 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
293 encoded_bytes, tlv_len, encode_tlv, rc);
294 break;
295
296 case QMI_STRUCT:
297 rc = qmi_encode_struct_elem(temp_ei, buf_dst, buf_src,
298 data_len_value, (enc_level + 1));
299 if (rc < 0)
300 return rc;
301 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
302 encoded_bytes, tlv_len, encode_tlv, rc);
303 break;
304
305 default:
306 pr_err("%s: Unrecognized data type\n", __func__);
307 return -EINVAL;
308
309 }
310
311 if (encode_tlv && enc_level == 1) {
312 QMI_ENCDEC_ENCODE_TLV(tlv_type, tlv_len, tlv_pointer);
Karthikeyan Ramasubramaniandc4d5632012-11-07 19:42:25 -0700313 QMI_ENCODE_LOG_TLV(tlv_type, tlv_len);
Karthikeyan Ramasubramaniand9522582012-07-18 19:25:37 -0600314 encoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
315 tlv_pointer = buf_dst;
316 tlv_len = 0;
317 buf_dst = buf_dst + TLV_LEN_SIZE + TLV_TYPE_SIZE;
318 encode_tlv = 0;
319 }
320 }
Karthikeyan Ramasubramaniandc4d5632012-11-07 19:42:25 -0700321 QMI_ENCODE_LOG_MSG(out_buf, encoded_bytes);
Karthikeyan Ramasubramaniand9522582012-07-18 19:25:37 -0600322 return encoded_bytes;
323}
324
325/**
326 * qmi_kernel_decode() - Decode to C Structure format
327 * @desc: Pointer to structure descriptor.
328 * @out_c_struct: Buffer to hold the decoded C structure.
329 * @in_buf: Buffer containg the QMI message to be decoded.
330 * @in_buf_len: Length of the incoming QMI message.
331 *
332 * @return: 0 on success, < 0 on error.
333 */
334int qmi_kernel_decode(struct msg_desc *desc, void *out_c_struct,
335 void *in_buf, uint32_t in_buf_len)
336{
337 int dec_level = 1;
338 int rc = 0;
339
340 if (!desc || !desc->ei_array)
341 return -EINVAL;
342
343 if (!out_c_struct || !in_buf || !in_buf_len)
344 return -EINVAL;
345
346 if (desc->max_msg_len < in_buf_len)
347 return -EINVAL;
348
349 rc = _qmi_kernel_decode(desc->ei_array, out_c_struct,
350 in_buf, in_buf_len, dec_level);
351 if (rc < 0)
352 return rc;
353 else
354 return 0;
355}
356EXPORT_SYMBOL(qmi_kernel_decode);
357
358/**
359 * qmi_decode_basic_elem() - Decodes elements of basic/primary data type
360 * @buf_dst: Buffer to store the decoded element.
361 * @buf_src: Buffer containing the elements in QMI wire format.
362 * @elem_len: Number of elements to be decoded.
363 * @elem_size: Size of a single instance of the element to be decoded.
364 *
365 * @return: Total size of the decoded data elements, in bytes.
366 *
367 * This function decodes the "elem_len" number of elements in QMI wire format,
368 * each of size "elem_size" bytes from the source buffer "buf_src" and stores
369 * the decoded elements in the destination buffer "buf_dst". The elements are
370 * of primary data type which include uint8_t - uint64_t or similar. This
371 * function returns the number of bytes of decoded information.
372 */
373static int qmi_decode_basic_elem(void *buf_dst, void *buf_src,
374 uint32_t elem_len, uint32_t elem_size)
375{
376 uint32_t i, rc = 0;
377
378 for (i = 0; i < elem_len; i++) {
379 QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, elem_size);
380 rc += elem_size;
381 }
382
383 return rc;
384}
385
386/**
387 * qmi_decode_struct_elem() - Decodes elements of struct data type
388 * @ei_array: Struct info array descibing the struct element.
389 * @buf_dst: Buffer to store the decoded element.
390 * @buf_src: Buffer containing the elements in QMI wire format.
391 * @elem_len: Number of elements to be decoded.
392 * @tlv_len: Total size of the encoded inforation corresponding to
393 * this struct element.
394 * @dec_level: Depth of the nested structure from the main structure.
395 *
396 * @return: Total size of the decoded data elements, on success.
397 * < 0 on error.
398 *
399 * This function decodes the "elem_len" number of elements in QMI wire format,
400 * each of size "(tlv_len/elem_len)" bytes from the source buffer "buf_src"
401 * and stores the decoded elements in the destination buffer "buf_dst". The
402 * elements are of struct data type which includes any C structure. This
403 * function returns the number of bytes of decoded information.
404 */
405static int qmi_decode_struct_elem(struct elem_info *ei_array, void *buf_dst,
406 void *buf_src, uint32_t elem_len,
407 uint32_t tlv_len, int dec_level)
408{
409 int i, rc, decoded_bytes = 0;
410 struct elem_info *temp_ei = ei_array;
411
412 for (i = 0; i < elem_len; i++) {
413 rc = _qmi_kernel_decode(temp_ei->ei_array, buf_dst, buf_src,
414 (tlv_len/elem_len), dec_level);
415 if (rc < 0)
416 return rc;
417 if (rc != (tlv_len/elem_len)) {
418 pr_err("%s: Fault in decoding\n", __func__);
419 return -EFAULT;
420 }
421 buf_src = buf_src + rc;
422 buf_dst = buf_dst + temp_ei->elem_size;
423 decoded_bytes += rc;
424 }
425
426 return decoded_bytes;
427}
428
429/**
430 * find_ei() - Find element info corresponding to TLV Type
431 * @ei_array: Struct info array of the message being decoded.
432 * @type: TLV Type of the element being searched.
433 *
434 * @return: Pointer to struct info, if found
435 *
436 * Every element that got encoded in the QMI message will have a type
437 * information associated with it. While decoding the QMI message,
438 * this function is used to find the struct info regarding the element
439 * that corresponds to the type being decoded.
440 */
441static struct elem_info *find_ei(struct elem_info *ei_array,
442 uint32_t type)
443{
444 struct elem_info *temp_ei = ei_array;
445 while (temp_ei->data_type != QMI_EOTI) {
446 if (temp_ei->tlv_type == (uint8_t)type)
447 return temp_ei;
448 temp_ei = temp_ei + 1;
449 }
450 return NULL;
451}
452
453/**
454 * _qmi_kernel_decode() - Core Decode Function
455 * @ei_array: Struct info array describing the structure to be decoded.
456 * @out_c_struct: Buffer to hold the decoded C struct
457 * @in_buf: Buffer containing the QMI message to be decoded
458 * @in_buf_len: Length of the QMI message to be decoded
459 * @dec_level: Decode level to indicate the depth of the nested structure,
460 * within the main structure, being decoded
461 *
462 * @return: Number of bytes of decoded information, on success
463 * < 0 on error.
464 */
465static int _qmi_kernel_decode(struct elem_info *ei_array,
466 void *out_c_struct,
467 void *in_buf, uint32_t in_buf_len,
468 int dec_level)
469{
470 struct elem_info *temp_ei = ei_array;
471 uint8_t opt_flag_value = 1;
472 uint32_t data_len_value = 0, data_len_sz = 0;
473 uint8_t *buf_dst = out_c_struct;
474 uint8_t *tlv_pointer;
475 uint32_t tlv_len = 0;
476 uint32_t tlv_type;
477 uint32_t decoded_bytes = 0;
478 void *buf_src = in_buf;
479 int rc;
480
Karthikeyan Ramasubramaniandc4d5632012-11-07 19:42:25 -0700481 QMI_DECODE_LOG_MSG(in_buf, in_buf_len);
Karthikeyan Ramasubramaniand9522582012-07-18 19:25:37 -0600482 while (decoded_bytes < in_buf_len) {
483 if (dec_level == 1) {
484 tlv_pointer = buf_src;
485 QMI_ENCDEC_DECODE_TLV(&tlv_type,
486 &tlv_len, tlv_pointer);
Karthikeyan Ramasubramaniandc4d5632012-11-07 19:42:25 -0700487 QMI_DECODE_LOG_TLV(tlv_type, tlv_len);
Karthikeyan Ramasubramaniand9522582012-07-18 19:25:37 -0600488 buf_src += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
489 decoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
490 temp_ei = find_ei(ei_array, tlv_type);
491 if (!temp_ei) {
492 pr_err("%s: Inval element info\n", __func__);
493 return -EINVAL;
494 }
495 }
496
497 buf_dst = out_c_struct + temp_ei->offset;
498 if (temp_ei->data_type == QMI_OPT_FLAG) {
499 memcpy(buf_dst, &opt_flag_value, sizeof(uint8_t));
500 temp_ei = temp_ei + 1;
501 buf_dst = out_c_struct + temp_ei->offset;
502 }
503
504 if (temp_ei->data_type == QMI_DATA_LEN) {
505 data_len_sz = temp_ei->elem_size == sizeof(uint8_t) ?
506 sizeof(uint8_t) : sizeof(uint16_t);
507 rc = qmi_decode_basic_elem(&data_len_value, buf_src,
508 1, data_len_sz);
509 memcpy(buf_dst, &data_len_value, sizeof(uint32_t));
510 temp_ei = temp_ei + 1;
511 buf_dst = out_c_struct + temp_ei->offset;
512 UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
513 }
514
515 if (temp_ei->is_array == NO_ARRAY) {
516 data_len_value = 1;
517 } else if (temp_ei->is_array == STATIC_ARRAY) {
518 data_len_value = temp_ei->elem_len;
519 } else if (data_len_value > temp_ei->elem_len) {
520 pr_err("%s: Data len %d > max spec %d\n",
521 __func__, data_len_value, temp_ei->elem_len);
522 return -ETOOSMALL;
523 }
524
525 switch (temp_ei->data_type) {
526 case QMI_UNSIGNED_1_BYTE:
527 case QMI_UNSIGNED_2_BYTE:
528 case QMI_UNSIGNED_4_BYTE:
529 case QMI_UNSIGNED_8_BYTE:
530 case QMI_SIGNED_2_BYTE_ENUM:
531 case QMI_SIGNED_4_BYTE_ENUM:
532 rc = qmi_decode_basic_elem(buf_dst, buf_src,
533 data_len_value, temp_ei->elem_size);
Karthikeyan Ramasubramaniandc4d5632012-11-07 19:42:25 -0700534 QMI_DECODE_LOG_ELEM(dec_level, data_len_value,
535 temp_ei->elem_size, buf_dst);
Karthikeyan Ramasubramaniand9522582012-07-18 19:25:37 -0600536 UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
537 break;
538
539 case QMI_STRUCT:
540 rc = qmi_decode_struct_elem(temp_ei, buf_dst, buf_src,
541 data_len_value, tlv_len, (dec_level + 1));
542 if (rc < 0)
543 return rc;
544 UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
545 break;
546 default:
547 pr_err("%s: Unrecognized data type\n", __func__);
548 return -EINVAL;
549 }
550 temp_ei = temp_ei + 1;
551 }
552 return decoded_bytes;
553}
554MODULE_DESCRIPTION("QMI kernel enc/dec");
555MODULE_LICENSE("GPL v2");