cfg80211: Add a function to get the number of supported channels
[firefly-linux-kernel-4.4.55.git] / net / wireless / util.c
index ce090c1c5e4fdb36459c4f6fde6b5af241a75f0e..d39c37104ae2f125c5def9c943dc65ab8a669f5a 100644 (file)
@@ -10,6 +10,7 @@
 #include <net/cfg80211.h>
 #include <net/ip.h>
 #include <net/dsfield.h>
+#include <linux/if_vlan.h>
 #include "core.h"
 #include "rdev-ops.h"
 
@@ -688,9 +689,11 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
 EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
 
 /* Given a data frame determine the 802.1p/1d tag to use. */
-unsigned int cfg80211_classify8021d(struct sk_buff *skb)
+unsigned int cfg80211_classify8021d(struct sk_buff *skb,
+                                   struct cfg80211_qos_map *qos_map)
 {
        unsigned int dscp;
+       unsigned char vlan_priority;
 
        /* skb->priority values from 256->263 are magic values to
         * directly indicate a specific 802.1d priority.  This is used
@@ -700,6 +703,13 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
        if (skb->priority >= 256 && skb->priority <= 263)
                return skb->priority - 256;
 
+       if (vlan_tx_tag_present(skb)) {
+               vlan_priority = (vlan_tx_tag_get(skb) & VLAN_PRIO_MASK)
+                       >> VLAN_PRIO_SHIFT;
+               if (vlan_priority > 0)
+                       return vlan_priority;
+       }
+
        switch (skb->protocol) {
        case htons(ETH_P_IP):
                dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc;
@@ -711,6 +721,21 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
                return 0;
        }
 
+       if (qos_map) {
+               unsigned int i, tmp_dscp = dscp >> 2;
+
+               for (i = 0; i < qos_map->num_des; i++) {
+                       if (tmp_dscp == qos_map->dscp_exception[i].dscp)
+                               return qos_map->dscp_exception[i].up;
+               }
+
+               for (i = 0; i < 8; i++) {
+                       if (tmp_dscp >= qos_map->up[i].low &&
+                           tmp_dscp <= qos_map->up[i].high)
+                               return i;
+               }
+       }
+
        return dscp >> 5;
 }
 EXPORT_SYMBOL(cfg80211_classify8021d);
@@ -854,6 +879,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 
                dev->ieee80211_ptr->use_4addr = false;
                dev->ieee80211_ptr->mesh_id_up_len = 0;
+               wdev_lock(dev->ieee80211_ptr);
+               rdev_set_qos_map(rdev, dev, NULL);
+               wdev_unlock(dev->ieee80211_ptr);
 
                switch (otype) {
                case NL80211_IFTYPE_AP:
@@ -1240,7 +1268,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
        enum cfg80211_chan_mode chmode;
        int num_different_channels = 0;
        int total = 1;
-       bool radar_required;
+       bool radar_required = false;
        int i, j;
 
        ASSERT_RTNL();
@@ -1255,14 +1283,20 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
        case NL80211_IFTYPE_MESH_POINT:
        case NL80211_IFTYPE_P2P_GO:
        case NL80211_IFTYPE_WDS:
-               radar_required = !!(chan &&
-                                   (chan->flags & IEEE80211_CHAN_RADAR));
+               /* if the interface could potentially choose a DFS channel,
+                * then mark DFS as required.
+                */
+               if (!chan) {
+                       if (chanmode != CHAN_MODE_UNDEFINED && radar_detect)
+                               radar_required = true;
+                       break;
+               }
+               radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR);
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_DEVICE:
        case NL80211_IFTYPE_MONITOR:
-               radar_required = false;
                break;
        case NUM_NL80211_IFTYPES:
        case NL80211_IFTYPE_UNSPECIFIED:
@@ -1447,6 +1481,19 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
        return 0;
 }
 
+unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy)
+{
+       enum ieee80211_band band;
+       unsigned int n_channels = 0;
+
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+               if (wiphy->bands[band])
+                       n_channels += wiphy->bands[band]->n_channels;
+
+       return n_channels;
+}
+EXPORT_SYMBOL(ieee80211_get_num_supported_channels);
+
 /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
 /* Ethernet-II snap header (RFC1042 for most EtherTypes) */
 const unsigned char rfc1042_header[] __aligned(2) =