mac80211: add rate mask logic for vht rates
[deliverable/linux.git] / net / mac80211 / iface.c
index ed1edac143729cc117c1cb63c5519285acff13a7..6964fc6a8ea2c7b46149e8be5e79c6f373f50d40 100644 (file)
@@ -1242,8 +1242,6 @@ static void ieee80211_iface_work(struct work_struct *work)
                                                        WLAN_BACK_RECIPIENT, 0,
                                                        false);
                        mutex_unlock(&local->sta_mtx);
-               } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_TDLS_CHSW) {
-                       ieee80211_process_tdls_channel_switch(sdata, skb);
                } else if (ieee80211_is_action(mgmt->frame_control) &&
                           mgmt->u.action.category == WLAN_CATEGORY_BACK) {
                        int len = skb->len;
@@ -1790,13 +1788,23 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                sband = local->hw.wiphy->bands[i];
                sdata->rc_rateidx_mask[i] =
                        sband ? (1 << sband->n_bitrates) - 1 : 0;
-               if (sband)
+               if (sband) {
+                       __le16 cap;
+                       u16 *vht_rate_mask;
+
                        memcpy(sdata->rc_rateidx_mcs_mask[i],
                               sband->ht_cap.mcs.rx_mask,
                               sizeof(sdata->rc_rateidx_mcs_mask[i]));
-               else
+
+                       cap = sband->vht_cap.vht_mcs.rx_mcs_map;
+                       vht_rate_mask = sdata->rc_rateidx_vht_mcs_mask[i];
+                       ieee80211_get_vht_mask_from_cap(cap, vht_rate_mask);
+               } else {
                        memset(sdata->rc_rateidx_mcs_mask[i], 0,
                               sizeof(sdata->rc_rateidx_mcs_mask[i]));
+                       memset(sdata->rc_rateidx_vht_mcs_mask[i], 0,
+                              sizeof(sdata->rc_rateidx_vht_mcs_mask[i]));
+               }
        }
 
        ieee80211_set_default_queues(sdata);
@@ -1863,10 +1871,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
        ieee80211_teardown_sdata(sdata);
 }
 
-/*
- * Remove all interfaces, may only be called at hardware unregistration
- * time because it doesn't do RCU-safe list removals.
- */
 void ieee80211_remove_interfaces(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata, *tmp;
@@ -1875,14 +1879,21 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
 
        ASSERT_RTNL();
 
-       /*
-        * Close all AP_VLAN interfaces first, as otherwise they
-        * might be closed while the AP interface they belong to
-        * is closed, causing unregister_netdevice_many() to crash.
+       /* Before destroying the interfaces, make sure they're all stopped so
+        * that the hardware is stopped. Otherwise, the driver might still be
+        * iterating the interfaces during the shutdown, e.g. from a worker
+        * or from RX processing or similar, and if it does so (using atomic
+        * iteration) while we're manipulating the list, the iteration will
+        * crash.
+        *
+        * After this, the hardware should be stopped and the driver should
+        * have stopped all of its activities, so that we can do RCU-unaware
+        * manipulations of the interface list below.
         */
-       list_for_each_entry(sdata, &local->interfaces, list)
-               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-                       dev_close(sdata->dev);
+       cfg80211_shutdown_all_interfaces(local->hw.wiphy);
+
+       WARN(local->open_count, "%s: open count remains %d\n",
+            wiphy_name(local->hw.wiphy), local->open_count);
 
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
This page took 0.075918 seconds and 5 git commands to generate.