Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src-draft/trunk]: src/sys/net80211 Defer management input via a ifqueue.



details:   https://anonhg.NetBSD.org/src-all/rev/44884fd6d5c6
branches:  trunk
changeset: 375275:44884fd6d5c6
user:      Martin Husemann <martin%NetBSD.org@localhost>
date:      Tue Sep 20 20:29:23 2022 +0200

description:
Defer management input via a ifqueue.

Introduce a helper function ieee80211_rx_enqueue() that handles all
the details of incoming traffic and can be safely called by
drivers with locks held.

diffstat:

 sys/net80211/ieee80211.c        |   12 ++++
 sys/net80211/ieee80211_netbsd.c |  120 ++++++++++++++++++++++++++++++++++++++++
 sys/net80211/ieee80211_netbsd.h |   10 +++
 3 files changed, 142 insertions(+), 0 deletions(-)

diffs (214 lines):

diff -r 00b5d2385f78 -r 44884fd6d5c6 sys/net80211/ieee80211.c
--- a/sys/net80211/ieee80211.c  Tue Sep 20 20:26:54 2022 +0200
+++ b/sys/net80211/ieee80211.c  Tue Sep 20 20:29:23 2022 +0200
@@ -435,6 +435,7 @@ ieee80211_ifattach(struct ieee80211com *
        if (workqueue_create(&ic->ic_tq, name,
            ieee80211_runwork, ic, PRI_SOFTNET, IPL_NET, WQ_MPSAFE))
                panic("net80211 workqueue not created");
+       ieee80211_init_mgmt_wqueue();
 #endif
 
        /*
@@ -483,6 +484,9 @@ void
 ieee80211_ifdetach(struct ieee80211com *ic)
 {
        struct ieee80211vap *vap;
+#if __NetBSD__
+       bool last_vap;
+#endif
 
        /*
         * We use this as an indicator that ifattach never had a chance to be
@@ -495,6 +499,9 @@ ieee80211_ifdetach(struct ieee80211com *
 
        mtx_lock(&ic_list_mtx);
        LIST_REMOVE(ic, ic_next);
+#if __NetBSD__
+       last_vap = LIST_EMPTY(&ic_head);
+#endif
        mtx_unlock(&ic_list_mtx);
 
        taskqueue_drain(ic->ic_tq, &ic->ic_restart_task);
@@ -532,6 +539,11 @@ ieee80211_ifdetach(struct ieee80211com *
        taskqueue_free(ic->ic_tq);
        IEEE80211_TX_LOCK_DESTROY(ic);
        IEEE80211_LOCK_DESTROY(ic);
+
+#if __NetBSD__
+       if (last_vap)
+               ieee80211_deinit_mgmt_wqueue();
+#endif
 }
 
 struct ieee80211com *
diff -r 00b5d2385f78 -r 44884fd6d5c6 sys/net80211/ieee80211_netbsd.c
--- a/sys/net80211/ieee80211_netbsd.c   Tue Sep 20 20:26:54 2022 +0200
+++ b/sys/net80211/ieee80211_netbsd.c   Tue Sep 20 20:29:23 2022 +0200
@@ -86,9 +86,14 @@ static struct if_clone wlan_cloner =
        IF_CLONE_WITH_ARGS_INITIALIZER(wlanname,
            wlan_clone_create, wlan_clone_destroy);
 
+static void ieee80211_rx_mgmt_cb(void *, int);
+static struct ifqueue ieee80211_rx_mgmt;
+static struct task ieee80211_mgmt_input;
+
 int
 ieee80211_init0(void)
 {
+
        return 0;
 }
 
@@ -1566,6 +1571,7 @@ ieee80211_activate(struct ieee80211com *
 void
 ieee80211_if_attach(struct ifnet *ifp, const uint8_t *lla)
 {
+
        ifp->if_type = IFT_ETHER;
        ifp->if_hdrlen = ETHER_HDR_LEN;
        ifp->if_dlt = DLT_EN10MB;
@@ -1581,3 +1587,117 @@ ieee80211_if_attach(struct ifnet *ifp, c
        ifp->if_broadcastaddr = etherbroadcastaddr;
        bpf_attach(ifp, DLT_EN10MB, ETHER_HDR_LEN);
 }
+
+/*
+ * If we have not yet initialized the ifq/task for global defered
+ * processing of mgmt/ctrl frames, do it now.
+ */
+void
+ieee80211_init_mgmt_wqueue(void)
+{
+       if (ieee80211_rx_mgmt.ifq_maxlen != 0)
+               return; /* been here before */
+
+       IFQ_SET_MAXLEN(&ieee80211_rx_mgmt, IFQ_MAXLEN);
+       IFQ_LOCK_INIT(&ieee80211_rx_mgmt);
+       TASK_INIT(&ieee80211_mgmt_input, 0, ieee80211_rx_mgmt_cb, 0);
+}
+
+/*
+ * The last VAP is gone, free taskquee and IFQ resources
+ */
+void
+ieee80211_deinit_mgmt_wqueue(void)
+{
+
+       IFQ_LOCK_DESTROY(&ieee80211_rx_mgmt);
+       TASK_DESTROY(&ieee80211_mgmt_input);
+       memset(&ieee80211_rx_mgmt, 0, sizeof ieee80211_rx_mgmt);
+       memset(&ieee80211_mgmt_input, 0, sizeof ieee80211_mgmt_input);
+}
+
+/*
+ * utility function to handle RX mbuf:
+ *  - classifies input and uses proper API to pass it further up the stack
+ *  - may queue and process input later in thread context, if input needs
+ *    more work than we are allowed in softint context
+ */
+void
+ieee80211_rx_enqueue(struct ieee80211com *ic, struct mbuf *m, int rssi)
+{
+       struct ieee80211_frame *wh;
+       struct ieee80211_node *ni;
+
+       wh = mtod(m, struct ieee80211_frame *);
+       ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
+
+       if (IEEE80211_IS_DATA(wh)) {
+               /*
+                * Just pass it up, it will be enqueued on the VAPs ifqueue
+               */
+               if (ni != NULL) {
+                       if (ni->ni_vap == NULL) {
+                               ieee80211_free_node(ni);
+                               return;
+                       }
+                       ieee80211_input(ni, m, rssi, 0);
+                       ieee80211_free_node(ni);
+               } else {
+                       /* XXX will this ever happen? */
+                       ieee80211_input_all(ic, m, rssi, 0);
+               }
+       } else {
+               /*
+                * We might need to take "heavy" locks during
+                * further processing (like the IC lock), and can
+                * not do this from softint or callout context.
+                */
+               M_SETCTX(m, ic);
+               m_append(m, sizeof(rssi), &rssi);
+               IF_ENQUEUE(&ieee80211_rx_mgmt, m);
+               taskqueue_enqueue(ic->ic_tq, &ieee80211_mgmt_input);
+       }
+}
+
+static void
+ieee80211_rx_mgmt_cb(void *a0, int a1)
+{
+       struct mbuf *m, *ml;
+       struct ieee80211com *ic;
+       struct ieee80211_node *ni;
+       struct ieee80211_frame *wh;
+       int rssi;
+
+       for (;;) {
+               IF_DEQUEUE(&ieee80211_rx_mgmt, m);
+               if (!m)
+                       return;
+               ic = M_GETCTX(m, struct ieee80211com *);
+               M_SETCTX(m, NULL);
+               /*
+                * usually this will be a single mbuf
+                */
+               for (ml = m; ml->m_next != NULL; ml = ml->m_next)
+                       ;
+               memcpy(&rssi, mtod(m, char *) + m->m_len - sizeof(rssi),
+                   sizeof(rssi));
+               m_adj(m, -(ssize_t)sizeof(rssi));
+
+
+               wh = mtod(m, struct ieee80211_frame *);
+               ni = ieee80211_find_rxnode(ic,
+                   (struct ieee80211_frame_min *)wh);
+
+               if (ni != NULL) {
+                       if (ni->ni_vap == NULL) {
+                               ieee80211_free_node(ni);
+                               return;
+                       }
+                       ieee80211_input(ni, m, rssi, 0);
+                       ieee80211_free_node(ni);
+               } else {
+                       ieee80211_input_all(ic, m, rssi, 0);
+               }
+       }
+}
+
diff -r 00b5d2385f78 -r 44884fd6d5c6 sys/net80211/ieee80211_netbsd.h
--- a/sys/net80211/ieee80211_netbsd.h   Tue Sep 20 20:26:54 2022 +0200
+++ b/sys/net80211/ieee80211_netbsd.h   Tue Sep 20 20:29:23 2022 +0200
@@ -135,6 +135,8 @@ void taskqueue_drain_timeout(struct work
         struct timeout_task *timeout_task);
 int  ieee80211_clone_attach(void);
 void ieee80211_if_attach(struct ifnet *ifp, const uint8_t *lla);
+void ieee80211_init_mgmt_wqueue(void);
+void ieee80211_deinit_mgmt_wqueue(void);
 
 
 #define TASK_INIT(var, pri, func, arg) do { \
@@ -1121,6 +1123,14 @@ int ieee80211_activate(struct ieee80211c
 #define        ieee80211_get_qos(WH)   \
        (((struct ieee80211_qosframe *)(void*)(WH))->i_qos[0])
 
+/*
+ * utility function to handle RX mbuf:
+ *  - classifies input and uses proper API to pass it further up the stack
+ *  - may queue and process input later in thread context, if input needs
+ *    more work than we are allowed in softint context
+ */
+void ieee80211_rx_enqueue(struct ieee80211com *ic, struct mbuf *m, int rssi);
+
 #endif /* _KERNEL */
 
 #endif /* _NET80211_IEEE80211_NETBSD_H_ */



Home | Main Index | Thread Index | Old Index