Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Conflicts:
	net/mac80211/chan.c
This commit is contained in:
John W. Linville 2014-04-30 12:04:27 -04:00
commit f6595444c1
62 changed files with 2061 additions and 892 deletions

View file

@ -100,6 +100,7 @@
!Finclude/net/cfg80211.h wdev_priv
!Finclude/net/cfg80211.h ieee80211_iface_limit
!Finclude/net/cfg80211.h ieee80211_iface_combination
!Finclude/net/cfg80211.h cfg80211_check_combinations
</chapter>
<chapter>
<title>Actions and configuration</title>

View file

@ -1090,7 +1090,8 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return ret;
}
static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
static void ar5523_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct ar5523 *ar = hw->priv;

View file

@ -3635,7 +3635,8 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
return ret;
}
static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct ath10k *ar = hw->priv;
bool skip;

View file

@ -1989,7 +1989,8 @@ static bool ath9k_has_tx_pending(struct ath_softc *sc)
return !!npend;
}
static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;

View file

@ -1707,7 +1707,9 @@ found:
return 0;
}
static void carl9170_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
static void carl9170_op_flush(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct ar9170 *ar = hw->priv;
unsigned int vid;

View file

@ -897,7 +897,8 @@ static bool brcms_tx_flush_completed(struct brcms_info *wl)
return result;
}
static void brcms_ops_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
static void brcms_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct brcms_info *wl = hw->priv;
int ret;

View file

@ -936,7 +936,8 @@ static int __cw1200_flush(struct cw1200_common *priv, bool drop)
return ret;
}
void cw1200_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
void cw1200_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct cw1200_common *priv = hw->priv;

View file

@ -40,7 +40,8 @@ int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
void cw1200_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
void cw1200_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
u64 cw1200_prepare_multicast(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list);

View file

@ -4755,7 +4755,8 @@ out:
}
EXPORT_SYMBOL(il_mac_change_interface);
void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
void il_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct il_priv *il = hw->priv;
unsigned long timeout = jiffies + msecs_to_jiffies(500);

View file

@ -1723,7 +1723,8 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum nl80211_iftype newtype, bool newp2p);
void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
void il_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
int il_alloc_txq_mem(struct il_priv *il);
void il_free_txq_mem(struct il_priv *il);

View file

@ -1091,7 +1091,8 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);

View file

@ -1676,7 +1676,9 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
return 0;
}
static void mac80211_hwsim_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
static void mac80211_hwsim_flush(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u32 queues, bool drop)
{
/* Not implemented, queues only on kernel side */
}
@ -2056,6 +2058,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_HAS_CHANNEL_SWITCH;
hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);

View file

@ -669,7 +669,8 @@ static unsigned int p54_flush_count(struct p54_common *priv)
return total;
}
static void p54_flush(struct ieee80211_hw *dev, u32 queues, bool drop)
static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct p54_common *priv = dev->priv;
unsigned int total, i;

View file

@ -1448,7 +1448,8 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,

View file

@ -747,7 +747,8 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;

View file

@ -1387,7 +1387,8 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
* before switch channel or power save, or tx buffer packet
* maybe send after offchannel or rf sleep, this may cause
* dis-association by AP */
static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
static void rtl_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);

View file

@ -5184,7 +5184,8 @@ out:
mutex_unlock(&wl->mutex);
}
static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
static void wlcore_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct wl1271 *wl = hw->priv;

View file

