1) Fix max frame length check to account for the firmware's Rx result
header in the buffer, which contains two uint16_t fields.
Frame data begins after this header.
2) Do not write to mbuf length fields before the mbuf has been removed
from the Rx ring.
Based on dragonfly commit 96eaecf93d9f731459a0df8efc72cfad034320bd
by Imre Vadasz.
Tested on 8260; ping and tcpbench still work.
ok?
diff refs/heads/master refs/heads/iwm-mbuf-hacks
blob - 038e6a63dfff113b525bb1e9a30c935996535569
blob + b586f473be83a7a68e251700242ba19baa60d83c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -3540,46 +3540,45 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_pac
rx_res = (struct iwm_rx_mpdu_res_start *)pkt->data;
wh = (struct ieee80211_frame *)(pkt->data + sizeof(*rx_res));
len = le16toh(rx_res->byte_count);
if (len < IEEE80211_MIN_LEN) {
ic->ic_stats.is_rx_tooshort++;
IC2IFP(ic)->if_ierrors++;
return;
}
- if (len > IWM_RBUF_SIZE) {
+ if (len > IWM_RBUF_SIZE - sizeof(*rx_res)) {
IC2IFP(ic)->if_ierrors++;
return;
}
rx_pkt_status = le32toh(*(uint32_t *)(pkt->data +
sizeof(*rx_res) + len));
- m = data->m;
- m->m_data = pkt->data + sizeof(*rx_res);
- m->m_pkthdr.len = m->m_len = len;
-
if (__predict_false(phy_info->cfg_phy_cnt > 20))
return;
if (!(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_CRC_OK) ||
!(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_OVERRUN_OK))
return; /* drop */
+ m = data->m;
+ if (iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0)
+ return;
+ m->m_data = pkt->data + sizeof(*rx_res);
+ m->m_pkthdr.len = m->m_len = len;
+
device_timestamp = le32toh(phy_info->system_timestamp);
if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_RX_ENERGY_API) {
rssi = iwm_get_signal_strength(sc, phy_info);
} else {
rssi = iwm_calc_rssi(sc, phy_info);
}
rssi = (0 - IWM_MIN_DBM) + rssi; /* normalize */
rssi = MIN(rssi, ic->ic_max_rssi); /* clip to max. 100% */
-
- if (iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0)
- return;
chanidx = letoh32(phy_info->channel);
if (chanidx < 0 || chanidx >= nitems(ic->ic_channels))
chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
ni = ieee80211_find_rxnode(ic, wh);
if (ni == ic->ic_bss) {
/*