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:
David S. Miller 2015-10-07 04:29:18 -07:00
commit 2579c98f0d
53 changed files with 982 additions and 489 deletions

View File

@ -6144,7 +6144,7 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size) u8 buf_size, bool amsdu)
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);

View File

@ -1659,7 +1659,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, 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_priv *priv = hw->priv;
struct ath9k_htc_sta *ista; struct ath9k_htc_sta *ista;

View File

@ -1856,7 +1856,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, 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_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);

View File

@ -1415,7 +1415,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, 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 ar9170 *ar = hw->priv;
struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;

View File

@ -859,7 +859,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size) u8 buf_size, bool amsdu)
{ {
struct wcn36xx *wcn = hw->priv; struct wcn36xx *wcn = hw->priv;
struct wcn36xx_sta *sta_priv = NULL; struct wcn36xx_sta *sta_priv = NULL;

View File

@ -820,7 +820,7 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size) u8 buf_size, bool amsdu)
{ {
struct brcms_info *wl = hw->priv; struct brcms_info *wl = hw->priv;
struct scb *scb = &wl->wlc->pri_scb; struct scb *scb = &wl->wlc->pri_scb;

View File

@ -2137,7 +2137,7 @@ int cw1200_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size) u8 buf_size, bool amsdu)
{ {
/* Aggregation is implemented fully in firmware, /* Aggregation is implemented fully in firmware,
* including block ack negotiation. Do not allow * including block ack negotiation. Do not allow

View File

@ -111,7 +111,7 @@ int cw1200_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size); u8 buf_size, bool amsdu);
void cw1200_suspend_resume(struct cw1200_common *priv, void cw1200_suspend_resume(struct cw1200_common *priv,
struct wsm_suspend_resume *arg); struct wsm_suspend_resume *arg);

View File

@ -1091,8 +1091,6 @@ static const char *get_info_element_string(u16 id)
MFIE_STRING(TIM); MFIE_STRING(TIM);
MFIE_STRING(IBSS_PARAMS); MFIE_STRING(IBSS_PARAMS);
MFIE_STRING(COUNTRY); MFIE_STRING(COUNTRY);
MFIE_STRING(HP_PARAMS);
MFIE_STRING(HP_TABLE);
MFIE_STRING(REQUEST); MFIE_STRING(REQUEST);
MFIE_STRING(CHALLENGE); MFIE_STRING(CHALLENGE);
MFIE_STRING(PWR_CONSTRAINT); MFIE_STRING(PWR_CONSTRAINT);

View File

@ -5984,7 +5984,7 @@ int
il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 * ssn, struct ieee80211_sta *sta, u16 tid, u16 * ssn,
u8 buf_size) u8 buf_size, bool amsdu)
{ {
struct il_priv *il = hw->priv; struct il_priv *il = hw->priv;
int ret = -EINVAL; int ret = -EINVAL;

View File

@ -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, int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 * ssn, struct ieee80211_sta *sta, u16 tid, u16 * ssn,
u8 buf_size); u8 buf_size, bool amsdu);
int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta); struct ieee80211_sta *sta);
void void

View File

@ -731,7 +731,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size) u8 buf_size, bool amsdu)
{ {
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
int ret = -EINVAL; int ret = -EINVAL;

View File

@ -820,7 +820,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, 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); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret; int ret;

View File

@ -1819,7 +1819,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size) u8 buf_size, bool amsdu)
{ {
switch (action) { switch (action) {
case IEEE80211_AMPDU_TX_START: case IEEE80211_AMPDU_TX_START:

View File

@ -335,7 +335,8 @@ static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
static int static int
mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, 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 mt7601u_dev *dev = hw->priv;
struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;

View File

@ -5423,7 +5423,7 @@ static int
mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size) u8 buf_size, bool amsdu)
{ {
int i, rc = 0; int i, rc = 0;

View File

@ -664,6 +664,7 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw,
* @tid: Traffic identifier. * @tid: Traffic identifier.
* @ssn: Pointer to ssn value. * @ssn: Pointer to ssn value.
* @buf_size: Buffer size (for kernel version > 2.6.38). * @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. * 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, struct ieee80211_sta *sta,
unsigned short tid, unsigned short tid,
unsigned short *ssn, unsigned short *ssn,
unsigned char buf_size) unsigned char buf_size,
bool amsdu)
{ {
int status = -EOPNOTSUPP; int status = -EOPNOTSUPP;
struct rsi_hw *adapter = hw->priv; struct rsi_hw *adapter = hw->priv;

View File

@ -7937,7 +7937,7 @@ EXPORT_SYMBOL_GPL(rt2800_get_tsf);
int rt2800_ampdu_action(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, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, 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; struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv;
int ret = 0; int ret = 0;

View File

@ -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, int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size); u8 buf_size, bool amsdu);
int rt2800_get_survey(struct ieee80211_hw *hw, int idx, int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey); struct survey_info *survey);
void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev); void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev);

View File

@ -1373,7 +1373,7 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size) u8 buf_size, bool amsdu)
{ {
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);

View File

@ -5263,7 +5263,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size) u8 buf_size, bool amsdu)
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);

View File

@ -1379,6 +1379,7 @@ struct ieee80211_ht_operation {
/* block-ack parameters */ /* block-ack parameters */
#define IEEE80211_ADDBA_PARAM_AMSDU_MASK 0x0001
#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C #define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0 #define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0
@ -1745,8 +1746,7 @@ enum ieee80211_eid {
WLAN_EID_TIM = 5, WLAN_EID_TIM = 5,
WLAN_EID_IBSS_PARAMS = 6, WLAN_EID_IBSS_PARAMS = 6,
WLAN_EID_COUNTRY = 7, WLAN_EID_COUNTRY = 7,
WLAN_EID_HP_PARAMS = 8, /* 8, 9 reserved */
WLAN_EID_HP_TABLE = 9,
WLAN_EID_REQUEST = 10, WLAN_EID_REQUEST = 10,
WLAN_EID_QBSS_LOAD = 11, WLAN_EID_QBSS_LOAD = 11,
WLAN_EID_EDCA_PARAM_SET = 12, WLAN_EID_EDCA_PARAM_SET = 12,

View File

@ -858,6 +858,8 @@ struct station_del_parameters {
/** /**
* enum cfg80211_station_type - the type of station being modified * enum cfg80211_station_type - the type of station being modified
* @CFG80211_STA_AP_CLIENT: client of an AP interface * @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 * @CFG80211_STA_AP_MLME_CLIENT: client of an AP interface that has
* the AP MLME in the device * the AP MLME in the device
* @CFG80211_STA_AP_STA: AP station on managed interface * @CFG80211_STA_AP_STA: AP station on managed interface
@ -873,6 +875,7 @@ struct station_del_parameters {
*/ */
enum cfg80211_station_type { enum cfg80211_station_type {
CFG80211_STA_AP_CLIENT, CFG80211_STA_AP_CLIENT,
CFG80211_STA_AP_CLIENT_UNASSOC,
CFG80211_STA_AP_MLME_CLIENT, CFG80211_STA_AP_MLME_CLIENT,
CFG80211_STA_AP_STA, CFG80211_STA_AP_STA,
CFG80211_STA_IBSS, CFG80211_STA_IBSS,
@ -2971,12 +2974,21 @@ enum wiphy_vendor_command_flags {
* @doit: callback for the operation, note that wdev is %NULL if the * @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 * flags didn't ask for a wdev and non-%NULL otherwise; the data
* pointer may be %NULL if userspace provided no data at all * 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 wiphy_vendor_command {
struct nl80211_vendor_cmd_info info; struct nl80211_vendor_cmd_info info;
u32 flags; u32 flags;
int (*doit)(struct wiphy *wiphy, struct wireless_dev *wdev, int (*doit)(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int data_len); 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);
}; };
/** /**

View File

@ -5,6 +5,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * 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 * 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 * 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 * @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 * interface debug files. Note that it will be NULL for the virtual
* monitor interface (if that is requested.) * 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 * @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *). * sizeof(void *).
* @txq: the multicast data TX queue (if driver uses the TXQ abstraction) * @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
@ -1384,6 +1387,8 @@ struct ieee80211_vif {
struct dentry *debugfs_dir; struct dentry *debugfs_dir;
#endif #endif
unsigned int probe_req_reg;
/* must be last */ /* must be last */
u8 drv_priv[0] __aligned(sizeof(void *)); u8 drv_priv[0] __aligned(sizeof(void *));
}; };
@ -1494,10 +1499,8 @@ enum ieee80211_key_flags {
* - Temporal Authenticator Rx MIC Key (64 bits) * - Temporal Authenticator Rx MIC Key (64 bits)
* @icv_len: The ICV length for this key type * @icv_len: The ICV length for this key type
* @iv_len: The IV length for this key type * @iv_len: The IV length for this key type
* @drv_priv: pointer for driver use
*/ */
struct ieee80211_key_conf { struct ieee80211_key_conf {
void *drv_priv;
atomic64_t tx_pn; atomic64_t tx_pn;
u32 cipher; u32 cipher;
u8 icv_len; u8 icv_len;
@ -1894,6 +1897,12 @@ struct ieee80211_txq {
* @IEEE80211_HW_TDLS_WIDER_BW: The device/driver supports wider bandwidth * @IEEE80211_HW_TDLS_WIDER_BW: The device/driver supports wider bandwidth
* than then BSS bandwidth for a TDLS link on the base channel. * 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 * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/ */
enum ieee80211_hw_flags { enum ieee80211_hw_flags {
@ -1927,6 +1936,8 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_CLONED_SKBS, IEEE80211_HW_SUPPORTS_CLONED_SKBS,
IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS, IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS,
IEEE80211_HW_TDLS_WIDER_BW, IEEE80211_HW_TDLS_WIDER_BW,
IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
IEEE80211_HW_BEACON_TX_STATUS,
/* keep last, obviously */ /* keep last, obviously */
NUM_IEEE80211_HW_FLAGS NUM_IEEE80211_HW_FLAGS
@ -2827,6 +2838,13 @@ enum ieee80211_reconfig_type {
* See the section "Frame filtering" for more information. * See the section "Frame filtering" for more information.
* This callback must be implemented and can sleep. * 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 * @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. * 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: * buffer size of 8. Correct ways to retransmit #1 would be:
* - TX: 1 or 18 or 81 * - TX: 1 or 18 or 81
* Even "189" would be wrong since 1 could be lost again. * 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. * Returns a negative error code on failure.
* The callback can sleep. * The callback can sleep.
@ -3266,6 +3287,10 @@ struct ieee80211_ops {
unsigned int changed_flags, unsigned int changed_flags,
unsigned int *total_flags, unsigned int *total_flags,
u64 multicast); 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, int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set); bool set);
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@ -3349,7 +3374,7 @@ struct ieee80211_ops {
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn, struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size); u8 buf_size, bool amsdu);
int (*get_survey)(struct ieee80211_hw *hw, int idx, int (*get_survey)(struct ieee80211_hw *hw, int idx,
struct survey_info *survey); struct survey_info *survey);
void (*rfkill_poll)(struct ieee80211_hw *hw); void (*rfkill_poll)(struct ieee80211_hw *hw);

View File

@ -79,7 +79,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
(int)reason); (int)reason);
if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, 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, sdata_info(sta->sdata,
"HW problem - can not stop rx aggregation for %pM tid %d\n", "HW problem - can not stop rx aggregation for %pM tid %d\n",
sta->sta.addr, tid); 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 ieee80211_local *local = sdata->local;
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_mgmt *mgmt; struct ieee80211_mgmt *mgmt;
bool amsdu = ieee80211_hw_check(&local->hw, SUPPORTS_AMSDU_IN_AMPDU);
u16 capab; u16 capab;
skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); 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.action_code = WLAN_ACTION_ADDBA_RESP;
mgmt->u.action.u.addba_resp.dialog_token = dialog_token; 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)(tid << 2); /* bit 5:2 TID number */
capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ 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]); __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, 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", ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
sta->sta.addr, tid, ret); sta->sta.addr, tid, ret);
if (ret) { if (ret) {

View File

@ -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.action_code = WLAN_ACTION_ADDBA_REQ;
mgmt->u.action.u.addba_req.dialog_token = dialog_token; 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)(tid << 2); /* bit 5:2 TID number */
capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ 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; return -EALREADY;
ret = drv_ampdu_action(local, sta->sdata, ret = drv_ampdu_action(local, sta->sdata,
IEEE80211_AMPDU_TX_STOP_FLUSH_CONT, IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
&sta->sta, tid, NULL, 0); &sta->sta, tid, NULL, 0, false);
WARN_ON_ONCE(ret); WARN_ON_ONCE(ret);
return 0; 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; tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
ret = drv_ampdu_action(local, sta->sdata, action, 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 */ /* HW shall not deny going back to legacy */
if (WARN_ON(ret)) { 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; start_seq_num = sta->tid_seq[tid] >> 4;
ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, 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) { if (ret) {
ht_dbg(sdata, ht_dbg(sdata,
"BA request denied - HW unavailable for %pM tid %d\n", "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, drv_ampdu_action(local, sta->sdata,
IEEE80211_AMPDU_TX_OPERATIONAL, 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 * 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; struct tid_ampdu_tx *tid_tx;
u16 capab, tid; u16 capab, tid;
u8 buf_size; u8 buf_size;
bool amsdu;
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); 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; tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; 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->buf_size = buf_size;
tid_tx->amsdu = amsdu;
if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)) if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))
ieee80211_agg_tx_operational(local, sta, tid); ieee80211_agg_tx_operational(local, sta, tid);

View File

@ -981,7 +981,7 @@ static int sta_apply_auth_flags(struct ieee80211_local *local,
* well. Some drivers require rate control initialized * well. Some drivers require rate control initialized
* before drv_sta_state() is called. * 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); rate_control_rate_init(sta);
ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); 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) local->hw.queues >= IEEE80211_NUM_ACS)
sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME); sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
/* auth flags will be set later for TDLS stations */ /* auth flags will be set later for TDLS,
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { * 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); ret = sta_apply_auth_flags(local, sta, mask, set);
if (ret) if (ret)
return 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); set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH);
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
!sdata->u.mgd.tdls_wider_bw_prohibited &&
ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) && ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) &&
params->ext_capab_len >= 8 && params->ext_capab_len >= 8 &&
params->ext_capab[7] & WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) 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); sta_apply_mesh_params(local, sta, params);
/* set the STA state after all sta info from usermode has been set */ /* 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); ret = sta_apply_auth_flags(local, sta, mask, set);
if (ret) if (ret)
return 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 * defaults -- if userspace wants something else we'll
* change it accordingly in sta_apply_parameters() * 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_AUTH);
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); 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); err = sta_apply_parameters(local, sta, params);
if (err) { 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 * for TDLS and for unassociated station, rate control should be
* rates are known and station is marked authorized * 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); rate_control_rate_init(sta);
layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
@ -1346,7 +1355,10 @@ static int ieee80211_change_station(struct wiphy *wiphy,
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_AP_VLAN:
statype = CFG80211_STA_AP_CLIENT; if (test_sta_flag(sta, WLAN_STA_ASSOC))
statype = CFG80211_STA_AP_CLIENT;
else
statype = CFG80211_STA_AP_CLIENT_UNASSOC;
break; break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
@ -3522,18 +3534,32 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
u16 frame_type, bool reg) u16 frame_type, bool reg)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
switch (frame_type) { switch (frame_type) {
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ: case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
if (reg) if (reg) {
local->probe_req_reg++; local->probe_req_reg++;
else sdata->vif.probe_req_reg++;
local->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) if (!local->open_count)
break; 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; break;
default: default:
break; break;

View File

@ -123,6 +123,8 @@ static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = {
FLAG(SUPPORTS_CLONED_SKBS), FLAG(SUPPORTS_CLONED_SKBS),
FLAG(SINGLE_SCAN_ON_ALL_BANDS), FLAG(SINGLE_SCAN_ON_ALL_BANDS),
FLAG(TDLS_WIDER_BW), FLAG(TDLS_WIDER_BW),
FLAG(SUPPORTS_AMSDU_IN_AMPDU),
FLAG(BEACON_TX_STATUS),
/* keep last for the build bug below */ /* keep last for the build bug below */
(void *)0x1 (void *)0x1

