aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/orinoco/fw.c12
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c99
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.h12
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 */
185static int 186static int
186symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, 187symbol_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 */
221static struct pdr * 209static const struct pdr *
222hermes_find_pdr(struct pdr *first_pdr, u32 record_id) 210hermes_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 */
247static struct pdi * 236static const struct pdi *
248hermes_find_pdi(struct pdi *first_pdi, u32 record_id) 237hermes_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 */
264static int 256static int
265hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi) 257hermes_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 */
346int hermes_apply_pda(hermes_t *hw, 339int 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 */
372size_t 369size_t
373hermes_blocks_length(const char *first_block) 370hermes_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 */
479int hermes_program(hermes_t *hw, const char *first_block, const char *end) 479int 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 */
617int hermes_apply_pda_with_defaults(hermes_t *hw, 617int 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
30int hermesi_program_init(hermes_t *hw, u32 offset); 30int hermesi_program_init(hermes_t *hw, u32 offset);
31int hermesi_program_end(hermes_t *hw); 31int hermesi_program_end(hermes_t *hw);
32int hermes_program(hermes_t *hw, const char *first_block, const char *end); 32int hermes_program(hermes_t *hw, const char *first_block, const void *end);
33 33
34int hermes_read_pda(hermes_t *hw, 34int 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);
39int hermes_apply_pda(hermes_t *hw, 39int 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);
42int hermes_apply_pda_with_defaults(hermes_t *hw, 44int 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
46size_t hermes_blocks_length(const char *first_block); 50size_t hermes_blocks_length(const char *first_block, const void *end);
47 51
48#endif /* _HERMES_DLD_H */ 52#endif /* _HERMES_DLD_H */