Hi Stefan,

On Fri, Sep 13, 2019 at 02:10:12PM +0200, Stefan Sperling wrote:
> Updated diff, rebased on top of -current
> 
> If you were seeing throughput problems when testing this diff in the
> previous round, please try again.
> 
> I suspect such problems were due to the ifq drop issue which has since
> been fixed in -current. The diff below results in more packets per interrupt
> being delivered to the network stack which is exactly what made ifq drops
> more likely to occur. This should no longer be an issue.
> 
> I have tested this diff on 8265 and 7260 and I don't see any problems.

iwm0 at pci2 dev 0 function 0 "Intel Dual Band Wireless-AC 8265" rev 0x78, msi
iwm0: hw rev 0x230, fw ver 22.361476.0, address 38:37:8b:XX:XX:XX

I've tested monitor mode and it seems to work:

$ ifconfig iwm0
iwm0: flags=8847<UP,BROADCAST,DEBUG,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 38:37:8b:XX:XX:XX
        index 1 priority 4 llprio 3
        groups: wlan egress
        media: IEEE802.11 autoselect monitor
        status: active
        ieee80211: nwid linksys chan 11 bssid 00:1d:7e:XX:XX:XX 29%

I've used kismet-201607R1p0 package and I could see networks and packets
being reported. Testing with tcpdump(8) also showed traffic visible from
various access points around:

# tcpdump -c 3 -y IEEE802_11_RADIO -ni iwm0  
tcpdump: listening on iwm0, link-type IEEE802_11_RADIO
21:25:12.586606 802.11: beacon, ssid (net_092382), rates, ds, tim, xrates, rsn, 
htcaps, <radiotap v0, chan 11, 11g, sig 50dBm, noise 28dBm>
21:25:12.653411 802.11: beacon, ssid (linksys), rates, ds, tim, erp, 47:1, 
xrates, vendor, <radiotap v0, chan 11, 11g, sig 25dBm, noise 28dBm>
21:25:12.755803 802.11: beacon, ssid (linksys), rates, ds, tim, erp, 47:1, 
xrates, vendor, <radiotap v0, chan 11, 11g, sig 23dBm, noise 28dBm>

I see in tcpdump output that all beacons are reported with chan 11,
where I know some of the access points are not on channel 11. Not
sure is this expected. Other than that, I don't see anything
concerning.

Regards,
 Mikolaj