View File

@ -2,6 +2,7 @@
* Copyright 2003-2005 Devicescape Software, Inc. * Copyright 2003-2005 Devicescape Software, Inc.
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net> * 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 * 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 * 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, \ .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) \ #define KEY_FILE(name, format) \
KEY_READ_##format(name) \ KEY_READ_##format(name) \
KEY_OPS(name) KEY_OPS(name)
@ -74,6 +83,41 @@ static ssize_t key_algorithm_read(struct file *file,
} }
KEY_OPS(algorithm); 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, static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos) 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); 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, static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
@ -278,6 +322,9 @@ KEY_OPS(key);
#define DEBUGFS_ADD(name) \ #define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0400, key->debugfs.dir, \ debugfs_create_file(#name, 0400, key->debugfs.dir, \
key, &key_##name##_ops); 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) 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(keyidx);
DEBUGFS_ADD(hw_key_idx); DEBUGFS_ADD(hw_key_idx);
DEBUGFS_ADD(algorithm); DEBUGFS_ADD(algorithm);
DEBUGFS_ADD(tx_spec); DEBUGFS_ADD_W(tx_spec);
DEBUGFS_ADD(rx_spec); DEBUGFS_ADD(rx_spec);
DEBUGFS_ADD(replays); DEBUGFS_ADD(replays);
DEBUGFS_ADD(icverrors); DEBUGFS_ADD(icverrors);

