mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	cfg80211: add rfkill support
To be easier on drivers and users, have cfg80211 register an rfkill structure that drivers can access. When soft-killed, simply take down all interfaces; when hard-killed the driver needs to notify us and we will take down the interfaces after the fact. While rfkilled, interfaces cannot be set UP. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
		
							parent
							
								
									6081162e2e
								
							
						
					
					
						commit
						1f87f7d3a3
					
				
					 11 changed files with 172 additions and 30 deletions
				
			
		| 
						 | 
					@ -106,4 +106,6 @@
 | 
				
			||||||
#define	EOWNERDEAD	130	/* Owner died */
 | 
					#define	EOWNERDEAD	130	/* Owner died */
 | 
				
			||||||
#define	ENOTRECOVERABLE	131	/* State not recoverable */
 | 
					#define	ENOTRECOVERABLE	131	/* State not recoverable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ERFKILL		132	/* Operation not possible due to RF-kill */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -757,13 +757,11 @@ enum wiphy_params_flags {
 | 
				
			||||||
 * @TX_POWER_AUTOMATIC: the dbm parameter is ignored
 | 
					 * @TX_POWER_AUTOMATIC: the dbm parameter is ignored
 | 
				
			||||||
 * @TX_POWER_LIMITED: limit TX power by the dbm parameter
 | 
					 * @TX_POWER_LIMITED: limit TX power by the dbm parameter
 | 
				
			||||||
 * @TX_POWER_FIXED: fix TX power to the dbm parameter
 | 
					 * @TX_POWER_FIXED: fix TX power to the dbm parameter
 | 
				
			||||||
 * @TX_POWER_OFF: turn off completely (will go away)
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
enum tx_power_setting {
 | 
					enum tx_power_setting {
 | 
				
			||||||
	TX_POWER_AUTOMATIC,
 | 
						TX_POWER_AUTOMATIC,
 | 
				
			||||||
	TX_POWER_LIMITED,
 | 
						TX_POWER_LIMITED,
 | 
				
			||||||
	TX_POWER_FIXED,
 | 
						TX_POWER_FIXED,
 | 
				
