robert@ noticed that iwm(4) Rx throughput increased after running:
        sysctl net.link.ifrxq.pressure_drop=32
The default value for this sysctl is 8.

dlg@ explained the problem to me:
[[[
the pressure stuff counts the number of times ifiq_input (which is
called from if_input) gets called before a corresponding ifiq_process
call gets run. if ifiq_input gets called a lot before ifiq_process runs,
pressure builds up and after ifiq_pressure_drop calls it will shed load
by dropping packets.

ifiq_input is built to handle a list of packets built by processing
the rx ring of a nic in a single interrupt. every hw interrupt should
cause a single ifiq_input call. the list is hopefully processed in nettq
in between the hw interrupts, but the pressure thresholds give you a bit
of leeway.
]]]

The wifi stack currently calls if_input once per packet instead of once
per interrupt. To make the wifi layer play nicely with the network stack
we can split ieee80211_input() into two parts:
 
1) enqueue frames pulled from hardware to an mbuf list: ieee80211_input()
1) deliver frames to network stack via if_input: ieee80211_input_flush()

Existing ieee80211_input() calls don't need to be adjusted because
enqueuing happens under the hood onto a new mbuf list in ieee80211com.
Drivers call ieee80211_input_flush() once per Rx interrupt.

This diff touches all drivers and should be tested on as many drivers
as possible. While these changes are mostly mechanical, a lot of this
touches legacy drivers which I cannot easily test.
Please thoroughly review for errors.

bwfm(4) does not use ieee80211_input() for data frames but has the
same bug and will need to be fixed separately (patrick@ is aware).

I expect that 11n mode in particular will benefit from this.
ifq pressure drops can be fairly easily triggered by Rx aggregation.

diff refs/heads/master refs/heads/ifqdrop
blob - a1ca62ea1a4b5af7d1d1765eb1da131e15e21e4e
blob + bb0660f8da5ea340de57519e471b3a1a88c7da33
--- sys/dev/ic/acx.c
+++ sys/dev/ic/acx.c
@@ -1398,6 +1398,7 @@ acx_rxeof(struct acx_softc *sc)
                        rxi.rxi_rssi = head->rbh_level;
                        rxi.rxi_tstamp = letoh32(head->rbh_time);
                        ieee80211_input(ifp, m, ni, &rxi);
+                       ieee80211_input_flush(ifp);
 
                        ieee80211_release_node(ic, ni);
                } else {
blob - d3b9ada242c555f179dad1529c20a1748d4b7917
blob + d62e42897867623911ae53637503a42178637603
--- sys/dev/ic/an.c
+++ sys/dev/ic/an.c
@@ -477,6 +477,7 @@ an_rxeof(struct an_softc *sc)
        rxi.rxi_rssi = frmhdr.an_rx_signal_strength;
        rxi.rxi_tstamp = an_switch32(frmhdr.an_rx_time);
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
        ieee80211_release_node(ic, ni);
 }
 
blob - d72e8edceada8a680744a6b8478bb91ac9e15e6e
blob + 14dc84e692380a6a59b9fd9e3846f83e9a28e461
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -960,7 +960,12 @@ ar5008_rx_process(struct athn_softc *sc)
 void
 ar5008_rx_intr(struct athn_softc *sc)
 {
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+
        while (ar5008_rx_process(sc) == 0);
+
+       ieee80211_input_flush(ifp);
 }
 
 int
blob - 69ade5ade5a35e632a025db327668d695a0edd2d
blob + c34c8dae63f268c4baa4b8be396e0a6f6af8d05b
--- sys/dev/ic/ar9003.c
+++ sys/dev/ic/ar9003.c
@@ -1066,7 +1066,12 @@ ar9003_rx_process(struct athn_softc *sc, int qid)
 void
 ar9003_rx_intr(struct athn_softc *sc, int qid)
 {
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+
        while (ar9003_rx_process(sc, qid) == 0);
+
+       ieee80211_input_flush(ifp);
 }
 
 int
