Merge tag 'gpio-v3.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[cascardo/linux.git] / net / wireless / util.c
index e5872ff..728f1c0 100644 (file)
@@ -476,7 +476,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
 EXPORT_SYMBOL(ieee80211_data_to_8023);
 
 int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
-                            enum nl80211_iftype iftype, u8 *bssid, bool qos)
+                            enum nl80211_iftype iftype,
+                            const u8 *bssid, bool qos)
 {
        struct ieee80211_hdr hdr;
        u16 hdrlen, ethertype;
@@ -770,7 +771,7 @@ EXPORT_SYMBOL(ieee80211_bss_get_ie);
 
 void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct net_device *dev = wdev->netdev;
        int i;
 
@@ -839,6 +840,9 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
                        __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
                                               ev->ij.channel);
                        break;
+               case EVENT_STOPPED:
+                       __cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev);
+                       break;
                }
                wdev_unlock(wdev);
 
@@ -888,11 +892,6 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                return -EBUSY;
 
        if (ntype != otype && netif_running(dev)) {
-               err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
-                                                   ntype);
-               if (err)
-                       return err;
-
                dev->ieee80211_ptr->use_4addr = false;
                dev->ieee80211_ptr->mesh_id_up_len = 0;
                wdev_lock(dev->ieee80211_ptr);
@@ -1268,6 +1267,120 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
        return res;
 }
 
+int cfg80211_iter_combinations(struct wiphy *wiphy,
+                              const int num_different_channels,
+                              const u8 radar_detect,
+                              const int iftype_num[NUM_NL80211_IFTYPES],
+                              void (*iter)(const struct ieee80211_iface_combination *c,
+                                           void *data),
+                              void *data)
+{
+       const struct ieee80211_regdomain *regdom;
+       enum nl80211_dfs_regions region = 0;
+       int i, j, iftype;
+       int num_interfaces = 0;
+       u32 used_iftypes = 0;
+
+       if (radar_detect) {
+               rcu_read_lock();
+               regdom = rcu_dereference(cfg80211_regdomain);
+               if (regdom)
+                       region = regdom->dfs_region;
+               rcu_read_unlock();
+       }
+
+       for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
+               num_interfaces += iftype_num[iftype];
+               if (iftype_num[iftype] > 0 &&
+                   !(wiphy->software_iftypes & BIT(iftype)))
+                       used_iftypes |= BIT(iftype);
+       }
+
+       for (i = 0; i < wiphy->n_iface_combinations; i++) {
+               const struct ieee80211_iface_combination *c;
+               struct ieee80211_iface_limit *limits;
+               u32 all_iftypes = 0;
+
+               c = &wiphy->iface_combinations[i];
+
+               if (num_interfaces > c->max_interfaces)
+                       continue;
+               if (num_different_channels > c->num_different_channels)
+                       continue;
+
+               limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
+                                GFP_KERNEL);
+               if (!limits)
+                       return -ENOMEM;
+
+               for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
+                       if (wiphy->software_iftypes & BIT(iftype))
+                               continue;
+                       for (j = 0; j < c->n_limits; j++) {
+                               all_iftypes |= limits[j].types;
+                               if (!(limits[j].types & BIT(iftype)))
+                                       continue;
+                               if (limits[j].max < iftype_num[iftype])
+                                       goto cont;
+                               limits[j].max -= iftype_num[iftype];
+                       }
+               }
+
+               if (radar_detect != (c->radar_detect_widths & radar_detect))
+                       goto cont;
+
+               if (radar_detect && c->radar_detect_regions &&
+                   !(c->radar_detect_regions & BIT(region)))
+                       goto cont;
+
+               /* Finally check that all iftypes that we're currently
+                * using are actually part of this combination. If they
+                * aren't then we can't use this combination and have
+                * to continue to the next.
+                */
+               if ((all_iftypes & used_iftypes) != used_iftypes)
+                       goto cont;
+
+               /* This combination covered all interface types and
+                * supported the requested numbers, so we're good.
+                */
+
+               (*iter)(c, data);
+ cont:
+               kfree(limits);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(cfg80211_iter_combinations);
+
+static void
+cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
+                         void *data)
+{
+       int *num = data;
+       (*num)++;
+}
+
+int cfg80211_check_combinations(struct wiphy *wiphy,
+                               const int num_different_channels,
+                               const u8 radar_detect,
+                               const int iftype_num[NUM_NL80211_IFTYPES])
+{
+       int err, num = 0;
+
+       err = cfg80211_iter_combinations(wiphy, num_different_channels,
+                                        radar_detect, iftype_num,
+                                        cfg80211_iter_sum_ifcombs, &num);
+       if (err)
+               return err;
+       if (num == 0)
+               return -EBUSY;
+
+       return 0;
+}
+EXPORT_SYMBOL(cfg80211_check_combinations);
+
 int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 struct wireless_dev *wdev,
                                 enum nl80211_iftype iftype,
