Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / iface.c
index 84cef600c5730e74c6456e801ffa93ef55e4e47f..ed1edac143729cc117c1cb63c5519285acff13a7 100644 (file)
@@ -338,7 +338,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 +378,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 +393,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 +454,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();
@@ -703,9 +703,6 @@ 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++;
 
@@ -835,13 +832,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--;
@@ -1055,12 +1049,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 +1062,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 +1102,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 +1140,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 +1174,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)
@@ -1564,7 +1586,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 +1729,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 */