Merge tag 'mmc-v4.2' of git://git.linaro.org/people/ulf.hansson/mmc
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / util.c
index 747bdcf72e92788574ec3e2e635b5e6b96cb75f0..b864ebc6ab8fbf2a09baca02e650e7fe0314cc75 100644 (file)
@@ -308,6 +308,11 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
                for (ac = 0; ac < n_acs; ac++) {
                        int ac_queue = sdata->vif.hw_queue[ac];
 
+                       if (local->ops->wake_tx_queue &&
+                           (atomic_read(&sdata->txqs_len[ac]) >
+                            local->hw.txq_ac_max_pending))
+                               continue;
+
                        if (ac_queue == queue ||
                            (sdata->vif.cab_queue == queue &&
                             local->queue_stop_reasons[ac_queue] == 0 &&
@@ -625,13 +630,14 @@ void ieee80211_wake_vif_queues(struct ieee80211_local *local,
                                        reason, true);
 }
 
-static void __iterate_active_interfaces(struct ieee80211_local *local,
-                                       u32 iter_flags,
-                                       void (*iterator)(void *data, u8 *mac,
-                                               struct ieee80211_vif *vif),
-                                       void *data)
+static void __iterate_interfaces(struct ieee80211_local *local,
+                                u32 iter_flags,
+                                void (*iterator)(void *data, u8 *mac,
+                                                 struct ieee80211_vif *vif),
+                                void *data)
 {
        struct ieee80211_sub_if_data *sdata;
+       bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
 
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                switch (sdata->vif.type) {
@@ -645,9 +651,9 @@ static void __iterate_active_interfaces(struct ieee80211_local *local,
                        break;
                }
                if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
-                   !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+                   active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
                        continue;
-               if (ieee80211_sdata_running(sdata))
+               if (ieee80211_sdata_running(sdata) || !active_only)
                        iterator(data, sdata->vif.addr,
                                 &sdata->vif);
        }
@@ -656,12 +662,12 @@ static void __iterate_active_interfaces(struct ieee80211_local *local,
                                      lockdep_is_held(&local->iflist_mtx) ||
                                      lockdep_rtnl_is_held());
        if (sdata &&
-           (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
+           (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
             sdata->flags & IEEE80211_SDATA_IN_DRIVER))
                iterator(data, sdata->vif.addr, &sdata->vif);
 }
 
-void ieee80211_iterate_active_interfaces(
+void ieee80211_iterate_interfaces(
        struct ieee80211_hw *hw, u32 iter_flags,
        void (*iterator)(void *data, u8 *mac,
                         struct ieee80211_vif *vif),
@@ -670,10 +676,10 @@ void ieee80211_iterate_active_interfaces(
        struct ieee80211_local *local = hw_to_local(hw);
 
        mutex_lock(&local->iflist_mtx);
-       __iterate_active_interfaces(local, iter_flags, iterator, data);
+       __iterate_interfaces(local, iter_flags, iterator, data);
        mutex_unlock(&local->iflist_mtx);
 }
-EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
+EXPORT_SYMBOL_GPL(ieee80211_iterate_interfaces);
 
 void ieee80211_iterate_active_interfaces_atomic(
        struct ieee80211_hw *hw, u32 iter_flags,
@@ -684,7 +690,8 @@ void ieee80211_iterate_active_interfaces_atomic(
        struct ieee80211_local *local = hw_to_local(hw);
 
        rcu_read_lock();
-       __iterate_active_interfaces(local, iter_flags, iterator, data);
+       __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
+                            iterator, data);
        rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
@@ -699,7 +706,8 @@ void ieee80211_iterate_active_interfaces_rtnl(
 
        ASSERT_RTNL();
 
-       __iterate_active_interfaces(local, iter_flags, iterator, data);
+       __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
+                            iterator, data);
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
 
@@ -742,6 +750,18 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
 }
 EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
 
+struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       if (!ieee80211_sdata_running(sdata) ||
+           !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+               return NULL;
+
+       return &sdata->wdev;
+}
+EXPORT_SYMBOL_GPL(ieee80211_vif_to_wdev);
+
 /*
  * Nothing should have been stuffed into the workqueue during
  * the suspend->resume cycle. Since we can't check each caller
@@ -1811,8 +1831,25 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-                   ieee80211_sdata_running(sdata))
+                   ieee80211_sdata_running(sdata)) {
                        res = drv_add_interface(local, sdata);
+                       if (WARN_ON(res))
+                               break;
+               }
+       }
+
+       /* If adding any of the interfaces failed above, roll back and
+        * report failure.
+        */
+       if (res) {
+               list_for_each_entry_continue_reverse(sdata, &local->interfaces,
+                                                    list)
+                       if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+                           sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+                           ieee80211_sdata_running(sdata))
+                               drv_remove_interface(local, sdata);
+               ieee80211_handle_reconfig_failure(local);
+               return res;
        }
 
        /* add channel contexts */
@@ -1985,6 +2022,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        mutex_unlock(&local->sta_mtx);
 
        /* add back keys */
+       list_for_each_entry(sdata, &local->interfaces, list)
+               ieee80211_reset_crypto_tx_tailroom(sdata);
+
        list_for_each_entry(sdata, &local->interfaces, list)
                if (ieee80211_sdata_running(sdata))
                        ieee80211_enable_keys(sdata);
@@ -2157,46 +2197,6 @@ void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata)
        mutex_unlock(&local->chanctx_mtx);
 }
 
-static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
-{
-       int i;
-
-       for (i = 0; i < n_ids; i++)
-               if (ids[i] == id)
-                       return true;
-       return false;
-}
-
-size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
-                             const u8 *ids, int n_ids,
-                             const u8 *after_ric, int n_after_ric,
-                             size_t offset)
-{
-       size_t pos = offset;
-
-       while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) {
-               if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) {
-                       pos += 2 + ies[pos + 1];
-
-                       while (pos < ielen &&
-                              !ieee80211_id_in_list(after_ric, n_after_ric,
-                                                    ies[pos]))
-                               pos += 2 + ies[pos + 1];
-               } else {
-                       pos += 2 + ies[pos + 1];
-               }
-       }
-
-       return pos;
-}
-
-size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
-                         const u8 *ids, int n_ids, size_t offset)
-{
-       return ieee80211_ie_split_ric(ies, ielen, ids, n_ids, NULL, 0, offset);
-}
-EXPORT_SYMBOL(ieee80211_ie_split);
-
 size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
 {
        size_t pos = offset;
@@ -2344,6 +2344,41 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
        return pos + sizeof(struct ieee80211_ht_operation);
 }
 