blob - c0c5f4241b010c5c38a557d97963fbdbc884336d
blob + 4d481bf2aada58fd7f9c484e3564db5b3d96d2b0
--- sys/dev/ic/ath.c
+++ sys/dev/ic/ath.c
@@ -2005,6 +2005,8 @@ ath_rx_proc(void *arg, int npending)
                TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
        } while (ath_rxbuf_init(sc, bf) == 0);
 
+       ieee80211_input_flush(ifp);
+
        ath_hal_set_rx_signal(ah);              /* rx signal state monitoring */
        ath_hal_start_rx(ah);                   /* in case of RXEOL */
 #undef PA2DESC
blob - cbf21da74007080c510fa9c56a58aedff62fa586
blob + 301b784e1b6878e0b024e17f7e515097fa6363d1
--- sys/dev/ic/atw.c
+++ sys/dev/ic/atw.c
@@ -3191,6 +3191,7 @@ atw_rxintr(struct atw_softc *sc)
                 */
                ieee80211_release_node(ic, ni);
        }
+       ieee80211_input_flush(ifp);
 
        /* Update the receive pointer. */
        sc->sc_rxptr = i;
blob - 7d6f2c5a5693881e2dffdd1814a757c9563196fc
blob + 9ce7309aeb96e7282fc8ac28e3cfc633e1d9f592
--- sys/dev/ic/bwfm.c
+++ sys/dev/ic/bwfm.c
@@ -2118,6 +2118,7 @@ bwfm_rx_auth_ind(struct bwfm_softc *sc, struct bwfm_ev
        rxi.rxi_rssi = 0;
        rxi.rxi_tstamp = 0;
        ieee80211_input(ifp, m, ic->ic_bss, &rxi);
+       ieee80211_input_flush(ifp);
 }
 
 void
@@ -2174,6 +2175,7 @@ bwfm_rx_assoc_ind(struct bwfm_softc *sc, struct bwfm_e
        rxi.rxi_rssi = 0;
        rxi.rxi_tstamp = 0;
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
 }
 
 void
@@ -2229,6 +2231,7 @@ bwfm_rx_leave_ind(struct bwfm_softc *sc, struct bwfm_e
        rxi.rxi_rssi = 0;
        rxi.rxi_tstamp = 0;
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
 }
 #endif
 
@@ -2418,6 +2421,7 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_
        rxi.rxi_rssi = (int16_t)letoh16(bss->rssi);
        rxi.rxi_tstamp = 0;
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
        /* Restore channel */
        if (bss_chan)
                ni->ni_chan = bss_chan;
blob - 58417ce6f7de644fe86347459c04553956b2edc0
blob + 25a40399a82089a496698f4a1fb8d88cb59375ac
--- sys/dev/ic/bwi.c
+++ sys/dev/ic/bwi.c
@@ -8466,6 +8466,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx)
 next:
                idx = (idx + 1) % BWI_RX_NDESC;
        }
+       ieee80211_input_flush(ifp);
 
        rbd->rbd_idx = idx;
        bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0,
blob - 6a8c5646f0b6f649a60793e127cbd746d8ee89d7
blob + bcd515d11a392f49f75914f1af6581b35b8cf054
--- sys/dev/ic/malo.c
+++ sys/dev/ic/malo.c
@@ -1727,6 +1727,7 @@ skip:
                sc->sc_rxring.cur = (sc->sc_rxring.cur + 1) %
                    MALO_RX_RING_COUNT;
        }
+       ieee80211_input_flush(ifp);
 
        malo_mem_write4(sc, sc->sc_RxPdRdPtr, rxRdPtr);
 }
blob - f44264645097e6f991f5642f7973ed5ebe3e5d7e
blob + 2f316718eb1c5310c46c64394c8b3603b056499e
--- sys/dev/ic/pgt.c
+++ sys/dev/ic/pgt.c
@@ -1036,6 +1036,7 @@ input:
                        ifp->if_ierrors++;
                }
        }
+       ieee80211_input_flush(ifp);
 }
 
 void
blob - c8d85564272d263215e829d007c11a47741316e6
blob + 32b3ddbc260c86e39043baef04ceb64edf4c02b4
--- sys/dev/ic/rt2560.c
+++ sys/dev/ic/rt2560.c
@@ -1220,6 +1220,7 @@ skip:             desc->flags = htole32(RT2560_RX_BUSY);
                sc->rxq.cur_decrypt =
                    (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT;
        }
