diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2012-07-13 11:25:05 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2012-07-13 11:25:05 +0000 |
commit | b3959feb902204ecbc1e8fc0d53138d21c8d4f33 (patch) | |
tree | d7f622e4246a6c46f95b5c3e5653ddfb3ffafbc0 /sys | |
parent | c39ab8589f2d6913986511d0c2a7bea296b5d37d (diff) |
Fix wireless scanning on slow systems with a high RX rate and interface
in debug mode.
If the interface is in debug mode ieee80211_input() will print messages
about received frames to the console. On slow systems, printf() calls can
take so long that the next RX interrupt will be serviced immediately, if
the RX rate is sufficiently high. This effectively locks the system at IPL_NET.
If a concurrent scan is running, the scan will never finish because it
relies on a timeout at IPL_SOFTCLOCK to hop channels every 200msec.
This timeout never runs in the above situation, leaving the wireless
interface in 'scan' state forever.
To give the timeout a chance to run, perform the printf() call from a
work queue (idea from guenther@). This allows edd's slow soekris AP to
recover from 'ifconfig ral0 debug down up' in noisy RF environments.
With input from guenther, kettenis, blambert and deraadt.
ok deraadt
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net80211/ieee80211_input.c | 101 |
1 files changed, 69 insertions, 32 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index bdb667601c3..62e220d5418 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_input.c,v 1.119 2011/04/05 11:48:28 blambert Exp $ */ +/* $OpenBSD: ieee80211_input.c,v 1.120 2012/07/13 11:25:04 stsp Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe @@ -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 ieee80211com *, struct mbuf *, void ieee80211_bar_tid(struct ieee80211com *, struct ieee80211_node *, u_int8_t, u_int16_t); #endif +void ieee80211_input_print(struct ieee80211com *, struct ifnet *, + struct ieee80211_frame *, struct ieee80211_rxinfo *); +void ieee80211_input_print_task(void *, void *); /* * Retrieve the length in bytes of an 802.11 header. @@ -152,6 +156,68 @@ ieee80211_get_hdrlen(const struct ieee80211_frame *wh) return size; } +/* + * Work queue task that prints a received frame. Avoids printf() from + * interrupt context at IPL_NET making slow machines unusable when many + * frames are received and the interface is put in debug mode. + */ +void +ieee80211_input_print_task(void *arg1, void *arg2) +{ + char *msg = arg1; + + printf("%s", msg); + free(msg, M_DEVBUF); + +} + +void +ieee80211_input_print(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 printing 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)]); + + error = workq_add_task(NULL, 0, ieee80211_input_print_task, msg, NULL); + if (error) + 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 +533,8 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, 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(ic, ifp, wh, rxi); #if NBPFILTER > 0 if (ic->ic_rawbpf) bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_IN); |