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:
commit
f6595444c1
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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[])
|
||||
|
|
|
@ -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, ¶ms->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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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, ¶ms.chandef)) {
|
||||
if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.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,
|
||||
¶ms.chandef);
|
||||
¶ms.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(¶ms.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,
|
||||
¶ms->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, ¶ms->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(¶ms->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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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, },
|
||||
|
|
|
@ -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,
|
||||
¶ms.chandef);
|
||||
¶ms.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(¶ms.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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define MICHAEL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/ieee80211.h>
|
||||
|
||||
#define MICHAEL_MIC_LEN 8
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue