Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
353c7815
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 3 年多
通知
13
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
353c7815
编写于
11月 05, 2013
作者:
J
John W. Linville
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-john' of
git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Conflicts: net/wireless/reg.c
上级
01925efd
d0a361a5
变更
38
隐藏空白更改
内联
并排
Showing
38 changed file
with
1305 addition
and
456 deletion
+1305
-456
Documentation/DocBook/80211.tmpl
Documentation/DocBook/80211.tmpl
+2
-2
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mac80211_hwsim.c
+24
-3
include/linux/ieee80211.h
include/linux/ieee80211.h
+20
-0
include/net/cfg80211.h
include/net/cfg80211.h
+14
-0
include/net/mac80211.h
include/net/mac80211.h
+18
-0
include/uapi/linux/nl80211.h
include/uapi/linux/nl80211.h
+22
-5
net/mac80211/Kconfig
net/mac80211/Kconfig
+12
-0
net/mac80211/aes_ccm.c
net/mac80211/aes_ccm.c
+56
-113
net/mac80211/aes_ccm.h
net/mac80211/aes_ccm.h
+6
-8
net/mac80211/cfg.c
net/mac80211/cfg.c
+136
-6
net/mac80211/debug.h
net/mac80211/debug.h
+10
-0
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_netdev.c
+16
-9
net/mac80211/ht.c
net/mac80211/ht.c
+31
-10
net/mac80211/ibss.c
net/mac80211/ibss.c
+51
-65
net/mac80211/ieee80211_i.h
net/mac80211/ieee80211_i.h
+42
-8
net/mac80211/iface.c
net/mac80211/iface.c
+3
-0
net/mac80211/key.h
net/mac80211/key.h
+1
-1
net/mac80211/mesh.c
net/mac80211/mesh.c
+299
-3
net/mac80211/mesh_plink.c
net/mac80211/mesh_plink.c
+2
-1
net/mac80211/mesh_ps.c
net/mac80211/mesh_ps.c
+18
-15
net/mac80211/mlme.c
net/mac80211/mlme.c
+15
-17
net/mac80211/rx.c
net/mac80211/rx.c
+4
-1
net/mac80211/spectmgmt.c
net/mac80211/spectmgmt.c
+20
-13
net/mac80211/sta_info.c
net/mac80211/sta_info.c
+72
-0
net/mac80211/sta_info.h
net/mac80211/sta_info.h
+5
-0
net/mac80211/status.c
net/mac80211/status.c
+19
-12
net/mac80211/tx.c
net/mac80211/tx.c
+45
-0
net/mac80211/util.c
net/mac80211/util.c
+121
-3
net/mac80211/wpa.c
net/mac80211/wpa.c
+20
-24
net/rfkill/Kconfig
net/rfkill/Kconfig
+1
-1
net/rfkill/rfkill-gpio.c
net/rfkill/rfkill-gpio.c
+98
-113
net/wireless/chan.c
net/wireless/chan.c
+2
-1
net/wireless/ibss.c
net/wireless/ibss.c
+20
-4
net/wireless/nl80211.c
net/wireless/nl80211.c
+56
-6
net/wireless/reg.c
net/wireless/reg.c
+10
-4
net/wireless/reg.h
net/wireless/reg.h
+2
-2
net/wireless/sme.c
net/wireless/sme.c
+2
-2
net/wireless/util.c
net/wireless/util.c
+10
-4
未找到文件。
Documentation/DocBook/80211.tmpl
浏览文件 @
353c7815
...
...
@@ -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
...
...
drivers/net/wireless/mac80211_hwsim.c
浏览文件 @
353c7815
...
...
@@ -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
)
{
...
...
include/linux/ieee80211.h
浏览文件 @
353c7815
...
...
@@ -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
*
...
...
include/net/cfg80211.h
浏览文件 @
353c7815
...
...
@@ -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
;
...
...
include/net/mac80211.h
浏览文件 @
353c7815
...
...
@@ -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 */
include/uapi/linux/nl80211.h
浏览文件 @
353c7815
...
...
@@ -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.11
d
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.
*
* @
IEEE
80211_DFS_USABLE: The channel can be used, but channel availability
* @
NL
80211_DFS_USABLE: The channel can be used, but channel availability
* check (CAC) must be performed before using it for AP or IBSS.
* @
IEEE
80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
* @
NL
80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
* is therefore marked as not available.
* @
IEEE
80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
* @
NL
80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
*/
enum
nl80211_dfs_state
{
NL80211_DFS_USABLE
,
NL80211_DFS_UNAVAILABLE
,
...
...
net/mac80211/Kconfig
浏览文件 @
353c7815
...
...
@@ -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
...
...
net/mac80211/aes_ccm.c
浏览文件 @
353c7815
...
...
@@ -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
;
b_0
=
scratch
+
3
*
AES_BLOCK_SIZE
;
aad
=
scratch
+
4
*
AES_BLOCK_SIZE
;
b
=
scratch
;
s_0
=
scratch
+
AES_BLOCK_SIZE
;
crypto_cipher_encrypt_one
(
tfm
,
b
,
b_0
);
struct
scatterlist
assoc
,
pt
,
ct
[
2
];
struct
{
struct
aead_request
req
;
u8
priv
[
crypto_aead_reqsize
(
tfm
)];
}
aead_req
;
/* 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
);
memset
(
&
aead_req
,
0
,
sizeof
(
aead_req
));
aad
+=
AES_BLOCK_SIZE
;
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
);
for
(
i
=
0
;
i
<
AES_BLOCK_SIZE
;
i
++
)
aad
[
i
]
^=
b
[
i
]
;
crypto_cipher_encrypt_one
(
tfm
,
a
,
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
);
/* 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
;
b
=
scratch
;
s_0
=
scratch
+
AES_BLOCK_SIZE
;
e
=
scratch
+
2
*
AES_BLOCK_SIZE
;
b_0
=
scratch
+
3
*
AES_BLOCK_SIZE
;
num_blocks
=
DIV_ROUND_UP
(
data_len
,
AES_BLOCK_SIZE
);
last_len
=
data_len
%
AES_BLOCK_SIZE
;
aes_ccm_prepare
(
tfm
,
scratch
,
b
);
/* 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
;
/* 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
];
struct
scatterlist
assoc
,
pt
,
ct
[
2
];
struct
{
struct
aead_request
req
;
u8
priv
[
crypto_aead_reqsize
(
tfm
)];
}
aead_req
;
memset
(
&
aead_req
,
0
,
sizeof
(
aead_req
));
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
);
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
);
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
;
b
=
scratch
;
s_0
=
scratch
+
AES_BLOCK_SIZE
;
a
=
scratch
+
2
*
AES_BLOCK_SIZE
;
b_0
=
scratch
+
3
*
AES_BLOCK_SIZE
;
num_blocks
=
DIV_ROUND_UP
(
data_len
,
AES_BLOCK_SIZE
);
last_len
=
data_len
%
AES_BLOCK_SIZE
;
aes_ccm_prepare
(
tfm
,
scratch
,
a
);
/* 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
;
}
struct
crypto_aead
*
tfm
;
int
err
;
tfm
=
crypto_alloc_aead
(
"ccm(aes)"
,
0
,
CRYPTO_ALG_ASYNC
);
if
(
IS_ERR
(
tfm
))
return
tfm
;
struct
crypto_cipher
*
ieee80211_aes_key_setup_encrypt
(
const
u8
key
[])
{
struct
crypto_cipher
*
tfm
;
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
;
tfm
=
crypto_alloc_cipher
(
"aes"
,
0
,
CRYPTO_ALG_ASYNC
);
if
(
!
IS_ERR
(
tfm
))
crypto_cipher_setkey
(
tfm
,
key
,
WLAN_KEY_LEN_CCMP
);
return
tfm
;
crypto_free_aead
(
tfm
);
return
ERR_PTR
(
err
);
}
void
ieee80211_aes_key_free
(
struct
crypto_cipher
*
tfm
)
void
ieee80211_aes_key_free
(
struct
crypto_aead
*
tfm
)
{
crypto_free_
cipher
(
tfm
);
crypto_free_
aead
(
tfm
);
}
net/mac80211/aes_ccm.h
浏览文件 @
353c7815
...
...
@@ -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 */
net/mac80211/cfg.c
浏览文件 @
353c7815
...
...
@@ -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
;
}
...
...
net/mac80211/debug.h
浏览文件 @
353c7815
...
...
@@ -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__)
...
...
net/mac80211/debugfs_netdev.c
浏览文件 @
353c7815
...
...
@@ -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
\n
used: %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
\n
used: %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
\n
used: %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
);
...
...
net/mac80211/ht.c
浏览文件 @
353c7815
...
...
@@ -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
);
net/mac80211/ibss.c
浏览文件 @
353c7815
...
...
@@ -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
(
&
params
,
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
,
&
params
.
count
,
&
mode
,
&
params
.
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
,
&
params
.
chandef
,
IEEE80211_CHAN_DISABLED
))
{
if
(
!
cfg80211_reg_can_beacon
(
sdata
->
local
->
hw
.
wiphy
,
&
params
.
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
,
&
params
);
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
,
&
params
.
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 */
...
...
net/mac80211/ieee80211_i.h
浏览文件 @
353c7815
...
...
@@ -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
...
...
net/mac80211/iface.c
浏览文件 @
353c7815
...
...
@@ -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
;
...
...
net/mac80211/key.h
浏览文件 @
353c7815
...
...
@@ -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
{
...
...
net/mac80211/mesh.c
浏览文件 @
353c7815
...
...
@@ -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
(
&
params
,
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
,
&
params
.
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
,
&
params
.
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
,
&
params
,
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
,
&
params
.
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
();
...
...
net/mac80211/mesh_plink.c
浏览文件 @
353c7815
...
...
@@ -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
;
}
...
...
net/mac80211/mesh_ps.c
浏览文件 @
353c7815
...
...
@@ -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
;
...
...
net/mac80211/mlme.c
浏览文件 @
353c7815
...
...
@@ -958,9 +958,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct
cfg80211_bss
*
cbss
=
ifmgd
->
associated
;
struct
ieee80211_chanctx
*
chanctx
;
enum
ieee80211_band
current_band
;
u8
count
;
u8
mode
;
struct
cfg80211_chan_def
new_chandef
=
{};
struct
ieee80211_csa_ie
csa_ie
;
int
res
;
sdata_assert_lock
(
sdata
);
...
...
@@ -976,24 +974,24 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return
;
current_band
=
cbss
->
channel
->
band
;
memset
(
&
csa_ie
,
0
,
sizeof
(
csa_ie
));
res
=
ieee80211_parse_ch_switch_ie
(
sdata
,
elems
,
beacon
,
current_band
,
ifmgd
->
flags
,
ifmgd
->
associated
->
bssid
,
&
count
,
&
mode
,
&
new_chandef
);
ifmgd
->
associated
->
bssid
,
&
csa_ie
);
if
(
res
<
0
)
ieee80211_queue_work
(
&
local
->
hw
,
&
ifmgd
->
csa_connection_drop_work
);
if
(
res
)
return
;
if
(
!
cfg80211_chandef_usable
(
local
->
hw
.
wiphy
,
&
new_
chandef
,
if
(
!
cfg80211_chandef_usable
(
local
->
hw
.
wiphy
,
&
csa_ie
.
chandef
,
IEEE80211_CHAN_DISABLED
))
{
sdata_info
(
sdata
,
"AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting
\n
"
,
ifmgd
->
associated
->
bssid
,
new_
chandef
.
chan
->
center_freq
,
new_chandef
.
width
,
new_
chandef
.
center_freq1
,
new_
chandef
.
center_freq2
);
csa_ie
.
chandef
.
chan
->
center_freq
,
csa_ie
.
chandef
.
width
,
csa_ie
.
chandef
.
center_freq1
,
csa_ie
.
chandef
.
center_freq2
);
ieee80211_queue_work
(
&
local
->
hw
,
&
ifmgd
->
csa_connection_drop_work
);
return
;
...
...
@@ -1037,9 +1035,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
mutex_unlock
(
&
local
->
chanctx_mtx
);
local
->
csa_chandef
=
new_
chandef
;
local
->
csa_chandef
=
csa_ie
.
chandef
;
if
(
mode
)
if
(
csa_ie
.
mode
)
ieee80211_stop_queues_by_reason
(
&
local
->
hw
,
IEEE80211_MAX_QUEUE_MAP
,
IEEE80211_QUEUE_STOP_REASON_CSA
);
...
...
@@ -1048,9 +1046,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
/* use driver's channel switch callback */
struct
ieee80211_channel_switch
ch_switch
=
{
.
timestamp
=
timestamp
,
.
block_tx
=
mode
,
.
chandef
=
new_
chandef
,
.
count
=
count
,
.
block_tx
=
csa_ie
.
mode
,
.
chandef
=
csa_ie
.
chandef
,
.
count
=
c
sa_ie
.
c
ount
,
};
drv_channel_switch
(
local
,
&
ch_switch
);
...
...
@@ -1058,11 +1056,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
/* channel switch handled in software */
if
(
count
<=
1
)
if
(
c
sa_ie
.
c
ount
<=
1
)
ieee80211_queue_work
(
&
local
->
hw
,
&
ifmgd
->
chswitch_work
);
else
mod_timer
(
&
ifmgd
->
chswitch_timer
,
TU_TO_EXP_TIME
(
count
*
cbss
->
beacon_interval
));
TU_TO_EXP_TIME
(
c
sa_ie
.
c
ount
*
cbss
->
beacon_interval
));
}
static
u32
ieee80211_handle_pwr_constr
(
struct
ieee80211_sub_if_data
*
sdata
,
...
...
@@ -3500,7 +3498,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ieee80211_beacon_connection_loss_work
);
INIT_WORK
(
&
ifmgd
->
csa_connection_drop_work
,
ieee80211_csa_connection_drop_work
);
INIT_WORK
(
&
ifmgd
->
request_smps_work
,
ieee80211_request_smps_work
);
INIT_WORK
(
&
ifmgd
->
request_smps_work
,
ieee80211_request_smps_
mgd_
work
);
setup_timer
(
&
ifmgd
->
timer
,
ieee80211_sta_timer
,
(
unsigned
long
)
sdata
);
setup_timer
(
&
ifmgd
->
bcn_mon_timer
,
ieee80211_sta_bcn_mon_timer
,
...
...
net/mac80211/rx.c
浏览文件 @
353c7815
...
...
@@ -2593,13 +2593,16 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
break
;
if
(
sdata
->
vif
.
type
!=
NL80211_IFTYPE_STATION
&&
sdata
->
vif
.
type
!=
NL80211_IFTYPE_ADHOC
)
sdata
->
vif
.
type
!=
NL80211_IFTYPE_ADHOC
&&
sdata
->
vif
.
type
!=
NL80211_IFTYPE_MESH_POINT
)
break
;
if
(
sdata
->
vif
.
type
==
NL80211_IFTYPE_STATION
)
bssid
=
sdata
->
u
.
mgd
.
bssid
;
else
if
(
sdata
->
vif
.
type
==
NL80211_IFTYPE_ADHOC
)
bssid
=
sdata
->
u
.
ibss
.
bssid
;
else
if
(
sdata
->
vif
.
type
==
NL80211_IFTYPE_MESH_POINT
)
bssid
=
mgmt
->
sa
;
else
break
;
...
...
net/mac80211/spectmgmt.c
浏览文件 @
353c7815
...
...
@@ -24,8 +24,8 @@
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
)
{
enum
ieee80211_band
new_band
;
int
new_freq
;
...
...
@@ -62,18 +62,24 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
return
-
EINVAL
;
}
new_chan_no
=
elems
->
ext_chansw_ie
->
new_ch_num
;
*
count
=
elems
->
ext_chansw_ie
->
count
;
*
mode
=
elems
->
ext_chansw_ie
->
mode
;
csa_ie
->
count
=
elems
->
ext_chansw_ie
->
count
;
csa_ie
->
mode
=
elems
->
ext_chansw_ie
->
mode
;
}
else
if
(
elems
->
ch_switch_ie
)
{
new_band
=
current_band
;
new_chan_no
=
elems
->
ch_switch_ie
->
new_ch_num
;
*
count
=
elems
->
ch_switch_ie
->
count
;
*
mode
=
elems
->
ch_switch_ie
->
mode
;
csa_ie
->
count
=
elems
->
ch_switch_ie
->
count
;
csa_ie
->
mode
=
elems
->
ch_switch_ie
->
mode
;
}
else
{
/* nothing here we understand */
return
1
;
}
/* Mesh Channel Switch Parameters Element */
if
(
elems
->
mesh_chansw_params_ie
)
{
csa_ie
->
ttl
=
elems
->
mesh_chansw_params_ie
->
mesh_ttl
;
csa_ie
->
mode
=
elems
->
mesh_chansw_params_ie
->
mesh_flags
;
}
new_freq
=
ieee80211_channel_to_frequency
(
new_chan_no
,
new_band
);
new_chan
=
ieee80211_get_channel
(
sdata
->
local
->
hw
.
wiphy
,
new_freq
);
if
(
!
new_chan
||
new_chan
->
flags
&
IEEE80211_CHAN_DISABLED
)
{
...
...
@@ -103,25 +109,26 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
default:
/* secondary_channel_offset was present but is invalid */
case
IEEE80211_HT_PARAM_CHA_SEC_NONE
:
cfg80211_chandef_create
(
new_
chandef
,
new_chan
,
cfg80211_chandef_create
(
&
csa_ie
->
chandef
,
new_chan
,
NL80211_CHAN_HT20
);
break
;
case
IEEE80211_HT_PARAM_CHA_SEC_ABOVE
:
cfg80211_chandef_create
(
new_
chandef
,
new_chan
,
cfg80211_chandef_create
(
&
csa_ie
->
chandef
,
new_chan
,
NL80211_CHAN_HT40PLUS
);
break
;
case
IEEE80211_HT_PARAM_CHA_SEC_BELOW
:
cfg80211_chandef_create
(
new_
chandef
,
new_chan
,
cfg80211_chandef_create
(
&
csa_ie
->
chandef
,
new_chan
,
NL80211_CHAN_HT40MINUS
);
break
;
case
-
1
:
cfg80211_chandef_create
(
new_
chandef
,
new_chan
,
cfg80211_chandef_create
(
&
csa_ie
->
chandef
,
new_chan
,
NL80211_CHAN_NO_HT
);
/* keep width for 5/10 MHz channels */
switch
(
sdata
->
vif
.
bss_conf
.
chandef
.
width
)
{
case
NL80211_CHAN_WIDTH_5
:
case
NL80211_CHAN_WIDTH_10
:
new_chandef
->
width
=
sdata
->
vif
.
bss_conf
.
chandef
.
width
;
csa_ie
->
chandef
.
width
=
sdata
->
vif
.
bss_conf
.
chandef
.
width
;
break
;
default:
break
;
...
...
@@ -171,13 +178,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
/* if VHT data is there validate & use it */
if
(
new_vht_chandef
.
chan
)
{
if
(
!
cfg80211_chandef_compatible
(
&
new_vht_chandef
,
new_
chandef
))
{
&
csa_ie
->
chandef
))
{
sdata_info
(
sdata
,
"BSS %pM: CSA has inconsistent channel data, disconnecting
\n
"
,
bssid
);
return
-
EINVAL
;
}
*
new_
chandef
=
new_vht_chandef
;
csa_ie
->
chandef
=
new_vht_chandef
;
}
return
0
;
...
...
net/mac80211/sta_info.c
浏览文件 @
353c7815
...
...
@@ -385,6 +385,30 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta
->
last_seq_ctrl
[
i
]
=
cpu_to_le16
(
USHRT_MAX
);
sta
->
sta
.
smps_mode
=
IEEE80211_SMPS_OFF
;
if
(
sdata
->
vif
.
type
==
NL80211_IFTYPE_AP
||
sdata
->
vif
.
type
==
NL80211_IFTYPE_AP_VLAN
)
{
struct
ieee80211_supported_band
*
sband
=
local
->
hw
.
wiphy
->
bands
[
ieee80211_get_sdata_band
(
sdata
)];
u8
smps
=
(
sband
->
ht_cap
.
cap
&
IEEE80211_HT_CAP_SM_PS
)
>>
IEEE80211_HT_CAP_SM_PS_SHIFT
;
/*
* Assume that hostapd advertises our caps in the beacon and
* this is the known_smps_mode for a station that just assciated
*/
switch
(
smps
)
{
case
WLAN_HT_SMPS_CONTROL_DISABLED
:
sta
->
known_smps_mode
=
IEEE80211_SMPS_OFF
;
break
;
case
WLAN_HT_SMPS_CONTROL_STATIC
:
sta
->
known_smps_mode
=
IEEE80211_SMPS_STATIC
;
break
;
case
WLAN_HT_SMPS_CONTROL_DYNAMIC
:
sta
->
known_smps_mode
=
IEEE80211_SMPS_DYNAMIC
;
break
;
default:
WARN_ON
(
1
);
}
}
sta_dbg
(
sdata
,
"Allocated STA %pM
\n
"
,
sta
->
sta
.
addr
);
...
...
@@ -1069,6 +1093,19 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
ieee80211_add_pending_skbs_fn
(
local
,
&
pending
,
clear_sta_ps_flags
,
sta
);
/* This station just woke up and isn't aware of our SMPS state */
if
(
!
ieee80211_smps_is_restrictive
(
sta
->
known_smps_mode
,
sdata
->
smps_mode
)
&&
sta
->
known_smps_mode
!=
sdata
->
bss
->
req_smps
&&
sta_info_tx_streams
(
sta
)
!=
1
)
{
ht_dbg
(
sdata
,
"%pM just woke up and MIMO capable - update SMPS
\n
"
,
sta
->
sta
.
addr
);
ieee80211_send_smps_action
(
sdata
,
sdata
->
bss
->
req_smps
,
sta
->
sta
.
addr
,
sdata
->
vif
.
bss_conf
.
bssid
);
}
local
->
total_ps_buffered
-=
buffered
;
sta_info_recalc_tim
(
sta
);
...
...
@@ -1520,3 +1557,38 @@ int sta_info_move_state(struct sta_info *sta,
return
0
;
}
u8
sta_info_tx_streams
(
struct
sta_info
*
sta
)
{
struct
ieee80211_sta_ht_cap
*
ht_cap
=
&
sta
->
sta
.
ht_cap
;
u8
rx_streams
;
if
(
!
sta
->
sta
.
ht_cap
.
ht_supported
)
return
1
;
if
(
sta
->
sta
.
vht_cap
.
vht_supported
)
{
int
i
;
u16
tx_mcs_map
=
le16_to_cpu
(
sta
->
sta
.
vht_cap
.
vht_mcs
.
tx_mcs_map
);
for
(
i
=
7
;
i
>=
0
;
i
--
)
if
((
tx_mcs_map
&
(
0x3
<<
(
i
*
2
)))
!=
IEEE80211_VHT_MCS_NOT_SUPPORTED
)
return
i
+
1
;
}
if
(
ht_cap
->
mcs
.
rx_mask
[
3
])
rx_streams
=
4
;
else
if
(
ht_cap
->
mcs
.
rx_mask
[
2
])
rx_streams
=
3
;
else
if
(
ht_cap
->
mcs
.
rx_mask
[
1
])
rx_streams
=
2
;
else
rx_streams
=
1
;
if
(
!
(
ht_cap
->
mcs
.
tx_params
&
IEEE80211_HT_MCS_TX_RX_DIFF
))
return
rx_streams
;
return
((
ht_cap
->
mcs
.
tx_params
&
IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK
)
>>
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT
)
+
1
;
}
net/mac80211/sta_info.h
浏览文件 @
353c7815
...
...
@@ -301,6 +301,8 @@ struct sta_ampdu_mlme {
* @chains: chains ever used for RX from this station
* @chain_signal_last: last signal (per chain)
* @chain_signal_avg: signal average (per chain)
* @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
* AP only.
*/
struct
sta_info
{
/* General information, mostly static */
...
...
@@ -411,6 +413,8 @@ struct sta_info {
unsigned
int
lost_packets
;
unsigned
int
beacon_loss_count
;
enum
ieee80211_smps_mode
known_smps_mode
;
/* keep last! */
struct
ieee80211_sta
sta
;
};
...
...
@@ -613,6 +617,7 @@ void sta_set_rate_info_rx(struct sta_info *sta,
struct
rate_info
*
rinfo
);
void
ieee80211_sta_expire
(
struct
ieee80211_sub_if_data
*
sdata
,
unsigned
long
exp_time
);
u8
sta_info_tx_streams
(
struct
sta_info
*
sta
);
void
ieee80211_sta_ps_deliver_wakeup
(
struct
sta_info
*
sta
);
void
ieee80211_sta_ps_deliver_poll_response
(
struct
sta_info
*
sta
);
...
...
net/mac80211/status.c
浏览文件 @
353c7815
...
...
@@ -194,29 +194,36 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
if
(
ieee80211_is_action
(
mgmt
->
frame_control
)
&&
mgmt
->
u
.
action
.
category
==
WLAN_CATEGORY_HT
&&
mgmt
->
u
.
action
.
u
.
ht_smps
.
action
==
WLAN_HT_ACTION_SMPS
&&
sdata
->
vif
.
type
==
NL80211_IFTYPE_STATION
&&
ieee80211_sdata_running
(
sdata
))
{
/*
* This update looks racy, but isn't -- if we come
* here we've definitely got a station that we're
* talking to, and on a managed interface that can
* only be the AP. And the only other place updating
* this variable in managed mode is before association.
*/
enum
ieee80211_smps_mode
smps_mode
;
switch
(
mgmt
->
u
.
action
.
u
.
ht_smps
.
smps_control
)
{
case
WLAN_HT_SMPS_CONTROL_DYNAMIC
:
s
data
->
s
mps_mode
=
IEEE80211_SMPS_DYNAMIC
;
smps_mode
=
IEEE80211_SMPS_DYNAMIC
;
break
;
case
WLAN_HT_SMPS_CONTROL_STATIC
:
s
data
->
s
mps_mode
=
IEEE80211_SMPS_STATIC
;
smps_mode
=
IEEE80211_SMPS_STATIC
;
break
;
case
WLAN_HT_SMPS_CONTROL_DISABLED
:
default:
/* shouldn't happen since we don't send that */
s
data
->
s
mps_mode
=
IEEE80211_SMPS_OFF
;
smps_mode
=
IEEE80211_SMPS_OFF
;
break
;
}
ieee80211_queue_work
(
&
local
->
hw
,
&
sdata
->
recalc_smps
);
if
(
sdata
->
vif
.
type
==
NL80211_IFTYPE_STATION
)
{
/*
* This update looks racy, but isn't -- if we come
* here we've definitely got a station that we're
* talking to, and on a managed interface that can
* only be the AP. And the only other place updating
* this variable in managed mode is before association.
*/
sdata
->
smps_mode
=
smps_mode
;
ieee80211_queue_work
(
&
local
->
hw
,
&
sdata
->
recalc_smps
);
}
else
if
(
sdata
->
vif
.
type
==
NL80211_IFTYPE_AP
||
sdata
->
vif
.
type
==
NL80211_IFTYPE_AP_VLAN
)
{
sta
->
known_smps_mode
=
smps_mode
;
}
}
}
...
...
net/mac80211/tx.c
浏览文件 @
353c7815
...
...
@@ -1367,6 +1367,35 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
return
0
;
}
bool
ieee80211_tx_prepare_skb
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
sk_buff
*
skb
,
int
band
,
struct
ieee80211_sta
**
sta
)
{
struct
ieee80211_sub_if_data
*
sdata
=
vif_to_sdata
(
vif
);
struct
ieee80211_tx_info
*
info
=
IEEE80211_SKB_CB
(
skb
);
struct
ieee80211_tx_data
tx
;
if
(
ieee80211_tx_prepare
(
sdata
,
&
tx
,
skb
)
==
TX_DROP
)
return
false
;
info
->
band
=
band
;
info
->
control
.
vif
=
vif
;
info
->
hw_queue
=
vif
->
hw_queue
[
skb_get_queue_mapping
(
skb
)];
if
(
invoke_tx_handlers
(
&
tx
))
return
false
;
if
(
sta
)
{
if
(
tx
.
sta
)
*
sta
=
&
tx
.
sta
->
sta
;
else
*
sta
=
NULL
;
}
return
true
;
}
EXPORT_SYMBOL
(
ieee80211_tx_prepare_skb
);
/*
* Returns false if the frame couldn't be transmitted but was queued instead.
*/
...
...
@@ -2370,6 +2399,10 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
beacon_data
=
beacon
->
head
;
beacon_data_len
=
beacon
->
head_len
;
break
;
case
NL80211_IFTYPE_MESH_POINT
:
beacon_data
=
beacon
->
head
;
beacon_data_len
=
beacon
->
head_len
;
break
;
default:
return
;
}
...
...
@@ -2424,6 +2457,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
if
(
!
beacon
)
goto
out
;
beacon_data
=
beacon
->
head
;
beacon_data_len
=
beacon
->
head_len
;
}
else
if
(
vif
->
type
==
NL80211_IFTYPE_MESH_POINT
)
{
struct
ieee80211_if_mesh
*
ifmsh
=
&
sdata
->
u
.
mesh
;
beacon
=
rcu_dereference
(
ifmsh
->
beacon
);
if
(
!
beacon
)
goto
out
;
beacon_data
=
beacon
->
head
;
beacon_data_len
=
beacon
->
head_len
;
}
else
{
...
...
@@ -2531,6 +2573,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
if
(
!
bcn
)
goto
out
;
if
(
sdata
->
vif
.
csa_active
)
ieee80211_update_csa
(
sdata
,
bcn
);
if
(
ifmsh
->
sync_ops
)
ifmsh
->
sync_ops
->
adjust_tbtt
(
sdata
);
...
...
net/mac80211/util.c
浏览文件 @
353c7815
...
...
@@ -300,9 +300,6 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
if
(
!
sdata
->
dev
)
continue
;
if
(
test_bit
(
SDATA_STATE_OFFCHANNEL
,
&
sdata
->
state
))
continue
;
if
(
sdata
->
vif
.
cab_queue
!=
IEEE80211_INVAL_HW_QUEUE
&&
local
->
queue_stop_reasons
[
sdata
->
vif
.
cab_queue
]
!=
0
)
continue
;
...
...
@@ -743,6 +740,7 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
case
WLAN_EID_TIMEOUT_INTERVAL
:
case
WLAN_EID_SECONDARY_CHANNEL_OFFSET
:
case
WLAN_EID_WIDE_BW_CHANNEL_SWITCH
:
case
WLAN_EID_CHAN_SWITCH_PARAM
:
/*
* not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
* that if the content gets bigger it might be needed more than once
...
...
@@ -908,6 +906,14 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
}
elems
->
sec_chan_offs
=
(
void
*
)
pos
;
break
;
case
WLAN_EID_CHAN_SWITCH_PARAM
:
if
(
elen
!=
sizeof
(
*
elems
->
mesh_chansw_params_ie
))
{
elem_parse_failed
=
true
;
break
;
}
elems
->
mesh_chansw_params_ie
=
(
void
*
)
pos
;
break
;
case
WLAN_EID_WIDE_BW_CHANNEL_SWITCH
:
if
(
!
action
||
elen
!=
sizeof
(
*
elems
->
wide_bw_chansw_ie
))
{
...
...
@@ -2354,3 +2360,115 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
return
ret
;
}
/*
* Returns true if smps_mode_new is strictly more restrictive than
* smps_mode_old.
*/
bool
ieee80211_smps_is_restrictive
(
enum
ieee80211_smps_mode
smps_mode_old
,
enum
ieee80211_smps_mode
smps_mode_new
)
{
if
(
WARN_ON_ONCE
(
smps_mode_old
==
IEEE80211_SMPS_AUTOMATIC
||
smps_mode_new
==
IEEE80211_SMPS_AUTOMATIC
))
return
false
;
switch
(
smps_mode_old
)
{
case
IEEE80211_SMPS_STATIC
:
return
false
;
case
IEEE80211_SMPS_DYNAMIC
:
return
smps_mode_new
==
IEEE80211_SMPS_STATIC
;
case
IEEE80211_SMPS_OFF
:
return
smps_mode_new
!=
IEEE80211_SMPS_OFF
;
default:
WARN_ON
(
1
);
}
return
false
;
}
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_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
;
if
(
sdata
->
vif
.
type
!=
NL80211_IFTYPE_ADHOC
&&
sdata
->
vif
.
type
!=
NL80211_IFTYPE_MESH_POINT
)
return
-
EOPNOTSUPP
;
skb
=
dev_alloc_skb
(
local
->
tx_headroom
+
hdr_len
+
5
+
/* channel switch announcement element */
3
+
/* secondary channel offset element */
8
);
/* mesh channel switch parameters element */
if
(
!
skb
)
return
-
ENOMEM
;
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
);
if
(
ieee80211_vif_is_mesh
(
&
sdata
->
vif
))
{
memcpy
(
mgmt
->
bssid
,
sdata
->
vif
.
addr
,
ETH_ALEN
);
}
else
{
struct
ieee80211_if_ibss
*
ifibss
=
&
sdata
->
u
.
ibss
;
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
;
}
if
(
ieee80211_vif_is_mesh
(
&
sdata
->
vif
))
{
struct
ieee80211_if_mesh
*
ifmsh
=
&
sdata
->
u
.
mesh
;
__le16
pre_value
;
skb_put
(
skb
,
8
);
*
pos
++
=
WLAN_EID_CHAN_SWITCH_PARAM
;
/* EID */
*
pos
++
=
6
;
/* IE length */
*
pos
++
=
sdata
->
u
.
mesh
.
mshcfg
.
dot11MeshTTL
;
/* Mesh TTL */
*
pos
=
0x00
;
/* Mesh Flag: Tx Restrict, Initiator, Reason */
*
pos
|=
WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR
;
*
pos
++
|=
csa_settings
->
block_tx
?
WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT
:
0x00
;
put_unaligned_le16
(
WLAN_REASON_MESH_CHAN
,
pos
);
/* Reason Cd */
pos
+=
2
;
if
(
!
ifmsh
->
pre_value
)
ifmsh
->
pre_value
=
1
;
else
ifmsh
->
pre_value
++
;
pre_value
=
cpu_to_le16
(
ifmsh
->
pre_value
);
memcpy
(
pos
,
&
pre_value
,
2
);
/* Precedence Value */
pos
+=
2
;
ifmsh
->
chsw_init
=
true
;
}
ieee80211_tx_skb
(
sdata
,
skb
);
return
0
;
}
net/mac80211/wpa.c
浏览文件 @
353c7815
...
...
@@ -301,22 +301,16 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
}
static
void
ccmp_special_blocks
(
struct
sk_buff
*
skb
,
u8
*
pn
,
u8
*
scratch
,
static
void
ccmp_special_blocks
(
struct
sk_buff
*
skb
,
u8
*
pn
,
u8
*
b_0
,
u8
*
aad
,
int
encrypted
)
{
__le16
mask_fc
;
int
a4_included
,
mgmt
;
u8
qos_tid
;
u8
*
b_0
,
*
aad
;
u16
data_len
,
len_a
;
u16
len_a
;
unsigned
int
hdrlen
;
struct
ieee80211_hdr
*
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
memset
(
scratch
,
0
,
6
*
AES_BLOCK_SIZE
);
b_0
=
scratch
+
3
*
AES_BLOCK_SIZE
;
aad
=
scratch
+
4
*
AES_BLOCK_SIZE
;
/*
* Mask FC: zero subtype b4 b5 b6 (if not mgmt)
* Retry, PwrMgt, MoreData; set Protected
...
...
@@ -338,20 +332,21 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
else
qos_tid
=
0
;
data_len
=
skb
->
len
-
hdrlen
-
IEEE80211_CCMP_HDR_LEN
;
if
(
encrypted
)
data_len
-=
IEEE80211_CCMP_MIC_LEN
;
/* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
* mode authentication are not allowed to collide, yet both are derived
* from this vector b_0. We only set L := 1 here to indicate that the
* data size can be represented in (L+1) bytes. The CCM layer will take
* care of storing the data length in the top (L+1) bytes and setting
* and clearing the other bits as is required to derive the two IVs.
*/
b_0
[
0
]
=
0x1
;
/* First block, b_0 */
b_0
[
0
]
=
0x59
;
/* flags: Adata: 1, M: 011, L: 001 */
/* Nonce: Nonce Flags | A2 | PN
* Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
*/
b_0
[
1
]
=
qos_tid
|
(
mgmt
<<
4
);
memcpy
(
&
b_0
[
2
],
hdr
->
addr2
,
ETH_ALEN
);
memcpy
(
&
b_0
[
8
],
pn
,
IEEE80211_CCMP_PN_LEN
);
/* l(m) */
put_unaligned_be16
(
data_len
,
&
b_0
[
14
]);
/* AAD (extra authenticate-only data) / masked 802.11 header
* FC | A1 | A2 | A3 | SC | [A4] | [QC] */
...
...
@@ -407,7 +402,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
u8
*
pos
;
u8
pn
[
6
];
u64
pn64
;
u8
scratch
[
6
*
AES_BLOCK_SIZE
];
u8
aad
[
2
*
AES_BLOCK_SIZE
];
u8
b_0
[
AES_BLOCK_SIZE
];
if
(
info
->
control
.
hw_key
&&
!
(
info
->
control
.
hw_key
->
flags
&
IEEE80211_KEY_FLAG_GENERATE_IV
)
&&
...
...
@@ -460,9 +456,9 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
return
0
;
pos
+=
IEEE80211_CCMP_HDR_LEN
;
ccmp_special_blocks
(
skb
,
pn
,
scratch
,
0
);
ieee80211_aes_ccm_encrypt
(
key
->
u
.
ccmp
.
tfm
,
scratch
,
pos
,
len
,
pos
,
skb_put
(
skb
,
IEEE80211_CCMP_MIC_LEN
));
ccmp_special_blocks
(
skb
,
pn
,
b_0
,
aad
,
0
);
ieee80211_aes_ccm_encrypt
(
key
->
u
.
ccmp
.
tfm
,
b_0
,
aad
,
pos
,
len
,
skb_put
(
skb
,
IEEE80211_CCMP_MIC_LEN
));
return
0
;
}
...
...
@@ -525,16 +521,16 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
}
if
(
!
(
status
->
flag
&
RX_FLAG_DECRYPTED
))
{
u8
scratch
[
6
*
AES_BLOCK_SIZE
];
u8
aad
[
2
*
AES_BLOCK_SIZE
];
u8
b_0
[
AES_BLOCK_SIZE
];
/* hardware didn't decrypt/verify MIC */
ccmp_special_blocks
(
skb
,
pn
,
scratch
,
1
);
ccmp_special_blocks
(
skb
,
pn
,
b_0
,
aad
,
1
);
if
(
ieee80211_aes_ccm_decrypt
(
key
->
u
.
ccmp
.
tfm
,
scratch
,
key
->
u
.
ccmp
.
tfm
,
b_0
,
aad
,
skb
->
data
+
hdrlen
+
IEEE80211_CCMP_HDR_LEN
,
data_len
,
skb
->
data
+
skb
->
len
-
IEEE80211_CCMP_MIC_LEN
,
skb
->
data
+
hdrlen
+
IEEE80211_CCMP_HDR_LEN
))
skb
->
data
+
skb
->
len
-
IEEE80211_CCMP_MIC_LEN
))
return
RX_DROP_UNUSABLE
;
}
...
...
net/rfkill/Kconfig
浏览文件 @
353c7815
...
...
@@ -36,7 +36,7 @@ config RFKILL_REGULATOR
config RFKILL_GPIO
tristate "GPIO RFKILL driver"
depends on RFKILL && GPIOLIB
&& HAVE_CLK
depends on RFKILL && GPIOLIB
default n
help
If you say yes here you get support of a generic gpio RFKILL
...
...
net/rfkill/rfkill-gpio.c
浏览文件 @
353c7815
...
...
@@ -24,27 +24,23 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/acpi_gpio.h>
#include <linux/rfkill-gpio.h>
enum
rfkill_gpio_clk_state
{
UNSPECIFIED
=
0
,
PWR_ENABLED
,
PWR_DISABLED
}
;
struct
rfkill_gpio_data
{
const
char
*
name
;
enum
rfkill_type
type
;
int
reset_gpio
;
int
shutdown_gpio
;
#define PWR_CLK_SET(_RF, _EN) \
((_RF)->pwr_clk_enabled = (!(_EN) ? PWR_ENABLED : PWR_DISABLED))
#define PWR_CLK_ENABLED(_RF) ((_RF)->pwr_clk_enabled == PWR_ENABLED)
#define PWR_CLK_DISABLED(_RF) ((_RF)->pwr_clk_enabled != PWR_ENABLED)
struct
rfkill
*
rfkill_dev
;
char
*
reset_name
;
char
*
shutdown_name
;
struct
clk
*
clk
;
struct
rfkill_gpio_data
{
struct
rfkill_gpio_platform_data
*
pdata
;
struct
rfkill
*
rfkill_dev
;
char
*
reset_name
;
char
*
shutdown_name
;
enum
rfkill_gpio_clk_state
pwr_clk_enabled
;
struct
clk
*
pwr_clk
;
bool
clk_enabled
;
};
static
int
rfkill_gpio_set_power
(
void
*
data
,
bool
blocked
)
...
...
@@ -52,23 +48,22 @@ static int rfkill_gpio_set_power(void *data, bool blocked)
struct
rfkill_gpio_data
*
rfkill
=
data
;
if
(
blocked
)
{
if
(
gpio_is_valid
(
rfkill
->
pdata
->
shutdown_gpio
))
gpio_
direction_output
(
rfkill
->
pdata
->
shutdown_gpio
,
0
);
if
(
gpio_is_valid
(
rfkill
->
pdata
->
reset_gpio
))
gpio_
direction_output
(
rfkill
->
pdata
->
reset_gpio
,
0
);
if
(
rfkill
->
pwr_clk
&&
PWR_CLK_ENABLED
(
rfkill
)
)
clk_disable
(
rfkill
->
pwr_
clk
);
if
(
gpio_is_valid
(
rfkill
->
shutdown_gpio
))
gpio_
set_value
(
rfkill
->
shutdown_gpio
,
0
);
if
(
gpio_is_valid
(
rfkill
->
reset_gpio
))
gpio_
set_value
(
rfkill
->
reset_gpio
,
0
);
if
(
!
IS_ERR
(
rfkill
->
clk
)
&&
rfkill
->
clk_enabled
)
clk_disable
(
rfkill
->
clk
);
}
else
{
if
(
rfkill
->
pwr_clk
&&
PWR_CLK_DISABLED
(
rfkill
)
)
clk_enable
(
rfkill
->
pwr_
clk
);
if
(
gpio_is_valid
(
rfkill
->
pdata
->
reset_gpio
))
gpio_
direction_output
(
rfkill
->
pdata
->
reset_gpio
,
1
);
if
(
gpio_is_valid
(
rfkill
->
pdata
->
shutdown_gpio
))
gpio_
direction_output
(
rfkill
->
pdata
->
shutdown_gpio
,
1
);
if
(
!
IS_ERR
(
rfkill
->
clk
)
&&
!
rfkill
->
clk_enabled
)
clk_enable
(
rfkill
->
clk
);
if
(
gpio_is_valid
(
rfkill
->
reset_gpio
))
gpio_
set_value
(
rfkill
->
reset_gpio
,
1
);
if
(
gpio_is_valid
(
rfkill
->
shutdown_gpio
))
gpio_
set_value
(
rfkill
->
shutdown_gpio
,
1
);
}
if
(
rfkill
->
pwr_clk
)
PWR_CLK_SET
(
rfkill
,
blocked
);
rfkill
->
clk_enabled
=
blocked
;
return
0
;
}
...
...
@@ -77,117 +72,112 @@ static const struct rfkill_ops rfkill_gpio_ops = {
.
set_block
=
rfkill_gpio_set_power
,
};
static
int
rfkill_gpio_acpi_probe
(
struct
device
*
dev
,
struct
rfkill_gpio_data
*
rfkill
)
{
const
struct
acpi_device_id
*
id
;
id
=
acpi_match_device
(
dev
->
driver
->
acpi_match_table
,
dev
);
if
(
!
id
)
return
-
ENODEV
;
rfkill
->
name
=
dev_name
(
dev
);
rfkill
->
type
=
(
unsigned
)
id
->
driver_data
;
rfkill
->
reset_gpio
=
acpi_get_gpio_by_index
(
dev
,
0
,
NULL
);
rfkill
->
shutdown_gpio
=
acpi_get_gpio_by_index
(
dev
,
1
,
NULL
);
return
0
;
}
static
int
rfkill_gpio_probe
(
struct
platform_device
*
pdev
)
{
struct
rfkill_gpio_data
*
rfkill
;
struct
rfkill_gpio_platform_data
*
pdata
=
pdev
->
dev
.
platform_data
;
struct
rfkill_gpio_data
*
rfkill
;
const
char
*
clk_name
=
NULL
;
int
ret
=
0
;
int
len
=
0
;
if
(
!
pdata
)
{
pr_warn
(
"%s: No platform data specified
\n
"
,
__func__
);
return
-
EINVAL
;
rfkill
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
rfkill
),
GFP_KERNEL
);
if
(
!
rfkill
)
return
-
ENOMEM
;
if
(
ACPI_HANDLE
(
&
pdev
->
dev
))
{
ret
=
rfkill_gpio_acpi_probe
(
&
pdev
->
dev
,
rfkill
);
if
(
ret
)
return
ret
;
}
else
if
(
pdata
)
{
clk_name
=
pdata
->
power_clk_name
;
rfkill
->
name
=
pdata
->
name
;
rfkill
->
type
=
pdata
->
type
;
rfkill
->
reset_gpio
=
pdata
->
reset_gpio
;
rfkill
->
shutdown_gpio
=
pdata
->
shutdown_gpio
;
}
else
{
return
-
ENODEV
;
}
/* make sure at-least one of the GPIO is defined and that
* a name is specified for this instance */
if
(
!
pdata
->
name
||
(
!
gpio_is_valid
(
pdata
->
reset_gpio
)
&&
!
gpio_is_valid
(
pdata
->
shutdown_gpio
))
)
{
if
(
(
!
gpio_is_valid
(
rfkill
->
reset_gpio
)
&&
!
gpio_is_valid
(
rfkill
->
shutdown_gpio
))
||
!
rfkill
->
name
)
{
pr_warn
(
"%s: invalid platform data
\n
"
,
__func__
);
return
-
EINVAL
;
}
rfkill
=
kzalloc
(
sizeof
(
*
rfkill
),
GFP_KERNEL
);
if
(
!
rfkill
)
return
-
ENOMEM
;
if
(
pdata
->
gpio_runtime_setup
)
{
if
(
pdata
&&
pdata
->
gpio_runtime_setup
)
{
ret
=
pdata
->
gpio_runtime_setup
(
pdev
);
if
(
ret
)
{
pr_warn
(
"%s: can't set up gpio
\n
"
,
__func__
);
goto
fail_alloc
;
return
ret
;
}
}
rfkill
->
pdata
=
pdata
;
len
=
strlen
(
pdata
->
name
);
rfkill
->
reset_name
=
kzalloc
(
len
+
7
,
GFP_KERNEL
);
if
(
!
rfkill
->
reset_name
)
{
ret
=
-
ENOMEM
;
goto
fail_alloc
;
}
len
=
strlen
(
rfkill
->
name
);
rfkill
->
reset_name
=
devm_kzalloc
(
&
pdev
->
dev
,
len
+
7
,
GFP_KERNEL
);
if
(
!
rfkill
->
reset_name
)
return
-
ENOMEM
;
rfkill
->
shutdown_name
=
kzalloc
(
len
+
10
,
GFP_KERNEL
);
if
(
!
rfkill
->
shutdown_name
)
{
ret
=
-
ENOMEM
;
goto
fail_reset_name
;
}
rfkill
->
shutdown_name
=
devm_kzalloc
(
&
pdev
->
dev
,
len
+
10
,
GFP_KERNEL
);
if
(
!
rfkill
->
shutdown_name
)
return
-
ENOMEM
;
snprintf
(
rfkill
->
reset_name
,
len
+
6
,
"%s_reset"
,
pdata
->
name
);
snprintf
(
rfkill
->
shutdown_name
,
len
+
9
,
"%s_shutdown"
,
pdata
->
name
);
snprintf
(
rfkill
->
reset_name
,
len
+
6
,
"%s_reset"
,
rfkill
->
name
);
snprintf
(
rfkill
->
shutdown_name
,
len
+
9
,
"%s_shutdown"
,
rfkill
->
name
);
if
(
pdata
->
power_clk_name
)
{
rfkill
->
pwr_clk
=
clk_get
(
&
pdev
->
dev
,
pdata
->
power_clk_name
);
if
(
IS_ERR
(
rfkill
->
pwr_clk
))
{
pr_warn
(
"%s: can't find pwr_clk.
\n
"
,
__func__
);
ret
=
PTR_ERR
(
rfkill
->
pwr_clk
);
goto
fail_shutdown_name
;
}
}
rfkill
->
clk
=
devm_clk_get
(
&
pdev
->
dev
,
clk_name
);
if
(
gpio_is_valid
(
pdata
->
reset_gpio
))
{
ret
=
gpio_request
(
pdata
->
reset_gpio
,
rfkill
->
reset_name
);
if
(
gpio_is_valid
(
rfkill
->
reset_gpio
))
{
ret
=
devm_gpio_request_one
(
&
pdev
->
dev
,
rfkill
->
reset_gpio
,
0
,
rfkill
->
reset_name
);
if
(
ret
)
{
pr_warn
(
"%s: failed to get reset gpio.
\n
"
,
__func__
);
goto
fail_clock
;
return
ret
;
}
}
if
(
gpio_is_valid
(
pdata
->
shutdown_gpio
))
{
ret
=
gpio_request
(
pdata
->
shutdown_gpio
,
rfkill
->
shutdown_name
);
if
(
gpio_is_valid
(
rfkill
->
shutdown_gpio
))
{
ret
=
devm_gpio_request_one
(
&
pdev
->
dev
,
rfkill
->
shutdown_gpio
,
0
,
rfkill
->
shutdown_name
);
if
(
ret
)
{
pr_warn
(
"%s: failed to get shutdown gpio.
\n
"
,
__func__
);
goto
fail_res
et
;
return
r
et
;
}
}
rfkill
->
rfkill_dev
=
rfkill_alloc
(
pdata
->
name
,
&
pdev
->
dev
,
pdata
->
type
,
&
rfkill_gpio_ops
,
rfkill
);
if
(
!
rfkill
->
rfkill_dev
)
{
ret
=
-
ENOMEM
;
goto
fail_shutdown
;
}
rfkill
->
rfkill_dev
=
rfkill_alloc
(
rfkill
->
name
,
&
pdev
->
dev
,
rfkill
->
type
,
&
rfkill_gpio_ops
,
rfkill
);
if
(
!
rfkill
->
rfkill_dev
)
return
-
ENOMEM
;
ret
=
rfkill_register
(
rfkill
->
rfkill_dev
);
if
(
ret
<
0
)
goto
fail_rfkill
;
return
ret
;
platform_set_drvdata
(
pdev
,
rfkill
);
dev_info
(
&
pdev
->
dev
,
"%s device registered.
\n
"
,
pdata
->
name
);
dev_info
(
&
pdev
->
dev
,
"%s device registered.
\n
"
,
rfkill
->
name
);
return
0
;
fail_rfkill:
rfkill_destroy
(
rfkill
->
rfkill_dev
);
fail_shutdown:
if
(
gpio_is_valid
(
pdata
->
shutdown_gpio
))
gpio_free
(
pdata
->
shutdown_gpio
);
fail_reset:
if
(
gpio_is_valid
(
pdata
->
reset_gpio
))
gpio_free
(
pdata
->
reset_gpio
);
fail_clock:
if
(
rfkill
->
pwr_clk
)
clk_put
(
rfkill
->
pwr_clk
);
fail_shutdown_name:
kfree
(
rfkill
->
shutdown_name
);
fail_reset_name:
kfree
(
rfkill
->
reset_name
);
fail_alloc:
kfree
(
rfkill
);
return
ret
;
}
static
int
rfkill_gpio_remove
(
struct
platform_device
*
pdev
)
...
...
@@ -195,31 +185,26 @@ static int rfkill_gpio_remove(struct platform_device *pdev)
struct
rfkill_gpio_data
*
rfkill
=
platform_get_drvdata
(
pdev
);
struct
rfkill_gpio_platform_data
*
pdata
=
pdev
->
dev
.
platform_data
;
if
(
pdata
->
gpio_runtime_close
)
if
(
pdata
&&
pdata
->
gpio_runtime_close
)
pdata
->
gpio_runtime_close
(
pdev
);
rfkill_unregister
(
rfkill
->
rfkill_dev
);
rfkill_destroy
(
rfkill
->
rfkill_dev
);
if
(
gpio_is_valid
(
rfkill
->
pdata
->
shutdown_gpio
))
gpio_free
(
rfkill
->
pdata
->
shutdown_gpio
);
if
(
gpio_is_valid
(
rfkill
->
pdata
->
reset_gpio
))
gpio_free
(
rfkill
->
pdata
->
reset_gpio
);
if
(
rfkill
->
pwr_clk
&&
PWR_CLK_ENABLED
(
rfkill
))
clk_disable
(
rfkill
->
pwr_clk
);
if
(
rfkill
->
pwr_clk
)
clk_put
(
rfkill
->
pwr_clk
);
kfree
(
rfkill
->
shutdown_name
);
kfree
(
rfkill
->
reset_name
);
kfree
(
rfkill
);
return
0
;
}
static
const
struct
acpi_device_id
rfkill_acpi_match
[]
=
{
{
"BCM4752"
,
RFKILL_TYPE_GPS
},
{
},
};
static
struct
platform_driver
rfkill_gpio_driver
=
{
.
probe
=
rfkill_gpio_probe
,
.
remove
=
rfkill_gpio_remove
,
.
driver
=
{
.
name
=
"rfkill_gpio"
,
.
owner
=
THIS_MODULE
,
.
name
=
"rfkill_gpio"
,
.
owner
=
THIS_MODULE
,
.
acpi_match_table
=
ACPI_PTR
(
rfkill_acpi_match
),
},
};
...
...
net/wireless/chan.c
浏览文件 @
353c7815
...
...
@@ -504,7 +504,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
case
NL80211_IFTYPE_ADHOC
:
if
(
wdev
->
current_bss
)
{
*
chan
=
wdev
->
current_bss
->
pub
.
channel
;
*
chanmode
=
wdev
->
ibss_fixed
*
chanmode
=
(
wdev
->
ibss_fixed
&&
!
wdev
->
ibss_dfs_possible
)
?
CHAN_MODE_SHARED
:
CHAN_MODE_EXCLUSIVE
;
return
;
...
...
net/wireless/ibss.c
浏览文件 @
353c7815
...
...
@@ -83,6 +83,8 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
struct
cfg80211_cached_keys
*
connkeys
)
{
struct
wireless_dev
*
wdev
=
dev
->
ieee80211_ptr
;
struct
ieee80211_channel
*
check_chan
;
u8
radar_detect_width
=
0
;
int
err
;
ASSERT_WDEV_LOCK
(
wdev
);
...
...
@@ -114,14 +116,28 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
wdev
->
connect_keys
=
connkeys
;
wdev
->
ibss_fixed
=
params
->
channel_fixed
;
wdev
->
ibss_dfs_possible
=
params
->
userspace_handles_dfs
;
#ifdef CONFIG_CFG80211_WEXT
wdev
->
wext
.
ibss
.
chandef
=
params
->
chandef
;
#endif
check_chan
=
params
->
chandef
.
chan
;
if
(
params
->
userspace_handles_dfs
)
{
/* use channel NULL to check for radar even if the current
* channel is not a radar channel - it might decide to change
* to DFS channel later.
*/
radar_detect_width
=
BIT
(
params
->
chandef
.
width
);
check_chan
=
NULL
;
}
err
=
cfg80211_can_use_iftype_chan
(
rdev
,
wdev
,
wdev
->
iftype
,
check_chan
,
(
params
->
channel_fixed
&&
!
radar_detect_width
)
?
CHAN_MODE_SHARED
:
CHAN_MODE_EXCLUSIVE
,
radar_detect_width
);
err
=
cfg80211_can_use_chan
(
rdev
,
wdev
,
params
->
chandef
.
chan
,
params
->
channel_fixed
?
CHAN_MODE_SHARED
:
CHAN_MODE_EXCLUSIVE
);
if
(
err
)
{
wdev
->
connect_keys
=
NULL
;
return
err
;
...
...
net/wireless/nl80211.c
浏览文件 @
353c7815
...
...
@@ -354,6 +354,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[
NL80211_ATTR_CSA_IES
]
=
{
.
type
=
NLA_NESTED
},
[
NL80211_ATTR_CSA_C_OFF_BEACON
]
=
{
.
type
=
NLA_U16
},
[
NL80211_ATTR_CSA_C_OFF_PRESP
]
=
{
.
type
=
NLA_U16
},
[
NL80211_ATTR_STA_SUPPORTED_CHANNELS
]
=
{
.
type
=
NLA_BINARY
},
[
NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES
]
=
{
.
type
=
NLA_BINARY
},
[
NL80211_ATTR_HANDLE_DFS
]
=
{
.
type
=
NLA_FLAG
},
};
/* policy for the key attributes */
...
...
@@ -3896,9 +3899,45 @@ static int nl80211_parse_sta_wme(struct genl_info *info,
return
0
;
}
static
int
nl80211_parse_sta_channel_info
(
struct
genl_info
*
info
,
struct
station_parameters
*
params
)
{
if
(
info
->
attrs
[
NL80211_ATTR_STA_SUPPORTED_CHANNELS
])
{
params
->
supported_channels
=
nla_data
(
info
->
attrs
[
NL80211_ATTR_STA_SUPPORTED_CHANNELS
]);
params
->
supported_channels_len
=
nla_len
(
info
->
attrs
[
NL80211_ATTR_STA_SUPPORTED_CHANNELS
]);
/*
* Need to include at least one (first channel, number of
* channels) tuple for each subband, and must have proper
* tuples for the rest of the data as well.
*/
if
(
params
->
supported_channels_len
<
2
)
return
-
EINVAL
;
if
(
params
->
supported_channels_len
%
2
)
return
-
EINVAL
;
}
if
(
info
->
attrs
[
NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES
])
{
params
->
supported_oper_classes
=
nla_data
(
info
->
attrs
[
NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES
]);
params
->
supported_oper_classes_len
=
nla_len
(
info
->
attrs
[
NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES
]);
/*
* The value of the Length field of the Supported Operating
* Classes element is between 2 and 253.
*/
if
(
params
->
supported_oper_classes_len
<
2
||
params
->
supported_oper_classes_len
>
253
)
return
-
EINVAL
;
}
return
0
;
}
static
int
nl80211_set_station_tdls
(
struct
genl_info
*
info
,
struct
station_parameters
*
params
)
{
int
err
;
/* Dummy STA entry gets updated once the peer capabilities are known */
if
(
info
->
attrs
[
NL80211_ATTR_PEER_AID
])
params
->
aid
=
nla_get_u16
(
info
->
attrs
[
NL80211_ATTR_PEER_AID
]);
...
...
@@ -3909,6 +3948,10 @@ static int nl80211_set_station_tdls(struct genl_info *info,
params
->
vht_capa
=
nla_data
(
info
->
attrs
[
NL80211_ATTR_VHT_CAPABILITY
]);
err
=
nl80211_parse_sta_channel_info
(
info
,
params
);
if
(
err
)
return
err
;
return
nl80211_parse_sta_wme
(
info
,
params
);
}
...
...
@@ -4089,6 +4132,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
return
-
EINVAL
;
}
err
=
nl80211_parse_sta_channel_info
(
info
,
&
params
);
if
(
err
)
return
err
;
err
=
nl80211_parse_sta_wme
(
info
,
&
params
);
if
(
err
)
return
err
;
...
...
@@ -5653,6 +5700,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
return
-
EINVAL
;
break
;
case
NL80211_IFTYPE_ADHOC
:
case
NL80211_IFTYPE_MESH_POINT
:
break
;
default:
return
-
EOPNOTSUPP
;
...
...
@@ -5665,9 +5713,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
return
-
EINVAL
;
/* only important for AP, IBSS and mesh create IEs internally */
if
(
need_new_beacon
&&
(
!
info
->
attrs
[
NL80211_ATTR_CSA_IES
]
||
!
info
->
attrs
[
NL80211_ATTR_CSA_C_OFF_BEACON
]))
if
(
need_new_beacon
&&
!
info
->
attrs
[
NL80211_ATTR_CSA_IES
])
return
-
EINVAL
;
params
.
count
=
nla_get_u32
(
info
->
attrs
[
NL80211_ATTR_CH_SWITCH_COUNT
]);
...
...
@@ -5722,9 +5768,9 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
if
(
!
cfg80211_reg_can_beacon
(
&
rdev
->
wiphy
,
&
params
.
chandef
))
return
-
EINVAL
;
/* DFS channels are only supported for AP/P2P GO ... for now. */
if
(
dev
->
ieee80211_ptr
->
iftype
==
NL80211_IFTYPE_AP
||
dev
->
ieee80211_ptr
->
iftype
==
NL80211_IFTYPE_P2P_GO
)
{
dev
->
ieee80211_ptr
->
iftype
==
NL80211_IFTYPE_P2P_GO
||
dev
->
ieee80211_ptr
->
iftype
==
NL80211_IFTYPE_ADHOC
)
{
err
=
cfg80211_chandef_dfs_required
(
wdev
->
wiphy
,
&
params
.
chandef
);
if
(
err
<
0
)
{
...
...
@@ -6556,6 +6602,9 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss
.
control_port
=
nla_get_flag
(
info
->
attrs
[
NL80211_ATTR_CONTROL_PORT
]);
ibss
.
userspace_handles_dfs
=
nla_get_flag
(
info
->
attrs
[
NL80211_ATTR_HANDLE_DFS
]);
err
=
cfg80211_join_ibss
(
rdev
,
dev
,
&
ibss
,
connkeys
);
if
(
err
)
kfree
(
connkeys
);
...
...
@@ -10762,7 +10811,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
if
(
WARN_ON
(
wdev
->
iftype
!=
NL80211_IFTYPE_AP
&&
wdev
->
iftype
!=
NL80211_IFTYPE_P2P_GO
&&
wdev
->
iftype
!=
NL80211_IFTYPE_ADHOC
))
wdev
->
iftype
!=
NL80211_IFTYPE_ADHOC
&&
wdev
->
iftype
!=
NL80211_IFTYPE_MESH_POINT
))
goto
out
;
wdev
->
channel
=
chandef
->
chan
;
...
...
net/wireless/reg.c
浏览文件 @
353c7815
...
...
@@ -787,7 +787,6 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator)
EXPORT_SYMBOL
(
reg_initiator_name
);
#ifdef CONFIG_CFG80211_REG_DEBUG
static
void
chan_reg_rule_print_dbg
(
struct
ieee80211_channel
*
chan
,
const
struct
ieee80211_reg_rule
*
reg_rule
)
{
...
...
@@ -974,6 +973,13 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
}
#endif
static
bool
wiphy_strict_alpha2_regd
(
struct
wiphy
*
wiphy
)
{
if
(
wiphy
->
flags
&
WIPHY_FLAG_STRICT_REGULATORY
&&
!
(
wiphy
->
flags
&
WIPHY_FLAG_CUSTOM_REGULATORY
))
return
true
;
return
false
;
}
static
bool
ignore_reg_update
(
struct
wiphy
*
wiphy
,
enum
nl80211_reg_initiator
initiator
)
...
...
@@ -1000,7 +1006,7 @@ static bool ignore_reg_update(struct wiphy *wiphy,
* wiphy->regd will be set once the device has its own
* desired regulatory domain set
*/
if
(
wiphy
->
flags
&
WIPHY_FLAG_STRICT_REGULATORY
&&
!
wiphy
->
regd
&&
if
(
wiphy
_strict_alpha2_regd
(
wiphy
)
&&
!
wiphy
->
regd
&&
initiator
!=
NL80211_REGDOM_SET_BY_COUNTRY_IE
&&
!
is_world_regdom
(
lr
->
alpha2
))
{
REG_DBG_PRINT
(
"Ignoring regulatory request set by %s "
...
...
@@ -1706,8 +1712,8 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
}
EXPORT_SYMBOL
(
regulatory_hint
);
void
regulatory_hint_
11d
(
struct
wiphy
*
wiphy
,
enum
ieee80211_band
band
,
const
u8
*
country_ie
,
u8
country_ie_len
)
void
regulatory_hint_
country_ie
(
struct
wiphy
*
wiphy
,
enum
ieee80211_band
band
,
const
u8
*
country_ie
,
u8
country_ie_len
)
{
char
alpha2
[
2
];
enum
environment_cap
env
=
ENVIRON_ANY
;
...
...
net/wireless/reg.h
浏览文件 @
353c7815
...
...
@@ -58,7 +58,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
gfp_t
gfp
);
/**
* regulatory_hint_
11d
- hints a country IE as a regulatory domain
* regulatory_hint_
country_ie
- hints a country IE as a regulatory domain
* @wiphy: the wireless device giving the hint (used only for reporting
* conflicts)
* @band: the band on which the country IE was received on. This determines
...
...
@@ -78,7 +78,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
* not observed. For this reason if a triplet is seen with channel
* information for a band the BSS is not present in it will be ignored.
*/
void
regulatory_hint_
11d
(
struct
wiphy
*
wiphy
,
void
regulatory_hint_
country_ie
(
struct
wiphy
*
wiphy
,
enum
ieee80211_band
band
,
const
u8
*
country_ie
,
u8
country_ie_len
);
...
...
net/wireless/sme.c
浏览文件 @
353c7815
...
...
@@ -682,8 +682,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
* - country_ie + 2, the start of the country ie data, and
* - and country_ie[1] which is the IE length
*/
regulatory_hint_
11d
(
wdev
->
wiphy
,
bss
->
channel
->
band
,
country_ie
+
2
,
country_ie
[
1
]);
regulatory_hint_
country_ie
(
wdev
->
wiphy
,
bss
->
channel
->
band
,
country_ie
+
2
,
country_ie
[
1
]);
kfree
(
country_ie
);
}
...
...
net/wireless/util.c
浏览文件 @
353c7815
...
...
@@ -1249,7 +1249,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
enum
cfg80211_chan_mode
chmode
;
int
num_different_channels
=
0
;
int
total
=
1
;
bool
radar_required
;
bool
radar_required
=
false
;
int
i
,
j
;
ASSERT_RTNL
();
...
...
@@ -1264,14 +1264,20 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
case
NL80211_IFTYPE_MESH_POINT
:
case
NL80211_IFTYPE_P2P_GO
:
case
NL80211_IFTYPE_WDS
:
radar_required
=
!!
(
chan
&&
(
chan
->
flags
&
IEEE80211_CHAN_RADAR
));
/* if the interface could potentially choose a DFS channel,
* then mark DFS as required.
*/
if
(
!
chan
)
{
if
(
chanmode
!=
CHAN_MODE_UNDEFINED
&&
radar_detect
)
radar_required
=
true
;
break
;
}
radar_required
=
!!
(
chan
->
flags
&
IEEE80211_CHAN_RADAR
);
break
;
case
NL80211_IFTYPE_P2P_CLIENT
:
case
NL80211_IFTYPE_STATION
:
case
NL80211_IFTYPE_P2P_DEVICE
:
case
NL80211_IFTYPE_MONITOR
:
radar_required
=
false
;
break
;
case
NUM_NL80211_IFTYPES
:
case
NL80211_IFTYPE_UNSPECIFIED
:
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录