static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { struct ieee80211vap *vap = dev->priv; struct ieee80211com *ic = vap->iv_ic; struct ieee80211_channel *c, *c2; int i; if (freq->e > 1) return -EINVAL; if (freq->e == 1) i = (ic->ic_mhz2ieee)(ic, freq->m / 100000, 0); else i = freq->m; if (i != 0) { if (i > IEEE80211_CHAN_MAX) return -EINVAL; c = findchannel(ic, i, vap->iv_des_mode); if (c == NULL) { c = findchannel(ic, i, IEEE80211_MODE_AUTO); if (c == NULL) /* no channel */ return -EINVAL; } /* * Fine tune channel selection based on desired mode: * if 11b is requested, find the 11b version of any * 11g channel returned, * if static turbo, find the turbo version of any * 11a channel return, * otherwise we should be ok with what we've got. */ switch (vap->iv_des_mode) { case IEEE80211_MODE_11B: if (IEEE80211_IS_CHAN_ANYG(c)) { c2 = findchannel(ic, i, IEEE80211_MODE_11B); /* NB: should not happen, =>'s 11g w/o 11b */ if (c2 != NULL) c = c2; } break; case IEEE80211_MODE_TURBO_A: if (IEEE80211_IS_CHAN_A(c)) { c2 = findchannel(ic, i, IEEE80211_MODE_TURBO_A); if (c2 != NULL) c = c2; } break; default: /* NB: no static turboG */ break; } if (ieee80211_check_mode_consistency(ic,vap->iv_des_mode,c)) { if (vap->iv_opmode == IEEE80211_M_HOSTAP) return -EINVAL; } if (vap->iv_state == IEEE80211_S_RUN && c == ic->ic_bsschan) return 0; /* no change, return */ /* Don't allow to change to channel with radar found */ if (c->ic_flags & IEEE80211_CHAN_RADAR) return -EINVAL; /* * Mark desired channel and if running force a * radio change. */ vap->iv_des_chan = c; } else { /* * Intepret channel 0 to mean "no desired channel"; * otherwise there's no way to undo fixing the desired * channel. */ if (vap->iv_des_chan == IEEE80211_CHAN_ANYC) return 0; vap->iv_des_chan = IEEE80211_CHAN_ANYC; } #if 0 if (vap->iv_des_chan != IEEE80211_CHAN_ANYC) { int mode = ieee80211_chan2mode(vap->iv_des_chan); if (mode != ic->ic_curmode) ieee80211_setmode(ic, mode); } #endif if ((vap->iv_opmode == IEEE80211_M_MONITOR || vap->iv_opmode == IEEE80211_M_WDS) && vap->iv_des_chan != IEEE80211_CHAN_ANYC) { /* * Monitor and wds modes can switch directly. */ ic->ic_curchan = vap->iv_des_chan; if (vap->iv_state == IEEE80211_S_RUN) { ic->ic_set_channel(ic); } } else { /* * Need to go through the state machine in case we need * to reassociate or the like. The state machine will * pickup the desired channel and avoid scanning. */ if (IS_UP_AUTO(vap)) ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); } return 0; }