summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2015-08-23 01:17:52 +0000
committeradrian <adrian@FreeBSD.org>2015-08-23 01:17:52 +0000
commit2af8300f0a0bd96ae7c076d410b2e6e808060d5a (patch)
tree01064c872b4c5dba07790a3b4d62db81faec81ab /sys/net80211
parent6129bf3e3a3f2de61c8d5f0f59b95cf9d3096dd4 (diff)
downloadFreeBSD-src-2af8300f0a0bd96ae7c076d410b2e6e808060d5a.zip
FreeBSD-src-2af8300f0a0bd96ae7c076d410b2e6e808060d5a.tar.gz
Reset the channel to the first available channel if the interface
is configured on a channel that isn't valid in the new operating mode. This isn't strictly true - it should find the first channel that is available for the given operating mode. However, I think defaulting to the first channel is fine - it's typically available for all modes. If someone would like to correctly implement this feature - try to find a channel that is valid for the given operating mode and error out if we can't find one. This prevents various NICs (eg wpi(4)) from throwing a firmware error. Tested: * ath(4), STA/AP mode * iwn(4), STA/adhoc mode PR: kern/202502 Submitted by: Andriy Voskoboinyk <s3erios@gmail.com>
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211_proto.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index 01c60e1..548daca 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -1215,6 +1215,41 @@ ieee80211_waitfor_parent(struct ieee80211com *ic)
}
/*
+ * Check to see whether the current channel needs reset.
+ *
+ * Some devices don't handle being given an invalid channel
+ * in their operating mode very well (eg wpi(4) will throw a
+ * firmware exception.)
+ *
+ * Return 0 if we're ok, 1 if the channel needs to be reset.
+ *
+ * See PR kern/202502.
+ */
+static int
+ieee80211_start_check_reset_chan(struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+
+ if ((vap->iv_opmode == IEEE80211_M_IBSS &&
+ IEEE80211_IS_CHAN_NOADHOC(ic->ic_curchan)) ||
+ (vap->iv_opmode == IEEE80211_M_HOSTAP &&
+ IEEE80211_IS_CHAN_NOHOSTAP(ic->ic_curchan)))
+ return (1);
+ return (0);
+}
+
+/*
+ * Reset the curchan to a known good state.
+ */
+static void
+ieee80211_start_reset_chan(struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+
+ ic->ic_curchan = &ic->ic_channels[0];
+}
+
+/*
* Start a vap running. If this is the first vap to be
* set running on the underlying device then we
* automatically bring the device up.
@@ -1248,6 +1283,11 @@ ieee80211_start_locked(struct ieee80211vap *vap)
*/
if (ic->ic_nrunning++ == 0 &&
(parent->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+
+ /* reset the channel to a known good channel */
+ if (ieee80211_start_check_reset_chan(vap))
+ ieee80211_start_reset_chan(vap);
+
IEEE80211_DPRINTF(vap,
IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
"%s: up parent %s\n", __func__, parent->if_xname);
OpenPOWER on IntegriCloud