cfg80211: allow wiphy specific regdomain management
Add a new regulatory flag that allows a driver to manage regdomain changes/updates for its own wiphy. A self-managed wiphys only employs regulatory information obtained from the FW and driver and does not use other cfg80211 sources like beacon-hints, country-code IEs and hints from other devices on the same system. Conversely, a self-managed wiphy does not share its regulatory hints with other devices in the system. If a system contains several devices, one or more of which are self-managed, there might be contradictory regulatory settings between them. Usage of flag is generally discouraged. Only use it if the FW/driver is incompatible with non-locally originated hints. A new API lets the driver send a complete regdomain, to be applied on its wiphy only. After a wiphy-specific regdomain change takes place, usermode will get a new type of change notification. The regulatory core also takes care enforce regulatory restrictions, in case some interfaces are on forbidden channels. Signed-off-by: Jonathan Doron <jonathanx.doron@intel.com> Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com> Reviewed-by: Luis R. Rodriguez <mcgrof@suse.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
		
					parent
					
						
							
								ad30ca2c03
							
						
					
				
			
			
				commit
				
					
						b0d7aa5959
					
				
			
		
					 8 changed files with 188 additions and 19 deletions
				
			
		| 
						 | 
					@ -3807,6 +3807,20 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
 | 
					int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * regulatory_set_wiphy_regd - set regdom info for self managed drivers
 | 
				
			||||||
 | 
					 * @wiphy: the wireless device we want to process the regulatory domain on
 | 
				
			||||||
 | 
					 * @rd: the regulatory domain informatoin to use for this wiphy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Set the regulatory domain information for self-managed wiphys, only they
 | 
				
			||||||
 | 
					 * may use this function. See %REGULATORY_WIPHY_SELF_MANAGED for more
 | 
				
			||||||
 | 
					 * information.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return: 0 on success. -EINVAL, -EPERM
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int regulatory_set_wiphy_regd(struct wiphy *wiphy,
 | 
				
			||||||
 | 
								      struct ieee80211_regdomain *rd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
 | 
					 * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
 | 
				
			||||||
 * @wiphy: the wireless device we want to process the regulatory domain on
 | 
					 * @wiphy: the wireless device we want to process the regulatory domain on
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,6 +147,24 @@ struct regulatory_request {
 | 
				
			||||||
 *	NL80211_IFTYPE_P2P_CLIENT, NL80211_IFTYPE_P2P_GO,
 | 
					 *	NL80211_IFTYPE_P2P_CLIENT, NL80211_IFTYPE_P2P_GO,
 | 
				
			||||||
 *	NL80211_IFTYPE_P2P_DEVICE. The flag will be set by default if a device
 | 
					 *	NL80211_IFTYPE_P2P_DEVICE. The flag will be set by default if a device
 | 
				
			||||||
 *	includes any modes unsupported for enforcement checking.
 | 
					 *	includes any modes unsupported for enforcement checking.
 | 
				
			||||||
 | 
					 * @REGULATORY_WIPHY_SELF_MANAGED: for devices that employ wiphy-specific
 | 
				
			||||||
 | 
					 *	regdom management. These devices will ignore all regdom changes not
 | 
				
			||||||
 | 
					 *	originating from their own wiphy.
 | 
				
			||||||
 | 
					 *	A self-managed wiphys only employs regulatory information obtained from
 | 
				
			||||||
 | 
					 *	the FW and driver and does not use other cfg80211 sources like
 | 
				
			||||||
 | 
					 *	beacon-hints, country-code IEs and hints from other devices on the same
 | 
				
			||||||
 | 
					 *	system. Conversely, a self-managed wiphy does not share its regulatory
 | 
				
			||||||
 | 
					 *	hints with other devices in the system. If a system contains several
 | 
				
			||||||
 | 
					 *	devices, one or more of which are self-managed, there might be
 | 
				
			||||||
 | 
					 *	contradictory regulatory settings between them. Usage of flag is
 | 
				
			||||||
 | 
					 *	generally discouraged. Only use it if the FW/driver is incompatible
 | 
				
			||||||
 | 
					 *	with non-locally originated hints.
 | 
				
			||||||
 | 
					 *	This flag is incompatible with the flags: %REGULATORY_CUSTOM_REG,
 | 
				
			||||||
 | 
					 *	%REGULATORY_STRICT_REG, %REGULATORY_COUNTRY_IE_FOLLOW_POWER,
 | 
				
			||||||
 | 
					 *	%REGULATORY_COUNTRY_IE_IGNORE and %REGULATORY_DISABLE_BEACON_HINTS.
 | 
				
			||||||
 | 
					 *	Mixing any of the above flags with this flag will result in a failure
 | 
				
			||||||
 | 
					 *	to register the wiphy. This flag implies
 | 
				
			||||||
 | 
					 *	%REGULATORY_DISABLE_BEACON_HINTS and %REGULATORY_COUNTRY_IE_IGNORE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
enum ieee80211_regulatory_flags {
 | 
					enum ieee80211_regulatory_flags {
 | 
				
			||||||
	REGULATORY_CUSTOM_REG			= BIT(0),
 | 
						REGULATORY_CUSTOM_REG			= BIT(0),
 | 
				
			||||||
| 
						 | 
					@ -156,6 +174,7 @@ enum ieee80211_regulatory_flags {
 | 
				
			||||||
	REGULATORY_COUNTRY_IE_IGNORE		= BIT(4),
 | 
						REGULATORY_COUNTRY_IE_IGNORE		= BIT(4),
 | 
				
			||||||
	REGULATORY_ENABLE_RELAX_NO_IR           = BIT(5),
 | 
						REGULATORY_ENABLE_RELAX_NO_IR           = BIT(5),
 | 
				
			||||||
	REGULATORY_IGNORE_STALE_KICKOFF         = BIT(6),
 | 
						REGULATORY_IGNORE_STALE_KICKOFF         = BIT(6),
 | 
				
			||||||
 | 
						REGULATORY_WIPHY_SELF_MANAGED		= BIT(7),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ieee80211_freq_range {
 | 
					struct ieee80211_freq_range {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -782,6 +782,10 @@
 | 
				
			||||||
 *	peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel
 | 
					 *	peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel
 | 
				
			||||||
 *	when this command completes.
 | 
					 *	when this command completes.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * @NL80211_CMD_WIPHY_REG_CHANGE: Similar to %NL80211_CMD_REG_CHANGE, but used
 | 
				
			||||||
 | 
					 *	as an event to indicate changes for devices with wiphy-specific regdom
 | 
				
			||||||
 | 
					 *	management.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * @NL80211_CMD_MAX: highest used command number
 | 
					 * @NL80211_CMD_MAX: highest used command number
 | 
				
			||||||
 * @__NL80211_CMD_AFTER_LAST: internal use
 | 
					 * @__NL80211_CMD_AFTER_LAST: internal use
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -966,6 +970,8 @@ enum nl80211_commands {
 | 
				
			||||||
	NL80211_CMD_TDLS_CHANNEL_SWITCH,
 | 
						NL80211_CMD_TDLS_CHANNEL_SWITCH,
 | 
				
			||||||
	NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
 | 
						NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NL80211_CMD_WIPHY_REG_CHANGE,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* add new commands above here */
 | 
						/* add new commands above here */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* used to define NL80211_CMD_MAX below */
 | 
						/* used to define NL80211_CMD_MAX below */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -561,6 +561,14 @@ int wiphy_register(struct wiphy *wiphy)
 | 
				
			||||||
				       BIT(NL80211_IFTYPE_MONITOR)))
 | 
									       BIT(NL80211_IFTYPE_MONITOR)))
 | 
				
			||||||
		wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
 | 
							wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) &&
 | 
				
			||||||
 | 
							    (wiphy->regulatory_flags &
 | 
				
			||||||
 | 
										(REGULATORY_CUSTOM_REG |
 | 
				
			||||||
 | 
										 REGULATORY_STRICT_REG |
 | 
				
			||||||
 | 
										 REGULATORY_COUNTRY_IE_FOLLOW_POWER |
 | 
				
			||||||
 | 
										 REGULATORY_COUNTRY_IE_IGNORE))))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (WARN_ON(wiphy->coalesce &&
 | 
						if (WARN_ON(wiphy->coalesce &&
 | 
				
			||||||
		    (!wiphy->coalesce->n_rules ||
 | 
							    (!wiphy->coalesce->n_rules ||
 | 
				
			||||||
		     !wiphy->coalesce->n_patterns) &&
 | 
							     !wiphy->coalesce->n_patterns) &&
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,13 @@ struct cfg80211_registered_device {
 | 
				
			||||||
	 * the country on the country IE changed. */
 | 
						 * the country on the country IE changed. */
 | 
				
			||||||
	char country_ie_alpha2[2];
 | 
						char country_ie_alpha2[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * the driver requests the regulatory core to set this regulatory
 | 
				
			||||||
 | 
						 * domain as the wiphy's. Only used for %REGULATORY_WIPHY_SELF_MANAGED
 | 
				
			||||||
 | 
						 * devices using the regulatory_set_wiphy_regd() API
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						const struct ieee80211_regdomain *requested_regd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If a Country IE has been received this tells us the environment
 | 
						/* If a Country IE has been received this tells us the environment
 | 
				
			||||||
	 * which its telling us its in. This defaults to ENVIRON_ANY */
 | 
						 * which its telling us its in. This defaults to ENVIRON_ANY */
 | 
				
			||||||
	enum environment_cap env;
 | 
						enum environment_cap env;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11042,25 +11042,9 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
				NL80211_MCGRP_SCAN, GFP_KERNEL);
 | 
									NL80211_MCGRP_SCAN, GFP_KERNEL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
 | 
				
			||||||
 * This can happen on global regulatory changes or device specific settings
 | 
										  struct regulatory_request *request)
 | 
				
			||||||
 * based on custom world regulatory domains.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void nl80211_send_reg_change_event(struct regulatory_request *request)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sk_buff *msg;
 | 
					 | 
				
			||||||
	void *hdr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!msg)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE);
 | 
					 | 
				
			||||||
	if (!hdr) {
 | 
					 | 
				
			||||||
		nlmsg_free(msg);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Userspace can always count this one always being set */
 | 
						/* Userspace can always count this one always being set */
 | 
				
			||||||
	if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
 | 
						if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
 | 
				
			||||||
		goto nla_put_failure;
 | 
							goto nla_put_failure;
 | 
				
			||||||
| 
						 | 
					@ -11094,6 +11078,35 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
 | 
				
			||||||
			goto nla_put_failure;
 | 
								goto nla_put_failure;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					nla_put_failure:
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This can happen on global regulatory changes or device specific settings
 | 
				
			||||||
 | 
					 * based on custom regulatory domains.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
 | 
				
			||||||
 | 
									     struct regulatory_request *request)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sk_buff *msg;
 | 
				
			||||||
 | 
						void *hdr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!msg)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
 | 
				
			||||||
 | 
						if (!hdr) {
 | 
				
			||||||
 | 
							nlmsg_free(msg);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nl80211_reg_change_event_fill(msg, request) == false)
 | 
				
			||||||
 | 
							goto nla_put_failure;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	genlmsg_end(msg, hdr);
 | 
						genlmsg_end(msg, hdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,21 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
			     struct net_device *netdev, u32 cmd);
 | 
								     struct net_device *netdev, u32 cmd);
 | 
				
			||||||
void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 | 
					void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
				     struct net_device *netdev);
 | 
									     struct net_device *netdev);
 | 
				
			||||||
