madwifi: fix run-time channel switching in ap mode (including CSA)
authorFelix Fietkau <nbd@openwrt.org>
Wed, 25 Mar 2009 01:26:55 +0000 (01:26 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Wed, 25 Mar 2009 01:26:55 +0000 (01:26 +0000)
SVN-Revision: 15032

package/madwifi/patches/415-chan_switch.patch [new file with mode: 0644]

diff --git a/package/madwifi/patches/415-chan_switch.patch b/package/madwifi/patches/415-chan_switch.patch
new file mode 100644 (file)
index 0000000..8505064
--- /dev/null
@@ -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;