+       ieee80211_input_flush(ifp);
 }
 
 /*
blob - 591115f692d4f77a522d114e5a91d6026e3452fe
blob + 8e090624a986aee3b0748884baa8a84332d92ff5
--- sys/dev/ic/rt2661.c
+++ sys/dev/ic/rt2661.c
@@ -1302,6 +1302,7 @@ skip:             desc->flags |= htole32(RT2661_RX_BUSY);
 
                sc->rxq.cur = (sc->rxq.cur + 1) % RT2661_RX_RING_COUNT;
        }
+       ieee80211_input_flush(ifp);
 }
 
 #ifndef IEEE80211_STA_ONLY
blob - c6c811c835ef4558079c00d50041075b9a8321bb
blob + 2fc9aedb090a50080c099d5b24ca96535ccf33dc
--- sys/dev/ic/rt2860.c
+++ sys/dev/ic/rt2860.c
@@ -1432,6 +1432,7 @@ skip:             rxd->sdl0 &= ~htole16(RT2860_RX_DDONE);
 
                sc->rxq.cur = (sc->rxq.cur + 1) % RT2860_RX_RING_COUNT;
        }
+       ieee80211_input_flush(ifp);
 
        /* tell HW what we have processed */
        RAL_WRITE(sc, RT2860_RX_CALC_IDX,
blob - ce7686c40fa4b1166d0af3fe54d8cad60704f556
blob + 420bcd5f0db656fb85833f6ad290b2432c1fe82f
--- sys/dev/ic/rtw.c
+++ sys/dev/ic/rtw.c
@@ -1294,6 +1294,7 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
 next:
                rtw_rxdesc_init(rdb, rs, next, 0);
        }
+       ieee80211_input_flush(&sc->sc_if);
        rdb->rdb_next = next;
 
        KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
blob - cd0d354d12f45e34327a1d9d2d6ae5b480f9e305
blob + cf8f4f3f38d70f01c28136f6a2e3f9f8fa9dc7c4
--- sys/dev/pci/if_ipw.c
+++ sys/dev/pci/if_ipw.c
@@ -966,6 +966,7 @@ ipw_rx_intr(struct ipw_softc *sc)
                    i * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
                    BUS_DMASYNC_PREWRITE);
        }
+       ieee80211_input_flush(&sc->sc_ic.ic_if);
 
        /* tell the firmware what we have processed */
        sc->rxcur = (r == 0) ? IPW_NRBD - 1 : r - 1;
blob - bdb4827425118b9159ae05ad1263bdf5c084254f
blob + 77621142318b26269d864de7443d3f6cd27ffe27
--- sys/dev/pci/if_iwi.c
+++ sys/dev/pci/if_iwi.c
@@ -1105,6 +1105,7 @@ iwi_rx_intr(struct iwi_softc *sc)
 
                sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT;
        }
+       ieee80211_input_flush(&sc->sc_ic.ic_if);
 
        /* tell the firmware what we have processed */
        hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1;
blob - 0b2116dbc13428f1726773000e8e6a8c251d86b4
blob + d347c3d8f4853099592dd1617dcfd5946bdd5c6c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -7289,6 +7289,7 @@ iwm_notif_intr(struct iwm_softc *sc)
 
                ADVANCE_RXQ(sc);
        }
+       ieee80211_input_flush(&sc->sc_ic.ic_if);
 
        /*
         * Tell the firmware what we have processed.
blob - 6be794c2cd435c74b1b5c3f028b9613dc74ecf20
blob + 06d0e55d42910fc8c60bd29078829399cf337fe4
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2913,6 +2913,7 @@ iwn_notif_intr(struct iwn_softc *sc)
 
                sc->rxq.cur = (sc->rxq.cur + 1) % IWN_RX_RING_COUNT;
        }
+       ieee80211_input_flush(&sc->sc_ic.ic_if);
 
        /* Tell the firmware what we have processed. */
        hw = (hw == 0) ? IWN_RX_RING_COUNT - 1 : hw - 1;