View File

@ -114,14 +114,6 @@ static ssize_t ieee80211_if_fmt_##name( \
return scnprintf(buf, buflen, "%pM\n", sdata->field); \ 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) \ #define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, field) \
static ssize_t ieee80211_if_fmt_##name( \ static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, \ const struct ieee80211_sub_if_data *sdata, \
@ -247,8 +239,6 @@ IEEE80211_IF_FILE_R(hw_queues);
/* STA attributes */ /* STA attributes */
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); 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); IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, 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); 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 */ /* AP attributes */
IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC); 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); 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(bssid);
DEBUGFS_ADD(aid); DEBUGFS_ADD(aid);
DEBUGFS_ADD(last_beacon);
DEBUGFS_ADD(ave_beacon);
DEBUGFS_ADD(beacon_timeout); DEBUGFS_ADD(beacon_timeout);
DEBUGFS_ADD_MODE(smps, 0600); DEBUGFS_ADD_MODE(smps, 0600);
DEBUGFS_ADD_MODE(tkip_mic_test, 0200); DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
DEBUGFS_ADD_MODE(beacon_loss, 0200); DEBUGFS_ADD_MODE(beacon_loss, 0200);
DEBUGFS_ADD_MODE(uapsd_queues, 0600); DEBUGFS_ADD_MODE(uapsd_queues, 0600);
DEBUGFS_ADD_MODE(uapsd_max_sp_len, 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) static void add_ap_files(struct ieee80211_sub_if_data *sdata)

