mac80211: merge a client mode channel switch handling fix
authorFelix Fietkau <nbd@openwrt.org>
Fri, 3 May 2013 09:14:03 +0000 (09:14 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Fri, 3 May 2013 09:14:03 +0000 (09:14 +0000)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
SVN-Revision: 36531

package/mac80211/patches/300-pending_work.patch

index 379e8f47ee34eadefded97ff1e48021de634814f..5d946ca102ada537c674e34852cc47bb9faab7c4 100644 (file)
  
        if (!local->ops->channel_switch) {
                /* call "hw_config" only if doing sw channel switch */
-@@ -1054,56 +1013,193 @@ static void ieee80211_chswitch_timer(uns
+@@ -1054,56 +1013,208 @@ static void ieee80211_chswitch_timer(uns
        ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
  }
  
  ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 -                               const struct ieee80211_channel_sw_ie *sw_elem,
 -                               struct ieee80211_bss *bss, u64 timestamp)
-+                               u64 timestamp, struct ieee802_11_elems *elems)
++                               u64 timestamp, struct ieee802_11_elems *elems,
++                               bool beacon)
  {
 -      struct cfg80211_bss *cbss =
 -              container_of((void *)bss, struct cfg80211_bss, priv);
 +      struct cfg80211_chan_def new_vht_chandef = {};
 +      const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
 +      const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
++      const struct ieee80211_ht_operation *ht_oper;
 +      int secondary_channel_offset = -1;
  
        ASSERT_MGD_MTX(ifmgd);
  
 -      if (!ifmgd->associated)
 +      if (!cbss)
++              return;
++
++      if (local->scanning)
                return;
  
 -      if (sdata->local->scanning)
-+      if (local->scanning)
++      /* disregard subsequent announcements if we are already processing */
++      if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
                return;
  
 -      /* Disregard subsequent beacons if we are already running a timer
 -         processing a CSA */
--
-+      /* disregard subsequent announcements if we are already processing */
-       if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
-               return;
--      new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
--      if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) {
 +      sec_chan_offs = elems->sec_chan_offs;
 +      wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
++      ht_oper = elems->ht_operation;
 +
 +      if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
 +                          IEEE80211_STA_DISABLE_40MHZ)) {
 +              sec_chan_offs = NULL;
 +              wide_bw_chansw_ie = NULL;
++              /* only used for bandwidth here */
++              ht_oper = NULL;
 +      }
-+
+-      if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
 +      if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
 +              wide_bw_chansw_ie = NULL;
 +
 +              mode = elems->ch_switch_ie->mode;
 +      } else {
 +              /* nothing here we understand */
-+              return;
+               return;
 +      }
 +
 +      bss = (void *)cbss->priv;
-+
+-      new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
+-      if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) {
 +      new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
 +      new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
 +      if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {
 +              return;
 +      }
 +
-+      if (sec_chan_offs) {
++      if (!beacon && sec_chan_offs) {
 +              secondary_channel_offset = sec_chan_offs->sec_chan_offs;
++      } else if (beacon && ht_oper) {
++              secondary_channel_offset =
++                      ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
 +      } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
-+              /* if HT is enabled and the IE not present, it's still HT */
++              /*
++               * If it's not a beacon, HT is enabled and the IE not present,
++               * it's 20 MHz, 802.11-2012 8.5.2.6:
++               *      This element [the Secondary Channel Offset Element] is
++               *      present when switching to a 40 MHz channel. It may be
++               *      present when switching to a 20 MHz channel (in which
++               *      case the secondary channel offset is set to SCN).
++               */
 +              secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
 +      }
 +
                return;
        }
        chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
