diff options
Diffstat (limited to 'net/wireless/reg.c')
| -rw-r--r-- | net/wireless/reg.c | 141 | 
1 files changed, 121 insertions, 20 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3302c56f60d..f65feaad155 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2,13 +2,22 @@   * Copyright 2002-2005, Instant802 Networks, Inc.   * Copyright 2005-2006, Devicescape Software, Inc.   * Copyright 2007	Johannes Berg <johannes@sipsolutions.net> - * Copyright 2008	Luis R. Rodriguez <lrodriguz@atheros.com> + * Copyright 2008-2011	Luis R. Rodriguez <mcgrof@qca.qualcomm.com>   * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ +  /**   * DOC: Wireless regulatory infrastructure   * @@ -873,10 +882,22 @@ static void handle_channel(struct wiphy *wiphy,  	chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);  	chan->max_antenna_gain = min(chan->orig_mag,  		(int) MBI_TO_DBI(power_rule->max_antenna_gain)); -	if (chan->orig_mpwr) -		chan->max_power = min(chan->orig_mpwr, -			(int) MBM_TO_DBM(power_rule->max_eirp)); -	else +	if (chan->orig_mpwr) { +		/* +		 * Devices that have their own custom regulatory domain +		 * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the +		 * passed country IE power settings. +		 */ +		if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && +		    wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && +		    wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { +			chan->max_power = +				MBM_TO_DBM(power_rule->max_eirp); +		} else { +			chan->max_power = min(chan->orig_mpwr, +				(int) MBM_TO_DBM(power_rule->max_eirp)); +		} +	} else  		chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);  } @@ -1139,6 +1160,8 @@ static void wiphy_update_regulatory(struct wiphy *wiphy,  	if (ignore_reg_update(wiphy, initiator))  		return; +	last_request->dfs_region = cfg80211_regdomain->dfs_region; +  	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {  		if (wiphy->bands[band])  			handle_band(wiphy, band, initiator); @@ -1161,9 +1184,21 @@ void regulatory_update(struct wiphy *wiphy,  static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)  {  	struct cfg80211_registered_device *rdev; +	struct wiphy *wiphy; -	list_for_each_entry(rdev, &cfg80211_rdev_list, list) -		wiphy_update_regulatory(&rdev->wiphy, initiator); +	list_for_each_entry(rdev, &cfg80211_rdev_list, list) { +		wiphy = &rdev->wiphy; +		wiphy_update_regulatory(wiphy, initiator); +		/* +		 * Regulatory updates set by CORE are ignored for custom +		 * regulatory cards. Let us notify the changes to the driver, +		 * as some drivers used this to restore its orig_* reg domain. +		 */ +		if (initiator == NL80211_REGDOM_SET_BY_CORE && +		    wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && +		    wiphy->reg_notifier) +			wiphy->reg_notifier(wiphy, last_request); +	}  }  static void handle_channel_custom(struct wiphy *wiphy, @@ -1454,18 +1489,18 @@ new_request:  }  /* This processes *all* regulatory hints */ -static void reg_process_hint(struct regulatory_request *reg_request) +static void reg_process_hint(struct regulatory_request *reg_request, +			     enum nl80211_reg_initiator reg_initiator)  {  	int r = 0;  	struct wiphy *wiphy = NULL; -	enum nl80211_reg_initiator initiator = reg_request->initiator;  	BUG_ON(!reg_request->alpha2);  	if (wiphy_idx_valid(reg_request->wiphy_idx))  		wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); -	if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && +	if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER &&  	    !wiphy) {  		kfree(reg_request);  		return; @@ -1475,7 +1510,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)  	/* This is required so that the orig_* parameters are saved */  	if (r == -EALREADY && wiphy &&  	    wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { -		wiphy_update_regulatory(wiphy, initiator); +		wiphy_update_regulatory(wiphy, reg_initiator);  		return;  	} @@ -1484,7 +1519,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)  	 * source of bogus requests.  	 */  	if (r != -EALREADY && -	    reg_request->initiator == NL80211_REGDOM_SET_BY_USER) +	    reg_initiator == NL80211_REGDOM_SET_BY_USER)  		schedule_delayed_work(®_timeout, msecs_to_jiffies(3142));  } @@ -1521,7 +1556,7 @@ static void reg_process_pending_hints(void)  	spin_unlock(®_requests_lock); -	reg_process_hint(reg_request); +	reg_process_hint(reg_request, reg_request->initiator);  out:  	mutex_unlock(®_mutex); @@ -1766,6 +1801,26 @@ static void restore_alpha2(char *alpha2, bool reset_user)  		REG_DBG_PRINT("Restoring regulatory settings\n");  } +static void restore_custom_reg_settings(struct wiphy *wiphy) +{ +	struct ieee80211_supported_band *sband; +	enum ieee80211_band band; +	struct ieee80211_channel *chan; +	int i; + +	for (band = 0; band < IEEE80211_NUM_BANDS; band++) { +		sband = wiphy->bands[band]; +		if (!sband) +			continue; +		for (i = 0; i < sband->n_channels; i++) { +			chan = &sband->channels[i]; +			chan->flags = chan->orig_flags; +			chan->max_antenna_gain = chan->orig_mag; +			chan->max_power = chan->orig_mpwr; +		} +	} +} +  /*   * Restoring regulatory settings involves ingoring any   * possibly stale country IE information and user regulatory @@ -1784,9 +1839,11 @@ static void restore_alpha2(char *alpha2, bool reset_user)  static void restore_regulatory_settings(bool reset_user)  {  	char alpha2[2]; +	char world_alpha2[2];  	struct reg_beacon *reg_beacon, *btmp;  	struct regulatory_request *reg_request, *tmp;  	LIST_HEAD(tmp_reg_req_list); +	struct cfg80211_registered_device *rdev;  	mutex_lock(&cfg80211_mutex);  	mutex_lock(®_mutex); @@ -1834,11 +1891,18 @@ static void restore_regulatory_settings(bool reset_user)  	/* First restore to the basic regulatory settings */  	cfg80211_regdomain = cfg80211_world_regdom; +	world_alpha2[0] = cfg80211_regdomain->alpha2[0]; +	world_alpha2[1] = cfg80211_regdomain->alpha2[1]; + +	list_for_each_entry(rdev, &cfg80211_rdev_list, list) { +		if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY) +			restore_custom_reg_settings(&rdev->wiphy); +	}  	mutex_unlock(®_mutex);  	mutex_unlock(&cfg80211_mutex); -	regulatory_hint_core(cfg80211_regdomain->alpha2); +	regulatory_hint_core(world_alpha2);  	/*  	 * This restores the ieee80211_regdom module parameter @@ -1935,7 +1999,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)  	const struct ieee80211_freq_range *freq_range = NULL;  	const struct ieee80211_power_rule *power_rule = NULL; -	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)\n");  	for (i = 0; i < rd->n_reg_rules; i++) {  		reg_rule = &rd->reg_rules[i]; @@ -1947,14 +2011,14 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)  		 * in certain regions  		 */  		if (power_rule->max_antenna_gain) -			pr_info("    (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n", +			pr_info("  (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n",  				freq_range->start_freq_khz,  				freq_range->end_freq_khz,  				freq_range->max_bandwidth_khz,  				power_rule->max_antenna_gain,  				power_rule->max_eirp);  		else -			pr_info("    (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n", +			pr_info("  (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n",  				freq_range->start_freq_khz,  				freq_range->end_freq_khz,  				freq_range->max_bandwidth_khz, @@ -1962,6 +2026,42 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)  	}  } +bool reg_supported_dfs_region(u8 dfs_region) +{ +	switch (dfs_region) { +	case NL80211_DFS_UNSET: +	case NL80211_DFS_FCC: +	case NL80211_DFS_ETSI: +	case NL80211_DFS_JP: +		return true; +	default: +		REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n", +			      dfs_region); +		return false; +	} +} + +static void print_dfs_region(u8 dfs_region) +{ +	if (!dfs_region) +		return; + +	switch (dfs_region) { +	case NL80211_DFS_FCC: +		pr_info(" DFS Master region FCC"); +		break; +	case NL80211_DFS_ETSI: +		pr_info(" DFS Master region ETSI"); +		break; +	case NL80211_DFS_JP: +		pr_info(" DFS Master region JP"); +		break; +	default: +		pr_info(" DFS Master region Uknown"); +		break; +	} +} +  static void print_regdomain(const struct ieee80211_regdomain *rd)  { @@ -1989,6 +2089,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)  			pr_info("Regulatory domain changed to country: %c%c\n",  				rd->alpha2[0], rd->alpha2[1]);  	} +	print_dfs_region(rd->dfs_region);  	print_rd_rules(rd);  }  |