View File

@ -8,6 +8,60 @@
#include "trace.h" #include "trace.h"
#include "driver-ops.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 __must_check
int drv_sta_state(struct ieee80211_local *local, int drv_sta_state(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
@ -39,3 +93,171 @@ int drv_sta_state(struct ieee80211_local *local,
trace_drv_return_int(local, ret); trace_drv_return_int(local, ret);
return 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;
}

View File

@ -137,59 +137,15 @@ static inline void drv_set_wakeup(struct ieee80211_local *local,
} }
#endif #endif
static inline int drv_add_interface(struct ieee80211_local *local, int drv_add_interface(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata) struct ieee80211_sub_if_data *sdata);
{
int ret;
might_sleep(); int drv_change_interface(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum nl80211_iftype type, bool p2p);
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || void drv_remove_interface(struct ieee80211_local *local,
(sdata->vif.type == NL80211_IFTYPE_MONITOR && struct ieee80211_sub_if_data *sdata);
!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,
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;
}
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);
}
static inline int drv_config(struct ieee80211_local *local, u32 changed) 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); 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, static inline int drv_set_tim(struct ieee80211_local *local,
struct ieee80211_sta *sta, bool set) 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 old_state,
enum ieee80211_sta_state new_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_sub_if_data *sdata,
struct ieee80211_sta *sta, u32 changed) 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);
}
static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local, static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, 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); 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, struct ieee80211_sub_if_data *sdata, u16 ac,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params);
{
int ret = -EOPNOTSUPP;
might_sleep(); u64 drv_get_tsf(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
if (!check_sdata_in_driver(sdata)) void drv_set_tsf(struct ieee80211_local *local,
return -EIO; struct ieee80211_sub_if_data *sdata,
u64 tsf);
if (WARN_ONCE(params->cw_min == 0 || void drv_reset_tsf(struct ieee80211_local *local,
params->cw_min > params->cw_max, struct ieee80211_sub_if_data *sdata);
"%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,
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);
}
static inline int drv_tx_last_beacon(struct ieee80211_local *local) 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; 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, struct ieee80211_sub_if_data *sdata,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, struct ieee80211_sta *sta, u16 tid,
u16 *ssn, u8 buf_size) 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);
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;
}
static inline int drv_get_survey(struct ieee80211_local *local, int idx, static inline int drv_get_survey(struct ieee80211_local *local, int idx,
struct survey_info *survey) struct survey_info *survey)
@ -1066,58 +944,9 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
trace_drv_return_void(local); trace_drv_return_void(local);
} }
static inline int int drv_switch_vif_chanctx(struct ieee80211_local *local,
drv_switch_vif_chanctx(struct ieee80211_local *local, struct ieee80211_vif_chanctx_switch *vifs,
struct ieee80211_vif_chanctx_switch *vifs, int n_vifs, enum ieee80211_chanctx_switch_mode mode);
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;
}
static inline int drv_start_ap(struct ieee80211_local *local, static inline int drv_start_ap(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata) struct ieee80211_sub_if_data *sdata)

View File

@ -419,6 +419,8 @@ struct ieee80211_sta_tx_tspec {
bool downgraded; bool downgraded;
}; };
DECLARE_EWMA(beacon_signal, 16, 4)
struct ieee80211_if_managed { struct ieee80211_if_managed {
struct timer_list timer; struct timer_list timer;
struct timer_list conn_mon_timer; struct timer_list conn_mon_timer;
@ -490,16 +492,7 @@ struct ieee80211_if_managed {
s16 p2p_noa_index; s16 p2p_noa_index;
/* Signal strength from the last Beacon frame in the current BSS. */ struct ewma_beacon_signal ave_beacon_signal;
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;
/* /*
* Number of Beacon frames used in ave_beacon_signal. This can be used * 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 */ struct sk_buff *teardown_skb; /* A copy to send through the AP */
spinlock_t teardown_lock; /* To lock changing teardown_skb */ spinlock_t teardown_lock; /* To lock changing teardown_skb */
bool tdls_chan_switch_prohibited; bool tdls_chan_switch_prohibited;
bool tdls_wider_bw_prohibited;
/* WMM-AC TSPEC support */ /* WMM-AC TSPEC support */
struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS]; 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 * struct sk_buff *
ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u32 info_flags); 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(struct sta_info *sta);
void ieee80211_check_fast_xmit_all(struct ieee80211_local *local); 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_dynamic_ps_timer(unsigned long data);
void ieee80211_send_nullfunc(struct ieee80211_local *local, void ieee80211_send_nullfunc(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
int powersave); bool powersave);
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr); struct ieee80211_hdr *hdr);
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,

View File

@ -1204,7 +1204,7 @@ static void ieee80211_iface_work(struct work_struct *work)
if (!ieee80211_sdata_running(sdata)) if (!ieee80211_sdata_running(sdata))
return; return;
if (local->scanning) if (test_bit(SCAN_SW_SCANNING, &local->scanning))
return; return;
if (!ieee80211_can_run_worker(local)) if (!ieee80211_can_run_worker(local))

