|
@@ -91,10 +91,6 @@ static struct regulatory_request __rcu *last_request =
|
|
/* To trigger userspace events */
|
|
/* To trigger userspace events */
|
|
static struct platform_device *reg_pdev;
|
|
static struct platform_device *reg_pdev;
|
|
|
|
|
|
-static const struct device_type reg_device_type = {
|
|
|
|
- .uevent = reg_device_uevent,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* Central wireless core regulatory domains, we only need two,
|
|
* Central wireless core regulatory domains, we only need two,
|
|
* the current one and a world regulatory domain in case we have no
|
|
* the current one and a world regulatory domain in case we have no
|
|
@@ -244,19 +240,21 @@ static char user_alpha2[2];
|
|
module_param(ieee80211_regdom, charp, 0444);
|
|
module_param(ieee80211_regdom, charp, 0444);
|
|
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
|
|
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
|
|
|
|
|
|
-static void reg_kfree_last_request(void)
|
|
|
|
|
|
+static void reg_free_request(struct regulatory_request *lr)
|
|
{
|
|
{
|
|
- struct regulatory_request *lr;
|
|
|
|
-
|
|
|
|
- lr = get_last_request();
|
|
|
|
-
|
|
|
|
if (lr != &core_request_world && lr)
|
|
if (lr != &core_request_world && lr)
|
|
kfree_rcu(lr, rcu_head);
|
|
kfree_rcu(lr, rcu_head);
|
|
}
|
|
}
|
|
|
|
|
|
static void reg_update_last_request(struct regulatory_request *request)
|
|
static void reg_update_last_request(struct regulatory_request *request)
|
|
{
|
|
{
|
|
- reg_kfree_last_request();
|
|
|
|
|
|
+ struct regulatory_request *lr;
|
|
|
|
+
|
|
|
|
+ lr = get_last_request();
|
|
|
|
+ if (lr == request)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ reg_free_request(lr);
|
|
rcu_assign_pointer(last_request, request);
|
|
rcu_assign_pointer(last_request, request);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -487,11 +485,16 @@ static inline void reg_regdb_query(const char *alpha2) {}
|
|
|
|
|
|
/*
|
|
/*
|
|
* This lets us keep regulatory code which is updated on a regulatory
|
|
* This lets us keep regulatory code which is updated on a regulatory
|
|
- * basis in userspace. Country information is filled in by
|
|
|
|
- * reg_device_uevent
|
|
|
|
|
|
+ * basis in userspace.
|
|
*/
|
|
*/
|
|
static int call_crda(const char *alpha2)
|
|
static int call_crda(const char *alpha2)
|
|
{
|
|
{
|
|
|
|
+ char country[12];
|
|
|
|
+ char *env[] = { country, NULL };
|
|
|
|
+
|
|
|
|
+ snprintf(country, sizeof(country), "COUNTRY=%c%c",
|
|
|
|
+ alpha2[0], alpha2[1]);
|
|
|
|
+
|
|
if (!is_world_regdom((char *) alpha2))
|
|
if (!is_world_regdom((char *) alpha2))
|
|
pr_info("Calling CRDA for country: %c%c\n",
|
|
pr_info("Calling CRDA for country: %c%c\n",
|
|
alpha2[0], alpha2[1]);
|
|
alpha2[0], alpha2[1]);
|
|
@@ -501,7 +504,7 @@ static int call_crda(const char *alpha2)
|
|
/* query internal regulatory database (if it exists) */
|
|
/* query internal regulatory database (if it exists) */
|
|
reg_regdb_query(alpha2);
|
|
reg_regdb_query(alpha2);
|
|
|
|
|
|
- return kobject_uevent(®_pdev->dev.kobj, KOBJ_CHANGE);
|
|
|
|
|
|
+ return kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, env);
|
|
}
|
|
}
|
|
|
|
|
|
static enum reg_request_treatment
|
|
static enum reg_request_treatment
|
|
@@ -755,6 +758,9 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
|
|
power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
|
|
power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
|
|
power_rule2->max_antenna_gain);
|
|
power_rule2->max_antenna_gain);
|
|
|
|
|
|
|
|
+ intersected_rule->dfs_cac_ms = max(rule1->dfs_cac_ms,
|
|
|
|
+ rule2->dfs_cac_ms);
|
|
|
|
+
|
|
if (!is_valid_reg_rule(intersected_rule))
|
|
if (!is_valid_reg_rule(intersected_rule))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
@@ -1077,6 +1083,14 @@ static void handle_channel(struct wiphy *wiphy,
|
|
min_t(int, chan->orig_mag,
|
|
min_t(int, chan->orig_mag,
|
|
MBI_TO_DBI(power_rule->max_antenna_gain));
|
|
MBI_TO_DBI(power_rule->max_antenna_gain));
|
|
chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
|
|
chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
|
|
|
|
+
|
|
|
|
+ if (chan->flags & IEEE80211_CHAN_RADAR) {
|
|
|
|
+ if (reg_rule->dfs_cac_ms)
|
|
|
|
+ chan->dfs_cac_ms = reg_rule->dfs_cac_ms;
|
|
|
|
+ else
|
|
|
|
+ chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (chan->orig_mpwr) {
|
|
if (chan->orig_mpwr) {
|
|
/*
|
|
/*
|
|
* Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
|
|
* Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
|
|
@@ -2255,9 +2269,9 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
|
|
const struct ieee80211_reg_rule *reg_rule = NULL;
|
|
const struct ieee80211_reg_rule *reg_rule = NULL;
|
|
const struct ieee80211_freq_range *freq_range = NULL;
|
|
const struct ieee80211_freq_range *freq_range = NULL;
|
|
const struct ieee80211_power_rule *power_rule = NULL;
|
|
const struct ieee80211_power_rule *power_rule = NULL;
|
|
- char bw[32];
|
|
|
|
|
|
+ char bw[32], cac_time[32];
|
|
|
|
|
|
- pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n");
|
|
|
|
|
|
+ pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp), (dfs_cac_time)\n");
|
|
|
|
|
|
for (i = 0; i < rd->n_reg_rules; i++) {
|
|
for (i = 0; i < rd->n_reg_rules; i++) {
|
|
reg_rule = &rd->reg_rules[i];
|
|
reg_rule = &rd->reg_rules[i];
|
|
@@ -2272,23 +2286,32 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
|
|
snprintf(bw, sizeof(bw), "%d KHz",
|
|
snprintf(bw, sizeof(bw), "%d KHz",
|
|
freq_range->max_bandwidth_khz);
|
|
freq_range->max_bandwidth_khz);
|
|
|
|
|
|
|
|
+ if (reg_rule->flags & NL80211_RRF_DFS)
|
|
|
|
+ scnprintf(cac_time, sizeof(cac_time), "%u s",
|
|
|
|
+ reg_rule->dfs_cac_ms/1000);
|
|
|
|
+ else
|
|
|
|
+ scnprintf(cac_time, sizeof(cac_time), "N/A");
|
|
|
|
+
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* There may not be documentation for max antenna gain
|
|
* There may not be documentation for max antenna gain
|
|
* in certain regions
|
|
* in certain regions
|
|
*/
|
|
*/
|
|
if (power_rule->max_antenna_gain)
|
|
if (power_rule->max_antenna_gain)
|
|
- pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n",
|
|
|
|
|
|
+ pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm), (%s)\n",
|
|
freq_range->start_freq_khz,
|
|
freq_range->start_freq_khz,
|
|
freq_range->end_freq_khz,
|
|
freq_range->end_freq_khz,
|
|
bw,
|
|
bw,
|
|
power_rule->max_antenna_gain,
|
|
power_rule->max_antenna_gain,
|
|
- power_rule->max_eirp);
|
|
|
|
|
|
+ power_rule->max_eirp,
|
|
|
|
+ cac_time);
|
|
else
|
|
else
|
|
- pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n",
|
|
|
|
|
|
+ pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm), (%s)\n",
|
|
freq_range->start_freq_khz,
|
|
freq_range->start_freq_khz,
|
|
freq_range->end_freq_khz,
|
|
freq_range->end_freq_khz,
|
|
bw,
|
|
bw,
|
|
- power_rule->max_eirp);
|
|
|
|
|
|
+ power_rule->max_eirp,
|
|
|
|
+ cac_time);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2361,9 +2384,6 @@ static int reg_set_rd_user(const struct ieee80211_regdomain *rd,
|
|
{
|
|
{
|
|
const struct ieee80211_regdomain *intersected_rd = NULL;
|
|
const struct ieee80211_regdomain *intersected_rd = NULL;
|
|
|
|
|
|
- if (is_world_regdom(rd->alpha2))
|
|
|
|
- return -EINVAL;
|
|
|
|
-
|
|
|
|
if (!regdom_changes(rd->alpha2))
|
|
if (!regdom_changes(rd->alpha2))
|
|
return -EALREADY;
|
|
return -EALREADY;
|
|
|
|
|
|
@@ -2552,26 +2572,6 @@ int set_regdom(const struct ieee80211_regdomain *rd)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|
|
|
-{
|
|
|
|
- struct regulatory_request *lr;
|
|
|
|
- u8 alpha2[2];
|
|
|
|
- bool add = false;
|
|
|
|
-
|
|
|
|
- rcu_read_lock();
|
|
|
|
- lr = get_last_request();
|
|
|
|
- if (lr && !lr->processed) {
|
|
|
|
- memcpy(alpha2, lr->alpha2, 2);
|
|
|
|
- add = true;
|
|
|
|
- }
|
|
|
|
- rcu_read_unlock();
|
|
|
|
-
|
|
|
|
- if (add)
|
|
|
|
- return add_uevent_var(env, "COUNTRY=%c%c",
|
|
|
|
- alpha2[0], alpha2[1]);
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
void wiphy_regulatory_register(struct wiphy *wiphy)
|
|
void wiphy_regulatory_register(struct wiphy *wiphy)
|
|
{
|
|
{
|
|
struct regulatory_request *lr;
|
|
struct regulatory_request *lr;
|
|
@@ -2622,8 +2622,6 @@ int __init regulatory_init(void)
|
|
if (IS_ERR(reg_pdev))
|
|
if (IS_ERR(reg_pdev))
|
|
return PTR_ERR(reg_pdev);
|
|
return PTR_ERR(reg_pdev);
|
|
|
|
|
|
- reg_pdev->dev.type = ®_device_type;
|
|
|
|
-
|
|
|
|
spin_lock_init(®_requests_lock);
|
|
spin_lock_init(®_requests_lock);
|
|
spin_lock_init(®_pending_beacons_lock);
|
|
spin_lock_init(®_pending_beacons_lock);
|
|
|
|
|