These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / mac80211 / iface.c
index 84cef60..c9e325d 100644 (file)
@@ -76,7 +76,8 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
 void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
                              bool update_bss)
 {
-       if (__ieee80211_recalc_txpower(sdata) || update_bss)
+       if (__ieee80211_recalc_txpower(sdata) ||
+           (update_bss && ieee80211_sdata_running(sdata)))
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
 }
 
@@ -338,7 +339,7 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
        if ((iftype != NL80211_IFTYPE_AP &&
             iftype != NL80211_IFTYPE_P2P_GO &&
             iftype != NL80211_IFTYPE_MESH_POINT) ||
-           !(sdata->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) {
+           !ieee80211_hw_check(&sdata->local->hw, QUEUE_CONTROL)) {
                sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
                return 0;
        }
@@ -378,7 +379,7 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
        int i;
 
        for (i = 0; i < IEEE80211_NUM_ACS; i++) {
-               if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
+               if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
                        sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE;
                else if (local->hw.queues >= IEEE80211_NUM_ACS)
                        sdata->vif.hw_queue[i] = i;
@@ -393,7 +394,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
        struct ieee80211_sub_if_data *sdata;
        int ret;
 
-       if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
+       if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
                return 0;
 
        ASSERT_RTNL();
@@ -454,7 +455,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
 
-       if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
+       if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
                return;
 
        ASSERT_RTNL();
@@ -661,11 +662,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                }
 
                /*
-                * set default queue parameters so drivers don't
+                * Set default queue parameters so drivers don't
                 * need to initialise the hardware if the hardware
-                * doesn't start up with sane defaults
+                * doesn't start up with sane defaults.
+                * Enable QoS for anything but station interfaces.
                 */
-               ieee80211_set_wmm_default(sdata, true);
+               ieee80211_set_wmm_default(sdata, true,
+                       sdata->vif.type != NL80211_IFTYPE_STATION);
        }
 
        set_bit(SDATA_STATE_RUNNING, &sdata->state);
@@ -703,16 +706,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
        if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
                atomic_inc(&local->iff_allmultis);
 
-       if (sdata->flags & IEEE80211_SDATA_PROMISC)
-               atomic_inc(&local->iff_promiscs);
-
        if (coming_up)
                local->open_count++;
 
        if (hw_reconf_flags)
                ieee80211_hw_config(local, hw_reconf_flags);
 
-       ieee80211_recalc_ps(local, -1);
+       ieee80211_recalc_ps(local);
 
        if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
@@ -835,13 +835,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                     ((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
                      (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)));
 
-       /* don't count this interface for promisc/allmulti while it is down */
+       /* don't count this interface for allmulti while it is down */
        if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
                atomic_dec(&local->iff_allmultis);
 
-       if (sdata->flags & IEEE80211_SDATA_PROMISC)
-               atomic_dec(&local->iff_promiscs);
-
        if (sdata->vif.type == NL80211_IFTYPE_AP) {
                local->fif_pspoll--;
                local->fif_probe_req--;
@@ -1022,7 +1019,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                        drv_remove_interface(local, sdata);
        }
 
-       ieee80211_recalc_ps(local, -1);
+       ieee80211_recalc_ps(local);
 
        if (cancel_scan)
                flush_delayed_work(&local->scan_work);
@@ -1055,12 +1052,10 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
-       int allmulti, promisc, sdata_allmulti, sdata_promisc;
+       int allmulti, sdata_allmulti;
 
        allmulti = !!(dev->flags & IFF_ALLMULTI);
-       promisc = !!(dev->flags & IFF_PROMISC);
        sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
-       sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);
 
        if (allmulti != sdata_allmulti) {
                if (dev->flags & IFF_ALLMULTI)
@@ -1070,13 +1065,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
                sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
        }
 
-       if (promisc != sdata_promisc) {
-               if (dev->flags & IFF_PROMISC)
-                       atomic_inc(&local->iff_promiscs);
-               else
-                       atomic_dec(&local->iff_promiscs);
-               sdata->flags ^= IEEE80211_SDATA_PROMISC;
-       }
        spin_lock_bh(&local->filter_lock);
        __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
        spin_unlock_bh(&local->filter_lock);