blob - 2c53aa925247b5056360daf479fca12e45624107
blob + 9dc76928c677c89fc9f7d2aa09082bf73e62190c
--- sys/dev/pci/if_rtwn.c
+++ sys/dev/pci/if_rtwn.c
@@ -1511,6 +1511,8 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
                rtwn_tx_done(sc, RTWN_VO_QUEUE);
        if ((status & (R88E_HIMR_ROK | R88E_HIMR_RDU)) ||
            (estatus & R88E_HIMRE_RXFOVW)) {
+               struct ieee80211com *ic = &sc->sc_sc.sc_ic;
+
                bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
                    sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
                    BUS_DMASYNC_POSTREAD);
@@ -1524,6 +1526,7 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
 
                        rtwn_rx_frame(sc, rx_desc, rx_data, i);
                }
+               ieee80211_input_flush(&ic->ic_if);
        }
 
        if (status & R88E_HIMR_HSISR_IND_ON_INT) {
@@ -1561,6 +1564,8 @@ rtwn_intr(void *xsc)
 
        /* Vendor driver treats RX errors like ROK... */
        if (status & (R92C_IMR_ROK | R92C_IMR_RXFOVW | R92C_IMR_RDU)) {
+               struct ieee80211com *ic = &sc->sc_sc.sc_ic;
+
                bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
                    sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
                    BUS_DMASYNC_POSTREAD);
@@ -1574,6 +1579,7 @@ rtwn_intr(void *xsc)
 
                        rtwn_rx_frame(sc, rx_desc, rx_data, i);
                }
+               ieee80211_input_flush(&ic->ic_if);
        }
 
        if (status & R92C_IMR_BDOK)
blob - 2a91ccec016f8047bfe26ede71e8881404fef619
blob + 02f8191621b3c3967aab4abec9447c7cd4e5ffac
--- sys/dev/pci/if_wpi.c
+++ sys/dev/pci/if_wpi.c
@@ -1527,6 +1527,7 @@ wpi_notif_intr(struct wpi_softc *sc)
 
                sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT;
        }
+       ieee80211_input_flush(&ic->ic_if);
 
        /* Tell the firmware what we have processed. */
        hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1;
blob - 39edb129685cac47d29224f18c6f2e7c92922720
blob + 2fe4fc1af606a4ab32e6dcce83cc7c710e3c814b
--- sys/dev/usb/if_athn_usb.c
+++ sys/dev/usb/if_athn_usb.c
@@ -2175,6 +2175,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
                buf += off;
                len -= off;
        }
+       ieee80211_input_flush(ifp);
 
  resubmit:
        /* Setup a new transfer. */
blob - 7c49042002e73f07bda3c9a5dc7e13e9d7e97503
blob + 46fa39efc05c66d59e7e73c94dfe2b5ec635d9ad
--- sys/dev/usb/if_atu.c
+++ sys/dev/usb/if_atu.c
@@ -1743,6 +1743,7 @@ atu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
        rxi.rxi_rssi = h->rssi;
        rxi.rxi_tstamp = UGETDW(h->rx_time);
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
 
        ieee80211_release_node(ic, ni);
 done1:
blob - cb7e65865adb17b86e10bf5c2bc59983a5c8c2c9
blob + 3c8da94867b14ab18d315b7c69c1188cc770569d
--- sys/dev/usb/if_otus.c
+++ sys/dev/usb/if_otus.c
@@ -1241,6 +1241,7 @@ otus_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
                buf += hlen;
                len -= hlen;
        }
+       ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  resubmit:
        usbd_setup_xfer(xfer, sc->data_rx_pipe, data, data->buf, OTUS_RXBUFSZ,
blob - 9d81664f824def87770512b3e61a015782c99be0
blob + 623fd79146a1879baf23aee4380611444c21f440
--- sys/dev/usb/if_ral.c
+++ sys/dev/usb/if_ral.c
@@ -782,6 +782,7 @@ ural_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
        rxi.rxi_rssi = desc->rssi;
        rxi.rxi_tstamp = 0;     /* unused */
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
 
        /* node is no longer needed */
        ieee80211_release_node(ic, ni);
blob - 417666c3503da89fce1d3dc4301b48376dcf7e41
blob + e8d263d2c4322d44836e0197cdd909adc795648e
--- sys/dev/usb/if_rsu.c
+++ sys/dev/usb/if_rsu.c
@@ -1120,6 +1120,7 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, i
        rxi.rxi_rssi = letoh32(bss->rssi);
        rxi.rxi_tstamp = 0;
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
 }
