Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
commit
3d5c203272
@ -2990,13 +2990,15 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
{
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
if (vif->nw_type != AP_NETWORK)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Use this only for authorizing/unauthorizing a station */
|
||||
if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
|
||||
return -EOPNOTSUPP;
|
||||
err = cfg80211_check_station_change(wiphy, params,
|
||||
CFG80211_STA_AP_MLME_CLIENT);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
|
||||
return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
|
||||
|
@ -150,10 +150,6 @@ struct il3945_frame {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
|
||||
#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
|
||||
#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
|
||||
|
||||
#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
|
||||
#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
|
||||
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
|
||||
|
@ -2258,7 +2258,7 @@ il4965_tx_agg_start(struct il_priv *il, struct ieee80211_vif *vif,
|
||||
|
||||
spin_lock_irqsave(&il->sta_lock, flags);
|
||||
tid_data = &il->stations[sta_id].tid[tid];
|
||||
*ssn = SEQ_TO_SN(tid_data->seq_number);
|
||||
*ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
|
||||
tid_data->agg.txq_id = txq_id;
|
||||
il_set_swq_id(&il->txq[txq_id], il4965_get_ac_from_tid(tid), txq_id);
|
||||
spin_unlock_irqrestore(&il->sta_lock, flags);
|
||||
@ -2408,7 +2408,7 @@ il4965_txq_check_empty(struct il_priv *il, int sta_id, u8 tid, int txq_id)
|
||||
/* aggregated HW queue */
|
||||
if (txq_id == tid_data->agg.txq_id &&
|
||||
q->read_ptr == q->write_ptr) {
|
||||
u16 ssn = SEQ_TO_SN(tid_data->seq_number);
|
||||
u16 ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
|
||||
int tx_fifo = il4965_get_fifo_from_tid(tid);
|
||||
D_HT("HW queue empty: continue DELBA flow\n");
|
||||
il4965_txq_agg_disable(il, txq_id, ssn, tx_fifo);
|
||||
@ -2627,7 +2627,8 @@ il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr)
|
||||
static inline u32
|
||||
il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp)
|
||||
{
|
||||
return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN;
|
||||
return le32_to_cpup(&tx_resp->u.status +
|
||||
tx_resp->frame_count) & IEEE80211_MAX_SN;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
@ -2717,15 +2718,15 @@ il4965_tx_status_reply_tx(struct il_priv *il, struct il_ht_agg *agg,
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
|
||||
sc = le16_to_cpu(hdr->seq_ctrl);
|
||||
if (idx != (SEQ_TO_SN(sc) & 0xff)) {
|
||||
if (idx != (IEEE80211_SEQ_TO_SN(sc) & 0xff)) {
|
||||
IL_ERR("BUG_ON idx doesn't match seq control"
|
||||
" idx=%d, seq_idx=%d, seq=%d\n", idx,
|
||||
SEQ_TO_SN(sc), hdr->seq_ctrl);
|
||||
IEEE80211_SEQ_TO_SN(sc), hdr->seq_ctrl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx,
|
||||
SEQ_TO_SN(sc));
|
||||
IEEE80211_SEQ_TO_SN(sc));
|
||||
|
||||
sh = idx - start;
|
||||
if (sh > 64) {
|
||||
|
@ -541,10 +541,6 @@ struct il_frame {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
|
||||
#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
|
||||
#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
|
||||
|
||||
enum {
|
||||
CMD_SYNC = 0,
|
||||
CMD_SIZE_NORMAL = 0,
|
||||
|
@ -1137,7 +1137,8 @@ done:
|
||||
static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel *channel,
|
||||
int duration)
|
||||
int duration,
|
||||
enum ieee80211_roc_type type)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
|
||||
|
@ -418,7 +418,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
|
||||
" Tx flags = 0x%08x, agg.state = %d",
|
||||
info->flags, tid_data->agg.state);
|
||||
IWL_ERR(priv, "sta_id = %d, tid = %d seq_num = %d",
|
||||
sta_id, tid, SEQ_TO_SN(tid_data->seq_number));
|
||||
sta_id, tid,
|
||||
IEEE80211_SEQ_TO_SN(tid_data->seq_number));
|
||||
goto drop_unlock_sta;
|
||||
}
|
||||
|
||||
@ -569,7 +570,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
|
||||
return 0;
|
||||
}
|
||||
|
||||
tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
|
||||
tid_data->agg.ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
|
||||
|
||||
/* There are still packets for this RA / TID in the HW */
|
||||
if (!test_bit(txq_id, priv->agg_q_alloc)) {
|
||||
@ -651,7 +652,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
|
||||
|
||||
spin_lock_bh(&priv->sta_lock);
|
||||
tid_data = &priv->tid_data[sta_id][tid];
|
||||
tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
|
||||
tid_data->agg.ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
|
||||
tid_data->agg.txq_id = txq_id;
|
||||
|
||||
*ssn = tid_data->agg.ssn;
|
||||
@ -911,7 +912,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
|
||||
static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
|
||||
{
|
||||
return le32_to_cpup((__le32 *)&tx_resp->status +
|
||||
tx_resp->frame_count) & MAX_SN;
|
||||
tx_resp->frame_count) & IEEE80211_MAX_SN;
|
||||
}
|
||||
|
||||
static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
|
||||
@ -1148,7 +1149,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
||||
|
||||
if (tx_resp->frame_count == 1) {
|
||||
u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl);
|
||||
next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10);
|
||||
next_reclaimed = IEEE80211_SEQ_TO_SN(next_reclaimed + 0x10);
|
||||
|
||||
if (is_agg) {
|
||||
/* If this is an aggregation queue, we can rely on the
|
||||
|
@ -114,9 +114,6 @@
|
||||
* completely agnostic to these differences.
|
||||
* The transport does provide helper functionnality (i.e. SYNC / ASYNC mode),
|
||||
*/
|
||||
#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
|
||||
#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
|
||||
#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
|
||||
#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f)
|
||||
#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8)
|
||||
#define SEQ_TO_INDEX(s) ((s) & 0xff)
|
||||
|
@ -1081,7 +1081,8 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
static int iwl_mvm_roc(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel *channel,
|
||||
int duration)
|
||||
int duration,
|
||||
enum ieee80211_roc_type type)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct cfg80211_chan_def chandef;
|
||||
@ -1092,8 +1093,8 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d)\n", channel->hw_value,
|
||||
duration);
|
||||
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
|
||||
duration, type);
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
|
@ -686,7 +686,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
tid_data = &mvmsta->tid_data[tid];
|
||||
tid_data->ssn = SEQ_TO_SN(tid_data->seq_number);
|
||||
tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
|
||||
tid_data->txq_id = txq_id;
|
||||
*ssn = tid_data->ssn;
|
||||
|
||||
@ -779,7 +779,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
|
||||
switch (tid_data->state) {
|
||||
case IWL_AGG_ON:
|
||||
tid_data->ssn = SEQ_TO_SN(tid_data->seq_number);
|
||||
tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"ssn = %d, next_recl = %d\n",
|
||||
|
@ -641,7 +641,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
||||
next_reclaimed = ssn;
|
||||
} else {
|
||||
/* The next packet to be reclaimed is the one after this one */
|
||||
next_reclaimed = SEQ_TO_SN(seq_ctl + 0x10);
|
||||
next_reclaimed = IEEE80211_SEQ_TO_SN(seq_ctl + 0x10);
|
||||
}
|
||||
|
||||
IWL_DEBUG_TX_REPLY(mvm,
|
||||
|
@ -1581,7 +1581,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
||||
* Check here that the packets are in the right place on the ring.
|
||||
*/
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
|
||||
wifi_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
|
||||
WARN_ONCE((iwl_read_prph(trans, SCD_AGGR_SEL) & BIT(txq_id)) &&
|
||||
((wifi_seq & 0xff) != q->write_ptr),
|
||||
"Q: %d WiFi Seq %d tfdNum %d",
|
||||
|
@ -1535,7 +1535,8 @@ static void hw_roc_done(struct work_struct *work)
|
||||
static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel *chan,
|
||||
int duration)
|
||||
int duration,
|
||||
enum ieee80211_roc_type type)
|
||||
{
|
||||
struct mac80211_hwsim_data *hwsim = hw->priv;
|
||||
|
||||
|
@ -2127,9 +2127,6 @@ value to host byte ordering.*/
|
||||
#define WLAN_FC_GET_TYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE)
|
||||
#define WLAN_FC_GET_STYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE)
|
||||
#define WLAN_FC_MORE_DATA(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_MOREDATA)
|
||||
#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
|
||||
#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
|
||||
#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
|
||||
|
||||
#define RT_RF_OFF_LEVL_ASPM BIT(0) /*PCI ASPM */
|
||||
#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /*PCI clock request */
|
||||
|
@ -4956,7 +4956,8 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop)
|
||||
static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel *chan,
|
||||
int duration)
|
||||
int duration,
|
||||
enum ieee80211_roc_type type)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct wl1271 *wl = hw->priv;
|
||||
|
@ -113,6 +113,34 @@
|
||||
#define IEEE80211_CTL_EXT_SSW_FBACK 0x9000
|
||||
#define IEEE80211_CTL_EXT_SSW_ACK 0xa000
|
||||
|
||||
|
||||
#define IEEE80211_SN_MASK ((IEEE80211_SCTL_SEQ) >> 4)
|
||||
#define IEEE80211_MAX_SN IEEE80211_SN_MASK
|
||||
#define IEEE80211_SN_MODULO (IEEE80211_MAX_SN + 1)
|
||||
|
||||
static inline int ieee80211_sn_less(u16 sn1, u16 sn2)
|
||||
{
|
||||
return ((sn1 - sn2) & IEEE80211_SN_MASK) > (IEEE80211_SN_MODULO >> 1);
|
||||
}
|
||||
|
||||
static inline u16 ieee80211_sn_add(u16 sn1, u16 sn2)
|
||||
{
|
||||
return (sn1 + sn2) & IEEE80211_SN_MASK;
|
||||
}
|
||||
|
||||
static inline u16 ieee80211_sn_inc(u16 sn)
|
||||
{
|
||||
return ieee80211_sn_add(sn, 1);
|
||||
}
|
||||
|
||||
static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
|
||||
{
|
||||
return (sn1 - sn2) & IEEE80211_SN_MASK;
|
||||
}
|
||||
|
||||
#define IEEE80211_SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
|
||||
#define IEEE80211_SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
|
||||
|
||||
/* miscellaneous IEEE 802.11 constants */
|
||||
#define IEEE80211_MAX_FRAG_THRESHOLD 2352
|
||||
#define IEEE80211_MAX_RTS_THRESHOLD 2353
|
||||
@ -185,7 +213,7 @@ struct ieee80211_hdr {
|
||||
u8 addr3[6];
|
||||
__le16 seq_ctrl;
|
||||
u8 addr4[6];
|
||||
} __packed;
|
||||
} __packed __aligned(2);
|
||||
|
||||
struct ieee80211_hdr_3addr {
|
||||
__le16 frame_control;
|
||||
@ -194,7 +222,7 @@ struct ieee80211_hdr_3addr {
|
||||
u8 addr2[6];
|
||||
u8 addr3[6];
|
||||
__le16 seq_ctrl;
|
||||
} __packed;
|
||||
} __packed __aligned(2);
|
||||
|
||||
struct ieee80211_qos_hdr {
|
||||
__le16 frame_control;
|
||||
@ -204,7 +232,7 @@ struct ieee80211_qos_hdr {
|
||||
u8 addr3[6];
|
||||
__le16 seq_ctrl;
|
||||
__le16 qos_ctrl;
|
||||
} __packed;
|
||||
} __packed __aligned(2);
|
||||
|
||||
/**
|
||||
* ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set
|
||||
@ -581,7 +609,7 @@ struct ieee80211s_hdr {
|
||||
__le32 seqnum;
|
||||
u8 eaddr1[6];
|
||||
u8 eaddr2[6];
|
||||
} __packed;
|
||||
} __packed __aligned(2);
|
||||
|
||||
/* Mesh flags */
|
||||
#define MESH_FLAGS_AE_A4 0x1
|
||||
@ -875,7 +903,7 @@ struct ieee80211_mgmt {
|
||||
} u;
|
||||
} __packed action;
|
||||
} u;
|
||||
} __packed;
|
||||
} __packed __aligned(2);
|
||||
|
||||
/* Supported Rates value encodings in 802.11n-2009 7.3.2.2 */
|
||||
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
|
||||
@ -906,20 +934,20 @@ struct ieee80211_rts {
|
||||
__le16 duration;
|
||||
u8 ra[6];
|
||||
u8 ta[6];
|
||||
} __packed;
|
||||
} __packed __aligned(2);
|
||||
|
||||
struct ieee80211_cts {
|
||||
__le16 frame_control;
|
||||
__le16 duration;
|
||||
u8 ra[6];
|
||||
} __packed;
|
||||
} __packed __aligned(2);
|
||||
|
||||
struct ieee80211_pspoll {
|
||||
__le16 frame_control;
|
||||
__le16 aid;
|
||||
u8 bssid[6];
|
||||
u8 ta[6];
|
||||
} __packed;
|
||||
} __packed __aligned(2);
|
||||
|
||||
/* TDLS */
|
||||
|
||||
@ -1290,11 +1318,6 @@ struct ieee80211_vht_operation {
|
||||
} __packed;
|
||||
|
||||
|
||||
#define IEEE80211_VHT_MCS_ZERO_TO_SEVEN_SUPPORT 0
|
||||
#define IEEE80211_VHT_MCS_ZERO_TO_EIGHT_SUPPORT 1
|
||||
#define IEEE80211_VHT_MCS_ZERO_TO_NINE_SUPPORT 2
|
||||
#define IEEE80211_VHT_MCS_NOT_SUPPORTED 3
|
||||
|
||||
/* 802.11ac VHT Capabilities */
|
||||
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
|
||||
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001
|
||||
@ -1310,10 +1333,11 @@ struct ieee80211_vht_operation {
|
||||
#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200
|
||||
#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300
|
||||
#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400
|
||||
#define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700
|
||||
#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800
|
||||
#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000
|
||||
#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000
|
||||
#define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000
|
||||
#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX 0x00030000
|
||||
#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000
|
||||
#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000
|
||||
#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000
|
||||
|
@ -610,23 +610,11 @@ struct cfg80211_ap_settings {
|
||||
bool radar_required;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum plink_action - actions to perform in mesh peers
|
||||
*
|
||||
* @PLINK_ACTION_INVALID: action 0 is reserved
|
||||
* @PLINK_ACTION_OPEN: start mesh peer link establishment
|
||||
* @PLINK_ACTION_BLOCK: block traffic from this mesh peer
|
||||
*/
|
||||
enum plink_actions {
|
||||
PLINK_ACTION_INVALID,
|
||||
PLINK_ACTION_OPEN,
|
||||
PLINK_ACTION_BLOCK,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum station_parameters_apply_mask - station parameter values to apply
|
||||
* @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
|
||||
* @STATION_PARAM_APPLY_CAPABILITY: apply new capability
|
||||
* @STATION_PARAM_APPLY_PLINK_STATE: apply new plink state
|
||||
*
|
||||
* Not all station parameters have in-band "no change" signalling,
|
||||
* for those that don't these flags will are used.
|
||||
@ -634,6 +622,7 @@ enum plink_actions {
|
||||
enum station_parameters_apply_mask {
|
||||
STATION_PARAM_APPLY_UAPSD = BIT(0),
|
||||
STATION_PARAM_APPLY_CAPABILITY = BIT(1),
|
||||
STATION_PARAM_APPLY_PLINK_STATE = BIT(2),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -669,7 +658,7 @@ enum station_parameters_apply_mask {
|
||||
* @ext_capab_len: number of extended capabilities
|
||||
*/
|
||||
struct station_parameters {
|
||||
u8 *supported_rates;
|
||||
const u8 *supported_rates;
|
||||
struct net_device *vlan;
|
||||
u32 sta_flags_mask, sta_flags_set;
|
||||
u32 sta_modify_mask;
|
||||
@ -678,16 +667,59 @@ struct station_parameters {
|
||||
u8 supported_rates_len;
|
||||
u8 plink_action;
|
||||
u8 plink_state;
|
||||
struct ieee80211_ht_cap *ht_capa;
|
||||
struct ieee80211_vht_cap *vht_capa;
|
||||
const struct ieee80211_ht_cap *ht_capa;
|
||||
const struct ieee80211_vht_cap *vht_capa;
|
||||
u8 uapsd_queues;
|
||||
u8 max_sp;
|
||||
enum nl80211_mesh_power_mode local_pm;
|
||||
u16 capability;
|
||||
u8 *ext_capab;
|
||||
const u8 *ext_capab;
|
||||
u8 ext_capab_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum cfg80211_station_type - the type of station being modified
|
||||
* @CFG80211_STA_AP_CLIENT: client of an AP interface
|
||||
* @CFG80211_STA_AP_MLME_CLIENT: client of an AP interface that has
|
||||
* the AP MLME in the device
|
||||
* @CFG80211_STA_AP_STA: AP station on managed interface
|
||||
* @CFG80211_STA_IBSS: IBSS station
|
||||
* @CFG80211_STA_TDLS_PEER_SETUP: TDLS peer on managed interface (dummy entry
|
||||
* while TDLS setup is in progress, it moves out of this state when
|
||||
* being marked authorized; use this only if TDLS with external setup is
|
||||
* supported/used)
|
||||
* @CFG80211_STA_TDLS_PEER_ACTIVE: TDLS peer on managed interface (active
|
||||
* entry that is operating, has been marked authorized by userspace)
|
||||
* @CFG80211_STA_MESH_PEER_KERNEL: peer on mesh interface (kernel managed)
|
||||
* @CFG80211_STA_MESH_PEER_USER: peer on mesh interface (user managed)
|
||||
*/
|
||||
enum cfg80211_station_type {
|
||||
CFG80211_STA_AP_CLIENT,
|
||||
CFG80211_STA_AP_MLME_CLIENT,
|
||||
CFG80211_STA_AP_STA,
|
||||
CFG80211_STA_IBSS,
|
||||
CFG80211_STA_TDLS_PEER_SETUP,
|
||||
CFG80211_STA_TDLS_PEER_ACTIVE,
|
||||
CFG80211_STA_MESH_PEER_KERNEL,
|
||||
CFG80211_STA_MESH_PEER_USER,
|
||||
};
|
||||
|
||||
/**
|
||||
* cfg80211_check_station_change - validate parameter changes
|
||||
* @wiphy: the wiphy this operates on
|
||||
* @params: the new parameters for a station
|
||||
* @statype: the type of station being modified
|
||||
*
|
||||
* Utility function for the @change_station driver method. Call this function
|
||||
* with the appropriate station type looking up the station (and checking that
|
||||
* it exists). It will verify whether the station change is acceptable, and if
|
||||
* not will return an error code. Note that it may modify the parameters for
|
||||
* backward compatibility reasons, so don't use them before calling this.
|
||||
*/
|
||||
int cfg80211_check_station_change(struct wiphy *wiphy,
|
||||
struct station_parameters *params,
|
||||
enum cfg80211_station_type statype);
|
||||
|
||||
/**
|
||||
* enum station_info_flags - station information flags
|
||||
*
|
||||
@ -1119,6 +1151,7 @@ struct mesh_config {
|
||||
* @ie_len: length of vendor information elements
|
||||
* @is_authenticated: this mesh requires authentication
|
||||
* @is_secure: this mesh uses security
|
||||
* @user_mpm: userspace handles all MPM functions
|
||||
* @dtim_period: DTIM period to use
|
||||
* @beacon_interval: beacon interval to use
|
||||
* @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
|
||||
@ -1136,6 +1169,7 @@ struct mesh_setup {
|
||||
u8 ie_len;
|
||||
bool is_authenticated;
|
||||
bool is_secure;
|
||||
bool user_mpm;
|
||||
u8 dtim_period;
|
||||
u16 beacon_interval;
|
||||
int mcast_rate[IEEE80211_NUM_BANDS];
|
||||
@ -1398,9 +1432,11 @@ struct cfg80211_auth_request {
|
||||
* enum cfg80211_assoc_req_flags - Over-ride default behaviour in association.
|
||||
*
|
||||
* @ASSOC_REQ_DISABLE_HT: Disable HT (802.11n)
|
||||
* @ASSOC_REQ_DISABLE_VHT: Disable VHT
|
||||
*/
|
||||
enum cfg80211_assoc_req_flags {
|
||||
ASSOC_REQ_DISABLE_HT = BIT(0),
|
||||
ASSOC_REQ_DISABLE_VHT = BIT(1),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1422,6 +1458,8 @@ enum cfg80211_assoc_req_flags {
|
||||
* @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask
|
||||
* will be used in ht_capa. Un-supported values will be ignored.
|
||||
* @ht_capa_mask: The bits of ht_capa which are to be used.
|
||||
* @vht_capa: VHT capability override
|
||||
* @vht_capa_mask: VHT capability mask indicating which fields to use
|
||||
*/
|
||||
struct cfg80211_assoc_request {
|
||||
struct cfg80211_bss *bss;
|
||||
@ -1432,6 +1470,7 @@ struct cfg80211_assoc_request {
|
||||
u32 flags;
|
||||
struct ieee80211_ht_cap ht_capa;
|
||||
struct ieee80211_ht_cap ht_capa_mask;
|
||||
struct ieee80211_vht_cap vht_capa, vht_capa_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1542,6 +1581,8 @@ struct cfg80211_ibss_params {
|
||||
* @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask
|
||||
* will be used in ht_capa. Un-supported values will be ignored.
|
||||
* @ht_capa_mask: The bits of ht_capa which are to be used.
|
||||
* @vht_capa: VHT Capability overrides
|
||||
* @vht_capa_mask: The bits of vht_capa which are to be used.
|
||||
*/
|
||||
struct cfg80211_connect_params {
|
||||
struct ieee80211_channel *channel;
|
||||
@ -1560,6 +1601,8 @@ struct cfg80211_connect_params {
|
||||
int bg_scan_period;
|
||||
struct ieee80211_ht_cap ht_capa;
|
||||
struct ieee80211_ht_cap ht_capa_mask;
|
||||
struct ieee80211_vht_cap vht_capa;
|
||||
struct ieee80211_vht_cap vht_capa_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1721,6 +1764,21 @@ struct cfg80211_gtk_rekey_data {
|
||||
u8 replay_ctr[NL80211_REPLAY_CTR_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_update_ft_ies_params - FT IE Information
|
||||
*
|
||||
* This structure provides information needed to update the fast transition IE
|
||||
*
|
||||
* @md: The Mobility Domain ID, 2 Octet value
|
||||
* @ie: Fast Transition IEs
|
||||
* @ie_len: Length of ft_ie in octets
|
||||
*/
|
||||
struct cfg80211_update_ft_ies_params {
|
||||
u16 md;
|
||||
const u8 *ie;
|
||||
size_t ie_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_ops - backend description for wireless configuration
|
||||
*
|
||||
@ -1781,9 +1839,8 @@ struct cfg80211_gtk_rekey_data {
|
||||
* @change_station: Modify a given station. Note that flags changes are not much
|
||||
* validated in cfg80211, in particular the auth/assoc/authorized flags
|
||||
* might come to the driver in invalid combinations -- make sure to check
|
||||
* them, also against the existing state! Also, supported_rates changes are
|
||||
* not checked in station mode -- drivers need to reject (or ignore) them
|
||||
* for anything but TDLS peers.
|
||||
* them, also against the existing state! Drivers must call
|
||||
* cfg80211_check_station_change() to validate the information.
|
||||
* @get_station: get station information for the station identified by @mac
|
||||
* @dump_station: dump station callback -- resume dump at index @idx
|
||||
*
|
||||
@ -2168,6 +2225,8 @@ struct cfg80211_ops {
|
||||
int (*start_radar_detection)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_update_ft_ies_params *ftie);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2485,6 +2544,8 @@ struct wiphy_wowlan_support {
|
||||
* @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
|
||||
* @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden.
|
||||
* If null, then none can be over-ridden.
|
||||
* @vht_capa_mod_mask: Specify what VHT capabilities can be over-ridden.
|
||||
* If null, then none can be over-ridden.
|
||||
*
|
||||
* @max_acl_mac_addrs: Maximum number of MAC addresses that the device
|
||||
* supports for ACL.
|
||||
@ -2593,6 +2654,7 @@ struct wiphy {
|
||||
struct dentry *debugfsdir;
|
||||
|
||||
const struct ieee80211_ht_cap *ht_capa_mod_mask;
|
||||
const struct ieee80211_vht_cap *vht_capa_mod_mask;
|
||||
|
||||
#ifdef CONFIG_NET_NS
|
||||
/* the network namespace this phy lives in currently */
|
||||
@ -4001,6 +4063,30 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate);
|
||||
*/
|
||||
void cfg80211_unregister_wdev(struct wireless_dev *wdev);
|
||||
|
||||
/**
|
||||
* struct cfg80211_ft_event - FT Information Elements
|
||||
* @ies: FT IEs
|
||||
* @ies_len: length of the FT IE in bytes
|
||||
* @target_ap: target AP's MAC address
|
||||
* @ric_ies: RIC IE
|
||||
* @ric_ies_len: length of the RIC IE in bytes
|
||||
*/
|
||||
struct cfg80211_ft_event_params {
|
||||
const u8 *ies;
|
||||
size_t ies_len;
|
||||
const u8 *target_ap;
|
||||
const u8 *ric_ies;
|
||||
size_t ric_ies_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* cfg80211_ft_event - notify userspace about FT IE and RIC IE
|
||||
* @netdev: network device
|
||||
* @ft_event: IE information
|
||||
*/
|
||||
void cfg80211_ft_event(struct net_device *netdev,
|
||||
struct cfg80211_ft_event_params *ft_event);
|
||||
|
||||
/**
|
||||
* cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer
|
||||
* @ies: the input IE buffer
|
||||
|
@ -1101,8 +1101,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
|
||||
* These flags are used for communication about keys between the driver
|
||||
* and mac80211, with the @flags parameter of &struct ieee80211_key_conf.
|
||||
*
|
||||
* @IEEE80211_KEY_FLAG_WMM_STA: Set by mac80211, this flag indicates
|
||||
* that the STA this key will be used with could be using QoS.
|
||||
* @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the
|
||||
* driver to indicate that it requires IV generation for this
|
||||
* particular key.
|
||||
@ -1127,7 +1125,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
|
||||
* %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW.
|
||||
*/
|
||||
enum ieee80211_key_flags {
|
||||
IEEE80211_KEY_FLAG_WMM_STA = 1<<0,
|
||||
IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1,
|
||||
IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
|
||||
IEEE80211_KEY_FLAG_PAIRWISE = 1<<3,
|
||||
@ -1231,9 +1228,8 @@ enum ieee80211_sta_rx_bandwidth {
|
||||
* @addr: MAC address
|
||||
* @aid: AID we assigned to the station if we're an AP
|
||||
* @supp_rates: Bitmap of supported rates (per band)
|
||||
* @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities
|
||||
* @vht_cap: VHT capabilities of this STA; Not restricting any capabilities
|
||||
* of remote STA. Taking as is.
|
||||
* @ht_cap: HT capabilities of this STA; restricted to our own capabilities
|
||||
* @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
|
||||
* @wme: indicates whether the STA supports WME. Only valid during AP-mode.
|
||||
* @drv_priv: data area for driver use, will always be aligned to
|
||||
* sizeof(void *), size is determined in hw information.
|
||||
@ -2134,6 +2130,24 @@ enum ieee80211_rate_control_changed {
|
||||
IEEE80211_RC_NSS_CHANGED = BIT(3),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_roc_type - remain on channel type
|
||||
*
|
||||
* With the support for multi channel contexts and multi channel operations,
|
||||
* remain on channel operations might be limited/deferred/aborted by other
|
||||
* flows/operations which have higher priority (and vise versa).
|
||||
* Specifying the ROC type can be used by devices to prioritize the ROC
|
||||
* operations compared to other operations/flows.
|
||||
*
|
||||
* @IEEE80211_ROC_TYPE_NORMAL: There are no special requirements for this ROC.
|
||||
* @IEEE80211_ROC_TYPE_MGMT_TX: The remain on channel request is required
|
||||
* for sending managment frames offchannel.
|
||||
*/
|
||||
enum ieee80211_roc_type {
|
||||
IEEE80211_ROC_TYPE_NORMAL = 0,
|
||||
IEEE80211_ROC_TYPE_MGMT_TX,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_ops - callbacks from mac80211 to the driver
|
||||
*
|
||||
@ -2687,7 +2701,8 @@ struct ieee80211_ops {
|
||||
int (*remain_on_channel)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel *chan,
|
||||
int duration);
|
||||
int duration,
|
||||
enum ieee80211_roc_type type);
|
||||
int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
|
||||
int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
|
||||
void (*get_ringparam)(struct ieee80211_hw *hw,
|
||||
|
@ -36,7 +36,21 @@
|
||||
* The station is still assumed to belong to the AP interface it was added
|
||||
* to.
|
||||
*
|
||||
* TODO: need more info?
|
||||
* Station handling varies per interface type and depending on the driver's
|
||||
* capabilities.
|
||||
*
|
||||
* For drivers supporting TDLS with external setup (WIPHY_FLAG_SUPPORTS_TDLS
|
||||
* and WIPHY_FLAG_TDLS_EXTERNAL_SETUP), the station lifetime is as follows:
|
||||
* - a setup station entry is added, not yet authorized, without any rate
|
||||
* or capability information, this just exists to avoid race conditions
|
||||
* - when the TDLS setup is done, a single NL80211_CMD_SET_STATION is valid
|
||||
* to add rate and capability information to the station and at the same
|
||||
* time mark it authorized.
|
||||
* - %NL80211_TDLS_ENABLE_LINK is then used
|
||||
* - after this, the only valid operation is to remove it by tearing down
|
||||
* the TDLS link (%NL80211_TDLS_DISABLE_LINK)
|
||||
*
|
||||
* TODO: need more info for other interface types
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -499,9 +513,11 @@
|
||||
* @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
|
||||
* beacon or probe response from a compatible mesh peer. This is only
|
||||
* sent while no station information (sta_info) exists for the new peer
|
||||
* candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On
|
||||
* reception of this notification, userspace may decide to create a new
|
||||
* station (@NL80211_CMD_NEW_STATION). To stop this notification from
|
||||
* candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH,
|
||||
* @NL80211_MESH_SETUP_USERSPACE_AMPE, or
|
||||
* @NL80211_MESH_SETUP_USERSPACE_MPM is set. On reception of this
|
||||
* notification, userspace may decide to create a new station
|
||||
* (@NL80211_CMD_NEW_STATION). To stop this notification from
|
||||
* reoccurring, the userspace authentication daemon may want to create the
|
||||
* new station with the AUTHENTICATED flag unset and maybe change it later
|
||||
* depending on the authentication result.
|
||||
@ -611,6 +627,18 @@
|
||||
* %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the
|
||||
* event.
|
||||
*
|
||||
* @NL80211_CMD_GET_PROTOCOL_FEATURES: Get global nl80211 protocol features,
|
||||
* i.e. features for the nl80211 protocol rather than device features.
|
||||
* Returns the features in the %NL80211_ATTR_PROTOCOL_FEATURES bitmap.
|
||||
*
|
||||
* @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition
|
||||
* Information Element to the WLAN driver
|
||||
*
|
||||
* @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver
|
||||
* to the supplicant. This will carry the target AP's MAC address along
|
||||
* with the relevant Information Elements. This event is used to report
|
||||
* received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE).
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -765,6 +793,11 @@ enum nl80211_commands {
|
||||
|
||||
NL80211_CMD_RADAR_DETECT,
|
||||
|
||||
NL80211_CMD_GET_PROTOCOL_FEATURES,
|
||||
|
||||
NL80211_CMD_UPDATE_FT_IES,
|
||||
NL80211_CMD_FT_EVENT,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@ -884,7 +917,8 @@ enum nl80211_commands {
|
||||
* consisting of a nested array.
|
||||
*
|
||||
* @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
|
||||
* @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
|
||||
* @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link
|
||||
* (see &enum nl80211_plink_action).
|
||||
* @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
|
||||
* @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
|
||||
* info given for %NL80211_CMD_GET_MPATH, nested attribute described at
|
||||
@ -1167,10 +1201,10 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
|
||||
* allows auth frames in a mesh to be passed to userspace for processing via
|
||||
* the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
|
||||
* @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as
|
||||
* defined in &enum nl80211_plink_state. Used when userspace is
|
||||
* driving the peer link management state machine.
|
||||
* @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled.
|
||||
* @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as defined in
|
||||
* &enum nl80211_plink_state. Used when userspace is driving the peer link
|
||||
* management state machine. @NL80211_MESH_SETUP_USERSPACE_AMPE or
|
||||
* @NL80211_MESH_SETUP_USERSPACE_MPM must be enabled.
|
||||
*
|
||||
* @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy
|
||||
* capabilities, the supported WoWLAN triggers
|
||||
@ -1368,6 +1402,18 @@ enum nl80211_commands {
|
||||
* advertised to the driver, e.g., to enable TDLS off channel operations
|
||||
* and PU-APSD.
|
||||
*
|
||||
* @NL80211_ATTR_PROTOCOL_FEATURES: global nl80211 feature flags, see
|
||||
* &enum nl80211_protocol_features, the attribute is a u32.
|
||||
*
|
||||
* @NL80211_ATTR_SPLIT_WIPHY_DUMP: flag attribute, userspace supports
|
||||
* receiving the data for a single wiphy split across multiple
|
||||
* messages, given with wiphy dump message
|
||||
*
|
||||
* @NL80211_ATTR_MDID: Mobility Domain Identifier
|
||||
*
|
||||
* @NL80211_ATTR_IE_RIC: Resource Information Container Information
|
||||
* Element
|
||||
*
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -1654,6 +1700,15 @@ enum nl80211_attrs {
|
||||
NL80211_ATTR_STA_CAPABILITY,
|
||||
NL80211_ATTR_STA_EXT_CAPABILITY,
|
||||
|
||||
NL80211_ATTR_PROTOCOL_FEATURES,
|
||||
NL80211_ATTR_SPLIT_WIPHY_DUMP,
|
||||
|
||||
NL80211_ATTR_DISABLE_VHT,
|
||||
NL80211_ATTR_VHT_CAPABILITY_MASK,
|
||||
|
||||
NL80211_ATTR_MDID,
|
||||
NL80211_ATTR_IE_RIC,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@ -2412,8 +2467,10 @@ enum nl80211_mesh_power_mode {
|
||||
* @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
|
||||
* point.
|
||||
*
|
||||
* @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
|
||||
* open peer links when we detect compatible mesh peers.
|
||||
* @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically open
|
||||
* peer links when we detect compatible mesh peers. Disabled if
|
||||
* @NL80211_MESH_SETUP_USERSPACE_MPM or @NL80211_MESH_SETUP_USERSPACE_AMPE are
|
||||
* set.
|
||||
*
|
||||
* @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
|
||||
* containing a PREQ that an MP can send to a particular destination (path
|
||||
@ -2559,6 +2616,9 @@ enum nl80211_meshconf_params {
|
||||
* vendor specific synchronization method or disable it to use the default
|
||||
* neighbor offset synchronization
|
||||
*
|
||||
* @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will
|
||||
* implement an MPM which handles peer allocation and state.
|
||||
*
|
||||
* @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
|
||||
*
|
||||
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
|
||||
@ -2571,6 +2631,7 @@ enum nl80211_mesh_setup_params {
|
||||
NL80211_MESH_SETUP_USERSPACE_AUTH,
|
||||
NL80211_MESH_SETUP_USERSPACE_AMPE,
|
||||
NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
|
||||
NL80211_MESH_SETUP_USERSPACE_MPM,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
|
||||
@ -3307,6 +3368,23 @@ enum nl80211_plink_state {
|
||||
MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_plink_action - actions to perform in mesh peers
|
||||
*
|
||||
* @NL80211_PLINK_ACTION_NO_ACTION: perform no action
|
||||
* @NL80211_PLINK_ACTION_OPEN: start mesh peer link establishment
|
||||
* @NL80211_PLINK_ACTION_BLOCK: block traffic from this mesh peer
|
||||
* @NUM_NL80211_PLINK_ACTIONS: number of possible actions
|
||||
*/
|
||||
enum plink_actions {
|
||||
NL80211_PLINK_ACTION_NO_ACTION,
|
||||
NL80211_PLINK_ACTION_OPEN,
|
||||
NL80211_PLINK_ACTION_BLOCK,
|
||||
|
||||
NUM_NL80211_PLINK_ACTIONS,
|
||||
};
|
||||
|
||||
|
||||
#define NL80211_KCK_LEN 16
|
||||
#define NL80211_KEK_LEN 16
|
||||
#define NL80211_REPLAY_CTR_LEN 8
|
||||
@ -3456,6 +3534,10 @@ enum nl80211_ap_sme_features {
|
||||
* stations the authenticated/associated bits have to be set in the mask.
|
||||
* @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits
|
||||
* (HT40, VHT 80/160 MHz) if this flag is set
|
||||
* @NL80211_FEATURE_USERSPACE_MPM: This driver supports a userspace Mesh
|
||||
* Peering Management entity which may be implemented by registering for
|
||||
* beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is
|
||||
* still generated by the driver.
|
||||
*/
|
||||
enum nl80211_feature_flags {
|
||||
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
|
||||
@ -3474,6 +3556,7 @@ enum nl80211_feature_flags {
|
||||
/* bit 13 is reserved */
|
||||
NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14,
|
||||
NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
|
||||
NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3587,4 +3670,16 @@ enum nl80211_dfs_state {
|
||||
NL80211_DFS_AVAILABLE,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum enum nl80211_protocol_features - nl80211 protocol features
|
||||
* @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting
|
||||
* wiphy dumps (if requested by the application with the attribute
|
||||
* %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the
|
||||
* wiphy dump by %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFINDEX or
|
||||
* %NL80211_ATTR_WDEV.
|
||||
*/
|
||||
enum nl80211_protocol_features {
|
||||
NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP = 1 << 0,
|
||||
};
|
||||
|
||||
#endif /* __LINUX_NL80211_H */
|
||||
|
@ -254,7 +254,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
__ieee80211_key_free(key);
|
||||
__ieee80211_key_free(key, true);
|
||||
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
@ -1035,9 +1035,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
||||
sta_info_flush_defer(vlan);
|
||||
sta_info_flush_defer(sdata);
|
||||
rcu_barrier();
|
||||
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
||||
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
|
||||
sta_info_flush_cleanup(vlan);
|
||||
ieee80211_free_keys(vlan);
|
||||
}
|
||||
sta_info_flush_cleanup(sdata);
|
||||
ieee80211_free_keys(sdata);
|
||||
|
||||
sdata->vif.bss_conf.enable_beacon = false;
|
||||
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
|
||||
@ -1177,6 +1180,18 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
||||
mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
|
||||
if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
|
||||
set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
|
||||
} else if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
|
||||
/*
|
||||
* TDLS -- everything follows authorized, but
|
||||
* only becoming authorized is possible, not
|
||||
* going back
|
||||
*/
|
||||
if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
|
||||
set |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
|
||||
BIT(NL80211_STA_FLAG_ASSOCIATED);
|
||||
mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
|
||||
BIT(NL80211_STA_FLAG_ASSOCIATED);
|
||||
}
|
||||
}
|
||||
|
||||
ret = sta_apply_auth_flags(local, sta, mask, set);
|
||||
@ -1261,7 +1276,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
u32 changed = 0;
|
||||
if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) {
|
||||
|
||||
if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) {
|
||||
switch (params->plink_state) {
|
||||
case NL80211_PLINK_ESTAB:
|
||||
if (sta->plink_state != NL80211_PLINK_ESTAB)
|
||||
@ -1292,15 +1308,18 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
||||
/* nothing */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (params->plink_action) {
|
||||
case PLINK_ACTION_OPEN:
|
||||
changed |= mesh_plink_open(sta);
|
||||
break;
|
||||
case PLINK_ACTION_BLOCK:
|
||||
changed |= mesh_plink_block(sta);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (params->plink_action) {
|
||||
case NL80211_PLINK_ACTION_NO_ACTION:
|
||||
/* nothing */
|
||||
break;
|
||||
case NL80211_PLINK_ACTION_OPEN:
|
||||
changed |= mesh_plink_open(sta);
|
||||
break;
|
||||
case NL80211_PLINK_ACTION_BLOCK:
|
||||
changed |= mesh_plink_block(sta);
|
||||
break;
|
||||
}
|
||||
|
||||
if (params->local_pm)
|
||||
@ -1346,8 +1365,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
* defaults -- if userspace wants something else we'll
|
||||
* change it accordingly in sta_apply_parameters()
|
||||
*/
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) {
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
}
|
||||
|
||||
err = sta_apply_parameters(local, sta, params);
|
||||
if (err) {
|
||||
@ -1356,8 +1377,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
}
|
||||
|
||||
/*
|
||||
* for TDLS, rate control should be initialized only when supported
|
||||
* rates are known.
|
||||
* for TDLS, rate control should be initialized only when
|
||||
* rates are known and station is marked authorized
|
||||
*/
|
||||
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
|
||||
rate_control_rate_init(sta);
|
||||
@ -1394,50 +1415,67 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
}
|
||||
|
||||
static int ieee80211_change_station(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u8 *mac,
|
||||
struct net_device *dev, u8 *mac,
|
||||
struct station_parameters *params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *vlansdata;
|
||||
enum cfg80211_station_type statype;
|
||||
int err;
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
sta = sta_info_get_bss(sdata, mac);
|
||||
if (!sta) {
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
return -ENOENT;
|
||||
err = -ENOENT;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* in station mode, some updates are only valid with TDLS */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
(params->supported_rates || params->ht_capa || params->vht_capa ||
|
||||
params->sta_modify_mask ||
|
||||
(params->sta_flags_mask & BIT(NL80211_STA_FLAG_WME))) &&
|
||||
!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
return -EINVAL;
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (sdata->u.mesh.user_mpm)
|
||||
statype = CFG80211_STA_MESH_PEER_USER;
|
||||
else
|
||||
statype = CFG80211_STA_MESH_PEER_KERNEL;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
statype = CFG80211_STA_IBSS;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
|
||||
statype = CFG80211_STA_AP_STA;
|
||||
break;
|
||||
}
|
||||
if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
|
||||
statype = CFG80211_STA_TDLS_PEER_ACTIVE;
|
||||
else
|
||||
statype = CFG80211_STA_TDLS_PEER_SETUP;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
statype = CFG80211_STA_AP_CLIENT;
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
err = cfg80211_check_station_change(wiphy, params, statype);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
if (params->vlan && params->vlan != sta->sdata->dev) {
|
||||
bool prev_4addr = false;
|
||||
bool new_4addr = false;
|
||||
|
||||
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
|
||||
|
||||
if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
vlansdata->vif.type != NL80211_IFTYPE_AP) {
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params->vlan->ieee80211_ptr->use_4addr) {
|
||||
if (vlansdata->u.vlan.sta) {
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
return -EBUSY;
|
||||
err = -EBUSY;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
|
||||
@ -1464,12 +1502,12 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
||||
}
|
||||
|
||||
err = sta_apply_parameters(local, sta, params);
|
||||
if (err) {
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates)
|
||||
/* When peer becomes authorized, init rate control as well */
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
|
||||
test_sta_flag(sta, WLAN_STA_AUTHORIZED))
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
@ -1479,7 +1517,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
ieee80211_recalc_ps_vif(sdata);
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_err:
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
@ -1687,6 +1729,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
|
||||
ifmsh->mesh_sp_id = setup->sync_method;
|
||||
ifmsh->mesh_pp_id = setup->path_sel_proto;
|
||||
ifmsh->mesh_pm_id = setup->path_metric;
|
||||
ifmsh->user_mpm = setup->user_mpm;
|
||||
ifmsh->security = IEEE80211_MESH_SEC_NONE;
|
||||
if (setup->is_authenticated)
|
||||
ifmsh->security |= IEEE80211_MESH_SEC_AUTHED;
|
||||
@ -1730,8 +1773,11 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
|
||||
conf->dot11MeshTTL = nconf->dot11MeshTTL;
|
||||
if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask))
|
||||
conf->element_ttl = nconf->element_ttl;
|
||||
if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
|
||||
if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) {
|
||||
if (ifmsh->user_mpm)
|
||||
return -EBUSY;
|
||||
conf->auto_open_plinks = nconf->auto_open_plinks;
|
||||
}
|
||||
if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask))
|
||||
conf->dot11MeshNbrOffsetMaxNeighbor =
|
||||
nconf->dot11MeshNbrOffsetMaxNeighbor;
|
||||
@ -2371,7 +2417,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_channel *channel,
|
||||
unsigned int duration, u64 *cookie,
|
||||
struct sk_buff *txskb)
|
||||
struct sk_buff *txskb,
|
||||
enum ieee80211_roc_type type)
|
||||
{
|
||||
struct ieee80211_roc_work *roc, *tmp;
|
||||
bool queued = false;
|
||||
@ -2390,6 +2437,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
||||
roc->duration = duration;
|
||||
roc->req_duration = duration;
|
||||
roc->frame = txskb;
|
||||
roc->type = type;
|
||||
roc->mgmt_tx_cookie = (unsigned long)txskb;
|
||||
roc->sdata = sdata;
|
||||
INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
|
||||
@ -2420,7 +2468,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
||||
if (!duration)
|
||||
duration = 10;
|
||||
|
||||
ret = drv_remain_on_channel(local, sdata, channel, duration);
|
||||
ret = drv_remain_on_channel(local, sdata, channel, duration, type);
|
||||
if (ret) {
|
||||
kfree(roc);
|
||||
return ret;
|
||||
@ -2439,10 +2487,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
||||
*
|
||||
* If it hasn't started yet, just increase the duration
|
||||
* and add the new one to the list of dependents.
|
||||
* If the type of the new ROC has higher priority, modify the
|
||||
* type of the previous one to match that of the new one.
|
||||
*/
|
||||
if (!tmp->started) {
|
||||
list_add_tail(&roc->list, &tmp->dependents);
|
||||
tmp->duration = max(tmp->duration, roc->duration);
|
||||
tmp->type = max(tmp->type, roc->type);
|
||||
queued = true;
|
||||
break;
|
||||
}
|
||||
@ -2454,16 +2505,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
||||
/*
|
||||
* In the offloaded ROC case, if it hasn't begun, add
|
||||
* this new one to the dependent list to be handled
|
||||
* when the the master one begins. If it has begun,
|
||||
* when the master one begins. If it has begun,
|
||||
* check that there's still a minimum time left and
|
||||
* if so, start this one, transmitting the frame, but
|
||||
* add it to the list directly after this one with a
|
||||
* add it to the list directly after this one with
|
||||
* a reduced time so we'll ask the driver to execute
|
||||
* it right after finishing the previous one, in the
|
||||
* hope that it'll also be executed right afterwards,
|
||||
* effectively extending the old one.
|
||||
* If there's no minimum time left, just add it to the
|
||||
* normal list.
|
||||
* TODO: the ROC type is ignored here, assuming that it
|
||||
* is better to immediately use the current ROC.
|
||||
*/
|
||||
if (!tmp->hw_begun) {
|
||||
list_add_tail(&roc->list, &tmp->dependents);
|
||||
@ -2557,7 +2610,8 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ret = ieee80211_start_roc_work(local, sdata, chan,
|
||||
duration, cookie, NULL);
|
||||
duration, cookie, NULL,
|
||||
IEEE80211_ROC_TYPE_NORMAL);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return ret;
|
||||
@ -2790,7 +2844,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
|
||||
/* This will handle all kinds of coalescing and immediate TX */
|
||||
ret = ieee80211_start_roc_work(local, sdata, chan,
|
||||
wait, cookie, skb);
|
||||
wait, cookie, skb,
|
||||
IEEE80211_ROC_TYPE_MGMT_TX);
|
||||
if (ret)
|
||||
kfree_skb(skb);
|
||||
out_unlock:
|
||||
@ -3285,6 +3340,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
int ret = -ENODATA;
|
||||
|
||||
@ -3293,6 +3349,16 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
|
||||
if (chanctx_conf) {
|
||||
*chandef = chanctx_conf->def;
|
||||
ret = 0;
|
||||
} else if (local->open_count > 0 &&
|
||||
local->open_count == local->monitors &&
|
||||
sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
if (local->use_chanctx)
|
||||
*chandef = local->monitor_chandef;
|
||||
else
|
||||
cfg80211_chandef_create(chandef,
|
||||
local->_oper_channel,
|
||||
local->_oper_channel_type);
|
||||
ret = 0;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -325,6 +325,36 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
|
||||
}
|
||||
STA_OPS(ht_capa);
|
||||
|
||||
static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[128], *p = buf;
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct ieee80211_sta_vht_cap *vhtc = &sta->sta.vht_cap;
|
||||
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "VHT %ssupported\n",
|
||||
vhtc->vht_supported ? "" : "not ");
|
||||
if (vhtc->vht_supported) {
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.8x\n", vhtc->cap);
|
||||
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "RX MCS: %.4x\n",
|
||||
le16_to_cpu(vhtc->vht_mcs.rx_mcs_map));
|
||||
if (vhtc->vht_mcs.rx_highest)
|
||||
p += scnprintf(p, sizeof(buf)+buf-p,
|
||||
"MCS RX highest: %d Mbps\n",
|
||||
le16_to_cpu(vhtc->vht_mcs.rx_highest));
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "TX MCS: %.4x\n",
|
||||
le16_to_cpu(vhtc->vht_mcs.tx_mcs_map));
|
||||
if (vhtc->vht_mcs.tx_highest)
|
||||
p += scnprintf(p, sizeof(buf)+buf-p,
|
||||
"MCS TX highest: %d Mbps\n",
|
||||
le16_to_cpu(vhtc->vht_mcs.tx_highest));
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
}
|
||||
STA_OPS(vht_capa);
|
||||
|
||||
static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@ -405,6 +435,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
|
||||
DEBUGFS_ADD(dev);
|
||||
DEBUGFS_ADD(last_signal);
|
||||
DEBUGFS_ADD(ht_capa);
|
||||
DEBUGFS_ADD(vht_capa);
|
||||
DEBUGFS_ADD(last_ack_signal);
|
||||
DEBUGFS_ADD(current_tx_rate);
|
||||
DEBUGFS_ADD(last_rx_rate);
|
||||
|
@ -787,15 +787,16 @@ static inline int drv_get_antenna(struct ieee80211_local *local,
|
||||
static inline int drv_remain_on_channel(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_channel *chan,
|
||||
unsigned int duration)
|
||||
unsigned int duration,
|
||||
enum ieee80211_roc_type type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
|
||||
trace_drv_remain_on_channel(local, sdata, chan, duration);
|
||||
trace_drv_remain_on_channel(local, sdata, chan, duration, type);
|
||||
ret = local->ops->remain_on_channel(&local->hw, &sdata->vif,
|
||||
chan, duration);
|
||||
chan, duration, type);
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
return ret;
|
||||
|
@ -40,13 +40,6 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
|
||||
if (!ht_cap->ht_supported)
|
||||
return;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION) {
|
||||
/* AP interfaces call this code when adding new stations,
|
||||
* so just silently ignore non station interfaces.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOTE: If you add more over-rides here, update register_hw
|
||||
* ht_capa_mod_msk logic in main.c as well.
|
||||
* And, if this method can ever change ht_cap.ht_supported, fix
|
||||
@ -97,7 +90,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
const struct ieee80211_ht_cap *ht_cap_ie,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_sta_ht_cap ht_cap;
|
||||
struct ieee80211_sta_ht_cap ht_cap, own_cap;
|
||||
u8 ampdu_info, tx_mcs_set_cap;
|
||||
int i, max_tx_streams;
|
||||
bool changed;
|
||||
@ -111,6 +104,18 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ht_cap.ht_supported = true;
|
||||
|
||||
own_cap = sband->ht_cap;
|
||||
|
||||
/*
|
||||
* If user has specified capability over-rides, take care
|
||||
* of that if the station we're setting up is the AP that
|
||||
* we advertised a restricted capability set to. Override
|
||||
* our own capabilities and then use those below.
|
||||
*/
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
|
||||
ieee80211_apply_htcap_overrides(sdata, &own_cap);
|
||||
|
||||
/*
|
||||
* The bits listed in this expression should be
|
||||
* the same for the peer and us, if the station
|
||||
@ -118,21 +123,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
* we mask them out.
|
||||
*/
|
||||
ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) &
|
||||
(sband->ht_cap.cap |
|
||||
~(IEEE80211_HT_CAP_LDPC_CODING |
|
||||
IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
||||
IEEE80211_HT_CAP_GRN_FLD |
|
||||
IEEE80211_HT_CAP_SGI_20 |
|
||||
IEEE80211_HT_CAP_SGI_40 |
|
||||
IEEE80211_HT_CAP_DSSSCCK40));
|
||||
(own_cap.cap | ~(IEEE80211_HT_CAP_LDPC_CODING |
|
||||
IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
||||
IEEE80211_HT_CAP_GRN_FLD |
|
||||
IEEE80211_HT_CAP_SGI_20 |
|
||||
IEEE80211_HT_CAP_SGI_40 |
|
||||
IEEE80211_HT_CAP_DSSSCCK40));
|
||||
|
||||
/*
|
||||
* The STBC bits are asymmetric -- if we don't have
|
||||
* TX then mask out the peer's RX and vice versa.
|
||||
*/
|
||||
if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
|
||||
if (!(own_cap.cap & IEEE80211_HT_CAP_TX_STBC))
|
||||
ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC;
|
||||
if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC))
|
||||
if (!(own_cap.cap & IEEE80211_HT_CAP_RX_STBC))
|
||||
ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC;
|
||||
|
||||
ampdu_info = ht_cap_ie->ampdu_params_info;
|
||||
@ -142,7 +146,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
(ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
|
||||
|
||||
/* own MCS TX capabilities */
|
||||
tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
|
||||
tx_mcs_set_cap = own_cap.mcs.tx_params;
|
||||
|
||||
/* Copy peer MCS TX capabilities, the driver might need them. */
|
||||
ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params;
|
||||
@ -168,26 +172,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
for (i = 0; i < max_tx_streams; i++)
|
||||
ht_cap.mcs.rx_mask[i] =
|
||||
sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
|
||||
own_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
|
||||
|
||||
if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
|
||||
for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
|
||||
i < IEEE80211_HT_MCS_MASK_LEN; i++)
|
||||
ht_cap.mcs.rx_mask[i] =
|
||||
sband->ht_cap.mcs.rx_mask[i] &
|
||||
own_cap.mcs.rx_mask[i] &
|
||||
ht_cap_ie->mcs.rx_mask[i];
|
||||
|
||||
/* handle MCS rate 32 too */
|
||||
if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
|
||||
if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
|
||||
ht_cap.mcs.rx_mask[32/8] |= 1;
|
||||
|
||||
apply:
|
||||
/*
|
||||
* If user has specified capability over-rides, take care
|
||||
* of that here.
|
||||
*/
|
||||
ieee80211_apply_htcap_overrides(sdata, &ht_cap);
|
||||
|
||||
changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
|
||||
|
||||
memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
|
||||
|
@ -985,37 +985,10 @@ static void ieee80211_ibss_timer(unsigned long data)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
(struct ieee80211_sub_if_data *) data;
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (local->quiescing) {
|
||||
ifibss->timer_running = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
|
||||
if (del_timer_sync(&ifibss->timer))
|
||||
ifibss->timer_running = true;
|
||||
}
|
||||
|
||||
void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
|
||||
if (ifibss->timer_running) {
|
||||
add_timer(&ifibss->timer);
|
||||
ifibss->timer_running = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
|
@ -315,6 +315,7 @@ struct ieee80211_roc_work {
|
||||
u32 duration, req_duration;
|
||||
struct sk_buff *frame;
|
||||
u64 cookie, mgmt_tx_cookie;
|
||||
enum ieee80211_roc_type type;
|
||||
};
|
||||
|
||||
/* flags used in struct ieee80211_if_managed.flags */
|
||||
@ -400,7 +401,6 @@ struct ieee80211_if_managed {
|
||||
|
||||
u16 aid;
|
||||
|
||||
unsigned long timers_running; /* used for quiesce/restart */
|
||||
bool powersave; /* powersave requested for this iface */
|
||||
bool broken_ap; /* AP is broken -- turn off powersave */
|
||||
u8 dtim_period;
|
||||
@ -479,6 +479,8 @@ struct ieee80211_if_managed {
|
||||
|
||||
struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */
|
||||
struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
|
||||
struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */
|
||||
struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */
|
||||
};
|
||||
|
||||
struct ieee80211_if_ibss {
|
||||
@ -490,8 +492,6 @@ struct ieee80211_if_ibss {
|
||||
|
||||
u32 basic_rates;
|
||||
|
||||
bool timer_running;
|
||||
|
||||
bool fixed_bssid;
|
||||
bool fixed_channel;
|
||||
bool privacy;
|
||||
@ -543,8 +543,6 @@ struct ieee80211_if_mesh {
|
||||
struct timer_list mesh_path_timer;
|
||||
struct timer_list mesh_path_root_timer;
|
||||
|
||||
unsigned long timers_running;
|
||||
|
||||
unsigned long wrkq_flags;
|
||||
|
||||
u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
|
||||
@ -590,6 +588,7 @@ struct ieee80211_if_mesh {
|
||||
IEEE80211_MESH_SEC_AUTHED = 0x1,
|
||||
IEEE80211_MESH_SEC_SECURED = 0x2,
|
||||
} security;
|
||||
bool user_mpm;
|
||||
/* Extensible Synchronization Framework */
|
||||
const struct ieee80211_mesh_sync_ops *sync_ops;
|
||||
s64 sync_offset_clockdrift_max;
|
||||
@ -682,6 +681,8 @@ struct ieee80211_sub_if_data {
|
||||
|
||||
/* count for keys needing tailroom space allocation */
|
||||
int crypto_tx_tailroom_needed_cnt;
|
||||
int crypto_tx_tailroom_pending_dec;
|
||||
struct delayed_work dec_tailroom_needed_wk;
|
||||
|
||||
struct net_device *dev;
|
||||
struct ieee80211_local *local;
|
||||
@ -765,10 +766,6 @@ struct ieee80211_sub_if_data {
|
||||
} debugfs;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct ieee80211_bss_conf suspend_bss_conf;
|
||||
#endif
|
||||
|
||||
/* must be last, dynamically sized area in this! */
|
||||
struct ieee80211_vif vif;
|
||||
};
|
||||
@ -1136,11 +1133,6 @@ struct ieee80211_local {
|
||||
|
||||
struct ieee80211_sub_if_data __rcu *p2p_sdata;
|
||||
|
||||
/* dummy netdev for use w/ NAPI */
|
||||
struct net_device napi_dev;
|
||||
|
||||
struct napi_struct napi;
|
||||
|
||||
/* virtual monitor interface */
|
||||
struct ieee80211_sub_if_data __rcu *monitor_sdata;
|
||||
struct cfg80211_chan_def monitor_chandef;
|
||||
@ -1283,8 +1275,6 @@ void
|
||||
ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
||||
const struct ieee80211_channel_sw_ie *sw_elem,
|
||||
struct ieee80211_bss *bss, u64 timestamp);
|
||||
void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
@ -1302,8 +1292,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
|
||||
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_ibss_params *params);
|
||||
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
@ -1441,6 +1429,8 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta);
|
||||
void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, u8 opmode,
|
||||
enum ieee80211_band band, bool nss_only);
|
||||
void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta_vht_cap *vht_cap);
|
||||
|
||||
/* Spectrum management */
|
||||
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -107,7 +107,7 @@ void ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
active = !list_empty(&local->chanctx_list);
|
||||
active = !list_empty(&local->chanctx_list) || local->monitors;
|
||||
|
||||
if (!local->ops->remain_on_channel) {
|
||||
list_for_each_entry(roc, &local->roc_list, list) {
|
||||
@ -485,8 +485,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||
res = drv_start(local);
|
||||
if (res)
|
||||
goto err_del_bss;
|
||||
if (local->ops->napi_poll)
|
||||
napi_enable(&local->napi);
|
||||
/* we're brought up, everything changes */
|
||||
hw_reconf_flags = ~0;
|
||||
ieee80211_led_radio(local, true);
|
||||
@ -541,6 +539,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, 1);
|
||||
ieee80211_configure_filter(local);
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
netif_carrier_on(dev);
|
||||
break;
|
||||
@ -812,6 +813,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
ieee80211_configure_filter(local);
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
/* relies on synchronize_rcu() below */
|
||||
@ -832,14 +836,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
rcu_barrier();
|
||||
sta_info_flush_cleanup(sdata);
|
||||
|
||||
skb_queue_purge(&sdata->skb_queue);
|
||||
|
||||
/*
|
||||
* Free all remaining keys, there shouldn't be any,
|
||||
* except maybe group keys in AP more or WDS?
|
||||
* except maybe in WDS mode?
|
||||
*/
|
||||
ieee80211_free_keys(sdata);
|
||||
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_AP:
|
||||
skb_queue_purge(&sdata->skb_queue);
|
||||
|
||||
drv_remove_interface_debugfs(local, sdata);
|
||||
|
||||
if (going_down)
|
||||
@ -851,8 +857,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
|
||||
if (local->open_count == 0) {
|
||||
if (local->ops->napi_poll)
|
||||
napi_disable(&local->napi);
|
||||
ieee80211_clear_tx_pending(local);
|
||||
ieee80211_stop_device(local);
|
||||
|
||||
@ -1541,6 +1545,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk);
|
||||
INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work,
|
||||
ieee80211_dfs_cac_timer_work);
|
||||
INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk,
|
||||
ieee80211_delayed_tailroom_dec);
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
@ -397,7 +397,8 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
|
||||
return key;
|
||||
}
|
||||
|
||||
static void __ieee80211_key_destroy(struct ieee80211_key *key)
|
||||
static void __ieee80211_key_destroy(struct ieee80211_key *key,
|
||||
bool delay_tailroom)
|
||||
{
|
||||
if (!key)
|
||||
return;
|
||||
@ -416,8 +417,18 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
|
||||
if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
|
||||
ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
|
||||
if (key->local) {
|
||||
struct ieee80211_sub_if_data *sdata = key->sdata;
|
||||
|
||||
ieee80211_debugfs_key_remove(key);
|
||||
key->sdata->crypto_tx_tailroom_needed_cnt--;
|
||||
|
||||
if (delay_tailroom) {
|
||||
/* see ieee80211_delayed_tailroom_dec */
|
||||
sdata->crypto_tx_tailroom_pending_dec++;
|
||||
schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
|
||||
HZ/2);
|
||||
} else {
|
||||
sdata->crypto_tx_tailroom_needed_cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(key);
|
||||
@ -440,32 +451,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
||||
key->sdata = sdata;
|
||||
key->sta = sta;
|
||||
|
||||
if (sta) {
|
||||
/*
|
||||
* some hardware cannot handle TKIP with QoS, so
|
||||
* we indicate whether QoS could be in use.
|
||||
*/
|
||||
if (test_sta_flag(sta, WLAN_STA_WME))
|
||||
key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
|
||||
} else {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
struct sta_info *ap;
|
||||
|
||||
/*
|
||||
* We're getting a sta pointer in, so must be under
|
||||
* appropriate locking for sta_info_get().
|
||||
*/
|
||||
|
||||
/* same here, the AP could be using QoS */
|
||||
ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
|
||||
if (ap) {
|
||||
if (test_sta_flag(ap, WLAN_STA_WME))
|
||||
key->conf.flags |=
|
||||
IEEE80211_KEY_FLAG_WMM_STA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&sdata->local->key_mtx);
|
||||
|
||||
if (sta && pairwise)
|
||||
@ -478,7 +463,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
||||
increment_tailroom_need_count(sdata);
|
||||
|
||||
__ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
|
||||
__ieee80211_key_destroy(old_key);
|
||||
__ieee80211_key_destroy(old_key, true);
|
||||
|
||||
ieee80211_debugfs_key_add(key);
|
||||
|
||||
@ -489,7 +474,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __ieee80211_key_free(struct ieee80211_key *key)
|
||||
void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
|
||||
{
|
||||
if (!key)
|
||||
return;
|
||||
@ -501,14 +486,14 @@ void __ieee80211_key_free(struct ieee80211_key *key)
|
||||
__ieee80211_key_replace(key->sdata, key->sta,
|
||||
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
|
||||
key, NULL);
|
||||
__ieee80211_key_destroy(key);
|
||||
__ieee80211_key_destroy(key, delay_tailroom);
|
||||
}
|
||||
|
||||
void ieee80211_key_free(struct ieee80211_local *local,
|
||||
struct ieee80211_key *key)
|
||||
{
|
||||
mutex_lock(&local->key_mtx);
|
||||
__ieee80211_key_free(key);
|
||||
__ieee80211_key_free(key, true);
|
||||
mutex_unlock(&local->key_mtx);
|
||||
}
|
||||
|
||||
@ -566,36 +551,60 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_iter_keys);
|
||||
|
||||
void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_key *key;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
mutex_lock(&sdata->local->key_mtx);
|
||||
|
||||
list_for_each_entry(key, &sdata->key_list, list)
|
||||
ieee80211_key_disable_hw_accel(key);
|
||||
|
||||
mutex_unlock(&sdata->local->key_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_key *key, *tmp;
|
||||
|
||||
cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
|
||||
|
||||
mutex_lock(&sdata->local->key_mtx);
|
||||
|
||||
sdata->crypto_tx_tailroom_needed_cnt -=
|
||||
sdata->crypto_tx_tailroom_pending_dec;
|
||||
sdata->crypto_tx_tailroom_pending_dec = 0;
|
||||
|
||||
ieee80211_debugfs_key_remove_mgmt_default(sdata);
|
||||
|
||||
list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
|
||||
__ieee80211_key_free(key);
|
||||
__ieee80211_key_free(key, false);
|
||||
|
||||
ieee80211_debugfs_key_update_default(sdata);
|
||||
|
||||
WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
|
||||
sdata->crypto_tx_tailroom_pending_dec);
|
||||
|
||||
mutex_unlock(&sdata->local->key_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
sdata = container_of(wk, struct ieee80211_sub_if_data,
|
||||
dec_tailroom_needed_wk.work);
|
||||
|
||||
/*
|
||||
* The reason for the delayed tailroom needed decrementing is to
|
||||
* make roaming faster: during roaming, all keys are first deleted
|
||||
* and then new keys are installed. The first new key causes the
|
||||
* crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes
|
||||
* the cost of synchronize_net() (which can be slow). Avoid this
|
||||
* by deferring the crypto_tx_tailroom_needed_cnt decrementing on
|
||||
* key removal for a while, so if we roam the value is larger than
|
||||
* zero and no 0->1 transition happens.
|
||||
*
|
||||
* The cost is that if the AP switching was from an AP with keys
|
||||
* to one without, we still allocate tailroom while it would no
|
||||
* longer be needed. However, in the typical (fast) roaming case
|
||||
* within an ESS this usually won't happen.
|
||||
*/
|
||||
|
||||
mutex_lock(&sdata->local->key_mtx);
|
||||
sdata->crypto_tx_tailroom_needed_cnt -=
|
||||
sdata->crypto_tx_tailroom_pending_dec;
|
||||
sdata->crypto_tx_tailroom_pending_dec = 0;
|
||||
mutex_unlock(&sdata->local->key_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
|
||||
const u8 *replay_ctr, gfp_t gfp)
|
||||
|
@ -134,7 +134,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
|
||||
int __must_check ieee80211_key_link(struct ieee80211_key *key,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta);
|
||||
void __ieee80211_key_free(struct ieee80211_key *key);
|
||||
void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
|
||||
void ieee80211_key_free(struct ieee80211_local *local,
|
||||
struct ieee80211_key *key);
|
||||
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
|
||||
@ -143,9 +143,10 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
|
||||
int idx);
|
||||
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
#define key_mtx_dereference(local, ref) \
|
||||
rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
|
||||
|
||||
void ieee80211_delayed_tailroom_dec(struct work_struct *wk);
|
||||
|
||||
#endif /* IEEE80211_KEY_H */
|
||||
|
@ -399,30 +399,6 @@ static int ieee80211_ifa6_changed(struct notifier_block *nb,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
container_of(napi, struct ieee80211_local, napi);
|
||||
|
||||
return local->ops->napi_poll(&local->hw, budget);
|
||||
}
|
||||
|
||||
void ieee80211_napi_schedule(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
napi_schedule(&local->napi);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_napi_schedule);
|
||||
|
||||
void ieee80211_napi_complete(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
napi_complete(&local->napi);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_napi_complete);
|
||||
|
||||
/* There isn't a lot of sense in it, but you can transmit anything you like */
|
||||
static const struct ieee80211_txrx_stypes
|
||||
ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
@ -501,6 +477,27 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = {
|
||||
.vht_cap_info =
|
||||
cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC |
|
||||
IEEE80211_VHT_CAP_SHORT_GI_80 |
|
||||
IEEE80211_VHT_CAP_SHORT_GI_160 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_1 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_2 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_3 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_4 |
|
||||
IEEE80211_VHT_CAP_TXSTBC |
|
||||
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
|
||||
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
|
||||
IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
|
||||
IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK),
|
||||
.supp_mcs = {
|
||||
.rx_mcs_map = cpu_to_le16(~0),
|
||||
.tx_mcs_map = cpu_to_le16(~0),
|
||||
},
|
||||
};
|
||||
|
||||
static const u8 extended_capabilities[] = {
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
WLAN_EXT_CAPA8_OPMODE_NOTIF,
|
||||
@ -572,7 +569,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
|
||||
NL80211_FEATURE_SAE |
|
||||
NL80211_FEATURE_HT_IBSS |
|
||||
NL80211_FEATURE_VIF_TXPOWER;
|
||||
NL80211_FEATURE_VIF_TXPOWER |
|
||||
NL80211_FEATURE_USERSPACE_MPM;
|
||||
|
||||
if (!ops->hw_scan)
|
||||
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
|
||||
@ -609,6 +607,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
|
||||
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
|
||||
wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
|
||||
wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask;
|
||||
|
||||
INIT_LIST_HEAD(&local->interfaces);
|
||||
|
||||
@ -664,9 +663,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
skb_queue_head_init(&local->skb_queue);
|
||||
skb_queue_head_init(&local->skb_queue_unreliable);
|
||||
|
||||
/* init dummy netdev for use w/ NAPI */
|
||||
init_dummy_netdev(&local->napi_dev);
|
||||
|
||||
ieee80211_led_names(local);
|
||||
|
||||
ieee80211_roc_setup(local);
|
||||
@ -1021,9 +1017,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
goto fail_ifa6;
|
||||
#endif
|
||||
|
||||
netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
|
||||
local->hw.napi_weight);
|
||||
|
||||
return 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
|
@ -13,10 +13,6 @@
|
||||
#include "ieee80211_i.h"
|
||||
#include "mesh.h"
|
||||
|
||||
#define TMR_RUNNING_HK 0
|
||||
#define TMR_RUNNING_MP 1
|
||||
#define TMR_RUNNING_MPR 2
|
||||
|
||||
static int mesh_allocated;
|
||||
static struct kmem_cache *rm_cache;
|
||||
|
||||
@ -50,11 +46,6 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
|
||||
|
||||
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
|
||||
|
||||
if (local->quiescing) {
|
||||
set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
}
|
||||
|
||||
@ -165,7 +156,7 @@ void mesh_sta_cleanup(struct sta_info *sta)
|
||||
* an update.
|
||||
*/
|
||||
changed = mesh_accept_plinks_update(sdata);
|
||||
if (sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
|
||||
if (!sdata->u.mesh.user_mpm) {
|
||||
changed |= mesh_plink_deactivate(sta);
|
||||
del_timer_sync(&sta->plink_timer);
|
||||
}
|
||||
@ -479,15 +470,8 @@ static void ieee80211_mesh_path_timer(unsigned long data)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
(struct ieee80211_sub_if_data *) data;
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (local->quiescing) {
|
||||
set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||
}
|
||||
|
||||
static void ieee80211_mesh_path_root_timer(unsigned long data)
|
||||
@ -495,16 +479,10 @@ static void ieee80211_mesh_path_root_timer(unsigned long data)
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
(struct ieee80211_sub_if_data *) data;
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
|
||||
|
||||
if (local->quiescing) {
|
||||
set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||
}
|
||||
|
||||
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
|
||||
@ -622,35 +600,6 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
|
||||
round_jiffies(TU_TO_EXP_TIME(interval)));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
|
||||
/* use atomic bitops in case all timers fire at the same time */
|
||||
|
||||
if (del_timer_sync(&ifmsh->housekeeping_timer))
|
||||
set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
|
||||
if (del_timer_sync(&ifmsh->mesh_path_timer))
|
||||
set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
|
||||
if (del_timer_sync(&ifmsh->mesh_path_root_timer))
|
||||
set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
|
||||
}
|
||||
|
||||
void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
|
||||
if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running))
|
||||
add_timer(&ifmsh->housekeeping_timer);
|
||||
if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running))
|
||||
add_timer(&ifmsh->mesh_path_timer);
|
||||
if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running))
|
||||
add_timer(&ifmsh->mesh_path_root_timer);
|
||||
ieee80211_mesh_root_setup(ifmsh);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
|
||||
{
|
||||
@ -871,8 +820,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
local->fif_other_bss--;
|
||||
atomic_dec(&local->iff_allmultis);
|
||||
ieee80211_configure_filter(local);
|
||||
|
||||
sdata->u.mesh.timers_running = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -313,8 +313,6 @@ void mesh_path_timer(unsigned long data);
|
||||
void mesh_path_flush_by_nexthop(struct sta_info *sta);
|
||||
void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
|
||||
@ -359,22 +357,12 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
|
||||
|
||||
void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_plink_quiesce(struct sta_info *sta);
|
||||
void mesh_plink_restart(struct sta_info *sta);
|
||||
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211s_stop(void);
|
||||
#else
|
||||
static inline void
|
||||
ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
|
||||
static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
|
||||
{}
|
||||
static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
|
||||
{}
|
||||
static inline void mesh_plink_quiesce(struct sta_info *sta) {}
|
||||
static inline void mesh_plink_restart(struct sta_info *sta) {}
|
||||
static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
|
||||
{ return false; }
|
||||
static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
|
||||
|
@ -420,7 +420,6 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
|
||||
return NULL;
|
||||
|
||||
sta->plink_state = NL80211_PLINK_LISTEN;
|
||||
init_timer(&sta->plink_timer);
|
||||
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
@ -437,8 +436,9 @@ mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr,
|
||||
{
|
||||
struct sta_info *sta = NULL;
|
||||
|
||||
/* Userspace handles peer allocation when security is enabled */
|
||||
if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
|
||||
/* Userspace handles station allocation */
|
||||
if (sdata->u.mesh.user_mpm ||
|
||||
sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
|
||||
cfg80211_notify_new_peer_candidate(sdata->dev, addr,
|
||||
elems->ie_start,
|
||||
elems->total_len,
|
||||
@ -534,10 +534,8 @@ static void mesh_plink_timer(unsigned long data)
|
||||
*/
|
||||
sta = (struct sta_info *) data;
|
||||
|
||||
if (sta->sdata->local->quiescing) {
|
||||
sta->plink_timer_was_running = true;
|
||||
if (sta->sdata->local->quiescing)
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
if (sta->ignore_plink_timer) {
|
||||
@ -598,29 +596,6 @@ static void mesh_plink_timer(unsigned long data)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void mesh_plink_quiesce(struct sta_info *sta)
|
||||
{
|
||||
if (!ieee80211_vif_is_mesh(&sta->sdata->vif))
|
||||
return;
|
||||
|
||||
/* no kernel mesh sta timers have been initialized */
|
||||
if (sta->sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
|
||||
return;
|
||||
|
||||
if (del_timer_sync(&sta->plink_timer))
|
||||
sta->plink_timer_was_running = true;
|
||||
}
|
||||
|
||||
void mesh_plink_restart(struct sta_info *sta)
|
||||
{
|
||||
if (sta->plink_timer_was_running) {
|
||||
add_timer(&sta->plink_timer);
|
||||
sta->plink_timer_was_running = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
|
||||
{
|
||||
sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
|
||||
@ -695,6 +670,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||
if (len < IEEE80211_MIN_ACTION_SIZE + 3)
|
||||
return;
|
||||
|
||||
if (sdata->u.mesh.user_mpm)
|
||||
/* userspace must register for these */
|
||||
return;
|
||||
|
||||
if (is_multicast_ether_addr(mgmt->da)) {
|
||||
mpl_dbg(sdata,
|
||||
"Mesh plink: ignore frame from multicast address\n");
|
||||
|
@ -87,9 +87,6 @@ MODULE_PARM_DESC(probe_wait_ms,
|
||||
*/
|
||||
#define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
|
||||
|
||||
#define TMR_RUNNING_TIMER 0
|
||||
#define TMR_RUNNING_CHANSW 1
|
||||
|
||||
/*
|
||||
* All cfg80211 functions have to be called outside a locked
|
||||
* section so that they can acquire a lock themselves... This
|
||||
@ -609,6 +606,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
|
||||
BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap));
|
||||
|
||||
memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
|
||||
ieee80211_apply_vhtcap_overrides(sdata, &vht_cap);
|
||||
|
||||
/* determine capability flags */
|
||||
cap = vht_cap.cap;
|
||||
@ -647,6 +645,9 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
|
||||
our_mcs = (le16_to_cpu(vht_cap.vht_mcs.rx_mcs_map) &
|
||||
mask) >> shift;
|
||||
|
||||
if (our_mcs == IEEE80211_VHT_MCS_NOT_SUPPORTED)
|
||||
continue;
|
||||
|
||||
switch (ap_mcs) {
|
||||
default:
|
||||
if (our_mcs <= ap_mcs)
|
||||
@ -1035,14 +1036,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
(struct ieee80211_sub_if_data *) data;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
if (sdata->local->quiescing) {
|
||||
set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1799,9 +1794,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
sdata->vif.bss_conf.p2p_ctwindow = 0;
|
||||
sdata->vif.bss_conf.p2p_oppps = false;
|
||||
|
||||
/* on the next assoc, re-program HT parameters */
|
||||
/* on the next assoc, re-program HT/VHT parameters */
|
||||
memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
|
||||
memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
|
||||
memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa));
|
||||
memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask));
|
||||
|
||||
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
|
||||
|
||||
@ -1827,8 +1824,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
del_timer_sync(&sdata->u.mgd.timer);
|
||||
del_timer_sync(&sdata->u.mgd.chswitch_timer);
|
||||
|
||||
sdata->u.mgd.timers_running = 0;
|
||||
|
||||
sdata->vif.bss_conf.dtim_period = 0;
|
||||
|
||||
ifmgd->flags = 0;
|
||||
@ -3137,15 +3132,8 @@ static void ieee80211_sta_timer(unsigned long data)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
(struct ieee80211_sub_if_data *) data;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (local->quiescing) {
|
||||
set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||
}
|
||||
|
||||
static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
|
||||
@ -3497,68 +3485,6 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
/*
|
||||
* we need to use atomic bitops for the running bits
|
||||
* only because both timers might fire at the same
|
||||
* time -- the code here is properly synchronised.
|
||||
*/
|
||||
|
||||
cancel_work_sync(&ifmgd->request_smps_work);
|
||||
|
||||
cancel_work_sync(&ifmgd->monitor_work);
|
||||
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
|
||||
cancel_work_sync(&ifmgd->csa_connection_drop_work);
|
||||
if (del_timer_sync(&ifmgd->timer))
|
||||
set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
|
||||
|
||||
cancel_work_sync(&ifmgd->chswitch_work);
|
||||
if (del_timer_sync(&ifmgd->chswitch_timer))
|
||||
set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
|
||||
|
||||
/* these will just be re-established on connection */
|
||||
del_timer_sync(&ifmgd->conn_mon_timer);
|
||||
del_timer_sync(&ifmgd->bcn_mon_timer);
|
||||
}
|
||||
|
||||
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
mutex_lock(&ifmgd->mtx);
|
||||
if (!ifmgd->associated) {
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
|
||||
sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
|
||||
mlme_dbg(sdata, "driver requested disconnect after resume\n");
|
||||
ieee80211_sta_connection_lost(sdata,
|
||||
ifmgd->associated->bssid,
|
||||
WLAN_REASON_UNSPECIFIED,
|
||||
true);
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
|
||||
add_timer(&ifmgd->timer);
|
||||
if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
|
||||
add_timer(&ifmgd->chswitch_timer);
|
||||
ieee80211_sta_reset_beacon_monitor(sdata);
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_restart_sta_timer(sdata);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* interface setup */
|
||||
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
@ -4064,6 +3990,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
|
||||
}
|
||||
|
||||
if (req->flags & ASSOC_REQ_DISABLE_VHT)
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
|
||||
|
||||
/* Also disable HT if we don't support it or the AP doesn't use WMM */
|
||||
sband = local->hw.wiphy->bands[req->bss->channel->band];
|
||||
if (!sband->ht_cap.ht_supported ||
|
||||
@ -4087,6 +4016,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
|
||||
sizeof(ifmgd->ht_capa_mask));
|
||||
|
||||
memcpy(&ifmgd->vht_capa, &req->vht_capa, sizeof(ifmgd->vht_capa));
|
||||
memcpy(&ifmgd->vht_capa_mask, &req->vht_capa_mask,
|
||||
sizeof(ifmgd->vht_capa_mask));
|
||||
|
||||
if (req->ie && req->ie_len) {
|
||||
memcpy(assoc_data->ie, req->ie, req->ie_len);
|
||||
assoc_data->ie_len = req->ie_len;
|
||||
@ -4315,6 +4248,17 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
/*
|
||||
* Make sure some work items will not run after this,
|
||||
* they will not do anything but might not have been
|
||||
* cancelled when disconnecting.
|
||||
*/
|
||||
cancel_work_sync(&ifmgd->monitor_work);
|
||||
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
|
||||
cancel_work_sync(&ifmgd->request_smps_work);
|
||||
cancel_work_sync(&ifmgd->csa_connection_drop_work);
|
||||
cancel_work_sync(&ifmgd->chswitch_work);
|
||||
|
||||
mutex_lock(&ifmgd->mtx);
|
||||
if (ifmgd->assoc_data)
|
||||
ieee80211_destroy_assoc_data(sdata, false);
|
||||
|
@ -277,7 +277,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
|
||||
duration = 10;
|
||||
|
||||
ret = drv_remain_on_channel(local, roc->sdata, roc->chan,
|
||||
duration);
|
||||
duration, roc->type);
|
||||
|
||||
roc->started = true;
|
||||
|
||||
|
@ -6,32 +6,11 @@
|
||||
#include "driver-ops.h"
|
||||
#include "led.h"
|
||||
|
||||
/* return value indicates whether the driver should be further notified */
|
||||
static void ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ieee80211_sta_quiesce(sdata);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ieee80211_ibss_quiesce(sdata);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
ieee80211_mesh_quiesce(sdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cancel_work_sync(&sdata->work);
|
||||
}
|
||||
|
||||
int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_chanctx *ctx;
|
||||
|
||||
if (!local->open_count)
|
||||
goto suspend;
|
||||
@ -93,19 +72,12 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
return err;
|
||||
} else if (err > 0) {
|
||||
WARN_ON(err != 1);
|
||||
local->wowlan = false;
|
||||
return err;
|
||||
} else {
|
||||
list_for_each_entry(sdata, &local->interfaces, list)
|
||||
if (ieee80211_sdata_running(sdata))
|
||||
ieee80211_quiesce(sdata);
|
||||
goto suspend;
|
||||
}
|
||||
}
|
||||
|
||||
/* disable keys */
|
||||
list_for_each_entry(sdata, &local->interfaces, list)
|
||||
ieee80211_disable_keys(sdata);
|
||||
|
||||
/* tear down aggregation sessions and remove STAs */
|
||||
mutex_lock(&local->sta_mtx);
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
@ -117,100 +89,25 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
WARN_ON(drv_sta_state(local, sta->sdata, sta,
|
||||
state, state - 1));
|
||||
}
|
||||
|
||||
mesh_plink_quiesce(sta);
|
||||
}
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
|
||||
/* remove all interfaces */
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
static u8 zero_addr[ETH_ALEN] = {};
|
||||
u32 changed = 0;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
/* skip these */
|
||||
continue;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (sdata->vif.bss_conf.assoc)
|
||||
changed = BSS_CHANGED_ASSOC |
|
||||
BSS_CHANGED_BSSID |
|
||||
BSS_CHANGED_IDLE;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (sdata->vif.bss_conf.enable_beacon)
|
||||
changed = BSS_CHANGED_BEACON_ENABLED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ieee80211_quiesce(sdata);
|
||||
|
||||
sdata->suspend_bss_conf = sdata->vif.bss_conf;
|
||||
memset(&sdata->vif.bss_conf, 0, sizeof(sdata->vif.bss_conf));
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
if (sdata->suspend_bss_conf.bssid)
|
||||
sdata->vif.bss_conf.bssid = zero_addr;
|
||||
|
||||
/* disable beaconing or remove association */
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP &&
|
||||
rcu_access_pointer(sdata->u.ap.beacon))
|
||||
drv_stop_ap(local, sdata);
|
||||
|
||||
if (local->use_chanctx) {
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
conf = rcu_dereference_protected(
|
||||
sdata->vif.chanctx_conf,
|
||||
lockdep_is_held(&local->chanctx_mtx));
|
||||
if (conf) {
|
||||
ctx = container_of(conf,
|
||||
struct ieee80211_chanctx,
|
||||
conf);
|
||||
drv_unassign_vif_chanctx(local, sdata, ctx);
|
||||
}
|
||||
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
}
|
||||
drv_remove_interface(local, sdata);
|
||||
}
|
||||
|
||||
sdata = rtnl_dereference(local->monitor_sdata);
|
||||
if (sdata) {
|
||||
if (local->use_chanctx) {
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
conf = rcu_dereference_protected(
|
||||
sdata->vif.chanctx_conf,
|
||||
lockdep_is_held(&local->chanctx_mtx));
|
||||
if (conf) {
|
||||
ctx = container_of(conf,
|
||||
struct ieee80211_chanctx,
|
||||
conf);
|
||||
drv_unassign_vif_chanctx(local, sdata, ctx);
|
||||
}
|
||||
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
}
|
||||
|
||||
if (sdata)
|
||||
drv_remove_interface(local, sdata);
|
||||
}
|
||||
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
list_for_each_entry(ctx, &local->chanctx_list, list)
|
||||
drv_remove_chanctx(local, ctx);
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
/*
|
||||
* We disconnected on all interfaces before suspend, all channel
|
||||
* contexts should be released.
|
||||
*/
|
||||
WARN_ON(!list_empty(&local->chanctx_list));
|
||||
|
||||
/* stop hardware - this must stop RX */
|
||||
if (local->open_count)
|
||||
|
@ -55,7 +55,6 @@
|
||||
#include "rate.h"
|
||||
#include "rc80211_minstrel.h"
|
||||
|
||||
#define SAMPLE_COLUMNS 10
|
||||
#define SAMPLE_TBL(_mi, _idx, _col) \
|
||||
_mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col]
|
||||
|
||||
@ -70,16 +69,31 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
|
||||
return i;
|
||||
}
|
||||
|
||||
/* find & sort topmost throughput rates */
|
||||
static inline void
|
||||
minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
|
||||
{
|
||||
int j = MAX_THR_RATES;
|
||||
|
||||
while (j > 0 && mi->r[i].cur_tp > mi->r[tp_list[j - 1]].cur_tp)
|
||||
j--;
|
||||
if (j < MAX_THR_RATES - 1)
|
||||
memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1));
|
||||
if (j < MAX_THR_RATES)
|
||||
tp_list[j] = i;
|
||||
}
|
||||
|
||||
static void
|
||||
minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
|
||||
{
|
||||
u32 max_tp = 0, index_max_tp = 0, index_max_tp2 = 0;
|
||||
u32 max_prob = 0, index_max_prob = 0;
|
||||
u8 tmp_tp_rate[MAX_THR_RATES];
|
||||
u8 tmp_prob_rate = 0;
|
||||
u32 usecs;
|
||||
u32 p;
|
||||
int i;
|
||||
|
||||
mi->stats_update = jiffies;
|
||||
for (i=0; i < MAX_THR_RATES; i++)
|
||||
tmp_tp_rate[i] = 0;
|
||||
|
||||
for (i = 0; i < mi->n_rates; i++) {
|
||||
struct minstrel_rate *mr = &mi->r[i];
|
||||
|
||||
@ -87,27 +101,32 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
|
||||
if (!usecs)
|
||||
usecs = 1000000;
|
||||
|
||||
/* To avoid rounding issues, probabilities scale from 0 (0%)
|
||||
* to 18000 (100%) */
|
||||
if (mr->attempts) {
|
||||
p = (mr->success * 18000) / mr->attempts;
|
||||
if (unlikely(mr->attempts > 0)) {
|
||||
mr->sample_skipped = 0;
|
||||
mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
|
||||
mr->succ_hist += mr->success;
|
||||
mr->att_hist += mr->attempts;
|
||||
mr->cur_prob = p;
|
||||
p = ((p * (100 - mp->ewma_level)) + (mr->probability *
|
||||
mp->ewma_level)) / 100;
|
||||
mr->probability = p;
|
||||
mr->cur_tp = p * (1000000 / usecs);
|
||||
}
|
||||
mr->probability = minstrel_ewma(mr->probability,
|
||||
mr->cur_prob,
|
||||
EWMA_LEVEL);
|
||||
} else
|
||||
mr->sample_skipped++;
|
||||
|
||||
mr->last_success = mr->success;
|
||||
mr->last_attempts = mr->attempts;
|
||||
mr->success = 0;
|
||||
mr->attempts = 0;
|
||||
|
||||
/* Update throughput per rate, reset thr. below 10% success */
|
||||
if (mr->probability < MINSTREL_FRAC(10, 100))
|
||||
mr->cur_tp = 0;
|
||||
else
|
||||
mr->cur_tp = mr->probability * (1000000 / usecs);
|
||||
|
||||
/* Sample less often below the 10% chance of success.
|
||||
* Sample less often above the 95% chance of success. */
|
||||
if ((mr->probability > 17100) || (mr->probability < 1800)) {
|
||||
if (mr->probability > MINSTREL_FRAC(95, 100) ||
|
||||
mr->probability < MINSTREL_FRAC(10, 100)) {
|
||||
mr->adjusted_retry_count = mr->retry_count >> 1;
|
||||
if (mr->adjusted_retry_count > 2)
|
||||
mr->adjusted_retry_count = 2;
|
||||
@ -118,35 +137,30 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
|
||||
}
|
||||
if (!mr->adjusted_retry_count)
|
||||
mr->adjusted_retry_count = 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < mi->n_rates; i++) {
|
||||
struct minstrel_rate *mr = &mi->r[i];
|
||||
if (max_tp < mr->cur_tp) {
|
||||
index_max_tp = i;
|
||||
max_tp = mr->cur_tp;
|
||||
}
|
||||
if (max_prob < mr->probability) {
|
||||
index_max_prob = i;
|
||||
max_prob = mr->probability;
|
||||
minstrel_sort_best_tp_rates(mi, i, tmp_tp_rate);
|
||||
|
||||
/* To determine the most robust rate (max_prob_rate) used at
|
||||
* 3rd mmr stage we distinct between two cases:
|
||||
* (1) if any success probabilitiy >= 95%, out of those rates
|
||||
* choose the maximum throughput rate as max_prob_rate
|
||||
* (2) if all success probabilities < 95%, the rate with
|
||||
* highest success probability is choosen as max_prob_rate */
|
||||
if (mr->probability >= MINSTREL_FRAC(95,100)) {
|
||||
if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp)
|
||||
tmp_prob_rate = i;
|
||||
} else {
|
||||
if (mr->probability >= mi->r[tmp_prob_rate].probability)
|
||||
tmp_prob_rate = i;
|
||||
}
|
||||
}
|
||||
|
||||
max_tp = 0;
|
||||
for (i = 0; i < mi->n_rates; i++) {
|
||||
struct minstrel_rate *mr = &mi->r[i];
|
||||
/* Assign the new rate set */
|
||||
memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate));
|
||||
mi->max_prob_rate = tmp_prob_rate;
|
||||
|
||||
if (i == index_max_tp)
|
||||
continue;
|
||||
|
||||
if (max_tp < mr->cur_tp) {
|
||||
index_max_tp2 = i;
|
||||
max_tp = mr->cur_tp;
|
||||
}
|
||||
}
|
||||
mi->max_tp_rate = index_max_tp;
|
||||
mi->max_tp_rate2 = index_max_tp2;
|
||||
mi->max_prob_rate = index_max_prob;
|
||||
/* Reset update timer */
|
||||
mi->stats_update = jiffies;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -207,10 +221,10 @@ static int
|
||||
minstrel_get_next_sample(struct minstrel_sta_info *mi)
|
||||
{
|
||||
unsigned int sample_ndx;
|
||||
sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column);
|
||||
mi->sample_idx++;
|
||||
if ((int) mi->sample_idx > (mi->n_rates - 2)) {
|
||||
mi->sample_idx = 0;
|
||||
sample_ndx = SAMPLE_TBL(mi, mi->sample_row, mi->sample_column);
|
||||
mi->sample_row++;
|
||||
if ((int) mi->sample_row >= mi->n_rates) {
|
||||
mi->sample_row = 0;
|
||||
mi->sample_column++;
|
||||
if (mi->sample_column >= SAMPLE_COLUMNS)
|
||||
mi->sample_column = 0;
|
||||
@ -228,31 +242,37 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
|
||||
struct minstrel_priv *mp = priv;
|
||||
struct ieee80211_tx_rate *ar = info->control.rates;
|
||||
unsigned int ndx, sample_ndx = 0;
|
||||
bool mrr;
|
||||
bool sample_slower = false;
|
||||
bool sample = false;
|
||||
bool mrr_capable;
|
||||
bool indirect_rate_sampling = false;
|
||||
bool rate_sampling = false;
|
||||
int i, delta;
|
||||
int mrr_ndx[3];
|
||||
int sample_rate;
|
||||
int sampling_ratio;
|
||||
|
||||
/* management/no-ack frames do not use rate control */
|
||||
if (rate_control_send_low(sta, priv_sta, txrc))
|
||||
return;
|
||||
|
||||
mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
|
||||
|
||||
ndx = mi->max_tp_rate;
|
||||
|
||||
if (mrr)
|
||||
sample_rate = mp->lookaround_rate_mrr;
|
||||
/* check multi-rate-retry capabilities & adjust lookaround_rate */
|
||||
mrr_capable = mp->has_mrr &&
|
||||
!txrc->rts &&
|
||||
!txrc->bss_conf->use_cts_prot;
|
||||
if (mrr_capable)
|
||||
sampling_ratio = mp->lookaround_rate_mrr;
|
||||
else
|
||||
sample_rate = mp->lookaround_rate;
|
||||
sampling_ratio = mp->lookaround_rate;
|
||||
|
||||
/* init rateindex [ndx] with max throughput rate */
|
||||
ndx = mi->max_tp_rate[0];
|
||||
|
||||
/* increase sum packet counter */
|
||||
mi->packet_count++;
|
||||
delta = (mi->packet_count * sample_rate / 100) -
|
||||
|
||||
delta = (mi->packet_count * sampling_ratio / 100) -
|
||||
(mi->sample_count + mi->sample_deferred / 2);
|
||||
|
||||
/* delta > 0: sampling required */
|
||||
if ((delta > 0) && (mrr || !mi->prev_sample)) {
|
||||
if ((delta > 0) && (mrr_capable || !mi->prev_sample)) {
|
||||
struct minstrel_rate *msr;
|
||||
if (mi->packet_count >= 10000) {
|
||||
mi->sample_deferred = 0;
|
||||
@ -271,21 +291,28 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
|
||||
mi->sample_count += (delta - mi->n_rates * 2);
|
||||
}
|
||||
|
||||
/* get next random rate sample */
|
||||
sample_ndx = minstrel_get_next_sample(mi);
|
||||
msr = &mi->r[sample_ndx];
|
||||
sample = true;
|
||||
sample_slower = mrr && (msr->perfect_tx_time >
|
||||
mi->r[ndx].perfect_tx_time);
|
||||
rate_sampling = true;
|
||||
|
||||
if (!sample_slower) {
|
||||
/* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage)
|
||||
* rate sampling method should be used.
|
||||
* Respect such rates that are not sampled for 20 interations.
|
||||
*/
|
||||
if (mrr_capable &&
|
||||
msr->perfect_tx_time > mi->r[ndx].perfect_tx_time &&
|
||||
msr->sample_skipped < 20)
|
||||
indirect_rate_sampling = true;
|
||||
|
||||
if (!indirect_rate_sampling) {
|
||||
if (msr->sample_limit != 0) {
|
||||
ndx = sample_ndx;
|
||||
mi->sample_count++;
|
||||
if (msr->sample_limit > 0)
|
||||
msr->sample_limit--;
|
||||
} else {
|
||||
sample = false;
|
||||
}
|
||||
} else
|
||||
rate_sampling = false;
|
||||
} else {
|
||||
/* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
|
||||
* packets that have the sampling rate deferred to the
|
||||
@ -297,34 +324,39 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
|
||||
mi->sample_deferred++;
|
||||
}
|
||||
}
|
||||
mi->prev_sample = sample;
|
||||
mi->prev_sample = rate_sampling;
|
||||
|
||||
/* If we're not using MRR and the sampling rate already
|
||||
* has a probability of >95%, we shouldn't be attempting
|
||||
* to use it, as this only wastes precious airtime */
|
||||
if (!mrr && sample && (mi->r[ndx].probability > 17100))
|
||||
ndx = mi->max_tp_rate;
|
||||
if (!mrr_capable && rate_sampling &&
|
||||
(mi->r[ndx].probability > MINSTREL_FRAC(95, 100)))
|
||||
ndx = mi->max_tp_rate[0];
|
||||
|
||||
/* mrr setup for 1st stage */
|
||||
ar[0].idx = mi->r[ndx].rix;
|
||||
ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info);
|
||||
|
||||
if (!mrr) {
|
||||
if (!sample)
|
||||
/* non mrr setup for 2nd stage */
|
||||
if (!mrr_capable) {
|
||||
if (!rate_sampling)
|
||||
ar[0].count = mp->max_retry;
|
||||
ar[1].idx = mi->lowest_rix;
|
||||
ar[1].count = mp->max_retry;
|
||||
return;
|
||||
}
|
||||
|
||||
/* MRR setup */
|
||||
if (sample) {
|
||||
if (sample_slower)
|
||||
/* mrr setup for 2nd stage */
|
||||
if (rate_sampling) {
|
||||
if (indirect_rate_sampling)
|
||||
mrr_ndx[0] = sample_ndx;
|
||||
else
|
||||
mrr_ndx[0] = mi->max_tp_rate;
|
||||
mrr_ndx[0] = mi->max_tp_rate[0];
|
||||
} else {
|
||||
mrr_ndx[0] = mi->max_tp_rate2;
|
||||
mrr_ndx[0] = mi->max_tp_rate[1];
|
||||
}
|
||||
|
||||
/* mrr setup for 3rd & 4th stage */
|
||||
mrr_ndx[1] = mi->max_prob_rate;
|
||||
mrr_ndx[2] = 0;
|
||||
for (i = 1; i < 4; i++) {
|
||||
@ -351,26 +383,21 @@ static void
|
||||
init_sample_table(struct minstrel_sta_info *mi)
|
||||
{
|
||||
unsigned int i, col, new_idx;
|
||||
unsigned int n_srates = mi->n_rates - 1;
|
||||
u8 rnd[8];
|
||||
|
||||
mi->sample_column = 0;
|
||||
mi->sample_idx = 0;
|
||||
memset(mi->sample_table, 0, SAMPLE_COLUMNS * mi->n_rates);
|
||||
mi->sample_row = 0;
|
||||
memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates);
|
||||
|
||||
for (col = 0; col < SAMPLE_COLUMNS; col++) {
|
||||
for (i = 0; i < n_srates; i++) {
|
||||
for (i = 0; i < mi->n_rates; i++) {
|
||||
get_random_bytes(rnd, sizeof(rnd));
|
||||
new_idx = (i + rnd[i & 7]) % n_srates;
|
||||
new_idx = (i + rnd[i & 7]) % mi->n_rates;
|
||||
|
||||
while (SAMPLE_TBL(mi, new_idx, col) != 0)
|
||||
new_idx = (new_idx + 1) % n_srates;
|
||||
while (SAMPLE_TBL(mi, new_idx, col) != 0xff)
|
||||
new_idx = (new_idx + 1) % mi->n_rates;
|
||||
|
||||
/* Don't sample the slowest rate (i.e. slowest base
|
||||
* rate). We must presume that the slowest rate works
|
||||
* fine, or else other management frames will also be
|
||||
* failing and the link will break */
|
||||
SAMPLE_TBL(mi, new_idx, col) = i + 1;
|
||||
SAMPLE_TBL(mi, new_idx, col) = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -542,9 +569,6 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
||||
mp->lookaround_rate = 5;
|
||||
mp->lookaround_rate_mrr = 10;
|
||||
|
||||
/* moving average weight for EWMA */
|
||||
mp->ewma_level = 75;
|
||||
|
||||
/* maximum time that the hw is allowed to stay in one MRR segment */
|
||||
mp->segment_size = 6000;
|
||||
|
||||
|
@ -9,6 +9,28 @@
|
||||
#ifndef __RC_MINSTREL_H
|
||||
#define __RC_MINSTREL_H
|
||||
|
||||
#define EWMA_LEVEL 75 /* ewma weighting factor [%] */
|
||||
#define SAMPLE_COLUMNS 10 /* number of columns in sample table */
|
||||
|
||||
|
||||
/* scaled fraction values */
|
||||
#define MINSTREL_SCALE 16
|
||||
#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
|
||||
#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
|
||||
|
||||
/* number of highest throughput rates to consider*/
|
||||
#define MAX_THR_RATES 4
|
||||
|
||||
/*
|
||||
* Perform EWMA (Exponentially Weighted Moving Average) calculation
|
||||
*/
|
||||
static inline int
|
||||
minstrel_ewma(int old, int new, int weight)
|
||||
{
|
||||
return (new * (100 - weight) + old * weight) / 100;
|
||||
}
|
||||
|
||||
|
||||
struct minstrel_rate {
|
||||
int bitrate;
|
||||
int rix;
|
||||
@ -26,6 +48,7 @@ struct minstrel_rate {
|
||||
u32 attempts;
|
||||
u32 last_attempts;
|
||||
u32 last_success;
|
||||
u8 sample_skipped;
|
||||
|
||||
/* parts per thousand */
|
||||
u32 cur_prob;
|
||||
@ -45,14 +68,13 @@ struct minstrel_sta_info {
|
||||
|
||||
unsigned int lowest_rix;
|
||||
|
||||
unsigned int max_tp_rate;
|
||||
unsigned int max_tp_rate2;
|
||||
unsigned int max_prob_rate;
|
||||
u8 max_tp_rate[MAX_THR_RATES];
|
||||
u8 max_prob_rate;
|
||||
unsigned int packet_count;
|
||||
unsigned int sample_count;
|
||||
int sample_deferred;
|
||||
|
||||
unsigned int sample_idx;
|
||||
unsigned int sample_row;
|
||||
unsigned int sample_column;
|
||||
|
||||
int n_rates;
|
||||
@ -73,7 +95,6 @@ struct minstrel_priv {
|
||||
unsigned int cw_min;
|
||||
unsigned int cw_max;
|
||||
unsigned int max_retry;
|
||||
unsigned int ewma_level;
|
||||
unsigned int segment_size;
|
||||
unsigned int update_interval;
|
||||
unsigned int lookaround_rate;
|
||||
|
@ -73,15 +73,17 @@ minstrel_stats_open(struct inode *inode, struct file *file)
|
||||
for (i = 0; i < mi->n_rates; i++) {
|
||||
struct minstrel_rate *mr = &mi->r[i];
|
||||
|
||||
*(p++) = (i == mi->max_tp_rate) ? 'T' : ' ';
|
||||
*(p++) = (i == mi->max_tp_rate2) ? 't' : ' ';
|
||||
*(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' ';
|
||||
*(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' ';
|
||||
*(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' ';
|
||||
*(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' ';
|
||||
*(p++) = (i == mi->max_prob_rate) ? 'P' : ' ';
|
||||
p += sprintf(p, "%3u%s", mr->bitrate / 2,
|
||||
(mr->bitrate & 1 ? ".5" : " "));
|
||||
|
||||
tp = mr->cur_tp / ((18000 << 10) / 96);
|
||||
prob = mr->cur_prob / 18;
|
||||
eprob = mr->probability / 18;
|
||||
tp = MINSTREL_TRUNC(mr->cur_tp / 10);
|
||||
prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
|
||||
eprob = MINSTREL_TRUNC(mr->probability * 1000);
|
||||
|
||||
p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
|
||||
"%3u(%3u) %8llu %8llu\n",
|
||||
|
@ -17,8 +17,6 @@
|
||||
#include "rc80211_minstrel_ht.h"
|
||||
|
||||
#define AVG_PKT_SIZE 1200
|
||||
#define SAMPLE_COLUMNS 10
|
||||
#define EWMA_LEVEL 75
|
||||
|
||||
/* Number of bits for an average sized packet */
|
||||
#define MCS_NBITS (AVG_PKT_SIZE << 3)
|
||||
@ -26,11 +24,11 @@
|
||||
/* Number of symbols for a packet with (bps) bits per symbol */
|
||||
#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
|
||||
|
||||
/* Transmission time for a packet containing (syms) symbols */
|
||||
/* Transmission time (nanoseconds) for a packet containing (syms) symbols */
|
||||
#define MCS_SYMBOL_TIME(sgi, syms) \
|
||||
(sgi ? \
|
||||
((syms) * 18 + 4) / 5 : /* syms * 3.6 us */ \
|
||||
(syms) << 2 /* syms * 4 us */ \
|
||||
((syms) * 18000 + 4000) / 5 : /* syms * 3.6 us */ \
|
||||
((syms) * 1000) << 2 /* syms * 4 us */ \
|
||||
)
|
||||
|
||||
/* Transmit duration for the raw data part of an average sized packet */
|
||||
@ -64,9 +62,9 @@
|
||||
}
|
||||
|
||||
#define CCK_DURATION(_bitrate, _short, _len) \
|
||||
(10 /* SIFS */ + \
|
||||
(1000 * (10 /* SIFS */ + \
|
||||
(_short ? 72 + 24 : 144 + 48 ) + \
|
||||
(8 * (_len + 4) * 10) / (_bitrate))
|
||||
(8 * (_len + 4) * 10) / (_bitrate)))
|
||||
|
||||
#define CCK_ACK_DURATION(_bitrate, _short) \
|
||||
(CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \
|
||||
@ -128,15 +126,6 @@ const struct mcs_group minstrel_mcs_groups[] = {
|
||||
|
||||
static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
|
||||
|
||||
/*
|
||||
* Perform EWMA (Exponentially Weighted Moving Average) calculation
|
||||
*/
|
||||
static int
|
||||
minstrel_ewma(int old, int new, int weight)
|
||||
{
|
||||
return (new * (100 - weight) + old * weight) / 100;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an MCS group index based on mac80211 rate information
|
||||
*/
|
||||
@ -211,7 +200,8 @@ static void
|
||||
minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
|
||||
{
|
||||
struct minstrel_rate_stats *mr;
|
||||
unsigned int usecs = 0;
|
||||
unsigned int nsecs = 0;
|
||||
unsigned int tp;
|
||||
|
||||
mr = &mi->groups[group].rates[rate];
|
||||
|
||||
@ -221,10 +211,12 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
|
||||
}
|
||||
|
||||
if (group != MINSTREL_CCK_GROUP)
|
||||
usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
|
||||
nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
|
||||
|
||||
usecs += minstrel_mcs_groups[group].duration[rate];
|
||||
mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
|
||||
nsecs += minstrel_mcs_groups[group].duration[rate];
|
||||
tp = 1000000 * ((mr->probability * 1000) / nsecs);
|
||||
|
||||
mr->cur_tp = MINSTREL_TRUNC(tp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -308,8 +300,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||
}
|
||||
}
|
||||
|
||||
/* try to sample up to half of the available rates during each interval */
|
||||
mi->sample_count *= 4;
|
||||
/* try to sample all available rates during each interval */
|
||||
mi->sample_count *= 8;
|
||||
|
||||
cur_prob = 0;
|
||||
cur_prob_tp = 0;
|
||||
@ -320,20 +312,13 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||
if (!mg->supported)
|
||||
continue;
|
||||
|
||||
mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
|
||||
if (cur_prob_tp < mr->cur_tp &&
|
||||
minstrel_mcs_groups[group].streams == 1) {
|
||||
mi->max_prob_rate = mg->max_prob_rate;
|
||||
cur_prob = mr->cur_prob;
|
||||
cur_prob_tp = mr->cur_tp;
|
||||
}
|
||||
|
||||
mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
|
||||
if (cur_tp < mr->cur_tp) {
|
||||
mi->max_tp_rate2 = mi->max_tp_rate;
|
||||
cur_tp2 = cur_tp;
|
||||
mi->max_tp_rate = mg->max_tp_rate;
|
||||
cur_tp = mr->cur_tp;
|
||||
mi->max_prob_streams = minstrel_mcs_groups[group].streams - 1;
|
||||
}
|
||||
|
||||
mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
|
||||
@ -343,6 +328,23 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||
}
|
||||
}
|
||||
|
||||
if (mi->max_prob_streams < 1)
|
||||
mi->max_prob_streams = 1;
|
||||
|
||||
for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
|
||||
mg = &mi->groups[group];
|
||||
if (!mg->supported)
|
||||
continue;
|
||||
mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
|
||||
if (cur_prob_tp < mr->cur_tp &&
|
||||
minstrel_mcs_groups[group].streams <= mi->max_prob_streams) {
|
||||
mi->max_prob_rate = mg->max_prob_rate;
|
||||
cur_prob = mr->cur_prob;
|
||||
cur_prob_tp = mr->cur_tp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mi->stats_update = jiffies;
|
||||
}
|
||||
|
||||
@ -467,7 +469,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
|
||||
if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
|
||||
mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
|
||||
mi->sample_tries = 2;
|
||||
mi->sample_tries = 1;
|
||||
mi->sample_count--;
|
||||
}
|
||||
|
||||
@ -536,7 +538,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
|
||||
mr->retry_updated = true;
|
||||
|
||||
group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
|
||||
tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len;
|
||||
tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000;
|
||||
|
||||
/* Contention time for first 2 tries */
|
||||
ctime = (t_slot * cw) >> 1;
|
||||
@ -616,6 +618,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||
{
|
||||
struct minstrel_rate_stats *mr;
|
||||
struct minstrel_mcs_group_data *mg;
|
||||
unsigned int sample_dur, sample_group;
|
||||
int sample_idx = 0;
|
||||
|
||||
if (mi->sample_wait > 0) {
|
||||
@ -626,11 +629,11 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||
if (!mi->sample_tries)
|
||||
return -1;
|
||||
|
||||
mi->sample_tries--;
|
||||
mg = &mi->groups[mi->sample_group];
|
||||
sample_idx = sample_table[mg->column][mg->index];
|
||||
mr = &mg->rates[sample_idx];
|
||||
sample_idx += mi->sample_group * MCS_GROUP_RATES;
|
||||
sample_group = mi->sample_group;
|
||||
sample_idx += sample_group * MCS_GROUP_RATES;
|
||||
minstrel_next_sample_idx(mi);
|
||||
|
||||
/*
|
||||
@ -651,14 +654,18 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||
* Make sure that lower rates get sampled only occasionally,
|
||||
* if the link is working perfectly.
|
||||
*/
|
||||
if (minstrel_get_duration(sample_idx) >
|
||||
minstrel_get_duration(mi->max_tp_rate)) {
|
||||
sample_dur = minstrel_get_duration(sample_idx);
|
||||
if (sample_dur >= minstrel_get_duration(mi->max_tp_rate2) &&
|
||||
(mi->max_prob_streams <
|
||||
minstrel_mcs_groups[sample_group].streams ||
|
||||
sample_dur >= minstrel_get_duration(mi->max_prob_rate))) {
|
||||
if (mr->sample_skipped < 20)
|
||||
return -1;
|
||||
|
||||
if (mi->sample_slow++ > 2)
|
||||
return -1;
|
||||
}
|
||||
mi->sample_tries--;
|
||||
|
||||
return sample_idx;
|
||||
}
|
||||
|
@ -16,11 +16,6 @@
|
||||
#define MINSTREL_MAX_STREAMS 3
|
||||
#define MINSTREL_STREAM_GROUPS 4
|
||||
|
||||
/* scaled fraction values */
|
||||
#define MINSTREL_SCALE 16
|
||||
#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
|
||||
#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
|
||||
|
||||
#define MCS_GROUP_RATES 8
|
||||
|
||||
struct mcs_group {
|
||||
@ -85,6 +80,7 @@ struct minstrel_ht_sta {
|
||||
|
||||
/* best probability rate */
|
||||
unsigned int max_prob_rate;
|
||||
unsigned int max_prob_streams;
|
||||
|
||||
/* time of last status update */
|
||||
unsigned long stats_update;
|
||||
|
@ -648,24 +648,6 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
#define SEQ_MODULO 0x1000
|
||||
#define SEQ_MASK 0xfff
|
||||
|
||||
static inline int seq_less(u16 sq1, u16 sq2)
|
||||
{
|
||||
return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
|
||||
}
|
||||
|
||||
static inline u16 seq_inc(u16 sq)
|
||||
{
|
||||
return (sq + 1) & SEQ_MASK;
|
||||
}
|
||||
|
||||
static inline u16 seq_sub(u16 sq1, u16 sq2)
|
||||
{
|
||||
return (sq1 - sq2) & SEQ_MASK;
|
||||
}
|
||||
|
||||
static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
int index,
|
||||
@ -687,7 +669,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
||||
__skb_queue_tail(frames, skb);
|
||||
|
||||
no_frame:
|
||||
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
|
||||
tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
|
||||
}
|
||||
|
||||
static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata,
|
||||
@ -699,8 +681,9 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata
|
||||
|
||||
lockdep_assert_held(&tid_agg_rx->reorder_lock);
|
||||
|
||||
while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
|
||||
index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
|
||||
tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
|
||||
frames);
|
||||
@ -727,8 +710,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||
lockdep_assert_held(&tid_agg_rx->reorder_lock);
|
||||
|
||||
/* release the buffer until next missing frame */
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
|
||||
tid_agg_rx->ssn) % tid_agg_rx->buf_size;
|
||||
if (!tid_agg_rx->reorder_buf[index] &&
|
||||
tid_agg_rx->stored_mpdu_num) {
|
||||
/*
|
||||
@ -756,19 +739,22 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||
* Increment the head seq# also for the skipped slots.
|
||||
*/
|
||||
tid_agg_rx->head_seq_num =
|
||||
(tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
|
||||
(tid_agg_rx->head_seq_num +
|
||||
skipped) & IEEE80211_SN_MASK;
|
||||
skipped = 0;
|
||||
}
|
||||
} else while (tid_agg_rx->reorder_buf[index]) {
|
||||
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
|
||||
frames);
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
|
||||
tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
}
|
||||
|
||||
if (tid_agg_rx->stored_mpdu_num) {
|
||||
j = index = seq_sub(tid_agg_rx->head_seq_num,
|
||||
tid_agg_rx->ssn) % tid_agg_rx->buf_size;
|
||||
j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
|
||||
tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
|
||||
for (; j != (index - 1) % tid_agg_rx->buf_size;
|
||||
j = (j + 1) % tid_agg_rx->buf_size) {
|
||||
@ -809,7 +795,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
|
||||
head_seq_num = tid_agg_rx->head_seq_num;
|
||||
|
||||
/* frame with out of date sequence number */
|
||||
if (seq_less(mpdu_seq_num, head_seq_num)) {
|
||||
if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
|
||||
dev_kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
@ -818,8 +804,9 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
|
||||
* If frame the sequence number exceeds our buffering window
|
||||
* size release some previous frames to make room for this one.
|
||||
*/
|
||||
if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
|
||||
head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
|
||||
if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) {
|
||||
head_seq_num = ieee80211_sn_inc(
|
||||
ieee80211_sn_sub(mpdu_seq_num, buf_size));
|
||||
/* release stored frames up to new head to stack */
|
||||
ieee80211_release_reorder_frames(sdata, tid_agg_rx,
|
||||
head_seq_num, frames);
|
||||
@ -827,7 +814,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
|
||||
|
||||
/* Now the new frame is always in the range of the reordering buffer */
|
||||
|
||||
index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
|
||||
index = ieee80211_sn_sub(mpdu_seq_num,
|
||||
tid_agg_rx->ssn) % tid_agg_rx->buf_size;
|
||||
|
||||
/* check if we already stored this frame */
|
||||
if (tid_agg_rx->reorder_buf[index]) {
|
||||
@ -843,7 +831,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
|
||||
*/
|
||||
if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
|
||||
tid_agg_rx->stored_mpdu_num == 0) {
|
||||
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
|
||||
tid_agg_rx->head_seq_num =
|
||||
ieee80211_sn_inc(tid_agg_rx->head_seq_num);
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
@ -1894,8 +1883,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
|
||||
* 'align' will only take the values 0 or 2 here
|
||||
* since all frames are required to be aligned
|
||||
* to 2-byte boundaries when being passed to
|
||||
* mac80211. That also explains the __skb_push()
|
||||
* below.
|
||||
* mac80211; the code here works just as well if
|
||||
* that isn't true, but mac80211 assumes it can
|
||||
* access fields as 2-byte aligned (e.g. for
|
||||
* compare_ether_addr)
|
||||
*/
|
||||
align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3;
|
||||
if (align) {
|
||||
@ -2552,7 +2543,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
case WLAN_SP_MESH_PEERING_CONFIRM:
|
||||
if (!ieee80211_vif_is_mesh(&sdata->vif))
|
||||
goto invalid;
|
||||
if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
|
||||
if (sdata->u.mesh.user_mpm)
|
||||
/* userspace handles this frame */
|
||||
break;
|
||||
goto queue;
|
||||
|
@ -342,6 +342,11 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||
INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
|
||||
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
|
||||
mutex_init(&sta->ampdu_mlme.mtx);
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif) &&
|
||||
!sdata->u.mesh.user_mpm)
|
||||
init_timer(&sta->plink_timer);
|
||||
#endif
|
||||
|
||||
memcpy(sta->sta.addr, addr, ETH_ALEN);
|
||||
sta->local = local;
|
||||
@ -794,9 +799,11 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
|
||||
|
||||
mutex_lock(&local->key_mtx);
|
||||
for (i = 0; i < NUM_DEFAULT_KEYS; i++)
|
||||
__ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]));
|
||||
__ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]),
|
||||
true);
|
||||
if (sta->ptk)
|
||||
__ieee80211_key_free(key_mtx_dereference(local, sta->ptk));
|
||||
__ieee80211_key_free(key_mtx_dereference(local, sta->ptk),
|
||||
true);
|
||||
mutex_unlock(&local->key_mtx);
|
||||
|
||||
sta->dead = true;
|
||||
|
@ -281,7 +281,6 @@ struct sta_ampdu_mlme {
|
||||
* @plink_state: peer link state
|
||||
* @plink_timeout: timeout of peer link
|
||||
* @plink_timer: peer link watch timer
|
||||
* @plink_timer_was_running: used by suspend/resume to restore timers
|
||||
* @t_offset: timing offset relative to this host
|
||||
* @t_offset_setpoint: reference timing offset of this sta to be used when
|
||||
* calculating clockdrift
|
||||
@ -379,7 +378,6 @@ struct sta_info {
|
||||
__le16 reason;
|
||||
u8 plink_retries;
|
||||
bool ignore_plink_timer;
|
||||
bool plink_timer_was_running;
|
||||
enum nl80211_plink_state plink_state;
|
||||
u32 plink_timeout;
|
||||
struct timer_list plink_timer;
|
||||
|
@ -1042,15 +1042,17 @@ TRACE_EVENT(drv_remain_on_channel,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_channel *chan,
|
||||
unsigned int duration),
|
||||
unsigned int duration,
|
||||
enum ieee80211_roc_type type),
|
||||
|
||||
TP_ARGS(local, sdata, chan, duration),
|
||||
TP_ARGS(local, sdata, chan, duration, type),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(int, center_freq)
|
||||
__field(unsigned int, duration)
|
||||
__field(u32, type)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
@ -1058,12 +1060,13 @@ TRACE_EVENT(drv_remain_on_channel,
|
||||
VIF_ASSIGN;
|
||||
__entry->center_freq = chan->center_freq;
|
||||
__entry->duration = duration;
|
||||
__entry->type = type;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms",
|
||||
LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms type=%d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG,
|
||||
__entry->center_freq, __entry->duration
|
||||
__entry->center_freq, __entry->duration, __entry->type
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -1231,34 +1231,40 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
||||
if (local->queue_stop_reasons[q] ||
|
||||
(!txpending && !skb_queue_empty(&local->pending[q]))) {
|
||||
if (unlikely(info->flags &
|
||||
IEEE80211_TX_INTFL_OFFCHAN_TX_OK &&
|
||||
local->queue_stop_reasons[q] &
|
||||
~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL))) {
|
||||
IEEE80211_TX_INTFL_OFFCHAN_TX_OK)) {
|
||||
if (local->queue_stop_reasons[q] &
|
||||
~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL)) {
|
||||
/*
|
||||
* Drop off-channel frames if queues
|
||||
* are stopped for any reason other
|
||||
* than off-channel operation. Never
|
||||
* queue them.
|
||||
*/
|
||||
spin_unlock_irqrestore(
|
||||
&local->queue_stop_reason_lock,
|
||||
flags);
|
||||
ieee80211_purge_tx_queue(&local->hw,
|
||||
skbs);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Drop off-channel frames if queues are stopped
|
||||
* for any reason other than off-channel
|
||||
* operation. Never queue them.
|
||||
* Since queue is stopped, queue up frames for
|
||||
* later transmission from the tx-pending
|
||||
* tasklet when the queue is woken again.
|
||||
*/
|
||||
spin_unlock_irqrestore(
|
||||
&local->queue_stop_reason_lock, flags);
|
||||
ieee80211_purge_tx_queue(&local->hw, skbs);
|
||||
return true;
|
||||
if (txpending)
|
||||
skb_queue_splice_init(skbs,
|
||||
&local->pending[q]);
|
||||
else
|
||||
skb_queue_splice_tail_init(skbs,
|
||||
&local->pending[q]);
|
||||
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
|
||||
flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since queue is stopped, queue up frames for later
|
||||
* transmission from the tx-pending tasklet when the
|
||||
* queue is woken again.
|
||||
*/
|
||||
if (txpending)
|
||||
skb_queue_splice_init(skbs, &local->pending[q]);
|
||||
else
|
||||
skb_queue_splice_tail_init(skbs,
|
||||
&local->pending[q]);
|
||||
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
|
||||
flags);
|
||||
return false;
|
||||
}
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
@ -1844,9 +1850,24 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
if (!is_multicast_ether_addr(skb->data)) {
|
||||
struct sta_info *next_hop;
|
||||
bool mpp_lookup = true;
|
||||
|
||||
mpath = mesh_path_lookup(sdata, skb->data);
|
||||
if (!mpath)
|
||||
if (mpath) {
|
||||
mpp_lookup = false;
|
||||
next_hop = rcu_dereference(mpath->next_hop);
|
||||
if (!next_hop ||
|
||||
!(mpath->flags & (MESH_PATH_ACTIVE |
|
||||
MESH_PATH_RESOLVING)))
|
||||
mpp_lookup = true;
|
||||
}
|
||||
|
||||
if (mpp_lookup)
|
||||
mppath = mpp_path_lookup(sdata, skb->data);
|
||||
|
||||
if (mppath && mpath)
|
||||
mesh_path_del(mpath->sdata, mpath->dst);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2350,9 +2371,9 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
|
||||
if (local->tim_in_locked_section) {
|
||||
__ieee80211_beacon_add_tim(sdata, ps, skb);
|
||||
} else {
|
||||
spin_lock(&local->tim_lock);
|
||||
spin_lock_bh(&local->tim_lock);
|
||||
__ieee80211_beacon_add_tim(sdata, ps, skb);
|
||||
spin_unlock(&local->tim_lock);
|
||||
spin_unlock_bh(&local->tim_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2724,7 +2745,8 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
|
||||
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||
}
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
|
||||
if (!ieee80211_tx_prepare(sdata, &tx, skb))
|
||||
break;
|
||||
dev_kfree_skb_any(skb);
|
||||
|
@ -1357,6 +1357,25 @@ void ieee80211_stop_device(struct ieee80211_local *local)
|
||||
drv_stop(local);
|
||||
}
|
||||
|
||||
static void ieee80211_assign_chanctx(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
struct ieee80211_chanctx *ctx;
|
||||
|
||||
if (!local->use_chanctx)
|
||||
return;
|
||||
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
||||
lockdep_is_held(&local->chanctx_mtx));
|
||||
if (conf) {
|
||||
ctx = container_of(conf, struct ieee80211_chanctx, conf);
|
||||
drv_assign_vif_chanctx(local, sdata, ctx);
|
||||
}
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
}
|
||||
|
||||
int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
@ -1445,36 +1464,14 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
struct ieee80211_chanctx_conf *ctx_conf;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
||||
lockdep_is_held(&local->chanctx_mtx));
|
||||
if (ctx_conf) {
|
||||
ctx = container_of(ctx_conf, struct ieee80211_chanctx,
|
||||
conf);
|
||||
drv_assign_vif_chanctx(local, sdata, ctx);
|
||||
}
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
ieee80211_assign_chanctx(local, sdata);
|
||||
}
|
||||
|
||||
sdata = rtnl_dereference(local->monitor_sdata);
|
||||
if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) {
|
||||
struct ieee80211_chanctx_conf *ctx_conf;
|
||||
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
||||
lockdep_is_held(&local->chanctx_mtx));
|
||||
if (ctx_conf) {
|
||||
ctx = container_of(ctx_conf, struct ieee80211_chanctx,
|
||||
conf);
|
||||
drv_assign_vif_chanctx(local, sdata, ctx);
|
||||
}
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
}
|
||||
if (sdata && ieee80211_sdata_running(sdata))
|
||||
ieee80211_assign_chanctx(local, sdata);
|
||||
|
||||
/* add STAs back */
|
||||
mutex_lock(&local->sta_mtx);
|
||||
@ -1534,11 +1531,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
BSS_CHANGED_IDLE |
|
||||
BSS_CHANGED_TXPOWER;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (local->resuming && !reconfig_due_to_wowlan)
|
||||
sdata->vif.bss_conf = sdata->suspend_bss_conf;
|
||||
#endif
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
changed |= BSS_CHANGED_ASSOC |
|
||||
@ -1678,28 +1670,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
mb();
|
||||
local->resuming = false;
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
switch(sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ieee80211_sta_restart(sdata);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ieee80211_ibss_restart(sdata);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
ieee80211_mesh_restart(sdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mod_timer(&local->sta_cleanup, jiffies + 1);
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
list_for_each_entry(sta, &local->sta_list, list)
|
||||
mesh_plink_restart(sta);
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
#else
|
||||
WARN_ON(1);
|
||||
#endif
|
||||
|
@ -13,6 +13,104 @@
|
||||
#include "rate.h"
|
||||
|
||||
|
||||
static void __check_vhtcap_disable(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta_vht_cap *vht_cap,
|
||||
u32 flag)
|
||||
{
|
||||
__le32 le_flag = cpu_to_le32(flag);
|
||||
|
||||
if (sdata->u.mgd.vht_capa_mask.vht_cap_info & le_flag &&
|
||||
!(sdata->u.mgd.vht_capa.vht_cap_info & le_flag))
|
||||
vht_cap->cap &= ~flag;
|
||||
}
|
||||
|
||||
void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta_vht_cap *vht_cap)
|
||||
{
|
||||
int i;
|
||||
u16 rxmcs_mask, rxmcs_cap, rxmcs_n, txmcs_mask, txmcs_cap, txmcs_n;
|
||||
|
||||
if (!vht_cap->vht_supported)
|
||||
return;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
|
||||
__check_vhtcap_disable(sdata, vht_cap,
|
||||
IEEE80211_VHT_CAP_RXLDPC);
|
||||
__check_vhtcap_disable(sdata, vht_cap,
|
||||
IEEE80211_VHT_CAP_SHORT_GI_80);
|
||||
__check_vhtcap_disable(sdata, vht_cap,
|
||||
IEEE80211_VHT_CAP_SHORT_GI_160);
|
||||
__check_vhtcap_disable(sdata, vht_cap,
|
||||
IEEE80211_VHT_CAP_TXSTBC);
|
||||
__check_vhtcap_disable(sdata, vht_cap,
|
||||
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
|
||||
__check_vhtcap_disable(sdata, vht_cap,
|
||||
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
|
||||
__check_vhtcap_disable(sdata, vht_cap,
|
||||
IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN);
|
||||
__check_vhtcap_disable(sdata, vht_cap,
|
||||
IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN);
|
||||
|
||||
/* Allow user to decrease AMPDU length exponent */
|
||||
if (sdata->u.mgd.vht_capa_mask.vht_cap_info &
|
||||
cpu_to_le32(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK)) {
|
||||
u32 cap, n;
|
||||
|
||||
n = le32_to_cpu(sdata->u.mgd.vht_capa.vht_cap_info) &
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
|
||||
n >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
|
||||
cap = vht_cap->cap & IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
|
||||
cap >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
|
||||
|
||||
if (n < cap) {
|
||||
vht_cap->cap &=
|
||||
~IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
|
||||
vht_cap->cap |=
|
||||
n << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow the user to decrease MCSes */
|
||||
rxmcs_mask =
|
||||
le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.rx_mcs_map);
|
||||
rxmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.rx_mcs_map);
|
||||
rxmcs_n &= rxmcs_mask;
|
||||
rxmcs_cap = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
|
||||
|
||||
txmcs_mask =
|
||||
le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.tx_mcs_map);
|
||||
txmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.tx_mcs_map);
|
||||
txmcs_n &= txmcs_mask;
|
||||
txmcs_cap = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
|
||||
for (i = 0; i < 8; i++) {
|
||||
u8 m, n, c;
|
||||
|
||||
m = (rxmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
n = (rxmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
c = (rxmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
|
||||
if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) ||
|
||||
n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) {
|
||||
rxmcs_cap &= ~(3 << 2*i);
|
||||
rxmcs_cap |= (rxmcs_n & (3 << 2*i));
|
||||
}
|
||||
|
||||
m = (txmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
n = (txmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
c = (txmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
|
||||
if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) ||
|
||||
n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) {
|
||||
txmcs_cap &= ~(3 << 2*i);
|
||||
txmcs_cap |= (txmcs_n & (3 << 2*i));
|
||||
}
|
||||
}
|
||||
vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_cap);
|
||||
vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_cap);
|
||||
}
|
||||
|
||||
void
|
||||
ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_supported_band *sband,
|
||||
@ -20,6 +118,8 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
|
||||
struct ieee80211_sta_vht_cap own_cap;
|
||||
u32 cap_info, i;
|
||||
|
||||
memset(vht_cap, 0, sizeof(*vht_cap));
|
||||
|
||||
@ -35,12 +135,122 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
vht_cap->vht_supported = true;
|
||||
|
||||
vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info);
|
||||
own_cap = sband->vht_cap;
|
||||
/*
|
||||
* If user has specified capability overrides, take care
|
||||
* of that if the station we're setting up is the AP that
|
||||
* we advertised a restricted capability set to. Override
|
||||
* our own capabilities and then use those below.
|
||||
*/
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
|
||||
ieee80211_apply_vhtcap_overrides(sdata, &own_cap);
|
||||
|
||||
/* take some capabilities as-is */
|
||||
cap_info = le32_to_cpu(vht_cap_ie->vht_cap_info);
|
||||
vht_cap->cap = cap_info;
|
||||
vht_cap->cap &= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
|
||||
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
|
||||
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
|
||||
IEEE80211_VHT_CAP_RXLDPC |
|
||||
IEEE80211_VHT_CAP_VHT_TXOP_PS |
|
||||
IEEE80211_VHT_CAP_HTC_VHT |
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
|
||||
IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB |
|
||||
IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB |
|
||||
IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
|
||||
IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
|
||||
|
||||
/* and some based on our own capabilities */
|
||||
switch (own_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
|
||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
|
||||
vht_cap->cap |= cap_info &
|
||||
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
|
||||
vht_cap->cap |= cap_info &
|
||||
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
|
||||
break;
|
||||
default:
|
||||
/* nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
/* symmetric capabilities */
|
||||
vht_cap->cap |= cap_info & own_cap.cap &
|
||||
(IEEE80211_VHT_CAP_SHORT_GI_80 |
|
||||
IEEE80211_VHT_CAP_SHORT_GI_160);
|
||||
|
||||
/* remaining ones */
|
||||
if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
|
||||
vht_cap->cap |= cap_info &
|
||||
(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
|
||||
IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX |
|
||||
IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX);
|
||||
}
|
||||
|
||||
if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
|
||||
vht_cap->cap |= cap_info &
|
||||
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
|
||||
|
||||
if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
|
||||
vht_cap->cap |= cap_info &
|
||||
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
|
||||
|
||||
if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)
|
||||
vht_cap->cap |= cap_info &
|
||||
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
|
||||
|
||||
if (own_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
|
||||
vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_RXSTBC_MASK;
|
||||
|
||||
if (own_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
|
||||
vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_TXSTBC;
|
||||
|
||||
/* Copy peer MCS info, the driver might need them. */
|
||||
memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
|
||||
sizeof(struct ieee80211_vht_mcs_info));
|
||||
|
||||
/* but also restrict MCSes */
|
||||
for (i = 0; i < 8; i++) {
|
||||
u16 own_rx, own_tx, peer_rx, peer_tx;
|
||||
|
||||
own_rx = le16_to_cpu(own_cap.vht_mcs.rx_mcs_map);
|
||||
own_rx = (own_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
|
||||
own_tx = le16_to_cpu(own_cap.vht_mcs.tx_mcs_map);
|
||||
own_tx = (own_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
|
||||
peer_rx = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
|
||||
peer_rx = (peer_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
|
||||
peer_tx = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
|
||||
peer_tx = (peer_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
|
||||
if (peer_tx != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
|
||||
if (own_rx == IEEE80211_VHT_MCS_NOT_SUPPORTED)
|
||||
peer_tx = IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
else if (own_rx < peer_tx)
|
||||
peer_tx = own_rx;
|
||||
}
|
||||
|
||||
if (peer_rx != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
|
||||
if (own_tx == IEEE80211_VHT_MCS_NOT_SUPPORTED)
|
||||
peer_rx = IEEE80211_VHT_MCS_NOT_SUPPORTED;
|
||||
else if (own_tx < peer_rx)
|
||||
peer_rx = own_tx;
|
||||
}
|
||||
|
||||
vht_cap->vht_mcs.rx_mcs_map &=
|
||||
~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2);
|
||||
vht_cap->vht_mcs.rx_mcs_map |= cpu_to_le16(peer_rx << i * 2);
|
||||
|
||||
vht_cap->vht_mcs.tx_mcs_map &=
|
||||
~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2);
|
||||
vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(peer_tx << i * 2);
|
||||
}
|
||||
|
||||
/* finally set up the bandwidth */
|
||||
switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
|
||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
|
||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
|
||||
|
@ -51,7 +51,7 @@ static int rfkill_regulator_set_block(void *data, bool blocked)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rfkill_ops rfkill_regulator_ops = {
|
||||
static struct rfkill_ops rfkill_regulator_ops = {
|
||||
.set_block = rfkill_regulator_set_block,
|
||||
};
|
||||
|
||||
|
@ -46,65 +46,3 @@ int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void cfg80211_ch_switch_notify(struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_ch_switch_notify(dev, chandef);
|
||||
|
||||
wdev_lock(wdev);
|
||||
|
||||
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_GO))
|
||||
goto out;
|
||||
|
||||
wdev->channel = chandef->chan;
|
||||
nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
|
||||
out:
|
||||
wdev_unlock(wdev);
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_ch_switch_notify);
|
||||
|
||||
bool cfg80211_rx_spurious_frame(struct net_device *dev,
|
||||
const u8 *addr, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
bool ret;
|
||||
|
||||
trace_cfg80211_rx_spurious_frame(dev, addr);
|
||||
|
||||
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
|
||||
trace_cfg80211_return_bool(false);
|
||||
return false;
|
||||
}
|
||||
ret = nl80211_unexpected_frame(dev, addr, gfp);
|
||||
trace_cfg80211_return_bool(ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
|
||||
|
||||
bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
|
||||
const u8 *addr, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
bool ret;
|
||||
|
||||
trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
|
||||
|
||||
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_GO &&
|
||||
wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
|
||||
trace_cfg80211_return_bool(false);
|
||||
return false;
|
||||
}
|
||||
ret = nl80211_unexpected_4addr_frame(dev, addr, gfp);
|
||||
trace_cfg80211_return_bool(ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
|
||||
|
@ -367,8 +367,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
|
||||
rdev->wiphy.rts_threshold = (u32) -1;
|
||||
rdev->wiphy.coverage_class = 0;
|
||||
|
||||
rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH |
|
||||
NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
|
||||
rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH;
|
||||
|
||||
return &rdev->wiphy;
|
||||
}
|
||||
@ -815,6 +814,46 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
|
||||
rdev->num_running_monitor_ifaces += num;
|
||||
}
|
||||
|
||||
void cfg80211_leave(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
struct net_device *dev = wdev->netdev;
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
cfg80211_leave_ibss(rdev, dev, true);
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
mutex_lock(&rdev->sched_scan_mtx);
|
||||
__cfg80211_stop_sched_scan(rdev, false);
|
||||
mutex_unlock(&rdev->sched_scan_mtx);
|
||||
|
||||
wdev_lock(wdev);
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
kfree(wdev->wext.ie);
|
||||
wdev->wext.ie = NULL;
|
||||
wdev->wext.ie_len = 0;
|
||||
wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
|
||||
#endif
|
||||
__cfg80211_disconnect(rdev, dev,
|
||||
WLAN_REASON_DEAUTH_LEAVING, true);
|
||||
cfg80211_mlme_down(rdev, dev);
|
||||
wdev_unlock(wdev);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
cfg80211_leave_mesh(rdev, dev);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
cfg80211_stop_ap(rdev, dev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
wdev->beacon_interval = 0;
|
||||
}
|
||||
|
||||
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
unsigned long state,
|
||||
void *ndev)
|
||||
@ -883,38 +922,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
dev->priv_flags |= IFF_DONT_BRIDGE;
|
||||
break;
|
||||
case NETDEV_GOING_DOWN:
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
cfg80211_leave_ibss(rdev, dev, true);
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
mutex_lock(&rdev->sched_scan_mtx);
|
||||
__cfg80211_stop_sched_scan(rdev, false);
|
||||
mutex_unlock(&rdev->sched_scan_mtx);
|
||||
|
||||
wdev_lock(wdev);
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
kfree(wdev->wext.ie);
|
||||
wdev->wext.ie = NULL;
|
||||
wdev->wext.ie_len = 0;
|
||||
wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
|
||||
#endif
|
||||
__cfg80211_disconnect(rdev, dev,
|
||||
WLAN_REASON_DEAUTH_LEAVING, true);
|
||||
cfg80211_mlme_down(rdev, dev);
|
||||
wdev_unlock(wdev);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
cfg80211_leave_mesh(rdev, dev);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
cfg80211_stop_ap(rdev, dev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
wdev->beacon_interval = 0;
|
||||
cfg80211_leave(rdev, wdev);
|
||||
break;
|
||||
case NETDEV_DOWN:
|
||||
cfg80211_update_iface_num(rdev, wdev->iftype, -1);
|
||||
|
@ -330,20 +330,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
const u8 *bssid, const u8 *prev_bssid,
|
||||
const u8 *bssid,
|
||||
const u8 *ssid, int ssid_len,
|
||||
const u8 *ie, int ie_len, bool use_mfp,
|
||||
struct cfg80211_crypto_settings *crypt,
|
||||
u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
|
||||
struct ieee80211_ht_cap *ht_capa_mask);
|
||||
struct cfg80211_assoc_request *req);
|
||||
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, struct ieee80211_channel *chan,
|
||||
const u8 *bssid, const u8 *prev_bssid,
|
||||
struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
const u8 *bssid,
|
||||
const u8 *ssid, int ssid_len,
|
||||
const u8 *ie, int ie_len, bool use_mfp,
|
||||
struct cfg80211_crypto_settings *crypt,
|
||||
u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
|
||||
struct ieee80211_ht_cap *ht_capa_mask);
|
||||
struct cfg80211_assoc_request *req);
|
||||
int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, const u8 *bssid,
|
||||
const u8 *ie, int ie_len, u16 reason,
|
||||
@ -375,6 +370,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
|
||||
bool no_cck, bool dont_wait_for_ack, u64 *cookie);
|
||||
void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
|
||||
const struct ieee80211_ht_cap *ht_capa_mask);
|
||||
void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
|
||||
const struct ieee80211_vht_cap *vht_capa_mask);
|
||||
|
||||
/* SME */
|
||||
int __cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
@ -503,6 +500,9 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
||||
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_iftype iftype, int num);
|
||||
|
||||
void cfg80211_leave(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev);
|
||||
|
||||
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
|
||||
|
||||
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
|
||||
|
@ -85,6 +85,7 @@ const struct mesh_setup default_mesh_setup = {
|
||||
.ie = NULL,
|
||||
.ie_len = 0,
|
||||
.is_secure = false,
|
||||
.user_mpm = false,
|
||||
.beacon_interval = MESH_DEFAULT_BEACON_INTERVAL,
|
||||
.dtim_period = MESH_DEFAULT_DTIM_PERIOD,
|
||||
};
|
||||
@ -233,20 +234,6 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cfg80211_notify_new_peer_candidate(struct net_device *dev,
|
||||
const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
|
||||
trace_cfg80211_notify_new_peer_candidate(dev, macaddr);
|
||||
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
|
||||
return;
|
||||
|
||||
nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev,
|
||||
macaddr, ie, ie_len, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
|
||||
|
||||
static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
|
@ -187,30 +187,6 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_disassoc);
|
||||
|
||||
void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_send_unprot_deauth(dev);
|
||||
nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
|
||||
|
||||
void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_send_unprot_disassoc(dev);
|
||||
nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
|
||||
|
||||
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
@ -367,27 +343,38 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
|
||||
p1[i] &= p2[i];
|
||||
}
|
||||
|
||||
/* Do a logical ht_capa &= ht_capa_mask. */
|
||||
void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
|
||||
const struct ieee80211_vht_cap *vht_capa_mask)
|
||||
{
|
||||
int i;
|
||||
u8 *p1, *p2;
|
||||
if (!vht_capa_mask) {
|
||||
memset(vht_capa, 0, sizeof(*vht_capa));
|
||||
return;
|
||||
}
|
||||
|
||||
p1 = (u8*)(vht_capa);
|
||||
p2 = (u8*)(vht_capa_mask);
|
||||
for (i = 0; i < sizeof(*vht_capa); i++)
|
||||
p1[i] &= p2[i];
|
||||
}
|
||||
|
||||
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
const u8 *bssid, const u8 *prev_bssid,
|
||||
const u8 *bssid,
|
||||
const u8 *ssid, int ssid_len,
|
||||
const u8 *ie, int ie_len, bool use_mfp,
|
||||
struct cfg80211_crypto_settings *crypt,
|
||||
u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
|
||||
struct ieee80211_ht_cap *ht_capa_mask)
|
||||
struct cfg80211_assoc_request *req)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_assoc_request req;
|
||||
int err;
|
||||
bool was_connected = false;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
|
||||
if (wdev->current_bss && prev_bssid &&
|
||||
ether_addr_equal(wdev->current_bss->pub.bssid, prev_bssid)) {
|
||||
if (wdev->current_bss && req->prev_bssid &&
|
||||
ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) {
|
||||
/*
|
||||
* Trying to reassociate: Allow this to proceed and let the old
|
||||
* association to be dropped when the new one is completed.
|
||||
@ -399,40 +386,30 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
} else if (wdev->current_bss)
|
||||
return -EALREADY;
|
||||
|
||||
req.ie = ie;
|
||||
req.ie_len = ie_len;
|
||||
memcpy(&req.crypto, crypt, sizeof(req.crypto));
|
||||
req.use_mfp = use_mfp;
|
||||
req.prev_bssid = prev_bssid;
|
||||
req.flags = assoc_flags;
|
||||
if (ht_capa)
|
||||
memcpy(&req.ht_capa, ht_capa, sizeof(req.ht_capa));
|
||||
if (ht_capa_mask)
|
||||
memcpy(&req.ht_capa_mask, ht_capa_mask,
|
||||
sizeof(req.ht_capa_mask));
|
||||
cfg80211_oper_and_ht_capa(&req.ht_capa_mask,
|
||||
cfg80211_oper_and_ht_capa(&req->ht_capa_mask,
|
||||
rdev->wiphy.ht_capa_mod_mask);
|
||||
cfg80211_oper_and_vht_capa(&req->vht_capa_mask,
|
||||
rdev->wiphy.vht_capa_mod_mask);
|
||||
|
||||
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
if (!req.bss) {
|
||||
req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
if (!req->bss) {
|
||||
if (was_connected)
|
||||
wdev->sme_state = CFG80211_SME_CONNECTED;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
|
||||
CHAN_MODE_SHARED);
|
||||
err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = rdev_assoc(rdev, dev, &req);
|
||||
err = rdev_assoc(rdev, dev, req);
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
if (was_connected)
|
||||
wdev->sme_state = CFG80211_SME_CONNECTED;
|
||||
cfg80211_put_bss(&rdev->wiphy, req.bss);
|
||||
cfg80211_put_bss(&rdev->wiphy, req->bss);
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -441,21 +418,17 @@ out:
|
||||
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
const u8 *bssid, const u8 *prev_bssid,
|
||||
const u8 *bssid,
|
||||
const u8 *ssid, int ssid_len,
|
||||
const u8 *ie, int ie_len, bool use_mfp,
|
||||
struct cfg80211_crypto_settings *crypt,
|
||||
u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
|
||||
struct ieee80211_ht_cap *ht_capa_mask)
|
||||
struct cfg80211_assoc_request *req)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
wdev_lock(wdev);
|
||||
err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
|
||||
ssid, ssid_len, ie, ie_len, use_mfp, crypt,
|
||||
assoc_flags, ht_capa, ht_capa_mask);
|
||||
err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid,
|
||||
ssid, ssid_len, req);
|
||||
wdev_unlock(wdev);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
@ -577,62 +550,6 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
|
||||
}
|
||||
}
|
||||
|
||||
void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
|
||||
struct ieee80211_channel *chan,
|
||||
unsigned int duration, gfp_t gfp)
|
||||
{
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
|
||||
nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, duration, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_ready_on_channel);
|
||||
|
||||
void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
|
||||
struct ieee80211_channel *chan,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
|
||||
nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
|
||||
|
||||
void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
|
||||
struct station_info *sinfo, gfp_t gfp)
|
||||
{
|
||||
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_new_sta(dev, mac_addr, sinfo);
|
||||
nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_new_sta);
|
||||
|
||||
void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
|
||||
{
|
||||
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_del_sta(dev, mac_addr);
|
||||
nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_del_sta);
|
||||
|
||||
void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
|
||||
enum nl80211_connect_failed_reason reason,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
nl80211_send_conn_failed_event(rdev, dev, mac_addr, reason, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_conn_failed);
|
||||
|
||||
struct cfg80211_mgmt_registration {
|
||||
struct list_head list;
|
||||
|
||||
@ -909,85 +826,6 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_mgmt);
|
||||
|
||||
void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
||||
const u8 *buf, size_t len, bool ack, gfp_t gfp)
|
||||
{
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
|
||||
|
||||
/* Indicate TX status of the Action frame to user space */
|
||||
nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
|
||||
|
||||
void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
||||
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
|
||||
|
||||
/* Indicate roaming trigger event to user space */
|
||||
nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
|
||||
|
||||
void cfg80211_cqm_pktloss_notify(struct net_device *dev,
|
||||
const u8 *peer, u32 num_packets, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
|
||||
|
||||
/* Indicate roaming trigger event to user space */
|
||||
nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
|
||||
|
||||
void cfg80211_cqm_txe_notify(struct net_device *dev,
|
||||
const u8 *peer, u32 num_packets,
|
||||
u32 rate, u32 intvl, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets,
|
||||
rate, intvl, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
|
||||
|
||||
void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *replay_ctr, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_gtk_rekey_notify(dev, bssid);
|
||||
nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
|
||||
|
||||
void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
|
||||
const u8 *bssid, bool preauth, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
|
||||
nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
|
||||
|
||||
void cfg80211_dfs_channels_update_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,12 +29,6 @@ void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
|
||||
void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
const u8 *buf, size_t len, gfp_t gfp);
|
||||
void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
const u8 *buf, size_t len, gfp_t gfp);
|
||||
void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
const u8 *buf, size_t len, gfp_t gfp);
|
||||
void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
const u8 *addr, gfp_t gfp);
|
||||
@ -54,10 +48,6 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u16 reason,
|
||||
const u8 *ie, size_t ie_len, bool from_ap);
|
||||
|
||||
void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
const u8 *macaddr, const u8* ie, u8 ie_len,
|
||||
gfp_t gfp);
|
||||
void
|
||||
nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *addr,
|
||||
@ -73,41 +63,10 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
gfp_t gfp);
|
||||
|
||||
void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, u64 cookie,
|
||||
struct ieee80211_channel *chan,
|
||||
unsigned int duration, gfp_t gfp);
|
||||
void nl80211_send_remain_on_channel_cancel(
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
u64 cookie, struct ieee80211_channel *chan, gfp_t gfp);
|
||||
|
||||
void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, const u8 *mac_addr,
|
||||
struct station_info *sinfo, gfp_t gfp);
|
||||
void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, const u8 *mac_addr,
|
||||
gfp_t gfp);
|
||||
|
||||
void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, const u8 *mac_addr,
|
||||
enum nl80211_connect_failed_reason reason,
|
||||
gfp_t gfp);
|
||||
|
||||
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, u32 nlpid,
|
||||
int freq, int sig_dbm,
|
||||
const u8 *buf, size_t len, gfp_t gfp);
|
||||
void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, u64 cookie,
|
||||
const u8 *buf, size_t len, bool ack,
|
||||
gfp_t gfp);
|
||||
|
||||
void
|
||||
nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
||||
gfp_t gfp);
|
||||
|
||||
void
|
||||
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
|
||||
@ -115,31 +74,4 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_radar_event event,
|
||||
struct net_device *netdev, gfp_t gfp);
|
||||
|
||||
void
|
||||
nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *peer,
|
||||
u32 num_packets, gfp_t gfp);
|
||||
|
||||
void
|
||||
nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *peer,
|
||||
u32 num_packets, u32 rate, u32 intvl, gfp_t gfp);
|
||||
|
||||
void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
const u8 *replay_ctr, gfp_t gfp);
|
||||
|
||||
void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, int index,
|
||||
const u8 *bssid, bool preauth, gfp_t gfp);
|
||||
|
||||
void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef, gfp_t gfp);
|
||||
|
||||
bool nl80211_unexpected_frame(struct net_device *dev,
|
||||
const u8 *addr, gfp_t gfp);
|
||||
bool nl80211_unexpected_4addr_frame(struct net_device *dev,
|
||||
const u8 *addr, gfp_t gfp);
|
||||
|
||||
#endif /* __NET_WIRELESS_NL80211_H */
|
||||
|
@ -6,11 +6,12 @@
|
||||
#include "core.h"
|
||||
#include "trace.h"
|
||||
|
||||
static inline int rdev_suspend(struct cfg80211_registered_device *rdev)
|
||||
static inline int rdev_suspend(struct cfg80211_registered_device *rdev,
|
||||
struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
int ret;
|
||||
trace_rdev_suspend(&rdev->wiphy, rdev->wowlan);
|
||||
ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
|
||||
trace_rdev_suspend(&rdev->wiphy, wowlan);
|
||||
ret = rdev->ops->suspend(&rdev->wiphy, wowlan);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
@ -887,4 +888,17 @@ static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int rdev_update_ft_ies(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_update_ft_ies_params *ftie)
|
||||
{
|
||||
int ret;
|
||||
|
||||
trace_rdev_update_ft_ies(&rdev->wiphy, dev, ftie);
|
||||
ret = rdev->ops->update_ft_ies(&rdev->wiphy, dev, ftie);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __CFG80211_RDEV_OPS */
|
||||
|
@ -184,14 +184,14 @@ static const struct ieee80211_regdomain world_regdom = {
|
||||
NL80211_RRF_NO_IBSS |
|
||||
NL80211_RRF_NO_OFDM),
|
||||
/* IEEE 802.11a, channel 36..48 */
|
||||
REG_RULE(5180-10, 5240+10, 40, 6, 20,
|
||||
REG_RULE(5180-10, 5240+10, 80, 6, 20,
|
||||
NL80211_RRF_PASSIVE_SCAN |
|
||||
NL80211_RRF_NO_IBSS),
|
||||
|
||||
/* NB: 5260 MHz - 5700 MHz requies DFS */
|
||||
/* NB: 5260 MHz - 5700 MHz requires DFS */
|
||||
|
||||
/* IEEE 802.11a, channel 149..165 */
|
||||
REG_RULE(5745-10, 5825+10, 40, 6, 20,
|
||||
REG_RULE(5745-10, 5825+10, 80, 6, 20,
|
||||
NL80211_RRF_PASSIVE_SCAN |
|
||||
NL80211_RRF_NO_IBSS),
|
||||
|
||||
|
@ -159,7 +159,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct cfg80211_connect_params *params;
|
||||
const u8 *prev_bssid = NULL;
|
||||
struct cfg80211_assoc_request req = {};
|
||||
int err;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
@ -186,16 +186,20 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
|
||||
BUG_ON(!rdev->ops->assoc);
|
||||
wdev->conn->state = CFG80211_CONN_ASSOCIATING;
|
||||
if (wdev->conn->prev_bssid_valid)
|
||||
prev_bssid = wdev->conn->prev_bssid;
|
||||
err = __cfg80211_mlme_assoc(rdev, wdev->netdev,
|
||||
params->channel, params->bssid,
|
||||
prev_bssid,
|
||||
params->ssid, params->ssid_len,
|
||||
params->ie, params->ie_len,
|
||||
params->mfp != NL80211_MFP_NO,
|
||||
¶ms->crypto,
|
||||
params->flags, ¶ms->ht_capa,
|
||||
¶ms->ht_capa_mask);
|
||||
req.prev_bssid = wdev->conn->prev_bssid;
|
||||
req.ie = params->ie;
|
||||
req.ie_len = params->ie_len;
|
||||
req.use_mfp = params->mfp != NL80211_MFP_NO;
|
||||
req.crypto = params->crypto;
|
||||
req.flags = params->flags;
|
||||
req.ht_capa = params->ht_capa;
|
||||
req.ht_capa_mask = params->ht_capa_mask;
|
||||
req.vht_capa = params->vht_capa;
|
||||
req.vht_capa_mask = params->vht_capa_mask;
|
||||
|
||||
err = __cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel,
|
||||
params->bssid, params->ssid,
|
||||
params->ssid_len, &req);
|
||||
if (err)
|
||||
__cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
|
||||
NULL, 0,
|
||||
|
@ -83,6 +83,14 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
struct wireless_dev *wdev;
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list)
|
||||
cfg80211_leave(rdev, wdev);
|
||||
}
|
||||
|
||||
static int wiphy_suspend(struct device *dev, pm_message_t state)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
|
||||
@ -90,12 +98,19 @@ static int wiphy_suspend(struct device *dev, pm_message_t state)
|
||||
|
||||
rdev->suspend_at = get_seconds();
|
||||
|
||||
if (rdev->ops->suspend) {
|
||||
rtnl_lock();
|
||||
if (rdev->wiphy.registered)
|
||||
ret = rdev_suspend(rdev);
|
||||
rtnl_unlock();
|
||||
rtnl_lock();
|
||||
if (rdev->wiphy.registered) {
|
||||
if (!rdev->wowlan)
|
||||
cfg80211_leave_all(rdev);
|
||||
if (rdev->ops->suspend)
|
||||
ret = rdev_suspend(rdev, rdev->wowlan);
|
||||
if (ret == 1) {
|
||||
/* Driver refuse to configure wowlan */
|
||||
cfg80211_leave_all(rdev);
|
||||
ret = rdev_suspend(rdev, NULL);
|
||||
}
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1785,6 +1785,26 @@ TRACE_EVENT(rdev_set_mac_acl,
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_update_ft_ies,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
struct cfg80211_update_ft_ies_params *ftie),
|
||||
TP_ARGS(wiphy, netdev, ftie),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
__field(u16, md)
|
||||
__dynamic_array(u8, ie, ftie->ie_len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
__entry->md = ftie->md;
|
||||
memcpy(__get_dynamic_array(ie), ftie->ie, ftie->ie_len);
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", md: 0x%x",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->md)
|
||||
);
|
||||
|
||||
/*************************************************************
|
||||
* cfg80211 exported functions traces *
|
||||
*************************************************************/
|
||||
@ -2413,6 +2433,32 @@ TRACE_EVENT(cfg80211_report_wowlan_wakeup,
|
||||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_ft_event,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
struct cfg80211_ft_event_params *ft_event),
|
||||
TP_ARGS(wiphy, netdev, ft_event),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
__dynamic_array(u8, ies, ft_event->ies_len)
|
||||
MAC_ENTRY(target_ap)
|
||||
__dynamic_array(u8, ric_ies, ft_event->ric_ies_len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
if (ft_event->ies)
|
||||
memcpy(__get_dynamic_array(ies), ft_event->ies,
|
||||
ft_event->ies_len);
|
||||
MAC_ASSIGN(target_ap, ft_event->target_ap);
|
||||
if (ft_event->ric_ies)
|
||||
memcpy(__get_dynamic_array(ric_ies), ft_event->ric_ies,
|
||||
ft_event->ric_ies_len);
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", target_ap: " MAC_PR_FMT,
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap))
|
||||
);
|
||||
|
||||
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
|
Loading…
Reference in New Issue
Block a user