You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Conflicts: net/wireless/reg.c
This commit is contained in:
@@ -152,8 +152,8 @@
|
||||
!Finclude/net/cfg80211.h cfg80211_scan_request
|
||||
!Finclude/net/cfg80211.h cfg80211_scan_done
|
||||
!Finclude/net/cfg80211.h cfg80211_bss
|
||||
!Finclude/net/cfg80211.h cfg80211_inform_bss_frame
|
||||
!Finclude/net/cfg80211.h cfg80211_inform_bss
|
||||
!Finclude/net/cfg80211.h cfg80211_inform_bss_width_frame
|
||||
!Finclude/net/cfg80211.h cfg80211_inform_bss_width
|
||||
!Finclude/net/cfg80211.h cfg80211_unlink_bss
|
||||
!Finclude/net/cfg80211.h cfg80211_find_ie
|
||||
!Finclude/net/cfg80211.h ieee80211_bss_get_ie
|
||||
|
||||
@@ -167,6 +167,7 @@ struct hwsim_vif_priv {
|
||||
u32 magic;
|
||||
u8 bssid[ETH_ALEN];
|
||||
bool assoc;
|
||||
bool bcn_en;
|
||||
u16 aid;
|
||||
};
|
||||
|
||||
@@ -1170,6 +1171,16 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
|
||||
*total_flags = data->rx_filter;
|
||||
}
|
||||
|
||||
static void mac80211_hwsim_bcn_en_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
unsigned int *count = data;
|
||||
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
|
||||
|
||||
if (vp->bcn_en)
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *info,
|
||||
@@ -1180,7 +1191,8 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
|
||||
|
||||
hwsim_check_magic(vif);
|
||||
|
||||
wiphy_debug(hw->wiphy, "%s(changed=0x%x)\n", __func__, changed);
|
||||
wiphy_debug(hw->wiphy, "%s(changed=0x%x vif->addr=%pM)\n",
|
||||
__func__, changed, vif->addr);
|
||||
|
||||
if (changed & BSS_CHANGED_BSSID) {
|
||||
wiphy_debug(hw->wiphy, "%s: BSSID changed: %pM\n",
|
||||
@@ -1202,6 +1214,7 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
||||
wiphy_debug(hw->wiphy, " BCN EN: %d\n", info->enable_beacon);
|
||||
vp->bcn_en = info->enable_beacon;
|
||||
if (data->started &&
|
||||
!hrtimer_is_queued(&data->beacon_timer.timer) &&
|
||||
info->enable_beacon) {
|
||||
@@ -1215,8 +1228,16 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
|
||||
tasklet_hrtimer_start(&data->beacon_timer,
|
||||
ns_to_ktime(until_tbtt * 1000),
|
||||
HRTIMER_MODE_REL);
|
||||
} else if (!info->enable_beacon)
|
||||
tasklet_hrtimer_cancel(&data->beacon_timer);
|
||||
} else if (!info->enable_beacon) {
|
||||
unsigned int count = 0;
|
||||
ieee80211_iterate_active_interfaces(
|
||||
data->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
mac80211_hwsim_bcn_en_iter, &count);
|
||||
wiphy_debug(hw->wiphy, " beaconing vifs remaining: %u",
|
||||
count);
|
||||
if (count == 0)
|
||||
tasklet_hrtimer_cancel(&data->beacon_timer);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
|
||||
|
||||
@@ -696,6 +696,18 @@ struct ieee80211_sec_chan_offs_ie {
|
||||
u8 sec_chan_offs;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ieee80211_mesh_chansw_params_ie - mesh channel switch parameters IE
|
||||
*
|
||||
* This structure represents the "Mesh Channel Switch Paramters element"
|
||||
*/
|
||||
struct ieee80211_mesh_chansw_params_ie {
|
||||
u8 mesh_ttl;
|
||||
u8 mesh_flags;
|
||||
__le16 mesh_reason;
|
||||
__le16 mesh_pre_value;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ieee80211_wide_bw_chansw_ie - wide bandwidth channel switch IE
|
||||
*/
|
||||
@@ -750,6 +762,14 @@ enum mesh_config_capab_flags {
|
||||
IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL = 0x40,
|
||||
};
|
||||
|
||||
/**
|
||||
* mesh channel switch parameters element's flag indicator
|
||||
*
|
||||
*/
|
||||
#define WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT BIT(0)
|
||||
#define WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR BIT(1)
|
||||
#define WLAN_EID_CHAN_SWITCH_PARAM_REASON BIT(2)
|
||||
|
||||
/**
|
||||
* struct ieee80211_rann_ie
|
||||
*
|
||||
|
||||
@@ -744,6 +744,10 @@ enum station_parameters_apply_mask {
|
||||
* @capability: station capability
|
||||
* @ext_capab: extended capabilities of the station
|
||||
* @ext_capab_len: number of extended capabilities
|
||||
* @supported_channels: supported channels in IEEE 802.11 format
|
||||
* @supported_channels_len: number of supported channels
|
||||
* @supported_oper_classes: supported oper classes in IEEE 802.11 format
|
||||
* @supported_oper_classes_len: number of supported operating classes
|
||||
*/
|
||||
struct station_parameters {
|
||||
const u8 *supported_rates;
|
||||
@@ -763,6 +767,10 @@ struct station_parameters {
|
||||
u16 capability;
|
||||
const u8 *ext_capab;
|
||||
u8 ext_capab_len;
|
||||
const u8 *supported_channels;
|
||||
u8 supported_channels_len;
|
||||
const u8 *supported_oper_classes;
|
||||
u8 supported_oper_classes_len;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1656,6 +1664,9 @@ struct cfg80211_disassoc_request {
|
||||
* sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
|
||||
* required to assume that the port is unauthorized until authorized by
|
||||
* user space. Otherwise, port is marked authorized by default.
|
||||
* @userspace_handles_dfs: whether user space controls DFS operation, i.e.
|
||||
* changes the channel when a radar is detected. This is required
|
||||
* to operate on DFS channels.
|
||||
* @basic_rates: bitmap of basic rates to use when creating the IBSS
|
||||
* @mcast_rate: per-band multicast rate index + 1 (0: disabled)
|
||||
* @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask
|
||||
@@ -1673,6 +1684,7 @@ struct cfg80211_ibss_params {
|
||||
bool channel_fixed;
|
||||
bool privacy;
|
||||
bool control_port;
|
||||
bool userspace_handles_dfs;
|
||||
int mcast_rate[IEEE80211_NUM_BANDS];
|
||||
struct ieee80211_ht_cap ht_capa;
|
||||
struct ieee80211_ht_cap ht_capa_mask;
|
||||
@@ -3053,6 +3065,7 @@ struct cfg80211_cached_keys;
|
||||
* @conn: (private) cfg80211 software SME connection state machine data
|
||||
* @connect_keys: (private) keys to set after connection is established
|
||||
* @ibss_fixed: (private) IBSS is using fixed BSSID
|
||||
* @ibss_dfs_possible: (private) IBSS may change to a DFS channel
|
||||
* @event_list: (private) list for internal event processing
|
||||
* @event_lock: (private) lock for event list
|
||||
*/
|
||||
@@ -3091,6 +3104,7 @@ struct wireless_dev {
|
||||
struct ieee80211_channel *channel;
|
||||
|
||||
bool ibss_fixed;
|
||||
bool ibss_dfs_possible;
|
||||
|
||||
bool ps;
|
||||
int ps_timeout;
|
||||
|
||||
@@ -1503,6 +1503,10 @@ struct ieee80211_tx_control {
|
||||
* @IEEE80211_HW_TIMING_BEACON_ONLY: Use sync timing from beacon frames
|
||||
* only, to allow getting TBTT of a DTIM beacon.
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORTS_HT_CCK_RATES: Hardware supports mixing HT/CCK rates
|
||||
* and can cope with CCK rates in an aggregation session (e.g. by not
|
||||
* using aggregation for such frames.)
|
||||
*
|
||||
* @IEEE80211_HW_CHANCTX_STA_CSA: Support 802.11h based channel-switch (CSA)
|
||||
* for a single active channel while using channel contexts. When support
|
||||
* is not enabled the default action is to disconnect when getting the
|
||||
@@ -4567,4 +4571,18 @@ void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
|
||||
struct cfg80211_wowlan_wakeup *wakeup,
|
||||
gfp_t gfp);
|
||||
|
||||
/**
|
||||
* ieee80211_tx_prepare_skb - prepare an 802.11 skb for transmission
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
* @vif: virtual interface
|
||||
* @skb: frame to be sent from within the driver
|
||||
* @band: the band to transmit on
|
||||
* @sta: optional pointer to get the station to send the frame to
|
||||
*
|
||||
* Note: must be called under RCU lock
|
||||
*/
|
||||
bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, struct sk_buff *skb,
|
||||
int band, struct ieee80211_sta **sta);
|
||||
|
||||
#endif /* MAC80211_H */
|
||||
|
||||
@@ -988,7 +988,7 @@ enum nl80211_commands {
|
||||
* to query the CRDA to retrieve one regulatory domain. This attribute can
|
||||
* also be used by userspace to query the kernel for the currently set
|
||||
* regulatory domain. We chose an alpha2 as that is also used by the
|
||||
* IEEE-802.11d country information element to identify a country.
|
||||
* IEEE-802.11 country information element to identify a country.
|
||||
* Users can also simply ask the wireless core to set regulatory domain
|
||||
* to a specific alpha2.
|
||||
* @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
|
||||
@@ -1496,6 +1496,18 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32.
|
||||
* As specified in the &enum nl80211_rxmgmt_flags.
|
||||
*
|
||||
* @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels.
|
||||
*
|
||||
* @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported
|
||||
* supported operating classes.
|
||||
*
|
||||
* @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space
|
||||
* controls DFS operation in IBSS mode. If the flag is included in
|
||||
* %NL80211_CMD_JOIN_IBSS request, the driver will allow use of DFS
|
||||
* channels and reports radar events to userspace. Userspace is required
|
||||
* to react to radar events, e.g. initiate a channel switch or leave the
|
||||
* IBSS network.
|
||||
*
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
@@ -1806,6 +1818,12 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_RXMGMT_FLAGS,
|
||||
|
||||
NL80211_ATTR_STA_SUPPORTED_CHANNELS,
|
||||
|
||||
NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
|
||||
|
||||
NL80211_ATTR_HANDLE_DFS,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@@ -3860,13 +3878,12 @@ enum nl80211_radar_event {
|
||||
*
|
||||
* Channel states used by the DFS code.
|
||||
*
|
||||
* @IEEE80211_DFS_USABLE: The channel can be used, but channel availability
|
||||
* @NL80211_DFS_USABLE: The channel can be used, but channel availability
|
||||
* check (CAC) must be performed before using it for AP or IBSS.
|
||||
* @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
|
||||
* @NL80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
|
||||
* is therefore marked as not available.
|
||||
* @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
|
||||
* @NL80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
|
||||
*/
|
||||
|
||||
enum nl80211_dfs_state {
|
||||
NL80211_DFS_USABLE,
|
||||
NL80211_DFS_UNAVAILABLE,
|
||||
|
||||
@@ -4,6 +4,7 @@ config MAC80211
|
||||
select CRYPTO
|
||||
select CRYPTO_ARC4
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_CCM
|
||||
select CRC32
|
||||
select AVERAGE
|
||||
---help---
|
||||
@@ -258,6 +259,17 @@ config MAC80211_MESH_SYNC_DEBUG
|
||||
|
||||
Do not select this option.
|
||||
|
||||
config MAC80211_MESH_CSA_DEBUG
|
||||
bool "Verbose mesh channel switch debugging"
|
||||
depends on MAC80211_DEBUG_MENU
|
||||
depends on MAC80211_MESH
|
||||
---help---
|
||||
Selecting this option causes mac80211 to print out very verbose mesh
|
||||
channel switch debugging messages (when mac80211 is taking part in a
|
||||
mesh network).
|
||||
|
||||
Do not select this option.
|
||||
|
||||
config MAC80211_MESH_PS_DEBUG
|
||||
bool "Verbose mesh powersave debugging"
|
||||
depends on MAC80211_DEBUG_MENU
|
||||
|
||||
+52
-109
@@ -2,6 +2,8 @@
|
||||
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
*
|
||||
* Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
@@ -17,134 +19,75 @@
|
||||
#include "key.h"
|
||||
#include "aes_ccm.h"
|
||||
|
||||
static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a)
|
||||
void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
int i;
|
||||
u8 *b_0, *aad, *b, *s_0;
|
||||
struct scatterlist assoc, pt, ct[2];
|
||||
struct {
|
||||
struct aead_request req;
|
||||
u8 priv[crypto_aead_reqsize(tfm)];
|
||||
} aead_req;
|
||||
|
||||
b_0 = scratch + 3 * AES_BLOCK_SIZE;
|
||||
aad = scratch + 4 * AES_BLOCK_SIZE;
|
||||
b = scratch;
|
||||
s_0 = scratch + AES_BLOCK_SIZE;
|
||||
memset(&aead_req, 0, sizeof(aead_req));
|
||||
|
||||
crypto_cipher_encrypt_one(tfm, b, b_0);
|
||||
sg_init_one(&pt, data, data_len);
|
||||
sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
|
||||
sg_init_table(ct, 2);
|
||||
sg_set_buf(&ct[0], data, data_len);
|
||||
sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN);
|
||||
|
||||
/* Extra Authenticate-only data (always two AES blocks) */
|
||||
for (i = 0; i < AES_BLOCK_SIZE; i++)
|
||||
aad[i] ^= b[i];
|
||||
crypto_cipher_encrypt_one(tfm, b, aad);
|
||||
aead_request_set_tfm(&aead_req.req, tfm);
|
||||
aead_request_set_assoc(&aead_req.req, &assoc, assoc.length);
|
||||
aead_request_set_crypt(&aead_req.req, &pt, ct, data_len, b_0);
|
||||
|
||||
aad += AES_BLOCK_SIZE;
|
||||
|
||||
for (i = 0; i < AES_BLOCK_SIZE; i++)
|
||||
aad[i] ^= b[i];
|
||||
crypto_cipher_encrypt_one(tfm, a, aad);
|
||||
|
||||
/* Mask out bits from auth-only-b_0 */
|
||||
b_0[0] &= 0x07;
|
||||
|
||||
/* S_0 is used to encrypt T (= MIC) */
|
||||
b_0[14] = 0;
|
||||
b_0[15] = 0;
|
||||
crypto_cipher_encrypt_one(tfm, s_0, b_0);
|
||||
crypto_aead_encrypt(&aead_req.req);
|
||||
}
|
||||
|
||||
|
||||
void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *data, size_t data_len,
|
||||
u8 *cdata, u8 *mic)
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
int i, j, last_len, num_blocks;
|
||||
u8 *pos, *cpos, *b, *s_0, *e, *b_0;
|
||||
struct scatterlist assoc, pt, ct[2];
|
||||
struct {
|
||||
struct aead_request req;
|
||||
u8 priv[crypto_aead_reqsize(tfm)];
|
||||
} aead_req;
|
||||
|
||||
b = scratch;
|
||||
s_0 = scratch + AES_BLOCK_SIZE;
|
||||
e = scratch + 2 * AES_BLOCK_SIZE;
|
||||
b_0 = scratch + 3 * AES_BLOCK_SIZE;
|
||||
memset(&aead_req, 0, sizeof(aead_req));
|
||||
|
||||
num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
|
||||
last_len = data_len % AES_BLOCK_SIZE;
|
||||
aes_ccm_prepare(tfm, scratch, b);
|
||||
sg_init_one(&pt, data, data_len);
|
||||
sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
|
||||
sg_init_table(ct, 2);
|
||||
sg_set_buf(&ct[0], data, data_len);
|
||||
sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN);
|
||||
|
||||
/* Process payload blocks */
|
||||
pos = data;
|
||||
cpos = cdata;
|
||||
for (j = 1; j <= num_blocks; j++) {
|
||||
int blen = (j == num_blocks && last_len) ?
|
||||
last_len : AES_BLOCK_SIZE;
|
||||
aead_request_set_tfm(&aead_req.req, tfm);
|
||||
aead_request_set_assoc(&aead_req.req, &assoc, assoc.length);
|
||||
aead_request_set_crypt(&aead_req.req, ct, &pt,
|
||||
data_len + IEEE80211_CCMP_MIC_LEN, b_0);
|
||||
|
||||
/* Authentication followed by encryption */
|
||||
for (i = 0; i < blen; i++)
|
||||
b[i] ^= pos[i];
|
||||
crypto_cipher_encrypt_one(tfm, b, b);
|
||||
|
||||
b_0[14] = (j >> 8) & 0xff;
|
||||
b_0[15] = j & 0xff;
|
||||
crypto_cipher_encrypt_one(tfm, e, b_0);
|
||||
for (i = 0; i < blen; i++)
|
||||
*cpos++ = *pos++ ^ e[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++)
|
||||
mic[i] = b[i] ^ s_0[i];
|
||||
return crypto_aead_decrypt(&aead_req.req);
|
||||
}
|
||||
|
||||
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *cdata, size_t data_len, u8 *mic, u8 *data)
|
||||
struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[])
|
||||
{
|
||||
int i, j, last_len, num_blocks;
|
||||
u8 *pos, *cpos, *b, *s_0, *a, *b_0;
|
||||
struct crypto_aead *tfm;
|
||||
int err;
|
||||
|
||||
b = scratch;
|
||||
s_0 = scratch + AES_BLOCK_SIZE;
|
||||
a = scratch + 2 * AES_BLOCK_SIZE;
|
||||
b_0 = scratch + 3 * AES_BLOCK_SIZE;
|
||||
tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm))
|
||||
return tfm;
|
||||
|
||||
num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
|
||||
last_len = data_len % AES_BLOCK_SIZE;
|
||||
aes_ccm_prepare(tfm, scratch, a);
|
||||
err = crypto_aead_setkey(tfm, key, WLAN_KEY_LEN_CCMP);
|
||||
if (!err)
|
||||
err = crypto_aead_setauthsize(tfm, IEEE80211_CCMP_MIC_LEN);
|
||||
if (!err)
|
||||
return tfm;
|
||||
|
||||
/* Process payload blocks */
|
||||
cpos = cdata;
|
||||
pos = data;
|
||||
for (j = 1; j <= num_blocks; j++) {
|
||||
int blen = (j == num_blocks && last_len) ?
|
||||
last_len : AES_BLOCK_SIZE;
|
||||
|
||||
/* Decryption followed by authentication */
|
||||
b_0[14] = (j >> 8) & 0xff;
|
||||
b_0[15] = j & 0xff;
|
||||
crypto_cipher_encrypt_one(tfm, b, b_0);
|
||||
for (i = 0; i < blen; i++) {
|
||||
*pos = *cpos++ ^ b[i];
|
||||
a[i] ^= *pos++;
|
||||
}
|
||||
crypto_cipher_encrypt_one(tfm, a, a);
|
||||
}
|
||||
|
||||
for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++) {
|
||||
if ((mic[i] ^ s_0[i]) != a[i])
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
crypto_free_aead(tfm);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
|
||||
struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[])
|
||||
void ieee80211_aes_key_free(struct crypto_aead *tfm)
|
||||
{
|
||||
struct crypto_cipher *tfm;
|
||||
|
||||
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
|
||||
if (!IS_ERR(tfm))
|
||||
crypto_cipher_setkey(tfm, key, WLAN_KEY_LEN_CCMP);
|
||||
|
||||
return tfm;
|
||||
}
|
||||
|
||||
|
||||
void ieee80211_aes_key_free(struct crypto_cipher *tfm)
|
||||
{
|
||||
crypto_free_cipher(tfm);
|
||||
crypto_free_aead(tfm);
|
||||
}
|
||||
|
||||
@@ -12,13 +12,11 @@
|
||||
|
||||
#include <linux/crypto.h>
|
||||
|
||||
struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]);
|
||||
void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *data, size_t data_len,
|
||||
u8 *cdata, u8 *mic);
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
u8 *cdata, size_t data_len,
|
||||
u8 *mic, u8 *data);
|
||||
void ieee80211_aes_key_free(struct crypto_cipher *tfm);
|
||||
struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]);
|
||||
void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic);
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic);
|
||||
void ieee80211_aes_key_free(struct crypto_aead *tfm);
|
||||
|
||||
#endif /* AES_CCM_H */
|
||||
|
||||
+136
-6
@@ -1059,6 +1059,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
||||
/* abort any running channel switch */
|
||||
sdata->vif.csa_active = false;
|
||||
cancel_work_sync(&sdata->csa_finalize_work);
|
||||
cancel_work_sync(&sdata->u.ap.request_smps_work);
|
||||
|
||||
/* turn off carrier for this interface and dependent VLANs */
|
||||
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
||||
@@ -1342,8 +1343,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
||||
sta->plink_state = params->plink_state;
|
||||
|
||||
ieee80211_mps_sta_status_update(sta);
|
||||
changed |=
|
||||
ieee80211_mps_local_status_update(sdata);
|
||||
changed |= ieee80211_mps_set_sta_local_pm(sta,
|
||||
NL80211_MESH_POWER_UNKNOWN);
|
||||
break;
|
||||
default:
|
||||
/* nothing */
|
||||
@@ -1553,6 +1554,20 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
||||
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
|
||||
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
|
||||
sta->known_smps_mode != sta->sdata->bss->req_smps &&
|
||||
test_sta_flag(sta, WLAN_STA_AUTHORIZED) &&
|
||||
sta_info_tx_streams(sta) != 1) {
|
||||
ht_dbg(sta->sdata,
|
||||
"%pM just authorized and MIMO capable - update SMPS\n",
|
||||
sta->sta.addr);
|
||||
ieee80211_send_smps_action(sta->sdata,
|
||||
sta->sdata->bss->req_smps,
|
||||
sta->sta.addr,
|
||||
sta->sdata->vif.bss_conf.bssid);
|
||||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
@@ -2337,8 +2352,92 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy,
|
||||
}
|
||||
#endif
|
||||
|
||||
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps_mode)
|
||||
int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps_mode)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
enum ieee80211_smps_mode old_req;
|
||||
int i;
|
||||
|
||||
if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP))
|
||||
return -EINVAL;
|
||||
|
||||
if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
|
||||
return 0;
|
||||
|
||||
old_req = sdata->u.ap.req_smps;
|
||||
sdata->u.ap.req_smps = smps_mode;
|
||||
|
||||
/* AUTOMATIC doesn't mean much for AP - don't allow it */
|
||||
if (old_req == smps_mode ||
|
||||
smps_mode == IEEE80211_SMPS_AUTOMATIC)
|
||||
return 0;
|
||||
|
||||
/* If no associated stations, there's no need to do anything */
|
||||
if (!atomic_read(&sdata->u.ap.num_mcast_sta)) {
|
||||
sdata->smps_mode = smps_mode;
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ht_dbg(sdata,
|
||||
"SMSP %d requested in AP mode, sending Action frame to %d stations\n",
|
||||
smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta));
|
||||
|
||||
mutex_lock(&sdata->local->sta_mtx);
|
||||
for (i = 0; i < STA_HASH_SIZE; i++) {
|
||||
for (sta = rcu_dereference_protected(sdata->local->sta_hash[i],
|
||||
lockdep_is_held(&sdata->local->sta_mtx));
|
||||
sta;
|
||||
sta = rcu_dereference_protected(sta->hnext,
|
||||
lockdep_is_held(&sdata->local->sta_mtx))) {
|
||||
/*
|
||||
* Only stations associated to our AP and
|
||||
* associated VLANs
|
||||
*/
|
||||
if (sta->sdata->bss != &sdata->u.ap)
|
||||
continue;
|
||||
|
||||
/* This station doesn't support MIMO - skip it */
|
||||
if (sta_info_tx_streams(sta) == 1)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Don't wake up a STA just to send the action frame
|
||||
* unless we are getting more restrictive.
|
||||
*/
|
||||
if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
|
||||
!ieee80211_smps_is_restrictive(sta->known_smps_mode,
|
||||
smps_mode)) {
|
||||
ht_dbg(sdata,
|
||||
"Won't send SMPS to sleeping STA %pM\n",
|
||||
sta->sta.addr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the STA is not authorized, wait until it gets
|
||||
* authorized and the action frame will be sent then.
|
||||
*/
|
||||
if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
|
||||
continue;
|
||||
|
||||
ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr);
|
||||
ieee80211_send_smps_action(sdata, smps_mode,
|
||||
sta->sta.addr,
|
||||
sdata->vif.bss_conf.bssid);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
|
||||
sdata->smps_mode = smps_mode;
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps_mode)
|
||||
{
|
||||
const u8 *ap;
|
||||
enum ieee80211_smps_mode old_req;
|
||||
@@ -2346,6 +2445,9 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
lockdep_assert_held(&sdata->wdev.mtx);
|
||||
|
||||
if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION))
|
||||
return -EINVAL;
|
||||
|
||||
old_req = sdata->u.mgd.req_smps;
|
||||
sdata->u.mgd.req_smps = smps_mode;
|
||||
|
||||
@@ -2402,7 +2504,7 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
/* no change, but if automatic follow powersave */
|
||||
sdata_lock(sdata);
|
||||
__ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
|
||||
__ieee80211_request_smps_mgd(sdata, sdata->u.mgd.req_smps);
|
||||
sdata_unlock(sdata);
|
||||
|
||||
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
|
||||
@@ -2860,7 +2962,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
|
||||
container_of(work, struct ieee80211_sub_if_data,
|
||||
csa_finalize_work);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int err, changed;
|
||||
int err, changed = 0;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return;
|
||||
@@ -2892,6 +2994,13 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ieee80211_ibss_finish_csa(sdata);
|
||||
break;
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
err = ieee80211_mesh_finish_csa(sdata);
|
||||
if (err < 0)
|
||||
return;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return;
|
||||
@@ -2912,6 +3021,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_chanctx *chanctx;
|
||||
struct ieee80211_if_mesh __maybe_unused *ifmsh;
|
||||
int err, num_chanctx;
|
||||
|
||||
if (!list_empty(&local->roc_list) || local->scanning)
|
||||
@@ -2995,6 +3105,26 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||
if (err < 0)
|
||||
return err;
|
||||
break;
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
ifmsh = &sdata->u.mesh;
|
||||
|
||||
if (!ifmsh->mesh_id)
|
||||
return -EINVAL;
|
||||
|
||||
if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
|
||||
return -EINVAL;
|
||||
|
||||
/* changes into another band are not supported */
|
||||
if (sdata->vif.bss_conf.chandef.chan->band !=
|
||||
params->chandef.chan->band)
|
||||
return -EINVAL;
|
||||
|
||||
err = ieee80211_mesh_csa_beacon(sdata, params, true);
|
||||
if (err < 0)
|
||||
return err;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@
|
||||
#define MAC80211_MESH_SYNC_DEBUG 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH_CSA_DEBUG
|
||||
#define MAC80211_MESH_CSA_DEBUG 1
|
||||
#else
|
||||
#define MAC80211_MESH_CSA_DEBUG 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH_PS_DEBUG
|
||||
#define MAC80211_MESH_PS_DEBUG 1
|
||||
#else
|
||||
@@ -157,6 +163,10 @@ do { \
|
||||
_sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \
|
||||
sdata, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define mcsa_dbg(sdata, fmt, ...) \
|
||||
_sdata_dbg(MAC80211_MESH_CSA_DEBUG, \
|
||||
sdata, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define mps_dbg(sdata, fmt, ...) \
|
||||
_sdata_dbg(MAC80211_MESH_PS_DEBUG, \
|
||||
sdata, fmt, ##__VA_ARGS__)
|
||||
|
||||
@@ -224,12 +224,15 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
|
||||
smps_mode == IEEE80211_SMPS_AUTOMATIC))
|
||||
return -EINVAL;
|
||||
|
||||
/* supported only on managed interfaces for now */
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sdata_lock(sdata);
|
||||
err = __ieee80211_request_smps(sdata, smps_mode);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
err = __ieee80211_request_smps_mgd(sdata, smps_mode);
|
||||
else
|
||||
err = __ieee80211_request_smps_ap(sdata, smps_mode);
|
||||
sdata_unlock(sdata);
|
||||
|
||||
return err;
|
||||
@@ -245,12 +248,15 @@ static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
|
||||
static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
|
||||
char *buf, int buflen)
|
||||
{
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return snprintf(buf, buflen, "request: %s\nused: %s\n",
|
||||
smps_modes[sdata->u.mgd.req_smps],
|
||||
smps_modes[sdata->smps_mode]);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
return snprintf(buf, buflen, "request: %s\nused: %s\n",
|
||||
smps_modes[sdata->u.mgd.req_smps],
|
||||
smps_modes[sdata->smps_mode]);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
return snprintf(buf, buflen, "request: %s\nused: %s\n",
|
||||
smps_modes[sdata->u.ap.req_smps],
|
||||
smps_modes[sdata->smps_mode]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
|
||||
@@ -563,6 +569,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
|
||||
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(num_mcast_sta);
|
||||
DEBUGFS_ADD_MODE(smps, 0600);
|
||||
DEBUGFS_ADD(num_sta_ps);
|
||||
DEBUGFS_ADD(dtim_count);
|
||||
DEBUGFS_ADD(num_buffered_multicast);
|
||||
|
||||
+31
-10
@@ -448,14 +448,25 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_request_smps_work(struct work_struct *work)
|
||||
void ieee80211_request_smps_mgd_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
container_of(work, struct ieee80211_sub_if_data,
|
||||
u.mgd.request_smps_work);
|
||||
|
||||
sdata_lock(sdata);
|
||||
__ieee80211_request_smps(sdata, sdata->u.mgd.driver_smps_mode);
|
||||
__ieee80211_request_smps_mgd(sdata, sdata->u.mgd.driver_smps_mode);
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
|
||||
void ieee80211_request_smps_ap_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
container_of(work, struct ieee80211_sub_if_data,
|
||||
u.ap.request_smps_work);
|
||||
|
||||
sdata_lock(sdata);
|
||||
__ieee80211_request_smps_ap(sdata, sdata->u.ap.driver_smps_mode);
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
|
||||
@@ -464,19 +475,29 @@ void ieee80211_request_smps(struct ieee80211_vif *vif,
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
|
||||
if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
|
||||
if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION &&
|
||||
vif->type != NL80211_IFTYPE_AP))
|
||||
return;
|
||||
|
||||
if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
|
||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||
|
||||
if (sdata->u.mgd.driver_smps_mode == smps_mode)
|
||||
return;
|
||||
|
||||
sdata->u.mgd.driver_smps_mode = smps_mode;
|
||||
|
||||
ieee80211_queue_work(&sdata->local->hw,
|
||||
&sdata->u.mgd.request_smps_work);
|
||||
if (vif->type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->u.mgd.driver_smps_mode == smps_mode)
|
||||
return;
|
||||
sdata->u.mgd.driver_smps_mode = smps_mode;
|
||||
ieee80211_queue_work(&sdata->local->hw,
|
||||
&sdata->u.mgd.request_smps_work);
|
||||
} else {
|
||||
/* AUTOMATIC is meaningless in AP mode */
|
||||
if (WARN_ON_ONCE(smps_mode == IEEE80211_SMPS_AUTOMATIC))
|
||||
return;
|
||||
if (sdata->u.ap.driver_smps_mode == smps_mode)
|
||||
return;
|
||||
sdata->u.ap.driver_smps_mode = smps_mode;
|
||||
ieee80211_queue_work(&sdata->local->hw,
|
||||
&sdata->u.ap.request_smps_work);
|
||||
}
|
||||
}
|
||||
/* this might change ... don't want non-open drivers using it */
|
||||
EXPORT_SYMBOL_GPL(ieee80211_request_smps);
|
||||
|
||||
+51
-65
@@ -229,6 +229,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
struct beacon_data *presp;
|
||||
enum nl80211_bss_scan_width scan_width;
|
||||
bool have_higher_than_11mbit;
|
||||
bool radar_required = false;
|
||||
int err;
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
@@ -273,6 +274,23 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
chandef.width = NL80211_CHAN_WIDTH_20;
|
||||
chandef.center_freq1 = chan->center_freq;
|
||||
/* check again for downgraded chandef */
|
||||
if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
|
||||
sdata_info(sdata,
|
||||
"Failed to join IBSS, beacons forbidden\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
|
||||
&chandef);
|
||||
if (err > 0) {
|
||||
if (!ifibss->userspace_handles_dfs) {
|
||||
sdata_info(sdata,
|
||||
"Failed to join IBSS, DFS channel without control program\n");
|
||||
return;
|
||||
}
|
||||
radar_required = true;
|
||||
}
|
||||
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
@@ -297,6 +315,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
rcu_assign_pointer(ifibss->presp, presp);
|
||||
mgmt = (void *)presp->head;
|
||||
|
||||
sdata->radar_required = radar_required;
|
||||
sdata->vif.bss_conf.enable_beacon = true;
|
||||
sdata->vif.bss_conf.beacon_int = beacon_int;
|
||||
sdata->vif.bss_conf.basic_rates = basic_rates;
|
||||
@@ -445,60 +464,6 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
tsf, false);
|
||||
}
|
||||
|
||||
static int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_csa_settings *csa_settings)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int freq;
|
||||
int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) +
|
||||
sizeof(mgmt->u.action.u.chan_switch);
|
||||
u8 *pos;
|
||||
|
||||
skb = dev_alloc_skb(local->tx_headroom + hdr_len +
|
||||
5 + /* channel switch announcement element */
|
||||
3); /* secondary channel offset element */
|
||||
if (!skb)
|
||||
return -1;
|
||||
|
||||
skb_reserve(skb, local->tx_headroom);
|
||||
mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len);
|
||||
memset(mgmt, 0, hdr_len);
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
||||
eth_broadcast_addr(mgmt->da);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
|
||||
mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
|
||||
mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
|
||||
pos = skb_put(skb, 5);
|
||||
*pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */
|
||||
*pos++ = 3; /* IE length */
|
||||
*pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */
|
||||
freq = csa_settings->chandef.chan->center_freq;
|
||||
*pos++ = ieee80211_frequency_to_channel(freq); /* channel */
|
||||
*pos++ = csa_settings->count; /* count */
|
||||
|
||||
if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) {
|
||||
enum nl80211_channel_type ch_type;
|
||||
|
||||
skb_put(skb, 3);
|
||||
*pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */
|
||||
*pos++ = 1; /* IE length */
|
||||
ch_type = cfg80211_get_chandef_type(&csa_settings->chandef);
|
||||
if (ch_type == NL80211_CHAN_HT40PLUS)
|
||||
*pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
|
||||
else
|
||||
*pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
|
||||
}
|
||||
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_csa_settings *csa_settings)
|
||||
{
|
||||
@@ -796,19 +761,34 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work)
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||
}
|
||||
|
||||
static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
int err;
|
||||
|
||||
/* if the current channel is a DFS channel, mark the channel as
|
||||
* unavailable.
|
||||
*/
|
||||
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
|
||||
&ifibss->chandef);
|
||||
if (err > 0)
|
||||
cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef,
|
||||
GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static bool
|
||||
ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee802_11_elems *elems,
|
||||
bool beacon)
|
||||
{
|
||||
struct cfg80211_csa_settings params;
|
||||
struct ieee80211_csa_ie csa_ie;
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_chanctx *chanctx;
|
||||
enum nl80211_channel_type ch_type;
|
||||
int err, num_chanctx;
|
||||
u32 sta_flags;
|
||||
u8 mode;
|
||||
|
||||
if (sdata->vif.csa_active)
|
||||
return true;
|
||||
@@ -831,12 +811,10 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
memset(&csa_ie, 0, sizeof(csa_ie));
|
||||
err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
|
||||
ifibss->chandef.chan->band,
|
||||
sta_flags, ifibss->bssid,
|
||||
¶ms.count, &mode,
|
||||
¶ms.chandef);
|
||||
|
||||
sta_flags, ifibss->bssid, &csa_ie);
|
||||
/* can't switch to destination channel, fail */
|
||||
if (err < 0)
|
||||
goto disconnect;
|
||||
@@ -845,6 +823,9 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
params.count = csa_ie.count;
|
||||
params.chandef = csa_ie.chandef;
|
||||
|
||||
if (ifibss->chandef.chan->band != params.chandef.chan->band)
|
||||
goto disconnect;
|
||||
|
||||
@@ -880,8 +861,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
||||
goto disconnect;
|
||||
}
|
||||
|
||||
if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef,
|
||||
IEEE80211_CHAN_DISABLED)) {
|
||||
if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.chandef)) {
|
||||
sdata_info(sdata,
|
||||
"IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
|
||||
ifibss->bssid,
|
||||
@@ -897,10 +877,11 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
||||
if (err < 0)
|
||||
goto disconnect;
|
||||
if (err) {
|
||||
params.radar_required = true;
|
||||
/* IBSS-DFS only allowed with a control program */
|
||||
if (!ifibss->userspace_handles_dfs)
|
||||
goto disconnect;
|
||||
|
||||
/* TODO: IBSS-DFS not (yet) supported, disconnect. */
|
||||
goto disconnect;
|
||||
params.radar_required = true;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
@@ -931,7 +912,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
||||
"received channel switch announcement to go to channel %d MHz\n",
|
||||
params.chandef.chan->center_freq);
|
||||
|
||||
params.block_tx = !!mode;
|
||||
params.block_tx = !!csa_ie.mode;
|
||||
|
||||
ieee80211_ibss_csa_beacon(sdata, ¶ms);
|
||||
sdata->csa_radar_required = params.radar_required;
|
||||
@@ -947,12 +928,16 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_bss_info_change_notify(sdata, err);
|
||||
drv_channel_switch_beacon(sdata, ¶ms.chandef);
|
||||
|
||||
ieee80211_ibss_csa_mark_radar(sdata);
|
||||
|
||||
return true;
|
||||
disconnect:
|
||||
ibss_dbg(sdata, "Can't handle channel switch, disconnect\n");
|
||||
ieee80211_queue_work(&sdata->local->hw,
|
||||
&ifibss->csa_connection_drop_work);
|
||||
|
||||
ieee80211_ibss_csa_mark_radar(sdata);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1688,6 +1673,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
sdata->u.ibss.privacy = params->privacy;
|
||||
sdata->u.ibss.control_port = params->control_port;
|
||||
sdata->u.ibss.userspace_handles_dfs = params->userspace_handles_dfs;
|
||||
sdata->u.ibss.basic_rates = params->basic_rates;
|
||||
|
||||
/* fix basic_rates if channel does not support these rates */
|
||||
|
||||
@@ -262,6 +262,10 @@ struct ieee80211_if_ap {
|
||||
|
||||
struct ps_data ps;
|
||||
atomic_t num_mcast_sta; /* number of stations receiving multicast */
|
||||
enum ieee80211_smps_mode req_smps, /* requested smps mode */
|
||||
driver_smps_mode; /* smps mode request */
|
||||
|
||||
struct work_struct request_smps_work;
|
||||
};
|
||||
|
||||
struct ieee80211_if_wds {
|
||||
@@ -498,6 +502,7 @@ struct ieee80211_if_ibss {
|
||||
bool privacy;
|
||||
|
||||
bool control_port;
|
||||
bool userspace_handles_dfs;
|
||||
|
||||
u8 bssid[ETH_ALEN] __aligned(2);
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
@@ -539,6 +544,11 @@ struct ieee80211_mesh_sync_ops {
|
||||
/* add other framework functions here */
|
||||
};
|
||||
|
||||
struct mesh_csa_settings {
|
||||
struct rcu_head rcu_head;
|
||||
struct cfg80211_csa_settings settings;
|
||||
};
|
||||
|
||||
struct ieee80211_if_mesh {
|
||||
struct timer_list housekeeping_timer;
|
||||
struct timer_list mesh_path_timer;
|
||||
@@ -599,6 +609,11 @@ struct ieee80211_if_mesh {
|
||||
int ps_peers_light_sleep;
|
||||
int ps_peers_deep_sleep;
|
||||
struct ps_data ps;
|
||||
/* Channel Switching Support */
|
||||
struct mesh_csa_settings __rcu *csa;
|
||||
bool chsw_init;
|
||||
u8 chsw_ttl;
|
||||
u16 pre_value;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
@@ -1207,6 +1222,14 @@ struct ieee80211_ra_tid {
|
||||
u16 tid;
|
||||
};
|
||||
|
||||
/* this struct holds the value parsing from channel switch IE */
|
||||
struct ieee80211_csa_ie {
|
||||
struct cfg80211_chan_def chandef;
|
||||
u8 mode;
|
||||
u8 count;
|
||||
u8 ttl;
|
||||
};
|
||||
|
||||
/* Parsed Information Elements */
|
||||
struct ieee802_11_elems {
|
||||
const u8 *ie_start;
|
||||
@@ -1243,6 +1266,7 @@ struct ieee802_11_elems {
|
||||
const struct ieee80211_timeout_interval_ie *timeout_int;
|
||||
const u8 *opmode_notif;
|
||||
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
|
||||
const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
|
||||
|
||||
/* length of them, respectively */
|
||||
u8 ssid_len;
|
||||
@@ -1343,6 +1367,10 @@ void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_csa_settings *csa_settings,
|
||||
bool csa_action);
|
||||
int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
/* scan/BSS handling */
|
||||
void ieee80211_scan_work(struct work_struct *work);
|
||||
@@ -1439,7 +1467,10 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps, const u8 *da,
|
||||
const u8 *bssid);
|
||||
void ieee80211_request_smps_work(struct work_struct *work);
|
||||
void ieee80211_request_smps_ap_work(struct work_struct *work);
|
||||
void ieee80211_request_smps_mgd_work(struct work_struct *work);
|
||||
bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
|
||||
enum ieee80211_smps_mode smps_mode_new);
|
||||
|
||||
void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
u16 initiator, u16 reason, bool stop);
|
||||
@@ -1501,17 +1532,16 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
|
||||
* %IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT,
|
||||
* %IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ,
|
||||
* %IEEE80211_STA_DISABLE_160MHZ.
|
||||
* @count: to be filled with the counter until the switch (on success only)
|
||||
* @bssid: the currently connected bssid (for reporting)
|
||||
* @mode: to be filled with CSA mode (on success only)
|
||||
* @new_chandef: to be filled with destination chandef (on success only)
|
||||
* @csa_ie: parsed 802.11 csa elements on count, mode, chandef and mesh ttl.
|
||||
All of them will be filled with if success only.
|
||||
* Return: 0 on success, <0 on error and >0 if there is nothing to parse.
|
||||
*/
|
||||
int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee802_11_elems *elems, bool beacon,
|
||||
enum ieee80211_band current_band,
|
||||
u32 sta_flags, u8 *bssid, u8 *count, u8 *mode,
|
||||
struct cfg80211_chan_def *new_chandef);
|
||||
u32 sta_flags, u8 *bssid,
|
||||
struct ieee80211_csa_ie *csa_ie);
|
||||
|
||||
/* Suspend/resume and hw reconfiguration */
|
||||
int ieee80211_reconfig(struct ieee80211_local *local);
|
||||
@@ -1657,8 +1687,10 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
||||
u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee802_11_elems *elems,
|
||||
enum ieee80211_band band, u32 *basic_rates);
|
||||
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps_mode);
|
||||
int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps_mode);
|
||||
int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps_mode);
|
||||
void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
|
||||
@@ -1714,6 +1746,8 @@ void ieee80211_dfs_cac_timer(unsigned long data);
|
||||
void ieee80211_dfs_cac_timer_work(struct work_struct *work);
|
||||
void ieee80211_dfs_cac_cancel(struct ieee80211_local *local);
|
||||
void ieee80211_dfs_radar_detected_work(struct work_struct *work);
|
||||
int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_csa_settings *csa_settings);
|
||||
|
||||
#ifdef CONFIG_MAC80211_NOINLINE
|
||||
#define debug_noinline noinline
|
||||
|
||||
@@ -1293,7 +1293,10 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
|
||||
case NL80211_IFTYPE_AP:
|
||||
skb_queue_head_init(&sdata->u.ap.ps.bc_buf);
|
||||
INIT_LIST_HEAD(&sdata->u.ap.vlans);
|
||||
INIT_WORK(&sdata->u.ap.request_smps_work,
|
||||
ieee80211_request_smps_ap_work);
|
||||
sdata->vif.bss_conf.bssid = sdata->vif.addr;
|
||||
sdata->u.ap.req_smps = IEEE80211_SMPS_OFF;
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
type = NL80211_IFTYPE_STATION;
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ struct ieee80211_key {
|
||||
* Management frames.
|
||||
*/
|
||||
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
|
||||
struct crypto_cipher *tfm;
|
||||
struct crypto_aead *tfm;
|
||||
u32 replays; /* dot11RSNAStatsCCMPReplays */
|
||||
} ccmp;
|
||||
struct {
|
||||
|
||||
+299
-3
@@ -12,6 +12,7 @@
|
||||
#include <asm/unaligned.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "mesh.h"
|
||||
#include "driver-ops.h"
|
||||
|
||||
static int mesh_allocated;
|
||||
static struct kmem_cache *rm_cache;
|
||||
@@ -610,6 +611,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct mesh_csa_settings *csa;
|
||||
enum ieee80211_band band;
|
||||
u8 *pos;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
@@ -624,6 +626,10 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
|
||||
|
||||
head_len = hdr_len +
|
||||
2 + /* NULL SSID */
|
||||
/* Channel Switch Announcement */
|
||||
2 + sizeof(struct ieee80211_channel_sw_ie) +
|
||||
/* Mesh Channel Swith Parameters */
|
||||
2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
|
||||
2 + 8 + /* supported rates */
|
||||
2 + 3; /* DS params */
|
||||
tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
|
||||
@@ -665,6 +671,38 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
|
||||
*pos++ = WLAN_EID_SSID;
|
||||
*pos++ = 0x0;
|
||||
|
||||
rcu_read_lock();
|
||||
csa = rcu_dereference(ifmsh->csa);
|
||||
if (csa) {
|
||||
__le16 pre_value;
|
||||
|
||||
pos = skb_put(skb, 13);
|
||||
memset(pos, 0, 13);
|
||||
*pos++ = WLAN_EID_CHANNEL_SWITCH;
|
||||
*pos++ = 3;
|
||||
*pos++ = 0x0;
|
||||
*pos++ = ieee80211_frequency_to_channel(
|
||||
csa->settings.chandef.chan->center_freq);
|
||||
sdata->csa_counter_offset_beacon = hdr_len + 6;
|
||||
*pos++ = csa->settings.count;
|
||||
*pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
|
||||
*pos++ = 6;
|
||||
if (ifmsh->chsw_init) {
|
||||
*pos++ = ifmsh->mshcfg.dot11MeshTTL;
|
||||
*pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
|
||||
} else {
|
||||
*pos++ = ifmsh->chsw_ttl;
|
||||
}
|
||||
*pos++ |= csa->settings.block_tx ?
|
||||
WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
|
||||
put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
|
||||
pos += 2;
|
||||
pre_value = cpu_to_le16(ifmsh->pre_value);
|
||||
memcpy(pos, &pre_value, 2);
|
||||
pos += 2;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
|
||||
mesh_add_ds_params_ie(sdata, skb))
|
||||
goto out_free;
|
||||
@@ -812,6 +850,127 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
ieee80211_configure_filter(local);
|
||||
}
|
||||
|
||||
static bool
|
||||
ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee802_11_elems *elems, bool beacon)
|
||||
{
|
||||
struct cfg80211_csa_settings params;
|
||||
struct ieee80211_csa_ie csa_ie;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_chanctx *chanctx;
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
|
||||
int err, num_chanctx;
|
||||
u32 sta_flags;
|
||||
|
||||
if (sdata->vif.csa_active)
|
||||
return true;
|
||||
|
||||
if (!ifmsh->mesh_id)
|
||||
return false;
|
||||
|
||||
sta_flags = IEEE80211_STA_DISABLE_VHT;
|
||||
switch (sdata->vif.bss_conf.chandef.width) {
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
sta_flags |= IEEE80211_STA_DISABLE_HT;
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
memset(&csa_ie, 0, sizeof(csa_ie));
|
||||
err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, band,
|
||||
sta_flags, sdata->vif.addr,
|
||||
&csa_ie);
|
||||
if (err < 0)
|
||||
return false;
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
params.chandef = csa_ie.chandef;
|
||||
params.count = csa_ie.count;
|
||||
|
||||
if (sdata->vif.bss_conf.chandef.chan->band !=
|
||||
params.chandef.chan->band)
|
||||
return false;
|
||||
|
||||
if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef,
|
||||
IEEE80211_CHAN_DISABLED)) {
|
||||
sdata_info(sdata,
|
||||
"mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting\n",
|
||||
sdata->vif.addr,
|
||||
params.chandef.chan->center_freq,
|
||||
params.chandef.width,
|
||||
params.chandef.center_freq1,
|
||||
params.chandef.center_freq2);
|
||||
return false;
|
||||
}
|
||||
|
||||
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
|
||||
¶ms.chandef);
|
||||
if (err < 0)
|
||||
return false;
|
||||
if (err) {
|
||||
params.radar_required = true;
|
||||
/* TODO: DFS not (yet) supported */
|
||||
return false;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (!chanctx_conf)
|
||||
goto failed_chswitch;
|
||||
|
||||
/* don't handle for multi-VIF cases */
|
||||
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
|
||||
if (chanctx->refcount > 1)
|
||||
goto failed_chswitch;
|
||||
|
||||
num_chanctx = 0;
|
||||
list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
|
||||
num_chanctx++;
|
||||
|
||||
if (num_chanctx > 1)
|
||||
goto failed_chswitch;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
mcsa_dbg(sdata,
|
||||
"received channel switch announcement to go to channel %d MHz\n",
|
||||
params.chandef.chan->center_freq);
|
||||
|
||||
params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
|
||||
if (beacon)
|
||||
ifmsh->chsw_ttl = csa_ie.ttl - 1;
|
||||
else
|
||||
ifmsh->chsw_ttl = 0;
|
||||
|
||||
if (ifmsh->chsw_ttl > 0)
|
||||
if (ieee80211_mesh_csa_beacon(sdata, ¶ms, false) < 0)
|
||||
return false;
|
||||
|
||||
sdata->csa_radar_required = params.radar_required;
|
||||
|
||||
if (params.block_tx)
|
||||
ieee80211_stop_queues_by_reason(&sdata->local->hw,
|
||||
IEEE80211_MAX_QUEUE_MAP,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
|
||||
sdata->local->csa_chandef = params.chandef;
|
||||
sdata->vif.csa_active = true;
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, err);
|
||||
drv_channel_switch_beacon(sdata, ¶ms.chandef);
|
||||
|
||||
return true;
|
||||
failed_chswitch:
|
||||
rcu_read_unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len)
|
||||
@@ -918,6 +1077,142 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
if (ifmsh->sync_ops)
|
||||
ifmsh->sync_ops->rx_bcn_presp(sdata,
|
||||
stype, mgmt, &elems, rx_status);
|
||||
|
||||
if (!ifmsh->chsw_init)
|
||||
ieee80211_mesh_process_chnswitch(sdata, &elems, true);
|
||||
}
|
||||
|
||||
int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct mesh_csa_settings *tmp_csa_settings;
|
||||
int ret = 0;
|
||||
|
||||
/* Reset the TTL value and Initiator flag */
|
||||
ifmsh->chsw_init = false;
|
||||
ifmsh->chsw_ttl = 0;
|
||||
|
||||
/* Remove the CSA and MCSP elements from the beacon */
|
||||
tmp_csa_settings = rcu_dereference(ifmsh->csa);
|
||||
rcu_assign_pointer(ifmsh->csa, NULL);
|
||||
kfree_rcu(tmp_csa_settings, rcu_head);
|
||||
ret = ieee80211_mesh_rebuild_beacon(sdata);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
|
||||
|
||||
mcsa_dbg(sdata, "complete switching to center freq %d MHz",
|
||||
sdata->vif.bss_conf.chandef.chan->center_freq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_csa_settings *csa_settings,
|
||||
bool csa_action)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct mesh_csa_settings *tmp_csa_settings;
|
||||
int ret = 0;
|
||||
|
||||
tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
|
||||
GFP_ATOMIC);
|
||||
if (!tmp_csa_settings)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(&tmp_csa_settings->settings, csa_settings,
|
||||
sizeof(struct cfg80211_csa_settings));
|
||||
|
||||
rcu_assign_pointer(ifmsh->csa, tmp_csa_settings);
|
||||
|
||||
ret = ieee80211_mesh_rebuild_beacon(sdata);
|
||||
if (ret) {
|
||||
tmp_csa_settings = rcu_dereference(ifmsh->csa);
|
||||
rcu_assign_pointer(ifmsh->csa, NULL);
|
||||
kfree_rcu(tmp_csa_settings, rcu_head);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
|
||||
|
||||
if (csa_action)
|
||||
ieee80211_send_action_csa(sdata, csa_settings);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt_fwd;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
u8 *pos = mgmt->u.action.u.chan_switch.variable;
|
||||
size_t offset_ttl;
|
||||
|
||||
skb = dev_alloc_skb(local->tx_headroom + len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
skb_reserve(skb, local->tx_headroom);
|
||||
mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len);
|
||||
|
||||
/* offset_ttl is based on whether the secondary channel
|
||||
* offset is available or not. Substract 1 from the mesh TTL
|
||||
* and disable the initiator flag before forwarding.
|
||||
*/
|
||||
offset_ttl = (len < 42) ? 7 : 10;
|
||||
*(pos + offset_ttl) -= 1;
|
||||
*(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
|
||||
sdata->u.mesh.chsw_ttl = *(pos + offset_ttl);
|
||||
|
||||
memcpy(mgmt_fwd, mgmt, len);
|
||||
eth_broadcast_addr(mgmt_fwd->da);
|
||||
memcpy(mgmt_fwd->sa, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(mgmt_fwd->bssid, sdata->vif.addr, ETH_ALEN);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct ieee802_11_elems elems;
|
||||
u16 pre_value;
|
||||
bool fwd_csa = true;
|
||||
size_t baselen;
|
||||
u8 *pos, ttl;
|
||||
|
||||
if (mgmt->u.action.u.measurement.action_code !=
|
||||
WLAN_ACTION_SPCT_CHL_SWITCH)
|
||||
return;
|
||||
|
||||
pos = mgmt->u.action.u.chan_switch.variable;
|
||||
baselen = offsetof(struct ieee80211_mgmt,
|
||||
u.action.u.chan_switch.variable);
|
||||
ieee802_11_parse_elems(pos, len - baselen, false, &elems);
|
||||
|
||||
ttl = elems.mesh_chansw_params_ie->mesh_ttl;
|
||||
if (!--ttl)
|
||||
fwd_csa = false;
|
||||
|
||||
pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
|
||||
if (ifmsh->pre_value >= pre_value)
|
||||
return;
|
||||
|
||||
ifmsh->pre_value = pre_value;
|
||||
|
||||
if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
|
||||
mcsa_dbg(sdata, "Failed to process CSA action frame");
|
||||
return;
|
||||
}
|
||||
|
||||
/* forward or re-broadcast the CSA frame */
|
||||
if (fwd_csa) {
|
||||
if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
|
||||
mcsa_dbg(sdata, "Failed to forward the CSA frame");
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
|
||||
@@ -939,6 +1234,9 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
|
||||
if (mesh_action_is_path_sel(mgmt))
|
||||
mesh_rx_path_sel_frame(sdata, mgmt, len);
|
||||
break;
|
||||
case WLAN_CATEGORY_SPECTRUM_MGMT:
|
||||
mesh_rx_csa_frame(sdata, mgmt, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1056,13 +1354,11 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
|
||||
(unsigned long) sdata);
|
||||
|
||||
ifmsh->accepting_plinks = true;
|
||||
ifmsh->preq_id = 0;
|
||||
ifmsh->sn = 0;
|
||||
ifmsh->num_gates = 0;
|
||||
atomic_set(&ifmsh->mpaths, 0);
|
||||
mesh_rmc_init(sdata);
|
||||
ifmsh->last_preq = jiffies;
|
||||
ifmsh->next_perr = jiffies;
|
||||
ifmsh->chsw_init = false;
|
||||
/* Allocate all mesh structures when creating the first mesh interface. */
|
||||
if (!mesh_allocated)
|
||||
ieee80211s_init();
|
||||
|
||||
@@ -222,7 +222,8 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta)
|
||||
mesh_path_flush_by_nexthop(sta);
|
||||
|
||||
ieee80211_mps_sta_status_update(sta);
|
||||
changed |= ieee80211_mps_local_status_update(sdata);
|
||||
changed |= ieee80211_mps_set_sta_local_pm(sta,
|
||||
NL80211_MESH_POWER_UNKNOWN);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
+18
-15
@@ -152,6 +152,9 @@ u32 ieee80211_mps_set_sta_local_pm(struct sta_info *sta,
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
|
||||
if (sta->local_pm == pm)
|
||||
return 0;
|
||||
|
||||
mps_dbg(sdata, "local STA operates in mode %d with %pM\n",
|
||||
pm, sta->sta.addr);
|
||||
|
||||
@@ -245,6 +248,14 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta)
|
||||
|
||||
do_buffer = (pm != NL80211_MESH_POWER_ACTIVE);
|
||||
|
||||
/* clear the MPSP flags for non-peers or active STA */
|
||||
if (sta->plink_state != NL80211_PLINK_ESTAB) {
|
||||
clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
|
||||
clear_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT);
|
||||
} else if (!do_buffer) {
|
||||
clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
|
||||
}
|
||||
|
||||
/* Don't let the same PS state be set twice */
|
||||
if (test_sta_flag(sta, WLAN_STA_PS_STA) == do_buffer)
|
||||
return;
|
||||
@@ -257,14 +268,6 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta)
|
||||
} else {
|
||||
ieee80211_sta_ps_deliver_wakeup(sta);
|
||||
}
|
||||
|
||||
/* clear the MPSP flags for non-peers or active STA */
|
||||
if (sta->plink_state != NL80211_PLINK_ESTAB) {
|
||||
clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
|
||||
clear_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT);
|
||||
} else if (!do_buffer) {
|
||||
clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
|
||||
}
|
||||
}
|
||||
|
||||
static void mps_set_sta_peer_pm(struct sta_info *sta,
|
||||
@@ -444,8 +447,7 @@ static void mpsp_qos_null_append(struct sta_info *sta,
|
||||
*/
|
||||
static void mps_frame_deliver(struct sta_info *sta, int n_frames)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_local *local = sta->sdata->local;
|
||||
int ac;
|
||||
struct sk_buff_head frames;
|
||||
struct sk_buff *skb;
|
||||
@@ -558,10 +560,10 @@ void ieee80211_mpsp_trigger_process(u8 *qc, struct sta_info *sta,
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_mps_frame_release - release buffered frames in response to beacon
|
||||
* ieee80211_mps_frame_release - release frames buffered due to mesh power save
|
||||
*
|
||||
* @sta: mesh STA
|
||||
* @elems: beacon IEs
|
||||
* @elems: IEs of beacon or probe response
|
||||
*
|
||||
* For peers if we have individually-addressed frames buffered or the peer
|
||||
* indicates buffered frames, send a corresponding MPSP trigger frame. Since
|
||||
@@ -588,9 +590,10 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
|
||||
(!elems->awake_window || !le16_to_cpu(*elems->awake_window)))
|
||||
return;
|
||||
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
buffer_local += skb_queue_len(&sta->ps_tx_buf[ac]) +
|
||||
skb_queue_len(&sta->tx_filtered[ac]);
|
||||
if (!test_sta_flag(sta, WLAN_STA_MPSP_OWNER))
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
buffer_local += skb_queue_len(&sta->ps_tx_buf[ac]) +
|
||||
skb_queue_len(&sta->tx_filtered[ac]);
|
||||
|
||||
if (!has_buffered && !buffer_local)
|
||||
return;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user