@ -1414,23 +1414,15 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
* before switch channel or power save, or tx buffer packet
* maybe send after offchannel or rf sleep, this may cause
* dis-association by AP */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
static void rtl_op_flush(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
if (rtlpriv->intf_ops->flush)
rtlpriv->intf_ops->flush(hw, queues, drop);
}
#else
static void rtl_op_flush(struct ieee80211_hw *hw, bool drop)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
if (rtlpriv->intf_ops->flush)
rtlpriv->intf_ops->flush(hw, drop);
}
#endif
const struct ieee80211_ops rtl_ops = {
.start = rtl_op_start,

View file

@ -109,6 +109,13 @@ enum ieee80211_band {
* channel as the control or any of the secondary channels.
* This may be due to the driver or due to regulatory bandwidth
* restrictions.
* @IEEE80211_CHAN_INDOOR_ONLY: see %NL80211_FREQUENCY_ATTR_INDOOR_ONLY
* @IEEE80211_CHAN_GO_CONCURRENT: see %NL80211_FREQUENCY_ATTR_GO_CONCURRENT
* @IEEE80211_CHAN_NO_20MHZ: 20 MHz bandwidth is not permitted
* on this channel.
* @IEEE80211_CHAN_NO_10MHZ: 10 MHz bandwidth is not permitted
* on this channel.
*
*/
enum ieee80211_channel_flags {
IEEE80211_CHAN_DISABLED = 1<<0,
@ -120,6 +127,10 @@ enum ieee80211_channel_flags {
IEEE80211_CHAN_NO_OFDM = 1<<6,
IEEE80211_CHAN_NO_80MHZ = 1<<7,
IEEE80211_CHAN_NO_160MHZ = 1<<8,
IEEE80211_CHAN_INDOOR_ONLY = 1<<9,
IEEE80211_CHAN_GO_CONCURRENT = 1<<10,
IEEE80211_CHAN_NO_20MHZ = 1<<11,
IEEE80211_CHAN_NO_10MHZ = 1<<12,
};
#define IEEE80211_CHAN_NO_HT40 \
@ -441,10 +452,13 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
* cfg80211_chandef_dfs_required - checks if radar detection is required
* @wiphy: the wiphy to validate against
* @chandef: the channel definition to check
* Return: 1 if radar detection is required, 0 if it is not, < 0 on error
* @iftype: the interface type as specified in &enum nl80211_iftype
* Returns:
* 1 if radar detection is required, 0 if it is not, < 0 on error
*/
int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef);
const struct cfg80211_chan_def *chandef,
enum nl80211_iftype);
/**
* ieee80211_chandef_rate_flags - returns rate flags for a channel
@ -654,7 +668,6 @@ struct cfg80211_acl_data {
* @p2p_opp_ps: P2P opportunistic PS
* @acl: ACL configuration used by the drivers which has support for
* MAC address based access control
* @radar_required: set if radar detection is required
*/
struct cfg80211_ap_settings {
struct cfg80211_chan_def chandef;
@ -672,7 +685,6 @@ struct cfg80211_ap_settings {
u8 p2p_ctwindow;
bool p2p_opp_ps;
const struct cfg80211_acl_data *acl;
bool radar_required;
};
/**
@ -2278,6 +2290,10 @@ struct cfg80211_qos_map {
* @channel_switch: initiate channel-switch procedure (with CSA)
*
* @set_qos_map: Set QoS mapping information to the driver
*
* @set_ap_chanwidth: Set the AP (including P2P GO) mode channel width for the
* given interface This is used e.g. for dynamic HT 20/40 MHz channel width
* changes during the lifetime of the BSS.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@ -2521,9 +2537,13 @@ struct cfg80211_ops {
int (*channel_switch)(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_csa_settings *params);
int (*set_qos_map)(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_qos_map *qos_map);
int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef);
};
/*
@ -3194,6 +3214,7 @@ struct cfg80211_cached_keys;
* @ibss_dfs_possible: (private) IBSS may change to a DFS channel
* @event_list: (private) list for internal event processing
* @event_lock: (private) lock for event list
* @owner_nlportid: (private) owner socket port ID
*/
struct wireless_dev {
struct wiphy *wiphy;
@ -3241,6 +3262,8 @@ struct wireless_dev {
unsigned long cac_start_time;
unsigned int cac_time_ms;
u32 owner_nlportid;
#ifdef CONFIG_CFG80211_WEXT
/* wext data */
struct {
@ -3600,7 +3623,7 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
* default channel settings will be disregarded. If no rule is found for a
* channel on the regulatory domain the channel will be disabled.
* Drivers using this for a wiphy should also set the wiphy flag
* WIPHY_FLAG_CUSTOM_REGULATORY or cfg80211 will set it for the wiphy
* REGULATORY_CUSTOM_REG or cfg80211 will set it for the wiphy
* that called this helper.
*/
void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
@ -4531,12 +4554,14 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
* cfg80211_reg_can_beacon - check if beaconing is allowed
* @wiphy: the wiphy
* @chandef: the channel definition
* @iftype: interface type
*
* Return: %true if there is no secondary channel or the secondary channel(s)
* can be used for beaconing (i.e. is not a radar channel etc.)
*/
bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef);
struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype);
/*
* cfg80211_ch_switch_notify - update wdev channel and notify userspace
@ -4682,6 +4707,55 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp);
*/
unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
/**
* cfg80211_check_combinations - check interface combinations
*
* @wiphy: the wiphy
* @num_different_channels: the number of different channels we want
* to use for verification
* @radar_detect: a bitmap where each bit corresponds to a channel
* width where radar detection is needed, as in the definition of
* &struct ieee80211_iface_combination.@radar_detect_widths
* @iftype_num: array with the numbers of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
*
* This function can be called by the driver to check whether a
* combination of interfaces and their types are allowed according to
* the interface combinations.
*/
int cfg80211_check_combinations(struct wiphy *wiphy,
const int num_different_channels,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES]);
/**
* cfg80211_iter_combinations - iterate over matching combinations
*
* @wiphy: the wiphy
* @num_different_channels: the number of different channels we want
* to use for verification
* @radar_detect: a bitmap where each bit corresponds to a channel
* width where radar detection is needed, as in the definition of
* &struct ieee80211_iface_combination.@radar_detect_widths
* @iftype_num: array with the numbers of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
* @iter: function to call for each matching combination
* @data: pointer to pass to iter function
*
* This function can be called by the driver to check what possible
* combinations it fits in at a given moment, e.g. for channel switching
* purposes.
*/
int cfg80211_iter_combinations(struct wiphy *wiphy,
const int num_different_channels,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES],
void (*iter)(const struct ieee80211_iface_combination *c,
void *data),
void *data);
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */

View file

@ -1202,14 +1202,18 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
* fall back to software crypto. Note that this flag deals only with
* RX, if your crypto engine can't deal with TX you can also set the
* %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW.
* @IEEE80211_KEY_FLAG_GENERATE_IV_MGMT: This flag should be set by the
* driver for a CCMP key to indicate that is requires IV generation
* only for managment frames (MFP).
*/
enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1,
IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
IEEE80211_KEY_FLAG_PAIRWISE = 1<<3,
IEEE80211_KEY_FLAG_SW_MGMT_TX = 1<<4,
IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5,
IEEE80211_KEY_FLAG_RX_MGMT = 1<<6,
IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0),
IEEE80211_KEY_FLAG_GENERATE_IV = BIT(1),
IEEE80211_KEY_FLAG_GENERATE_MMIC = BIT(2),
IEEE80211_KEY_FLAG_PAIRWISE = BIT(3),
IEEE80211_KEY_FLAG_SW_MGMT_TX = BIT(4),
IEEE80211_KEY_FLAG_PUT_IV_SPACE = BIT(5),
IEEE80211_KEY_FLAG_RX_MGMT = BIT(6),
};
/**
@ -1555,6 +1559,12 @@ struct ieee80211_tx_control {
* for a single active channel while using channel contexts. When support
* is not enabled the default action is to disconnect when getting the
* CSA frame.
*
* @IEEE80211_HW_CHANGE_RUNNING_CHANCTX: The hardware can change a
* channel context on-the-fly. This is needed for channel switch
* on single-channel hardware. It can also be used as an
* optimization in certain channel switch cases with
* multi-channel.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
@ -1586,6 +1596,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26,
IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27,
IEEE80211_HW_CHANCTX_STA_CSA = 1<<28,
IEEE80211_HW_CHANGE_RUNNING_CHANCTX = 1<<29,
};
/**
@ -2609,6 +2620,7 @@ enum ieee80211_roc_type {
* of queues to flush, which is useful if different virtual interfaces
* use different hardware queues; it may also indicate all queues.
* If the parameter @drop is set to %true, pending frames may be dropped.
* Note that vif can be NULL.
* The callback can sleep.
*
* @channel_switch: Drivers that need (or want) to offload the channel
@ -2871,7 +2883,8 @@ struct ieee80211_ops {
struct netlink_callback *cb,
void *data, int len);
#endif
void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop);
void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
void (*channel_switch)(struct ieee80211_hw *hw,
struct ieee80211_channel_switch *ch_switch);
int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
@ -4576,7 +4589,9 @@ conf_is_ht40(struct ieee80211_conf *conf)
static inline bool
conf_is_ht(struct ieee80211_conf *conf)
{
return conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
return (conf->chandef.width != NL80211_CHAN_WIDTH_5) &&
(conf->chandef.width != NL80211_CHAN_WIDTH_10) &&
(conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT);
}
static inline enum nl80211_iftype

View file

@ -131,6 +131,11 @@ struct regulatory_request {
* all country IE information processed by the regulatory core. This will
* override %REGULATORY_COUNTRY_IE_FOLLOW_POWER as all country IEs will
* be ignored.
* @REGULATORY_ENABLE_RELAX_NO_IR: for devices that wish to allow the
* NO_IR relaxation, which enables transmissions on channels on which
* otherwise initiating radiation is not allowed. This will enable the
* relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration
* option
*/
enum ieee80211_regulatory_flags {
REGULATORY_CUSTOM_REG = BIT(0),
@ -138,6 +143,7 @@ enum ieee80211_regulatory_flags {
REGULATORY_DISABLE_BEACON_HINTS = BIT(2),
REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3),
REGULATORY_COUNTRY_IE_IGNORE = BIT(4),
REGULATORY_ENABLE_RELAX_NO_IR = BIT(5),
};
struct ieee80211_freq_range {

View file

@ -1579,6 +1579,10 @@ enum nl80211_commands {
* @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
* As specified in the &enum nl80211_tdls_peer_capability.
*
* @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
* creation then the new interface will be owned by the netlink socket
* that created it and will be destroyed when the socket is closed
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@ -1914,6 +1918,8 @@ enum nl80211_attrs {
NL80211_ATTR_TDLS_PEER_CAPABILITY,
NL80211_ATTR_IFACE_SOCKET_OWNER,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -2336,9 +2342,34 @@ enum nl80211_band_attr {
* using this channel as the primary or any of the secondary channels
* isn't possible
* @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
* @NL80211_FREQUENCY_ATTR_INDOOR_ONLY: Only indoor use is permitted on this
* channel. A channel that has the INDOOR_ONLY attribute can only be
* used when there is a clear assessment that the device is operating in
* an indoor surroundings, i.e., it is connected to AC power (and not
* through portable DC inverters) or is under the control of a master
* that is acting as an AP and is connected to AC power.
* @NL80211_FREQUENCY_ATTR_GO_CONCURRENT: GO operation is allowed on this
* channel if it's connected concurrently to a BSS on the same channel on
* the 2 GHz band or to a channel in the same UNII band (on the 5 GHz
* band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO on a
* channel that has the GO_CONCURRENT attribute set can be done when there
* is a clear assessment that the device is operating under the guidance of
* an authorized master, i.e., setting up a GO while the device is also
* connected to an AP with DFS and radar detection on the UNII band (it is
* up to user-space, i.e., wpa_supplicant to perform the required
* verifications)
* @NL80211_FREQUENCY_ATTR_NO_20MHZ: 20 MHz operation is not allowed
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
*
* See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122
* for more information on the FCC description of the relaxations allowed
* by NL80211_FREQUENCY_ATTR_INDOOR_ONLY and
* NL80211_FREQUENCY_ATTR_GO_CONCURRENT.
*/
enum nl80211_frequency_attr {
__NL80211_FREQUENCY_ATTR_INVALID,
@ -2355,6 +2386,10 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_80MHZ,
NL80211_FREQUENCY_ATTR_NO_160MHZ,
NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
NL80211_FREQUENCY_ATTR_INDOOR_ONLY,
NL80211_FREQUENCY_ATTR_GO_CONCURRENT,
NL80211_FREQUENCY_ATTR_NO_20MHZ,
NL80211_FREQUENCY_ATTR_NO_10MHZ,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@ -2573,10 +2608,13 @@ enum nl80211_dfs_regions {
* present has been registered with the wireless core that
* has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
* supported feature.
* @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the
* platform is operating in an indoor environment.
*/
enum nl80211_user_reg_hint_type {
NL80211_USER_REG_HINT_USER = 0,
NL80211_USER_REG_HINT_CELL_BASE = 1,
NL80211_USER_REG_HINT_INDOOR = 2,
};
/**
@ -3891,6 +3929,9 @@ enum nl80211_ap_sme_features {
* interface. An active monitor interface behaves like a normal monitor
* interface, but gets added to the driver. It ensures that incoming
* unicast packets directed at the configured interface address get ACKed.
* @NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE: This driver supports dynamic
* channel bandwidth change (e.g., HT 20 <-> 40 MHz channel) during the
* lifetime of a BSS.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@ -3911,6 +3952,7 @@ enum nl80211_feature_flags {
NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17,
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE = 1 << 18,
};
/**

View file

@ -23,12 +23,13 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
u8 *data, size_t data_len, u8 *mic)
{
struct scatterlist assoc, pt, ct[2];
struct {
struct aead_request req;
u8 priv[crypto_aead_reqsize(tfm)];
} aead_req;
memset(&aead_req, 0, sizeof(aead_req));
char aead_req_data[sizeof(struct aead_request) +
crypto_aead_reqsize(tfm)]
__aligned(__alignof__(struct aead_request));
struct aead_request *aead_req = (void *) aead_req_data;
memset(aead_req, 0, sizeof(aead_req_data));
sg_init_one(&pt, data, data_len);
sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
@ -36,23 +37,23 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
sg_set_buf(&ct[0], data, data_len);
sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN);
aead_request_set_tfm(&aead_req.req, tfm);
aead_request_set_assoc(&aead_req.req, &assoc, assoc.length);
aead_request_set_crypt(&aead_req.req, &pt, ct, data_len, b_0);
aead_request_set_tfm(aead_req, tfm);
aead_request_set_assoc(aead_req, &assoc, assoc.length);
aead_request_set_crypt(aead_req, &pt, ct, data_len, b_0);
crypto_aead_encrypt(&aead_req.req);
crypto_aead_encrypt(aead_req);
}
int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
u8 *data, size_t data_len, u8 *mic)
{
struct scatterlist assoc, pt, ct[2];
struct {
struct aead_request req;
u8 priv[crypto_aead_reqsize(tfm)];
} aead_req;
char aead_req_data[sizeof(struct aead_request) +
crypto_aead_reqsize(tfm)]
__aligned(__alignof__(struct aead_request));
struct aead_request *aead_req = (void *) aead_req_data;
memset(&aead_req, 0, sizeof(aead_req));
memset(aead_req, 0, sizeof(aead_req_data));
sg_init_one(&pt, data, data_len);
sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
@ -60,12 +61,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
sg_set_buf(&ct[0], data, data_len);
sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN);
aead_request_set_tfm(&aead_req.req, tfm);
aead_request_set_assoc(&aead_req.req, &assoc, assoc.length);
aead_request_set_crypt(&aead_req.req, ct, &pt,
aead_request_set_tfm(aead_req, tfm);
aead_request_set_assoc(aead_req, &assoc, assoc.length);
aead_request_set_crypt(aead_req, ct, &pt,
data_len + IEEE80211_CCMP_MIC_LEN, b_0);
return crypto_aead_decrypt(&aead_req.req);
return crypto_aead_decrypt(aead_req);
}
struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[])

View file

@ -109,6 +109,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
static int ieee80211_start_p2p_device(struct wiphy *wiphy,
struct wireless_dev *wdev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
int ret;
mutex_lock(&sdata->local->chanctx_mtx);
ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
mutex_unlock(&sdata->local->chanctx_mtx);
if (ret < 0)
return ret;
return ieee80211_do_open(wdev, true);
}
@ -972,13 +981,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->needed_rx_chains = sdata->local->rx_chains;
mutex_lock(&local->mtx);
sdata->radar_required = params->radar_required;
err = ieee80211_vif_use_channel(sdata, &params->chandef,
IEEE80211_CHANCTX_SHARED);
if (!err)
ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
mutex_unlock(&local->mtx);
if (err)
return err;
ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
/*
* Apply control port protocol, this allows us to
@ -1131,8 +1140,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
skb_queue_purge(&sdata->u.ap.ps.bc_buf);
ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
mutex_lock(&local->mtx);
ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
ieee80211_vif_release_channel(sdata);
mutex_unlock(&local->mtx);
@ -1566,7 +1575,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
sta->sdata->u.vlan.sta) {
rcu_assign_pointer(sta->sdata->u.vlan.sta, NULL);
RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
prev_4addr = true;
}
@ -2930,7 +2939,6 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
/* whatever, but channel contexts should not complain about that one */
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = local->rx_chains;
sdata->radar_required = true;
err = ieee80211_vif_use_channel(sdata, chandef,
IEEE80211_CHANCTX_SHARED);
@ -3217,7 +3225,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *chanctx;
int err, num_chanctx, changed = 0;
@ -3233,23 +3241,24 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
&sdata->vif.bss_conf.chandef))
return -EINVAL;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
mutex_lock(&local->chanctx_mtx);
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf) {
mutex_unlock(&local->chanctx_mtx);
return -EBUSY;
}
/* don't handle for multi-VIF cases */
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
if (chanctx->refcount > 1) {
rcu_read_unlock();
chanctx = container_of(conf, struct ieee80211_chanctx, conf);
if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
mutex_unlock(&local->chanctx_mtx);
return -EBUSY;
}
num_chanctx = 0;
list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
num_chanctx++;
rcu_read_unlock();
mutex_unlock(&local->chanctx_mtx);
if (num_chanctx > 1)
return -EBUSY;
@ -3949,6 +3958,21 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy,
return 0;
}
static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
int ret;
u32 changed = 0;
ret = ieee80211_vif_change_bandwidth(sdata, chandef, &changed);
if (ret == 0)
ieee80211_bss_info_change_notify(sdata, changed);
return ret;
}
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@ -4029,4 +4053,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.start_radar_detection = ieee80211_start_radar_detection,
.channel_switch = ieee80211_channel_switch,
.set_qos_map = ieee80211_set_qos_map,
.set_ap_chanwidth = ieee80211_set_ap_chanwidth,
};

View file

@ -9,6 +9,170 @@
#include "ieee80211_i.h"
#include "driver-ops.h"
static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
struct ieee80211_sub_if_data *sdata;
int num = 0;
lockdep_assert_held(&local->chanctx_mtx);
list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
num++;
return num;
}
static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
struct ieee80211_sub_if_data *sdata;
int num = 0;
lockdep_assert_held(&local->chanctx_mtx);
list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
num++;
return num;
}
int ieee80211_chanctx_refcount(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
return ieee80211_chanctx_num_assigned(local, ctx) +
ieee80211_chanctx_num_reserved(local, ctx);
}
static int ieee80211_num_chanctx(struct ieee80211_local *local)
{
struct ieee80211_chanctx *ctx;
int num = 0;
lockdep_assert_held(&local->chanctx_mtx);
list_for_each_entry(ctx, &local->chanctx_list, list)
num++;
return num;
}
static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
{
lockdep_assert_held(&local->chanctx_mtx);
return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
}
static const struct cfg80211_chan_def *
ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
const struct cfg80211_chan_def *compat)
{
struct ieee80211_sub_if_data *sdata;
lockdep_assert_held(&local->chanctx_mtx);
list_for_each_entry(sdata, &ctx->reserved_vifs,
reserved_chanctx_list) {
if (!compat)
compat = &sdata->reserved_chandef;
compat = cfg80211_chandef_compatible(&sdata->reserved_chandef,
compat);
if (!compat)
break;
}
return compat;
}
static const struct cfg80211_chan_def *
ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
const struct cfg80211_chan_def *compat)
{
struct ieee80211_sub_if_data *sdata;
lockdep_assert_held(&local->chanctx_mtx);
list_for_each_entry(sdata, &ctx->assigned_vifs,
assigned_chanctx_list) {
if (sdata->reserved_chanctx != NULL)
continue;
if (!compat)
compat = &sdata->vif.bss_conf.chandef;
compat = cfg80211_chandef_compatible(
&sdata->vif.bss_conf.chandef, compat);
if (!compat)
break;
}
return compat;
}
static const struct cfg80211_chan_def *
ieee80211_chanctx_combined_chandef(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
const struct cfg80211_chan_def *compat)
{
lockdep_assert_held(&local->chanctx_mtx);
compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat);
if (!compat)
return NULL;
compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat);
if (!compat)
return NULL;
return compat;
}
static bool
ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
const struct cfg80211_chan_def *def)
{
lockdep_assert_held(&local->chanctx_mtx);
if (ieee80211_chanctx_combined_chandef(local, ctx, def))
return true;
if (!list_empty(&ctx->reserved_vifs) &&
ieee80211_chanctx_reserved_chandef(local, ctx, def))
return true;
return false;
}
static struct ieee80211_chanctx *
ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
lockdep_assert_held(&local->chanctx_mtx);
if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
return NULL;
list_for_each_entry(ctx, &local->chanctx_list, list) {
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
continue;
if (!ieee80211_chanctx_can_reserve_chandef(local, ctx,
chandef))
continue;
return ctx;
}
return NULL;
}
static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
{
switch (sta->bandwidth) {
@ -190,6 +354,11 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
if (!compat)
continue;
compat = ieee80211_chanctx_reserved_chandef(local, ctx,
compat);
if (!compat)
continue;
ieee80211_change_chanctx(local, ctx, compat);
return ctx;
@ -217,62 +386,91 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
}
static struct ieee80211_chanctx *
ieee80211_new_chanctx(struct ieee80211_local *local,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode)
ieee80211_alloc_chanctx(struct ieee80211_local *local,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
u32 changed;
int err;
lockdep_assert_held(&local->chanctx_mtx);
ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
if (!ctx)
return ERR_PTR(-ENOMEM);
return NULL;
INIT_LIST_HEAD(&ctx->assigned_vifs);
INIT_LIST_HEAD(&ctx->reserved_vifs);
ctx->conf.def = *chandef;
ctx->conf.rx_chains_static = 1;
ctx->conf.rx_chains_dynamic = 1;
ctx->mode = mode;
ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
ieee80211_recalc_chanctx_min_def(local, ctx);
return ctx;
}
static int ieee80211_add_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
u32 changed;
int err;
lockdep_assert_held(&local->mtx);
lockdep_assert_held(&local->chanctx_mtx);
if (!local->use_chanctx)
local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
/* we hold the mutex to prevent idle from changing */
lockdep_assert_held(&local->mtx);
/* turn idle off *before* setting channel -- some drivers need that */
changed = ieee80211_idle_off(local);
if (changed)
ieee80211_hw_config(local, changed);
if (!local->use_chanctx) {
local->_oper_chandef = *chandef;
local->_oper_chandef = ctx->conf.def;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
} else {
err = drv_add_chanctx(local, ctx);
if (err) {
kfree(ctx);
ieee80211_recalc_idle(local);
return ERR_PTR(err);
return err;
}
}
/* and keep the mutex held until the new chanctx is on the list */
list_add_rcu(&ctx->list, &local->chanctx_list);
return 0;
}
static struct ieee80211_chanctx *
ieee80211_new_chanctx(struct ieee80211_local *local,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
int err;
lockdep_assert_held(&local->mtx);
lockdep_assert_held(&local->chanctx_mtx);
ctx = ieee80211_alloc_chanctx(local, chandef, mode);
if (!ctx)
return ERR_PTR(-ENOMEM);
err = ieee80211_add_chanctx(local, ctx);
if (err) {
kfree(ctx);
return ERR_PTR(err);
}
list_add_rcu(&ctx->list, &local->chanctx_list);
return ctx;
}
static void ieee80211_free_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
static void ieee80211_del_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
bool check_single_channel = false;
lockdep_assert_held(&local->chanctx_mtx);
WARN_ON_ONCE(ctx->refcount != 0);
if (!local->use_chanctx) {
struct cfg80211_chan_def *chandef = &local->_oper_chandef;
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
@ -282,8 +480,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
/* NOTE: Disabling radar is only valid here for
* single channel context. To be sure, check it ...
*/
if (local->hw.conf.radar_enabled)
check_single_channel = true;
WARN_ON(local->hw.conf.radar_enabled &&
!list_empty(&local->chanctx_list));
local->hw.conf.radar_enabled = false;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
@ -291,39 +490,19 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
drv_remove_chanctx(local, ctx);
}
list_del_rcu(&ctx->list);
kfree_rcu(ctx, rcu_head);
/* throw a warning if this wasn't the only channel context. */
WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
ieee80211_recalc_idle(local);
}
static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx)
static void ieee80211_free_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
struct ieee80211_local *local = sdata->local;
int ret;
lockdep_assert_held(&local->chanctx_mtx);
ret = drv_assign_vif_chanctx(local, sdata, ctx);
if (ret)
return ret;
WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
ctx->refcount++;
ieee80211_recalc_txpower(sdata);
ieee80211_recalc_chanctx_min_def(local, ctx);
sdata->vif.bss_conf.idle = false;
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
sdata->vif.type != NL80211_IFTYPE_MONITOR)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
return 0;
list_del_rcu(&ctx->list);
ieee80211_del_chanctx(local, ctx);
kfree_rcu(ctx, rcu_head);
}
static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
@ -384,30 +563,58 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
}
static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx)
static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *new_ctx)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *curr_ctx = NULL;
int ret = 0;
lockdep_assert_held(&local->chanctx_mtx);
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
ctx->refcount--;
rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
if (conf) {
curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
sdata->vif.bss_conf.idle = true;
drv_unassign_vif_chanctx(local, sdata, curr_ctx);
conf = NULL;
list_del(&sdata->assigned_chanctx_list);
}
if (new_ctx) {
ret = drv_assign_vif_chanctx(local, sdata, new_ctx);
if (ret)
goto out;
conf = &new_ctx->conf;
list_add(&sdata->assigned_chanctx_list,
&new_ctx->assigned_vifs);
}
out:
rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
sdata->vif.bss_conf.idle = !conf;
if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
ieee80211_recalc_chanctx_chantype(local, curr_ctx);
ieee80211_recalc_smps_chanctx(local, curr_ctx);
ieee80211_recalc_radar_chanctx(local, curr_ctx);
ieee80211_recalc_chanctx_min_def(local, curr_ctx);
}
if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
ieee80211_recalc_txpower(sdata);
ieee80211_recalc_chanctx_min_def(local, new_ctx);
}
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
sdata->vif.type != NL80211_IFTYPE_MONITOR)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_IDLE);
drv_unassign_vif_chanctx(local, sdata, ctx);
if (ctx->refcount > 0) {
ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
ieee80211_recalc_smps_chanctx(local, ctx);
ieee80211_recalc_radar_chanctx(local, ctx);
ieee80211_recalc_chanctx_min_def(local, ctx);
}
return ret;
}
static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
@ -425,8 +632,11 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
ctx = container_of(conf, struct ieee80211_chanctx, conf);
ieee80211_unassign_vif_chanctx(sdata, ctx);
if (ctx->refcount == 0)
if (sdata->reserved_chanctx)
ieee80211_vif_unreserve_chanctx(sdata);
ieee80211_assign_vif_chanctx(sdata, NULL);
if (ieee80211_chanctx_refcount(local, ctx) == 0)
ieee80211_free_chanctx(local, ctx);
}
@ -526,6 +736,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *ctx;
u8 radar_detect_width = 0;
int ret;
lockdep_assert_held(&local->mtx);
@ -533,6 +744,22 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
mutex_lock(&local->chanctx_mtx);
ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
chandef,
sdata->wdev.iftype);
if (ret < 0)
goto out;
if (ret > 0)
radar_detect_width = BIT(chandef->width);
sdata->radar_required = ret;
ret = ieee80211_check_combinations(sdata, chandef, mode,
radar_detect_width);
if (ret < 0)
goto out;
__ieee80211_vif_release_channel(sdata);
ctx = ieee80211_find_chanctx(local, chandef, mode);
@ -548,7 +775,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
ret = ieee80211_assign_vif_chanctx(sdata, ctx);
if (ret) {
/* if assign fails refcount stays the same */
if (ctx->refcount == 0)
if (ieee80211_chanctx_refcount(local, ctx) == 0)
ieee80211_free_chanctx(local, ctx);
goto out;
}
@ -560,39 +787,20 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
return ret;
}
int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
u32 *changed)
static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx,
u32 *changed)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *ctx;
const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
int ret;
u32 chanctx_changed = 0;
lockdep_assert_held(&local->mtx);
/* should never be called if not performing a channel switch. */
if (WARN_ON(!sdata->vif.csa_active))
return -EINVAL;
if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
IEEE80211_CHAN_DISABLED))
return -EINVAL;
mutex_lock(&local->chanctx_mtx);
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf) {
ret = -EINVAL;
goto out;
}
ctx = container_of(conf, struct ieee80211_chanctx, conf);
if (ctx->refcount != 1) {
ret = -EINVAL;
goto out;
}
if (ieee80211_chanctx_refcount(local, ctx) != 1)
return -EINVAL;
if (sdata->vif.bss_conf.chandef.width != chandef->width) {
chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
@ -610,12 +818,224 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_radar_chanctx(local, ctx);
ieee80211_recalc_chanctx_min_def(local, ctx);
ret = 0;
return 0;
}
int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
u32 *changed)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *ctx;
int ret;
lockdep_assert_held(&local->mtx);
/* should never be called if not performing a channel switch. */
if (WARN_ON(!sdata->vif.csa_active))
return -EINVAL;
mutex_lock(&local->chanctx_mtx);
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf) {
ret = -EINVAL;
goto out;
}
ctx = container_of(conf, struct ieee80211_chanctx, conf);
ret = __ieee80211_vif_change_channel(sdata, ctx, changed);
out:
mutex_unlock(&local->chanctx_mtx);
return ret;
}
static void
__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
bool clear)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *vlan;
struct ieee80211_chanctx_conf *conf;
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
return;
lockdep_assert_held(&local->mtx);
/* Check that conf exists, even when clearing this function
* must be called with the AP's channel context still there
* as it would otherwise cause VLANs to have an invalid
* channel context pointer for a while, possibly pointing
* to a channel context that has already been freed.
*/
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
WARN_ON(!conf);
if (clear)
conf = NULL;
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
}
void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
bool clear)
{
struct ieee80211_local *local = sdata->local;
mutex_lock(&local->chanctx_mtx);
__ieee80211_vif_copy_chanctx_to_vlans(sdata, clear);
mutex_unlock(&local->chanctx_mtx);
}
int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_chanctx *ctx = sdata->reserved_chanctx;
lockdep_assert_held(&sdata->local->chanctx_mtx);
if (WARN_ON(!ctx))
return -EINVAL;
list_del(&sdata->reserved_chanctx_list);
sdata->reserved_chanctx = NULL;
if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
ieee80211_free_chanctx(sdata->local, ctx);
return 0;
}
int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode,
bool radar_required)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *new_ctx, *curr_ctx;
int ret = 0;
mutex_lock(&local->chanctx_mtx);
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf) {
ret = -EINVAL;
goto out;
}
curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
if (!new_ctx) {
if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
(local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
/* if we're the only users of the chanctx and
* the driver supports changing a running
* context, reserve our current context
*/
new_ctx = curr_ctx;
} else if (ieee80211_can_create_new_chanctx(local)) {
/* create a new context and reserve it */
new_ctx = ieee80211_new_chanctx(local, chandef, mode);
if (IS_ERR(new_ctx)) {
ret = PTR_ERR(new_ctx);
goto out;
}
} else {
ret = -EBUSY;
goto out;
}
}
list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
sdata->reserved_chanctx = new_ctx;
sdata->reserved_chandef = *chandef;
sdata->reserved_radar_required = radar_required;
out:
mutex_unlock(&local->chanctx_mtx);
return ret;
}
int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
u32 *changed)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *ctx;
struct ieee80211_chanctx *old_ctx;
struct ieee80211_chanctx_conf *conf;
int ret;
u32 tmp_changed = *changed;
/* TODO: need to recheck if the chandef is usable etc.? */
lockdep_assert_held(&local->mtx);
mutex_lock(&local->chanctx_mtx);
ctx = sdata->reserved_chanctx;
if (WARN_ON(!ctx)) {
ret = -EINVAL;
goto out;
}
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf) {
ret = -EINVAL;
goto out;
}
old_ctx = container_of(conf, struct ieee80211_chanctx, conf);
if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
tmp_changed |= BSS_CHANGED_BANDWIDTH;
sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
/* unref our reservation */
sdata->reserved_chanctx = NULL;
sdata->radar_required = sdata->reserved_radar_required;
list_del(&sdata->reserved_chanctx_list);
if (old_ctx == ctx) {
/* This is our own context, just change it */
ret = __ieee80211_vif_change_channel(sdata, old_ctx,
&tmp_changed);
if (ret)
goto out;
} else {
ret = ieee80211_assign_vif_chanctx(sdata, ctx);
if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
ieee80211_free_chanctx(local, old_ctx);
if (ret) {
/* if assign fails refcount stays the same */
if (ieee80211_chanctx_refcount(local, ctx) == 0)
ieee80211_free_chanctx(local, ctx);
goto out;
}
if (sdata->vif.type == NL80211_IFTYPE_AP)
__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
}
*changed = tmp_changed;
ieee80211_recalc_chanctx_chantype(local, ctx);
ieee80211_recalc_smps_chanctx(local, ctx);
ieee80211_recalc_radar_chanctx(local, ctx);
ieee80211_recalc_chanctx_min_def(local, ctx);
out:
mutex_unlock(&local->chanctx_mtx);
return ret;
}
int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
u32 *changed)
@ -695,40 +1115,6 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&local->chanctx_mtx);
}
void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
bool clear)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *vlan;
struct ieee80211_chanctx_conf *conf;
ASSERT_RTNL();
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
return;
mutex_lock(&local->chanctx_mtx);
/*
* Check that conf exists, even when clearing this function
* must be called with the AP's channel context still there
* as it would otherwise cause VLANs to have an invalid
* channel context pointer for a while, possibly pointing
* to a channel context that has already been freed.
*/
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
WARN_ON(!conf);
if (clear)
conf = NULL;
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
mutex_unlock(&local->chanctx_mtx);
}
void ieee80211_iter_chan_contexts_atomic(
struct ieee80211_hw *hw,
void (*iter)(struct ieee80211_hw *hw,

View file

@ -128,7 +128,7 @@ static ssize_t sta_tx_latency_stat_write(struct file *file,
if (!strcmp(buf, TX_LATENCY_DISABLED)) {
if (!tx_latency)
goto unlock;
rcu_assign_pointer(local->tx_latency, NULL);
RCU_INIT_POINTER(local->tx_latency, NULL);
synchronize_rcu();
kfree(tx_latency);
goto unlock;

View file

@ -1,6 +1,8 @@
#ifndef __MAC80211_DEBUGFS_H
#define __MAC80211_DEBUGFS_H
#include "ieee80211_i.h"
#ifdef CONFIG_MAC80211_DEBUGFS
void debugfs_hw_add(struct ieee80211_local *local);
int __printf(4, 5) mac80211_format_buffer(char __user *userbuf, size_t count,

View file

@ -3,6 +3,8 @@
#ifndef __IEEE80211_DEBUGFS_NETDEV_H
#define __IEEE80211_DEBUGFS_NETDEV_H
#include "ieee80211_i.h"
#ifdef CONFIG_MAC80211_DEBUGFS
void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);

View file

@ -726,13 +726,19 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local)
}
static inline void drv_flush(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
u32 queues, bool drop)
{
struct ieee80211_vif *vif = sdata ? &sdata->vif : NULL;
might_sleep();
if (sdata)
check_sdata_in_driver(sdata);
trace_drv_flush(local, queues, drop);
if (local->ops->flush)
local->ops->flush(&local->hw, queues, drop);
local->ops->flush(&local->hw, vif, queues, drop);
trace_drv_return_void(local);
}

View file

@ -31,6 +31,18 @@ static void __check_htcap_disable(struct ieee80211_ht_cap *ht_capa,
}
}
static void __check_htcap_enable(struct ieee80211_ht_cap *ht_capa,
struct ieee80211_ht_cap *ht_capa_mask,
struct ieee80211_sta_ht_cap *ht_cap,
u16 flag)
{
__le16 le_flag = cpu_to_le16(flag);
if ((ht_capa_mask->cap_info & le_flag) &&
(ht_capa->cap_info & le_flag))
ht_cap->cap |= flag;
}
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta_ht_cap *ht_cap)
{
@ -59,7 +71,7 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
smask = (u8 *)(&ht_capa_mask->mcs.rx_mask);
/* NOTE: If you add more over-rides here, update register_hw
* ht_capa_mod_msk logic in main.c as well.
* ht_capa_mod_mask logic in main.c as well.
* And, if this method can ever change ht_cap.ht_supported, fix
* the check in ieee80211_add_ht_ie.
*/
@ -86,6 +98,14 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
__check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
IEEE80211_HT_CAP_MAX_AMSDU);
/* Allow user to disable LDPC */
__check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
IEEE80211_HT_CAP_LDPC_CODING);
/* Allow user to enable 40 MHz intolerant bit. */
__check_htcap_enable(ht_capa, ht_capa_mask, ht_cap,
IEEE80211_HT_CAP_40MHZ_INTOLERANT);
/* Allow user to decrease AMPDU factor */
if (ht_capa_mask->ampdu_params_info &
IEEE80211_HT_AMPDU_PARM_FACTOR) {

View file

@ -228,7 +228,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct beacon_data *presp;
enum nl80211_bss_scan_width scan_width;
bool have_higher_than_11mbit;
bool radar_required = false;
bool radar_required;
int err;
sdata_assert_lock(sdata);
@ -253,7 +253,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
presp = rcu_dereference_protected(ifibss->presp,
lockdep_is_held(&sdata->wdev.mtx));
rcu_assign_pointer(ifibss->presp, NULL);
RCU_INIT_POINTER(ifibss->presp, NULL);
if (presp)
kfree_rcu(presp, rcu_head);
@ -262,7 +262,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
/* make a copy of the chandef, it could be modified below. */
chandef = *req_chandef;
chan = chandef.chan;
if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef,
NL80211_IFTYPE_ADHOC)) {
if (chandef.width == NL80211_CHAN_WIDTH_5 ||
chandef.width == NL80211_CHAN_WIDTH_10 ||
chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
@ -274,7 +275,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
chandef.width = NL80211_CHAN_WIDTH_20;
chandef.center_freq1 = chan->center_freq;
/* check again for downgraded chandef */
if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef,
NL80211_IFTYPE_ADHOC)) {
sdata_info(sdata,
"Failed to join IBSS, beacons forbidden\n");
return;
@ -282,21 +284,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
}
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
&chandef);
&chandef, NL80211_IFTYPE_ADHOC);
if (err < 0) {
sdata_info(sdata,
"Failed to join IBSS, invalid chandef\n");
return;
}
if (err > 0) {
if (!ifibss->userspace_handles_dfs) {
sdata_info(sdata,
"Failed to join IBSS, DFS channel without control program\n");
return;
}
radar_required = true;
if (err > 0 && !ifibss->userspace_handles_dfs) {
sdata_info(sdata,
"Failed to join IBSS, DFS channel without control program\n");
return;
}
radar_required = err;
mutex_lock(&local->mtx);
if (ieee80211_vif_use_channel(sdata, &chandef,
ifibss->fixed_channel ?
@ -775,7 +776,8 @@ static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
* unavailable.
*/
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
&ifibss->chandef);
&ifibss->chandef,
NL80211_IFTYPE_ADHOC);
if (err > 0)
cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef,
GFP_ATOMIC);
@ -861,7 +863,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
goto disconnect;
}
if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef)) {
if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef,
NL80211_IFTYPE_ADHOC)) {
sdata_info(sdata,
"IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
ifibss->bssid,
@ -873,17 +876,17 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
&params.chandef);
&params.chandef,
NL80211_IFTYPE_ADHOC);
if (err < 0)
goto disconnect;
if (err) {
if (err > 0 && !ifibss->userspace_handles_dfs) {
/* IBSS-DFS only allowed with a control program */
if (!ifibss->userspace_handles_dfs)
goto disconnect;
params.radar_required = true;
goto disconnect;
}
params.radar_required = err;
if (cfg80211_chandef_identical(&params.chandef,
&sdata->vif.bss_conf.chandef)) {
ibss_dbg(sdata,
@ -1636,7 +1639,33 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
u32 changed = 0;
u32 rate_flags;
struct ieee80211_supported_band *sband;
enum ieee80211_chanctx_mode chanmode;
struct ieee80211_local *local = sdata->local;
int radar_detect_width = 0;
int i;
int ret;
ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
&params->chandef,
sdata->wdev.iftype);
if (ret < 0)
return ret;
if (ret > 0) {
if (!params->userspace_handles_dfs)
return -EINVAL;
radar_detect_width = BIT(params->chandef.width);
}
chanmode = (params->channel_fixed && !ret) ?
IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
mutex_lock(&local->chanctx_mtx);
ret = ieee80211_check_combinations(sdata, &params->chandef, chanmode,
radar_detect_width);
mutex_unlock(&local->chanctx_mtx);
if (ret < 0)
return ret;
if (params->bssid) {
memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
@ -1651,7 +1680,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
/* fix basic_rates if channel does not support these rates */
rate_flags = ieee80211_chandef_rate_flags(&params->chandef);
sband = sdata->local->hw.wiphy->bands[params->chandef.chan->band];
sband = local->hw.wiphy->bands[params->chandef.chan->band];
for (i = 0; i < sband->n_bitrates; i++) {
if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
sdata->u.ibss.basic_rates &= ~BIT(i);
@ -1700,9 +1729,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
ieee80211_bss_info_change_notify(sdata, changed);
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = sdata->local->rx_chains;
sdata->needed_rx_chains = local->rx_chains;
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
ieee80211_queue_work(&local->hw, &sdata->work);
return 0;
}

View file

@ -260,7 +260,7 @@ struct ieee80211_if_ap {
/* to be used after channel switch. */
struct cfg80211_beacon_data *next_beacon;
struct list_head vlans;
struct list_head vlans; /* write-protected with RTNL and local->mtx */
struct ps_data ps;
atomic_t num_mcast_sta; /* number of stations receiving multicast */
@ -276,7 +276,7 @@ struct ieee80211_if_wds {
};
struct ieee80211_if_vlan {
struct list_head list;
struct list_head list; /* write-protected with RTNL and local->mtx */
/* used for all tx if the VLAN is configured to 4-addr mode */
struct sta_info __rcu *sta;
@ -691,8 +691,10 @@ struct ieee80211_chanctx {
struct list_head list;
struct rcu_head rcu_head;
struct list_head assigned_vifs;
struct list_head reserved_vifs;
enum ieee80211_chanctx_mode mode;
int refcount;
bool driver_present;
struct ieee80211_chanctx_conf conf;
@ -756,6 +758,14 @@ struct ieee80211_sub_if_data {
bool csa_radar_required;
struct cfg80211_chan_def csa_chandef;
struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */
/* context reservation -- protected with chanctx_mtx */
struct ieee80211_chanctx *reserved_chanctx;
struct cfg80211_chan_def reserved_chandef;
bool reserved_radar_required;
/* used to reconfigure hardware SM PS */
struct work_struct recalc_smps;
@ -1770,6 +1780,16 @@ int __must_check
ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode);
int __must_check
ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode,
bool radar_required);
int __must_check
ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
u32 *changed);
int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
int __must_check
ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
@ -1782,6 +1802,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
bool clear);
int ieee80211_chanctx_refcount(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx);
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
@ -1805,6 +1827,11 @@ int ieee80211_cs_headroom(struct ieee80211_local *local,
enum nl80211_iftype iftype);
void ieee80211_recalc_dtim(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode chanmode,
u8 radar_detect);
int ieee80211_max_num_channels(struct ieee80211_local *local);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline

View file

@ -250,6 +250,7 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *nsdata;
int ret;
ASSERT_RTNL();
@ -300,7 +301,10 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
}
}
return 0;
mutex_lock(&local->chanctx_mtx);
ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
mutex_unlock(&local->chanctx_mtx);
return ret;
}
static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
@ -423,7 +427,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
mutex_unlock(&local->mtx);
if (ret) {
mutex_lock(&local->iflist_mtx);
rcu_assign_pointer(local->monitor_sdata, NULL);
RCU_INIT_POINTER(local->monitor_sdata, NULL);
mutex_unlock(&local->iflist_mtx);
synchronize_net();
drv_remove_interface(local, sdata);
@ -452,7 +456,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
return;
}
rcu_assign_pointer(local->monitor_sdata, NULL);
RCU_INIT_POINTER(local->monitor_sdata, NULL);
mutex_unlock(&local->iflist_mtx);
synchronize_net();
@ -492,7 +496,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
if (!sdata->bss)
return -ENOLINK;
mutex_lock(&local->mtx);
list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
mutex_unlock(&local->mtx);
master = container_of(sdata->bss,
struct ieee80211_sub_if_data, u.ap);
@ -722,8 +728,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
drv_stop(local);
err_del_bss:
sdata->bss = NULL;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
mutex_lock(&local->mtx);
list_del(&sdata->u.vlan.list);
mutex_unlock(&local->mtx);
}
/* might already be clear but that doesn't matter */
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
return res;
@ -875,8 +884,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
mutex_lock(&local->mtx);
list_del(&sdata->u.vlan.list);
rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
mutex_unlock(&local->mtx);
RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL);
/* no need to tell driver */
break;
case NL80211_IFTYPE_MONITOR:
@ -895,7 +906,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
break;
case NL80211_IFTYPE_P2P_DEVICE:
/* relies on synchronize_rcu() below */
rcu_assign_pointer(local->p2p_sdata, NULL);
RCU_INIT_POINTER(local->p2p_sdata, NULL);
/* fall through */
default:
cancel_work_sync(&sdata->work);
@ -1280,6 +1291,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
INIT_WORK(&sdata->work, ieee80211_iface_work);
INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
INIT_LIST_HEAD(&sdata->reserved_chanctx_list);
switch (type) {
case NL80211_IFTYPE_P2P_GO:
@ -1774,20 +1787,19 @@ static int netdev_notify(struct notifier_block *nb,
struct ieee80211_sub_if_data *sdata;
if (state != NETDEV_CHANGENAME)
return 0;
return NOTIFY_DONE;
if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
return 0;
return NOTIFY_DONE;
if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
return 0;
return NOTIFY_DONE;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
memcpy(sdata->name, dev->name, IFNAMSIZ);
ieee80211_debugfs_rename_netdev(sdata);
return 0;
return NOTIFY_OK;
}
static struct notifier_block mac80211_netdev_notifier = {

View file

@ -340,7 +340,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
sdata_unlock(sdata);
return NOTIFY_DONE;
return NOTIFY_OK;
}
#endif
@ -371,7 +371,7 @@ static int ieee80211_ifa6_changed(struct notifier_block *nb,
drv_ipv6_addr_change(local, sdata, idev);
return NOTIFY_DONE;
return NOTIFY_OK;
}
#endif
@ -446,7 +446,9 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
.cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_MAX_AMSDU |
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40),
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_LDPC_CODING |
IEEE80211_HT_CAP_40MHZ_INTOLERANT),
.mcs = {
.rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, },