View File

@ -543,7 +543,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
NL80211_FEATURE_HT_IBSS | NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_VIF_TXPOWER | NL80211_FEATURE_VIF_TXPOWER |
NL80211_FEATURE_MAC_ON_CREATE | NL80211_FEATURE_MAC_ON_CREATE |
NL80211_FEATURE_USERSPACE_MPM; NL80211_FEATURE_USERSPACE_MPM |
NL80211_FEATURE_FULL_AP_CLIENT_STATE;
if (!ops->hw_scan) if (!ops->hw_scan)
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |

View File

@ -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, ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
ie->ht_operation, &sta_chan_def); 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, if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
&sta_chan_def)) &sta_chan_def))
return false; 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_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *channel; 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_supported_band *sband;
struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_ht_cap *ht_cap;
u8 *pos; 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]; sband = local->hw.wiphy->bands[channel->band];
ht_cap = &sband->ht_cap; 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; return 0;
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation)) 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; 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) static void ieee80211_mesh_path_timer(unsigned long data)
{ {
struct ieee80211_sub_if_data *sdata = struct ieee80211_sub_if_data *sdata =
@ -540,9 +606,9 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
* *
* Return the header length. * 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, struct ieee80211s_hdr *meshhdr,
const char *addr4or5, const char *addr6) const char *addr4or5, const char *addr6)
{ {
if (WARN_ON(!addr4or5 && addr6)) if (WARN_ON(!addr4or5 && addr6))
return 0; return 0;
@ -637,6 +703,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
2 + ifmsh->mesh_id_len + 2 + ifmsh->mesh_id_len +
2 + sizeof(struct ieee80211_meshconf_ie) + 2 + sizeof(struct ieee80211_meshconf_ie) +
2 + sizeof(__le16) + /* awake window */ 2 + sizeof(__le16) + /* awake window */
2 + sizeof(struct ieee80211_vht_cap) +
2 + sizeof(struct ieee80211_vht_operation) +
ifmsh->ie_len; ifmsh->ie_len;
bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL); 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_meshid_ie(sdata, skb) ||
mesh_add_meshconf_ie(sdata, skb) || mesh_add_meshconf_ie(sdata, skb) ||
mesh_add_awake_window_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)) mesh_add_vendor_ies(sdata, skb))
goto out_free; goto out_free;

View File

@ -207,9 +207,9 @@ struct mesh_rmc {
/* Various */ /* Various */
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
const u8 *da, const u8 *sa); 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, struct ieee80211s_hdr *meshhdr,
const char *addr4or5, const char *addr6); const char *addr4or5, const char *addr6);
int mesh_rmc_check(struct ieee80211_sub_if_data *sdata, int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
const u8 *addr, struct ieee80211s_hdr *mesh_hdr); const u8 *addr, struct ieee80211s_hdr *mesh_hdr);
bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, bool mesh_matches_local(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); struct sk_buff *skb);
int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata, int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb); 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); void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
void ieee80211s_init(void); void ieee80211s_init(void);

View File

@ -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_meshconf_ie) +
2 + sizeof(struct ieee80211_ht_cap) + 2 + sizeof(struct ieee80211_ht_cap) +
2 + sizeof(struct ieee80211_ht_operation) + 2 + sizeof(struct ieee80211_ht_operation) +
2 + sizeof(struct ieee80211_vht_cap) +
2 + sizeof(struct ieee80211_vht_operation) +
2 + 8 + /* peering IE */ 2 + 8 + /* peering IE */
sdata->u.mesh.ie_len); sdata->u.mesh.ie_len);
if (!skb) 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 (action != WLAN_SP_MESH_PEERING_CLOSE) {
if (mesh_add_ht_cap_ie(sdata, skb) || 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; goto free;
} }
@ -402,6 +406,9 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
elems->ht_cap_elem, sta)) elems->ht_cap_elem, sta))
changed |= IEEE80211_RC_BW_CHANGED; 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) if (bw != sta->sta.bandwidth)
changed |= IEEE80211_RC_BW_CHANGED; changed |= IEEE80211_RC_BW_CHANGED;

View File