@@ -1276,7 +1389,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 u8 radar_detect)
 {
        struct wireless_dev *wdev_iter;
-       u32 used_iftypes = BIT(iftype);
        int num[NUM_NL80211_IFTYPES];
        struct ieee80211_channel
                        *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS];
@@ -1284,7 +1396,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;
-       int i, j;
+       int i;
 
        ASSERT_RTNL();
 
@@ -1306,6 +1418,11 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 
        num[iftype] = 1;
 
+       /* TODO: We'll probably not need this anymore, since this
+        * should only be called with CHAN_MODE_UNDEFINED. There are
+        * still a couple of pending calls where other chanmodes are
+        * used, but we should get rid of them.
+        */
        switch (chanmode) {
        case CHAN_MODE_UNDEFINED:
                break;
@@ -1369,65 +1486,13 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 
                num[wdev_iter->iftype]++;
                total++;
-               used_iftypes |= BIT(wdev_iter->iftype);
        }
 
        if (total == 1 && !radar_detect)
                return 0;
 
-       for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
-               const struct ieee80211_iface_combination *c;
-               struct ieee80211_iface_limit *limits;
-               u32 all_iftypes = 0;
-
-               c = &rdev->wiphy.iface_combinations[i];
-
-               if (total > c->max_interfaces)
-                       continue;
-               if (num_different_channels > c->num_different_channels)
-                       continue;
-
-               limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
-                                GFP_KERNEL);
-               if (!limits)
-                       return -ENOMEM;
-
-               for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
-                       if (rdev->wiphy.software_iftypes & BIT(iftype))
-                               continue;
-                       for (j = 0; j < c->n_limits; j++) {
-                               all_iftypes |= limits[j].types;
-                               if (!(limits[j].types & BIT(iftype)))
-                                       continue;
-                               if (limits[j].max < num[iftype])
-                                       goto cont;
-                               limits[j].max -= num[iftype];
-                       }
-               }
-
-               if (radar_detect && !(c->radar_detect_widths & radar_detect))
-                       goto cont;
-
-               /*
-                * Finally check that all iftypes that we're currently
-                * using are actually part of this combination. If they
-                * aren't then we can't use this combination and have
-                * to continue to the next.
-                */
-               if ((all_iftypes & used_iftypes) != used_iftypes)
-                       goto cont;
-
-               /*
-                * This combination covered all interface types and
-                * supported the requested numbers, so we're good.
-                */
-               kfree(limits);
-               return 0;
- cont:
-               kfree(limits);
-       }
-
-       return -EBUSY;
+       return cfg80211_check_combinations(&rdev->wiphy, num_different_channels,
+                                          radar_detect, num);
 }
 
 int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
@@ -1481,6 +1546,24 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy)
 }
 EXPORT_SYMBOL(ieee80211_get_num_supported_channels);
 
+int cfg80211_get_station(struct net_device *dev, const u8 *mac_addr,
+                        struct station_info *sinfo)
+{
+       struct cfg80211_registered_device *rdev;
+       struct wireless_dev *wdev;
+
+       wdev = dev->ieee80211_ptr;
+       if (!wdev)
+               return -EOPNOTSUPP;
+
+       rdev = wiphy_to_rdev(wdev->wiphy);
+       if (!rdev->ops->get_station)
+               return -EOPNOTSUPP;
+
+       return rdev_get_station(rdev, dev, mac_addr, sinfo);
+}
+EXPORT_SYMBOL(cfg80211_get_station);
+
 /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
 /* Ethernet-II snap header (RFC1042 for most EtherTypes) */
 const unsigned char rfc1042_header[] __aligned(2) =