View file

@ -366,20 +366,15 @@ int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
return 0;
/* find RSN IE */
data = ifmsh->ie;
while (data < ifmsh->ie + ifmsh->ie_len) {
if (*data == WLAN_EID_RSN) {
len = data[1] + 2;
break;
}
data++;
}
data = cfg80211_find_ie(WLAN_EID_RSN, ifmsh->ie, ifmsh->ie_len);
if (!data)
return 0;
if (len) {
if (skb_tailroom(skb) < len)
return -ENOMEM;
memcpy(skb_put(skb, len), data, len);
}
len = data[1] + 2;
if (skb_tailroom(skb) < len)
return -ENOMEM;
memcpy(skb_put(skb, len), data, len);
return 0;
}
@ -829,7 +824,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
bcn = rcu_dereference_protected(ifmsh->beacon,
lockdep_is_held(&sdata->wdev.mtx));
rcu_assign_pointer(ifmsh->beacon, NULL);
RCU_INIT_POINTER(ifmsh->beacon, NULL);
kfree_rcu(bcn, rcu_head);
/* flush STAs and mpaths on this iface */
@ -903,14 +898,15 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
}
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
&params.chandef);
&params.chandef,
NL80211_IFTYPE_MESH_POINT);
if (err < 0)
return false;
if (err) {
params.radar_required = true;
if (err > 0)
/* TODO: DFS not (yet) supported */
return false;
}
params.radar_required = err;
if (cfg80211_chandef_identical(&params.chandef,
&sdata->vif.bss_conf.chandef)) {
@ -1068,7 +1064,7 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
/* Remove the CSA and MCSP elements from the beacon */
tmp_csa_settings = rcu_dereference(ifmsh->csa);
rcu_assign_pointer(ifmsh->csa, NULL);
RCU_INIT_POINTER(ifmsh->csa, NULL);
if (tmp_csa_settings)
kfree_rcu(tmp_csa_settings, rcu_head);
ret = ieee80211_mesh_rebuild_beacon(sdata);
@ -1102,7 +1098,7 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
ret = ieee80211_mesh_rebuild_beacon(sdata);
if (ret) {
tmp_csa_settings = rcu_dereference(ifmsh->csa);
rcu_assign_pointer(ifmsh->csa, NULL);
RCU_INIT_POINTER(ifmsh->csa, NULL);
kfree_rcu(tmp_csa_settings, rcu_head);
return ret;
}

View file

@ -37,7 +37,7 @@ static inline u32 u32_field_get(const u8 *preq_elem, int offset, bool ae)
return get_unaligned_le32(preq_elem + offset);
}
static inline u32 u16_field_get(const u8 *preq_elem, int offset, bool ae)
static inline u16 u16_field_get(const u8 *preq_elem, int offset, bool ae)
{
if (ae)
offset += 6;
@ -544,9 +544,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
if (time_after(jiffies, ifmsh->last_sn_update +
net_traversal_jiffies(sdata)) ||
time_before(jiffies, ifmsh->last_sn_update)) {
target_sn = ++ifmsh->sn;
++ifmsh->sn;
ifmsh->last_sn_update = jiffies;
}
target_sn = ifmsh->sn;
} else if (is_broadcast_ether_addr(target_addr) &&
(target_flags & IEEE80211_PREQ_TO_FLAG)) {
rcu_read_lock();

View file

@ -11,6 +11,7 @@
#define MICHAEL_H
#include <linux/types.h>
#include <linux/ieee80211.h>
#define MICHAEL_MIC_LEN 8

View file

@ -1089,7 +1089,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
struct ieee80211_chanctx, conf);
if (chanctx->refcount > 1) {
if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
sdata_info(sdata,
"channel switch with multiple interfaces on the same channel, disconnecting\n");
ieee80211_queue_work(&local->hw,
@ -3701,7 +3701,7 @@ int ieee80211_max_network_latency(struct notifier_block *nb,
ieee80211_recalc_ps(local, latency_usec);
mutex_unlock(&local->iflist_mtx);
return 0;
return NOTIFY_OK;
}
static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata,

View file

@ -54,24 +54,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
return skb;
}
static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len)
static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr;
hdr = (void *)(skb->data);
struct ieee80211_hdr *hdr = (void *)skb->data;
if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
RX_FLAG_FAILED_PLCP_CRC |
RX_FLAG_AMPDU_IS_ZEROLEN))
return 1;
return true;
if (unlikely(skb->len < 16 + present_fcs_len))
return 1;
return true;
if (ieee80211_is_ctl(hdr->frame_control) &&
!ieee80211_is_pspoll(hdr->frame_control) &&
!ieee80211_is_back_req(hdr->frame_control))
return 1;
return 0;
return true;
return false;
}
static int
@ -3190,7 +3191,7 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
}
/*
* This is the actual Rx frames handler. as it blongs to Rx path it must
* This is the actual Rx frames handler. as it belongs to Rx path it must
* be called with rcu_read_lock protection.
*/
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,