void nl80211_send_reg_change_event(struct regulatory_request *request);
 | 
					void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
 | 
				
			||||||
 | 
									     struct regulatory_request *request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					nl80211_send_reg_change_event(struct regulatory_request *request)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						nl80211_common_reg_change_event(NL80211_CMD_REG_CHANGE, request);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					nl80211_send_wiphy_reg_change_event(struct regulatory_request *request)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						nl80211_common_reg_change_event(NL80211_CMD_WIPHY_REG_CHANGE, request);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
 | 
					void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
			  struct net_device *netdev,
 | 
								  struct net_device *netdev,
 | 
				
			||||||
			  const u8 *buf, size_t len, gfp_t gfp);
 | 
								  const u8 *buf, size_t len, gfp_t gfp);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1307,6 +1307,9 @@ static bool ignore_reg_update(struct wiphy *wiphy,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct regulatory_request *lr = get_last_request();
 | 
						struct regulatory_request *lr = get_last_request();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!lr) {
 | 
						if (!lr) {
 | 
				
			||||||
		REG_DBG_PRINT("Ignoring regulatory request set by %s "
 | 
							REG_DBG_PRINT("Ignoring regulatory request set by %s "
 | 
				
			||||||
			      "since last_request is not set\n",
 | 
								      "since last_request is not set\n",
 | 
				
			||||||
| 
						 | 
					@ -2147,11 +2150,52 @@ static void reg_process_pending_beacon_hints(void)
 | 
				
			||||||
	spin_unlock_bh(®_pending_beacons_lock);
 | 
						spin_unlock_bh(®_pending_beacons_lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void reg_process_self_managed_hints(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cfg80211_registered_device *rdev;
 | 
				
			||||||
 | 
						struct wiphy *wiphy;
 | 
				
			||||||
 | 
						const struct ieee80211_regdomain *tmp;
 | 
				
			||||||
 | 
						const struct ieee80211_regdomain *regd;
 | 
				
			||||||
 | 
						enum ieee80211_band band;
 | 
				
			||||||
 | 
						struct regulatory_request request = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
 | 
				
			||||||
 | 
							wiphy = &rdev->wiphy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							spin_lock(®_requests_lock);
 | 
				
			||||||
 | 
							regd = rdev->requested_regd;
 | 
				
			||||||
 | 
							rdev->requested_regd = NULL;
 | 
				
			||||||
 | 
							spin_unlock(®_requests_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (regd == NULL)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tmp = get_wiphy_regdom(wiphy);
 | 
				
			||||||
 | 
							rcu_assign_pointer(wiphy->regd, regd);
 | 
				
			||||||
 | 
							rcu_free_regdom(tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (band = 0; band < IEEE80211_NUM_BANDS; band++)
 | 
				
			||||||
 | 
								handle_band_custom(wiphy, wiphy->bands[band], regd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							reg_process_ht_flags(wiphy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							request.wiphy_idx = get_wiphy_idx(wiphy);
 | 
				
			||||||
 | 
							request.alpha2[0] = regd->alpha2[0];
 | 
				
			||||||
 | 
							request.alpha2[1] = regd->alpha2[1];
 | 
				
			||||||
 | 
							request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							nl80211_send_wiphy_reg_change_event(&request);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg_check_channels();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void reg_todo(struct work_struct *work)
 | 
					static void reg_todo(struct work_struct *work)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	rtnl_lock();
 | 
						rtnl_lock();
 | 
				
			||||||
	reg_process_pending_hints();
 | 
						reg_process_pending_hints();
 | 
				
			||||||
	reg_process_pending_beacon_hints();
 | 
						reg_process_pending_beacon_hints();
 | 
				
			||||||
 | 
						reg_process_self_managed_hints();
 | 
				
			||||||
	rtnl_unlock();
 | 
						rtnl_unlock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2432,6 +2476,8 @@ static void restore_regulatory_settings(bool reset_user)
 | 
				
			||||||
	world_alpha2[1] = cfg80211_world_regdom->alpha2[1];
 | 
						world_alpha2[1] = cfg80211_world_regdom->alpha2[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
 | 
						list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
 | 
				
			||||||
 | 
							if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
		if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG)
 | 
							if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG)
 | 
				
			||||||
			restore_custom_reg_settings(&rdev->wiphy);
 | 
								restore_custom_reg_settings(&rdev->wiphy);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -2835,10 +2881,52 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int regulatory_set_wiphy_regd(struct wiphy *wiphy,
 | 
				
			||||||
 | 
								      struct ieee80211_regdomain *rd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct ieee80211_regdomain *regd;
 | 
				
			||||||
 | 
						const struct ieee80211_regdomain *prev_regd;
 | 
				
			||||||
 | 
						struct cfg80211_registered_device *rdev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(!wiphy || !rd))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN(!(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED),
 | 
				
			||||||
 | 
							 "wiphy should have REGULATORY_WIPHY_SELF_MANAGED\n"))
 | 
				
			||||||
 | 
							return -EPERM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN(!is_valid_rd(rd), "Invalid regulatory domain detected\n")) {
 | 
				
			||||||
 | 
							print_regdomain_info(rd);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						regd = reg_copy_regd(rd);
 | 
				
			||||||
 | 
						if (IS_ERR(regd))
 | 
				
			||||||
 | 
							return PTR_ERR(regd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rdev = wiphy_to_rdev(wiphy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock(®_requests_lock);
 | 
				
			||||||
 | 
						prev_regd = rdev->requested_regd;
 | 
				
			||||||
 | 
						rdev->requested_regd = regd;
 | 
				
			||||||
 | 
						spin_unlock(®_requests_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(prev_regd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						schedule_work(®_work);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(regulatory_set_wiphy_regd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wiphy_regulatory_register(struct wiphy *wiphy)
 | 
					void wiphy_regulatory_register(struct wiphy *wiphy)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct regulatory_request *lr;
 | 
						struct regulatory_request *lr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* self-managed devices ignore external hints */
 | 
				
			||||||
 | 
						if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
 | 
				
			||||||
 | 
							wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS |
 | 
				
			||||||
 | 
										   REGULATORY_COUNTRY_IE_IGNORE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!reg_dev_ignore_cell_hint(wiphy))
 | 
						if (!reg_dev_ignore_cell_hint(wiphy))
 | 
				
			||||||
		reg_num_devs_support_basehint++;
 | 
							reg_num_devs_support_basehint++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue