|
@@ -13,6 +13,7 @@
|
|
|
#include <net/dsfield.h>
|
|
|
#include <linux/if_vlan.h>
|
|
|
#include <linux/mpls.h>
|
|
|
+#include <linux/gcd.h>
|
|
|
#include "core.h"
|
|
|
#include "rdev-ops.h"
|
|
|
|
|
@@ -1558,47 +1559,53 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
|
|
|
}
|
|
|
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
|
|
|
|
|
|
-int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
|
|
- enum nl80211_iftype iftype, u32 beacon_int)
|
|
|
+static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
|
|
|
+ u32 *beacon_int_gcd,
|
|
|
+ bool *beacon_int_different)
|
|
|
{
|
|
|
struct wireless_dev *wdev;
|
|
|
- struct iface_combination_params params = {
|
|
|
- .beacon_int_gcd = beacon_int, /* GCD(n) = n */
|
|
|
- };
|
|
|
|
|
|
- if (beacon_int < 10 || beacon_int > 10000)
|
|
|
- return -EINVAL;
|
|
|
+ *beacon_int_gcd = 0;
|
|
|
+ *beacon_int_different = false;
|
|
|
|
|
|
- params.iftype_num[iftype] = 1;
|
|
|
- list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
|
|
+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
|
|
|
if (!wdev->beacon_interval)
|
|
|
continue;
|
|
|
|
|
|
- params.iftype_num[wdev->iftype]++;
|
|
|
- }
|
|
|
-
|
|
|
- list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
|
|
- u32 bi_prev = wdev->beacon_interval;
|
|
|
-
|
|
|
- if (!wdev->beacon_interval)
|
|
|
+ if (!*beacon_int_gcd) {
|
|
|
+ *beacon_int_gcd = wdev->beacon_interval;
|
|
|
continue;
|
|
|
+ }
|
|
|
|
|
|
- /* slight optimisation - skip identical BIs */
|
|
|
- if (wdev->beacon_interval == beacon_int)
|
|
|
+ if (wdev->beacon_interval == *beacon_int_gcd)
|
|
|
continue;
|
|
|
|
|
|
- params.beacon_int_different = true;
|
|
|
-
|
|
|
- /* Get the GCD */
|
|
|
- while (bi_prev != 0) {
|
|
|
- u32 tmp_bi = bi_prev;
|
|
|
+ *beacon_int_different = true;
|
|
|
+ *beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval);
|
|
|
+ }
|
|
|
|
|
|
- bi_prev = params.beacon_int_gcd % bi_prev;
|
|
|
- params.beacon_int_gcd = tmp_bi;
|
|
|
- }
|
|
|
+ if (new_beacon_int && *beacon_int_gcd != new_beacon_int) {
|
|
|
+ if (*beacon_int_gcd)
|
|
|
+ *beacon_int_different = true;
|
|
|
+ *beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int);
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- return cfg80211_check_combinations(&rdev->wiphy, ¶ms);
|
|
|
+int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
|
|
+ enum nl80211_iftype iftype, u32 beacon_int)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * This is just a basic pre-condition check; if interface combinations
|
|
|
+ * are possible the driver must already be checking those with a call
|
|
|
+ * to cfg80211_check_combinations(), in which case we'll validate more
|
|
|
+ * through the cfg80211_calculate_bi_data() call and code in
|
|
|
+ * cfg80211_iter_combinations().
|
|
|
+ */
|
|
|
+
|
|
|
+ if (beacon_int < 10 || beacon_int > 10000)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
int cfg80211_iter_combinations(struct wiphy *wiphy,
|
|
@@ -1612,6 +1619,21 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
|
|
|
int i, j, iftype;
|
|
|
int num_interfaces = 0;
|
|
|
u32 used_iftypes = 0;
|
|
|
+ u32 beacon_int_gcd;
|
|
|
+ bool beacon_int_different;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This is a bit strange, since the iteration used to rely only on
|
|
|
+ * the data given by the driver, but here it now relies on context,
|
|
|
+ * in form of the currently operating interfaces.
|
|
|
+ * This is OK for all current users, and saves us from having to
|
|
|
+ * push the GCD calculations into all the drivers.
|
|
|
+ * In the future, this should probably rely more on data that's in
|
|
|
+ * cfg80211 already - the only thing not would appear to be any new
|
|
|
+ * interfaces (while being brought up) and channel/radar data.
|
|
|
+ */
|
|
|
+ cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
|
|
|
+ &beacon_int_gcd, &beacon_int_different);
|
|
|
|
|
|
if (params->radar_detect) {
|
|
|
rcu_read_lock();
|
|
@@ -1674,12 +1696,11 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
|
|
|
if ((all_iftypes & used_iftypes) != used_iftypes)
|
|
|
goto cont;
|
|
|
|
|
|
- if (params->beacon_int_gcd) {
|
|
|
+ if (beacon_int_gcd) {
|
|
|
if (c->beacon_int_min_gcd &&
|
|
|
- params->beacon_int_gcd < c->beacon_int_min_gcd)
|
|
|
+ beacon_int_gcd < c->beacon_int_min_gcd)
|
|
|
goto cont;
|
|
|
- if (!c->beacon_int_min_gcd &&
|
|
|
- params->beacon_int_different)
|
|
|
+ if (!c->beacon_int_min_gcd && beacon_int_different)
|
|
|
goto cont;
|
|
|
}
|
|
|
|