Defer rtm_80211info() call from ieee80211_set_link_state() to a task context.
authorstsp <stsp@openbsd.org>
Sun, 5 Dec 2021 11:33:45 +0000 (11:33 +0000)
committerstsp <stsp@openbsd.org>
Sun, 5 Dec 2021 11:33:45 +0000 (11:33 +0000)
Sending routing messages requires a socket lock which may sleep.
ieee80211_set_link_state() is called from interrupts and timeouts where
sleeping is not allowed. mvs@ pointed out that if_link_state_change()
is already using a task for this reason.

Should fix a witness-related panic reported by cheloha@

ok mvs@ tobhe@ florian@

sys/net80211/ieee80211.c
sys/net80211/ieee80211_proto.c
sys/net80211/ieee80211_proto.h
sys/net80211/ieee80211_var.h

index 7bb6819..83d4eac 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211.c,v 1.85 2021/10/11 09:01:06 stsp Exp $     */
+/*     $OpenBSD: ieee80211.c,v 1.86 2021/12/05 11:33:45 stsp Exp $     */
 /*     $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $    */
 
 /*-
@@ -193,6 +193,7 @@ ieee80211_ifattach(struct ifnet *ifp)
        if_addgroup(ifp, "wlan");
        ifp->if_priority = IF_WIRELESS_DEFAULT_PRIORITY;
 
+       task_set(&ic->ic_rtm_80211info_task, ieee80211_rtm_80211info_task, ic);
        ieee80211_set_link_state(ic, LINK_STATE_DOWN);
 
        timeout_set(&ic->ic_bgscan_timeout, ieee80211_bgscan_timeout, ifp);
@@ -203,6 +204,7 @@ ieee80211_ifdetach(struct ifnet *ifp)
 {
        struct ieee80211com *ic = (void *)ifp;
 
+       task_del(systq, &ic->ic_rtm_80211info_task);
        timeout_del(&ic->ic_bgscan_timeout);
 
        /*
index 447a267..afffb2b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_proto.c,v 1.106 2021/12/03 12:41:36 stsp Exp $      */
+/*     $OpenBSD: ieee80211_proto.c,v 1.107 2021/12/05 11:33:45 stsp Exp $      */
 /*     $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $       */
 
 /*-
@@ -1287,6 +1287,31 @@ justcleanup:
        return 0;
 }
 
+void
+ieee80211_rtm_80211info_task(void *arg)
+{
+       struct ieee80211com *ic = arg;
+       struct ifnet *ifp = &ic->ic_if;
+       struct if_ieee80211_data ifie;
+       int s = splnet();
+
+       if (LINK_STATE_IS_UP(ifp->if_link_state)) {
+               memset(&ifie, 0, sizeof(ifie));
+               ifie.ifie_nwid_len = ic->ic_bss->ni_esslen;
+               memcpy(ifie.ifie_nwid, ic->ic_bss->ni_essid,
+                   sizeof(ifie.ifie_nwid));
+               memcpy(ifie.ifie_addr, ic->ic_bss->ni_bssid,
+                   sizeof(ifie.ifie_addr));
+               ifie.ifie_channel = ieee80211_chan2ieee(ic,
+                   ic->ic_bss->ni_chan);
+               ifie.ifie_flags = ic->ic_flags;
+               ifie.ifie_xflags = ic->ic_xflags;
+               rtm_80211info(&ic->ic_if, &ifie);
+       }
+
+       splx(s);
+}
+
 void
 ieee80211_set_link_state(struct ieee80211com *ic, int nstate)
 {
@@ -1307,20 +1332,8 @@ ieee80211_set_link_state(struct ieee80211com *ic, int nstate)
        }
        if (nstate != ifp->if_link_state) {
                ifp->if_link_state = nstate;
-               if (LINK_STATE_IS_UP(nstate)) {
-                       struct if_ieee80211_data ifie;
-                       memset(&ifie, 0, sizeof(ifie));
-                       ifie.ifie_nwid_len = ic->ic_bss->ni_esslen;
-                       memcpy(ifie.ifie_nwid, ic->ic_bss->ni_essid,
-                           sizeof(ifie.ifie_nwid));
-                       memcpy(ifie.ifie_addr, ic->ic_bss->ni_bssid,
-                           sizeof(ifie.ifie_addr));
-                       ifie.ifie_channel = ieee80211_chan2ieee(ic,
-                           ic->ic_bss->ni_chan);
-                       ifie.ifie_flags = ic->ic_flags;
-                       ifie.ifie_xflags = ic->ic_xflags;
-                       rtm_80211info(&ic->ic_if, &ifie);
-               }
+               if (LINK_STATE_IS_UP(nstate))
+                       task_add(systq, &ic->ic_rtm_80211info_task);
                if_link_state_change(ifp);
        }
 }
index 7208e5d..da0ab91 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_proto.h,v 1.46 2019/09/12 12:55:07 stsp Exp $       */
+/*     $OpenBSD: ieee80211_proto.h,v 1.47 2021/12/05 11:33:45 stsp Exp $       */
 /*     $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $       */
 
 /*-
@@ -63,6 +63,7 @@ extern        void ieee80211_proto_detach(struct ifnet *);
 struct ieee80211_node;
 struct ieee80211_rxinfo;
 struct ieee80211_rsnparams;
+extern void ieee80211_rtm_80211info_task(void *);
 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 *);
index dd17ed7..d211947 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_var.h,v 1.108 2021/12/03 12:41:36 stsp Exp $        */
+/*     $OpenBSD: ieee80211_var.h,v 1.109 2021/12/05 11:33:45 stsp Exp $        */
 /*     $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */
 
 /*-
@@ -306,6 +306,7 @@ struct ieee80211com {
        struct timeout          ic_inact_timeout; /* node inactivity timeout */
        struct timeout          ic_node_cache_timeout;
 #endif
+       struct task             ic_rtm_80211info_task;
        int                     ic_des_esslen;
        u_int8_t                ic_des_essid[IEEE80211_NWID_LEN];
        struct ieee80211_channel *ic_des_chan;  /* desired channel */