ioctl_cfg80211.c revision 27fd731ece203c37f0a3708cafc95e9cead8cd2d
1b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger/******************************************************************************
2b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger *
3b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
4b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger *
5b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger * This program is free software; you can redistribute it and/or modify it
6b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger * under the terms of version 2 of the GNU General Public License as
7b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger * published by the Free Software Foundation.
8b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger *
9b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger * This program is distributed in the hope that it will be useful, but WITHOUT
10b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger * more details.
13b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger *
14b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger ******************************************************************************/
15b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define  _IOCTL_CFG80211_C_
16b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
17b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#include <osdep_service.h>
18b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#include <drv_types.h>
19b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#include <rtw_ioctl_set.h>
20b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#include <xmit_osdep.h>
21b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
22b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#include "ioctl_cfg80211.h"
23b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
24b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define RTW_MAX_MGMT_TX_CNT 8
25b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
26b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define RTW_MAX_REMAIN_ON_CHANNEL_DURATION 65535	/* ms */
27b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define RTW_MAX_NUM_PMKIDS 4
28b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
29b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic const u32 rtw_cipher_suites[] = {
30b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	WLAN_CIPHER_SUITE_WEP40,
31b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	WLAN_CIPHER_SUITE_WEP104,
32b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	WLAN_CIPHER_SUITE_TKIP,
33b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	WLAN_CIPHER_SUITE_CCMP,
34b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger};
35b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
36b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define RATETAB_ENT(_rate, _rateid, _flags) {			\
37b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.bitrate	= (_rate),				\
38b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.hw_value	= (_rateid),				\
39b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.flags		= (_flags),				\
40b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
41b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
42b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define CHAN2G(_channel, _freq, _flags) {			\
43b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.band			= IEEE80211_BAND_2GHZ,		\
44b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.center_freq		= (_freq),			\
45b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.hw_value		= (_channel),			\
46b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.flags			= (_flags),			\
47b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.max_antenna_gain	= 0,				\
48b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.max_power		= 30,				\
49b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
50b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
51b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define CHAN5G(_channel, _flags) {				\
52b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.band			= IEEE80211_BAND_5GHZ,		\
53b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.center_freq		= 5000 + (5 * (_channel)),	\
54b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.hw_value		= (_channel),			\
55b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.flags			= (_flags),			\
56b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.max_antenna_gain	= 0,				\
57b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.max_power		= 30,				\
58b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
59b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
60b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic struct ieee80211_rate rtw_rates[] = {
61b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(10, 0x1, 0),
62b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(20, 0x2, 0),
63b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(55, 0x4, 0),
64b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(110, 0x8, 0),
65b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(60, 0x10, 0),
66b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(90, 0x20, 0),
67b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(120, 0x40, 0),
68b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(180, 0x80, 0),
69b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(240, 0x100, 0),
70b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(360, 0x200, 0),
71b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(480, 0x400, 0),
72b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RATETAB_ENT(540, 0x800, 0),
73b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger};
74b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
75b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define rtw_a_rates		(rtw_rates + 4)
76b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define RTW_A_RATES_NUM	8
77b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define rtw_g_rates		(rtw_rates + 0)
78b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define RTW_G_RATES_NUM	12
79b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
80b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define RTW_2G_CHANNELS_NUM 14
81b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define RTW_5G_CHANNELS_NUM 37
82b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
83b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic struct ieee80211_channel rtw_2ghz_channels[] = {
84b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(1, 2412, 0),
85b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(2, 2417, 0),
86b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(3, 2422, 0),
87b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(4, 2427, 0),
88b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(5, 2432, 0),
89b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(6, 2437, 0),
90b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(7, 2442, 0),
91b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(8, 2447, 0),
92b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(9, 2452, 0),
93b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(10, 2457, 0),
94b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(11, 2462, 0),
95b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(12, 2467, 0),
96b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(13, 2472, 0),
97b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN2G(14, 2484, 0),
98b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger};
99b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
100b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic struct ieee80211_channel rtw_5ghz_a_channels[] = {
101b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(34, 0), CHAN5G(36, 0),
102b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(38, 0), CHAN5G(40, 0),
103b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(42, 0), CHAN5G(44, 0),
104b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(46, 0), CHAN5G(48, 0),
105b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(52, 0), CHAN5G(56, 0),
106b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(60, 0), CHAN5G(64, 0),
107b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(100, 0), CHAN5G(104, 0),
108b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(108, 0), CHAN5G(112, 0),
109b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(116, 0), CHAN5G(120, 0),
110b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(124, 0), CHAN5G(128, 0),
111b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(132, 0), CHAN5G(136, 0),
112b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(140, 0), CHAN5G(149, 0),
113b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(153, 0), CHAN5G(157, 0),
114b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(161, 0), CHAN5G(165, 0),
115b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(184, 0), CHAN5G(188, 0),
116b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(192, 0), CHAN5G(196, 0),
117b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(200, 0), CHAN5G(204, 0),
118b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(208, 0), CHAN5G(212, 0),
119b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	CHAN5G(216, 0),
120b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger};
121b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
122b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic void rtw_2g_channels_init(struct ieee80211_channel *channels)
123b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
124b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy((void *)channels, (void *)rtw_2ghz_channels,
125b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	       sizeof(struct ieee80211_channel) * RTW_2G_CHANNELS_NUM);
126b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
127b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
128b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic void rtw_5g_channels_init(struct ieee80211_channel *channels)
129b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
130b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy((void *)channels, (void *)rtw_5ghz_a_channels,
131b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	       sizeof(struct ieee80211_channel) * RTW_5G_CHANNELS_NUM);
132b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
133b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
134b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic void rtw_2g_rates_init(struct ieee80211_rate *rates)
135b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
136b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy(rates, rtw_g_rates,
137b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	       sizeof(struct ieee80211_rate) * RTW_G_RATES_NUM);
138b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
139b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
140b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic void rtw_5g_rates_init(struct ieee80211_rate *rates)
141b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
142b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy(rates, rtw_a_rates,
143b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	       sizeof(struct ieee80211_rate) * RTW_A_RATES_NUM);
144b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
145b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
146b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic struct ieee80211_supported_band *
147b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerrtw_spt_band_alloc(enum ieee80211_band band)
148b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
149b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct ieee80211_supported_band *spt_band = NULL;
150b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int n_channels, n_bitrates;
151b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
152b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (band == IEEE80211_BAND_2GHZ) {
153b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		n_channels = RTW_2G_CHANNELS_NUM;
154b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		n_bitrates = RTW_G_RATES_NUM;
155b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else if (band == IEEE80211_BAND_5GHZ) {
156b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		n_channels = RTW_5G_CHANNELS_NUM;
157b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		n_bitrates = RTW_A_RATES_NUM;
158b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
159b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
160b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
161b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spt_band = kzalloc(sizeof(struct ieee80211_supported_band) +
162b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			   sizeof(struct ieee80211_channel) * n_channels +
163b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			   sizeof(struct ieee80211_rate) * n_bitrates,
164b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			   GFP_KERNEL);
165b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!spt_band)
166b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
167b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
168b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spt_band->channels =
169b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		(struct ieee80211_channel *)(((u8 *) spt_band) +
170b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					     sizeof(struct
171b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						    ieee80211_supported_band));
172b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spt_band->bitrates =
173b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		(struct ieee80211_rate *)(((u8 *) spt_band->channels) +
174b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  sizeof(struct ieee80211_channel) *
175b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  n_channels);
176b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spt_band->band = band;
177b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spt_band->n_channels = n_channels;
178b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spt_band->n_bitrates = n_bitrates;
179b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
180b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (band == IEEE80211_BAND_2GHZ) {
181b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_2g_channels_init(spt_band->channels);
182b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_2g_rates_init(spt_band->bitrates);
183b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else if (band == IEEE80211_BAND_5GHZ) {
184b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_5g_channels_init(spt_band->channels);
185b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_5g_rates_init(spt_band->bitrates);
186b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
187b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
188b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* spt_band.ht_cap */
189b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
190b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
191b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return spt_band;
192b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
193b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
194b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic const struct ieee80211_txrx_stypes
195b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerrtw_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
196b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	[NL80211_IFTYPE_ADHOC] = {
197b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.tx = 0xffff,
198b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.rx = BIT(IEEE80211_STYPE_ACTION >> 4)
199b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	},
200b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	[NL80211_IFTYPE_STATION] = {
201b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.tx = 0xffff,
202b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
203b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
204b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	},
205b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	[NL80211_IFTYPE_AP] = {
206b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.tx = 0xffff,
207b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
208b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
209b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
210b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_DISASSOC >> 4) |
211b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_AUTH >> 4) |
212b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_DEAUTH >> 4) |
213b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_ACTION >> 4)
214b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	},
215b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	[NL80211_IFTYPE_AP_VLAN] = {
216b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* copy AP */
217b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.tx = 0xffff,
218b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
219b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
220b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
221b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_DISASSOC >> 4) |
222b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_AUTH >> 4) |
223b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_DEAUTH >> 4) |
224b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_ACTION >> 4)
225b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	},
226b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	[NL80211_IFTYPE_P2P_CLIENT] = {
227b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.tx = 0xffff,
228b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
229b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
230b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	},
231b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	[NL80211_IFTYPE_P2P_GO] = {
232b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.tx = 0xffff,
233b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
234b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
235b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
236b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_DISASSOC >> 4) |
237b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_AUTH >> 4) |
238b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_DEAUTH >> 4) |
239b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		      BIT(IEEE80211_STYPE_ACTION >> 4)
240b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	},
241b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger};
242b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
243b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define MAX_BSSINFO_LEN 1000
244b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter,
245b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				   struct wlan_network *pnetwork)
246b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
247b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
248b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct ieee80211_channel *notify_channel;
249b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct cfg80211_bss *bss;
250b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* struct ieee80211_supported_band *band; */
251b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u16 channel;
252b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u32 freq;
253b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u64 notify_timestamp;
254b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u16 notify_capability;
255b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u16 notify_interval;
256b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 *notify_ie;
257b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	size_t notify_ielen;
258b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	s32 notify_signal;
259b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 buf[MAX_BSSINFO_LEN], *pbuf;
260f844717c6a5b30ed605e6fbfcab685c6d2e58592Jes Sorensen	size_t len;
261b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct ieee80211_hdr *pwlanhdr;
262b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wireless_dev *wdev = padapter->rtw_wdev;
263b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wiphy *wiphy = wdev->wiphy;
264b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
265b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
266b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* DBG_8723A("%s\n", __func__); */
267b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
268f844717c6a5b30ed605e6fbfcab685c6d2e58592Jes Sorensen	if (pnetwork->network.IELength > MAX_IE_SZ) {
269b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s IE Length too long > %d byte\n", __func__,
270f844717c6a5b30ed605e6fbfcab685c6d2e58592Jes Sorensen			  MAX_IE_SZ);
271b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
272b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
273b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
27437cb982c2685029e716bfeccf55ec244a6919a32Jes Sorensen	channel = pnetwork->network.DSConfig;
275b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (channel <= RTW_CH_MAX_2G_CHANNEL)
276b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		freq = ieee80211_channel_to_frequency(channel,
277b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						      IEEE80211_BAND_2GHZ);
278b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	else
279b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		freq = ieee80211_channel_to_frequency(channel,
280b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						      IEEE80211_BAND_5GHZ);
281b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
282b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	notify_channel = ieee80211_get_channel(wiphy, freq);
283b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
284b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	notify_timestamp = jiffies_to_msecs(jiffies) * 1000;	/* uSec */
285b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
286b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	notify_interval =
2879a7e35f1eabe4090f7f9943d51afe2a4b6086aaeJes Sorensen		get_unaligned_le16(
288b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			rtw_get_beacon_interval23a_from_ie(pnetwork->network.IEs));
289b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	notify_capability =
2906a235443be58fbdfebb02f536c6338ba82ab399aJes Sorensen		get_unaligned_le16(
291b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			rtw_get_capability23a_from_ie(pnetwork->network.IEs));
292b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
293b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	notify_ie = pnetwork->network.IEs + _FIXED_IE_LENGTH_;
294b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	notify_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_;
295b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
296b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* We've set wiphy's signal_type as CFG80211_SIGNAL_TYPE_MBM:
297b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *  signal strength in mBm (100*dBm)
298b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 */
299b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, _FW_LINKED) &&
300b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    is_same_network23a(&pmlmepriv->cur_network.network,
301b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			    &pnetwork->network)) {
302b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		notify_signal = 100 * translate_percentage_to_dbm(padapter->recvpriv.signal_strength);	/* dbm */
303b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
304b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		notify_signal = 100 * translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength);	/* dbm */
305b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
306b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pbuf = buf;
307b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
308b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwlanhdr = (struct ieee80211_hdr *)pbuf;
309b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3101daffaeecb4bf01c4a34fc2330c745ace5af3f60Jes Sorensen	pwlanhdr->seq_ctrl = 0;
311b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
312b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (pnetwork->network.reserved == 1) {	/*  WIFI_BEACON */
31343c34be13047dd53e70bc4759ff314424db7036bJes Sorensen		eth_broadcast_addr(pwlanhdr->addr1);
314036cdd9cb34a10aabb80a97a41fb9dcfead7d113Jes Sorensen		pwlanhdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
315036cdd9cb34a10aabb80a97a41fb9dcfead7d113Jes Sorensen						      IEEE80211_STYPE_BEACON);
316b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
317888df442ef023adbca6536888eae65b2cd8ae295Jes Sorensen		ether_addr_copy(pwlanhdr->addr1, myid(&padapter->eeprompriv));
318036cdd9cb34a10aabb80a97a41fb9dcfead7d113Jes Sorensen		pwlanhdr->frame_control =
319036cdd9cb34a10aabb80a97a41fb9dcfead7d113Jes Sorensen			cpu_to_le16(IEEE80211_FTYPE_MGMT |
320036cdd9cb34a10aabb80a97a41fb9dcfead7d113Jes Sorensen				    IEEE80211_STYPE_PROBE_RESP);
321b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
322b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
323888df442ef023adbca6536888eae65b2cd8ae295Jes Sorensen	ether_addr_copy(pwlanhdr->addr2, pnetwork->network.MacAddress);
324888df442ef023adbca6536888eae65b2cd8ae295Jes Sorensen	ether_addr_copy(pwlanhdr->addr3, pnetwork->network.MacAddress);
325b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
326b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pbuf += sizeof(struct ieee80211_hdr_3addr);
327b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	len = sizeof(struct ieee80211_hdr_3addr);
328b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
329b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy(pbuf, pnetwork->network.IEs, pnetwork->network.IELength);
330b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	len += pnetwork->network.IELength;
331b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
332b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	bss = cfg80211_inform_bss_frame(wiphy, notify_channel,
333b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					(struct ieee80211_mgmt *)buf, len,
334b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					notify_signal, GFP_ATOMIC);
335b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
336b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (unlikely(!bss)) {
337b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("rtw_cfg80211_inform_bss error\n");
338b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return -EINVAL;
339b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
340b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
341b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	cfg80211_put_bss(wiphy, bss);
342b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
343b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
344b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
345b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
346b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
347b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingervoid rtw_cfg80211_indicate_connect(struct rtw_adapter *padapter)
348b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
349b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
350b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wlan_network *cur_network = &pmlmepriv->cur_network;
351b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wireless_dev *pwdev = padapter->rtw_wdev;
352b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
353b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s(padapter =%p)\n", __func__, padapter);
354b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
355b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (pwdev->iftype != NL80211_IFTYPE_STATION &&
356b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
357b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return;
358b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
359b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
360b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return;
361b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
36256828797acdb99d23b5e5e5c52e7d571d59b783fJes Sorensen	if (padapter->mlmepriv.to_roaming > 0) {
363b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct wiphy *wiphy = pwdev->wiphy;
364b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct ieee80211_channel *notify_channel;
365b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		u32 freq;
36637cb982c2685029e716bfeccf55ec244a6919a32Jes Sorensen		u16 channel = cur_network->network.DSConfig;
367b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
368b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (channel <= RTW_CH_MAX_2G_CHANNEL)
369b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			freq =
370b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			    ieee80211_channel_to_frequency(channel,
371b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger							   IEEE80211_BAND_2GHZ);
372b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		else
373b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			freq =
374b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			    ieee80211_channel_to_frequency(channel,
375b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger							   IEEE80211_BAND_5GHZ);
376b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
377b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		notify_channel = ieee80211_get_channel(wiphy, freq);
378b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
379b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s call cfg80211_roamed\n", __func__);
380b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		cfg80211_roamed(padapter->pnetdev, notify_channel,
381b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				cur_network->network.MacAddress,
382b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				pmlmepriv->assoc_req +
383b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				sizeof(struct ieee80211_hdr_3addr) + 2,
384b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				pmlmepriv->assoc_req_len -
385b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				sizeof(struct ieee80211_hdr_3addr) - 2,
386b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				pmlmepriv->assoc_rsp +
387b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				sizeof(struct ieee80211_hdr_3addr) + 6,
388b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				pmlmepriv->assoc_rsp_len -
389b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				sizeof(struct ieee80211_hdr_3addr) - 6,
390b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				GFP_ATOMIC);
391b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
392b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		cfg80211_connect_result(padapter->pnetdev,
393b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					cur_network->network.MacAddress,
394b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					pmlmepriv->assoc_req +
395b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					sizeof(struct ieee80211_hdr_3addr) + 2,
396b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					pmlmepriv->assoc_req_len -
397b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					sizeof(struct ieee80211_hdr_3addr) - 2,
398b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					pmlmepriv->assoc_rsp +
399b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					sizeof(struct ieee80211_hdr_3addr) + 6,
400b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					pmlmepriv->assoc_rsp_len -
401b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					sizeof(struct ieee80211_hdr_3addr) - 6,
402b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					WLAN_STATUS_SUCCESS, GFP_ATOMIC);
403b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
404b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
405b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
406b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingervoid rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter)
407b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
408b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
409b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wireless_dev *pwdev = padapter->rtw_wdev;
410b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
411b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s(padapter =%p)\n", __func__, padapter);
412b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
413b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (pwdev->iftype != NL80211_IFTYPE_STATION &&
414b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
415b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return;
416b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
417b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
418b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return;
419b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
420b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!padapter->mlmepriv.not_indic_disco) {
421b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING)) {
422b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			cfg80211_connect_result(padapter->pnetdev, NULL, NULL,
423b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						0, NULL, 0,
424b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						WLAN_STATUS_UNSPECIFIED_FAILURE,
425b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						GFP_ATOMIC);
426b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		} else {
427b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			cfg80211_disconnected(padapter->pnetdev, 0, NULL,
428b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					      0, GFP_ATOMIC);
429b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
430b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
431b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
432b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
433b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#ifdef CONFIG_8723AU_AP_MODE
43416b9632da2c071d74934447e266717787bec449bJes Sorensenstatic int set_pairwise_key(struct rtw_adapter *padapter, struct sta_info *psta)
435b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
436b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct cmd_obj *ph2c;
437b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct set_stakey_parm *psetstakey_para;
438b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
43916b9632da2c071d74934447e266717787bec449bJes Sorensen	int res = _SUCCESS;
440b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
441b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
442b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ph2c == NULL) {
443b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		res = _FAIL;
444b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
445b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
446b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
447b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL);
448b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (psetstakey_para == NULL) {
449b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		kfree(ph2c);
450b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		res = _FAIL;
451b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
452b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
453b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
454b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
455b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
4567989bcf3e21683f413dd1488718166d3ff474bf3Jes Sorensen	psetstakey_para->algorithm = psta->dot118021XPrivacy;
457b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
458888df442ef023adbca6536888eae65b2cd8ae295Jes Sorensen	ether_addr_copy(psetstakey_para->addr, psta->hwaddr);
459b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
460b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16);
461b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
462b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
463b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
464b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
465b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return res;
466b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
467b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
4687989bcf3e21683f413dd1488718166d3ff474bf3Jes Sorensenstatic int set_group_key(struct rtw_adapter *padapter, u8 *key, u32 alg,
4694e489d91b4fe320b1260a504a61eb806f3044e61Jes Sorensen			 u8 keyid)
470b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
471b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 keylen;
472b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct cmd_obj *pcmd;
473b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct setkey_parm *psetkeyparm;
474b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
475b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int res = _SUCCESS;
476b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
477b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s\n", __func__);
478b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
4794e489d91b4fe320b1260a504a61eb806f3044e61Jes Sorensen	if (keyid >= 4) {
4804e489d91b4fe320b1260a504a61eb806f3044e61Jes Sorensen		res = _FAIL;
4814e489d91b4fe320b1260a504a61eb806f3044e61Jes Sorensen		goto exit;
4824e489d91b4fe320b1260a504a61eb806f3044e61Jes Sorensen	}
4834e489d91b4fe320b1260a504a61eb806f3044e61Jes Sorensen
484b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
485b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!pcmd) {
486b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		res = _FAIL;
487b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
488b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
489b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	psetkeyparm = kzalloc(sizeof(struct setkey_parm), GFP_KERNEL);
490b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!psetkeyparm) {
491b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		kfree(pcmd);
492b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		res = _FAIL;
493b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
494b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
495b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
4964e489d91b4fe320b1260a504a61eb806f3044e61Jes Sorensen	psetkeyparm->keyid = keyid;
497b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (is_wep_enc(alg))
4984e489d91b4fe320b1260a504a61eb806f3044e61Jes Sorensen		padapter->mlmepriv.key_mask |= BIT(psetkeyparm->keyid);
499b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
500b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	psetkeyparm->algorithm = alg;
501b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
502b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	psetkeyparm->set_tx = 1;
503b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
504b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	switch (alg) {
5059e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	case WLAN_CIPHER_SUITE_WEP40:
506b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		keylen = 5;
507b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
5089e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	case WLAN_CIPHER_SUITE_WEP104:
509b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		keylen = 13;
510b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
5119e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	case WLAN_CIPHER_SUITE_TKIP:
5129e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	case WLAN_CIPHER_SUITE_CCMP:
513b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	default:
514b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		keylen = 16;
515b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
516b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
517b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy(&psetkeyparm->key[0], key, keylen);
518b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
519b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pcmd->cmdcode = _SetKey_CMD_;
520b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pcmd->parmbuf = (u8 *) psetkeyparm;
521b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pcmd->cmdsz = (sizeof(struct setkey_parm));
522b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pcmd->rsp = NULL;
523b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pcmd->rspsz = 0;
524b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
525b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	res = rtw_enqueue_cmd23a(pcmdpriv, pcmd);
526b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
527b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
528b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return res;
529b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
530b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
531e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensenstatic int set_wep_key(struct rtw_adapter *padapter, u8 *key, u16 keylen,
5324e489d91b4fe320b1260a504a61eb806f3044e61Jes Sorensen		       u8 keyid)
533b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
5349e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	u32 alg;
535b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
536b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	switch (keylen) {
537b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case 5:
5389e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		alg = WLAN_CIPHER_SUITE_WEP40;
539b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
540b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case 13:
5419e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		alg = WLAN_CIPHER_SUITE_WEP104;
542b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
543b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	default:
5449e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		alg = 0;
545b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
546b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
547b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return set_group_key(padapter, key, alg, keyid);
548b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
549b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
550b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_ap_set_encryption(struct net_device *dev,
551b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  struct ieee_param *param,
552b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  u32 param_len)
553b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
554b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
555e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen	u16 wep_key_len;
5564e489d91b4fe320b1260a504a61eb806f3044e61Jes Sorensen	u8 wep_key_idx;
557b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct sta_info *psta = NULL, *pbcmc_sta = NULL;
558b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = netdev_priv(dev);
559b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
560b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct security_priv *psecuritypriv = &padapter->securitypriv;
561b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct sta_priv *pstapriv = &padapter->stapriv;
562b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
563b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s\n", __func__);
564b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
565b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	param->u.crypt.err = 0;
566b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
567b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
568b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* sizeof(struct ieee_param) = 64 bytes; */
569b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* if (param_len !=  (u32) ((u8 *) param->u.crypt.key -
570b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	   (u8 *) param) + param->u.crypt.key_len) */
571b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) {
572b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EINVAL;
573b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
574b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
575b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
576b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (is_broadcast_ether_addr(param->sta_addr)) {
577b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (param->u.crypt.idx >= WEP_KEYS) {
578b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ret = -EINVAL;
579b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto exit;
580b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
581b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
582b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psta = rtw_get_stainfo23a(pstapriv, param->sta_addr);
583b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (!psta) {
584b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			/* ret = -EINVAL; */
585b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			DBG_8723A("rtw_set_encryption(), sta has already "
586b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				  "been removed or never been added\n");
587b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto exit;
588b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
589b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
590b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
591b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) {
592b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* todo:clear default encryption keys */
593b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
594b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("clear default encryption keys, keyid =%d\n",
595b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  param->u.crypt.idx);
596b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
597b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
598b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
599b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
600b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) {
601b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("r871x_set_encryption, crypt.alg = WEP\n");
602b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
603b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		wep_key_idx = param->u.crypt.idx;
604b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		wep_key_len = param->u.crypt.key_len;
605b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
606b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("r871x_set_encryption, wep_key_idx =%d, len =%d\n",
607b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  wep_key_idx, wep_key_len);
608b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
609b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) {
610b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ret = -EINVAL;
611b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto exit;
612b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
613b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
614b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (wep_key_len > 0) {
615b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			wep_key_len = wep_key_len <= 5 ? 5 : 13;
616b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
617b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
618b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (psecuritypriv->bWepDefaultKeyIdxSet == 0) {
619b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			/* wep default key has not been set, so use
620b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			   this key index as default key. */
621b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
622b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->ndisencryptstatus =
623b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				Ndis802_11Encryption1Enabled;
6249e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen			psecuritypriv->dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_WEP40;
6259e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen			psecuritypriv->dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_WEP40;
626b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
627b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (wep_key_len == 13) {
6289e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen				psecuritypriv->dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_WEP104;
6299e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen				psecuritypriv->dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_WEP104;
630b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
631b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
632b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
633b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
634b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
635e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen		memcpy(&psecuritypriv->wep_key[wep_key_idx].key,
636b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		       param->u.crypt.key, wep_key_len);
637b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
638e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen		psecuritypriv->wep_key[wep_key_idx].keylen = wep_key_len;
639b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
640b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		set_wep_key(padapter, param->u.crypt.key, wep_key_len,
641b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			    wep_key_idx);
642b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
643b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
644b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
645b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
646b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
647b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) {	/*  group key */
648b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (param->u.crypt.set_tx == 0) {	/* group key */
649b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (strcmp(param->u.crypt.alg, "WEP") == 0) {
6509cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen				DBG_8723A("%s, set group_key, WEP\n", __func__);
651b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
652b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				memcpy(psecuritypriv->
653b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       dot118021XGrpKey[param->u.crypt.idx].
654b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       skey, param->u.crypt.key,
655b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       (param->u.crypt.key_len >
656b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					16 ? 16 : param->u.crypt.key_len));
657b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
6589e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen				psecuritypriv->dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_WEP40;
659b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				if (param->u.crypt.key_len == 13) {
660b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					psecuritypriv->dot118021XGrpPrivacy =
6619e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen					    WLAN_CIPHER_SUITE_WEP104;
662b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				}
663b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
664b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			} else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
665b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				DBG_8723A("%s, set group_key, TKIP\n",
666b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  __func__);
667b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
6689e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen				psecuritypriv->dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_TKIP;
669b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
670b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				memcpy(psecuritypriv->
671b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       dot118021XGrpKey[param->u.crypt.idx].
672b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       skey, param->u.crypt.key,
673b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       (param->u.crypt.key_len >
674b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					16 ? 16 : param->u.crypt.key_len));
675b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
676b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				/* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
677b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				/* set mic key */
678b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				memcpy(psecuritypriv->
679b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       dot118021XGrptxmickey[param->u.crypt.
680b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger							     idx].skey,
681b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       &param->u.crypt.key[16], 8);
682b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				memcpy(psecuritypriv->
683b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       dot118021XGrprxmickey[param->u.crypt.
684b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger							     idx].skey,
685b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       &param->u.crypt.key[24], 8);
686b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
6879216c517fb0192d1828169d8af2bac59ee8e3173Jes Sorensen				psecuritypriv->busetkipkey = 1;
688b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
689b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			} else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
690b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				DBG_8723A("%s, set group_key, CCMP\n",
691b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  __func__);
692b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
6939e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen				psecuritypriv->dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_CCMP;
694b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
695b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				memcpy(psecuritypriv->
696b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       dot118021XGrpKey[param->u.crypt.idx].
697b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       skey, param->u.crypt.key,
698b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       (param->u.crypt.key_len >
699b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					16 ? 16 : param->u.crypt.key_len));
700b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			} else {
701b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				DBG_8723A("%s, set group_key, none\n",
702b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  __func__);
703b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
704b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				psecuritypriv->dot118021XGrpPrivacy =
7059e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen				    0;
706b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
707b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
708b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
709b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
7109216c517fb0192d1828169d8af2bac59ee8e3173Jes Sorensen			psecuritypriv->binstallGrpkey = 1;
711b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
712b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->dot11PrivacyAlgrthm =
713b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				psecuritypriv->dot118021XGrpPrivacy;
714b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
715b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			set_group_key(padapter, param->u.crypt.key,
716b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				      psecuritypriv->dot118021XGrpPrivacy,
717b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				      param->u.crypt.idx);
718b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
719b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter);
720b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (pbcmc_sta) {
721b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				pbcmc_sta->ieee8021x_blocked = false;
722b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				/* rx will use bmc_sta's dot118021XPrivacy */
723b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				pbcmc_sta->dot118021XPrivacy =
724b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					psecuritypriv->dot118021XGrpPrivacy;
725b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
726b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
727b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
728b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
729b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
730b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
731b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
732b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
733b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (psecuritypriv->dot11AuthAlgrthm ==
734b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    dot11AuthAlgrthm_8021X && psta) {	/*  psk/802_1x */
735b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
736b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (param->u.crypt.set_tx == 1) {
737b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				/* pairwise key */
738b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				memcpy(psta->dot118021x_UncstKey.skey,
739b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       param->u.crypt.key,
740b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       (param->u.crypt.key_len >
741b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					16 ? 16 : param->u.crypt.key_len));
742b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
743b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				if (!strcmp(param->u.crypt.alg, "WEP")) {
744b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					DBG_8723A("%s, set pairwise key, WEP\n",
745b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						  __func__);
746b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
7479e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen					psta->dot118021XPrivacy = WLAN_CIPHER_SUITE_WEP40;
748b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					if (param->u.crypt.key_len == 13) {
749b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						psta->dot118021XPrivacy =
7509e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen							WLAN_CIPHER_SUITE_WEP104;
751b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					}
752b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				} else if (!strcmp(param->u.crypt.alg, "TKIP")) {
753b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					DBG_8723A("%s, set pairwise key, "
754b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						  "TKIP\n", __func__);
755b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
7569e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen					psta->dot118021XPrivacy = WLAN_CIPHER_SUITE_TKIP;
757b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
758b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					/* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
759b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					/* set mic key */
760b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(psta->dot11tkiptxmickey.skey,
761b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       &param->u.crypt.key[16], 8);
762b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(psta->dot11tkiprxmickey.skey,
763b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       &param->u.crypt.key[24], 8);
764b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
7659216c517fb0192d1828169d8af2bac59ee8e3173Jes Sorensen					psecuritypriv->busetkipkey = 1;
766b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
767b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				} else if (!strcmp(param->u.crypt.alg, "CCMP")) {
768b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
769b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					DBG_8723A("%s, set pairwise key, "
770b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						  "CCMP\n", __func__);
771b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
7729e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen					psta->dot118021XPrivacy = WLAN_CIPHER_SUITE_CCMP;
773b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				} else {
774b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					DBG_8723A("%s, set pairwise key, "
775b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						  "none\n", __func__);
776b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
7779e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen					psta->dot118021XPrivacy = 0;
778b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				}
779b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
780b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				set_pairwise_key(padapter, psta);
781b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
782b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				psta->ieee8021x_blocked = false;
783b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
784b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				psta->bpairwise_key_installed = true;
785b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			} else {	/* group key??? */
786b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				if (!strcmp(param->u.crypt.alg, "WEP")) {
787b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(psecuritypriv->
788b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       dot118021XGrpKey[param->u.crypt.
789b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger								idx].skey,
790b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       param->u.crypt.key,
791b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       (param->u.crypt.key_len >
792b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						16 ? 16 : param->u.crypt.
793b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						key_len));
794b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
795b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					psecuritypriv->dot118021XGrpPrivacy =
7969e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen						WLAN_CIPHER_SUITE_WEP40;
797b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					if (param->u.crypt.key_len == 13) {
798b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						psecuritypriv->
799b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						    dot118021XGrpPrivacy =
8009e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen							WLAN_CIPHER_SUITE_WEP104;
801b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					}
802b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				} else if (!strcmp(param->u.crypt.alg, "TKIP")) {
803b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					psecuritypriv->dot118021XGrpPrivacy =
8049e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen					    WLAN_CIPHER_SUITE_TKIP;
805b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
806b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(psecuritypriv->
807b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       dot118021XGrpKey[param->u.crypt.
808b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger								idx].skey,
809b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       param->u.crypt.key,
810b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       (param->u.crypt.key_len >
811b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						16 ? 16 : param->u.crypt.
812b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						key_len));
813b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
814b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					/* DEBUG_ERR("set key length :param->u"
815b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					   ".crypt.key_len =%d\n",
816b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					   param->u.crypt.key_len); */
817b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					/* set mic key */
818b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(psecuritypriv->
819b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       dot118021XGrptxmickey[param->u.
820b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger								     crypt.idx].
821b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       skey, &param->u.crypt.key[16],
822b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       8);
823b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(psecuritypriv->
824b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       dot118021XGrprxmickey[param->u.
825b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger								     crypt.idx].
826b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       skey, &param->u.crypt.key[24],
827b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       8);
828b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
8299216c517fb0192d1828169d8af2bac59ee8e3173Jes Sorensen					psecuritypriv->busetkipkey = 1;
830b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
831b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				} else if (!strcmp(param->u.crypt.alg, "CCMP")) {
832b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					psecuritypriv->dot118021XGrpPrivacy =
8339e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen						WLAN_CIPHER_SUITE_CCMP;
834b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
835b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(psecuritypriv->
836b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       dot118021XGrpKey[param->u.crypt.
837b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger								idx].skey,
838b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       param->u.crypt.key,
839b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       (param->u.crypt.key_len >
840b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						16 ? 16 : param->u.crypt.
841b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						key_len));
842b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				} else {
843b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					psecuritypriv->dot118021XGrpPrivacy =
8449e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen						0;
845b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				}
846b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
847b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				psecuritypriv->dot118021XGrpKeyid =
848b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					param->u.crypt.idx;
849b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
8509216c517fb0192d1828169d8af2bac59ee8e3173Jes Sorensen				psecuritypriv->binstallGrpkey = 1;
851b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
852b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				psecuritypriv->dot11PrivacyAlgrthm =
853b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					psecuritypriv->dot118021XGrpPrivacy;
854b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
855b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				set_group_key(padapter, param->u.crypt.key,
856b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					      psecuritypriv->
857b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					      dot118021XGrpPrivacy,
858b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					      param->u.crypt.idx);
859b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
860b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter);
861b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				if (pbcmc_sta) {
862b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					/* rx will use bmc_sta's
863b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					   dot118021XPrivacy */
864b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					pbcmc_sta->ieee8021x_blocked = false;
865b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;
866b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				}
867b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
868b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
869b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
870b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
871b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
872b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
873b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
874b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
875b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
876b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#endif
877b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
878b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_set_encryption(struct net_device *dev,
879b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       struct ieee_param *param, u32 param_len)
880b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
881b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
882e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen	u32 wep_key_idx;
883e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen	u16 wep_key_len;
884b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = netdev_priv(dev);
885b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
886b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct security_priv *psecuritypriv = &padapter->securitypriv;
887b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
888b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s\n", __func__);
889b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
890b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	param->u.crypt.err = 0;
891b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
892b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
893b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (param_len <
894b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    (u32) ((u8 *) param->u.crypt.key - (u8 *) param) +
895b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    param->u.crypt.key_len) {
896b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EINVAL;
897b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
898b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
899b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
900b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (is_broadcast_ether_addr(param->sta_addr)) {
901b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (param->u.crypt.idx >= WEP_KEYS) {
902b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ret = -EINVAL;
903b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto exit;
904b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
905b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
906b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EINVAL;
907b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
908b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
909b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
910b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (strcmp(param->u.crypt.alg, "WEP") == 0) {
911b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_,
912b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			 ("wpa_set_encryption, crypt.alg = WEP\n"));
913b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("wpa_set_encryption, crypt.alg = WEP\n");
914b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
915b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		wep_key_idx = param->u.crypt.idx;
916b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		wep_key_len = param->u.crypt.key_len;
917b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
918b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if ((wep_key_idx > WEP_KEYS) || (wep_key_len <= 0)) {
919b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ret = -EINVAL;
920b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto exit;
921b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
922b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
923b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (psecuritypriv->bWepDefaultKeyIdxSet == 0) {
924b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			/* wep default key has not been set, so use this
925b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			   key index as default key. */
926b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
927b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			wep_key_len = wep_key_len <= 5 ? 5 : 13;
928b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
929b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->ndisencryptstatus =
930b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				Ndis802_11Encryption1Enabled;
9319e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen			psecuritypriv->dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_WEP40;
9329e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen			psecuritypriv->dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_WEP40;
933b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
934b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (wep_key_len == 13) {
9359e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen				psecuritypriv->dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_WEP104;
9369e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen				psecuritypriv->dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_WEP104;
937b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
938b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
939b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
940b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
941b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
942e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen		memcpy(&psecuritypriv->wep_key[wep_key_idx].key,
943b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		       param->u.crypt.key, wep_key_len);
944b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
945e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen		psecuritypriv->wep_key[wep_key_idx].keylen = wep_key_len;
946b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
947b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_set_key23a(padapter, psecuritypriv, wep_key_idx, 0);
948b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
949b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
950b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
951b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
952b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (padapter->securitypriv.dot11AuthAlgrthm ==
953b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    dot11AuthAlgrthm_8021X) {	/*  802_1x */
954b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct sta_info *psta, *pbcmc_sta;
955b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct sta_priv *pstapriv = &padapter->stapriv;
956b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
957b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (check_fwstate(pmlmepriv,
958b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				  WIFI_STATION_STATE | WIFI_MP_STATE)) {
959b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			/* sta mode */
960b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psta = rtw_get_stainfo23a(pstapriv, get_bssid(pmlmepriv));
961b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (psta == NULL) {
962b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				DBG_8723A("%s, : Obtain Sta_info fail\n",
963b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  __func__);
964b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			} else {
965b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				/* Jeff: don't disable ieee8021x_blocked
966b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				   while clearing key */
967b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				if (strcmp(param->u.crypt.alg, "none") != 0)
968b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					psta->ieee8021x_blocked = false;
969b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
970b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				if ((padapter->securitypriv.ndisencryptstatus ==
971b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     Ndis802_11Encryption2Enabled) ||
972b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				    (padapter->securitypriv.ndisencryptstatus ==
973b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     Ndis802_11Encryption3Enabled)) {
974b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					psta->dot118021XPrivacy =
975b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						padapter->securitypriv.
976b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						dot11PrivacyAlgrthm;
977b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				}
978b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
979b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				if (param->u.crypt.set_tx == 1) {
980b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					/* pairwise key */
981b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					DBG_8723A("%s, : param->u.crypt.set_tx"
982b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						  " == 1\n", __func__);
983b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
984b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(psta->dot118021x_UncstKey.skey,
985b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       param->u.crypt.key,
986b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       (param->u.crypt.key_len >
987b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						16 ? 16 : param->u.crypt.
988b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						key_len));
989b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
990b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					if (strcmp(param->u.crypt.alg,
991b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						   "TKIP") == 0) {
992b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						memcpy(psta->dot11tkiptxmickey.
993b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						       skey,
994b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						       &param->u.crypt.key[16],
995b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						       8);
996b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						memcpy(psta->dot11tkiprxmickey.
997b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						       skey,
998b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						       &param->u.crypt.key[24],
999b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						       8);
1000b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1001b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						padapter->securitypriv.
10029216c517fb0192d1828169d8af2bac59ee8e3173Jes Sorensen							busetkipkey = 0;
1003b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					}
1004b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					DBG_8723A(" ~~~~set sta key:unicastkey\n");
1005b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1006b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					rtw_setstakey_cmd23a(padapter,
1007b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger							  (unsigned char *)psta,
1008b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger							  true);
1009b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				} else {	/* group key */
1010b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(padapter->securitypriv.
1011b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       dot118021XGrpKey[param->u.crypt.
1012b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger								idx].skey,
1013b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       param->u.crypt.key,
1014b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       (param->u.crypt.key_len >
1015b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						16 ? 16 : param->u.crypt.
1016b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						key_len));
1017b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(padapter->securitypriv.
1018b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       dot118021XGrptxmickey[param->u.
1019b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger								     crypt.idx].
1020b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       skey, &param->u.crypt.key[16],
1021b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       8);
1022b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					memcpy(padapter->securitypriv.
1023b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       dot118021XGrprxmickey[param->u.
1024b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger								     crypt.idx].
1025b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       skey, &param->u.crypt.key[24],
1026b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       8);
1027b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					padapter->securitypriv.binstallGrpkey =
10289216c517fb0192d1828169d8af2bac59ee8e3173Jes Sorensen						1;
1029b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					/* DEBUG_ERR((" param->u.crypt.key_len"
1030b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					   "=%d\n", param->u.crypt.key_len)); */
1031b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					DBG_8723A
1032b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					    (" ~~~~set sta key:groupkey\n");
1033b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1034b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					padapter->securitypriv.
1035b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					    dot118021XGrpKeyid =
1036b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						param->u.crypt.idx;
1037b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1038b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					rtw_set_key23a(padapter,
1039b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						    &padapter->securitypriv,
1040b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						    param->u.crypt.idx, 1);
1041b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				}
1042b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
1043b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1044b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter);
1045b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (pbcmc_sta) {
1046b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				/* Jeff: don't disable ieee8021x_blocked
1047b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				   while clearing key */
1048b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				if (strcmp(param->u.crypt.alg, "none") != 0)
1049b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					pbcmc_sta->ieee8021x_blocked = false;
1050b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1051b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				if ((padapter->securitypriv.ndisencryptstatus ==
1052b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     Ndis802_11Encryption2Enabled) ||
1053b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				    (padapter->securitypriv.ndisencryptstatus ==
1054b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     Ndis802_11Encryption3Enabled)) {
1055b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					pbcmc_sta->dot118021XPrivacy =
1056b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					    padapter->securitypriv.
1057b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					    dot11PrivacyAlgrthm;
1058b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				}
1059b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
1060b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		} else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {	/* adhoc mode */
1061b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
1062b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1063b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1064b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
1065b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1066b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s, ret =%d\n", __func__, ret);
1067b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1068b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1069b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1070b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
1071b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1072b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1073b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev,
1074b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				u8 key_index, bool pairwise,
1075b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				const u8 *mac_addr, struct key_params *params)
1076b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1077b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	char *alg_name;
1078b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u32 param_len;
10796f1c59bf2c00eeba0f9ad9ce176cce731de1a8e5Jes Sorensen	struct ieee_param *param;
1080b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
1081b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy);
1082b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
1083b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1084b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1085a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s): adding key for %pM\n", __func__, ndev->name,
1086b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  mac_addr);
1087b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("cipher = 0x%x\n", params->cipher);
1088b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("key_len = 0x%x\n", params->key_len);
1089b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("seq_len = 0x%x\n", params->seq_len);
1090b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("key_index =%d\n", key_index);
1091b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("pairwise =%d\n", pairwise);
1092b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1093b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	param_len = sizeof(struct ieee_param) + params->key_len;
1094b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	param = kzalloc(param_len, GFP_KERNEL);
10956f1c59bf2c00eeba0f9ad9ce176cce731de1a8e5Jes Sorensen	if (!param)
10966f1c59bf2c00eeba0f9ad9ce176cce731de1a8e5Jes Sorensen		return -ENOMEM;
1097b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1098b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	param->cmd = IEEE_CMD_SET_ENCRYPTION;
109943c34be13047dd53e70bc4759ff314424db7036bJes Sorensen	eth_broadcast_addr(param->sta_addr);
1100b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1101b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	switch (params->cipher) {
1102b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case IW_AUTH_CIPHER_NONE:
1103b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* todo: remove key */
1104b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* remove = 1; */
1105b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		alg_name = "none";
1106b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1107b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WLAN_CIPHER_SUITE_WEP40:
1108b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WLAN_CIPHER_SUITE_WEP104:
1109b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		alg_name = "WEP";
1110b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1111b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WLAN_CIPHER_SUITE_TKIP:
1112b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		alg_name = "TKIP";
1113b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1114b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WLAN_CIPHER_SUITE_CCMP:
1115b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		alg_name = "CCMP";
1116b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1117b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1118b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	default:
1119b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENOTSUPP;
1120b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto addkey_end;
1121b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1122b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1123b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
1124b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1125b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
1126b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		param->u.crypt.set_tx = 0;	/* for wpa/wpa2 group key */
1127b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
1128b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		param->u.crypt.set_tx = 1;	/* for wpa/wpa2 pairwise key */
1129b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1130b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1131b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* param->u.crypt.idx = key_index - 1; */
1132b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	param->u.crypt.idx = key_index;
1133b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1134b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (params->seq_len && params->seq) {
1135b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(param->u.crypt.seq, params->seq, params->seq_len);
1136b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1137b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1138b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (params->key_len && params->key) {
1139b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		param->u.crypt.key_len = params->key_len;
1140b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(param->u.crypt.key, params->key, params->key_len);
1141b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1142b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1143b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
1144b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = rtw_cfg80211_set_encryption(ndev, param, param_len);
1145b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
1146b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#ifdef CONFIG_8723AU_AP_MODE
1147b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (mac_addr)
1148888df442ef023adbca6536888eae65b2cd8ae295Jes Sorensen			ether_addr_copy(param->sta_addr, mac_addr);
1149b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1150b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = rtw_cfg80211_ap_set_encryption(ndev, param, param_len);
1151b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#endif
1152b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
1153b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("error! fw_state = 0x%x, iftype =%d\n",
1154b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  pmlmepriv->fw_state, rtw_wdev->iftype);
1155b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1156b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1157b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1158b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingeraddkey_end:
1159b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	kfree(param);
1160b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1161b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
1162b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1163b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1164b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int
1165b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingercfg80211_rtw_get_key(struct wiphy *wiphy, struct net_device *ndev,
1166b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		     u8 key_index, bool pairwise, const u8 *mac_addr,
1167b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		     void *cookie,
1168b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		     void (*callback) (void *cookie, struct key_params *))
1169b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1170a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
1171b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
1172b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1173b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1174b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev,
1175b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				u8 key_index, bool pairwise,
1176b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				const u8 *mac_addr)
1177b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1178b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = netdev_priv(ndev);
1179b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct security_priv *psecuritypriv = &padapter->securitypriv;
1180b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1181a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s): key_index =%d\n", __func__, ndev->name, key_index);
1182b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1183b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (key_index == psecuritypriv->dot11PrivacyKeyIndex) {
1184b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* clear the flag of wep default key set. */
1185b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->bWepDefaultKeyIdxSet = 0;
1186b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1187b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1188b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
1189b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1190b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1191b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_set_default_key(struct wiphy *wiphy,
1192b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					struct net_device *ndev, u8 key_index,
1193b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					bool unicast, bool multicast)
1194b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1195b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = netdev_priv(ndev);
1196b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct security_priv *psecuritypriv = &padapter->securitypriv;
1197b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1198a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s): key_index =%d, unicast =%d, multicast =%d.\n",
1199a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen		  __func__, ndev->name, key_index, unicast, multicast);
1200b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1201e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen	if (key_index < NUM_WEP_KEYS &&
1202e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen	    (psecuritypriv->dot11PrivacyAlgrthm == WLAN_CIPHER_SUITE_WEP40 ||
1203e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen	     psecuritypriv->dot11PrivacyAlgrthm == WLAN_CIPHER_SUITE_WEP104)) {
1204b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* set wep default key */
1205b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
1206b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1207b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->dot11PrivacyKeyIndex = key_index;
1208b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
12099e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		psecuritypriv->dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_WEP40;
12109e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		psecuritypriv->dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_WEP40;
1211e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen		if (psecuritypriv->wep_key[key_index].keylen == 13) {
1212e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen			psecuritypriv->dot11PrivacyAlgrthm =
1213e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen				WLAN_CIPHER_SUITE_WEP104;
1214e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen			psecuritypriv->dot118021XGrpPrivacy =
1215e0827909a27c5d90bf88f714e108de9419fd8b29Jes Sorensen				WLAN_CIPHER_SUITE_WEP104;
1216b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
1217b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1218b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* set the flag to represent that wep default key
1219b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		   has been set */
1220b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->bWepDefaultKeyIdxSet = 1;
1221b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1222b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1223b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
1224b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1225b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
122627fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensenstatic u16 rtw_get_cur_max_rate(struct rtw_adapter *adapter)
122727fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen{
122827fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	int i = 0;
122927fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	const u8 *p;
123027fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	u16 rate = 0, max_rate = 0;
123127fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
123227fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
123327fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	struct registry_priv *pregistrypriv = &adapter->registrypriv;
123427fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
123527fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	struct wlan_bssid_ex  *pcur_bss = &pmlmepriv->cur_network.network;
123627fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	struct ieee80211_ht_cap *pht_capie;
123727fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	u8 rf_type = 0;
123827fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0;
123927fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	u16 mcs_rate = 0;
124027fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen
124127fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, &pcur_bss->IEs[12],
124227fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen			     pcur_bss->IELength - 12);
124327fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	if (p && p[1] > 0) {
124427fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		pht_capie = (struct ieee80211_ht_cap *)(p + 2);
124527fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen
124627fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		memcpy(&mcs_rate, &pht_capie->mcs, 2);
124727fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen
124827fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		/* bw_40MHz = (pht_capie->cap_info&
124927fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		   IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1:0; */
125027fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		/* cur_bwmod is updated by beacon, pmlmeinfo is
125127fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		   updated by association response */
125227fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		bw_40MHz = (pmlmeext->cur_bwmode &&
125327fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen			    (pmlmeinfo->HT_info.ht_param &
125427fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen			     IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) ? 1:0;
125527fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen
125627fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		/* short_GI = (pht_capie->cap_info & (IEEE80211_HT_CAP
125727fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		   _SGI_20|IEEE80211_HT_CAP_SGI_40)) ? 1 : 0; */
125827fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		short_GI_20 = (pmlmeinfo->ht_cap.cap_info &
125927fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen			       cpu_to_le16(IEEE80211_HT_CAP_SGI_20)) ? 1:0;
126027fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		short_GI_40 = (pmlmeinfo->ht_cap.cap_info &
126127fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen			       cpu_to_le16(IEEE80211_HT_CAP_SGI_40)) ? 1:0;
126227fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen
126327fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		rf_type = rtl8723a_get_rf_type(adapter);
126427fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		max_rate = rtw_mcs_rate23a(rf_type, bw_40MHz &
126527fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen					   pregistrypriv->cbw40_enable,
126627fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen					   short_GI_20, short_GI_40,
126727fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen					   &pmlmeinfo->ht_cap.mcs);
126827fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	} else {
126927fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		while (pcur_bss->SupportedRates[i] != 0 &&
127027fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		       pcur_bss->SupportedRates[i] != 0xFF) {
127127fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen			rate = pcur_bss->SupportedRates[i] & 0x7F;
127227fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen			if (rate>max_rate)
127327fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen				max_rate = rate;
127427fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen			i++;
127527fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		}
127627fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen
127727fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		max_rate = max_rate * 10 / 2;
127827fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	}
127927fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen
128027fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen	return max_rate;
128127fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen}
128227fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen
1283b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_get_station(struct wiphy *wiphy,
1284b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				    struct net_device *ndev,
1285f9da455b93f6ba076935b4ef4589f61e529ae046Linus Torvalds				    const u8 *mac, struct station_info *sinfo)
1286b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1287b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
1288b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
1289b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1290b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct sta_info *psta = NULL;
1291b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct sta_priv *pstapriv = &padapter->stapriv;
1292b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1293b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	sinfo->filled = 0;
1294b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1295b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!mac) {
1296a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen		DBG_8723A("%s(%s): mac ==%p\n", __func__, ndev->name, mac);
1297b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENOENT;
1298b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
1299b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1300b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1301b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	psta = rtw_get_stainfo23a(pstapriv, mac);
1302b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (psta == NULL) {
1303b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s, sta_info is null\n", __func__);
1304b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENOENT;
1305b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
1306b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1307a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s): mac =" MAC_FMT "\n", __func__, ndev->name,
1308b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  MAC_ARG(mac));
1309b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1310b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* for infra./P2PClient mode */
1311b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) &&
1312b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    check_fwstate(pmlmepriv, _FW_LINKED)) {
1313b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct wlan_network *cur_network = &pmlmepriv->cur_network;
1314b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1315cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen		if (!ether_addr_equal(mac, cur_network->network.MacAddress)) {
1316b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			DBG_8723A("%s, mismatch bssid =" MAC_FMT "\n", __func__,
1317b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				  MAC_ARG(cur_network->network.MacAddress));
1318b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ret = -ENOENT;
1319b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto exit;
1320b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
1321b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1322b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo->filled |= STATION_INFO_SIGNAL;
1323b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv.
1324b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger							    signal_strength);
1325b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1326b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo->filled |= STATION_INFO_TX_BITRATE;
132727fd731ece203c37f0a3708cafc95e9cead8cd2dJes Sorensen		sinfo->txrate.legacy = rtw_get_cur_max_rate(padapter);
1328b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1329b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo->filled |= STATION_INFO_RX_PACKETS;
1330b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo->rx_packets = sta_rx_data_pkts(psta);
1331b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1332b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo->filled |= STATION_INFO_TX_PACKETS;
1333b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo->tx_packets = psta->sta_stats.tx_pkts;
1334b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1335b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1336b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* for Ad-Hoc/AP mode */
1337b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
1338b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	     check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
1339b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	     check_fwstate(pmlmepriv, WIFI_AP_STATE)) &&
1340b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    check_fwstate(pmlmepriv, _FW_LINKED)
1341b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    ) {
1342b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* TODO: should acquire station info... */
1343b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1344b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1345b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
1346b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
1347b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1348b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1349efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensenint cfg80211_infrastructure_mode(struct rtw_adapter* padapter,
1350efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen				 enum nl80211_iftype ifmode)
1351efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen{
1352efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1353efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	struct wlan_network *cur_network = &pmlmepriv->cur_network;
1354efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	enum nl80211_iftype old_mode;
1355efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1356efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	old_mode = cur_network->network.ifmode;
1357efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1358efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_,
1359efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		 ("+%s: old =%d new =%d fw_state = 0x%08x\n", __func__,
1360efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		  old_mode, ifmode, get_fwstate(pmlmepriv)));
1361efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1362efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	if (old_mode != ifmode) {
1363efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		spin_lock_bh(&pmlmepriv->lock);
1364efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1365efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
1366efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			 (" change mode!"));
1367efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1368efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		if (old_mode == NL80211_IFTYPE_AP ||
1369efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		    old_mode == NL80211_IFTYPE_P2P_GO) {
1370efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			/* change to other mode from Ndis802_11APMode */
1371efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			cur_network->join_res = -1;
1372efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1373efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen#ifdef CONFIG_8723AU_AP_MODE
1374efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			stop_ap_mode23a(padapter);
1375efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen#endif
1376efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		}
1377efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1378efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		if (check_fwstate(pmlmepriv, _FW_LINKED) ||
1379efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		    old_mode == NL80211_IFTYPE_ADHOC)
1380efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			rtw_disassoc_cmd23a(padapter, 0, true);
1381efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1382efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		if (check_fwstate(pmlmepriv, _FW_LINKED) ||
1383efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		    check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
1384efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			rtw_free_assoc_resources23a(padapter, 1);
1385efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1386efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		if (old_mode == NL80211_IFTYPE_STATION ||
1387efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		    old_mode == NL80211_IFTYPE_P2P_CLIENT ||
1388efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		    old_mode == NL80211_IFTYPE_ADHOC) {
1389efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			if (check_fwstate(pmlmepriv, _FW_LINKED)) {
1390efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen				/* will clr Linked_state; before this function,
1391efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen				   we must have chked whether issue
1392efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen				   dis-assoc_cmd or not */
1393efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen				rtw_indicate_disconnect23a(padapter);
1394efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			}
1395efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	       }
1396efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1397efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		cur_network->network.ifmode = ifmode;
1398efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1399efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		_clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE);
1400efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1401efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		switch (ifmode) {
1402efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		case NL80211_IFTYPE_ADHOC:
1403efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
1404efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			break;
1405efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1406efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		case NL80211_IFTYPE_P2P_CLIENT:
1407efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		case NL80211_IFTYPE_STATION:
1408efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			set_fwstate(pmlmepriv, WIFI_STATION_STATE);
1409efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			break;
1410efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1411efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		case NL80211_IFTYPE_P2P_GO:
1412efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		case NL80211_IFTYPE_AP:
1413efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			set_fwstate(pmlmepriv, WIFI_AP_STATE);
1414efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen#ifdef CONFIG_8723AU_AP_MODE
1415efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			start_ap_mode23a(padapter);
1416efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			/* rtw_indicate_connect23a(padapter); */
1417efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen#endif
1418efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			break;
1419efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1420efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		default:
1421efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen			break;
1422efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		}
1423efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1424efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		/* SecClearAllKeys(adapter); */
1425efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1426efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		/* RT_TRACE(COMP_OID_SET, DBG_LOUD,
1427efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		   ("set_infrastructure: fw_state:%x after changing mode\n", */
1428efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		/* get_fwstate(pmlmepriv))); */
1429efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1430efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		spin_unlock_bh(&pmlmepriv->lock);
1431efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	}
1432efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1433efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	return _SUCCESS;
1434efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen}
1435efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen
1436b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_change_iface(struct wiphy *wiphy,
1437b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     struct net_device *ndev,
1438b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     enum nl80211_iftype type, u32 *flags,
1439b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     struct vif_params *params)
1440b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1441b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	enum nl80211_iftype old_type;
1442b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
1443b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
1444b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy);
1445b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
1446b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1447a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s): call netdev_open23a\n", __func__, ndev->name);
1448b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1449b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	old_type = rtw_wdev->iftype;
1450a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s): old_iftype =%d, new_iftype =%d\n",
1451a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen		  __func__, ndev->name, old_type, type);
1452b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1453b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (old_type != type) {
1454b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pmlmeext->action_public_rxseq = 0xffff;
1455b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pmlmeext->action_public_dialog_token = 0xff;
1456b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1457b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1458b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	switch (type) {
1459b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_ADHOC:
1460b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_P2P_CLIENT:
1461b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_STATION:
1462b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_P2P_GO:
1463b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_AP:
1464efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	case NL80211_IFTYPE_UNSPECIFIED:
1465b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1466b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	default:
1467b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return -EOPNOTSUPP;
1468b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1469b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1470b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	rtw_wdev->iftype = type;
1471b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1472efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	if (cfg80211_infrastructure_mode(padapter, type) != _SUCCESS) {
1473b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_wdev->iftype = old_type;
1474b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EPERM;
1475b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
1476b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1477b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1478efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	rtw_setopmode_cmd23a(padapter, type);
1479b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1480b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
1481b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
1482b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1483b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1484b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingervoid rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv,
1485b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     bool aborted)
1486b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1487b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_lock_bh(&pwdev_priv->scan_req_lock);
1488b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (pwdev_priv->scan_request != NULL) {
1489b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s with scan req\n", __func__);
1490141bd353c5a9ba987dbe7b28ffdd034bb3ed55baJes Sorensen
1491b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (pwdev_priv->scan_request->wiphy !=
1492b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		    pwdev_priv->rtw_wdev->wiphy)
1493b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			DBG_8723A("error wiphy compare\n");
1494b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		else
1495b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			cfg80211_scan_done(pwdev_priv->scan_request, aborted);
1496b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1497b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pwdev_priv->scan_request = NULL;
1498b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
1499b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s without scan req\n", __func__);
1500b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1501b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_unlock_bh(&pwdev_priv->scan_req_lock);
1502b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1503b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1504b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingervoid rtw_cfg80211_surveydone_event_callback(struct rtw_adapter *padapter)
1505b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1506b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct list_head *plist, *phead, *ptmp;
1507b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1508b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_queue *queue = &pmlmepriv->scanned_queue;
1509b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wlan_network *pnetwork;
1510b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1511b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_lock_bh(&pmlmepriv->scanned_queue.lock);
1512b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1513b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	phead = get_list_head(queue);
1514b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1515b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	list_for_each_safe(plist, ptmp, phead) {
1516b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pnetwork = container_of(plist, struct wlan_network, list);
1517b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1518b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* report network only if the current channel set
1519b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		   contains the channel to which this network belongs */
1520b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (rtw_ch_set_search_ch23a
1521b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		    (padapter->mlmeextpriv.channel_set,
152237cb982c2685029e716bfeccf55ec244a6919a32Jes Sorensen		     pnetwork->network.DSConfig) >= 0)
1523b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			rtw_cfg80211_inform_bss(padapter, pnetwork);
1524b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1525b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1526b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1527b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1528b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* call this after other things have been done */
1529b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev),
1530b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					false);
1531b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1532b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1533b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_set_probe_req_wpsp2pie(struct rtw_adapter *padapter,
1534b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       char *buf, int len)
1535b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1536b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
1537d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen	const u8 *wps_ie;
1538b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1539b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1540b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s, ielen =%d\n", __func__, len);
1541b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1542b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (len > 0) {
1543d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen		wps_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
1544d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen						 WLAN_OUI_TYPE_MICROSOFT_WPS,
1545d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen						 buf, len);
1546b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (wps_ie) {
1547d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen			DBG_8723A("probe_req_wps_ielen =%d\n", wps_ie[1]);
1548141bd353c5a9ba987dbe7b28ffdd034bb3ed55baJes Sorensen
1549b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (pmlmepriv->wps_probe_req_ie) {
1550b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				pmlmepriv->wps_probe_req_ie_len = 0;
1551b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				kfree(pmlmepriv->wps_probe_req_ie);
1552b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				pmlmepriv->wps_probe_req_ie = NULL;
1553b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
1554b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1555d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen			pmlmepriv->wps_probe_req_ie = kmemdup(wps_ie, wps_ie[1],
15564a6eea4dcbc0328c3126fed264c42b0725bea659Benoit Taine							      GFP_KERNEL);
1557b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (pmlmepriv->wps_probe_req_ie == NULL) {
1558b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
1559b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  __func__, __LINE__);
1560b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				return -EINVAL;
1561b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
1562d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen			pmlmepriv->wps_probe_req_ie_len = wps_ie[1];
1563b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
1564b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1565b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1566b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
1567b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1568b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1569b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_scan(struct wiphy *wiphy,
1570b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			     struct cfg80211_scan_request *request)
1571b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1572b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int i;
1573b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 _status = false;
1574b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
1575b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
1576b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1577b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct cfg80211_ssid ssid[RTW_SSID_SCAN_AMOUNT];
1578b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT];
1579b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev);
1580b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct cfg80211_ssid *ssids = request->ssids;
1581b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	bool need_indicate_scan_done = false;
1582b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1583a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, padapter->pnetdev->name);
1584b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1585b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_lock_bh(&pwdev_priv->scan_req_lock);
1586b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwdev_priv->scan_request = request;
1587b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_unlock_bh(&pwdev_priv->scan_req_lock);
1588b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1589b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
1590b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s under WIFI_AP_STATE\n", __func__);
1591b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* need_indicate_scan_done = true; */
1592b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* goto check_need_indicate_scan_done; */
1593b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1594b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1595b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (rtw_pwr_wakeup(padapter) == _FAIL) {
1596b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		need_indicate_scan_done = true;
1597b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto check_need_indicate_scan_done;
1598b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1599b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1600b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (request->ie && request->ie_len > 0) {
1601b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_cfg80211_set_probe_req_wpsp2pie(padapter,
1602b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						    (u8 *) request->ie,
1603b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						    request->ie_len);
1604b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1605b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1606b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) {
1607b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s, bBusyTraffic == true\n", __func__);
1608b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		need_indicate_scan_done = true;
1609b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto check_need_indicate_scan_done;
1610b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1611b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (rtw_is_scan_deny(padapter)) {
16129cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen		DBG_8723A("%s(%s): scan deny\n", __func__,
16139cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen			  padapter->pnetdev->name);
1614b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		need_indicate_scan_done = true;
1615b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto check_need_indicate_scan_done;
1616b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1617b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1618b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) ==
1619b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    true) {
1620b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s, fwstate = 0x%x\n", __func__, pmlmepriv->fw_state);
1621b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		need_indicate_scan_done = true;
1622b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto check_need_indicate_scan_done;
1623b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1624b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1625b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memset(ssid, 0, sizeof(struct cfg80211_ssid) * RTW_SSID_SCAN_AMOUNT);
1626b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* parsing request ssids, n_ssids */
1627b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	for (i = 0; i < request->n_ssids && i < RTW_SSID_SCAN_AMOUNT; i++) {
1628b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("ssid =%s, len =%d\n", ssids[i].ssid,
1629b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  ssids[i].ssid_len);
1630b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(ssid[i].ssid, ssids[i].ssid, ssids[i].ssid_len);
1631b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ssid[i].ssid_len = ssids[i].ssid_len;
1632b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1633b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1634b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* parsing channels, n_channels */
1635b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memset(ch, 0,
1636b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	       sizeof(struct rtw_ieee80211_channel) * RTW_CHANNEL_SCAN_AMOUNT);
1637b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1638b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (request->n_channels == 1) {
1639b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		for (i = 0; i < request->n_channels &&
1640b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		     i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
16419cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen			DBG_8723A("%s:(%s):" CHAN_FMT "\n",
16429cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen				  __func__, padapter->pnetdev->name,
1643b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				  CHAN_ARG(request->channels[i]));
1644b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ch[i].hw_value = request->channels[i]->hw_value;
1645b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ch[i].flags = request->channels[i]->flags;
1646b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
1647b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1648b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1649b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_lock_bh(&pmlmepriv->lock);
1650b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (request->n_channels == 1) {
1651b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(&ch[1], &ch[0], sizeof(struct rtw_ieee80211_channel));
1652b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(&ch[2], &ch[0], sizeof(struct rtw_ieee80211_channel));
1653b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		_status = rtw_sitesurvey_cmd23a(padapter, ssid,
1654b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					     RTW_SSID_SCAN_AMOUNT, ch, 3);
1655b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
1656b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		_status = rtw_sitesurvey_cmd23a(padapter, ssid,
1657b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					     RTW_SSID_SCAN_AMOUNT, NULL, 0);
1658b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1659b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_unlock_bh(&pmlmepriv->lock);
1660b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1661b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (_status == false)
1662b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -1;
1663b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1664b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingercheck_need_indicate_scan_done:
1665b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (need_indicate_scan_done)
1666b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_cfg80211_surveydone_event_callback(padapter);
1667b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
1668b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1669b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1670b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1671b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1672b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s\n", __func__);
1673b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
1674b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1675b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1676b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
1677b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				  struct cfg80211_ibss_params *params)
1678b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1679a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
1680b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
1681b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1682b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1683b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
1684b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1685a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
1686b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
1687b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1688b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1689b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv,
1690b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					u32 wpa_version)
1691b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1692b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s, wpa_version =%d\n", __func__, wpa_version);
1693b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1694b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!wpa_version) {
1695b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
1696b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return 0;
1697b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1698b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1699b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) {
1700b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK;
1701b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1702b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1703b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger/*
1704b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (wpa_version & NL80211_WPA_VERSION_2)
1705b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	{
1706b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK;
1707b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1708b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger*/
1709b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1710b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
1711b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1712b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1713b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_set_auth_type(struct security_priv *psecuritypriv,
1714b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				      enum nl80211_auth_type sme_auth_type)
1715b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1716b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s, nl80211_auth_type =%d\n", __func__, sme_auth_type);
1717b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1718b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	switch (sme_auth_type) {
1719b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_AUTHTYPE_AUTOMATIC:
1720b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
1721b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1722b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1723b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_AUTHTYPE_OPEN_SYSTEM:
1724b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
1725b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1726b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (psecuritypriv->ndisauthtype > Ndis802_11AuthModeWPA)
1727b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->dot11AuthAlgrthm =
1728b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				dot11AuthAlgrthm_8021X;
1729b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1730b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_AUTHTYPE_SHARED_KEY:
1731b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
1732b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1733b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
1734b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1735b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	default:
1736b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
1737b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* return -ENOTSUPP; */
1738b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1739b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1740b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
1741b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1742b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1743b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv,
1744b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				   u32 cipher, bool ucast)
1745b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1746b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u32 ndisencryptstatus = Ndis802_11EncryptionDisabled;
1747b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1748b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u32 *profile_cipher = ucast ? &psecuritypriv->dot11PrivacyAlgrthm :
1749b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    &psecuritypriv->dot118021XGrpPrivacy;
1750b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1751b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s, ucast =%d, cipher = 0x%x\n", __func__, ucast, cipher);
1752b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1753b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!cipher) {
17549e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		*profile_cipher = 0;
1755b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->ndisencryptstatus = ndisencryptstatus;
1756b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return 0;
1757b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1758b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1759b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	switch (cipher) {
1760b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case IW_AUTH_CIPHER_NONE:
17619e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		*profile_cipher = 0;
1762b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ndisencryptstatus = Ndis802_11EncryptionDisabled;
1763b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1764b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WLAN_CIPHER_SUITE_WEP40:
17659e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		*profile_cipher = WLAN_CIPHER_SUITE_WEP40;
1766b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ndisencryptstatus = Ndis802_11Encryption1Enabled;
1767b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1768b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WLAN_CIPHER_SUITE_WEP104:
17699e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		*profile_cipher = WLAN_CIPHER_SUITE_WEP104;
1770b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ndisencryptstatus = Ndis802_11Encryption1Enabled;
1771b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1772b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WLAN_CIPHER_SUITE_TKIP:
17739e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		*profile_cipher = WLAN_CIPHER_SUITE_TKIP;
1774b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ndisencryptstatus = Ndis802_11Encryption2Enabled;
1775b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1776b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WLAN_CIPHER_SUITE_CCMP:
17779e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		*profile_cipher = WLAN_CIPHER_SUITE_CCMP;
1778b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ndisencryptstatus = Ndis802_11Encryption3Enabled;
1779b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1780b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	default:
1781b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("Unsupported cipher: 0x%x\n", cipher);
1782b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return -ENOTSUPP;
1783b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1784b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1785b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ucast)
1786b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->ndisencryptstatus = ndisencryptstatus;
1787b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1788b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
1789b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1790b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1791b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_set_key_mgt(struct security_priv *psecuritypriv,
1792b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				    u32 key_mgt)
1793b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1794b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s, key_mgt = 0x%x\n", __func__, key_mgt);
1795b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1796b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (key_mgt == WLAN_AKM_SUITE_8021X)
1797b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
1798b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	else if (key_mgt == WLAN_AKM_SUITE_PSK)
1799b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
1800b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	else
1801b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("Invalid key mgt: 0x%x\n", key_mgt);
1802b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1803b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
1804b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1805b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1806b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_set_wpa_ie(struct rtw_adapter *padapter, const u8 *pie,
1807b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				   size_t ielen)
1808b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
1809d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen	const u8 *wps_ie;
18109bf29cb9404c8368d7a501e5266e0cfcf0bce702Jes Sorensen	u8 *buf = NULL;
1811b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int group_cipher = 0, pairwise_cipher = 0;
1812b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
181358aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen	const u8 *pwpa, *pwpa2;
1814b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int i;
1815b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1816b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!pie || !ielen) {
1817b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* Treat this as normal case, but need to clear
1818b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		   WIFI_UNDER_WPS */
1819b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		_clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
1820b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
1821b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1822b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ielen > MAX_WPA_IE_LEN + MAX_WPS_IE_LEN + MAX_P2P_IE_LEN) {
1823b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EINVAL;
1824b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
1825b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
18264a6eea4dcbc0328c3126fed264c42b0725bea659Benoit Taine	buf = kmemdup(pie, ielen, GFP_KERNEL);
1827b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (buf == NULL) {
1828b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENOMEM;
1829b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
1830b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1831b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1832b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* dump */
1833b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("set wpa_ie(length:%zu):\n", ielen);
1834b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	for (i = 0; i < ielen; i = i + 8)
1835b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n",
1836b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  buf[i], buf[i + 1],
1837b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  buf[i + 2], buf[i + 3], buf[i + 4],
1838b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  buf[i + 5], buf[i + 6], buf[i + 7]);
1839b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ielen < RSN_HEADER_LEN) {
1840b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_,
1841b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			 ("Ie len too short %d\n", (int)ielen));
1842b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -1;
1843b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
1844b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1845b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
184658aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen	pwpa = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
184758aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen				       WLAN_OUI_TYPE_MICROSOFT_WPA,
184858aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen				       buf, ielen);
184958aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen	if (pwpa && pwpa[1] > 0) {
185058aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen		if (rtw_parse_wpa_ie23a(pwpa, pwpa[1] + 2, &group_cipher,
185158aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen					&pairwise_cipher, NULL) == _SUCCESS) {
1852b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			padapter->securitypriv.dot11AuthAlgrthm =
1853b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				dot11AuthAlgrthm_8021X;
1854b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			padapter->securitypriv.ndisauthtype =
1855b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				Ndis802_11AuthModeWPAPSK;
185658aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen			memcpy(padapter->securitypriv.supplicant_ie, pwpa,
185758aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen			       pwpa[1] + 2);
1858b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
185958aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen			DBG_8723A("got wpa_ie, wpa_ielen:%u\n", pwpa[1]);
1860b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
1861b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1862b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
186358aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen	pwpa2 = cfg80211_find_ie(WLAN_EID_RSN, buf, ielen);
186458aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen	if (pwpa2 && pwpa2[1] > 0) {
186558aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen		if (rtw_parse_wpa2_ie23a (pwpa2, pwpa2[1] + 2, &group_cipher,
186658aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen					  &pairwise_cipher, NULL) == _SUCCESS) {
1867b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			padapter->securitypriv.dot11AuthAlgrthm =
1868b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				dot11AuthAlgrthm_8021X;
1869b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			padapter->securitypriv.ndisauthtype =
1870b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				Ndis802_11AuthModeWPA2PSK;
187158aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen			memcpy(padapter->securitypriv.supplicant_ie, pwpa2,
187258aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen			       pwpa2[1] + 2);
1873b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
187458aedb498f8a9870ff871058d4b91d77457fc14cJes Sorensen			DBG_8723A("got wpa2_ie, wpa2_ielen:%u\n", pwpa2[1]);
1875b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
1876b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1877b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1878b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (group_cipher == 0) {
1879b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		group_cipher = WPA_CIPHER_NONE;
1880b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1881b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (pairwise_cipher == 0) {
1882b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pairwise_cipher = WPA_CIPHER_NONE;
1883b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1884b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1885b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	switch (group_cipher) {
1886b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WPA_CIPHER_NONE:
18879e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		padapter->securitypriv.dot118021XGrpPrivacy = 0;
1888b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->securitypriv.ndisencryptstatus =
1889b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			Ndis802_11EncryptionDisabled;
1890b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1891b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WPA_CIPHER_WEP40:
18929e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		padapter->securitypriv.dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_WEP40;
1893b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->securitypriv.ndisencryptstatus =
1894b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			Ndis802_11Encryption1Enabled;
1895b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1896b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WPA_CIPHER_TKIP:
18979e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		padapter->securitypriv.dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_TKIP;
1898b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->securitypriv.ndisencryptstatus =
1899b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			Ndis802_11Encryption2Enabled;
1900b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1901b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WPA_CIPHER_CCMP:
19029e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		padapter->securitypriv.dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_CCMP;
1903b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->securitypriv.ndisencryptstatus =
1904b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			Ndis802_11Encryption3Enabled;
1905b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1906b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WPA_CIPHER_WEP104:
19079e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		padapter->securitypriv.dot118021XGrpPrivacy = WLAN_CIPHER_SUITE_WEP104;
1908b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->securitypriv.ndisencryptstatus =
1909b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			Ndis802_11Encryption1Enabled;
1910b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1911b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1912b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1913b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	switch (pairwise_cipher) {
1914b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WPA_CIPHER_NONE:
19159e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		padapter->securitypriv.dot11PrivacyAlgrthm = 0;
1916b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->securitypriv.ndisencryptstatus =
1917b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			Ndis802_11EncryptionDisabled;
1918b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1919b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WPA_CIPHER_WEP40:
19209e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		padapter->securitypriv.dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_WEP40;
1921b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->securitypriv.ndisencryptstatus =
1922b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			Ndis802_11Encryption1Enabled;
1923b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1924b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WPA_CIPHER_TKIP:
19259e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		padapter->securitypriv.dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_TKIP;
1926b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->securitypriv.ndisencryptstatus =
1927b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			Ndis802_11Encryption2Enabled;
1928b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1929b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WPA_CIPHER_CCMP:
19309e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		padapter->securitypriv.dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_CCMP;
1931b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->securitypriv.ndisencryptstatus =
1932b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			Ndis802_11Encryption3Enabled;
1933b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1934b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case WPA_CIPHER_WEP104:
19359e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen		padapter->securitypriv.dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_WEP104;
1936b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->securitypriv.ndisencryptstatus =
1937b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			Ndis802_11Encryption1Enabled;
1938b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
1939b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1940b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1941d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen	wps_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
1942d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen					 WLAN_OUI_TYPE_MICROSOFT_WPS,
1943d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen					 buf, ielen);
1944d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen	if (wps_ie && wps_ie[1] > 0) {
1945d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen		DBG_8723A("got wps_ie, wps_ielen:%u\n", wps_ie[1]);
1946d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen		padapter->securitypriv.wps_ie_len = wps_ie[1];
1947d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen		memcpy(padapter->securitypriv.wps_ie, wps_ie,
1948d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen		       padapter->securitypriv.wps_ie_len);
1949d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen		set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS);
1950d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen	} else {
1951d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen		_clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
1952b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
1953b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1954b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* TKIP and AES disallow multicast packets until installing group key */
19559e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	if (padapter->securitypriv.dot11PrivacyAlgrthm ==
19569e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	    WLAN_CIPHER_SUITE_TKIP ||
19579e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	    padapter->securitypriv.dot11PrivacyAlgrthm ==
19589e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	    WLAN_CIPHER_SUITE_CCMP)
1959b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* WPS open need to enable multicast */
1960b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true)*/
1961763b4247cafdb978630d4da7ff48c8113c7d961eJes Sorensen		rtl8723a_off_rcr_am(padapter);
1962b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1963b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
1964b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		 ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->"
1965b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  "securitypriv.ndisencryptstatus =%d padapter->"
1966b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  "securitypriv.ndisauthtype =%d\n", pairwise_cipher,
1967b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  padapter->securitypriv.ndisencryptstatus,
1968b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  padapter->securitypriv.ndisauthtype));
1969b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
1970b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
1971b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	kfree(buf);
1972b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ret)
1973b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		_clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
1974b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
1975b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
1976b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
19776893c8ebba521ea9d0f1cc4a53233fcb09271d52Jes Sorensenstatic int rtw_cfg80211_add_wep(struct rtw_adapter *padapter,
1978deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen				struct rtw_wep_key *wep, u8 keyid)
19791e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen{
1980deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen	int res;
19811e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen	struct security_priv *psecuritypriv = &padapter->securitypriv;
19821e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen
1983deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen	if (keyid >= NUM_WEP_KEYS) {
19841e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
19851e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen			 ("%s:keyid>4 =>fail\n", __func__));
19861e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		res = _FAIL;
19871e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		goto exit;
19881e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen	}
19891e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen
1990deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen	switch (wep->keylen) {
19914d9c63bbd207b20ae648bd6bd3ebcf6e52619616Jes Sorensen	case WLAN_KEY_LEN_WEP40:
19921e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		psecuritypriv->dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_WEP40;
19931e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
19941e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen			 ("%s:wep->KeyLength = 5\n", __func__));
19951e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		break;
19964d9c63bbd207b20ae648bd6bd3ebcf6e52619616Jes Sorensen	case WLAN_KEY_LEN_WEP104:
19971e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		psecuritypriv->dot11PrivacyAlgrthm = WLAN_CIPHER_SUITE_WEP104;
19981e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
19991e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen			 ("%s:wep->KeyLength = 13\n", __func__));
20001e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		break;
20011e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen	default:
20021e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		psecuritypriv->dot11PrivacyAlgrthm = 0;
20031e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
20041e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen			 ("%s:wep->KeyLength!= 5 or 13\n", __func__));
20051e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		res = _FAIL;
20061e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		goto exit;
20071e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen	}
20081e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen
20091e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
2010deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		 ("%s:before memcpy, wep->KeyLength = 0x%x keyid =%x\n",
2011deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		  __func__, wep->keylen, keyid));
20121e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen
2013deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen	memcpy(&psecuritypriv->wep_key[keyid], wep, sizeof(struct rtw_wep_key));
20141e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen
20151e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen	psecuritypriv->dot11PrivacyKeyIndex = keyid;
20161e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen
20171e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
20181e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		 ("%s:security key material : "
20191e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  "%x %x %x %x %x %x %x %x %x %x %x %x %x\n", __func__,
20201e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[0],
20211e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[1],
20221e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[2],
20231e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[3],
20241e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[4],
20251e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[5],
20261e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[6],
20271e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[7],
20281e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[8],
20291e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[9],
20301e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[10],
20311e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[11],
20321e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen		  psecuritypriv->wep_key[keyid].key[12]));
20331e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen
20341e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen	res = rtw_set_key23a(padapter, psecuritypriv, keyid, 1);
20351e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen
20361e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensenexit:
20371e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen
20381e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen	return res;
20391e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen}
20401e6e7f6030f3cec00641c5a356b5986723f33df6Jes Sorensen
2041e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensenstatic int rtw_set_ssid(struct rtw_adapter *padapter,
2042e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen			struct wlan_network *newnetwork)
204397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen{
204497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
204597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	struct wlan_network *pnetwork = &pmlmepriv->cur_network;
204697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	int status = _SUCCESS;
204797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	u32 cur_time = 0;
204897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
204997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	DBG_8723A_LEVEL(_drv_always_, "set ssid [%s] fw_state = 0x%08x\n",
2050e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen			newnetwork->network.Ssid.ssid, get_fwstate(pmlmepriv));
205197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
205297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	if (padapter->hw_init_completed == false) {
205397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
205497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			 ("set_ssid: hw_init_completed == false =>exit!!!\n"));
205597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		status = _FAIL;
205697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		goto exit;
205797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	}
205897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
205997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	spin_lock_bh(&pmlmepriv->lock);
206097c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
206197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	DBG_8723A("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
206297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
206397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		goto handle_tkip_countermeasure;
206497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
206597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
206697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
206797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			 ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
206897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
2069e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen		if (pmlmepriv->assoc_ssid.ssid_len ==
2070e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen		    newnetwork->network.Ssid.ssid_len &&
2071e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen		    !memcmp(&pmlmepriv->assoc_ssid.ssid,
2072e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen			    newnetwork->network.Ssid.ssid,
2073e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen			    newnetwork->network.Ssid.ssid_len)) {
207497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
207597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				RT_TRACE(_module_rtl871x_ioctl_set_c_,
207697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen					 _drv_err_, ("New SSID is same SSID, "
207797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen						     "fw_state = 0x%08x\n",
207897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen						     get_fwstate(pmlmepriv)));
207997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
208097c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				if (rtw_is_same_ibss23a(padapter, pnetwork)) {
208197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen					/*
208297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen					 * it means driver is in
208397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen					 * WIFI_ADHOC_MASTER_STATE, we needn't
208497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen					 * create bss again.
208597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen					 */
208697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen					goto release_mlme_lock;
208797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				}
208897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
208997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				/*
209097c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				 * if in WIFI_ADHOC_MASTER_STATE |
209197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				 * WIFI_ADHOC_STATE, create bss or
209297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				 * rejoin again
209397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				 */
209497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				rtw_disassoc_cmd23a(padapter, 0, true);
209597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
209697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				if (check_fwstate(pmlmepriv, _FW_LINKED))
209797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen					rtw_indicate_disconnect23a(padapter);
209897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
209997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				rtw_free_assoc_resources23a(padapter, 1);
210097c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
210197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				if (check_fwstate(pmlmepriv,
210297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen						  WIFI_ADHOC_MASTER_STATE)) {
210397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen					_clr_fwstate_(pmlmepriv,
210497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen						      WIFI_ADHOC_MASTER_STATE);
210597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen					set_fwstate(pmlmepriv,
210697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen						    WIFI_ADHOC_STATE);
210797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				}
210897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			} else {
210997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				rtw_lps_ctrl_wk_cmd23a(padapter,
211097c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen						       LPS_CTRL_JOINBSS, 1);
211197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			}
211297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		} else {
211397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
211497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				 ("Set SSID not the same ssid\n"));
211597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
2116e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen				 ("set_ssid =[%s] len = 0x%x\n",
2117e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen				  newnetwork->network.Ssid.ssid,
2118e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen				  newnetwork->network.Ssid.ssid_len));
211997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
212097c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				 ("assoc_ssid =[%s] len = 0x%x\n",
212197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				  pmlmepriv->assoc_ssid.ssid,
212297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				  pmlmepriv->assoc_ssid.ssid_len));
212397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
212497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			rtw_disassoc_cmd23a(padapter, 0, true);
212597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
212697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			if (check_fwstate(pmlmepriv, _FW_LINKED))
212797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				rtw_indicate_disconnect23a(padapter);
212897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
212997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			rtw_free_assoc_resources23a(padapter, 1);
213097c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
213197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
213297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
213397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen				set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
213497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			}
213597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		}
213697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	}
213797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
213897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensenhandle_tkip_countermeasure:
213997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
214097c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	if (padapter->securitypriv.btkip_countermeasure == true) {
214197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		cur_time = jiffies;
214297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
214397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		if ((cur_time -
214497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		     padapter->securitypriv.btkip_countermeasure_time) >
214597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		    60 * HZ) {
214697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			padapter->securitypriv.btkip_countermeasure = false;
214797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			padapter->securitypriv.btkip_countermeasure_time = 0;
214897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		} else {
214997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			status = _FAIL;
215097c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen			goto release_mlme_lock;
215197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		}
215297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	}
215397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
2154e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen	memcpy(&pmlmepriv->assoc_ssid, &newnetwork->network.Ssid,
2155e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen	       sizeof(struct cfg80211_ssid));
2156e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen
215797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	pmlmepriv->assoc_by_bssid = false;
215897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
215972795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen	pmlmepriv->to_join = true;
216072795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen
216172795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen	if (!check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
216272795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen		pmlmepriv->cur_network.join_res = -2;
216397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
216472795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen		status = rtw_do_join_network(padapter, newnetwork);
216572795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen		if (status == _SUCCESS) {
216672795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen			pmlmepriv->to_join = false;
216772795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen		} else {
216872795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen			if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
216972795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen				/* switch to ADHOC_MASTER */
217072795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen				status = rtw_do_join_adhoc(padapter);
217172795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen				if (status != _SUCCESS)
217272795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen					goto release_mlme_lock;
217372795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen			} else {
217472795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen				/* can't associate ; reset under-linking */
217572795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen				_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
217672795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen				status = _FAIL;
217772795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen				pmlmepriv->to_join = false;
217872795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen			}
217972795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen		}
218072795e9de7deae0952d1174cfb37cb869b582d29Jes Sorensen	}
218197c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensenrelease_mlme_lock:
218297c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	spin_unlock_bh(&pmlmepriv->lock);
218397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
218497c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensenexit:
218597c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
218697c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		 ("-%s: status =%d\n", __func__, status));
218797c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
218897c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen	return status;
218997c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen}
219097c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen
2191b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev,
2192b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				struct cfg80211_connect_params *sme)
2193b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2194b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
2195b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct list_head *phead, *plist, *ptmp;
2196b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wlan_network *pnetwork = NULL;
2197b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* u8 matched_by_bssid = false; */
2198b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* u8 matched_by_ssid = false; */
2199b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 matched = false;
2200b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
2201b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
2202b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct security_priv *psecuritypriv = &padapter->securitypriv;
2203b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_queue *queue = &pmlmepriv->scanned_queue;
2204b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2205a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("=>" "%s(%s)\n", __func__, ndev->name);
2206b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("privacy =%d, key =%p, key_len =%d, key_idx =%d\n",
2207b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  sme->privacy, sme->key, sme->key_len, sme->key_idx);
2208b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2209b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (_FAIL == rtw_pwr_wakeup(padapter)) {
2210b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EPERM;
2211b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2212b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2213b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2214b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
2215b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EPERM;
2216b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2217b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2218b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2219c5178b0bc2ea2e72d45a90ae346a9b2fda0b5f08Jes Sorensen	if (!sme->ssid || !sme->ssid_len ||
2220c5178b0bc2ea2e72d45a90ae346a9b2fda0b5f08Jes Sorensen	    sme->ssid_len > IEEE80211_MAX_SSID_LEN) {
2221b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EINVAL;
2222b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2223b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2224b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2225c5178b0bc2ea2e72d45a90ae346a9b2fda0b5f08Jes Sorensen	DBG_8723A("ssid =%s, len =%zu\n", sme->ssid, sme->ssid_len);
2226b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2227b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (sme->bssid)
2228b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("bssid =" MAC_FMT "\n", MAC_ARG(sme->bssid));
2229b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2230b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
2231b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EBUSY;
2232b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s, fw_state = 0x%x, goto exit\n", __func__,
2233b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  pmlmepriv->fw_state);
2234b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2235b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2236b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
2237b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_scan_abort23a(padapter);
2238b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2239b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2240b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_lock_bh(&queue->lock);
2241b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2242b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	phead = get_list_head(queue);
2243b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2244b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	list_for_each_safe(plist, ptmp, phead) {
2245b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pnetwork = container_of(plist, struct wlan_network, list);
2246b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2247b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (sme->bssid) {
2248cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen			if (!ether_addr_equal(pnetwork->network.MacAddress,
2249cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen					      sme->bssid))
2250b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				continue;
2251b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
2252b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2253b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (sme->ssid && sme->ssid_len) {
2254b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (pnetwork->network.Ssid.ssid_len != sme->ssid_len ||
2255b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			    memcmp(pnetwork->network.Ssid.ssid, sme->ssid,
2256b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				   sme->ssid_len))
2257b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				continue;
2258b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
2259b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2260b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (sme->bssid) {
22619ab98d42401d50d6ab5f6ef59e1d63c486391f1cJes Sorensen			if (ether_addr_equal(pnetwork->network.MacAddress,
22629ab98d42401d50d6ab5f6ef59e1d63c486391f1cJes Sorensen					     sme->bssid)) {
2263b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				DBG_8723A("matched by bssid\n");
2264b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2265b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				matched = true;
2266b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				break;
2267b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
2268b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		} else if (sme->ssid && sme->ssid_len) {
22699ab98d42401d50d6ab5f6ef59e1d63c486391f1cJes Sorensen			if (!memcmp(pnetwork->network.Ssid.ssid,
22709ab98d42401d50d6ab5f6ef59e1d63c486391f1cJes Sorensen				    sme->ssid, sme->ssid_len) &&
2271c5178b0bc2ea2e72d45a90ae346a9b2fda0b5f08Jes Sorensen			    pnetwork->network.Ssid.ssid_len == sme->ssid_len) {
2272b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				DBG_8723A("matched by ssid\n");
2273c5178b0bc2ea2e72d45a90ae346a9b2fda0b5f08Jes Sorensen
2274b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				matched = true;
2275b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				break;
2276b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
2277b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
2278b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2279b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2280b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_unlock_bh(&queue->lock);
2281b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2282c5178b0bc2ea2e72d45a90ae346a9b2fda0b5f08Jes Sorensen	if (!matched || !pnetwork) {
2283b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENOENT;
2284b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("connect, matched == false, goto exit\n");
2285b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2286b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2287b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2288efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen	if (cfg80211_infrastructure_mode(
2289efc7144ff163bb1305ec8585e9e2f93ad9b06bd9Jes Sorensen		    padapter, pnetwork->network.ifmode) != _SUCCESS) {
2290b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EPERM;
2291b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2292b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2293b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2294b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled;
22959e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	psecuritypriv->dot11PrivacyAlgrthm = 0;
22969e3d6df2df8dbc4c2c5fb733dc494dfc82e0e2aeJes Sorensen	psecuritypriv->dot118021XGrpPrivacy = 0;
2297b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
2298b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
2299b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2300c5178b0bc2ea2e72d45a90ae346a9b2fda0b5f08Jes Sorensen	ret = rtw_cfg80211_set_wpa_version(psecuritypriv,
2301c5178b0bc2ea2e72d45a90ae346a9b2fda0b5f08Jes Sorensen					   sme->crypto.wpa_versions);
2302b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ret < 0)
2303b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2304b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2305b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ret = rtw_cfg80211_set_auth_type(psecuritypriv, sme->auth_type);
2306b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2307b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ret < 0)
2308b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2309b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2310b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s, ie_len =%zu\n", __func__, sme->ie_len);
2311b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2312b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ret = rtw_cfg80211_set_wpa_ie(padapter, sme->ie, sme->ie_len);
2313b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ret < 0)
2314b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2315b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2316b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (sme->crypto.n_ciphers_pairwise) {
2317b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = rtw_cfg80211_set_cipher(psecuritypriv,
2318b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					      sme->crypto.ciphers_pairwise[0],
2319b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					      true);
2320b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (ret < 0)
2321b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto exit;
2322b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2323b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2324b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* For WEP Shared auth */
2325b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if ((psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Shared ||
2326b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	     psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Auto) &&
2327b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    sme->key) {
2328deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		struct rtw_wep_key wep_key;
2329deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		u8 wep_key_idx, wep_key_len;
2330b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s(): Shared/Auto WEP\n", __func__);
2331b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2332b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		wep_key_idx = sme->key_idx;
2333b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		wep_key_len = sme->key_len;
2334b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2335deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		if (wep_key_idx > WEP_KEYS || !wep_key_len ||
2336deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		    wep_key_len > WLAN_KEY_LEN_WEP104) {
2337b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ret = -EINVAL;
2338b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto exit;
2339b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
2340b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2341deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		wep_key_len = wep_key_len <= 5 ? 5 : 13;
2342b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2343deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		memset(&wep_key, 0, sizeof(struct rtw_wep_key));
2344b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2345deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		wep_key.keylen = wep_key_len;
2346b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2347deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		if (wep_key_len == 13) {
2348deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen			padapter->securitypriv.dot11PrivacyAlgrthm =
2349deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen				WLAN_CIPHER_SUITE_WEP104;
2350deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen			padapter->securitypriv.dot118021XGrpPrivacy =
2351deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen				WLAN_CIPHER_SUITE_WEP104;
2352b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		} else {
2353deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen			padapter->securitypriv.dot11PrivacyAlgrthm =
2354deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen				WLAN_CIPHER_SUITE_WEP40;
2355deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen			padapter->securitypriv.dot118021XGrpPrivacy =
2356deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen				WLAN_CIPHER_SUITE_WEP40;
2357b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
2358b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2359deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		memcpy(wep_key.key, (void *)sme->key, wep_key.keylen);
2360b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2361deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		if (rtw_cfg80211_add_wep(padapter, &wep_key, wep_key_idx) !=
2362deff11554fa4a0bf0f3616d29f0636ab5ff52758Jes Sorensen		    _SUCCESS)
2363b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ret = -EOPNOTSUPP;
2364b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2365b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (ret < 0)
2366b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto exit;
2367b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2368b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2369b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ret = rtw_cfg80211_set_cipher(psecuritypriv,
2370b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				      sme->crypto.cipher_group, false);
2371b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ret < 0)
2372c5178b0bc2ea2e72d45a90ae346a9b2fda0b5f08Jes Sorensen		goto exit;
2373b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2374b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (sme->crypto.n_akm_suites) {
2375b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = rtw_cfg80211_set_key_mgt(psecuritypriv,
2376b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					       sme->crypto.akm_suites[0]);
2377b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (ret < 0)
2378b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto exit;
2379b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2380b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
238139dbc446a7168e4d7542d6523132ee44189d0ba2Jes Sorensen	if (psecuritypriv->ndisauthtype > 3)
238239dbc446a7168e4d7542d6523132ee44189d0ba2Jes Sorensen		psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
238339dbc446a7168e4d7542d6523132ee44189d0ba2Jes Sorensen
238439dbc446a7168e4d7542d6523132ee44189d0ba2Jes Sorensen	if (rtw_set_auth23a(padapter, psecuritypriv) != _SUCCESS) {
238539dbc446a7168e4d7542d6523132ee44189d0ba2Jes Sorensen		ret = -EBUSY;
238639dbc446a7168e4d7542d6523132ee44189d0ba2Jes Sorensen		goto exit;
238739dbc446a7168e4d7542d6523132ee44189d0ba2Jes Sorensen	}
2388b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2389b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* rtw_set_802_11_encryption_mode(padapter,
2390b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	   padapter->securitypriv.ndisencryptstatus); */
2391b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2392e73d82efa4583e5ecaf598d85341403806a16e62Jes Sorensen	if (rtw_set_ssid(padapter, pnetwork) != _SUCCESS) {
239397c4361d50e833a0c178cf425590a15e9663f3d0Jes Sorensen		ret = -EBUSY;
2394b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2395b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2396b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2397b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("set ssid:dot11AuthAlgrthm =%d, dot11PrivacyAlgrthm =%d, "
2398b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  "dot118021XGrpPrivacy =%d\n", psecuritypriv->dot11AuthAlgrthm,
2399b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  psecuritypriv->dot11PrivacyAlgrthm,
2400b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  psecuritypriv->dot118021XGrpPrivacy);
2401b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2402b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
2403b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2404b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("<=%s, ret %d\n", __func__, ret);
2405b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2406b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
2407b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2408b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2409b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev,
2410b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				   u16 reason_code)
2411b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2412b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
2413b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2414a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
2415b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2416b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	rtw_set_roaming(padapter, 0);
2417b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2418b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
2419b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_scan_abort23a(padapter);
2420b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		LeaveAllPowerSaveMode23a(padapter);
2421b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_disassoc_cmd23a(padapter, 500, false);
2422b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2423b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s...call rtw_indicate_disconnect23a\n", __func__);
2424b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2425b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->mlmepriv.not_indic_disco = true;
2426b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_indicate_disconnect23a(padapter);
2427b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		padapter->mlmepriv.not_indic_disco = false;
2428b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2429b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		rtw_free_assoc_resources23a(padapter, 1);
2430b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2431b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2432b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
2433b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2434b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2435b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_set_txpower(struct wiphy *wiphy,
2436b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				    struct wireless_dev *wdev,
2437b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				    enum nl80211_tx_power_setting type, int mbm)
2438b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2439b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s\n", __func__);
2440b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
2441b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2442b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2443b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_get_txpower(struct wiphy *wiphy,
2444b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				    struct wireless_dev *wdev, int *dbm)
2445b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2446b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s\n", __func__);
2447b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	*dbm = (12);
2448b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
2449b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2450b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2451b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerinline bool rtw_cfg80211_pwr_mgmt(struct rtw_adapter *adapter)
2452b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2453b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_wdev_priv *rtw_wdev_priv = wdev_to_priv(adapter->rtw_wdev);
2454b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return rtw_wdev_priv->power_mgmt;
2455b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2456b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2457b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_set_power_mgmt(struct wiphy *wiphy,
2458b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       struct net_device *ndev,
2459b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       bool enabled, int timeout)
2460b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2461b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
2462b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_wdev_priv *rtw_wdev_priv = wdev_to_priv(padapter->rtw_wdev);
2463b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2464a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s): enabled:%u, timeout:%d\n",
2465a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen		  __func__, ndev->name, enabled, timeout);
2466b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2467b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	rtw_wdev_priv->power_mgmt = enabled;
2468b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2469b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!enabled)
2470b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		LPS_Leave23a(padapter);
2471b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2472b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
2473b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2474b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2475b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_set_pmksa(struct wiphy *wiphy,
2476b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				  struct net_device *netdev,
2477b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				  struct cfg80211_pmksa *pmksa)
2478b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2479b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 index, blInserted = false;
2480b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
2481b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct security_priv *psecuritypriv = &padapter->securitypriv;
2482b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2483a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, netdev->name);
2484b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2485cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen	if (is_zero_ether_addr(pmksa->bssid))
2486b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return -EINVAL;
2487b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2488b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	blInserted = false;
2489b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2490b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* overwrite PMKID */
2491b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	for (index = 0; index < NUM_PMKID_CACHE; index++) {
2492cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen		if (ether_addr_equal(psecuritypriv->PMKIDList[index].Bssid,
2493cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen				     pmksa->bssid)) {
2494b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			/* BSSID is matched, the same AP => rewrite with
2495b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			   new PMKID. */
2496a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen			DBG_8723A("%s(%s):  BSSID exists in the PMKList.\n",
2497a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen				  __func__, netdev->name);
2498b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2499b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			memcpy(psecuritypriv->PMKIDList[index].PMKID,
2500b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			       pmksa->pmkid, WLAN_PMKID_LEN);
2501b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->PMKIDList[index].bUsed = true;
2502b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->PMKIDIndex = index + 1;
2503b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			blInserted = true;
2504b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			break;
2505b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
2506b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2507b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2508b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!blInserted) {
2509b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/*  Find a new entry */
2510a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen		DBG_8723A("%s(%s): Use new entry index = %d for this PMKID\n",
2511a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen			  __func__, netdev->name, psecuritypriv->PMKIDIndex);
2512b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2513888df442ef023adbca6536888eae65b2cd8ae295Jes Sorensen		ether_addr_copy(
2514888df442ef023adbca6536888eae65b2cd8ae295Jes Sorensen			psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].
2515888df442ef023adbca6536888eae65b2cd8ae295Jes Sorensen			Bssid, pmksa->bssid);
2516b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].
2517b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		       PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2518b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2519b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed =
2520b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			true;
2521b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psecuritypriv->PMKIDIndex++;
2522b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (psecuritypriv->PMKIDIndex == 16) {
2523b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->PMKIDIndex = 0;
2524b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
2525b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2526b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2527b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
2528b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2529b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2530b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_del_pmksa(struct wiphy *wiphy,
2531b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				  struct net_device *netdev,
2532b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				  struct cfg80211_pmksa *pmksa)
2533b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2534b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 index, bMatched = false;
2535b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
2536b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct security_priv *psecuritypriv = &padapter->securitypriv;
2537b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2538a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, netdev->name);
2539b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2540b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	for (index = 0; index < NUM_PMKID_CACHE; index++) {
2541cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen		if (ether_addr_equal(psecuritypriv->PMKIDList[index].Bssid,
2542cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen				     pmksa->bssid)) {
2543cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen			/* BSSID is matched, the same AP => Remove this PMKID
2544cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen			   information and reset it. */
254543c34be13047dd53e70bc4759ff314424db7036bJes Sorensen			eth_zero_addr(psecuritypriv->PMKIDList[index].Bssid);
2546b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			memset(psecuritypriv->PMKIDList[index].PMKID, 0x00,
2547b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			       WLAN_PMKID_LEN);
2548b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			psecuritypriv->PMKIDList[index].bUsed = false;
2549b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			bMatched = true;
2550b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			break;
2551b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
2552b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2553b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2554b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (false == bMatched) {
2555a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen		DBG_8723A("%s(%s): do not have matched BSSID\n", __func__,
2556a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen			  netdev->name);
2557b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return -EINVAL;
2558b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2559b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2560b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
2561b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2562b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2563b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy,
2564b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				    struct net_device *netdev)
2565b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2566b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
2567b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct security_priv *psecuritypriv = &padapter->securitypriv;
2568b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2569a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, netdev->name);
2570b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2571b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memset(&psecuritypriv->PMKIDList[0], 0x00,
2572b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	       sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
2573b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	psecuritypriv->PMKIDIndex = 0;
2574b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2575b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
2576b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2577b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2578b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#ifdef CONFIG_8723AU_AP_MODE
2579b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingervoid rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter,
2580b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     u8 *pmgmt_frame, uint frame_len)
2581b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2582b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	s32 freq;
2583b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int channel;
2584b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2585b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct net_device *ndev = padapter->pnetdev;
2586b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2587b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s(padapter =%p,%s)\n", __func__, padapter, ndev->name);
2588b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2589b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#if defined(RTW_USE_CFG80211_STA_EVENT)
2590b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	{
2591b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct station_info sinfo;
2592b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		u8 ie_offset;
2593b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (ieee80211_is_assoc_req(hdr->frame_control))
2594b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ie_offset = _ASOCREQ_IE_OFFSET_;
2595b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		else		/*  WIFI_REASSOCREQ */
2596b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			ie_offset = _REASOCREQ_IE_OFFSET_;
2597b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2598b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo.filled = 0;
2599b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
2600b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo.assoc_req_ies = pmgmt_frame + WLAN_HDR_A3_LEN + ie_offset;
2601b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		sinfo.assoc_req_ies_len =
2602b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			frame_len - WLAN_HDR_A3_LEN - ie_offset;
2603b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		cfg80211_new_sta(ndev, hdr->addr2, &sinfo, GFP_ATOMIC);
2604b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2605b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#else /* defined(RTW_USE_CFG80211_STA_EVENT) */
2606b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	channel = pmlmeext->cur_channel;
2607b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (channel <= RTW_CH_MAX_2G_CHANNEL)
2608b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		freq = ieee80211_channel_to_frequency(channel,
2609b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						      IEEE80211_BAND_2GHZ);
2610b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	else
2611b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		freq = ieee80211_channel_to_frequency(channel,
2612b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						      IEEE80211_BAND_5GHZ);
2613b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
261456b0bd91e0087e0b172aec022bdfb4fcd9de9194Jes Sorensen	cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, pmgmt_frame, frame_len,
261556b0bd91e0087e0b172aec022bdfb4fcd9de9194Jes Sorensen			 0, GFP_ATOMIC);
2616b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */
2617b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2618b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2619b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingervoid rtw_cfg80211_indicate_sta_disassoc(struct rtw_adapter *padapter,
2620b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					unsigned char *da,
2621b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					unsigned short reason)
2622b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2623b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	s32 freq;
2624b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int channel;
2625b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	uint frame_len;
2626cc531f6154167893f1cf8ab084871fe06b38fb2bJes Sorensen	struct ieee80211_mgmt mgmt;
2627b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2628b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
2629b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct net_device *ndev = padapter->pnetdev;
2630b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2631b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s(padapter =%p,%s)\n", __func__, padapter, ndev->name);
2632b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2633cc531f6154167893f1cf8ab084871fe06b38fb2bJes Sorensen	memset(&mgmt, 0, sizeof(struct ieee80211_mgmt));
26341daffaeecb4bf01c4a34fc2330c745ace5af3f60Jes Sorensen
2635b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#if defined(RTW_USE_CFG80211_STA_EVENT)
2636b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	cfg80211_del_sta(ndev, da, GFP_ATOMIC);
2637b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#else /* defined(RTW_USE_CFG80211_STA_EVENT) */
2638b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	channel = pmlmeext->cur_channel;
2639b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (channel <= RTW_CH_MAX_2G_CHANNEL)
2640b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		freq = ieee80211_channel_to_frequency(channel,
2641b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						      IEEE80211_BAND_2GHZ);
2642b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	else
2643b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		freq = ieee80211_channel_to_frequency(channel,
2644b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						      IEEE80211_BAND_5GHZ);
2645b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2646cc531f6154167893f1cf8ab084871fe06b38fb2bJes Sorensen	mgmt.frame_control =
2647036cdd9cb34a10aabb80a97a41fb9dcfead7d113Jes Sorensen		cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH);
2648b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2649cc531f6154167893f1cf8ab084871fe06b38fb2bJes Sorensen	ether_addr_copy(mgmt.da, myid(&padapter->eeprompriv));
2650cc531f6154167893f1cf8ab084871fe06b38fb2bJes Sorensen	ether_addr_copy(mgmt.sa, da);
2651cc531f6154167893f1cf8ab084871fe06b38fb2bJes Sorensen	ether_addr_copy(mgmt.bssid, get_my_bssid23a(&pmlmeinfo->network));
2652b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2653cc531f6154167893f1cf8ab084871fe06b38fb2bJes Sorensen	mgmt.seq_ctrl = cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
2654b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pmlmeext->mgnt_seq++;
2655b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2656cc531f6154167893f1cf8ab084871fe06b38fb2bJes Sorensen	mgmt.u.disassoc.reason_code = cpu_to_le16(reason);
2657b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2658cc531f6154167893f1cf8ab084871fe06b38fb2bJes Sorensen	frame_len = sizeof(struct ieee80211_hdr_3addr) + 2;
2659b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2660cc531f6154167893f1cf8ab084871fe06b38fb2bJes Sorensen	cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, (u8 *)&mgmt, frame_len,
266156b0bd91e0087e0b172aec022bdfb4fcd9de9194Jes Sorensen			 0, GFP_ATOMIC);
2662b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */
2663b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2664b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2665b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_monitor_if_open(struct net_device *ndev)
2666b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2667b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
2668b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2669b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s\n", __func__);
2670b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2671b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
2672b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2673b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2674b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_monitor_if_close(struct net_device *ndev)
2675b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2676b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
2677b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2678b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s\n", __func__);
2679b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2680b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
2681b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2682b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2683b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb,
2684b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					      struct net_device *ndev)
2685b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2686b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
2687b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int rtap_len;
2688b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int qos_len = 0;
2689b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int dot11_hdr_len = 24;
2690b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int snap_len = 6;
2691b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	unsigned char *pdata;
2692b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	unsigned char src_mac_addr[6];
2693b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	unsigned char dst_mac_addr[6];
2694b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct ieee80211_hdr *dot11_hdr;
2695b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct ieee80211_radiotap_header *rtap_hdr;
2696b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = netdev_priv(ndev);
2697b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2698a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
2699b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2700b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
2701b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto fail;
2702b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2703b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
2704b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (unlikely(rtap_hdr->it_version))
2705b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto fail;
2706b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2707b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	rtap_len = ieee80211_get_radiotap_len(skb->data);
2708b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (unlikely(skb->len < rtap_len))
2709b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto fail;
2710b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2711b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (rtap_len != 14) {
2712b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("radiotap len (should be 14): %d\n", rtap_len);
2713b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto fail;
2714b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2715b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2716b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* Skip the ratio tap header */
2717b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	skb_pull(skb, rtap_len);
2718b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2719b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	dot11_hdr = (struct ieee80211_hdr *)skb->data;
2720b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* Check if the QoS bit is set */
2721b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ieee80211_is_data(dot11_hdr->frame_control)) {
2722b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* Check if this ia a Wireless Distribution System (WDS) frame
2723b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		 * which has 4 MAC addresses
2724b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		 */
2725b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (ieee80211_is_data_qos(dot11_hdr->frame_control))
2726b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			qos_len = IEEE80211_QOS_CTL_LEN;
2727b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (ieee80211_has_a4(dot11_hdr->frame_control))
2728b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			dot11_hdr_len += 6;
2729b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2730b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
2731b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
2732b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2733b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/*
2734b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		 * Skip the 802.11 header, QoS (if any) and SNAP,
2735b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		 * but leave spaces for two MAC addresses
2736b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		 */
2737b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		skb_pull(skb, dot11_hdr_len + qos_len + snap_len -
2738b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			 ETH_ALEN * 2);
2739b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pdata = (unsigned char *)skb->data;
2740888df442ef023adbca6536888eae65b2cd8ae295Jes Sorensen		ether_addr_copy(pdata, dst_mac_addr);
2741888df442ef023adbca6536888eae65b2cd8ae295Jes Sorensen		ether_addr_copy(pdata + ETH_ALEN, src_mac_addr);
2742b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2743b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("should be eapol packet\n");
2744b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2745b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* Use the real net device to transmit the packet */
2746b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = rtw_xmit23a_entry23a(skb, padapter->pnetdev);
2747b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2748b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return ret;
2749b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2750b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else if (ieee80211_is_action(dot11_hdr->frame_control)) {
275138eb09b5be235eeaf1c4d0a2100d3cb2a3e0b3a3Jes Sorensen		struct ieee80211_mgmt *mgmt;
2752b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* only for action frames */
2753b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct xmit_frame *pmgntframe;
2754b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct pkt_attrib *pattrib;
2755b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		unsigned char *pframe;
2756b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* u8 category, action, OUI_Subtype, dialogToken = 0; */
2757b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* unsigned char        *frame_body; */
2758b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2759b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2760b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		u32 len = skb->len;
2761b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		u8 category, action;
2762b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
276338eb09b5be235eeaf1c4d0a2100d3cb2a3e0b3a3Jes Sorensen		mgmt = (struct ieee80211_mgmt *)dot11_hdr;
2764b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2765a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen		DBG_8723A("RTW_Tx:da =" MAC_FMT " via %s(%s)\n",
276638eb09b5be235eeaf1c4d0a2100d3cb2a3e0b3a3Jes Sorensen			  MAC_ARG(mgmt->da), __func__, ndev->name);
276738eb09b5be235eeaf1c4d0a2100d3cb2a3e0b3a3Jes Sorensen		category = mgmt->u.action.category;
276838eb09b5be235eeaf1c4d0a2100d3cb2a3e0b3a3Jes Sorensen		action = mgmt->u.action.u.wme_action.action_code;
27692e74d336edb945b4a1f851e821001093e4094729Jes Sorensen		DBG_8723A("RTW_Tx:category(%u), action(%u)\n",
27702e74d336edb945b4a1f851e821001093e4094729Jes Sorensen			  category, action);
277198fb81291d30f83838379bf1522fead6673b5fdfJes Sorensen
2772b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* starting alloc mgmt frame to dump it */
2773b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
2774b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (pmgntframe == NULL)
2775b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			goto fail;
2776b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2777b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* update attribute */
2778b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pattrib = &pmgntframe->attrib;
2779b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		update_mgntframe_attrib23a(padapter, pattrib);
2780b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pattrib->retry_ctrl = false;
2781b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2782b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
2783b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2784b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
2785b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2786b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(pframe, skb->data, len);
2787b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pattrib->pktlen = len;
2788b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2789b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* update seq number */
2790b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pmlmeext->mgnt_seq = le16_to_cpu(dot11_hdr->seq_ctrl) >> 4;
2791b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pattrib->seqnum = pmlmeext->mgnt_seq;
2792b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pmlmeext->mgnt_seq++;
2793b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2794b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pattrib->last_txcmdsz = pattrib->pktlen;
2795b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2796b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		dump_mgntframe23a(padapter, pmgntframe);
2797b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2798b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2799b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerfail:
2800b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2801b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	dev_kfree_skb(skb);
2802b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2803b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
2804b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2805b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2806b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int
2807b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerrtw_cfg80211_monitor_if_set_mac_address(struct net_device *ndev, void *addr)
2808b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2809b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
2810b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2811b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s\n", __func__);
2812b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2813b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
2814b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2815b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2816b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic const struct net_device_ops rtw_cfg80211_monitor_if_ops = {
2817b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.ndo_open = rtw_cfg80211_monitor_if_open,
2818b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.ndo_stop = rtw_cfg80211_monitor_if_close,
2819b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry,
2820b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.ndo_set_mac_address = rtw_cfg80211_monitor_if_set_mac_address,
2821b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger};
2822b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2823b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_cfg80211_add_monitor_if(struct rtw_adapter *padapter, char *name,
2824b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       struct net_device **ndev)
2825b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2826b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
2827b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct net_device *mon_ndev = NULL;
2828b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wireless_dev *mon_wdev = NULL;
2829b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev);
2830b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2831b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!name) {
28329cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen		DBG_8723A("%s(%s): without specific name\n",
28339cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen			  __func__, padapter->pnetdev->name);
2834b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EINVAL;
2835b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto out;
2836b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2837b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2838b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (pwdev_priv->pmon_ndev) {
28399cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen		DBG_8723A("%s(%s): monitor interface exist: %s\n", __func__,
28409cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen			  padapter->pnetdev->name, pwdev_priv->pmon_ndev->name);
2841b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EBUSY;
2842b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto out;
2843b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2844b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2845b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	mon_ndev = alloc_etherdev(sizeof(struct rtw_adapter));
2846b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!mon_ndev) {
28479cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen		DBG_8723A("%s(%s): allocate ndev fail\n", __func__,
28489cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen			  padapter->pnetdev->name);
2849b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENOMEM;
2850b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto out;
2851b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2852b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2853b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	mon_ndev->type = ARPHRD_IEEE80211_RADIOTAP;
2854b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	strncpy(mon_ndev->name, name, IFNAMSIZ);
2855b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	mon_ndev->name[IFNAMSIZ - 1] = 0;
2856b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	mon_ndev->destructor = rtw_ndev_destructor;
2857b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2858b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	mon_ndev->netdev_ops = &rtw_cfg80211_monitor_if_ops;
2859b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2860b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/*  wdev */
2861b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	mon_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
2862b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!mon_wdev) {
28639cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen		DBG_8723A("%s(%s): allocate mon_wdev fail\n", __func__,
28649cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen			  padapter->pnetdev->name);
2865b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENOMEM;
2866b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto out;
2867b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2868b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2869b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	mon_wdev->wiphy = padapter->rtw_wdev->wiphy;
2870b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	mon_wdev->netdev = mon_ndev;
2871b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	mon_wdev->iftype = NL80211_IFTYPE_MONITOR;
2872b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	mon_ndev->ieee80211_ptr = mon_wdev;
2873b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2874b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ret = register_netdevice(mon_ndev);
2875b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ret) {
2876b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto out;
2877b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2878b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2879b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	*ndev = pwdev_priv->pmon_ndev = mon_ndev;
2880b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy(pwdev_priv->ifname_mon, name, IFNAMSIZ + 1);
2881b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2882b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerout:
2883b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ret) {
2884b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		kfree(mon_wdev);
2885b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		mon_wdev = NULL;
2886b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2887b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2888b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ret && mon_ndev) {
2889b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		free_netdev(mon_ndev);
2890b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		*ndev = mon_ndev = NULL;
2891b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2892b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2893b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
2894b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2895b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2896b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic struct wireless_dev *
2897b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingercfg80211_rtw_add_virtual_intf(struct wiphy *wiphy, const char *name,
2898b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			      enum nl80211_iftype type, u32 *flags,
2899b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			      struct vif_params *params)
2900b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2901b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
2902b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct net_device *ndev = NULL;
2903b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
2904b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
29059cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen	DBG_8723A("%s(%s): wiphy:%s, name:%s, type:%d\n", __func__,
29069cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen		  padapter->pnetdev->name, wiphy_name(wiphy), name, type);
2907b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2908b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	switch (type) {
2909b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_ADHOC:
2910b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_AP_VLAN:
2911b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_WDS:
2912b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_MESH_POINT:
2913b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENODEV;
2914b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
2915b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_MONITOR:
2916b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret =
2917b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		    rtw_cfg80211_add_monitor_if(padapter, (char *)name, &ndev);
2918b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
2919b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2920b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_P2P_CLIENT:
2921b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_STATION:
2922b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENODEV;
2923b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
2924b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2925b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_P2P_GO:
2926b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	case NL80211_IFTYPE_AP:
2927b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENODEV;
2928b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
2929b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	default:
2930b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENODEV;
2931b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("Unsupported interface type\n");
2932b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		break;
2933b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2934b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
29359cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen	DBG_8723A("%s(%s): ndev:%p, ret:%d\n", __func__,
29369cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen		  padapter->pnetdev->name,
2937b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  ndev, ret);
2938b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2939b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ndev ? ndev->ieee80211_ptr : ERR_PTR(ret);
2940b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2941b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2942b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy,
2943b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					 struct wireless_dev *wdev)
2944b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2945b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_wdev_priv *pwdev_priv =
2946b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    (struct rtw_wdev_priv *)wiphy_priv(wiphy);
2947b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct net_device *ndev;
2948b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ndev = wdev ? wdev->netdev : NULL;
2949b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2950b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!ndev)
2951b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
2952b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2953b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	unregister_netdevice(ndev);
2954b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2955b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ndev == pwdev_priv->pmon_ndev) {
2956b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pwdev_priv->pmon_ndev = NULL;
2957b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pwdev_priv->ifname_mon[0] = '\0';
2958a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen		DBG_8723A("%s(%s): remove monitor interface\n",
2959a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen			  __func__, ndev->name);
2960b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
2961b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2962b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
2963b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
2964b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
2965b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2966b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int rtw_add_beacon(struct rtw_adapter *adapter, const u8 *head,
2967b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  size_t head_len, const u8 *tail, size_t tail_len)
2968b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
2969b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
2970b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 *pbuf = NULL;
2971b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	uint len, wps_ielen = 0;
2972b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
2973b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* struct sta_priv *pstapriv = &padapter->stapriv; */
2974b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2975b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s beacon_head_len =%zu, beacon_tail_len =%zu\n",
2976b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  __func__, head_len, tail_len);
2977b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2978b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
2979b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return -EINVAL;
2980b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2981b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (head_len < 24)
2982b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return -EINVAL;
2983b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2984b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pbuf = kzalloc(head_len + tail_len, GFP_KERNEL);
2985b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!pbuf)
2986b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return -ENOMEM;
2987b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/*  24 = beacon header len. */
2988b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy(pbuf, (void *)head + 24, head_len - 24);
2989b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy(pbuf + head_len - 24, (void *)tail, tail_len);
2990b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2991b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	len = head_len + tail_len - 24;
2992b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
2993b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* check wps ie if inclued */
2994d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen	if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
2995d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen				    WLAN_OUI_TYPE_MICROSOFT_WPS,
2996d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen				    pbuf + _FIXED_IE_LENGTH_,
2997d3797af488780e4f83d92ea0a3dc0a6381b566f3Jes Sorensen				    len - _FIXED_IE_LENGTH_))
2998b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("add bcn, wps_ielen =%d\n", wps_ielen);
2999b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3000b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* pbss_network->IEs will not include p2p_ie, wfd ie */
30019300c94b8a817f3b96cf00d2bdeed6751c2744d8Jes Sorensen	rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_,
30029300c94b8a817f3b96cf00d2bdeed6751c2744d8Jes Sorensen			     WLAN_EID_VENDOR_SPECIFIC, P2P_OUI23A, 4);
30039300c94b8a817f3b96cf00d2bdeed6751c2744d8Jes Sorensen	rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_,
30049300c94b8a817f3b96cf00d2bdeed6751c2744d8Jes Sorensen			     WLAN_EID_VENDOR_SPECIFIC, WFD_OUI23A, 4);
3005b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3006b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (rtw_check_beacon_data23a(adapter, pbuf, len) == _SUCCESS) {
3007b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = 0;
3008b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
3009b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EINVAL;
3010b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3011b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3012b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	kfree(pbuf);
3013b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3014b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
3015b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3016b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3017b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3018b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				 struct cfg80211_ap_settings *settings)
3019b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3020b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
3021b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *adapter = wiphy_to_adapter(wiphy);
3022b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3023a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s): hidden_ssid:%d, auth_type:%d\n",
3024a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen		  __func__, ndev->name, settings->hidden_ssid,
3025b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		  settings->auth_type);
3026b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3027b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ret = rtw_add_beacon(adapter, settings->beacon.head,
3028b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			     settings->beacon.head_len, settings->beacon.tail,
3029b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			     settings->beacon.tail_len);
3030b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3031b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	adapter->mlmeextpriv.mlmext_info.hidden_ssid_mode =
3032b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		settings->hidden_ssid;
3033b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3034b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (settings->ssid && settings->ssid_len) {
3035b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct wlan_bssid_ex *pbss_network =
3036b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			&adapter->mlmepriv.cur_network.network;
3037b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		struct wlan_bssid_ex *pbss_network_ext =
3038b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			&adapter->mlmeextpriv.mlmext_info.network;
3039b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3040b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(pbss_network->Ssid.ssid, (void *)settings->ssid,
3041b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		       settings->ssid_len);
3042b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pbss_network->Ssid.ssid_len = settings->ssid_len;
3043b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		memcpy(pbss_network_ext->Ssid.ssid, (void *)settings->ssid,
3044b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		       settings->ssid_len);
3045b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pbss_network_ext->Ssid.ssid_len = settings->ssid_len;
3046b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3047b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3048b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
3049b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3050b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3051b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_change_beacon(struct wiphy *wiphy,
3052b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				      struct net_device *ndev,
3053b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				      struct cfg80211_beacon_data *info)
3054b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3055b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
3056b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *adapter = wiphy_to_adapter(wiphy);
3057b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3058a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
3059b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3060b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ret = rtw_add_beacon(adapter, info->head, info->head_len, info->tail,
3061b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			     info->tail_len);
3062b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3063b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
3064b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3065b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3066b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
3067b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3068a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
3069b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
3070b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3071b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3072b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_add_station(struct wiphy *wiphy,
3073f9da455b93f6ba076935b4ef4589f61e529ae046Linus Torvalds				    struct net_device *ndev, const u8 *mac,
3074b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				    struct station_parameters *params)
3075b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3076a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
3077b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3078b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
3079b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3080b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3081b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_del_station(struct wiphy *wiphy,
3082f9da455b93f6ba076935b4ef4589f61e529ae046Linus Torvalds				    struct net_device *ndev, const u8 *mac)
3083b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3084b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
3085b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct list_head *phead, *plist, *ptmp;
3086b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 updated = 0;
3087b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct sta_info *psta;
3088b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter = netdev_priv(ndev);
3089b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
3090b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct sta_priv *pstapriv = &padapter->stapriv;
3091b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3092a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("+%s(%s)\n", __func__, ndev->name);
3093b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3094b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true) {
3095b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s, fw_state != FW_LINKED|WIFI_AP_STATE\n",
3096b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  __func__);
3097b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return -EINVAL;
3098b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3099b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3100b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!mac) {
3101b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("flush all sta, and cam_entry\n");
3102b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3103b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		flush_all_cam_entry23a(padapter);	/* clear CAM */
3104b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3105b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = rtw_sta_flush23a(padapter);
3106b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3107b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return ret;
3108b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3109b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3110b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("free sta macaddr =" MAC_FMT "\n", MAC_ARG(mac));
3111b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3112b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (is_broadcast_ether_addr(mac))
3113b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return -EINVAL;
3114b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3115b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_lock_bh(&pstapriv->asoc_list_lock);
3116b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3117b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	phead = &pstapriv->asoc_list;
3118b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3119b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* check asoc_queue */
3120b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	list_for_each_safe(plist, ptmp, phead) {
3121b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		psta = container_of(plist, struct sta_info, asoc_list);
3122b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3123cc2db7cb8de67cb172b90b72bf42c784b08959adJes Sorensen		if (ether_addr_equal(mac, psta->hwaddr)) {
3124b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			if (psta->dot8021xalg == 1 &&
3125b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			    psta->bpairwise_key_installed == false) {
3126b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				DBG_8723A("%s, sta's dot8021xalg = 1 and "
3127b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  "key_installed = false\n", __func__);
3128b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			} else {
3129b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				DBG_8723A("free psta =%p, aid =%d\n", psta,
3130b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					  psta->aid);
3131b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3132b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				list_del_init(&psta->asoc_list);
3133b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				pstapriv->asoc_list_cnt--;
3134b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3135b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				/* spin_unlock_bh(&pstapriv->asoc_list_lock); */
3136b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				updated =
3137b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				    ap_free_sta23a(padapter, psta, true,
3138b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						WLAN_REASON_DEAUTH_LEAVING);
3139b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				/* spin_lock_bh(&pstapriv->asoc_list_lock); */
3140b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3141b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				psta = NULL;
3142b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3143b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				break;
3144b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			}
3145b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		}
3146b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3147b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3148b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_unlock_bh(&pstapriv->asoc_list_lock);
3149b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3150b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	associated_clients_update23a(padapter, updated);
3151b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3152a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("-%s(%s)\n", __func__, ndev->name);
3153b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3154b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
3155b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3156b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3157b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_change_station(struct wiphy *wiphy,
3158f9da455b93f6ba076935b4ef4589f61e529ae046Linus Torvalds				       struct net_device *ndev, const u8 *mac,
3159b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       struct station_parameters *params)
3160b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3161a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
3162b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
3163b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3164b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3165b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_dump_station(struct wiphy *wiphy,
3166b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     struct net_device *ndev, int idx, u8 *mac,
3167b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				     struct station_info *sinfo)
3168b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3169a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
3170b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3171b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* TODO: dump scanned queue */
3172b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3173b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return -ENOENT;
3174b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3175b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3176b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev,
3177b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				   struct bss_parameters *params)
3178b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3179a790d58e6832262692416d41af99670b7aa1dca4Jes Sorensen	DBG_8723A("%s(%s)\n", __func__, ndev->name);
3180b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return 0;
3181b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3182b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#endif /* CONFIG_8723AU_AP_MODE */
3183b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3184b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int _cfg80211_rtw_mgmt_tx(struct rtw_adapter *padapter, u8 tx_ch,
3185b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				 const u8 *buf, size_t len)
3186b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3187b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct xmit_frame *pmgntframe;
3188b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct pkt_attrib *pattrib;
3189b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	unsigned char *pframe;
3190b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = _FAIL;
3191b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct ieee80211_hdr *pwlanhdr;
3192b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
3193b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
3194b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3195b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (_FAIL == rtw_pwr_wakeup(padapter)) {
3196b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -EFAULT;
3197b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
3198b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3199b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3200b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	rtw_set_scan_deny(padapter, 1000);
3201b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3202b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	rtw_scan_abort23a(padapter);
3203b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3204b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (tx_ch != rtw_get_oper_ch23a(padapter)) {
3205b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED))
3206b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			pmlmeext->cur_channel = tx_ch;
3207b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		set_channel_bwmode23a(padapter, tx_ch,
3208b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				   HAL_PRIME_CHNL_OFFSET_DONT_CARE,
3209b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				   HT_CHANNEL_WIDTH_20);
3210b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3211b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3212b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* starting alloc mgmt frame to dump it */
3213b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
3214de62f67a00286eb78d44762ce845b00742d79dd0Jes Sorensen	if (!pmgntframe) {
3215b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		/* ret = -ENOMEM; */
3216b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = _FAIL;
3217b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
3218b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3219b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3220b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* update attribute */
3221b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pattrib = &pmgntframe->attrib;
3222b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	update_mgntframe_attrib23a(padapter, pattrib);
3223b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pattrib->retry_ctrl = false;
3224b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3225b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
3226b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3227b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pframe = (u8 *) (pmgntframe->buf_addr) + TXDESC_OFFSET;
3228b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3229b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	memcpy(pframe, (void *)buf, len);
3230b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pattrib->pktlen = len;
3231b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3232b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwlanhdr = (struct ieee80211_hdr *)pframe;
3233b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* update seq number */
3234b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pmlmeext->mgnt_seq = le16_to_cpu(pwlanhdr->seq_ctrl) >> 4;
3235b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pattrib->seqnum = pmlmeext->mgnt_seq;
3236b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pmlmeext->mgnt_seq++;
3237b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3238b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pattrib->last_txcmdsz = pattrib->pktlen;
3239b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3240de62f67a00286eb78d44762ce845b00742d79dd0Jes Sorensen	ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe);
3241b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3242de62f67a00286eb78d44762ce845b00742d79dd0Jes Sorensen	if (ret  != _SUCCESS)
3243de62f67a00286eb78d44762ce845b00742d79dd0Jes Sorensen		DBG_8723A("%s, ack == false\n", __func__);
3244de62f67a00286eb78d44762ce845b00742d79dd0Jes Sorensen	else
3245de62f67a00286eb78d44762ce845b00742d79dd0Jes Sorensen		DBG_8723A("%s, ack == true\n", __func__);
3246b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3247b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
3248b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3249b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s, ret =%d\n", __func__, ret);
3250b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3251b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
3252b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3253b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3254b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3255b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				struct cfg80211_mgmt_tx_params *params,
3256b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				u64 *cookie)
3257b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3258b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_adapter *padapter =
3259b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		(struct rtw_adapter *)wiphy_to_adapter(wiphy);
3260b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
3261b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int tx_ret;
3262b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u32 dump_limit = RTW_MAX_MGMT_TX_CNT;
3263b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u32 dump_cnt = 0;
3264b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	bool ack = true;
3265b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 category, action;
3266b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	unsigned long start = jiffies;
3267b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	size_t len = params->len;
3268b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct ieee80211_channel *chan = params->chan;
3269b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	const u8 *buf = params->buf;
3270ea2ea44079784794838dc0ae953967990f8457d5Jes Sorensen	struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *)buf;
3271b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 tx_ch = (u8) ieee80211_frequency_to_channel(chan->center_freq);
3272b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3273ea2ea44079784794838dc0ae953967990f8457d5Jes Sorensen	if (!ieee80211_is_action(hdr->frame_control))
3274ea2ea44079784794838dc0ae953967990f8457d5Jes Sorensen		return -EINVAL;
3275ea2ea44079784794838dc0ae953967990f8457d5Jes Sorensen
3276b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* cookie generation */
3277b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	*cookie = (unsigned long)buf;
3278b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
32799cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen	DBG_8723A("%s(%s): len =%zu, ch =%d\n", __func__,
32809cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen		  padapter->pnetdev->name, len, tx_ch);
3281b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3282b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* indicate ack before issue frame to avoid racing with rsp frame */
328356b0bd91e0087e0b172aec022bdfb4fcd9de9194Jes Sorensen	cfg80211_mgmt_tx_status(padapter->rtw_wdev, *cookie, buf, len, ack,
328456b0bd91e0087e0b172aec022bdfb4fcd9de9194Jes Sorensen				GFP_KERNEL);
3285b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3286b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("RTW_Tx:tx_ch =%d, da =" MAC_FMT "\n", tx_ch,
3287ea2ea44079784794838dc0ae953967990f8457d5Jes Sorensen		  MAC_ARG(hdr->da));
3288ea2ea44079784794838dc0ae953967990f8457d5Jes Sorensen	category = hdr->u.action.category;
3289ea2ea44079784794838dc0ae953967990f8457d5Jes Sorensen	action = hdr->u.action.u.wme_action.action_code;
32902e74d336edb945b4a1f851e821001093e4094729Jes Sorensen	DBG_8723A("RTW_Tx:category(%u), action(%u)\n", category, action);
3291b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3292b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	do {
3293b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		dump_cnt++;
3294b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		tx_ret = _cfg80211_rtw_mgmt_tx(padapter, tx_ch, buf, len);
3295b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} while (dump_cnt < dump_limit && tx_ret != _SUCCESS);
3296b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3297b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (tx_ret != _SUCCESS || dump_cnt > 1) {
32989cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen		DBG_8723A("%s(%s): %s (%d/%d) in %d ms\n",
32999cd613c739ee436862e681acad8ded18ff85fd9aJes Sorensen			  __func__, padapter->pnetdev->name,
3300b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  tx_ret == _SUCCESS ? "OK" : "FAIL", dump_cnt,
3301b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			  dump_limit, jiffies_to_msecs(jiffies - start));
3302b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3303b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3304b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
3305b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3306b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3307b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy,
3308b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					     struct wireless_dev *wdev,
3309b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger					     u16 frame_type, bool reg)
3310b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3311b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
3312b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return;
3313b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3314b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return;
3315b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3316b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3317b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic struct cfg80211_ops rtw_cfg80211_ops = {
3318b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.change_virtual_intf = cfg80211_rtw_change_iface,
3319b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.add_key = cfg80211_rtw_add_key,
3320b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.get_key = cfg80211_rtw_get_key,
3321b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.del_key = cfg80211_rtw_del_key,
3322b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.set_default_key = cfg80211_rtw_set_default_key,
3323b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.get_station = cfg80211_rtw_get_station,
3324b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.scan = cfg80211_rtw_scan,
3325b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.set_wiphy_params = cfg80211_rtw_set_wiphy_params,
3326b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.connect = cfg80211_rtw_connect,
3327b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.disconnect = cfg80211_rtw_disconnect,
3328b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.join_ibss = cfg80211_rtw_join_ibss,
3329b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.leave_ibss = cfg80211_rtw_leave_ibss,
3330b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.set_tx_power = cfg80211_rtw_set_txpower,
3331b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.get_tx_power = cfg80211_rtw_get_txpower,
3332b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.set_power_mgmt = cfg80211_rtw_set_power_mgmt,
3333b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.set_pmksa = cfg80211_rtw_set_pmksa,
3334b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.del_pmksa = cfg80211_rtw_del_pmksa,
3335b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.flush_pmksa = cfg80211_rtw_flush_pmksa,
3336b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3337b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#ifdef CONFIG_8723AU_AP_MODE
3338b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.add_virtual_intf = cfg80211_rtw_add_virtual_intf,
3339b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.del_virtual_intf = cfg80211_rtw_del_virtual_intf,
3340b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3341b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.start_ap = cfg80211_rtw_start_ap,
3342b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.change_beacon = cfg80211_rtw_change_beacon,
3343b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.stop_ap = cfg80211_rtw_stop_ap,
3344b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3345b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.add_station = cfg80211_rtw_add_station,
3346b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.del_station = cfg80211_rtw_del_station,
3347b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.change_station = cfg80211_rtw_change_station,
3348b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.dump_station = cfg80211_rtw_dump_station,
3349b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.change_bss = cfg80211_rtw_change_bss,
3350b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#endif /* CONFIG_8723AU_AP_MODE */
3351b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3352b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.mgmt_tx = cfg80211_rtw_mgmt_tx,
3353b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	.mgmt_frame_register = cfg80211_rtw_mgmt_frame_register,
3354b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger};
3355b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3356b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap,
3357b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       enum ieee80211_band band, u8 rf_type)
3358b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3359b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3360b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define MAX_BIT_RATE_40MHZ_MCS15	300	/* Mbps */
3361b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#define MAX_BIT_RATE_40MHZ_MCS7		150	/* Mbps */
3362b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3363b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ht_cap->ht_supported = true;
3364b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3365b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
3366b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20 |
3367b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU;
3368b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3369b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/*
3370b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *Maximum length of AMPDU that the STA can receive.
3371b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
3372b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 */
3373b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
3374b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3375b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/*Minimum MPDU start spacing , */
3376b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
3377b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3378b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
3379b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3380b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/*
3381b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *hw->wiphy->bands[IEEE80211_BAND_2GHZ]
3382b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *base on ant_num
3383b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *rx_mask: RX mask
3384b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7
3385b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *if rx_ant = 2 rx_mask[1]= 0xff;==>MCS8-MCS15
3386b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *if rx_ant >= 3 rx_mask[2]= 0xff;
3387b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *if BW_40 rx_mask[4]= 0x01;
3388b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 *highest supported RX rate
3389b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 */
3390b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (rf_type == RF_1T1R) {
3391b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ht_cap->mcs.rx_mask[0] = 0xFF;
3392b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ht_cap->mcs.rx_mask[1] = 0x00;
3393b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ht_cap->mcs.rx_mask[4] = 0x01;
3394b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3395b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS7;
3396b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else if ((rf_type == RF_1T2R) || (rf_type == RF_2T2R)) {
3397b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ht_cap->mcs.rx_mask[0] = 0xFF;
3398b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ht_cap->mcs.rx_mask[1] = 0xFF;
3399b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ht_cap->mcs.rx_mask[4] = 0x01;
3400b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3401b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS15;
3402b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	} else {
3403b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s, error rf_type =%d\n", __func__, rf_type);
3404b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3405b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3406b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3407b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3408b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingervoid rtw_cfg80211_init_wiphy(struct rtw_adapter *padapter)
3409b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3410b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	u8 rf_type;
3411b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct ieee80211_supported_band *bands;
3412b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wireless_dev *pwdev = padapter->rtw_wdev;
3413b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wiphy *wiphy = pwdev->wiphy;
3414b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3415c2370e83ab5432e2d32e9c097930c69366d27b4cJes Sorensen	rf_type = rtl8723a_get_rf_type(padapter);
3416b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3417b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s:rf_type =%d\n", __func__, rf_type);
3418b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3419b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */
3420b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	{
3421b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		bands = wiphy->bands[IEEE80211_BAND_2GHZ];
3422b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (bands)
3423b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			rtw_cfg80211_init_ht_capab(&bands->ht_cap,
3424b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						   IEEE80211_BAND_2GHZ,
3425b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						   rf_type);
3426b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3427b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3428b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* if (padapter->registrypriv.wireless_mode & WIRELESS_11A) */
3429b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	{
3430b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		bands = wiphy->bands[IEEE80211_BAND_5GHZ];
3431b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		if (bands)
3432b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger			rtw_cfg80211_init_ht_capab(&bands->ht_cap,
3433b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						   IEEE80211_BAND_5GHZ,
3434b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger						   rf_type);
3435b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3436b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3437b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3438b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerstatic void rtw_cfg80211_preinit_wiphy(struct rtw_adapter *padapter,
3439b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger				       struct wiphy *wiphy)
3440b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3441b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
3442b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3443b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->max_scan_ssids = RTW_SSID_SCAN_AMOUNT;
3444b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
3445b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->max_num_pmkids = RTW_MAX_NUM_PMKIDS;
3446b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3447b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->max_remain_on_channel_duration =
3448b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    RTW_MAX_REMAIN_ON_CHANNEL_DURATION;
3449b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3450b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3451b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    BIT(NL80211_IFTYPE_ADHOC) |
3452b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#ifdef CONFIG_8723AU_AP_MODE
3453b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR) |
3454b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#endif
3455b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    0;
3456b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3457b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#ifdef CONFIG_8723AU_AP_MODE
3458b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->mgmt_stypes = rtw_cfg80211_default_mgmt_stypes;
3459b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger#endif /* CONFIG_8723AU_AP_MODE */
3460b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3461b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
3462b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3463b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/*
3464b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	   wiphy->iface_combinations = &rtw_combinations;
3465b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	   wiphy->n_iface_combinations = 1;
3466b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	 */
3467b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3468b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->cipher_suites = rtw_cipher_suites;
3469b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->n_cipher_suites = ARRAY_SIZE(rtw_cipher_suites);
3470b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3471b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */
3472b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->bands[IEEE80211_BAND_2GHZ] =
3473b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    rtw_spt_band_alloc(IEEE80211_BAND_2GHZ);
3474b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* if (padapter->registrypriv.wireless_mode & WIRELESS_11A) */
3475b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->bands[IEEE80211_BAND_5GHZ] =
3476b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	    rtw_spt_band_alloc(IEEE80211_BAND_5GHZ);
3477b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3478b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
3479b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX | WIPHY_FLAG_HAVE_AP_SME;
3480b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3481b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE)
3482b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
3483b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	else
3484b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
3485b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3486b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3487b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerint rtw_wdev_alloc(struct rtw_adapter *padapter, struct device *dev)
3488b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3489b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	int ret = 0;
3490b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wiphy *wiphy;
3491b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct wireless_dev *wdev;
3492b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_wdev_priv *pwdev_priv;
3493b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct net_device *pnetdev = padapter->pnetdev;
3494b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3495b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s(padapter =%p)\n", __func__, padapter);
3496b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3497b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* wiphy */
3498b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy = wiphy_new(&rtw_cfg80211_ops, sizeof(struct rtw_wdev_priv));
3499b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!wiphy) {
3500b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("Couldn't allocate wiphy device\n");
3501b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		ret = -ENOMEM;
3502b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		goto exit;
3503b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3504d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen
3505d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen	/*  wdev */
3506d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen	wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
3507d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen	if (!wdev) {
3508d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen		DBG_8723A("Couldn't allocate wireless device\n");
3509d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen		ret = -ENOMEM;
3510d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen		goto free_wiphy;
3511d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen	}
3512d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen
3513b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	set_wiphy_dev(wiphy, dev);
3514b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	rtw_cfg80211_preinit_wiphy(padapter, wiphy);
3515b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3516b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	ret = wiphy_register(wiphy);
3517b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (ret < 0) {
3518b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("Couldn't register wiphy device\n");
3519d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen		goto free_wdev;
3520b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3521b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3522b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wdev->wiphy = wiphy;
3523b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wdev->netdev = pnetdev;
3524b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* wdev->iftype = NL80211_IFTYPE_STATION; */
3525b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/*  for rtw_setopmode_cmd23a() in cfg80211_rtw_change_iface() */
3526b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wdev->iftype = NL80211_IFTYPE_MONITOR;
3527b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	padapter->rtw_wdev = wdev;
3528b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pnetdev->ieee80211_ptr = wdev;
3529b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3530b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	/* init pwdev_priv */
3531b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwdev_priv = wdev_to_priv(wdev);
3532b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwdev_priv->rtw_wdev = wdev;
3533b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwdev_priv->pmon_ndev = NULL;
3534b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwdev_priv->ifname_mon[0] = '\0';
3535b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwdev_priv->padapter = padapter;
3536b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwdev_priv->scan_request = NULL;
3537b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	spin_lock_init(&pwdev_priv->scan_req_lock);
3538b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3539b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwdev_priv->p2p_enabled = false;
3540b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3541b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE)
3542b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pwdev_priv->power_mgmt = true;
3543b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	else
3544b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		pwdev_priv->power_mgmt = false;
3545b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3546b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
3547d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensenfree_wdev:
3548d165e4efbc6d76cff51abb523567a840cb6623b9Jes Sorensen	kfree(wdev);
3549b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerfree_wiphy:
3550b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy_free(wiphy);
3551b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingerexit:
3552b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	return ret;
3553b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3554b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3555b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingervoid rtw_wdev_free(struct wireless_dev *wdev)
3556b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3557b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s(wdev =%p)\n", __func__, wdev);
3558b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3559b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!wdev)
3560b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return;
3561b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3562b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	kfree(wdev->wiphy->bands[IEEE80211_BAND_2GHZ]);
3563b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	kfree(wdev->wiphy->bands[IEEE80211_BAND_5GHZ]);
3564b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3565b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy_free(wdev->wiphy);
3566b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3567b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	kfree(wdev);
3568b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3569b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3570b1925ad84625302fac456d8671b2acafcabf57f5Larry Fingervoid rtw_wdev_unregister(struct wireless_dev *wdev)
3571b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger{
3572b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	struct rtw_wdev_priv *pwdev_priv;
3573b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3574b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	DBG_8723A("%s(wdev =%p)\n", __func__, wdev);
3575b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3576b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (!wdev)
3577b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		return;
3578b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3579b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	pwdev_priv = wdev_to_priv(wdev);
3580b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3581b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	rtw_cfg80211_indicate_scan_done(pwdev_priv, true);
3582b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3583b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	if (pwdev_priv->pmon_ndev) {
3584b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		DBG_8723A("%s, unregister monitor interface\n", __func__);
3585b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger		unregister_netdev(pwdev_priv->pmon_ndev);
3586b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	}
3587b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger
3588b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger	wiphy_unregister(wdev->wiphy);
3589b1925ad84625302fac456d8671b2acafcabf57f5Larry Finger}
3590