On Mon, Sep 09, 2019 at 06:17:34PM -0300, Martin Pieuchot wrote:
> On 09/09/19(Mon) 16:37, Stefan Sperling wrote:
> > On Mon, Sep 09, 2019 at 03:10:04PM +0200, Stefan Sperling wrote:
> > > 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:
> > 
> > Updated diff which avoids purging the input queue at every state
> > change, e.g. even during SCAN->SCAN. With this we only purge the
> > queue if we're leaving RUN state or going back to INIT state.
> 
> Thanks a lot!  I must say I looked at this in the past but got lost in
> ieee80211_input().
> 
> Why not keep ieee80211_input() as a wrapper around your new mechanism?
> This way you don't need to touch all drivers at once.

We can keep ieee80211_input() for use by drivers that really only deliver
one frame per interrupt. Now we don't need to touch some drivers at all.

> I'd also suggest using a queue on-stack like we do for Ethernet drivers,
> this would get rid of the cleanup of `ic_ml' when the state change.  It
> would also help developers familiar with Ethernet drivers to understand
> what's happening ;o)

Yes, thanks for this suggestion! Things make a lot more sense this way.

> What about:
> 
>         ieee80211_enqueue(ifp, m, ni, &rxi, &ml);
>         ieee80211_inputm(ifp, &ml);

I don't like the name ieee80211_enqueue() because while data frames are
being enqueued, management frames are not enqueued. Instead, they cause
immediate state changes in the net80211 stack such as allocation of a
new node when a beacon is received state changes, e.g. RUN -> AUTH when
a deauth frame is received.

When drivers have the mbuf list on the stack we do not need a wrapper
for if_input() since drivers can just call it directly.

So I have chosen to use the following instead:

          ieee80211_inputm(ifp, m, ni, &rxi, &ml);
          if_input(ifp, &ml);

With ieee80211_input() being a wrapper around these two calls.

> Are you sure if_input() needs to be called at splnet()?  I don't think
> so because many pseudo-drivers call it at a different IPL.

I did this only because I was afraid the global ic_ml might be accessed
by hardware interrupts while we're running newstate() in a task as some
drivers will do. This becomes a non-issue with mbuf lists on the stack.

New diff with above changes:

diff refs/heads/master refs/heads/ifqdrop
blob - d72e8edceada8a680744a6b8478bb91ac9e15e6e
blob + a3203d7eb1a67d478bf280a551a43f2dc66c0965
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -789,7 +789,7 @@ ar5008_rx_radiotap(struct athn_softc *sc, struct mbuf 
 #endif
 
 static __inline int
-ar5008_rx_process(struct athn_softc *sc)
+ar5008_rx_process(struct athn_softc *sc, struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -931,7 +931,7 @@ ar5008_rx_process(struct athn_softc *sc)
        rxi.rxi_rssi = MS(ds->ds_status4, AR_RXS4_RSSI_COMBINED);
        rxi.rxi_rssi += AR_DEFAULT_NOISE_FLOOR;
        rxi.rxi_tstamp = ds->ds_status2;
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
@@ -960,7 +960,13 @@ ar5008_rx_process(struct athn_softc *sc)
 void
 ar5008_rx_intr(struct athn_softc *sc)
 {
-       while (ar5008_rx_process(sc) == 0);
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+
+       while (ar5008_rx_process(sc, &ml) == 0);
+
+       if_input(ifp, &ml);
 }
 
 int
blob - 69ade5ade5a35e632a025db327668d695a0edd2d
blob + dafa3bd1f0b4ca2124c6d963c82e289594e88b27
--- sys/dev/ic/ar9003.c
+++ sys/dev/ic/ar9003.c
@@ -83,7 +83,7 @@ void  ar9003_reset_txsring(struct athn_softc *);
 void   ar9003_rx_enable(struct athn_softc *);
 void   ar9003_rx_radiotap(struct athn_softc *, struct mbuf *,
            struct ar_rx_status *);
-int    ar9003_rx_process(struct athn_softc *, int);
+int    ar9003_rx_process(struct athn_softc *, int, struct mbuf_list *);
 void   ar9003_rx_intr(struct athn_softc *, int);
 int    ar9003_tx_process(struct athn_softc *);
 void   ar9003_tx_intr(struct athn_softc *);
@@ -916,7 +916,7 @@ ar9003_rx_radiotap(struct athn_softc *sc, struct mbuf 
 #endif
 
 int
-ar9003_rx_process(struct athn_softc *sc, int qid)
+ar9003_rx_process(struct athn_softc *sc, int qid, struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -1036,7 +1036,7 @@ ar9003_rx_process(struct athn_softc *sc, int qid)
        rxi.rxi_flags = 0;      /* XXX */
        rxi.rxi_rssi = MS(ds->ds_status5, AR_RXS5_RSSI_COMBINED);
        rxi.rxi_tstamp = ds->ds_status3;
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
@@ -1066,7 +1066,13 @@ ar9003_rx_process(struct athn_softc *sc, int qid)
 void
 ar9003_rx_intr(struct athn_softc *sc, int qid)
 {
-       while (ar9003_rx_process(sc, qid) == 0);
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+
+       while (ar9003_rx_process(sc, qid, &ml) == 0);
+
+       if_input(ifp, &ml);
 }
 
 int
blob - c0c5f4241b010c5c38a557d97963fbdbc884336d
blob + c4414e5113134012edaf4ce4557bb7e25987e9ef
--- sys/dev/ic/ath.c
+++ sys/dev/ic/ath.c
@@ -1795,6 +1795,7 @@ ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *b
 void
 ath_rx_proc(void *arg, int npending)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
 #define        PA2DESC(_sc, _pa) \
        ((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \
                ((_pa) - (_sc)->sc_desc_paddr)))
@@ -1946,7 +1947,7 @@ ath_rx_proc(void *arg, int npending)
                if (!ath_softcrypto && (wh->i_fc[1] & IEEE80211_FC1_WEP)) {
                        /*
                         * WEP is decrypted by hardware. Clear WEP bit
-                        * and trim WEP header for ieee80211_input().
+                        * and trim WEP header for ieee80211_inputm().
                         */
                        wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
                        bcopy(wh, &whbuf, sizeof(whbuf));
@@ -1988,7 +1989,7 @@ ath_rx_proc(void *arg, int npending)
                 */
                rxi.rxi_rssi = ds->ds_rxstat.rs_rssi;
                rxi.rxi_tstamp = ds->ds_rxstat.rs_tstamp;
-               ieee80211_input(ifp, m, ni, &rxi);
+               ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
                /* Handle the rate adaption */
                ieee80211_rssadapt_input(ic, ni, &an->an_rssadapt,
@@ -2004,6 +2005,8 @@ ath_rx_proc(void *arg, int npending)
        rx_next:
                TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
        } while (ath_rxbuf_init(sc, bf) == 0);
+
+       if_input(ifp, &ml);
 
        ath_hal_set_rx_signal(ah);              /* rx signal state monitoring */
        ath_hal_start_rx(ah);                   /* in case of RXEOL */
blob - cbf21da74007080c510fa9c56a58aedff62fa586
blob + 6f609b3d8e77c27ba27e6be88cff55fbf87bbb2c
--- sys/dev/ic/atw.c
+++ sys/dev/ic/atw.c
@@ -3029,6 +3029,7 @@ atw_hw_decrypted(struct atw_softc *sc, struct ieee8021
 void
 atw_rxintr(struct atw_softc *sc)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        static int rate_tbl[] = {2, 4, 11, 22, 44};
        struct ieee80211com *ic = &sc->sc_ic;
        struct ieee80211_rxinfo rxi;
@@ -3183,7 +3184,7 @@ atw_rxintr(struct atw_softc *sc)
 #endif
                rxi.rxi_rssi = (int)rssi;
                rxi.rxi_tstamp = 0;
-               ieee80211_input(ifp, m, ni, &rxi);
+               ieee80211_inputm(ifp, m, ni, &rxi, &ml);
                /*
                 * The frame may have caused the node to be marked for
                 * reclamation (e.g. in response to a DEAUTH message)
@@ -3191,6 +3192,7 @@ atw_rxintr(struct atw_softc *sc)
                 */
                ieee80211_release_node(ic, ni);
        }
+       if_input(ifp, &ml);
 
        /* Update the receive pointer. */
        sc->sc_rxptr = i;
blob - 58417ce6f7de644fe86347459c04553956b2edc0
blob + b383588620701ca5c656d29c0384393696914cdc
--- sys/dev/ic/bwi.c
+++ sys/dev/ic/bwi.c
@@ -8355,6 +8355,7 @@ bwi_next_scan(void *xsc)
 int
 bwi_rxeof(struct bwi_softc *sc, int end_idx)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct bwi_ring_data *rd = &sc->sc_rx_rdata;
        struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
        struct ieee80211com *ic = &sc->sc_ic;
@@ -8455,7 +8456,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx)
 
                rxi.rxi_rssi = hdr->rxh_rssi;
                rxi.rxi_tstamp = letoh16(hdr->rxh_tsf);
-               ieee80211_input(ifp, m, ni, &rxi);
+               ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
                ieee80211_release_node(ic, ni);
 
@@ -8466,6 +8467,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx)
 next:
                idx = (idx + 1) % BWI_RX_NDESC;
        }
+       if_input(ifp, &ml);
 
        rbd->rbd_idx = idx;
        bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0,
blob - 6a8c5646f0b6f649a60793e127cbd746d8ee89d7
blob + af91b6b414ecc45cd3caceec3f0a7ea6e2aae400
--- sys/dev/ic/malo.c
+++ sys/dev/ic/malo.c
@@ -1593,6 +1593,7 @@ malo_tx_setup_desc(struct malo_softc *sc, struct malo_
 void
 malo_rx_intr(struct malo_softc *sc)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
        struct malo_rx_desc *desc;
@@ -1711,7 +1712,7 @@ malo_rx_intr(struct malo_softc *sc)
                rxi.rxi_flags = 0;
                rxi.rxi_rssi = desc->rssi;
                rxi.rxi_tstamp = 0;     /* unused */
-               ieee80211_input(ifp, m, ni, &rxi);
+               ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
                /* node is no longer needed */
                ieee80211_release_node(ic, ni);
@@ -1727,6 +1728,7 @@ skip:
                sc->sc_rxring.cur = (sc->sc_rxring.cur + 1) %
                    MALO_RX_RING_COUNT;
        }
+       if_input(ifp, &ml);
 
        malo_mem_write4(sc, sc->sc_RxPdRdPtr, rxRdPtr);
 }
blob - f44264645097e6f991f5642f7973ed5ebe3e5d7e
blob + 695723c6f054b8ab264aefb609696dffbaae6c6b
--- sys/dev/ic/pgt.c
+++ sys/dev/ic/pgt.c
@@ -899,6 +899,7 @@ void
 pgt_input_frames(struct pgt_softc *sc, struct mbuf *m)
 {
        struct ether_header eh;
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct ifnet *ifp;
        struct ieee80211_channel *chan;
        struct ieee80211_rxinfo rxi;
@@ -1022,7 +1023,7 @@ input:
                        rxi.rxi_flags = 0;
                        ni->ni_rssi = rxi.rxi_rssi = rssi;
                        ni->ni_rstamp = rxi.rxi_tstamp = rstamp;
-                       ieee80211_input(ifp, m, ni, &rxi);
+                       ieee80211_inputm(ifp, m, ni, &rxi, &ml);
                        /*
                         * The frame may have caused the node to be marked for
                         * reclamation (e.g. in response to a DEAUTH message)
@@ -1036,6 +1037,7 @@ input:
                        ifp->if_ierrors++;
                }
        }
+       if_input(ifp, &ml);
 }
 
 void
blob - c8d85564272d263215e829d007c11a47741316e6
blob + 4b6e4c0592a9ac543cc83d2ff6ccc692427c0adf
--- sys/dev/ic/rt2560.c
+++ sys/dev/ic/rt2560.c
@@ -1076,6 +1076,7 @@ rt2560_prio_intr(struct rt2560_softc *sc)
 void
 rt2560_decryption_intr(struct rt2560_softc *sc)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
        struct ieee80211_frame *wh;
@@ -1204,7 +1205,7 @@ rt2560_decryption_intr(struct rt2560_softc *sc)
                rxi.rxi_flags = 0;
                rxi.rxi_rssi = desc->rssi;
                rxi.rxi_tstamp = 0;     /* unused */
-               ieee80211_input(ifp, m, ni, &rxi);
+               ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
                /* node is no longer needed */
                ieee80211_release_node(ic, ni);
@@ -1220,6 +1221,7 @@ skip:             desc->flags = htole32(RT2560_RX_BUSY);
                sc->rxq.cur_decrypt =
                    (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT;
        }
+       if_input(ifp, &ml);
 }
 
 /*
blob - 591115f692d4f77a522d114e5a91d6026e3452fe
blob + 44f767f9bba3aec85758600684dc786d5eab3ed3
--- sys/dev/ic/rt2661.c
+++ sys/dev/ic/rt2661.c
@@ -1153,6 +1153,7 @@ rt2661_tx_dma_intr(struct rt2661_softc *sc, struct rt2
 void
 rt2661_rx_intr(struct rt2661_softc *sc)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
        struct ieee80211_frame *wh;
@@ -1279,7 +1280,7 @@ rt2661_rx_intr(struct rt2661_softc *sc)
                rxi.rxi_flags = 0;
                rxi.rxi_rssi = desc->rssi;
                rxi.rxi_tstamp = 0;     /* unused */
-               ieee80211_input(ifp, m, ni, &rxi);
+               ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
                /*-
                 * Keep track of the average RSSI using an Exponential Moving
@@ -1302,6 +1303,7 @@ skip:             desc->flags |= htole32(RT2661_RX_BUSY);
 
                sc->rxq.cur = (sc->rxq.cur + 1) % RT2661_RX_RING_COUNT;
        }
+       if_input(ifp, &ml);
 }
 
 #ifndef IEEE80211_STA_ONLY
blob - c6c811c835ef4558079c00d50041075b9a8321bb
blob + 286f4c859d84a8dc13a54e74c355bc443cf2f7e8
--- sys/dev/ic/rt2860.c
+++ sys/dev/ic/rt2860.c
@@ -1260,6 +1260,7 @@ rt2860_maxrssi_chain(struct rt2860_softc *sc, const st
 void
 rt2860_rx_intr(struct rt2860_softc *sc)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
        struct ieee80211_frame *wh;
@@ -1419,7 +1420,7 @@ skipbpf:
                /* send the frame to the 802.11 layer */
                rxi.rxi_rssi = rssi;
                rxi.rxi_tstamp = 0;     /* unused */
-               ieee80211_input(ifp, m, ni, &rxi);
+               ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
                /* node is no longer needed */
                ieee80211_release_node(ic, ni);
@@ -1432,6 +1433,7 @@ skip:             rxd->sdl0 &= ~htole16(RT2860_RX_DDONE);
 
                sc->rxq.cur = (sc->rxq.cur + 1) % RT2860_RX_RING_COUNT;
        }
+       if_input(ifp, &ml);
 
        /* tell HW what we have processed */
        RAL_WRITE(sc, RT2860_RX_CALC_IDX,
blob - ce7686c40fa4b1166d0af3fe54d8cad60704f556
blob + 344ffd4381400698d23f8aaee3c623fe649f885f
--- sys/dev/ic/rtw.c
+++ sys/dev/ic/rtw.c
@@ -1081,6 +1081,7 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
        static const int ratetbl[4] = {2, 4, 11, 22};   /* convert rates:
                                                         * hardware -> net80211
                                                         */
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        u_int next, nproc = 0;
        int hwrate, len, rate, rssi, sq;
        u_int32_t hrssi, hstat, htsfth, htsftl;
@@ -1289,11 +1290,12 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
                rxi.rxi_flags = 0;
                rxi.rxi_rssi = rssi;
                rxi.rxi_tstamp = htsftl;
-               ieee80211_input(&sc->sc_if, m, ni, &rxi);
+               ieee80211_inputm(&sc->sc_if, m, ni, &rxi, &ml);
                ieee80211_release_node(&sc->sc_ic, ni);
 next:
                rtw_rxdesc_init(rdb, rs, next, 0);
        }
+       if_input(&sc->sc_if, &ml);
        rdb->rdb_next = next;
 
        KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
blob - cd0d354d12f45e34327a1d9d2d6ae5b480f9e305
blob + abcd1e0c7f2509e16102d1ea96e245dca587de90
--- sys/dev/pci/if_ipw.c
+++ sys/dev/pci/if_ipw.c
@@ -71,7 +71,8 @@ uint16_t      ipw_read_prom_word(struct ipw_softc *, uint8_
 void           ipw_command_intr(struct ipw_softc *, struct ipw_soft_buf *);
 void           ipw_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *);
 void           ipw_data_intr(struct ipw_softc *, struct ipw_status *,
-                   struct ipw_soft_bd *, struct ipw_soft_buf *);
+                   struct ipw_soft_bd *, struct ipw_soft_buf *,
+                   struct mbuf_list *);
 void           ipw_notification_intr(struct ipw_softc *,
                    struct ipw_soft_buf *);
 void           ipw_rx_intr(struct ipw_softc *);
@@ -816,7 +817,7 @@ ipw_newstate_intr(struct ipw_softc *sc, struct ipw_sof
 
 void
 ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
-    struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf)
+    struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf, struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -903,7 +904,7 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status 
        rxi.rxi_flags = 0;
        rxi.rxi_rssi = status->rssi;
        rxi.rxi_tstamp = 0;     /* unused */
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
        ieee80211_release_node(ic, ni);
 }
@@ -917,6 +918,7 @@ ipw_notification_intr(struct ipw_softc *sc, struct ipw
 void
 ipw_rx_intr(struct ipw_softc *sc)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct ipw_status *status;
        struct ipw_soft_bd *sbd;
        struct ipw_soft_buf *sbuf;
@@ -949,7 +951,7 @@ ipw_rx_intr(struct ipw_softc *sc)
 
                case IPW_STATUS_CODE_DATA_802_3:
                case IPW_STATUS_CODE_DATA_802_11:
-                       ipw_data_intr(sc, status, sbd, sbuf);
+                       ipw_data_intr(sc, status, sbd, sbuf, &ml);
                        break;
 
                case IPW_STATUS_CODE_NOTIFICATION:
@@ -966,6 +968,7 @@ ipw_rx_intr(struct ipw_softc *sc)
                    i * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
                    BUS_DMASYNC_PREWRITE);
        }
+       if_input(&sc->sc_ic.ic_if, &ml);
 
        /* tell the firmware what we have processed */
        sc->rxcur = (r == 0) ? IPW_NRBD - 1 : r - 1;
blob - bdb4827425118b9159ae05ad1263bdf5c084254f
blob + 84366f6545bde46339adf1da2956b9af8f544469
--- sys/dev/pci/if_iwi.c
+++ sys/dev/pci/if_iwi.c
@@ -87,7 +87,7 @@ int           iwi_find_txnode(struct iwi_softc *, const 
uint8_t
 int            iwi_newstate(struct ieee80211com *, enum ieee80211_state, int);
 uint8_t                iwi_rate(int);
 void           iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *,
-                   struct iwi_frame *);
+                   struct iwi_frame *, struct mbuf_list *);
 void           iwi_notification_intr(struct iwi_softc *, struct iwi_rx_data *,
                    struct iwi_notif *);
 void           iwi_rx_intr(struct iwi_softc *);
@@ -854,7 +854,7 @@ iwi_rate(int plcp)
 
 void
 iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data,
-    struct iwi_frame *frame)
+    struct iwi_frame *frame, struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -954,7 +954,7 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_dat
        rxi.rxi_flags = 0;
        rxi.rxi_rssi = frame->rssi_dbm;
        rxi.rxi_tstamp = 0;     /* unused */
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
        /* node is no longer needed */
        ieee80211_release_node(ic, ni);
@@ -1073,6 +1073,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi
 void
 iwi_rx_intr(struct iwi_softc *sc)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct iwi_rx_data *data;
        struct iwi_hdr *hdr;
        uint32_t hw;
@@ -1090,7 +1091,7 @@ iwi_rx_intr(struct iwi_softc *sc)
                switch (hdr->type) {
                case IWI_HDR_TYPE_FRAME:
                        iwi_frame_intr(sc, data,
-                           (struct iwi_frame *)(hdr + 1));
+                           (struct iwi_frame *)(hdr + 1), &ml);
                        break;
 
                case IWI_HDR_TYPE_NOTIF:
@@ -1105,6 +1106,7 @@ iwi_rx_intr(struct iwi_softc *sc)
 
                sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT;
        }
+       if_input(&sc->sc_ic.ic_if, &ml);
 
        /* tell the firmware what we have processed */
        hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1;
blob - 0b2116dbc13428f1726773000e8e6a8c251d86b4
blob + 26bd730272774dc8cef58c87638c21c0536a016a
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -368,7 +368,7 @@ void        iwm_rx_rx_phy_cmd(struct iwm_softc *, struct 
iwm_
            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 iwm_rx_data *, struct mbuf_list *);
 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 *);
@@ -3431,7 +3431,7 @@ iwm_get_noise(const struct iwm_statistics_rx_non_phy *
 
 void
 iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
-    struct iwm_rx_data *data)
+    struct iwm_rx_data *data, struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ieee80211_frame *wh;
@@ -3564,9 +3564,9 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_pac
                bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
        }
 #endif
-       ieee80211_input(IC2IFP(ic), m, ni, &rxi);
+       ieee80211_inputm(IC2IFP(ic), m, ni, &rxi, ml);
        /*
-        * ieee80211_input() might have changed our BSS.
+        * ieee80211_inputm() might have changed our BSS.
         * Restore ic_bss's channel if we are still in the same BSS.
         */
        if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
@@ -7005,6 +7005,7 @@ do {                                                      
                \
 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,
@@ -7042,7 +7043,7 @@ iwm_notif_intr(struct iwm_softc *sc)
                        break;
 
                case IWM_REPLY_RX_MPDU_CMD:
-                       iwm_rx_rx_mpdu(sc, pkt, data);
+                       iwm_rx_rx_mpdu(sc, pkt, data, &ml);
                        break;
 
                case IWM_TX_CMD:
@@ -7289,6 +7290,7 @@ iwm_notif_intr(struct iwm_softc *sc)
 
                ADVANCE_RXQ(sc);
        }
+       if_input(&sc->sc_ic.ic_if, &ml);
 
        /*
         * Tell the firmware what we have processed.
blob - 6be794c2cd435c74b1b5c3f028b9613dc74ecf20
blob + c76b53c4c97d6c49f2837667b8758958163246f4
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -156,7 +156,7 @@ int         iwn_ccmp_decap(struct iwn_softc *, struct mbuf 
*,
 void           iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *,
                    struct iwn_rx_data *);
 void           iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
-                   struct iwn_rx_data *);
+                   struct iwn_rx_data *, struct mbuf_list *);
 void           iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
                    struct iwn_rx_data *);
 void           iwn5000_rx_calib_results(struct iwn_softc *,
@@ -1937,7 +1937,7 @@ iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, s
                         * Such frames may be received out of order due to
                         * legitimate retransmissions of failed subframes
                         * in previous A-MPDUs. Duplicates will be handled
-                        * in ieee80211_input() as part of A-MPDU reordering.
+                        * in ieee80211_inputm() as part of A-MPDU reordering.
                         */
                } else if (ieee80211_has_seq(wh)) {
                        /*
@@ -2007,7 +2007,7 @@ iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *d
  */
 void
 iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
-    struct iwn_rx_data *data)
+    struct iwn_rx_data *data, struct mbuf_list *ml)
 {
        struct iwn_ops *ops = &sc->ops;
        struct ieee80211com *ic = &sc->sc_ic;
@@ -2240,7 +2240,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *
        /* Send the frame to the 802.11 layer. */
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = 0;     /* unused */
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
        /* Restore BSS channel. */
        if (ni == ic->ic_bss)
@@ -2737,6 +2737,7 @@ iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc 
 void
 iwn_notif_intr(struct iwn_softc *sc)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct iwn_ops *ops = &sc->ops;
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -2768,7 +2769,7 @@ iwn_notif_intr(struct iwn_softc *sc)
                case IWN_RX_DONE:               /* 4965AGN only. */
                case IWN_MPDU_RX_DONE:
                        /* An 802.11 frame has been received. */
-                       iwn_rx_done(sc, desc, data);
+                       iwn_rx_done(sc, desc, data, &ml);
                        break;
                case IWN_RX_COMPRESSED_BA:
                        /* A Compressed BlockAck has been received. */
@@ -2913,6 +2914,7 @@ iwn_notif_intr(struct iwn_softc *sc)
 
                sc->rxq.cur = (sc->rxq.cur + 1) % IWN_RX_RING_COUNT;
        }
+       if_input(&sc->sc_ic.ic_if, &ml);
 
        /* Tell the firmware what we have processed. */
        hw = (hw == 0) ? IWN_RX_RING_COUNT - 1 : hw - 1;
blob - 2c53aa925247b5056360daf479fca12e45624107
blob + 15629e1a07ec75f8eea39d7a629d2d84da6e550e
--- sys/dev/pci/if_rtwn.c
+++ sys/dev/pci/if_rtwn.c
@@ -248,7 +248,8 @@ uint8_t             rtwn_pci_read_1(void *, uint16_t);
 uint16_t       rtwn_pci_read_2(void *, uint16_t);
 uint32_t       rtwn_pci_read_4(void *, uint16_t);
 void           rtwn_rx_frame(struct rtwn_pci_softc *,
-                   struct r92c_rx_desc_pci *, struct rtwn_rx_data *, int);
+                   struct r92c_rx_desc_pci *, struct rtwn_rx_data *, int,
+                   struct mbuf_list *);
 int            rtwn_tx(void *, struct mbuf *, struct ieee80211_node *);
 void           rtwn_tx_done(struct rtwn_pci_softc *, int);
 int            rtwn_alloc_buffers(void *);
@@ -813,7 +814,7 @@ rtwn_pci_read_4(void *cookie, uint16_t addr)
 
 void
 rtwn_rx_frame(struct rtwn_pci_softc *sc, struct r92c_rx_desc_pci *rx_desc,
-    struct rtwn_rx_data *rx_data, int desc_idx)
+    struct rtwn_rx_data *rx_data, int desc_idx, struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_sc.sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -974,7 +975,7 @@ rtwn_rx_frame(struct rtwn_pci_softc *sc, struct r92c_r
        rxi.rxi_flags = 0;
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = 0;     /* Unused. */
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
 }
@@ -1480,6 +1481,7 @@ rtwn_pci_stop(void *cookie)
 int
 rtwn_88e_intr(struct rtwn_pci_softc *sc)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        u_int32_t status, estatus;
        int i;
 
@@ -1511,6 +1513,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);
@@ -1522,8 +1526,9 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
                        if (letoh32(rx_desc->rxdw0) & R92C_RXDW0_OWN)
                                continue;
 
-                       rtwn_rx_frame(sc, rx_desc, rx_data, i);
+                       rtwn_rx_frame(sc, rx_desc, rx_data, i, &ml);
                }
+               if_input(&ic->ic_if, &ml);
        }
 
        if (status & R88E_HIMR_HSISR_IND_ON_INT) {
@@ -1543,6 +1548,7 @@ int
 rtwn_intr(void *xsc)
 {
        struct rtwn_pci_softc *sc = xsc;
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        u_int32_t status;
        int i;
 
@@ -1561,6 +1567,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);
@@ -1572,8 +1580,9 @@ rtwn_intr(void *xsc)
                        if (letoh32(rx_desc->rxdw0) & R92C_RXDW0_OWN)
                                continue;
 
-                       rtwn_rx_frame(sc, rx_desc, rx_data, i);
+                       rtwn_rx_frame(sc, rx_desc, rx_data, i, &ml);
                }
+               if_input(&ic->ic_if, &ml);
        }
 
        if (status & R92C_IMR_BDOK)
blob - 2a91ccec016f8047bfe26ede71e8881404fef619
blob + 87f91434312f42404dbb02241eb2d4804ebbdd12
--- sys/dev/pci/if_wpi.c
+++ sys/dev/pci/if_wpi.c
@@ -103,7 +103,7 @@ void                wpi_calib_timeout(void *);
 int            wpi_ccmp_decap(struct wpi_softc *, struct mbuf *,
                    struct ieee80211_key *);
 void           wpi_rx_done(struct wpi_softc *, struct wpi_rx_desc *,
-                   struct wpi_rx_data *);
+                   struct wpi_rx_data *, struct mbuf_list *);
 void           wpi_tx_done(struct wpi_softc *, struct wpi_rx_desc *);
 void           wpi_cmd_done(struct wpi_softc *, struct wpi_rx_desc *);
 void           wpi_notif_intr(struct wpi_softc *);
@@ -1180,7 +1180,7 @@ wpi_ccmp_decap(struct wpi_softc *sc, struct mbuf *m, s
 
 void
 wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc,
-    struct wpi_rx_data *data)
+    struct wpi_rx_data *data, struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -1344,7 +1344,7 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *
        /* Send the frame to the 802.11 layer. */
        rxi.rxi_rssi = stat->rssi;
        rxi.rxi_tstamp = 0;     /* unused */
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
@@ -1412,6 +1412,7 @@ wpi_cmd_done(struct wpi_softc *sc, struct wpi_rx_desc 
 void
 wpi_notif_intr(struct wpi_softc *sc)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
        uint32_t hw;
@@ -1438,7 +1439,7 @@ wpi_notif_intr(struct wpi_softc *sc)
                switch (desc->type) {
                case WPI_RX_DONE:
                        /* An 802.11 frame has been received. */
-                       wpi_rx_done(sc, desc, data);
+                       wpi_rx_done(sc, desc, data, &ml);
                        break;
 
                case WPI_TX_DONE:
@@ -1527,6 +1528,7 @@ wpi_notif_intr(struct wpi_softc *sc)
 
                sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT;
        }
+       if_input(&ic->ic_if, &ml);
 
        /* Tell the firmware what we have processed. */
        hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1;
blob - 39edb129685cac47d29224f18c6f2e7c92922720
blob + 281a19ea8aa92c91869ae177649be9196c947ac3
--- sys/dev/usb/if_athn_usb.c
+++ sys/dev/usb/if_athn_usb.c
@@ -176,7 +176,8 @@ void                athn_usb_intr(struct usbd_xfer *, void 
*,
                    usbd_status);
 void           athn_usb_rx_radiotap(struct athn_softc *, struct mbuf *,
                    struct ar_rx_status *);
-void           athn_usb_rx_frame(struct athn_usb_softc *, struct mbuf *);
+void           athn_usb_rx_frame(struct athn_usb_softc *, struct mbuf *,
+                   struct mbuf_list *);
 void           athn_usb_rxeof(struct usbd_xfer *, void *,
                    usbd_status);
 void           athn_usb_txeof(struct usbd_xfer *, void *,
@@ -1994,7 +1995,8 @@ athn_usb_rx_radiotap(struct athn_softc *sc, struct mbu
 #endif
 
 void
-athn_usb_rx_frame(struct athn_usb_softc *usc, struct mbuf *m)
+athn_usb_rx_frame(struct athn_usb_softc *usc, struct mbuf *m,
+    struct mbuf_list *ml)
 {
        struct athn_softc *sc = &usc->sc_sc;
        struct ieee80211com *ic = &sc->sc_ic;
@@ -2060,7 +2062,7 @@ athn_usb_rx_frame(struct athn_usb_softc *usc, struct m
        rxi.rxi_flags = 0;
        rxi.rxi_rssi = rs->rs_rssi + AR_USB_DEFAULT_NF;
        rxi.rxi_tstamp = betoh64(rs->rs_tstamp);
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
@@ -2074,6 +2076,7 @@ void
 athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
     usbd_status status)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct athn_usb_rx_data *data = priv;
        struct athn_usb_softc *usc = data->sc;
        struct athn_softc *sc = &usc->sc_sc;
@@ -2101,7 +2104,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
                        if (__predict_true(stream->m != NULL)) {
                                memcpy(mtod(stream->m, uint8_t *) +
                                    stream->moff, buf, stream->left);
-                               athn_usb_rx_frame(usc, stream->m);
+                               athn_usb_rx_frame(usc, stream->m, &ml);
                                stream->m = NULL;
                        }
                        /* Next header is 32-bit aligned. */
@@ -2167,7 +2170,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
                if (__predict_true(m != NULL)) {
                        /* We have all the pktlen bytes in this xfer. */
                        memcpy(mtod(m, uint8_t *), buf, pktlen);
-                       athn_usb_rx_frame(usc, m);
+                       athn_usb_rx_frame(usc, m, &ml);
                }
 
                /* Next header is 32-bit aligned. */
@@ -2175,6 +2178,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
                buf += off;
                len -= off;
        }
+       if_input(ifp, &ml);
 
  resubmit:
        /* Setup a new transfer. */
blob - cb7e65865adb17b86e10bf5c2bc59983a5c8c2c9
blob + 7461c3e57fb2d76faa3c0da0380827a85d19d5f7
--- sys/dev/usb/if_otus.c
+++ sys/dev/usb/if_otus.c
@@ -124,7 +124,8 @@ void                otus_newassoc(struct ieee80211com *, 
struct ieee
                    int);
 void           otus_intr(struct usbd_xfer *, void *, usbd_status);
 void           otus_cmd_rxeof(struct otus_softc *, uint8_t *, int);
-void           otus_sub_rxeof(struct otus_softc *, uint8_t *, int);
+void           otus_sub_rxeof(struct otus_softc *, uint8_t *, int,
+                   struct mbuf_list *);
 void           otus_rxeof(struct usbd_xfer *, void *, usbd_status);
 void           otus_txeof(struct usbd_xfer *, void *, usbd_status);
 int            otus_tx(struct otus_softc *, struct mbuf *,
@@ -1064,7 +1065,8 @@ otus_cmd_rxeof(struct otus_softc *sc, uint8_t *buf, in
 }
 
 void
-otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, int len)
+otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, int len,
+    struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -1195,7 +1197,7 @@ otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, in
        rxi.rxi_flags = 0;
        rxi.rxi_rssi = tail->rssi;
        rxi.rxi_tstamp = 0;     /* unused */
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
@@ -1205,6 +1207,7 @@ otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, in
 void
 otus_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct otus_rx_data *data = priv;
        struct otus_softc *sc = data->sc;
        caddr_t buf = data->buf;
@@ -1234,13 +1237,14 @@ otus_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
                        break;
                }
                /* Process sub-xfer. */
-               otus_sub_rxeof(sc, (uint8_t *)&head[1], hlen);
+               otus_sub_rxeof(sc, (uint8_t *)&head[1], hlen, &ml);
 
                /* Next sub-xfer is aligned on a 32-bit boundary. */
                hlen = (sizeof (*head) + hlen + 3) & ~3;
                buf += hlen;
                len -= hlen;
        }
+       if_input(&sc->sc_ic.ic_if, &ml);
 
  resubmit:
        usbd_setup_xfer(xfer, sc->data_rx_pipe, data, data->buf, OTUS_RXBUFSZ,
blob - 417666c3503da89fce1d3dc4301b48376dcf7e41
blob + 71c2c98b878349169107680c071978482dce1678
--- sys/dev/usb/if_rsu.c
+++ sys/dev/usb/if_rsu.c
@@ -161,7 +161,8 @@ void                rsu_event_join_bss(struct rsu_softc *, 
uint8_t *
 void           rsu_rx_event(struct rsu_softc *, uint8_t, uint8_t *, int);
 void           rsu_rx_multi_event(struct rsu_softc *, uint8_t *, int);
 int8_t         rsu_get_rssi(struct rsu_softc *, int, void *);
-void           rsu_rx_frame(struct rsu_softc *, uint8_t *, int);
+void           rsu_rx_frame(struct rsu_softc *, uint8_t *, int,
+                   struct mbuf_list *);
 void           rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int);
 void           rsu_rxeof(struct usbd_xfer *, void *, usbd_status);
 void           rsu_txeof(struct usbd_xfer *, void *, usbd_status);
@@ -1261,7 +1262,8 @@ rsu_get_rssi(struct rsu_softc *sc, int rate, void *phy
 }
 
 void
-rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen)
+rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen,
+    struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -1371,7 +1373,7 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int p
        rxi.rxi_flags = 0;
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = 0;     /* Unused. */
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
        splx(s);
@@ -1380,6 +1382,7 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int p
 void
 rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct r92s_rx_stat *stat;
        uint32_t rxdw0;
        int totlen, pktlen, infosz, npkts;
@@ -1408,13 +1411,14 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf,
                        break;
 
                /* Process 802.11 frame. */
-               rsu_rx_frame(sc, buf, pktlen);
+               rsu_rx_frame(sc, buf, pktlen, &ml);
 
                /* Next chunk is 128-byte aligned. */
                totlen = (totlen + 127) & ~127;
                buf += totlen;
                len -= totlen;
        }
+       if_input(&sc->sc_ic.ic_if, &ml);
 }
 
 void
blob - fc6ba52f271725fe7afbb4abf1a4a1700920a1b4
blob + f22d6d4decb01bab31aa8c0f6fae587651dd3589
--- sys/dev/usb/if_run.c
+++ sys/dev/usb/if_run.c
@@ -376,7 +376,8 @@ void                run_calibrate_to(void *);
 void           run_calibrate_cb(struct run_softc *, void *);
 void           run_newassoc(struct ieee80211com *, struct ieee80211_node *,
                    int);
-void           run_rx_frame(struct run_softc *, uint8_t *, int);
+void           run_rx_frame(struct run_softc *, uint8_t *, int,
+                   struct mbuf_list *);
 void           run_rxeof(struct usbd_xfer *, void *, usbd_status);
 void           run_txeof(struct usbd_xfer *, void *, usbd_status);
 int            run_tx(struct run_softc *, struct mbuf *,
@@ -2158,7 +2159,8 @@ run_maxrssi_chain(struct run_softc *sc, const struct r
 }
 
 void
-run_rx_frame(struct run_softc *sc, uint8_t *buf, int dmalen)
+run_rx_frame(struct run_softc *sc, uint8_t *buf, int dmalen,
+    struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -2295,7 +2297,7 @@ run_rx_frame(struct run_softc *sc, uint8_t *buf, int d
        ni = ieee80211_find_rxnode(ic, wh);
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = 0;     /* unused */
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
        /* node is no longer needed */
        ieee80211_release_node(ic, ni);
@@ -2305,6 +2307,7 @@ run_rx_frame(struct run_softc *sc, uint8_t *buf, int d
 void
 run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct run_rx_data *data = priv;
        struct run_softc *sc = data->sc;
        uint8_t *buf;
@@ -2348,10 +2351,11 @@ run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
                            dmalen + 8, xferlen));
                        break;
                }
-               run_rx_frame(sc, buf + sizeof (uint32_t), dmalen);
+               run_rx_frame(sc, buf + sizeof (uint32_t), dmalen, &ml);
                buf += dmalen + 8;
                xferlen -= dmalen + 8;
        }
+       if_input(&sc->sc_ic.ic_if, &ml);
 
 skip:  /* setup a new transfer */
        usbd_setup_xfer(xfer, sc->rxq.pipeh, data, data->buf, RUN_MAX_RXSZ,
blob - 96a1ad1a91c3e98ebc6dece98df6ac277046612c
blob + 12fc517090e80d703749a326949aeaaf83617639
--- sys/dev/usb/if_urtwn.c
+++ sys/dev/usb/if_urtwn.c
@@ -380,7 +380,8 @@ void                urtwn_set_key_cb(struct urtwn_softc *, 
void *);
 void           urtwn_delete_key(struct ieee80211com *,
                    struct ieee80211_node *, struct ieee80211_key *);
 void           urtwn_delete_key_cb(struct urtwn_softc *, void *);
-void           urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int);
+void           urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int,
+                   struct mbuf_list *);
 void           urtwn_rxeof(struct usbd_xfer *, void *,
                    usbd_status);
 void           urtwn_txeof(struct usbd_xfer *, void *,
@@ -1083,7 +1084,8 @@ urtwn_delete_key_cb(struct urtwn_softc *sc, void *arg)
 }
 
 void
-urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen)
+urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen,
+    struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_sc.sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -1194,7 +1196,7 @@ urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, i
        rxi.rxi_flags = 0;
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = 0;     /* Unused. */
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
        splx(s);
@@ -1204,8 +1206,10 @@ void
 urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
     usbd_status status)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        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;
@@ -1298,13 +1302,14 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
                        break;
 
                /* Process 802.11 frame. */
-               urtwn_rx_frame(sc, buf, pktlen);
+               urtwn_rx_frame(sc, buf, pktlen, &ml);
 
                /* Handle chunk alignment. */
                totlen = (totlen + align) & ~align;
                buf += totlen;
                len -= totlen;
        }
+       if_input(&ic->ic_if, &ml);
 
  resubmit:
        /* Setup a new transfer. */
blob - 689ac7e7178ca36a091d25cc6f2cf8d15cc45b0b
blob + ea8545a4ba48d49eb2830b4e6886613e2e181a7c
--- sys/dev/usb/if_zyd.c
+++ sys/dev/usb/if_zyd.c
@@ -217,7 +217,8 @@ void                zyd_set_chan(struct zyd_softc *, struct 
ieee8021
 int            zyd_set_beacon_interval(struct zyd_softc *, int);
 uint8_t                zyd_plcp_signal(int);
 void           zyd_intr(struct usbd_xfer *, void *, usbd_status);
-void           zyd_rx_data(struct zyd_softc *, const uint8_t *, uint16_t);
+void           zyd_rx_data(struct zyd_softc *, const uint8_t *, uint16_t,
+                   struct mbuf_list *);
 void           zyd_rxeof(struct usbd_xfer *, void *, usbd_status);
 void           zyd_txeof(struct usbd_xfer *, void *, usbd_status);
 int            zyd_tx(struct zyd_softc *, struct mbuf *,
@@ -1894,7 +1895,8 @@ zyd_intr(struct usbd_xfer *xfer, void *priv, usbd_stat
 }
 
 void
-zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf, uint16_t len)
+zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf, uint16_t len,
+    struct mbuf_list *ml)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
@@ -1980,7 +1982,7 @@ zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf, 
        rxi.rxi_flags = 0;
        rxi.rxi_rssi = stat->rssi;
        rxi.rxi_tstamp = 0;     /* unused */
-       ieee80211_input(ifp, m, ni, &rxi);
+       ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
        /* node is no longer needed */
        ieee80211_release_node(ic, ni);
@@ -1991,6 +1993,7 @@ zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf, 
 void
 zyd_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
        struct zyd_rx_data *data = priv;
        struct zyd_softc *sc = data->sc;
        struct ieee80211com *ic = &sc->sc_ic;
@@ -2030,15 +2033,16 @@ zyd_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
                        if (len == 0 || p + len >= end)
                                break;
 
-                       zyd_rx_data(sc, p, len);
+                       zyd_rx_data(sc, p, len, &ml);
                        /* next frame is aligned on a 32-bit boundary */
                        p += (len + 3) & ~3;
                }
        } else {
                DPRINTFN(3, ("received single-frame transfer\n"));
 
-               zyd_rx_data(sc, data->buf, len);
+               zyd_rx_data(sc, data->buf, len, &ml);
        }
+       if_input(ifp, &ml);
 
 skip:  /* setup a new transfer */
        usbd_setup_xfer(xfer, sc->zyd_ep[ZYD_ENDPT_BIN], data, NULL,
blob - 73a9d5229502797c5279734663b1ac1591bec309
blob + 414b0a3419ed9a14e3331fa65a8bbb66a166391e
--- 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,10 +155,16 @@ 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 acts on management frames immediately and queues data frames
+ * on the specified mbuf list. Delivery of queued data frames to upper layers
+ * must be triggered with if_input(). Drivers should call if_input() only once
+ * per Rx interrupt to avoid triggering the input ifq pressure drop mechanism
+ * unnecessarily.
  */
 void
-ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
-    struct ieee80211_rxinfo *rxi)
+ieee80211_inputm(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
+    struct ieee80211_rxinfo *rxi, struct mbuf_list *ml)
 {
        struct ieee80211com *ic = (void *)ifp;
        struct ieee80211_frame *wh;
@@ -463,9 +469,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, ml);
                else
-                       ieee80211_decap(ic, m, ni, hdrlen);
+                       ieee80211_decap(ic, m, ni, hdrlen, ml);
                return;
 
        case IEEE80211_FC0_TYPE_MGT:
@@ -560,6 +566,17 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
        }
 }
 
+/* Input handler for drivers which only receive one frame per interrupt. */
+void
+ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
+    struct ieee80211_rxinfo *rxi)
+{
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+
+       ieee80211_inputm(ifp, m, ni, rxi, &ml);
+       if_input(ifp, &ml);
+}
+
 /*
  * Handle defragmentation (see 9.5 and Annex C).  We support the concurrent
  * reception of fragments of three fragmented MSDUs or MMPDUs.
@@ -856,8 +873,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 +937,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 +1000,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 +1008,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 +1074,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 - e622d35f4dcd21ea0bb40c6a5d0b3f758e197b38
blob + 52cf8fddfc1658a5c38a4895fff4e858d15bb876
--- sys/net80211/ieee80211_proto.h
+++ sys/net80211/ieee80211_proto.h
@@ -66,6 +66,9 @@ struct ieee80211_rsnparams;
 extern void ieee80211_set_link_state(struct ieee80211com *, int);
 extern u_int ieee80211_get_hdrlen(const struct ieee80211_frame *);
 extern int ieee80211_classify(struct ieee80211com *, struct mbuf *);
+extern void ieee80211_inputm(struct ifnet *, struct mbuf *,
+               struct ieee80211_node *, struct ieee80211_rxinfo *,
+               struct mbuf_list *);
 extern void ieee80211_input(struct ifnet *, struct mbuf *,
                struct ieee80211_node *, struct ieee80211_rxinfo *);
 extern int ieee80211_output(struct ifnet *, struct mbuf *, struct sockaddr *,

Reply via email to