@@ -1415,6 +1416,7 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf,
                buf += totlen;
                len -= totlen;
        }
+       ieee80211_input_flush(&sc->sc_ic.ic_if);
 }
 
 void
blob - 7126aaa9540a3f838e7bc1d4e80a06e759e98517
blob + 3fe904607ebf7584cee0348ebb9d4135510d499e
--- sys/dev/usb/if_rum.c
+++ sys/dev/usb/if_rum.c
@@ -851,6 +851,7 @@ rum_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
        rxi.rxi_rssi = desc->rssi;
        rxi.rxi_tstamp = 0;     /* unused */
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
 
        /* node is no longer needed */
        ieee80211_release_node(ic, ni);
blob - fc6ba52f271725fe7afbb4abf1a4a1700920a1b4
blob + 5342470a39c8094143e9372855c0511c2ed0161e
--- sys/dev/usb/if_run.c
+++ sys/dev/usb/if_run.c
@@ -2352,6 +2352,7 @@ run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
                buf += dmalen + 8;
                xferlen -= dmalen + 8;
        }
+       ieee80211_input_flush(&sc->sc_ic.ic_if);
 
 skip:  /* setup a new transfer */
        usbd_setup_xfer(xfer, sc->rxq.pipeh, data, data->buf, RUN_MAX_RXSZ,
blob - 30aa31b56bfd1226a4199c9024907adbbb3e429d
blob + d657466dccf52fb1271a3650718feecb6e19c297
--- sys/dev/usb/if_uath.c
+++ sys/dev/usb/if_uath.c
@@ -1265,6 +1265,7 @@ uath_data_rxeof(struct usbd_xfer *xfer, void *priv,
        rxi.rxi_rssi = (int)betoh32(desc->rssi);
        rxi.rxi_tstamp = 0;     /* unused */
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
 
        /* node is no longer needed */
        ieee80211_release_node(ic, ni);
blob - 6c8b66842fb650329fb36d812e76fa41be9ab9c7
blob + 72928af7c891bcc295dd79d71a2b6155a64eb0a5
--- sys/dev/usb/if_upgt.c
+++ sys/dev/usb/if_upgt.c
@@ -1748,6 +1748,7 @@ upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkgl
        rxi.rxi_rssi = rxdesc->rssi;
        rxi.rxi_tstamp = 0;     /* unused */
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
 
        /* node is no longer needed */
        ieee80211_release_node(ic, ni);
blob - 17d56c174230515195c13c070aed9065a68bc959
blob + 87bdc93a6df4786458f6eec62ceb025cc7e75a5a
--- sys/dev/usb/if_urtw.c
+++ sys/dev/usb/if_urtw.c
@@ -3161,6 +3161,7 @@ urtw_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = 0;
        ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_input_flush(ifp);
 
        /* node is no longer needed */
        ieee80211_release_node(ic, ni);
blob - 96a1ad1a91c3e98ebc6dece98df6ac277046612c
blob + 3f353ff8296162cde2163af94099b9a666bb106c
--- sys/dev/usb/if_urtwn.c
+++ sys/dev/usb/if_urtwn.c
@@ -1206,6 +1206,7 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
 {
        struct urtwn_rx_data *data = priv;
        struct urtwn_softc *sc = data->sc;
+       struct ieee80211com *ic = &sc->sc_sc.sc_ic;
        struct r92c_rx_desc_usb *rxd;
        uint32_t rxdw0;
        uint8_t *buf;
@@ -1305,6 +1306,7 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
                buf += totlen;
                len -= totlen;
        }
+       ieee80211_input_flush(&ic->ic_if);
 
  resubmit:
        /* Setup a new transfer. */
blob - 689ac7e7178ca36a091d25cc6f2cf8d15cc45b0b
blob + 498bb68138994cd361f996c866e95c959a5ddf15
--- sys/dev/usb/if_zyd.c
+++ sys/dev/usb/if_zyd.c
@@ -2039,6 +2039,7 @@ zyd_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
 
                zyd_rx_data(sc, data->buf, len);
        }
+       ieee80211_input_flush(ifp);
 
 skip:  /* setup a new transfer */
        usbd_setup_xfer(xfer, sc->zyd_ep[ZYD_ENDPT_BIN], data, NULL,
blob - ace97a38cc4ff76b454c1f6a12655565ad131275
blob + c20962c799b141638a2fff11d5ceef6d6db47667
--- sys/net80211/ieee80211.c
+++ sys/net80211/ieee80211.c
@@ -184,6 +184,8 @@ ieee80211_ifattach(struct ifnet *ifp)
        ic->ic_bmissthres = 7;  /* default 7 beacons */
        ic->ic_dtim_period = 1; /* all TIMs are DTIMs */
 
+       ml_init(&ic->ic_ml);
+
        ieee80211_node_attach(ifp);
        ieee80211_proto_attach(ifp);
 
@@ -200,6 +202,7 @@ ieee80211_ifdetach(struct ifnet *ifp)
 {
        struct ieee80211com *ic = (void *)ifp;
 
+       ml_purge(&ic->ic_ml);
        timeout_del(&ic->ic_bgscan_timeout);
        ieee80211_proto_detach(ifp);
        ieee80211_crypto_detach(ifp);
blob - 73a9d5229502797c5279734663b1ac1591bec309
blob + de36481038ec3372d0d5533002cbc62a1ebe2b6a
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -71,11 +71,11 @@ void        ieee80211_input_ba_seq(struct ieee80211com *,
            struct ieee80211_node *, uint8_t, uint16_t);
 struct mbuf *ieee80211_align_mbuf(struct mbuf *);
 void   ieee80211_decap(struct ieee80211com *, struct mbuf *,
-           struct ieee80211_node *, int);
+           struct ieee80211_node *, int, struct mbuf_list *);
 void   ieee80211_amsdu_decap(struct ieee80211com *, struct mbuf *,
-           struct ieee80211_node *, int);
-void   ieee80211_deliver_data(struct ieee80211com *, struct mbuf *,
-           struct ieee80211_node *, int);
+           struct ieee80211_node *, int, struct mbuf_list *);
+void   ieee80211_enqueue_data(struct ieee80211com *, struct mbuf *,
+           struct ieee80211_node *, int, struct mbuf_list *);
 int    ieee80211_parse_edca_params_body(struct ieee80211com *,
            const u_int8_t *);
 int    ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
@@ -155,6 +155,9 @@ ieee80211_get_hdrlen(const struct ieee80211_frame *wh)
  * any units so long as values have consistent units and higher values
  * mean ``better signal''.  The receive timestamp is currently not used
  * by the 802.11 layer.
+ *
+ * This function only queues frames for delivery.
+ * Actual delivery to upper layers is triggered by ieee80211_input_flush().
  */
 void
 ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
@@ -463,9 +466,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
 
                if ((ni->ni_flags & IEEE80211_NODE_HT) &&
                    hasqos && (qos & IEEE80211_QOS_AMSDU))
-                       ieee80211_amsdu_decap(ic, m, ni, hdrlen);
+                       ieee80211_amsdu_decap(ic, m, ni, hdrlen, &ic->ic_ml);
                else
-                       ieee80211_decap(ic, m, ni, hdrlen);
+                       ieee80211_decap(ic, m, ni, hdrlen, &ic->ic_ml);
                return;
 
        case IEEE80211_FC0_TYPE_MGT:
@@ -561,6 +564,22 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
 }
 
 /*
+ * Deliver frames queued by ieee80211_input() to the network stack.
+ * Drivers should call this function only once per Rx interrupt to avoid
+ * triggering the input ifq pressure drop mechanism unnecessarily.
+ */
+void
+ieee80211_input_flush(struct ifnet *ifp)
+{
+       struct ieee80211com *ic = (void *)ifp;
+       int s;
+
+       s = splnet();
+       if_input(ifp, &ic->ic_ml);
+       splx(s);
+}
+
+/*
  * Handle defragmentation (see 9.5 and Annex C).  We support the concurrent
  * reception of fragments of three fragmented MSDUs or MMPDUs.
  */
