Messages in this thread | | | From | You-Sheng Yang <> | Subject | iwlwifi may wrongly cast a iwl_cfg_trans_params to iwl_cfg | Date | Thu, 21 Jan 2021 21:36:48 +0800 |
| |
Hi,
With an Intel AX201 Wi-Fi [8086:43f0] subsystem [1a56:1652] pcie card, device fails to load firmware with following error messages:
Intel(R) Wireless WiFi driver for Linux iwlwifi 0000:00:14.3: enabling device (0000 -> 0002) iwlwifi 0000:00:14.3: Direct firmware load for (efault)128.ucode failed with error -2 iwlwifi 0000:00:14.3: Direct firmware load for (efault)127.ucode failed with error -2 ... iwlwifi 0000:00:14.3: Direct firmware load for (efault)0.ucode failed with error -2 iwlwifi 0000:00:14.3: no suitable firmware found! iwlwifi 0000:00:14.3: minimum version required: (efault)0 iwlwifi 0000:00:14.3: maximum version supported: (efault)128
This is also reported on some public forums:
* https://askubuntu.com/questions/1297311/ubuntu-20-04-wireless-not-working-for-intel-ax1650i-lenovo-thinkpad * https://www.reddit.com/r/pop_os/comments/jxmnre/wifi_and_bluetooth_issues_in_2010/
In drivers/net/wireless/intel/iwlwifi/pcie/drv.c:
static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, ... {IWL_PCI_DEVICE(0x43F0, PCI_ANY_ID, iwl_qu_long_latency_trans_cfg)}, ... };
The third argument to IWL_PCI_DEVICE macro will be assigned to driver_data field of struct pci_device_id. However, iwl5100_agn_cfg has type struct iwl_cfg, and yet iwl_qu_long_latency_trans_cfg is typed struct iwl_cfg_trans_params.
struct iwl_cfg_trans_params { ... };
struct iwl_cfg { struct iwl_cfg_trans_params trans; const char *name; const char *fw_name_pre; ... };
It's fine to cast a pointer to struct iwl_cfg, but it's not always valid to cast a struct iwl_cfg_trans_params to struct iwl_cfg.
In function iwl_pci_probe, it tries to find an alternative cfg by iterating throughout iwl_dev_info_table, but in our case, [8086:43f0] subsystem [1a56:1652], there will be no match in all of the candidates, and iwl_qu_long_latency_trans_cfg will be assigned as the ultimate struct iwl_cfg, which will be certainly wrong when you're trying to dereference anything beyond sizeof(struct iwl_cfg_trans_params), e.g. cfg->fw_name_pre.
In this case, ((struct iwl_cfg_trans_params*)&iwl_qu_long_latency_trans_cfg)->name will be "'", and ((struct iwl_cfg_trans_params*)&iwl_qu_long_latency_trans_cfg)->fw_name_pre gives "(efault)", pure garbage data.
So is there something missed in the iwl_dev_info_table, or better, just find another solid safe way to handle such trans/cfg mix?
Regards, You-Sheng Yang
| |