Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc: qcom: QMI encoding/decoding for big endian

The QMI_DATA_LEN type may have different sizes. Taking the element's
address of that type and interpret it as a smaller sized ones works fine
for little endian platforms but not for big endian ones. Instead use
temporary variables of smaller sized types and cast them correctly to
support big endian platforms.

Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>
Fixes: 9b8a11e82615 ("soc: qcom: Introduce QMI encoder/decoder")
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20250522143530.3623809-2-alexander.wilhelm@westermo.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>

authored by

Alexander Wilhelm and committed by
Bjorn Andersson
3ced38da b0123a8a

+38 -8
+38 -8
drivers/soc/qcom/qmi_encdec.c
··· 304 304 const void *buf_src; 305 305 int encode_tlv = 0; 306 306 int rc; 307 + u8 val8; 308 + u16 val16; 307 309 308 310 if (!ei_array) 309 311 return 0; ··· 340 338 break; 341 339 342 340 case QMI_DATA_LEN: 343 - memcpy(&data_len_value, buf_src, temp_ei->elem_size); 344 341 data_len_sz = temp_ei->elem_size == sizeof(u8) ? 345 342 sizeof(u8) : sizeof(u16); 346 343 /* Check to avoid out of range buffer access */ ··· 349 348 __func__); 350 349 return -ETOOSMALL; 351 350 } 352 - rc = qmi_encode_basic_elem(buf_dst, &data_len_value, 353 - 1, data_len_sz); 351 + if (data_len_sz == sizeof(u8)) { 352 + val8 = *(u8 *)buf_src; 353 + data_len_value = (u32)val8; 354 + rc = qmi_encode_basic_elem(buf_dst, &val8, 355 + 1, data_len_sz); 356 + } else { 357 + val16 = *(u16 *)buf_src; 358 + data_len_value = (u32)le16_to_cpu(val16); 359 + rc = qmi_encode_basic_elem(buf_dst, &val16, 360 + 1, data_len_sz); 361 + } 354 362 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst, 355 363 encoded_bytes, tlv_len, 356 364 encode_tlv, rc); ··· 533 523 u32 string_len = 0; 534 524 u32 string_len_sz = 0; 535 525 const struct qmi_elem_info *temp_ei = ei_array; 526 + u8 val8; 527 + u16 val16; 536 528 537 529 if (dec_level == 1) { 538 530 string_len = tlv_len; 539 531 } else { 540 532 string_len_sz = temp_ei->elem_len <= U8_MAX ? 541 533 sizeof(u8) : sizeof(u16); 542 - rc = qmi_decode_basic_elem(&string_len, buf_src, 543 - 1, string_len_sz); 534 + if (string_len_sz == sizeof(u8)) { 535 + rc = qmi_decode_basic_elem(&val8, buf_src, 536 + 1, string_len_sz); 537 + string_len = (u32)val8; 538 + } else { 539 + rc = qmi_decode_basic_elem(&val16, buf_src, 540 + 1, string_len_sz); 541 + string_len = (u32)val16; 542 + } 544 543 decoded_bytes += rc; 545 544 } 546 545 ··· 623 604 u32 decoded_bytes = 0; 624 605 const void *buf_src = in_buf; 625 606 int rc; 607 + u8 val8; 608 + u16 val16; 609 + u32 val32; 626 610 627 611 while (decoded_bytes < in_buf_len) { 628 612 if (dec_level >= 2 && temp_ei->data_type == QMI_EOTI) ··· 664 642 if (temp_ei->data_type == QMI_DATA_LEN) { 665 643 data_len_sz = temp_ei->elem_size == sizeof(u8) ? 666 644 sizeof(u8) : sizeof(u16); 667 - rc = qmi_decode_basic_elem(&data_len_value, buf_src, 668 - 1, data_len_sz); 669 - memcpy(buf_dst, &data_len_value, sizeof(u32)); 645 + if (data_len_sz == sizeof(u8)) { 646 + rc = qmi_decode_basic_elem(&val8, buf_src, 647 + 1, data_len_sz); 648 + data_len_value = (u32)val8; 649 + } else { 650 + rc = qmi_decode_basic_elem(&val16, buf_src, 651 + 1, data_len_sz); 652 + data_len_value = (u32)val16; 653 + } 654 + val32 = cpu_to_le32(data_len_value); 655 + memcpy(buf_dst, &val32, sizeof(u32)); 670 656 temp_ei = temp_ei + 1; 671 657 buf_dst = out_c_struct + temp_ei->offset; 672 658 tlv_len -= data_len_sz;