+u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
+                               const struct cfg80211_chan_def *chandef)
+{
+       struct ieee80211_vht_operation *vht_oper;
+
+       *pos++ = WLAN_EID_VHT_OPERATION;
+       *pos++ = sizeof(struct ieee80211_vht_operation);
+       vht_oper = (struct ieee80211_vht_operation *)pos;
+       vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel(
+                                                       chandef->center_freq1);
+       if (chandef->center_freq2)
+               vht_oper->center_freq_seg2_idx =
+                       ieee80211_frequency_to_channel(chandef->center_freq2);
+
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_160:
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
+               break;
+       case NL80211_CHAN_WIDTH_80P80:
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
+               break;
+       case NL80211_CHAN_WIDTH_80:
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
+               break;
+       default:
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
+               break;
+       }
+
+       /* don't require special VHT peer rates */
+       vht_oper->basic_mcs_set = cpu_to_le16(0xffff);
+
+       return pos + sizeof(struct ieee80211_vht_operation);
+}
+
 void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
                                  const struct ieee80211_ht_operation *ht_oper,
                                  struct cfg80211_chan_def *chandef)
@@ -2373,6 +2408,39 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
        cfg80211_chandef_create(chandef, control_chan, channel_type);
 }
 
+void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
+                                  const struct ieee80211_vht_operation *oper,
+                                  struct cfg80211_chan_def *chandef)
+{
+       if (!oper)
+               return;
+
+       chandef->chan = control_chan;
+
+       switch (oper->chan_width) {
+       case IEEE80211_VHT_CHANWIDTH_USE_HT:
+               break;
+       case IEEE80211_VHT_CHANWIDTH_80MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_80;
+               break;
+       case IEEE80211_VHT_CHANWIDTH_160MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_160;
+               break;
+       case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_80P80;
+               break;
+       default:
+               break;
+       }
+
+       chandef->center_freq1 =
+               ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
+                                              control_chan->band);
+       chandef->center_freq2 =
+               ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
+                                              control_chan->band);
+}
+
 int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
                             const struct ieee80211_supported_band *sband,
                             const u8 *srates, int srates_len, u32 *rates)
@@ -3252,3 +3320,20 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo)
 
        return buf;
 }
+
+void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
+                            struct sta_info *sta,
+                            struct txq_info *txqi, int tid)
+{
+       skb_queue_head_init(&txqi->queue);
+       txqi->txq.vif = &sdata->vif;
+
+       if (sta) {
+               txqi->txq.sta = &sta->sta;
+               sta->sta.txq[tid] = &txqi->txq;
+               txqi->txq.ac = ieee802_1d_to_ac[tid & 7];
+       } else {
+               sdata->vif.txq = &txqi->txq;
+               txqi->txq.ac = IEEE80211_AC_BE;
+       }
+}