> diff refs/heads/master refs/heads/iwm-multirx
> blob - 20ce2cbe3d2c2994b9a498965a3c9f29a5f31c9c
> blob + d3baf8473bd86beb05eaed7eb6cb715f90790c46
> --- sys/dev/pci/if_iwm.c
> +++ sys/dev/pci/if_iwm.c
> @@ -367,8 +367,10 @@ int      iwm_get_signal_strength(struct iwm_softc *, 
> struct
>  void iwm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_rx_packet *,
>           struct iwm_rx_data *);
>  int  iwm_get_noise(const struct iwm_statistics_rx_non_phy *);
> -void iwm_rx_rx_mpdu(struct iwm_softc *, struct iwm_rx_packet *,
> -         struct iwm_rx_data *, struct mbuf_list *);
> +int  iwm_rx_frame(struct iwm_softc *, struct mbuf *, uint32_t,
> +         struct mbuf_list *);
> +int  iwm_ccmp_decap(struct iwm_softc *, struct mbuf *,
> +         struct ieee80211_node *);
>  void iwm_enable_ht_cck_fallback(struct iwm_softc *, struct iwm_node *);
>  void iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
>           struct iwm_node *);
> @@ -429,7 +431,7 @@ uint8_t   iwm_ridx2rate(struct ieee80211_rateset *, int)
>  int  iwm_rval2ridx(int);
>  void iwm_ack_rates(struct iwm_softc *, struct iwm_node *, int *, int *);
>  void iwm_mac_ctxt_cmd_common(struct iwm_softc *, struct iwm_node *,
> -         struct iwm_mac_ctx_cmd *, uint32_t, int);
> +         struct iwm_mac_ctx_cmd *, uint32_t);
>  void iwm_mac_ctxt_cmd_fill_sta(struct iwm_softc *, struct iwm_node *,
>           struct iwm_mac_data_sta *, int);
>  int  iwm_mac_ctxt_cmd(struct iwm_softc *, struct iwm_node *, uint32_t, int);
> @@ -470,6 +472,11 @@ const char *iwm_desc_lookup(uint32_t);
>  void iwm_nic_error(struct iwm_softc *);
>  void iwm_nic_umac_error(struct iwm_softc *);
>  #endif
> +void iwm_rx_mpdu(struct iwm_softc *, struct mbuf *, size_t,
> +         struct mbuf_list *);
> +int  iwm_rx_pkt_valid(struct iwm_rx_packet *);
> +void iwm_rx_pkt(struct iwm_softc *, struct iwm_rx_data *,
> +         struct mbuf_list *);
>  void iwm_notif_intr(struct iwm_softc *);
>  int  iwm_intr(void *);
>  int  iwm_match(struct device *, void *, void *);
> @@ -1723,7 +1730,6 @@ iwm_nic_rx_init(struct iwm_softc *sc)
>           IWM_FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL            |
>           IWM_FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY               |  /* HW bug */
>           IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL   |
> -         IWM_FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK        |
>           (IWM_RX_RB_TIMEOUT << IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) |
>           IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K            |
>           IWM_RX_QUEUE_SIZE_LOG << IWM_FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS);
> @@ -3429,56 +3435,24 @@ iwm_get_noise(const struct iwm_statistics_rx_non_phy *
>       return (nbant == 0) ? -127 : (total / nbant) - 107;
>  }
>  
> -void
> -iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
> -    struct iwm_rx_data *data, struct mbuf_list *ml)
> +int
> +iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, uint32_t rx_pkt_status,
> +    struct mbuf_list *ml)
>  {
>       struct ieee80211com *ic = &sc->sc_ic;
>       struct ieee80211_frame *wh;
>       struct ieee80211_node *ni;
>       struct ieee80211_rxinfo rxi;
>       struct ieee80211_channel *bss_chan;
> -     struct mbuf *m;
>       struct iwm_rx_phy_info *phy_info;
> -     struct iwm_rx_mpdu_res_start *rx_res;
>       int device_timestamp;
> -     uint32_t len;
> -     uint32_t rx_pkt_status;
>       int rssi, chanidx;
>       uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
>  
> -     bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE,
> -         BUS_DMASYNC_POSTREAD);
> -
>       phy_info = &sc->sc_last_phy_info;
> -     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 - sizeof(*rx_res)) {
> -             IC2IFP(ic)->if_ierrors++;
> -             return;
> -     }
> -     rx_pkt_status = le32toh(*(uint32_t *)(pkt->data +
> -         sizeof(*rx_res) + len));
> -
>       if (__predict_false(phy_info->cfg_phy_cnt > 20))
> -             return;
> +             return EINVAL;
>  
> -     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) {
> @@ -3493,6 +3467,7 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_pac
>       if (chanidx < 0 || chanidx >= nitems(ic->ic_channels))  
>               chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
>  
> +     wh = mtod(m, struct ieee80211_frame *);
>       ni = ieee80211_find_rxnode(ic, wh);
>       if (ni == ic->ic_bss) {
>               /* 
> @@ -3572,6 +3547,8 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_pac
>       if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
>               ni->ni_chan = bss_chan;
>       ieee80211_release_node(ic, ni);
> +
> +     return 0;
>  }
>  
>  void
> @@ -4521,6 +4498,7 @@ void
>  iwm_power_build_cmd(struct iwm_softc *sc, struct iwm_node *in,
>      struct iwm_mac_power_cmd *cmd)
>  {
> +     struct ieee80211com *ic = &sc->sc_ic;
>       struct ieee80211_node *ni = &in->in_ni;
>       int dtim_period, dtim_msec, keep_alive;
>  
> @@ -4542,7 +4520,8 @@ iwm_power_build_cmd(struct iwm_softc *sc, struct iwm_n
>       keep_alive = roundup(keep_alive, 1000) / 1000;
>       cmd->keep_alive_seconds = htole16(keep_alive);
>  
> -     cmd->flags = htole16(IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK);
> +     if (ic->ic_opmode != IEEE80211_M_MONITOR)
> +             cmd->flags = htole16(IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK);
>  }
>  
>  int
> @@ -4569,13 +4548,15 @@ iwm_power_mac_update_mode(struct iwm_softc *sc, struct
>  int
>  iwm_power_update_device(struct iwm_softc *sc)
>  {
> -     struct iwm_device_power_cmd cmd = {
> -             .flags = htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
> -     };
> +     struct iwm_device_power_cmd cmd = { };
> +     struct ieee80211com *ic = &sc->sc_ic;
>  
>       if (!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
>               return 0;
>  
> +     if (ic->ic_opmode != IEEE80211_M_MONITOR)
> +             cmd.flags = htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);
> +
>       return iwm_send_cmd_pdu(sc,
>           IWM_POWER_TABLE_CMD, 0, sizeof(cmd), &cmd);
>  }
> @@ -4637,7 +4618,12 @@ iwm_add_sta_cmd(struct iwm_softc *sc, struct iwm_node 
>                       add_sta_cmd.tfd_queue_msk |=
>                           htole32(1 << iwm_ac_to_tx_fifo[ac]);
>               }
> -             IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid);
> +             if (ic->ic_opmode == IEEE80211_M_MONITOR)
> +                     IEEE80211_ADDR_COPY(&add_sta_cmd.addr,
> +                         etherbroadcastaddr);
> +             else
> +                     IEEE80211_ADDR_COPY(&add_sta_cmd.addr,
> +                         in->in_ni.ni_bssid);
>       }
>       add_sta_cmd.add_modify = update ? 1 : 0;
>       add_sta_cmd.station_flags_msk
> @@ -5307,7 +5293,7 @@ iwm_ack_rates(struct iwm_softc *sc, struct iwm_node *i
>  
>  void
>  iwm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in,
> -    struct iwm_mac_ctx_cmd *cmd, uint32_t action, int assoc)
> +    struct iwm_mac_ctx_cmd *cmd, uint32_t action)
>  {
>  #define IWM_EXP2(x)  ((1 << (x)) - 1)        /* CWmin = 2^ECWmin - 1 */
>       struct ieee80211com *ic = &sc->sc_ic;
> @@ -5319,12 +5305,21 @@ iwm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct i
>           in->in_color));
>       cmd->action = htole32(action);
>  
> -     cmd->mac_type = htole32(IWM_FW_MAC_TYPE_BSS_STA);
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR)
> +             cmd->mac_type = htole32(IWM_FW_MAC_TYPE_LISTENER);
> +     else if (ic->ic_opmode == IEEE80211_M_STA)
> +             cmd->mac_type = htole32(IWM_FW_MAC_TYPE_BSS_STA);
> +     else
> +             panic("unsupported operating mode %d\n", ic->ic_opmode);
>       cmd->tsf_id = htole32(IWM_TSF_ID_A);
>  
>       IEEE80211_ADDR_COPY(cmd->node_addr, ic->ic_myaddr);
> -     IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR) {
> +             IEEE80211_ADDR_COPY(cmd->bssid_addr, etherbroadcastaddr);
> +             return;
> +     }
>  
> +     IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
>       iwm_ack_rates(sc, in, &cck_ack_rates, &ofdm_ack_rates);
>       cmd->cck_rates = htole32(cck_ack_rates);
>       cmd->ofdm_rates = htole32(ofdm_ack_rates);
> @@ -5415,6 +5410,7 @@ int
>  iwm_mac_ctxt_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action,
>      int assoc)
>  {
> +     struct ieee80211com *ic = &sc->sc_ic;
>       struct ieee80211_node *ni = &in->in_ni;
>       struct iwm_mac_ctx_cmd cmd;
>       int active = (sc->sc_flags & IWM_FLAG_MAC_ACTIVE);
> @@ -5426,11 +5422,19 @@ iwm_mac_ctxt_cmd(struct iwm_softc *sc, struct iwm_node
>  
>       memset(&cmd, 0, sizeof(cmd));
>  
> -     iwm_mac_ctxt_cmd_common(sc, in, &cmd, action, assoc);
> +     iwm_mac_ctxt_cmd_common(sc, in, &cmd, action);
>  
> -     /* Allow beacons to pass through as long as we are not associated or we
> -      * do not have dtim period information */
> -     if (!assoc || !ni->ni_associd || !ni->ni_dtimperiod)
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR) {
> +             cmd.filter_flags |= htole32(IWM_MAC_FILTER_IN_PROMISC |
> +                 IWM_MAC_FILTER_IN_CONTROL_AND_MGMT |
> +                 IWM_MAC_FILTER_IN_BEACON |
> +                 IWM_MAC_FILTER_IN_PROBE_REQUEST |
> +                 IWM_MAC_FILTER_IN_CRC32);
> +     } else if (!assoc || !ni->ni_associd || !ni->ni_dtimperiod)
> +             /* 
> +              * Allow beacons to pass through as long as we are not
> +              * associated or we do not have dtim period information.
> +              */
>               cmd.filter_flags |= htole32(IWM_MAC_FILTER_IN_BEACON);
>       else
>               iwm_mac_ctxt_cmd_fill_sta(sc, in, &cmd.sta, assoc);
> @@ -5654,7 +5658,10 @@ iwm_auth(struct iwm_softc *sc)
>  
>       splassert(IPL_NET);
>  
> -     sc->sc_phyctxt[0].channel = in->in_ni.ni_chan;
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR)
> +             sc->sc_phyctxt[0].channel = ic->ic_ibss_chan;
> +     else
> +             sc->sc_phyctxt[0].channel = in->in_ni.ni_chan;
>       err = iwm_phy_ctxt_cmd(sc, &sc->sc_phyctxt[0], 1, 1,
>           IWM_FW_CTXT_ACTION_MODIFY, 0);
>       if (err) {
> @@ -5688,6 +5695,9 @@ iwm_auth(struct iwm_softc *sc)
>       }
>       sc->sc_flags |= IWM_FLAG_STA_ACTIVE;
>  
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR)
> +             return 0;
> +
>       /*
>        * Prevent the FW from wandering off channel during association
>        * by "protecting" the session with a time event.
> @@ -5818,8 +5828,16 @@ iwm_run(struct iwm_softc *sc)
>  
>       splassert(IPL_NET);
>  
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR) {
> +             /* Add a MAC context and a sniffing STA. */
> +             err = iwm_auth(sc);
> +             if (err)
> +                     return err;
> +     }
> +
>       /* Configure Rx chains for MIMO. */
> -     if ((in->in_ni.ni_flags & IEEE80211_NODE_HT) &&
> +     if ((ic->ic_opmode == IEEE80211_M_MONITOR ||
> +         (in->in_ni.ni_flags & IEEE80211_NODE_HT)) &&
>           !sc->sc_nvm.sku_cap_mimo_disable) {
>               err = iwm_phy_ctxt_cmd(sc, &sc->sc_phyctxt[0],
>                   2, 2, IWM_FW_CTXT_ACTION_MODIFY, 0);
> @@ -5887,6 +5905,11 @@ iwm_run(struct iwm_softc *sc)
>       ieee80211_amrr_node_init(&sc->sc_amrr, &in->in_amn);
>       ieee80211_mira_node_init(&in->in_mn);
>  
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR) {
> +             iwm_led_blink_start(sc);
> +             return 0;
> +     }
> +
>       /* Start at lowest available bit-rate, AMRR will raise. */
>       in->in_ni.ni_txrate = 0;
>       in->in_ni.ni_txmcs = 0;
> @@ -5906,6 +5929,9 @@ iwm_run_stop(struct iwm_softc *sc)
>  
>       splassert(IPL_NET);
>  
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR)
> +             iwm_led_blink_stop(sc);
> +
>       err = iwm_sf_config(sc, IWM_SF_INIT_OFF);
>       if (err)
>               return err;
> @@ -6524,6 +6550,12 @@ iwm_init(struct ifnet *ifp)
>       ifq_clr_oactive(&ifp->if_snd);
>       ifp->if_flags |= IFF_RUNNING;
>  
> +     if (ic->ic_opmode == IEEE80211_M_MONITOR) {
> +             ic->ic_bss->ni_chan = ic->ic_ibss_chan;
> +             ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
> +             return 0;
> +     }
> +
>       ieee80211_begin_scan(ifp);
>  
>       /* 
> @@ -7003,38 +7035,105 @@ do {                                                 
>                 \
>  #define ADVANCE_RXQ(sc) (sc->rxq.cur = (sc->rxq.cur + 1) % 
> IWM_RX_RING_COUNT);
>  
>  void
> -iwm_notif_intr(struct iwm_softc *sc)
> +iwm_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, size_t maxlen,
> +    struct mbuf_list *ml)
>  {
> -     struct mbuf_list ml = MBUF_LIST_INITIALIZER();
> -     uint16_t hw;
> +     struct ieee80211com *ic = &sc->sc_ic;
> +     struct ifnet *ifp = IC2IFP(ic);
> +     struct iwm_rx_packet *pkt;
> +     struct iwm_rx_mpdu_res_start *rx_res;
> +     uint16_t len;
> +     uint32_t rx_pkt_status;
> +     int rxfail;
>  
> -     bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map,
> -         0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD);
> +     pkt = mtod(m, struct iwm_rx_packet *);
> +     rx_res = (struct iwm_rx_mpdu_res_start *)pkt->data;
> +     len = le16toh(rx_res->byte_count);
> +     if (len < IEEE80211_MIN_LEN) {
> +             ic->ic_stats.is_rx_tooshort++;
> +             IC2IFP(ic)->if_ierrors++;
> +             m_freem(m);
> +             return;
> +     }
> +     if (len + sizeof(*rx_res) + sizeof(rx_pkt_status) > maxlen ||
> +         len > IEEE80211_MAX_LEN) {
> +             IC2IFP(ic)->if_ierrors++;
> +             m_freem(m);
> +             return;
> +     }
>  
> -     hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff;
> -     hw &= (IWM_RX_RING_COUNT - 1);
> -     while (sc->rxq.cur != hw) {
> -             struct iwm_rx_data *data = &sc->rxq.data[sc->rxq.cur];
> -             struct iwm_rx_packet *pkt;
> -             int qid, idx, code, handled = 1;
> +     memcpy(&rx_pkt_status, pkt->data + sizeof(*rx_res) + len,
> +         sizeof(rx_pkt_status));
> +     rx_pkt_status = le32toh(rx_pkt_status);
> +     rxfail = ((rx_pkt_status & IWM_RX_MPDU_RES_STATUS_CRC_OK) == 0 ||
> +         (rx_pkt_status & IWM_RX_MPDU_RES_STATUS_OVERRUN_OK) == 0);
> +     if (rxfail) {
> +             ifp->if_ierrors++;
> +             m_freem(m);
> +             return;
> +     }
>  
> -             bus_dmamap_sync(sc->sc_dmat, data->map, 0, sizeof(*pkt),
> -                 BUS_DMASYNC_POSTREAD);
> -             pkt = mtod(data->m, struct iwm_rx_packet *);
> +     /* Extract the 802.11 frame. */
> +     m->m_data = (caddr_t)pkt->data + sizeof(*rx_res);
> +     m->m_pkthdr.len = m->m_len = len;
> +     if (iwm_rx_frame(sc, m, rx_pkt_status, ml) != 0) {
> +             ifp->if_ierrors++;
> +             m_freem(m);
> +     }
> +}
>  
> +int
> +iwm_rx_pkt_valid(struct iwm_rx_packet *pkt)
> +{
> +     int qid, idx, code;
> +
> +     code = IWM_WIDE_ID(pkt->hdr.flags, pkt->hdr.code);
> +     qid = pkt->hdr.qid & ~0x80;
> +     idx = pkt->hdr.idx;
> +
> +     if ((code == 0 && qid == 0 && idx == 0) ||
> +         pkt->len_n_flags == htole32(IWM_FH_RSCSR_FRAME_INVALID))
> +             return 0;
> +
> +     return 1;
> +}
> +
> +void
> +iwm_rx_pkt(struct iwm_softc *sc, struct iwm_rx_data *data, struct mbuf_list 
> *ml)
> +{
> +     struct ifnet *ifp = IC2IFP(&sc->sc_ic);
> +     struct iwm_rx_packet *pkt, *nextpkt;
> +     uint32_t offset = 0, nextoff = 0, nmpdu = 0, len;
> +     struct mbuf *m0, *m;
> +     const size_t minsz = sizeof(pkt->len_n_flags) + sizeof(pkt->hdr);
> +     size_t remain = IWM_RBUF_SIZE;
> +     int qid, idx, code, handled = 1;
> +
> +     bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE,
> +         BUS_DMASYNC_POSTREAD);
> +
> +     m0 = data->m;
> +     while (m0 && offset + minsz < IWM_RBUF_SIZE) {
> +             pkt = (struct iwm_rx_packet *)(m0->m_data + offset);
> +
> +             if (!iwm_rx_pkt_valid(pkt))
> +                     break;
> +
> +             code = IWM_WIDE_ID(pkt->hdr.flags, pkt->hdr.code);
>               qid = pkt->hdr.qid & ~0x80;
>               idx = pkt->hdr.idx;
> +             len = sizeof(pkt->len_n_flags) + iwm_rx_packet_len(pkt);
> +             if (len < sizeof(pkt->hdr) ||
> +                 len > (IWM_RBUF_SIZE - offset - minsz))
> +                     break;
>  
> -             code = IWM_WIDE_ID(pkt->hdr.flags, pkt->hdr.code);
> -
> -             /*
> -              * randomly get these from the firmware, no idea why.
> -              * they at least seem harmless, so just ignore them for now
> -              */
> -             if (__predict_false((pkt->hdr.code == 0 && qid == 0 && idx == 0)
> -                 || pkt->len_n_flags == htole32(0x55550000))) {
> -                     ADVANCE_RXQ(sc);
> -                     continue;
> +             if (code == IWM_REPLY_RX_MPDU_CMD && ++nmpdu == 1) {
> +                     /* Take mbuf m0 off the RX ring. */
> +                     if (iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur)) {
> +                             ifp->if_ierrors++;
> +                             break;
> +                     }
> +                     KASSERT(data->m != m0);
>               }
>  
>               switch (code) {
> @@ -7042,10 +7141,40 @@ iwm_notif_intr(struct iwm_softc *sc)
>                       iwm_rx_rx_phy_cmd(sc, pkt, data);
>                       break;
>  
> -             case IWM_REPLY_RX_MPDU_CMD:
> -                     iwm_rx_rx_mpdu(sc, pkt, data, &ml);
> -                     break;
> +             case IWM_REPLY_RX_MPDU_CMD: {
> +                     nextoff = offset +
> +                         roundup(len, IWM_FH_RSCSR_FRAME_ALIGN);
> +                     nextpkt = (struct iwm_rx_packet *)
> +                         (m0->m_data + nextoff);
> +                     if (nextoff + minsz >= IWM_RBUF_SIZE ||
> +                         !iwm_rx_pkt_valid(nextpkt)) {
> +                             /* No need to copy last frame in buffer. */
> +                             if (offset > 0)
> +                                     m_adj(m0, offset);
> +                             iwm_rx_mpdu(sc, m0, remain - minsz, ml);
> +                             m0 = NULL; /* stack owns m0 now; abort loop */
> +                     } else {
> +                             /*
> +                              * Create an mbuf which points to the current
> +                              * packet. Always copy from offset zero to
> +                              * preserve m_pkthdr.
> +                              */
> +                             m = m_copym(m0, 0, M_COPYALL, M_DONTWAIT);
> +                             if (m == NULL) {
> +                                     ifp->if_ierrors++;
> +                                     break;
> +                             }
> +                             m_adj(m, offset);
> +                             iwm_rx_mpdu(sc, m, remain - minsz, ml);
> +                     }
>  
> +                     if (offset + minsz < remain)
> +                             remain -= offset;
> +                     else
> +                             remain = minsz;
> +                     break;
> +             }
> +
>               case IWM_TX_CMD:
>                       iwm_rx_tx_cmd(sc, pkt, data);
>                       break;
> @@ -7288,6 +7417,27 @@ iwm_notif_intr(struct iwm_softc *sc)
>                       iwm_cmd_done(sc, pkt);
>               }
>  
> +             offset += roundup(len, IWM_FH_RSCSR_FRAME_ALIGN);
> +     }
> +
> +     if (m0 && m0 != data->m)
> +             m_freem(m0);
> +}
> +
> +void
> +iwm_notif_intr(struct iwm_softc *sc)
> +{
> +     struct mbuf_list ml = MBUF_LIST_INITIALIZER();
> +     uint16_t hw;
> +
> +     bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map,
> +         0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD);
> +
> +     hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff;
> +     hw &= (IWM_RX_RING_COUNT - 1);
> +     while (sc->rxq.cur != hw) {
> +             struct iwm_rx_data *data = &sc->rxq.data[sc->rxq.cur];
> +             iwm_rx_pkt(sc, data, &ml);
>               ADVANCE_RXQ(sc);
>       }
>       if_input(&sc->sc_ic.ic_if, &ml);
> @@ -7772,6 +7922,7 @@ iwm_attach(struct device *parent, struct device *self,
>           IEEE80211_C_RSN |           /* WPA/RSN */
>           IEEE80211_C_SCANALL |       /* device scans all channels at once */
>           IEEE80211_C_SCANALLBAND |   /* device scans all bands at once */
> +         IEEE80211_C_MONITOR |       /* monitor mode supported */
>           IEEE80211_C_SHSLOT |        /* short slot time supported */
>           IEEE80211_C_SHPREAMBLE;     /* short preamble supported */
>  
> 

Reply via email to