cfg80211: advertise possible interface combinations
[deliverable/linux.git] / net / wireless / util.c
index 6a750bc6bcfe3cf3fddc82202a7d7ddeabf28720..95e4e254da0a2bbeb0b7355af7374e68b2e7f965 100644 (file)
@@ -803,6 +803,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                return -EBUSY;
 
        if (ntype != otype) {
+               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;
 
@@ -896,3 +901,103 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate)
        /* do NOT round down here */
        return (bitrate + 50000) / 100000;
 }
+
+int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
+                                u32 beacon_int)
+{
+       struct wireless_dev *wdev;
+       int res = 0;
+
+       if (!beacon_int)
+               return -EINVAL;
+
+       mutex_lock(&rdev->devlist_mtx);
+
+       list_for_each_entry(wdev, &rdev->netdev_list, list) {
+               if (!wdev->beacon_interval)
+                       continue;
+               if (wdev->beacon_interval != beacon_int) {
+                       res = -EINVAL;
+                       break;
+               }
+       }
+
+       mutex_unlock(&rdev->devlist_mtx);
+
+       return res;
+}
+
+int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
+                                 struct wireless_dev *wdev,
+                                 enum nl80211_iftype iftype)
+{
+       struct wireless_dev *wdev_iter;
+       int num[NUM_NL80211_IFTYPES];
+       int total = 1;
+       int i, j;
+
+       ASSERT_RTNL();
+
+       /* Always allow software iftypes */
+       if (rdev->wiphy.software_iftypes & BIT(iftype))
+               return 0;
+
+       /*
+        * Drivers will gradually all set this flag, until all
+        * have it we only enforce for those that set it.
+        */
+       if (!(rdev->wiphy.flags & WIPHY_FLAG_ENFORCE_COMBINATIONS))
+               return 0;
+
+       memset(num, 0, sizeof(num));
+
+       num[iftype] = 1;
+
+       mutex_lock(&rdev->devlist_mtx);
+       list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
+               if (wdev_iter == wdev)
+                       continue;
+               if (!netif_running(wdev_iter->netdev))
+                       continue;
+
+               if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
+                       continue;
+
+               num[wdev_iter->iftype]++;
+               total++;
+       }
+       mutex_unlock(&rdev->devlist_mtx);
+
+       for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
+               const struct ieee80211_iface_combination *c;
+               struct ieee80211_iface_limit *limits;
+
+               c = &rdev->wiphy.iface_combinations[i];
+
+               limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
+                                GFP_KERNEL);
+               if (!limits)
+                       return -ENOMEM;
+               if (total > c->max_interfaces)
+                       goto cont;
+
+               for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
+                       if (rdev->wiphy.software_iftypes & BIT(iftype))
+                               continue;
+                       for (j = 0; j < c->n_limits; j++) {
+                               if (!(limits[j].types & iftype))
+                                       continue;
+                               if (limits[j].max < num[iftype])
+                                       goto cont;
+                               limits[j].max -= num[iftype];
+                       }
+               }
+               /* yay, it fits */
+               kfree(limits);
+               return 0;
+ cont:
+               kfree(limits);
+       }
+
+       return -EBUSY;
+}
This page took 0.024903 seconds and 5 git commands to generate.