@ -81,13 +81,6 @@ MODULE_PARM_DESC(probe_wait_ms,
"Maximum time(ms) to wait for probe response" "Maximum time(ms) to wait for probe response"
" before disconnecting (reason 4)."); " 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 * How many Beacon frames need to have been used in average signal strength
* before starting to indicate signal change events. * 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, void ieee80211_send_nullfunc(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
int powersave) bool powersave)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_hdr_3addr *nullfunc; 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)); msecs_to_jiffies(conf->dynamic_ps_timeout));
} else { } else {
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK)) 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) && if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) 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( msecs_to_jiffies(
local->hw.conf.dynamic_ps_timeout)); local->hw.conf.dynamic_ps_timeout));
} else { } else {
ieee80211_send_nullfunc(local, sdata, 1); ieee80211_send_nullfunc(local, sdata, true);
/* Flush to get the tx status of nullfunc frame */ /* Flush to get the tx status of nullfunc frame */
ieee80211_flush_queues(local, sdata, false); 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)) { if (ieee80211_hw_check(&sdata->local->hw, REPORTS_TX_ACK_STATUS)) {
ifmgd->nullfunc_failed = false; ifmgd->nullfunc_failed = false;
ieee80211_send_nullfunc(sdata->local, sdata, 0); ieee80211_send_nullfunc(sdata->local, sdata, false);
} else { } else {
int ssid_len; int ssid_len;
@ -3262,16 +3255,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
if (ifmgd->associated && if (ifmgd->associated &&
ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
ieee80211_reset_ap_probe(sdata); 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; bssid = ifmgd->associated->bssid;
/* Track average RSSI from the Beacon frames of the current AP */ /* 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) { if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
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->last_cqm_event_signal = 0;
ifmgd->count_beacon_signal = 1; ifmgd->count_beacon_signal = 1;
ifmgd->last_ave_beacon_signal = 0; ifmgd->last_ave_beacon_signal = 0;
} else { } 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++; ifmgd->count_beacon_signal++;
} }
ewma_beacon_signal_add(&ifmgd->ave_beacon_signal, -rx_status->signal);
if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold && if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold &&
ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { 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; int last_sig = ifmgd->last_ave_beacon_signal;
struct ieee80211_event event = { struct ieee80211_event event = {
.type = RSSI_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 && if (bss_conf->cqm_rssi_thold &&
ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT && ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
!(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) { !(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 last_event = ifmgd->last_cqm_event_signal;
int thold = bss_conf->cqm_rssi_thold; int thold = bss_conf->cqm_rssi_thold;
int hyst = bss_conf->cqm_rssi_hyst; int hyst = bss_conf->cqm_rssi_hyst;
if (sig < thold && if (sig < thold &&
(last_event == 0 || sig < last_event - hyst)) { (last_event == 0 || sig < last_event - hyst)) {
ifmgd->last_cqm_event_signal = sig; ifmgd->last_cqm_event_signal = sig;
@ -3456,31 +3437,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
len - baselen, false, &elems, len - baselen, false, &elems,
care_about_ies, ncrc); care_about_ies, ncrc);
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK)) { if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
bool directed_tim = ieee80211_check_tim(elems.tim, ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) {
elems.tim_len, if (local->hw.conf.dynamic_ps_timeout > 0) {
ifmgd->aid); if (local->hw.conf.flags & IEEE80211_CONF_PS) {
if (directed_tim) { local->hw.conf.flags &= ~IEEE80211_CONF_PS;
if (local->hw.conf.dynamic_ps_timeout > 0) { ieee80211_hw_config(local,
if (local->hw.conf.flags & IEEE80211_CONF_PS) { IEEE80211_CONF_CHANGE_PS);
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
ieee80211_hw_config(local,
IEEE80211_CONF_CHANGE_PS);
}
ieee80211_send_nullfunc(local, sdata, 0);
} else if (!local->pspolling && sdata->u.mgd.powersave) {
local->pspolling = true;
/*
* Here is assumed that the driver will be
* able to send ps-poll frame and receive a
* response even though power save mode is
* enabled, but some drivers might require
* to disable power save here. This needs
* to be investigated.
*/
ieee80211_send_pspoll(local, sdata);
} }
ieee80211_send_nullfunc(local, sdata, false);
} else if (!local->pspolling && sdata->u.mgd.powersave) {
local->pspolling = true;
/*
* Here is assumed that the driver will be
* able to send ps-poll frame and receive a
* response even though power save mode is
* enabled, but some drivers might require
* to disable power save here. This needs
* to be investigated.
*/
ieee80211_send_pspoll(local, sdata);
} }
} }
@ -3717,12 +3694,14 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
reason); 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_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data;
u32 tx_flags = 0; u32 tx_flags = 0;
u16 trans = 1;
u16 status = 0;
sdata_assert_lock(sdata); sdata_assert_lock(sdata);
@ -3746,55 +3725,28 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
drv_mgd_prepare_tx(local, sdata); drv_mgd_prepare_tx(local, sdata);
if (auth_data->bss->proberesp_ies) { sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
u16 trans = 1; auth_data->bss->bssid, auth_data->tries,
u16 status = 0; IEEE80211_AUTH_MAX_TRIES);
sdata_info(sdata, "send auth to %pM (try %d/%d)\n", auth_data->expected_transaction = 2;
auth_data->bss->bssid, auth_data->tries,
IEEE80211_AUTH_MAX_TRIES);
auth_data->expected_transaction = 2; if (auth_data->algorithm == WLAN_AUTH_SAE) {
trans = auth_data->sae_trans;
if (auth_data->algorithm == WLAN_AUTH_SAE) { status = auth_data->sae_status;
trans = auth_data->sae_trans; auth_data->expected_transaction = trans;
status = auth_data->sae_status;
auth_data->expected_transaction = trans;
}
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_INTFL_MLME_CONN_TX;
ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
auth_data->data, auth_data->data_len,
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 (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_INTFL_MLME_CONN_TX;
ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
auth_data->data, auth_data->data_len,
auth_data->bss->bssid,
auth_data->bss->bssid, NULL, 0, 0,
tx_flags);
if (tx_flags == 0) { if (tx_flags == 0) {
auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
auth_data->timeout_started = true; auth_data->timeout_started = true;
@ -3874,8 +3826,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
bool status_acked = ifmgd->status_acked; bool status_acked = ifmgd->status_acked;
ifmgd->status_received = false; ifmgd->status_received = false;
if (ifmgd->auth_data && if (ifmgd->auth_data && ieee80211_is_auth(fc)) {
(ieee80211_is_probe_req(fc) || ieee80211_is_auth(fc))) {
if (status_acked) { if (status_acked) {
ifmgd->auth_data->timeout = ifmgd->auth_data->timeout =
jiffies + IEEE80211_AUTH_TIMEOUT_SHORT; 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 * so let's just kill the auth data
*/ */
ieee80211_destroy_auth_data(sdata, false); ieee80211_destroy_auth_data(sdata, false);
} else if (ieee80211_probe_auth(sdata)) { } else if (ieee80211_auth(sdata)) {
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
struct ieee80211_event event = { struct ieee80211_event event = {
.type = MLME_EVENT, .type = MLME_EVENT,
@ -4613,7 +4564,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
if (err) if (err)
goto err_clear; goto err_clear;
err = ieee80211_probe_auth(sdata); err = ieee80211_auth(sdata);
if (err) { if (err) {
sta_info_destroy_addr(sdata, req->bss->bssid); sta_info_destroy_addr(sdata, req->bss->bssid);
goto err_clear; goto err_clear;

View File

@ -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 * to send a new nullfunc frame to inform the AP that we
* are again sleeping. * 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 */ /* 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; struct ieee80211_local *local = sdata->local;
if (!local->ps_sdata) if (!local->ps_sdata)
ieee80211_send_nullfunc(local, sdata, 0); ieee80211_send_nullfunc(local, sdata, false);
else if (local->offchannel_ps_enabled) { else if (local->offchannel_ps_enabled) {
/* /*
* In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware * 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 * restart the timer now and send a nullfunc frame to inform
* the AP that we are awake. * 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 + mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
} }

View File

@ -23,7 +23,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
ieee80211_del_virtual_monitor(local); 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); mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) { list_for_each_entry(sta, &local->sta_list, list) {
set_sta_flag(sta, WLAN_STA_BLOCK_BA); set_sta_flag(sta, WLAN_STA_BLOCK_BA);

View File

@ -305,7 +305,10 @@ static void __rate_control_send_low(struct ieee80211_hw *hw,
info->control.rates[0].idx = i; info->control.rates[0].idx = i;
break; 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->control.rates[0].count =
(info->flags & IEEE80211_TX_CTL_NO_ACK) ? (info->flags & IEEE80211_TX_CTL_NO_ACK) ?

View File

@ -85,12 +85,10 @@ minstrel_stats_open(struct inode *inode, struct file *file)
file->private_data = ms; file->private_data = ms;
p = ms->buf; p = ms->buf;
p += sprintf(p, "\n"); p += sprintf(p, "\n");
p += sprintf(p, "best __________rate_________ ______" p += sprintf(p,
"statistics______ ________last_______ " "best __________rate_________ ________statistics________ ________last_______ ______sum-of________\n");
"______sum-of________\n"); p += sprintf(p,
p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob) " "rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n");
"sd(prob)] [prob.|retry|suc|att] "
"[#success | #attempts]\n");
for (i = 0; i < mi->n_rates; i++) { for (i = 0; i < mi->n_rates; i++) {
struct minstrel_rate *mr = &mi->r[i]; struct minstrel_rate *mr = &mi->r[i];
@ -112,7 +110,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u" p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u"
" %3u.%1u %3u %3u %-3u " " %3u.%1u %3u %3u %-3u "
"%9llu %-9llu\n", "%9llu %-9llu\n",
tp_max / 10, tp_max % 10, tp_max / 10, tp_max % 10,

View File

@ -86,7 +86,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u" p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u"
" %3u.%1u %3u %3u %-3u " " %3u.%1u %3u %3u %-3u "
"%9llu %-9llu\n", "%9llu %-9llu\n",
tp_max / 10, tp_max % 10, tp_max / 10, tp_max % 10,
@ -129,12 +129,10 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
p = ms->buf; p = ms->buf;
p += sprintf(p, "\n"); p += sprintf(p, "\n");
p += sprintf(p, " best ____________rate__________ " p += sprintf(p,
"______statistics______ ________last_______ " " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n");
"______sum-of________\n"); p += sprintf(p,
p += sprintf(p, "mode guard # rate [name idx airtime max_tp] " "mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n");
"[ ø(tp) ø(prob) sd(prob)] [prob.|retry|suc|att] [#success | "
"#attempts]\n");
p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
for (i = 0; i < MINSTREL_CCK_GROUP; i++) for (i = 0; i < MINSTREL_CCK_GROUP; i++)

View File

@ -133,6 +133,7 @@ enum ieee80211_agg_stop_reason {
* @buf_size: reorder buffer size at receiver * @buf_size: reorder buffer size at receiver
* @failed_bar_ssn: ssn of the last failed BAR tx attempt * @failed_bar_ssn: ssn of the last failed BAR tx attempt
* @bar_pending: BAR needs to be re-sent * @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 * This structure's lifetime is managed by RCU, assignments to
* the array holding it must hold the aggregation mutex. * the array holding it must hold the aggregation mutex.
@ -158,6 +159,7 @@ struct tid_ampdu_tx {
u16 failed_bar_ssn; u16 failed_bar_ssn;
bool bar_pending; bool bar_pending;
bool amsdu;
}; };
/** /**

View File

@ -668,16 +668,70 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
} }
EXPORT_SYMBOL(ieee80211_tx_status_noskb); 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 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_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
__le16 fc; __le16 fc;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata;
struct net_device *prev_dev = NULL;
struct sta_info *sta; struct sta_info *sta;
struct rhash_head *tmp; struct rhash_head *tmp;
int retry_count; int retry_count;
@ -685,7 +739,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
bool send_to_cooked; bool send_to_cooked;
bool acked; bool acked;
struct ieee80211_bar *bar; struct ieee80211_bar *bar;
int rtap_len;
int shift = 0; int shift = 0;
int tid = IEEE80211_NUM_TIDS; int tid = IEEE80211_NUM_TIDS;
const struct bucket_table *tbl; const struct bucket_table *tbl;
@ -878,51 +931,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
return; return;
} }
/* send frame to monitor interfaces now */ /* send to monitor interfaces */
rtap_len = ieee80211_tx_radiotap_len(info); ieee80211_tx_monitor(local, skb, sband, retry_count, shift, send_to_cooked);
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);
} }
EXPORT_SYMBOL(ieee80211_tx_status); EXPORT_SYMBOL(ieee80211_tx_status);

View File

@ -41,9 +41,11 @@ static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
bool chan_switch = local->hw.wiphy->features & bool chan_switch = local->hw.wiphy->features &
NL80211_FEATURE_TDLS_CHANNEL_SWITCH; 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); enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
bool vht = sband && sband->vht_cap.vht_supported; 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 */ /* proceed to downgrade the chandef until usable or the same */
while (uc.width > max_width && while (uc.width > max_width &&
!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, !cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &uc,
&uc, sdata->wdev.iftype)) sdata->wdev.iftype))
ieee80211_chandef_downgrade(&uc); ieee80211_chandef_downgrade(&uc);
if (!cfg80211_chandef_identical(&uc, &sta->tdls_chandef)) { if (!cfg80211_chandef_identical(&uc, &sta->tdls_chandef)) {

View File

@ -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, TRACE_EVENT(drv_set_tim,
TP_PROTO(struct ieee80211_local *local, TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sta *sta, bool set), struct ieee80211_sta *sta, bool set),
@ -944,9 +974,9 @@ TRACE_EVENT(drv_ampdu_action,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, 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( TP_STRUCT__entry(
LOCAL_ENTRY LOCAL_ENTRY
@ -955,6 +985,7 @@ TRACE_EVENT(drv_ampdu_action,
__field(u16, tid) __field(u16, tid)
__field(u16, ssn) __field(u16, ssn)
__field(u8, buf_size) __field(u8, buf_size)
__field(bool, amsdu)
VIF_ENTRY VIF_ENTRY
), ),
@ -966,12 +997,13 @@ TRACE_EVENT(drv_ampdu_action,
__entry->tid = tid; __entry->tid = tid;
__entry->ssn = ssn ? *ssn : 0; __entry->ssn = ssn ? *ssn : 0;
__entry->buf_size = buf_size; __entry->buf_size = buf_size;
__entry->amsdu = amsdu;
), ),
TP_printk( 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, LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
__entry->tid, __entry->buf_size __entry->tid, __entry->buf_size, __entry->amsdu
) )
); );

View File

@ -2767,7 +2767,8 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
*ieee80211_get_qos_ctl(hdr) = tid; *ieee80211_get_qos_ctl(hdr) = tid;
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); if (!sta->sta.txq[0])
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
} else { } else {
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number); hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number);
@ -3512,6 +3513,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
{ {
struct ieee80211_mutable_offsets offs = {}; struct ieee80211_mutable_offsets offs = {};
struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false); 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) if (tim_offset)
*tim_offset = offs.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) if (tim_length)
*tim_length = offs.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; return bcn;
} }
EXPORT_SYMBOL(ieee80211_beacon_get_tim); EXPORT_SYMBOL(ieee80211_beacon_get_tim);

