For the current cycle, we have the following right now:
* many internal fixes, API improvements, cleanups, etc. * full AP client state tracking in cfg80211/mac80211 from Ayala * VHT support (in mac80211) for mesh * some A-MSDU in A-MPDU support from Emmanuel * show current TX power to userspace (from Rafał) * support for netlink dump in vendor commands (myself) -----BEGIN PGP SIGNATURE----- iQIcBAABCAAGBQJWEp5XAAoJEDBSmw7B7bqr8DsQAICgQL7gSkHUlc6rbMJ9MzX+ 9W0SNpZHSmfE0ZsL3cCoeHbk5dGhX82GumIz4GeqtvIKUNHkC8qlnXJIKTEva+sp PjcF1wS0qQFdt6sg/Zxq+4Q8lZrZf1xP9W0x0ORYi9d9qej07JAZku8zYt4agpNV R4nCl/gKVF375aV8y+qi+WSZXx4j80dJkokoVk4hzotWjd0bGVL1T9YwDRzxg4FI S0DnkxlsD3MRHJXq+9+DbF5cuTjCG2LZNcDIBy455eWN27j9CWgEPVXoySQjDgQc ayf2siw7BccqnV84et0vi+0WYXdZCHm3zCen44s4vaCflhdGxdx48V+Lib6mluR3 OEM1V1l9uV97UyORPljRKvDURq2IUdLQw00of26CTX8qEnmQIfxC7qaRg0rYEiGW SbTClbEiEkBLV+sCStnkv8GJHNpvtI/2VQXH1ydrHsrWC3Sl9bpPOWYlNBPwdzM9 U4zgpxf6gLqlsukQKmMDmoKW7T04Fs0qgE99ThU2x6uTGsux8bfbxgzPCfUdeY8M HmCB5oBCZKJ5pzv6z6lUGc0cO42IL50aBrrlatrEekjevUXW3MMOZCwGrUXxpMw1 gd+2PnLCCUeDyKNvkpXEgr4uS9Egc0sWH1RlpDPaAA5gRdRHiDn7MK7Z+s5OpNIC wnFCQKB+KrNNrQFuXz9k =BF9F -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2015-10-05' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== For the current cycle, we have the following right now: * many internal fixes, API improvements, cleanups, etc. * full AP client state tracking in cfg80211/mac80211 from Ayala * VHT support (in mac80211) for mesh * some A-MSDU in A-MPDU support from Emmanuel * show current TX power to userspace (from Rafał) * support for netlink dump in vendor commands (myself) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
2579c98f0d
|
@ -6144,7 +6144,7 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
|
|
|
@ -1659,7 +1659,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn, u8 buf_size)
|
||||
u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct ath9k_htc_priv *priv = hw->priv;
|
||||
struct ath9k_htc_sta *ista;
|
||||
|
|
|
@ -1856,7 +1856,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn, u8 buf_size)
|
||||
u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
|
|
@ -1415,7 +1415,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn, u8 buf_size)
|
||||
u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct ar9170 *ar = hw->priv;
|
||||
struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
|
||||
|
|
|
@ -859,7 +859,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct wcn36xx *wcn = hw->priv;
|
||||
struct wcn36xx_sta *sta_priv = NULL;
|
||||
|
|
|
@ -820,7 +820,7 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct brcms_info *wl = hw->priv;
|
||||
struct scb *scb = &wl->wlc->pri_scb;
|
||||
|
|
|
@ -2137,7 +2137,7 @@ int cw1200_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
/* Aggregation is implemented fully in firmware,
|
||||
* including block ack negotiation. Do not allow
|
||||
|
|
|
@ -111,7 +111,7 @@ int cw1200_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size);
|
||||
u8 buf_size, bool amsdu);
|
||||
|
||||
void cw1200_suspend_resume(struct cw1200_common *priv,
|
||||
struct wsm_suspend_resume *arg);
|
||||
|
|
|
@ -1091,8 +1091,6 @@ static const char *get_info_element_string(u16 id)
|
|||
MFIE_STRING(TIM);
|
||||
MFIE_STRING(IBSS_PARAMS);
|
||||
MFIE_STRING(COUNTRY);
|
||||
MFIE_STRING(HP_PARAMS);
|
||||
MFIE_STRING(HP_TABLE);
|
||||
MFIE_STRING(REQUEST);
|
||||
MFIE_STRING(CHALLENGE);
|
||||
MFIE_STRING(PWR_CONSTRAINT);
|
||||
|
|
|
@ -5984,7 +5984,7 @@ int
|
|||
il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 * ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct il_priv *il = hw->priv;
|
||||
int ret = -EINVAL;
|
||||
|
|
|
@ -184,7 +184,7 @@ void il4965_mac_update_tkip_key(struct ieee80211_hw *hw,
|
|||
int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 * ssn,
|
||||
u8 buf_size);
|
||||
u8 buf_size, bool amsdu);
|
||||
int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
void
|
||||
|
|
|
@ -731,7 +731,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
int ret = -EINVAL;
|
||||
|
|
|
@ -820,7 +820,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn, u8 buf_size)
|
||||
u16 *ssn, u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
int ret;
|
||||
|
|
|
@ -1819,7 +1819,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
|
|
|
@ -335,7 +335,8 @@ static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
|||
static int
|
||||
mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size,
|
||||
bool amsdu)
|
||||
{
|
||||
struct mt7601u_dev *dev = hw->priv;
|
||||
struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
|
||||
|
|
|
@ -5423,7 +5423,7 @@ static int
|
|||
mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
|
||||
int i, rc = 0;
|
||||
|
|
|
@ -664,6 +664,7 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw,
|
|||
* @tid: Traffic identifier.
|
||||
* @ssn: Pointer to ssn value.
|
||||
* @buf_size: Buffer size (for kernel version > 2.6.38).
|
||||
* @amsdu: is AMSDU in AMPDU allowed
|
||||
*
|
||||
* Return: status: 0 on success, negative error code on failure.
|
||||
*/
|
||||
|
@ -673,7 +674,8 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_sta *sta,
|
||||
unsigned short tid,
|
||||
unsigned short *ssn,
|
||||
unsigned char buf_size)
|
||||
unsigned char buf_size,
|
||||
bool amsdu)
|
||||
{
|
||||
int status = -EOPNOTSUPP;
|
||||
struct rsi_hw *adapter = hw->priv;
|
||||
|
|
|
@ -7937,7 +7937,7 @@ EXPORT_SYMBOL_GPL(rt2800_get_tsf);
|
|||
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv;
|
||||
int ret = 0;
|
||||
|
|
|
@ -220,7 +220,7 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
|||
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size);
|
||||
u8 buf_size, bool amsdu);
|
||||
int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey);
|
||||
void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev);
|
||||
|
|
|
@ -1373,7 +1373,7 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
|
||||
|
|
|
@ -5263,7 +5263,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
u8 buf_size, bool amsdu)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
|
|
|
@ -1379,6 +1379,7 @@ struct ieee80211_ht_operation {
|
|||
|
||||
|
||||
/* block-ack parameters */
|
||||
#define IEEE80211_ADDBA_PARAM_AMSDU_MASK 0x0001
|
||||
#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
|
||||
#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
|
||||
#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0
|
||||
|
@ -1745,8 +1746,7 @@ enum ieee80211_eid {
|
|||
WLAN_EID_TIM = 5,
|
||||
WLAN_EID_IBSS_PARAMS = 6,
|
||||
WLAN_EID_COUNTRY = 7,
|
||||
WLAN_EID_HP_PARAMS = 8,
|
||||
WLAN_EID_HP_TABLE = 9,
|
||||
/* 8, 9 reserved */
|
||||
WLAN_EID_REQUEST = 10,
|
||||
WLAN_EID_QBSS_LOAD = 11,
|
||||
WLAN_EID_EDCA_PARAM_SET = 12,
|
||||
|
|
|
@ -858,6 +858,8 @@ struct station_del_parameters {
|
|||
/**
|
||||
* enum cfg80211_station_type - the type of station being modified
|
||||
* @CFG80211_STA_AP_CLIENT: client of an AP interface
|
||||
* @CFG80211_STA_AP_CLIENT_UNASSOC: client of an AP interface that is still
|
||||
* unassociated (update properties for this type of client is permitted)
|
||||
* @CFG80211_STA_AP_MLME_CLIENT: client of an AP interface that has
|
||||
* the AP MLME in the device
|
||||
* @CFG80211_STA_AP_STA: AP station on managed interface
|
||||
|
@ -873,6 +875,7 @@ struct station_del_parameters {
|
|||
*/
|
||||
enum cfg80211_station_type {
|
||||
CFG80211_STA_AP_CLIENT,
|
||||
CFG80211_STA_AP_CLIENT_UNASSOC,
|
||||
CFG80211_STA_AP_MLME_CLIENT,
|
||||
CFG80211_STA_AP_STA,
|
||||
CFG80211_STA_IBSS,
|
||||
|
@ -2971,12 +2974,21 @@ enum wiphy_vendor_command_flags {
|
|||
* @doit: callback for the operation, note that wdev is %NULL if the
|
||||
* flags didn't ask for a wdev and non-%NULL otherwise; the data
|
||||
* pointer may be %NULL if userspace provided no data at all
|
||||
* @dumpit: dump callback, for transferring bigger/multiple items. The
|
||||
* @storage points to cb->args[5], ie. is preserved over the multiple
|
||||
* dumpit calls.
|
||||
* It's recommended to not have the same sub command with both @doit and
|
||||
* @dumpit, so that userspace can assume certain ones are get and others
|
||||
* are used with dump requests.
|
||||
*/
|
||||
struct wiphy_vendor_command {
|
||||
struct nl80211_vendor_cmd_info info;
|
||||
u32 flags;
|
||||
int (*doit)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const void *data, int data_len);
|
||||
int (*dumpit)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct sk_buff *skb, const void *data, int data_len,
|
||||
unsigned long *storage);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -1360,6 +1361,8 @@ enum ieee80211_vif_flags {
|
|||
* @debugfs_dir: debugfs dentry, can be used by drivers to create own per
|
||||
* interface debug files. Note that it will be NULL for the virtual
|
||||
* monitor interface (if that is requested.)
|
||||
* @probe_req_reg: probe requests should be reported to mac80211 for this
|
||||
* interface.
|
||||
* @drv_priv: data area for driver use, will always be aligned to
|
||||
* sizeof(void *).
|
||||
* @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
|
||||
|
@ -1384,6 +1387,8 @@ struct ieee80211_vif {
|
|||
struct dentry *debugfs_dir;
|
||||
#endif
|
||||
|
||||
unsigned int probe_req_reg;
|
||||
|
||||
/* must be last */
|
||||
u8 drv_priv[0] __aligned(sizeof(void *));
|
||||
};
|
||||
|
@ -1494,10 +1499,8 @@ enum ieee80211_key_flags {
|
|||
* - Temporal Authenticator Rx MIC Key (64 bits)
|
||||
* @icv_len: The ICV length for this key type
|
||||
* @iv_len: The IV length for this key type
|
||||
* @drv_priv: pointer for driver use
|
||||
*/
|
||||
struct ieee80211_key_conf {
|
||||
void *drv_priv;
|
||||
atomic64_t tx_pn;
|
||||
u32 cipher;
|
||||
u8 icv_len;
|
||||
|
@ -1894,6 +1897,12 @@ struct ieee80211_txq {
|
|||
* @IEEE80211_HW_TDLS_WIDER_BW: The device/driver supports wider bandwidth
|
||||
* than then BSS bandwidth for a TDLS link on the base channel.
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU: The driver supports receiving A-MSDUs
|
||||
* within A-MPDU.
|
||||
*
|
||||
* @IEEE80211_HW_BEACON_TX_STATUS: The device/driver provides TX status
|
||||
* for sent beacons.
|
||||
*
|
||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
|
@ -1927,6 +1936,8 @@ enum ieee80211_hw_flags {
|
|||
IEEE80211_HW_SUPPORTS_CLONED_SKBS,
|
||||
IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS,
|
||||
IEEE80211_HW_TDLS_WIDER_BW,
|
||||
IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
|
||||
IEEE80211_HW_BEACON_TX_STATUS,
|
||||
|
||||
/* keep last, obviously */
|
||||
NUM_IEEE80211_HW_FLAGS
|
||||
|
@ -2827,6 +2838,13 @@ enum ieee80211_reconfig_type {
|
|||
* See the section "Frame filtering" for more information.
|
||||
* This callback must be implemented and can sleep.
|
||||
*
|
||||
* @config_iface_filter: Configure the interface's RX filter.
|
||||
* This callback is optional and is used to configure which frames
|
||||
* should be passed to mac80211. The filter_flags is the combination
|
||||
* of FIF_* flags. The changed_flags is a bit mask that indicates
|
||||
* which flags are changed.
|
||||
* This callback can sleep.
|
||||
*
|
||||
* @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
|
||||
* must be set or cleared for a given STA. Must be atomic.
|
||||
*
|
||||
|
@ -3016,6 +3034,9 @@ enum ieee80211_reconfig_type {
|
|||
* buffer size of 8. Correct ways to retransmit #1 would be:
|
||||
* - TX: 1 or 18 or 81
|
||||
* Even "189" would be wrong since 1 could be lost again.
|
||||
* The @amsdu parameter is valid when the action is set to
|
||||
* %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's ability
|
||||
* to receive A-MSDU within A-MPDU.
|
||||
*
|
||||
* Returns a negative error code on failure.
|
||||
* The callback can sleep.
|
||||
|
@ -3266,6 +3287,10 @@ struct ieee80211_ops {
|
|||
unsigned int changed_flags,
|
||||
unsigned int *total_flags,
|
||||
u64 multicast);
|
||||
void (*config_iface_filter)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
unsigned int filter_flags,
|
||||
unsigned int changed_flags);
|
||||
int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
||||
bool set);
|
||||
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
|
@ -3349,7 +3374,7 @@ struct ieee80211_ops {
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size);
|
||||
u8 buf_size, bool amsdu);
|
||||
int (*get_survey)(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey);
|
||||
void (*rfkill_poll)(struct ieee80211_hw *hw);
|
||||
|
|
|
@ -79,7 +79,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
|||
(int)reason);
|
||||
|
||||
if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL, 0))
|
||||
&sta->sta, tid, NULL, 0, false))
|
||||
sdata_info(sta->sdata,
|
||||
"HW problem - can not stop rx aggregation for %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
|
@ -189,6 +189,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
bool amsdu = ieee80211_hw_check(&local->hw, SUPPORTS_AMSDU_IN_AMPDU);
|
||||
u16 capab;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
|
||||
|
@ -217,7 +218,8 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
|
|||
mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
|
||||
mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
|
||||
|
||||
capab = (u16)(policy << 1); /* bit 1 aggregation policy */
|
||||
capab = (u16)(amsdu << 0); /* bit 0 A-MSDU support */
|
||||
capab |= (u16)(policy << 1); /* bit 1 aggregation policy */
|
||||
capab |= (u16)(tid << 2); /* bit 5:2 TID number */
|
||||
capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */
|
||||
|
||||
|
@ -321,7 +323,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
|||
__skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
|
||||
|
||||
ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num, 0);
|
||||
&sta->sta, tid, &start_seq_num, 0, false);
|
||||
ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
|
||||
sta->sta.addr, tid, ret);
|
||||
if (ret) {
|
||||
|
|
|
@ -97,7 +97,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
|
|||
mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
|
||||
|
||||
mgmt->u.action.u.addba_req.dialog_token = dialog_token;
|
||||
capab = (u16)(1 << 1); /* bit 1 aggregation policy */
|
||||
capab = (u16)(1 << 0); /* bit 0 A-MSDU support */
|
||||
capab |= (u16)(1 << 1); /* bit 1 aggregation policy */
|
||||
capab |= (u16)(tid << 2); /* bit 5:2 TID number */
|
||||
capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
|
||||
|
||||
|
@ -331,7 +332,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
|||
return -EALREADY;
|
||||
ret = drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
|
||||
&sta->sta, tid, NULL, 0);
|
||||
&sta->sta, tid, NULL, 0, false);
|
||||
WARN_ON_ONCE(ret);
|
||||
return 0;
|
||||
}
|
||||
|
@ -381,7 +382,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
|||
tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
|
||||
|
||||
ret = drv_ampdu_action(local, sta->sdata, action,
|
||||
&sta->sta, tid, NULL, 0);
|
||||
&sta->sta, tid, NULL, 0, false);
|
||||
|
||||
/* HW shall not deny going back to legacy */
|
||||
if (WARN_ON(ret)) {
|
||||
|
@ -469,7 +470,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
|||
start_seq_num = sta->tid_seq[tid] >> 4;
|
||||
|
||||
ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
|
||||
&sta->sta, tid, &start_seq_num, 0);
|
||||
&sta->sta, tid, &start_seq_num, 0, false);
|
||||
if (ret) {
|
||||
ht_dbg(sdata,
|
||||
"BA request denied - HW unavailable for %pM tid %d\n",
|
||||
|
@ -693,7 +694,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
|
|||
|
||||
drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
&sta->sta, tid, NULL, tid_tx->buf_size);
|
||||
&sta->sta, tid, NULL, tid_tx->buf_size,
|
||||
tid_tx->amsdu);
|
||||
|
||||
/*
|
||||
* synchronize with TX path, while splicing the TX path
|
||||
|
@ -918,8 +920,10 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
|||
struct tid_ampdu_tx *tid_tx;
|
||||
u16 capab, tid;
|
||||
u8 buf_size;
|
||||
bool amsdu;
|
||||
|
||||
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
|
||||
amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
|
||||
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
|
||||
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
|
||||
|
||||
|
@ -968,6 +972,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
|||
}
|
||||
|
||||
tid_tx->buf_size = buf_size;
|
||||
tid_tx->amsdu = amsdu;
|
||||
|
||||
if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))
|
||||
ieee80211_agg_tx_operational(local, sta, tid);
|
||||
|
|
|
@ -981,7 +981,7 @@ static int sta_apply_auth_flags(struct ieee80211_local *local,
|
|||
* well. Some drivers require rate control initialized
|
||||
* before drv_sta_state() is called.
|
||||
*/
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
|
||||
if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
|
@ -1120,8 +1120,11 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
|||
local->hw.queues >= IEEE80211_NUM_ACS)
|
||||
sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
|
||||
|
||||
/* auth flags will be set later for TDLS stations */
|
||||
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
|
||||
/* auth flags will be set later for TDLS,
|
||||
* and for unassociated stations that move to assocaited */
|
||||
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
|
||||
!((mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) &&
|
||||
(set & BIT(NL80211_STA_FLAG_ASSOCIATED)))) {
|
||||
ret = sta_apply_auth_flags(local, sta, mask, set);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1156,6 +1159,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
|||
set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH);
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
|
||||
!sdata->u.mgd.tdls_wider_bw_prohibited &&
|
||||
ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) &&
|
||||
params->ext_capab_len >= 8 &&
|
||||
params->ext_capab[7] & WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED)
|
||||
|
@ -1212,7 +1216,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
|||
sta_apply_mesh_params(local, sta, params);
|
||||
|
||||
/* set the STA state after all sta info from usermode has been set */
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
|
||||
set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
|
||||
ret = sta_apply_auth_flags(local, sta, mask, set);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1254,12 +1259,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
|
|||
* defaults -- if userspace wants something else we'll
|
||||
* change it accordingly in sta_apply_parameters()
|
||||
*/
|
||||
if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) {
|
||||
if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
|
||||
!(params->sta_flags_set & (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
|
||||
BIT(NL80211_STA_FLAG_ASSOCIATED)))) {
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
} else {
|
||||
sta->sta.tdls = true;
|
||||
}
|
||||
if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
|
||||
sta->sta.tdls = true;
|
||||
|
||||
err = sta_apply_parameters(local, sta, params);
|
||||
if (err) {
|
||||
|
@ -1268,10 +1275,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
|
|||
}
|
||||
|
||||
/*
|
||||
* for TDLS, rate control should be initialized only when
|
||||
* rates are known and station is marked authorized
|
||||
* for TDLS and for unassociated station, rate control should be
|
||||
* initialized only when rates are known and station is marked
|
||||
* authorized/associated
|
||||
*/
|
||||
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
|
||||
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
|
||||
test_sta_flag(sta, WLAN_STA_ASSOC))
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||
|
@ -1346,7 +1355,10 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
|||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
if (test_sta_flag(sta, WLAN_STA_ASSOC))
|
||||
statype = CFG80211_STA_AP_CLIENT;
|
||||
else
|
||||
statype = CFG80211_STA_AP_CLIENT_UNASSOC;
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
|
@ -3522,18 +3534,32 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
|
|||
u16 frame_type, bool reg)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
|
||||
switch (frame_type) {
|
||||
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
|
||||
if (reg)
|
||||
if (reg) {
|
||||
local->probe_req_reg++;
|
||||
else
|
||||
sdata->vif.probe_req_reg++;
|
||||
} else {
|
||||
if (local->probe_req_reg)
|
||||
local->probe_req_reg--;
|
||||
|
||||
if (sdata->vif.probe_req_reg)
|
||||
sdata->vif.probe_req_reg--;
|
||||
}
|
||||
|
||||
if (!local->open_count)
|
||||
break;
|
||||
|
||||
ieee80211_queue_work(&local->hw, &local->reconfig_filter);
|
||||
if (sdata->vif.probe_req_reg == 1)
|
||||
drv_config_iface_filter(local, sdata, FIF_PROBE_REQ,
|
||||
FIF_PROBE_REQ);
|
||||
else if (sdata->vif.probe_req_reg == 0)
|
||||
drv_config_iface_filter(local, sdata, 0,
|
||||
FIF_PROBE_REQ);
|
||||
|
||||
ieee80211_configure_filter(local);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -123,6 +123,8 @@ static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = {
|
|||
FLAG(SUPPORTS_CLONED_SKBS),
|
||||
FLAG(SINGLE_SCAN_ON_ALL_BANDS),
|
||||
FLAG(TDLS_WIDER_BW),
|
||||
FLAG(SUPPORTS_AMSDU_IN_AMPDU),
|
||||
FLAG(BEACON_TX_STATUS),
|
||||
|
||||
/* keep last for the build bug below */
|
||||
(void *)0x1
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright 2003-2005 Devicescape Software, Inc.
|
||||
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright (C) 2015 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -34,6 +35,14 @@ static const struct file_operations key_ ##name## _ops = { \
|
|||
.llseek = generic_file_llseek, \
|
||||
}
|
||||
|
||||
#define KEY_OPS_W(name) \
|
||||
static const struct file_operations key_ ##name## _ops = { \
|
||||
.read = key_##name##_read, \
|
||||
.write = key_##name##_write, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
}
|
||||
|
||||
#define KEY_FILE(name, format) \
|
||||
KEY_READ_##format(name) \
|
||||
KEY_OPS(name)
|
||||
|
@ -74,6 +83,41 @@ static ssize_t key_algorithm_read(struct file *file,
|
|||
}
|
||||
KEY_OPS(algorithm);
|
||||
|
||||
static ssize_t key_tx_spec_write(struct file *file, const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_key *key = file->private_data;
|
||||
u64 pn;
|
||||
int ret;
|
||||
|
||||
switch (key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
return -EINVAL;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
/* not supported yet */
|
||||
return -EOPNOTSUPP;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
ret = kstrtou64_from_user(userbuf, count, 16, &pn);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* PN is a 48-bit counter */
|
||||
if (pn >= (1ULL << 48))
|
||||
return -ERANGE;
|
||||
atomic64_set(&key->conf.tx_pn, pn);
|
||||
return count;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -110,7 +154,7 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
|
|||
}
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, len);
|
||||
}
|
||||
KEY_OPS(tx_spec);
|
||||
KEY_OPS_W(tx_spec);
|
||||
|
||||
static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
|
@ -278,6 +322,9 @@ KEY_OPS(key);
|
|||
#define DEBUGFS_ADD(name) \
|
||||
debugfs_create_file(#name, 0400, key->debugfs.dir, \
|
||||
key, &key_##name##_ops);
|
||||
#define DEBUGFS_ADD_W(name) \
|
||||
debugfs_create_file(#name, 0600, key->debugfs.dir, \
|
||||
key, &key_##name##_ops);
|
||||
|
||||
void ieee80211_debugfs_key_add(struct ieee80211_key *key)
|
||||
{
|
||||
|
@ -310,7 +357,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key)
|
|||
DEBUGFS_ADD(keyidx);
|
||||
DEBUGFS_ADD(hw_key_idx);
|
||||
DEBUGFS_ADD(algorithm);
|
||||
DEBUGFS_ADD(tx_spec);
|
||||
DEBUGFS_ADD_W(tx_spec);
|
||||
DEBUGFS_ADD(rx_spec);
|
||||
DEBUGFS_ADD(replays);
|
||||
DEBUGFS_ADD(icverrors);
|
||||
|
|
|
@ -114,14 +114,6 @@ static ssize_t ieee80211_if_fmt_##name( \
|
|||
return scnprintf(buf, buflen, "%pM\n", sdata->field); \
|
||||
}
|
||||
|
||||
#define IEEE80211_IF_FMT_DEC_DIV_16(name, field) \
|
||||
static ssize_t ieee80211_if_fmt_##name( \
|
||||
const struct ieee80211_sub_if_data *sdata, \
|
||||
char *buf, int buflen) \
|
||||
{ \
|
||||
return scnprintf(buf, buflen, "%d\n", sdata->field / 16); \
|
||||
}
|
||||
|
||||
#define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, field) \
|
||||
static ssize_t ieee80211_if_fmt_##name( \
|
||||
const struct ieee80211_sub_if_data *sdata, \
|
||||
|
@ -247,8 +239,6 @@ IEEE80211_IF_FILE_R(hw_queues);
|
|||
/* STA attributes */
|
||||
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
|
||||
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
|
||||
IEEE80211_IF_FILE(last_beacon, u.mgd.last_beacon_signal, DEC);
|
||||
IEEE80211_IF_FILE(ave_beacon, u.mgd.ave_beacon_signal, DEC_DIV_16);
|
||||
IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
|
||||
|
||||
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -455,6 +445,34 @@ static ssize_t ieee80211_if_parse_uapsd_max_sp_len(
|
|||
}
|
||||
IEEE80211_IF_FILE_RW(uapsd_max_sp_len);
|
||||
|
||||
static ssize_t ieee80211_if_fmt_tdls_wider_bw(
|
||||
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
|
||||
{
|
||||
const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
bool tdls_wider_bw;
|
||||
|
||||
tdls_wider_bw = ieee80211_hw_check(&sdata->local->hw, TDLS_WIDER_BW) &&
|
||||
!ifmgd->tdls_wider_bw_prohibited;
|
||||
|
||||
return snprintf(buf, buflen, "%d\n", tdls_wider_bw);
|
||||
}
|
||||
|
||||
static ssize_t ieee80211_if_parse_tdls_wider_bw(
|
||||
struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou8(buf, 0, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ifmgd->tdls_wider_bw_prohibited = !val;
|
||||
return buflen;
|
||||
}
|
||||
IEEE80211_IF_FILE_RW(tdls_wider_bw);
|
||||
|
||||
/* AP attributes */
|
||||
IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
|
||||
IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
|
||||
|
@ -606,14 +624,13 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
|
|||
{
|
||||
DEBUGFS_ADD(bssid);
|
||||
DEBUGFS_ADD(aid);
|
||||
DEBUGFS_ADD(last_beacon);
|
||||
DEBUGFS_ADD(ave_beacon);
|
||||
DEBUGFS_ADD(beacon_timeout);
|
||||
DEBUGFS_ADD_MODE(smps, 0600);
|
||||
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
|
||||
DEBUGFS_ADD_MODE(beacon_loss, 0200);
|
||||
DEBUGFS_ADD_MODE(uapsd_queues, 0600);
|
||||
DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600);
|
||||
DEBUGFS_ADD_MODE(tdls_wider_bw, 0600);
|
||||
}
|
||||
|
||||
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
|
||||
|
|
|
@ -8,6 +8,60 @@
|
|||
#include "trace.h"
|
||||
#include "driver-ops.h"
|
||||
|
||||
int drv_add_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
|
||||
!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))))
|
||||
return -EINVAL;
|
||||
|
||||
trace_drv_add_interface(local, sdata);
|
||||
ret = local->ops->add_interface(&local->hw, &sdata->vif);
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
if (ret == 0)
|
||||
sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int drv_change_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum nl80211_iftype type, bool p2p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return -EIO;
|
||||
|
||||
trace_drv_change_interface(local, sdata, type, p2p);
|
||||
ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
|
||||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void drv_remove_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
trace_drv_remove_interface(local, sdata);
|
||||
local->ops->remove_interface(&local->hw, &sdata->vif);
|
||||
sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
__must_check
|
||||
int drv_sta_state(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -39,3 +93,171 @@ int drv_sta_state(struct ieee80211_local *local,
|
|||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void drv_sta_rc_update(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *sta, u32 changed)
|
||||
{
|
||||
sdata = get_bss_sdata(sdata);
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
|
||||
(sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
|
||||
|
||||
trace_drv_sta_rc_update(local, sdata, sta, changed);
|
||||
if (local->ops->sta_rc_update)
|
||||
local->ops->sta_rc_update(&local->hw, &sdata->vif,
|
||||
sta, changed);
|
||||
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
int drv_conf_tx(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata, u16 ac,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return -EIO;
|
||||
|
||||
if (WARN_ONCE(params->cw_min == 0 ||
|
||||
params->cw_min > params->cw_max,
|
||||
"%s: invalid CW_min/CW_max: %d/%d\n",
|
||||
sdata->name, params->cw_min, params->cw_max))
|
||||
return -EINVAL;
|
||||
|
||||
trace_drv_conf_tx(local, sdata, ac, params);
|
||||
if (local->ops->conf_tx)
|
||||
ret = local->ops->conf_tx(&local->hw, &sdata->vif,
|
||||
ac, params);
|
||||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
u64 drv_get_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
u64 ret = -1ULL;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return ret;
|
||||
|
||||
trace_drv_get_tsf(local, sdata);
|
||||
if (local->ops->get_tsf)
|
||||
ret = local->ops->get_tsf(&local->hw, &sdata->vif);
|
||||
trace_drv_return_u64(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void drv_set_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
u64 tsf)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
trace_drv_set_tsf(local, sdata, tsf);
|
||||
if (local->ops->set_tsf)
|
||||
local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
void drv_reset_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
trace_drv_reset_tsf(local, sdata);
|
||||
if (local->ops->reset_tsf)
|
||||
local->ops->reset_tsf(&local->hw, &sdata->vif);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
int drv_switch_vif_chanctx(struct ieee80211_local *local,
|
||||
struct ieee80211_vif_chanctx_switch *vifs,
|
||||
int n_vifs, enum ieee80211_chanctx_switch_mode mode)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (!local->ops->switch_vif_chanctx)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
struct ieee80211_chanctx *new_ctx =
|
||||
container_of(vifs[i].new_ctx,
|
||||
struct ieee80211_chanctx,
|
||||
conf);
|
||||
struct ieee80211_chanctx *old_ctx =
|
||||
container_of(vifs[i].old_ctx,
|
||||
struct ieee80211_chanctx,
|
||||
conf);
|
||||
|
||||
WARN_ON_ONCE(!old_ctx->driver_present);
|
||||
WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
|
||||
new_ctx->driver_present) ||
|
||||
(mode == CHANCTX_SWMODE_REASSIGN_VIF &&
|
||||
!new_ctx->driver_present));
|
||||
}
|
||||
|
||||
trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode);
|
||||
ret = local->ops->switch_vif_chanctx(&local->hw,
|
||||
vifs, n_vifs, mode);
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) {
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
struct ieee80211_chanctx *new_ctx =
|
||||
container_of(vifs[i].new_ctx,
|
||||
struct ieee80211_chanctx,
|
||||
conf);
|
||||
struct ieee80211_chanctx *old_ctx =
|
||||
container_of(vifs[i].old_ctx,
|
||||
struct ieee80211_chanctx,
|
||||
conf);
|
||||
|
||||
new_ctx->driver_present = true;
|
||||
old_ctx->driver_present = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int drv_ampdu_action(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn, u8 buf_size, bool amsdu)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
might_sleep();
|
||||
|
||||
sdata = get_bss_sdata(sdata);
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return -EIO;
|
||||
|
||||
trace_drv_ampdu_action(local, sdata, action, sta, tid,
|
||||
ssn, buf_size, amsdu);
|
||||
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
|
||||
sta, tid, ssn, buf_size, amsdu);
|
||||
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -137,59 +137,15 @@ static inline void drv_set_wakeup(struct ieee80211_local *local,
|
|||
}
|
||||
#endif
|
||||
|
||||
static inline int drv_add_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
int ret;
|
||||
int drv_add_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
|
||||
!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))))
|
||||
return -EINVAL;
|
||||
|
||||
trace_drv_add_interface(local, sdata);
|
||||
ret = local->ops->add_interface(&local->hw, &sdata->vif);
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
if (ret == 0)
|
||||
sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int drv_change_interface(struct ieee80211_local *local,
|
||||
int drv_change_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum nl80211_iftype type, bool p2p)
|
||||
{
|
||||
int ret;
|
||||
enum nl80211_iftype type, bool p2p);
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return -EIO;
|
||||
|
||||
trace_drv_change_interface(local, sdata, type, p2p);
|
||||
ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
|
||||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void drv_remove_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
trace_drv_remove_interface(local, sdata);
|
||||
local->ops->remove_interface(&local->hw, &sdata->vif);
|
||||
sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
void drv_remove_interface(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
static inline int drv_config(struct ieee80211_local *local, u32 changed)
|
||||
{
|
||||
|
@ -260,6 +216,22 @@ static inline void drv_configure_filter(struct ieee80211_local *local,
|
|||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
static inline void drv_config_iface_filter(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
unsigned int filter_flags,
|
||||
unsigned int changed_flags)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
trace_drv_config_iface_filter(local, sdata, filter_flags,
|
||||
changed_flags);
|
||||
if (local->ops->config_iface_filter)
|
||||
local->ops->config_iface_filter(&local->hw, &sdata->vif,
|
||||
filter_flags,
|
||||
changed_flags);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
static inline int drv_set_tim(struct ieee80211_local *local,
|
||||
struct ieee80211_sta *sta, bool set)
|
||||
{
|
||||
|
@ -580,25 +552,9 @@ int drv_sta_state(struct ieee80211_local *local,
|
|||
enum ieee80211_sta_state old_state,
|
||||
enum ieee80211_sta_state new_state);
|
||||
|
||||
static inline void drv_sta_rc_update(struct ieee80211_local *local,
|
||||
void drv_sta_rc_update(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *sta, u32 changed)
|
||||
{
|
||||
sdata = get_bss_sdata(sdata);
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
|
||||
(sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
|
||||
|
||||
trace_drv_sta_rc_update(local, sdata, sta, changed);
|
||||
if (local->ops->sta_rc_update)
|
||||
local->ops->sta_rc_update(&local->hw, &sdata->vif,
|
||||
sta, changed);
|
||||
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
struct ieee80211_sta *sta, u32 changed);
|
||||
|
||||
static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -630,76 +586,17 @@ static inline void drv_sta_statistics(struct ieee80211_local *local,
|
|||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
static inline int drv_conf_tx(struct ieee80211_local *local,
|
||||
int drv_conf_tx(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata, u16 ac,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
const struct ieee80211_tx_queue_params *params);
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return -EIO;
|
||||
|
||||
if (WARN_ONCE(params->cw_min == 0 ||
|
||||
params->cw_min > params->cw_max,
|
||||
"%s: invalid CW_min/CW_max: %d/%d\n",
|
||||
sdata->name, params->cw_min, params->cw_max))
|
||||
return -EINVAL;
|
||||
|
||||
trace_drv_conf_tx(local, sdata, ac, params);
|
||||
if (local->ops->conf_tx)
|
||||
ret = local->ops->conf_tx(&local->hw, &sdata->vif,
|
||||
ac, params);
|
||||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline u64 drv_get_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
u64 ret = -1ULL;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return ret;
|
||||
|
||||
trace_drv_get_tsf(local, sdata);
|
||||
if (local->ops->get_tsf)
|
||||
ret = local->ops->get_tsf(&local->hw, &sdata->vif);
|
||||
trace_drv_return_u64(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void drv_set_tsf(struct ieee80211_local *local,
|
||||
u64 drv_get_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
void drv_set_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
u64 tsf)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
trace_drv_set_tsf(local, sdata, tsf);
|
||||
if (local->ops->set_tsf)
|
||||
local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
static inline void drv_reset_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
trace_drv_reset_tsf(local, sdata);
|
||||
if (local->ops->reset_tsf)
|
||||
local->ops->reset_tsf(&local->hw, &sdata->vif);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
u64 tsf);
|
||||
void drv_reset_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
static inline int drv_tx_last_beacon(struct ieee80211_local *local)
|
||||
{
|
||||
|
@ -714,30 +611,11 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline int drv_ampdu_action(struct ieee80211_local *local,
|
||||
int drv_ampdu_action(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn, u8 buf_size)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
might_sleep();
|
||||
|
||||
sdata = get_bss_sdata(sdata);
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return -EIO;
|
||||
|
||||
trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);
|
||||
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
|
||||
sta, tid, ssn, buf_size);
|
||||
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
u16 *ssn, u8 buf_size, bool amsdu);
|
||||
|
||||
static inline int drv_get_survey(struct ieee80211_local *local, int idx,
|
||||
struct survey_info *survey)
|
||||
|
@ -1066,58 +944,9 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
|
|||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
static inline int
|
||||
drv_switch_vif_chanctx(struct ieee80211_local *local,
|
||||
int drv_switch_vif_chanctx(struct ieee80211_local *local,
|
||||
struct ieee80211_vif_chanctx_switch *vifs,
|
||||
int n_vifs,
|
||||
enum ieee80211_chanctx_switch_mode mode)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (!local->ops->switch_vif_chanctx)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
struct ieee80211_chanctx *new_ctx =
|
||||
container_of(vifs[i].new_ctx,
|
||||
struct ieee80211_chanctx,
|
||||
conf);
|
||||
struct ieee80211_chanctx *old_ctx =
|
||||
container_of(vifs[i].old_ctx,
|
||||
struct ieee80211_chanctx,
|
||||
conf);
|
||||
|
||||
WARN_ON_ONCE(!old_ctx->driver_present);
|
||||
WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
|
||||
new_ctx->driver_present) ||
|
||||
(mode == CHANCTX_SWMODE_REASSIGN_VIF &&
|
||||
!new_ctx->driver_present));
|
||||
}
|
||||
|
||||
trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode);
|
||||
ret = local->ops->switch_vif_chanctx(&local->hw,
|
||||
vifs, n_vifs, mode);
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) {
|
||||
for (i = 0; i < n_vifs; i++) {
|
||||
struct ieee80211_chanctx *new_ctx =
|
||||
container_of(vifs[i].new_ctx,
|
||||
struct ieee80211_chanctx,
|
||||
conf);
|
||||
struct ieee80211_chanctx *old_ctx =
|
||||
container_of(vifs[i].old_ctx,
|
||||
struct ieee80211_chanctx,
|
||||
conf);
|
||||
|
||||
new_ctx->driver_present = true;
|
||||
old_ctx->driver_present = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
int n_vifs, enum ieee80211_chanctx_switch_mode mode);
|
||||
|
||||
static inline int drv_start_ap(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
|
|
|
@ -419,6 +419,8 @@ struct ieee80211_sta_tx_tspec {
|
|||
bool downgraded;
|
||||
};
|
||||
|
||||
DECLARE_EWMA(beacon_signal, 16, 4)
|
||||
|
||||
struct ieee80211_if_managed {
|
||||
struct timer_list timer;
|
||||
struct timer_list conn_mon_timer;
|
||||
|
@ -490,16 +492,7 @@ struct ieee80211_if_managed {
|
|||
|
||||
s16 p2p_noa_index;
|
||||
|
||||
/* Signal strength from the last Beacon frame in the current BSS. */
|
||||
int last_beacon_signal;
|
||||
|
||||
/*
|
||||
* Weighted average of the signal strength from Beacon frames in the
|
||||
* current BSS. This is in units of 1/16 of the signal unit to maintain
|
||||
* accuracy and to speed up calculations, i.e., the value need to be
|
||||
* divided by 16 to get the actual value.
|
||||
*/
|
||||
int ave_beacon_signal;
|
||||
struct ewma_beacon_signal ave_beacon_signal;
|
||||
|
||||
/*
|
||||
* Number of Beacon frames used in ave_beacon_signal. This can be used
|
||||
|
@ -535,6 +528,7 @@ struct ieee80211_if_managed {
|
|||
struct sk_buff *teardown_skb; /* A copy to send through the AP */
|
||||
spinlock_t teardown_lock; /* To lock changing teardown_skb */
|
||||
bool tdls_chan_switch_prohibited;
|
||||
bool tdls_wider_bw_prohibited;
|
||||
|
||||
/* WMM-AC TSPEC support */
|
||||
struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS];
|
||||
|
@ -1641,6 +1635,9 @@ void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
|
|||
struct sk_buff *
|
||||
ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, u32 info_flags);
|
||||
void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
|
||||
struct ieee80211_supported_band *sband,
|
||||
int retry_count, int shift, bool send_to_cooked);
|
||||
|
||||
void ieee80211_check_fast_xmit(struct sta_info *sta);
|
||||
void ieee80211_check_fast_xmit_all(struct ieee80211_local *local);
|
||||
|
@ -1853,7 +1850,7 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
|
|||
void ieee80211_dynamic_ps_timer(unsigned long data);
|
||||
void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
int powersave);
|
||||
bool powersave);
|
||||
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_hdr *hdr);
|
||||
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -1204,7 +1204,7 @@ static void ieee80211_iface_work(struct work_struct *work)
|
|||
if (!ieee80211_sdata_running(sdata))
|
||||
return;
|
||||
|
||||
if (local->scanning)
|
||||
if (test_bit(SCAN_SW_SCANNING, &local->scanning))
|
||||
return;
|
||||
|
||||
if (!ieee80211_can_run_worker(local))
|
||||
|
|
|
@ -543,7 +543,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
|
|||
NL80211_FEATURE_HT_IBSS |
|
||||
NL80211_FEATURE_VIF_TXPOWER |
|
||||
NL80211_FEATURE_MAC_ON_CREATE |
|
||||
NL80211_FEATURE_USERSPACE_MPM;
|
||||
NL80211_FEATURE_USERSPACE_MPM |
|
||||
NL80211_FEATURE_FULL_AP_CLIENT_STATE;
|
||||
|
||||
if (!ops->hw_scan)
|
||||
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
|
||||
|
|
|
@ -94,6 +94,9 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
|
||||
ie->ht_operation, &sta_chan_def);
|
||||
|
||||
ieee80211_vht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
|
||||
ie->vht_operation, &sta_chan_def);
|
||||
|
||||
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
|
||||
&sta_chan_def))
|
||||
return false;
|
||||
|
@ -436,8 +439,6 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_channel *channel;
|
||||
enum nl80211_channel_type channel_type =
|
||||
cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef);
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_sta_ht_cap *ht_cap;
|
||||
u8 *pos;
|
||||
|
@ -454,7 +455,10 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
|||
sband = local->hw.wiphy->bands[channel->band];
|
||||
ht_cap = &sband->ht_cap;
|
||||
|
||||
if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
|
||||
if (!ht_cap->ht_supported ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
|
||||
return 0;
|
||||
|
||||
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation))
|
||||
|
@ -467,6 +471,68 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
|
||||
struct ieee80211_supported_band *sband;
|
||||
u8 *pos;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
if (!sband->vht_cap.vht_supported ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
|
||||
return 0;
|
||||
|
||||
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_cap))
|
||||
return -ENOMEM;
|
||||
|
||||
pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_cap));
|
||||
ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, sband->vht_cap.cap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_channel *channel;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_sta_vht_cap *vht_cap;
|
||||
u8 *pos;
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (WARN_ON(!chanctx_conf)) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
channel = chanctx_conf->def.chan;
|
||||
rcu_read_unlock();
|
||||
|
||||
sband = local->hw.wiphy->bands[channel->band];
|
||||
vht_cap = &sband->vht_cap;
|
||||
|
||||
if (!vht_cap->vht_supported ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
|
||||
return 0;
|
||||
|
||||
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_operation))
|
||||
return -ENOMEM;
|
||||
|
||||
pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation));
|
||||
ieee80211_ie_build_vht_oper(pos, vht_cap,
|
||||
&sdata->vif.bss_conf.chandef);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_mesh_path_timer(unsigned long data)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
|
@ -540,7 +606,7 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
|||
*
|
||||
* Return the header length.
|
||||
*/
|
||||
int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
|
||||
unsigned int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211s_hdr *meshhdr,
|
||||
const char *addr4or5, const char *addr6)
|
||||
{
|
||||
|
@ -637,6 +703,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
|
|||
2 + ifmsh->mesh_id_len +
|
||||
2 + sizeof(struct ieee80211_meshconf_ie) +
|
||||
2 + sizeof(__le16) + /* awake window */
|
||||
2 + sizeof(struct ieee80211_vht_cap) +
|
||||
2 + sizeof(struct ieee80211_vht_operation) +
|
||||
ifmsh->ie_len;
|
||||
|
||||
bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL);
|
||||
|
@ -718,6 +786,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
|
|||
mesh_add_meshid_ie(sdata, skb) ||
|
||||
mesh_add_meshconf_ie(sdata, skb) ||
|
||||
mesh_add_awake_window_ie(sdata, skb) ||
|
||||
mesh_add_vht_cap_ie(sdata, skb) ||
|
||||
mesh_add_vht_oper_ie(sdata, skb) ||
|
||||
mesh_add_vendor_ies(sdata, skb))
|
||||
goto out_free;
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ struct mesh_rmc {
|
|||
/* Various */
|
||||
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
||||
const u8 *da, const u8 *sa);
|
||||
int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
|
||||
unsigned int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211s_hdr *meshhdr,
|
||||
const char *addr4or5, const char *addr6);
|
||||
int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -227,6 +227,10 @@ int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
|
|||
struct sk_buff *skb);
|
||||
int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211s_init(void);
|
||||
|
|
|
@ -226,6 +226,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
|
|||
2 + sizeof(struct ieee80211_meshconf_ie) +
|
||||
2 + sizeof(struct ieee80211_ht_cap) +
|
||||
2 + sizeof(struct ieee80211_ht_operation) +
|
||||
2 + sizeof(struct ieee80211_vht_cap) +
|
||||
2 + sizeof(struct ieee80211_vht_operation) +
|
||||
2 + 8 + /* peering IE */
|
||||
sdata->u.mesh.ie_len);
|
||||
if (!skb)
|
||||
|
@ -306,7 +308,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
if (action != WLAN_SP_MESH_PEERING_CLOSE) {
|
||||
if (mesh_add_ht_cap_ie(sdata, skb) ||
|
||||
mesh_add_ht_oper_ie(sdata, skb))
|
||||
mesh_add_ht_oper_ie(sdata, skb) ||
|
||||
mesh_add_vht_cap_ie(sdata, skb) ||
|
||||
mesh_add_vht_oper_ie(sdata, skb))
|
||||
goto free;
|
||||
}
|
||||
|
||||
|
@ -402,6 +406,9 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
|
|||
elems->ht_cap_elem, sta))
|
||||
changed |= IEEE80211_RC_BW_CHANGED;
|
||||
|
||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||
elems->vht_cap_elem, sta);
|
||||
|
||||
if (bw != sta->sta.bandwidth)
|
||||
changed |= IEEE80211_RC_BW_CHANGED;
|
||||
|
||||
|
|
|
@ -81,13 +81,6 @@ MODULE_PARM_DESC(probe_wait_ms,
|
|||
"Maximum time(ms) to wait for probe response"
|
||||
" before disconnecting (reason 4).");
|
||||
|
||||
/*
|
||||
* Weight given to the latest Beacon frame when calculating average signal
|
||||
* strength for Beacon frames received in the current BSS. This must be
|
||||
* between 1 and 15.
|
||||
*/
|
||||
#define IEEE80211_SIGNAL_AVE_WEIGHT 3
|
||||
|
||||
/*
|
||||
* How many Beacon frames need to have been used in average signal strength
|
||||
* before starting to indicate signal change events.
|
||||
|
@ -943,7 +936,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
|
|||
|
||||
void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
int powersave)
|
||||
bool powersave)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_hdr_3addr *nullfunc;
|
||||
|
@ -1427,7 +1420,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
|
|||
msecs_to_jiffies(conf->dynamic_ps_timeout));
|
||||
} else {
|
||||
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
|
||||
ieee80211_send_nullfunc(local, sdata, 1);
|
||||
ieee80211_send_nullfunc(local, sdata, true);
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
|
||||
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
|
||||
|
@ -1642,7 +1635,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
|
|||
msecs_to_jiffies(
|
||||
local->hw.conf.dynamic_ps_timeout));
|
||||
} else {
|
||||
ieee80211_send_nullfunc(local, sdata, 1);
|
||||
ieee80211_send_nullfunc(local, sdata, true);
|
||||
/* Flush to get the tx status of nullfunc frame */
|
||||
ieee80211_flush_queues(local, sdata, false);
|
||||
}
|
||||
|
@ -2275,7 +2268,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
if (ieee80211_hw_check(&sdata->local->hw, REPORTS_TX_ACK_STATUS)) {
|
||||
ifmgd->nullfunc_failed = false;
|
||||
ieee80211_send_nullfunc(sdata->local, sdata, 0);
|
||||
ieee80211_send_nullfunc(sdata->local, sdata, false);
|
||||
} else {
|
||||
int ssid_len;
|
||||
|
||||
|
@ -3262,16 +3255,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
if (ifmgd->associated &&
|
||||
ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
|
||||
ieee80211_reset_ap_probe(sdata);
|
||||
|
||||
if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
|
||||
ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {
|
||||
/* got probe response, continue with auth */
|
||||
sdata_info(sdata, "direct probe responded\n");
|
||||
ifmgd->auth_data->tries = 0;
|
||||
ifmgd->auth_data->timeout = jiffies;
|
||||
ifmgd->auth_data->timeout_started = true;
|
||||
run_again(sdata, ifmgd->auth_data->timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3374,24 +3357,21 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
bssid = ifmgd->associated->bssid;
|
||||
|
||||
/* Track average RSSI from the Beacon frames of the current AP */
|
||||
ifmgd->last_beacon_signal = rx_status->signal;
|
||||
if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
|
||||
ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
|
||||
ifmgd->ave_beacon_signal = rx_status->signal * 16;
|
||||
ewma_beacon_signal_init(&ifmgd->ave_beacon_signal);
|
||||
ifmgd->last_cqm_event_signal = 0;
|
||||
ifmgd->count_beacon_signal = 1;
|
||||
ifmgd->last_ave_beacon_signal = 0;
|
||||
} else {
|
||||
ifmgd->ave_beacon_signal =
|
||||
(IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
|
||||
(16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
|
||||
ifmgd->ave_beacon_signal) / 16;
|
||||
ifmgd->count_beacon_signal++;
|
||||
}
|
||||
|
||||
ewma_beacon_signal_add(&ifmgd->ave_beacon_signal, -rx_status->signal);
|
||||
|
||||
if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold &&
|
||||
ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
|
||||
int sig = ifmgd->ave_beacon_signal;
|
||||
int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
|
||||
int last_sig = ifmgd->last_ave_beacon_signal;
|
||||
struct ieee80211_event event = {
|
||||
.type = RSSI_EVENT,
|
||||
|
@ -3418,10 +3398,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
if (bss_conf->cqm_rssi_thold &&
|
||||
ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
|
||||
!(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) {
|
||||
int sig = ifmgd->ave_beacon_signal / 16;
|
||||
int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
|
||||
int last_event = ifmgd->last_cqm_event_signal;
|
||||
int thold = bss_conf->cqm_rssi_thold;
|
||||
int hyst = bss_conf->cqm_rssi_hyst;
|
||||
|
||||
if (sig < thold &&
|
||||
(last_event == 0 || sig < last_event - hyst)) {
|
||||
ifmgd->last_cqm_event_signal = sig;
|
||||
|
@ -3456,18 +3437,15 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
len - baselen, false, &elems,
|
||||
care_about_ies, ncrc);
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK)) {
|
||||
bool directed_tim = ieee80211_check_tim(elems.tim,
|
||||
elems.tim_len,
|
||||
ifmgd->aid);
|
||||
if (directed_tim) {
|
||||
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
|
||||
ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) {
|
||||
if (local->hw.conf.dynamic_ps_timeout > 0) {
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
|
||||
ieee80211_hw_config(local,
|
||||
IEEE80211_CONF_CHANGE_PS);
|
||||
}
|
||||
ieee80211_send_nullfunc(local, sdata, 0);
|
||||
ieee80211_send_nullfunc(local, sdata, false);
|
||||
} else if (!local->pspolling && sdata->u.mgd.powersave) {
|
||||
local->pspolling = true;
|
||||
|
||||
|
@ -3482,7 +3460,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_send_pspoll(local, sdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sdata->vif.p2p) {
|
||||
struct ieee80211_p2p_noa_attr noa = {};
|
||||
|
@ -3717,12 +3694,14 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
|
|||
reason);
|
||||
}
|
||||
|
||||
static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
|
||||
static int ieee80211_auth(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data;
|
||||
u32 tx_flags = 0;
|
||||
u16 trans = 1;
|
||||
u16 status = 0;
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
|
@ -3746,10 +3725,6 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
drv_mgd_prepare_tx(local, sdata);
|
||||
|
||||
if (auth_data->bss->proberesp_ies) {
|
||||
u16 trans = 1;
|
||||
u16 status = 0;
|
||||
|
||||
sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
|
||||
auth_data->bss->bssid, auth_data->tries,
|
||||
IEEE80211_AUTH_MAX_TRIES);
|
||||
|
@ -3771,29 +3746,6 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
|
|||
auth_data->bss->bssid,
|
||||
auth_data->bss->bssid, NULL, 0, 0,
|
||||
tx_flags);
|
||||
} else {
|
||||
const u8 *ssidie;
|
||||
|
||||
sdata_info(sdata, "direct probe to %pM (try %d/%i)\n",
|
||||
auth_data->bss->bssid, auth_data->tries,
|
||||
IEEE80211_AUTH_MAX_TRIES);
|
||||
|
||||
rcu_read_lock();
|
||||
ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);
|
||||
if (!ssidie) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* Direct probe is sent to broadcast address as some APs
|
||||
* will not answer to direct packet in unassociated state.
|
||||
*/
|
||||
ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL,
|
||||
ssidie + 2, ssidie[1],
|
||||
NULL, 0, (u32) -1, true, 0,
|
||||
auth_data->bss->channel, false);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
if (tx_flags == 0) {
|
||||
auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
|
||||
|
@ -3874,8 +3826,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
|||
bool status_acked = ifmgd->status_acked;
|
||||
|
||||
ifmgd->status_received = false;
|
||||
if (ifmgd->auth_data &&
|
||||
(ieee80211_is_probe_req(fc) || ieee80211_is_auth(fc))) {
|
||||
if (ifmgd->auth_data && ieee80211_is_auth(fc)) {
|
||||
if (status_acked) {
|
||||
ifmgd->auth_data->timeout =
|
||||
jiffies + IEEE80211_AUTH_TIMEOUT_SHORT;
|
||||
|
@ -3906,7 +3857,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
|||
* so let's just kill the auth data
|
||||
*/
|
||||
ieee80211_destroy_auth_data(sdata, false);
|
||||
} else if (ieee80211_probe_auth(sdata)) {
|
||||
} else if (ieee80211_auth(sdata)) {
|
||||
u8 bssid[ETH_ALEN];
|
||||
struct ieee80211_event event = {
|
||||
.type = MLME_EVENT,
|
||||
|
@ -4613,7 +4564,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
|||
if (err)
|
||||
goto err_clear;
|
||||
|
||||
err = ieee80211_probe_auth(sdata);
|
||||
err = ieee80211_auth(sdata);
|
||||
if (err) {
|
||||
sta_info_destroy_addr(sdata, req->bss->bssid);
|
||||
goto err_clear;
|
||||
|
|
|
@ -57,7 +57,7 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
|
|||
* to send a new nullfunc frame to inform the AP that we
|
||||
* are again sleeping.
|
||||
*/
|
||||
ieee80211_send_nullfunc(local, sdata, 1);
|
||||
ieee80211_send_nullfunc(local, sdata, true);
|
||||
}
|
||||
|
||||
/* inform AP that we are awake again, unless power save is enabled */
|
||||
|
@ -66,7 +66,7 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (!local->ps_sdata)
|
||||
ieee80211_send_nullfunc(local, sdata, 0);
|
||||
ieee80211_send_nullfunc(local, sdata, false);
|
||||
else if (local->offchannel_ps_enabled) {
|
||||
/*
|
||||
* In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
|
||||
|
@ -93,7 +93,7 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
|
|||
* restart the timer now and send a nullfunc frame to inform
|
||||
* the AP that we are awake.
|
||||
*/
|
||||
ieee80211_send_nullfunc(local, sdata, 0);
|
||||
ieee80211_send_nullfunc(local, sdata, false);
|
||||
mod_timer(&local->dynamic_ps_timer, jiffies +
|
||||
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||
|
||||
ieee80211_del_virtual_monitor(local);
|
||||
|
||||
if (ieee80211_hw_check(hw, AMPDU_AGGREGATION)) {
|
||||
if (ieee80211_hw_check(hw, AMPDU_AGGREGATION) &&
|
||||
!(wowlan && wowlan->any)) {
|
||||
mutex_lock(&local->sta_mtx);
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||||
|
|
|
@ -305,7 +305,10 @@ static void __rate_control_send_low(struct ieee80211_hw *hw,
|
|||
info->control.rates[0].idx = i;
|
||||
break;
|
||||
}
|
||||
WARN_ON_ONCE(i == sband->n_bitrates);
|
||||
WARN_ONCE(i == sband->n_bitrates,
|
||||
"no supported rates (0x%x) in rate_mask 0x%x with flags 0x%x\n",
|
||||
sta ? sta->supp_rates[sband->band] : 0,
|
||||
rate_mask, rate_flags);
|
||||
|
||||
info->control.rates[0].count =
|
||||
(info->flags & IEEE80211_TX_CTL_NO_ACK) ?
|
||||
|
|
|
@ -85,12 +85,10 @@ minstrel_stats_open(struct inode *inode, struct file *file)
|
|||
file->private_data = ms;
|
||||
p = ms->buf;
|
||||
p += sprintf(p, "\n");
|
||||
p += sprintf(p, "best __________rate_________ ______"
|
||||
"statistics______ ________last_______ "
|
||||
"______sum-of________\n");
|
||||
p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob) "
|
||||
"sd(prob)] [prob.|retry|suc|att] "
|
||||
"[#success | #attempts]\n");
|
||||
p += sprintf(p,
|
||||
"best __________rate_________ ________statistics________ ________last_______ ______sum-of________\n");
|
||||
p += sprintf(p,
|
||||
"rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n");
|
||||
|
||||
for (i = 0; i < mi->n_rates; i++) {
|
||||
struct minstrel_rate *mr = &mi->r[i];
|
||||
|
|
|
@ -129,12 +129,10 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
|
|||
p = ms->buf;
|
||||
|
||||
p += sprintf(p, "\n");
|
||||
p += sprintf(p, " best ____________rate__________ "
|
||||
"______statistics______ ________last_______ "
|
||||
"______sum-of________\n");
|
||||
p += sprintf(p, "mode guard # rate [name idx airtime max_tp] "
|
||||
"[ ø(tp) ø(prob) sd(prob)] [prob.|retry|suc|att] [#success | "
|
||||
"#attempts]\n");
|
||||
p += sprintf(p,
|
||||
" best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n");
|
||||
p += sprintf(p,
|
||||
"mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n");
|
||||
|
||||
p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
|
||||
for (i = 0; i < MINSTREL_CCK_GROUP; i++)
|
||||
|
|
|
@ -133,6 +133,7 @@ enum ieee80211_agg_stop_reason {
|
|||
* @buf_size: reorder buffer size at receiver
|
||||
* @failed_bar_ssn: ssn of the last failed BAR tx attempt
|
||||
* @bar_pending: BAR needs to be re-sent
|
||||
* @amsdu: support A-MSDU withing A-MDPU
|
||||
*
|
||||
* This structure's lifetime is managed by RCU, assignments to
|
||||
* the array holding it must hold the aggregation mutex.
|
||||
|
@ -158,6 +159,7 @@ struct tid_ampdu_tx {
|
|||
|
||||
u16 failed_bar_ssn;
|
||||
bool bar_pending;
|
||||
bool amsdu;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -668,16 +668,70 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_status_noskb);
|
||||
|
||||
void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
|
||||
struct ieee80211_supported_band *sband,
|
||||
int retry_count, int shift, bool send_to_cooked)
|
||||
{
|
||||
struct sk_buff *skb2;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct net_device *prev_dev = NULL;
|
||||
int rtap_len;
|
||||
|
||||
/* send frame to monitor interfaces now */
|
||||
rtap_len = ieee80211_tx_radiotap_len(info);
|
||||
if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
|
||||
pr_err("ieee80211_tx_status: headroom too small\n");
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count,
|
||||
rtap_len, shift);
|
||||
|
||||
/* XXX: is this sufficient for BPF? */
|
||||
skb_set_mac_header(skb, 0);
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
skb->protocol = htons(ETH_P_802_2);
|
||||
memset(skb->cb, 0, sizeof(skb->cb));
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
|
||||
!send_to_cooked)
|
||||
continue;
|
||||
|
||||
if (prev_dev) {
|
||||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
if (skb2) {
|
||||
skb2->dev = prev_dev;
|
||||
netif_rx(skb2);
|
||||
}
|
||||
}
|
||||
|
||||
prev_dev = sdata->dev;
|
||||
}
|
||||
}
|
||||
if (prev_dev) {
|
||||
skb->dev = prev_dev;
|
||||
netif_rx(skb);
|
||||
skb = NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
__le16 fc;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct net_device *prev_dev = NULL;
|
||||
struct sta_info *sta;
|
||||
struct rhash_head *tmp;
|
||||
int retry_count;
|
||||
|
@ -685,7 +739,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
bool send_to_cooked;
|
||||
bool acked;
|
||||
struct ieee80211_bar *bar;
|
||||
int rtap_len;
|
||||
int shift = 0;
|
||||
int tid = IEEE80211_NUM_TIDS;
|
||||
const struct bucket_table *tbl;
|
||||
|
@ -878,51 +931,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
return;
|
||||
}
|
||||
|
||||
/* send frame to monitor interfaces now */
|
||||
rtap_len = ieee80211_tx_radiotap_len(info);
|
||||
if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
|
||||
pr_err("ieee80211_tx_status: headroom too small\n");
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count,
|
||||
rtap_len, shift);
|
||||
|
||||
/* XXX: is this sufficient for BPF? */
|
||||
skb_set_mac_header(skb, 0);
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
skb->protocol = htons(ETH_P_802_2);
|
||||
memset(skb->cb, 0, sizeof(skb->cb));
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
|
||||
!send_to_cooked)
|
||||
continue;
|
||||
|
||||
if (prev_dev) {
|
||||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
if (skb2) {
|
||||
skb2->dev = prev_dev;
|
||||
netif_rx(skb2);
|
||||
}
|
||||
}
|
||||
|
||||
prev_dev = sdata->dev;
|
||||
}
|
||||
}
|
||||
if (prev_dev) {
|
||||
skb->dev = prev_dev;
|
||||
netif_rx(skb);
|
||||
skb = NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
dev_kfree_skb(skb);
|
||||
/* send to monitor interfaces */
|
||||
ieee80211_tx_monitor(local, skb, sband, retry_count, shift, send_to_cooked);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_status);
|
||||
|
||||
|
|
|
@ -41,9 +41,11 @@ static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata,
|
|||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
bool chan_switch = local->hw.wiphy->features &
|
||||
NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
|
||||
bool wider_band = ieee80211_hw_check(&local->hw, TDLS_WIDER_BW);
|
||||
bool wider_band = ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) &&
|
||||
!ifmgd->tdls_wider_bw_prohibited;
|
||||
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
|
||||
struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
|
||||
bool vht = sband && sband->vht_cap.vht_supported;
|
||||
|
@ -331,8 +333,8 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
/* proceed to downgrade the chandef until usable or the same */
|
||||
while (uc.width > max_width &&
|
||||
!cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
|
||||
&uc, sdata->wdev.iftype))
|
||||
!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &uc,
|
||||
sdata->wdev.iftype))
|
||||
ieee80211_chandef_downgrade(&uc);
|
||||
|
||||
if (!cfg80211_chandef_identical(&uc, &sta->tdls_chandef)) {
|
||||
|
|
|
@ -497,6 +497,36 @@ TRACE_EVENT(drv_configure_filter,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_config_iface_filter,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
unsigned int filter_flags,
|
||||
unsigned int changed_flags),
|
||||
|
||||
TP_ARGS(local, sdata, filter_flags, changed_flags),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(unsigned int, filter_flags)
|
||||
__field(unsigned int, changed_flags)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->filter_flags = filter_flags;
|
||||
__entry->changed_flags = changed_flags;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT
|
||||
" filter_flags: %#x changed_flags: %#x",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, __entry->filter_flags,
|
||||
__entry->changed_flags
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_set_tim,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sta *sta, bool set),
|
||||
|
@ -944,9 +974,9 @@ TRACE_EVENT(drv_ampdu_action,
|
|||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn, u8 buf_size),
|
||||
u16 *ssn, u8 buf_size, bool amsdu),
|
||||
|
||||
TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size),
|
||||
TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size, amsdu),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
|
@ -955,6 +985,7 @@ TRACE_EVENT(drv_ampdu_action,
|
|||
__field(u16, tid)
|
||||
__field(u16, ssn)
|
||||
__field(u8, buf_size)
|
||||
__field(bool, amsdu)
|
||||
VIF_ENTRY
|
||||
),
|
||||
|
||||
|
@ -966,12 +997,13 @@ TRACE_EVENT(drv_ampdu_action,
|
|||
__entry->tid = tid;
|
||||
__entry->ssn = ssn ? *ssn : 0;
|
||||
__entry->buf_size = buf_size;
|
||||
__entry->amsdu = amsdu;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d",
|
||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d amsdu:%d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
|
||||
__entry->tid, __entry->buf_size
|
||||
__entry->tid, __entry->buf_size, __entry->amsdu
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -2767,6 +2767,7 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
||||
*ieee80211_get_qos_ctl(hdr) = tid;
|
||||
if (!sta->sta.txq[0])
|
||||
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
|
||||
} else {
|
||||
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||
|
@ -3512,6 +3513,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct ieee80211_mutable_offsets offs = {};
|
||||
struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false);
|
||||
struct sk_buff *copy;
|
||||
struct ieee80211_supported_band *sband;
|
||||
int shift;
|
||||
|
||||
if (!bcn)
|
||||
return bcn;
|
||||
|
||||
if (tim_offset)
|
||||
*tim_offset = offs.tim_offset;
|
||||
|
@ -3519,6 +3526,19 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
|||
if (tim_length)
|
||||
*tim_length = offs.tim_length;
|
||||
|
||||
if (ieee80211_hw_check(hw, BEACON_TX_STATUS) ||
|
||||
!hw_to_local(hw)->monitors)
|
||||
return bcn;
|
||||
|
||||
/* send a copy to monitor interfaces */
|
||||
copy = skb_copy(bcn, GFP_ATOMIC);
|
||||
if (!copy)
|
||||
return bcn;
|
||||
|
||||
shift = ieee80211_vif_get_shift(vif);
|
||||
sband = hw->wiphy->bands[ieee80211_get_sdata_band(vif_to_sdata(vif))];
|
||||
ieee80211_tx_monitor(hw_to_local(hw), copy, sband, 1, shift, false);
|
||||
|
||||
return bcn;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_beacon_get_tim);
|
||||
|
|
|
@ -1966,7 +1966,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
if (!sdata->u.mgd.associated)
|
||||
continue;
|
||||
|
||||
ieee80211_send_nullfunc(local, sdata, 0);
|
||||
ieee80211_send_nullfunc(local, sdata, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2017,6 +2017,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
if (!local->resuming)
|
||||
ieee80211_sta_tear_down_BA_sessions(
|
||||
sta, AGG_STOP_LOCAL_REQUEST);
|
||||
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||||
|
@ -2324,6 +2325,8 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
|||
if (chandef->center_freq2)
|
||||
vht_oper->center_freq_seg2_idx =
|
||||
ieee80211_frequency_to_channel(chandef->center_freq2);
|
||||
else
|
||||
vht_oper->center_freq_seg2_idx = 0x00;
|
||||
|
||||
switch (chandef->width) {
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
|
@ -2541,7 +2544,7 @@ int ieee80211_ave_rssi(struct ieee80211_vif *vif)
|
|||
/* non-managed type inferfaces */
|
||||
return 0;
|
||||
}
|
||||
return ifmgd->ave_beacon_signal / 16;
|
||||
return -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
|
||||
|
||||
|
|
|
@ -419,6 +419,7 @@ use_default_name:
|
|||
device_initialize(&rdev->wiphy.dev);
|
||||
rdev->wiphy.dev.class = &ieee80211_class;
|
||||
rdev->wiphy.dev.platform_data = rdev;
|
||||
device_enable_async_suspend(&rdev->wiphy.dev);
|
||||
|
||||
INIT_LIST_HEAD(&rdev->destroy_list);
|
||||
spin_lock_init(&rdev->destroy_list_lock);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015 Intel Deutschland GmbH
|
||||
*/
|
||||
|
||||
#include <linux/if.h>
|
||||
|
@ -2403,6 +2404,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
|
|||
}
|
||||
}
|
||||
|
||||
if (rdev->ops->get_tx_power) {
|
||||
int dbm, ret;
|
||||
|
||||
ret = rdev_get_tx_power(rdev, wdev, &dbm);
|
||||
if (ret == 0 &&
|
||||
nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
|
||||
DBM_TO_MBM(dbm)))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
if (wdev->ssid_len) {
|
||||
if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
|
||||
goto nla_put_failure;
|
||||
|
@ -3998,7 +4009,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
|
|||
params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
|
||||
}
|
||||
|
||||
if (statype != CFG80211_STA_TDLS_PEER_SETUP) {
|
||||
if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
|
||||
statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
|
||||
/* reject other things that can't change */
|
||||
if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
|
||||
return -EINVAL;
|
||||
|
@ -4010,7 +4022,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (statype != CFG80211_STA_AP_CLIENT) {
|
||||
if (statype != CFG80211_STA_AP_CLIENT &&
|
||||
statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
|
||||
if (params->vlan)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -4022,6 +4035,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
|
|||
return -EOPNOTSUPP;
|
||||
break;
|
||||
case CFG80211_STA_AP_CLIENT:
|
||||
case CFG80211_STA_AP_CLIENT_UNASSOC:
|
||||
/* accept only the listed bits */
|
||||
if (params->sta_flags_mask &
|
||||
~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
|
||||
|
@ -9938,6 +9952,9 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
|
|||
if (!wdev->netdev && !wdev->p2p_started)
|
||||
return -ENETDOWN;
|
||||
}
|
||||
|
||||
if (!vcmd->doit)
|
||||
return -EOPNOTSUPP;
|
||||
} else {
|
||||
wdev = NULL;
|
||||
}
|
||||
|
@ -9957,6 +9974,193 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
struct cfg80211_registered_device **rdev,
|
||||
struct wireless_dev **wdev)
|
||||
{
|
||||
u32 vid, subcmd;
|
||||
unsigned int i;
|
||||
int vcmd_idx = -1;
|
||||
int err;
|
||||
void *data = NULL;
|
||||
unsigned int data_len = 0;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
if (cb->args[0]) {
|
||||
/* subtract the 1 again here */
|
||||
struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
|
||||
struct wireless_dev *tmp;
|
||||
|
||||
if (!wiphy) {
|
||||
err = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
*rdev = wiphy_to_rdev(wiphy);
|
||||
*wdev = NULL;
|
||||
|
||||
if (cb->args[1]) {
|
||||
list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
|
||||
if (tmp->identifier == cb->args[1] - 1) {
|
||||
*wdev = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* keep rtnl locked in successful case */
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
|
||||
nl80211_fam.attrbuf, nl80211_fam.maxattr,
|
||||
nl80211_policy);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
if (!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID] ||
|
||||
!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
|
||||
err = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
|
||||
nl80211_fam.attrbuf);
|
||||
if (IS_ERR(*wdev))
|
||||
*wdev = NULL;
|
||||
|
||||
*rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
|
||||
nl80211_fam.attrbuf);
|
||||
if (IS_ERR(*rdev)) {
|
||||
err = PTR_ERR(*rdev);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
vid = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID]);
|
||||
subcmd = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
|
||||
|
||||
for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
|
||||
const struct wiphy_vendor_command *vcmd;
|
||||
|
||||
vcmd = &(*rdev)->wiphy.vendor_commands[i];
|
||||
|
||||
if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
|
||||
continue;
|
||||
|
||||
if (!vcmd->dumpit) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
vcmd_idx = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (vcmd_idx < 0) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]) {
|
||||
data = nla_data(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
|
||||
data_len = nla_len(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
|
||||
}
|
||||
|
||||
/* 0 is the first index - add 1 to parse only once */
|
||||
cb->args[0] = (*rdev)->wiphy_idx + 1;
|
||||
/* add 1 to know if it was NULL */
|
||||
cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
|
||||
cb->args[2] = vcmd_idx;
|
||||
cb->args[3] = (unsigned long)data;
|
||||
cb->args[4] = data_len;
|
||||
|
||||
/* keep rtnl locked in successful case */
|
||||
return 0;
|
||||
out_unlock:
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct wireless_dev *wdev;
|
||||
unsigned int vcmd_idx;
|
||||
const struct wiphy_vendor_command *vcmd;
|
||||
void *data;
|
||||
int data_len;
|
||||
int err;
|
||||
struct nlattr *vendor_data;
|
||||
|
||||
err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
vcmd_idx = cb->args[2];
|
||||
data = (void *)cb->args[3];
|
||||
data_len = cb->args[4];
|
||||
vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
|
||||
|
||||
if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_NETDEV)) {
|
||||
if (!wdev)
|
||||
return -EINVAL;
|
||||
if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
|
||||
!wdev->netdev)
|
||||
return -EINVAL;
|
||||
|
||||
if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
|
||||
if (wdev->netdev &&
|
||||
!netif_running(wdev->netdev))
|
||||
return -ENETDOWN;
|
||||
if (!wdev->netdev && !wdev->p2p_started)
|
||||
return -ENETDOWN;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
NL80211_CMD_VENDOR);
|
||||
if (!hdr)
|
||||
break;
|
||||
|
||||
if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
(wdev && nla_put_u64(skb, NL80211_ATTR_WDEV,
|
||||
wdev_id(wdev)))) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
break;
|
||||
}
|
||||
|
||||
vendor_data = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
|
||||
if (!vendor_data) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
break;
|
||||
}
|
||||
|
||||
err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
|
||||
(unsigned long *)&cb->args[5]);
|
||||
nla_nest_end(skb, vendor_data);
|
||||
|
||||
if (err == -ENOBUFS || err == -ENOENT) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
break;
|
||||
} else if (err) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
}
|
||||
|
||||
err = skb->len;
|
||||
out:
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
|
||||
enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr,
|
||||
|
@ -10994,6 +11198,7 @@ static const struct genl_ops nl80211_ops[] = {
|
|||
{
|
||||
.cmd = NL80211_CMD_VENDOR,
|
||||
.doit = nl80211_vendor_cmd,
|
||||
.dumpit = nl80211_vendor_cmd_dump,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_WIPHY |
|
||||
|
|
|
@ -1040,8 +1040,8 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
|
|||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
const struct ieee80211_reg_rule *__freq_reg_info(struct wiphy *wiphy,
|
||||
u32 center_freq, u32 min_bw)
|
||||
static const struct ieee80211_reg_rule *
|
||||
__freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
|
||||
{
|
||||
const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
|
||||
const struct ieee80211_reg_rule *reg_rule = NULL;
|
||||
|
|
Loading…
Reference in New Issue