View file

@ -309,7 +309,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (local->scan_req != local->int_scan_req)
cfg80211_scan_done(local->scan_req, aborted);
local->scan_req = NULL;
rcu_assign_pointer(local->scan_sdata, NULL);
RCU_INIT_POINTER(local->scan_sdata, NULL);
local->scanning = 0;
local->scan_chandef.chan = NULL;
@ -559,7 +559,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_idle(local);
local->scan_req = NULL;
rcu_assign_pointer(local->scan_sdata, NULL);
RCU_INIT_POINTER(local->scan_sdata, NULL);
}
return rc;
@ -773,7 +773,7 @@ void ieee80211_scan_work(struct work_struct *work)
int rc;
local->scan_req = NULL;
rcu_assign_pointer(local->scan_sdata, NULL);
RCU_INIT_POINTER(local->scan_sdata, NULL);
rc = __ieee80211_start_scan(sdata, req);
if (rc) {
@ -1014,7 +1014,7 @@ out_free:
if (ret) {
/* Clean in case of failure after HW restart or upon resume. */
rcu_assign_pointer(local->sched_scan_sdata, NULL);
RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
local->sched_scan_req = NULL;
}
@ -1089,7 +1089,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
return;
}
rcu_assign_pointer(local->sched_scan_sdata, NULL);
RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
/* If sched scan was aborted by the driver. */
local->sched_scan_req = NULL;

View file

@ -552,7 +552,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
{
struct ieee80211_local *local = sta->local;
int err = 0;
int err;
might_sleep();
@ -570,7 +570,6 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
return 0;
out_free:
BUG_ON(!err);
sta_info_free(local, sta);
return err;
}

View file

@ -554,7 +554,7 @@ void ieee80211_flush_queues(struct ieee80211_local *local,
ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_FLUSH);
drv_flush(local, queues, false);
drv_flush(local, sdata, queues, false);
ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_FLUSH);
@ -1546,7 +1546,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
WARN_ON(local->resuming);
res = drv_add_interface(local, sdata);
if (WARN_ON(res)) {
rcu_assign_pointer(local->monitor_sdata, NULL);
RCU_INIT_POINTER(local->monitor_sdata, NULL);
synchronize_net();
kfree(sdata);
}
@ -1565,17 +1565,17 @@ int ieee80211_reconfig(struct ieee80211_local *local)
list_for_each_entry(ctx, &local->chanctx_list, list)
WARN_ON(drv_add_chanctx(local, ctx));
mutex_unlock(&local->chanctx_mtx);
}
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
ieee80211_assign_chanctx(local, sdata);
}
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
ieee80211_assign_chanctx(local, sdata);
}
sdata = rtnl_dereference(local->monitor_sdata);
if (sdata && ieee80211_sdata_running(sdata))
ieee80211_assign_chanctx(local, sdata);
sdata = rtnl_dereference(local->monitor_sdata);
if (sdata && ieee80211_sdata_running(sdata))
ieee80211_assign_chanctx(local, sdata);
}
/* add STAs back */
mutex_lock(&local->sta_mtx);
@ -1671,13 +1671,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
break;
case NL80211_IFTYPE_WDS:
break;
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MONITOR:
/* ignore virtual */
break;
case NL80211_IFTYPE_P2P_DEVICE:
changed = BSS_CHANGED_IDLE;
/* nothing to do */
break;
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
@ -2797,3 +2794,121 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
ps->dtim_count = dtim_count;
}
int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode chanmode,
u8 radar_detect)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *sdata_iter;
enum nl80211_iftype iftype = sdata->wdev.iftype;
int num[NUM_NL80211_IFTYPES];
struct ieee80211_chanctx *ctx;
int num_different_channels = 0;
int total = 1;
lockdep_assert_held(&local->chanctx_mtx);
if (WARN_ON(hweight32(radar_detect) > 1))
return -EINVAL;
if (WARN_ON(chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
!chandef->chan))
return -EINVAL;
if (chandef)
num_different_channels = 1;
if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
return -EINVAL;
/* Always allow software iftypes */
if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
if (radar_detect)
return -EINVAL;
return 0;
}
memset(num, 0, sizeof(num));
if (iftype != NL80211_IFTYPE_UNSPECIFIED)
num[iftype] = 1;
list_for_each_entry(ctx, &local->chanctx_list, list) {
if (ctx->conf.radar_enabled)
radar_detect |= BIT(ctx->conf.def.width);
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
num_different_channels++;
continue;
}
if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
cfg80211_chandef_compatible(chandef,
&ctx->conf.def))
continue;
num_different_channels++;
}
list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
struct wireless_dev *wdev_iter;
wdev_iter = &sdata_iter->wdev;
if (sdata_iter == sdata ||
rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL ||
local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
continue;
num[wdev_iter->iftype]++;
total++;
}
if (total == 1 && !radar_detect)
return 0;
return cfg80211_check_combinations(local->hw.wiphy,
num_different_channels,
radar_detect, num);
}
static void
ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
void *data)
{
u32 *max_num_different_channels = data;
*max_num_different_channels = max(*max_num_different_channels,
c->num_different_channels);
}
int ieee80211_max_num_channels(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
int num[NUM_NL80211_IFTYPES] = {};
struct ieee80211_chanctx *ctx;
int num_different_channels = 0;
u8 radar_detect = 0;
u32 max_num_different_channels = 1;
int err;
lockdep_assert_held(&local->chanctx_mtx);
list_for_each_entry(ctx, &local->chanctx_list, list) {
num_different_channels++;
if (ctx->conf.radar_enabled)
radar_detect |= BIT(ctx->conf.def.width);
}
list_for_each_entry_rcu(sdata, &local->interfaces, list)
num[sdata->wdev.iftype]++;
err = cfg80211_iter_combinations(local->hw.wiphy,
num_different_channels, radar_detect,
num, ieee80211_iter_max_chans,
&max_num_different_channels);
if (err < 0)
return err;
return max_num_different_channels;
}

View file

@ -406,7 +406,10 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
if (info->control.hw_key &&
!(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
!(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
!(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
!((info->control.hw_key->flags &
IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) &&
ieee80211_is_mgmt(hdr->frame_control))) {
/*
* hwaccel has no need for preallocated room for CCMP
* header or MIC fields

View file

@ -95,6 +95,43 @@ config CFG80211_CERTIFICATION_ONUS
you are a wireless researcher and are working in a controlled
and approved environment by your local regulatory agency.
config CFG80211_REG_CELLULAR_HINTS
bool "cfg80211 regulatory support for cellular base station hints"
depends on CFG80211_CERTIFICATION_ONUS
---help---
This option enables support for parsing regulatory hints
from cellular base stations. If enabled and at least one driver
claims support for parsing cellular base station hints the
regulatory core will allow and parse these regulatory hints.
The regulatory core will only apply these regulatory hints on
drivers that support this feature. You should only enable this
feature if you have tested and validated this feature on your
systems.
config CFG80211_REG_RELAX_NO_IR
bool "cfg80211 support for NO_IR relaxation"
depends on CFG80211_CERTIFICATION_ONUS
---help---
This option enables support for relaxation of the NO_IR flag for
situations that certain regulatory bodies have provided clarifications
on how relaxation can occur. This feature has an inherent dependency on
userspace features which must have been properly tested and as such is
not enabled by default.
A relaxation feature example is allowing the operation of a P2P group
owner (GO) on channels marked with NO_IR if there is an additional BSS
interface which associated to an AP which userspace assumes or confirms
to be an authorized master, i.e., with radar detection support and DFS
capabilities. However, note that in order to not create daisy chain
scenarios, this relaxation is not allowed in cases that the BSS client
is associated to P2P GO and in addition the P2P GO instantiated on
a channel due to this relaxation should not allow connection from
non P2P clients.
The regulatory core will apply these relaxations only for drivers that
support this feature by declaring the appropriate channel flags and
capabilities in their registration flow.
config CFG80211_DEFAULT_PS
bool "enable powersave by default"
depends on CFG80211

View file

@ -326,28 +326,57 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef)
const struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype)
{
int width;
int r;
int ret;
if (WARN_ON(!cfg80211_chandef_valid(chandef)))
return -EINVAL;
width = cfg80211_chandef_get_width(chandef);
if (width < 0)
return -EINVAL;
switch (iftype) {
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_MESH_POINT:
width = cfg80211_chandef_get_width(chandef);
if (width < 0)
return -EINVAL;
r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1,
width);
if (r)
return r;
ret = cfg80211_get_chans_dfs_required(wiphy,
chandef->center_freq1,
width);
if (ret < 0)
return ret;
else if (ret > 0)
return BIT(chandef->width);
if (!chandef->center_freq2)
return 0;
if (!chandef->center_freq2)
return 0;
return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
width);
ret = cfg80211_get_chans_dfs_required(wiphy,
chandef->center_freq2,
width);
if (ret < 0)
return ret;
else if (ret > 0)
return BIT(chandef->width);
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_UNSPECIFIED:
break;
case NUM_NL80211_IFTYPES:
WARN_ON(1);
}
return 0;
}
EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
@ -587,12 +616,14 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
width = 5;
break;
case NL80211_CHAN_WIDTH_10:
prohibited_flags |= IEEE80211_CHAN_NO_10MHZ;
width = 10;
break;
case NL80211_CHAN_WIDTH_20:
if (!ht_cap->ht_supported)
return false;
case NL80211_CHAN_WIDTH_20_NOHT:
prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
width = 20;
break;
case NL80211_CHAN_WIDTH_40:
@ -661,17 +692,112 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
}
EXPORT_SYMBOL(cfg80211_chandef_usable);
bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
/*
* For GO only, check if the channel can be used under permissive conditions
* mandated by the some regulatory bodies, i.e., the channel is marked with
* IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface
* associated to an AP on the same channel or on the same UNII band
* (assuming that the AP is an authorized master).
* In addition allow the GO to operate on a channel on which indoor operation is
* allowed, iff we are currently operating in an indoor environment.
*/
static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan)
{
struct wireless_dev *wdev_iter;
struct wiphy *wiphy = wiphy_idx_to_wiphy(rdev->wiphy_idx);
ASSERT_RTNL();
if (!config_enabled(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
!(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
return false;
if (regulatory_indoor_allowed() &&
(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
return true;
if (!(chan->flags & IEEE80211_CHAN_GO_CONCURRENT))
return false;
/*
* Generally, it is possible to rely on another device/driver to allow
* the GO concurrent relaxation, however, since the device can further
* enforce the relaxation (by doing a similar verifications as this),
* and thus fail the GO instantiation, consider only the interfaces of
* the current registered device.
*/
list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
struct ieee80211_channel *other_chan = NULL;
int r1, r2;
if (wdev_iter->iftype != NL80211_IFTYPE_STATION ||
!netif_running(wdev_iter->netdev))
continue;
wdev_lock(wdev_iter);
if (wdev_iter->current_bss)
other_chan = wdev_iter->current_bss->pub.channel;
wdev_unlock(wdev_iter);
if (!other_chan)
continue;
if (chan == other_chan)
return true;
if (chan->band != IEEE80211_BAND_5GHZ)
continue;
r1 = cfg80211_get_unii(chan->center_freq);
r2 = cfg80211_get_unii(other_chan->center_freq);
if (r1 != -EINVAL && r1 == r2) {
/*
* At some locations channels 149-165 are considered a
* bundle, but at other locations, e.g., Indonesia,
* channels 149-161 are considered a bundle while
* channel 165 is left out and considered to be in a
* different bundle. Thus, in case that there is a
* station interface connected to an AP on channel 165,
* it is assumed that channels 149-161 are allowed for
* GO operations. However, having a station interface
* connected to an AP on channels 149-161, does not
* allow GO operation on channel 165.
*/
if (chan->center_freq == 5825 &&
other_chan->center_freq != 5825)
continue;
return true;
}
}
return false;
}
bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
bool res;
u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_RADAR;
trace_cfg80211_reg_can_beacon(wiphy, chandef);
trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
/*
* Under certain conditions suggested by the some regulatory bodies
* a GO can operate on channels marked with IEEE80211_NO_IR
* so set this flag only if such relaxations are not enabled and
* the conditions are not met.
*/
if (iftype != NL80211_IFTYPE_P2P_GO ||
!cfg80211_go_permissive_chan(rdev, chandef->chan))
prohibited_flags |= IEEE80211_CHAN_NO_IR;
if (cfg80211_chandef_dfs_required(wiphy, chandef,
NL80211_IFTYPE_UNSPECIFIED) > 0 &&
cfg80211_chandef_dfs_available(wiphy, chandef)) {
/* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
prohibited_flags = IEEE80211_CHAN_DISABLED;
@ -701,6 +827,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
enum cfg80211_chan_mode *chanmode,
u8 *radar_detect)
{
int ret;
*chan = NULL;
*chanmode = CHAN_MODE_UNDEFINED;
@ -743,8 +871,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
*chan = wdev->chandef.chan;
*chanmode = CHAN_MODE_SHARED;
if (cfg80211_chandef_dfs_required(wdev->wiphy,
&wdev->chandef))
ret = cfg80211_chandef_dfs_required(wdev->wiphy,
&wdev->chandef,
wdev->iftype);
WARN_ON(ret < 0);
if (ret > 0)
*radar_detect |= BIT(wdev->chandef.width);
}
return;
@ -753,8 +884,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
*chan = wdev->chandef.chan;
*chanmode = CHAN_MODE_SHARED;
if (cfg80211_chandef_dfs_required(wdev->wiphy,
&wdev->chandef))
ret = cfg80211_chandef_dfs_required(wdev->wiphy,
&wdev->chandef,
wdev->iftype);
WARN_ON(ret < 0);
if (ret > 0)
*radar_detect |= BIT(wdev->chandef.width);
}
return;

View file

@ -69,7 +69,7 @@ struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
int get_wiphy_idx(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
return rdev->wiphy_idx;
}
@ -260,6 +260,45 @@ static void cfg80211_event_work(struct work_struct *work)
rtnl_unlock();
}
void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
{
struct cfg80211_iface_destroy *item;
ASSERT_RTNL();
spin_lock_irq(&rdev->destroy_list_lock);
while ((item = list_first_entry_or_null(&rdev->destroy_list,
struct cfg80211_iface_destroy,
list))) {
struct wireless_dev *wdev, *tmp;
u32 nlportid = item->nlportid;
list_del(&item->list);
kfree(item);
spin_unlock_irq(&rdev->destroy_list_lock);
list_for_each_entry_safe(wdev, tmp, &rdev->wdev_list, list) {
if (nlportid == wdev->owner_nlportid)
rdev_del_virtual_intf(rdev, wdev);
}
spin_lock_irq(&rdev->destroy_list_lock);
}
spin_unlock_irq(&rdev->destroy_list_lock);
}
static void cfg80211_destroy_iface_wk(struct work_struct *work)
{
struct cfg80211_registered_device *rdev;
rdev = container_of(work, struct cfg80211_registered_device,
destroy_work);
rtnl_lock();
cfg80211_destroy_ifaces(rdev);
rtnl_unlock();
}
/* exported functions */
struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
@ -318,6 +357,10 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
rdev->wiphy.dev.class = &ieee80211_class;
rdev->wiphy.dev.platform_data = rdev;
INIT_LIST_HEAD(&rdev->destroy_list);
spin_lock_init(&rdev->destroy_list_lock);
INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
#ifdef CONFIG_CFG80211_DEFAULT_PS
rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
#endif
@ -396,10 +439,7 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
for (j = 0; j < c->n_limits; j++) {
u16 types = c->limits[j].types;
/*
* interface types shouldn't overlap, this is
* used in cfg80211_can_change_interface()
*/
/* interface types shouldn't overlap */
if (WARN_ON(types & all_iftypes))
return -EINVAL;
all_iftypes |= types;
@ -435,7 +475,7 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
int wiphy_register(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
int res;
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
@ -616,7 +656,7 @@ EXPORT_SYMBOL(wiphy_register);
void wiphy_rfkill_start_polling(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
if (!rdev->ops->rfkill_poll)
return;
@ -627,7 +667,7 @@ EXPORT_SYMBOL(wiphy_rfkill_start_polling);
void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
rfkill_pause_polling(rdev->rfkill);
}
@ -635,7 +675,7 @@ EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
void wiphy_unregister(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
wait_event(rdev->dev_wait, ({
int __count;
@ -675,6 +715,7 @@ void wiphy_unregister(struct wiphy *wiphy)
cancel_work_sync(&rdev->conn_work);
flush_work(&rdev->event_work);
cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
flush_work(&rdev->destroy_work);
#ifdef CONFIG_PM
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
@ -707,7 +748,7 @@ EXPORT_SYMBOL(wiphy_free);
void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
if (rfkill_set_hw_state(rdev->rfkill, blocked))
schedule_work(&rdev->rfkill_sync);
@ -716,7 +757,7 @@ EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
void cfg80211_unregister_wdev(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
ASSERT_RTNL();
@ -796,12 +837,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev;
int ret;
if (!wdev)
return NOTIFY_DONE;
rdev = wiphy_to_dev(wdev->wiphy);
rdev = wiphy_to_rdev(wdev->wiphy);
WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
@ -959,13 +999,14 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
case NETDEV_PRE_UP:
if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
return notifier_from_errno(-EOPNOTSUPP);
ret = cfg80211_can_add_interface(rdev, wdev->iftype);
if (ret)
return notifier_from_errno(ret);
if (rfkill_blocked(rdev->rfkill))
return notifier_from_errno(-ERFKILL);
break;
default:
return NOTIFY_DONE;
}
return NOTIFY_DONE;
return NOTIFY_OK;
}
static struct notifier_block cfg80211_netdev_notifier = {

View file

@ -80,13 +80,17 @@ struct cfg80211_registered_device {
struct cfg80211_coalesce *coalesce;
spinlock_t destroy_list_lock;
struct list_head destroy_list;
struct work_struct destroy_work;
/* must be last because of the way we do wiphy_priv(),
* and it should at least be aligned to NETDEV_ALIGN */
struct wiphy wiphy __aligned(NETDEV_ALIGN);
};
static inline
struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
struct cfg80211_registered_device *wiphy_to_rdev(struct wiphy *wiphy)
{
BUG_ON(!wiphy);
return container_of(wiphy, struct cfg80211_registered_device, wiphy);
@ -232,6 +236,13 @@ struct cfg80211_beacon_registration {
u32 nlportid;
};
struct cfg80211_iface_destroy {
struct list_head list;
u32 nlportid;
};
void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev);
/* free object */
void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
@ -240,8 +251,8 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
void cfg80211_bss_age(struct cfg80211_registered_device *dev,
void cfg80211_bss_expire(struct cfg80211_registered_device *rdev);
void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
unsigned long age_secs);
/* IBSS */
@ -401,35 +412,6 @@ unsigned int
cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef);
static inline int
cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
enum nl80211_iftype iftype)
{
return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
CHAN_MODE_UNDEFINED, 0);
}
static inline int
cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype)
{
if (rfkill_blocked(rdev->rfkill))
return -ERFKILL;
return cfg80211_can_change_interface(rdev, NULL, iftype);
}
static inline int
cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
enum cfg80211_chan_mode chanmode)
{
return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
chan, chanmode, 0);
}
static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
{
unsigned long end = jiffies;

View file

@ -43,7 +43,7 @@ static void cfg80211_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *rp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
memset(rp, 0, sizeof(*rp));
@ -56,7 +56,7 @@ static int cfg80211_set_ringparam(struct net_device *dev,
struct ethtool_ringparam *rp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0)
return -EINVAL;
@ -70,7 +70,7 @@ static int cfg80211_set_ringparam(struct net_device *dev,
static int cfg80211_get_sset_count(struct net_device *dev, int sset)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
if (rdev->ops->get_et_sset_count)
return rdev_get_et_sset_count(rdev, dev, sset);
return -EOPNOTSUPP;
@ -80,7 +80,7 @@ static void cfg80211_get_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
if (rdev->ops->get_et_stats)
rdev_get_et_stats(rdev, dev, stats, data);
}
@ -88,7 +88,7 @@ static void cfg80211_get_stats(struct net_device *dev,
static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
if (rdev->ops->get_et_strings)
rdev_get_et_strings(rdev, dev, sset, data);
}

View file

@ -45,7 +45,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
cfg80211_upload_connect_keys(wdev);
nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bssid,
GFP_KERNEL);
#ifdef CONFIG_CFG80211_WEXT
memset(&wrqu, 0, sizeof(wrqu));
@ -58,7 +58,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
struct ieee80211_channel *channel, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_event *ev;
unsigned long flags;
@ -88,8 +88,6 @@ static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
struct cfg80211_cached_keys *connkeys)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_channel *check_chan;
u8 radar_detect_width = 0;
int err;
ASSERT_WDEV_LOCK(wdev);
@ -126,28 +124,6 @@ static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
#ifdef CONFIG_CFG80211_WEXT
wdev->wext.ibss.chandef = params->chandef;
#endif
check_chan = params->chandef.chan;
if (params->userspace_handles_dfs) {
/* Check for radar even if the current channel is not
* a radar channel - it might decide to change to DFS
* channel later.
*/
radar_detect_width = BIT(params->chandef.width);
}
err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
check_chan,
(params->channel_fixed &&
!radar_detect_width)
? CHAN_MODE_SHARED
: CHAN_MODE_EXCLUSIVE,
radar_detect_width);
if (err) {
wdev->connect_keys = NULL;
return err;
}
err = rdev_join_ibss(rdev, dev, params);
if (err) {
wdev->connect_keys = NULL;
@ -180,7 +156,7 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
int i;
ASSERT_WDEV_LOCK(wdev);
@ -335,7 +311,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
struct iw_freq *wextfreq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct ieee80211_channel *chan = NULL;
int err, freq;
@ -346,7 +322,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
if (!rdev->ops->join_ibss)
return -EOPNOTSUPP;
freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
freq = cfg80211_wext_freq(wextfreq);
if (freq < 0)
return freq;
@ -420,7 +396,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
struct iw_point *data, char *ssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
size_t len = data->length;
int err;
@ -487,7 +463,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
struct sockaddr *ap_addr, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
u8 *bssid = ap_addr->sa_data;
int err;
@ -505,6 +481,9 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
bssid = NULL;
if (bssid && !is_valid_ether_addr(bssid))
return -EINVAL;
/* both automatic */
if (!bssid && !wdev->wext.ibss.bssid)
return 0;

View file

@ -99,7 +99,6 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
const struct mesh_config *conf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
u8 radar_detect_width = 0;
int err;
BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
@ -175,22 +174,10 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
scan_width);
}
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef,
NL80211_IFTYPE_MESH_POINT))
return -EINVAL;
err = cfg80211_chandef_dfs_required(wdev->wiphy, &setup->chandef);
if (err < 0)
return err;
if (err)
radar_detect_width = BIT(setup->chandef.width);
err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
setup->chandef.chan,
CHAN_MODE_SHARED,
radar_detect_width);
if (err)
return err;
err = rdev_join_mesh(rdev, dev, conf, setup);
if (!err) {
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
@ -236,17 +223,6 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
if (!netif_running(wdev->netdev))
return -ENETDOWN;
/* cfg80211_can_use_chan() calls
* cfg80211_can_use_iftype_chan() with no radar
* detection, so if we're trying to use a radar
* channel here, something is wrong.
*/
WARN_ON_ONCE(chandef->chan->flags & IEEE80211_CHAN_RADAR);
err = cfg80211_can_use_chan(rdev, wdev, chandef->chan,
CHAN_MODE_SHARED);
if (err)
return err;
err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
chandef->chan);
if (!err)

View file

@ -23,7 +23,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
u8 *ie = mgmt->u.assoc_resp.variable;
int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
@ -54,7 +54,7 @@ EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
static void cfg80211_process_auth(struct wireless_dev *wdev,
const u8 *buf, size_t len)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
nl80211_send_rx_auth(rdev, wdev->netdev, buf, len, GFP_KERNEL);
cfg80211_sme_rx_auth(wdev, buf, len);
@ -63,7 +63,7 @@ static void cfg80211_process_auth(struct wireless_dev *wdev,
static void cfg80211_process_deauth(struct wireless_dev *wdev,
const u8 *buf, size_t len)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
const u8 *bssid = mgmt->bssid;
u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
@ -82,7 +82,7 @@ static void cfg80211_process_deauth(struct wireless_dev *wdev,
static void cfg80211_process_disassoc(struct wireless_dev *wdev,
const u8 *buf, size_t len)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
const u8 *bssid = mgmt->bssid;
u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
@ -123,7 +123,7 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
trace_cfg80211_send_auth_timeout(dev, addr);
@ -136,7 +136,7 @@ void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
trace_cfg80211_send_assoc_timeout(dev, bss->bssid);
@ -172,7 +172,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
const u8 *tsc, gfp_t gfp)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
char *buf = kmalloc(128, gfp);
@ -233,14 +233,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
if (!req.bss)
return -ENOENT;
err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
CHAN_MODE_SHARED);
if (err)
goto out;
err = rdev_auth(rdev, dev, &req);
out:
cfg80211_put_bss(&rdev->wiphy, req.bss);
return err;
}
@ -306,16 +300,10 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
if (!req->bss)
return -ENOENT;
err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
if (err)
goto out;
err = rdev_assoc(rdev, dev, req);
if (!err)
cfg80211_hold_bss(bss_from_pub(req->bss));
out:
if (err)
else
cfg80211_put_bss(&rdev->wiphy, req->bss);
return err;
@ -414,7 +402,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
int match_len)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_mgmt_registration *reg, *nreg;
int err = 0;
u16 mgmt_type;
@ -473,7 +461,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_mgmt_registration *reg, *tmp;
spin_lock_bh(&wdev->mgmt_registrations_lock);
@ -620,7 +608,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
const u8 *buf, size_t len, u32 flags, gfp_t gfp)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_mgmt_registration *reg;
const struct ieee80211_txrx_stypes *stypes =
&wiphy->mgmt_stypes[wdev->iftype];
@ -739,7 +727,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
gfp_t gfp)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
unsigned long timeout;
trace_cfg80211_radar_event(wiphy, chandef);
@ -764,7 +752,7 @@ void cfg80211_cac_event(struct net_device *netdev,
{
struct wireless_dev *wdev = netdev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
unsigned long timeout;
trace_cfg80211_cac_event(netdev, event);

File diff suppressed because it is too large Load diff

View file

@ -950,4 +950,17 @@ static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev,
return ret;
}
static inline int
rdev_set_ap_chanwidth(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct cfg80211_chan_def *chandef)
{
int ret;
trace_rdev_set_ap_chanwidth(&rdev->wiphy, dev, chandef);
ret = rdev->ops->set_ap_chanwidth(&rdev->wiphy, dev, chandef);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
#endif /* __CFG80211_RDEV_OPS */

View file

@ -65,11 +65,26 @@
#define REG_DBG_PRINT(args...)
#endif
/**
* enum reg_request_treatment - regulatory request treatment
*
* @REG_REQ_OK: continue processing the regulatory request
* @REG_REQ_IGNORE: ignore the regulatory request
* @REG_REQ_INTERSECT: the regulatory domain resulting from this request should
* be intersected with the current one.
* @REG_REQ_ALREADY_SET: the regulatory request will not change the current
* regulatory settings, and no further processing is required.
* @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no
* further processing is required, i.e., not need to update last_request
* etc. This should be used for user hints that do not provide an alpha2
* but some other type of regulatory hint, i.e., indoor operation.
*/
enum reg_request_treatment {
REG_REQ_OK,
REG_REQ_IGNORE,
REG_REQ_INTERSECT,
REG_REQ_ALREADY_SET,
REG_REQ_USER_HINT_HANDLED,
};
static struct regulatory_request core_request_world = {
@ -106,6 +121,14 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
*/
static int reg_num_devs_support_basehint;
/*
* State variable indicating if the platform on which the devices
* are attached is operating in an indoor environment. The state variable
* is relevant for all registered devices.
* (protected by RTNL)
*/
static bool reg_is_indoor;
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{
return rtnl_dereference(cfg80211_regdomain);
@ -240,8 +263,16 @@ static char user_alpha2[2];
module_param(ieee80211_regdom, charp, 0444);
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
static void reg_free_request(struct regulatory_request *lr)
static void reg_free_request(struct regulatory_request *request)
{
if (request != get_last_request())
kfree(request);
}
static void reg_free_last_request(void)
{
struct regulatory_request *lr = get_last_request();
if (lr != &core_request_world && lr)
kfree_rcu(lr, rcu_head);
}
@ -254,7 +285,7 @@ static void reg_update_last_request(struct regulatory_request *request)
if (lr == request)
return;
reg_free_request(lr);
reg_free_last_request();
rcu_assign_pointer(last_request, request);
}
@ -873,6 +904,8 @@ static u32 map_regdom_flags(u32 rd_flags)
channel_flags |= IEEE80211_CHAN_RADAR;
if (rd_flags & NL80211_RRF_NO_OFDM)
channel_flags |= IEEE80211_CHAN_NO_OFDM;
if (rd_flags & NL80211_RRF_NO_OUTDOOR)
channel_flags |= IEEE80211_CHAN_INDOOR_ONLY;
return channel_flags;
}
@ -902,7 +935,7 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
if (!band_rule_found)
band_rule_found = freq_in_rule_band(fr, center_freq);
bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20));
bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(5));
if (band_rule_found && bw_fits)
return rr;
@ -986,10 +1019,10 @@ static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
}
#endif
/*
* Note that right now we assume the desired channel bandwidth
* is always 20 MHz for each individual channel (HT40 uses 20 MHz
* per channel, the primary and the extension channel).
/* Find an ieee80211_reg_rule such that a 5MHz channel with frequency
* chan->center_freq fits there.
* If there is no such reg_rule, disable the channel, otherwise set the
* flags corresponding to the bandwidths allowed in the particular reg_rule
*/
static void handle_channel(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator,
@ -1050,8 +1083,12 @@ static void handle_channel(struct wiphy *wiphy,
if (reg_rule->flags & NL80211_RRF_AUTO_BW)
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
if (max_bandwidth_khz < MHZ_TO_KHZ(10))
bw_flags = IEEE80211_CHAN_NO_10MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(20))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(40))
bw_flags = IEEE80211_CHAN_NO_HT40;
bw_flags |= IEEE80211_CHAN_NO_HT40;
if (max_bandwidth_khz < MHZ_TO_KHZ(80))
bw_flags |= IEEE80211_CHAN_NO_80MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(160))
@ -1071,6 +1108,13 @@ static void handle_channel(struct wiphy *wiphy,
(int) MBI_TO_DBI(power_rule->max_antenna_gain);
chan->max_reg_power = chan->max_power = chan->orig_mpwr =
(int) MBM_TO_DBM(power_rule->max_eirp);
if (chan->flags & IEEE80211_CHAN_RADAR) {
chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
if (reg_rule->dfs_cac_ms)
chan->dfs_cac_ms = reg_rule->dfs_cac_ms;
}
return;
}
@ -1126,12 +1170,19 @@ static bool reg_request_cell_base(struct regulatory_request *request)
return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
}
static bool reg_request_indoor(struct regulatory_request *request)
{
if (request->initiator != NL80211_REGDOM_SET_BY_USER)
return false;
return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
}
bool reg_last_request_cell_base(void)
{
return reg_request_cell_base(get_last_request());
}
#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS
#ifdef CONFIG_CFG80211_REG_CELLULAR_HINTS
/* Core specific check */
static enum reg_request_treatment
reg_ignore_cell_hint(struct regulatory_request *pending_request)
@ -1471,8 +1522,12 @@ static void handle_channel_custom(struct wiphy *wiphy,
if (reg_rule->flags & NL80211_RRF_AUTO_BW)
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
if (max_bandwidth_khz < MHZ_TO_KHZ(10))
bw_flags = IEEE80211_CHAN_NO_10MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(20))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(40))
bw_flags = IEEE80211_CHAN_NO_HT40;
bw_flags |= IEEE80211_CHAN_NO_HT40;
if (max_bandwidth_khz < MHZ_TO_KHZ(80))
bw_flags |= IEEE80211_CHAN_NO_80MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(160))
@ -1568,6 +1623,11 @@ __reg_process_hint_user(struct regulatory_request *user_request)
{
struct regulatory_request *lr = get_last_request();
if (reg_request_indoor(user_request)) {
reg_is_indoor = true;
return REG_REQ_USER_HINT_HANDLED;
}
if (reg_request_cell_base(user_request))
return reg_ignore_cell_hint(user_request);
@ -1615,8 +1675,9 @@ reg_process_hint_user(struct regulatory_request *user_request)
treatment = __reg_process_hint_user(user_request);
if (treatment == REG_REQ_IGNORE ||
treatment == REG_REQ_ALREADY_SET) {
kfree(user_request);
treatment == REG_REQ_ALREADY_SET ||
treatment == REG_REQ_USER_HINT_HANDLED) {
reg_free_request(user_request);
return treatment;
}
@ -1676,14 +1737,15 @@ reg_process_hint_driver(struct wiphy *wiphy,
case REG_REQ_OK:
break;
case REG_REQ_IGNORE:
kfree(driver_request);
case REG_REQ_USER_HINT_HANDLED:
reg_free_request(driver_request);
return treatment;
case REG_REQ_INTERSECT:
/* fall through */
case REG_REQ_ALREADY_SET:
regd = reg_copy_regd(get_cfg80211_regdom());
if (IS_ERR(regd)) {
kfree(driver_request);
reg_free_request(driver_request);
return REG_REQ_IGNORE;
}
rcu_assign_pointer(wiphy->regd, regd);
@ -1775,12 +1837,13 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
case REG_REQ_OK:
break;
case REG_REQ_IGNORE:
case REG_REQ_USER_HINT_HANDLED:
/* fall through */
case REG_REQ_ALREADY_SET:
kfree(country_ie_request);
reg_free_request(country_ie_request);
return treatment;
case REG_REQ_INTERSECT:
kfree(country_ie_request);
reg_free_request(country_ie_request);
/*
* This doesn't happen yet, not sure we
* ever want to support it for this case.
@ -1841,7 +1904,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
return;
out_free:
kfree(reg_request);
reg_free_request(reg_request);
}
/*
@ -1857,7 +1920,7 @@ static void reg_process_pending_hints(void)
/* When last_request->processed becomes true this will be rescheduled */
if (lr && !lr->processed) {
REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n");
reg_process_hint(lr);
return;
}
@ -1967,6 +2030,22 @@ int regulatory_hint_user(const char *alpha2,
return 0;
}
int regulatory_hint_indoor_user(void)
{
struct regulatory_request *request;
request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
if (!request)
return -ENOMEM;
request->wiphy_idx = WIPHY_IDX_INVALID;
request->initiator = NL80211_REGDOM_SET_BY_USER;
request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
queue_regulatory_request(request);
return 0;
}
/* Driver hints */
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
{
@ -2134,6 +2213,8 @@ static void restore_regulatory_settings(bool reset_user)
ASSERT_RTNL();
reg_is_indoor = false;
reset_regdomains(true, &world_regdom);
restore_alpha2(alpha2, reset_user);
@ -2594,7 +2675,7 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
reg_num_devs_support_basehint--;
rcu_free_regdom(get_wiphy_regdom(wiphy));
rcu_assign_pointer(wiphy->regd, NULL);
RCU_INIT_POINTER(wiphy->regd, NULL);
if (lr)
request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
@ -2614,6 +2695,40 @@ static void reg_timeout_work(struct work_struct *work)
rtnl_unlock();
}
/*
* See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for
* UNII band definitions
*/
int cfg80211_get_unii(int freq)
{
/* UNII-1 */
if (freq >= 5150 && freq <= 5250)
return 0;
/* UNII-2A */
if (freq > 5250 && freq <= 5350)
return 1;
/* UNII-2B */
if (freq > 5350 && freq <= 5470)
return 2;
/* UNII-2C */
if (freq > 5470 && freq <= 5725)
return 3;
/* UNII-3 */
if (freq > 5725 && freq <= 5825)
return 4;
return -EINVAL;
}
bool regulatory_indoor_allowed(void)
{
return reg_is_indoor;
}
int __init regulatory_init(void)
{
int err = 0;

View file

@ -25,6 +25,7 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);
int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type);
int regulatory_hint_indoor_user(void);
void wiphy_regulatory_register(struct wiphy *wiphy);
void wiphy_regulatory_deregister(struct wiphy *wiphy);
@ -104,4 +105,21 @@ void regulatory_hint_country_ie(struct wiphy *wiphy,
*/
void regulatory_hint_disconnect(void);
/**
* cfg80211_get_unii - get the U-NII band for the frequency
* @freq: the frequency for which we want to get the UNII band.
* Get a value specifying the U-NII band frequency belongs to.
* U-NII bands are defined by the FCC in C.F.R 47 part 15.
*
* Returns -EINVAL if freq is invalid, 0 for UNII-1, 1 for UNII-2A,
* 2 for UNII-2B, 3 for UNII-2C and 4 for UNII-3.
*/
int cfg80211_get_unii(int freq);
/**
* regulatory_indoor_allowed - is indoor operation allowed
*/
bool regulatory_indoor_allowed(void);
#endif /* __NET_WIRELESS_REG_H */

View file

@ -81,10 +81,10 @@ static void bss_free(struct cfg80211_internal_bss *bss)
kfree(bss);
}
static inline void bss_ref_get(struct cfg80211_registered_device *dev,
static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *bss)
{
lockdep_assert_held(&dev->bss_lock);
lockdep_assert_held(&rdev->bss_lock);
bss->refcount++;
if (bss->pub.hidden_beacon_bss) {
@ -95,10 +95,10 @@ static inline void bss_ref_get(struct cfg80211_registered_device *dev,
}
}
static inline void bss_ref_put(struct cfg80211_registered_device *dev,
static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *bss)
{
lockdep_assert_held(&dev->bss_lock);
lockdep_assert_held(&rdev->bss_lock);
if (bss->pub.hidden_beacon_bss) {
struct cfg80211_internal_bss *hbss;
@ -114,10 +114,10 @@ static inline void bss_ref_put(struct cfg80211_registered_device *dev,
bss_free(bss);
}
static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *bss)
{
lockdep_assert_held(&dev->bss_lock);
lockdep_assert_held(&rdev->bss_lock);
if (!list_empty(&bss->hidden_list)) {
/*
@ -134,31 +134,31 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
}
list_del_init(&bss->list);
rb_erase(&bss->rbn, &dev->bss_tree);
bss_ref_put(dev, bss);
rb_erase(&bss->rbn, &rdev->bss_tree);
bss_ref_put(rdev, bss);
return true;
}
static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
unsigned long expire_time)
{
struct cfg80211_internal_bss *bss, *tmp;
bool expired = false;
lockdep_assert_held(&dev->bss_lock);
lockdep_assert_held(&rdev->bss_lock);
list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
list_for_each_entry_safe(bss, tmp, &rdev->bss_list, list) {
if (atomic_read(&bss->hold))
continue;
if (!time_after(expire_time, bss->ts))
continue;
if (__cfg80211_unlink_bss(dev, bss))
if (__cfg80211_unlink_bss(rdev, bss))
expired = true;
}
if (expired)
dev->bss_generation++;
rdev->bss_generation++;
}
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
@ -238,11 +238,11 @@ void __cfg80211_scan_done(struct work_struct *wk)
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
{
trace_cfg80211_scan_done(request, aborted);
WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req);
request->aborted = aborted;
request->notified = true;
queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk);
queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk);
}
EXPORT_SYMBOL(cfg80211_scan_done);
@ -278,15 +278,15 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy)
{
trace_cfg80211_sched_scan_results(wiphy);
/* ignore if we're not scanning */
if (wiphy_to_dev(wiphy)->sched_scan_req)
if (wiphy_to_rdev(wiphy)->sched_scan_req)
queue_work(cfg80211_wq,
&wiphy_to_dev(wiphy)->sched_scan_results_wk);
&wiphy_to_rdev(wiphy)->sched_scan_results_wk);
}
EXPORT_SYMBOL(cfg80211_sched_scan_results);
void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
trace_cfg80211_sched_scan_stopped(wiphy);
@ -322,21 +322,21 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
return 0;
}
void cfg80211_bss_age(struct cfg80211_registered_device *dev,
void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
unsigned long age_secs)
{
struct cfg80211_internal_bss *bss;
unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
spin_lock_bh(&dev->bss_lock);
list_for_each_entry(bss, &dev->bss_list, list)
spin_lock_bh(&rdev->bss_lock);
list_for_each_entry(bss, &rdev->bss_list, list)
bss->ts -= age_jiffies;
spin_unlock_bh(&dev->bss_lock);
spin_unlock_bh(&rdev->bss_lock);
}
void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
void cfg80211_bss_expire(struct cfg80211_registered_device *rdev)
{
__cfg80211_bss_expire(dev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
__cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
}
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
@ -526,32 +526,34 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
const u8 *ssid, size_t ssid_len,
u16 capa_mask, u16 capa_val)
{
struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_internal_bss *bss, *res = NULL;
unsigned long now = jiffies;
trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask,
capa_val);
spin_lock_bh(&dev->bss_lock);
spin_lock_bh(&rdev->bss_lock);
list_for_each_entry(bss, &dev->bss_list, list) {
list_for_each_entry(bss, &rdev->bss_list, list) {
if ((bss->pub.capability & capa_mask) != capa_val)
continue;
if (channel && bss->pub.channel != channel)
continue;
if (!is_valid_ether_addr(bss->pub.bssid))
continue;
/* Don't get expired BSS structs */
if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
!atomic_read(&bss->hold))
continue;
if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
res = bss;
bss_ref_get(dev, res);
bss_ref_get(rdev, res);
break;
}
}
spin_unlock_bh(&dev->bss_lock);
spin_unlock_bh(&rdev->bss_lock);
if (!res)
return NULL;
trace_cfg80211_return_bss(&res->pub);
@ -559,10 +561,10 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
}
EXPORT_SYMBOL(cfg80211_get_bss);
static void rb_insert_bss(struct cfg80211_registered_device *dev,
static void rb_insert_bss(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *bss)
{
struct rb_node **p = &dev->bss_tree.rb_node;
struct rb_node **p = &rdev->bss_tree.rb_node;
struct rb_node *parent = NULL;
struct cfg80211_internal_bss *tbss;
int cmp;
@ -585,15 +587,15 @@ static void rb_insert_bss(struct cfg80211_registered_device *dev,
}
rb_link_node(&bss->rbn, parent, p);
rb_insert_color(&bss->rbn, &dev->bss_tree);
rb_insert_color(&bss->rbn, &rdev->bss_tree);
}
static struct cfg80211_internal_bss *
rb_find_bss(struct cfg80211_registered_device *dev,
rb_find_bss(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *res,
enum bss_compare_mode mode)
{
struct rb_node *n = dev->bss_tree.rb_node;
struct rb_node *n = rdev->bss_tree.rb_node;
struct cfg80211_internal_bss *bss;
int r;
@ -612,7 +614,7 @@ rb_find_bss(struct cfg80211_registered_device *dev,
return NULL;
}
static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *new)
{
const struct cfg80211_bss_ies *ies;
@ -642,7 +644,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
/* This is the bad part ... */
list_for_each_entry(bss, &dev->bss_list, list) {
list_for_each_entry(bss, &rdev->bss_list, list) {
if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid))
continue;
if (bss->pub.channel != new->pub.channel)
@ -676,7 +678,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
/* Returned bss is reference counted and must be cleaned up appropriately. */
static struct cfg80211_internal_bss *
cfg80211_bss_update(struct cfg80211_registered_device *dev,
cfg80211_bss_update(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *tmp,
bool signal_valid)
{
@ -687,14 +689,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
tmp->ts = jiffies;
spin_lock_bh(&dev->bss_lock);
spin_lock_bh(&rdev->bss_lock);
if (WARN_ON(!rcu_access_pointer(tmp->pub.ies))) {
spin_unlock_bh(&dev->bss_lock);
spin_unlock_bh(&rdev->bss_lock);
return NULL;
}
found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR);
found = rb_find_bss(rdev, tmp, BSS_CMP_REGULAR);
if (found) {
/* Update IEs */
@ -781,7 +783,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
* is allocated on the stack since it's not needed in the
* more common case of an update
*/
new = kzalloc(sizeof(*new) + dev->wiphy.bss_priv_size,
new = kzalloc(sizeof(*new) + rdev->wiphy.bss_priv_size,
GFP_ATOMIC);
if (!new) {
ies = (void *)rcu_dereference(tmp->pub.beacon_ies);
@ -797,9 +799,9 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
INIT_LIST_HEAD(&new->hidden_list);
if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
hidden = rb_find_bss(dev, tmp, BSS_CMP_HIDE_ZLEN);
hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
if (!hidden)
hidden = rb_find_bss(dev, tmp,
hidden = rb_find_bss(rdev, tmp,
BSS_CMP_HIDE_NUL);
if (hidden) {
new->pub.hidden_beacon_bss = &hidden->pub;
@ -816,24 +818,24 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
* expensive search for any probe responses that should
* be grouped with this beacon for updates ...
*/
if (!cfg80211_combine_bsses(dev, new)) {
if (!cfg80211_combine_bsses(rdev, new)) {
kfree(new);
goto drop;
}
}
list_add_tail(&new->list, &dev->bss_list);
rb_insert_bss(dev, new);
list_add_tail(&new->list, &rdev->bss_list);
rb_insert_bss(rdev, new);
found = new;
}
dev->bss_generation++;
bss_ref_get(dev, found);
spin_unlock_bh(&dev->bss_lock);
rdev->bss_generation++;
bss_ref_get(rdev, found);
spin_unlock_bh(&rdev->bss_lock);
return found;
drop:
spin_unlock_bh(&dev->bss_lock);
spin_unlock_bh(&rdev->bss_lock);
return NULL;
}
@ -917,7 +919,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
rcu_assign_pointer(tmp.pub.beacon_ies, ies);
rcu_assign_pointer(tmp.pub.ies, ies);
res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp,
res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp,
rx_channel == channel);
if (!res)
return NULL;
@ -989,7 +991,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp,
res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp,
rx_channel == channel);
if (!res)
return NULL;
@ -1005,7 +1007,7 @@ EXPORT_SYMBOL(cfg80211_inform_bss_width_frame);
void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
{
struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_internal_bss *bss;
if (!pub)
@ -1013,15 +1015,15 @@ void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
bss = container_of(pub, struct cfg80211_internal_bss, pub);
spin_lock_bh(&dev->bss_lock);
bss_ref_get(dev, bss);
spin_unlock_bh(&dev->bss_lock);
spin_lock_bh(&rdev->bss_lock);
bss_ref_get(rdev, bss);
spin_unlock_bh(&rdev->bss_lock);
}
EXPORT_SYMBOL(cfg80211_ref_bss);
void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
{
struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_internal_bss *bss;
if (!pub)
@ -1029,15 +1031,15 @@ void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
bss = container_of(pub, struct cfg80211_internal_bss, pub);
spin_lock_bh(&dev->bss_lock);
bss_ref_put(dev, bss);
spin_unlock_bh(&dev->bss_lock);
spin_lock_bh(&rdev->bss_lock);
bss_ref_put(rdev, bss);
spin_unlock_bh(&rdev->bss_lock);
}
EXPORT_SYMBOL(cfg80211_put_bss);
void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
{
struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_internal_bss *bss;
if (WARN_ON(!pub))
@ -1045,12 +1047,12 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
bss = container_of(pub, struct cfg80211_internal_bss, pub);
spin_lock_bh(&dev->bss_lock);
spin_lock_bh(&rdev->bss_lock);
if (!list_empty(&bss->list)) {
if (__cfg80211_unlink_bss(dev, bss))
dev->bss_generation++;
if (__cfg80211_unlink_bss(rdev, bss))
rdev->bss_generation++;
}
spin_unlock_bh(&dev->bss_lock);
spin_unlock_bh(&rdev->bss_lock);
}
EXPORT_SYMBOL(cfg80211_unlink_bss);
@ -1067,7 +1069,7 @@ cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)
if (!dev)
return ERR_PTR(-ENODEV);
if (dev->ieee80211_ptr)
rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
rdev = wiphy_to_rdev(dev->ieee80211_ptr->wiphy);
else
rdev = ERR_PTR(-ENODEV);
dev_put(dev);
@ -1147,7 +1149,11 @@ int cfg80211_wext_siwscan(struct net_device *dev,
int k;
int wiphy_freq = wiphy->bands[band]->channels[j].center_freq;
for (k = 0; k < wreq->num_channels; k++) {
int wext_freq = cfg80211_wext_freq(wiphy, &wreq->channel_list[k]);
struct iw_freq *freq =
&wreq->channel_list[k];
int wext_freq =
cfg80211_wext_freq(freq);
if (wext_freq == wiphy_freq)
goto wext_freq_found;
}
@ -1459,7 +1465,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
}
static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
struct iw_request_info *info,
char *buf, size_t len)
{
@ -1467,18 +1473,18 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
char *end_buf = buf + len;
struct cfg80211_internal_bss *bss;
spin_lock_bh(&dev->bss_lock);
cfg80211_bss_expire(dev);
spin_lock_bh(&rdev->bss_lock);
cfg80211_bss_expire(rdev);
list_for_each_entry(bss, &dev->bss_list, list) {
list_for_each_entry(bss, &rdev->bss_list, list) {
if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
spin_unlock_bh(&dev->bss_lock);
spin_unlock_bh(&rdev->bss_lock);
return -E2BIG;
}
current_ev = ieee80211_bss(&dev->wiphy, info, bss,
current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
current_ev, end_buf);
}
spin_unlock_bh(&dev->bss_lock);
spin_unlock_bh(&rdev->bss_lock);
return current_ev - buf;
}

View file

@ -59,7 +59,7 @@ static void cfg80211_sme_free(struct wireless_dev *wdev)
static int cfg80211_conn_scan(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_scan_request *request;
int n_channels, err;
@ -130,7 +130,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
static int cfg80211_conn_do_work(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_connect_params *params;
struct cfg80211_assoc_request req = {};
int err;
@ -245,7 +245,7 @@ void cfg80211_conn_work(struct work_struct *work)
/* Returned bss is reference counted and must be cleaned up appropriately. */
static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_bss *bss;
u16 capa = WLAN_CAPABILITY_ESS;
@ -275,7 +275,7 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
static void __cfg80211_sme_scan_done(struct net_device *dev)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_bss *bss;
ASSERT_WDEV_LOCK(wdev);
@ -306,7 +306,7 @@ void cfg80211_sme_scan_done(struct net_device *dev)
void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);
@ -352,7 +352,7 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
if (!wdev->conn)
return false;
@ -386,7 +386,7 @@ void cfg80211_sme_deauth(struct wireless_dev *wdev)
void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
if (!wdev->conn)
return;
@ -397,7 +397,7 @@ void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
void cfg80211_sme_disassoc(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
if (!wdev->conn)
return;
@ -408,7 +408,7 @@ void cfg80211_sme_disassoc(struct wireless_dev *wdev)
void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
if (!wdev->conn)
return;
@ -421,7 +421,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
struct cfg80211_connect_params *connect,
const u8 *prev_bssid)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_bss *bss;
int err;
@ -468,7 +468,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
}
wdev->conn->params.ssid = wdev->ssid;
wdev->conn->params.ssid_len = connect->ssid_len;
wdev->conn->params.ssid_len = wdev->ssid_len;
/* see if we have the bss already */
bss = cfg80211_get_conn_bss(wdev);
@ -480,7 +480,6 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
/* we're good if we have a matching bss struct */
if (bss) {
wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
err = cfg80211_conn_do_work(wdev);
cfg80211_put_bss(wdev->wiphy, bss);
} else {
@ -506,7 +505,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
int err;
if (!wdev->conn)
@ -594,7 +593,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
return;
}
nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev,
bssid, req_ie, req_ie_len,
resp_ie, resp_ie_len,
status, GFP_KERNEL);
@ -625,7 +624,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
#endif
if (!bss && (status == WLAN_STATUS_SUCCESS)) {
WARN_ON_ONCE(!wiphy_to_dev(wdev->wiphy)->ops->connect);
WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
wdev->ssid, wdev->ssid_len,
WLAN_CAPABILITY_ESS,
@ -687,7 +686,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
u16 status, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_event *ev;
unsigned long flags;
@ -742,7 +741,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
cfg80211_hold_bss(bss_from_pub(bss));
wdev->current_bss = bss_from_pub(bss);
nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bss->bssid,
nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
wdev->netdev, bss->bssid,
req_ie, req_ie_len, resp_ie, resp_ie_len,
GFP_KERNEL);
@ -801,7 +801,7 @@ void cfg80211_roamed_bss(struct net_device *dev,
size_t resp_ie_len, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_event *ev;
unsigned long flags;
@ -834,7 +834,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
size_t ie_len, u16 reason, bool from_ap)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
int i;
#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
@ -880,7 +880,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
u8 *ie, size_t ie_len, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_event *ev;
unsigned long flags;

View file

@ -1919,6 +1919,24 @@ TRACE_EVENT(rdev_set_qos_map,
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->num_des)
);
TRACE_EVENT(rdev_set_ap_chanwidth,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_chan_def *chandef),
TP_ARGS(wiphy, netdev, chandef),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
CHAN_DEF_ENTRY
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
CHAN_DEF_ASSIGN(chandef);
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT,
WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
);
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/
@ -2193,18 +2211,21 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
);
TRACE_EVENT(cfg80211_reg_can_beacon,
TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
TP_ARGS(wiphy, chandef),
TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype),
TP_ARGS(wiphy, chandef, iftype),
TP_STRUCT__entry(
WIPHY_ENTRY
CHAN_DEF_ENTRY
__field(enum nl80211_iftype, iftype)
),
TP_fast_assign(
WIPHY_ASSIGN;
CHAN_DEF_ASSIGN(chandef);
__entry->iftype = iftype;
),
TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
);
TRACE_EVENT(cfg80211_chandef_dfs_required,

View file

@ -770,7 +770,7 @@ EXPORT_SYMBOL(ieee80211_bss_get_ie);
void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct net_device *dev = wdev->netdev;
int i;
@ -888,11 +888,6 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
return -EBUSY;
if (ntype != otype && netif_running(dev)) {
err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
ntype);
if (err)
return err;
dev->ieee80211_ptr->use_4addr = false;
dev->ieee80211_ptr->mesh_id_up_len = 0;
wdev_lock(dev->ieee80211_ptr);
@ -1268,6 +1263,106 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
return res;
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
const int num_different_channels,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES],
void (*iter)(const struct ieee80211_iface_combination *c,
void *data),
void *data)
{
int i, j, iftype;
int num_interfaces = 0;
u32 used_iftypes = 0;
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
num_interfaces += iftype_num[iftype];
if (iftype_num[iftype] > 0 &&
!(wiphy->software_iftypes & BIT(iftype)))
used_iftypes |= BIT(iftype);
}
for (i = 0; i < wiphy->n_iface_combinations; i++) {
const struct ieee80211_iface_combination *c;
struct ieee80211_iface_limit *limits;
u32 all_iftypes = 0;
c = &wiphy->iface_combinations[i];
if (num_interfaces > c->max_interfaces)
continue;
if (num_different_channels > c->num_different_channels)
continue;
limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
GFP_KERNEL);
if (!limits)
return -ENOMEM;
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
if (wiphy->software_iftypes & BIT(iftype))
continue;
for (j = 0; j < c->n_limits; j++) {
all_iftypes |= limits[j].types;
if (!(limits[j].types & BIT(iftype)))
continue;
if (limits[j].max < iftype_num[iftype])
goto cont;
limits[j].max -= iftype_num[iftype];
}
}
if (radar_detect != (c->radar_detect_widths & radar_detect))
goto cont;
/* Finally check that all iftypes that we're currently
* using are actually part of this combination. If they
* aren't then we can't use this combination and have
* to continue to the next.
*/
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
/* This combination covered all interface types and
* supported the requested numbers, so we're good.
*/
(*iter)(c, data);
cont:
kfree(limits);
}
return 0;
}
EXPORT_SYMBOL(cfg80211_iter_combinations);
static void
cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
void *data)
{
int *num = data;
(*num)++;
}
int cfg80211_check_combinations(struct wiphy *wiphy,
const int num_different_channels,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES])
{
int err, num = 0;
err = cfg80211_iter_combinations(wiphy, num_different_channels,
radar_detect, iftype_num,
cfg80211_iter_sum_ifcombs, &num);
if (err)
return err;
if (num == 0)
return -EBUSY;
return 0;
}
EXPORT_SYMBOL(cfg80211_check_combinations);
int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
enum nl80211_iftype iftype,
@ -1276,7 +1371,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
u8 radar_detect)
{
struct wireless_dev *wdev_iter;
u32 used_iftypes = BIT(iftype);
int num[NUM_NL80211_IFTYPES];
struct ieee80211_channel
*used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS];
@ -1284,7 +1378,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
enum cfg80211_chan_mode chmode;
int num_different_channels = 0;
int total = 1;
int i, j;
int i;
ASSERT_RTNL();
@ -1306,6 +1400,11 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
num[iftype] = 1;
/* TODO: We'll probably not need this anymore, since this
* should only be called with CHAN_MODE_UNDEFINED. There are
* still a couple of pending calls where other chanmodes are
* used, but we should get rid of them.
*/
switch (chanmode) {
case CHAN_MODE_UNDEFINED:
break;
@ -1369,65 +1468,13 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
num[wdev_iter->iftype]++;
total++;
used_iftypes |= BIT(wdev_iter->iftype);
}
if (total == 1 && !radar_detect)
return 0;
for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
const struct ieee80211_iface_combination *c;
struct ieee80211_iface_limit *limits;
u32 all_iftypes = 0;
c = &rdev->wiphy.iface_combinations[i];
if (total > c->max_interfaces)
continue;
if (num_different_channels > c->num_different_channels)
continue;
limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
GFP_KERNEL);
if (!limits)
return -ENOMEM;
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
if (rdev->wiphy.software_iftypes & BIT(iftype))
continue;
for (j = 0; j < c->n_limits; j++) {
all_iftypes |= limits[j].types;
if (!(limits[j].types & BIT(iftype)))
continue;
if (limits[j].max < num[iftype])
goto cont;
limits[j].max -= num[iftype];
}
}
if (radar_detect && !(c->radar_detect_widths & radar_detect))
goto cont;
/*
* Finally check that all iftypes that we're currently
* using are actually part of this combination. If they
* aren't then we can't use this combination and have
* to continue to the next.
*/
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
/*
* This combination covered all interface types and
* supported the requested numbers, so we're good.
*/
kfree(limits);
return 0;
cont:
kfree(limits);
}
return -EBUSY;
return cfg80211_check_combinations(&rdev->wiphy, num_different_channels,
radar_detect, num);
}
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,

View file

@ -73,7 +73,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
struct vif_params vifparams;
enum nl80211_iftype type;
rdev = wiphy_to_dev(wdev->wiphy);
rdev = wiphy_to_rdev(wdev->wiphy);
switch (*mode) {
case IW_MODE_INFRA:
@ -253,12 +253,12 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
/**
* cfg80211_wext_freq - get wext frequency for non-"auto"
* @wiphy: the wiphy
* @dev: the net device
* @freq: the wext freq encoding
*
* Returns a frequency, or a negative error code, or 0 for auto.
*/
int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq)
int cfg80211_wext_freq(struct iw_freq *freq)
{
/*
* Parse frequency - return 0 for auto and
@ -286,7 +286,7 @@ int cfg80211_wext_siwrts(struct net_device *dev,
struct iw_param *rts, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
u32 orts = wdev->wiphy->rts_threshold;
int err;
@ -324,7 +324,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev,
struct iw_param *frag, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
u32 ofrag = wdev->wiphy->frag_threshold;
int err;
@ -364,7 +364,7 @@ static int cfg80211_wext_siwretry(struct net_device *dev,
struct iw_param *retry, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
u32 changed = 0;
u8 olong = wdev->wiphy->retry_long;
u8 oshort = wdev->wiphy->retry_short;
@ -587,7 +587,7 @@ static int cfg80211_wext_siwencode(struct net_device *dev,
struct iw_point *erq, char *keybuf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
int idx, err;
bool remove = false;
struct key_params params;
@ -647,7 +647,7 @@ static int cfg80211_wext_siwencodeext(struct net_device *dev,
struct iw_point *erq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
const u8 *addr;
int idx;
@ -775,7 +775,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
struct iw_freq *wextfreq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_chan_def chandef = {
.width = NL80211_CHAN_WIDTH_20_NOHT,
};
@ -787,7 +787,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
case NL80211_IFTYPE_MONITOR:
freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
freq = cfg80211_wext_freq(wextfreq);
if (freq < 0)
return freq;
if (freq == 0)
@ -798,7 +798,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
return -EINVAL;
return cfg80211_set_monitor_channel(rdev, &chandef);
case NL80211_IFTYPE_MESH_POINT:
freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
freq = cfg80211_wext_freq(wextfreq);
if (freq < 0)
return freq;
if (freq == 0)
@ -818,7 +818,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
struct iw_freq *freq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_chan_def chandef;
int ret;
@ -847,7 +847,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev,
union iwreq_data *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
enum nl80211_tx_power_setting type;
int dbm = 0;
@ -899,7 +899,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev,
union iwreq_data *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
int err, val;
if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
@ -1119,7 +1119,7 @@ static int cfg80211_wext_siwpower(struct net_device *dev,
struct iw_param *wrq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
bool ps = wdev->ps;
int timeout = wdev->ps_timeout;
int err;
@ -1177,7 +1177,7 @@ static int cfg80211_wds_wext_siwap(struct net_device *dev,
struct sockaddr *addr, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
int err;
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS))
@ -1221,7 +1221,7 @@ static int cfg80211_wext_siwrate(struct net_device *dev,
struct iw_param *rate, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_bitrate_mask mask;
u32 fixed, maxrate;
struct ieee80211_supported_band *sband;
@ -1272,7 +1272,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
struct iw_param *rate, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
/* we are under RTNL - globally locked - so can use a static struct */
static struct station_info sinfo;
u8 addr[ETH_ALEN];
@ -1310,7 +1310,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
/* we are under RTNL - globally locked - so can use static structs */
static struct iw_statistics wstats;
static struct station_info sinfo;
@ -1449,7 +1449,7 @@ static int cfg80211_wext_siwpmksa(struct net_device *dev,
struct iw_point *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_pmksa cfg_pmksa;
struct iw_pmksa *pmksa = (struct iw_pmksa *)extra;

View file

@ -50,7 +50,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
struct iw_point *data, char *extra);
int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq);
int cfg80211_wext_freq(struct iw_freq *freq);
extern const struct iw_handler_def cfg80211_wext_handler;

View file

@ -67,7 +67,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
struct iw_freq *wextfreq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct ieee80211_channel *chan = NULL;
int err, freq;
@ -75,7 +75,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
return -EINVAL;
freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
freq = cfg80211_wext_freq(wextfreq);
if (freq < 0)
return freq;
@ -169,7 +169,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
struct iw_point *data, char *ssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
size_t len = data->length;
int err;
@ -260,7 +260,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
struct sockaddr *ap_addr, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
u8 *bssid = ap_addr->sa_data;
int err;
@ -333,7 +333,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
struct iw_point *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
u8 *ie = extra;
int ie_len = data->length, err;
@ -390,7 +390,7 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
if (!wdev)
return -EOPNOTSUPP;
rdev = wiphy_to_dev(wdev->wiphy);
rdev = wiphy_to_rdev(wdev->wiphy);
if (wdev->iftype != NL80211_IFTYPE_STATION)
return -EINVAL;