Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
a006827a
Commit
a006827a
authored
Jul 22, 2014
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge
git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
parents
1d9e954e
08cf42e8
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
707 additions
and
169 deletions
+707
-169
include/linux/ieee80211.h
include/linux/ieee80211.h
+20
-0
include/net/mac80211.h
include/net/mac80211.h
+34
-0
net/mac80211/agg-rx.c
net/mac80211/agg-rx.c
+84
-26
net/mac80211/chan.c
net/mac80211/chan.c
+1
-1
net/mac80211/ht.c
net/mac80211/ht.c
+6
-4
net/mac80211/ibss.c
net/mac80211/ibss.c
+2
-11
net/mac80211/ieee80211_i.h
net/mac80211/ieee80211_i.h
+30
-4
net/mac80211/iface.c
net/mac80211/iface.c
+29
-2
net/mac80211/key.c
net/mac80211/key.c
+0
-3
net/mac80211/mlme.c
net/mac80211/mlme.c
+5
-17
net/mac80211/rx.c
net/mac80211/rx.c
+46
-19
net/mac80211/sta_info.h
net/mac80211/sta_info.h
+6
-2
net/mac80211/tdls.c
net/mac80211/tdls.c
+394
-65
net/mac80211/util.c
net/mac80211/util.c
+15
-0
net/mac80211/vht.c
net/mac80211/vht.c
+4
-0
net/mac80211/wpa.c
net/mac80211/wpa.c
+1
-1
net/wireless/Kconfig
net/wireless/Kconfig
+6
-0
net/wireless/genregdb.awk
net/wireless/genregdb.awk
+22
-13
net/wireless/nl80211.c
net/wireless/nl80211.c
+2
-1
No files found.
include/linux/ieee80211.h
View file @
a006827a
...
...
@@ -1001,6 +1001,26 @@ struct ieee80211_vendor_ie {
u8
oui_type
;
}
__packed
;
struct
ieee80211_wmm_ac_param
{
u8
aci_aifsn
;
/* AIFSN, ACM, ACI */
u8
cw
;
/* ECWmin, ECWmax (CW = 2^ECW - 1) */
__le16
txop_limit
;
}
__packed
;
struct
ieee80211_wmm_param_ie
{
u8
element_id
;
/* Element ID: 221 (0xdd); */
u8
len
;
/* Length: 24 */
/* required fields for WMM version 1 */
u8
oui
[
3
];
/* 00:50:f2 */
u8
oui_type
;
/* 2 */
u8
oui_subtype
;
/* 1 */
u8
version
;
/* 1 for WMM version 1.0 */
u8
qos_info
;
/* AP/STA specific QoS info */
u8
reserved
;
/* 0 */
/* AC_BE, AC_BK, AC_VI, AC_VO */
struct
ieee80211_wmm_ac_param
ac
[
4
];
}
__packed
;
/* Control frames */
struct
ieee80211_rts
{
__le16
frame_control
;
...
...
include/net/mac80211.h
View file @
a006827a
...
...
@@ -4552,6 +4552,40 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
*/
void
ieee80211_send_bar
(
struct
ieee80211_vif
*
vif
,
u8
*
ra
,
u16
tid
,
u16
ssn
);
/**
* ieee80211_start_rx_ba_session_offl - start a Rx BA session
*
* Some device drivers may offload part of the Rx aggregation flow including
* AddBa/DelBa negotiation but may otherwise be incapable of full Rx
* reordering.
*
* Create structures responsible for reordering so device drivers may call here
* when they complete AddBa negotiation.
*
* @vif: &struct ieee80211_vif pointer from the add_interface callback
* @addr: station mac address
* @tid: the rx tid
*/
void
ieee80211_start_rx_ba_session_offl
(
struct
ieee80211_vif
*
vif
,
const
u8
*
addr
,
u16
tid
);
/**
* ieee80211_stop_rx_ba_session_offl - stop a Rx BA session
*
* Some device drivers may offload part of the Rx aggregation flow including
* AddBa/DelBa negotiation but may otherwise be incapable of full Rx
* reordering.
*
* Destroy structures responsible for reordering so device drivers may call here
* when they complete DelBa negotiation.
*
* @vif: &struct ieee80211_vif pointer from the add_interface callback
* @addr: station mac address
* @tid: the rx tid
*/
void
ieee80211_stop_rx_ba_session_offl
(
struct
ieee80211_vif
*
vif
,
const
u8
*
addr
,
u16
tid
);
/* Rate control API */
/**
...
...
net/mac80211/agg-rx.c
View file @
a006827a
...
...
@@ -52,7 +52,7 @@ static void ieee80211_free_tid_rx(struct rcu_head *h)
del_timer_sync
(
&
tid_rx
->
reorder_timer
);
for
(
i
=
0
;
i
<
tid_rx
->
buf_size
;
i
++
)
dev_kfree_skb
(
tid_rx
->
reorder_buf
[
i
]);
__skb_queue_purge
(
&
tid_rx
->
reorder_buf
[
i
]);
kfree
(
tid_rx
->
reorder_buf
);
kfree
(
tid_rx
->
reorder_time
);
kfree
(
tid_rx
);
...
...
@@ -224,28 +224,15 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
ieee80211_tx_skb
(
sdata
,
skb
);
}
void
ieee80211_process_addba_request
(
struct
ieee80211_local
*
local
,
struct
sta_info
*
sta
,
struct
ieee80211_mgmt
*
mgmt
,
size_t
len
)
void
__ieee80211_start_rx_ba_session
(
struct
sta_info
*
sta
,
u8
dialog_token
,
u16
timeout
,
u16
start_seq_num
,
u16
ba_policy
,
u16
tid
,
u16
buf_size
,
bool
tx
)
{
struct
ieee80211_local
*
local
=
sta
->
sdata
->
local
;
struct
tid_ampdu_rx
*
tid_agg_rx
;
u16
capab
,
tid
,
timeout
,
ba_policy
,
buf_size
,
start_seq_num
,
status
;
u8
dialog_token
;
int
ret
=
-
EOPNOTSUPP
;
/* extract session parameters from addba request frame */
dialog_token
=
mgmt
->
u
.
action
.
u
.
addba_req
.
dialog_token
;
timeout
=
le16_to_cpu
(
mgmt
->
u
.
action
.
u
.
addba_req
.
timeout
);
start_seq_num
=
le16_to_cpu
(
mgmt
->
u
.
action
.
u
.
addba_req
.
start_seq_num
)
>>
4
;
capab
=
le16_to_cpu
(
mgmt
->
u
.
action
.
u
.
addba_req
.
capab
);
ba_policy
=
(
capab
&
IEEE80211_ADDBA_PARAM_POLICY_MASK
)
>>
1
;
tid
=
(
capab
&
IEEE80211_ADDBA_PARAM_TID_MASK
)
>>
2
;
buf_size
=
(
capab
&
IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK
)
>>
6
;
status
=
WLAN_STATUS_REQUEST_DECLINED
;
int
i
,
ret
=
-
EOPNOTSUPP
;
u16
status
=
WLAN_STATUS_REQUEST_DECLINED
;
if
(
test_sta_flag
(
sta
,
WLAN_STA_BLOCK_BA
))
{
ht_dbg
(
sta
->
sdata
,
...
...
@@ -264,7 +251,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
status
=
WLAN_STATUS_INVALID_QOS_PARAM
;
ht_dbg_ratelimited
(
sta
->
sdata
,
"AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d
\n
"
,
mgmt
->
sa
,
tid
,
ba_policy
,
buf_size
);
sta
->
sta
.
addr
,
tid
,
ba_policy
,
buf_size
);
goto
end_no_lock
;
}
/* determine default buffer size */
...
...
@@ -281,7 +268,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
if
(
sta
->
ampdu_mlme
.
tid_rx
[
tid
])
{
ht_dbg_ratelimited
(
sta
->
sdata
,
"unexpected AddBA Req from %pM on tid %u
\n
"
,
mgmt
->
sa
,
tid
);
sta
->
sta
.
addr
,
tid
);
/* delete existing Rx BA session on the same tid */
___ieee80211_stop_rx_ba_session
(
sta
,
tid
,
WLAN_BACK_RECIPIENT
,
...
...
@@ -308,7 +295,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
/* prepare reordering buffer */
tid_agg_rx
->
reorder_buf
=
kcalloc
(
buf_size
,
sizeof
(
struct
sk_buff
*
),
GFP_KERNEL
);
kcalloc
(
buf_size
,
sizeof
(
struct
sk_buff
_head
),
GFP_KERNEL
);
tid_agg_rx
->
reorder_time
=
kcalloc
(
buf_size
,
sizeof
(
unsigned
long
),
GFP_KERNEL
);
if
(
!
tid_agg_rx
->
reorder_buf
||
!
tid_agg_rx
->
reorder_time
)
{
...
...
@@ -318,6 +305,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
goto
end
;
}
for
(
i
=
0
;
i
<
buf_size
;
i
++
)
__skb_queue_head_init
(
&
tid_agg_rx
->
reorder_buf
[
i
]);
ret
=
drv_ampdu_action
(
local
,
sta
->
sdata
,
IEEE80211_AMPDU_RX_START
,
&
sta
->
sta
,
tid
,
&
start_seq_num
,
0
);
ht_dbg
(
sta
->
sdata
,
"Rx A-MPDU request on %pM tid %d result %d
\n
"
,
...
...
@@ -350,6 +340,74 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
mutex_unlock
(
&
sta
->
ampdu_mlme
.
mtx
);
end_no_lock:
ieee80211_send_addba_resp
(
sta
->
sdata
,
sta
->
sta
.
addr
,
tid
,
dialog_token
,
status
,
1
,
buf_size
,
timeout
);
if
(
tx
)
ieee80211_send_addba_resp
(
sta
->
sdata
,
sta
->
sta
.
addr
,
tid
,
dialog_token
,
status
,
1
,
buf_size
,
timeout
);
}
void
ieee80211_process_addba_request
(
struct
ieee80211_local
*
local
,
struct
sta_info
*
sta
,
struct
ieee80211_mgmt
*
mgmt
,
size_t
len
)
{
u16
capab
,
tid
,
timeout
,
ba_policy
,
buf_size
,
start_seq_num
;
u8
dialog_token
;
/* extract session parameters from addba request frame */
dialog_token
=
mgmt
->
u
.
action
.
u
.
addba_req
.
dialog_token
;
timeout
=
le16_to_cpu
(
mgmt
->
u
.
action
.
u
.
addba_req
.
timeout
);
start_seq_num
=
le16_to_cpu
(
mgmt
->
u
.
action
.
u
.
addba_req
.
start_seq_num
)
>>
4
;
capab
=
le16_to_cpu
(
mgmt
->
u
.
action
.
u
.
addba_req
.
capab
);
ba_policy
=
(
capab
&
IEEE80211_ADDBA_PARAM_POLICY_MASK
)
>>
1
;
tid
=
(
capab
&
IEEE80211_ADDBA_PARAM_TID_MASK
)
>>
2
;
buf_size
=
(
capab
&
IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK
)
>>
6
;
__ieee80211_start_rx_ba_session
(
sta
,
dialog_token
,
timeout
,
start_seq_num
,
ba_policy
,
tid
,
buf_size
,
true
);
}
void
ieee80211_start_rx_ba_session_offl
(
struct
ieee80211_vif
*
vif
,
const
u8
*
addr
,
u16
tid
)
{
struct
ieee80211_sub_if_data
*
sdata
=
vif_to_sdata
(
vif
);
struct
ieee80211_local
*
local
=
sdata
->
local
;
struct
ieee80211_rx_agg
*
rx_agg
;
struct
sk_buff
*
skb
=
dev_alloc_skb
(
0
);
if
(
unlikely
(
!
skb
))
return
;
rx_agg
=
(
struct
ieee80211_rx_agg
*
)
&
skb
->
cb
;
memcpy
(
&
rx_agg
->
addr
,
addr
,
ETH_ALEN
);
rx_agg
->
tid
=
tid
;
skb
->
pkt_type
=
IEEE80211_SDATA_QUEUE_RX_AGG_START
;
skb_queue_tail
(
&
sdata
->
skb_queue
,
skb
);
ieee80211_queue_work
(
&
local
->
hw
,
&
sdata
->
work
);
}
EXPORT_SYMBOL
(
ieee80211_start_rx_ba_session_offl
);
void
ieee80211_stop_rx_ba_session_offl
(
struct
ieee80211_vif
*
vif
,
const
u8
*
addr
,
u16
tid
)
{
struct
ieee80211_sub_if_data
*
sdata
=
vif_to_sdata
(
vif
);
struct
ieee80211_local
*
local
=
sdata
->
local
;
struct
ieee80211_rx_agg
*
rx_agg
;
struct
sk_buff
*
skb
=
dev_alloc_skb
(
0
);
if
(
unlikely
(
!
skb
))
return
;
rx_agg
=
(
struct
ieee80211_rx_agg
*
)
&
skb
->
cb
;
memcpy
(
&
rx_agg
->
addr
,
addr
,
ETH_ALEN
);
rx_agg
->
tid
=
tid
;
skb
->
pkt_type
=
IEEE80211_SDATA_QUEUE_RX_AGG_STOP
;
skb_queue_tail
(
&
sdata
->
skb_queue
,
skb
);
ieee80211_queue_work
(
&
local
->
hw
,
&
sdata
->
work
);
}
EXPORT_SYMBOL
(
ieee80211_stop_rx_ba_session_offl
);
net/mac80211/chan.c
View file @
a006827a
...
...
@@ -66,7 +66,7 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
static
struct
ieee80211_chanctx
*
ieee80211_vif_get_chanctx
(
struct
ieee80211_sub_if_data
*
sdata
)
{
struct
ieee80211_local
*
local
=
sdata
->
local
;
struct
ieee80211_local
*
local
__maybe_unused
=
sdata
->
local
;
struct
ieee80211_chanctx_conf
*
conf
;
conf
=
rcu_dereference_protected
(
sdata
->
vif
.
chanctx_conf
,
...
...
net/mac80211/ht.c
View file @
a006827a
...
...
@@ -150,13 +150,12 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
/*
* If user has specified capability over-rides, take care
* of that if the station we're setting up is the AP that
* of that if the station we're setting up is the AP
or TDLS peer
that
* we advertised a restricted capability set to. Override
* our own capabilities and then use those below.
*/
if
((
sdata
->
vif
.
type
==
NL80211_IFTYPE_STATION
||
sdata
->
vif
.
type
==
NL80211_IFTYPE_ADHOC
)
&&
!
test_sta_flag
(
sta
,
WLAN_STA_TDLS_PEER
))
if
(
sdata
->
vif
.
type
==
NL80211_IFTYPE_STATION
||
sdata
->
vif
.
type
==
NL80211_IFTYPE_ADHOC
)
ieee80211_apply_htcap_overrides
(
sdata
,
&
own_cap
);
/*
...
...
@@ -228,6 +227,9 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
if
(
own_cap
.
mcs
.
rx_mask
[
32
/
8
]
&
ht_cap_ie
->
mcs
.
rx_mask
[
32
/
8
]
&
1
)
ht_cap
.
mcs
.
rx_mask
[
32
/
8
]
|=
1
;
/* set Rx highest rate */
ht_cap
.
mcs
.
rx_highest
=
ht_cap_ie
->
mcs
.
rx_highest
;
apply:
changed
=
memcmp
(
&
sta
->
sta
.
ht_cap
,
&
ht_cap
,
sizeof
(
ht_cap
));
...
...
net/mac80211/ibss.c
View file @
a006827a
...
...
@@ -189,17 +189,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
chandef
,
0
);
}
if
(
local
->
hw
.
queues
>=
IEEE80211_NUM_ACS
)
{
*
pos
++
=
WLAN_EID_VENDOR_SPECIFIC
;
*
pos
++
=
7
;
/* len */
*
pos
++
=
0x00
;
/* Microsoft OUI 00:50:F2 */
*
pos
++
=
0x50
;
*
pos
++
=
0xf2
;
*
pos
++
=
2
;
/* WME */
*
pos
++
=
0
;
/* WME info */
*
pos
++
=
1
;
/* WME ver */
*
pos
++
=
0
;
/* U-APSD no in use */
}
if
(
local
->
hw
.
queues
>=
IEEE80211_NUM_ACS
)
pos
=
ieee80211_add_wmm_info_ie
(
pos
,
0
);
/* U-APSD not in use */
presp
->
head_len
=
pos
-
presp
->
head
;
if
(
WARN_ON
(
presp
->
head_len
>
frame_len
))
...
...
net/mac80211/ieee80211_i.h
View file @
a006827a
...
...
@@ -345,7 +345,6 @@ enum ieee80211_sta_flags {
IEEE80211_STA_CONNECTION_POLL
=
BIT
(
1
),
IEEE80211_STA_CONTROL_PORT
=
BIT
(
2
),
IEEE80211_STA_DISABLE_HT
=
BIT
(
4
),
IEEE80211_STA_CSA_RECEIVED
=
BIT
(
5
),
IEEE80211_STA_MFP_ENABLED
=
BIT
(
6
),
IEEE80211_STA_UAPSD_ENABLED
=
BIT
(
7
),
IEEE80211_STA_NULLFUNC_ACKED
=
BIT
(
8
),
...
...
@@ -503,6 +502,9 @@ struct ieee80211_if_managed {
struct
ieee80211_ht_cap
ht_capa_mask
;
/* Valid parts of ht_capa */
struct
ieee80211_vht_cap
vht_capa
;
/* configured VHT overrides */
struct
ieee80211_vht_cap
vht_capa_mask
;
/* Valid parts of vht_capa */
u8
tdls_peer
[
ETH_ALEN
]
__aligned
(
2
);
struct
delayed_work
tdls_peer_del_work
;
};
struct
ieee80211_if_ibss
{
...
...
@@ -815,9 +817,6 @@ struct ieee80211_sub_if_data {
bool
radar_required
;
struct
delayed_work
dfs_cac_timer_work
;
u8
tdls_peer
[
ETH_ALEN
]
__aligned
(
2
);
struct
delayed_work
tdls_peer_del_work
;
/*
* AP this belongs to: self in AP mode and
* corresponding AP in VLAN mode, NULL for
...
...
@@ -926,10 +925,17 @@ ieee80211_vif_get_shift(struct ieee80211_vif *vif)
return
shift
;
}
struct
ieee80211_rx_agg
{
u8
addr
[
ETH_ALEN
];
u16
tid
;
};
enum
sdata_queue_type
{
IEEE80211_SDATA_QUEUE_TYPE_FRAME
=
0
,
IEEE80211_SDATA_QUEUE_AGG_START
=
1
,
IEEE80211_SDATA_QUEUE_AGG_STOP
=
2
,
IEEE80211_SDATA_QUEUE_RX_AGG_START
=
3
,
IEEE80211_SDATA_QUEUE_RX_AGG_STOP
=
4
,
};
enum
{
...
...
@@ -1578,6 +1584,10 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
u16
initiator
,
u16
reason
,
bool
stop
);
void
__ieee80211_stop_rx_ba_session
(
struct
sta_info
*
sta
,
u16
tid
,
u16
initiator
,
u16
reason
,
bool
stop
);
void
__ieee80211_start_rx_ba_session
(
struct
sta_info
*
sta
,
u8
dialog_token
,
u16
timeout
,
u16
start_seq_num
,
u16
ba_policy
,
u16
tid
,
u16
buf_size
,
bool
tx
);
void
ieee80211_sta_tear_down_BA_sessions
(
struct
sta_info
*
sta
,
enum
ieee80211_agg_stop_reason
reason
);
void
ieee80211_process_delba
(
struct
ieee80211_sub_if_data
*
sdata
,
...
...
@@ -1730,6 +1740,21 @@ static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
ieee802_11_parse_elems_crc
(
start
,
len
,
action
,
elems
,
0
,
0
);
}
static
inline
bool
ieee80211_rx_reorder_ready
(
struct
sk_buff_head
*
frames
)
{
struct
sk_buff
*
tail
=
skb_peek_tail
(
frames
);
struct
ieee80211_rx_status
*
status
;
if
(
!
tail
)
return
false
;
status
=
IEEE80211_SKB_RXCB
(
tail
);
if
(
status
->
flag
&
RX_FLAG_AMSDU_MORE
)
return
false
;
return
true
;
}
void
ieee80211_dynamic_ps_enable_work
(
struct
work_struct
*
work
);
void
ieee80211_dynamic_ps_disable_work
(
struct
work_struct
*
work
);
void
ieee80211_dynamic_ps_timer
(
unsigned
long
data
);
...
...
@@ -1824,6 +1849,7 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
int
ieee80211_add_ext_srates_ie
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
sk_buff
*
skb
,
bool
need_basic
,
enum
ieee80211_band
band
);
u8
*
ieee80211_add_wmm_info_ie
(
u8
*
buf
,
u8
qosinfo
);
/* channel management */
void
ieee80211_ht_oper_to_chandef
(
struct
ieee80211_channel
*
control_chan
,
...
...
net/mac80211/iface.c
View file @
a006827a
...
...
@@ -1140,6 +1140,7 @@ static void ieee80211_iface_work(struct work_struct *work)
struct
sk_buff
*
skb
;
struct
sta_info
*
sta
;
struct
ieee80211_ra_tid
*
ra_tid
;
struct
ieee80211_rx_agg
*
rx_agg
;
if
(
!
ieee80211_sdata_running
(
sdata
))
return
;
...
...
@@ -1167,6 +1168,34 @@ static void ieee80211_iface_work(struct work_struct *work)
ra_tid
=
(
void
*
)
&
skb
->
cb
;
ieee80211_stop_tx_ba_cb
(
&
sdata
->
vif
,
ra_tid
->
ra
,
ra_tid
->
tid
);
}
else
if
(
skb
->
pkt_type
==
IEEE80211_SDATA_QUEUE_RX_AGG_START
)
{
rx_agg
=
(
void
*
)
&
skb
->
cb
;
mutex_lock
(
&
local
->
sta_mtx
);
sta
=
sta_info_get_bss
(
sdata
,
rx_agg
->
addr
);
if
(
sta
)
{
u16
last_seq
;
last_seq
=
le16_to_cpu
(
sta
->
last_seq_ctrl
[
rx_agg
->
tid
]);
__ieee80211_start_rx_ba_session
(
sta
,
0
,
0
,
ieee80211_sn_inc
(
last_seq
),
1
,
rx_agg
->
tid
,
IEEE80211_MAX_AMPDU_BUF
,
false
);
}
mutex_unlock
(
&
local
->
sta_mtx
);
}
else
if
(
skb
->
pkt_type
==
IEEE80211_SDATA_QUEUE_RX_AGG_STOP
)
{
rx_agg
=
(
void
*
)
&
skb
->
cb
;
mutex_lock
(
&
local
->
sta_mtx
);
sta
=
sta_info_get_bss
(
sdata
,
rx_agg
->
addr
);
if
(
sta
)
__ieee80211_stop_rx_ba_session
(
sta
,
rx_agg
->
tid
,
WLAN_BACK_RECIPIENT
,
0
,
false
);
mutex_unlock
(
&
local
->
sta_mtx
);
}
else
if
(
ieee80211_is_action
(
mgmt
->
frame_control
)
&&
mgmt
->
u
.
action
.
category
==
WLAN_CATEGORY_BACK
)
{
int
len
=
skb
->
len
;
...
...
@@ -1672,8 +1701,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
ieee80211_dfs_cac_timer_work
);
INIT_DELAYED_WORK
(
&
sdata
->
dec_tailroom_needed_wk
,
ieee80211_delayed_tailroom_dec
);
INIT_DELAYED_WORK
(
&
sdata
->
tdls_peer_del_work
,
ieee80211_tdls_peer_del_work
);
for
(
i
=
0
;
i
<
IEEE80211_NUM_BANDS
;
i
++
)
{
struct
ieee80211_supported_band
*
sband
;
...
...
net/mac80211/key.c
View file @
a006827a
...
...
@@ -482,9 +482,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
int
idx
,
ret
;
bool
pairwise
;
if
(
WARN_ON
(
!
sdata
||
!
key
))
return
-
EINVAL
;
pairwise
=
key
->
conf
.
flags
&
IEEE80211_KEY_FLAG_PAIRWISE
;
idx
=
key
->
conf
.
keyidx
;
key
->
local
=
sdata
->
local
;
...
...
net/mac80211/mlme.c
View file @
a006827a
...
...
@@ -830,16 +830,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
qos_info
=
0
;
}
pos
=
skb_put
(
skb
,
9
);
*
pos
++
=
WLAN_EID_VENDOR_SPECIFIC
;
*
pos
++
=
7
;
/* len */
*
pos
++
=
0x00
;
/* Microsoft OUI 00:50:F2 */
*
pos
++
=
0x50
;
*
pos
++
=
0xf2
;
*
pos
++
=
2
;
/* WME */
*
pos
++
=
0
;
/* WME info */
*
pos
++
=
1
;
/* WME ver */
*
pos
++
=
qos_info
;
pos
=
ieee80211_add_wmm_info_ie
(
skb_put
(
skb
,
9
),
qos_info
);
}
/* add any remaining custom (i.e. vendor specific here) IEs */
...
...
@@ -1005,8 +996,6 @@ static void ieee80211_chswitch_work(struct work_struct *work)
sdata
->
csa_block_tx
=
false
;
}
ifmgd
->
flags
&=
~
IEEE80211_STA_CSA_RECEIVED
;
ieee80211_sta_reset_beacon_monitor
(
sdata
);
ieee80211_sta_reset_conn_monitor
(
sdata
);
...
...
@@ -1064,7 +1053,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return
;
/* disregard subsequent announcements if we are already processing */
if
(
ifmgd
->
flags
&
IEEE80211_STA_CSA_RECEIVED
)
if
(
sdata
->
vif
.
csa_active
)
return
;
current_band
=
cbss
->
channel
->
band
;
...
...
@@ -1091,8 +1080,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return
;
}
ifmgd
->
flags
|=
IEEE80211_STA_CSA_RECEIVED
;
mutex_lock
(
&
local
->
mtx
);
mutex_lock
(
&
local
->
chanctx_mtx
);
conf
=
rcu_dereference_protected
(
sdata
->
vif
.
chanctx_conf
,
...
...
@@ -2108,8 +2095,6 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
ieee80211_set_disassoc
(
sdata
,
IEEE80211_STYPE_DEAUTH
,
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY
,
true
,
frame_buf
);
ifmgd
->
flags
&=
~
IEEE80211_STA_CSA_RECEIVED
;
mutex_lock
(
&
local
->
mtx
);
sdata
->
vif
.
csa_active
=
false
;
if
(
sdata
->
csa_block_tx
)
{
...
...
@@ -3722,6 +3707,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
INIT_WORK
(
&
ifmgd
->
csa_connection_drop_work
,
ieee80211_csa_connection_drop_work
);
INIT_WORK
(
&
ifmgd
->
request_smps_work
,
ieee80211_request_smps_mgd_work
);
INIT_DELAYED_WORK
(
&
ifmgd
->
tdls_peer_del_work
,
ieee80211_tdls_peer_del_work
);
setup_timer
(
&
ifmgd
->
timer
,
ieee80211_sta_timer
,
(
unsigned
long
)
sdata
);
setup_timer
(
&
ifmgd
->
bcn_mon_timer
,
ieee80211_sta_bcn_mon_timer
,
...
...
@@ -4585,6 +4572,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
cancel_work_sync
(
&
ifmgd
->
request_smps_work
);
cancel_work_sync
(
&
ifmgd
->
csa_connection_drop_work
);
cancel_work_sync
(
&
ifmgd
->
chswitch_work
);
cancel_delayed_work_sync
(
&
ifmgd
->
tdls_peer_del_work
);
sdata_lock
(
sdata
);
if
(
ifmgd
->
assoc_data
)
{
...
...
net/mac80211/rx.c
View file @
a006827a
...
...
@@ -688,20 +688,27 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
int
index
,
struct
sk_buff_head
*
frames
)
{
struct
sk_buff
*
skb
=
tid_agg_rx
->
reorder_buf
[
index
];
struct
sk_buff_head
*
skb_list
=
&
tid_agg_rx
->
reorder_buf
[
index
];
struct
sk_buff
*
skb
;
struct
ieee80211_rx_status
*
status
;
lockdep_assert_held
(
&
tid_agg_rx
->
reorder_lock
);
if
(
!
skb
)
if
(
skb_queue_empty
(
skb_list
))
goto
no_frame
;
if
(
!
ieee80211_rx_reorder_ready
(
skb_list
))
{
__skb_queue_purge
(
skb_list
);
goto
no_frame
;
}
/* release
the frame
from the reorder ring buffer */
/* release
frames
from the reorder ring buffer */
tid_agg_rx
->
stored_mpdu_num
--
;
tid_agg_rx
->
reorder_buf
[
index
]
=
NULL
;
status
=
IEEE80211_SKB_RXCB
(
skb
);
status
->
rx_flags
|=
IEEE80211_RX_DEFERRED_RELEASE
;
__skb_queue_tail
(
frames
,
skb
);
while
((
skb
=
__skb_dequeue
(
skb_list
)))
{
status
=
IEEE80211_SKB_RXCB
(
skb
);
status
->
rx_flags
|=
IEEE80211_RX_DEFERRED_RELEASE
;
__skb_queue_tail
(
frames
,
skb
);
}
no_frame:
tid_agg_rx
->
head_seq_num
=
ieee80211_sn_inc
(
tid_agg_rx
->
head_seq_num
);
...
...
@@ -738,13 +745,13 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
struct
tid_ampdu_rx
*
tid_agg_rx
,
struct
sk_buff_head
*
frames
)
{
int
index
,
j
;
int
index
,
i
,
j
;
lockdep_assert_held
(
&
tid_agg_rx
->
reorder_lock
);
/* release the buffer until next missing frame */
index
=
tid_agg_rx
->
head_seq_num
%
tid_agg_rx
->
buf_size
;
if
(
!
tid_agg_rx
->
reorder_buf
[
index
]
&&
if
(
!
ieee80211_rx_reorder_ready
(
&
tid_agg_rx
->
reorder_buf
[
index
])
&&
tid_agg_rx
->
stored_mpdu_num
)
{
/*
* No buffers ready to be released, but check whether any
...
...
@@ -753,7 +760,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
int
skipped
=
1
;
for
(
j
=
(
index
+
1
)
%
tid_agg_rx
->
buf_size
;
j
!=
index
;
j
=
(
j
+
1
)
%
tid_agg_rx
->
buf_size
)
{
if
(
!
tid_agg_rx
->
reorder_buf
[
j
])
{
if
(
!
ieee80211_rx_reorder_ready
(
&
tid_agg_rx
->
reorder_buf
[
j
]))
{
skipped
++
;
continue
;
}
...
...
@@ -762,6 +770,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
HT_RX_REORDER_BUF_TIMEOUT
))
goto
set_release_timer
;
/* don't leave incomplete A-MSDUs around */
for
(
i
=
(
index
+
1
)
%
tid_agg_rx
->
buf_size
;
i
!=
j
;
i
=
(
i
+
1
)
%
tid_agg_rx
->
buf_size
)
__skb_queue_purge
(
&
tid_agg_rx
->
reorder_buf
[
i
]);
ht_dbg_ratelimited
(
sdata
,
"release an RX reorder frame due to timeout on earlier frames
\n
"
);
ieee80211_release_reorder_frame
(
sdata
,
tid_agg_rx
,
j
,
...
...
@@ -775,7 +788,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
skipped
)
&
IEEE80211_SN_MASK
;
skipped
=
0
;
}
}
else
while
(
tid_agg_rx
->
reorder_buf
[
index
])
{
}
else
while
(
ieee80211_rx_reorder_ready
(
&
tid_agg_rx
->
reorder_buf
[
index
]))
{
ieee80211_release_reorder_frame
(
sdata
,
tid_agg_rx
,
index
,
frames
);
index
=
tid_agg_rx
->
head_seq_num
%
tid_agg_rx
->
buf_size
;
...
...
@@ -786,7 +800,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
for
(;
j
!=
(
index
-
1
)
%
tid_agg_rx
->
buf_size
;
j
=
(
j
+
1
)
%
tid_agg_rx
->
buf_size
)
{
if
(
tid_agg_rx
->
reorder_buf
[
j
])
if
(
ieee80211_rx_reorder_ready
(
&
tid_agg_rx
->
reorder_buf
[
j
]))
break
;
}
...
...
@@ -811,6 +826,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
struct
sk_buff_head
*
frames
)
{
struct
ieee80211_hdr
*
hdr
=
(
struct
ieee80211_hdr
*
)
skb
->
data
;
struct
ieee80211_rx_status
*
status
=
IEEE80211_SKB_RXCB
(
skb
);
u16
sc
=
le16_to_cpu
(
hdr
->
seq_ctrl
);
u16
mpdu_seq_num
=
(
sc
&
IEEE80211_SCTL_SEQ
)
>>
4
;
u16
head_seq_num
,
buf_size
;
...
...
@@ -845,7 +861,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
index
=
mpdu_seq_num
%
tid_agg_rx
->
buf_size
;
/* check if we already stored this frame */
if
(
tid_agg_rx
->
reorder_buf
[
index
]
)
{
if
(
ieee80211_rx_reorder_ready
(
&
tid_agg_rx
->
reorder_buf
[
index
])
)
{
dev_kfree_skb
(
skb
);
goto
out
;
}
...
...
@@ -858,17 +874,20 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
*/
if
(
mpdu_seq_num
==
tid_agg_rx
->
head_seq_num
&&
tid_agg_rx
->
stored_mpdu_num
==
0
)
{
tid_agg_rx
->
head_seq_num
=
ieee80211_sn_inc
(
tid_agg_rx
->
head_seq_num
);
if
(
!
(
status
->
flag
&
RX_FLAG_AMSDU_MORE
))
tid_agg_rx
->
head_seq_num
=
ieee80211_sn_inc
(
tid_agg_rx
->
head_seq_num
);
ret
=
false
;
goto
out
;
}
/* put the frame in the reordering buffer */
tid_agg_rx
->
reorder_buf
[
index
]
=
skb
;
tid_agg_rx
->
reorder_time
[
index
]
=
jiffies
;
tid_agg_rx
->
stored_mpdu_num
++
;
ieee80211_sta_reorder_release
(
sdata
,
tid_agg_rx
,
frames
);
__skb_queue_tail
(
&
tid_agg_rx
->
reorder_buf
[
index
],
skb
);
if
(
!
(
status
->
flag
&
RX_FLAG_AMSDU_MORE
))
{
tid_agg_rx
->
reorder_time
[
index
]
=
jiffies
;
tid_agg_rx
->
stored_mpdu_num
++
;
ieee80211_sta_reorder_release
(
sdata
,
tid_agg_rx
,
frames
);
}
out:
spin_unlock
(
&
tid_agg_rx
->
reorder_lock
);
...
...
@@ -3129,6 +3148,14 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
if
(
!
ieee80211_is_beacon
(
hdr
->
frame_control
))
return
false
;
status
->
rx_flags
&=
~
IEEE80211_RX_RA_MATCH
;
}
else
if
(
!
ieee80211_has_tods
(
hdr
->
frame_control
))
{
/* ignore data frames to TDLS-peers */
if
(
ieee80211_is_data
(
hdr
->
frame_control
))
return
false
;
/* ignore action frames to TDLS-peers */
if
(
ieee80211_is_action
(
hdr
->
frame_control
)
&&
!
ether_addr_equal
(
bssid
,
hdr
->
addr1
))
return
false
;
}
break
;
case
NL80211_IFTYPE_WDS
:
...
...
net/mac80211/sta_info.h
View file @
a006827a
...
...
@@ -47,6 +47,8 @@
* @WLAN_STA_TDLS_PEER: Station is a TDLS peer.
* @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct
* packets. This means the link is enabled.
* @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this
* station.
* @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was
* keeping station in power-save mode, reply when the driver
* unblocks the station.
...
...
@@ -76,6 +78,7 @@ enum ieee80211_sta_info_flags {
WLAN_STA_PSPOLL
,
WLAN_STA_TDLS_PEER
,
WLAN_STA_TDLS_PEER_AUTH
,
WLAN_STA_TDLS_INITIATOR
,
WLAN_STA_UAPSD
,
WLAN_STA_SP
,
WLAN_STA_4ADDR_EVENT
,
...
...
@@ -152,7 +155,8 @@ struct tid_ampdu_tx {
/**
* struct tid_ampdu_rx - TID aggregation information (Rx).
*
* @reorder_buf: buffer to reorder incoming aggregated MPDUs
* @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an
* A-MSDU with individually reported subframes.
* @reorder_time: jiffies when skb was added
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
* @reorder_timer: releases expired frames from the reorder buffer.
...
...
@@ -177,7 +181,7 @@ struct tid_ampdu_tx {
struct
tid_ampdu_rx
{
struct
rcu_head
rcu_head
;
spinlock_t
reorder_lock
;
struct
sk_buff
*
*
reorder_buf
;
struct
sk_buff
_head
*
reorder_buf
;
unsigned
long
*
reorder_time
;
struct
timer_list
session_timer
;
struct
timer_list
reorder_timer
;
...
...
net/mac80211/tdls.c
View file @
a006827a
...
...
@@ -8,6 +8,7 @@
*/
#include <linux/ieee80211.h>
#include <linux/log2.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
...
...
@@ -21,14 +22,14 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk)
struct
ieee80211_local
*
local
;
sdata
=
container_of
(
wk
,
struct
ieee80211_sub_if_data
,
tdls_peer_del_work
.
work
);
u
.
mgd
.
tdls_peer_del_work
.
work
);
local
=
sdata
->
local
;
mutex_lock
(
&
local
->
mtx
);
if
(
!
is_zero_ether_addr
(
sdata
->
tdls_peer
))
{
tdls_dbg
(
sdata
,
"TDLS del peer %pM
\n
"
,
sdata
->
tdls_peer
);
sta_info_destroy_addr
(
sdata
,
sdata
->
tdls_peer
);
eth_zero_addr
(
sdata
->
tdls_peer
);
if
(
!
is_zero_ether_addr
(
sdata
->
u
.
mgd
.
tdls_peer
))
{
tdls_dbg
(
sdata
,
"TDLS del peer %pM
\n
"
,
sdata
->
u
.
mgd
.
tdls_peer
);
sta_info_destroy_addr
(
sdata
,
sdata
->
u
.
mgd
.
tdls_peer
);
eth_zero_addr
(
sdata
->
u
.
mgd
.
tdls_peer
);
}
mutex_unlock
(
&
local
->
mtx
);
}
...
...
@@ -46,11 +47,16 @@ static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
*
pos
++
=
WLAN_EXT_CAPA5_TDLS_ENABLED
;
}
static
u16
ieee80211_get_tdls_sta_capab
(
struct
ieee80211_sub_if_data
*
sdata
)
static
u16
ieee80211_get_tdls_sta_capab
(
struct
ieee80211_sub_if_data
*
sdata
,
u16
status_code
)
{
struct
ieee80211_local
*
local
=
sdata
->
local
;
u16
capab
;
/* The capability will be 0 when sending a failure code */
if
(
status_code
!=
0
)
return
0
;
capab
=
0
;
if
(
ieee80211_get_sdata_band
(
sdata
)
!=
IEEE80211_BAND_2GHZ
)
return
capab
;
...
...
@@ -63,19 +69,332 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
return
capab
;
}
static
void
ieee80211_tdls_add_link_ie
(
struct
sk_buff
*
skb
,
const
u8
*
src_addr
,
const
u8
*
peer
,
const
u8
*
bssid
)
static
void
ieee80211_tdls_add_link_ie
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
sk_buff
*
skb
,
const
u8
*
peer
,
bool
initiator
)
{
struct
ieee80211_tdls_lnkie
*
lnkid
;
const
u8
*
init_addr
,
*
rsp_addr
;
if
(
initiator
)
{
init_addr
=
sdata
->
vif
.
addr
;
rsp_addr
=
peer
;
}
else
{
init_addr
=
peer
;
rsp_addr
=
sdata
->
vif
.
addr
;
}
lnkid
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
struct
ieee80211_tdls_lnkie
));
lnkid
->
ie_type
=
WLAN_EID_LINK_ID
;
lnkid
->
ie_len
=
sizeof
(
struct
ieee80211_tdls_lnkie
)
-
2
;
memcpy
(
lnkid
->
bssid
,
bssid
,
ETH_ALEN
);
memcpy
(
lnkid
->
init_sta
,
src_addr
,
ETH_ALEN
);
memcpy
(
lnkid
->
resp_sta
,
peer
,
ETH_ALEN
);
memcpy
(
lnkid
->
bssid
,
sdata
->
u
.
mgd
.
bssid
,
ETH_ALEN
);
memcpy
(
lnkid
->
init_sta
,
init_addr
,
ETH_ALEN
);
memcpy
(
lnkid
->
resp_sta
,
rsp_addr
,
ETH_ALEN
);
}
/* translate numbering in the WMM parameter IE to the mac80211 notation */
static
enum
ieee80211_ac_numbers
ieee80211_ac_from_wmm
(
int
ac
)
{
switch
(
ac
)
{
default:
WARN_ON_ONCE
(
1
);
case
0
:
return
IEEE80211_AC_BE
;
case
1
:
return
IEEE80211_AC_BK
;
case
2
:
return
IEEE80211_AC_VI
;
case
3
:
return
IEEE80211_AC_VO
;
}
}
static
u8
ieee80211_wmm_aci_aifsn
(
int
aifsn
,
bool
acm
,
int
aci
)
{
u8
ret
;
ret
=
aifsn
&
0x0f
;
if
(
acm
)
ret
|=
0x10
;
ret
|=
(
aci
<<
5
)
&
0x60
;
return
ret
;
}
static
u8
ieee80211_wmm_ecw
(
u16
cw_min
,
u16
cw_max
)
{
return
((
ilog2
(
cw_min
+
1
)
<<
0x0
)
&
0x0f
)
|
((
ilog2
(
cw_max
+
1
)
<<
0x4
)
&
0xf0
);
}
static
void
ieee80211_tdls_add_wmm_param_ie
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
sk_buff
*
skb
)
{
struct
ieee80211_wmm_param_ie
*
wmm
;
struct
ieee80211_tx_queue_params
*
txq
;
int
i
;
wmm
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
wmm
));
memset
(
wmm
,
0
,
sizeof
(
*
wmm
));
wmm
->
element_id
=
WLAN_EID_VENDOR_SPECIFIC
;
wmm
->
len
=
sizeof
(
*
wmm
)
-
2
;
wmm
->
oui
[
0
]
=
0x00
;
/* Microsoft OUI 00:50:F2 */
wmm
->
oui
[
1
]
=
0x50
;
wmm
->
oui
[
2
]
=
0xf2
;
wmm
->
oui_type
=
2
;
/* WME */
wmm
->
oui_subtype
=
1
;
/* WME param */
wmm
->
version
=
1
;
/* WME ver */
wmm
->
qos_info
=
0
;
/* U-APSD not in use */
/*
* Use the EDCA parameters defined for the BSS, or default if the AP
* doesn't support it, as mandated by 802.11-2012 section 10.22.4
*/
for
(
i
=
0
;
i
<
IEEE80211_NUM_ACS
;
i
++
)
{
txq
=
&
sdata
->
tx_conf
[
ieee80211_ac_from_wmm
(
i
)];
wmm
->
ac
[
i
].
aci_aifsn
=
ieee80211_wmm_aci_aifsn
(
txq
->
aifs
,
txq
->
acm
,
i
);
wmm
->
ac
[
i
].
cw
=
ieee80211_wmm_ecw
(
txq
->
cw_min
,
txq
->
cw_max
);
wmm
->
ac
[
i
].
txop_limit
=
cpu_to_le16
(
txq
->
txop
);
}
}
static
void
ieee80211_tdls_add_setup_start_ies
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
sk_buff
*
skb
,
const
u8
*
peer
,
u8
action_code
,
bool
initiator
,
const
u8
*
extra_ies
,
size_t
extra_ies_len
)
{
enum
ieee80211_band
band
=
ieee80211_get_sdata_band
(
sdata
);
struct
ieee80211_local
*
local
=
sdata
->
local
;
struct
ieee80211_supported_band
*
sband
;
struct
ieee80211_sta_ht_cap
ht_cap
;
struct
sta_info
*
sta
=
NULL
;
size_t
offset
=
0
,
noffset
;
u8
*
pos
;
rcu_read_lock
();
/* we should have the peer STA if we're already responding */
if
(
action_code
==
WLAN_TDLS_SETUP_RESPONSE
)
{
sta
=
sta_info_get
(
sdata
,
peer
);
if
(
WARN_ON_ONCE
(
!
sta
))
{
rcu_read_unlock
();
return
;
}
}
ieee80211_add_srates_ie
(
sdata
,
skb
,
false
,
band
);
ieee80211_add_ext_srates_ie
(
sdata
,
skb
,
false
,
band
);
/* add any custom IEs that go before Extended Capabilities */
if
(
extra_ies_len
)
{
static
const
u8
before_ext_cap
[]
=
{
WLAN_EID_SUPP_RATES
,
WLAN_EID_COUNTRY
,
WLAN_EID_EXT_SUPP_RATES
,
WLAN_EID_SUPPORTED_CHANNELS
,
WLAN_EID_RSN
,
};
noffset
=
ieee80211_ie_split
(
extra_ies
,
extra_ies_len
,
before_ext_cap
,
ARRAY_SIZE
(
before_ext_cap
),
offset
);
pos
=
skb_put
(
skb
,
noffset
-
offset
);
memcpy
(
pos
,
extra_ies
+
offset
,
noffset
-
offset
);
offset
=
noffset
;
}
ieee80211_tdls_add_ext_capab
(
skb
);
/* add the QoS element if we support it */
if
(
local
->
hw
.
queues
>=
IEEE80211_NUM_ACS
&&
action_code
!=
WLAN_PUB_ACTION_TDLS_DISCOVER_RES
)
ieee80211_add_wmm_info_ie
(
skb_put
(
skb
,
9
),
0
);
/* no U-APSD */
/* add any custom IEs that go before HT capabilities */
if
(
extra_ies_len
)
{
static
const
u8
before_ht_cap
[]
=
{
WLAN_EID_SUPP_RATES
,
WLAN_EID_COUNTRY
,
WLAN_EID_EXT_SUPP_RATES
,
WLAN_EID_SUPPORTED_CHANNELS
,
WLAN_EID_RSN
,
WLAN_EID_EXT_CAPABILITY
,
WLAN_EID_QOS_CAPA
,
WLAN_EID_FAST_BSS_TRANSITION
,
WLAN_EID_TIMEOUT_INTERVAL
,
WLAN_EID_SUPPORTED_REGULATORY_CLASSES
,
};
noffset
=
ieee80211_ie_split
(
extra_ies
,
extra_ies_len
,
before_ht_cap
,
ARRAY_SIZE
(
before_ht_cap
),
offset
);
pos
=
skb_put
(
skb
,
noffset
-
offset
);
memcpy
(
pos
,
extra_ies
+
offset
,
noffset
-
offset
);
offset
=
noffset
;
}
/*
* with TDLS we can switch channels, and HT-caps are not necessarily
* the same on all bands. The specification limits the setup to a
* single HT-cap, so use the current band for now.
*/
sband
=
local
->
hw
.
wiphy
->
bands
[
band
];
memcpy
(
&
ht_cap
,
&
sband
->
ht_cap
,
sizeof
(
ht_cap
));
if
((
action_code
==
WLAN_TDLS_SETUP_REQUEST
||
action_code
==
WLAN_TDLS_SETUP_RESPONSE
)
&&
ht_cap
.
ht_supported
&&
(
!
sta
||
sta
->
sta
.
ht_cap
.
ht_supported
))
{
if
(
action_code
==
WLAN_TDLS_SETUP_REQUEST
)
{
ieee80211_apply_htcap_overrides
(
sdata
,
&
ht_cap
);
/* disable SMPS in TDLS initiator */
ht_cap
.
cap
|=
(
WLAN_HT_CAP_SM_PS_DISABLED
<<
IEEE80211_HT_CAP_SM_PS_SHIFT
);
}
else
{
/* disable SMPS in TDLS responder */
sta
->
sta
.
ht_cap
.
cap
|=
(
WLAN_HT_CAP_SM_PS_DISABLED
<<
IEEE80211_HT_CAP_SM_PS_SHIFT
);
/* the peer caps are already intersected with our own */
memcpy
(
&
ht_cap
,
&
sta
->
sta
.
ht_cap
,
sizeof
(
ht_cap
));
}
pos
=
skb_put
(
skb
,
sizeof
(
struct
ieee80211_ht_cap
)
+
2
);
ieee80211_ie_build_ht_cap
(
pos
,
&
ht_cap
,
ht_cap
.
cap
);
}
rcu_read_unlock
();
/* add any remaining IEs */
if
(
extra_ies_len
)
{
noffset
=
extra_ies_len
;
pos
=
skb_put
(
skb
,
noffset
-
offset
);
memcpy
(
pos
,
extra_ies
+
offset
,
noffset
-
offset
);
}
ieee80211_tdls_add_link_ie
(
sdata
,
skb
,
peer
,
initiator
);
}
static
void
ieee80211_tdls_add_setup_cfm_ies
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
sk_buff
*
skb
,
const
u8
*
peer
,
bool
initiator
,
const
u8
*
extra_ies
,
size_t
extra_ies_len
)
{
struct
ieee80211_local
*
local
=
sdata
->
local
;
struct
ieee80211_if_managed
*
ifmgd
=
&
sdata
->
u
.
mgd
;
size_t
offset
=
0
,
noffset
;
struct
sta_info
*
sta
,
*
ap_sta
;
u8
*
pos
;
rcu_read_lock
();
sta
=
sta_info_get
(
sdata
,
peer
);
ap_sta
=
sta_info_get
(
sdata
,
ifmgd
->
bssid
);
if
(
WARN_ON_ONCE
(
!
sta
||
!
ap_sta
))
{
rcu_read_unlock
();
return
;
}
/* add any custom IEs that go before the QoS IE */
if
(
extra_ies_len
)
{
static
const
u8
before_qos
[]
=
{
WLAN_EID_RSN
,
};
noffset
=
ieee80211_ie_split
(
extra_ies
,
extra_ies_len
,
before_qos
,
ARRAY_SIZE
(
before_qos
),
offset
);
pos
=
skb_put
(
skb
,
noffset
-
offset
);
memcpy
(
pos
,
extra_ies
+
offset
,
noffset
-
offset
);
offset
=
noffset
;
}
/* add the QoS param IE if both the peer and we support it */
if
(
local
->
hw
.
queues
>=
IEEE80211_NUM_ACS
&&
test_sta_flag
(
sta
,
WLAN_STA_WME
))
ieee80211_tdls_add_wmm_param_ie
(
sdata
,
skb
);
/* add any custom IEs that go before HT operation */
if
(
extra_ies_len
)
{
static
const
u8
before_ht_op
[]
=
{
WLAN_EID_RSN
,
WLAN_EID_QOS_CAPA
,
WLAN_EID_FAST_BSS_TRANSITION
,
WLAN_EID_TIMEOUT_INTERVAL
,
};
noffset
=
ieee80211_ie_split
(
extra_ies
,
extra_ies_len
,
before_ht_op
,
ARRAY_SIZE
(
before_ht_op
),
offset
);
pos
=
skb_put
(
skb
,
noffset
-
offset
);
memcpy
(
pos
,
extra_ies
+
offset
,
noffset
-
offset
);
offset
=
noffset
;
}
/* if HT support is only added in TDLS, we need an HT-operation IE */
if
(
!
ap_sta
->
sta
.
ht_cap
.
ht_supported
&&
sta
->
sta
.
ht_cap
.
ht_supported
)
{
struct
ieee80211_chanctx_conf
*
chanctx_conf
=
rcu_dereference
(
sdata
->
vif
.
chanctx_conf
);
if
(
!
WARN_ON
(
!
chanctx_conf
))
{
pos
=
skb_put
(
skb
,
2
+
sizeof
(
struct
ieee80211_ht_operation
));
/* send an empty HT operation IE */
ieee80211_ie_build_ht_oper
(
pos
,
&
sta
->
sta
.
ht_cap
,
&
chanctx_conf
->
def
,
0
);
}
}
rcu_read_unlock
();
/* add any remaining IEs */
if
(
extra_ies_len
)
{
noffset
=
extra_ies_len
;
pos
=
skb_put
(
skb
,
noffset
-
offset
);
memcpy
(
pos
,
extra_ies
+
offset
,
noffset
-
offset
);
}
ieee80211_tdls_add_link_ie
(
sdata
,
skb
,
peer
,
initiator
);
}
static
void
ieee80211_tdls_add_ies
(
struct
ieee80211_sub_if_data
*
sdata
,
struct
sk_buff
*
skb
,
const
u8
*
peer
,
u8
action_code
,
u16
status_code
,
bool
initiator
,
const
u8
*
extra_ies
,
size_t
extra_ies_len
)
{
switch
(
action_code
)
{
case
WLAN_TDLS_SETUP_REQUEST
:
case
WLAN_TDLS_SETUP_RESPONSE
:
case
WLAN_PUB_ACTION_TDLS_DISCOVER_RES
:
if
(
status_code
==
0
)
ieee80211_tdls_add_setup_start_ies
(
sdata
,
skb
,
peer
,
action_code
,
initiator
,
extra_ies
,
extra_ies_len
);
break
;
case
WLAN_TDLS_SETUP_CONFIRM
:
if
(
status_code
==
0
)
ieee80211_tdls_add_setup_cfm_ies
(
sdata
,
skb
,
peer
,
initiator
,
extra_ies
,
extra_ies_len
);
break
;
case
WLAN_TDLS_TEARDOWN
:
case
WLAN_TDLS_DISCOVERY_REQUEST
:
if
(
extra_ies_len
)
memcpy
(
skb_put
(
skb
,
extra_ies_len
),
extra_ies
,
extra_ies_len
);
if
(
status_code
==
0
||
action_code
==
WLAN_TDLS_TEARDOWN
)
ieee80211_tdls_add_link_ie
(
sdata
,
skb
,
peer
,
initiator
);
break
;
}
}
static
int
...
...
@@ -84,7 +403,6 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
u16
status_code
,
struct
sk_buff
*
skb
)
{
struct
ieee80211_sub_if_data
*
sdata
=
IEEE80211_DEV_TO_SUB_IF
(
dev
);
enum
ieee80211_band
band
=
ieee80211_get_sdata_band
(
sdata
);
struct
ieee80211_tdls_data
*
tf
;
tf
=
(
void
*
)
skb_put
(
skb
,
offsetof
(
struct
ieee80211_tdls_data
,
u
));
...
...
@@ -102,11 +420,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
skb_put
(
skb
,
sizeof
(
tf
->
u
.
setup_req
));
tf
->
u
.
setup_req
.
dialog_token
=
dialog_token
;
tf
->
u
.
setup_req
.
capability
=
cpu_to_le16
(
ieee80211_get_tdls_sta_capab
(
sdata
));
ieee80211_add_srates_ie
(
sdata
,
skb
,
false
,
band
);
ieee80211_add_ext_srates_ie
(
sdata
,
skb
,
false
,
band
);
ieee80211_tdls_add_ext_capab
(
skb
);
cpu_to_le16
(
ieee80211_get_tdls_sta_capab
(
sdata
,
status_code
));
break
;
case
WLAN_TDLS_SETUP_RESPONSE
:
tf
->
category
=
WLAN_CATEGORY_TDLS
;
...
...
@@ -116,11 +431,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
tf
->
u
.
setup_resp
.
status_code
=
cpu_to_le16
(
status_code
);
tf
->
u
.
setup_resp
.
dialog_token
=
dialog_token
;
tf
->
u
.
setup_resp
.
capability
=
cpu_to_le16
(
ieee80211_get_tdls_sta_capab
(
sdata
));
ieee80211_add_srates_ie
(
sdata
,
skb
,
false
,
band
);
ieee80211_add_ext_srates_ie
(
sdata
,
skb
,
false
,
band
);
ieee80211_tdls_add_ext_capab
(
skb
);
cpu_to_le16
(
ieee80211_get_tdls_sta_capab
(
sdata
,
status_code
));
break
;
case
WLAN_TDLS_SETUP_CONFIRM
:
tf
->
category
=
WLAN_CATEGORY_TDLS
;
...
...
@@ -157,7 +469,6 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
u16
status_code
,
struct
sk_buff
*
skb
)
{
struct
ieee80211_sub_if_data
*
sdata
=
IEEE80211_DEV_TO_SUB_IF
(
dev
);
enum
ieee80211_band
band
=
ieee80211_get_sdata_band
(
sdata
);
struct
ieee80211_mgmt
*
mgmt
;
mgmt
=
(
void
*
)
skb_put
(
skb
,
24
);
...
...
@@ -178,11 +489,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
mgmt
->
u
.
action
.
u
.
tdls_discover_resp
.
dialog_token
=
dialog_token
;
mgmt
->
u
.
action
.
u
.
tdls_discover_resp
.
capability
=
cpu_to_le16
(
ieee80211_get_tdls_sta_capab
(
sdata
));
ieee80211_add_srates_ie
(
sdata
,
skb
,
false
,
band
);
ieee80211_add_ext_srates_ie
(
sdata
,
skb
,
false
,
band
);
ieee80211_tdls_add_ext_capab
(
skb
);
cpu_to_le16
(
ieee80211_get_tdls_sta_capab
(
sdata
,
status_code
));
break
;
default:
return
-
EINVAL
;
...
...
@@ -202,7 +510,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
struct
ieee80211_local
*
local
=
sdata
->
local
;
struct
sk_buff
*
skb
=
NULL
;
bool
send_direct
;
const
u8
*
init_addr
,
*
rsp_addr
;
struct
sta_info
*
sta
;
int
ret
;
skb
=
dev_alloc_skb
(
local
->
hw
.
extra_tx_headroom
+
...
...
@@ -210,6 +518,9 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
sizeof
(
struct
ieee80211_tdls_data
))
+
50
+
/* supported rates */
7
+
/* ext capab */
26
+
/* max(WMM-info, WMM-param) */
2
+
max
(
sizeof
(
struct
ieee80211_ht_cap
),
sizeof
(
struct
ieee80211_ht_operation
))
+
extra_ies_len
+
sizeof
(
struct
ieee80211_tdls_lnkie
));
if
(
!
skb
)
...
...
@@ -242,45 +553,48 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
if
(
ret
<
0
)
goto
fail
;
if
(
extra_ies_len
)
memcpy
(
skb_put
(
skb
,
extra_ies_len
),
extra_ies
,
extra_ies_len
);
rcu_read_lock
();
sta
=
sta_info_get
(
sdata
,
peer
);
/*
sanity check for initiator
*/
/*
infer the initiator if we can, to support old userspace
*/
switch
(
action_code
)
{
case
WLAN_TDLS_SETUP_REQUEST
:
if
(
sta
)
set_sta_flag
(
sta
,
WLAN_STA_TDLS_INITIATOR
);
/* fall-through */
case
WLAN_TDLS_SETUP_CONFIRM
:
case
WLAN_TDLS_DISCOVERY_REQUEST
:
if
(
!
initiator
)
{
ret
=
-
EINVAL
;
goto
fail
;
}
initiator
=
true
;
break
;
case
WLAN_TDLS_SETUP_RESPONSE
:
/*
* In some testing scenarios, we send a request and response.
* Make the last packet sent take effect for the initiator
* value.
*/
if
(
sta
)
clear_sta_flag
(
sta
,
WLAN_STA_TDLS_INITIATOR
);
/* fall-through */
case
WLAN_PUB_ACTION_TDLS_DISCOVER_RES
:
if
(
initiator
)
{
ret
=
-
EINVAL
;
goto
fail
;
}
initiator
=
false
;
break
;
case
WLAN_TDLS_TEARDOWN
:
/* any value is ok */
break
;
default:
ret
=
-
ENOTSUPP
;
goto
fail
;
break
;
}
if
(
initiator
)
{
init_addr
=
sdata
->
vif
.
addr
;
rsp_addr
=
peer
;
}
else
{
init_addr
=
peer
;
rsp_addr
=
sdata
->
vif
.
addr
;
}
if
(
sta
&&
test_sta_flag
(
sta
,
WLAN_STA_TDLS_INITIATOR
))
initiator
=
true
;
ieee80211_tdls_add_link_ie
(
skb
,
init_addr
,
rsp_addr
,
sdata
->
u
.
mgd
.
bssid
);
rcu_read_unlock
();
if
(
ret
<
0
)
goto
fail
;
ieee80211_tdls_add_ies
(
sdata
,
skb
,
peer
,
action_code
,
status_code
,
initiator
,
extra_ies
,
extra_ies_len
);
if
(
send_direct
)
{
ieee80211_tx_skb
(
sdata
,
skb
);
return
0
;
...
...
@@ -327,8 +641,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
mutex_lock
(
&
local
->
mtx
);
/* we don't support concurrent TDLS peer setups */
if
(
!
is_zero_ether_addr
(
sdata
->
tdls_peer
)
&&
!
ether_addr_equal
(
sdata
->
tdls_peer
,
peer
))
{
if
(
!
is_zero_ether_addr
(
sdata
->
u
.
mgd
.
tdls_peer
)
&&
!
ether_addr_equal
(
sdata
->
u
.
mgd
.
tdls_peer
,
peer
))
{
ret
=
-
EBUSY
;
goto
exit
;
}
...
...
@@ -336,15 +650,19 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
/*
* make sure we have a STA representing the peer so we drop or buffer
* non-TDLS-setup frames to the peer. We can't send other packets
* during setup through the AP path
* during setup through the AP path.
* Allow error packets to be sent - sometimes we don't even add a STA
* before failing the setup.
*/
rcu_read_lock
();
if
(
!
sta_info_get
(
sdata
,
peer
))
{
if
(
status_code
==
0
)
{
rcu_read_lock
();
if
(
!
sta_info_get
(
sdata
,
peer
))
{
rcu_read_unlock
();
ret
=
-
ENOLINK
;
goto
exit
;
}
rcu_read_unlock
();
ret
=
-
ENOLINK
;
goto
exit
;
}
rcu_read_unlock
();
ieee80211_flush_queues
(
local
,
sdata
);
...
...
@@ -355,9 +673,9 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
if
(
ret
<
0
)
goto
exit
;
memcpy
(
sdata
->
tdls_peer
,
peer
,
ETH_ALEN
);
memcpy
(
sdata
->
u
.
mgd
.
tdls_peer
,
peer
,
ETH_ALEN
);
ieee80211_queue_delayed_work
(
&
sdata
->
local
->
hw
,
&
sdata
->
tdls_peer_del_work
,
&
sdata
->
u
.
mgd
.
tdls_peer_del_work
,
TDLS_PEER_SETUP_TIMEOUT
);
exit:
...
...
@@ -513,11 +831,22 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
set_sta_flag
(
sta
,
WLAN_STA_TDLS_PEER_AUTH
);
rcu_read_unlock
();
WARN_ON_ONCE
(
is_zero_ether_addr
(
sdata
->
tdls_peer
)
||
!
ether_addr_equal
(
sdata
->
tdls_peer
,
peer
));
WARN_ON_ONCE
(
is_zero_ether_addr
(
sdata
->
u
.
mgd
.
tdls_peer
)
||
!
ether_addr_equal
(
sdata
->
u
.
mgd
.
tdls_peer
,
peer
));
ret
=
0
;
break
;
case
NL80211_TDLS_DISABLE_LINK
:
/*
* The teardown message in ieee80211_tdls_mgmt_teardown() was
* created while the queues were stopped, so it might still be
* pending. Before flushing the queues we need to be sure the
* message is handled by the tasklet handling pending messages,
* otherwise we might start destroying the station before
* sending the teardown packet.
* Note that this only forces the tasklet to flush pendings -
* not to stop the tasklet from rescheduling itself.
*/
tasklet_kill
(
&
local
->
tx_pending_tasklet
);
/* flush a potentially queued teardown packet */
ieee80211_flush_queues
(
local
,
sdata
);
...
...
@@ -528,9 +857,9 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
break
;
}
if
(
ret
==
0
&&
ether_addr_equal
(
sdata
->
tdls_peer
,
peer
))
{
cancel_delayed_work
(
&
sdata
->
tdls_peer_del_work
);
eth_zero_addr
(
sdata
->
tdls_peer
);
if
(
ret
==
0
&&
ether_addr_equal
(
sdata
->
u
.
mgd
.
tdls_peer
,
peer
))
{
cancel_delayed_work
(
&
sdata
->
u
.
mgd
.
tdls_peer_del_work
);
eth_zero_addr
(
sdata
->
u
.
mgd
.
tdls_peer
);
}
mutex_unlock
(
&
local
->
mtx
);
...
...
net/mac80211/util.c
View file @
a006827a
...
...
@@ -3083,3 +3083,18 @@ int ieee80211_max_num_channels(struct ieee80211_local *local)
return
max_num_different_channels
;
}
u8
*
ieee80211_add_wmm_info_ie
(
u8
*
buf
,
u8
qosinfo
)
{
*
buf
++
=
WLAN_EID_VENDOR_SPECIFIC
;
*
buf
++
=
7
;
/* len */
*
buf
++
=
0x00
;
/* Microsoft OUI 00:50:F2 */
*
buf
++
=
0x50
;
*
buf
++
=
0xf2
;
*
buf
++
=
2
;
/* WME */
*
buf
++
=
0
;
/* WME info */
*
buf
++
=
1
;
/* WME ver */
*
buf
++
=
qosinfo
;
/* U-APSD no in use */
return
buf
;
}
net/mac80211/vht.c
View file @
a006827a
...
...
@@ -129,6 +129,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
if
(
!
vht_cap_ie
||
!
sband
->
vht_cap
.
vht_supported
)
return
;
/* don't support VHT for TDLS peers for now */
if
(
test_sta_flag
(
sta
,
WLAN_STA_TDLS_PEER
))
return
;
/*
* A VHT STA must support 40 MHz, but if we verify that here
* then we break a few things - some APs (e.g. Netgear R6300v2
...
...
net/mac80211/wpa.c
View file @
a006827a
...
...
@@ -811,7 +811,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
ieee80211_rx_result
ieee80211_crypto_hw_decrypt
(
struct
ieee80211_rx_data
*
rx
)
{
if
(
rx
->
sta
->
cipher_scheme
)
if
(
rx
->
sta
&&
rx
->
sta
->
cipher_scheme
)
return
ieee80211_crypto_cs_decrypt
(
rx
);
return
RX_DROP_UNUSABLE
;
...
...
net/wireless/Kconfig
View file @
a006827a
...
...
@@ -162,6 +162,12 @@ config CFG80211_INTERNAL_REGDB
and includes code to query that database. This is an alternative
to using CRDA for defining regulatory rules for the kernel.
Using this option requires some parsing of the db.txt at build time,
the parser will be upkept with the latest wireless-regdb updates but
older wireless-regdb formats will be ignored. The parser may later
be replaced to avoid issues with conflicts on versions of
wireless-regdb.
For details see:
http://wireless.kernel.org/en/developers/Regulatory
...
...
net/wireless/genregdb.awk
View file @
a006827a
...
...
@@ -51,32 +51,41 @@ function parse_country_head() {
function
parse_reg_rule
()
{
flag_starts_at
=
7
start
=
$1
sub
(
/
\(
/
,
""
,
start
)
end
=
$3
bw
=
$5
sub
(
/
\)
,/
,
""
,
bw
)
gain
=
$6
sub
(
/
\(
/
,
""
,
gain
)
sub
(
/,/
,
""
,
gain
)
power
=
$7
sub
(
/
\)
/
,
""
,
power
)
sub
(
/,/
,
""
,
power
)
gain
=
0
power
=
$6
# power might be in mW...
units
=
$8
units
=
$7
dfs_cac
=
0
sub
(
/
\(
/
,
""
,
power
)
sub
(
/
\)
,/
,
""
,
power
)
sub
(
/
\)
,/
,
""
,
units
)
sub
(
/
\)
/
,
""
,
units
)
sub
(
/,/
,
""
,
units
)
dfs_cac
=
$9
if
(
units
==
"mW"
)
{
flag_starts_at
=
8
power
=
10
*
log
(
power
)
/
log
(
10
)
if
(
$8
~
/
[
[:digit:
]
]/
)
{
flag_starts_at
=
9
dfs_cac
=
$8
}
}
else
{
dfs_cac
=
$8
if
(
$7
~
/
[
[:digit:
]
]/
)
{
flag_starts_at
=
8
dfs_cac
=
$7
}
}
sub
(
/,/
,
""
,
dfs_cac
)
sub
(
/
\(
/
,
""
,
dfs_cac
)
sub
(
/
\)
/
,
""
,
dfs_cac
)
sub
(
/
\)
,
/
,
""
,
dfs_cac
)
flagstr
=
""
for
(
i
=
8
;
i
<=
NF
;
i
++
)
for
(
i
=
flag_starts_at
;
i
<=
NF
;
i
++
)
flagstr
=
flagstr
$i
split
(
flagstr
,
flagarray
,
","
)
flags
=
""
...
...
net/wireless/nl80211.c
View file @
a006827a
...
...
@@ -3814,7 +3814,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
{
if
(
params
->
listen_interval
!=
-
1
)
return
-
EINVAL
;
if
(
params
->
aid
)
if
(
params
->
aid
&&
!
(
params
->
sta_flags_set
&
BIT
(
NL80211_STA_FLAG_TDLS_PEER
)))
return
-
EINVAL
;
/* When you run into this, adjust the code below for the new flag */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment