diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 101 |
1 files changed, 63 insertions, 38 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 3368cfd25a99..22c0149e5d4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1806,12 +1806,21 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
1806 | const u8 *data; | 1806 | const u8 *data; |
1807 | int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp; | 1807 | int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp; |
1808 | u64 alternatives; | 1808 | u64 alternatives; |
1809 | u32 tlv_len; | ||
1810 | enum iwl_ucode_tlv_type tlv_type; | ||
1811 | const u8 *tlv_data; | ||
1812 | int ret = 0; | ||
1809 | 1813 | ||
1810 | if (len < sizeof(*ucode)) | 1814 | if (len < sizeof(*ucode)) { |
1815 | IWL_ERR(priv, "uCode has invalid length: %zd\n", len); | ||
1811 | return -EINVAL; | 1816 | return -EINVAL; |
1817 | } | ||
1812 | 1818 | ||
1813 | if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) | 1819 | if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) { |
1820 | IWL_ERR(priv, "invalid uCode magic: 0X%x\n", | ||
1821 | le32_to_cpu(ucode->magic)); | ||
1814 | return -EINVAL; | 1822 | return -EINVAL; |
1823 | } | ||
1815 | 1824 | ||
1816 | /* | 1825 | /* |
1817 | * Check which alternatives are present, and "downgrade" | 1826 | * Check which alternatives are present, and "downgrade" |
@@ -1836,11 +1845,9 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
1836 | 1845 | ||
1837 | len -= sizeof(*ucode); | 1846 | len -= sizeof(*ucode); |
1838 | 1847 | ||
1839 | while (len >= sizeof(*tlv)) { | 1848 | while (len >= sizeof(*tlv) && !ret) { |
1840 | u32 tlv_len; | ||
1841 | enum iwl_ucode_tlv_type tlv_type; | ||
1842 | u16 tlv_alt; | 1849 | u16 tlv_alt; |
1843 | const u8 *tlv_data; | 1850 | u32 fixed_tlv_size = 4; |
1844 | 1851 | ||
1845 | len -= sizeof(*tlv); | 1852 | len -= sizeof(*tlv); |
1846 | tlv = (void *)data; | 1853 | tlv = (void *)data; |
@@ -1850,8 +1857,11 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
1850 | tlv_alt = le16_to_cpu(tlv->alternative); | 1857 | tlv_alt = le16_to_cpu(tlv->alternative); |
1851 | tlv_data = tlv->data; | 1858 | tlv_data = tlv->data; |
1852 | 1859 | ||
1853 | if (len < tlv_len) | 1860 | if (len < tlv_len) { |
1861 | IWL_ERR(priv, "invalid TLV len: %zd/%u\n", | ||
1862 | len, tlv_len); | ||
1854 | return -EINVAL; | 1863 | return -EINVAL; |
1864 | } | ||
1855 | len -= ALIGN(tlv_len, 4); | 1865 | len -= ALIGN(tlv_len, 4); |
1856 | data += sizeof(*tlv) + ALIGN(tlv_len, 4); | 1866 | data += sizeof(*tlv) + ALIGN(tlv_len, 4); |
1857 | 1867 | ||
@@ -1885,56 +1895,71 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
1885 | pieces->boot_size = tlv_len; | 1895 | pieces->boot_size = tlv_len; |
1886 | break; | 1896 | break; |
1887 | case IWL_UCODE_TLV_PROBE_MAX_LEN: | 1897 | case IWL_UCODE_TLV_PROBE_MAX_LEN: |
1888 | if (tlv_len != 4) | 1898 | if (tlv_len != fixed_tlv_size) |
1889 | return -EINVAL; | 1899 | ret = -EINVAL; |
1890 | capa->max_probe_length = | 1900 | else |
1891 | le32_to_cpup((__le32 *)tlv_data); | 1901 | capa->max_probe_length = |
1902 | le32_to_cpup((__le32 *)tlv_data); | ||
1892 | break; | 1903 | break; |
1893 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: | 1904 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: |
1894 | if (tlv_len != 4) | 1905 | if (tlv_len != fixed_tlv_size) |
1895 | return -EINVAL; | 1906 | ret = -EINVAL; |
1896 | pieces->init_evtlog_ptr = | 1907 | else |
1897 | le32_to_cpup((__le32 *)tlv_data); | 1908 | pieces->init_evtlog_ptr = |
1909 | le32_to_cpup((__le32 *)tlv_data); | ||
1898 | break; | 1910 | break; |
1899 | case IWL_UCODE_TLV_INIT_EVTLOG_SIZE: | 1911 | case IWL_UCODE_TLV_INIT_EVTLOG_SIZE: |
1900 | if (tlv_len != 4) | 1912 | if (tlv_len != fixed_tlv_size) |
1901 | return -EINVAL; | 1913 | ret = -EINVAL; |
1902 | pieces->init_evtlog_size = | 1914 | else |
1903 | le32_to_cpup((__le32 *)tlv_data); | 1915 | pieces->init_evtlog_size = |
1916 | le32_to_cpup((__le32 *)tlv_data); | ||
1904 | break; | 1917 | break; |
1905 | case IWL_UCODE_TLV_INIT_ERRLOG_PTR: | 1918 | case IWL_UCODE_TLV_INIT_ERRLOG_PTR: |
1906 | if (tlv_len != 4) | 1919 | if (tlv_len != fixed_tlv_size) |
1907 | return -EINVAL; | 1920 | ret = -EINVAL; |
1908 | pieces->init_errlog_ptr = | 1921 | else |
1909 | le32_to_cpup((__le32 *)tlv_data); | 1922 | pieces->init_errlog_ptr = |
1923 | le32_to_cpup((__le32 *)tlv_data); | ||
1910 | break; | 1924 | break; |
1911 | case IWL_UCODE_TLV_RUNT_EVTLOG_PTR: | 1925 | case IWL_UCODE_TLV_RUNT_EVTLOG_PTR: |
1912 | if (tlv_len != 4) | 1926 | if (tlv_len != fixed_tlv_size) |
1913 | return -EINVAL; | 1927 | ret = -EINVAL; |
1914 | pieces->inst_evtlog_ptr = | 1928 | else |
1915 | le32_to_cpup((__le32 *)tlv_data); | 1929 | pieces->inst_evtlog_ptr = |
1930 | le32_to_cpup((__le32 *)tlv_data); | ||
1916 | break; | 1931 | break; |
1917 | case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE: | 1932 | case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE: |
1918 | if (tlv_len != 4) | 1933 | if (tlv_len != fixed_tlv_size) |
1919 | return -EINVAL; | 1934 | ret = -EINVAL; |
1920 | pieces->inst_evtlog_size = | 1935 | else |
1921 | le32_to_cpup((__le32 *)tlv_data); | 1936 | pieces->inst_evtlog_size = |
1937 | le32_to_cpup((__le32 *)tlv_data); | ||
1922 | break; | 1938 | break; |
1923 | case IWL_UCODE_TLV_RUNT_ERRLOG_PTR: | 1939 | case IWL_UCODE_TLV_RUNT_ERRLOG_PTR: |
1924 | if (tlv_len != 4) | 1940 | if (tlv_len != fixed_tlv_size) |
1925 | return -EINVAL; | 1941 | ret = -EINVAL; |
1926 | pieces->inst_errlog_ptr = | 1942 | else |
1927 | le32_to_cpup((__le32 *)tlv_data); | 1943 | pieces->inst_errlog_ptr = |
1944 | le32_to_cpup((__le32 *)tlv_data); | ||
1928 | break; | 1945 | break; |
1929 | default: | 1946 | default: |
1947 | IWL_WARN(priv, "unknown TLV: %d\n", tlv_type); | ||
1930 | break; | 1948 | break; |
1931 | } | 1949 | } |
1932 | } | 1950 | } |
1933 | 1951 | ||
1934 | if (len) | 1952 | if (len) { |
1935 | return -EINVAL; | 1953 | IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len); |
1954 | iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len); | ||
1955 | ret = -EINVAL; | ||
1956 | } else if (ret) { | ||
1957 | IWL_ERR(priv, "TLV %d has invalid size: %u\n", | ||
1958 | tlv_type, tlv_len); | ||
1959 | iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)tlv_data, tlv_len); | ||
1960 | } | ||
1936 | 1961 | ||
1937 | return 0; | 1962 | return ret; |
1938 | } | 1963 | } |
1939 | 1964 | ||
1940 | /** | 1965 | /** |