@@ -1117,6 +1105,35 @@ static u16 ieee80211_netdev_select_queue(struct net_device *dev,
        return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
 }
 
+static struct rtnl_link_stats64 *
+ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+       int i;
+
+       for_each_possible_cpu(i) {
+               const struct pcpu_sw_netstats *tstats;
+               u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+               unsigned int start;
+
+               tstats = per_cpu_ptr(dev->tstats, i);
+
+               do {
+                       start = u64_stats_fetch_begin_irq(&tstats->syncp);
+                       rx_packets = tstats->rx_packets;
+                       tx_packets = tstats->tx_packets;
+                       rx_bytes = tstats->rx_bytes;
+                       tx_bytes = tstats->tx_bytes;
+               } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
+
+               stats->rx_packets += rx_packets;
+               stats->tx_packets += tx_packets;
+               stats->rx_bytes   += rx_bytes;
+               stats->tx_bytes   += tx_bytes;
+       }
+
+       return stats;
+}
+
 static const struct net_device_ops ieee80211_dataif_ops = {
        .ndo_open               = ieee80211_open,
        .ndo_stop               = ieee80211_stop,
@@ -1126,6 +1143,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
        .ndo_change_mtu         = ieee80211_change_mtu,
        .ndo_set_mac_address    = ieee80211_change_mac,
        .ndo_select_queue       = ieee80211_netdev_select_queue,
+       .ndo_get_stats64        = ieee80211_get_stats64,
 };
 
 static u16 ieee80211_monitor_select_queue(struct net_device *dev,
@@ -1159,14 +1177,21 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
        .ndo_change_mtu         = ieee80211_change_mtu,
        .ndo_set_mac_address    = ieee80211_change_mac,
        .ndo_select_queue       = ieee80211_monitor_select_queue,
+       .ndo_get_stats64        = ieee80211_get_stats64,
 };
 
+static void ieee80211_if_free(struct net_device *dev)
+{
+       free_percpu(dev->tstats);
+       free_netdev(dev);
+}
+
 static void ieee80211_if_setup(struct net_device *dev)
 {
        ether_setup(dev);
        dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->netdev_ops = &ieee80211_dataif_ops;
-       dev->destructor = free_netdev;
+       dev->destructor = ieee80211_if_free;
 }
 
 static void ieee80211_iface_work(struct work_struct *work)
@@ -1182,7 +1207,7 @@ static void ieee80211_iface_work(struct work_struct *work)
        if (!ieee80211_sdata_running(sdata))
                return;
 
-       if (local->scanning)
+       if (test_bit(SCAN_SW_SCANNING, &local->scanning))
                return;
 
        if (!ieee80211_can_run_worker(local))
@@ -1220,8 +1245,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;
@@ -1564,7 +1587,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_P2P_GO:
-               if (local->hw.flags & IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF) {
+               if (ieee80211_hw_check(&local->hw, P2P_DEV_ADDR_FOR_INTF)) {
                        list_for_each_entry(sdata, &local->interfaces, list) {
                                if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE)
                                        continue;
@@ -1707,6 +1730,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                        return -ENOMEM;
                dev_net_set(ndev, wiphy_net(local->hw.wiphy));
 
+               ndev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+               if (!ndev->tstats) {
+                       free_netdev(ndev);
+                       return -ENOMEM;
+               }
+
                ndev->needed_headroom = local->tx_headroom +
                                        4*6 /* four MAC addresses */
                                        + 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */
@@ -1762,13 +1791,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);
@@ -1823,6 +1862,7 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
                unregister_netdevice(sdata->dev);
        } else {
                cfg80211_unregister_wdev(&sdata->wdev);
+               ieee80211_teardown_sdata(sdata);
                kfree(sdata);
        }
 }
@@ -1832,13 +1872,8 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
        if (WARN_ON_ONCE(!test_bit(SDATA_STATE_RUNNING, &sdata->state)))
                return;
        ieee80211_do_stop(sdata, true);
-       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;
@@ -1847,14 +1882,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) {