View File

@ -1966,7 +1966,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (!sdata->u.mgd.associated) if (!sdata->u.mgd.associated)
continue; continue;
ieee80211_send_nullfunc(local, sdata, 0); ieee80211_send_nullfunc(local, sdata, false);
} }
} }
@ -2017,8 +2017,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mutex_lock(&local->sta_mtx); mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) { list_for_each_entry(sta, &local->sta_list, list) {
ieee80211_sta_tear_down_BA_sessions( if (!local->resuming)
sta, AGG_STOP_LOCAL_REQUEST); ieee80211_sta_tear_down_BA_sessions(
sta, AGG_STOP_LOCAL_REQUEST);
clear_sta_flag(sta, WLAN_STA_BLOCK_BA); 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) if (chandef->center_freq2)
vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg2_idx =
ieee80211_frequency_to_channel(chandef->center_freq2); ieee80211_frequency_to_channel(chandef->center_freq2);
else
vht_oper->center_freq_seg2_idx = 0x00;
switch (chandef->width) { switch (chandef->width) {
case NL80211_CHAN_WIDTH_160: case NL80211_CHAN_WIDTH_160:
@ -2541,7 +2544,7 @@ int ieee80211_ave_rssi(struct ieee80211_vif *vif)
/* non-managed type inferfaces */ /* non-managed type inferfaces */
return 0; return 0;
} }
return ifmgd->ave_beacon_signal / 16; return -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
} }
EXPORT_SYMBOL_GPL(ieee80211_ave_rssi); EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);

