Running "ifconfig ral0 debug down up" can leave slow systems, such as edd@'s soekris, with an unusable wireless interface until reboot.
The net80211 layer will run a scan when the interface comes up. The scan hops from channel to channel every 200msec. This hopping is controlled via a timeout that runs at IPL_SOFTCLOCK. When the scan reaches the last channel it terminates. The problem with soekris is that, in noisy environments, they take so much time printing debug messsages about received frames from ieee80211_input() to the serial console that another RX interrupt will run next at IPL_NET. This prevents the scan from running its 200msc timeout handler at IPL_SOFTCLOCK, and the scan never finishes. With the diff below, we print the message from a work queue at IPL_TTY instead (idea from guenther@). This allows the soekris to finish the scan. The box is still hardly responsive during the scan but at least concurrent SSH sessions remain somewhat responsive and eventually the soekris recovers completely. Index: ieee80211_input.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v retrieving revision 1.119 diff -u -p -r1.119 ieee80211_input.c --- ieee80211_input.c 5 Apr 2011 11:48:28 -0000 1.119 +++ ieee80211_input.c 12 Jul 2012 15:42:24 -0000 @@ -42,6 +42,7 @@ #include <sys/errno.h> #include <sys/proc.h> #include <sys/sysctl.h> +#include <sys/workq.h> #include <net/if.h> #include <net/if_dl.h> @@ -131,6 +132,9 @@ void ieee80211_recv_bar(struct ieee80211 void ieee80211_bar_tid(struct ieee80211com *, struct ieee80211_node *, u_int8_t, u_int16_t); #endif +void ieee80211_input_print_frame(struct ieee80211com *, struct ifnet *, + struct ieee80211_frame *, struct ieee80211_rxinfo *); +void ieee80211_input_print_frame_task(void *, void *); /* * Retrieve the length in bytes of an 802.11 header. @@ -152,6 +156,71 @@ ieee80211_get_hdrlen(const struct ieee80 return size; } +/* Work queue task that prints a received frame. Avoids printf() from + * interrupt context at IPL_NET making slow machines unusable when many + * rames are received and the interface is put in debug mode. */ +void +ieee80211_input_print_frame_task(void *arg1, void *arg2) +{ + char *msg = arg1; + + printf(msg); + free(msg, M_DEVBUF); +} + +void +ieee80211_input_print_frame(struct ieee80211com *ic, struct ifnet *ifp, + struct ieee80211_frame *wh, struct ieee80211_rxinfo *rxi) +{ + int doprint, error; + char *msg; + u_int8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + /* avoid to print too many frames */ + doprint = 0; + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BEACON: + if (ic->ic_state == IEEE80211_S_SCAN) + doprint = 1; + break; +#ifndef IEEE80211_STA_ONLY + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + if (ic->ic_opmode == IEEE80211_M_IBSS) + doprint = 1; + break; +#endif + default: + doprint = 1; + break; + } +#ifdef IEEE80211_DEBUG + doprint += ieee80211_debug; +#endif + if (!doprint) + return; + + msg = malloc(1024, M_DEVBUF, M_NOWAIT); + if (msg == NULL) + return; + + snprintf(msg, 1024, "%s: received %s from %s rssi %d mode %s\n", + ifp->if_xname, + ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], + ether_sprintf(wh->i_addr2), rxi->rxi_rssi, + ieee80211_phymode_name[ieee80211_chan2mode( + ic, ic->ic_bss->ni_chan)]); + + if (ic->ic_print_workq) { + error = workq_add_task(ic->ic_print_workq, 0, + ieee80211_input_print_frame_task, msg, NULL); + if (error) + free(msg, M_DEVBUF); + } else { + printf(msg); + free(msg, M_DEVBUF); + } +} + /* * Process a received frame. The node associated with the sender * should be supplied. If nothing was found in the node table then @@ -467,37 +536,8 @@ ieee80211_input(struct ifnet *ifp, struc goto out; } - if (ifp->if_flags & IFF_DEBUG) { - /* avoid to print too many frames */ - int doprint = 0; - - switch (subtype) { - case IEEE80211_FC0_SUBTYPE_BEACON: - if (ic->ic_state == IEEE80211_S_SCAN) - doprint = 1; - break; -#ifndef IEEE80211_STA_ONLY - case IEEE80211_FC0_SUBTYPE_PROBE_REQ: - if (ic->ic_opmode == IEEE80211_M_IBSS) - doprint = 1; - break; -#endif - default: - doprint = 1; - break; - } -#ifdef IEEE80211_DEBUG - doprint += ieee80211_debug; -#endif - if (doprint) - printf("%s: received %s from %s rssi %d mode %s\n", - ifp->if_xname, - ieee80211_mgt_subtype_name[subtype - >> IEEE80211_FC0_SUBTYPE_SHIFT], - ether_sprintf(wh->i_addr2), rxi->rxi_rssi, - ieee80211_phymode_name[ieee80211_chan2mode(ic, - ic->ic_bss->ni_chan)]); - } + if (ifp->if_flags & IFF_DEBUG) + ieee80211_input_print_frame(ic, ifp, wh, rxi); #if NBPFILTER > 0 if (ic->ic_rawbpf) bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_IN); Index: ieee80211_node.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_node.c,v retrieving revision 1.68 diff -u -p -r1.68 ieee80211_node.c --- ieee80211_node.c 25 Jan 2012 17:04:02 -0000 1.68 +++ ieee80211_node.c 12 Jul 2012 15:17:18 -0000 @@ -45,6 +45,7 @@ #include <sys/proc.h> #include <sys/sysctl.h> #include <sys/tree.h> +#include <sys/workq.h> #include <net/if.h> #include <net/if_dl.h> @@ -153,6 +154,7 @@ ieee80211_node_attach(struct ifnet *ifp) ic->ic_max_aid = IEEE80211_AID_DEF; else if (ic->ic_max_aid > IEEE80211_AID_MAX) ic->ic_max_aid = IEEE80211_AID_MAX; + ic->ic_print_workq = workq_create(ifp->if_xname, 1, IPL_TTY); #ifndef IEEE80211_STA_ONLY size = howmany(ic->ic_max_aid, 32) * sizeof(u_int32_t); ic->ic_aid_bitmap = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); @@ -227,6 +229,10 @@ ieee80211_node_detach(struct ifnet *ifp) timeout_del(&ic->ic_node_cache_timeout); #endif timeout_del(&ic->ic_rsn_timeout); + if (ic->ic_print_workq) { + workq_destroy(ic->ic_print_workq); + ic->ic_print_workq = NULL; + } } /* Index: ieee80211_var.h =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_var.h,v retrieving revision 1.62 diff -u -p -r1.62 ieee80211_var.h --- ieee80211_var.h 21 Jan 2012 19:42:16 -0000 1.62 +++ ieee80211_var.h 12 Jul 2012 15:12:53 -0000 @@ -320,6 +320,8 @@ struct ieee80211com { u_int8_t ic_sup_mcs[16]; u_int8_t ic_dialog_token; + struct workq *ic_print_workq; + LIST_HEAD(, ieee80211_vap) ic_vaps; }; #define ic_if ic_ac.ac_if