			||||||
	TX_POWER_OFF,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -855,8 +853,10 @@ enum tx_power_setting {
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @set_tx_power: set the transmit power according to the parameters
 | 
					 * @set_tx_power: set the transmit power according to the parameters
 | 
				
			||||||
 * @get_tx_power: store the current TX power into the dbm variable;
 | 
					 * @get_tx_power: store the current TX power into the dbm variable;
 | 
				
			||||||
 *	return 0 if successful; or -ENETDOWN if successful but power
 | 
					 *	return 0 if successful
 | 
				
			||||||
 *	is disabled (this will go away)
 | 
					 *
 | 
				
			||||||
 | 
					 * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
 | 
				
			||||||
 | 
					 *	functions to adjust rfkill hw state
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct cfg80211_ops {
 | 
					struct cfg80211_ops {
 | 
				
			||||||
	int	(*suspend)(struct wiphy *wiphy);
 | 
						int	(*suspend)(struct wiphy *wiphy);
 | 
				
			||||||
| 
						 | 
					@ -952,6 +952,8 @@ struct cfg80211_ops {
 | 
				
			||||||
	int	(*set_tx_power)(struct wiphy *wiphy,
 | 
						int	(*set_tx_power)(struct wiphy *wiphy,
 | 
				
			||||||
				enum tx_power_setting type, int dbm);
 | 
									enum tx_power_setting type, int dbm);
 | 
				
			||||||
	int	(*get_tx_power)(struct wiphy *wiphy, int *dbm);
 | 
						int	(*get_tx_power)(struct wiphy *wiphy, int *dbm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void	(*rfkill_poll)(struct wiphy *wiphy);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1666,4 +1668,23 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
 | 
					void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * wiphy_rfkill_set_hw_state - notify cfg80211 about hw block state
 | 
				
			||||||
 | 
					 * @wiphy: the wiphy
 | 
				
			||||||
 | 
					 * @blocked: block status
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * wiphy_rfkill_start_polling - start polling rfkill
 | 
				
			||||||
 | 
					 * @wiphy: the wiphy
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wiphy_rfkill_start_polling(struct wiphy *wiphy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * wiphy_rfkill_stop_polling - stop polling rfkill
 | 
				
			||||||
 | 
					 * @wiphy: the wiphy
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __NET_CFG80211_H */
 | 
					#endif /* __NET_CFG80211_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -526,7 +526,7 @@ enum ieee80211_conf_flags {
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * enum ieee80211_conf_changed - denotes which configuration changed
 | 
					 * enum ieee80211_conf_changed - denotes which configuration changed
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed
 | 
					 * @_IEEE80211_CONF_CHANGE_RADIO_ENABLED: DEPRECATED
 | 
				
			||||||
 * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed
 | 
					 * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed
 | 
				
			||||||
 * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed
 | 
					 * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed
 | 
				
			||||||
 * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed
 | 
					 * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed
 | 
				
			||||||
| 
						 | 
					@ -536,7 +536,7 @@ enum ieee80211_conf_flags {
 | 
				
			||||||
 * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
 | 
					 * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
enum ieee80211_conf_changed {
 | 
					enum ieee80211_conf_changed {
 | 
				
			||||||
	IEEE80211_CONF_CHANGE_RADIO_ENABLED	= BIT(0),
 | 
						_IEEE80211_CONF_CHANGE_RADIO_ENABLED	= BIT(0),
 | 
				
			||||||
	IEEE80211_CONF_CHANGE_LISTEN_INTERVAL	= BIT(2),
 | 
						IEEE80211_CONF_CHANGE_LISTEN_INTERVAL	= BIT(2),
 | 
				
			||||||
	IEEE80211_CONF_CHANGE_RADIOTAP		= BIT(3),
 | 
						IEEE80211_CONF_CHANGE_RADIOTAP		= BIT(3),
 | 
				
			||||||
	IEEE80211_CONF_CHANGE_PS		= BIT(4),
 | 
						IEEE80211_CONF_CHANGE_PS		= BIT(4),
 | 
				
			||||||
| 
						 | 
					@ -546,6 +546,14 @@ enum ieee80211_conf_changed {
 | 
				
			||||||
	IEEE80211_CONF_CHANGE_IDLE		= BIT(8),
 | 
						IEEE80211_CONF_CHANGE_IDLE		= BIT(8),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline __deprecated enum ieee80211_conf_changed
 | 
				
			||||||
 | 
					__IEEE80211_CONF_CHANGE_RADIO_ENABLED(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return _IEEE80211_CONF_CHANGE_RADIO_ENABLED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#define IEEE80211_CONF_CHANGE_RADIO_ENABLED \
 | 
				
			||||||
 | 
						__IEEE80211_CONF_CHANGE_RADIO_ENABLED()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct ieee80211_conf - configuration of the device
 | 
					 * struct ieee80211_conf - configuration of the device
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -585,7 +593,7 @@ struct ieee80211_conf {
 | 
				
			||||||
	int max_sleep_period;
 | 
						int max_sleep_period;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u16 listen_interval;
 | 
						u16 listen_interval;
 | 
				
			||||||
	bool radio_enabled;
 | 
						bool __deprecated radio_enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u8 long_frame_max_tx_count, short_frame_max_tx_count;
 | 
						u8 long_frame_max_tx_count, short_frame_max_tx_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1396,6 +1404,10 @@ enum ieee80211_ampdu_mlme_action {
 | 
				
			||||||
 * 	is the first frame we expect to perform the action on. Notice
 | 
					 * 	is the first frame we expect to perform the action on. Notice
 | 
				
			||||||
 * 	that TX/RX_STOP can pass NULL for this parameter.
 | 
					 * 	that TX/RX_STOP can pass NULL for this parameter.
 | 
				
			||||||
 *	Returns a negative error code on failure.
 | 
					 *	Returns a negative error code on failure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
 | 
				
			||||||
 | 
					 *	need to set wiphy->rfkill_poll to %true before registration,
 | 
				
			||||||
 | 
					 *	and need to call wiphy_rfkill_set_hw_state() in the callback.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct ieee80211_ops {
 | 
					struct ieee80211_ops {
 | 
				
			||||||
	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
 | 
						int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
 | 
				
			||||||
| 
						 | 
					@ -1444,6 +1456,8 @@ struct ieee80211_ops {
 | 
				
			||||||
	int (*ampdu_action)(struct ieee80211_hw *hw,
 | 
						int (*ampdu_action)(struct ieee80211_hw *hw,
 | 
				
			||||||
			    enum ieee80211_ampdu_mlme_action action,
 | 
								    enum ieee80211_ampdu_mlme_action action,
 | 
				
			||||||
			    struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 | 
								    struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void (*rfkill_poll)(struct ieee80211_hw *hw);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1340,7 +1340,6 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
 | 
				
			||||||
	struct ieee80211_local *local = wiphy_priv(wiphy);
 | 
						struct ieee80211_local *local = wiphy_priv(wiphy);
 | 
				
			||||||
	struct ieee80211_channel *chan = local->hw.conf.channel;
 | 
						struct ieee80211_channel *chan = local->hw.conf.channel;
 | 
				
			||||||
	u32 changes = 0;
 | 
						u32 changes = 0;
 | 
				
			||||||
	bool radio_enabled = true;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (type) {
 | 
						switch (type) {
 | 
				
			||||||
	case TX_POWER_AUTOMATIC:
 | 
						case TX_POWER_AUTOMATIC:
 | 
				
			||||||
| 
						 | 
					@ -1359,14 +1358,6 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		local->user_power_level = dbm;
 | 
							local->user_power_level = dbm;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case TX_POWER_OFF:
 | 
					 | 
				
			||||||
		radio_enabled = false;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (radio_enabled != local->hw.conf.radio_enabled) {
 | 
					 | 
				
			||||||
		changes |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
 | 
					 | 
				
			||||||
		local->hw.conf.radio_enabled = radio_enabled;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ieee80211_hw_config(local, changes);
 | 
						ieee80211_hw_config(local, changes);
 | 
				
			||||||
| 
						 | 
					@ -1380,12 +1371,16 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*dbm = local->hw.conf.power_level;
 | 
						*dbm = local->hw.conf.power_level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!local->hw.conf.radio_enabled)
 | 
					 | 
				
			||||||
		return -ENETDOWN;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ieee80211_rfkill_poll(struct wiphy *wiphy)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ieee80211_local *local = wiphy_priv(wiphy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						drv_rfkill_poll(local);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cfg80211_ops mac80211_config_ops = {
 | 
					struct cfg80211_ops mac80211_config_ops = {
 | 
				
			||||||
	.add_virtual_intf = ieee80211_add_iface,
 | 
						.add_virtual_intf = ieee80211_add_iface,
 | 
				
			||||||
	.del_virtual_intf = ieee80211_del_iface,
 | 
						.del_virtual_intf = ieee80211_del_iface,
 | 
				
			||||||
| 
						 | 
					@ -1427,4 +1422,5 @@ struct cfg80211_ops mac80211_config_ops = {
 | 
				
			||||||
	.set_wiphy_params = ieee80211_set_wiphy_params,
 | 
						.set_wiphy_params = ieee80211_set_wiphy_params,
 | 
				
			||||||
	.set_tx_power = ieee80211_set_tx_power,
 | 
						.set_tx_power = ieee80211_set_tx_power,
 | 
				
			||||||
	.get_tx_power = ieee80211_get_tx_power,
 | 
						.get_tx_power = ieee80211_get_tx_power,
 | 
				
			||||||
 | 
						.rfkill_poll = ieee80211_rfkill_poll,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -181,4 +181,11 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
 | 
				
			||||||
						sta, tid, ssn);
 | 
											sta, tid, ssn);
 | 
				
			||||||
	return -EOPNOTSUPP;
 | 
						return -EOPNOTSUPP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void drv_rfkill_poll(struct ieee80211_local *local)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (local->ops->rfkill_poll)
 | 
				
			||||||
 | 
							local->ops->rfkill_poll(&local->hw);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#endif /* __MAC80211_DRIVER_OPS */
 | 
					#endif /* __MAC80211_DRIVER_OPS */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,7 +170,7 @@ static int ieee80211_open(struct net_device *dev)
 | 
				
			||||||
			goto err_del_bss;
 | 
								goto err_del_bss;
 | 
				
			||||||
		/* we're brought up, everything changes */
 | 
							/* we're brought up, everything changes */
 | 
				
			||||||
		hw_reconf_flags = ~0;
 | 
							hw_reconf_flags = ~0;
 | 
				
			||||||
		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
 | 
							ieee80211_led_radio(local, true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -560,7 +560,7 @@ static int ieee80211_stop(struct net_device *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		drv_stop(local);
 | 
							drv_stop(local);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ieee80211_led_radio(local, 0);
 | 
							ieee80211_led_radio(local, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		flush_workqueue(local->hw.workqueue);
 | 
							flush_workqueue(local->hw.workqueue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -973,7 +973,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 | 
				
			||||||
	if (local->open_count) {
 | 
						if (local->open_count) {
 | 
				
			||||||
		res = drv_start(local);
 | 
							res = drv_start(local);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ieee80211_led_radio(local, hw->conf.radio_enabled);
 | 
							ieee80211_led_radio(local, true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* add interfaces */
 | 
						/* add interfaces */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
config CFG80211
 | 
					config CFG80211
 | 
				
			||||||
	tristate "Improved wireless configuration API"
 | 
						tristate "Improved wireless configuration API"
 | 
				
			||||||
 | 
						depends on RFKILL || !RFKILL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config CFG80211_REG_DEBUG
 | 
					config CFG80211_REG_DEBUG
 | 
				
			||||||
	bool "cfg80211 regulatory debugging"
 | 
						bool "cfg80211 regulatory debugging"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include <linux/debugfs.h>
 | 
					#include <linux/debugfs.h>
 | 
				
			||||||
#include <linux/notifier.h>
 | 
					#include <linux/notifier.h>
 | 
				
			||||||
#include <linux/device.h>
 | 
					#include <linux/device.h>
 | 
				
			||||||
 | 
					#include <linux/rtnetlink.h>
 | 
				
			||||||
#include <net/genetlink.h>
 | 
					#include <net/genetlink.h>
 | 
				
			||||||
#include <net/cfg80211.h>
 | 
					#include <net/cfg80211.h>
 | 
				
			||||||
#include "nl80211.h"
 | 
					#include "nl80211.h"
 | 
				
			||||||
| 
						 | 
					@ -227,6 +228,41 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cfg80211_registered_device *drv = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						drv->ops->rfkill_poll(&drv->wiphy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int cfg80211_rfkill_set_block(void *data, bool blocked)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cfg80211_registered_device *drv = data;
 | 
				
			||||||
 | 
						struct wireless_dev *wdev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!blocked)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtnl_lock();
 | 
				
			||||||
 | 
						mutex_lock(&drv->devlist_mtx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry(wdev, &drv->netdev_list, list)
 | 
				
			||||||
 | 
							dev_close(wdev->netdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&drv->devlist_mtx);
 | 
				
			||||||
 | 
						rtnl_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cfg80211_rfkill_sync_work(struct work_struct *work)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cfg80211_registered_device *drv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						drv = container_of(work, struct cfg80211_registered_device, rfkill_sync);
 | 
				
			||||||
 | 
						cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* exported functions */
 | 
					/* exported functions */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 | 
					struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 | 
				
			||||||
| 
						 | 
					@ -274,6 +310,18 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 | 
				
			||||||
	drv->wiphy.dev.class = &ieee80211_class;
 | 
						drv->wiphy.dev.class = &ieee80211_class;
 | 
				
			||||||
	drv->wiphy.dev.platform_data = drv;
 | 
						drv->wiphy.dev.platform_data = drv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						drv->rfkill_ops.set_block = cfg80211_rfkill_set_block;
 | 
				
			||||||
 | 
						drv->rfkill = rfkill_alloc(dev_name(&drv->wiphy.dev),
 | 
				
			||||||
 | 
									   &drv->wiphy.dev, RFKILL_TYPE_WLAN,
 | 
				
			||||||
 | 
									   &drv->rfkill_ops, drv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!drv->rfkill) {
 | 
				
			||||||
 | 
							kfree(drv);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
 | 
						 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
 | 
				
			||||||
	 * Fragmentation and RTS threshold are disabled by default with the
 | 
						 * Fragmentation and RTS threshold are disabled by default with the
 | 
				
			||||||
| 
						 | 
					@ -356,6 +404,10 @@ int wiphy_register(struct wiphy *wiphy)
 | 
				
			||||||
	if (res)
 | 
						if (res)
 | 
				
			||||||
		goto out_unlock;
 | 
							goto out_unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res = rfkill_register(drv->rfkill);
 | 
				
			||||||
 | 
						if (res)
 | 
				
			||||||
 | 
							goto out_rm_dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_add(&drv->list, &cfg80211_drv_list);
 | 
						list_add(&drv->list, &cfg80211_drv_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* add to debugfs */
 | 
						/* add to debugfs */
 | 
				
			||||||
| 
						 | 
					@ -379,16 +431,41 @@ int wiphy_register(struct wiphy *wiphy)
 | 
				
			||||||
	cfg80211_debugfs_drv_add(drv);
 | 
						cfg80211_debugfs_drv_add(drv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = 0;
 | 
						res = 0;
 | 
				
			||||||
out_unlock:
 | 
						goto out_unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 out_rm_dev:
 | 
				
			||||||
 | 
						device_del(&drv->wiphy.dev);
 | 
				
			||||||
 | 
					 out_unlock:
 | 
				
			||||||
	mutex_unlock(&cfg80211_mutex);
 | 
						mutex_unlock(&cfg80211_mutex);
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(wiphy_register);
 | 
					EXPORT_SYMBOL(wiphy_register);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wiphy_rfkill_start_polling(struct wiphy *wiphy)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!drv->ops->rfkill_poll)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						drv->rfkill_ops.poll = cfg80211_rfkill_poll;
 | 
				
			||||||
 | 
						rfkill_resume_polling(drv->rfkill);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(wiphy_rfkill_start_polling);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rfkill_pause_polling(drv->rfkill);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wiphy_unregister(struct wiphy *wiphy)
 | 
					void wiphy_unregister(struct wiphy *wiphy)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
 | 
						struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rfkill_unregister(drv->rfkill);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* protect the device list */
 | 
						/* protect the device list */
 | 
				
			||||||
	mutex_lock(&cfg80211_mutex);
 | 
						mutex_lock(&cfg80211_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -425,6 +502,7 @@ EXPORT_SYMBOL(wiphy_unregister);
 | 
				
			||||||
void cfg80211_dev_free(struct cfg80211_registered_device *drv)
 | 
					void cfg80211_dev_free(struct cfg80211_registered_device *drv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cfg80211_internal_bss *scan, *tmp;
 | 
						struct cfg80211_internal_bss *scan, *tmp;
 | 
				
			||||||
 | 
						rfkill_destroy(drv->rfkill);
 | 
				
			||||||
	mutex_destroy(&drv->mtx);
 | 
						mutex_destroy(&drv->mtx);
 | 
				
			||||||
	mutex_destroy(&drv->devlist_mtx);
 | 
						mutex_destroy(&drv->devlist_mtx);
 | 
				
			||||||
	list_for_each_entry_safe(scan, tmp, &drv->bss_list, list)
 | 
						list_for_each_entry_safe(scan, tmp, &drv->bss_list, list)
 | 
				
			||||||
| 
						 | 
					@ -438,6 +516,15 @@ void wiphy_free(struct wiphy *wiphy)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(wiphy_free);
 | 
					EXPORT_SYMBOL(wiphy_free);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rfkill_set_hw_state(drv->rfkill, blocked))
 | 
				
			||||||
 | 
							schedule_work(&drv->rfkill_sync);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 | 
					static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 | 
				
			||||||
					 unsigned long state,
 | 
										 unsigned long state,
 | 
				
			||||||
					 void *ndev)
 | 
										 void *ndev)
 | 
				
			||||||
| 
						 | 
					@ -446,7 +533,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 | 
				
			||||||
	struct cfg80211_registered_device *rdev;
 | 
						struct cfg80211_registered_device *rdev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dev->ieee80211_ptr)
 | 
						if (!dev->ieee80211_ptr)
 | 
				
			||||||
		return 0;
 | 
							return NOTIFY_DONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
 | 
						rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -492,9 +579,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		mutex_unlock(&rdev->devlist_mtx);
 | 
							mutex_unlock(&rdev->devlist_mtx);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case NETDEV_PRE_UP:
 | 
				
			||||||
 | 
							if (rfkill_blocked(rdev->rfkill))
 | 
				
			||||||
 | 
								return notifier_from_errno(-ERFKILL);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return NOTIFY_DONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct notifier_block cfg80211_netdev_notifier = {
 | 
					static struct notifier_block cfg80211_netdev_notifier = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,8 @@
 | 
				
			||||||
#include <linux/kref.h>
 | 
					#include <linux/kref.h>
 | 
				
			||||||
#include <linux/rbtree.h>
 | 
					#include <linux/rbtree.h>
 | 
				
			||||||
#include <linux/debugfs.h>
 | 
					#include <linux/debugfs.h>
 | 
				
			||||||
 | 
					#include <linux/rfkill.h>
 | 
				
			||||||
 | 
					#include <linux/workqueue.h>
 | 
				
			||||||
#include <net/genetlink.h>
 | 
					#include <net/genetlink.h>
 | 
				
			||||||
#include <net/cfg80211.h>
 | 
					#include <net/cfg80211.h>
 | 
				
			||||||
#include "reg.h"
 | 
					#include "reg.h"
 | 
				
			||||||
| 
						 | 
					@ -24,6 +26,11 @@ struct cfg80211_registered_device {
 | 
				
			||||||
	 * any call is in progress */
 | 
						 * any call is in progress */
 | 
				
			||||||
	struct mutex mtx;
 | 
						struct mutex mtx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* rfkill support */
 | 
				
			||||||
 | 
						struct rfkill_ops rfkill_ops;
 | 
				
			||||||
 | 
						struct rfkill *rfkill;
 | 
				
			||||||
 | 
						struct work_struct rfkill_sync;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* ISO / IEC 3166 alpha2 for which this device is receiving
 | 
						/* ISO / IEC 3166 alpha2 for which this device is receiving
 | 
				
			||||||
	 * country IEs on, this can help disregard country IEs from APs
 | 
						 * country IEs on, this can help disregard country IEs from APs
 | 
				
			||||||
	 * on the same alpha2 quickly. The alpha2 may differ from
 | 
						 * on the same alpha2 quickly. The alpha2 may differ from
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -764,6 +764,8 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* only change when not disabling */
 | 
						/* only change when not disabling */
 | 
				
			||||||
	if (!data->txpower.disabled) {
 | 
						if (!data->txpower.disabled) {
 | 
				
			||||||
 | 
							rfkill_set_sw_state(rdev->rfkill, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (data->txpower.fixed) {
 | 
							if (data->txpower.fixed) {
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * wext doesn't support negative values, see
 | 
								 * wext doesn't support negative values, see
 | 
				
			||||||
| 
						 | 
					@ -787,7 +789,9 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		type = TX_POWER_OFF;
 | 
							rfkill_set_sw_state(rdev->rfkill, true);
 | 
				
			||||||
 | 
							schedule_work(&rdev->rfkill_sync);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);;
 | 
						return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);;
 | 
				
			||||||
| 
						 | 
					@ -811,13 +815,12 @@ int cfg80211_wext_giwtxpower(struct net_device *dev,
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = rdev->ops->get_tx_power(wdev->wiphy, &val);
 | 
						err = rdev->ops->get_tx_power(wdev->wiphy, &val);
 | 
				
			||||||
	/* HACK!!! */
 | 
						if (err)
 | 
				
			||||||
	if (err && err != -ENETDOWN)
 | 
					 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* well... oh well */
 | 
						/* well... oh well */
 | 
				
			||||||
	data->txpower.fixed = 1;
 | 
						data->txpower.fixed = 1;
 | 
				
			||||||
	data->txpower.disabled = err == -ENETDOWN;
 | 
						data->txpower.disabled = rfkill_blocked(rdev->rfkill);
 | 
				
			||||||
	data->txpower.value = val;
 | 
						data->txpower.value = val;
 | 
				
			||||||
	data->txpower.flags = IW_TXPOW_DBM;
 | 
						data->txpower.flags = IW_TXPOW_DBM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue