]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/wireless/util.c
wireless: report reasonable bitrate for MCS rates through wext
[karo-tx-linux.git] / net / wireless / util.c
index 3fc2df86278fcf7390c5d2b3cce484a7abb04f4d..a3c841a255dbb19db337c44d7ede680362cfce90 100644 (file)
@@ -320,7 +320,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
                break;
        case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
                if (unlikely(iftype != NL80211_IFTYPE_WDS &&
-                            iftype != NL80211_IFTYPE_MESH_POINT))
+                            iftype != NL80211_IFTYPE_MESH_POINT &&
+                            iftype != NL80211_IFTYPE_AP_VLAN &&
+                            iftype != NL80211_IFTYPE_STATION))
                        return -1;
                if (iftype == NL80211_IFTYPE_MESH_POINT) {
                        struct ieee80211s_hdr *meshdr =
@@ -656,7 +658,14 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
            !(rdev->wiphy.interface_modes & (1 << ntype)))
                return -EOPNOTSUPP;
 
+       /* if it's part of a bridge, reject changing type to station/ibss */
+       if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC ||
+                            ntype == NL80211_IFTYPE_STATION))
+               return -EBUSY;
+
        if (ntype != otype) {
+               dev->ieee80211_ptr->use_4addr = false;
+
                switch (otype) {
                case NL80211_IFTYPE_ADHOC:
                        cfg80211_leave_ibss(rdev, dev, false);
@@ -680,5 +689,67 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 
        WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
 
+       if (!err && params && params->use_4addr != -1)
+               dev->ieee80211_ptr->use_4addr = params->use_4addr;
+
+       if (!err) {
+               dev->priv_flags &= ~IFF_DONT_BRIDGE;
+               switch (ntype) {
+               case NL80211_IFTYPE_STATION:
+                       if (dev->ieee80211_ptr->use_4addr)
+                               break;
+                       /* fall through */
+               case NL80211_IFTYPE_ADHOC:
+                       dev->priv_flags |= IFF_DONT_BRIDGE;
+                       break;
+               case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_AP_VLAN:
+               case NL80211_IFTYPE_WDS:
+               case NL80211_IFTYPE_MESH_POINT:
+                       /* bridging OK */
+                       break;
+               case NL80211_IFTYPE_MONITOR:
+                       /* monitor can't bridge anyway */
+                       break;
+               case NL80211_IFTYPE_UNSPECIFIED:
+               case __NL80211_IFTYPE_AFTER_LAST:
+                       /* not happening */
+                       break;
+               }
+       }
+
        return err;
 }
+
+u16 cfg80211_calculate_bitrate(struct rate_info *rate)
+{
+       int modulation, streams, bitrate;
+
+       if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+               return rate->legacy;
+
+       /* the formula below does only work for MCS values smaller than 32 */
+       if (rate->mcs >= 32)
+               return 0;
+
+       modulation = rate->mcs & 7;
+       streams = (rate->mcs >> 3) + 1;
+
+       bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ?
+                       13500000 : 6500000;
+
+       if (modulation < 4)
+               bitrate *= (modulation + 1);
+       else if (modulation == 4)
+               bitrate *= (modulation + 2);
+       else
+               bitrate *= (modulation + 3);
+
+       bitrate *= streams;
+
+       if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+               bitrate = (bitrate / 9) * 10;
+
+       /* do NOT round down here */
+       return (bitrate + 50000) / 100000;
+}