@@ -856,8 +875,8 @@ ieee80211_ba_move_window(struct ieee80211com *ic, stru
 }
 
 void
-ieee80211_deliver_data(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int mcast)
+ieee80211_enqueue_data(struct ieee80211com *ic, struct mbuf *m,
+    struct ieee80211_node *ni, int mcast, struct mbuf_list *ml)
 {
        struct ifnet *ifp = &ic->ic_if;
        struct ether_header *eh;
@@ -920,16 +939,14 @@ ieee80211_deliver_data(struct ieee80211com *ic, struct
 #endif
                        ieee80211_eapol_key_input(ic, m, ni);
                } else {
-                       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
-                       ml_enqueue(&ml, m);
-                       if_input(ifp, &ml);
+                       ml_enqueue(ml, m);
                }
        }
 }
 
 void
 ieee80211_decap(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int hdrlen)
+    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
 {
        struct ether_header eh;
        struct ieee80211_frame *wh;
@@ -985,7 +1002,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
                        return;
                }
        }
-       ieee80211_deliver_data(ic, m, ni, mcast);
+       ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 }
 
 /*
@@ -993,7 +1010,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
  */
 void
 ieee80211_amsdu_decap(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int hdrlen)
+    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
 {
        struct mbuf *n;
        struct ether_header *eh;
@@ -1059,7 +1076,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct 
                        m_freem(m);
                        break;
                }
