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