From b364aae25446830875836ba3ff0ced6aa8365869 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 25 Mar 2009 01:26:55 +0000 Subject: [PATCH] madwifi: fix run-time channel switching in ap mode (including CSA) SVN-Revision: 15032 --- package/madwifi/patches/415-chan_switch.patch | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 package/madwifi/patches/415-chan_switch.patch diff --git a/package/madwifi/patches/415-chan_switch.patch b/package/madwifi/patches/415-chan_switch.patch new file mode 100644 index 0000000000..85050647ca --- /dev/null +++ b/package/madwifi/patches/415-chan_switch.patch @@ -0,0 +1,187 @@ +--- 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) +@@ -4625,7 +4597,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;