--- a/net80211/ieee80211_beacon.c +++ b/net80211/ieee80211_beacon.c @@ -224,18 +224,18 @@ ieee80211_beacon_alloc(struct ieee80211_ pktlen = 8 /* time stamp */ + sizeof(u_int16_t) /* beacon interval */ + sizeof(u_int16_t) /* capability information */ - + 2 + ni->ni_esslen /* ssid */ + + 2 + IEEE80211_NWID_LEN /* ssid */ + 2 + IEEE80211_RATE_SIZE /* supported rates */ + 7 /* FH/DS parameters max(7,3) */ - + 2 + 4 + vap->iv_tim_len /* IBSS/TIM parameter set*/ + + sizeof(struct ieee80211_tim_ie) + 128 /* IBSS/TIM parameter set*/ + ic->ic_country_ie.country_len + 2 /* country code */ + 3 /* power constraint */ + 5 /* channel switch announcement */ + 3 /* ERP */ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) /* Ext. Supp. Rates */ - + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ + + (ic->ic_caps & IEEE80211_C_WME ? /* WME */ sizeof(struct ieee80211_wme_param) : 0) - + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ + + (ic->ic_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 2 * sizeof(struct ieee80211_ie_wpa) : 0) + sizeof(struct ieee80211_ie_athAdvCap) #ifdef ATH_SUPERG_XR @@ -290,17 +290,26 @@ ieee80211_beacon_update(struct ieee80211 IEEE80211_LOCK_IRQ(ic); /* Check if we need to change channel right now */ - if ((ic->ic_flags & IEEE80211_F_DOTH) && - (vap->iv_flags & IEEE80211_F_CHANSWITCH)) { - struct ieee80211_channel *c = + if (ic->ic_flags & IEEE80211_F_CHANSWITCH) { + struct ieee80211_channel *c = ieee80211_doth_findchan(vap, ic->ic_chanchange_chan); - - if (!vap->iv_chanchange_count && !c) { - vap->iv_flags &= ~IEEE80211_F_CHANSWITCH; - ic->ic_flags &= ~IEEE80211_F_CHANSWITCH; - } else if (vap->iv_chanchange_count && - ((!ic->ic_chanchange_tbtt) || - (vap->iv_chanchange_count == ic->ic_chanchange_tbtt))) { + struct ieee80211vap *avp; + int do_switch = 1; + + TAILQ_FOREACH(avp, &ic->ic_vaps, iv_next) { + if (!(avp->iv_flags & IEEE80211_F_CHANSWITCH)) + continue; + + do_switch = 0; + break; + } + if (vap->iv_flags & IEEE80211_F_CHANSWITCH) { + if (vap->iv_chanchange_count-- <= 1) { + vap->iv_flags &= ~IEEE80211_F_CHANSWITCH; + vap->iv_chanchange_count = 0; + } + } + if (do_switch) { u_int8_t *frm; IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, @@ -316,16 +325,7 @@ ieee80211_beacon_update(struct ieee80211 } else ic->ic_bsschan = c; - skb_pull(skb, sizeof(struct ieee80211_frame)); - skb_trim(skb, 0); - frm = skb->data; - skb_put(skb, ieee80211_beacon_init(ni, bo, frm) - frm); - skb_push(skb, sizeof(struct ieee80211_frame)); - - vap->iv_chanchange_count = 0; - vap->iv_flags &= ~IEEE80211_F_CHANSWITCH; ic->ic_flags &= ~IEEE80211_F_CHANSWITCH; - /* NB: Only for the first VAP to get here, and when we * have a valid channel to which to change. */ if (c && (ic->ic_curchan != c)) { @@ -488,22 +488,20 @@ ieee80211_beacon_update(struct ieee80211 if (IEEE80211_IS_MODE_BEACON(vap->iv_opmode)) { - if ((ic->ic_flags & IEEE80211_F_DOTH) && - (ic->ic_flags & IEEE80211_F_CHANSWITCH)) { + if (ic->ic_flags & IEEE80211_F_CHANSWITCH) { struct ieee80211_ie_csa *csa_ie = (struct ieee80211_ie_csa *)bo->bo_chanswitch; - IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, + if (csa_ie->csa_len == 0) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: Sending 802.11h chanswitch IE: " "%d/%d\n", __func__, ic->ic_chanchange_chan, ic->ic_chanchange_tbtt); - if (!vap->iv_chanchange_count) { - vap->iv_flags |= IEEE80211_F_CHANSWITCH; /* copy out trailer to open up a slot */ memmove(bo->bo_chanswitch + sizeof(*csa_ie), - bo->bo_chanswitch, + bo->bo_chanswitch, bo->bo_chanswitch_trailerlen); /* add ie in opened slot */ @@ -523,17 +521,15 @@ ieee80211_beacon_update(struct ieee80211 bo->bo_ath_caps += sizeof(*csa_ie); bo->bo_xr += sizeof(*csa_ie); - /* indicate new beacon length so other layers + /* indicate new beacon length so other layers * may manage memory */ skb_put(skb, sizeof(*csa_ie)); len_changed = 1; - } else if(csa_ie->csa_count) - csa_ie->csa_count--; - - vap->iv_chanchange_count++; - IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, - "%s: CHANSWITCH IE, change in %d TBTT\n", - __func__, csa_ie->csa_count); + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, + "%s: CHANSWITCH IE, change in %d TBTT\n", + __func__, csa_ie->csa_count); + } } #ifdef ATH_SUPERG_XR if (vap->iv_flags & IEEE80211_F_XRUPDATE) { --- a/net80211/ieee80211_wireless.c +++ b/net80211/ieee80211_wireless.c @@ -699,39 +699,11 @@ ieee80211_ioctl_siwfreq(struct net_devic 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 == vap->iv_des_chan)) - return 0; /* no change, return */ /* Don't allow to change to channel with radar found */ if (c->ic_flags & IEEE80211_CHAN_RADAR) @@ -4634,7 +4606,13 @@ static void pre_announced_chanswitch(struct net_device *dev, u_int32_t channel, u_int32_t tbtt) { struct ieee80211vap *vap = dev->priv; struct ieee80211com *ic = vap->iv_ic; + struct ieee80211vap *avp; + /* now flag the beacon update to include the channel switch IE */ + TAILQ_FOREACH(avp, &ic->ic_vaps, iv_next) { + avp->iv_flags |= IEEE80211_F_CHANSWITCH; + avp->iv_chanchange_count = tbtt; + } ic->ic_flags |= IEEE80211_F_CHANSWITCH; ic->ic_chanchange_chan = channel; ic->ic_chanchange_tbtt = tbtt;