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