-               ieee80211_deliver_data(ic, m, ni, mcast);
+               ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 
                if (n->m_pkthdr.len == 0) {
                        m_freem(n);
blob - d00d1b631f2966efbd88992c92fea88a99e3ddf8
blob + 43f9de3d52b149afef46a71ff51a94b81b6799b9
--- sys/net80211/ieee80211_proto.c
+++ sys/net80211/ieee80211_proto.c
@@ -974,9 +974,11 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee8
        struct ieee80211_node *ni;
        enum ieee80211_state ostate;
        u_int rate;
-#ifndef IEEE80211_STA_ONLY
        int s;
-#endif
+
+       s = splnet();
+       ml_purge(&ic->ic_ml);
+       splx(s);
 
        ostate = ic->ic_state;
        if (ifp->if_flags & IFF_DEBUG)
blob - e622d35f4dcd21ea0bb40c6a5d0b3f758e197b38
blob + c1d3ad65a46f76266533a4cfd5fffa08b4fa6537
--- sys/net80211/ieee80211_proto.h
+++ sys/net80211/ieee80211_proto.h
@@ -68,6 +68,7 @@ extern        u_int ieee80211_get_hdrlen(const struct ieee802
 extern int ieee80211_classify(struct ieee80211com *, struct mbuf *);
 extern void ieee80211_input(struct ifnet *, struct mbuf *,
                struct ieee80211_node *, struct ieee80211_rxinfo *);
+extern void ieee80211_input_flush(struct ifnet *);
 extern int ieee80211_output(struct ifnet *, struct mbuf *, struct sockaddr *,
                struct rtentry *);
 extern void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
blob - 2a567a01422aaaf6024b05c5589f6f45b3744100
blob + fcbe48513883c4c81cfb4c4d96e4d5d08a07ab7f
--- sys/net80211/ieee80211_var.h
+++ sys/net80211/ieee80211_var.h
@@ -340,6 +340,8 @@ struct ieee80211com {
        u_int8_t                ic_dialog_token;
        int                     ic_fixed_mcs;
        TAILQ_HEAD(, ieee80211_ess)      ic_ess;
+
+       struct mbuf_list ic_ml; /* frames queued for if_input() */
 };
 #define        ic_if           ic_ac.ac_if
 #define        ic_softc        ic_if.if_softc


Reply via email to