Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/usb/wlan/if_upgt.c
Show First 20 Lines • Show All 1,037 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
upgt_eeprom_parse(struct upgt_softc *sc) | upgt_eeprom_parse(struct upgt_softc *sc) | ||||
{ | { | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct upgt_eeprom_header *eeprom_header; | struct upgt_eeprom_header *eeprom_header; | ||||
struct upgt_eeprom_option *eeprom_option; | struct upgt_eeprom_option *eeprom_option; | ||||
uint16_t option_len; | uint32_t option_len; | ||||
uint16_t option_type; | uint16_t option_type; | ||||
uint16_t preamble_len; | uint16_t preamble_len; | ||||
int option_end = 0; | int option_end = 0; | ||||
/* calculate eeprom options start offset */ | /* calculate eeprom options start offset */ | ||||
eeprom_header = (struct upgt_eeprom_header *)sc->sc_eeprom; | eeprom_header = (struct upgt_eeprom_header *)sc->sc_eeprom; | ||||
preamble_len = le16toh(eeprom_header->preamble_len); | preamble_len = le16toh(eeprom_header->preamble_len); | ||||
eeprom_option = (struct upgt_eeprom_option *)(sc->sc_eeprom + | eeprom_option = (struct upgt_eeprom_option *)(sc->sc_eeprom + | ||||
(sizeof(struct upgt_eeprom_header) + preamble_len)); | (sizeof(struct upgt_eeprom_header) + preamble_len)); | ||||
while (!option_end) { | while (!option_end) { | ||||
/* sanity check */ | /* sanity check */ | ||||
if (eeprom_option >= (struct upgt_eeprom_option *) | if (eeprom_option >= (struct upgt_eeprom_option *) | ||||
(sc->sc_eeprom + UPGT_EEPROM_SIZE)) { | (sc->sc_eeprom + UPGT_EEPROM_SIZE) || | ||||
eeprom_option < (struct upgt_eeprom_option *) | |||||
sc->sc_eeprom) { | |||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* the eeprom option length is stored in words */ | /* the eeprom option length is stored in words */ | ||||
option_len = | option_len = | ||||
(le16toh(eeprom_option->len) - 1) * sizeof(uint16_t); | (le16toh(eeprom_option->len) - 1) * sizeof(uint16_t); | ||||
option_type = | option_type = | ||||
le16toh(eeprom_option->type); | le16toh(eeprom_option->type); | ||||
▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | upgt_rxeof(struct usb_xfer *xfer, struct upgt_data *data, int *rssi) | ||||
header = (struct upgt_lmac_header *)(data->buf + 4); | header = (struct upgt_lmac_header *)(data->buf + 4); | ||||
h1_type = header->header1.type; | h1_type = header->header1.type; | ||||
h2_type = le16toh(header->header2.type); | h2_type = le16toh(header->header2.type); | ||||
if (h1_type == UPGT_H1_TYPE_CTRL && h2_type == UPGT_H2_TYPE_EEPROM) { | if (h1_type == UPGT_H1_TYPE_CTRL && h2_type == UPGT_H2_TYPE_EEPROM) { | ||||
eeprom = (struct upgt_lmac_eeprom *)(data->buf + 4); | eeprom = (struct upgt_lmac_eeprom *)(data->buf + 4); | ||||
uint16_t eeprom_offset = le16toh(eeprom->offset); | uint16_t eeprom_offset = le16toh(eeprom->offset); | ||||
uint16_t eeprom_len = le16toh(eeprom->len); | uint16_t eeprom_len = le16toh(eeprom->len); | ||||
hselasky: missing range checks for eeprom_len being valid. | |||||
DPRINTF(sc, UPGT_DEBUG_FW, | DPRINTF(sc, UPGT_DEBUG_FW, | ||||
"received EEPROM block (offset=%d, len=%d)\n", | "received EEPROM block (offset=%d, len=%d)\n", | ||||
eeprom_offset, eeprom_len); | eeprom_offset, eeprom_len); | ||||
memcpy(sc->sc_eeprom + eeprom_offset, | memcpy(sc->sc_eeprom + eeprom_offset, | ||||
data->buf + sizeof(struct upgt_lmac_eeprom) + 4, | data->buf + sizeof(struct upgt_lmac_eeprom) + 4, | ||||
eeprom_len); | eeprom_len); | ||||
/* EEPROM data has arrived in time, wakeup. */ | /* EEPROM data has arrived in time, wakeup. */ | ||||
wakeup(sc); | wakeup(sc); | ||||
} else if (h1_type == UPGT_H1_TYPE_CTRL && | } else if (h1_type == UPGT_H1_TYPE_CTRL && | ||||
h2_type == UPGT_H2_TYPE_TX_DONE) { | h2_type == UPGT_H2_TYPE_TX_DONE) { | ||||
DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: received 802.11 TX done\n", | DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: received 802.11 TX done\n", | ||||
__func__); | __func__); | ||||
upgt_tx_done(sc, data->buf + 4); | upgt_tx_done(sc, data->buf + 4); | ||||
} else if (h1_type == UPGT_H1_TYPE_RX_DATA || | } else if (h1_type == UPGT_H1_TYPE_RX_DATA || | ||||
h1_type == UPGT_H1_TYPE_RX_DATA_MGMT) { | h1_type == UPGT_H1_TYPE_RX_DATA_MGMT) { | ||||
DPRINTF(sc, UPGT_DEBUG_RECV, "%s: received 802.11 RX data\n", | DPRINTF(sc, UPGT_DEBUG_RECV, "%s: received 802.11 RX data\n", | ||||
__func__); | __func__); | ||||
m = upgt_rx(sc, data->buf + 4, le16toh(header->header1.len), | m = upgt_rx(sc, data->buf + 4, le16toh(header->header1.len), | ||||
hselaskyUnsubmitted Done Inline Actionsmissing range check for header->header1.len being valid. hselasky: missing range check for header->header1.len being valid. | |||||
rssi); | rssi); | ||||
} else if (h1_type == UPGT_H1_TYPE_CTRL && | } else if (h1_type == UPGT_H1_TYPE_CTRL && | ||||
h2_type == UPGT_H2_TYPE_STATS) { | h2_type == UPGT_H2_TYPE_STATS) { | ||||
DPRINTF(sc, UPGT_DEBUG_STAT, "%s: received statistic data\n", | DPRINTF(sc, UPGT_DEBUG_STAT, "%s: received statistic data\n", | ||||
__func__); | __func__); | ||||
/* TODO: what could we do with the statistic data? */ | /* TODO: what could we do with the statistic data? */ | ||||
} else { | } else { | ||||
/* ignore unknown frame types */ | /* ignore unknown frame types */ | ||||
Show All 18 Lines | for (i = 0; i < size; i += sizeof(uint32_t)) { | ||||
crc = htole32(crc ^ *buf++); | crc = htole32(crc ^ *buf++); | ||||
crc = htole32((crc >> 5) ^ (crc << 3)); | crc = htole32((crc >> 5) ^ (crc << 3)); | ||||
} | } | ||||
return (crc); | return (crc); | ||||
} | } | ||||
static struct mbuf * | static struct mbuf * | ||||
upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi) | upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi) | ||||
hselaskyUnsubmitted Done Inline Actionsuint32_t pkglen hselasky: uint32_t pkglen | |||||
{ | { | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct upgt_lmac_rx_desc *rxdesc; | struct upgt_lmac_rx_desc *rxdesc; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
/* | /* | ||||
* don't pass packets to the ieee80211 framework if the driver isn't | * don't pass packets to the ieee80211 framework if the driver isn't | ||||
* RUNNING. | * RUNNING. | ||||
*/ | */ | ||||
if (!(sc->sc_flags & UPGT_FLAG_INITDONE)) | if (!(sc->sc_flags & UPGT_FLAG_INITDONE)) | ||||
return (NULL); | return (NULL); | ||||
/* access RX packet descriptor */ | /* access RX packet descriptor */ | ||||
rxdesc = (struct upgt_lmac_rx_desc *)data; | rxdesc = (struct upgt_lmac_rx_desc *)data; | ||||
hselaskyUnsubmitted Done Inline Actionsif (pkglen > (MCLBYTES - ETHER_ALIGN - IEEE80211_CRC_LEN )) xxx error; hselasky: if (pkglen > (MCLBYTES - ETHER_ALIGN - IEEE80211_CRC_LEN ))
xxx error; | |||||
/* create mbuf which is suitable for strict alignment archs */ | /* create mbuf which is suitable for strict alignment archs */ | ||||
KASSERT((pkglen + ETHER_ALIGN) < MCLBYTES, | KASSERT((pkglen + ETHER_ALIGN) < MCLBYTES, | ||||
hselaskyUnsubmitted Done Inline ActionsRemove this KASSERT() - we don't want to panic on corrupt USB data! hselasky: Remove this KASSERT() - we don't want to panic on corrupt USB data! | |||||
("A current mbuf storage is small (%d)", pkglen + ETHER_ALIGN)); | ("A current mbuf storage is small (%d)", pkglen + ETHER_ALIGN)); | ||||
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | ||||
if (m == NULL) { | if (m == NULL) { | ||||
device_printf(sc->sc_dev, "could not create RX mbuf\n"); | device_printf(sc->sc_dev, "could not create RX mbuf\n"); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
m_adj(m, ETHER_ALIGN); | m_adj(m, ETHER_ALIGN); | ||||
memcpy(mtod(m, char *), rxdesc->data, pkglen); | memcpy(mtod(m, char *), rxdesc->data, pkglen); | ||||
▲ Show 20 Lines • Show All 241 Lines • ▼ Show 20 Lines | upgt_mem_init(struct upgt_softc *sc) | ||||
for (i = 0; i < UPGT_MEMORY_MAX_PAGES; i++) { | for (i = 0; i < UPGT_MEMORY_MAX_PAGES; i++) { | ||||
sc->sc_memory.page[i].used = 0; | sc->sc_memory.page[i].used = 0; | ||||
if (i == 0) { | if (i == 0) { | ||||
/* | /* | ||||
* The first memory page is always reserved for | * The first memory page is always reserved for | ||||
* command data. | * command data. | ||||
*/ | */ | ||||
hselaskyUnsubmitted Done Inline ActionsPlease add checks here for frame_start wrapping around. hselasky: Please add checks here for frame_start wrapping around. | |||||
sc->sc_memory.page[i].addr = | sc->sc_memory.page[i].addr = | ||||
sc->sc_memaddr_frame_start + MCLBYTES; | sc->sc_memaddr_frame_start + MCLBYTES; | ||||
} else { | } else { | ||||
sc->sc_memory.page[i].addr = | sc->sc_memory.page[i].addr = | ||||
sc->sc_memory.page[i - 1].addr + MCLBYTES; | sc->sc_memory.page[i - 1].addr + MCLBYTES; | ||||
} | } | ||||
if (sc->sc_memory.page[i].addr + MCLBYTES >= | if (sc->sc_memory.page[i].addr + MCLBYTES >= | ||||
Show All 28 Lines | if (fw == NULL) { | ||||
device_printf(sc->sc_dev, "could not read microcode %s\n", | device_printf(sc->sc_dev, "could not read microcode %s\n", | ||||
upgt_fwname); | upgt_fwname); | ||||
return EIO; | return EIO; | ||||
} | } | ||||
/* | /* | ||||
* Seek to beginning of Boot Record Area (BRA). | * Seek to beginning of Boot Record Area (BRA). | ||||
*/ | */ | ||||
for (offset = 0; offset < fw->datasize; offset += sizeof(*uc)) { | for (offset = 0; offset < fw->datasize; offset += sizeof(*uc)) { | ||||
hselaskyUnsubmitted Done Inline ActionsThe for-loop condition should read: (offset + sizeof(*uc)) <= fw->datasize Else you might read data which is not inside the BRA. hselasky: The for-loop condition should read: (offset + sizeof(*uc)) <= fw->datasize
Else you might read… | |||||
uc = (const uint32_t *)((const uint8_t *)fw->data + offset); | uc = (const uint32_t *)((const uint8_t *)fw->data + offset); | ||||
if (*uc == 0) | if (*uc == 0) | ||||
break; | break; | ||||
} | } | ||||
for (; offset < fw->datasize; offset += sizeof(*uc)) { | for (; offset < fw->datasize; offset += sizeof(*uc)) { | ||||
hselaskyUnsubmitted Done Inline ActionsSame here. hselasky: Same here. | |||||
uc = (const uint32_t *)((const uint8_t *)fw->data + offset); | uc = (const uint32_t *)((const uint8_t *)fw->data + offset); | ||||
if (*uc != 0) | if (*uc != 0) | ||||
break; | break; | ||||
} | } | ||||
if (offset == fw->datasize) { | if (offset >= fw->datasize) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"firmware Boot Record Area not found\n"); | "firmware Boot Record Area not found\n"); | ||||
error = EIO; | error = EIO; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
DPRINTF(sc, UPGT_DEBUG_FW, | DPRINTF(sc, UPGT_DEBUG_FW, | ||||
"firmware Boot Record Area found at offset %d\n", offset); | "firmware Boot Record Area found at offset %d\n", offset); | ||||
/* | /* | ||||
* Parse Boot Record Area (BRA) options. | * Parse Boot Record Area (BRA) options. | ||||
*/ | */ | ||||
while (offset < fw->datasize && bra_end == 0) { | while (offset < fw->datasize && bra_end == 0) { | ||||
/* get current BRA option */ | /* get current BRA option */ | ||||
p = (const uint8_t *)fw->data + offset; | p = (const uint8_t *)fw->data + offset; | ||||
bra_opt = (const struct upgt_fw_bra_option *)p; | bra_opt = (const struct upgt_fw_bra_option *)p; | ||||
bra_option_type = le32toh(bra_opt->type); | bra_option_type = le32toh(bra_opt->type); | ||||
bra_option_len = le32toh(bra_opt->len) * sizeof(*uc); | bra_option_len = le32toh(bra_opt->len) * sizeof(*uc); | ||||
if (bra_option_len / sizeof(*uc) != le32toh(bra_opt->len)) { | |||||
hselaskyUnsubmitted Done Inline ActionsPlease also add this check: if (sizeof(struct upgt_fw_bra_option) > (size_t)(fw->datasize - offset) || (bra_option_len > (size_t)(fw->datasize - offset - sizeof(struct upgt_fw_bra_option))) hselasky: Please also add this check:
```
if (sizeof(struct upgt_fw_bra_option) > (size_t)(fw->datasize… | |||||
device_printf(sc->sc_dev, "bra_option_len overflow\n"); | |||||
error = EINVAL; | |||||
goto fail; | |||||
} | |||||
switch (bra_option_type) { | switch (bra_option_type) { | ||||
case UPGT_BRA_TYPE_FW: | case UPGT_BRA_TYPE_FW: | ||||
DPRINTF(sc, UPGT_DEBUG_FW, "UPGT_BRA_TYPE_FW len=%d\n", | DPRINTF(sc, UPGT_DEBUG_FW, "UPGT_BRA_TYPE_FW len=%d\n", | ||||
bra_option_len); | bra_option_len); | ||||
if (bra_option_len != UPGT_BRA_FWTYPE_SIZE) { | if (bra_option_len != UPGT_BRA_FWTYPE_SIZE) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
▲ Show 20 Lines • Show All 511 Lines • ▼ Show 20 Lines | setup: | ||||
UPGT_STAT_DEC(sc, st_tx_pending); | UPGT_STAT_DEC(sc, st_tx_pending); | ||||
STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); | STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); | ||||
UPGT_STAT_INC(sc, st_tx_active); | UPGT_STAT_INC(sc, st_tx_active); | ||||
usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); | usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); | ||||
usbd_transfer_submit(xfer); | usbd_transfer_submit(xfer); | ||||
upgt_start(sc); | upgt_start(sc); | ||||
break; | break; | ||||
default: | default: | ||||
avosAuthorUnsubmitted Not Done Inline ActionsIMHO, this code path will never work: typically error handling duplicates USB_ST_TRANSFERRED event with non-zero status code passed to ieee80211_tx_complete(). avos: IMHO, this code path will never work: typically error handling duplicates USB_ST_TRANSFERRED… | |||||
data = STAILQ_FIRST(&sc->sc_tx_active); | data = STAILQ_FIRST(&sc->sc_tx_active); | ||||
if (data == NULL) | if (data == NULL) | ||||
goto setup; | goto setup; | ||||
if (data->ni != NULL) { | if (data->ni != NULL) { | ||||
if_inc_counter(data->ni->ni_vap->iv_ifp, | if_inc_counter(data->ni->ni_vap->iv_ifp, | ||||
IFCOUNTER_OERRORS, 1); | IFCOUNTER_OERRORS, 1); | ||||
ieee80211_free_node(data->ni); | ieee80211_free_node(data->ni); | ||||
data->ni = NULL; | data->ni = NULL; | ||||
Show All 31 Lines |
missing range checks for eeprom_len being valid.