diff options
| author | Ivo van Doorn <ivdoorn@gmail.com> | 2009-01-27 18:33:47 -0500 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2009-02-09 15:03:35 -0500 |
| commit | 0cbe0064614ace61e08618948f82c6d525e75017 (patch) | |
| tree | dc6f68d5da42ab6ada2fab2bd4e5fecfa6f1ed8c | |
| parent | a2c9b652a12a550d3d8509e9bae43bac396c5076 (diff) | |
rt2x00: Validate firmware in driver
The get_firmware_crc() callback function isn't flexible
enough when dealing with multiple firmware versions.
It might in some cases be possible that the firmware
file contains multiple CRC checksums.
Create the check_firmware() callback function where the driver
has complete freedom in how to validate the firmware.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00.h | 7 | ||||
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00firmware.c | 27 | ||||
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00reg.h | 10 | ||||
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt61pci.c | 29 | ||||
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt73usb.c | 29 |
5 files changed, 68 insertions, 34 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 94fb571667f..84bd6f19acb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
| @@ -468,9 +468,10 @@ struct rt2x00lib_ops { | |||
| 468 | */ | 468 | */ |
| 469 | int (*probe_hw) (struct rt2x00_dev *rt2x00dev); | 469 | int (*probe_hw) (struct rt2x00_dev *rt2x00dev); |
| 470 | char *(*get_firmware_name) (struct rt2x00_dev *rt2x00dev); | 470 | char *(*get_firmware_name) (struct rt2x00_dev *rt2x00dev); |
| 471 | u16 (*get_firmware_crc) (const void *data, const size_t len); | 471 | int (*check_firmware) (struct rt2x00_dev *rt2x00dev, |
| 472 | int (*load_firmware) (struct rt2x00_dev *rt2x00dev, const void *data, | 472 | const u8 *data, const size_t len); |
| 473 | const size_t len); | 473 | int (*load_firmware) (struct rt2x00_dev *rt2x00dev, |
| 474 | const u8 *data, const size_t len); | ||
| 474 | 475 | ||
| 475 | /* | 476 | /* |
| 476 | * Device initialization/deinitialization handlers. | 477 | * Device initialization/deinitialization handlers. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index 2a7e8bc0016..d2deea2f267 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c | |||
| @@ -35,7 +35,6 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev) | |||
| 35 | const struct firmware *fw; | 35 | const struct firmware *fw; |
| 36 | char *fw_name; | 36 | char *fw_name; |
| 37 | int retval; | 37 | int retval; |
| 38 | u16 crc; | ||
| 39 | 38 | ||
| 40 | /* | 39 | /* |
| 41 | * Read correct firmware from harddisk. | 40 | * Read correct firmware from harddisk. |
| @@ -61,16 +60,26 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev) | |||
| 61 | return -ENOENT; | 60 | return -ENOENT; |
| 62 | } | 61 | } |
| 63 | 62 | ||
| 64 | crc = rt2x00dev->ops->lib->get_firmware_crc(fw->data, fw->size); | ||
| 65 | if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) { | ||
| 66 | ERROR(rt2x00dev, "Firmware checksum error.\n"); | ||
| 67 | retval = -ENOENT; | ||
| 68 | goto exit; | ||
| 69 | } | ||
| 70 | |||
| 71 | INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n", | 63 | INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n", |
| 72 | fw->data[fw->size - 4], fw->data[fw->size - 3]); | 64 | fw->data[fw->size - 4], fw->data[fw->size - 3]); |
| 73 | 65 | ||
| 66 | retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, fw->data, fw->size); | ||
| 67 | switch (retval) { | ||
| 68 | case FW_OK: | ||
| 69 | break; | ||
| 70 | case FW_BAD_CRC: | ||
| 71 | ERROR(rt2x00dev, "Firmware checksum error.\n"); | ||
| 72 | goto exit; | ||
| 73 | case FW_BAD_LENGTH: | ||
| 74 | ERROR(rt2x00dev, | ||
| 75 | "Invalid firmware file length (len=%zu)\n", fw->size); | ||
| 76 | goto exit; | ||
| 77 | case FW_BAD_VERSION: | ||
| 78 | ERROR(rt2x00dev, | ||
| 79 | "Current firmware does not support detected chipset.\n"); | ||
| 80 | goto exit; | ||
| 81 | }; | ||
| 82 | |||
| 74 | rt2x00dev->fw = fw; | 83 | rt2x00dev->fw = fw; |
| 75 | 84 | ||
| 76 | return 0; | 85 | return 0; |
| @@ -78,7 +87,7 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev) | |||
| 78 | exit: | 87 | exit: |
| 79 | release_firmware(fw); | 88 | release_firmware(fw); |
| 80 | 89 | ||
| 81 | return retval; | 90 | return -ENOENT; |
| 82 | } | 91 | } |
| 83 | 92 | ||
| 84 | int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) | 93 | int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) |
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 9ddc2d07eef..861322d97fc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h | |||
| @@ -135,6 +135,16 @@ enum rate_modulation { | |||
| 135 | }; | 135 | }; |
| 136 | 136 | ||
| 137 | /* | 137 | /* |
| 138 | * Firmware validation error codes | ||
| 139 | */ | ||
| 140 | enum firmware_errors { | ||
| 141 | FW_OK, | ||
| 142 | FW_BAD_CRC, | ||
| 143 | FW_BAD_LENGTH, | ||
| 144 | FW_BAD_VERSION, | ||
| 145 | }; | ||
| 146 | |||
| 147 | /* | ||
| 138 | * Register handlers. | 148 | * Register handlers. |
| 139 | * We store the position of a register field inside a field structure, | 149 | * We store the position of a register field inside a field structure, |
| 140 | * This will simplify the process of setting and reading a certain field | 150 | * This will simplify the process of setting and reading a certain field |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index c7ad1b3d476..0be147f364e 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
| @@ -1176,34 +1176,41 @@ static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) | |||
| 1176 | return fw_name; | 1176 | return fw_name; |
| 1177 | } | 1177 | } |
| 1178 | 1178 | ||
| 1179 | static u16 rt61pci_get_firmware_crc(const void *data, const size_t len) | 1179 | static int rt61pci_check_firmware(struct rt2x00_dev *rt2x00dev, |
| 1180 | const u8 *data, const size_t len) | ||
| 1180 | { | 1181 | { |
| 1182 | u16 fw_crc; | ||
| 1181 | u16 crc; | 1183 | u16 crc; |
| 1182 | 1184 | ||
| 1183 | /* | 1185 | /* |
| 1184 | * Use the crc itu-t algorithm. | 1186 | * Only support 8kb firmware files. |
| 1187 | */ | ||
| 1188 | if (len != 8192) | ||
| 1189 | return FW_BAD_LENGTH; | ||
| 1190 | |||
| 1191 | /* | ||
| 1185 | * The last 2 bytes in the firmware array are the crc checksum itself, | 1192 | * The last 2 bytes in the firmware array are the crc checksum itself, |
| 1186 | * this means that we should never pass those 2 bytes to the crc | 1193 | * this means that we should never pass those 2 bytes to the crc |
| 1187 | * algorithm. | 1194 | * algorithm. |
| 1188 | */ | 1195 | */ |
| 1196 | fw_crc = (data[len - 2] << 8 | data[len - 1]); | ||
| 1197 | |||
| 1198 | /* | ||
| 1199 | * Use the crc itu-t algorithm. | ||
| 1200 | */ | ||
| 1189 | crc = crc_itu_t(0, data, len - 2); | 1201 | crc = crc_itu_t(0, data, len - 2); |
| 1190 | crc = crc_itu_t_byte(crc, 0); | 1202 | crc = crc_itu_t_byte(crc, 0); |
| 1191 | crc = crc_itu_t_byte(crc, 0); | 1203 | crc = crc_itu_t_byte(crc, 0); |
| 1192 | 1204 | ||
| 1193 | return crc; | 1205 | return (fw_crc == crc) ? FW_OK : FW_BAD_CRC; |
| 1194 | } | 1206 | } |
| 1195 | 1207 | ||
| 1196 | static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, | 1208 | static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, |
| 1197 | const size_t len) | 1209 | const u8 *data, const size_t len) |
| 1198 | { | 1210 | { |
| 1199 | int i; | 1211 | int i; |
| 1200 | u32 reg; | 1212 | u32 reg; |
| 1201 | 1213 | ||
| 1202 | if (len != 8192) { | ||
| 1203 | ERROR(rt2x00dev, "Invalid firmware file length (len=%zu)\n", len); | ||
| 1204 | return -ENOENT; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | /* | 1214 | /* |
| 1208 | * Wait for stable hardware. | 1215 | * Wait for stable hardware. |
| 1209 | */ | 1216 | */ |
| @@ -2750,7 +2757,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { | |||
| 2750 | .irq_handler = rt61pci_interrupt, | 2757 | .irq_handler = rt61pci_interrupt, |
| 2751 | .probe_hw = rt61pci_probe_hw, | 2758 | .probe_hw = rt61pci_probe_hw, |
| 2752 | .get_firmware_name = rt61pci_get_firmware_name, | 2759 | .get_firmware_name = rt61pci_get_firmware_name, |
| 2753 | .get_firmware_crc = rt61pci_get_firmware_crc, | 2760 | .check_firmware = rt61pci_check_firmware, |
| 2754 | .load_firmware = rt61pci_load_firmware, | 2761 | .load_firmware = rt61pci_load_firmware, |
| 2755 | .initialize = rt2x00pci_initialize, | 2762 | .initialize = rt2x00pci_initialize, |
| 2756 | .uninitialize = rt2x00pci_uninitialize, | 2763 | .uninitialize = rt2x00pci_uninitialize, |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 24e97b341cf..be791a43c05 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
| @@ -1061,35 +1061,42 @@ static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev) | |||
| 1061 | return FIRMWARE_RT2571; | 1061 | return FIRMWARE_RT2571; |
| 1062 | } | 1062 | } |
| 1063 | 1063 | ||
| 1064 | static u16 rt73usb_get_firmware_crc(const void *data, const size_t len) | 1064 | static int rt73usb_check_firmware(struct rt2x00_dev *rt2x00dev, |
| 1065 | const u8 *data, const size_t len) | ||
| 1065 | { | 1066 | { |
| 1067 | u16 fw_crc; | ||
| 1066 | u16 crc; | 1068 | u16 crc; |
| 1067 | 1069 | ||
| 1068 | /* | 1070 | /* |
| 1069 | * Use the crc itu-t algorithm. | 1071 | * Only support 2kb firmware files. |
| 1072 | */ | ||
| 1073 | if (len != 2048) | ||
| 1074 | return FW_BAD_LENGTH; | ||
| 1075 | |||
| 1076 | /* | ||
| 1070 | * The last 2 bytes in the firmware array are the crc checksum itself, | 1077 | * The last 2 bytes in the firmware array are the crc checksum itself, |
| 1071 | * this means that we should never pass those 2 bytes to the crc | 1078 | * this means that we should never pass those 2 bytes to the crc |
| 1072 | * algorithm. | 1079 | * algorithm. |
| 1073 | */ | 1080 | */ |
| 1081 | fw_crc = (data[len - 2] << 8 | data[len - 1]); | ||
| 1082 | |||
| 1083 | /* | ||
| 1084 | * Use the crc itu-t algorithm. | ||
| 1085 | */ | ||
| 1074 | crc = crc_itu_t(0, data, len - 2); | 1086 | crc = crc_itu_t(0, data, len - 2); |
| 1075 | crc = crc_itu_t_byte(crc, 0); | 1087 | crc = crc_itu_t_byte(crc, 0); |
| 1076 | crc = crc_itu_t_byte(crc, 0); | 1088 | crc = crc_itu_t_byte(crc, 0); |
| 1077 | 1089 | ||
| 1078 | return crc; | 1090 | return (fw_crc == crc) ? FW_OK : FW_BAD_CRC; |
| 1079 | } | 1091 | } |
| 1080 | 1092 | ||
| 1081 | static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, | 1093 | static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, |
| 1082 | const size_t len) | 1094 | const u8 *data, const size_t len) |
| 1083 | { | 1095 | { |
| 1084 | unsigned int i; | 1096 | unsigned int i; |
| 1085 | int status; | 1097 | int status; |
| 1086 | u32 reg; | 1098 | u32 reg; |
| 1087 | 1099 | ||
| 1088 | if (len != 2048) { | ||
| 1089 | ERROR(rt2x00dev, "Invalid firmware file length (len=%zu)\n", len); | ||
| 1090 | return -ENOENT; | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | /* | 1100 | /* |
| 1094 | * Wait for stable hardware. | 1101 | * Wait for stable hardware. |
| 1095 | */ | 1102 | */ |
| @@ -2278,7 +2285,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { | |||
| 2278 | static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { | 2285 | static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { |
| 2279 | .probe_hw = rt73usb_probe_hw, | 2286 | .probe_hw = rt73usb_probe_hw, |
| 2280 | .get_firmware_name = rt73usb_get_firmware_name, | 2287 | .get_firmware_name = rt73usb_get_firmware_name, |
| 2281 | .get_firmware_crc = rt73usb_get_firmware_crc, | 2288 | .check_firmware = rt73usb_check_firmware, |
| 2282 | .load_firmware = rt73usb_load_firmware, | 2289 | .load_firmware = rt73usb_load_firmware, |
| 2283 | .initialize = rt2x00usb_initialize, | 2290 | .initialize = rt2x00usb_initialize, |
| 2284 | .uninitialize = rt2x00usb_uninitialize, | 2291 | .uninitialize = rt2x00usb_uninitialize, |
