Merge tag 'for-linus-v3.10-rc3' of git://oss.sgi.com/xfs/xfs
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / mac80211 / mlme.c
index 29620bfc7a69663c34ab89b5bd03875eaaa4c25c..a46e490f20dd777d2d7f8dd39c5bee02e4eb60ef 100644 (file)
@@ -1015,7 +1015,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
 
 static void
 ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
-                                u64 timestamp, struct ieee802_11_elems *elems)
+                                u64 timestamp, struct ieee802_11_elems *elems,
+                                bool beacon)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -1032,6 +1033,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        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);
@@ -1048,11 +1050,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
        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_DISABLE_VHT)
@@ -1094,10 +1099,20 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                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;
        }
 
@@ -2796,7 +2811,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                mutex_unlock(&local->iflist_mtx);
        }
 
-       ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems);
+       ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
+                                        elems, true);
 
 }
 
@@ -3210,7 +3226,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 
                        ieee80211_sta_process_chanswitch(sdata,
                                                         rx_status->mactime,
-                                                        &elems);
+                                                        &elems, false);
                } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
                        ies_len = skb->len -
                                  offsetof(struct ieee80211_mgmt,
@@ -3232,7 +3248,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 
                        ieee80211_sta_process_chanswitch(sdata,
                                                         rx_status->mactime,
-                                                        &elems);
+                                                        &elems, false);
                }
                break;
        }
@@ -3623,6 +3639,31 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
        }
 }
 
+#ifdef CONFIG_PM
+void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+       mutex_lock(&ifmgd->mtx);
+       if (!ifmgd->associated) {
+               mutex_unlock(&ifmgd->mtx);
+               return;
+       }
+
+       if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
+               sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
+               mlme_dbg(sdata, "driver requested disconnect after resume\n");
+               ieee80211_sta_connection_lost(sdata,
+                                             ifmgd->associated->bssid,
+                                             WLAN_REASON_UNSPECIFIED,
+                                             true);
+               mutex_unlock(&ifmgd->mtx);
+               return;
+       }
+       mutex_unlock(&ifmgd->mtx);
+}
+#endif
+
 /* interface setup */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 {
@@ -4329,7 +4370,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
        bool tx = !req->local_state_change;
-       bool sent_frame = false;
+       bool report_frame = false;
 
        mutex_lock(&ifmgd->mtx);
 
@@ -4346,7 +4387,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
                ieee80211_destroy_auth_data(sdata, false);
                mutex_unlock(&ifmgd->mtx);
 
-               sent_frame = tx;
+               report_frame = true;
                goto out;
        }
 
@@ -4354,12 +4395,12 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
            ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       req->reason_code, tx, frame_buf);
-               sent_frame = tx;
+               report_frame = true;
        }
        mutex_unlock(&ifmgd->mtx);
 
  out:
-       if (sent_frame)
+       if (report_frame)
                __cfg80211_send_deauth(sdata->dev, frame_buf,
                                       IEEE80211_DEAUTH_FRAME_LEN);