Signed-off-by: Michael Buesch <mb@xxxxxxxxx> Index: wireless-dev-new/drivers/net/wireless/b43/b43.h =================================================================== --- wireless-dev-new.orig/drivers/net/wireless/b43/b43.h 2007-08-18 19:05:09.000000000 +0200 +++ wireless-dev-new/drivers/net/wireless/b43/b43.h 2007-08-18 19:12:05.000000000 +0200 @@ -405,11 +405,32 @@ enum { struct b43_dmaring; struct b43_pioqueue; -struct b43_initval { - __be16 offset; - __be16 size; - __be32 value; -} __attribute__ ((__packed__)); +/* The firmware file header */ +#define B43_FW_TYPE_UCODE 'u' +#define B43_FW_TYPE_PCM 'p' +#define B43_FW_TYPE_IV 'i' +struct b43_fw_header { + /* File type */ + u8 type; + /* File format version */ + u8 ver; + u8 __padding[2]; + /* Size of the data. For ucode and PCM this is in bytes. + * For IV this is number-of-ivs. */ + __be32 size; +} __attribute__((__packed__)); + +/* Initial Value file format */ +#define B43_IV_OFFSET_MASK 0x7FFF +#define B43_IV_32BIT 0x8000 +struct b43_iv { + __be16 offset_size; + union { + __be16 d16; + __be32 d32; + } data __attribute__((__packed__)); +} __attribute__((__packed__)); + #define B43_PHYMODE(phytype) (1 << (phytype)) #define B43_PHYMODE_A B43_PHYMODE(B43_PHYTYPE_A) Index: wireless-dev-new/drivers/net/wireless/b43/main.c =================================================================== --- wireless-dev-new.orig/drivers/net/wireless/b43/main.c 2007-08-18 19:05:09.000000000 +0200 +++ wireless-dev-new/drivers/net/wireless/b43/main.c 2007-08-18 23:13:21.000000000 +0200 @@ -39,6 +39,7 @@ #include <linux/workqueue.h> #include <linux/skbuff.h> #include <linux/dma-mapping.h> +#include <asm/unaligned.h> #include "b43.h" #include "main.h" @@ -1585,6 +1586,8 @@ static int do_request_fw(struct b43_wlde { const size_t plen = sizeof(modparam_fwpostfix) + 32; char path[plen]; + struct b43_fw_header *hdr; + u32 size; int err; if (!name) @@ -1598,8 +1601,29 @@ static int do_request_fw(struct b43_wlde b43err(dev->wl, "Firmware file \"%s\" not found " "or load failed.\n", path); } + if ((*fw)->size < sizeof(struct b43_fw_header)) + goto err_format; + hdr = (struct b43_fw_header *)((*fw)->data); + switch (hdr->type) { + case B43_FW_TYPE_UCODE: + case B43_FW_TYPE_PCM: + size = be32_to_cpu(hdr->size); + if (size != (*fw)->size - sizeof(struct b43_fw_header)) + goto err_format; + /* fallthrough */ + case B43_FW_TYPE_IV: + if (hdr->ver != 1) + goto err_format; + break; + default: + goto err_format; + } return err; + +err_format: + b43err(dev->wl, "Firmware file \"%s\" format error.\n", path); + return -EPROTO; } static int b43_request_firmware(struct b43_wldev *dev) @@ -1719,6 +1743,7 @@ error: static int b43_upload_microcode(struct b43_wldev *dev) { + const size_t hdr_len = sizeof(struct b43_fw_header); const __be32 *data; unsigned int i, len; u16 fwrev, fwpatch, fwdate, fwtime; @@ -1726,24 +1751,26 @@ static int b43_upload_microcode(struct b int err = 0; /* Upload Microcode. */ - data = (__be32 *) (dev->fw.ucode->data); - len = dev->fw.ucode->size / sizeof(__be32); + data = (__be32 *) (dev->fw.ucode->data + hdr_len); + len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32); b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000); for (i = 0; i < len; i++) { b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); udelay(10); } - /* Upload PCM data. */ - data = (__be32 *) (dev->fw.pcm->data); - len = dev->fw.pcm->size / sizeof(__be32); - b43_shm_control_word(dev, B43_SHM_HW, 0x01EA); - b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000); - /* No need for autoinc bit in SHM_HW */ - b43_shm_control_word(dev, B43_SHM_HW, 0x01EB); - for (i = 0; i < len; i++) { - b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); - udelay(10); + if (dev->fw.pcm) { + /* Upload PCM data. */ + data = (__be32 *) (dev->fw.pcm->data + hdr_len); + len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32); + b43_shm_control_word(dev, B43_SHM_HW, 0x01EA); + b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000); + /* No need for autoinc bit in SHM_HW */ + b43_shm_control_word(dev, B43_SHM_HW, 0x01EB); + for (i = 0; i < len; i++) { + b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); + udelay(10); + } } b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL); @@ -1797,34 +1824,61 @@ static int b43_upload_microcode(struct b } static int b43_write_initvals(struct b43_wldev *dev, - const struct b43_initval *data, - size_t count) + const struct b43_iv *ivals, + size_t count, + size_t array_size) { - u16 offset, size; - u32 value; + const struct b43_iv *iv; + u16 offset; size_t i; + bool bit32; + BUILD_BUG_ON(sizeof(struct b43_iv) != 6); + iv = ivals; for (i = 0; i < count; i++) { - offset = be16_to_cpu(data[i].offset); - size = be16_to_cpu(data[i].size); - value = be32_to_cpu(data[i].value); - - if (unlikely(offset >= 0x1000)) + if (array_size < sizeof(iv->offset_size)) goto err_format; - if (size == 2) { - if (unlikely(value & 0xFFFF0000)) + array_size -= sizeof(iv->offset_size); + offset = be16_to_cpu(iv->offset_size); + bit32 = !!(offset & B43_IV_32BIT); + offset &= B43_IV_OFFSET_MASK; + if (offset >= 0x1000) + goto err_format; + if (bit32) { + u32 value; + + if (array_size < sizeof(iv->data.d32)) goto err_format; - b43_write16(dev, offset, (u16) value); - } else if (size == 4) { + array_size -= sizeof(iv->data.d32); + + value = be32_to_cpu(get_unaligned(&iv->data.d32)); b43_write32(dev, offset, value); - } else - goto err_format; + + iv = (const struct b43_iv *)((const uint8_t *)iv + + sizeof(__be16) + + sizeof(__be32)); + } else { + u16 value; + + if (array_size < sizeof(iv->data.d16)) + goto err_format; + array_size -= sizeof(iv->data.d16); + + value = be16_to_cpu(iv->data.d16); + b43_write16(dev, offset, value); + + iv = (const struct b43_iv *)((const uint8_t *)iv + + sizeof(__be16) + + sizeof(__be16)); + } } + if (array_size) + goto err_format; return 0; err_format: - b43err(dev->wl, "Initial Values Firmware file-format error\n"); + b43err(dev->wl, "Initial Values Firmware file-format error.\n"); b43_print_fw_helptext(dev->wl); return -EPROTO; @@ -1832,20 +1886,28 @@ err_format: static int b43_upload_initvals(struct b43_wldev *dev) { + const size_t hdr_len = sizeof(struct b43_fw_header); + const struct b43_fw_header *hdr; struct b43_firmware *fw = &dev->fw; - struct b43_initval *ivals; + const struct b43_iv *ivals; size_t count; int err; - ivals = (struct b43_initval *)(fw->initvals->data); - count = fw->initvals->size / sizeof(struct b43_initval); - err = b43_write_initvals(dev, ivals, count); + hdr = (const struct b43_fw_header *)(fw->initvals->data); + ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len); + count = be32_to_cpu(hdr->size); + err = b43_write_initvals(dev, ivals, count, + fw->initvals->size - hdr_len); if (err) goto out; if (fw->initvals_band) { - ivals = (struct b43_initval *)(fw->initvals_band->data); - count = fw->initvals_band->size / sizeof(struct b43_initval); - err = b43_write_initvals(dev, ivals, count); + hdr = (const struct b43_fw_header *)(fw->initvals_band->data); + ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len); + count = be32_to_cpu(hdr->size); + err = b43_write_initvals(dev, ivals, count, + fw->initvals_band->size - hdr_len); + if (err) + goto out; } out: -- - To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html