Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/usb/wlan/if_uath.c
Show First 20 Lines • Show All 2,195 Lines • ▼ Show 20 Lines | uath_sysctl_node(struct uath_softc *sc) | ||||
UATH_SYSCTL_STAT_ADD32(ctx, child, "tx_inactive", | UATH_SYSCTL_STAT_ADD32(ctx, child, "tx_inactive", | ||||
&stats->st_tx_inactive, "Inactive numbers in TX queue"); | &stats->st_tx_inactive, "Inactive numbers in TX queue"); | ||||
UATH_SYSCTL_STAT_ADD32(ctx, child, "tx_pending", | UATH_SYSCTL_STAT_ADD32(ctx, child, "tx_pending", | ||||
&stats->st_tx_pending, "Pending numbers in TX queue"); | &stats->st_tx_pending, "Pending numbers in TX queue"); | ||||
} | } | ||||
#undef UATH_SYSCTL_STAT_ADD32 | #undef UATH_SYSCTL_STAT_ADD32 | ||||
CTASSERT(sizeof(u_int) >= sizeof(uint32_t)); | |||||
static void | static void | ||||
uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd) | uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd) | ||||
{ | { | ||||
struct uath_cmd_hdr *hdr; | struct uath_cmd_hdr *hdr; | ||||
int dlen; | uint32_t dlen; | ||||
hdr = (struct uath_cmd_hdr *)cmd->buf; | hdr = (struct uath_cmd_hdr *)cmd->buf; | ||||
/* NB: msgid is passed thru w/o byte swapping */ | /* NB: msgid is passed thru w/o byte swapping */ | ||||
#ifdef UATH_DEBUG | #ifdef UATH_DEBUG | ||||
if (sc->sc_debug & UATH_DEBUG_CMDS) { | if (sc->sc_debug & UATH_DEBUG_CMDS) { | ||||
int len = be32toh(hdr->len); | uint32_t len = be32toh(hdr->len); | ||||
printf("%s: %s [ix %u] len %u status %u\n", | printf("%s: %s [ix %u] len %u status %u\n", | ||||
__func__, uath_codename(be32toh(hdr->code)), | __func__, uath_codename(be32toh(hdr->code)), | ||||
hdr->msgid, len, be32toh(hdr->magic)); | hdr->msgid, len, be32toh(hdr->magic)); | ||||
if (sc->sc_debug & UATH_DEBUG_CMDS_DUMP) | if (sc->sc_debug & UATH_DEBUG_CMDS_DUMP) | ||||
uath_dump_cmd(cmd->buf, | uath_dump_cmd(cmd->buf, | ||||
len > UATH_MAX_CMDSZ ? sizeof(*hdr) : len, '-'); | len > UATH_MAX_CMDSZ ? sizeof(*hdr) : len, '-'); | ||||
} | } | ||||
#endif | #endif | ||||
hdr->code = be32toh(hdr->code); | hdr->code = be32toh(hdr->code); | ||||
hdr->len = be32toh(hdr->len); | hdr->len = be32toh(hdr->len); | ||||
hselasky: If hdr->len comes from HW, please verify that value is valid! | |||||
Done Inline ActionsDone in uath_intr_rx_callback() avos: Done in uath_intr_rx_callback() | |||||
hdr->magic = be32toh(hdr->magic); /* target status on return */ | hdr->magic = be32toh(hdr->magic); /* target status on return */ | ||||
switch (hdr->code & 0xff) { | switch (hdr->code & 0xff) { | ||||
/* reply to a read command */ | /* reply to a read command */ | ||||
default: | default: | ||||
dlen = hdr->len - sizeof(*hdr); | dlen = hdr->len - sizeof(*hdr); | ||||
Done Inline ActionsMissing upper range check? hselasky: Missing upper range check? | |||||
if (dlen < 0) { | |||||
device_printf(sc->sc_dev, | |||||
"Invalid header length %d\n", dlen); | |||||
return; | |||||
} | |||||
DPRINTF(sc, UATH_DEBUG_RX_PROC | UATH_DEBUG_RECV_ALL, | DPRINTF(sc, UATH_DEBUG_RX_PROC | UATH_DEBUG_RECV_ALL, | ||||
"%s: code %d data len %u\n", | "%s: code %d data len %u\n", | ||||
__func__, hdr->code & 0xff, dlen); | __func__, hdr->code & 0xff, dlen); | ||||
/* | /* | ||||
* The first response from the target after the | * The first response from the target after the | ||||
* HOST_AVAILABLE has an invalid msgid so we must | * HOST_AVAILABLE has an invalid msgid so we must | ||||
* treat it specially. | * treat it specially. | ||||
*/ | */ | ||||
if (hdr->msgid < UATH_CMD_LIST_COUNT) { | if (hdr->msgid < UATH_CMD_LIST_COUNT) { | ||||
uint32_t *rp = (uint32_t *)(hdr+1); | uint32_t *rp = (uint32_t *)(hdr+1); | ||||
u_int olen; | u_int olen; | ||||
if (!(sizeof(*hdr) <= hdr->len && | if (!(sizeof(*hdr) <= hdr->len && | ||||
Done Inline ActionsCan you invert this code? It makes it more clear: !(a && b) == ((!a) || (!b)) if (hdr->len < sizeof(*hdr) || hdr->len >= UATH_MAX_CMDSZ) hselasky: Can you invert this code? It makes it more clear:
!(a && b) == ((!a) || (!b))
if (hdr->len <… | |||||
hdr->len < UATH_MAX_CMDSZ)) { | hdr->len < UATH_MAX_CMDSZ)) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: invalid WDC msg length %u; " | "%s: invalid WDC msg length %u; " | ||||
"msg ignored\n", __func__, hdr->len); | "msg ignored\n", __func__, hdr->len); | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Calculate return/receive payload size; the | * Calculate return/receive payload size; the | ||||
* first word, if present, always gives the | * first word, if present, always gives the | ||||
* number of bytes--unless it's 0 in which | * number of bytes--unless it's 0 in which | ||||
* case a single 32-bit word should be present. | * case a single 32-bit word should be present. | ||||
*/ | */ | ||||
if (dlen >= (int)sizeof(uint32_t)) { | if (dlen >= sizeof(uint32_t)) { | ||||
olen = be32toh(rp[0]); | olen = be32toh(rp[0]); | ||||
dlen -= sizeof(uint32_t); | dlen -= sizeof(uint32_t); | ||||
if (olen == 0) { | if (olen == 0) { | ||||
/* convention is 0 =>'s one word */ | /* convention is 0 =>'s one word */ | ||||
olen = sizeof(uint32_t); | olen = sizeof(uint32_t); | ||||
/* XXX KASSERT(olen == dlen ) */ | /* XXX KASSERT(olen == dlen ) */ | ||||
} | } | ||||
} else | } else | ||||
olen = 0; | olen = 0; | ||||
if (cmd->odata != NULL) { | if (cmd->odata != NULL) { | ||||
/* NB: cmd->olen validated in uath_cmd */ | /* NB: cmd->olen validated in uath_cmd */ | ||||
if (olen > (u_int)cmd->olen) { | if (olen > (u_int)cmd->olen) { | ||||
/* XXX complain? */ | /* XXX complain? */ | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: cmd 0x%x olen %u cmd olen %u\n", | "%s: cmd 0x%x olen %u cmd olen %u\n", | ||||
__func__, hdr->code, olen, | __func__, hdr->code, olen, | ||||
cmd->olen); | cmd->olen); | ||||
olen = cmd->olen; | olen = cmd->olen; | ||||
} | } | ||||
if (olen > (u_int)dlen) { | if (olen > dlen) { | ||||
/* XXX complain, shouldn't happen */ | /* XXX complain, shouldn't happen */ | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: cmd 0x%x olen %u dlen %u\n", | "%s: cmd 0x%x olen %u dlen %u\n", | ||||
__func__, hdr->code, olen, dlen); | __func__, hdr->code, olen, dlen); | ||||
olen = dlen; | olen = dlen; | ||||
} | } | ||||
/* XXX have submitter do this */ | /* XXX have submitter do this */ | ||||
/* copy answer into caller's supplied buffer */ | /* copy answer into caller's supplied buffer */ | ||||
bcopy(&rp[1], cmd->odata, olen); | bcopy(&rp[1], cmd->odata, olen); | ||||
cmd->olen = olen; | cmd->olen = olen; | ||||
} | } | ||||
} | } | ||||
wakeup_one(cmd); /* wake up caller */ | wakeup_one(cmd); /* wake up caller */ | ||||
break; | break; | ||||
case WDCMSG_TARGET_START: | case WDCMSG_TARGET_START: | ||||
if (hdr->msgid >= UATH_CMD_LIST_COUNT) { | if (hdr->msgid >= UATH_CMD_LIST_COUNT) { | ||||
/* XXX */ | /* XXX */ | ||||
return; | return; | ||||
} | } | ||||
dlen = hdr->len - sizeof(*hdr); | dlen = hdr->len - sizeof(*hdr); | ||||
if (dlen != (int)sizeof(uint32_t)) { | if (dlen != sizeof(uint32_t)) { | ||||
/* XXX something wrong */ | device_printf(sc->sc_dev, | ||||
"%s: dlen (%u) != %zu!\n", | |||||
__func__, dlen, sizeof(uint32_t)); | |||||
return; | return; | ||||
} | } | ||||
/* XXX have submitter do this */ | /* XXX have submitter do this */ | ||||
/* copy answer into caller's supplied buffer */ | /* copy answer into caller's supplied buffer */ | ||||
bcopy(hdr+1, cmd->odata, sizeof(uint32_t)); | bcopy(hdr+1, cmd->odata, sizeof(uint32_t)); | ||||
cmd->olen = sizeof(uint32_t); | cmd->olen = sizeof(uint32_t); | ||||
wakeup_one(cmd); /* wake up caller */ | wakeup_one(cmd); /* wake up caller */ | ||||
break; | break; | ||||
Show All 12 Lines | #endif | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
uath_intr_rx_callback(struct usb_xfer *xfer, usb_error_t error) | uath_intr_rx_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct uath_softc *sc = usbd_xfer_softc(xfer); | struct uath_softc *sc = usbd_xfer_softc(xfer); | ||||
struct uath_cmd *cmd; | struct uath_cmd *cmd; | ||||
struct uath_cmd_hdr *hdr; | |||||
struct usb_page_cache *pc; | struct usb_page_cache *pc; | ||||
int actlen; | int actlen; | ||||
usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | ||||
UATH_ASSERT_LOCKED(sc); | UATH_ASSERT_LOCKED(sc); | ||||
switch (USB_GET_STATE(xfer)) { | switch (USB_GET_STATE(xfer)) { | ||||
case USB_ST_TRANSFERRED: | case USB_ST_TRANSFERRED: | ||||
cmd = STAILQ_FIRST(&sc->sc_cmd_waiting); | cmd = STAILQ_FIRST(&sc->sc_cmd_waiting); | ||||
if (cmd == NULL) | if (cmd == NULL) | ||||
goto setup; | goto setup; | ||||
STAILQ_REMOVE_HEAD(&sc->sc_cmd_waiting, next); | STAILQ_REMOVE_HEAD(&sc->sc_cmd_waiting, next); | ||||
UATH_STAT_DEC(sc, st_cmd_waiting); | UATH_STAT_DEC(sc, st_cmd_waiting); | ||||
STAILQ_INSERT_TAIL(&sc->sc_cmd_inactive, cmd, next); | STAILQ_INSERT_TAIL(&sc->sc_cmd_inactive, cmd, next); | ||||
UATH_STAT_INC(sc, st_cmd_inactive); | UATH_STAT_INC(sc, st_cmd_inactive); | ||||
KASSERT(actlen >= (int)sizeof(struct uath_cmd_hdr), | if (actlen < sizeof(struct uath_cmd_hdr)) { | ||||
("short xfer error")); | device_printf(sc->sc_dev, | ||||
"%s: short xfer error (actlen %d)\n", | |||||
__func__, actlen); | |||||
goto setup; | |||||
} | |||||
pc = usbd_xfer_get_frame(xfer, 0); | pc = usbd_xfer_get_frame(xfer, 0); | ||||
usbd_copy_out(pc, 0, cmd->buf, actlen); | usbd_copy_out(pc, 0, cmd->buf, actlen); | ||||
hdr = (struct uath_cmd_hdr *)cmd->buf; | |||||
hdr->len = be32toh(hdr->len); | |||||
if (hdr->len > actlen) { | |||||
Done Inline Actionsif (hdr->len > (uint32_t)actlen) hselasky: if (hdr->len > (uint32_t)actlen) | |||||
device_printf(sc->sc_dev, | |||||
"%s: truncated xfer (len %u, actlen %d)\n", | |||||
__func__, hdr->len, actlen); | |||||
goto setup; | |||||
} | |||||
uath_cmdeof(sc, cmd); | uath_cmdeof(sc, cmd); | ||||
case USB_ST_SETUP: | case USB_ST_SETUP: | ||||
setup: | setup: | ||||
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); | usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); | ||||
usbd_transfer_submit(xfer); | usbd_transfer_submit(xfer); | ||||
break; | break; | ||||
default: | default: | ||||
if (error != USB_ERR_CANCELLED) { | if (error != USB_ERR_CANCELLED) { | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, | ||||
if (actlen < (int)UATH_MIN_RXBUFSZ) { | if (actlen < (int)UATH_MIN_RXBUFSZ) { | ||||
DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, | DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, | ||||
"%s: wrong xfer size (len=%d)\n", __func__, actlen); | "%s: wrong xfer size (len=%d)\n", __func__, actlen); | ||||
counter_u64_add(ic->ic_ierrors, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
chunk = (struct uath_chunk *)data->buf; | chunk = (struct uath_chunk *)data->buf; | ||||
if (chunk->seqnum == 0 && chunk->flags == 0 && chunk->length == 0) { | chunklen = be16toh(chunk->length); | ||||
if (chunk->seqnum == 0 && chunk->flags == 0 && chunklen == 0) { | |||||
device_printf(sc->sc_dev, "%s: strange response\n", __func__); | device_printf(sc->sc_dev, "%s: strange response\n", __func__); | ||||
counter_u64_add(ic->ic_ierrors, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
UATH_RESET_INTRX(sc); | UATH_RESET_INTRX(sc); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
if (chunklen > actlen) { | |||||
device_printf(sc->sc_dev, | |||||
"%s: invalid chunk length (len %u > actlen %d)\n", | |||||
__func__, chunklen, actlen); | |||||
counter_u64_add(ic->ic_ierrors, 1); | |||||
/* XXX cleanup? */ | |||||
UATH_RESET_INTRX(sc); | |||||
return (NULL); | |||||
} | |||||
if (chunk->seqnum != sc->sc_intrx_nextnum) { | if (chunk->seqnum != sc->sc_intrx_nextnum) { | ||||
DPRINTF(sc, UATH_DEBUG_XMIT, "invalid seqnum %d, expected %d\n", | DPRINTF(sc, UATH_DEBUG_XMIT, "invalid seqnum %d, expected %d\n", | ||||
chunk->seqnum, sc->sc_intrx_nextnum); | chunk->seqnum, sc->sc_intrx_nextnum); | ||||
UATH_STAT_INC(sc, st_badchunkseqnum); | UATH_STAT_INC(sc, st_badchunkseqnum); | ||||
if (sc->sc_intrx_head != NULL) | if (sc->sc_intrx_head != NULL) | ||||
m_freem(sc->sc_intrx_head); | m_freem(sc->sc_intrx_head); | ||||
UATH_RESET_INTRX(sc); | UATH_RESET_INTRX(sc); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* check multi-chunk frames */ | /* check multi-chunk frames */ | ||||
if ((chunk->seqnum == 0 && !(chunk->flags & UATH_CFLAGS_FINAL)) || | if ((chunk->seqnum == 0 && !(chunk->flags & UATH_CFLAGS_FINAL)) || | ||||
(chunk->seqnum != 0 && (chunk->flags & UATH_CFLAGS_FINAL)) || | (chunk->seqnum != 0 && (chunk->flags & UATH_CFLAGS_FINAL)) || | ||||
chunk->flags & UATH_CFLAGS_RXMSG) | chunk->flags & UATH_CFLAGS_RXMSG) | ||||
UATH_STAT_INC(sc, st_multichunk); | UATH_STAT_INC(sc, st_multichunk); | ||||
chunklen = be16toh(chunk->length); | if (chunk->flags & UATH_CFLAGS_FINAL) { | ||||
Done Inline Actionschunklen should also be checked against actlen ??? hselasky: chunklen should also be checked against actlen ??? | |||||
if (chunk->flags & UATH_CFLAGS_FINAL) | if (chunklen < sizeof(struct uath_rx_desc)) { | ||||
device_printf(sc->sc_dev, | |||||
"%s: invalid chunk length %d\n", | |||||
__func__, chunklen); | |||||
counter_u64_add(ic->ic_ierrors, 1); | |||||
if (sc->sc_intrx_head != NULL) | |||||
m_freem(sc->sc_intrx_head); | |||||
UATH_RESET_INTRX(sc); | |||||
return (NULL); | |||||
} | |||||
chunklen -= sizeof(struct uath_rx_desc); | chunklen -= sizeof(struct uath_rx_desc); | ||||
} | |||||
if (chunklen > 0 && | if (chunklen > 0 && | ||||
(!(chunk->flags & UATH_CFLAGS_FINAL) || !(chunk->seqnum == 0))) { | (!(chunk->flags & UATH_CFLAGS_FINAL) || !(chunk->seqnum == 0))) { | ||||
/* we should use intermediate RX buffer */ | /* we should use intermediate RX buffer */ | ||||
if (chunk->seqnum == 0) | if (chunk->seqnum == 0) | ||||
UATH_RESET_INTRX(sc); | UATH_RESET_INTRX(sc); | ||||
if ((sc->sc_intrx_len + sizeof(struct uath_rx_desc) + | if ((sc->sc_intrx_len + sizeof(struct uath_rx_desc) + | ||||
chunklen) > UATH_MAX_INTRX_SIZE) { | chunklen) > UATH_MAX_INTRX_SIZE) { | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, | ||||
/* | /* | ||||
* if the frame is not set UATH_CFLAGS_RXMSG, then rx descriptor is | * if the frame is not set UATH_CFLAGS_RXMSG, then rx descriptor is | ||||
* located at the end, 32-bit aligned | * located at the end, 32-bit aligned | ||||
*/ | */ | ||||
desc = (chunk->flags & UATH_CFLAGS_RXMSG) ? | desc = (chunk->flags & UATH_CFLAGS_RXMSG) ? | ||||
(struct uath_rx_desc *)(chunk + 1) : | (struct uath_rx_desc *)(chunk + 1) : | ||||
(struct uath_rx_desc *)(((uint8_t *)chunk) + | (struct uath_rx_desc *)(((uint8_t *)chunk) + | ||||
sizeof(struct uath_chunk) + be16toh(chunk->length) - | sizeof(struct uath_chunk) + be16toh(chunk->length) - | ||||
sizeof(struct uath_rx_desc)); | sizeof(struct uath_rx_desc)); | ||||
if ((uint8_t *)chunk + actlen - sizeof(struct uath_rx_desc) < | |||||
(uint8_t *)desc) { | |||||
device_printf(sc->sc_dev, | |||||
"%s: wrong Rx descriptor pointer " | |||||
"(desc %p chunk %p actlen %d)\n", | |||||
__func__, desc, chunk, actlen); | |||||
counter_u64_add(ic->ic_ierrors, 1); | |||||
if (sc->sc_intrx_head != NULL) | |||||
m_freem(sc->sc_intrx_head); | |||||
UATH_RESET_INTRX(sc); | |||||
return (NULL); | |||||
} | |||||
Done Inline ActionsAre the offsets and payloads within the USB buffer and below actlen ? hselasky: Are the offsets and payloads within the USB buffer and below actlen ? | |||||
*pdesc = desc; | *pdesc = desc; | ||||
DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, | DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, | ||||
"%s: frame len %u code %u status %u rate %u antenna %u " | "%s: frame len %u code %u status %u rate %u antenna %u " | ||||
"rssi %d channel %u phyerror %u connix %u decrypterror %u " | "rssi %d channel %u phyerror %u connix %u decrypterror %u " | ||||
"keycachemiss %u\n", __func__, be32toh(desc->framelen) | "keycachemiss %u\n", __func__, be32toh(desc->framelen) | ||||
, be32toh(desc->code), be32toh(desc->status), be32toh(desc->rate) | , be32toh(desc->code), be32toh(desc->status), be32toh(desc->rate) | ||||
, be32toh(desc->antenna), be32toh(desc->rssi), be32toh(desc->channel) | , be32toh(desc->antenna), be32toh(desc->rssi), be32toh(desc->channel) | ||||
Show All 11 Lines | if (be32toh(desc->len) > MCLBYTES) { | ||||
UATH_RESET_INTRX(sc); | UATH_RESET_INTRX(sc); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
uath_update_rxstat(sc, be32toh(desc->status)); | uath_update_rxstat(sc, be32toh(desc->status)); | ||||
/* finalize mbuf */ | /* finalize mbuf */ | ||||
if (sc->sc_intrx_head == NULL) { | if (sc->sc_intrx_head == NULL) { | ||||
m->m_pkthdr.len = m->m_len = | uint32_t framelen; | ||||
be32toh(desc->framelen) - UATH_RX_DUMMYSIZE; | |||||
framelen = be32toh(desc->framelen) - UATH_RX_DUMMYSIZE; | |||||
if (framelen > actlen - sizeof(struct uath_chunk)) { | |||||
device_printf(sc->sc_dev, | |||||
"%s: wrong frame length (%u, actlen %d)!\n", | |||||
__func__, framelen, actlen); | |||||
counter_u64_add(ic->ic_ierrors, 1); | |||||
if (sc->sc_intrx_head != NULL) | |||||
m_freem(sc->sc_intrx_head); | |||||
UATH_RESET_INTRX(sc); | |||||
return (NULL); | |||||
} | |||||
m->m_pkthdr.len = m->m_len = framelen; | |||||
Done Inline ActionsMissing upper and lower checks for desc->framelen ! hselasky: Missing upper and lower checks for desc->framelen ! | |||||
Done Inline ActionsAdd this check first? Or is it redundant? cast: actlen - sizeof(struct uath_chunk) to uint32_t: framelen > (uint32_t)(actlen - sizeof(struct uath_chunk)) hselasky: Add this check first? Or is it redundant?
actlen < sizeof(struct uath_chunk) ||
cast: actlen… | |||||
Done Inline ActionsAlready checked at the top of the function ('if (actlen < (int)UATH_MIN_RXBUFSZ)') avos: Already checked at the top of the function ('if (actlen < (int)UATH_MIN_RXBUFSZ)') | |||||
m->m_data += sizeof(struct uath_chunk); | m->m_data += sizeof(struct uath_chunk); | ||||
} else { | } else { | ||||
mp = sc->sc_intrx_head; | mp = sc->sc_intrx_head; | ||||
mp->m_flags |= M_PKTHDR; | mp->m_flags |= M_PKTHDR; | ||||
mp->m_pkthdr.len = sc->sc_intrx_len; | mp->m_pkthdr.len = sc->sc_intrx_len; | ||||
m = mp; | m = mp; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 200 Lines • Show Last 20 Lines |
If hdr->len comes from HW, please verify that value is valid!