Merge tag 'iommu-updates-v3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/joro...
[linux-2.6-microblaze.git] / net / wireless / util.c
index 2762e83..16d76a8 100644 (file)
@@ -11,6 +11,8 @@
 #include <net/ip.h>
 #include <net/dsfield.h>
 #include "core.h"
+#include "rdev-ops.h"
+
 
 struct ieee80211_rate *
 ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
@@ -686,10 +688,13 @@ EXPORT_SYMBOL(cfg80211_classify8021d);
 
 const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
 {
-       if (bss->information_elements == NULL)
+       const struct cfg80211_bss_ies *ies;
+
+       ies = rcu_dereference(bss->ies);
+       if (!ies)
                return NULL;
-       return cfg80211_find_ie(ie, bss->information_elements,
-                                bss->len_information_elements);
+
+       return cfg80211_find_ie(ie, ies->data, ies->len);
 }
 EXPORT_SYMBOL(ieee80211_bss_get_ie);
 
@@ -705,19 +710,18 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
        for (i = 0; i < 6; i++) {
                if (!wdev->connect_keys->params[i].cipher)
                        continue;
-               if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL,
-                                       &wdev->connect_keys->params[i])) {
+               if (rdev_add_key(rdev, dev, i, false, NULL,
+                                &wdev->connect_keys->params[i])) {
                        netdev_err(dev, "failed to set key %d\n", i);
                        continue;
                }
                if (wdev->connect_keys->def == i)
-                       if (rdev->ops->set_default_key(wdev->wiphy, dev,
-                                                      i, true, true)) {
+                       if (rdev_set_default_key(rdev, dev, i, true, true)) {
                                netdev_err(dev, "failed to set defkey %d\n", i);
                                continue;
                        }
                if (wdev->connect_keys->defmgmt == i)
-                       if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i))
+                       if (rdev_set_default_mgmt_key(rdev, dev, i))
                                netdev_err(dev, "failed to set mgtdef %d\n", i);
        }
 
@@ -850,8 +854,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                cfg80211_process_rdev_events(rdev);
        }
 
-       err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev,
-                                            ntype, flags, params);
+       err = rdev_change_virtual_intf(rdev, dev, ntype, flags, params);
 
        WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
 
@@ -944,14 +947,86 @@ static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
        return __mcs2bitrate[rate->mcs];
 }
 
+static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
+{
+       static const u32 base[4][10] = {
+               {   6500000,
+                  13000000,
+                  19500000,
+                  26000000,
+                  39000000,
+                  52000000,
+                  58500000,
+                  65000000,
+                  78000000,
+                  0,
+               },
+               {  13500000,
+                  27000000,
+                  40500000,
+                  54000000,
+                  81000000,
+                 108000000,
+                 121500000,
+                 135000000,
+                 162000000,
+                 180000000,
+               },
+               {  29300000,
+                  58500000,
+                  87800000,
+                 117000000,
+                 175500000,
+                 234000000,
+                 263300000,
+                 292500000,
+                 351000000,
+                 390000000,
+               },
+               {  58500000,
+                 117000000,
+                 175500000,
+                 234000000,
+                 351000000,
+                 468000000,
+                 526500000,
+                 585000000,
+                 702000000,
+                 780000000,
+               },
+       };
+       u32 bitrate;
+       int idx;
+
+       if (WARN_ON_ONCE(rate->mcs > 9))
+               return 0;
+
+       idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH |
+                            RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 :
+                 rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 :
+                 rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0;
+
+       bitrate = base[idx][rate->mcs];
+       bitrate *= rate->nss;
+
+       if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+               bitrate = (bitrate / 9) * 10;
+
+       /* do NOT round down here */
+       return (bitrate + 50000) / 100000;
+}
+
 u32 cfg80211_calculate_bitrate(struct rate_info *rate)
 {
        int modulation, streams, bitrate;
 
-       if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+       if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
+           !(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
                return rate->legacy;
        if (rate->flags & RATE_INFO_FLAGS_60G)
                return cfg80211_calculate_bitrate_60g(rate);
+       if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
+               return cfg80211_calculate_bitrate_vht(rate);
 
        /* the formula below does only work for MCS values smaller than 32 */
        if (WARN_ON_ONCE(rate->mcs >= 32))
@@ -980,6 +1055,106 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
 }
 EXPORT_SYMBOL(cfg80211_calculate_bitrate);
 
+int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
+                         enum ieee80211_p2p_attr_id attr,
+                         u8 *buf, unsigned int bufsize)
+{
+       u8 *out = buf;
+       u16 attr_remaining = 0;
+       bool desired_attr = false;
+       u16 desired_len = 0;
+
+       while (len > 0) {
+               unsigned int iedatalen;
+               unsigned int copy;
+               const u8 *iedata;
+
+               if (len < 2)
+                       return -EILSEQ;
+               iedatalen = ies[1];
+               if (iedatalen + 2 > len)
+                       return -EILSEQ;
+
+               if (ies[0] != WLAN_EID_VENDOR_SPECIFIC)
+                       goto cont;
+
+               if (iedatalen < 4)
+                       goto cont;
+
+               iedata = ies + 2;
+
+               /* check WFA OUI, P2P subtype */
+               if (iedata[0] != 0x50 || iedata[1] != 0x6f ||
+                   iedata[2] != 0x9a || iedata[3] != 0x09)
+                       goto cont;
+
+               iedatalen -= 4;
+               iedata += 4;
+
+               /* check attribute continuation into this IE */
+               copy = min_t(unsigned int, attr_remaining, iedatalen);
+               if (copy && desired_attr) {
+                       desired_len += copy;
+                       if (out) {
+                               memcpy(out, iedata, min(bufsize, copy));
+                               out += min(bufsize, copy);
+                               bufsize -= min(bufsize, copy);
+                       }
+
+
+                       if (copy == attr_remaining)
+                               return desired_len;
+               }
+
+               attr_remaining -= copy;
+               if (attr_remaining)
+                       goto cont;
+
+               iedatalen -= copy;
+               iedata += copy;
+
+               while (iedatalen > 0) {
+                       u16 attr_len;
+
+                       /* P2P attribute ID & size must fit */
+                       if (iedatalen < 3)
+                               return -EILSEQ;
+                       desired_attr = iedata[0] == attr;
+                       attr_len = get_unaligned_le16(iedata + 1);
+                       iedatalen -= 3;
+                       iedata += 3;
+
+                       copy = min_t(unsigned int, attr_len, iedatalen);
+
+                       if (desired_attr) {
+                               desired_len += copy;
+                               if (out) {
+                                       memcpy(out, iedata, min(bufsize, copy));
+                                       out += min(bufsize, copy);
+                                       bufsize -= min(bufsize, copy);
+                               }
+
+                               if (copy == attr_len)
+                                       return desired_len;
+                       }
+
+                       iedata += copy;
+                       iedatalen -= copy;
+                       attr_remaining = attr_len - copy;
+               }
+
+ cont:
+               len -= ies[1] + 2;
+               ies += ies[1] + 2;
+       }
+
+       if (attr_remaining && desired_attr)
+               return -EILSEQ;
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL(cfg80211_get_p2p_attr);
+
 int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
                                 u32 beacon_int)
 {