Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/usb/wlan/if_upgt.c
Show First 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | |||||
static int upgt_fw_verify(struct upgt_softc *); | static int upgt_fw_verify(struct upgt_softc *); | ||||
static int upgt_mem_init(struct upgt_softc *); | static int upgt_mem_init(struct upgt_softc *); | ||||
static int upgt_fw_load(struct upgt_softc *); | static int upgt_fw_load(struct upgt_softc *); | ||||
static int upgt_fw_copy(const uint8_t *, char *, int); | static int upgt_fw_copy(const uint8_t *, char *, int); | ||||
static uint32_t upgt_crc32_le(const void *, size_t); | static uint32_t upgt_crc32_le(const void *, size_t); | ||||
static struct mbuf * | static struct mbuf * | ||||
upgt_rxeof(struct usb_xfer *, struct upgt_data *, int *); | upgt_rxeof(struct usb_xfer *, struct upgt_data *, int *); | ||||
static struct mbuf * | static struct mbuf * | ||||
upgt_rx(struct upgt_softc *, uint8_t *, int, int *); | upgt_rx(struct upgt_softc *, uint8_t *, uint16_t, int *); | ||||
static void upgt_txeof(struct usb_xfer *, struct upgt_data *); | static void upgt_txeof(struct usb_xfer *, struct upgt_data *); | ||||
static int upgt_eeprom_read(struct upgt_softc *); | static int upgt_eeprom_read(struct upgt_softc *); | ||||
static int upgt_eeprom_parse(struct upgt_softc *); | static int upgt_eeprom_parse(struct upgt_softc *); | ||||
static void upgt_eeprom_parse_hwrx(struct upgt_softc *, uint8_t *); | static void upgt_eeprom_parse_hwrx(struct upgt_softc *, uint8_t *); | ||||
static void upgt_eeprom_parse_freq3(struct upgt_softc *, uint8_t *, int); | static void upgt_eeprom_parse_freq3(struct upgt_softc *, uint8_t *, int); | ||||
static void upgt_eeprom_parse_freq4(struct upgt_softc *, uint8_t *, int); | static void upgt_eeprom_parse_freq4(struct upgt_softc *, uint8_t *, int); | ||||
static void upgt_eeprom_parse_freq6(struct upgt_softc *, uint8_t *, int); | static void upgt_eeprom_parse_freq6(struct upgt_softc *, uint8_t *, int); | ||||
static uint32_t upgt_chksum_le(const uint32_t *, size_t); | static uint32_t upgt_chksum_le(const uint32_t *, size_t); | ||||
▲ Show 20 Lines • Show All 171 Lines • ▼ Show 20 Lines | #endif | ||||
DPRINTF(sc, UPGT_DEBUG_FW, "memory address frame start=0x%08x\n", | DPRINTF(sc, UPGT_DEBUG_FW, "memory address frame start=0x%08x\n", | ||||
sc->sc_memaddr_frame_start); | sc->sc_memaddr_frame_start); | ||||
DPRINTF(sc, UPGT_DEBUG_FW, "memory address frame end=0x%08x\n", | DPRINTF(sc, UPGT_DEBUG_FW, "memory address frame end=0x%08x\n", | ||||
sc->sc_memaddr_frame_end); | sc->sc_memaddr_frame_end); | ||||
DPRINTF(sc, UPGT_DEBUG_FW, "memory address rx start=0x%08x\n", | DPRINTF(sc, UPGT_DEBUG_FW, "memory address rx start=0x%08x\n", | ||||
sc->sc_memaddr_rx_start); | sc->sc_memaddr_rx_start); | ||||
upgt_mem_init(sc); | error = upgt_mem_init(sc); | ||||
if (error) | |||||
goto fail4; | |||||
/* Load the firmware. */ | /* Load the firmware. */ | ||||
error = upgt_fw_load(sc); | error = upgt_fw_load(sc); | ||||
if (error) | if (error) | ||||
goto fail4; | goto fail4; | ||||
/* Read the whole EEPROM content and parse it. */ | /* Read the whole EEPROM content and parse it. */ | ||||
error = upgt_eeprom_read(sc); | error = upgt_eeprom_read(sc); | ||||
▲ Show 20 Lines • Show All 720 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 270 Lines • ▼ Show 20 Lines | |||||
static struct mbuf * | static struct mbuf * | ||||
upgt_rxeof(struct usb_xfer *xfer, struct upgt_data *data, int *rssi) | upgt_rxeof(struct usb_xfer *xfer, struct upgt_data *data, int *rssi) | ||||
{ | { | ||||
struct mbuf *m = NULL; | struct mbuf *m = NULL; | ||||
struct upgt_softc *sc = usbd_xfer_softc(xfer); | struct upgt_softc *sc = usbd_xfer_softc(xfer); | ||||
struct upgt_lmac_header *header; | struct upgt_lmac_header *header; | ||||
struct upgt_lmac_eeprom *eeprom; | struct upgt_lmac_eeprom *eeprom; | ||||
uint8_t h1_type; | uint8_t h1_type; | ||||
uint16_t h2_type; | uint16_t h2_type, pkglen; | ||||
int actlen, sumlen; | int actlen, sumlen; | ||||
usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); | usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); | ||||
UPGT_ASSERT_LOCKED(sc); | UPGT_ASSERT_LOCKED(sc); | ||||
if (actlen < 1) | if (actlen < 1) | ||||
return (NULL); | return (NULL); | ||||
Show All 15 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); | ||||
int buf_offset = sizeof(struct upgt_lmac_eeprom) + 4; | |||||
hselasky: missing range checks for eeprom_len being valid. | |||||
if (eeprom_len > actlen - buf_offset || | |||||
eeprom_len > sizeof(sc->sc_eeprom) - eeprom_offset) { | |||||
device_printf(sc->sc_dev, | |||||
"%s: wrong eeprom length (%u) / offset (%u)!\n", | |||||
__func__, eeprom_len, eeprom_offset); | |||||
return (NULL); | |||||
} | |||||
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 + buf_offset, | ||||
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), | |||||
Done Inline Actionsmissing range check for header->header1.len being valid. hselasky: missing range check for header->header1.len being valid. | |||||
rssi); | pkglen = le16toh(header->header1.len); | ||||
if (actlen - 4 < pkglen) { | |||||
device_printf(sc->sc_dev, | |||||
"%s: actlen - 4 (%d) < pkglen (%d)!\n", | |||||
__func__, actlen - 4, pkglen); | |||||
return (NULL); | |||||
} | |||||
m = upgt_rx(sc, data->buf + 4, pkglen, 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 */ | ||||
DPRINTF(sc, UPGT_DEBUG_INTR, | DPRINTF(sc, UPGT_DEBUG_INTR, | ||||
Show All 17 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, uint16_t pkglen, int *rssi) | ||||
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; | ||||
if (pkglen < IEEE80211_ACK_LEN) { | |||||
device_printf(sc->sc_dev, | |||||
"%s: frame is too short! (pkglen %d)\n", | |||||
__func__, pkglen); | |||||
return (NULL); | |||||
} | |||||
if (pkglen >= MCLBYTES - ETHER_ALIGN) { | |||||
device_printf(sc->sc_dev, | |||||
"%s: A current mbuf storage is small (%d)\n", | |||||
__func__, pkglen + ETHER_ALIGN); | |||||
return (NULL); | |||||
} | |||||
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, | |||||
("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); | ||||
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! | |||||
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); | ||||
/* trim FCS */ | /* trim FCS */ | ||||
m->m_len = m->m_pkthdr.len = pkglen - IEEE80211_CRC_LEN; | m->m_len = m->m_pkthdr.len = pkglen - IEEE80211_CRC_LEN; | ||||
▲ Show 20 Lines • Show All 232 Lines • ▼ Show 20 Lines | upgt_fw_copy(const uint8_t *src, char *dst, int size) | ||||
return (i); | return (i); | ||||
} | } | ||||
static int | static int | ||||
upgt_mem_init(struct upgt_softc *sc) | upgt_mem_init(struct upgt_softc *sc) | ||||
{ | { | ||||
int i; | int i; | ||||
if ((uint64_t)(sc->sc_memaddr_frame_start + MCLBYTES) > | |||||
sc->sc_memaddr_frame_end) { | |||||
device_printf(sc->sc_dev, | |||||
"%s: start (%u) + MCLBYTES > end (%u)!\n", | |||||
__func__, sc->sc_memaddr_frame_start, | |||||
sc->sc_memaddr_frame_end); | |||||
return (EINVAL); | |||||
} | |||||
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. | ||||
*/ | */ | ||||
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; | ||||
} | } | ||||
/* Memory wrap check. */ | |||||
if (sc->sc_memaddr_frame_start > sc->sc_memory.page[i].addr) { | |||||
device_printf(sc->sc_dev, | |||||
"%s: frame_start (%u) is too large!\n", | |||||
__func__, sc->sc_memaddr_frame_start); | |||||
return (EINVAL); | |||||
} | |||||
if (sc->sc_memory.page[i].addr + MCLBYTES >= | if (sc->sc_memory.page[i].addr + MCLBYTES >= | ||||
sc->sc_memaddr_frame_end) | sc->sc_memaddr_frame_end) | ||||
break; | break; | ||||
DPRINTF(sc, UPGT_DEBUG_FW, "memory address page %d=0x%08x\n", | DPRINTF(sc, UPGT_DEBUG_FW, "memory address page %d=0x%08x\n", | ||||
i, sc->sc_memory.page[i].addr); | i, sc->sc_memory.page[i].addr); | ||||
} | } | ||||
Show All 21 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 + sizeof(*uc) <= fw->datasize; | |||||
offset += sizeof(*uc)) { | |||||
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 + sizeof(*uc) <= fw->datasize; offset += sizeof(*uc)) { | ||||
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 + sizeof(*uc) > 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 - sizeof(*bra_opt) && 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 > (size_t)(fw->datasize - offset - | |||||
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… | |||||
sizeof(*bra_opt)) || | |||||
bra_option_len / sizeof(*uc) != le32toh(bra_opt->len)) { | |||||
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, | ||||
"wrong UPGT_BRA_TYPE_FW len\n"); | "wrong UPGT_BRA_TYPE_FW len\n"); | ||||
Show All 22 Lines | case UPGT_BRA_TYPE_DEPIF: | ||||
DPRINTF(sc, UPGT_DEBUG_FW, | DPRINTF(sc, UPGT_DEBUG_FW, | ||||
"UPGT_BRA_TYPE_DEPIF len=%d\n", bra_option_len); | "UPGT_BRA_TYPE_DEPIF len=%d\n", bra_option_len); | ||||
break; | break; | ||||
case UPGT_BRA_TYPE_EXPIF: | case UPGT_BRA_TYPE_EXPIF: | ||||
DPRINTF(sc, UPGT_DEBUG_FW, | DPRINTF(sc, UPGT_DEBUG_FW, | ||||
"UPGT_BRA_TYPE_EXPIF len=%d\n", bra_option_len); | "UPGT_BRA_TYPE_EXPIF len=%d\n", bra_option_len); | ||||
break; | break; | ||||
case UPGT_BRA_TYPE_DESCR: | case UPGT_BRA_TYPE_DESCR: | ||||
if (sizeof(*descr) > fw->datasize - offset - | |||||
sizeof(*bra_opt) || | |||||
sizeof(*descr) > bra_option_len) { | |||||
device_printf(sc->sc_dev, "%s: no place for" | |||||
"'struct upgt_fw_bra_descr' (%zu / %u)\n", | |||||
__func__, | |||||
fw->datasize - offset - sizeof(*bra_opt), | |||||
bra_option_len); | |||||
error = EIO; | |||||
goto fail; | |||||
} | |||||
DPRINTF(sc, UPGT_DEBUG_FW, | DPRINTF(sc, UPGT_DEBUG_FW, | ||||
"UPGT_BRA_TYPE_DESCR len=%d\n", bra_option_len); | "UPGT_BRA_TYPE_DESCR len=%d\n", bra_option_len); | ||||
descr = (const struct upgt_fw_bra_descr *)bra_opt->data; | descr = (const struct upgt_fw_bra_descr *)bra_opt->data; | ||||
sc->sc_memaddr_frame_start = | sc->sc_memaddr_frame_start = | ||||
le32toh(descr->memaddr_space_start); | le32toh(descr->memaddr_space_start); | ||||
sc->sc_memaddr_frame_end = | sc->sc_memaddr_frame_end = | ||||
▲ Show 20 Lines • Show All 274 Lines • ▼ Show 20 Lines | upgt_gettxbuf(struct upgt_softc *sc) | ||||
return (bf); | return (bf); | ||||
} | } | ||||
static int | static int | ||||
upgt_tx_start(struct upgt_softc *sc, struct mbuf *m, struct ieee80211_node *ni, | upgt_tx_start(struct upgt_softc *sc, struct mbuf *m, struct ieee80211_node *ni, | ||||
struct upgt_data *data) | struct upgt_data *data) | ||||
{ | { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
int error = 0, len; | int error = 0; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_key *k; | struct ieee80211_key *k; | ||||
struct upgt_lmac_mem *mem; | struct upgt_lmac_mem *mem; | ||||
struct upgt_lmac_tx_desc *txdesc; | struct upgt_lmac_tx_desc *txdesc; | ||||
uint32_t len; | |||||
UPGT_ASSERT_LOCKED(sc); | UPGT_ASSERT_LOCKED(sc); | ||||
/* Calculate frame size. */ | |||||
len = sizeof(*mem) + sizeof(*txdesc) + m->m_pkthdr.len; | |||||
/* We need to align the frame to a 4 byte boundary. */ | |||||
len = (len + 3) & ~3; | |||||
if (len > MCLBYTES) { | |||||
device_printf(sc->sc_dev, | |||||
"%s: the frame %p is too big (%d)\n", | |||||
__func__, m, m->m_pkthdr.len); | |||||
error = EINVAL; | |||||
goto done; | |||||
} | |||||
upgt_set_led(sc, UPGT_LED_BLINK); | upgt_set_led(sc, UPGT_LED_BLINK); | ||||
/* | /* | ||||
* Software crypto. | * Software crypto. | ||||
*/ | */ | ||||
wh = mtod(m, struct ieee80211_frame *); | wh = mtod(m, struct ieee80211_frame *); | ||||
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { | ||||
k = ieee80211_crypto_encap(ni, m); | k = ieee80211_crypto_encap(ni, m); | ||||
Show All 40 Lines | if (ieee80211_radiotap_active_vap(vap)) { | ||||
tap->wt_rate = 0; /* XXX where to get from? */ | tap->wt_rate = 0; /* XXX where to get from? */ | ||||
ieee80211_radiotap_tx(vap, m); | ieee80211_radiotap_tx(vap, m); | ||||
} | } | ||||
/* copy frame below our TX descriptor header */ | /* copy frame below our TX descriptor header */ | ||||
m_copydata(m, 0, m->m_pkthdr.len, | m_copydata(m, 0, m->m_pkthdr.len, | ||||
data->buf + (sizeof(*mem) + sizeof(*txdesc))); | data->buf + (sizeof(*mem) + sizeof(*txdesc))); | ||||
/* calculate frame size */ | |||||
len = sizeof(*mem) + sizeof(*txdesc) + m->m_pkthdr.len; | |||||
/* we need to align the frame to a 4 byte boundary */ | |||||
len = (len + 3) & ~3; | |||||
/* calculate frame checksum */ | /* calculate frame checksum */ | ||||
mem->chksum = upgt_chksum_le((uint32_t *)txdesc, len - sizeof(*mem)); | mem->chksum = upgt_chksum_le((uint32_t *)txdesc, len - sizeof(*mem)); | ||||
data->ni = ni; | data->ni = ni; | ||||
data->m = m; | data->m = m; | ||||
data->buflen = len; | data->buflen = len; | ||||
DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: TX start data sending (%d bytes)\n", | DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: TX start data sending (%u bytes)\n", | ||||
__func__, len); | __func__, len); | ||||
KASSERT(len <= MCLBYTES, ("mbuf is small for saving data")); | |||||
upgt_bulk_tx(sc, data); | upgt_bulk_tx(sc, data); | ||||
done: | done: | ||||
/* | /* | ||||
* If we don't regulary read the device statistics, the RX queue | * If we don't regulary read the device statistics, the RX queue | ||||
* will stall. It's strange, but it works, so we keep reading | * will stall. It's strange, but it works, so we keep reading | ||||
* the statistics here. *shrug* | * the statistics here. *shrug* | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 105 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: | ||||
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.