summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2009-03-25 01:26:55 +0000
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2009-03-25 01:26:55 +0000
commite791a5327e9f02bb88c5380e7933170f5d5710ef (patch)
tree580c53ae227e8e4075527a18f0bf644dc2faab10
parenta5fbb602d476c54718ceff0576772f841def79f5 (diff)
madwifi: fix run-time channel switching in ap mode (including CSA)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@15032 3c298f89-4303-0410-b956-a3cf2f4a3e73
-rw-r--r--package/madwifi/patches/415-chan_switch.patch187
1 files changed, 187 insertions, 0 deletions
diff --git a/package/madwifi/patches/415-chan_switch.patch b/package/madwifi/patches/415-chan_switch.patch
new file mode 100644
index 000000000..85050647c
--- /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;