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

Bluetooth: Fix endian and alignment issue with ath3k version handling

The ath3k driver is treating the version information badly when it
comes to loading the right firmware version and comparing that it
actually matches with the hardware.

Initially this showed up as this:

CHECK drivers/bluetooth/ath3k.c
drivers/bluetooth/ath3k.c:373:17: warning: cast to restricted __le32
drivers/bluetooth/ath3k.c:435:17: warning: cast to restricted __le32

However when fixing this by actually using __packed and __le32 for
the ath3_version structure, more issues came up:

CHECK drivers/bluetooth/ath3k.c
drivers/bluetooth/ath3k.c:381:32: warning: incorrect type in assignment (different base types)
drivers/bluetooth/ath3k.c:381:32: expected restricted __le32 [usertype] rom_version
drivers/bluetooth/ath3k.c:381:32: got int [signed] <noident>
drivers/bluetooth/ath3k.c:382:34: warning: incorrect type in assignment (different base types)
drivers/bluetooth/ath3k.c:382:34: expected restricted __le32 [usertype] build_version
drivers/bluetooth/ath3k.c:382:34: got int [signed] <noident>
drivers/bluetooth/ath3k.c:386:28: warning: restricted __le32 degrades to integer
drivers/bluetooth/ath3k.c:386:56: warning: restricted __le32 degrades to integer

This patch fixes every instance of the firmware version handling and
makes sure it is endian safe and uses proper unaligned access.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>

authored by

Marcel Holtmann and committed by
Johan Hedberg
72dd2b2a d1d588c1

+16 -13
+16 -13
drivers/bluetooth/ath3k.c
··· 27 27 #include <linux/device.h> 28 28 #include <linux/firmware.h> 29 29 #include <linux/usb.h> 30 + #include <asm/unaligned.h> 30 31 #include <net/bluetooth/bluetooth.h> 31 32 32 33 #define VERSION "1.0" ··· 51 50 #define ATH3K_NAME_LEN 0xFF 52 51 53 52 struct ath3k_version { 54 - unsigned int rom_version; 55 - unsigned int build_version; 56 - unsigned int ram_version; 57 - unsigned char ref_clock; 58 - unsigned char reserved[0x07]; 59 - }; 53 + __le32 rom_version; 54 + __le32 build_version; 55 + __le32 ram_version; 56 + __u8 ref_clock; 57 + __u8 reserved[7]; 58 + } __packed; 60 59 61 60 static const struct usb_device_id ath3k_table[] = { 62 61 /* Atheros AR3011 */ ··· 350 349 unsigned char fw_state; 351 350 char filename[ATH3K_NAME_LEN] = {0}; 352 351 const struct firmware *firmware; 353 - struct ath3k_version fw_version, pt_version; 352 + struct ath3k_version fw_version; 353 + __u32 pt_rom_version, pt_build_version; 354 354 int ret; 355 355 356 356 ret = ath3k_get_state(udev, &fw_state); ··· 372 370 } 373 371 374 372 snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu", 375 - le32_to_cpu(fw_version.rom_version)); 373 + le32_to_cpu(fw_version.rom_version)); 376 374 377 375 ret = request_firmware(&firmware, filename, &udev->dev); 378 376 if (ret < 0) { ··· 380 378 return ret; 381 379 } 382 380 383 - pt_version.rom_version = *(int *)(firmware->data + firmware->size - 8); 384 - pt_version.build_version = *(int *) 385 - (firmware->data + firmware->size - 4); 381 + pt_rom_version = get_unaligned_le32(firmware->data + 382 + firmware->size - 8); 383 + pt_build_version = get_unaligned_le32(firmware->data + 384 + firmware->size - 4); 386 385 387 - if ((pt_version.rom_version != fw_version.rom_version) || 388 - (pt_version.build_version <= fw_version.build_version)) { 386 + if (pt_rom_version != le32_to_cpu(fw_version.rom_version) || 387 + pt_build_version <= le32_to_cpu(fw_version.build_version)) { 389 388 BT_ERR("Patch file version did not match with firmware"); 390 389 release_firmware(firmware); 391 390 return -EINVAL;