Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
fa597844
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
160
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
fa597844
编写于
8月 09, 2013
作者:
J
John W. Linville
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-john' of
git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
上级
2437f3c5
73da7d5b
变更
19
隐藏空白更改
内联
并排
Showing
19 changed file
with
772 addition
and
34 deletion
+772
-34
include/linux/ieee80211.h
include/linux/ieee80211.h
+9
-0
include/net/cfg80211.h
include/net/cfg80211.h
+33
-0
include/net/mac80211.h
include/net/mac80211.h
+37
-0
include/uapi/linux/nl80211.h
include/uapi/linux/nl80211.h
+30
-0
net/mac80211/cfg.c
net/mac80211/cfg.c
+185
-2
net/mac80211/chan.c
net/mac80211/chan.c
+58
-0
net/mac80211/debugfs_sta.c
net/mac80211/debugfs_sta.c
+9
-0
net/mac80211/driver-ops.h
net/mac80211/driver-ops.h
+13
-0
net/mac80211/ibss.c
net/mac80211/ibss.c
+29
-1
net/mac80211/ieee80211_i.h
net/mac80211/ieee80211_i.h
+17
-1
net/mac80211/iface.c
net/mac80211/iface.c
+9
-0
net/mac80211/led.c
net/mac80211/led.c
+7
-12
net/mac80211/led.h
net/mac80211/led.h
+2
-2
net/mac80211/status.c
net/mac80211/status.c
+64
-14
net/mac80211/trace.h
net/mac80211/trace.h
+26
-0
net/mac80211/tx.c
net/mac80211/tx.c
+78
-1
net/wireless/nl80211.c
net/wireless/nl80211.c
+121
-1
net/wireless/rdev-ops.h
net/wireless/rdev-ops.h
+12
-0
net/wireless/trace.h
net/wireless/trace.h
+33
-0
未找到文件。
include/linux/ieee80211.h
浏览文件 @
fa597844
...
...
@@ -1709,6 +1709,10 @@ enum ieee80211_eid {
WLAN_EID_OPMODE_NOTIF
=
199
,
WLAN_EID_WIDE_BW_CHANNEL_SWITCH
=
194
,
WLAN_EID_CHANNEL_SWITCH_WRAPPER
=
196
,
WLAN_EID_EXTENDED_BSS_LOAD
=
193
,
WLAN_EID_VHT_TX_POWER_ENVELOPE
=
195
,
WLAN_EID_AID
=
197
,
WLAN_EID_QUIET_CHANNEL
=
198
,
/* 802.11ad */
WLAN_EID_NON_TX_BSSID_CAP
=
83
,
...
...
@@ -1860,6 +1864,11 @@ enum ieee80211_tdls_actioncode {
WLAN_TDLS_DISCOVERY_REQUEST
=
10
,
};
/* Interworking capabilities are set in 7th bit of 4th byte of the
* @WLAN_EID_EXT_CAPABILITY information element
*/
#define WLAN_EXT_CAPA4_INTERWORKING_ENABLED BIT(7)
/*
* TDLS capabililites to be enabled in the 5th byte of the
* @WLAN_EID_EXT_CAPABILITY information element
...
...
include/net/cfg80211.h
浏览文件 @
fa597844
...
...
@@ -665,6 +665,30 @@ struct cfg80211_ap_settings {
bool
radar_required
;
};
/**
* struct cfg80211_csa_settings - channel switch settings
*
* Used for channel switch
*
* @chandef: defines the channel to use after the switch
* @beacon_csa: beacon data while performing the switch
* @counter_offset_beacon: offset for the counter within the beacon (tail)
* @counter_offset_presp: offset for the counter within the probe response
* @beacon_after: beacon data to be used on the new channel
* @radar_required: whether radar detection is required on the new channel
* @block_tx: whether transmissions should be blocked while changing
* @count: number of beacons until switch
*/
struct
cfg80211_csa_settings
{
struct
cfg80211_chan_def
chandef
;
struct
cfg80211_beacon_data
beacon_csa
;
u16
counter_offset_beacon
,
counter_offset_presp
;
struct
cfg80211_beacon_data
beacon_after
;
bool
radar_required
;
bool
block_tx
;
u8
count
;
};
/**
* enum station_parameters_apply_mask - station parameter values to apply
* @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
...
...
@@ -2139,6 +2163,8 @@ struct cfg80211_update_ft_ies_params {
* @crit_proto_stop: Indicates critical protocol no longer needs increased link
* reliability. This operation can not fail.
* @set_coalesce: Set coalesce parameters.
*
* @channel_switch: initiate channel-switch procedure (with CSA)
*/
struct
cfg80211_ops
{
int
(
*
suspend
)(
struct
wiphy
*
wiphy
,
struct
cfg80211_wowlan
*
wow
);
...
...
@@ -2376,6 +2402,10 @@ struct cfg80211_ops {
struct
wireless_dev
*
wdev
);
int
(
*
set_coalesce
)(
struct
wiphy
*
wiphy
,
struct
cfg80211_coalesce
*
coalesce
);
int
(
*
channel_switch
)(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
struct
cfg80211_csa_settings
*
params
);
};
/*
...
...
@@ -2441,6 +2471,8 @@ struct cfg80211_ops {
* @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX.
* @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call.
* @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
* @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in
* beaconing mode (AP, IBSS, Mesh, ...).
*/
enum
wiphy_flags
{
WIPHY_FLAG_CUSTOM_REGULATORY
=
BIT
(
0
),
...
...
@@ -2465,6 +2497,7 @@ enum wiphy_flags {
WIPHY_FLAG_OFFCHAN_TX
=
BIT
(
20
),
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL
=
BIT
(
21
),
WIPHY_FLAG_SUPPORTS_5_10_MHZ
=
BIT
(
22
),
WIPHY_FLAG_HAS_CHANNEL_SWITCH
=
BIT
(
23
),
};
/**
...
...
include/net/mac80211.h
浏览文件 @
fa597844
...
...
@@ -152,11 +152,14 @@ struct ieee80211_low_level_stats {
* @IEEE80211_CHANCTX_CHANGE_WIDTH: The channel width changed
* @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed
* @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed
* @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel,
* this is used only with channel switching with CSA
*/
enum
ieee80211_chanctx_change
{
IEEE80211_CHANCTX_CHANGE_WIDTH
=
BIT
(
0
),
IEEE80211_CHANCTX_CHANGE_RX_CHAINS
=
BIT
(
1
),
IEEE80211_CHANCTX_CHANGE_RADAR
=
BIT
(
2
),
IEEE80211_CHANCTX_CHANGE_CHANNEL
=
BIT
(
3
),
};
/**
...
...
@@ -1084,6 +1087,7 @@ enum ieee80211_vif_flags {
* @addr: address of this interface
* @p2p: indicates whether this AP or STA interface is a p2p
* interface, i.e. a GO or p2p-sta respectively
* @csa_active: marks whether a channel switch is going on
* @driver_flags: flags/capabilities the driver has for this interface,
* these need to be set (or cleared) when the interface is added
* or, if supported by the driver, the interface type is changed
...
...
@@ -1106,6 +1110,7 @@ struct ieee80211_vif {
struct
ieee80211_bss_conf
bss_conf
;
u8
addr
[
ETH_ALEN
];
bool
p2p
;
bool
csa_active
;
u8
cab_queue
;
u8
hw_queue
[
IEEE80211_NUM_ACS
];
...
...
@@ -2637,6 +2642,16 @@ enum ieee80211_roc_type {
* @ipv6_addr_change: IPv6 address assignment on the given interface changed.
* Currently, this is only called for managed or P2P client interfaces.
* This callback is optional; it must not sleep.
*
* @channel_switch_beacon: Starts a channel switch to a new channel.
* Beacons are modified to include CSA or ECSA IEs before calling this
* function. The corresponding count fields in these IEs must be
* decremented, and when they reach zero the driver must call
* ieee80211_csa_finish(). Drivers which use ieee80211_beacon_get()
* get the csa counter decremented by mac80211, but must check if it is
* zero using ieee80211_csa_is_complete() after the beacon has been
* transmitted and then call ieee80211_csa_finish().
*
*/
struct
ieee80211_ops
{
void
(
*
tx
)(
struct
ieee80211_hw
*
hw
,
...
...
@@ -2824,6 +2839,9 @@ struct ieee80211_ops {
struct
ieee80211_vif
*
vif
,
struct
inet6_dev
*
idev
);
#endif
void
(
*
channel_switch_beacon
)(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
cfg80211_chan_def
*
chandef
);
};
/**
...
...
@@ -3318,6 +3336,25 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
return
ieee80211_beacon_get_tim
(
hw
,
vif
,
NULL
,
NULL
);
}
/**
* ieee80211_csa_finish - notify mac80211 about channel switch
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
*
* After a channel switch announcement was scheduled and the counter in this
* announcement hit zero, this function must be called by the driver to
* notify mac80211 that the channel can be changed.
*/
void
ieee80211_csa_finish
(
struct
ieee80211_vif
*
vif
);
/**
* ieee80211_csa_is_complete - find out if counters reached zero
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
*
* This function returns whether the channel switch counters reached zero.
*/
bool
ieee80211_csa_is_complete
(
struct
ieee80211_vif
*
vif
);
/**
* ieee80211_proberesp_get - retrieve a Probe Response template
* @hw: pointer obtained from ieee80211_alloc_hw().
...
...
include/uapi/linux/nl80211.h
浏览文件 @
fa597844
...
...
@@ -676,6 +676,16 @@
* @NL80211_CMD_GET_COALESCE: Get currently supported coalesce rules.
* @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules.
*
* @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the
* the new channel information (Channel Switch Announcement - CSA)
* in the beacon for some time (as defined in the
* %NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the
* new channel. Userspace provides the new channel information (using
* %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel
* width). %NL80211_ATTR_CH_SWITCH_BLOCK_TX may be supplied to inform
* other station that transmission must be blocked until the channel
* switch is complete.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
...
...
@@ -841,6 +851,8 @@ enum nl80211_commands {
NL80211_CMD_GET_COALESCE
,
NL80211_CMD_SET_COALESCE
,
NL80211_CMD_CHANNEL_SWITCH
,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
...
...
@@ -1469,6 +1481,18 @@ enum nl80211_commands {
*
* @NL80211_ATTR_COALESCE_RULE: Coalesce rule information.
*
* @NL80211_ATTR_CH_SWITCH_COUNT: u32 attribute specifying the number of TBTT's
* until the channel switch event.
* @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
* must be blocked on the current channel (before the channel switch
* operation).
* @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
* for the time while performing a channel switch.
* @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter
* field in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
* @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter
* field in the probe response (%NL80211_ATTR_PROBE_RESP).
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
...
...
@@ -1771,6 +1795,12 @@ enum nl80211_attrs {
NL80211_ATTR_COALESCE_RULE
,
NL80211_ATTR_CH_SWITCH_COUNT
,
NL80211_ATTR_CH_SWITCH_BLOCK_TX
,
NL80211_ATTR_CSA_IES
,
NL80211_ATTR_CSA_C_OFF_BEACON
,
NL80211_ATTR_CSA_C_OFF_PRESP
,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST
,
...
...
net/mac80211/cfg.c
浏览文件 @
fa597844
...
...
@@ -862,8 +862,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
return
0
;
}
static
int
ieee80211_assign_beacon
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
cfg80211_beacon_data
*
params
)
int
ieee80211_assign_beacon
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
cfg80211_beacon_data
*
params
)
{
struct
beacon_data
*
new
,
*
old
;
int
new_head_len
,
new_tail_len
;
...
...
@@ -1026,6 +1026,12 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
sdata
=
IEEE80211_DEV_TO_SUB_IF
(
dev
);
/* don't allow changing the beacon while CSA is in place - offset
* of channel switch counter may change
*/
if
(
sdata
->
vif
.
csa_active
)
return
-
EBUSY
;
old
=
rtnl_dereference
(
sdata
->
u
.
ap
.
beacon
);
if
(
!
old
)
return
-
ENOENT
;
...
...
@@ -1050,6 +1056,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
return
-
ENOENT
;
old_probe_resp
=
rtnl_dereference
(
sdata
->
u
.
ap
.
probe_resp
);
/* abort any running channel switch */
sdata
->
vif
.
csa_active
=
false
;
cancel_work_sync
(
&
sdata
->
csa_finalize_work
);
/* turn off carrier for this interface and dependent VLANs */
list_for_each_entry
(
vlan
,
&
sdata
->
u
.
ap
.
vlans
,
u
.
vlan
.
list
)
netif_carrier_off
(
vlan
->
dev
);
...
...
@@ -2777,6 +2787,178 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
return
0
;
}
static
struct
cfg80211_beacon_data
*
cfg80211_beacon_dup
(
struct
cfg80211_beacon_data
*
beacon
)
{
struct
cfg80211_beacon_data
*
new_beacon
;
u8
*
pos
;
int
len
;
len
=
beacon
->
head_len
+
beacon
->
tail_len
+
beacon
->
beacon_ies_len
+
beacon
->
proberesp_ies_len
+
beacon
->
assocresp_ies_len
+
beacon
->
probe_resp_len
;
new_beacon
=
kzalloc
(
sizeof
(
*
new_beacon
)
+
len
,
GFP_KERNEL
);
if
(
!
new_beacon
)
return
NULL
;
pos
=
(
u8
*
)(
new_beacon
+
1
);
if
(
beacon
->
head_len
)
{
new_beacon
->
head_len
=
beacon
->
head_len
;
new_beacon
->
head
=
pos
;
memcpy
(
pos
,
beacon
->
head
,
beacon
->
head_len
);
pos
+=
beacon
->
head_len
;
}
if
(
beacon
->
tail_len
)
{
new_beacon
->
tail_len
=
beacon
->
tail_len
;
new_beacon
->
tail
=
pos
;
memcpy
(
pos
,
beacon
->
tail
,
beacon
->
tail_len
);
pos
+=
beacon
->
tail_len
;
}
if
(
beacon
->
beacon_ies_len
)
{
new_beacon
->
beacon_ies_len
=
beacon
->
beacon_ies_len
;
new_beacon
->
beacon_ies
=
pos
;
memcpy
(
pos
,
beacon
->
beacon_ies
,
beacon
->
beacon_ies_len
);
pos
+=
beacon
->
beacon_ies_len
;
}
if
(
beacon
->
proberesp_ies_len
)
{
new_beacon
->
proberesp_ies_len
=
beacon
->
proberesp_ies_len
;
new_beacon
->
proberesp_ies
=
pos
;
memcpy
(
pos
,
beacon
->
proberesp_ies
,
beacon
->
proberesp_ies_len
);
pos
+=
beacon
->
proberesp_ies_len
;
}
if
(
beacon
->
assocresp_ies_len
)
{
new_beacon
->
assocresp_ies_len
=
beacon
->
assocresp_ies_len
;
new_beacon
->
assocresp_ies
=
pos
;
memcpy
(
pos
,
beacon
->
assocresp_ies
,
beacon
->
assocresp_ies_len
);
pos
+=
beacon
->
assocresp_ies_len
;
}
if
(
beacon
->
probe_resp_len
)
{
new_beacon
->
probe_resp_len
=
beacon
->
probe_resp_len
;
beacon
->
probe_resp
=
pos
;
memcpy
(
pos
,
beacon
->
probe_resp
,
beacon
->
probe_resp_len
);
pos
+=
beacon
->
probe_resp_len
;
}
return
new_beacon
;
}
void
ieee80211_csa_finalize_work
(
struct
work_struct
*
work
)
{
struct
ieee80211_sub_if_data
*
sdata
=
container_of
(
work
,
struct
ieee80211_sub_if_data
,
csa_finalize_work
);
struct
ieee80211_local
*
local
=
sdata
->
local
;
int
err
,
changed
;
if
(
!
ieee80211_sdata_running
(
sdata
))
return
;
if
(
WARN_ON
(
sdata
->
vif
.
type
!=
NL80211_IFTYPE_AP
))
return
;
sdata
->
radar_required
=
sdata
->
csa_radar_required
;
err
=
ieee80211_vif_change_channel
(
sdata
,
&
local
->
csa_chandef
,
&
changed
);
if
(
WARN_ON
(
err
<
0
))
return
;
err
=
ieee80211_assign_beacon
(
sdata
,
sdata
->
u
.
ap
.
next_beacon
);
if
(
err
<
0
)
return
;
changed
|=
err
;
kfree
(
sdata
->
u
.
ap
.
next_beacon
);
sdata
->
u
.
ap
.
next_beacon
=
NULL
;
sdata
->
vif
.
csa_active
=
false
;
ieee80211_wake_queues_by_reason
(
&
sdata
->
local
->
hw
,
IEEE80211_MAX_QUEUE_MAP
,
IEEE80211_QUEUE_STOP_REASON_CSA
);
ieee80211_bss_info_change_notify
(
sdata
,
changed
);
cfg80211_ch_switch_notify
(
sdata
->
dev
,
&
local
->
csa_chandef
);
}
static
int
ieee80211_channel_switch
(
struct
wiphy
*
wiphy
,
struct
net_device
*
dev
,
struct
cfg80211_csa_settings
*
params
)
{
struct
ieee80211_sub_if_data
*
sdata
=
IEEE80211_DEV_TO_SUB_IF
(
dev
);
struct
ieee80211_local
*
local
=
sdata
->
local
;
struct
ieee80211_chanctx_conf
*
chanctx_conf
;
struct
ieee80211_chanctx
*
chanctx
;
int
err
,
num_chanctx
;
if
(
!
list_empty
(
&
local
->
roc_list
)
||
local
->
scanning
)
return
-
EBUSY
;
if
(
sdata
->
wdev
.
cac_started
)
return
-
EBUSY
;
if
(
cfg80211_chandef_identical
(
&
params
->
chandef
,
&
sdata
->
vif
.
bss_conf
.
chandef
))
return
-
EINVAL
;
rcu_read_lock
();
chanctx_conf
=
rcu_dereference
(
sdata
->
vif
.
chanctx_conf
);
if
(
!
chanctx_conf
)
{
rcu_read_unlock
();
return
-
EBUSY
;
}
/* don't handle for multi-VIF cases */
chanctx
=
container_of
(
chanctx_conf
,
struct
ieee80211_chanctx
,
conf
);
if
(
chanctx
->
refcount
>
1
)
{
rcu_read_unlock
();
return
-
EBUSY
;
}
num_chanctx
=
0
;
list_for_each_entry_rcu
(
chanctx
,
&
local
->
chanctx_list
,
list
)
num_chanctx
++
;
rcu_read_unlock
();
if
(
num_chanctx
>
1
)
return
-
EBUSY
;
/* don't allow another channel switch if one is already active. */
if
(
sdata
->
vif
.
csa_active
)
return
-
EBUSY
;
/* only handle AP for now. */
switch
(
sdata
->
vif
.
type
)
{
case
NL80211_IFTYPE_AP
:
break
;
default:
return
-
EOPNOTSUPP
;
}
sdata
->
u
.
ap
.
next_beacon
=
cfg80211_beacon_dup
(
&
params
->
beacon_after
);
if
(
!
sdata
->
u
.
ap
.
next_beacon
)
return
-
ENOMEM
;
sdata
->
csa_counter_offset_beacon
=
params
->
counter_offset_beacon
;
sdata
->
csa_counter_offset_presp
=
params
->
counter_offset_presp
;
sdata
->
csa_radar_required
=
params
->
radar_required
;
if
(
params
->
block_tx
)
ieee80211_stop_queues_by_reason
(
&
local
->
hw
,
IEEE80211_MAX_QUEUE_MAP
,
IEEE80211_QUEUE_STOP_REASON_CSA
);
err
=
ieee80211_assign_beacon
(
sdata
,
&
params
->
beacon_csa
);
if
(
err
<
0
)
return
err
;
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
0
;
}
static
int
ieee80211_mgmt_tx
(
struct
wiphy
*
wiphy
,
struct
wireless_dev
*
wdev
,
struct
ieee80211_channel
*
chan
,
bool
offchan
,
unsigned
int
wait
,
const
u8
*
buf
,
size_t
len
,
...
...
@@ -3494,4 +3676,5 @@ struct cfg80211_ops mac80211_config_ops = {
.
get_et_strings
=
ieee80211_get_et_strings
,
.
get_channel
=
ieee80211_cfg_get_channel
,
.
start_radar_detection
=
ieee80211_start_radar_detection
,
.
channel_switch
=
ieee80211_channel_switch
,
};
net/mac80211/chan.c
浏览文件 @
fa597844
...
...
@@ -410,6 +410,64 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
return
ret
;
}
int
ieee80211_vif_change_channel
(
struct
ieee80211_sub_if_data
*
sdata
,
const
struct
cfg80211_chan_def
*
chandef
,
u32
*
changed
)
{
struct
ieee80211_local
*
local
=
sdata
->
local
;
struct
ieee80211_chanctx_conf
*
conf
;
struct
ieee80211_chanctx
*
ctx
;
int
ret
;
u32
chanctx_changed
=
0
;
/* should never be called if not performing a channel switch. */
if
(
WARN_ON
(
!
sdata
->
vif
.
csa_active
))
return
-
EINVAL
;
if
(
!
cfg80211_chandef_usable
(
sdata
->
local
->
hw
.
wiphy
,
chandef
,
IEEE80211_CHAN_DISABLED
))
return
-
EINVAL
;
mutex_lock
(
&
local
->
chanctx_mtx
);
conf
=
rcu_dereference_protected
(
sdata
->
vif
.
chanctx_conf
,
lockdep_is_held
(
&
local
->
chanctx_mtx
));
if
(
!
conf
)
{
ret
=
-
EINVAL
;
goto
out
;
}
ctx
=
container_of
(
conf
,
struct
ieee80211_chanctx
,
conf
);
if
(
ctx
->
refcount
!=
1
)
{
ret
=
-
EINVAL
;
goto
out
;
}
if
(
sdata
->
vif
.
bss_conf
.
chandef
.
width
!=
chandef
->
width
)
{
chanctx_changed
=
IEEE80211_CHANCTX_CHANGE_WIDTH
;
*
changed
|=
BSS_CHANGED_BANDWIDTH
;
}
sdata
->
vif
.
bss_conf
.
chandef
=
*
chandef
;
ctx
->
conf
.
def
=
*
chandef
;
chanctx_changed
|=
IEEE80211_CHANCTX_CHANGE_CHANNEL
;
drv_change_chanctx
(
local
,
ctx
,
chanctx_changed
);
if
(
!
local
->
use_chanctx
)
{
local
->
_oper_chandef
=
*
chandef
;
ieee80211_hw_config
(
local
,
0
);
}
ieee80211_recalc_chanctx_chantype
(
local
,
ctx
);
ieee80211_recalc_smps_chanctx
(
local
,
ctx
);
ieee80211_recalc_radar_chanctx
(
local
,
ctx
);
ret
=
0
;
out:
mutex_unlock
(
&
local
->
chanctx_mtx
);
return
ret
;
}
int
ieee80211_vif_change_bandwidth
(
struct
ieee80211_sub_if_data
*
sdata
,
const
struct
cfg80211_chan_def
*
chandef
,
u32
*
changed
)
...
...
net/mac80211/debugfs_sta.c
浏览文件 @
fa597844
...
...
@@ -455,6 +455,15 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD_COUNTER
(
tx_retry_count
,
tx_retry_count
);
DEBUGFS_ADD_COUNTER
(
wep_weak_iv_count
,
wep_weak_iv_count
);
if
(
sizeof
(
sta
->
driver_buffered_tids
)
==
sizeof
(
u32
))
debugfs_create_x32
(
"driver_buffered_tids"
,
0400
,
sta
->
debugfs
.
dir
,
(
u32
*
)
&
sta
->
driver_buffered_tids
);
else
debugfs_create_x64
(
"driver_buffered_tids"
,
0400
,
sta
->
debugfs
.
dir
,
(
u64
*
)
&
sta
->
driver_buffered_tids
);
drv_sta_add_debugfs
(
local
,
sdata
,
&
sta
->
sta
,
sta
->
debugfs
.
dir
);
}
...
...
net/mac80211/driver-ops.h
浏览文件 @
fa597844
...
...
@@ -1072,4 +1072,17 @@ static inline void drv_ipv6_addr_change(struct ieee80211_local *local,
}
#endif
static
inline
void
drv_channel_switch_beacon
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
cfg80211_chan_def
*
chandef
)
{
struct
ieee80211_local
*
local
=
sdata
->
local
;
if
(
local
->
ops
->
channel_switch_beacon
)
{
trace_drv_channel_switch_beacon
(
local
,
sdata
,
chandef
);
local
->
ops
->
channel_switch_beacon
(
&
local
->
hw
,
&
sdata
->
vif
,
chandef
);
}
}
#endif
/* __MAC80211_DRIVER_OPS */
net/mac80211/ibss.c
浏览文件 @
fa597844
...
...
@@ -30,6 +30,7 @@
#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
#define IEEE80211_IBSS_RSN_INACTIVITY_LIMIT (10 * HZ)
#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
...
...
@@ -740,6 +741,33 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
return
active
;
}
static
void
ieee80211_ibss_sta_expire
(
struct
ieee80211_sub_if_data
*
sdata
)
{
struct
ieee80211_local
*
local
=
sdata
->
local
;
struct
sta_info
*
sta
,
*
tmp
;
unsigned
long
exp_time
=
IEEE80211_IBSS_INACTIVITY_LIMIT
;
unsigned
long
exp_rsn_time
=
IEEE80211_IBSS_RSN_INACTIVITY_LIMIT
;
mutex_lock
(
&
local
->
sta_mtx
);
list_for_each_entry_safe
(
sta
,
tmp
,
&
local
->
sta_list
,
list
)
{
if
(
sdata
!=
sta
->
sdata
)
continue
;
if
(
time_after
(
jiffies
,
sta
->
last_rx
+
exp_time
)
||
(
time_after
(
jiffies
,
sta
->
last_rx
+
exp_rsn_time
)
&&
sta
->
sta_state
!=
IEEE80211_STA_AUTHORIZED
))
{
sta_dbg
(
sta
->
sdata
,
"expiring inactive %sSTA %pM
\n
"
,
sta
->
sta_state
!=
IEEE80211_STA_AUTHORIZED
?
"not authorized "
:
""
,
sta
->
sta
.
addr
);
WARN_ON
(
__sta_info_destroy
(
sta
));
}
}
mutex_unlock
(
&
local
->
sta_mtx
);
}
/*
* This function is called with state == IEEE80211_IBSS_MLME_JOINED
*/
...
...
@@ -754,7 +782,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
mod_timer
(
&
ifibss
->
timer
,
round_jiffies
(
jiffies
+
IEEE80211_IBSS_MERGE_INTERVAL
));
ieee80211_
sta_expire
(
sdata
,
IEEE80211_IBSS_INACTIVITY_LIMIT
);
ieee80211_
ibss_sta_expire
(
sdata
);
if
(
time_before
(
jiffies
,
ifibss
->
last_scan_completed
+
IEEE80211_IBSS_MERGE_INTERVAL
))
...
...
net/mac80211/ieee80211_i.h
浏览文件 @
fa597844
...
...
@@ -259,6 +259,8 @@ struct ieee80211_if_ap {
struct
beacon_data
__rcu
*
beacon
;
struct
probe_resp
__rcu
*
probe_resp
;
/* to be used after channel switch. */
struct
cfg80211_beacon_data
*
next_beacon
;
struct
list_head
vlans
;
struct
ps_data
ps
;
...
...
@@ -716,6 +718,11 @@ struct ieee80211_sub_if_data {
struct
ieee80211_tx_queue_params
tx_conf
[
IEEE80211_NUM_ACS
];
struct
work_struct
csa_finalize_work
;
int
csa_counter_offset_beacon
;
int
csa_counter_offset_presp
;
bool
csa_radar_required
;
/* used to reconfigure hardware SM PS */
struct
work_struct
recalc_smps
;
...
...
@@ -1094,7 +1101,6 @@ struct ieee80211_local {
u32
dot11TransmittedFrameCount
;
#ifdef CONFIG_MAC80211_LEDS
int
tx_led_counter
,
rx_led_counter
;
struct
led_trigger
*
tx_led
,
*
rx_led
,
*
assoc_led
,
*
radio_led
;
struct
tpt_led_trigger
*
tpt_led_trigger
;
char
tx_led_name
[
32
],
rx_led_name
[
32
],
...
...
@@ -1373,6 +1379,9 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free);
void
ieee80211_sw_roc_work
(
struct
work_struct
*
work
);
void
ieee80211_handle_roc_started
(
struct
ieee80211_roc_work
*
roc
);
/* channel switch handling */
void
ieee80211_csa_finalize_work
(
struct
work_struct
*
work
);
/* interface handling */
int
ieee80211_iface_init
(
void
);
void
ieee80211_iface_exit
(
void
);
...
...
@@ -1394,6 +1403,8 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
bool
__ieee80211_recalc_txpower
(
struct
ieee80211_sub_if_data
*
sdata
);
void
ieee80211_recalc_txpower
(
struct
ieee80211_sub_if_data
*
sdata
);
int
ieee80211_assign_beacon
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
cfg80211_beacon_data
*
params
);
static
inline
bool
ieee80211_sdata_running
(
struct
ieee80211_sub_if_data
*
sdata
)
{
...
...
@@ -1655,6 +1666,11 @@ int __must_check
ieee80211_vif_change_bandwidth
(
struct
ieee80211_sub_if_data
*
sdata
,
const
struct
cfg80211_chan_def
*
chandef
,
u32
*
changed
);
/* NOTE: only use ieee80211_vif_change_channel() for channel switch */
int
__must_check
ieee80211_vif_change_channel
(
struct
ieee80211_sub_if_data
*
sdata
,
const
struct
cfg80211_chan_def
*
chandef
,
u32
*
changed
);
void
ieee80211_vif_release_channel
(
struct
ieee80211_sub_if_data
*
sdata
);
void
ieee80211_vif_vlan_copy_chanctx
(
struct
ieee80211_sub_if_data
*
sdata
);
void
ieee80211_vif_copy_chanctx_to_vlans
(
struct
ieee80211_sub_if_data
*
sdata
,
...
...
net/mac80211/iface.c
浏览文件 @
fa597844
...
...
@@ -274,6 +274,12 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
if
(
iftype
==
NL80211_IFTYPE_ADHOC
&&
nsdata
->
vif
.
type
==
NL80211_IFTYPE_ADHOC
)
return
-
EBUSY
;
/*
* will not add another interface while any channel
* switch is active.
*/
if
(
nsdata
->
vif
.
csa_active
)
return
-
EBUSY
;
/*
* The remaining checks are only performed for interfaces
...
...
@@ -804,6 +810,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
cancel_work_sync
(
&
local
->
dynamic_ps_enable_work
);
cancel_work_sync
(
&
sdata
->
recalc_smps
);
sdata
->
vif
.
csa_active
=
false
;
cancel_work_sync
(
&
sdata
->
csa_finalize_work
);
cancel_delayed_work_sync
(
&
sdata
->
dfs_cac_timer_work
);
...
...
@@ -1267,6 +1275,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
skb_queue_head_init
(
&
sdata
->
skb_queue
);
INIT_WORK
(
&
sdata
->
work
,
ieee80211_iface_work
);
INIT_WORK
(
&
sdata
->
recalc_smps
,
ieee80211_recalc_smps_work
);
INIT_WORK
(
&
sdata
->
csa_finalize_work
,
ieee80211_csa_finalize_work
);
switch
(
type
)
{
case
NL80211_IFTYPE_P2P_GO
:
...
...
net/mac80211/led.c
浏览文件 @
fa597844
...
...
@@ -12,27 +12,22 @@
#include <linux/export.h>
#include "led.h"
#define MAC80211_BLINK_DELAY 50
/* ms */
void
ieee80211_led_rx
(
struct
ieee80211_local
*
local
)
{
unsigned
long
led_delay
=
MAC80211_BLINK_DELAY
;
if
(
unlikely
(
!
local
->
rx_led
))
return
;
if
(
local
->
rx_led_counter
++
%
2
==
0
)
led_trigger_event
(
local
->
rx_led
,
LED_OFF
);
else
led_trigger_event
(
local
->
rx_led
,
LED_FULL
);
led_trigger_blink_oneshot
(
local
->
rx_led
,
&
led_delay
,
&
led_delay
,
0
);
}
/* q is 1 if a packet was enqueued, 0 if it has been transmitted */
void
ieee80211_led_tx
(
struct
ieee80211_local
*
local
,
int
q
)
void
ieee80211_led_tx
(
struct
ieee80211_local
*
local
)
{
unsigned
long
led_delay
=
MAC80211_BLINK_DELAY
;
if
(
unlikely
(
!
local
->
tx_led
))
return
;
/* not sure how this is supposed to work ... */
local
->
tx_led_counter
+=
2
*
q
-
1
;
if
(
local
->
tx_led_counter
%
2
==
0
)
led_trigger_event
(
local
->
tx_led
,
LED_OFF
);
else
led_trigger_event
(
local
->
tx_led
,
LED_FULL
);
led_trigger_blink_oneshot
(
local
->
tx_led
,
&
led_delay
,
&
led_delay
,
0
);
}
void
ieee80211_led_assoc
(
struct
ieee80211_local
*
local
,
bool
associated
)
...
...
net/mac80211/led.h
浏览文件 @
fa597844
...
...
@@ -13,7 +13,7 @@
#ifdef CONFIG_MAC80211_LEDS
void
ieee80211_led_rx
(
struct
ieee80211_local
*
local
);
void
ieee80211_led_tx
(
struct
ieee80211_local
*
local
,
int
q
);
void
ieee80211_led_tx
(
struct
ieee80211_local
*
local
);
void
ieee80211_led_assoc
(
struct
ieee80211_local
*
local
,
bool
associated
);
void
ieee80211_led_radio
(
struct
ieee80211_local
*
local
,
...
...
@@ -27,7 +27,7 @@ void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
static
inline
void
ieee80211_led_rx
(
struct
ieee80211_local
*
local
)
{
}
static
inline
void
ieee80211_led_tx
(
struct
ieee80211_local
*
local
,
int
q
)
static
inline
void
ieee80211_led_tx
(
struct
ieee80211_local
*
local
)
{
}
static
inline
void
ieee80211_led_assoc
(
struct
ieee80211_local
*
local
,
...
...
net/mac80211/status.c
浏览文件 @
fa597844
...
...
@@ -235,7 +235,8 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info)
/* IEEE80211_RADIOTAP_RATE rate */
if
(
info
->
status
.
rates
[
0
].
idx
>=
0
&&
!
(
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_MCS
))
!
(
info
->
status
.
rates
[
0
].
flags
&
(
IEEE80211_TX_RC_MCS
|
IEEE80211_TX_RC_VHT_MCS
)))
len
+=
2
;
/* IEEE80211_RADIOTAP_TX_FLAGS */
...
...
@@ -244,16 +245,21 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info)
/* IEEE80211_RADIOTAP_DATA_RETRIES */
len
+=
1
;
/* IEEE80211_TX_RC_MCS */
if
(
info
->
status
.
rates
[
0
].
idx
>=
0
&&
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_MCS
)
len
+=
3
;
/* IEEE80211_RADIOTAP_MCS
* IEEE80211_RADIOTAP_VHT */
if
(
info
->
status
.
rates
[
0
].
idx
>=
0
)
{
if
(
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_MCS
)
len
+=
3
;
else
if
(
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_VHT_MCS
)
len
=
ALIGN
(
len
,
2
)
+
12
;
}
return
len
;
}
static
void
ieee80211_add_tx_radiotap_header
(
struct
ieee80211_supported_band
*
sband
,
ieee80211_add_tx_radiotap_header
(
struct
ieee80211_local
*
local
,
struct
ieee80211_supported_band
*
sband
,
struct
sk_buff
*
skb
,
int
retry_count
,
int
rtap_len
,
int
shift
)
{
...
...
@@ -280,7 +286,8 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
/* IEEE80211_RADIOTAP_RATE */
if
(
info
->
status
.
rates
[
0
].
idx
>=
0
&&
!
(
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_MCS
))
{
!
(
info
->
status
.
rates
[
0
].
flags
&
(
IEEE80211_TX_RC_MCS
|
IEEE80211_TX_RC_VHT_MCS
)))
{
u16
rate
;
rthdr
->
it_present
|=
cpu_to_le32
(
1
<<
IEEE80211_RADIOTAP_RATE
);
...
...
@@ -310,9 +317,12 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
*
pos
=
retry_count
;
pos
++
;
/* IEEE80211_TX_RC_MCS */
if
(
info
->
status
.
rates
[
0
].
idx
>=
0
&&
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_MCS
)
{
if
(
info
->
status
.
rates
[
0
].
idx
<
0
)
return
;
/* IEEE80211_RADIOTAP_MCS
* IEEE80211_RADIOTAP_VHT */
if
(
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_MCS
)
{
rthdr
->
it_present
|=
cpu_to_le32
(
1
<<
IEEE80211_RADIOTAP_MCS
);
pos
[
0
]
=
IEEE80211_RADIOTAP_MCS_HAVE_MCS
|
IEEE80211_RADIOTAP_MCS_HAVE_GI
|
...
...
@@ -325,8 +335,48 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
pos
[
1
]
|=
IEEE80211_RADIOTAP_MCS_FMT_GF
;
pos
[
2
]
=
info
->
status
.
rates
[
0
].
idx
;
pos
+=
3
;
}
}
else
if
(
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_VHT_MCS
)
{
u16
known
=
local
->
hw
.
radiotap_vht_details
&
(
IEEE80211_RADIOTAP_VHT_KNOWN_GI
|
IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH
);
rthdr
->
it_present
|=
cpu_to_le32
(
1
<<
IEEE80211_RADIOTAP_VHT
);
/* required alignment from rthdr */
pos
=
(
u8
*
)
rthdr
+
ALIGN
(
pos
-
(
u8
*
)
rthdr
,
2
);
/* u16 known - IEEE80211_RADIOTAP_VHT_KNOWN_* */
put_unaligned_le16
(
known
,
pos
);
pos
+=
2
;
/* u8 flags - IEEE80211_RADIOTAP_VHT_FLAG_* */
if
(
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_SHORT_GI
)
*
pos
|=
IEEE80211_RADIOTAP_VHT_FLAG_SGI
;
pos
++
;
/* u8 bandwidth */
if
(
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_40_MHZ_WIDTH
)
*
pos
=
1
;
else
if
(
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_80_MHZ_WIDTH
)
*
pos
=
4
;
else
if
(
info
->
status
.
rates
[
0
].
flags
&
IEEE80211_TX_RC_160_MHZ_WIDTH
)
*
pos
=
11
;
else
/* IEEE80211_TX_RC_{20_MHZ_WIDTH,FIXME:DUP_DATA} */
*
pos
=
0
;
pos
++
;
/* u8 mcs_nss[4] */
*
pos
=
(
ieee80211_rate_get_vht_mcs
(
&
info
->
status
.
rates
[
0
])
<<
4
)
|
ieee80211_rate_get_vht_nss
(
&
info
->
status
.
rates
[
0
]);
pos
+=
4
;
/* u8 coding */
pos
++
;
/* u8 group_id */
pos
++
;
/* u16 partial_aid */
pos
+=
2
;
}
}
static
void
ieee80211_report_used_skb
(
struct
ieee80211_local
*
local
,
...
...
@@ -564,7 +614,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
rcu_read_unlock
();
ieee80211_led_tx
(
local
,
0
);
ieee80211_led_tx
(
local
);
/* SNMP counters
* Fragments are passed to low-level drivers as separate skbs, so these
...
...
@@ -631,8 +681,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
dev_kfree_skb
(
skb
);
return
;
}
ieee80211_add_tx_radiotap_header
(
sband
,
skb
,
retry_count
,
rtap_len
,
shift
);
ieee80211_add_tx_radiotap_header
(
local
,
sband
,
skb
,
retry_count
,
rtap_len
,
shift
);
/* XXX: is this sufficient for BPF? */
skb_set_mac_header
(
skb
,
0
);
...
...
net/mac80211/trace.h
浏览文件 @
fa597844
...
...
@@ -1906,6 +1906,32 @@ TRACE_EVENT(api_radar_detected,
)
);
TRACE_EVENT
(
drv_channel_switch_beacon
,
TP_PROTO
(
struct
ieee80211_local
*
local
,
struct
ieee80211_sub_if_data
*
sdata
,
struct
cfg80211_chan_def
*
chandef
),
TP_ARGS
(
local
,
sdata
,
chandef
),
TP_STRUCT__entry
(
LOCAL_ENTRY
VIF_ENTRY
CHANDEF_ENTRY
),
TP_fast_assign
(
LOCAL_ASSIGN
;
VIF_ASSIGN
;
CHANDEF_ASSIGN
(
chandef
);
),
TP_printk
(
LOCAL_PR_FMT
VIF_PR_FMT
" channel switch to "
CHANDEF_PR_FMT
,
LOCAL_PR_ARG
,
VIF_PR_ARG
,
CHANDEF_PR_ARG
)
);
#ifdef CONFIG_MAC80211_MESSAGE_TRACING
#undef TRACE_SYSTEM
#define TRACE_SYSTEM mac80211_msg
...
...
net/mac80211/tx.c
浏览文件 @
fa597844
...
...
@@ -1300,7 +1300,6 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
txpending
);
ieee80211_tpt_led_trig_tx
(
local
,
fc
,
led_len
);
ieee80211_led_tx
(
local
,
1
);
WARN_ON_ONCE
(
!
skb_queue_empty
(
skbs
));
...
...
@@ -2339,6 +2338,81 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
return
0
;
}
void
ieee80211_csa_finish
(
struct
ieee80211_vif
*
vif
)
{
struct
ieee80211_sub_if_data
*
sdata
=
vif_to_sdata
(
vif
);
ieee80211_queue_work
(
&
sdata
->
local
->
hw
,
&
sdata
->
csa_finalize_work
);
}
EXPORT_SYMBOL
(
ieee80211_csa_finish
);
static
void
ieee80211_update_csa
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
beacon_data
*
beacon
)
{
struct
probe_resp
*
resp
;
int
counter_offset_beacon
=
sdata
->
csa_counter_offset_beacon
;
int
counter_offset_presp
=
sdata
->
csa_counter_offset_presp
;
/* warn if the driver did not check for/react to csa completeness */
if
(
WARN_ON
(((
u8
*
)
beacon
->
tail
)[
counter_offset_beacon
]
==
0
))
return
;
((
u8
*
)
beacon
->
tail
)[
counter_offset_beacon
]
--
;
if
(
sdata
->
vif
.
type
==
NL80211_IFTYPE_AP
&&
counter_offset_presp
)
{
rcu_read_lock
();
resp
=
rcu_dereference
(
sdata
->
u
.
ap
.
probe_resp
);
/* if nl80211 accepted the offset, this should not happen. */
if
(
WARN_ON
(
!
resp
))
{
rcu_read_unlock
();
return
;
}
resp
->
data
[
counter_offset_presp
]
--
;
rcu_read_unlock
();
}
}
bool
ieee80211_csa_is_complete
(
struct
ieee80211_vif
*
vif
)
{
struct
ieee80211_sub_if_data
*
sdata
=
vif_to_sdata
(
vif
);
struct
beacon_data
*
beacon
=
NULL
;
u8
*
beacon_data
;
size_t
beacon_data_len
;
int
counter_beacon
=
sdata
->
csa_counter_offset_beacon
;
int
ret
=
false
;
if
(
!
ieee80211_sdata_running
(
sdata
))
return
false
;
rcu_read_lock
();
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
{
struct
ieee80211_if_ap
*
ap
=
&
sdata
->
u
.
ap
;
beacon
=
rcu_dereference
(
ap
->
beacon
);
if
(
WARN_ON
(
!
beacon
||
!
beacon
->
tail
))
goto
out
;
beacon_data
=
beacon
->
tail
;
beacon_data_len
=
beacon
->
tail_len
;
}
else
{
WARN_ON
(
1
);
goto
out
;
}
if
(
WARN_ON
(
counter_beacon
>
beacon_data_len
))
goto
out
;
if
(
beacon_data
[
counter_beacon
]
==
0
)
ret
=
true
;
out:
rcu_read_unlock
();
return
ret
;
}
EXPORT_SYMBOL
(
ieee80211_csa_is_complete
);
struct
sk_buff
*
ieee80211_beacon_get_tim
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
u16
*
tim_offset
,
u16
*
tim_length
)
...
...
@@ -2369,6 +2443,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
struct
beacon_data
*
beacon
=
rcu_dereference
(
ap
->
beacon
);
if
(
beacon
)
{
if
(
sdata
->
vif
.
csa_active
)
ieee80211_update_csa
(
sdata
,
beacon
);
/*
* headroom, head length,
* tail length and maximum TIM length
...
...
net/wireless/nl80211.c
浏览文件 @
fa597844
...
...
@@ -349,6 +349,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[
NL80211_ATTR_IE_RIC
]
=
{
.
type
=
NLA_BINARY
,
.
len
=
IEEE80211_MAX_DATA_LEN
},
[
NL80211_ATTR_PEER_AID
]
=
{
.
type
=
NLA_U16
},
[
NL80211_ATTR_CH_SWITCH_COUNT
]
=
{
.
type
=
NLA_U32
},
[
NL80211_ATTR_CH_SWITCH_BLOCK_TX
]
=
{
.
type
=
NLA_FLAG
},
[
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
},
};
/* policy for the key attributes */
...
...
@@ -1424,6 +1429,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
if
(
state
->
split
)
{
CMD
(
crit_proto_start
,
CRIT_PROTOCOL_START
);
CMD
(
crit_proto_stop
,
CRIT_PROTOCOL_STOP
);
if
(
dev
->
wiphy
.
flags
&
WIPHY_FLAG_HAS_CHANNEL_SWITCH
)
CMD
(
channel_switch
,
CHANNEL_SWITCH
);
}
#ifdef CONFIG_NL80211_TESTMODE
...
...
@@ -5615,6 +5622,111 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
return
err
;
}
static
int
nl80211_channel_switch
(
struct
sk_buff
*
skb
,
struct
genl_info
*
info
)
{
struct
cfg80211_registered_device
*
rdev
=
info
->
user_ptr
[
0
];
struct
net_device
*
dev
=
info
->
user_ptr
[
1
];
struct
wireless_dev
*
wdev
=
dev
->
ieee80211_ptr
;
struct
cfg80211_csa_settings
params
;
/* csa_attrs is defined static to avoid waste of stack size - this
* function is called under RTNL lock, so this should not be a problem.
*/
static
struct
nlattr
*
csa_attrs
[
NL80211_ATTR_MAX
+
1
];
u8
radar_detect_width
=
0
;
int
err
;
if
(
!
rdev
->
ops
->
channel_switch
||
!
(
rdev
->
wiphy
.
flags
&
WIPHY_FLAG_HAS_CHANNEL_SWITCH
))
return
-
EOPNOTSUPP
;
/* may add IBSS support later */
if
(
dev
->
ieee80211_ptr
->
iftype
!=
NL80211_IFTYPE_AP
&&
dev
->
ieee80211_ptr
->
iftype
!=
NL80211_IFTYPE_P2P_GO
)
return
-
EOPNOTSUPP
;
memset
(
&
params
,
0
,
sizeof
(
params
));
if
(
!
info
->
attrs
[
NL80211_ATTR_WIPHY_FREQ
]
||
!
info
->
attrs
[
NL80211_ATTR_CH_SWITCH_COUNT
])
return
-
EINVAL
;
/* only important for AP, IBSS and mesh create IEs internally */
if
(
!
info
->
attrs
[
NL80211_ATTR_CSA_IES
])
return
-
EINVAL
;
/* useless if AP is not running */
if
(
!
wdev
->
beacon_interval
)
return
-
EINVAL
;
params
.
count
=
nla_get_u32
(
info
->
attrs
[
NL80211_ATTR_CH_SWITCH_COUNT
]);
err
=
nl80211_parse_beacon
(
info
->
attrs
,
&
params
.
beacon_after
);
if
(
err
)
return
err
;
err
=
nla_parse_nested
(
csa_attrs
,
NL80211_ATTR_MAX
,
info
->
attrs
[
NL80211_ATTR_CSA_IES
],
nl80211_policy
);
if
(
err
)
return
err
;
err
=
nl80211_parse_beacon
(
csa_attrs
,
&
params
.
beacon_csa
);
if
(
err
)
return
err
;
if
(
!
csa_attrs
[
NL80211_ATTR_CSA_C_OFF_BEACON
])
return
-
EINVAL
;
params
.
counter_offset_beacon
=
nla_get_u16
(
csa_attrs
[
NL80211_ATTR_CSA_C_OFF_BEACON
]);
if
(
params
.
counter_offset_beacon
>=
params
.
beacon_csa
.
tail_len
)
return
-
EINVAL
;
/* sanity check - counters should be the same */
if
(
params
.
beacon_csa
.
tail
[
params
.
counter_offset_beacon
]
!=
params
.
count
)
return
-
EINVAL
;
if
(
csa_attrs
[
NL80211_ATTR_CSA_C_OFF_PRESP
])
{
params
.
counter_offset_presp
=
nla_get_u16
(
csa_attrs
[
NL80211_ATTR_CSA_C_OFF_PRESP
]);
if
(
params
.
counter_offset_presp
>=
params
.
beacon_csa
.
probe_resp_len
)
return
-
EINVAL
;
if
(
params
.
beacon_csa
.
probe_resp
[
params
.
counter_offset_presp
]
!=
params
.
count
)
return
-
EINVAL
;
}
err
=
nl80211_parse_chandef
(
rdev
,
info
,
&
params
.
chandef
);
if
(
err
)
return
err
;
if
(
!
cfg80211_reg_can_beacon
(
&
rdev
->
wiphy
,
&
params
.
chandef
))
return
-
EINVAL
;
err
=
cfg80211_chandef_dfs_required
(
wdev
->
wiphy
,
&
params
.
chandef
);
if
(
err
<
0
)
{
return
err
;
}
else
if
(
err
)
{
radar_detect_width
=
BIT
(
params
.
chandef
.
width
);
params
.
radar_required
=
true
;
}
err
=
cfg80211_can_use_iftype_chan
(
rdev
,
wdev
,
wdev
->
iftype
,
params
.
chandef
.
chan
,
CHAN_MODE_SHARED
,
radar_detect_width
);
if
(
err
)
return
err
;
if
(
info
->
attrs
[
NL80211_ATTR_CH_SWITCH_BLOCK_TX
])
params
.
block_tx
=
true
;
return
rdev_channel_switch
(
rdev
,
dev
,
&
params
);
}
static
int
nl80211_send_bss
(
struct
sk_buff
*
msg
,
struct
netlink_callback
*
cb
,
u32
seq
,
int
flags
,
struct
cfg80211_registered_device
*
rdev
,
...
...
@@ -9365,7 +9477,15 @@ static struct genl_ops nl80211_ops[] = {
.
flags
=
GENL_ADMIN_PERM
,
.
internal_flags
=
NL80211_FLAG_NEED_WIPHY
|
NL80211_FLAG_NEED_RTNL
,
}
},
{
.
cmd
=
NL80211_CMD_CHANNEL_SWITCH
,
.
doit
=
nl80211_channel_switch
,
.
policy
=
nl80211_policy
,
.
flags
=
GENL_ADMIN_PERM
,
.
internal_flags
=
NL80211_FLAG_NEED_NETDEV_UP
|
NL80211_FLAG_NEED_RTNL
,
},
};
static
struct
genl_multicast_group
nl80211_mlme_mcgrp
=
{
...
...
net/wireless/rdev-ops.h
浏览文件 @
fa597844
...
...
@@ -923,4 +923,16 @@ static inline void rdev_crit_proto_stop(struct cfg80211_registered_device *rdev,
trace_rdev_return_void
(
&
rdev
->
wiphy
);
}
static
inline
int
rdev_channel_switch
(
struct
cfg80211_registered_device
*
rdev
,
struct
net_device
*
dev
,
struct
cfg80211_csa_settings
*
params
)
{
int
ret
;
trace_rdev_channel_switch
(
&
rdev
->
wiphy
,
dev
,
params
);
ret
=
rdev
->
ops
->
channel_switch
(
&
rdev
->
wiphy
,
dev
,
params
);
trace_rdev_return_int
(
&
rdev
->
wiphy
,
ret
);
return
ret
;
}
#endif
/* __CFG80211_RDEV_OPS */
net/wireless/trace.h
浏览文件 @
fa597844
...
...
@@ -1841,6 +1841,39 @@ TRACE_EVENT(rdev_crit_proto_stop,
WIPHY_PR_ARG
,
WDEV_PR_ARG
)
);
TRACE_EVENT
(
rdev_channel_switch
,
TP_PROTO
(
struct
wiphy
*
wiphy
,
struct
net_device
*
netdev
,
struct
cfg80211_csa_settings
*
params
),
TP_ARGS
(
wiphy
,
netdev
,
params
),
TP_STRUCT__entry
(
WIPHY_ENTRY
NETDEV_ENTRY
CHAN_DEF_ENTRY
__field
(
u16
,
counter_offset_beacon
)
__field
(
u16
,
counter_offset_presp
)
__field
(
bool
,
radar_required
)
__field
(
bool
,
block_tx
)
__field
(
u8
,
count
)
),
TP_fast_assign
(
WIPHY_ASSIGN
;
NETDEV_ASSIGN
;
CHAN_DEF_ASSIGN
(
&
params
->
chandef
);
__entry
->
counter_offset_beacon
=
params
->
counter_offset_beacon
;
__entry
->
counter_offset_presp
=
params
->
counter_offset_presp
;
__entry
->
radar_required
=
params
->
radar_required
;
__entry
->
block_tx
=
params
->
block_tx
;
__entry
->
count
=
params
->
count
;
),
TP_printk
(
WIPHY_PR_FMT
", "
NETDEV_PR_FMT
", "
CHAN_DEF_PR_FMT
", block_tx: %d, count: %u, radar_required: %d"
", counter offsets (beacon/presp): %u/%u"
,
WIPHY_PR_ARG
,
NETDEV_PR_ARG
,
CHAN_DEF_PR_ARG
,
__entry
->
block_tx
,
__entry
->
count
,
__entry
->
radar_required
,
__entry
->
counter_offset_beacon
,
__entry
->
counter_offset_presp
)
);
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录