-@@ -1111,40 +1207,39 @@ ieee80211_sta_process_chanswitch(struct 
+@@ -1111,40 +1222,39 @@ ieee80211_sta_process_chanswitch(struct 
        if (chanctx->refcount > 1) {
                sdata_info(sdata,
                           "channel switch with multiple interfaces on the same channel, disconnecting\n");
  }
  
  static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
-@@ -2120,7 +2215,6 @@ void ieee80211_beacon_loss(struct ieee80
+@@ -2120,7 +2230,6 @@ void ieee80211_beacon_loss(struct ieee80
  
        trace_api_beacon_loss(sdata);
  
        sdata->u.mgd.connection_loss = false;
        ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
  }
-@@ -2170,7 +2264,7 @@ static void ieee80211_auth_challenge(str
+@@ -2170,7 +2279,7 @@ static void ieee80211_auth_challenge(str
        u32 tx_flags = 0;
  
        pos = mgmt->u.auth.variable;
        if (!elems.challenge)
                return;
        auth_data->expected_transaction = 4;
-@@ -2435,7 +2529,7 @@ static bool ieee80211_assoc_success(stru
+@@ -2435,7 +2544,7 @@ static bool ieee80211_assoc_success(stru
        }
  
        pos = mgmt->u.assoc_resp.variable;
  
        if (!elems.supp_rates) {
                sdata_info(sdata, "no SuppRates element in AssocResp\n");
-@@ -2604,7 +2698,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee
+@@ -2604,7 +2713,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee
                   capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
  
        pos = mgmt->u.assoc_resp.variable;
  
        if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
            elems.timeout_int &&
-@@ -2659,6 +2753,8 @@ static void ieee80211_rx_bss_info(struct
+@@ -2659,6 +2768,8 @@ static void ieee80211_rx_bss_info(struct
        struct ieee80211_channel *channel;
        bool need_ps = false;
  
        if ((sdata->u.mgd.associated &&
             ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) ||
            (sdata->u.mgd.assoc_data &&
-@@ -2689,7 +2785,8 @@ static void ieee80211_rx_bss_info(struct
+@@ -2689,7 +2800,8 @@ static void ieee80211_rx_bss_info(struct
        if (bss)
                ieee80211_rx_bss_put(local, bss);
  
                return;
  
        if (need_ps) {
-@@ -2698,10 +2795,8 @@ static void ieee80211_rx_bss_info(struct
+@@ -2698,10 +2810,9 @@ static void ieee80211_rx_bss_info(struct
                mutex_unlock(&local->iflist_mtx);
        }
  
 -          memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0)
 -              ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie,
 -                                               bss, rx_status->mactime);
-+      ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems);
++      ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
++                                       elems, true);
 +
  }
  
  
-@@ -2726,7 +2821,7 @@ static void ieee80211_rx_mgmt_probe_resp
+@@ -2726,7 +2837,7 @@ static void ieee80211_rx_mgmt_probe_resp
                return;
  
        ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
  
        ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
  
-@@ -2809,7 +2904,7 @@ ieee80211_rx_mgmt_beacon(struct ieee8021
+@@ -2809,7 +2920,7 @@ ieee80211_rx_mgmt_beacon(struct ieee8021
        if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
            ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
                ieee802_11_parse_elems(mgmt->u.beacon.variable,
  
                ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
                ifmgd->assoc_data->have_beacon = true;
-@@ -2919,7 +3014,7 @@ ieee80211_rx_mgmt_beacon(struct ieee8021
+@@ -2919,7 +3030,7 @@ ieee80211_rx_mgmt_beacon(struct ieee8021
  
        ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
        ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
                                          care_about_ies, ncrc);
  
        if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
-@@ -3066,6 +3161,8 @@ void ieee80211_sta_rx_queued_mgmt(struct
+@@ -3066,6 +3177,8 @@ void ieee80211_sta_rx_queued_mgmt(struct
        enum rx_mgmt_action rma = RX_MGMT_NONE;
        u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
        u16 fc;
  
        rx_status = (struct ieee80211_rx_status *) skb->cb;
        mgmt = (struct ieee80211_mgmt *) skb->data;
-@@ -3095,14 +3192,48 @@ void ieee80211_sta_rx_queued_mgmt(struct
+@@ -3095,14 +3208,48 @@ void ieee80211_sta_rx_queued_mgmt(struct
                rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss);
                break;
        case IEEE80211_STYPE_ACTION:
 -                                      rx_status->mactime);
 -                      break;
 +                                                       rx_status->mactime,
-+                                                       &elems);
++                                                       &elems, false);
 +              } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
 +                      ies_len = skb->len -
 +                                offsetof(struct ieee80211_mgmt,
 +
 +                      ieee80211_sta_process_chanswitch(sdata,
 +                                                       rx_status->mactime,
-+                                                       &elems);
++                                                       &elems, false);
                }
 +              break;
        }