diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/orinoco/fw.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/hermes_dld.c | 99 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/hermes_dld.h | 12 |
3 files changed, 67 insertions, 56 deletions
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c index 9f163feb9362..e7abb45d6753 100644 --- a/drivers/net/wireless/orinoco/fw.c +++ b/drivers/net/wireless/orinoco/fw.c | |||
@@ -83,7 +83,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
83 | const struct firmware *fw_entry; | 83 | const struct firmware *fw_entry; |
84 | const struct orinoco_fw_header *hdr; | 84 | const struct orinoco_fw_header *hdr; |
85 | const unsigned char *first_block; | 85 | const unsigned char *first_block; |
86 | const unsigned char *end; | 86 | const void *end; |
87 | const char *firmware; | 87 | const char *firmware; |
88 | const char *fw_err; | 88 | const char *fw_err; |
89 | struct net_device *dev = priv->ndev; | 89 | struct net_device *dev = priv->ndev; |
@@ -152,7 +152,8 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
152 | le16_to_cpu(hdr->headersize) + | 152 | le16_to_cpu(hdr->headersize) + |
153 | le32_to_cpu(hdr->pdr_offset)); | 153 | le32_to_cpu(hdr->pdr_offset)); |
154 | 154 | ||
155 | err = hermes_apply_pda_with_defaults(hw, first_block, pda); | 155 | err = hermes_apply_pda_with_defaults(hw, first_block, end, pda, |
156 | &pda[fw->pda_size / sizeof(*pda)]); | ||
156 | printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); | 157 | printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); |
157 | if (err) | 158 | if (err) |
158 | goto abort; | 159 | goto abort; |
@@ -184,7 +185,7 @@ free: | |||
184 | */ | 185 | */ |
185 | static int | 186 | static int |
186 | symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | 187 | symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, |
187 | const unsigned char *image, const unsigned char *end, | 188 | const unsigned char *image, const void *end, |
188 | int secondary) | 189 | int secondary) |
189 | { | 190 | { |
190 | hermes_t *hw = &priv->hw; | 191 | hermes_t *hw = &priv->hw; |
@@ -225,9 +226,10 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | |||
225 | 226 | ||
226 | /* Write the PDA to the adapter */ | 227 | /* Write the PDA to the adapter */ |
227 | if (secondary) { | 228 | if (secondary) { |
228 | size_t len = hermes_blocks_length(first_block); | 229 | size_t len = hermes_blocks_length(first_block, end); |
229 | ptr = first_block + len; | 230 | ptr = first_block + len; |
230 | ret = hermes_apply_pda(hw, ptr, pda); | 231 | ret = hermes_apply_pda(hw, ptr, end, pda, |
232 | &pda[fw->pda_size / sizeof(*pda)]); | ||
231 | kfree(pda); | 233 | kfree(pda); |
232 | if (ret) | 234 | if (ret) |
233 | return ret; | 235 | return ret; |
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c index 5260ceb5cfec..a9ba195cdada 100644 --- a/drivers/net/wireless/orinoco/hermes_dld.c +++ b/drivers/net/wireless/orinoco/hermes_dld.c | |||
@@ -71,18 +71,6 @@ | |||
71 | #define BLOCK_END 0xFFFFFFFF /* Last image block */ | 71 | #define BLOCK_END 0xFFFFFFFF /* Last image block */ |
72 | #define TEXT_END 0x1A /* End of text header */ | 72 | #define TEXT_END 0x1A /* End of text header */ |
73 | 73 | ||
74 | /* | ||
75 | * PDA == Production Data Area | ||
76 | * | ||
77 | * In principle, the max. size of the PDA is is 4096 words. Currently, | ||
78 | * however, only about 500 bytes of this area are used. | ||
79 | * | ||
80 | * Some USB implementations can't handle sizes in excess of 1016. Note | ||
81 | * that PDA is not actually used in those USB environments, but may be | ||
82 | * retrieved by common code. | ||
83 | */ | ||
84 | #define MAX_PDA_SIZE 1000 | ||
85 | |||
86 | /* Limit the amout we try to download in a single shot. | 74 | /* Limit the amout we try to download in a single shot. |
87 | * Size is in bytes. | 75 | * Size is in bytes. |
88 | */ | 76 | */ |
@@ -218,13 +206,14 @@ hermes_aux_control(hermes_t *hw, int enabled) | |||
218 | * Scan PDR for the record with the specified RECORD_ID. | 206 | * Scan PDR for the record with the specified RECORD_ID. |
219 | * If it's not found, return NULL. | 207 | * If it's not found, return NULL. |
220 | */ | 208 | */ |
221 | static struct pdr * | 209 | static const struct pdr * |
222 | hermes_find_pdr(struct pdr *first_pdr, u32 record_id) | 210 | hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end) |
223 | { | 211 | { |
224 | struct pdr *pdr = first_pdr; | 212 | const struct pdr *pdr = first_pdr; |
225 | void *end = (void *)first_pdr + MAX_PDA_SIZE; | ||
226 | 213 | ||
227 | while (((void *)pdr < end) && | 214 | end -= sizeof(struct pdr); |
215 | |||
216 | while (((void *) pdr <= end) && | ||
228 | (pdr_id(pdr) != PDI_END)) { | 217 | (pdr_id(pdr) != PDI_END)) { |
229 | /* | 218 | /* |
230 | * PDR area is currently not terminated by PDI_END. | 219 | * PDR area is currently not terminated by PDI_END. |
@@ -244,12 +233,15 @@ hermes_find_pdr(struct pdr *first_pdr, u32 record_id) | |||
244 | } | 233 | } |
245 | 234 | ||
246 | /* Scan production data items for a particular entry */ | 235 | /* Scan production data items for a particular entry */ |
247 | static struct pdi * | 236 | static const struct pdi * |
248 | hermes_find_pdi(struct pdi *first_pdi, u32 record_id) | 237 | hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end) |
249 | { | 238 | { |
250 | struct pdi *pdi = first_pdi; | 239 | const struct pdi *pdi = first_pdi; |
240 | |||
241 | end -= sizeof(struct pdi); | ||
251 | 242 | ||
252 | while (pdi_id(pdi) != PDI_END) { | 243 | while (((void *) pdi <= end) && |
244 | (pdi_id(pdi) != PDI_END)) { | ||
253 | 245 | ||
254 | /* If the record ID matches, we are done */ | 246 | /* If the record ID matches, we are done */ |
255 | if (pdi_id(pdi) == record_id) | 247 | if (pdi_id(pdi) == record_id) |
@@ -262,12 +254,13 @@ hermes_find_pdi(struct pdi *first_pdi, u32 record_id) | |||
262 | 254 | ||
263 | /* Process one Plug Data Item - find corresponding PDR and plug it */ | 255 | /* Process one Plug Data Item - find corresponding PDR and plug it */ |
264 | static int | 256 | static int |
265 | hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi) | 257 | hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr, |
258 | const struct pdi *pdi, const void *pdr_end) | ||
266 | { | 259 | { |
267 | struct pdr *pdr; | 260 | const struct pdr *pdr; |
268 | 261 | ||
269 | /* Find the PDR corresponding to this PDI */ | 262 | /* Find the PDR corresponding to this PDI */ |
270 | pdr = hermes_find_pdr(first_pdr, pdi_id(pdi)); | 263 | pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end); |
271 | 264 | ||
272 | /* No match is found, safe to ignore */ | 265 | /* No match is found, safe to ignore */ |
273 | if (!pdr) | 266 | if (!pdr) |
@@ -345,18 +338,22 @@ int hermes_read_pda(hermes_t *hw, | |||
345 | */ | 338 | */ |
346 | int hermes_apply_pda(hermes_t *hw, | 339 | int hermes_apply_pda(hermes_t *hw, |
347 | const char *first_pdr, | 340 | const char *first_pdr, |
348 | const __le16 *pda) | 341 | const void *pdr_end, |
342 | const __le16 *pda, | ||
343 | const void *pda_end) | ||
349 | { | 344 | { |
350 | int ret; | 345 | int ret; |
351 | const struct pdi *pdi; | 346 | const struct pdi *pdi; |
352 | struct pdr *pdr; | 347 | const struct pdr *pdr; |
353 | 348 | ||
354 | pdr = (struct pdr *) first_pdr; | 349 | pdr = (const struct pdr *) first_pdr; |
350 | pda_end -= sizeof(struct pdi); | ||
355 | 351 | ||
356 | /* Go through every PDI and plug them into the adapter */ | 352 | /* Go through every PDI and plug them into the adapter */ |
357 | pdi = (const struct pdi *) (pda + 2); | 353 | pdi = (const struct pdi *) (pda + 2); |
358 | while (pdi_id(pdi) != PDI_END) { | 354 | while (((void *) pdi <= pda_end) && |
359 | ret = hermes_plug_pdi(hw, pdr, pdi); | 355 | (pdi_id(pdi) != PDI_END)) { |
356 | ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end); | ||
360 | if (ret) | 357 | if (ret) |
361 | return ret; | 358 | return ret; |
362 | 359 | ||
@@ -370,15 +367,18 @@ int hermes_apply_pda(hermes_t *hw, | |||
370 | * including the header data. | 367 | * including the header data. |
371 | */ | 368 | */ |
372 | size_t | 369 | size_t |
373 | hermes_blocks_length(const char *first_block) | 370 | hermes_blocks_length(const char *first_block, const void *end) |
374 | { | 371 | { |
375 | const struct dblock *blk = (const struct dblock *) first_block; | 372 | const struct dblock *blk = (const struct dblock *) first_block; |
376 | int total_len = 0; | 373 | int total_len = 0; |
377 | int len; | 374 | int len; |
378 | 375 | ||
376 | end -= sizeof(*blk); | ||
377 | |||
379 | /* Skip all blocks to locate Plug Data References | 378 | /* Skip all blocks to locate Plug Data References |
380 | * (Spectrum CS) */ | 379 | * (Spectrum CS) */ |
381 | while (dblock_addr(blk) != BLOCK_END) { | 380 | while (((void *) blk <= end) && |
381 | (dblock_addr(blk) != BLOCK_END)) { | ||
382 | len = dblock_len(blk); | 382 | len = dblock_len(blk); |
383 | total_len += sizeof(*blk) + len; | 383 | total_len += sizeof(*blk) + len; |
384 | blk = (struct dblock *) &blk->data[len]; | 384 | blk = (struct dblock *) &blk->data[len]; |
@@ -476,7 +476,7 @@ int hermesi_program_end(hermes_t *hw) | |||
476 | } | 476 | } |
477 | 477 | ||
478 | /* Program the data blocks */ | 478 | /* Program the data blocks */ |
479 | int hermes_program(hermes_t *hw, const char *first_block, const char *end) | 479 | int hermes_program(hermes_t *hw, const char *first_block, const void *end) |
480 | { | 480 | { |
481 | const struct dblock *blk; | 481 | const struct dblock *blk; |
482 | u32 blkaddr; | 482 | u32 blkaddr; |
@@ -488,14 +488,14 @@ int hermes_program(hermes_t *hw, const char *first_block, const char *end) | |||
488 | 488 | ||
489 | blk = (const struct dblock *) first_block; | 489 | blk = (const struct dblock *) first_block; |
490 | 490 | ||
491 | if ((const char *) blk > (end - sizeof(*blk))) | 491 | if ((void *) blk > (end - sizeof(*blk))) |
492 | return -EIO; | 492 | return -EIO; |
493 | 493 | ||
494 | blkaddr = dblock_addr(blk); | 494 | blkaddr = dblock_addr(blk); |
495 | blklen = dblock_len(blk); | 495 | blklen = dblock_len(blk); |
496 | 496 | ||
497 | while ((blkaddr != BLOCK_END) && | 497 | while ((blkaddr != BLOCK_END) && |
498 | (((const char *) blk + blklen) <= end)) { | 498 | (((void *) blk + blklen) <= end)) { |
499 | printk(KERN_DEBUG PFX | 499 | printk(KERN_DEBUG PFX |
500 | "Programming block of length %d to address 0x%08x\n", | 500 | "Programming block of length %d to address 0x%08x\n", |
501 | blklen, blkaddr); | 501 | blklen, blkaddr); |
@@ -527,7 +527,7 @@ int hermes_program(hermes_t *hw, const char *first_block, const char *end) | |||
527 | #endif | 527 | #endif |
528 | blk = (const struct dblock *) &blk->data[blklen]; | 528 | blk = (const struct dblock *) &blk->data[blklen]; |
529 | 529 | ||
530 | if ((const char *) blk > (end - sizeof(*blk))) | 530 | if ((void *) blk > (end - sizeof(*blk))) |
531 | return -EIO; | 531 | return -EIO; |
532 | 532 | ||
533 | blkaddr = dblock_addr(blk); | 533 | blkaddr = dblock_addr(blk); |
@@ -545,9 +545,9 @@ static const struct { \ | |||
545 | __le16 id; \ | 545 | __le16 id; \ |
546 | u8 val[length]; \ | 546 | u8 val[length]; \ |
547 | } __attribute__ ((packed)) default_pdr_data_##pid = { \ | 547 | } __attribute__ ((packed)) default_pdr_data_##pid = { \ |
548 | cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ | 548 | cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ |
549 | sizeof(__le16)) - 1), \ | 549 | sizeof(__le16)) - 1), \ |
550 | cpu_to_le16(pid), \ | 550 | cpu_to_le16(pid), \ |
551 | data \ | 551 | data \ |
552 | } | 552 | } |
553 | 553 | ||
@@ -616,17 +616,20 @@ DEFINE_DEFAULT_PDR(0x0161, 256, | |||
616 | */ | 616 | */ |
617 | int hermes_apply_pda_with_defaults(hermes_t *hw, | 617 | int hermes_apply_pda_with_defaults(hermes_t *hw, |
618 | const char *first_pdr, | 618 | const char *first_pdr, |
619 | const __le16 *pda) | 619 | const void *pdr_end, |
620 | const __le16 *pda, | ||
621 | const void *pda_end) | ||
620 | { | 622 | { |
621 | const struct pdr *pdr = (const struct pdr *) first_pdr; | 623 | const struct pdr *pdr = (const struct pdr *) first_pdr; |
622 | struct pdi *first_pdi = (struct pdi *) &pda[2]; | 624 | const struct pdi *first_pdi = (const struct pdi *) &pda[2]; |
623 | struct pdi *pdi; | 625 | const struct pdi *pdi; |
624 | struct pdi *default_pdi = NULL; | 626 | const struct pdi *default_pdi = NULL; |
625 | struct pdi *outdoor_pdi; | 627 | const struct pdi *outdoor_pdi; |
626 | void *end = (void *)first_pdr + MAX_PDA_SIZE; | ||
627 | int record_id; | 628 | int record_id; |
628 | 629 | ||
629 | while (((void *)pdr < end) && | 630 | pdr_end -= sizeof(struct pdr); |
631 | |||
632 | while (((void *) pdr <= pdr_end) && | ||
630 | (pdr_id(pdr) != PDI_END)) { | 633 | (pdr_id(pdr) != PDI_END)) { |
631 | /* | 634 | /* |
632 | * For spectrum_cs firmwares, | 635 | * For spectrum_cs firmwares, |
@@ -638,7 +641,7 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, | |||
638 | break; | 641 | break; |
639 | record_id = pdr_id(pdr); | 642 | record_id = pdr_id(pdr); |
640 | 643 | ||
641 | pdi = hermes_find_pdi(first_pdi, record_id); | 644 | pdi = hermes_find_pdi(first_pdi, record_id, pda_end); |
642 | if (pdi) | 645 | if (pdi) |
643 | printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", | 646 | printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", |
644 | record_id, pdi); | 647 | record_id, pdi); |
@@ -646,7 +649,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, | |||
646 | switch (record_id) { | 649 | switch (record_id) { |
647 | case 0x110: /* Modem REFDAC values */ | 650 | case 0x110: /* Modem REFDAC values */ |
648 | case 0x120: /* Modem VGDAC values */ | 651 | case 0x120: /* Modem VGDAC values */ |
649 | outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1); | 652 | outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1, |
653 | pda_end); | ||
650 | default_pdi = NULL; | 654 | default_pdi = NULL; |
651 | if (outdoor_pdi) { | 655 | if (outdoor_pdi) { |
652 | pdi = outdoor_pdi; | 656 | pdi = outdoor_pdi; |
@@ -687,7 +691,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, | |||
687 | 691 | ||
688 | if (pdi) { | 692 | if (pdi) { |
689 | /* Lengths of the data in PDI and PDR must match */ | 693 | /* Lengths of the data in PDI and PDR must match */ |
690 | if (pdi_len(pdi) == pdr_len(pdr)) { | 694 | if ((pdi_len(pdi) == pdr_len(pdr)) && |
695 | ((void *) pdi->data + pdi_len(pdi) < pda_end)) { | ||
691 | /* do the actual plugging */ | 696 | /* do the actual plugging */ |
692 | hermes_aux_setaddr(hw, pdr_addr(pdr)); | 697 | hermes_aux_setaddr(hw, pdr_addr(pdr)); |
693 | hermes_write_bytes(hw, HERMES_AUXDATA, | 698 | hermes_write_bytes(hw, HERMES_AUXDATA, |
diff --git a/drivers/net/wireless/orinoco/hermes_dld.h b/drivers/net/wireless/orinoco/hermes_dld.h index 6fcb26277999..583a5bcf9175 100644 --- a/drivers/net/wireless/orinoco/hermes_dld.h +++ b/drivers/net/wireless/orinoco/hermes_dld.h | |||
@@ -29,7 +29,7 @@ | |||
29 | 29 | ||
30 | int hermesi_program_init(hermes_t *hw, u32 offset); | 30 | int hermesi_program_init(hermes_t *hw, u32 offset); |
31 | int hermesi_program_end(hermes_t *hw); | 31 | int hermesi_program_end(hermes_t *hw); |
32 | int hermes_program(hermes_t *hw, const char *first_block, const char *end); | 32 | int hermes_program(hermes_t *hw, const char *first_block, const void *end); |
33 | 33 | ||
34 | int hermes_read_pda(hermes_t *hw, | 34 | int hermes_read_pda(hermes_t *hw, |
35 | __le16 *pda, | 35 | __le16 *pda, |
@@ -38,11 +38,15 @@ int hermes_read_pda(hermes_t *hw, | |||
38 | int use_eeprom); | 38 | int use_eeprom); |
39 | int hermes_apply_pda(hermes_t *hw, | 39 | int hermes_apply_pda(hermes_t *hw, |
40 | const char *first_pdr, | 40 | const char *first_pdr, |
41 | const __le16 *pda); | 41 | const void *pdr_end, |
42 | const __le16 *pda, | ||
43 | const void *pda_end); | ||
42 | int hermes_apply_pda_with_defaults(hermes_t *hw, | 44 | int hermes_apply_pda_with_defaults(hermes_t *hw, |
43 | const char *first_pdr, | 45 | const char *first_pdr, |
44 | const __le16 *pda); | 46 | const void *pdr_end, |
47 | const __le16 *pda, | ||
48 | const void *pda_end); | ||
45 | 49 | ||
46 | size_t hermes_blocks_length(const char *first_block); | 50 | size_t hermes_blocks_length(const char *first_block, const void *end); |
47 | 51 | ||
48 | #endif /* _HERMES_DLD_H */ | 52 | #endif /* _HERMES_DLD_H */ |