From e798b40ea0544f3813d4fbf7be2d26cbec7f6a9f Mon Sep 17 00:00:00 2001 From: stsp Date: Sun, 5 Dec 2021 11:33:45 +0000 Subject: [PATCH] Defer rtm_80211info() call from ieee80211_set_link_state() to a task context. 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 | 4 +++- sys/net80211/ieee80211_proto.c | 43 ++++++++++++++++++++++------------ sys/net80211/ieee80211_proto.h | 3 ++- sys/net80211/ieee80211_var.h | 3 ++- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index 7bb68194dd7..83d4eac091a 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -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); /* diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index 447a2676bfb..afffb2b26df 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -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); } } diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h index 7208e5dc0be..da0ab9168df 100644 --- a/sys/net80211/ieee80211_proto.h +++ b/sys/net80211/ieee80211_proto.h @@ -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 *); diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index dd17ed76031..d211947e3d0 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -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 */ -- 2.20.1