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>
This commit is contained in:
adrian 2015-08-23 01:17:52 +00:00
parent 6129bf3e3a
commit 2af8300f0a

View File

@ -1214,6 +1214,41 @@ ieee80211_waitfor_parent(struct ieee80211com *ic)
taskqueue_unblock(ic->ic_tq);
}
/*
* 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
@ -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);