Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 23 Aug 2015 01:17:52 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r287029 - head/sys/net80211
Message-ID:  <201508230117.t7N1Hqj8017109@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Sun Aug 23 01:17:52 2015
New Revision: 287029
URL: https://svnweb.freebsd.org/changeset/base/287029

Log:
  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>

Modified:
  head/sys/net80211/ieee80211_proto.c

Modified: head/sys/net80211/ieee80211_proto.c
==============================================================================
--- head/sys/net80211/ieee80211_proto.c	Sat Aug 22 23:09:19 2015	(r287028)
+++ head/sys/net80211/ieee80211_proto.c	Sun Aug 23 01:17:52 2015	(r287029)
@@ -1215,6 +1215,41 @@ ieee80211_waitfor_parent(struct ieee8021
 }
 
 /*
+ * 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 ieee80211v
 		 */
 		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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201508230117.t7N1Hqj8017109>