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 94fb571667fe..84bd6f19acb0 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 2a7e8bc0016b..d2deea2f2679 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 9ddc2d07eef8..861322d97fce 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 c7ad1b3d4765..0be147f364e7 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 24e97b341cf8..be791a43c054 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, |