View File

@ -419,6 +419,7 @@ use_default_name:
device_initialize(&rdev->wiphy.dev); device_initialize(&rdev->wiphy.dev);
rdev->wiphy.dev.class = &ieee80211_class; rdev->wiphy.dev.class = &ieee80211_class;
rdev->wiphy.dev.platform_data = rdev; rdev->wiphy.dev.platform_data = rdev;
device_enable_async_suspend(&rdev->wiphy.dev);
INIT_LIST_HEAD(&rdev->destroy_list); INIT_LIST_HEAD(&rdev->destroy_list);
spin_lock_init(&rdev->destroy_list_lock); spin_lock_init(&rdev->destroy_list_lock);

View File

@ -3,6 +3,7 @@
* *
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2015 Intel Deutschland GmbH
*/ */
#include <linux/if.h> #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 (wdev->ssid_len) {
if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid)) if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
goto nla_put_failure; 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); 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 */ /* reject other things that can't change */
if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
return -EINVAL; return -EINVAL;
@ -4010,7 +4022,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
return -EINVAL; return -EINVAL;
} }
if (statype != CFG80211_STA_AP_CLIENT) { if (statype != CFG80211_STA_AP_CLIENT &&
statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
if (params->vlan) if (params->vlan)
return -EINVAL; return -EINVAL;
} }
@ -4022,6 +4035,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
return -EOPNOTSUPP; return -EOPNOTSUPP;
break; break;
case CFG80211_STA_AP_CLIENT: case CFG80211_STA_AP_CLIENT:
case CFG80211_STA_AP_CLIENT_UNASSOC:
/* accept only the listed bits */ /* accept only the listed bits */
if (params->sta_flags_mask & if (params->sta_flags_mask &
~(BIT(NL80211_STA_FLAG_AUTHORIZED) | ~(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) if (!wdev->netdev && !wdev->p2p_started)
return -ENETDOWN; return -ENETDOWN;
} }
if (!vcmd->doit)
return -EOPNOTSUPP;
} else { } else {
wdev = NULL; wdev = NULL;
} }
@ -9957,6 +9974,193 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
return -EOPNOTSUPP; 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, struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
enum nl80211_commands cmd, enum nl80211_commands cmd,
enum nl80211_attrs attr, enum nl80211_attrs attr,
@ -10994,6 +11198,7 @@ static const struct genl_ops nl80211_ops[] = {
{ {
.cmd = NL80211_CMD_VENDOR, .cmd = NL80211_CMD_VENDOR,
.doit = nl80211_vendor_cmd, .doit = nl80211_vendor_cmd,
.dumpit = nl80211_vendor_cmd_dump,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WIPHY | .internal_flags = NL80211_FLAG_NEED_WIPHY |

View File

@ -1040,8 +1040,8 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
const struct ieee80211_reg_rule *__freq_reg_info(struct wiphy *wiphy, static const struct ieee80211_reg_rule *
u32 center_freq, u32 min_bw) __freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
{ {
const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy); const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_reg_rule *reg_rule = NULL;