diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2014-03-28 22:37:40 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-04-05 17:51:23 -0400 |
commit | b1925ad84625302fac456d8671b2acafcabf57f5 (patch) | |
tree | dc29690f13d2220eeb2262874b43e8a039a58168 | |
parent | f7c92d2cc2beb3367f244480300eaecdd9502932 (diff) |
staging: r8723au: Add source files for new driver - part 3
The Realtek USB device RTL8723AU is found in Lenovo Yoga 13 tablets.
A driver for it has been available in a GitHub repo for several months.
This commit contains the third part of source files. The source
is arbitrarily split to avoid E-mail files that are too large.
Jes Sorensen at RedHat has made many improvements to the vendor code,
and he has been doing the testing. I do not have access to this device.
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Jes Sorensen <Jes.Sorensen@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c | 4501 | ||||
-rw-r--r-- | drivers/staging/rtl8723au/os_dep/mlme_linux.c | 187 | ||||
-rw-r--r-- | drivers/staging/rtl8723au/os_dep/os_intfs.c | 970 | ||||
-rw-r--r-- | drivers/staging/rtl8723au/os_dep/osdep_service.c | 429 | ||||
-rw-r--r-- | drivers/staging/rtl8723au/os_dep/recv_linux.c | 225 | ||||
-rw-r--r-- | drivers/staging/rtl8723au/os_dep/usb_intf.c | 836 | ||||
-rw-r--r-- | drivers/staging/rtl8723au/os_dep/usb_ops_linux.c | 283 | ||||
-rw-r--r-- | drivers/staging/rtl8723au/os_dep/xmit_linux.c | 195 |
8 files changed, 7626 insertions, 0 deletions
diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c new file mode 100644 index 000000000000..1c99616f51ac --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c | |||
@@ -0,0 +1,4501 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | ******************************************************************************/ | ||
15 | #define _IOCTL_CFG80211_C_ | ||
16 | |||
17 | #include <osdep_service.h> | ||
18 | #include <drv_types.h> | ||
19 | #include <rtw_ioctl_set.h> | ||
20 | #include <xmit_osdep.h> | ||
21 | |||
22 | #include "ioctl_cfg80211.h" | ||
23 | #include <linux/version.h> | ||
24 | |||
25 | #define RTW_MAX_MGMT_TX_CNT 8 | ||
26 | |||
27 | #define RTW_MAX_REMAIN_ON_CHANNEL_DURATION 65535 /* ms */ | ||
28 | #define RTW_MAX_NUM_PMKIDS 4 | ||
29 | |||
30 | #define RTW_CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ | ||
31 | |||
32 | static const u32 rtw_cipher_suites[] = { | ||
33 | WLAN_CIPHER_SUITE_WEP40, | ||
34 | WLAN_CIPHER_SUITE_WEP104, | ||
35 | WLAN_CIPHER_SUITE_TKIP, | ||
36 | WLAN_CIPHER_SUITE_CCMP, | ||
37 | }; | ||
38 | |||
39 | #define RATETAB_ENT(_rate, _rateid, _flags) { \ | ||
40 | .bitrate = (_rate), \ | ||
41 | .hw_value = (_rateid), \ | ||
42 | .flags = (_flags), \ | ||
43 | } | ||
44 | |||
45 | #define CHAN2G(_channel, _freq, _flags) { \ | ||
46 | .band = IEEE80211_BAND_2GHZ, \ | ||
47 | .center_freq = (_freq), \ | ||
48 | .hw_value = (_channel), \ | ||
49 | .flags = (_flags), \ | ||
50 | .max_antenna_gain = 0, \ | ||
51 | .max_power = 30, \ | ||
52 | } | ||
53 | |||
54 | #define CHAN5G(_channel, _flags) { \ | ||
55 | .band = IEEE80211_BAND_5GHZ, \ | ||
56 | .center_freq = 5000 + (5 * (_channel)), \ | ||
57 | .hw_value = (_channel), \ | ||
58 | .flags = (_flags), \ | ||
59 | .max_antenna_gain = 0, \ | ||
60 | .max_power = 30, \ | ||
61 | } | ||
62 | |||
63 | static struct ieee80211_rate rtw_rates[] = { | ||
64 | RATETAB_ENT(10, 0x1, 0), | ||
65 | RATETAB_ENT(20, 0x2, 0), | ||
66 | RATETAB_ENT(55, 0x4, 0), | ||
67 | RATETAB_ENT(110, 0x8, 0), | ||
68 | RATETAB_ENT(60, 0x10, 0), | ||
69 | RATETAB_ENT(90, 0x20, 0), | ||
70 | RATETAB_ENT(120, 0x40, 0), | ||
71 | RATETAB_ENT(180, 0x80, 0), | ||
72 | RATETAB_ENT(240, 0x100, 0), | ||
73 | RATETAB_ENT(360, 0x200, 0), | ||
74 | RATETAB_ENT(480, 0x400, 0), | ||
75 | RATETAB_ENT(540, 0x800, 0), | ||
76 | }; | ||
77 | |||
78 | #define rtw_a_rates (rtw_rates + 4) | ||
79 | #define RTW_A_RATES_NUM 8 | ||
80 | #define rtw_g_rates (rtw_rates + 0) | ||
81 | #define RTW_G_RATES_NUM 12 | ||
82 | |||
83 | #define RTW_2G_CHANNELS_NUM 14 | ||
84 | #define RTW_5G_CHANNELS_NUM 37 | ||
85 | |||
86 | static struct ieee80211_channel rtw_2ghz_channels[] = { | ||
87 | CHAN2G(1, 2412, 0), | ||
88 | CHAN2G(2, 2417, 0), | ||
89 | CHAN2G(3, 2422, 0), | ||
90 | CHAN2G(4, 2427, 0), | ||
91 | CHAN2G(5, 2432, 0), | ||
92 | CHAN2G(6, 2437, 0), | ||
93 | CHAN2G(7, 2442, 0), | ||
94 | CHAN2G(8, 2447, 0), | ||
95 | CHAN2G(9, 2452, 0), | ||
96 | CHAN2G(10, 2457, 0), | ||
97 | CHAN2G(11, 2462, 0), | ||
98 | CHAN2G(12, 2467, 0), | ||
99 | CHAN2G(13, 2472, 0), | ||
100 | CHAN2G(14, 2484, 0), | ||
101 | }; | ||
102 | |||
103 | static struct ieee80211_channel rtw_5ghz_a_channels[] = { | ||
104 | CHAN5G(34, 0), CHAN5G(36, 0), | ||
105 | CHAN5G(38, 0), CHAN5G(40, 0), | ||
106 | CHAN5G(42, 0), CHAN5G(44, 0), | ||
107 | CHAN5G(46, 0), CHAN5G(48, 0), | ||
108 | CHAN5G(52, 0), CHAN5G(56, 0), | ||
109 | CHAN5G(60, 0), CHAN5G(64, 0), | ||
110 | CHAN5G(100, 0), CHAN5G(104, 0), | ||
111 | CHAN5G(108, 0), CHAN5G(112, 0), | ||
112 | CHAN5G(116, 0), CHAN5G(120, 0), | ||
113 | CHAN5G(124, 0), CHAN5G(128, 0), | ||
114 | CHAN5G(132, 0), CHAN5G(136, 0), | ||
115 | CHAN5G(140, 0), CHAN5G(149, 0), | ||
116 | CHAN5G(153, 0), CHAN5G(157, 0), | ||
117 | CHAN5G(161, 0), CHAN5G(165, 0), | ||
118 | CHAN5G(184, 0), CHAN5G(188, 0), | ||
119 | CHAN5G(192, 0), CHAN5G(196, 0), | ||
120 | CHAN5G(200, 0), CHAN5G(204, 0), | ||
121 | CHAN5G(208, 0), CHAN5G(212, 0), | ||
122 | CHAN5G(216, 0), | ||
123 | }; | ||
124 | |||
125 | static void rtw_2g_channels_init(struct ieee80211_channel *channels) | ||
126 | { | ||
127 | memcpy((void *)channels, (void *)rtw_2ghz_channels, | ||
128 | sizeof(struct ieee80211_channel) * RTW_2G_CHANNELS_NUM); | ||
129 | } | ||
130 | |||
131 | static void rtw_5g_channels_init(struct ieee80211_channel *channels) | ||
132 | { | ||
133 | memcpy((void *)channels, (void *)rtw_5ghz_a_channels, | ||
134 | sizeof(struct ieee80211_channel) * RTW_5G_CHANNELS_NUM); | ||
135 | } | ||
136 | |||
137 | static void rtw_2g_rates_init(struct ieee80211_rate *rates) | ||
138 | { | ||
139 | memcpy(rates, rtw_g_rates, | ||
140 | sizeof(struct ieee80211_rate) * RTW_G_RATES_NUM); | ||
141 | } | ||
142 | |||
143 | static void rtw_5g_rates_init(struct ieee80211_rate *rates) | ||
144 | { | ||
145 | memcpy(rates, rtw_a_rates, | ||
146 | sizeof(struct ieee80211_rate) * RTW_A_RATES_NUM); | ||
147 | } | ||
148 | |||
149 | static struct ieee80211_supported_band * | ||
150 | rtw_spt_band_alloc(enum ieee80211_band band) | ||
151 | { | ||
152 | struct ieee80211_supported_band *spt_band = NULL; | ||
153 | int n_channels, n_bitrates; | ||
154 | |||
155 | if (band == IEEE80211_BAND_2GHZ) { | ||
156 | n_channels = RTW_2G_CHANNELS_NUM; | ||
157 | n_bitrates = RTW_G_RATES_NUM; | ||
158 | } else if (band == IEEE80211_BAND_5GHZ) { | ||
159 | n_channels = RTW_5G_CHANNELS_NUM; | ||
160 | n_bitrates = RTW_A_RATES_NUM; | ||
161 | } else { | ||
162 | goto exit; | ||
163 | } | ||
164 | spt_band = kzalloc(sizeof(struct ieee80211_supported_band) + | ||
165 | sizeof(struct ieee80211_channel) * n_channels + | ||
166 | sizeof(struct ieee80211_rate) * n_bitrates, | ||
167 | GFP_KERNEL); | ||
168 | if (!spt_band) | ||
169 | goto exit; | ||
170 | |||
171 | spt_band->channels = | ||
172 | (struct ieee80211_channel *)(((u8 *) spt_band) + | ||
173 | sizeof(struct | ||
174 | ieee80211_supported_band)); | ||
175 | spt_band->bitrates = | ||
176 | (struct ieee80211_rate *)(((u8 *) spt_band->channels) + | ||
177 | sizeof(struct ieee80211_channel) * | ||
178 | n_channels); | ||
179 | spt_band->band = band; | ||
180 | spt_band->n_channels = n_channels; | ||
181 | spt_band->n_bitrates = n_bitrates; | ||
182 | |||
183 | if (band == IEEE80211_BAND_2GHZ) { | ||
184 | rtw_2g_channels_init(spt_band->channels); | ||
185 | rtw_2g_rates_init(spt_band->bitrates); | ||
186 | } else if (band == IEEE80211_BAND_5GHZ) { | ||
187 | rtw_5g_channels_init(spt_band->channels); | ||
188 | rtw_5g_rates_init(spt_band->bitrates); | ||
189 | } | ||
190 | |||
191 | /* spt_band.ht_cap */ | ||
192 | |||
193 | exit: | ||
194 | return spt_band; | ||
195 | } | ||
196 | |||
197 | static const struct ieee80211_txrx_stypes | ||
198 | rtw_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | ||
199 | [NL80211_IFTYPE_ADHOC] = { | ||
200 | .tx = 0xffff, | ||
201 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ||
202 | }, | ||
203 | [NL80211_IFTYPE_STATION] = { | ||
204 | .tx = 0xffff, | ||
205 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
206 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
207 | }, | ||
208 | [NL80211_IFTYPE_AP] = { | ||
209 | .tx = 0xffff, | ||
210 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
211 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
212 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
213 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
214 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
215 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
216 | BIT(IEEE80211_STYPE_ACTION >> 4) | ||
217 | }, | ||
218 | [NL80211_IFTYPE_AP_VLAN] = { | ||
219 | /* copy AP */ | ||
220 | .tx = 0xffff, | ||
221 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
222 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
223 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
224 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
225 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
226 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
227 | BIT(IEEE80211_STYPE_ACTION >> 4) | ||
228 | }, | ||
229 | [NL80211_IFTYPE_P2P_CLIENT] = { | ||
230 | .tx = 0xffff, | ||
231 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
232 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
233 | }, | ||
234 | [NL80211_IFTYPE_P2P_GO] = { | ||
235 | .tx = 0xffff, | ||
236 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
237 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
238 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
239 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
240 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
241 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
242 | BIT(IEEE80211_STYPE_ACTION >> 4) | ||
243 | }, | ||
244 | }; | ||
245 | |||
246 | #define MAX_BSSINFO_LEN 1000 | ||
247 | static int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter, | ||
248 | struct wlan_network *pnetwork) | ||
249 | { | ||
250 | int ret = 0; | ||
251 | struct ieee80211_channel *notify_channel; | ||
252 | struct cfg80211_bss *bss; | ||
253 | /* struct ieee80211_supported_band *band; */ | ||
254 | u16 channel; | ||
255 | u32 freq; | ||
256 | u64 notify_timestamp; | ||
257 | u16 notify_capability; | ||
258 | u16 notify_interval; | ||
259 | u8 *notify_ie; | ||
260 | size_t notify_ielen; | ||
261 | s32 notify_signal; | ||
262 | u8 buf[MAX_BSSINFO_LEN], *pbuf; | ||
263 | size_t len, bssinf_len = 0; | ||
264 | struct ieee80211_hdr *pwlanhdr; | ||
265 | unsigned short *fctrl; | ||
266 | u8 bc_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
267 | |||
268 | struct wireless_dev *wdev = padapter->rtw_wdev; | ||
269 | struct wiphy *wiphy = wdev->wiphy; | ||
270 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
271 | |||
272 | /* DBG_8723A("%s\n", __func__); */ | ||
273 | |||
274 | bssinf_len = | ||
275 | pnetwork->network.IELength + sizeof(struct ieee80211_hdr_3addr); | ||
276 | if (bssinf_len > MAX_BSSINFO_LEN) { | ||
277 | DBG_8723A("%s IE Length too long > %d byte\n", __func__, | ||
278 | MAX_BSSINFO_LEN); | ||
279 | goto exit; | ||
280 | } | ||
281 | |||
282 | channel = pnetwork->network.Configuration.DSConfig; | ||
283 | if (channel <= RTW_CH_MAX_2G_CHANNEL) | ||
284 | freq = ieee80211_channel_to_frequency(channel, | ||
285 | IEEE80211_BAND_2GHZ); | ||
286 | else | ||
287 | freq = ieee80211_channel_to_frequency(channel, | ||
288 | IEEE80211_BAND_5GHZ); | ||
289 | |||
290 | notify_channel = ieee80211_get_channel(wiphy, freq); | ||
291 | |||
292 | /* rtw_get_timestampe_from_ie23a() */ | ||
293 | notify_timestamp = jiffies_to_msecs(jiffies) * 1000; /* uSec */ | ||
294 | |||
295 | notify_interval = | ||
296 | le16_to_cpu(*(u16 *) | ||
297 | rtw_get_beacon_interval23a_from_ie(pnetwork->network.IEs)); | ||
298 | notify_capability = | ||
299 | le16_to_cpu(*(u16 *) | ||
300 | rtw_get_capability23a_from_ie(pnetwork->network.IEs)); | ||
301 | |||
302 | notify_ie = pnetwork->network.IEs + _FIXED_IE_LENGTH_; | ||
303 | notify_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_; | ||
304 | |||
305 | /* We've set wiphy's signal_type as CFG80211_SIGNAL_TYPE_MBM: | ||
306 | * signal strength in mBm (100*dBm) | ||
307 | */ | ||
308 | if (check_fwstate(pmlmepriv, _FW_LINKED) && | ||
309 | is_same_network23a(&pmlmepriv->cur_network.network, | ||
310 | &pnetwork->network)) { | ||
311 | notify_signal = 100 * translate_percentage_to_dbm(padapter->recvpriv.signal_strength); /* dbm */ | ||
312 | } else { | ||
313 | notify_signal = 100 * translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength); /* dbm */ | ||
314 | } | ||
315 | pbuf = buf; | ||
316 | |||
317 | pwlanhdr = (struct ieee80211_hdr *)pbuf; | ||
318 | fctrl = &pwlanhdr->frame_control; | ||
319 | *(fctrl) = 0; | ||
320 | |||
321 | SetSeqNum(pwlanhdr, 0); | ||
322 | |||
323 | if (pnetwork->network.reserved == 1) { /* WIFI_BEACON */ | ||
324 | memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); | ||
325 | SetFrameSubType(pbuf, WIFI_BEACON); | ||
326 | } else { | ||
327 | memcpy(pwlanhdr->addr1, myid(&padapter->eeprompriv), ETH_ALEN); | ||
328 | SetFrameSubType(pbuf, WIFI_PROBERSP); | ||
329 | } | ||
330 | |||
331 | memcpy(pwlanhdr->addr2, pnetwork->network.MacAddress, ETH_ALEN); | ||
332 | memcpy(pwlanhdr->addr3, pnetwork->network.MacAddress, ETH_ALEN); | ||
333 | |||
334 | pbuf += sizeof(struct ieee80211_hdr_3addr); | ||
335 | len = sizeof(struct ieee80211_hdr_3addr); | ||
336 | |||
337 | memcpy(pbuf, pnetwork->network.IEs, pnetwork->network.IELength); | ||
338 | len += pnetwork->network.IELength; | ||
339 | |||
340 | bss = cfg80211_inform_bss_frame(wiphy, notify_channel, | ||
341 | (struct ieee80211_mgmt *)buf, len, | ||
342 | notify_signal, GFP_ATOMIC); | ||
343 | |||
344 | if (unlikely(!bss)) { | ||
345 | DBG_8723A("rtw_cfg80211_inform_bss error\n"); | ||
346 | return -EINVAL; | ||
347 | } | ||
348 | |||
349 | cfg80211_put_bss(wiphy, bss); | ||
350 | |||
351 | exit: | ||
352 | return ret; | ||
353 | } | ||
354 | |||
355 | void rtw_cfg80211_indicate_connect(struct rtw_adapter *padapter) | ||
356 | { | ||
357 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
358 | struct wlan_network *cur_network = &pmlmepriv->cur_network; | ||
359 | struct wireless_dev *pwdev = padapter->rtw_wdev; | ||
360 | #ifdef CONFIG_8723AU_P2P | ||
361 | struct wifidirect_info *pwdinfo = &padapter->wdinfo; | ||
362 | #endif | ||
363 | |||
364 | DBG_8723A("%s(padapter =%p)\n", __func__, padapter); | ||
365 | |||
366 | if (pwdev->iftype != NL80211_IFTYPE_STATION && | ||
367 | pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT) | ||
368 | return; | ||
369 | |||
370 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) | ||
371 | return; | ||
372 | |||
373 | #ifdef CONFIG_8723AU_P2P | ||
374 | if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { | ||
375 | rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); | ||
376 | rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); | ||
377 | rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); | ||
378 | DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =%d\n", | ||
379 | __func__, rtw_p2p_role(pwdinfo), | ||
380 | rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo)); | ||
381 | } | ||
382 | #endif /* CONFIG_8723AU_P2P */ | ||
383 | |||
384 | if (rtw_to_roaming(padapter) > 0) { | ||
385 | struct wiphy *wiphy = pwdev->wiphy; | ||
386 | struct ieee80211_channel *notify_channel; | ||
387 | u32 freq; | ||
388 | u16 channel = cur_network->network.Configuration.DSConfig; | ||
389 | |||
390 | if (channel <= RTW_CH_MAX_2G_CHANNEL) | ||
391 | freq = | ||
392 | ieee80211_channel_to_frequency(channel, | ||
393 | IEEE80211_BAND_2GHZ); | ||
394 | else | ||
395 | freq = | ||
396 | ieee80211_channel_to_frequency(channel, | ||
397 | IEEE80211_BAND_5GHZ); | ||
398 | |||
399 | notify_channel = ieee80211_get_channel(wiphy, freq); | ||
400 | |||
401 | DBG_8723A("%s call cfg80211_roamed\n", __func__); | ||
402 | cfg80211_roamed(padapter->pnetdev, notify_channel, | ||
403 | cur_network->network.MacAddress, | ||
404 | pmlmepriv->assoc_req + | ||
405 | sizeof(struct ieee80211_hdr_3addr) + 2, | ||
406 | pmlmepriv->assoc_req_len - | ||
407 | sizeof(struct ieee80211_hdr_3addr) - 2, | ||
408 | pmlmepriv->assoc_rsp + | ||
409 | sizeof(struct ieee80211_hdr_3addr) + 6, | ||
410 | pmlmepriv->assoc_rsp_len - | ||
411 | sizeof(struct ieee80211_hdr_3addr) - 6, | ||
412 | GFP_ATOMIC); | ||
413 | } else { | ||
414 | cfg80211_connect_result(padapter->pnetdev, | ||
415 | cur_network->network.MacAddress, | ||
416 | pmlmepriv->assoc_req + | ||
417 | sizeof(struct ieee80211_hdr_3addr) + 2, | ||
418 | pmlmepriv->assoc_req_len - | ||
419 | sizeof(struct ieee80211_hdr_3addr) - 2, | ||
420 | pmlmepriv->assoc_rsp + | ||
421 | sizeof(struct ieee80211_hdr_3addr) + 6, | ||
422 | pmlmepriv->assoc_rsp_len - | ||
423 | sizeof(struct ieee80211_hdr_3addr) - 6, | ||
424 | WLAN_STATUS_SUCCESS, GFP_ATOMIC); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter) | ||
429 | { | ||
430 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
431 | struct wireless_dev *pwdev = padapter->rtw_wdev; | ||
432 | #ifdef CONFIG_8723AU_P2P | ||
433 | struct wifidirect_info *pwdinfo = &padapter->wdinfo; | ||
434 | #endif | ||
435 | |||
436 | DBG_8723A("%s(padapter =%p)\n", __func__, padapter); | ||
437 | |||
438 | if (pwdev->iftype != NL80211_IFTYPE_STATION && | ||
439 | pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT) | ||
440 | return; | ||
441 | |||
442 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) | ||
443 | return; | ||
444 | |||
445 | #ifdef CONFIG_8723AU_P2P | ||
446 | if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { | ||
447 | del_timer_sync(&pwdinfo->find_phase_timer); | ||
448 | del_timer_sync(&pwdinfo->restore_p2p_state_timer); | ||
449 | del_timer_sync(&pwdinfo->pre_tx_scan_timer); | ||
450 | |||
451 | rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); | ||
452 | rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); | ||
453 | |||
454 | DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =%d\n", | ||
455 | __func__, rtw_p2p_role(pwdinfo), | ||
456 | rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo)); | ||
457 | } | ||
458 | #endif /* CONFIG_8723AU_P2P */ | ||
459 | |||
460 | if (!padapter->mlmepriv.not_indic_disco) { | ||
461 | if (check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING)) { | ||
462 | cfg80211_connect_result(padapter->pnetdev, NULL, NULL, | ||
463 | 0, NULL, 0, | ||
464 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
465 | GFP_ATOMIC); | ||
466 | } else { | ||
467 | cfg80211_disconnected(padapter->pnetdev, 0, NULL, | ||
468 | 0, GFP_ATOMIC); | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | |||
473 | #ifdef CONFIG_8723AU_AP_MODE | ||
474 | static u8 set_pairwise_key(struct rtw_adapter *padapter, struct sta_info *psta) | ||
475 | { | ||
476 | struct cmd_obj *ph2c; | ||
477 | struct set_stakey_parm *psetstakey_para; | ||
478 | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; | ||
479 | u8 res = _SUCCESS; | ||
480 | |||
481 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | ||
482 | if (ph2c == NULL) { | ||
483 | res = _FAIL; | ||
484 | goto exit; | ||
485 | } | ||
486 | |||
487 | psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL); | ||
488 | if (psetstakey_para == NULL) { | ||
489 | kfree(ph2c); | ||
490 | res = _FAIL; | ||
491 | goto exit; | ||
492 | } | ||
493 | |||
494 | init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); | ||
495 | |||
496 | psetstakey_para->algorithm = (u8) psta->dot118021XPrivacy; | ||
497 | |||
498 | memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN); | ||
499 | |||
500 | memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16); | ||
501 | |||
502 | res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); | ||
503 | |||
504 | exit: | ||
505 | return res; | ||
506 | } | ||
507 | |||
508 | static int set_group_key(struct rtw_adapter *padapter, u8 *key, u8 alg, | ||
509 | int keyid) | ||
510 | { | ||
511 | u8 keylen; | ||
512 | struct cmd_obj *pcmd; | ||
513 | struct setkey_parm *psetkeyparm; | ||
514 | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; | ||
515 | int res = _SUCCESS; | ||
516 | |||
517 | DBG_8723A("%s\n", __func__); | ||
518 | |||
519 | pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | ||
520 | if (!pcmd) { | ||
521 | res = _FAIL; | ||
522 | goto exit; | ||
523 | } | ||
524 | psetkeyparm = kzalloc(sizeof(struct setkey_parm), GFP_KERNEL); | ||
525 | if (!psetkeyparm) { | ||
526 | kfree(pcmd); | ||
527 | res = _FAIL; | ||
528 | goto exit; | ||
529 | } | ||
530 | |||
531 | psetkeyparm->keyid = (u8) keyid; | ||
532 | if (is_wep_enc(alg)) | ||
533 | padapter->mlmepriv.key_mask |= CHKBIT(psetkeyparm->keyid); | ||
534 | |||
535 | psetkeyparm->algorithm = alg; | ||
536 | |||
537 | psetkeyparm->set_tx = 1; | ||
538 | |||
539 | switch (alg) { | ||
540 | case _WEP40_: | ||
541 | keylen = 5; | ||
542 | break; | ||
543 | case _WEP104_: | ||
544 | keylen = 13; | ||
545 | break; | ||
546 | case _TKIP_: | ||
547 | case _TKIP_WTMIC_: | ||
548 | case _AES_: | ||
549 | default: | ||
550 | keylen = 16; | ||
551 | } | ||
552 | |||
553 | memcpy(&psetkeyparm->key[0], key, keylen); | ||
554 | |||
555 | pcmd->cmdcode = _SetKey_CMD_; | ||
556 | pcmd->parmbuf = (u8 *) psetkeyparm; | ||
557 | pcmd->cmdsz = (sizeof(struct setkey_parm)); | ||
558 | pcmd->rsp = NULL; | ||
559 | pcmd->rspsz = 0; | ||
560 | |||
561 | INIT_LIST_HEAD(&pcmd->list); | ||
562 | |||
563 | res = rtw_enqueue_cmd23a(pcmdpriv, pcmd); | ||
564 | |||
565 | exit: | ||
566 | return res; | ||
567 | } | ||
568 | |||
569 | static int set_wep_key(struct rtw_adapter *padapter, u8 *key, u8 keylen, | ||
570 | int keyid) | ||
571 | { | ||
572 | u8 alg; | ||
573 | |||
574 | switch (keylen) { | ||
575 | case 5: | ||
576 | alg = _WEP40_; | ||
577 | break; | ||
578 | case 13: | ||
579 | alg = _WEP104_; | ||
580 | break; | ||
581 | default: | ||
582 | alg = _NO_PRIVACY_; | ||
583 | } | ||
584 | |||
585 | return set_group_key(padapter, key, alg, keyid); | ||
586 | } | ||
587 | |||
588 | static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, | ||
589 | struct ieee_param *param, | ||
590 | u32 param_len) | ||
591 | { | ||
592 | int ret = 0; | ||
593 | u32 wep_key_idx, wep_key_len; | ||
594 | struct sta_info *psta = NULL, *pbcmc_sta = NULL; | ||
595 | struct rtw_adapter *padapter = netdev_priv(dev); | ||
596 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
597 | struct security_priv *psecuritypriv = &padapter->securitypriv; | ||
598 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
599 | |||
600 | DBG_8723A("%s\n", __func__); | ||
601 | |||
602 | param->u.crypt.err = 0; | ||
603 | param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; | ||
604 | |||
605 | /* sizeof(struct ieee_param) = 64 bytes; */ | ||
606 | /* if (param_len != (u32) ((u8 *) param->u.crypt.key - | ||
607 | (u8 *) param) + param->u.crypt.key_len) */ | ||
608 | if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) { | ||
609 | ret = -EINVAL; | ||
610 | goto exit; | ||
611 | } | ||
612 | |||
613 | if (is_broadcast_ether_addr(param->sta_addr)) { | ||
614 | if (param->u.crypt.idx >= WEP_KEYS) { | ||
615 | ret = -EINVAL; | ||
616 | goto exit; | ||
617 | } | ||
618 | } else { | ||
619 | psta = rtw_get_stainfo23a(pstapriv, param->sta_addr); | ||
620 | if (!psta) { | ||
621 | /* ret = -EINVAL; */ | ||
622 | DBG_8723A("rtw_set_encryption(), sta has already " | ||
623 | "been removed or never been added\n"); | ||
624 | goto exit; | ||
625 | } | ||
626 | } | ||
627 | |||
628 | if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) { | ||
629 | /* todo:clear default encryption keys */ | ||
630 | |||
631 | DBG_8723A("clear default encryption keys, keyid =%d\n", | ||
632 | param->u.crypt.idx); | ||
633 | |||
634 | goto exit; | ||
635 | } | ||
636 | |||
637 | if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) { | ||
638 | DBG_8723A("r871x_set_encryption, crypt.alg = WEP\n"); | ||
639 | |||
640 | wep_key_idx = param->u.crypt.idx; | ||
641 | wep_key_len = param->u.crypt.key_len; | ||
642 | |||
643 | DBG_8723A("r871x_set_encryption, wep_key_idx =%d, len =%d\n", | ||
644 | wep_key_idx, wep_key_len); | ||
645 | |||
646 | if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) { | ||
647 | ret = -EINVAL; | ||
648 | goto exit; | ||
649 | } | ||
650 | |||
651 | if (wep_key_len > 0) { | ||
652 | wep_key_len = wep_key_len <= 5 ? 5 : 13; | ||
653 | } | ||
654 | |||
655 | if (psecuritypriv->bWepDefaultKeyIdxSet == 0) { | ||
656 | /* wep default key has not been set, so use | ||
657 | this key index as default key. */ | ||
658 | |||
659 | psecuritypriv->ndisencryptstatus = | ||
660 | Ndis802_11Encryption1Enabled; | ||
661 | psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; | ||
662 | psecuritypriv->dot118021XGrpPrivacy = _WEP40_; | ||
663 | |||
664 | if (wep_key_len == 13) { | ||
665 | psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; | ||
666 | psecuritypriv->dot118021XGrpPrivacy = _WEP104_; | ||
667 | } | ||
668 | |||
669 | psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; | ||
670 | } | ||
671 | |||
672 | memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], | ||
673 | param->u.crypt.key, wep_key_len); | ||
674 | |||
675 | psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len; | ||
676 | |||
677 | set_wep_key(padapter, param->u.crypt.key, wep_key_len, | ||
678 | wep_key_idx); | ||
679 | |||
680 | goto exit; | ||
681 | |||
682 | } | ||
683 | |||
684 | if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /* group key */ | ||
685 | if (param->u.crypt.set_tx == 0) { /* group key */ | ||
686 | if (strcmp(param->u.crypt.alg, "WEP") == 0) { | ||
687 | DBG_8723A("%s, set group_key, WEP\n", | ||
688 | __func__); | ||
689 | |||
690 | memcpy(psecuritypriv-> | ||
691 | dot118021XGrpKey[param->u.crypt.idx]. | ||
692 | skey, param->u.crypt.key, | ||
693 | (param->u.crypt.key_len > | ||
694 | 16 ? 16 : param->u.crypt.key_len)); | ||
695 | |||
696 | psecuritypriv->dot118021XGrpPrivacy = _WEP40_; | ||
697 | if (param->u.crypt.key_len == 13) { | ||
698 | psecuritypriv->dot118021XGrpPrivacy = | ||
699 | _WEP104_; | ||
700 | } | ||
701 | |||
702 | } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { | ||
703 | DBG_8723A("%s, set group_key, TKIP\n", | ||
704 | __func__); | ||
705 | |||
706 | psecuritypriv->dot118021XGrpPrivacy = _TKIP_; | ||
707 | |||
708 | memcpy(psecuritypriv-> | ||
709 | dot118021XGrpKey[param->u.crypt.idx]. | ||
710 | skey, param->u.crypt.key, | ||
711 | (param->u.crypt.key_len > | ||
712 | 16 ? 16 : param->u.crypt.key_len)); | ||
713 | |||
714 | /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ | ||
715 | /* set mic key */ | ||
716 | memcpy(psecuritypriv-> | ||
717 | dot118021XGrptxmickey[param->u.crypt. | ||
718 | idx].skey, | ||
719 | ¶m->u.crypt.key[16], 8); | ||
720 | memcpy(psecuritypriv-> | ||
721 | dot118021XGrprxmickey[param->u.crypt. | ||
722 | idx].skey, | ||
723 | ¶m->u.crypt.key[24], 8); | ||
724 | |||
725 | psecuritypriv->busetkipkey = true; | ||
726 | |||
727 | } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { | ||
728 | DBG_8723A("%s, set group_key, CCMP\n", | ||
729 | __func__); | ||
730 | |||
731 | psecuritypriv->dot118021XGrpPrivacy = _AES_; | ||
732 | |||
733 | memcpy(psecuritypriv-> | ||
734 | dot118021XGrpKey[param->u.crypt.idx]. | ||
735 | skey, param->u.crypt.key, | ||
736 | (param->u.crypt.key_len > | ||
737 | 16 ? 16 : param->u.crypt.key_len)); | ||
738 | } else { | ||
739 | DBG_8723A("%s, set group_key, none\n", | ||
740 | __func__); | ||
741 | |||
742 | psecuritypriv->dot118021XGrpPrivacy = | ||
743 | _NO_PRIVACY_; | ||
744 | } | ||
745 | |||
746 | psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; | ||
747 | |||
748 | psecuritypriv->binstallGrpkey = true; | ||
749 | |||
750 | psecuritypriv->dot11PrivacyAlgrthm = | ||
751 | psecuritypriv->dot118021XGrpPrivacy; | ||
752 | |||
753 | set_group_key(padapter, param->u.crypt.key, | ||
754 | psecuritypriv->dot118021XGrpPrivacy, | ||
755 | param->u.crypt.idx); | ||
756 | |||
757 | pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter); | ||
758 | if (pbcmc_sta) { | ||
759 | pbcmc_sta->ieee8021x_blocked = false; | ||
760 | /* rx will use bmc_sta's dot118021XPrivacy */ | ||
761 | pbcmc_sta->dot118021XPrivacy = | ||
762 | psecuritypriv->dot118021XGrpPrivacy; | ||
763 | |||
764 | } | ||
765 | |||
766 | } | ||
767 | |||
768 | goto exit; | ||
769 | } | ||
770 | |||
771 | if (psecuritypriv->dot11AuthAlgrthm == | ||
772 | dot11AuthAlgrthm_8021X && psta) { /* psk/802_1x */ | ||
773 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { | ||
774 | if (param->u.crypt.set_tx == 1) { | ||
775 | /* pairwise key */ | ||
776 | memcpy(psta->dot118021x_UncstKey.skey, | ||
777 | param->u.crypt.key, | ||
778 | (param->u.crypt.key_len > | ||
779 | 16 ? 16 : param->u.crypt.key_len)); | ||
780 | |||
781 | if (!strcmp(param->u.crypt.alg, "WEP")) { | ||
782 | DBG_8723A("%s, set pairwise key, WEP\n", | ||
783 | __func__); | ||
784 | |||
785 | psta->dot118021XPrivacy = _WEP40_; | ||
786 | if (param->u.crypt.key_len == 13) { | ||
787 | psta->dot118021XPrivacy = | ||
788 | _WEP104_; | ||
789 | } | ||
790 | } else if (!strcmp(param->u.crypt.alg, "TKIP")) { | ||
791 | DBG_8723A("%s, set pairwise key, " | ||
792 | "TKIP\n", __func__); | ||
793 | |||
794 | psta->dot118021XPrivacy = _TKIP_; | ||
795 | |||
796 | /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ | ||
797 | /* set mic key */ | ||
798 | memcpy(psta->dot11tkiptxmickey.skey, | ||
799 | ¶m->u.crypt.key[16], 8); | ||
800 | memcpy(psta->dot11tkiprxmickey.skey, | ||
801 | ¶m->u.crypt.key[24], 8); | ||
802 | |||
803 | psecuritypriv->busetkipkey = true; | ||
804 | |||
805 | } else if (!strcmp(param->u.crypt.alg, "CCMP")) { | ||
806 | |||
807 | DBG_8723A("%s, set pairwise key, " | ||
808 | "CCMP\n", __func__); | ||
809 | |||
810 | psta->dot118021XPrivacy = _AES_; | ||
811 | } else { | ||
812 | DBG_8723A("%s, set pairwise key, " | ||
813 | "none\n", __func__); | ||
814 | |||
815 | psta->dot118021XPrivacy = _NO_PRIVACY_; | ||
816 | } | ||
817 | |||
818 | set_pairwise_key(padapter, psta); | ||
819 | |||
820 | psta->ieee8021x_blocked = false; | ||
821 | |||
822 | psta->bpairwise_key_installed = true; | ||
823 | } else { /* group key??? */ | ||
824 | if (!strcmp(param->u.crypt.alg, "WEP")) { | ||
825 | memcpy(psecuritypriv-> | ||
826 | dot118021XGrpKey[param->u.crypt. | ||
827 | idx].skey, | ||
828 | param->u.crypt.key, | ||
829 | (param->u.crypt.key_len > | ||
830 | 16 ? 16 : param->u.crypt. | ||
831 | key_len)); | ||
832 | |||
833 | psecuritypriv->dot118021XGrpPrivacy = | ||
834 | _WEP40_; | ||
835 | if (param->u.crypt.key_len == 13) { | ||
836 | psecuritypriv-> | ||
837 | dot118021XGrpPrivacy = | ||
838 | _WEP104_; | ||
839 | } | ||
840 | } else if (!strcmp(param->u.crypt.alg, "TKIP")) { | ||
841 | psecuritypriv->dot118021XGrpPrivacy = | ||
842 | _TKIP_; | ||
843 | |||
844 | memcpy(psecuritypriv-> | ||
845 | dot118021XGrpKey[param->u.crypt. | ||
846 | idx].skey, | ||
847 | param->u.crypt.key, | ||
848 | (param->u.crypt.key_len > | ||
849 | 16 ? 16 : param->u.crypt. | ||
850 | key_len)); | ||
851 | |||
852 | /* DEBUG_ERR("set key length :param->u" | ||
853 | ".crypt.key_len =%d\n", | ||
854 | param->u.crypt.key_len); */ | ||
855 | /* set mic key */ | ||
856 | memcpy(psecuritypriv-> | ||
857 | dot118021XGrptxmickey[param->u. | ||
858 | crypt.idx]. | ||
859 | skey, ¶m->u.crypt.key[16], | ||
860 | 8); | ||
861 | memcpy(psecuritypriv-> | ||
862 | dot118021XGrprxmickey[param->u. | ||
863 | crypt.idx]. | ||
864 | skey, ¶m->u.crypt.key[24], | ||
865 | 8); | ||
866 | |||
867 | psecuritypriv->busetkipkey = true; | ||
868 | |||
869 | } else if (!strcmp(param->u.crypt.alg, "CCMP")) { | ||
870 | psecuritypriv->dot118021XGrpPrivacy = | ||
871 | _AES_; | ||
872 | |||
873 | memcpy(psecuritypriv-> | ||
874 | dot118021XGrpKey[param->u.crypt. | ||
875 | idx].skey, | ||
876 | param->u.crypt.key, | ||
877 | (param->u.crypt.key_len > | ||
878 | 16 ? 16 : param->u.crypt. | ||
879 | key_len)); | ||
880 | } else { | ||
881 | psecuritypriv->dot118021XGrpPrivacy = | ||
882 | _NO_PRIVACY_; | ||
883 | } | ||
884 | |||
885 | psecuritypriv->dot118021XGrpKeyid = | ||
886 | param->u.crypt.idx; | ||
887 | |||
888 | psecuritypriv->binstallGrpkey = true; | ||
889 | |||
890 | psecuritypriv->dot11PrivacyAlgrthm = | ||
891 | psecuritypriv->dot118021XGrpPrivacy; | ||
892 | |||
893 | set_group_key(padapter, param->u.crypt.key, | ||
894 | psecuritypriv-> | ||
895 | dot118021XGrpPrivacy, | ||
896 | param->u.crypt.idx); | ||
897 | |||
898 | pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter); | ||
899 | if (pbcmc_sta) { | ||
900 | /* rx will use bmc_sta's | ||
901 | dot118021XPrivacy */ | ||
902 | pbcmc_sta->ieee8021x_blocked = false; | ||
903 | pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy; | ||
904 | } | ||
905 | } | ||
906 | } | ||
907 | } | ||
908 | |||
909 | exit: | ||
910 | |||
911 | return ret; | ||
912 | |||
913 | } | ||
914 | #endif | ||
915 | |||
916 | static int rtw_cfg80211_set_encryption(struct net_device *dev, | ||
917 | struct ieee_param *param, u32 param_len) | ||
918 | { | ||
919 | int ret = 0; | ||
920 | u32 wep_key_idx, wep_key_len; | ||
921 | struct rtw_adapter *padapter = netdev_priv(dev); | ||
922 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
923 | struct security_priv *psecuritypriv = &padapter->securitypriv; | ||
924 | #ifdef CONFIG_8723AU_P2P | ||
925 | struct wifidirect_info *pwdinfo = &padapter->wdinfo; | ||
926 | #endif /* CONFIG_8723AU_P2P */ | ||
927 | |||
928 | |||
929 | |||
930 | DBG_8723A("%s\n", __func__); | ||
931 | |||
932 | param->u.crypt.err = 0; | ||
933 | param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; | ||
934 | |||
935 | if (param_len < | ||
936 | (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + | ||
937 | param->u.crypt.key_len) { | ||
938 | ret = -EINVAL; | ||
939 | goto exit; | ||
940 | } | ||
941 | |||
942 | if (is_broadcast_ether_addr(param->sta_addr)) { | ||
943 | if (param->u.crypt.idx >= WEP_KEYS) { | ||
944 | ret = -EINVAL; | ||
945 | goto exit; | ||
946 | } | ||
947 | } else { | ||
948 | ret = -EINVAL; | ||
949 | goto exit; | ||
950 | } | ||
951 | |||
952 | if (strcmp(param->u.crypt.alg, "WEP") == 0) { | ||
953 | RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, | ||
954 | ("wpa_set_encryption, crypt.alg = WEP\n")); | ||
955 | DBG_8723A("wpa_set_encryption, crypt.alg = WEP\n"); | ||
956 | |||
957 | wep_key_idx = param->u.crypt.idx; | ||
958 | wep_key_len = param->u.crypt.key_len; | ||
959 | |||
960 | if ((wep_key_idx > WEP_KEYS) || (wep_key_len <= 0)) { | ||
961 | ret = -EINVAL; | ||
962 | goto exit; | ||
963 | } | ||
964 | |||
965 | if (psecuritypriv->bWepDefaultKeyIdxSet == 0) { | ||
966 | /* wep default key has not been set, so use this | ||
967 | key index as default key. */ | ||
968 | |||
969 | wep_key_len = wep_key_len <= 5 ? 5 : 13; | ||
970 | |||
971 | psecuritypriv->ndisencryptstatus = | ||
972 | Ndis802_11Encryption1Enabled; | ||
973 | psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; | ||
974 | psecuritypriv->dot118021XGrpPrivacy = _WEP40_; | ||
975 | |||
976 | if (wep_key_len == 13) { | ||
977 | psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; | ||
978 | psecuritypriv->dot118021XGrpPrivacy = _WEP104_; | ||
979 | } | ||
980 | |||
981 | psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; | ||
982 | } | ||
983 | |||
984 | memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], | ||
985 | param->u.crypt.key, wep_key_len); | ||
986 | |||
987 | psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len; | ||
988 | |||
989 | rtw_set_key23a(padapter, psecuritypriv, wep_key_idx, 0); | ||
990 | |||
991 | goto exit; | ||
992 | } | ||
993 | |||
994 | if (padapter->securitypriv.dot11AuthAlgrthm == | ||
995 | dot11AuthAlgrthm_8021X) { /* 802_1x */ | ||
996 | struct sta_info *psta, *pbcmc_sta; | ||
997 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
998 | |||
999 | if (check_fwstate(pmlmepriv, | ||
1000 | WIFI_STATION_STATE | WIFI_MP_STATE)) { | ||
1001 | /* sta mode */ | ||
1002 | psta = rtw_get_stainfo23a(pstapriv, get_bssid(pmlmepriv)); | ||
1003 | if (psta == NULL) { | ||
1004 | DBG_8723A("%s, : Obtain Sta_info fail\n", | ||
1005 | __func__); | ||
1006 | } else { | ||
1007 | /* Jeff: don't disable ieee8021x_blocked | ||
1008 | while clearing key */ | ||
1009 | if (strcmp(param->u.crypt.alg, "none") != 0) | ||
1010 | psta->ieee8021x_blocked = false; | ||
1011 | |||
1012 | if ((padapter->securitypriv.ndisencryptstatus == | ||
1013 | Ndis802_11Encryption2Enabled) || | ||
1014 | (padapter->securitypriv.ndisencryptstatus == | ||
1015 | Ndis802_11Encryption3Enabled)) { | ||
1016 | psta->dot118021XPrivacy = | ||
1017 | padapter->securitypriv. | ||
1018 | dot11PrivacyAlgrthm; | ||
1019 | } | ||
1020 | |||
1021 | if (param->u.crypt.set_tx == 1) { | ||
1022 | /* pairwise key */ | ||
1023 | DBG_8723A("%s, : param->u.crypt.set_tx" | ||
1024 | " == 1\n", __func__); | ||
1025 | |||
1026 | memcpy(psta->dot118021x_UncstKey.skey, | ||
1027 | param->u.crypt.key, | ||
1028 | (param->u.crypt.key_len > | ||
1029 | 16 ? 16 : param->u.crypt. | ||
1030 | key_len)); | ||
1031 | |||
1032 | if (strcmp(param->u.crypt.alg, | ||
1033 | "TKIP") == 0) { | ||
1034 | memcpy(psta->dot11tkiptxmickey. | ||
1035 | skey, | ||
1036 | ¶m->u.crypt.key[16], | ||
1037 | 8); | ||
1038 | memcpy(psta->dot11tkiprxmickey. | ||
1039 | skey, | ||
1040 | ¶m->u.crypt.key[24], | ||
1041 | 8); | ||
1042 | |||
1043 | padapter->securitypriv. | ||
1044 | busetkipkey = false; | ||
1045 | } | ||
1046 | DBG_8723A(" ~~~~set sta key:unicastkey\n"); | ||
1047 | |||
1048 | rtw_setstakey_cmd23a(padapter, | ||
1049 | (unsigned char *)psta, | ||
1050 | true); | ||
1051 | } else { /* group key */ | ||
1052 | memcpy(padapter->securitypriv. | ||
1053 | dot118021XGrpKey[param->u.crypt. | ||
1054 | idx].skey, | ||
1055 | param->u.crypt.key, | ||
1056 | (param->u.crypt.key_len > | ||
1057 | 16 ? 16 : param->u.crypt. | ||
1058 | key_len)); | ||
1059 | memcpy(padapter->securitypriv. | ||
1060 | dot118021XGrptxmickey[param->u. | ||
1061 | crypt.idx]. | ||
1062 | skey, ¶m->u.crypt.key[16], | ||
1063 | 8); | ||
1064 | memcpy(padapter->securitypriv. | ||
1065 | dot118021XGrprxmickey[param->u. | ||
1066 | crypt.idx]. | ||
1067 | skey, ¶m->u.crypt.key[24], | ||
1068 | 8); | ||
1069 | padapter->securitypriv.binstallGrpkey = | ||
1070 | true; | ||
1071 | /* DEBUG_ERR((" param->u.crypt.key_len" | ||
1072 | "=%d\n", param->u.crypt.key_len)); */ | ||
1073 | DBG_8723A | ||
1074 | (" ~~~~set sta key:groupkey\n"); | ||
1075 | |||
1076 | padapter->securitypriv. | ||
1077 | dot118021XGrpKeyid = | ||
1078 | param->u.crypt.idx; | ||
1079 | |||
1080 | rtw_set_key23a(padapter, | ||
1081 | &padapter->securitypriv, | ||
1082 | param->u.crypt.idx, 1); | ||
1083 | #ifdef CONFIG_8723AU_P2P | ||
1084 | if (rtw_p2p_chk_state | ||
1085 | (pwdinfo, | ||
1086 | P2P_STATE_PROVISIONING_ING)) { | ||
1087 | rtw_p2p_set_state(pwdinfo, | ||
1088 | P2P_STATE_PROVISIONING_DONE); | ||
1089 | } | ||
1090 | #endif /* CONFIG_8723AU_P2P */ | ||
1091 | |||
1092 | } | ||
1093 | } | ||
1094 | |||
1095 | pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter); | ||
1096 | if (pbcmc_sta) { | ||
1097 | /* Jeff: don't disable ieee8021x_blocked | ||
1098 | while clearing key */ | ||
1099 | if (strcmp(param->u.crypt.alg, "none") != 0) | ||
1100 | pbcmc_sta->ieee8021x_blocked = false; | ||
1101 | |||
1102 | if ((padapter->securitypriv.ndisencryptstatus == | ||
1103 | Ndis802_11Encryption2Enabled) || | ||
1104 | (padapter->securitypriv.ndisencryptstatus == | ||
1105 | Ndis802_11Encryption3Enabled)) { | ||
1106 | pbcmc_sta->dot118021XPrivacy = | ||
1107 | padapter->securitypriv. | ||
1108 | dot11PrivacyAlgrthm; | ||
1109 | } | ||
1110 | } | ||
1111 | } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { /* adhoc mode */ | ||
1112 | } | ||
1113 | } | ||
1114 | |||
1115 | exit: | ||
1116 | |||
1117 | DBG_8723A("%s, ret =%d\n", __func__, ret); | ||
1118 | |||
1119 | |||
1120 | |||
1121 | return ret; | ||
1122 | } | ||
1123 | |||
1124 | static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, | ||
1125 | u8 key_index, bool pairwise, | ||
1126 | const u8 *mac_addr, struct key_params *params) | ||
1127 | { | ||
1128 | char *alg_name; | ||
1129 | u32 param_len; | ||
1130 | struct ieee_param *param = NULL; | ||
1131 | int ret = 0; | ||
1132 | struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy); | ||
1133 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
1134 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
1135 | |||
1136 | DBG_8723A(FUNC_NDEV_FMT " adding key for %pM\n", FUNC_NDEV_ARG(ndev), | ||
1137 | mac_addr); | ||
1138 | DBG_8723A("cipher = 0x%x\n", params->cipher); | ||
1139 | DBG_8723A("key_len = 0x%x\n", params->key_len); | ||
1140 | DBG_8723A("seq_len = 0x%x\n", params->seq_len); | ||
1141 | DBG_8723A("key_index =%d\n", key_index); | ||
1142 | DBG_8723A("pairwise =%d\n", pairwise); | ||
1143 | |||
1144 | param_len = sizeof(struct ieee_param) + params->key_len; | ||
1145 | param = kzalloc(param_len, GFP_KERNEL); | ||
1146 | if (param == NULL) | ||
1147 | return -1; | ||
1148 | |||
1149 | param->cmd = IEEE_CMD_SET_ENCRYPTION; | ||
1150 | memset(param->sta_addr, 0xff, ETH_ALEN); | ||
1151 | |||
1152 | switch (params->cipher) { | ||
1153 | case IW_AUTH_CIPHER_NONE: | ||
1154 | /* todo: remove key */ | ||
1155 | /* remove = 1; */ | ||
1156 | alg_name = "none"; | ||
1157 | break; | ||
1158 | case WLAN_CIPHER_SUITE_WEP40: | ||
1159 | case WLAN_CIPHER_SUITE_WEP104: | ||
1160 | alg_name = "WEP"; | ||
1161 | break; | ||
1162 | case WLAN_CIPHER_SUITE_TKIP: | ||
1163 | alg_name = "TKIP"; | ||
1164 | break; | ||
1165 | case WLAN_CIPHER_SUITE_CCMP: | ||
1166 | alg_name = "CCMP"; | ||
1167 | break; | ||
1168 | |||
1169 | default: | ||
1170 | ret = -ENOTSUPP; | ||
1171 | goto addkey_end; | ||
1172 | } | ||
1173 | |||
1174 | strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); | ||
1175 | |||
1176 | if (!mac_addr || is_broadcast_ether_addr(mac_addr)) { | ||
1177 | param->u.crypt.set_tx = 0; /* for wpa/wpa2 group key */ | ||
1178 | } else { | ||
1179 | param->u.crypt.set_tx = 1; /* for wpa/wpa2 pairwise key */ | ||
1180 | } | ||
1181 | |||
1182 | /* param->u.crypt.idx = key_index - 1; */ | ||
1183 | param->u.crypt.idx = key_index; | ||
1184 | |||
1185 | if (params->seq_len && params->seq) { | ||
1186 | memcpy(param->u.crypt.seq, params->seq, params->seq_len); | ||
1187 | } | ||
1188 | |||
1189 | if (params->key_len && params->key) { | ||
1190 | param->u.crypt.key_len = params->key_len; | ||
1191 | memcpy(param->u.crypt.key, params->key, params->key_len); | ||
1192 | } | ||
1193 | |||
1194 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { | ||
1195 | ret = rtw_cfg80211_set_encryption(ndev, param, param_len); | ||
1196 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { | ||
1197 | #ifdef CONFIG_8723AU_AP_MODE | ||
1198 | if (mac_addr) | ||
1199 | memcpy(param->sta_addr, (void *)mac_addr, ETH_ALEN); | ||
1200 | |||
1201 | ret = rtw_cfg80211_ap_set_encryption(ndev, param, param_len); | ||
1202 | #endif | ||
1203 | } else { | ||
1204 | DBG_8723A("error! fw_state = 0x%x, iftype =%d\n", | ||
1205 | pmlmepriv->fw_state, rtw_wdev->iftype); | ||
1206 | |||
1207 | } | ||
1208 | |||
1209 | addkey_end: | ||
1210 | kfree(param); | ||
1211 | |||
1212 | return ret; | ||
1213 | } | ||
1214 | |||
1215 | static int | ||
1216 | cfg80211_rtw_get_key(struct wiphy *wiphy, struct net_device *ndev, | ||
1217 | u8 key_index, bool pairwise, const u8 *mac_addr, | ||
1218 | void *cookie, | ||
1219 | void (*callback) (void *cookie, struct key_params *)) | ||
1220 | { | ||
1221 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev, | ||
1226 | u8 key_index, bool pairwise, | ||
1227 | const u8 *mac_addr) | ||
1228 | { | ||
1229 | struct rtw_adapter *padapter = netdev_priv(ndev); | ||
1230 | struct security_priv *psecuritypriv = &padapter->securitypriv; | ||
1231 | |||
1232 | DBG_8723A(FUNC_NDEV_FMT " key_index =%d\n", FUNC_NDEV_ARG(ndev), | ||
1233 | key_index); | ||
1234 | |||
1235 | if (key_index == psecuritypriv->dot11PrivacyKeyIndex) { | ||
1236 | /* clear the flag of wep default key set. */ | ||
1237 | psecuritypriv->bWepDefaultKeyIdxSet = 0; | ||
1238 | } | ||
1239 | |||
1240 | return 0; | ||
1241 | } | ||
1242 | |||
1243 | static int cfg80211_rtw_set_default_key(struct wiphy *wiphy, | ||
1244 | struct net_device *ndev, u8 key_index, | ||
1245 | bool unicast, bool multicast) | ||
1246 | { | ||
1247 | struct rtw_adapter *padapter = netdev_priv(ndev); | ||
1248 | struct security_priv *psecuritypriv = &padapter->securitypriv; | ||
1249 | |||
1250 | DBG_8723A(FUNC_NDEV_FMT " key_index =%d" | ||
1251 | ", unicast =%d, multicast =%d.\n", FUNC_NDEV_ARG(ndev), | ||
1252 | key_index, unicast, multicast); | ||
1253 | |||
1254 | if ((key_index < WEP_KEYS) && | ||
1255 | ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) || | ||
1256 | (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_))) { | ||
1257 | /* set wep default key */ | ||
1258 | psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; | ||
1259 | |||
1260 | psecuritypriv->dot11PrivacyKeyIndex = key_index; | ||
1261 | |||
1262 | psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; | ||
1263 | psecuritypriv->dot118021XGrpPrivacy = _WEP40_; | ||
1264 | if (psecuritypriv->dot11DefKeylen[key_index] == 13) { | ||
1265 | psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; | ||
1266 | psecuritypriv->dot118021XGrpPrivacy = _WEP104_; | ||
1267 | } | ||
1268 | |||
1269 | /* set the flag to represent that wep default key | ||
1270 | has been set */ | ||
1271 | psecuritypriv->bWepDefaultKeyIdxSet = 1; | ||
1272 | } | ||
1273 | |||
1274 | return 0; | ||
1275 | } | ||
1276 | |||
1277 | static int cfg80211_rtw_get_station(struct wiphy *wiphy, | ||
1278 | struct net_device *ndev, | ||
1279 | u8 *mac, struct station_info *sinfo) | ||
1280 | { | ||
1281 | int ret = 0; | ||
1282 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
1283 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
1284 | struct sta_info *psta = NULL; | ||
1285 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
1286 | |||
1287 | sinfo->filled = 0; | ||
1288 | |||
1289 | if (!mac) { | ||
1290 | DBG_8723A(FUNC_NDEV_FMT " mac ==%p\n", FUNC_NDEV_ARG(ndev), mac); | ||
1291 | ret = -ENOENT; | ||
1292 | goto exit; | ||
1293 | } | ||
1294 | |||
1295 | psta = rtw_get_stainfo23a(pstapriv, mac); | ||
1296 | if (psta == NULL) { | ||
1297 | DBG_8723A("%s, sta_info is null\n", __func__); | ||
1298 | ret = -ENOENT; | ||
1299 | goto exit; | ||
1300 | } | ||
1301 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1302 | DBG_8723A(FUNC_NDEV_FMT " mac =" MAC_FMT "\n", FUNC_NDEV_ARG(ndev), | ||
1303 | MAC_ARG(mac)); | ||
1304 | #endif | ||
1305 | |||
1306 | /* for infra./P2PClient mode */ | ||
1307 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && | ||
1308 | check_fwstate(pmlmepriv, _FW_LINKED)) { | ||
1309 | struct wlan_network *cur_network = &pmlmepriv->cur_network; | ||
1310 | |||
1311 | if (memcmp(mac, cur_network->network.MacAddress, ETH_ALEN)) { | ||
1312 | DBG_8723A("%s, mismatch bssid =" MAC_FMT "\n", __func__, | ||
1313 | MAC_ARG(cur_network->network.MacAddress)); | ||
1314 | ret = -ENOENT; | ||
1315 | goto exit; | ||
1316 | } | ||
1317 | |||
1318 | sinfo->filled |= STATION_INFO_SIGNAL; | ||
1319 | sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv. | ||
1320 | signal_strength); | ||
1321 | |||
1322 | sinfo->filled |= STATION_INFO_TX_BITRATE; | ||
1323 | sinfo->txrate.legacy = rtw_get_cur_max_rate23a(padapter); | ||
1324 | |||
1325 | sinfo->filled |= STATION_INFO_RX_PACKETS; | ||
1326 | sinfo->rx_packets = sta_rx_data_pkts(psta); | ||
1327 | |||
1328 | sinfo->filled |= STATION_INFO_TX_PACKETS; | ||
1329 | sinfo->tx_packets = psta->sta_stats.tx_pkts; | ||
1330 | } | ||
1331 | |||
1332 | /* for Ad-Hoc/AP mode */ | ||
1333 | if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || | ||
1334 | check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || | ||
1335 | check_fwstate(pmlmepriv, WIFI_AP_STATE)) && | ||
1336 | check_fwstate(pmlmepriv, _FW_LINKED) | ||
1337 | ) { | ||
1338 | /* TODO: should acquire station info... */ | ||
1339 | } | ||
1340 | |||
1341 | exit: | ||
1342 | return ret; | ||
1343 | } | ||
1344 | |||
1345 | static int cfg80211_rtw_change_iface(struct wiphy *wiphy, | ||
1346 | struct net_device *ndev, | ||
1347 | enum nl80211_iftype type, u32 *flags, | ||
1348 | struct vif_params *params) | ||
1349 | { | ||
1350 | enum nl80211_iftype old_type; | ||
1351 | enum ndis_802_11_net_infra networkType; | ||
1352 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
1353 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | ||
1354 | struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy); | ||
1355 | #ifdef CONFIG_8723AU_P2P | ||
1356 | struct wifidirect_info *pwdinfo = &padapter->wdinfo; | ||
1357 | #endif | ||
1358 | int ret = 0; | ||
1359 | u8 change = false; | ||
1360 | |||
1361 | DBG_8723A(FUNC_NDEV_FMT " call netdev_open23a\n", FUNC_NDEV_ARG(ndev)); | ||
1362 | if (netdev_open23a(ndev) != 0) { | ||
1363 | ret = -EPERM; | ||
1364 | goto exit; | ||
1365 | } | ||
1366 | |||
1367 | if (_FAIL == rtw_pwr_wakeup(padapter)) { | ||
1368 | ret = -EPERM; | ||
1369 | goto exit; | ||
1370 | } | ||
1371 | |||
1372 | old_type = rtw_wdev->iftype; | ||
1373 | DBG_8723A(FUNC_NDEV_FMT " old_iftype =%d, new_iftype =%d\n", | ||
1374 | FUNC_NDEV_ARG(ndev), old_type, type); | ||
1375 | |||
1376 | if (old_type != type) { | ||
1377 | change = true; | ||
1378 | pmlmeext->action_public_rxseq = 0xffff; | ||
1379 | pmlmeext->action_public_dialog_token = 0xff; | ||
1380 | } | ||
1381 | |||
1382 | switch (type) { | ||
1383 | case NL80211_IFTYPE_ADHOC: | ||
1384 | networkType = Ndis802_11IBSS; | ||
1385 | break; | ||
1386 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1387 | case NL80211_IFTYPE_STATION: | ||
1388 | networkType = Ndis802_11Infrastructure; | ||
1389 | #ifdef CONFIG_8723AU_P2P | ||
1390 | if (change && rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { | ||
1391 | del_timer_sync(&pwdinfo->find_phase_timer); | ||
1392 | del_timer_sync(&pwdinfo->restore_p2p_state_timer); | ||
1393 | del_timer_sync(&pwdinfo->pre_tx_scan_timer); | ||
1394 | |||
1395 | /* it means remove GO and change mode from AP(GO) | ||
1396 | to station(P2P DEVICE) */ | ||
1397 | rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); | ||
1398 | rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); | ||
1399 | |||
1400 | DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =" | ||
1401 | "%d\n", __func__, rtw_p2p_role(pwdinfo), | ||
1402 | rtw_p2p_state(pwdinfo), | ||
1403 | rtw_p2p_pre_state(pwdinfo)); | ||
1404 | } | ||
1405 | #endif /* CONFIG_8723AU_P2P */ | ||
1406 | break; | ||
1407 | case NL80211_IFTYPE_P2P_GO: | ||
1408 | case NL80211_IFTYPE_AP: | ||
1409 | networkType = Ndis802_11APMode; | ||
1410 | #ifdef CONFIG_8723AU_P2P | ||
1411 | if (change && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { | ||
1412 | /* it means P2P Group created, we will be GO | ||
1413 | and change mode from P2P DEVICE to AP(GO) */ | ||
1414 | rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); | ||
1415 | } | ||
1416 | #endif /* CONFIG_8723AU_P2P */ | ||
1417 | break; | ||
1418 | default: | ||
1419 | return -EOPNOTSUPP; | ||
1420 | } | ||
1421 | |||
1422 | rtw_wdev->iftype = type; | ||
1423 | |||
1424 | if (rtw_set_802_11_infrastructure_mode23a(padapter, networkType) == false) { | ||
1425 | rtw_wdev->iftype = old_type; | ||
1426 | ret = -EPERM; | ||
1427 | goto exit; | ||
1428 | } | ||
1429 | |||
1430 | rtw_setopmode_cmd23a(padapter, networkType); | ||
1431 | |||
1432 | exit: | ||
1433 | return ret; | ||
1434 | } | ||
1435 | |||
1436 | void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv, | ||
1437 | bool aborted) | ||
1438 | { | ||
1439 | spin_lock_bh(&pwdev_priv->scan_req_lock); | ||
1440 | if (pwdev_priv->scan_request != NULL) { | ||
1441 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1442 | DBG_8723A("%s with scan req\n", __func__); | ||
1443 | #endif | ||
1444 | if (pwdev_priv->scan_request->wiphy != | ||
1445 | pwdev_priv->rtw_wdev->wiphy) | ||
1446 | DBG_8723A("error wiphy compare\n"); | ||
1447 | else | ||
1448 | cfg80211_scan_done(pwdev_priv->scan_request, aborted); | ||
1449 | |||
1450 | pwdev_priv->scan_request = NULL; | ||
1451 | } else { | ||
1452 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1453 | DBG_8723A("%s without scan req\n", __func__); | ||
1454 | #endif | ||
1455 | } | ||
1456 | spin_unlock_bh(&pwdev_priv->scan_req_lock); | ||
1457 | } | ||
1458 | |||
1459 | void rtw_cfg80211_surveydone_event_callback(struct rtw_adapter *padapter) | ||
1460 | { | ||
1461 | struct list_head *plist, *phead, *ptmp; | ||
1462 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
1463 | struct rtw_queue *queue = &pmlmepriv->scanned_queue; | ||
1464 | struct wlan_network *pnetwork; | ||
1465 | |||
1466 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1467 | DBG_8723A("%s\n", __func__); | ||
1468 | #endif | ||
1469 | |||
1470 | spin_lock_bh(&pmlmepriv->scanned_queue.lock); | ||
1471 | |||
1472 | phead = get_list_head(queue); | ||
1473 | |||
1474 | list_for_each_safe(plist, ptmp, phead) { | ||
1475 | pnetwork = container_of(plist, struct wlan_network, list); | ||
1476 | |||
1477 | /* report network only if the current channel set | ||
1478 | contains the channel to which this network belongs */ | ||
1479 | if (rtw_ch_set_search_ch23a | ||
1480 | (padapter->mlmeextpriv.channel_set, | ||
1481 | pnetwork->network.Configuration.DSConfig) >= 0) | ||
1482 | rtw_cfg80211_inform_bss(padapter, pnetwork); | ||
1483 | } | ||
1484 | |||
1485 | spin_unlock_bh(&pmlmepriv->scanned_queue.lock); | ||
1486 | |||
1487 | /* call this after other things have been done */ | ||
1488 | rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev), | ||
1489 | false); | ||
1490 | } | ||
1491 | |||
1492 | static int rtw_cfg80211_set_probe_req_wpsp2pie(struct rtw_adapter *padapter, | ||
1493 | char *buf, int len) | ||
1494 | { | ||
1495 | int ret = 0; | ||
1496 | uint wps_ielen = 0; | ||
1497 | u8 *wps_ie; | ||
1498 | u32 p2p_ielen = 0; | ||
1499 | u8 *p2p_ie; | ||
1500 | u32 wfd_ielen = 0; | ||
1501 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
1502 | |||
1503 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1504 | DBG_8723A("%s, ielen =%d\n", __func__, len); | ||
1505 | #endif | ||
1506 | |||
1507 | if (len > 0) { | ||
1508 | wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen); | ||
1509 | if (wps_ie) { | ||
1510 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1511 | DBG_8723A("probe_req_wps_ielen =%d\n", wps_ielen); | ||
1512 | #endif | ||
1513 | if (pmlmepriv->wps_probe_req_ie) { | ||
1514 | pmlmepriv->wps_probe_req_ie_len = 0; | ||
1515 | kfree(pmlmepriv->wps_probe_req_ie); | ||
1516 | pmlmepriv->wps_probe_req_ie = NULL; | ||
1517 | } | ||
1518 | |||
1519 | pmlmepriv->wps_probe_req_ie = | ||
1520 | kmalloc(wps_ielen, GFP_KERNEL); | ||
1521 | if (pmlmepriv->wps_probe_req_ie == NULL) { | ||
1522 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
1523 | __func__, __LINE__); | ||
1524 | return -EINVAL; | ||
1525 | } | ||
1526 | memcpy(pmlmepriv->wps_probe_req_ie, wps_ie, wps_ielen); | ||
1527 | pmlmepriv->wps_probe_req_ie_len = wps_ielen; | ||
1528 | } | ||
1529 | #ifdef CONFIG_8723AU_P2P | ||
1530 | p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen); | ||
1531 | if (p2p_ie) { | ||
1532 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1533 | DBG_8723A("probe_req_p2p_ielen =%d\n", p2p_ielen); | ||
1534 | #endif | ||
1535 | |||
1536 | if (pmlmepriv->p2p_probe_req_ie) { | ||
1537 | pmlmepriv->p2p_probe_req_ie_len = 0; | ||
1538 | kfree(pmlmepriv->p2p_probe_req_ie); | ||
1539 | pmlmepriv->p2p_probe_req_ie = NULL; | ||
1540 | } | ||
1541 | |||
1542 | pmlmepriv->p2p_probe_req_ie = | ||
1543 | kmalloc(p2p_ielen, GFP_KERNEL); | ||
1544 | if (pmlmepriv->p2p_probe_req_ie == NULL) { | ||
1545 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
1546 | __func__, __LINE__); | ||
1547 | return -EINVAL; | ||
1548 | |||
1549 | } | ||
1550 | memcpy(pmlmepriv->p2p_probe_req_ie, p2p_ie, p2p_ielen); | ||
1551 | pmlmepriv->p2p_probe_req_ie_len = p2p_ielen; | ||
1552 | } | ||
1553 | #endif /* CONFIG_8723AU_P2P */ | ||
1554 | |||
1555 | /* buf += p2p_ielen; */ | ||
1556 | /* len -= p2p_ielen; */ | ||
1557 | |||
1558 | #ifdef CONFIG_8723AU_P2P | ||
1559 | if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) { | ||
1560 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1561 | DBG_8723A("probe_req_wfd_ielen =%d\n", wfd_ielen); | ||
1562 | #endif | ||
1563 | |||
1564 | if (pmlmepriv->wfd_probe_req_ie) { | ||
1565 | pmlmepriv->wfd_probe_req_ie_len = 0; | ||
1566 | kfree(pmlmepriv->wfd_probe_req_ie); | ||
1567 | pmlmepriv->wfd_probe_req_ie = NULL; | ||
1568 | } | ||
1569 | |||
1570 | pmlmepriv->wfd_probe_req_ie = | ||
1571 | kmalloc(wfd_ielen, GFP_KERNEL); | ||
1572 | if (pmlmepriv->wfd_probe_req_ie == NULL) { | ||
1573 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
1574 | __func__, __LINE__); | ||
1575 | return -EINVAL; | ||
1576 | |||
1577 | } | ||
1578 | rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_probe_req_ie, | ||
1579 | &pmlmepriv->wfd_probe_req_ie_len); | ||
1580 | } | ||
1581 | #endif /* CONFIG_8723AU_P2P */ | ||
1582 | |||
1583 | } | ||
1584 | |||
1585 | return ret; | ||
1586 | } | ||
1587 | |||
1588 | static int cfg80211_rtw_scan(struct wiphy *wiphy, | ||
1589 | struct cfg80211_scan_request *request) | ||
1590 | { | ||
1591 | int i; | ||
1592 | u8 _status = false; | ||
1593 | int ret = 0; | ||
1594 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
1595 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
1596 | struct cfg80211_ssid ssid[RTW_SSID_SCAN_AMOUNT]; | ||
1597 | struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; | ||
1598 | #ifdef CONFIG_8723AU_P2P | ||
1599 | struct wifidirect_info *pwdinfo = &padapter->wdinfo; | ||
1600 | #endif /* CONFIG_8723AU_P2P */ | ||
1601 | struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); | ||
1602 | struct cfg80211_ssid *ssids = request->ssids; | ||
1603 | int social_channel = 0; | ||
1604 | bool need_indicate_scan_done = false; | ||
1605 | |||
1606 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1607 | DBG_8723A(FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); | ||
1608 | #endif | ||
1609 | |||
1610 | spin_lock_bh(&pwdev_priv->scan_req_lock); | ||
1611 | pwdev_priv->scan_request = request; | ||
1612 | spin_unlock_bh(&pwdev_priv->scan_req_lock); | ||
1613 | |||
1614 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { | ||
1615 | |||
1616 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1617 | DBG_8723A("%s under WIFI_AP_STATE\n", __func__); | ||
1618 | #endif | ||
1619 | /* need_indicate_scan_done = true; */ | ||
1620 | /* goto check_need_indicate_scan_done; */ | ||
1621 | } | ||
1622 | |||
1623 | if (rtw_pwr_wakeup(padapter) == _FAIL) { | ||
1624 | need_indicate_scan_done = true; | ||
1625 | goto check_need_indicate_scan_done; | ||
1626 | } | ||
1627 | #ifdef CONFIG_8723AU_P2P | ||
1628 | if (ssids->ssid != NULL && | ||
1629 | !memcmp(ssids->ssid, "DIRECT-", 7) && | ||
1630 | rtw_get_p2p_ie23a((u8 *) request->ie, request->ie_len, NULL, NULL)) { | ||
1631 | if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { | ||
1632 | rtw_p2p_enable23a(padapter, P2P_ROLE_DEVICE); | ||
1633 | wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = true; | ||
1634 | } else { | ||
1635 | rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); | ||
1636 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1637 | DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__, | ||
1638 | rtw_p2p_role(pwdinfo), | ||
1639 | rtw_p2p_state(pwdinfo)); | ||
1640 | #endif | ||
1641 | } | ||
1642 | rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); | ||
1643 | |||
1644 | if (request->n_channels == 3 && | ||
1645 | request->channels[0]->hw_value == 1 && | ||
1646 | request->channels[1]->hw_value == 6 && | ||
1647 | request->channels[2]->hw_value == 11) | ||
1648 | social_channel = 1; | ||
1649 | } | ||
1650 | #endif /* CONFIG_8723AU_P2P */ | ||
1651 | |||
1652 | if (request->ie && request->ie_len > 0) { | ||
1653 | rtw_cfg80211_set_probe_req_wpsp2pie(padapter, | ||
1654 | (u8 *) request->ie, | ||
1655 | request->ie_len); | ||
1656 | } | ||
1657 | |||
1658 | if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) { | ||
1659 | DBG_8723A("%s, bBusyTraffic == true\n", __func__); | ||
1660 | need_indicate_scan_done = true; | ||
1661 | goto check_need_indicate_scan_done; | ||
1662 | } | ||
1663 | if (rtw_is_scan_deny(padapter)) { | ||
1664 | DBG_8723A(FUNC_ADPT_FMT ": scan deny\n", | ||
1665 | FUNC_ADPT_ARG(padapter)); | ||
1666 | need_indicate_scan_done = true; | ||
1667 | goto check_need_indicate_scan_done; | ||
1668 | } | ||
1669 | |||
1670 | if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) == | ||
1671 | true) { | ||
1672 | DBG_8723A("%s, fwstate = 0x%x\n", __func__, pmlmepriv->fw_state); | ||
1673 | need_indicate_scan_done = true; | ||
1674 | goto check_need_indicate_scan_done; | ||
1675 | } | ||
1676 | #ifdef CONFIG_8723AU_P2P | ||
1677 | if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && | ||
1678 | !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) { | ||
1679 | rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); | ||
1680 | rtw_free_network_queue23a(padapter, true); | ||
1681 | |||
1682 | if (social_channel == 0) | ||
1683 | rtw_p2p_findphase_ex_set(pwdinfo, | ||
1684 | P2P_FINDPHASE_EX_NONE); | ||
1685 | else | ||
1686 | rtw_p2p_findphase_ex_set(pwdinfo, | ||
1687 | P2P_FINDPHASE_EX_SOCIAL_LAST); | ||
1688 | } | ||
1689 | #endif /* CONFIG_8723AU_P2P */ | ||
1690 | |||
1691 | memset(ssid, 0, sizeof(struct cfg80211_ssid) * RTW_SSID_SCAN_AMOUNT); | ||
1692 | /* parsing request ssids, n_ssids */ | ||
1693 | for (i = 0; i < request->n_ssids && i < RTW_SSID_SCAN_AMOUNT; i++) { | ||
1694 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1695 | DBG_8723A("ssid =%s, len =%d\n", ssids[i].ssid, | ||
1696 | ssids[i].ssid_len); | ||
1697 | #endif | ||
1698 | memcpy(ssid[i].ssid, ssids[i].ssid, ssids[i].ssid_len); | ||
1699 | ssid[i].ssid_len = ssids[i].ssid_len; | ||
1700 | } | ||
1701 | |||
1702 | /* parsing channels, n_channels */ | ||
1703 | memset(ch, 0, | ||
1704 | sizeof(struct rtw_ieee80211_channel) * RTW_CHANNEL_SCAN_AMOUNT); | ||
1705 | |||
1706 | if (request->n_channels == 1) { | ||
1707 | for (i = 0; i < request->n_channels && | ||
1708 | i < RTW_CHANNEL_SCAN_AMOUNT; i++) { | ||
1709 | #ifdef CONFIG_DEBUG_CFG80211 | ||
1710 | DBG_8723A(FUNC_ADPT_FMT CHAN_FMT "\n", | ||
1711 | FUNC_ADPT_ARG(padapter), | ||
1712 | CHAN_ARG(request->channels[i])); | ||
1713 | #endif | ||
1714 | ch[i].hw_value = request->channels[i]->hw_value; | ||
1715 | ch[i].flags = request->channels[i]->flags; | ||
1716 | } | ||
1717 | } | ||
1718 | |||
1719 | spin_lock_bh(&pmlmepriv->lock); | ||
1720 | if (request->n_channels == 1) { | ||
1721 | memcpy(&ch[1], &ch[0], sizeof(struct rtw_ieee80211_channel)); | ||
1722 | memcpy(&ch[2], &ch[0], sizeof(struct rtw_ieee80211_channel)); | ||
1723 | _status = rtw_sitesurvey_cmd23a(padapter, ssid, | ||
1724 | RTW_SSID_SCAN_AMOUNT, ch, 3); | ||
1725 | } else { | ||
1726 | _status = rtw_sitesurvey_cmd23a(padapter, ssid, | ||
1727 | RTW_SSID_SCAN_AMOUNT, NULL, 0); | ||
1728 | } | ||
1729 | spin_unlock_bh(&pmlmepriv->lock); | ||
1730 | |||
1731 | if (_status == false) | ||
1732 | ret = -1; | ||
1733 | |||
1734 | check_need_indicate_scan_done: | ||
1735 | if (need_indicate_scan_done) | ||
1736 | rtw_cfg80211_surveydone_event_callback(padapter); | ||
1737 | return ret; | ||
1738 | } | ||
1739 | |||
1740 | static int cfg80211_rtw_set_wiphy_params(struct wiphy *wiphy, u32 changed) | ||
1741 | { | ||
1742 | DBG_8723A("%s\n", __func__); | ||
1743 | return 0; | ||
1744 | } | ||
1745 | |||
1746 | static int cfg80211_rtw_join_ibss(struct wiphy *wiphy, struct net_device *ndev, | ||
1747 | struct cfg80211_ibss_params *params) | ||
1748 | { | ||
1749 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
1750 | return 0; | ||
1751 | } | ||
1752 | |||
1753 | static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) | ||
1754 | { | ||
1755 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
1756 | return 0; | ||
1757 | } | ||
1758 | |||
1759 | static int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv, | ||
1760 | u32 wpa_version) | ||
1761 | { | ||
1762 | DBG_8723A("%s, wpa_version =%d\n", __func__, wpa_version); | ||
1763 | |||
1764 | if (!wpa_version) { | ||
1765 | psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; | ||
1766 | return 0; | ||
1767 | } | ||
1768 | |||
1769 | if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) { | ||
1770 | psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK; | ||
1771 | } | ||
1772 | |||
1773 | /* | ||
1774 | if (wpa_version & NL80211_WPA_VERSION_2) | ||
1775 | { | ||
1776 | psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK; | ||
1777 | } | ||
1778 | */ | ||
1779 | |||
1780 | return 0; | ||
1781 | } | ||
1782 | |||
1783 | static int rtw_cfg80211_set_auth_type(struct security_priv *psecuritypriv, | ||
1784 | enum nl80211_auth_type sme_auth_type) | ||
1785 | { | ||
1786 | DBG_8723A("%s, nl80211_auth_type =%d\n", __func__, sme_auth_type); | ||
1787 | |||
1788 | switch (sme_auth_type) { | ||
1789 | case NL80211_AUTHTYPE_AUTOMATIC: | ||
1790 | psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; | ||
1791 | |||
1792 | break; | ||
1793 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | ||
1794 | psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; | ||
1795 | |||
1796 | if (psecuritypriv->ndisauthtype > Ndis802_11AuthModeWPA) | ||
1797 | psecuritypriv->dot11AuthAlgrthm = | ||
1798 | dot11AuthAlgrthm_8021X; | ||
1799 | break; | ||
1800 | case NL80211_AUTHTYPE_SHARED_KEY: | ||
1801 | psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; | ||
1802 | |||
1803 | psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; | ||
1804 | break; | ||
1805 | default: | ||
1806 | psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; | ||
1807 | /* return -ENOTSUPP; */ | ||
1808 | } | ||
1809 | |||
1810 | return 0; | ||
1811 | } | ||
1812 | |||
1813 | static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv, | ||
1814 | u32 cipher, bool ucast) | ||
1815 | { | ||
1816 | u32 ndisencryptstatus = Ndis802_11EncryptionDisabled; | ||
1817 | |||
1818 | u32 *profile_cipher = ucast ? &psecuritypriv->dot11PrivacyAlgrthm : | ||
1819 | &psecuritypriv->dot118021XGrpPrivacy; | ||
1820 | |||
1821 | DBG_8723A("%s, ucast =%d, cipher = 0x%x\n", __func__, ucast, cipher); | ||
1822 | |||
1823 | if (!cipher) { | ||
1824 | *profile_cipher = _NO_PRIVACY_; | ||
1825 | psecuritypriv->ndisencryptstatus = ndisencryptstatus; | ||
1826 | return 0; | ||
1827 | } | ||
1828 | |||
1829 | switch (cipher) { | ||
1830 | case IW_AUTH_CIPHER_NONE: | ||
1831 | *profile_cipher = _NO_PRIVACY_; | ||
1832 | ndisencryptstatus = Ndis802_11EncryptionDisabled; | ||
1833 | break; | ||
1834 | case WLAN_CIPHER_SUITE_WEP40: | ||
1835 | *profile_cipher = _WEP40_; | ||
1836 | ndisencryptstatus = Ndis802_11Encryption1Enabled; | ||
1837 | break; | ||
1838 | case WLAN_CIPHER_SUITE_WEP104: | ||
1839 | *profile_cipher = _WEP104_; | ||
1840 | ndisencryptstatus = Ndis802_11Encryption1Enabled; | ||
1841 | break; | ||
1842 | case WLAN_CIPHER_SUITE_TKIP: | ||
1843 | *profile_cipher = _TKIP_; | ||
1844 | ndisencryptstatus = Ndis802_11Encryption2Enabled; | ||
1845 | break; | ||
1846 | case WLAN_CIPHER_SUITE_CCMP: | ||
1847 | *profile_cipher = _AES_; | ||
1848 | ndisencryptstatus = Ndis802_11Encryption3Enabled; | ||
1849 | break; | ||
1850 | default: | ||
1851 | DBG_8723A("Unsupported cipher: 0x%x\n", cipher); | ||
1852 | return -ENOTSUPP; | ||
1853 | } | ||
1854 | |||
1855 | if (ucast) | ||
1856 | psecuritypriv->ndisencryptstatus = ndisencryptstatus; | ||
1857 | |||
1858 | return 0; | ||
1859 | } | ||
1860 | |||
1861 | static int rtw_cfg80211_set_key_mgt(struct security_priv *psecuritypriv, | ||
1862 | u32 key_mgt) | ||
1863 | { | ||
1864 | DBG_8723A("%s, key_mgt = 0x%x\n", __func__, key_mgt); | ||
1865 | |||
1866 | if (key_mgt == WLAN_AKM_SUITE_8021X) | ||
1867 | psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; | ||
1868 | else if (key_mgt == WLAN_AKM_SUITE_PSK) | ||
1869 | psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; | ||
1870 | else | ||
1871 | DBG_8723A("Invalid key mgt: 0x%x\n", key_mgt); | ||
1872 | |||
1873 | return 0; | ||
1874 | } | ||
1875 | |||
1876 | static int rtw_cfg80211_set_wpa_ie(struct rtw_adapter *padapter, const u8 *pie, | ||
1877 | size_t ielen) | ||
1878 | { | ||
1879 | u8 *buf = NULL, *pos = NULL; | ||
1880 | int group_cipher = 0, pairwise_cipher = 0; | ||
1881 | int ret = 0; | ||
1882 | int wpa_ielen = 0; | ||
1883 | int wpa2_ielen = 0; | ||
1884 | u8 *pwpa, *pwpa2; | ||
1885 | u8 null_addr[] = { 0, 0, 0, 0, 0, 0 }; | ||
1886 | int i; | ||
1887 | |||
1888 | if (!pie || !ielen) { | ||
1889 | /* Treat this as normal case, but need to clear | ||
1890 | WIFI_UNDER_WPS */ | ||
1891 | _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); | ||
1892 | goto exit; | ||
1893 | } | ||
1894 | if (ielen > MAX_WPA_IE_LEN + MAX_WPS_IE_LEN + MAX_P2P_IE_LEN) { | ||
1895 | ret = -EINVAL; | ||
1896 | goto exit; | ||
1897 | } | ||
1898 | buf = kzalloc(ielen, GFP_KERNEL); | ||
1899 | if (buf == NULL) { | ||
1900 | ret = -ENOMEM; | ||
1901 | goto exit; | ||
1902 | } | ||
1903 | memcpy(buf, pie, ielen); | ||
1904 | |||
1905 | /* dump */ | ||
1906 | DBG_8723A("set wpa_ie(length:%zu):\n", ielen); | ||
1907 | for (i = 0; i < ielen; i = i + 8) | ||
1908 | DBG_8723A("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", | ||
1909 | buf[i], buf[i + 1], | ||
1910 | buf[i + 2], buf[i + 3], buf[i + 4], | ||
1911 | buf[i + 5], buf[i + 6], buf[i + 7]); | ||
1912 | pos = buf; | ||
1913 | if (ielen < RSN_HEADER_LEN) { | ||
1914 | RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, | ||
1915 | ("Ie len too short %d\n", (int)ielen)); | ||
1916 | ret = -1; | ||
1917 | goto exit; | ||
1918 | } | ||
1919 | |||
1920 | pwpa = rtw_get_wpa_ie23a(buf, &wpa_ielen, ielen); | ||
1921 | if (pwpa && wpa_ielen > 0) { | ||
1922 | if (rtw_parse_wpa_ie23a(pwpa, wpa_ielen + 2, &group_cipher, | ||
1923 | &pairwise_cipher, NULL) == _SUCCESS) { | ||
1924 | padapter->securitypriv.dot11AuthAlgrthm = | ||
1925 | dot11AuthAlgrthm_8021X; | ||
1926 | padapter->securitypriv.ndisauthtype = | ||
1927 | Ndis802_11AuthModeWPAPSK; | ||
1928 | memcpy(padapter->securitypriv.supplicant_ie, &pwpa[0], | ||
1929 | wpa_ielen + 2); | ||
1930 | |||
1931 | DBG_8723A("got wpa_ie, wpa_ielen:%u\n", wpa_ielen); | ||
1932 | } | ||
1933 | } | ||
1934 | |||
1935 | pwpa2 = rtw_get_wpa2_ie23a(buf, &wpa2_ielen, ielen); | ||
1936 | if (pwpa2 && wpa2_ielen > 0) { | ||
1937 | if (rtw_parse_wpa2_ie23a (pwpa2, wpa2_ielen + 2, &group_cipher, | ||
1938 | &pairwise_cipher, NULL) == _SUCCESS) { | ||
1939 | padapter->securitypriv.dot11AuthAlgrthm = | ||
1940 | dot11AuthAlgrthm_8021X; | ||
1941 | padapter->securitypriv.ndisauthtype = | ||
1942 | Ndis802_11AuthModeWPA2PSK; | ||
1943 | memcpy(padapter->securitypriv.supplicant_ie, &pwpa2[0], | ||
1944 | wpa2_ielen + 2); | ||
1945 | |||
1946 | DBG_8723A("got wpa2_ie, wpa2_ielen:%u\n", wpa2_ielen); | ||
1947 | } | ||
1948 | } | ||
1949 | |||
1950 | if (group_cipher == 0) { | ||
1951 | group_cipher = WPA_CIPHER_NONE; | ||
1952 | } | ||
1953 | if (pairwise_cipher == 0) { | ||
1954 | pairwise_cipher = WPA_CIPHER_NONE; | ||
1955 | } | ||
1956 | |||
1957 | switch (group_cipher) { | ||
1958 | case WPA_CIPHER_NONE: | ||
1959 | padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; | ||
1960 | padapter->securitypriv.ndisencryptstatus = | ||
1961 | Ndis802_11EncryptionDisabled; | ||
1962 | break; | ||
1963 | case WPA_CIPHER_WEP40: | ||
1964 | padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; | ||
1965 | padapter->securitypriv.ndisencryptstatus = | ||
1966 | Ndis802_11Encryption1Enabled; | ||
1967 | break; | ||
1968 | case WPA_CIPHER_TKIP: | ||
1969 | padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_; | ||
1970 | padapter->securitypriv.ndisencryptstatus = | ||
1971 | Ndis802_11Encryption2Enabled; | ||
1972 | break; | ||
1973 | case WPA_CIPHER_CCMP: | ||
1974 | padapter->securitypriv.dot118021XGrpPrivacy = _AES_; | ||
1975 | padapter->securitypriv.ndisencryptstatus = | ||
1976 | Ndis802_11Encryption3Enabled; | ||
1977 | break; | ||
1978 | case WPA_CIPHER_WEP104: | ||
1979 | padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; | ||
1980 | padapter->securitypriv.ndisencryptstatus = | ||
1981 | Ndis802_11Encryption1Enabled; | ||
1982 | break; | ||
1983 | } | ||
1984 | |||
1985 | switch (pairwise_cipher) { | ||
1986 | case WPA_CIPHER_NONE: | ||
1987 | padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; | ||
1988 | padapter->securitypriv.ndisencryptstatus = | ||
1989 | Ndis802_11EncryptionDisabled; | ||
1990 | break; | ||
1991 | case WPA_CIPHER_WEP40: | ||
1992 | padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; | ||
1993 | padapter->securitypriv.ndisencryptstatus = | ||
1994 | Ndis802_11Encryption1Enabled; | ||
1995 | break; | ||
1996 | case WPA_CIPHER_TKIP: | ||
1997 | padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_; | ||
1998 | padapter->securitypriv.ndisencryptstatus = | ||
1999 | Ndis802_11Encryption2Enabled; | ||
2000 | break; | ||
2001 | case WPA_CIPHER_CCMP: | ||
2002 | padapter->securitypriv.dot11PrivacyAlgrthm = _AES_; | ||
2003 | padapter->securitypriv.ndisencryptstatus = | ||
2004 | Ndis802_11Encryption3Enabled; | ||
2005 | break; | ||
2006 | case WPA_CIPHER_WEP104: | ||
2007 | padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; | ||
2008 | padapter->securitypriv.ndisencryptstatus = | ||
2009 | Ndis802_11Encryption1Enabled; | ||
2010 | break; | ||
2011 | } | ||
2012 | |||
2013 | { /* handle wps_ie */ | ||
2014 | uint wps_ielen; | ||
2015 | u8 *wps_ie; | ||
2016 | |||
2017 | wps_ie = rtw_get_wps_ie23a(buf, ielen, NULL, &wps_ielen); | ||
2018 | if (wps_ie && wps_ielen > 0) { | ||
2019 | DBG_8723A("got wps_ie, wps_ielen:%u\n", wps_ielen); | ||
2020 | padapter->securitypriv.wps_ie_len = | ||
2021 | wps_ielen < | ||
2022 | MAX_WPS_IE_LEN ? wps_ielen : MAX_WPS_IE_LEN; | ||
2023 | memcpy(padapter->securitypriv.wps_ie, wps_ie, | ||
2024 | padapter->securitypriv.wps_ie_len); | ||
2025 | set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS); | ||
2026 | } else { | ||
2027 | _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); | ||
2028 | } | ||
2029 | } | ||
2030 | |||
2031 | #ifdef CONFIG_8723AU_P2P | ||
2032 | { /* check p2p_ie for assoc req; */ | ||
2033 | uint p2p_ielen = 0; | ||
2034 | u8 *p2p_ie; | ||
2035 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
2036 | |||
2037 | p2p_ie = rtw_get_p2p_ie23a(buf, ielen, NULL, &p2p_ielen); | ||
2038 | if (p2p_ie) { | ||
2039 | #ifdef CONFIG_DEBUG_CFG80211 | ||
2040 | DBG_8723A("%s p2p_assoc_req_ielen =%d\n", __func__, | ||
2041 | p2p_ielen); | ||
2042 | #endif | ||
2043 | |||
2044 | if (pmlmepriv->p2p_assoc_req_ie) { | ||
2045 | pmlmepriv->p2p_assoc_req_ie_len = 0; | ||
2046 | kfree(pmlmepriv->p2p_assoc_req_ie); | ||
2047 | pmlmepriv->p2p_assoc_req_ie = NULL; | ||
2048 | } | ||
2049 | |||
2050 | pmlmepriv->p2p_assoc_req_ie = | ||
2051 | kmalloc(p2p_ielen, GFP_KERNEL); | ||
2052 | if (pmlmepriv->p2p_assoc_req_ie == NULL) { | ||
2053 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
2054 | __func__, __LINE__); | ||
2055 | goto exit; | ||
2056 | } | ||
2057 | memcpy(pmlmepriv->p2p_assoc_req_ie, p2p_ie, p2p_ielen); | ||
2058 | pmlmepriv->p2p_assoc_req_ie_len = p2p_ielen; | ||
2059 | } | ||
2060 | } | ||
2061 | #endif /* CONFIG_8723AU_P2P */ | ||
2062 | |||
2063 | #ifdef CONFIG_8723AU_P2P | ||
2064 | { /* check wfd_ie for assoc req; */ | ||
2065 | uint wfd_ielen = 0; | ||
2066 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
2067 | |||
2068 | if (rtw_get_wfd_ie(buf, ielen, NULL, &wfd_ielen)) { | ||
2069 | #ifdef CONFIG_DEBUG_CFG80211 | ||
2070 | DBG_8723A("%s wfd_assoc_req_ielen =%d\n", __func__, | ||
2071 | wfd_ielen); | ||
2072 | #endif | ||
2073 | |||
2074 | if (pmlmepriv->wfd_assoc_req_ie) { | ||
2075 | pmlmepriv->wfd_assoc_req_ie_len = 0; | ||
2076 | kfree(pmlmepriv->wfd_assoc_req_ie); | ||
2077 | pmlmepriv->wfd_assoc_req_ie = NULL; | ||
2078 | } | ||
2079 | |||
2080 | pmlmepriv->wfd_assoc_req_ie = | ||
2081 | kmalloc(wfd_ielen, GFP_KERNEL); | ||
2082 | if (pmlmepriv->wfd_assoc_req_ie == NULL) { | ||
2083 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
2084 | __func__, __LINE__); | ||
2085 | goto exit; | ||
2086 | } | ||
2087 | rtw_get_wfd_ie(buf, ielen, pmlmepriv->wfd_assoc_req_ie, | ||
2088 | &pmlmepriv->wfd_assoc_req_ie_len); | ||
2089 | } | ||
2090 | } | ||
2091 | #endif /* CONFIG_8723AU_P2P */ | ||
2092 | |||
2093 | /* TKIP and AES disallow multicast packets until installing group key */ | ||
2094 | if (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_ || | ||
2095 | padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_ || | ||
2096 | padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) | ||
2097 | /* WPS open need to enable multicast */ | ||
2098 | /* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true)*/ | ||
2099 | rtw_hal_set_hwreg23a(padapter, HW_VAR_OFF_RCR_AM, null_addr); | ||
2100 | |||
2101 | RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, | ||
2102 | ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->" | ||
2103 | "securitypriv.ndisencryptstatus =%d padapter->" | ||
2104 | "securitypriv.ndisauthtype =%d\n", pairwise_cipher, | ||
2105 | padapter->securitypriv.ndisencryptstatus, | ||
2106 | padapter->securitypriv.ndisauthtype)); | ||
2107 | |||
2108 | exit: | ||
2109 | kfree(buf); | ||
2110 | if (ret) | ||
2111 | _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); | ||
2112 | return ret; | ||
2113 | } | ||
2114 | |||
2115 | static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, | ||
2116 | struct cfg80211_connect_params *sme) | ||
2117 | { | ||
2118 | int ret = 0; | ||
2119 | struct list_head *phead, *plist, *ptmp; | ||
2120 | struct wlan_network *pnetwork = NULL; | ||
2121 | enum ndis_802_11_auth_mode authmode; | ||
2122 | struct cfg80211_ssid ndis_ssid; | ||
2123 | u8 *dst_ssid; | ||
2124 | u8 *src_ssid; | ||
2125 | u8 *dst_bssid; | ||
2126 | const u8 *src_bssid; | ||
2127 | /* u8 matched_by_bssid = false; */ | ||
2128 | /* u8 matched_by_ssid = false; */ | ||
2129 | u8 matched = false; | ||
2130 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
2131 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
2132 | struct security_priv *psecuritypriv = &padapter->securitypriv; | ||
2133 | struct rtw_queue *queue = &pmlmepriv->scanned_queue; | ||
2134 | |||
2135 | DBG_8723A("=>" FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
2136 | DBG_8723A("privacy =%d, key =%p, key_len =%d, key_idx =%d\n", | ||
2137 | sme->privacy, sme->key, sme->key_len, sme->key_idx); | ||
2138 | |||
2139 | if (wdev_to_priv(padapter->rtw_wdev)->block) { | ||
2140 | ret = -EBUSY; | ||
2141 | DBG_8723A("%s wdev_priv.block is set\n", __func__); | ||
2142 | goto exit; | ||
2143 | } | ||
2144 | |||
2145 | if (_FAIL == rtw_pwr_wakeup(padapter)) { | ||
2146 | ret = -EPERM; | ||
2147 | goto exit; | ||
2148 | } | ||
2149 | |||
2150 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { | ||
2151 | ret = -EPERM; | ||
2152 | goto exit; | ||
2153 | } | ||
2154 | |||
2155 | if (!sme->ssid || !sme->ssid_len) { | ||
2156 | ret = -EINVAL; | ||
2157 | goto exit; | ||
2158 | } | ||
2159 | |||
2160 | if (sme->ssid_len > IW_ESSID_MAX_SIZE) { | ||
2161 | ret = -E2BIG; | ||
2162 | goto exit; | ||
2163 | } | ||
2164 | |||
2165 | memset(&ndis_ssid, 0, sizeof(struct cfg80211_ssid)); | ||
2166 | ndis_ssid.ssid_len = sme->ssid_len; | ||
2167 | memcpy(ndis_ssid.ssid, sme->ssid, sme->ssid_len); | ||
2168 | |||
2169 | DBG_8723A("ssid =%s, len =%zu\n", ndis_ssid.ssid, sme->ssid_len); | ||
2170 | |||
2171 | if (sme->bssid) | ||
2172 | DBG_8723A("bssid =" MAC_FMT "\n", MAC_ARG(sme->bssid)); | ||
2173 | |||
2174 | if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { | ||
2175 | ret = -EBUSY; | ||
2176 | DBG_8723A("%s, fw_state = 0x%x, goto exit\n", __func__, | ||
2177 | pmlmepriv->fw_state); | ||
2178 | goto exit; | ||
2179 | } | ||
2180 | if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { | ||
2181 | rtw_scan_abort23a(padapter); | ||
2182 | } | ||
2183 | |||
2184 | spin_lock_bh(&queue->lock); | ||
2185 | |||
2186 | phead = get_list_head(queue); | ||
2187 | |||
2188 | list_for_each_safe(plist, ptmp, phead) { | ||
2189 | pnetwork = container_of(plist, struct wlan_network, list); | ||
2190 | |||
2191 | dst_ssid = pnetwork->network.Ssid.ssid; | ||
2192 | dst_bssid = pnetwork->network.MacAddress; | ||
2193 | |||
2194 | if (sme->bssid) { | ||
2195 | if (memcmp(pnetwork->network.MacAddress, | ||
2196 | sme->bssid, ETH_ALEN)) | ||
2197 | continue; | ||
2198 | } | ||
2199 | |||
2200 | if (sme->ssid && sme->ssid_len) { | ||
2201 | if (pnetwork->network.Ssid.ssid_len != sme->ssid_len || | ||
2202 | memcmp(pnetwork->network.Ssid.ssid, sme->ssid, | ||
2203 | sme->ssid_len)) | ||
2204 | continue; | ||
2205 | } | ||
2206 | |||
2207 | if (sme->bssid) { | ||
2208 | src_bssid = sme->bssid; | ||
2209 | |||
2210 | if ((!memcmp(dst_bssid, src_bssid, ETH_ALEN))) { | ||
2211 | DBG_8723A("matched by bssid\n"); | ||
2212 | |||
2213 | ndis_ssid.ssid_len = | ||
2214 | pnetwork->network.Ssid.ssid_len; | ||
2215 | memcpy(ndis_ssid.ssid, | ||
2216 | pnetwork->network.Ssid.ssid, | ||
2217 | pnetwork->network.Ssid.ssid_len); | ||
2218 | |||
2219 | matched = true; | ||
2220 | break; | ||
2221 | } | ||
2222 | |||
2223 | } else if (sme->ssid && sme->ssid_len) { | ||
2224 | src_ssid = ndis_ssid.ssid; | ||
2225 | |||
2226 | if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.ssid_len)) && | ||
2227 | (pnetwork->network.Ssid.ssid_len == | ||
2228 | ndis_ssid.ssid_len)) { | ||
2229 | DBG_8723A("matched by ssid\n"); | ||
2230 | matched = true; | ||
2231 | break; | ||
2232 | } | ||
2233 | } | ||
2234 | } | ||
2235 | |||
2236 | spin_unlock_bh(&queue->lock); | ||
2237 | |||
2238 | if (!matched || (pnetwork == NULL)) { | ||
2239 | ret = -ENOENT; | ||
2240 | DBG_8723A("connect, matched == false, goto exit\n"); | ||
2241 | goto exit; | ||
2242 | } | ||
2243 | |||
2244 | if (rtw_set_802_11_infrastructure_mode23a | ||
2245 | (padapter, pnetwork->network.InfrastructureMode) == false) { | ||
2246 | ret = -EPERM; | ||
2247 | goto exit; | ||
2248 | } | ||
2249 | |||
2250 | psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled; | ||
2251 | psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; | ||
2252 | psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; | ||
2253 | psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; | ||
2254 | psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; | ||
2255 | |||
2256 | ret = | ||
2257 | rtw_cfg80211_set_wpa_version(psecuritypriv, | ||
2258 | sme->crypto.wpa_versions); | ||
2259 | if (ret < 0) | ||
2260 | goto exit; | ||
2261 | |||
2262 | ret = rtw_cfg80211_set_auth_type(psecuritypriv, sme->auth_type); | ||
2263 | |||
2264 | if (ret < 0) | ||
2265 | goto exit; | ||
2266 | |||
2267 | DBG_8723A("%s, ie_len =%zu\n", __func__, sme->ie_len); | ||
2268 | |||
2269 | ret = rtw_cfg80211_set_wpa_ie(padapter, sme->ie, sme->ie_len); | ||
2270 | if (ret < 0) | ||
2271 | goto exit; | ||
2272 | |||
2273 | if (sme->crypto.n_ciphers_pairwise) { | ||
2274 | ret = rtw_cfg80211_set_cipher(psecuritypriv, | ||
2275 | sme->crypto.ciphers_pairwise[0], | ||
2276 | true); | ||
2277 | if (ret < 0) | ||
2278 | goto exit; | ||
2279 | } | ||
2280 | |||
2281 | /* For WEP Shared auth */ | ||
2282 | if ((psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Shared || | ||
2283 | psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Auto) && | ||
2284 | sme->key) { | ||
2285 | u32 wep_key_idx, wep_key_len, wep_total_len; | ||
2286 | struct ndis_802_11_wep *pwep = NULL; | ||
2287 | DBG_8723A("%s(): Shared/Auto WEP\n", __func__); | ||
2288 | |||
2289 | wep_key_idx = sme->key_idx; | ||
2290 | wep_key_len = sme->key_len; | ||
2291 | |||
2292 | if (sme->key_idx > WEP_KEYS) { | ||
2293 | ret = -EINVAL; | ||
2294 | goto exit; | ||
2295 | } | ||
2296 | |||
2297 | if (wep_key_len > 0) { | ||
2298 | wep_key_len = wep_key_len <= 5 ? 5 : 13; | ||
2299 | wep_total_len = | ||
2300 | wep_key_len + | ||
2301 | offsetof(struct ndis_802_11_wep, KeyMaterial); | ||
2302 | pwep = (struct ndis_802_11_wep *)kmalloc(wep_total_len, | ||
2303 | GFP_KERNEL); | ||
2304 | if (pwep == NULL) { | ||
2305 | DBG_8723A(" wpa_set_encryption: pwep " | ||
2306 | "allocate fail !!!\n"); | ||
2307 | ret = -ENOMEM; | ||
2308 | goto exit; | ||
2309 | } | ||
2310 | |||
2311 | memset(pwep, 0, wep_total_len); | ||
2312 | |||
2313 | pwep->KeyLength = wep_key_len; | ||
2314 | pwep->Length = wep_total_len; | ||
2315 | |||
2316 | if (wep_key_len == 13) { | ||
2317 | padapter->securitypriv.dot11PrivacyAlgrthm = | ||
2318 | _WEP104_; | ||
2319 | padapter->securitypriv.dot118021XGrpPrivacy = | ||
2320 | _WEP104_; | ||
2321 | } | ||
2322 | } else { | ||
2323 | ret = -EINVAL; | ||
2324 | goto exit; | ||
2325 | } | ||
2326 | |||
2327 | pwep->KeyIndex = wep_key_idx; | ||
2328 | pwep->KeyIndex |= 0x80000000; | ||
2329 | |||
2330 | memcpy(pwep->KeyMaterial, (void *)sme->key, pwep->KeyLength); | ||
2331 | |||
2332 | if (rtw_set_802_11_add_wep23a(padapter, pwep) == (u8) _FAIL) { | ||
2333 | ret = -EOPNOTSUPP; | ||
2334 | } | ||
2335 | |||
2336 | kfree(pwep); | ||
2337 | |||
2338 | if (ret < 0) | ||
2339 | goto exit; | ||
2340 | } | ||
2341 | |||
2342 | ret = rtw_cfg80211_set_cipher(psecuritypriv, | ||
2343 | sme->crypto.cipher_group, false); | ||
2344 | if (ret < 0) | ||
2345 | return ret; | ||
2346 | |||
2347 | if (sme->crypto.n_akm_suites) { | ||
2348 | ret = rtw_cfg80211_set_key_mgt(psecuritypriv, | ||
2349 | sme->crypto.akm_suites[0]); | ||
2350 | if (ret < 0) | ||
2351 | goto exit; | ||
2352 | } | ||
2353 | |||
2354 | authmode = psecuritypriv->ndisauthtype; | ||
2355 | rtw_set_802_11_authentication_mode23a(padapter, authmode); | ||
2356 | |||
2357 | /* rtw_set_802_11_encryption_mode(padapter, | ||
2358 | padapter->securitypriv.ndisencryptstatus); */ | ||
2359 | |||
2360 | if (rtw_set_802_11_ssid23a(padapter, &ndis_ssid) == false) { | ||
2361 | ret = -1; | ||
2362 | goto exit; | ||
2363 | } | ||
2364 | |||
2365 | DBG_8723A("set ssid:dot11AuthAlgrthm =%d, dot11PrivacyAlgrthm =%d, " | ||
2366 | "dot118021XGrpPrivacy =%d\n", psecuritypriv->dot11AuthAlgrthm, | ||
2367 | psecuritypriv->dot11PrivacyAlgrthm, | ||
2368 | psecuritypriv->dot118021XGrpPrivacy); | ||
2369 | |||
2370 | exit: | ||
2371 | |||
2372 | DBG_8723A("<=%s, ret %d\n", __func__, ret); | ||
2373 | |||
2374 | return ret; | ||
2375 | } | ||
2376 | |||
2377 | static int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev, | ||
2378 | u16 reason_code) | ||
2379 | { | ||
2380 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
2381 | |||
2382 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
2383 | |||
2384 | rtw_set_roaming(padapter, 0); | ||
2385 | |||
2386 | if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { | ||
2387 | rtw_scan_abort23a(padapter); | ||
2388 | LeaveAllPowerSaveMode23a(padapter); | ||
2389 | rtw_disassoc_cmd23a(padapter, 500, false); | ||
2390 | |||
2391 | DBG_8723A("%s...call rtw_indicate_disconnect23a\n", __func__); | ||
2392 | |||
2393 | padapter->mlmepriv.not_indic_disco = true; | ||
2394 | rtw_indicate_disconnect23a(padapter); | ||
2395 | padapter->mlmepriv.not_indic_disco = false; | ||
2396 | |||
2397 | rtw_free_assoc_resources23a(padapter, 1); | ||
2398 | } | ||
2399 | |||
2400 | return 0; | ||
2401 | } | ||
2402 | |||
2403 | static int cfg80211_rtw_set_txpower(struct wiphy *wiphy, | ||
2404 | struct wireless_dev *wdev, | ||
2405 | enum nl80211_tx_power_setting type, int mbm) | ||
2406 | { | ||
2407 | DBG_8723A("%s\n", __func__); | ||
2408 | return 0; | ||
2409 | } | ||
2410 | |||
2411 | static int cfg80211_rtw_get_txpower(struct wiphy *wiphy, | ||
2412 | struct wireless_dev *wdev, int *dbm) | ||
2413 | { | ||
2414 | DBG_8723A("%s\n", __func__); | ||
2415 | *dbm = (12); | ||
2416 | return 0; | ||
2417 | } | ||
2418 | |||
2419 | inline bool rtw_cfg80211_pwr_mgmt(struct rtw_adapter *adapter) | ||
2420 | { | ||
2421 | struct rtw_wdev_priv *rtw_wdev_priv = wdev_to_priv(adapter->rtw_wdev); | ||
2422 | return rtw_wdev_priv->power_mgmt; | ||
2423 | } | ||
2424 | |||
2425 | static int cfg80211_rtw_set_power_mgmt(struct wiphy *wiphy, | ||
2426 | struct net_device *ndev, | ||
2427 | bool enabled, int timeout) | ||
2428 | { | ||
2429 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
2430 | struct rtw_wdev_priv *rtw_wdev_priv = wdev_to_priv(padapter->rtw_wdev); | ||
2431 | |||
2432 | DBG_8723A(FUNC_NDEV_FMT " enabled:%u, timeout:%d\n", | ||
2433 | FUNC_NDEV_ARG(ndev), enabled, timeout); | ||
2434 | |||
2435 | rtw_wdev_priv->power_mgmt = enabled; | ||
2436 | |||
2437 | if (!enabled) | ||
2438 | LPS_Leave23a(padapter); | ||
2439 | |||
2440 | return 0; | ||
2441 | } | ||
2442 | |||
2443 | static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy, | ||
2444 | struct net_device *netdev, | ||
2445 | struct cfg80211_pmksa *pmksa) | ||
2446 | { | ||
2447 | u8 index, blInserted = false; | ||
2448 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
2449 | struct security_priv *psecuritypriv = &padapter->securitypriv; | ||
2450 | u8 strZeroMacAddress[ETH_ALEN] = { 0x00 }; | ||
2451 | |||
2452 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(netdev)); | ||
2453 | |||
2454 | if (!memcmp(pmksa->bssid, strZeroMacAddress, ETH_ALEN)) { | ||
2455 | return -EINVAL; | ||
2456 | } | ||
2457 | |||
2458 | blInserted = false; | ||
2459 | |||
2460 | /* overwrite PMKID */ | ||
2461 | for (index = 0; index < NUM_PMKID_CACHE; index++) { | ||
2462 | if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, | ||
2463 | pmksa->bssid, ETH_ALEN)) { | ||
2464 | /* BSSID is matched, the same AP => rewrite with | ||
2465 | new PMKID. */ | ||
2466 | DBG_8723A(FUNC_NDEV_FMT | ||
2467 | " BSSID exists in the PMKList.\n", | ||
2468 | FUNC_NDEV_ARG(netdev)); | ||
2469 | |||
2470 | memcpy(psecuritypriv->PMKIDList[index].PMKID, | ||
2471 | pmksa->pmkid, WLAN_PMKID_LEN); | ||
2472 | psecuritypriv->PMKIDList[index].bUsed = true; | ||
2473 | psecuritypriv->PMKIDIndex = index + 1; | ||
2474 | blInserted = true; | ||
2475 | break; | ||
2476 | } | ||
2477 | } | ||
2478 | |||
2479 | if (!blInserted) { | ||
2480 | /* Find a new entry */ | ||
2481 | DBG_8723A(FUNC_NDEV_FMT | ||
2482 | " Use the new entry index = %d for this PMKID.\n", | ||
2483 | FUNC_NDEV_ARG(netdev), psecuritypriv->PMKIDIndex); | ||
2484 | |||
2485 | memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex]. | ||
2486 | Bssid, pmksa->bssid, ETH_ALEN); | ||
2487 | memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex]. | ||
2488 | PMKID, pmksa->pmkid, WLAN_PMKID_LEN); | ||
2489 | |||
2490 | psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = | ||
2491 | true; | ||
2492 | psecuritypriv->PMKIDIndex++; | ||
2493 | if (psecuritypriv->PMKIDIndex == 16) { | ||
2494 | psecuritypriv->PMKIDIndex = 0; | ||
2495 | } | ||
2496 | } | ||
2497 | |||
2498 | return 0; | ||
2499 | } | ||
2500 | |||
2501 | static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy, | ||
2502 | struct net_device *netdev, | ||
2503 | struct cfg80211_pmksa *pmksa) | ||
2504 | { | ||
2505 | u8 index, bMatched = false; | ||
2506 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
2507 | struct security_priv *psecuritypriv = &padapter->securitypriv; | ||
2508 | |||
2509 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(netdev)); | ||
2510 | |||
2511 | for (index = 0; index < NUM_PMKID_CACHE; index++) { | ||
2512 | if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, | ||
2513 | pmksa->bssid, ETH_ALEN)) { | ||
2514 | /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ | ||
2515 | memset(psecuritypriv->PMKIDList[index].Bssid, 0x00, | ||
2516 | ETH_ALEN); | ||
2517 | memset(psecuritypriv->PMKIDList[index].PMKID, 0x00, | ||
2518 | WLAN_PMKID_LEN); | ||
2519 | psecuritypriv->PMKIDList[index].bUsed = false; | ||
2520 | bMatched = true; | ||
2521 | break; | ||
2522 | } | ||
2523 | } | ||
2524 | |||
2525 | if (false == bMatched) { | ||
2526 | DBG_8723A(FUNC_NDEV_FMT " do not have matched BSSID\n", | ||
2527 | FUNC_NDEV_ARG(netdev)); | ||
2528 | return -EINVAL; | ||
2529 | } | ||
2530 | |||
2531 | return 0; | ||
2532 | } | ||
2533 | |||
2534 | static int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy, | ||
2535 | struct net_device *netdev) | ||
2536 | { | ||
2537 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
2538 | struct security_priv *psecuritypriv = &padapter->securitypriv; | ||
2539 | |||
2540 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(netdev)); | ||
2541 | |||
2542 | memset(&psecuritypriv->PMKIDList[0], 0x00, | ||
2543 | sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); | ||
2544 | psecuritypriv->PMKIDIndex = 0; | ||
2545 | |||
2546 | return 0; | ||
2547 | } | ||
2548 | |||
2549 | #ifdef CONFIG_8723AU_AP_MODE | ||
2550 | void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter, | ||
2551 | u8 *pmgmt_frame, uint frame_len) | ||
2552 | { | ||
2553 | s32 freq; | ||
2554 | int channel; | ||
2555 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | ||
2556 | struct net_device *ndev = padapter->pnetdev; | ||
2557 | |||
2558 | DBG_8723A("%s(padapter =%p,%s)\n", __func__, padapter, ndev->name); | ||
2559 | |||
2560 | #if defined(RTW_USE_CFG80211_STA_EVENT) | ||
2561 | { | ||
2562 | struct station_info sinfo; | ||
2563 | u8 ie_offset; | ||
2564 | if (ieee80211_is_assoc_req(hdr->frame_control)) | ||
2565 | ie_offset = _ASOCREQ_IE_OFFSET_; | ||
2566 | else /* WIFI_REASSOCREQ */ | ||
2567 | ie_offset = _REASOCREQ_IE_OFFSET_; | ||
2568 | |||
2569 | sinfo.filled = 0; | ||
2570 | sinfo.filled = STATION_INFO_ASSOC_REQ_IES; | ||
2571 | sinfo.assoc_req_ies = pmgmt_frame + WLAN_HDR_A3_LEN + ie_offset; | ||
2572 | sinfo.assoc_req_ies_len = | ||
2573 | frame_len - WLAN_HDR_A3_LEN - ie_offset; | ||
2574 | cfg80211_new_sta(ndev, hdr->addr2, &sinfo, GFP_ATOMIC); | ||
2575 | } | ||
2576 | #else /* defined(RTW_USE_CFG80211_STA_EVENT) */ | ||
2577 | channel = pmlmeext->cur_channel; | ||
2578 | if (channel <= RTW_CH_MAX_2G_CHANNEL) | ||
2579 | freq = ieee80211_channel_to_frequency(channel, | ||
2580 | IEEE80211_BAND_2GHZ); | ||
2581 | else | ||
2582 | freq = ieee80211_channel_to_frequency(channel, | ||
2583 | IEEE80211_BAND_5GHZ); | ||
2584 | |||
2585 | rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len, | ||
2586 | GFP_ATOMIC); | ||
2587 | #endif /* defined(RTW_USE_CFG80211_STA_EVENT) */ | ||
2588 | } | ||
2589 | |||
2590 | void rtw_cfg80211_indicate_sta_disassoc(struct rtw_adapter *padapter, | ||
2591 | unsigned char *da, | ||
2592 | unsigned short reason) | ||
2593 | { | ||
2594 | s32 freq; | ||
2595 | int channel; | ||
2596 | u8 *pmgmt_frame; | ||
2597 | uint frame_len; | ||
2598 | struct ieee80211_hdr *pwlanhdr; | ||
2599 | unsigned short *fctrl; | ||
2600 | u8 mgmt_buf[128] = { 0 }; | ||
2601 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | ||
2602 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; | ||
2603 | struct net_device *ndev = padapter->pnetdev; | ||
2604 | |||
2605 | DBG_8723A("%s(padapter =%p,%s)\n", __func__, padapter, ndev->name); | ||
2606 | |||
2607 | #if defined(RTW_USE_CFG80211_STA_EVENT) | ||
2608 | cfg80211_del_sta(ndev, da, GFP_ATOMIC); | ||
2609 | #else /* defined(RTW_USE_CFG80211_STA_EVENT) */ | ||
2610 | channel = pmlmeext->cur_channel; | ||
2611 | if (channel <= RTW_CH_MAX_2G_CHANNEL) | ||
2612 | freq = ieee80211_channel_to_frequency(channel, | ||
2613 | IEEE80211_BAND_2GHZ); | ||
2614 | else | ||
2615 | freq = ieee80211_channel_to_frequency(channel, | ||
2616 | IEEE80211_BAND_5GHZ); | ||
2617 | |||
2618 | pmgmt_frame = mgmt_buf; | ||
2619 | pwlanhdr = (struct ieee80211_hdr *)pmgmt_frame; | ||
2620 | |||
2621 | fctrl = &pwlanhdr->frame_control; | ||
2622 | *(fctrl) = 0; | ||
2623 | |||
2624 | memcpy(pwlanhdr->addr1, myid(&padapter->eeprompriv), ETH_ALEN); | ||
2625 | memcpy(pwlanhdr->addr2, da, ETH_ALEN); | ||
2626 | memcpy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN); | ||
2627 | |||
2628 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); | ||
2629 | pmlmeext->mgnt_seq++; | ||
2630 | SetFrameSubType(pmgmt_frame, WIFI_DEAUTH); | ||
2631 | |||
2632 | pmgmt_frame += sizeof(struct ieee80211_hdr_3addr); | ||
2633 | frame_len = sizeof(struct ieee80211_hdr_3addr); | ||
2634 | |||
2635 | reason = cpu_to_le16(reason); | ||
2636 | pmgmt_frame = rtw_set_fixed_ie23a(pmgmt_frame, | ||
2637 | WLAN_REASON_PREV_AUTH_NOT_VALID, | ||
2638 | (unsigned char *)&reason, &frame_len); | ||
2639 | |||
2640 | rtw_cfg80211_rx_mgmt(padapter, freq, 0, mgmt_buf, frame_len, | ||
2641 | GFP_ATOMIC); | ||
2642 | #endif /* defined(RTW_USE_CFG80211_STA_EVENT) */ | ||
2643 | } | ||
2644 | |||
2645 | static int rtw_cfg80211_monitor_if_open(struct net_device *ndev) | ||
2646 | { | ||
2647 | int ret = 0; | ||
2648 | |||
2649 | DBG_8723A("%s\n", __func__); | ||
2650 | |||
2651 | return ret; | ||
2652 | } | ||
2653 | |||
2654 | static int rtw_cfg80211_monitor_if_close(struct net_device *ndev) | ||
2655 | { | ||
2656 | int ret = 0; | ||
2657 | |||
2658 | DBG_8723A("%s\n", __func__); | ||
2659 | |||
2660 | return ret; | ||
2661 | } | ||
2662 | |||
2663 | static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, | ||
2664 | struct net_device *ndev) | ||
2665 | { | ||
2666 | int ret = 0; | ||
2667 | int rtap_len; | ||
2668 | int qos_len = 0; | ||
2669 | int dot11_hdr_len = 24; | ||
2670 | int snap_len = 6; | ||
2671 | unsigned char *pdata; | ||
2672 | unsigned char src_mac_addr[6]; | ||
2673 | unsigned char dst_mac_addr[6]; | ||
2674 | struct ieee80211_hdr *dot11_hdr; | ||
2675 | struct ieee80211_radiotap_header *rtap_hdr; | ||
2676 | struct rtw_adapter *padapter = netdev_priv(ndev); | ||
2677 | |||
2678 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
2679 | |||
2680 | if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) | ||
2681 | goto fail; | ||
2682 | |||
2683 | rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; | ||
2684 | if (unlikely(rtap_hdr->it_version)) | ||
2685 | goto fail; | ||
2686 | |||
2687 | rtap_len = ieee80211_get_radiotap_len(skb->data); | ||
2688 | if (unlikely(skb->len < rtap_len)) | ||
2689 | goto fail; | ||
2690 | |||
2691 | if (rtap_len != 14) { | ||
2692 | DBG_8723A("radiotap len (should be 14): %d\n", rtap_len); | ||
2693 | goto fail; | ||
2694 | } | ||
2695 | |||
2696 | /* Skip the ratio tap header */ | ||
2697 | skb_pull(skb, rtap_len); | ||
2698 | |||
2699 | dot11_hdr = (struct ieee80211_hdr *)skb->data; | ||
2700 | /* Check if the QoS bit is set */ | ||
2701 | if (ieee80211_is_data(dot11_hdr->frame_control)) { | ||
2702 | /* Check if this ia a Wireless Distribution System (WDS) frame | ||
2703 | * which has 4 MAC addresses | ||
2704 | */ | ||
2705 | if (ieee80211_is_data_qos(dot11_hdr->frame_control)) | ||
2706 | qos_len = IEEE80211_QOS_CTL_LEN; | ||
2707 | if (ieee80211_has_a4(dot11_hdr->frame_control)) | ||
2708 | dot11_hdr_len += 6; | ||
2709 | |||
2710 | memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); | ||
2711 | memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); | ||
2712 | |||
2713 | /* | ||
2714 | * Skip the 802.11 header, QoS (if any) and SNAP, | ||
2715 | * but leave spaces for two MAC addresses | ||
2716 | */ | ||
2717 | skb_pull(skb, dot11_hdr_len + qos_len + snap_len - | ||
2718 | ETH_ALEN * 2); | ||
2719 | pdata = (unsigned char *)skb->data; | ||
2720 | memcpy(pdata, dst_mac_addr, ETH_ALEN); | ||
2721 | memcpy(pdata + ETH_ALEN, src_mac_addr, ETH_ALEN); | ||
2722 | |||
2723 | DBG_8723A("should be eapol packet\n"); | ||
2724 | |||
2725 | /* Use the real net device to transmit the packet */ | ||
2726 | ret = rtw_xmit23a_entry23a(skb, padapter->pnetdev); | ||
2727 | |||
2728 | return ret; | ||
2729 | |||
2730 | } else if (ieee80211_is_action(dot11_hdr->frame_control)) { | ||
2731 | /* only for action frames */ | ||
2732 | struct xmit_frame *pmgntframe; | ||
2733 | struct pkt_attrib *pattrib; | ||
2734 | unsigned char *pframe; | ||
2735 | /* u8 category, action, OUI_Subtype, dialogToken = 0; */ | ||
2736 | /* unsigned char *frame_body; */ | ||
2737 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
2738 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | ||
2739 | u32 len = skb->len; | ||
2740 | u8 category, action; | ||
2741 | int type = -1; | ||
2742 | |||
2743 | if (rtw_action_frame_parse23a(skb->data, len, &category, | ||
2744 | &action) == false) { | ||
2745 | DBG_8723A(FUNC_NDEV_FMT " frame_control:0x%x\n", | ||
2746 | FUNC_NDEV_ARG(ndev), | ||
2747 | le16_to_cpu(dot11_hdr->frame_control)); | ||
2748 | goto fail; | ||
2749 | } | ||
2750 | |||
2751 | DBG_8723A("RTW_Tx:da =" MAC_FMT " via " FUNC_NDEV_FMT "\n", | ||
2752 | MAC_ARG(dot11_hdr->addr1), FUNC_NDEV_ARG(ndev)); | ||
2753 | #ifdef CONFIG_8723AU_P2P | ||
2754 | type = rtw_p2p_check_frames(padapter, skb->data, len, true); | ||
2755 | if (type >= 0) | ||
2756 | goto dump; | ||
2757 | #endif | ||
2758 | if (category == WLAN_CATEGORY_PUBLIC) | ||
2759 | DBG_8723A("RTW_Tx:%s\n", action_public_str23a(action)); | ||
2760 | else | ||
2761 | DBG_8723A("RTW_Tx:category(%u), action(%u)\n", category, | ||
2762 | action); | ||
2763 | dump: | ||
2764 | /* starting alloc mgmt frame to dump it */ | ||
2765 | pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); | ||
2766 | if (pmgntframe == NULL) | ||
2767 | goto fail; | ||
2768 | |||
2769 | /* update attribute */ | ||
2770 | pattrib = &pmgntframe->attrib; | ||
2771 | update_mgntframe_attrib23a(padapter, pattrib); | ||
2772 | pattrib->retry_ctrl = false; | ||
2773 | |||
2774 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); | ||
2775 | |||
2776 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; | ||
2777 | |||
2778 | memcpy(pframe, skb->data, len); | ||
2779 | #ifdef CONFIG_8723AU_P2P | ||
2780 | if (type >= 0) { | ||
2781 | struct wifi_display_info *pwfd_info; | ||
2782 | |||
2783 | pwfd_info = padapter->wdinfo.wfd_info; | ||
2784 | |||
2785 | if (pwfd_info->wfd_enable) | ||
2786 | rtw_append_wfd_ie(padapter, pframe, &len); | ||
2787 | } | ||
2788 | #endif /* CONFIG_8723AU_P2P */ | ||
2789 | pattrib->pktlen = len; | ||
2790 | |||
2791 | /* update seq number */ | ||
2792 | pmlmeext->mgnt_seq = le16_to_cpu(dot11_hdr->seq_ctrl) >> 4; | ||
2793 | pattrib->seqnum = pmlmeext->mgnt_seq; | ||
2794 | pmlmeext->mgnt_seq++; | ||
2795 | |||
2796 | pattrib->last_txcmdsz = pattrib->pktlen; | ||
2797 | |||
2798 | dump_mgntframe23a(padapter, pmgntframe); | ||
2799 | } | ||
2800 | |||
2801 | fail: | ||
2802 | |||
2803 | dev_kfree_skb(skb); | ||
2804 | |||
2805 | return 0; | ||
2806 | } | ||
2807 | |||
2808 | static int | ||
2809 | rtw_cfg80211_monitor_if_set_mac_address(struct net_device *ndev, void *addr) | ||
2810 | { | ||
2811 | int ret = 0; | ||
2812 | |||
2813 | DBG_8723A("%s\n", __func__); | ||
2814 | |||
2815 | return ret; | ||
2816 | } | ||
2817 | |||
2818 | static const struct net_device_ops rtw_cfg80211_monitor_if_ops = { | ||
2819 | .ndo_open = rtw_cfg80211_monitor_if_open, | ||
2820 | .ndo_stop = rtw_cfg80211_monitor_if_close, | ||
2821 | .ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry, | ||
2822 | .ndo_set_mac_address = rtw_cfg80211_monitor_if_set_mac_address, | ||
2823 | }; | ||
2824 | |||
2825 | static int rtw_cfg80211_add_monitor_if(struct rtw_adapter *padapter, char *name, | ||
2826 | struct net_device **ndev) | ||
2827 | { | ||
2828 | int ret = 0; | ||
2829 | struct net_device *mon_ndev = NULL; | ||
2830 | struct wireless_dev *mon_wdev = NULL; | ||
2831 | struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); | ||
2832 | |||
2833 | if (!name) { | ||
2834 | DBG_8723A(FUNC_ADPT_FMT " without specific name\n", | ||
2835 | FUNC_ADPT_ARG(padapter)); | ||
2836 | ret = -EINVAL; | ||
2837 | goto out; | ||
2838 | } | ||
2839 | |||
2840 | if (pwdev_priv->pmon_ndev) { | ||
2841 | DBG_8723A(FUNC_ADPT_FMT " monitor interface exist: " NDEV_FMT | ||
2842 | "\n", FUNC_ADPT_ARG(padapter), | ||
2843 | NDEV_ARG(pwdev_priv->pmon_ndev)); | ||
2844 | ret = -EBUSY; | ||
2845 | goto out; | ||
2846 | } | ||
2847 | |||
2848 | mon_ndev = alloc_etherdev(sizeof(struct rtw_adapter)); | ||
2849 | if (!mon_ndev) { | ||
2850 | DBG_8723A(FUNC_ADPT_FMT " allocate ndev fail\n", | ||
2851 | FUNC_ADPT_ARG(padapter)); | ||
2852 | ret = -ENOMEM; | ||
2853 | goto out; | ||
2854 | } | ||
2855 | |||
2856 | mon_ndev->type = ARPHRD_IEEE80211_RADIOTAP; | ||
2857 | strncpy(mon_ndev->name, name, IFNAMSIZ); | ||
2858 | mon_ndev->name[IFNAMSIZ - 1] = 0; | ||
2859 | mon_ndev->destructor = rtw_ndev_destructor; | ||
2860 | |||
2861 | mon_ndev->netdev_ops = &rtw_cfg80211_monitor_if_ops; | ||
2862 | |||
2863 | /* wdev */ | ||
2864 | mon_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | ||
2865 | if (!mon_wdev) { | ||
2866 | DBG_8723A(FUNC_ADPT_FMT " allocate mon_wdev fail\n", | ||
2867 | FUNC_ADPT_ARG(padapter)); | ||
2868 | ret = -ENOMEM; | ||
2869 | goto out; | ||
2870 | } | ||
2871 | |||
2872 | mon_wdev->wiphy = padapter->rtw_wdev->wiphy; | ||
2873 | mon_wdev->netdev = mon_ndev; | ||
2874 | mon_wdev->iftype = NL80211_IFTYPE_MONITOR; | ||
2875 | mon_ndev->ieee80211_ptr = mon_wdev; | ||
2876 | |||
2877 | ret = register_netdevice(mon_ndev); | ||
2878 | if (ret) { | ||
2879 | goto out; | ||
2880 | } | ||
2881 | |||
2882 | *ndev = pwdev_priv->pmon_ndev = mon_ndev; | ||
2883 | memcpy(pwdev_priv->ifname_mon, name, IFNAMSIZ + 1); | ||
2884 | |||
2885 | out: | ||
2886 | if (ret) { | ||
2887 | kfree(mon_wdev); | ||
2888 | mon_wdev = NULL; | ||
2889 | } | ||
2890 | |||
2891 | if (ret && mon_ndev) { | ||
2892 | free_netdev(mon_ndev); | ||
2893 | *ndev = mon_ndev = NULL; | ||
2894 | } | ||
2895 | |||
2896 | return ret; | ||
2897 | } | ||
2898 | |||
2899 | static struct wireless_dev * | ||
2900 | cfg80211_rtw_add_virtual_intf(struct wiphy *wiphy, const char *name, | ||
2901 | enum nl80211_iftype type, u32 *flags, | ||
2902 | struct vif_params *params) | ||
2903 | { | ||
2904 | int ret = 0; | ||
2905 | struct net_device *ndev = NULL; | ||
2906 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
2907 | |||
2908 | DBG_8723A(FUNC_ADPT_FMT " wiphy:%s, name:%s, type:%d\n", | ||
2909 | FUNC_ADPT_ARG(padapter), wiphy_name(wiphy), name, type); | ||
2910 | |||
2911 | switch (type) { | ||
2912 | case NL80211_IFTYPE_ADHOC: | ||
2913 | case NL80211_IFTYPE_AP_VLAN: | ||
2914 | case NL80211_IFTYPE_WDS: | ||
2915 | case NL80211_IFTYPE_MESH_POINT: | ||
2916 | ret = -ENODEV; | ||
2917 | break; | ||
2918 | case NL80211_IFTYPE_MONITOR: | ||
2919 | ret = | ||
2920 | rtw_cfg80211_add_monitor_if(padapter, (char *)name, &ndev); | ||
2921 | break; | ||
2922 | |||
2923 | case NL80211_IFTYPE_P2P_CLIENT: | ||
2924 | case NL80211_IFTYPE_STATION: | ||
2925 | ret = -ENODEV; | ||
2926 | break; | ||
2927 | |||
2928 | case NL80211_IFTYPE_P2P_GO: | ||
2929 | case NL80211_IFTYPE_AP: | ||
2930 | ret = -ENODEV; | ||
2931 | break; | ||
2932 | default: | ||
2933 | ret = -ENODEV; | ||
2934 | DBG_8723A("Unsupported interface type\n"); | ||
2935 | break; | ||
2936 | } | ||
2937 | |||
2938 | DBG_8723A(FUNC_ADPT_FMT " ndev:%p, ret:%d\n", FUNC_ADPT_ARG(padapter), | ||
2939 | ndev, ret); | ||
2940 | |||
2941 | return ndev ? ndev->ieee80211_ptr : ERR_PTR(ret); | ||
2942 | } | ||
2943 | |||
2944 | static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy, | ||
2945 | struct wireless_dev *wdev) | ||
2946 | { | ||
2947 | struct rtw_wdev_priv *pwdev_priv = | ||
2948 | (struct rtw_wdev_priv *)wiphy_priv(wiphy); | ||
2949 | struct net_device *ndev; | ||
2950 | ndev = wdev ? wdev->netdev : NULL; | ||
2951 | |||
2952 | if (!ndev) | ||
2953 | goto exit; | ||
2954 | |||
2955 | unregister_netdevice(ndev); | ||
2956 | |||
2957 | if (ndev == pwdev_priv->pmon_ndev) { | ||
2958 | pwdev_priv->pmon_ndev = NULL; | ||
2959 | pwdev_priv->ifname_mon[0] = '\0'; | ||
2960 | DBG_8723A(FUNC_NDEV_FMT " remove monitor interface\n", | ||
2961 | FUNC_NDEV_ARG(ndev)); | ||
2962 | } | ||
2963 | |||
2964 | exit: | ||
2965 | return 0; | ||
2966 | } | ||
2967 | |||
2968 | static int rtw_add_beacon(struct rtw_adapter *adapter, const u8 *head, | ||
2969 | size_t head_len, const u8 *tail, size_t tail_len) | ||
2970 | { | ||
2971 | int ret = 0; | ||
2972 | u8 *pbuf = NULL; | ||
2973 | uint len, wps_ielen = 0; | ||
2974 | uint p2p_ielen = 0; | ||
2975 | u8 got_p2p_ie = false; | ||
2976 | struct mlme_priv *pmlmepriv = &adapter->mlmepriv; | ||
2977 | /* struct sta_priv *pstapriv = &padapter->stapriv; */ | ||
2978 | |||
2979 | DBG_8723A("%s beacon_head_len =%zu, beacon_tail_len =%zu\n", | ||
2980 | __func__, head_len, tail_len); | ||
2981 | |||
2982 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) | ||
2983 | return -EINVAL; | ||
2984 | |||
2985 | if (head_len < 24) | ||
2986 | return -EINVAL; | ||
2987 | |||
2988 | pbuf = kzalloc(head_len + tail_len, GFP_KERNEL); | ||
2989 | if (!pbuf) | ||
2990 | return -ENOMEM; | ||
2991 | /* 24 = beacon header len. */ | ||
2992 | memcpy(pbuf, (void *)head + 24, head_len - 24); | ||
2993 | memcpy(pbuf + head_len - 24, (void *)tail, tail_len); | ||
2994 | |||
2995 | len = head_len + tail_len - 24; | ||
2996 | |||
2997 | /* check wps ie if inclued */ | ||
2998 | if (rtw_get_wps_ie23a | ||
2999 | (pbuf + _FIXED_IE_LENGTH_, len - _FIXED_IE_LENGTH_, NULL, | ||
3000 | &wps_ielen)) | ||
3001 | DBG_8723A("add bcn, wps_ielen =%d\n", wps_ielen); | ||
3002 | |||
3003 | #ifdef CONFIG_8723AU_P2P | ||
3004 | /* check p2p ie if inclued */ | ||
3005 | if (rtw_get_p2p_ie23a | ||
3006 | (pbuf + _FIXED_IE_LENGTH_, len - _FIXED_IE_LENGTH_, NULL, | ||
3007 | &p2p_ielen)) { | ||
3008 | DBG_8723A("got p2p_ie, len =%d\n", p2p_ielen); | ||
3009 | got_p2p_ie = true; | ||
3010 | } | ||
3011 | #endif | ||
3012 | |||
3013 | /* pbss_network->IEs will not include p2p_ie, wfd ie */ | ||
3014 | rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, | ||
3015 | P2P_OUI23A, 4); | ||
3016 | rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, | ||
3017 | WFD_OUI23A, 4); | ||
3018 | |||
3019 | if (rtw_check_beacon_data23a(adapter, pbuf, len) == _SUCCESS) { | ||
3020 | #ifdef CONFIG_8723AU_P2P | ||
3021 | /* check p2p if enable */ | ||
3022 | if (got_p2p_ie == true) { | ||
3023 | struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; | ||
3024 | struct wifidirect_info *pwdinfo = &adapter->wdinfo; | ||
3025 | |||
3026 | if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { | ||
3027 | DBG_8723A("Enable P2P function for the first " | ||
3028 | "time\n"); | ||
3029 | rtw_p2p_enable23a(adapter, P2P_ROLE_GO); | ||
3030 | wdev_to_priv(adapter->rtw_wdev)->p2p_enabled = | ||
3031 | true; | ||
3032 | } else { | ||
3033 | del_timer_sync(&pwdinfo->find_phase_timer); | ||
3034 | del_timer_sync(&pwdinfo-> | ||
3035 | restore_p2p_state_timer); | ||
3036 | del_timer_sync(&pwdinfo->pre_tx_scan_timer); | ||
3037 | |||
3038 | DBG_8723A("enter GO Mode, p2p_ielen =%d\n", | ||
3039 | p2p_ielen); | ||
3040 | |||
3041 | rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); | ||
3042 | rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); | ||
3043 | pwdinfo->intent = 15; | ||
3044 | } | ||
3045 | |||
3046 | pwdinfo->operating_channel = pmlmeext->cur_channel; | ||
3047 | } | ||
3048 | #endif /* CONFIG_8723AU_P2P */ | ||
3049 | |||
3050 | ret = 0; | ||
3051 | |||
3052 | } else { | ||
3053 | ret = -EINVAL; | ||
3054 | } | ||
3055 | |||
3056 | kfree(pbuf); | ||
3057 | |||
3058 | return ret; | ||
3059 | } | ||
3060 | |||
3061 | static int cfg80211_rtw_start_ap(struct wiphy *wiphy, struct net_device *ndev, | ||
3062 | struct cfg80211_ap_settings *settings) | ||
3063 | { | ||
3064 | int ret = 0; | ||
3065 | struct rtw_adapter *adapter = wiphy_to_adapter(wiphy); | ||
3066 | |||
3067 | DBG_8723A(FUNC_NDEV_FMT " hidden_ssid:%d, auth_type:%d\n", | ||
3068 | FUNC_NDEV_ARG(ndev), settings->hidden_ssid, | ||
3069 | settings->auth_type); | ||
3070 | |||
3071 | ret = rtw_add_beacon(adapter, settings->beacon.head, | ||
3072 | settings->beacon.head_len, settings->beacon.tail, | ||
3073 | settings->beacon.tail_len); | ||
3074 | |||
3075 | adapter->mlmeextpriv.mlmext_info.hidden_ssid_mode = | ||
3076 | settings->hidden_ssid; | ||
3077 | |||
3078 | if (settings->ssid && settings->ssid_len) { | ||
3079 | struct wlan_bssid_ex *pbss_network = | ||
3080 | &adapter->mlmepriv.cur_network.network; | ||
3081 | struct wlan_bssid_ex *pbss_network_ext = | ||
3082 | &adapter->mlmeextpriv.mlmext_info.network; | ||
3083 | |||
3084 | if (0) | ||
3085 | DBG_8723A(FUNC_ADPT_FMT | ||
3086 | " ssid:(%s,%d), from ie:(%s,%d)\n", | ||
3087 | FUNC_ADPT_ARG(adapter), settings->ssid, | ||
3088 | (int)settings->ssid_len, | ||
3089 | pbss_network->Ssid.ssid, | ||
3090 | pbss_network->Ssid.ssid_len); | ||
3091 | |||
3092 | memcpy(pbss_network->Ssid.ssid, (void *)settings->ssid, | ||
3093 | settings->ssid_len); | ||
3094 | pbss_network->Ssid.ssid_len = settings->ssid_len; | ||
3095 | memcpy(pbss_network_ext->Ssid.ssid, (void *)settings->ssid, | ||
3096 | settings->ssid_len); | ||
3097 | pbss_network_ext->Ssid.ssid_len = settings->ssid_len; | ||
3098 | |||
3099 | if (0) | ||
3100 | DBG_8723A(FUNC_ADPT_FMT | ||
3101 | " after ssid:(%s,%d), (%s,%d)\n", | ||
3102 | FUNC_ADPT_ARG(adapter), | ||
3103 | pbss_network->Ssid.ssid, | ||
3104 | pbss_network->Ssid.ssid_len, | ||
3105 | pbss_network_ext->Ssid.ssid, | ||
3106 | pbss_network_ext->Ssid.ssid_len); | ||
3107 | } | ||
3108 | |||
3109 | return ret; | ||
3110 | } | ||
3111 | |||
3112 | static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, | ||
3113 | struct net_device *ndev, | ||
3114 | struct cfg80211_beacon_data *info) | ||
3115 | { | ||
3116 | int ret = 0; | ||
3117 | struct rtw_adapter *adapter = wiphy_to_adapter(wiphy); | ||
3118 | |||
3119 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
3120 | |||
3121 | ret = rtw_add_beacon(adapter, info->head, info->head_len, info->tail, | ||
3122 | info->tail_len); | ||
3123 | |||
3124 | return ret; | ||
3125 | } | ||
3126 | |||
3127 | static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev) | ||
3128 | { | ||
3129 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
3130 | return 0; | ||
3131 | } | ||
3132 | |||
3133 | static int cfg80211_rtw_add_station(struct wiphy *wiphy, | ||
3134 | struct net_device *ndev, u8 *mac, | ||
3135 | struct station_parameters *params) | ||
3136 | { | ||
3137 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
3138 | |||
3139 | return 0; | ||
3140 | } | ||
3141 | |||
3142 | static int cfg80211_rtw_del_station(struct wiphy *wiphy, | ||
3143 | struct net_device *ndev, u8 *mac) | ||
3144 | { | ||
3145 | int ret = 0; | ||
3146 | struct list_head *phead, *plist, *ptmp; | ||
3147 | u8 updated = 0; | ||
3148 | struct sta_info *psta; | ||
3149 | struct rtw_adapter *padapter = netdev_priv(ndev); | ||
3150 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
3151 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
3152 | |||
3153 | DBG_8723A("+" FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
3154 | |||
3155 | if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true) { | ||
3156 | DBG_8723A("%s, fw_state != FW_LINKED|WIFI_AP_STATE\n", | ||
3157 | __func__); | ||
3158 | return -EINVAL; | ||
3159 | } | ||
3160 | |||
3161 | if (!mac) { | ||
3162 | DBG_8723A("flush all sta, and cam_entry\n"); | ||
3163 | |||
3164 | flush_all_cam_entry23a(padapter); /* clear CAM */ | ||
3165 | |||
3166 | ret = rtw_sta_flush23a(padapter); | ||
3167 | |||
3168 | return ret; | ||
3169 | } | ||
3170 | |||
3171 | DBG_8723A("free sta macaddr =" MAC_FMT "\n", MAC_ARG(mac)); | ||
3172 | |||
3173 | if (is_broadcast_ether_addr(mac)) | ||
3174 | return -EINVAL; | ||
3175 | |||
3176 | spin_lock_bh(&pstapriv->asoc_list_lock); | ||
3177 | |||
3178 | phead = &pstapriv->asoc_list; | ||
3179 | |||
3180 | /* check asoc_queue */ | ||
3181 | list_for_each_safe(plist, ptmp, phead) { | ||
3182 | psta = container_of(plist, struct sta_info, asoc_list); | ||
3183 | |||
3184 | if (!memcmp(mac, psta->hwaddr, ETH_ALEN)) { | ||
3185 | if (psta->dot8021xalg == 1 && | ||
3186 | psta->bpairwise_key_installed == false) { | ||
3187 | DBG_8723A("%s, sta's dot8021xalg = 1 and " | ||
3188 | "key_installed = false\n", __func__); | ||
3189 | } else { | ||
3190 | DBG_8723A("free psta =%p, aid =%d\n", psta, | ||
3191 | psta->aid); | ||
3192 | |||
3193 | list_del_init(&psta->asoc_list); | ||
3194 | pstapriv->asoc_list_cnt--; | ||
3195 | |||
3196 | /* spin_unlock_bh(&pstapriv->asoc_list_lock); */ | ||
3197 | updated = | ||
3198 | ap_free_sta23a(padapter, psta, true, | ||
3199 | WLAN_REASON_DEAUTH_LEAVING); | ||
3200 | /* spin_lock_bh(&pstapriv->asoc_list_lock); */ | ||
3201 | |||
3202 | psta = NULL; | ||
3203 | |||
3204 | break; | ||
3205 | } | ||
3206 | } | ||
3207 | } | ||
3208 | |||
3209 | spin_unlock_bh(&pstapriv->asoc_list_lock); | ||
3210 | |||
3211 | associated_clients_update23a(padapter, updated); | ||
3212 | |||
3213 | DBG_8723A("-" FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
3214 | |||
3215 | return ret; | ||
3216 | } | ||
3217 | |||
3218 | static int cfg80211_rtw_change_station(struct wiphy *wiphy, | ||
3219 | struct net_device *ndev, u8 *mac, | ||
3220 | struct station_parameters *params) | ||
3221 | { | ||
3222 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
3223 | return 0; | ||
3224 | } | ||
3225 | |||
3226 | static int cfg80211_rtw_dump_station(struct wiphy *wiphy, | ||
3227 | struct net_device *ndev, int idx, u8 *mac, | ||
3228 | struct station_info *sinfo) | ||
3229 | { | ||
3230 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
3231 | |||
3232 | /* TODO: dump scanned queue */ | ||
3233 | |||
3234 | return -ENOENT; | ||
3235 | } | ||
3236 | |||
3237 | static int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev, | ||
3238 | struct bss_parameters *params) | ||
3239 | { | ||
3240 | DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); | ||
3241 | return 0; | ||
3242 | } | ||
3243 | #endif /* CONFIG_8723AU_AP_MODE */ | ||
3244 | |||
3245 | void rtw_cfg80211_rx_action_p2p(struct rtw_adapter *padapter, u8 *pmgmt_frame, | ||
3246 | uint frame_len) | ||
3247 | { | ||
3248 | int type; | ||
3249 | s32 freq; | ||
3250 | int channel; | ||
3251 | u8 category, action; | ||
3252 | |||
3253 | channel = rtw_get_oper_ch23a(padapter); | ||
3254 | |||
3255 | DBG_8723A("RTW_Rx:cur_ch =%d\n", channel); | ||
3256 | #ifdef CONFIG_8723AU_P2P | ||
3257 | type = rtw_p2p_check_frames(padapter, pmgmt_frame, frame_len, false); | ||
3258 | if (type >= 0) | ||
3259 | goto indicate; | ||
3260 | #endif | ||
3261 | rtw_action_frame_parse23a(pmgmt_frame, frame_len, &category, &action); | ||
3262 | DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, action); | ||
3263 | |||
3264 | indicate: | ||
3265 | if (channel <= RTW_CH_MAX_2G_CHANNEL) | ||
3266 | freq = ieee80211_channel_to_frequency(channel, | ||
3267 | IEEE80211_BAND_2GHZ); | ||
3268 | else | ||
3269 | freq = ieee80211_channel_to_frequency(channel, | ||
3270 | IEEE80211_BAND_5GHZ); | ||
3271 | |||
3272 | rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len, | ||
3273 | GFP_ATOMIC); | ||
3274 | } | ||
3275 | |||
3276 | void rtw_cfg80211_rx_p2p_action_public(struct rtw_adapter *padapter, | ||
3277 | u8 *pmgmt_frame, uint frame_len) | ||
3278 | { | ||
3279 | int type; | ||
3280 | s32 freq; | ||
3281 | int channel; | ||
3282 | u8 category, action; | ||
3283 | |||
3284 | channel = rtw_get_oper_ch23a(padapter); | ||
3285 | |||
3286 | DBG_8723A("RTW_Rx:cur_ch =%d\n", channel); | ||
3287 | #ifdef CONFIG_8723AU_P2P | ||
3288 | type = rtw_p2p_check_frames(padapter, pmgmt_frame, frame_len, false); | ||
3289 | if (type >= 0) { | ||
3290 | switch (type) { | ||
3291 | case P2P_GO_NEGO_CONF: | ||
3292 | case P2P_PROVISION_DISC_RESP: | ||
3293 | rtw_clear_scan_deny(padapter); | ||
3294 | } | ||
3295 | goto indicate; | ||
3296 | } | ||
3297 | #endif | ||
3298 | rtw_action_frame_parse23a(pmgmt_frame, frame_len, &category, &action); | ||
3299 | DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, action); | ||
3300 | |||
3301 | indicate: | ||
3302 | if (channel <= RTW_CH_MAX_2G_CHANNEL) | ||
3303 | freq = ieee80211_channel_to_frequency(channel, | ||
3304 | IEEE80211_BAND_2GHZ); | ||
3305 | else | ||
3306 | freq = ieee80211_channel_to_frequency(channel, | ||
3307 | IEEE80211_BAND_5GHZ); | ||
3308 | |||
3309 | rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len, | ||
3310 | GFP_ATOMIC); | ||
3311 | } | ||
3312 | |||
3313 | void rtw_cfg80211_rx_action(struct rtw_adapter *adapter, u8 *frame, | ||
3314 | uint frame_len, const char *msg) | ||
3315 | { | ||
3316 | s32 freq; | ||
3317 | int channel; | ||
3318 | u8 category, action; | ||
3319 | |||
3320 | channel = rtw_get_oper_ch23a(adapter); | ||
3321 | |||
3322 | rtw_action_frame_parse23a(frame, frame_len, &category, &action); | ||
3323 | |||
3324 | DBG_8723A("RTW_Rx:cur_ch =%d\n", channel); | ||
3325 | if (msg) | ||
3326 | DBG_8723A("RTW_Rx:%s\n", msg); | ||
3327 | else | ||
3328 | DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, | ||
3329 | action); | ||
3330 | |||
3331 | if (channel <= RTW_CH_MAX_2G_CHANNEL) | ||
3332 | freq = ieee80211_channel_to_frequency(channel, | ||
3333 | IEEE80211_BAND_2GHZ); | ||
3334 | else | ||
3335 | freq = ieee80211_channel_to_frequency(channel, | ||
3336 | IEEE80211_BAND_5GHZ); | ||
3337 | |||
3338 | rtw_cfg80211_rx_mgmt(adapter, freq, 0, frame, frame_len, GFP_ATOMIC); | ||
3339 | } | ||
3340 | |||
3341 | #ifdef CONFIG_8723AU_P2P | ||
3342 | void rtw_cfg80211_issue_p2p_provision_request23a(struct rtw_adapter *padapter, | ||
3343 | const u8 *buf, size_t len) | ||
3344 | { | ||
3345 | u16 wps_devicepassword_id = 0x0000; | ||
3346 | uint wps_devicepassword_id_len = 0; | ||
3347 | u8 wpsie[255] = { 0x00 }, p2p_ie[255] = { 0x00 }; | ||
3348 | uint p2p_ielen = 0; | ||
3349 | uint wpsielen = 0; | ||
3350 | u32 devinfo_contentlen = 0; | ||
3351 | u8 devinfo_content[64] = { 0x00 }; | ||
3352 | u16 capability = 0; | ||
3353 | uint capability_len = 0; | ||
3354 | |||
3355 | unsigned char category = WLAN_CATEGORY_PUBLIC; | ||
3356 | u8 action = P2P_PUB_ACTION_ACTION; | ||
3357 | u8 dialogToken = 1; | ||
3358 | u32 p2poui = cpu_to_be32(P2POUI); | ||
3359 | u8 oui_subtype = P2P_PROVISION_DISC_REQ; | ||
3360 | u32 p2pielen = 0; | ||
3361 | #ifdef CONFIG_8723AU_P2P | ||
3362 | u32 wfdielen = 0; | ||
3363 | #endif /* CONFIG_8723AU_P2P */ | ||
3364 | |||
3365 | struct xmit_frame *pmgntframe; | ||
3366 | struct pkt_attrib *pattrib; | ||
3367 | unsigned char *pframe; | ||
3368 | struct ieee80211_hdr *pwlanhdr, *hdr; | ||
3369 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
3370 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | ||
3371 | |||
3372 | struct wifidirect_info *pwdinfo = &padapter->wdinfo; | ||
3373 | u8 *frame_body = | ||
3374 | (unsigned char *)(buf + sizeof(struct ieee80211_hdr_3addr)); | ||
3375 | size_t frame_body_len = len - sizeof(struct ieee80211_hdr_3addr); | ||
3376 | |||
3377 | DBG_8723A("[%s] In\n", __func__); | ||
3378 | |||
3379 | hdr = (struct ieee80211_hdr *)buf; | ||
3380 | /* prepare for building provision_request frame */ | ||
3381 | memcpy(pwdinfo->tx_prov_disc_info.peerIFAddr, hdr->addr1, ETH_ALEN); | ||
3382 | memcpy(pwdinfo->tx_prov_disc_info.peerDevAddr, hdr->addr1, ETH_ALEN); | ||
3383 | |||
3384 | pwdinfo->tx_prov_disc_info.wps_config_method_request = | ||
3385 | WPS_CM_PUSH_BUTTON; | ||
3386 | |||
3387 | rtw_get_wps_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, | ||
3388 | frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, | ||
3389 | &wpsielen); | ||
3390 | rtw_get_wps_attr_content23a(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, | ||
3391 | (u8 *)&wps_devicepassword_id, | ||
3392 | &wps_devicepassword_id_len); | ||
3393 | wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id); | ||
3394 | |||
3395 | switch (wps_devicepassword_id) { | ||
3396 | case WPS_DPID_PIN: | ||
3397 | pwdinfo->tx_prov_disc_info.wps_config_method_request = | ||
3398 | WPS_CM_LABEL; | ||
3399 | break; | ||
3400 | case WPS_DPID_USER_SPEC: | ||
3401 | pwdinfo->tx_prov_disc_info.wps_config_method_request = | ||
3402 | WPS_CM_DISPLYA; | ||
3403 | break; | ||
3404 | case WPS_DPID_MACHINE_SPEC: | ||
3405 | break; | ||
3406 | case WPS_DPID_REKEY: | ||
3407 | break; | ||
3408 | case WPS_DPID_PBC: | ||
3409 | pwdinfo->tx_prov_disc_info.wps_config_method_request = | ||
3410 | WPS_CM_PUSH_BUTTON; | ||
3411 | break; | ||
3412 | case WPS_DPID_REGISTRAR_SPEC: | ||
3413 | pwdinfo->tx_prov_disc_info.wps_config_method_request = | ||
3414 | WPS_CM_KEYPAD; | ||
3415 | break; | ||
3416 | default: | ||
3417 | break; | ||
3418 | } | ||
3419 | |||
3420 | if (rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, | ||
3421 | frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, | ||
3422 | p2p_ie, &p2p_ielen)) { | ||
3423 | rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, | ||
3424 | P2P_ATTR_DEVICE_INFO, devinfo_content, | ||
3425 | &devinfo_contentlen); | ||
3426 | rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, | ||
3427 | (u8 *)&capability, &capability_len); | ||
3428 | } | ||
3429 | |||
3430 | /* start to build provision_request frame */ | ||
3431 | memset(wpsie, 0, sizeof(wpsie)); | ||
3432 | memset(p2p_ie, 0, sizeof(p2p_ie)); | ||
3433 | p2p_ielen = 0; | ||
3434 | |||
3435 | pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); | ||
3436 | if (pmgntframe == NULL) | ||
3437 | return; | ||
3438 | /* update attribute */ | ||
3439 | pattrib = &pmgntframe->attrib; | ||
3440 | update_mgntframe_attrib23a(padapter, pattrib); | ||
3441 | |||
3442 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); | ||
3443 | |||
3444 | pframe = (u8 *) (pmgntframe->buf_addr) + TXDESC_OFFSET; | ||
3445 | pwlanhdr = (struct ieee80211_hdr *)pframe; | ||
3446 | |||
3447 | pwlanhdr->frame_control = 0; | ||
3448 | |||
3449 | memcpy(pwlanhdr->addr1, pwdinfo->tx_prov_disc_info.peerDevAddr, | ||
3450 | ETH_ALEN); | ||
3451 | memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); | ||
3452 | memcpy(pwlanhdr->addr3, pwdinfo->tx_prov_disc_info.peerDevAddr, | ||
3453 | ETH_ALEN); | ||
3454 | |||
3455 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); | ||
3456 | pmlmeext->mgnt_seq++; | ||
3457 | SetFrameSubType(pframe, WIFI_ACTION); | ||
3458 | |||
3459 | pframe += sizeof(struct ieee80211_hdr_3addr); | ||
3460 | pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); | ||
3461 | |||
3462 | pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); | ||
3463 | pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); | ||
3464 | pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, | ||
3465 | &pattrib->pktlen); | ||
3466 | pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); | ||
3467 | pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); | ||
3468 | |||
3469 | /* build_prov_disc_request_p2p_ie23a */ | ||
3470 | /* P2P OUI */ | ||
3471 | p2pielen = 0; | ||
3472 | p2p_ie[p2pielen++] = 0x50; | ||
3473 | p2p_ie[p2pielen++] = 0x6F; | ||
3474 | p2p_ie[p2pielen++] = 0x9A; | ||
3475 | p2p_ie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ | ||
3476 | |||
3477 | /* Commented by Albert 20110301 */ | ||
3478 | /* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */ | ||
3479 | /* 1. P2P Capability */ | ||
3480 | /* 2. Device Info */ | ||
3481 | /* 3. Group ID ( When joining an operating P2P Group ) */ | ||
3482 | |||
3483 | /* P2P Capability ATTR */ | ||
3484 | /* Type: */ | ||
3485 | p2p_ie[p2pielen++] = P2P_ATTR_CAPABILITY; | ||
3486 | |||
3487 | /* Length: */ | ||
3488 | RTW_PUT_LE16(p2p_ie + p2pielen, 0x0002); | ||
3489 | p2pielen += 2; | ||
3490 | |||
3491 | /* Value: */ | ||
3492 | /* Device Capability Bitmap, 1 byte */ | ||
3493 | /* Group Capability Bitmap, 1 byte */ | ||
3494 | memcpy(p2p_ie + p2pielen, &capability, 2); | ||
3495 | p2pielen += 2; | ||
3496 | |||
3497 | /* Device Info ATTR */ | ||
3498 | /* Type: */ | ||
3499 | p2p_ie[p2pielen++] = P2P_ATTR_DEVICE_INFO; | ||
3500 | |||
3501 | /* Length: */ | ||
3502 | RTW_PUT_LE16(p2p_ie + p2pielen, devinfo_contentlen); | ||
3503 | p2pielen += 2; | ||
3504 | |||
3505 | /* Value: */ | ||
3506 | memcpy(p2p_ie + p2pielen, devinfo_content, devinfo_contentlen); | ||
3507 | p2pielen += devinfo_contentlen; | ||
3508 | |||
3509 | pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, | ||
3510 | (unsigned char *)p2p_ie, &p2p_ielen); | ||
3511 | pattrib->pktlen += p2p_ielen; | ||
3512 | |||
3513 | wpsielen = 0; | ||
3514 | /* WPS OUI */ | ||
3515 | *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); | ||
3516 | wpsielen += 4; | ||
3517 | |||
3518 | /* WPS version */ | ||
3519 | /* Type: */ | ||
3520 | *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); | ||
3521 | wpsielen += 2; | ||
3522 | |||
3523 | /* Length: */ | ||
3524 | *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); | ||
3525 | wpsielen += 2; | ||
3526 | |||
3527 | /* Value: */ | ||
3528 | wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ | ||
3529 | |||
3530 | /* Config Method */ | ||
3531 | /* Type: */ | ||
3532 | *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); | ||
3533 | wpsielen += 2; | ||
3534 | |||
3535 | /* Length: */ | ||
3536 | *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); | ||
3537 | wpsielen += 2; | ||
3538 | |||
3539 | /* Value: */ | ||
3540 | *(u16 *)(wpsie + wpsielen) = | ||
3541 | cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request); | ||
3542 | wpsielen += 2; | ||
3543 | |||
3544 | pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, | ||
3545 | (unsigned char *)wpsie, &pattrib->pktlen); | ||
3546 | |||
3547 | #ifdef CONFIG_8723AU_P2P | ||
3548 | wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe); | ||
3549 | pframe += wfdielen; | ||
3550 | pattrib->pktlen += wfdielen; | ||
3551 | #endif /* CONFIG_8723AU_P2P */ | ||
3552 | |||
3553 | pattrib->last_txcmdsz = pattrib->pktlen; | ||
3554 | |||
3555 | /* dump_mgntframe23a(padapter, pmgntframe); */ | ||
3556 | if (dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe) != _SUCCESS) | ||
3557 | DBG_8723A("%s, ack to\n", __func__); | ||
3558 | } | ||
3559 | |||
3560 | static s32 cfg80211_rtw_remain_on_channel(struct wiphy *wiphy, | ||
3561 | struct wireless_dev *wdev, | ||
3562 | struct ieee80211_channel *channel, | ||
3563 | unsigned int duration, u64 *cookie) | ||
3564 | { | ||
3565 | s32 err = 0; | ||
3566 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
3567 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | ||
3568 | struct wifidirect_info *pwdinfo = &padapter->wdinfo; | ||
3569 | struct cfg80211_wifidirect_info *pcfg80211_wdinfo = | ||
3570 | &padapter->cfg80211_wdinfo; | ||
3571 | u8 remain_ch = | ||
3572 | (u8) ieee80211_frequency_to_channel(channel->center_freq); | ||
3573 | u8 ready_on_channel = false; | ||
3574 | |||
3575 | DBG_8723A(FUNC_ADPT_FMT " ch:%u duration:%d\n", FUNC_ADPT_ARG(padapter), | ||
3576 | remain_ch, duration); | ||
3577 | |||
3578 | if (pcfg80211_wdinfo->is_ro_ch == true) { | ||
3579 | DBG_8723A("%s, cancel ro ch timer\n", __func__); | ||
3580 | |||
3581 | del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); | ||
3582 | |||
3583 | p2p_protocol_wk_hdl23a(padapter, P2P_RO_CH_WK); | ||
3584 | } | ||
3585 | |||
3586 | pcfg80211_wdinfo->is_ro_ch = true; | ||
3587 | |||
3588 | if (_FAIL == rtw_pwr_wakeup(padapter)) { | ||
3589 | err = -EFAULT; | ||
3590 | goto exit; | ||
3591 | } | ||
3592 | |||
3593 | memcpy(&pcfg80211_wdinfo->remain_on_ch_channel, channel, | ||
3594 | sizeof(struct ieee80211_channel)); | ||
3595 | pcfg80211_wdinfo->remain_on_ch_cookie = *cookie; | ||
3596 | |||
3597 | rtw_scan_abort23a(padapter); | ||
3598 | if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { | ||
3599 | rtw_p2p_enable23a(padapter, P2P_ROLE_DEVICE); | ||
3600 | wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = true; | ||
3601 | } else { | ||
3602 | rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); | ||
3603 | #ifdef CONFIG_DEBUG_CFG80211 | ||
3604 | DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__, | ||
3605 | rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); | ||
3606 | #endif | ||
3607 | } | ||
3608 | |||
3609 | rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); | ||
3610 | |||
3611 | if (duration < 400) | ||
3612 | duration = duration * 3; /* extend from exper. */ | ||
3613 | |||
3614 | pcfg80211_wdinfo->restore_channel = pmlmeext->cur_channel; | ||
3615 | |||
3616 | if (rtw_ch_set_search_ch23a(pmlmeext->channel_set, remain_ch) >= 0) { | ||
3617 | if (remain_ch != pmlmeext->cur_channel) { | ||
3618 | ready_on_channel = true; | ||
3619 | } | ||
3620 | } else { | ||
3621 | DBG_8723A("%s remain_ch:%u not in channel plan!!!!\n", | ||
3622 | __func__, remain_ch); | ||
3623 | } | ||
3624 | |||
3625 | /* call this after other things have been done */ | ||
3626 | if (ready_on_channel == true) { | ||
3627 | if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { | ||
3628 | pmlmeext->cur_channel = remain_ch; | ||
3629 | |||
3630 | set_channel_bwmode23a(padapter, remain_ch, | ||
3631 | HAL_PRIME_CHNL_OFFSET_DONT_CARE, | ||
3632 | HT_CHANNEL_WIDTH_20); | ||
3633 | } | ||
3634 | } | ||
3635 | DBG_8723A("%s, set ro ch timer, duration =%d\n", __func__, duration); | ||
3636 | mod_timer(&pcfg80211_wdinfo->remain_on_ch_timer, | ||
3637 | jiffies + msecs_to_jiffies(duration)); | ||
3638 | |||
3639 | rtw_cfg80211_ready_on_channel(padapter, *cookie, channel, channel_type, | ||
3640 | duration, GFP_KERNEL); | ||
3641 | |||
3642 | pwdinfo->listen_channel = pmlmeext->cur_channel; | ||
3643 | |||
3644 | exit: | ||
3645 | if (err) | ||
3646 | pcfg80211_wdinfo->is_ro_ch = false; | ||
3647 | |||
3648 | return err; | ||
3649 | } | ||
3650 | |||
3651 | static s32 cfg80211_rtw_cancel_remain_on_channel(struct wiphy *wiphy, | ||
3652 | struct wireless_dev *wdev, | ||
3653 | u64 cookie) | ||
3654 | { | ||
3655 | s32 err = 0; | ||
3656 | struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); | ||
3657 | struct wifidirect_info *pwdinfo = &padapter->wdinfo; | ||
3658 | struct cfg80211_wifidirect_info *pcfg80211_wdinfo = | ||
3659 | &padapter->cfg80211_wdinfo; | ||
3660 | |||
3661 | DBG_8723A(FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); | ||
3662 | |||
3663 | if (pcfg80211_wdinfo->is_ro_ch == true) { | ||
3664 | DBG_8723A("%s, cancel ro ch timer\n", __func__); | ||
3665 | del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); | ||
3666 | p2p_protocol_wk_hdl23a(padapter, P2P_RO_CH_WK); | ||
3667 | } | ||
3668 | |||
3669 | rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); | ||
3670 | #ifdef CONFIG_DEBUG_CFG80211 | ||
3671 | DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__, | ||
3672 | rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); | ||
3673 | #endif | ||
3674 | pcfg80211_wdinfo->is_ro_ch = false; | ||
3675 | |||
3676 | return err; | ||
3677 | } | ||
3678 | |||
3679 | #endif /* CONFIG_8723AU_P2P */ | ||
3680 | |||
3681 | static int _cfg80211_rtw_mgmt_tx(struct rtw_adapter *padapter, u8 tx_ch, | ||
3682 | const u8 *buf, size_t len) | ||
3683 | { | ||
3684 | struct xmit_frame *pmgntframe; | ||
3685 | struct pkt_attrib *pattrib; | ||
3686 | unsigned char *pframe; | ||
3687 | int ret = _FAIL; | ||
3688 | bool ack = true; | ||
3689 | struct ieee80211_hdr *pwlanhdr; | ||
3690 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
3691 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | ||
3692 | /* struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; */ | ||
3693 | |||
3694 | if (_FAIL == rtw_pwr_wakeup(padapter)) { | ||
3695 | ret = -EFAULT; | ||
3696 | goto exit; | ||
3697 | } | ||
3698 | |||
3699 | rtw_set_scan_deny(padapter, 1000); | ||
3700 | |||
3701 | rtw_scan_abort23a(padapter); | ||
3702 | |||
3703 | if (tx_ch != rtw_get_oper_ch23a(padapter)) { | ||
3704 | if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) | ||
3705 | pmlmeext->cur_channel = tx_ch; | ||
3706 | set_channel_bwmode23a(padapter, tx_ch, | ||
3707 | HAL_PRIME_CHNL_OFFSET_DONT_CARE, | ||
3708 | HT_CHANNEL_WIDTH_20); | ||
3709 | } | ||
3710 | |||
3711 | /* starting alloc mgmt frame to dump it */ | ||
3712 | pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); | ||
3713 | if (pmgntframe == NULL) { | ||
3714 | /* ret = -ENOMEM; */ | ||
3715 | ret = _FAIL; | ||
3716 | goto exit; | ||
3717 | } | ||
3718 | |||
3719 | /* update attribute */ | ||
3720 | pattrib = &pmgntframe->attrib; | ||
3721 | update_mgntframe_attrib23a(padapter, pattrib); | ||
3722 | pattrib->retry_ctrl = false; | ||
3723 | |||
3724 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); | ||
3725 | |||
3726 | pframe = (u8 *) (pmgntframe->buf_addr) + TXDESC_OFFSET; | ||
3727 | |||
3728 | memcpy(pframe, (void *)buf, len); | ||
3729 | pattrib->pktlen = len; | ||
3730 | |||
3731 | pwlanhdr = (struct ieee80211_hdr *)pframe; | ||
3732 | /* update seq number */ | ||
3733 | pmlmeext->mgnt_seq = le16_to_cpu(pwlanhdr->seq_ctrl) >> 4; | ||
3734 | pattrib->seqnum = pmlmeext->mgnt_seq; | ||
3735 | pmlmeext->mgnt_seq++; | ||
3736 | |||
3737 | #ifdef CONFIG_8723AU_P2P | ||
3738 | { | ||
3739 | struct wifi_display_info *pwfd_info; | ||
3740 | |||
3741 | pwfd_info = padapter->wdinfo.wfd_info; | ||
3742 | |||
3743 | if (true == pwfd_info->wfd_enable) { | ||
3744 | rtw_append_wfd_ie(padapter, pframe, &pattrib->pktlen); | ||
3745 | } | ||
3746 | } | ||
3747 | #endif /* CONFIG_8723AU_P2P */ | ||
3748 | |||
3749 | pattrib->last_txcmdsz = pattrib->pktlen; | ||
3750 | |||
3751 | if (dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe) != _SUCCESS) { | ||
3752 | ack = false; | ||
3753 | ret = _FAIL; | ||
3754 | |||
3755 | #ifdef CONFIG_DEBUG_CFG80211 | ||
3756 | DBG_8723A("%s, ack == _FAIL\n", __func__); | ||
3757 | #endif | ||
3758 | } else { | ||
3759 | #ifdef CONFIG_DEBUG_CFG80211 | ||
3760 | DBG_8723A("%s, ack =%d, ok!\n", __func__, ack); | ||
3761 | #endif | ||
3762 | ret = _SUCCESS; | ||
3763 | } | ||
3764 | |||
3765 | exit: | ||
3766 | |||
3767 | #ifdef CONFIG_DEBUG_CFG80211 | ||
3768 | DBG_8723A("%s, ret =%d\n", __func__, ret); | ||
3769 | #endif | ||
3770 | |||
3771 | return ret; | ||
3772 | } | ||
3773 | |||
3774 | static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
3775 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) | ||
3776 | struct ieee80211_channel *chan, | ||
3777 | bool offchan, | ||
3778 | unsigned int wait, | ||
3779 | const u8 *buf, size_t len, | ||
3780 | bool no_cck, bool dont_wait_for_ack, | ||
3781 | #else | ||
3782 | struct cfg80211_mgmt_tx_params *params, | ||
3783 | #endif | ||
3784 | u64 *cookie) | ||
3785 | { | ||
3786 | struct rtw_adapter *padapter = | ||
3787 | (struct rtw_adapter *)wiphy_to_adapter(wiphy); | ||
3788 | struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); | ||
3789 | int ret = 0; | ||
3790 | int tx_ret; | ||
3791 | u32 dump_limit = RTW_MAX_MGMT_TX_CNT; | ||
3792 | u32 dump_cnt = 0; | ||
3793 | bool ack = true; | ||
3794 | u8 category, action; | ||
3795 | int type = (-1); | ||
3796 | unsigned long start = jiffies; | ||
3797 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) | ||
3798 | size_t len = params->len; | ||
3799 | struct ieee80211_channel *chan = params->chan; | ||
3800 | const u8 *buf = params->buf; | ||
3801 | #endif | ||
3802 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)buf; | ||
3803 | u8 tx_ch = (u8) ieee80211_frequency_to_channel(chan->center_freq); | ||
3804 | |||
3805 | /* cookie generation */ | ||
3806 | *cookie = (unsigned long)buf; | ||
3807 | |||
3808 | #ifdef CONFIG_DEBUG_CFG80211 | ||
3809 | DBG_8723A(FUNC_ADPT_FMT " len =%zu, ch =%d" | ||
3810 | "\n", FUNC_ADPT_ARG(padapter), len, tx_ch); | ||
3811 | #endif /* CONFIG_DEBUG_CFG80211 */ | ||
3812 | |||
3813 | /* indicate ack before issue frame to avoid racing with rsp frame */ | ||
3814 | rtw_cfg80211_mgmt_tx_status(padapter, *cookie, buf, len, ack, | ||
3815 | GFP_KERNEL); | ||
3816 | |||
3817 | if (rtw_action_frame_parse23a(buf, len, &category, &action) == false) { | ||
3818 | DBG_8723A(FUNC_ADPT_FMT " frame_control:0x%x\n", | ||
3819 | FUNC_ADPT_ARG(padapter), | ||
3820 | le16_to_cpu(hdr->frame_control)); | ||
3821 | goto exit; | ||
3822 | } | ||
3823 | |||
3824 | DBG_8723A("RTW_Tx:tx_ch =%d, da =" MAC_FMT "\n", tx_ch, | ||
3825 | MAC_ARG(hdr->addr1)); | ||
3826 | #ifdef CONFIG_8723AU_P2P | ||
3827 | type = rtw_p2p_check_frames(padapter, buf, len, true); | ||
3828 | if (type >= 0) | ||
3829 | goto dump; | ||
3830 | #endif | ||
3831 | if (category == WLAN_CATEGORY_PUBLIC) | ||
3832 | DBG_8723A("RTW_Tx:%s\n", action_public_str23a(action)); | ||
3833 | else | ||
3834 | DBG_8723A("RTW_Tx:category(%u), action(%u)\n", | ||
3835 | category, action); | ||
3836 | |||
3837 | dump: | ||
3838 | do { | ||
3839 | dump_cnt++; | ||
3840 | tx_ret = _cfg80211_rtw_mgmt_tx(padapter, tx_ch, buf, len); | ||
3841 | } while (dump_cnt < dump_limit && tx_ret != _SUCCESS); | ||
3842 | |||
3843 | if (tx_ret != _SUCCESS || dump_cnt > 1) { | ||
3844 | DBG_8723A(FUNC_ADPT_FMT " %s (%d/%d) in %d ms\n", | ||
3845 | FUNC_ADPT_ARG(padapter), | ||
3846 | tx_ret == _SUCCESS ? "OK" : "FAIL", dump_cnt, | ||
3847 | dump_limit, jiffies_to_msecs(jiffies - start)); | ||
3848 | } | ||
3849 | |||
3850 | switch (type) { | ||
3851 | case P2P_GO_NEGO_CONF: | ||
3852 | rtw_clear_scan_deny(padapter); | ||
3853 | break; | ||
3854 | case P2P_INVIT_RESP: | ||
3855 | if (pwdev_priv->invit_info.flags & BIT(0) | ||
3856 | && pwdev_priv->invit_info.status == 0) { | ||
3857 | DBG_8723A(FUNC_ADPT_FMT " agree with invitation of " | ||
3858 | "persistent group\n", | ||
3859 | FUNC_ADPT_ARG(padapter)); | ||
3860 | rtw_set_scan_deny(padapter, 5000); | ||
3861 | rtw_pwr_wakeup_ex(padapter, 5000); | ||
3862 | rtw_clear_scan_deny(padapter); | ||
3863 | } | ||
3864 | break; | ||
3865 | } | ||
3866 | |||
3867 | exit: | ||
3868 | return ret; | ||
3869 | } | ||
3870 | |||
3871 | static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, | ||
3872 | struct wireless_dev *wdev, | ||
3873 | u16 frame_type, bool reg) | ||
3874 | { | ||
3875 | |||
3876 | #ifdef CONFIG_DEBUG_CFG80211 | ||
3877 | DBG_8723A(FUNC_ADPT_FMT " frame_type:%x, reg:%d\n", | ||
3878 | FUNC_ADPT_ARG(adapter), frame_type, reg); | ||
3879 | #endif | ||
3880 | |||
3881 | if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) | ||
3882 | return; | ||
3883 | |||
3884 | return; | ||
3885 | } | ||
3886 | |||
3887 | static int rtw_cfg80211_set_beacon_wpsp2pie(struct net_device *ndev, char *buf, | ||
3888 | int len) | ||
3889 | { | ||
3890 | int ret = 0; | ||
3891 | uint wps_ielen = 0; | ||
3892 | u8 *wps_ie; | ||
3893 | u32 p2p_ielen = 0; | ||
3894 | u8 wps_oui[8] = { 0x0, 0x50, 0xf2, 0x04 }; | ||
3895 | u8 *p2p_ie; | ||
3896 | u32 wfd_ielen = 0; | ||
3897 | struct rtw_adapter *padapter = netdev_priv(ndev); | ||
3898 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
3899 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | ||
3900 | |||
3901 | DBG_8723A(FUNC_NDEV_FMT " ielen =%d\n", FUNC_NDEV_ARG(ndev), len); | ||
3902 | |||
3903 | if (len > 0) { | ||
3904 | wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen); | ||
3905 | if (wps_ie) { | ||
3906 | #ifdef CONFIG_DEBUG_CFG80211 | ||
3907 | DBG_8723A("bcn_wps_ielen =%d\n", wps_ielen); | ||
3908 | #endif | ||
3909 | |||
3910 | if (pmlmepriv->wps_beacon_ie) { | ||
3911 | pmlmepriv->wps_beacon_ie_len = 0; | ||
3912 | kfree(pmlmepriv->wps_beacon_ie); | ||
3913 | pmlmepriv->wps_beacon_ie = NULL; | ||
3914 | } | ||
3915 | |||
3916 | pmlmepriv->wps_beacon_ie = | ||
3917 | kmalloc(wps_ielen, GFP_KERNEL); | ||
3918 | if (pmlmepriv->wps_beacon_ie == NULL) { | ||
3919 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
3920 | __func__, __LINE__); | ||
3921 | return -EINVAL; | ||
3922 | } | ||
3923 | memcpy(pmlmepriv->wps_beacon_ie, wps_ie, wps_ielen); | ||
3924 | pmlmepriv->wps_beacon_ie_len = wps_ielen; | ||
3925 | |||
3926 | update_beacon23a(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, | ||
3927 | true); | ||
3928 | } | ||
3929 | #ifdef CONFIG_8723AU_P2P | ||
3930 | p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen); | ||
3931 | if (p2p_ie) { | ||
3932 | #ifdef CONFIG_DEBUG_CFG80211 | ||
3933 | DBG_8723A("bcn_p2p_ielen =%d\n", p2p_ielen); | ||
3934 | #endif | ||
3935 | |||
3936 | if (pmlmepriv->p2p_beacon_ie) { | ||
3937 | pmlmepriv->p2p_beacon_ie_len = 0; | ||
3938 | kfree(pmlmepriv->p2p_beacon_ie); | ||
3939 | pmlmepriv->p2p_beacon_ie = NULL; | ||
3940 | } | ||
3941 | |||
3942 | pmlmepriv->p2p_beacon_ie = | ||
3943 | kmalloc(p2p_ielen, GFP_KERNEL); | ||
3944 | if (pmlmepriv->p2p_beacon_ie == NULL) { | ||
3945 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
3946 | __func__, __LINE__); | ||
3947 | return -EINVAL; | ||
3948 | } | ||
3949 | |||
3950 | memcpy(pmlmepriv->p2p_beacon_ie, p2p_ie, p2p_ielen); | ||
3951 | pmlmepriv->p2p_beacon_ie_len = p2p_ielen; | ||
3952 | } | ||
3953 | #endif /* CONFIG_8723AU_P2P */ | ||
3954 | |||
3955 | /* buf += p2p_ielen; */ | ||
3956 | /* len -= p2p_ielen; */ | ||
3957 | |||
3958 | #ifdef CONFIG_8723AU_P2P | ||
3959 | if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) { | ||
3960 | #ifdef CONFIG_DEBUG_CFG80211 | ||
3961 | DBG_8723A("bcn_wfd_ielen =%d\n", wfd_ielen); | ||
3962 | #endif | ||
3963 | |||
3964 | if (pmlmepriv->wfd_beacon_ie) { | ||
3965 | pmlmepriv->wfd_beacon_ie_len = 0; | ||
3966 | kfree(pmlmepriv->wfd_beacon_ie); | ||
3967 | pmlmepriv->wfd_beacon_ie = NULL; | ||
3968 | } | ||
3969 | |||
3970 | pmlmepriv->wfd_beacon_ie = | ||
3971 | kmalloc(wfd_ielen, GFP_KERNEL); | ||
3972 | if (pmlmepriv->wfd_beacon_ie == NULL) { | ||
3973 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
3974 | __func__, __LINE__); | ||
3975 | return -EINVAL; | ||
3976 | |||
3977 | } | ||
3978 | rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_beacon_ie, | ||
3979 | &pmlmepriv->wfd_beacon_ie_len); | ||
3980 | } | ||
3981 | #endif /* CONFIG_8723AU_P2P */ | ||
3982 | |||
3983 | pmlmeext->bstart_bss = true; | ||
3984 | |||
3985 | } | ||
3986 | |||
3987 | return ret; | ||
3988 | } | ||
3989 | |||
3990 | static int rtw_cfg80211_set_probe_resp_wpsp2pie(struct net_device *net, | ||
3991 | char *buf, int len) | ||
3992 | { | ||
3993 | struct rtw_adapter *padapter = netdev_priv(net); | ||
3994 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
3995 | int ret = 0; | ||
3996 | uint wps_ielen = 0; | ||
3997 | u8 *wps_ie; | ||
3998 | u32 p2p_ielen = 0; | ||
3999 | u8 *p2p_ie; | ||
4000 | u32 wfd_ielen = 0; | ||
4001 | |||
4002 | if (len > 0) { | ||
4003 | wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen); | ||
4004 | if (wps_ie) { | ||
4005 | uint attr_contentlen = 0; | ||
4006 | u16 uconfig_method, *puconfig_method = NULL; | ||
4007 | |||
4008 | if (pmlmepriv->wps_probe_resp_ie) { | ||
4009 | pmlmepriv->wps_probe_resp_ie_len = 0; | ||
4010 | kfree(pmlmepriv->wps_probe_resp_ie); | ||
4011 | pmlmepriv->wps_probe_resp_ie = NULL; | ||
4012 | } | ||
4013 | |||
4014 | pmlmepriv->wps_probe_resp_ie = | ||
4015 | kmalloc(wps_ielen, GFP_KERNEL); | ||
4016 | if (pmlmepriv->wps_probe_resp_ie == NULL) { | ||
4017 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
4018 | __func__, __LINE__); | ||
4019 | return -EINVAL; | ||
4020 | |||
4021 | } | ||
4022 | |||
4023 | /* add PUSH_BUTTON config_method by driver self in | ||
4024 | wpsie of probe_resp at GO Mode */ | ||
4025 | puconfig_method = (u16 *)rtw_get_wps_attr_content23a(wps_ie, wps_ielen, | ||
4026 | WPS_ATTR_CONF_METHOD, | ||
4027 | NULL, | ||
4028 | &attr_contentlen); | ||
4029 | if (puconfig_method) { | ||
4030 | uconfig_method = WPS_CM_PUSH_BUTTON; | ||
4031 | uconfig_method = cpu_to_be16(uconfig_method); | ||
4032 | |||
4033 | *puconfig_method |= uconfig_method; | ||
4034 | } | ||
4035 | |||
4036 | memcpy(pmlmepriv->wps_probe_resp_ie, wps_ie, wps_ielen); | ||
4037 | pmlmepriv->wps_probe_resp_ie_len = wps_ielen; | ||
4038 | |||
4039 | } | ||
4040 | |||
4041 | /* buf += wps_ielen; */ | ||
4042 | /* len -= wps_ielen; */ | ||
4043 | |||
4044 | #ifdef CONFIG_8723AU_P2P | ||
4045 | p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen); | ||
4046 | if (p2p_ie) { | ||
4047 | u8 is_GO = false; | ||
4048 | u32 attr_contentlen = 0; | ||
4049 | u16 cap_attr = 0; | ||
4050 | |||
4051 | #ifdef CONFIG_DEBUG_CFG80211 | ||
4052 | DBG_8723A("probe_resp_p2p_ielen =%d\n", p2p_ielen); | ||
4053 | #endif | ||
4054 | |||
4055 | /* Check P2P Capability ATTR */ | ||
4056 | if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, | ||
4057 | P2P_ATTR_CAPABILITY, | ||
4058 | (u8 *) &cap_attr, | ||
4059 | (uint *) &attr_contentlen)) { | ||
4060 | u8 grp_cap = 0; | ||
4061 | /* DBG_8723A( "[%s] Got P2P Capability Attr!!\n", __func__ ); */ | ||
4062 | cap_attr = le16_to_cpu(cap_attr); | ||
4063 | grp_cap = (u8) ((cap_attr >> 8) & 0xff); | ||
4064 | |||
4065 | is_GO = (grp_cap & BIT(0)) ? true : false; | ||
4066 | |||
4067 | if (is_GO) | ||
4068 | DBG_8723A | ||
4069 | ("Got P2P Capability Attr, grp_cap" | ||
4070 | "= 0x%x, is_GO\n", grp_cap); | ||
4071 | } | ||
4072 | |||
4073 | if (is_GO == false) { | ||
4074 | if (pmlmepriv->p2p_probe_resp_ie) { | ||
4075 | pmlmepriv->p2p_probe_resp_ie_len = 0; | ||
4076 | kfree(pmlmepriv->p2p_probe_resp_ie); | ||
4077 | pmlmepriv->p2p_probe_resp_ie = NULL; | ||
4078 | } | ||
4079 | |||
4080 | pmlmepriv->p2p_probe_resp_ie = | ||
4081 | kmalloc(p2p_ielen, GFP_KERNEL); | ||
4082 | if (pmlmepriv->p2p_probe_resp_ie == NULL) { | ||
4083 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
4084 | __func__, __LINE__); | ||
4085 | return -EINVAL; | ||
4086 | } | ||
4087 | memcpy(pmlmepriv->p2p_probe_resp_ie, p2p_ie, | ||
4088 | p2p_ielen); | ||
4089 | pmlmepriv->p2p_probe_resp_ie_len = p2p_ielen; | ||
4090 | } else { | ||
4091 | if (pmlmepriv->p2p_go_probe_resp_ie) { | ||
4092 | pmlmepriv->p2p_go_probe_resp_ie_len = 0; | ||
4093 | kfree(pmlmepriv->p2p_go_probe_resp_ie); | ||
4094 | pmlmepriv->p2p_go_probe_resp_ie = NULL; | ||
4095 | } | ||
4096 | |||
4097 | pmlmepriv->p2p_go_probe_resp_ie = | ||
4098 | kmalloc(p2p_ielen, GFP_KERNEL); | ||
4099 | if (pmlmepriv->p2p_go_probe_resp_ie == NULL) { | ||
4100 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
4101 | __func__, __LINE__); | ||
4102 | return -EINVAL; | ||
4103 | |||
4104 | } | ||
4105 | memcpy(pmlmepriv->p2p_go_probe_resp_ie, | ||
4106 | p2p_ie, p2p_ielen); | ||
4107 | pmlmepriv->p2p_go_probe_resp_ie_len = p2p_ielen; | ||
4108 | } | ||
4109 | } | ||
4110 | #endif /* CONFIG_8723AU_P2P */ | ||
4111 | |||
4112 | /* buf += p2p_ielen; */ | ||
4113 | /* len -= p2p_ielen; */ | ||
4114 | |||
4115 | #ifdef CONFIG_8723AU_P2P | ||
4116 | if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) { | ||
4117 | #ifdef CONFIG_DEBUG_CFG80211 | ||
4118 | DBG_8723A("probe_resp_wfd_ielen =%d\n", wfd_ielen); | ||
4119 | #endif | ||
4120 | |||
4121 | if (pmlmepriv->wfd_probe_resp_ie) { | ||
4122 | pmlmepriv->wfd_probe_resp_ie_len = 0; | ||
4123 | kfree(pmlmepriv->wfd_probe_resp_ie); | ||
4124 | pmlmepriv->wfd_probe_resp_ie = NULL; | ||
4125 | } | ||
4126 | |||
4127 | pmlmepriv->wfd_probe_resp_ie = | ||
4128 | kmalloc(wfd_ielen, GFP_KERNEL); | ||
4129 | if (pmlmepriv->wfd_probe_resp_ie == NULL) { | ||
4130 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
4131 | __func__, __LINE__); | ||
4132 | return -EINVAL; | ||
4133 | |||
4134 | } | ||
4135 | rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_probe_resp_ie, | ||
4136 | &pmlmepriv->wfd_probe_resp_ie_len); | ||
4137 | } | ||
4138 | #endif /* CONFIG_8723AU_P2P */ | ||
4139 | } | ||
4140 | |||
4141 | return ret; | ||
4142 | } | ||
4143 | |||
4144 | static int rtw_cfg80211_set_assoc_resp_wpsp2pie(struct net_device *net, | ||
4145 | char *buf, int len) | ||
4146 | { | ||
4147 | int ret = 0; | ||
4148 | struct rtw_adapter *padapter = netdev_priv(net); | ||
4149 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
4150 | |||
4151 | DBG_8723A("%s, ielen =%d\n", __func__, len); | ||
4152 | |||
4153 | if (len > 0) { | ||
4154 | if (pmlmepriv->wps_assoc_resp_ie) { | ||
4155 | pmlmepriv->wps_assoc_resp_ie_len = 0; | ||
4156 | kfree(pmlmepriv->wps_assoc_resp_ie); | ||
4157 | pmlmepriv->wps_assoc_resp_ie = NULL; | ||
4158 | } | ||
4159 | |||
4160 | pmlmepriv->wps_assoc_resp_ie = kmalloc(len, GFP_KERNEL); | ||
4161 | if (pmlmepriv->wps_assoc_resp_ie == NULL) { | ||
4162 | DBG_8723A("%s()-%d: kmalloc() ERROR!\n", | ||
4163 | __func__, __LINE__); | ||
4164 | return -EINVAL; | ||
4165 | |||
4166 | } | ||
4167 | memcpy(pmlmepriv->wps_assoc_resp_ie, buf, len); | ||
4168 | pmlmepriv->wps_assoc_resp_ie_len = len; | ||
4169 | } | ||
4170 | |||
4171 | return ret; | ||
4172 | } | ||
4173 | |||
4174 | int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len, | ||
4175 | int type) | ||
4176 | { | ||
4177 | int ret = 0; | ||
4178 | uint wps_ielen = 0; | ||
4179 | u32 p2p_ielen = 0; | ||
4180 | |||
4181 | #ifdef CONFIG_DEBUG_CFG80211 | ||
4182 | DBG_8723A("%s, ielen =%d\n", __func__, len); | ||
4183 | #endif | ||
4184 | |||
4185 | if ((rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen) && (wps_ielen > 0)) | ||
4186 | #ifdef CONFIG_8723AU_P2P | ||
4187 | || (rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen) && (p2p_ielen > 0)) | ||
4188 | #endif | ||
4189 | ) { | ||
4190 | if (net) { | ||
4191 | switch (type) { | ||
4192 | case 0x1: /* BEACON */ | ||
4193 | ret = | ||
4194 | rtw_cfg80211_set_beacon_wpsp2pie(net, buf, | ||
4195 | len); | ||
4196 | break; | ||
4197 | case 0x2: /* PROBE_RESP */ | ||
4198 | ret = | ||
4199 | rtw_cfg80211_set_probe_resp_wpsp2pie(net, | ||
4200 | buf, | ||
4201 | len); | ||
4202 | break; | ||
4203 | case 0x4: /* ASSOC_RESP */ | ||
4204 | ret = | ||
4205 | rtw_cfg80211_set_assoc_resp_wpsp2pie(net, | ||
4206 | buf, | ||
4207 | len); | ||
4208 | break; | ||
4209 | } | ||
4210 | } | ||
4211 | } | ||
4212 | |||
4213 | return ret; | ||
4214 | |||
4215 | } | ||
4216 | |||
4217 | static struct cfg80211_ops rtw_cfg80211_ops = { | ||
4218 | .change_virtual_intf = cfg80211_rtw_change_iface, | ||
4219 | .add_key = cfg80211_rtw_add_key, | ||
4220 | .get_key = cfg80211_rtw_get_key, | ||
4221 | .del_key = cfg80211_rtw_del_key, | ||
4222 | .set_default_key = cfg80211_rtw_set_default_key, | ||
4223 | .get_station = cfg80211_rtw_get_station, | ||
4224 | .scan = cfg80211_rtw_scan, | ||
4225 | .set_wiphy_params = cfg80211_rtw_set_wiphy_params, | ||
4226 | .connect = cfg80211_rtw_connect, | ||
4227 | .disconnect = cfg80211_rtw_disconnect, | ||
4228 | .join_ibss = cfg80211_rtw_join_ibss, | ||
4229 | .leave_ibss = cfg80211_rtw_leave_ibss, | ||
4230 | .set_tx_power = cfg80211_rtw_set_txpower, | ||
4231 | .get_tx_power = cfg80211_rtw_get_txpower, | ||
4232 | .set_power_mgmt = cfg80211_rtw_set_power_mgmt, | ||
4233 | .set_pmksa = cfg80211_rtw_set_pmksa, | ||
4234 | .del_pmksa = cfg80211_rtw_del_pmksa, | ||
4235 | .flush_pmksa = cfg80211_rtw_flush_pmksa, | ||
4236 | |||
4237 | #ifdef CONFIG_8723AU_AP_MODE | ||
4238 | .add_virtual_intf = cfg80211_rtw_add_virtual_intf, | ||
4239 | .del_virtual_intf = cfg80211_rtw_del_virtual_intf, | ||
4240 | |||
4241 | .start_ap = cfg80211_rtw_start_ap, | ||
4242 | .change_beacon = cfg80211_rtw_change_beacon, | ||
4243 | .stop_ap = cfg80211_rtw_stop_ap, | ||
4244 | |||
4245 | .add_station = cfg80211_rtw_add_station, | ||
4246 | .del_station = cfg80211_rtw_del_station, | ||
4247 | .change_station = cfg80211_rtw_change_station, | ||
4248 | .dump_station = cfg80211_rtw_dump_station, | ||
4249 | .change_bss = cfg80211_rtw_change_bss, | ||
4250 | #endif /* CONFIG_8723AU_AP_MODE */ | ||
4251 | |||
4252 | #ifdef CONFIG_8723AU_P2P | ||
4253 | .remain_on_channel = cfg80211_rtw_remain_on_channel, | ||
4254 | .cancel_remain_on_channel = cfg80211_rtw_cancel_remain_on_channel, | ||
4255 | #endif | ||
4256 | |||
4257 | .mgmt_tx = cfg80211_rtw_mgmt_tx, | ||
4258 | .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, | ||
4259 | }; | ||
4260 | |||
4261 | static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap, | ||
4262 | enum ieee80211_band band, u8 rf_type) | ||
4263 | { | ||
4264 | |||
4265 | #define MAX_BIT_RATE_40MHZ_MCS15 300 /* Mbps */ | ||
4266 | #define MAX_BIT_RATE_40MHZ_MCS7 150 /* Mbps */ | ||
4267 | |||
4268 | ht_cap->ht_supported = true; | ||
4269 | |||
4270 | ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
4271 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20 | | ||
4272 | IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; | ||
4273 | |||
4274 | /* | ||
4275 | *Maximum length of AMPDU that the STA can receive. | ||
4276 | *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) | ||
4277 | */ | ||
4278 | ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; | ||
4279 | |||
4280 | /*Minimum MPDU start spacing , */ | ||
4281 | ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; | ||
4282 | |||
4283 | ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | ||
4284 | |||
4285 | /* | ||
4286 | *hw->wiphy->bands[IEEE80211_BAND_2GHZ] | ||
4287 | *base on ant_num | ||
4288 | *rx_mask: RX mask | ||
4289 | *if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7 | ||
4290 | *if rx_ant = 2 rx_mask[1]= 0xff;==>MCS8-MCS15 | ||
4291 | *if rx_ant >= 3 rx_mask[2]= 0xff; | ||
4292 | *if BW_40 rx_mask[4]= 0x01; | ||
4293 | *highest supported RX rate | ||
4294 | */ | ||
4295 | if (rf_type == RF_1T1R) { | ||
4296 | ht_cap->mcs.rx_mask[0] = 0xFF; | ||
4297 | ht_cap->mcs.rx_mask[1] = 0x00; | ||
4298 | ht_cap->mcs.rx_mask[4] = 0x01; | ||
4299 | |||
4300 | ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS7; | ||
4301 | } else if ((rf_type == RF_1T2R) || (rf_type == RF_2T2R)) { | ||
4302 | ht_cap->mcs.rx_mask[0] = 0xFF; | ||
4303 | ht_cap->mcs.rx_mask[1] = 0xFF; | ||
4304 | ht_cap->mcs.rx_mask[4] = 0x01; | ||
4305 | |||
4306 | ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS15; | ||
4307 | } else { | ||
4308 | DBG_8723A("%s, error rf_type =%d\n", __func__, rf_type); | ||
4309 | } | ||
4310 | |||
4311 | } | ||
4312 | |||
4313 | void rtw_cfg80211_init_wiphy(struct rtw_adapter *padapter) | ||
4314 | { | ||
4315 | u8 rf_type; | ||
4316 | struct ieee80211_supported_band *bands; | ||
4317 | struct wireless_dev *pwdev = padapter->rtw_wdev; | ||
4318 | struct wiphy *wiphy = pwdev->wiphy; | ||
4319 | |||
4320 | rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); | ||
4321 | |||
4322 | DBG_8723A("%s:rf_type =%d\n", __func__, rf_type); | ||
4323 | |||
4324 | /* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */ | ||
4325 | { | ||
4326 | bands = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
4327 | if (bands) | ||
4328 | rtw_cfg80211_init_ht_capab(&bands->ht_cap, | ||
4329 | IEEE80211_BAND_2GHZ, | ||
4330 | rf_type); | ||
4331 | } | ||
4332 | |||
4333 | /* if (padapter->registrypriv.wireless_mode & WIRELESS_11A) */ | ||
4334 | { | ||
4335 | bands = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
4336 | if (bands) | ||
4337 | rtw_cfg80211_init_ht_capab(&bands->ht_cap, | ||
4338 | IEEE80211_BAND_5GHZ, | ||
4339 | rf_type); | ||
4340 | } | ||
4341 | } | ||
4342 | |||
4343 | static void rtw_cfg80211_preinit_wiphy(struct rtw_adapter *padapter, | ||
4344 | struct wiphy *wiphy) | ||
4345 | { | ||
4346 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
4347 | |||
4348 | wiphy->max_scan_ssids = RTW_SSID_SCAN_AMOUNT; | ||
4349 | wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
4350 | wiphy->max_num_pmkids = RTW_MAX_NUM_PMKIDS; | ||
4351 | |||
4352 | wiphy->max_remain_on_channel_duration = | ||
4353 | RTW_MAX_REMAIN_ON_CHANNEL_DURATION; | ||
4354 | |||
4355 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
4356 | BIT(NL80211_IFTYPE_ADHOC) | | ||
4357 | #ifdef CONFIG_8723AU_AP_MODE | ||
4358 | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR) | | ||
4359 | #endif | ||
4360 | #if defined(CONFIG_8723AU_P2P) | ||
4361 | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | | ||
4362 | #endif | ||
4363 | 0; | ||
4364 | |||
4365 | #ifdef CONFIG_8723AU_AP_MODE | ||
4366 | wiphy->mgmt_stypes = rtw_cfg80211_default_mgmt_stypes; | ||
4367 | #endif /* CONFIG_8723AU_AP_MODE */ | ||
4368 | |||
4369 | wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); | ||
4370 | |||
4371 | /* | ||
4372 | wiphy->iface_combinations = &rtw_combinations; | ||
4373 | wiphy->n_iface_combinations = 1; | ||
4374 | */ | ||
4375 | |||
4376 | wiphy->cipher_suites = rtw_cipher_suites; | ||
4377 | wiphy->n_cipher_suites = ARRAY_SIZE(rtw_cipher_suites); | ||
4378 | |||
4379 | /* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */ | ||
4380 | wiphy->bands[IEEE80211_BAND_2GHZ] = | ||
4381 | rtw_spt_band_alloc(IEEE80211_BAND_2GHZ); | ||
4382 | /* if (padapter->registrypriv.wireless_mode & WIRELESS_11A) */ | ||
4383 | wiphy->bands[IEEE80211_BAND_5GHZ] = | ||
4384 | rtw_spt_band_alloc(IEEE80211_BAND_5GHZ); | ||
4385 | |||
4386 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | ||
4387 | wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX | WIPHY_FLAG_HAVE_AP_SME; | ||
4388 | |||
4389 | if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE) | ||
4390 | wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; | ||
4391 | else | ||
4392 | wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | ||
4393 | } | ||
4394 | |||
4395 | int rtw_wdev_alloc(struct rtw_adapter *padapter, struct device *dev) | ||
4396 | { | ||
4397 | int ret = 0; | ||
4398 | struct wiphy *wiphy; | ||
4399 | struct wireless_dev *wdev; | ||
4400 | struct rtw_wdev_priv *pwdev_priv; | ||
4401 | struct net_device *pnetdev = padapter->pnetdev; | ||
4402 | |||
4403 | DBG_8723A("%s(padapter =%p)\n", __func__, padapter); | ||
4404 | |||
4405 | /* wiphy */ | ||
4406 | wiphy = wiphy_new(&rtw_cfg80211_ops, sizeof(struct rtw_wdev_priv)); | ||
4407 | if (!wiphy) { | ||
4408 | DBG_8723A("Couldn't allocate wiphy device\n"); | ||
4409 | ret = -ENOMEM; | ||
4410 | goto exit; | ||
4411 | } | ||
4412 | set_wiphy_dev(wiphy, dev); | ||
4413 | rtw_cfg80211_preinit_wiphy(padapter, wiphy); | ||
4414 | |||
4415 | ret = wiphy_register(wiphy); | ||
4416 | if (ret < 0) { | ||
4417 | DBG_8723A("Couldn't register wiphy device\n"); | ||
4418 | goto free_wiphy; | ||
4419 | } | ||
4420 | |||
4421 | /* wdev */ | ||
4422 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | ||
4423 | if (!wdev) { | ||
4424 | DBG_8723A("Couldn't allocate wireless device\n"); | ||
4425 | ret = -ENOMEM; | ||
4426 | goto unregister_wiphy; | ||
4427 | } | ||
4428 | wdev->wiphy = wiphy; | ||
4429 | wdev->netdev = pnetdev; | ||
4430 | /* wdev->iftype = NL80211_IFTYPE_STATION; */ | ||
4431 | /* for rtw_setopmode_cmd23a() in cfg80211_rtw_change_iface() */ | ||
4432 | wdev->iftype = NL80211_IFTYPE_MONITOR; | ||
4433 | padapter->rtw_wdev = wdev; | ||
4434 | pnetdev->ieee80211_ptr = wdev; | ||
4435 | |||
4436 | /* init pwdev_priv */ | ||
4437 | pwdev_priv = wdev_to_priv(wdev); | ||
4438 | pwdev_priv->rtw_wdev = wdev; | ||
4439 | pwdev_priv->pmon_ndev = NULL; | ||
4440 | pwdev_priv->ifname_mon[0] = '\0'; | ||
4441 | pwdev_priv->padapter = padapter; | ||
4442 | pwdev_priv->scan_request = NULL; | ||
4443 | spin_lock_init(&pwdev_priv->scan_req_lock); | ||
4444 | |||
4445 | pwdev_priv->p2p_enabled = false; | ||
4446 | pwdev_priv->provdisc_req_issued = false; | ||
4447 | rtw_wdev_invit_info_init(&pwdev_priv->invit_info); | ||
4448 | |||
4449 | if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE) | ||
4450 | pwdev_priv->power_mgmt = true; | ||
4451 | else | ||
4452 | pwdev_priv->power_mgmt = false; | ||
4453 | |||
4454 | return ret; | ||
4455 | unregister_wiphy: | ||
4456 | wiphy_unregister(wiphy); | ||
4457 | free_wiphy: | ||
4458 | wiphy_free(wiphy); | ||
4459 | exit: | ||
4460 | return ret; | ||
4461 | } | ||
4462 | |||
4463 | void rtw_wdev_free(struct wireless_dev *wdev) | ||
4464 | { | ||
4465 | struct rtw_wdev_priv *pwdev_priv; | ||
4466 | |||
4467 | DBG_8723A("%s(wdev =%p)\n", __func__, wdev); | ||
4468 | |||
4469 | if (!wdev) | ||
4470 | return; | ||
4471 | |||
4472 | pwdev_priv = wdev_to_priv(wdev); | ||
4473 | |||
4474 | kfree(wdev->wiphy->bands[IEEE80211_BAND_2GHZ]); | ||
4475 | kfree(wdev->wiphy->bands[IEEE80211_BAND_5GHZ]); | ||
4476 | |||
4477 | wiphy_free(wdev->wiphy); | ||
4478 | |||
4479 | kfree(wdev); | ||
4480 | } | ||
4481 | |||
4482 | void rtw_wdev_unregister(struct wireless_dev *wdev) | ||
4483 | { | ||
4484 | struct rtw_wdev_priv *pwdev_priv; | ||
4485 | |||
4486 | DBG_8723A("%s(wdev =%p)\n", __func__, wdev); | ||
4487 | |||
4488 | if (!wdev) | ||
4489 | return; | ||
4490 | |||
4491 | pwdev_priv = wdev_to_priv(wdev); | ||
4492 | |||
4493 | rtw_cfg80211_indicate_scan_done(pwdev_priv, true); | ||
4494 | |||
4495 | if (pwdev_priv->pmon_ndev) { | ||
4496 | DBG_8723A("%s, unregister monitor interface\n", __func__); | ||
4497 | unregister_netdev(pwdev_priv->pmon_ndev); | ||
4498 | } | ||
4499 | |||
4500 | wiphy_unregister(wdev->wiphy); | ||
4501 | } | ||
diff --git a/drivers/staging/rtl8723au/os_dep/mlme_linux.c b/drivers/staging/rtl8723au/os_dep/mlme_linux.c new file mode 100644 index 000000000000..b30d4d37556a --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/mlme_linux.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | ******************************************************************************/ | ||
15 | |||
16 | #define _MLME_OSDEP_C_ | ||
17 | |||
18 | #include <osdep_service.h> | ||
19 | #include <drv_types.h> | ||
20 | #include <mlme_osdep.h> | ||
21 | #include <rtw_ioctl_set.h> | ||
22 | |||
23 | void rtw_os_indicate_connect23a(struct rtw_adapter *adapter) | ||
24 | { | ||
25 | rtw_cfg80211_indicate_connect(adapter); | ||
26 | |||
27 | netif_carrier_on(adapter->pnetdev); | ||
28 | |||
29 | if (adapter->pid[2] != 0) | ||
30 | rtw_signal_process(adapter->pid[2], SIGALRM); | ||
31 | } | ||
32 | |||
33 | void rtw_os_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted) | ||
34 | { | ||
35 | rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev), | ||
36 | aborted); | ||
37 | } | ||
38 | |||
39 | static struct rt_pmkid_list backupPMKIDList[NUM_PMKID_CACHE]; | ||
40 | |||
41 | void rtw_reset_securitypriv23a(struct rtw_adapter *adapter) | ||
42 | { | ||
43 | u8 backupPMKIDIndex = 0; | ||
44 | u8 backupTKIPCountermeasure = 0x00; | ||
45 | unsigned long backupTKIPcountermeasure_time = 0; | ||
46 | |||
47 | if (adapter->securitypriv.dot11AuthAlgrthm == | ||
48 | dot11AuthAlgrthm_8021X) { /* 802.1x */ | ||
49 | /* We have to backup the PMK information for WiFi PMK | ||
50 | * Caching test item. | ||
51 | * Backup the btkip_countermeasure information. | ||
52 | * When the countermeasure is trigger, the driver have to | ||
53 | * disconnect with AP for 60 seconds. | ||
54 | */ | ||
55 | memset(&backupPMKIDList[0], 0x00, sizeof(struct rt_pmkid_list) * | ||
56 | NUM_PMKID_CACHE); | ||
57 | |||
58 | memcpy(&backupPMKIDList[0], &adapter->securitypriv.PMKIDList[0], | ||
59 | sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); | ||
60 | backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; | ||
61 | backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure; | ||
62 | backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time; | ||
63 | |||
64 | memset((unsigned char *)&adapter->securitypriv, 0, | ||
65 | sizeof (struct security_priv)); | ||
66 | /* Restore the PMK information to securitypriv structure | ||
67 | * for the following connection. | ||
68 | */ | ||
69 | memcpy(&adapter->securitypriv.PMKIDList[0], &backupPMKIDList[0], | ||
70 | sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); | ||
71 | adapter->securitypriv.PMKIDIndex = backupPMKIDIndex; | ||
72 | adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure; | ||
73 | adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time; | ||
74 | |||
75 | adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; | ||
76 | adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; | ||
77 | } else { /* reset values in securitypriv */ | ||
78 | struct security_priv *psec_priv = &adapter->securitypriv; | ||
79 | |||
80 | /* open system */ | ||
81 | psec_priv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; | ||
82 | psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_; | ||
83 | psec_priv->dot11PrivacyKeyIndex = 0; | ||
84 | |||
85 | psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_; | ||
86 | psec_priv->dot118021XGrpKeyid = 1; | ||
87 | |||
88 | psec_priv->ndisauthtype = Ndis802_11AuthModeOpen; | ||
89 | psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | void rtw_os_indicate_disconnect23a(struct rtw_adapter *adapter) | ||
94 | { | ||
95 | /* Do it first for tx broadcast pkt after disconnection issue! */ | ||
96 | netif_carrier_off(adapter->pnetdev); | ||
97 | |||
98 | rtw_cfg80211_indicate_disconnect(adapter); | ||
99 | |||
100 | rtw_reset_securitypriv23a(adapter); | ||
101 | } | ||
102 | |||
103 | void rtw_report_sec_ie23a(struct rtw_adapter *adapter, u8 authmode, u8 *sec_ie) | ||
104 | { | ||
105 | uint len; | ||
106 | u8 *buff, *p, i; | ||
107 | union iwreq_data wrqu; | ||
108 | |||
109 | RT_TRACE(_module_mlme_osdep_c_, _drv_info_, | ||
110 | ("+rtw_report_sec_ie23a, authmode =%d\n", authmode)); | ||
111 | |||
112 | buff = NULL; | ||
113 | if (authmode == _WPA_IE_ID_) { | ||
114 | RT_TRACE(_module_mlme_osdep_c_, _drv_info_, | ||
115 | ("rtw_report_sec_ie23a, authmode =%d\n", authmode)); | ||
116 | |||
117 | buff = kzalloc(IW_CUSTOM_MAX, GFP_KERNEL); | ||
118 | if (!buff) | ||
119 | return; | ||
120 | p = buff; | ||
121 | |||
122 | p += sprintf(p, "ASSOCINFO(ReqIEs ="); | ||
123 | |||
124 | len = sec_ie[1]+2; | ||
125 | len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX; | ||
126 | |||
127 | for (i = 0; i < len; i++) | ||
128 | p += sprintf(p, "%02x", sec_ie[i]); | ||
129 | |||
130 | p += sprintf(p, ")"); | ||
131 | |||
132 | memset(&wrqu, 0, sizeof(wrqu)); | ||
133 | |||
134 | wrqu.data.length = p-buff; | ||
135 | |||
136 | wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? | ||
137 | wrqu.data.length : IW_CUSTOM_MAX; | ||
138 | |||
139 | kfree(buff); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | #ifdef CONFIG_8723AU_AP_MODE | ||
144 | void rtw_indicate_sta_assoc_event23a(struct rtw_adapter *padapter, | ||
145 | struct sta_info *psta) | ||
146 | { | ||
147 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
148 | union iwreq_data wrqu; | ||
149 | |||
150 | if (psta == NULL) | ||
151 | return; | ||
152 | |||
153 | if (psta->aid > NUM_STA) | ||
154 | return; | ||
155 | |||
156 | if (pstapriv->sta_aid[psta->aid - 1] != psta) | ||
157 | return; | ||
158 | |||
159 | wrqu.addr.sa_family = ARPHRD_ETHER; | ||
160 | |||
161 | memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); | ||
162 | |||
163 | DBG_8723A("+rtw_indicate_sta_assoc_event23a\n"); | ||
164 | } | ||
165 | |||
166 | void rtw_indicate_sta_disassoc_event23a(struct rtw_adapter *padapter, | ||
167 | struct sta_info *psta) | ||
168 | { | ||
169 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
170 | union iwreq_data wrqu; | ||
171 | |||
172 | if (psta == NULL) | ||
173 | return; | ||
174 | |||
175 | if (psta->aid > NUM_STA) | ||
176 | return; | ||
177 | |||
178 | if (pstapriv->sta_aid[psta->aid - 1] != psta) | ||
179 | return; | ||
180 | |||
181 | wrqu.addr.sa_family = ARPHRD_ETHER; | ||
182 | |||
183 | memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); | ||
184 | |||
185 | DBG_8723A("+rtw_indicate_sta_disassoc_event23a\n"); | ||
186 | } | ||
187 | #endif | ||
diff --git a/drivers/staging/rtl8723au/os_dep/os_intfs.c b/drivers/staging/rtl8723au/os_dep/os_intfs.c new file mode 100644 index 000000000000..57eca7a45672 --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/os_intfs.c | |||
@@ -0,0 +1,970 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | ******************************************************************************/ | ||
15 | #define _OS_INTFS_C_ | ||
16 | |||
17 | #include <osdep_service.h> | ||
18 | #include <drv_types.h> | ||
19 | #include <xmit_osdep.h> | ||
20 | #include <recv_osdep.h> | ||
21 | #include <hal_intf.h> | ||
22 | #include <rtw_version.h> | ||
23 | #include <ethernet.h> | ||
24 | |||
25 | #include <usb_osintf.h> | ||
26 | #include <linux/version.h> | ||
27 | |||
28 | MODULE_LICENSE("GPL"); | ||
29 | MODULE_DESCRIPTION("Realtek Wireless Lan Driver"); | ||
30 | MODULE_AUTHOR("Realtek Semiconductor Corp."); | ||
31 | MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); | ||
32 | MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@redhat.com>"); | ||
33 | MODULE_VERSION(DRIVERVERSION); | ||
34 | MODULE_FIRMWARE("rtlwifi/rtl8821aefw.bin"); | ||
35 | |||
36 | /* module param defaults */ | ||
37 | static int rtw_chip_version = 0x00; | ||
38 | static int rtw_rfintfs = HWPI; | ||
39 | static int rtw_debug = 1; | ||
40 | |||
41 | static int rtw_channel = 1;/* ad-hoc support requirement */ | ||
42 | static int rtw_wireless_mode = WIRELESS_11BG_24N; | ||
43 | static int rtw_vrtl_carrier_sense = AUTO_VCS; | ||
44 | static int rtw_vcs_type = RTS_CTS;/* */ | ||
45 | static int rtw_rts_thresh = 2347;/* */ | ||
46 | static int rtw_frag_thresh = 2346;/* */ | ||
47 | static int rtw_preamble = PREAMBLE_LONG;/* long, short, auto */ | ||
48 | static int rtw_scan_mode = 1;/* active, passive */ | ||
49 | static int rtw_adhoc_tx_pwr = 1; | ||
50 | static int rtw_soft_ap; | ||
51 | static int rtw_power_mgnt = 1; | ||
52 | static int rtw_ips_mode = IPS_NORMAL; | ||
53 | |||
54 | static int rtw_smart_ps = 2; | ||
55 | |||
56 | module_param(rtw_ips_mode, int, 0644); | ||
57 | MODULE_PARM_DESC(rtw_ips_mode, "The default IPS mode"); | ||
58 | |||
59 | static int rtw_long_retry_lmt = 7; | ||
60 | static int rtw_short_retry_lmt = 7; | ||
61 | static int rtw_busy_thresh = 40; | ||
62 | static int rtw_ack_policy = NORMAL_ACK; | ||
63 | |||
64 | static int rtw_acm_method;/* 0:By SW 1:By HW. */ | ||
65 | |||
66 | static int rtw_wmm_enable = 1;/* default is set to enable the wmm. */ | ||
67 | static int rtw_uapsd_enable; | ||
68 | |||
69 | int rtw_ht_enable23A = 1; | ||
70 | /* 0 :diable, bit(0): enable 2.4g, bit(1): enable 5g */ | ||
71 | int rtw_cbw40_enable23A = 3; | ||
72 | int rtw_ampdu_enable23A = 1;/* for enable tx_ampdu */ | ||
73 | /* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable | ||
74 | * 2.4GHZ for IOT issue with bufflao's AP at 5GHZ | ||
75 | */ | ||
76 | static int rtw_rx_stbc = 1; | ||
77 | static int rtw_ampdu_amsdu;/* 0: disabled, 1:enabled, 2:auto */ | ||
78 | |||
79 | /* Use 2 path Tx to transmit MCS0~7 and legacy mode */ | ||
80 | static int rtw_lowrate_two_xmit = 1; | ||
81 | |||
82 | /* int rf_config = RF_1T2R; 1T2R */ | ||
83 | static int rtw_rf_config = RF_819X_MAX_TYPE; /* auto */ | ||
84 | static int rtw_low_power; | ||
85 | static int rtw_wifi_spec; | ||
86 | static int rtw_channel_plan = RT_CHANNEL_DOMAIN_MAX; | ||
87 | |||
88 | #ifdef CONFIG_8723AU_BT_COEXIST | ||
89 | static int rtw_btcoex_enable = 1; | ||
90 | static int rtw_bt_iso = 2;/* 0:Low, 1:High, 2:From Efuse */ | ||
91 | /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter, 4.Busy, 5.OtherBusy */ | ||
92 | static int rtw_bt_sco = 3; | ||
93 | /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ | ||
94 | static int rtw_bt_ampdu = 1 ; | ||
95 | #endif | ||
96 | |||
97 | /* 0:Reject AP's Add BA req, 1:Accept AP's Add BA req. */ | ||
98 | static int rtw_AcceptAddbaReq = true; | ||
99 | |||
100 | static int rtw_antdiv_cfg = 2; /* 0:OFF , 1:ON, 2:decide by Efuse config */ | ||
101 | static int rtw_antdiv_type; /* 0:decide by efuse */ | ||
102 | |||
103 | static int rtw_enusbss;/* 0:disable, 1:enable */ | ||
104 | |||
105 | static int rtw_hwpdn_mode = 2;/* 0:disable, 1:enable, 2: by EFUSE config */ | ||
106 | |||
107 | static int rtw_hwpwrp_detect; /* HW power ping detect 0:disable , 1:enable */ | ||
108 | |||
109 | static int rtw_hw_wps_pbc = 1; | ||
110 | |||
111 | static int rtw_80211d; | ||
112 | |||
113 | static int rtw_regulatory_id = 0xff;/* Regulatory tab id, 0xff = follow efuse's setting */ | ||
114 | |||
115 | module_param(rtw_regulatory_id, int, 0644); | ||
116 | |||
117 | static char *ifname = "wlan%d"; | ||
118 | module_param(ifname, charp, 0644); | ||
119 | MODULE_PARM_DESC(ifname, "The default name to allocate for first interface"); | ||
120 | |||
121 | static char *if2name = "wlan%d"; | ||
122 | module_param(if2name, charp, 0644); | ||
123 | MODULE_PARM_DESC(if2name, "The default name to allocate for second interface"); | ||
124 | |||
125 | module_param(rtw_channel_plan, int, 0644); | ||
126 | module_param(rtw_chip_version, int, 0644); | ||
127 | module_param(rtw_rfintfs, int, 0644); | ||
128 | module_param(rtw_channel, int, 0644); | ||
129 | module_param(rtw_wmm_enable, int, 0644); | ||
130 | module_param(rtw_vrtl_carrier_sense, int, 0644); | ||
131 | module_param(rtw_vcs_type, int, 0644); | ||
132 | module_param(rtw_busy_thresh, int, 0644); | ||
133 | module_param(rtw_ht_enable23A, int, 0644); | ||
134 | module_param(rtw_cbw40_enable23A, int, 0644); | ||
135 | module_param(rtw_ampdu_enable23A, int, 0644); | ||
136 | module_param(rtw_rx_stbc, int, 0644); | ||
137 | module_param(rtw_ampdu_amsdu, int, 0644); | ||
138 | |||
139 | module_param(rtw_lowrate_two_xmit, int, 0644); | ||
140 | |||
141 | module_param(rtw_rf_config, int, 0644); | ||
142 | module_param(rtw_power_mgnt, int, 0644); | ||
143 | module_param(rtw_smart_ps, int, 0644); | ||
144 | module_param(rtw_low_power, int, 0644); | ||
145 | module_param(rtw_wifi_spec, int, 0644); | ||
146 | |||
147 | module_param(rtw_antdiv_cfg, int, 0644); | ||
148 | |||
149 | module_param(rtw_enusbss, int, 0644); | ||
150 | module_param(rtw_hwpdn_mode, int, 0644); | ||
151 | module_param(rtw_hwpwrp_detect, int, 0644); | ||
152 | |||
153 | module_param(rtw_hw_wps_pbc, int, 0644); | ||
154 | |||
155 | static uint rtw_max_roaming_times = 2; | ||
156 | module_param(rtw_max_roaming_times, uint, 0644); | ||
157 | MODULE_PARM_DESC(rtw_max_roaming_times, "The max roaming times to try"); | ||
158 | |||
159 | module_param(rtw_80211d, int, 0644); | ||
160 | MODULE_PARM_DESC(rtw_80211d, "Enable 802.11d mechanism"); | ||
161 | |||
162 | #ifdef CONFIG_8723AU_BT_COEXIST | ||
163 | module_param(rtw_btcoex_enable, int, 0644); | ||
164 | MODULE_PARM_DESC(rtw_btcoex_enable, "Enable BT co-existence mechanism"); | ||
165 | #endif | ||
166 | |||
167 | static uint rtw_notch_filter; | ||
168 | module_param(rtw_notch_filter, uint, 0644); | ||
169 | MODULE_PARM_DESC(rtw_notch_filter, "0:Disable, 1:Enable, 2:Enable only for P2P"); | ||
170 | module_param_named(debug, rtw_debug, int, 0444); | ||
171 | MODULE_PARM_DESC(debug, "Set debug level (1-9) (default 1)"); | ||
172 | |||
173 | static int netdev_close(struct net_device *pnetdev); | ||
174 | |||
175 | static uint loadparam(struct rtw_adapter *padapter, struct net_device *pnetdev) | ||
176 | { | ||
177 | struct registry_priv *registry_par = &padapter->registrypriv; | ||
178 | uint status = _SUCCESS; | ||
179 | |||
180 | GlobalDebugLevel23A = rtw_debug; | ||
181 | registry_par->chip_version = (u8)rtw_chip_version; | ||
182 | registry_par->rfintfs = (u8)rtw_rfintfs; | ||
183 | memcpy(registry_par->ssid.ssid, "ANY", 3); | ||
184 | registry_par->ssid.ssid_len = 3; | ||
185 | registry_par->channel = (u8)rtw_channel; | ||
186 | registry_par->wireless_mode = (u8)rtw_wireless_mode; | ||
187 | registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense; | ||
188 | registry_par->vcs_type = (u8)rtw_vcs_type; | ||
189 | registry_par->rts_thresh = (u16)rtw_rts_thresh; | ||
190 | registry_par->frag_thresh = (u16)rtw_frag_thresh; | ||
191 | registry_par->preamble = (u8)rtw_preamble; | ||
192 | registry_par->scan_mode = (u8)rtw_scan_mode; | ||
193 | registry_par->adhoc_tx_pwr = (u8)rtw_adhoc_tx_pwr; | ||
194 | registry_par->soft_ap = (u8)rtw_soft_ap; | ||
195 | registry_par->smart_ps = (u8)rtw_smart_ps; | ||
196 | registry_par->power_mgnt = (u8)rtw_power_mgnt; | ||
197 | registry_par->ips_mode = (u8)rtw_ips_mode; | ||
198 | registry_par->long_retry_lmt = (u8)rtw_long_retry_lmt; | ||
199 | registry_par->short_retry_lmt = (u8)rtw_short_retry_lmt; | ||
200 | registry_par->busy_thresh = (u16)rtw_busy_thresh; | ||
201 | registry_par->ack_policy = (u8)rtw_ack_policy; | ||
202 | registry_par->acm_method = (u8)rtw_acm_method; | ||
203 | /* UAPSD */ | ||
204 | registry_par->wmm_enable = (u8)rtw_wmm_enable; | ||
205 | registry_par->uapsd_enable = (u8)rtw_uapsd_enable; | ||
206 | registry_par->ht_enable = (u8)rtw_ht_enable23A; | ||
207 | registry_par->cbw40_enable = (u8)rtw_cbw40_enable23A; | ||
208 | registry_par->ampdu_enable = (u8)rtw_ampdu_enable23A; | ||
209 | registry_par->rx_stbc = (u8)rtw_rx_stbc; | ||
210 | registry_par->ampdu_amsdu = (u8)rtw_ampdu_amsdu; | ||
211 | registry_par->lowrate_two_xmit = (u8)rtw_lowrate_two_xmit; | ||
212 | registry_par->rf_config = (u8)rtw_rf_config; | ||
213 | registry_par->low_power = (u8)rtw_low_power; | ||
214 | registry_par->wifi_spec = (u8)rtw_wifi_spec; | ||
215 | registry_par->channel_plan = (u8)rtw_channel_plan; | ||
216 | #ifdef CONFIG_8723AU_BT_COEXIST | ||
217 | registry_par->btcoex = (u8)rtw_btcoex_enable; | ||
218 | registry_par->bt_iso = (u8)rtw_bt_iso; | ||
219 | registry_par->bt_sco = (u8)rtw_bt_sco; | ||
220 | registry_par->bt_ampdu = (u8)rtw_bt_ampdu; | ||
221 | #endif | ||
222 | registry_par->bAcceptAddbaReq = (u8)rtw_AcceptAddbaReq; | ||
223 | registry_par->antdiv_cfg = (u8)rtw_antdiv_cfg; | ||
224 | registry_par->antdiv_type = (u8)rtw_antdiv_type; | ||
225 | |||
226 | /* 0:disable, 1:enable, 2:by EFUSE config */ | ||
227 | registry_par->hwpdn_mode = (u8)rtw_hwpdn_mode; | ||
228 | /* 0:disable, 1:enable */ | ||
229 | registry_par->hwpwrp_detect = (u8)rtw_hwpwrp_detect; | ||
230 | registry_par->hw_wps_pbc = (u8)rtw_hw_wps_pbc; | ||
231 | registry_par->max_roaming_times = (u8)rtw_max_roaming_times; | ||
232 | registry_par->enable80211d = (u8)rtw_80211d; | ||
233 | snprintf(registry_par->ifname, 16, "%s", ifname); | ||
234 | snprintf(registry_par->if2name, 16, "%s", if2name); | ||
235 | registry_par->notch_filter = (u8)rtw_notch_filter; | ||
236 | registry_par->regulatory_tid = (u8)rtw_regulatory_id; | ||
237 | return status; | ||
238 | } | ||
239 | |||
240 | static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p) | ||
241 | { | ||
242 | struct rtw_adapter *padapter = netdev_priv(pnetdev); | ||
243 | struct sockaddr *addr = p; | ||
244 | |||
245 | if (!padapter->bup) | ||
246 | ether_addr_copy(padapter->eeprompriv.mac_addr, addr->sa_data); | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev) | ||
251 | { | ||
252 | struct rtw_adapter *padapter = netdev_priv(pnetdev); | ||
253 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
254 | struct recv_priv *precvpriv = &padapter->recvpriv; | ||
255 | |||
256 | padapter->stats.tx_packets = pxmitpriv->tx_pkts; | ||
257 | padapter->stats.rx_packets = precvpriv->rx_pkts; | ||
258 | padapter->stats.tx_dropped = pxmitpriv->tx_drop; | ||
259 | padapter->stats.rx_dropped = precvpriv->rx_drop; | ||
260 | padapter->stats.tx_bytes = pxmitpriv->tx_bytes; | ||
261 | padapter->stats.rx_bytes = precvpriv->rx_bytes; | ||
262 | |||
263 | return &padapter->stats; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * AC to queue mapping | ||
268 | * | ||
269 | * AC_VO -> queue 0 | ||
270 | * AC_VI -> queue 1 | ||
271 | * AC_BE -> queue 2 | ||
272 | * AC_BK -> queue 3 | ||
273 | */ | ||
274 | static const u16 rtw_1d_to_queue[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; | ||
275 | |||
276 | /* Given a data frame determine the 802.1p/1d tag to use. */ | ||
277 | static unsigned int rtw_classify8021d(struct sk_buff *skb) | ||
278 | { | ||
279 | unsigned int dscp; | ||
280 | |||
281 | /* skb->priority values from 256->263 are magic values to | ||
282 | * directly indicate a specific 802.1d priority. This is used | ||
283 | * to allow 802.1d priority to be passed directly in from VLAN | ||
284 | * tags, etc. | ||
285 | */ | ||
286 | if (skb->priority >= 256 && skb->priority <= 263) | ||
287 | return skb->priority - 256; | ||
288 | switch (skb->protocol) { | ||
289 | case htons(ETH_P_IP): | ||
290 | dscp = ip_hdr(skb)->tos & 0xfc; | ||
291 | break; | ||
292 | default: | ||
293 | return 0; | ||
294 | } | ||
295 | return dscp >> 5; | ||
296 | } | ||
297 | |||
298 | static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, | ||
299 | void *accel_priv, | ||
300 | select_queue_fallback_t fallback) | ||
301 | { | ||
302 | struct rtw_adapter *padapter = netdev_priv(dev); | ||
303 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
304 | |||
305 | skb->priority = rtw_classify8021d(skb); | ||
306 | |||
307 | if (pmlmepriv->acm_mask != 0) | ||
308 | skb->priority = qos_acm23a(pmlmepriv->acm_mask, skb->priority); | ||
309 | return rtw_1d_to_queue[skb->priority]; | ||
310 | } | ||
311 | |||
312 | u16 rtw_recv_select_queue23a(struct sk_buff *skb) | ||
313 | { | ||
314 | struct iphdr *piphdr; | ||
315 | unsigned int dscp; | ||
316 | u16 eth_type; | ||
317 | u32 priority; | ||
318 | u8 *pdata = skb->data; | ||
319 | |||
320 | memcpy(ð_type, pdata + (ETH_ALEN << 1), 2); | ||
321 | switch (eth_type) { | ||
322 | case htons(ETH_P_IP): | ||
323 | piphdr = (struct iphdr *)(pdata + ETH_HLEN); | ||
324 | dscp = piphdr->tos & 0xfc; | ||
325 | priority = dscp >> 5; | ||
326 | break; | ||
327 | default: | ||
328 | priority = 0; | ||
329 | } | ||
330 | return rtw_1d_to_queue[priority]; | ||
331 | } | ||
332 | |||
333 | static const struct net_device_ops rtw_netdev_ops = { | ||
334 | .ndo_open = netdev_open23a, | ||
335 | .ndo_stop = netdev_close, | ||
336 | .ndo_start_xmit = rtw_xmit23a_entry23a, | ||
337 | .ndo_select_queue = rtw_select_queue, | ||
338 | .ndo_set_mac_address = rtw_net_set_mac_address, | ||
339 | .ndo_get_stats = rtw_net_get_stats, | ||
340 | }; | ||
341 | |||
342 | int rtw_init_netdev23a_name23a(struct net_device *pnetdev, const char *ifname) | ||
343 | { | ||
344 | if (dev_alloc_name(pnetdev, ifname) < 0) { | ||
345 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | ||
346 | ("dev_alloc_name, fail!\n")); | ||
347 | } | ||
348 | netif_carrier_off(pnetdev); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static const struct device_type wlan_type = { | ||
353 | .name = "wlan", | ||
354 | }; | ||
355 | |||
356 | struct net_device *rtw_init_netdev23a(struct rtw_adapter *old_padapter) | ||
357 | { | ||
358 | struct rtw_adapter *padapter; | ||
359 | struct net_device *pnetdev; | ||
360 | |||
361 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+init_net_dev\n")); | ||
362 | |||
363 | pnetdev = alloc_etherdev_mq(sizeof(struct rtw_adapter), 4); | ||
364 | if (!pnetdev) | ||
365 | return NULL; | ||
366 | |||
367 | pnetdev->dev.type = &wlan_type; | ||
368 | padapter = netdev_priv(pnetdev); | ||
369 | padapter->pnetdev = pnetdev; | ||
370 | |||
371 | DBG_8723A("register rtw_netdev_ops to netdev_ops\n"); | ||
372 | pnetdev->netdev_ops = &rtw_netdev_ops; | ||
373 | |||
374 | pnetdev->watchdog_timeo = HZ*3; /* 3 second timeout */ | ||
375 | |||
376 | /* step 2. */ | ||
377 | loadparam(padapter, pnetdev); | ||
378 | return pnetdev; | ||
379 | } | ||
380 | |||
381 | u32 rtw_start_drv_threads23a(struct rtw_adapter *padapter) | ||
382 | { | ||
383 | u32 _status = _SUCCESS; | ||
384 | |||
385 | RT_TRACE(_module_os_intfs_c_, _drv_info_, | ||
386 | ("+rtw_start_drv_threads23a\n")); | ||
387 | padapter->cmdThread = kthread_run(rtw_cmd_thread23a, padapter, | ||
388 | "RTW_CMD_THREAD"); | ||
389 | if (IS_ERR(padapter->cmdThread)) { | ||
390 | _status = _FAIL; | ||
391 | } else { | ||
392 | /* wait for cmd_thread to run */ | ||
393 | down(&padapter->cmdpriv.terminate_cmdthread_sema); | ||
394 | } | ||
395 | rtw_hal_start_thread23a(padapter); | ||
396 | return _status; | ||
397 | } | ||
398 | |||
399 | void rtw_stop_drv_threads23a(struct rtw_adapter *padapter) | ||
400 | { | ||
401 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_stop_drv_threads23a\n")); | ||
402 | |||
403 | /* Below is to termindate rtw_cmd_thread23a & event_thread... */ | ||
404 | up(&padapter->cmdpriv.cmd_queue_sema); | ||
405 | if (padapter->cmdThread) | ||
406 | down(&padapter->cmdpriv.terminate_cmdthread_sema); | ||
407 | rtw_hal_stop_thread23a(padapter); | ||
408 | } | ||
409 | |||
410 | static u8 rtw_init_default_value(struct rtw_adapter *padapter) | ||
411 | { | ||
412 | struct registry_priv *pregistrypriv = &padapter->registrypriv; | ||
413 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
414 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
415 | struct security_priv *psecuritypriv = &padapter->securitypriv; | ||
416 | u8 ret = _SUCCESS; | ||
417 | |||
418 | /* xmit_priv */ | ||
419 | pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense; | ||
420 | pxmitpriv->vcs = pregistrypriv->vcs_type; | ||
421 | pxmitpriv->vcs_type = pregistrypriv->vcs_type; | ||
422 | /* pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; */ | ||
423 | pxmitpriv->frag_len = pregistrypriv->frag_thresh; | ||
424 | |||
425 | /* mlme_priv */ | ||
426 | pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ | ||
427 | pmlmepriv->scan_mode = SCAN_ACTIVE; | ||
428 | |||
429 | /* ht_priv */ | ||
430 | pmlmepriv->htpriv.ampdu_enable = false;/* set to disabled */ | ||
431 | |||
432 | /* security_priv */ | ||
433 | psecuritypriv->binstallGrpkey = _FAIL; | ||
434 | |||
435 | /* open system */ | ||
436 | psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; | ||
437 | psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; | ||
438 | |||
439 | psecuritypriv->dot11PrivacyKeyIndex = 0; | ||
440 | |||
441 | psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; | ||
442 | psecuritypriv->dot118021XGrpKeyid = 1; | ||
443 | |||
444 | psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; | ||
445 | psecuritypriv->ndisencryptstatus = Ndis802_11WEPDisabled; | ||
446 | |||
447 | /* registry_priv */ | ||
448 | rtw_init_registrypriv_dev_network23a(padapter); | ||
449 | rtw_update_registrypriv_dev_network23a(padapter); | ||
450 | |||
451 | /* hal_priv */ | ||
452 | rtw_hal_def_value_init23a(padapter); | ||
453 | |||
454 | /* misc. */ | ||
455 | padapter->bReadPortCancel = false; | ||
456 | padapter->bWritePortCancel = false; | ||
457 | padapter->bRxRSSIDisplay = 0; | ||
458 | padapter->bNotifyChannelChange = 0; | ||
459 | #ifdef CONFIG_8723AU_P2P | ||
460 | padapter->bShowGetP2PState = 1; | ||
461 | #endif | ||
462 | return ret; | ||
463 | } | ||
464 | |||
465 | u8 rtw_reset_drv_sw23a(struct rtw_adapter *padapter) | ||
466 | { | ||
467 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
468 | struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; | ||
469 | u8 ret8 = _SUCCESS; | ||
470 | |||
471 | /* hal_priv */ | ||
472 | rtw_hal_def_value_init23a(padapter); | ||
473 | padapter->bReadPortCancel = false; | ||
474 | padapter->bWritePortCancel = false; | ||
475 | padapter->bRxRSSIDisplay = 0; | ||
476 | pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ | ||
477 | |||
478 | padapter->xmitpriv.tx_pkts = 0; | ||
479 | padapter->recvpriv.rx_pkts = 0; | ||
480 | |||
481 | pmlmepriv->LinkDetectInfo.bBusyTraffic = false; | ||
482 | |||
483 | _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING); | ||
484 | |||
485 | rtw_hal_sreset_reset23a_value23a(padapter); | ||
486 | pwrctrlpriv->pwr_state_check_cnts = 0; | ||
487 | |||
488 | /* mlmeextpriv */ | ||
489 | padapter->mlmeextpriv.sitesurvey_res.state = SCAN_DISABLE; | ||
490 | |||
491 | rtw_set_signal_stat_timer(&padapter->recvpriv); | ||
492 | return ret8; | ||
493 | } | ||
494 | |||
495 | u8 rtw_init_drv_sw23a(struct rtw_adapter *padapter) | ||
496 | { | ||
497 | u8 ret8 = _SUCCESS; | ||
498 | |||
499 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw23a\n")); | ||
500 | |||
501 | if ((rtw_init_cmd_priv23a(&padapter->cmdpriv)) == _FAIL) { | ||
502 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | ||
503 | ("\n Can't init cmd_priv\n")); | ||
504 | ret8 = _FAIL; | ||
505 | goto exit; | ||
506 | } | ||
507 | |||
508 | padapter->cmdpriv.padapter = padapter; | ||
509 | |||
510 | if (rtw_init_evt_priv23a(&padapter->evtpriv) == _FAIL) { | ||
511 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | ||
512 | ("\n Can't init evt_priv\n")); | ||
513 | ret8 = _FAIL; | ||
514 | goto exit; | ||
515 | } | ||
516 | |||
517 | if (rtw_init_mlme_priv23a(padapter) == _FAIL) { | ||
518 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | ||
519 | ("\n Can't init mlme_priv\n")); | ||
520 | ret8 = _FAIL; | ||
521 | goto exit; | ||
522 | } | ||
523 | |||
524 | #ifdef CONFIG_8723AU_P2P | ||
525 | rtw_init_wifidirect_timers23a(padapter); | ||
526 | init_wifidirect_info23a(padapter, P2P_ROLE_DISABLE); | ||
527 | reset_global_wifidirect_info23a(padapter); | ||
528 | rtw_init_cfg80211_wifidirect_info(padapter); | ||
529 | #ifdef CONFIG_8723AU_P2P | ||
530 | if (rtw_init_wifi_display_info(padapter) == _FAIL) | ||
531 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | ||
532 | ("\n Can't init init_wifi_display_info\n")); | ||
533 | #endif | ||
534 | #endif /* CONFIG_8723AU_P2P */ | ||
535 | |||
536 | if (init_mlme_ext_priv23a(padapter) == _FAIL) { | ||
537 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | ||
538 | ("\n Can't init mlme_ext_priv\n")); | ||
539 | ret8 = _FAIL; | ||
540 | goto exit; | ||
541 | } | ||
542 | |||
543 | if (_rtw_init_xmit_priv23a(&padapter->xmitpriv, padapter) == _FAIL) { | ||
544 | DBG_8723A("Can't _rtw_init_xmit_priv23a\n"); | ||
545 | ret8 = _FAIL; | ||
546 | goto exit; | ||
547 | } | ||
548 | |||
549 | if (_rtw_init_recv_priv23a(&padapter->recvpriv, padapter) == _FAIL) { | ||
550 | DBG_8723A("Can't _rtw_init_recv_priv23a\n"); | ||
551 | ret8 = _FAIL; | ||
552 | goto exit; | ||
553 | } | ||
554 | |||
555 | if (_rtw_init_sta_priv23a(&padapter->stapriv) == _FAIL) { | ||
556 | DBG_8723A("Can't _rtw_init_sta_priv23a\n"); | ||
557 | ret8 = _FAIL; | ||
558 | goto exit; | ||
559 | } | ||
560 | |||
561 | padapter->stapriv.padapter = padapter; | ||
562 | padapter->setband = GHZ24_50; | ||
563 | rtw_init_bcmc_stainfo23a(padapter); | ||
564 | |||
565 | rtw_init_pwrctrl_priv23a(padapter); | ||
566 | |||
567 | ret8 = rtw_init_default_value(padapter); | ||
568 | |||
569 | rtw_hal_dm_init23a(padapter); | ||
570 | rtw_hal_sw_led_init23a(padapter); | ||
571 | |||
572 | rtw_hal_sreset_init23a(padapter); | ||
573 | |||
574 | exit: | ||
575 | |||
576 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_init_drv_sw23a\n")); | ||
577 | return ret8; | ||
578 | } | ||
579 | |||
580 | void rtw_cancel_all_timer23a(struct rtw_adapter *padapter) | ||
581 | { | ||
582 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_cancel_all_timer23a\n")); | ||
583 | |||
584 | del_timer_sync(&padapter->mlmepriv.assoc_timer); | ||
585 | RT_TRACE(_module_os_intfs_c_, _drv_info_, | ||
586 | ("rtw_cancel_all_timer23a:cancel association timer complete!\n")); | ||
587 | |||
588 | del_timer_sync(&padapter->mlmepriv.scan_to_timer); | ||
589 | RT_TRACE(_module_os_intfs_c_, _drv_info_, | ||
590 | ("rtw_cancel_all_timer23a:cancel scan_to_timer!\n")); | ||
591 | |||
592 | del_timer_sync(&padapter->mlmepriv.dynamic_chk_timer); | ||
593 | RT_TRACE(_module_os_intfs_c_, _drv_info_, | ||
594 | ("rtw_cancel_all_timer23a:cancel dynamic_chk_timer!\n")); | ||
595 | |||
596 | /* cancel sw led timer */ | ||
597 | rtw_hal_sw_led_deinit23a(padapter); | ||
598 | RT_TRACE(_module_os_intfs_c_, _drv_info_, | ||
599 | ("rtw_cancel_all_timer23a:cancel DeInitSwLeds!\n")); | ||
600 | |||
601 | del_timer_sync(&padapter->pwrctrlpriv.pwr_state_check_timer); | ||
602 | |||
603 | #ifdef CONFIG_8723AU_P2P | ||
604 | del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); | ||
605 | #endif /* CONFIG_8723AU_P2P */ | ||
606 | |||
607 | del_timer_sync(&padapter->mlmepriv.set_scan_deny_timer); | ||
608 | rtw_clear_scan_deny(padapter); | ||
609 | RT_TRACE(_module_os_intfs_c_, _drv_info_, | ||
610 | ("rtw_cancel_all_timer23a:cancel set_scan_deny_timer!\n")); | ||
611 | |||
612 | del_timer_sync(&padapter->recvpriv.signal_stat_timer); | ||
613 | /* cancel dm timer */ | ||
614 | rtw_hal_dm_deinit23a(padapter); | ||
615 | } | ||
616 | |||
617 | u8 rtw_free_drv_sw23a(struct rtw_adapter *padapter) | ||
618 | { | ||
619 | #ifdef CONFIG_8723AU_P2P | ||
620 | struct wifidirect_info *pwdinfo; | ||
621 | #endif | ||
622 | |||
623 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("==>rtw_free_drv_sw23a")); | ||
624 | |||
625 | /* we can call rtw_p2p_enable23a here, but: | ||
626 | * 1. rtw_p2p_enable23a may have IO operation | ||
627 | * 2. rtw_p2p_enable23a is bundled with wext interface | ||
628 | */ | ||
629 | #ifdef CONFIG_8723AU_P2P | ||
630 | pwdinfo = &padapter->wdinfo; | ||
631 | if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { | ||
632 | del_timer_sync(&pwdinfo->find_phase_timer); | ||
633 | del_timer_sync(&pwdinfo->restore_p2p_state_timer); | ||
634 | del_timer_sync(&pwdinfo->pre_tx_scan_timer); | ||
635 | rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); | ||
636 | } | ||
637 | #endif | ||
638 | |||
639 | free_mlme_ext_priv23a(&padapter->mlmeextpriv); | ||
640 | |||
641 | rtw_free_cmd_priv23a(&padapter->cmdpriv); | ||
642 | |||
643 | rtw_free_evt_priv23a(&padapter->evtpriv); | ||
644 | |||
645 | rtw_free_mlme_priv23a(&padapter->mlmepriv); | ||
646 | |||
647 | _rtw_free_xmit_priv23a(&padapter->xmitpriv); | ||
648 | |||
649 | _rtw_free_sta_priv23a(&padapter->stapriv);/* will free bcmc_stainfo here */ | ||
650 | |||
651 | _rtw_free_recv_priv23a(&padapter->recvpriv); | ||
652 | |||
653 | rtw_free_pwrctrl_priv(padapter); | ||
654 | |||
655 | rtw_hal_free_data23a(padapter); | ||
656 | |||
657 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("<== rtw_free_drv_sw23a\n")); | ||
658 | |||
659 | /* free the old_pnetdev */ | ||
660 | if (padapter->rereg_nd_name_priv.old_pnetdev) { | ||
661 | free_netdev(padapter->rereg_nd_name_priv.old_pnetdev); | ||
662 | padapter->rereg_nd_name_priv.old_pnetdev = NULL; | ||
663 | } | ||
664 | |||
665 | /* clear pbuddy_adapter to avoid access wrong pointer. */ | ||
666 | if (padapter->pbuddy_adapter != NULL) | ||
667 | padapter->pbuddy_adapter->pbuddy_adapter = NULL; | ||
668 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_free_drv_sw23a\n")); | ||
669 | return _SUCCESS; | ||
670 | } | ||
671 | |||
672 | static int _rtw_drv_register_netdev(struct rtw_adapter *padapter, char *name) | ||
673 | { | ||
674 | struct net_device *pnetdev = padapter->pnetdev; | ||
675 | int ret = _SUCCESS; | ||
676 | |||
677 | /* alloc netdev name */ | ||
678 | rtw_init_netdev23a_name23a(pnetdev, name); | ||
679 | |||
680 | ether_addr_copy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr); | ||
681 | |||
682 | /* Tell the network stack we exist */ | ||
683 | if (register_netdev(pnetdev)) { | ||
684 | DBG_8723A(FUNC_NDEV_FMT "Failed!\n", FUNC_NDEV_ARG(pnetdev)); | ||
685 | ret = _FAIL; | ||
686 | goto error_register_netdev; | ||
687 | } | ||
688 | DBG_8723A("%s, MAC Address (if%d) = " MAC_FMT "\n", __func__, | ||
689 | (padapter->iface_id + 1), MAC_ARG(pnetdev->dev_addr)); | ||
690 | return ret; | ||
691 | |||
692 | error_register_netdev: | ||
693 | |||
694 | if (padapter->iface_id > IFACE_ID0) { | ||
695 | rtw_free_drv_sw23a(padapter); | ||
696 | |||
697 | free_netdev(pnetdev); | ||
698 | } | ||
699 | return ret; | ||
700 | } | ||
701 | |||
702 | int rtw_drv_register_netdev(struct rtw_adapter *if1) | ||
703 | { | ||
704 | struct dvobj_priv *dvobj = if1->dvobj; | ||
705 | int i, status = _SUCCESS; | ||
706 | |||
707 | if (dvobj->iface_nums < IFACE_ID_MAX) { | ||
708 | for (i = 0; i < dvobj->iface_nums; i++) { | ||
709 | struct rtw_adapter *padapter = dvobj->padapters[i]; | ||
710 | |||
711 | if (padapter) { | ||
712 | char *name; | ||
713 | |||
714 | if (padapter->iface_id == IFACE_ID0) | ||
715 | name = if1->registrypriv.ifname; | ||
716 | else if (padapter->iface_id == IFACE_ID1) | ||
717 | name = if1->registrypriv.if2name; | ||
718 | else | ||
719 | name = "wlan%d"; | ||
720 | status = _rtw_drv_register_netdev(padapter, | ||
721 | name); | ||
722 | if (status != _SUCCESS) | ||
723 | break; | ||
724 | } | ||
725 | } | ||
726 | } | ||
727 | return status; | ||
728 | } | ||
729 | |||
730 | int netdev_open23a(struct net_device *pnetdev) | ||
731 | { | ||
732 | struct rtw_adapter *padapter = netdev_priv(pnetdev); | ||
733 | struct pwrctrl_priv *pwrctrlpriv; | ||
734 | int ret = 0; | ||
735 | uint status; | ||
736 | |||
737 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+871x_drv - dev_open\n")); | ||
738 | DBG_8723A("+871x_drv - drv_open, bup =%d\n", padapter->bup); | ||
739 | |||
740 | mutex_lock(&adapter_to_dvobj(padapter)->hw_init_mutex); | ||
741 | |||
742 | pwrctrlpriv = &padapter->pwrctrlpriv; | ||
743 | if (pwrctrlpriv->ps_flag) { | ||
744 | padapter->net_closed = false; | ||
745 | goto netdev_open23a_normal_process; | ||
746 | } | ||
747 | |||
748 | if (!padapter->bup) { | ||
749 | padapter->bDriverStopped = false; | ||
750 | padapter->bSurpriseRemoved = false; | ||
751 | padapter->bCardDisableWOHSM = false; | ||
752 | |||
753 | status = rtw_hal_init23a(padapter); | ||
754 | if (status == _FAIL) { | ||
755 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | ||
756 | ("rtl871x_hal_init(): Can't init h/w!\n")); | ||
757 | goto netdev_open23a_error; | ||
758 | } | ||
759 | |||
760 | DBG_8723A("MAC Address = "MAC_FMT"\n", | ||
761 | MAC_ARG(pnetdev->dev_addr)); | ||
762 | |||
763 | status = rtw_start_drv_threads23a(padapter); | ||
764 | if (status == _FAIL) { | ||
765 | DBG_8723A("Initialize driver software resource Failed!\n"); | ||
766 | goto netdev_open23a_error; | ||
767 | } | ||
768 | |||
769 | if (init_hw_mlme_ext23a(padapter) == _FAIL) { | ||
770 | DBG_8723A("can't init mlme_ext_priv\n"); | ||
771 | goto netdev_open23a_error; | ||
772 | } | ||
773 | |||
774 | if (padapter->intf_start) | ||
775 | padapter->intf_start(padapter); | ||
776 | |||
777 | rtw_cfg80211_init_wiphy(padapter); | ||
778 | |||
779 | rtw_led_control(padapter, LED_CTL_NO_LINK); | ||
780 | |||
781 | padapter->bup = true; | ||
782 | } | ||
783 | padapter->net_closed = false; | ||
784 | |||
785 | mod_timer(&padapter->mlmepriv.dynamic_chk_timer, | ||
786 | jiffies + msecs_to_jiffies(2000)); | ||
787 | |||
788 | padapter->pwrctrlpriv.bips_processing = false; | ||
789 | rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); | ||
790 | |||
791 | /* netif_carrier_on(pnetdev);call this func when | ||
792 | rtw23a_joinbss_event_cb return success */ | ||
793 | if (!rtw_netif_queue_stopped(pnetdev)) | ||
794 | netif_tx_start_all_queues(pnetdev); | ||
795 | else | ||
796 | netif_tx_wake_all_queues(pnetdev); | ||
797 | |||
798 | netdev_open23a_normal_process: | ||
799 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-871x_drv - dev_open\n")); | ||
800 | DBG_8723A("-871x_drv - drv_open, bup =%d\n", padapter->bup); | ||
801 | exit: | ||
802 | mutex_unlock(&adapter_to_dvobj(padapter)->hw_init_mutex); | ||
803 | return ret; | ||
804 | |||
805 | netdev_open23a_error: | ||
806 | padapter->bup = false; | ||
807 | |||
808 | netif_carrier_off(pnetdev); | ||
809 | netif_tx_stop_all_queues(pnetdev); | ||
810 | |||
811 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | ||
812 | ("-871x_drv - dev_open, fail!\n")); | ||
813 | DBG_8723A("-871x_drv - drv_open fail, bup =%d\n", padapter->bup); | ||
814 | |||
815 | ret = -1; | ||
816 | goto exit; | ||
817 | } | ||
818 | |||
819 | static int ips_netdrv_open(struct rtw_adapter *padapter) | ||
820 | { | ||
821 | int status = _SUCCESS; | ||
822 | |||
823 | padapter->net_closed = false; | ||
824 | DBG_8723A("===> %s.........\n", __func__); | ||
825 | |||
826 | padapter->bDriverStopped = false; | ||
827 | padapter->bSurpriseRemoved = false; | ||
828 | padapter->bCardDisableWOHSM = false; | ||
829 | |||
830 | status = rtw_hal_init23a(padapter); | ||
831 | if (status == _FAIL) { | ||
832 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | ||
833 | ("ips_netdrv_open(): Can't init h/w!\n")); | ||
834 | goto netdev_open23a_error; | ||
835 | } | ||
836 | |||
837 | if (padapter->intf_start) | ||
838 | padapter->intf_start(padapter); | ||
839 | |||
840 | rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); | ||
841 | mod_timer(&padapter->mlmepriv.dynamic_chk_timer, | ||
842 | jiffies + msecs_to_jiffies(5000)); | ||
843 | |||
844 | return _SUCCESS; | ||
845 | |||
846 | netdev_open23a_error: | ||
847 | /* padapter->bup = false; */ | ||
848 | DBG_8723A("-ips_netdrv_open - drv_open failure, bup =%d\n", | ||
849 | padapter->bup); | ||
850 | |||
851 | return _FAIL; | ||
852 | } | ||
853 | |||
854 | int rtw_ips_pwr_up23a(struct rtw_adapter *padapter) | ||
855 | { | ||
856 | int result; | ||
857 | unsigned long start_time = jiffies; | ||
858 | |||
859 | DBG_8723A("===> rtw_ips_pwr_up23a..............\n"); | ||
860 | rtw_reset_drv_sw23a(padapter); | ||
861 | |||
862 | result = ips_netdrv_open(padapter); | ||
863 | |||
864 | rtw_led_control(padapter, LED_CTL_NO_LINK); | ||
865 | |||
866 | DBG_8723A("<=== rtw_ips_pwr_up23a.............. in %dms\n", | ||
867 | jiffies_to_msecs(jiffies - start_time)); | ||
868 | return result; | ||
869 | } | ||
870 | |||
871 | void rtw_ips_pwr_down23a(struct rtw_adapter *padapter) | ||
872 | { | ||
873 | unsigned long start_time = jiffies; | ||
874 | |||
875 | DBG_8723A("===> rtw_ips_pwr_down23a...................\n"); | ||
876 | |||
877 | padapter->bCardDisableWOHSM = true; | ||
878 | padapter->net_closed = true; | ||
879 | |||
880 | rtw_led_control(padapter, LED_CTL_POWER_OFF); | ||
881 | |||
882 | rtw_ips_dev_unload23a(padapter); | ||
883 | padapter->bCardDisableWOHSM = false; | ||
884 | DBG_8723A("<=== rtw_ips_pwr_down23a..................... in %dms\n", | ||
885 | jiffies_to_msecs(jiffies - start_time)); | ||
886 | } | ||
887 | |||
888 | void rtw_ips_dev_unload23a(struct rtw_adapter *padapter) | ||
889 | { | ||
890 | rtw_hal_set_hwreg23a(padapter, HW_VAR_FIFO_CLEARN_UP, NULL); | ||
891 | |||
892 | if (padapter->intf_stop) | ||
893 | padapter->intf_stop(padapter); | ||
894 | |||
895 | /* s5. */ | ||
896 | if (!padapter->bSurpriseRemoved) | ||
897 | rtw_hal_deinit23a(padapter); | ||
898 | } | ||
899 | |||
900 | int pm_netdev_open23a(struct net_device *pnetdev, u8 bnormal) | ||
901 | { | ||
902 | int status; | ||
903 | |||
904 | if (bnormal) | ||
905 | status = netdev_open23a(pnetdev); | ||
906 | else | ||
907 | status = (_SUCCESS == ips_netdrv_open(netdev_priv(pnetdev))) ? | ||
908 | (0) : (-1); | ||
909 | |||
910 | return status; | ||
911 | } | ||
912 | |||
913 | static int netdev_close(struct net_device *pnetdev) | ||
914 | { | ||
915 | struct rtw_adapter *padapter = netdev_priv(pnetdev); | ||
916 | |||
917 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+871x_drv - drv_close\n")); | ||
918 | |||
919 | if (padapter->pwrctrlpriv.bInternalAutoSuspend) { | ||
920 | if (padapter->pwrctrlpriv.rf_pwrstate == rf_off) | ||
921 | padapter->pwrctrlpriv.ps_flag = true; | ||
922 | } | ||
923 | padapter->net_closed = true; | ||
924 | |||
925 | if (padapter->pwrctrlpriv.rf_pwrstate == rf_on) { | ||
926 | DBG_8723A("(2)871x_drv - drv_close, bup =%d, hw_init_completed =%d\n", | ||
927 | padapter->bup, | ||
928 | padapter->hw_init_completed); | ||
929 | |||
930 | /* s1. */ | ||
931 | if (pnetdev) { | ||
932 | if (!rtw_netif_queue_stopped(pnetdev)) | ||
933 | netif_tx_stop_all_queues(pnetdev); | ||
934 | } | ||
935 | |||
936 | /* s2. */ | ||
937 | LeaveAllPowerSaveMode23a(padapter); | ||
938 | rtw_disassoc_cmd23a(padapter, 500, false); | ||
939 | /* s2-2. indicate disconnect to os */ | ||
940 | rtw_indicate_disconnect23a(padapter); | ||
941 | /* s2-3. */ | ||
942 | rtw_free_assoc_resources23a(padapter, 1); | ||
943 | /* s2-4. */ | ||
944 | rtw_free_network_queue23a(padapter, true); | ||
945 | /* Close LED */ | ||
946 | rtw_led_control(padapter, LED_CTL_POWER_OFF); | ||
947 | } | ||
948 | |||
949 | #ifdef CONFIG_8723AU_P2P | ||
950 | if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) | ||
951 | wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = false; | ||
952 | rtw_p2p_enable23a(padapter, P2P_ROLE_DISABLE); | ||
953 | #endif /* CONFIG_8723AU_P2P */ | ||
954 | |||
955 | rtw_scan_abort23a(padapter); | ||
956 | /* set this at the end */ | ||
957 | padapter->rtw_wdev->iftype = NL80211_IFTYPE_MONITOR; | ||
958 | |||
959 | RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-871x_drv - drv_close\n")); | ||
960 | DBG_8723A("-871x_drv - drv_close, bup =%d\n", padapter->bup); | ||
961 | |||
962 | return 0; | ||
963 | } | ||
964 | |||
965 | void rtw_ndev_destructor(struct net_device *ndev) | ||
966 | { | ||
967 | DBG_8723A(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); | ||
968 | kfree(ndev->ieee80211_ptr); | ||
969 | free_netdev(ndev); | ||
970 | } | ||
diff --git a/drivers/staging/rtl8723au/os_dep/osdep_service.c b/drivers/staging/rtl8723au/os_dep/osdep_service.c new file mode 100644 index 000000000000..aeb48db0ee8c --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/osdep_service.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | ******************************************************************************/ | ||
15 | |||
16 | |||
17 | #define _OSDEP_SERVICE_C_ | ||
18 | |||
19 | #include <osdep_service.h> | ||
20 | #include <drv_types.h> | ||
21 | #include <recv_osdep.h> | ||
22 | #include <linux/vmalloc.h> | ||
23 | |||
24 | #define RT_TAG ('1178') | ||
25 | |||
26 | /* | ||
27 | * Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE23a | ||
28 | * @return: one of RTW_STATUS_CODE23a | ||
29 | */ | ||
30 | inline int RTW_STATUS_CODE23a(int error_code) | ||
31 | { | ||
32 | if (error_code >= 0) | ||
33 | return _SUCCESS; | ||
34 | return _FAIL; | ||
35 | } | ||
36 | |||
37 | inline u8 *_rtw_vmalloc(u32 sz) | ||
38 | { | ||
39 | u8 *pbuf; | ||
40 | pbuf = vmalloc(sz); | ||
41 | |||
42 | return pbuf; | ||
43 | } | ||
44 | |||
45 | inline u8 *_rtw_zvmalloc(u32 sz) | ||
46 | { | ||
47 | u8 *pbuf; | ||
48 | pbuf = _rtw_vmalloc(sz); | ||
49 | if (pbuf != NULL) | ||
50 | memset(pbuf, 0, sz); | ||
51 | |||
52 | return pbuf; | ||
53 | } | ||
54 | |||
55 | inline void _rtw_vmfree(u8 *pbuf, u32 sz) | ||
56 | { | ||
57 | vfree(pbuf); | ||
58 | } | ||
59 | |||
60 | void _rtw_init_queue23a(struct rtw_queue *pqueue) | ||
61 | { | ||
62 | INIT_LIST_HEAD(&pqueue->queue); | ||
63 | spin_lock_init(&pqueue->lock); | ||
64 | } | ||
65 | |||
66 | u32 _rtw_queue_empty23a(struct rtw_queue *pqueue) | ||
67 | { | ||
68 | if (list_empty(&pqueue->queue)) | ||
69 | return true; | ||
70 | else | ||
71 | return false; | ||
72 | } | ||
73 | |||
74 | u32 rtw_get_current_time(void) | ||
75 | { | ||
76 | return jiffies; | ||
77 | } | ||
78 | |||
79 | inline u32 rtw_systime_to_ms23a(u32 systime) | ||
80 | { | ||
81 | return systime * 1000 / HZ; | ||
82 | } | ||
83 | |||
84 | inline u32 rtw_ms_to_systime23a(u32 ms) | ||
85 | { | ||
86 | return ms * HZ / 1000; | ||
87 | } | ||
88 | |||
89 | /* the input parameter start use the same unit as returned | ||
90 | * by rtw_get_current_time | ||
91 | */ | ||
92 | inline s32 rtw_get_passing_time_ms23a(u32 start) | ||
93 | { | ||
94 | return rtw_systime_to_ms23a(jiffies-start); | ||
95 | } | ||
96 | |||
97 | inline s32 rtw_get_time_interval_ms23a(u32 start, u32 end) | ||
98 | { | ||
99 | return rtw_systime_to_ms23a(end-start); | ||
100 | } | ||
101 | |||
102 | #define RTW_SUSPEND_LOCK_NAME "rtw_wifi" | ||
103 | |||
104 | inline void rtw_suspend_lock_init(void) | ||
105 | { | ||
106 | } | ||
107 | |||
108 | inline void rtw_suspend_lock_uninit(void) | ||
109 | { | ||
110 | } | ||
111 | |||
112 | inline void rtw_lock_suspend(void) | ||
113 | { | ||
114 | } | ||
115 | |||
116 | inline void rtw_unlock_suspend(void) | ||
117 | { | ||
118 | } | ||
119 | |||
120 | /* Open a file with the specific @param path, @param flag, @param mode | ||
121 | * @param fpp the pointer of struct file pointer to get struct | ||
122 | * file pointer while file opening is success | ||
123 | * @param path the path of the file to open | ||
124 | * @param flag file operation flags, please refer to linux document | ||
125 | * @param mode please refer to linux document | ||
126 | * @return Linux specific error code | ||
127 | */ | ||
128 | static int openFile(struct file **fpp, char *path, int flag, int mode) | ||
129 | { | ||
130 | struct file *fp; | ||
131 | |||
132 | fp = filp_open(path, flag, mode); | ||
133 | if (IS_ERR(fp)) { | ||
134 | *fpp = NULL; | ||
135 | return PTR_ERR(fp); | ||
136 | } else { | ||
137 | *fpp = fp; | ||
138 | return 0; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | /* Close the file with the specific @param fp | ||
143 | * @param fp the pointer of struct file to close | ||
144 | * @return always 0 | ||
145 | */ | ||
146 | static int closeFile(struct file *fp) | ||
147 | { | ||
148 | filp_close(fp, NULL); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static int readFile(struct file *fp, char *buf, int len) | ||
153 | { | ||
154 | int rlen = 0, sum = 0; | ||
155 | |||
156 | if (!fp->f_op || !fp->f_op->read) | ||
157 | return -EPERM; | ||
158 | |||
159 | while (sum < len) { | ||
160 | rlen = fp->f_op->read(fp, buf+sum, len-sum, &fp->f_pos); | ||
161 | if (rlen > 0) | ||
162 | sum += rlen; | ||
163 | else if (0 != rlen) | ||
164 | return rlen; | ||
165 | else | ||
166 | break; | ||
167 | } | ||
168 | return sum; | ||
169 | } | ||
170 | |||
171 | static int writeFile(struct file *fp, char *buf, int len) | ||
172 | { | ||
173 | int wlen = 0, sum = 0; | ||
174 | |||
175 | if (!fp->f_op || !fp->f_op->write) | ||
176 | return -EPERM; | ||
177 | |||
178 | while (sum < len) { | ||
179 | wlen = fp->f_op->write(fp, buf+sum, len-sum, &fp->f_pos); | ||
180 | if (wlen > 0) | ||
181 | sum += wlen; | ||
182 | else if (0 != wlen) | ||
183 | return wlen; | ||
184 | else | ||
185 | break; | ||
186 | } | ||
187 | return sum; | ||
188 | } | ||
189 | |||
190 | /* Test if the specifi @param path is a file and readable | ||
191 | * @param path the path of the file to test | ||
192 | * @return Linux specific error code | ||
193 | */ | ||
194 | static int isFileReadable(char *path) | ||
195 | { | ||
196 | struct file *fp; | ||
197 | int ret = 0; | ||
198 | mm_segment_t oldfs; | ||
199 | char buf; | ||
200 | |||
201 | fp = filp_open(path, O_RDONLY, 0); | ||
202 | if (IS_ERR(fp)) { | ||
203 | ret = PTR_ERR(fp); | ||
204 | } else { | ||
205 | oldfs = get_fs(); | ||
206 | set_fs(get_ds()); | ||
207 | |||
208 | if (1 != readFile(fp, &buf, 1)) | ||
209 | ret = PTR_ERR(fp); | ||
210 | |||
211 | set_fs(oldfs); | ||
212 | filp_close(fp, NULL); | ||
213 | } | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | /* Open the file with @param path and retrive the file content into | ||
218 | * memory starting from @param buf for @param sz at most | ||
219 | * @param path the path of the file to open and read | ||
220 | * @param buf the starting address of the buffer to store file content | ||
221 | * @param sz how many bytes to read at most | ||
222 | * @return the byte we've read, or Linux specific error code | ||
223 | */ | ||
224 | static int retriveFromFile(char *path, u8 *buf, u32 sz) | ||
225 | { | ||
226 | int ret = -1; | ||
227 | mm_segment_t oldfs; | ||
228 | struct file *fp; | ||
229 | |||
230 | if (path && buf) { | ||
231 | ret = openFile(&fp, path, O_RDONLY, 0); | ||
232 | if (!ret) { | ||
233 | DBG_8723A("%s openFile path:%s fp =%p\n", | ||
234 | __func__, path, fp); | ||
235 | |||
236 | oldfs = get_fs(); set_fs(get_ds()); | ||
237 | ret = readFile(fp, buf, sz); | ||
238 | set_fs(oldfs); | ||
239 | closeFile(fp); | ||
240 | |||
241 | DBG_8723A("%s readFile, ret:%d\n", __func__, ret); | ||
242 | } else { | ||
243 | DBG_8723A("%s openFile path:%s Fail, ret:%d\n", | ||
244 | __func__, path, ret); | ||
245 | } | ||
246 | } else { | ||
247 | DBG_8723A("%s NULL pointer\n", __func__); | ||
248 | ret = -EINVAL; | ||
249 | } | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | /* Open the file with @param path and wirte @param sz byte of data starting | ||
254 | * from @param buf into the file | ||
255 | * @param path the path of the file to open and write | ||
256 | * @param buf the starting address of the data to write into file | ||
257 | * @param sz how many bytes to write at most | ||
258 | * @return the byte we've written, or Linux specific error code | ||
259 | */ | ||
260 | static int storeToFile(char *path, u8 *buf, u32 sz) | ||
261 | { | ||
262 | struct file *fp; | ||
263 | int ret = 0; | ||
264 | mm_segment_t oldfs; | ||
265 | |||
266 | if (path && buf) { | ||
267 | ret = openFile(&fp, path, O_CREAT|O_WRONLY, 0666); | ||
268 | if (!ret) { | ||
269 | DBG_8723A("%s openFile path:%s fp =%p\n", __func__, | ||
270 | path, fp); | ||
271 | |||
272 | oldfs = get_fs(); set_fs(get_ds()); | ||
273 | ret = writeFile(fp, buf, sz); | ||
274 | set_fs(oldfs); | ||
275 | closeFile(fp); | ||
276 | |||
277 | DBG_8723A("%s writeFile, ret:%d\n", __func__, ret); | ||
278 | } else { | ||
279 | DBG_8723A("%s openFile path:%s Fail, ret:%d\n", | ||
280 | __func__, path, ret); | ||
281 | } | ||
282 | } else { | ||
283 | DBG_8723A("%s NULL pointer\n", __func__); | ||
284 | ret = -EINVAL; | ||
285 | } | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | /* | ||
290 | * Test if the specifi @param path is a file and readable | ||
291 | * @param path the path of the file to test | ||
292 | * @return true or false | ||
293 | */ | ||
294 | int rtw_is_file_readable(char *path) | ||
295 | { | ||
296 | if (isFileReadable(path) == 0) | ||
297 | return true; | ||
298 | else | ||
299 | return false; | ||
300 | } | ||
301 | |||
302 | /* Open the file with @param path and retrive the file content into memoryi | ||
303 | * starting from @param buf for @param sz at most | ||
304 | * @param path the path of the file to open and read | ||
305 | * @param buf the starting address of the buffer to store file content | ||
306 | * @param sz how many bytes to read at most | ||
307 | * @return the byte we've read | ||
308 | */ | ||
309 | int rtw_retrive_from_file(char *path, u8 *buf, u32 sz) | ||
310 | { | ||
311 | int ret = retriveFromFile(path, buf, sz); | ||
312 | return ret >= 0 ? ret : 0; | ||
313 | } | ||
314 | |||
315 | /* Open the file with @param path and wirte @param sz byte of | ||
316 | * data starting from @param buf into the file | ||
317 | * @param path the path of the file to open and write | ||
318 | * @param buf the starting address of the data to write into file | ||
319 | * @param sz how many bytes to write at most | ||
320 | * @return the byte we've written | ||
321 | */ | ||
322 | int rtw_store_to_file(char *path, u8 *buf, u32 sz) | ||
323 | { | ||
324 | int ret = storeToFile(path, buf, sz); | ||
325 | return ret >= 0 ? ret : 0; | ||
326 | } | ||
327 | |||
328 | u64 rtw_modular6423a(u64 x, u64 y) | ||
329 | { | ||
330 | return do_div(x, y); | ||
331 | } | ||
332 | |||
333 | u64 rtw_division6423a(u64 x, u64 y) | ||
334 | { | ||
335 | do_div(x, y); | ||
336 | return x; | ||
337 | } | ||
338 | |||
339 | /* rtw_cbuf_full23a - test if cbuf is full | ||
340 | * @cbuf: pointer of struct rtw_cbuf | ||
341 | * | ||
342 | * Returns: true if cbuf is full | ||
343 | */ | ||
344 | inline bool rtw_cbuf_full23a(struct rtw_cbuf *cbuf) | ||
345 | { | ||
346 | return (cbuf->write == cbuf->read-1) ? true : false; | ||
347 | } | ||
348 | |||
349 | /* rtw_cbuf_empty23a - test if cbuf is empty | ||
350 | * @cbuf: pointer of struct rtw_cbuf | ||
351 | * | ||
352 | * Returns: true if cbuf is empty | ||
353 | */ | ||
354 | inline bool rtw_cbuf_empty23a(struct rtw_cbuf *cbuf) | ||
355 | { | ||
356 | return (cbuf->write == cbuf->read) ? true : false; | ||
357 | } | ||
358 | |||
359 | /** | ||
360 | * rtw_cbuf_push23a - push a pointer into cbuf | ||
361 | * @cbuf: pointer of struct rtw_cbuf | ||
362 | * @buf: pointer to push in | ||
363 | * | ||
364 | * Lock free operation, be careful of the use scheme | ||
365 | * Returns: true push success | ||
366 | */ | ||
367 | bool rtw_cbuf_push23a(struct rtw_cbuf *cbuf, void *buf) | ||
368 | { | ||
369 | if (rtw_cbuf_full23a(cbuf)) | ||
370 | return _FAIL; | ||
371 | |||
372 | if (0) | ||
373 | DBG_8723A("%s on %u\n", __func__, cbuf->write); | ||
374 | cbuf->bufs[cbuf->write] = buf; | ||
375 | cbuf->write = (cbuf->write+1)%cbuf->size; | ||
376 | |||
377 | return _SUCCESS; | ||
378 | } | ||
379 | |||
380 | /** | ||
381 | * rtw_cbuf_pop23a - pop a pointer from cbuf | ||
382 | * @cbuf: pointer of struct rtw_cbuf | ||
383 | * | ||
384 | * Lock free operation, be careful of the use scheme | ||
385 | * Returns: pointer popped out | ||
386 | */ | ||
387 | void *rtw_cbuf_pop23a(struct rtw_cbuf *cbuf) | ||
388 | { | ||
389 | void *buf; | ||
390 | if (rtw_cbuf_empty23a(cbuf)) | ||
391 | return NULL; | ||
392 | |||
393 | if (0) | ||
394 | DBG_8723A("%s on %u\n", __func__, cbuf->read); | ||
395 | buf = cbuf->bufs[cbuf->read]; | ||
396 | cbuf->read = (cbuf->read+1)%cbuf->size; | ||
397 | |||
398 | return buf; | ||
399 | } | ||
400 | |||
401 | /** | ||
402 | * rtw_cbuf_alloc23a - allocte a rtw_cbuf with given size and do initialization | ||
403 | * @size: size of pointer | ||
404 | * | ||
405 | * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure | ||
406 | */ | ||
407 | struct rtw_cbuf *rtw_cbuf_alloc23a(u32 size) | ||
408 | { | ||
409 | struct rtw_cbuf *cbuf; | ||
410 | |||
411 | cbuf = kmalloc(sizeof(*cbuf) + sizeof(void *)*size, GFP_KERNEL); | ||
412 | |||
413 | if (cbuf) { | ||
414 | cbuf->write = 0; | ||
415 | cbuf->read = 0; | ||
416 | cbuf->size = size; | ||
417 | } | ||
418 | |||
419 | return cbuf; | ||
420 | } | ||
421 | |||
422 | /** | ||
423 | * rtw_cbuf_free - free the given rtw_cbuf | ||
424 | * @cbuf: pointer of struct rtw_cbuf to free | ||
425 | */ | ||
426 | void rtw_cbuf_free(struct rtw_cbuf *cbuf) | ||
427 | { | ||
428 | kfree(cbuf); | ||
429 | } | ||
diff --git a/drivers/staging/rtl8723au/os_dep/recv_linux.c b/drivers/staging/rtl8723au/os_dep/recv_linux.c new file mode 100644 index 000000000000..84402a589f25 --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/recv_linux.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | ******************************************************************************/ | ||
15 | #define _RECV_OSDEP_C_ | ||
16 | |||
17 | #include <osdep_service.h> | ||
18 | #include <drv_types.h> | ||
19 | |||
20 | #include <wifi.h> | ||
21 | #include <recv_osdep.h> | ||
22 | |||
23 | #include <osdep_intf.h> | ||
24 | #include <ethernet.h> | ||
25 | |||
26 | #include <usb_ops.h> | ||
27 | |||
28 | /* alloc os related resource in struct recv_frame */ | ||
29 | int rtw_os_recv_resource_alloc23a(struct rtw_adapter *padapter, | ||
30 | struct recv_frame *precvframe) | ||
31 | { | ||
32 | int res = _SUCCESS; | ||
33 | |||
34 | precvframe->pkt = NULL; | ||
35 | |||
36 | return res; | ||
37 | } | ||
38 | |||
39 | /* alloc os related resource in struct recv_buf */ | ||
40 | int rtw_os_recvbuf_resource_alloc23a(struct rtw_adapter *padapter, | ||
41 | struct recv_buf *precvbuf) | ||
42 | { | ||
43 | int res = _SUCCESS; | ||
44 | |||
45 | precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); | ||
46 | if (precvbuf->purb == NULL) | ||
47 | res = _FAIL; | ||
48 | |||
49 | precvbuf->pskb = NULL; | ||
50 | |||
51 | return res; | ||
52 | } | ||
53 | |||
54 | /* free os related resource in struct recv_buf */ | ||
55 | int rtw_os_recvbuf_resource_free23a(struct rtw_adapter *padapter, | ||
56 | struct recv_buf *precvbuf) | ||
57 | { | ||
58 | int ret = _SUCCESS; | ||
59 | |||
60 | usb_free_urb(precvbuf->purb); | ||
61 | |||
62 | if (precvbuf->pskb) | ||
63 | dev_kfree_skb_any(precvbuf->pskb); | ||
64 | |||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | void rtw_handle_tkip_mic_err23a(struct rtw_adapter *padapter, u8 bgroup) | ||
69 | { | ||
70 | enum nl80211_key_type key_type = 0; | ||
71 | union iwreq_data wrqu; | ||
72 | struct iw_michaelmicfailure ev; | ||
73 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
74 | struct security_priv *psecuritypriv = &padapter->securitypriv; | ||
75 | unsigned long cur_time; | ||
76 | |||
77 | if (psecuritypriv->last_mic_err_time == 0) { | ||
78 | psecuritypriv->last_mic_err_time = jiffies; | ||
79 | } else { | ||
80 | cur_time = jiffies; | ||
81 | |||
82 | if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) { | ||
83 | psecuritypriv->btkip_countermeasure = true; | ||
84 | psecuritypriv->last_mic_err_time = 0; | ||
85 | psecuritypriv->btkip_countermeasure_time = cur_time; | ||
86 | } else { | ||
87 | psecuritypriv->last_mic_err_time = jiffies; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | if (bgroup) | ||
92 | key_type |= NL80211_KEYTYPE_GROUP; | ||
93 | else | ||
94 | key_type |= NL80211_KEYTYPE_PAIRWISE; | ||
95 | |||
96 | cfg80211_michael_mic_failure(padapter->pnetdev, | ||
97 | (u8 *)&pmlmepriv->assoc_bssid[0], | ||
98 | key_type, -1, NULL, GFP_ATOMIC); | ||
99 | |||
100 | memset(&ev, 0x00, sizeof(ev)); | ||
101 | if (bgroup) | ||
102 | ev.flags |= IW_MICFAILURE_GROUP; | ||
103 | else | ||
104 | ev.flags |= IW_MICFAILURE_PAIRWISE; | ||
105 | |||
106 | ev.src_addr.sa_family = ARPHRD_ETHER; | ||
107 | ether_addr_copy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0]); | ||
108 | |||
109 | memset(&wrqu, 0x00, sizeof(wrqu)); | ||
110 | wrqu.data.length = sizeof(ev); | ||
111 | } | ||
112 | |||
113 | void rtw_hostapd_mlme_rx23a(struct rtw_adapter *padapter, | ||
114 | struct recv_frame *precv_frame) | ||
115 | { | ||
116 | } | ||
117 | |||
118 | int rtw_recv_indicatepkt23a(struct rtw_adapter *padapter, | ||
119 | struct recv_frame *precv_frame) | ||
120 | { | ||
121 | struct recv_priv *precvpriv; | ||
122 | struct rtw_queue *pfree_recv_queue; | ||
123 | struct sk_buff *skb; | ||
124 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
125 | |||
126 | precvpriv = &(padapter->recvpriv); | ||
127 | pfree_recv_queue = &(precvpriv->free_recv_queue); | ||
128 | |||
129 | skb = precv_frame->pkt; | ||
130 | if (!skb) { | ||
131 | RT_TRACE(_module_recv_osdep_c_, _drv_err_, | ||
132 | ("rtw_recv_indicatepkt23a():skb == NULL!!!!\n")); | ||
133 | goto _recv_indicatepkt_drop; | ||
134 | } | ||
135 | |||
136 | RT_TRACE(_module_recv_osdep_c_, _drv_info_, | ||
137 | ("rtw_recv_indicatepkt23a():skb != NULL !!!\n")); | ||
138 | RT_TRACE(_module_recv_osdep_c_, _drv_info_, | ||
139 | ("rtw_recv_indicatepkt23a():precv_frame->hdr.rx_data =%p\n", | ||
140 | precv_frame->pkt->data)); | ||
141 | RT_TRACE(_module_recv_osdep_c_, _drv_info_, | ||
142 | ("\n skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n", | ||
143 | skb->head, skb->data, | ||
144 | skb_tail_pointer(skb), skb_end_pointer(skb), skb->len)); | ||
145 | |||
146 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { | ||
147 | struct sk_buff *pskb2 = NULL; | ||
148 | struct sta_info *psta = NULL; | ||
149 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
150 | struct rx_pkt_attrib *pattrib = &precv_frame->attrib; | ||
151 | int bmcast = is_multicast_ether_addr(pattrib->dst); | ||
152 | |||
153 | /* DBG_8723A("bmcast =%d\n", bmcast); */ | ||
154 | |||
155 | if (!ether_addr_equal(pattrib->dst, | ||
156 | myid(&padapter->eeprompriv))) { | ||
157 | /* DBG_8723A("not ap psta =%p, addr =%pM\n", psta, pattrib->dst); */ | ||
158 | if (bmcast) { | ||
159 | psta = rtw_get_bcmc_stainfo23a(padapter); | ||
160 | pskb2 = skb_clone(skb, GFP_ATOMIC); | ||
161 | } else { | ||
162 | psta = rtw_get_stainfo23a(pstapriv, pattrib->dst); | ||
163 | } | ||
164 | |||
165 | if (psta) { | ||
166 | struct net_device *pnetdev = padapter->pnetdev; | ||
167 | |||
168 | /* DBG_8723A("directly forwarding to the rtw_xmit23a_entry23a\n"); */ | ||
169 | |||
170 | /* skb->ip_summed = CHECKSUM_NONE; */ | ||
171 | skb->dev = pnetdev; | ||
172 | skb_set_queue_mapping(skb, rtw_recv_select_queue23a(skb)); | ||
173 | |||
174 | rtw_xmit23a_entry23a(skb, pnetdev); | ||
175 | |||
176 | if (bmcast) | ||
177 | skb = pskb2; | ||
178 | else | ||
179 | goto _recv_indicatepkt_end; | ||
180 | } | ||
181 | } else { /* to APself */ | ||
182 | /* DBG_8723A("to APSelf\n"); */ | ||
183 | } | ||
184 | } | ||
185 | |||
186 | skb->ip_summed = CHECKSUM_NONE; | ||
187 | skb->dev = padapter->pnetdev; | ||
188 | skb->protocol = eth_type_trans(skb, padapter->pnetdev); | ||
189 | |||
190 | netif_rx(skb); | ||
191 | |||
192 | _recv_indicatepkt_end: | ||
193 | |||
194 | precv_frame->pkt = NULL; /* pointers to NULL before rtw_free_recvframe23a() */ | ||
195 | |||
196 | rtw_free_recvframe23a(precv_frame, pfree_recv_queue); | ||
197 | |||
198 | RT_TRACE(_module_recv_osdep_c_, _drv_info_, | ||
199 | ("\n rtw_recv_indicatepkt23a :after netif_rx!!!!\n")); | ||
200 | return _SUCCESS; | ||
201 | |||
202 | _recv_indicatepkt_drop: | ||
203 | |||
204 | rtw_free_recvframe23a(precv_frame, pfree_recv_queue); | ||
205 | return _FAIL; | ||
206 | } | ||
207 | |||
208 | void rtw_os_read_port23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf) | ||
209 | { | ||
210 | struct recv_priv *precvpriv = &padapter->recvpriv; | ||
211 | |||
212 | /* free skb in recv_buf */ | ||
213 | dev_kfree_skb_any(precvbuf->pskb); | ||
214 | |||
215 | precvbuf->pskb = NULL; | ||
216 | |||
217 | rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, precvbuf); | ||
218 | } | ||
219 | |||
220 | void rtw_init_recv_timer23a(struct recv_reorder_ctrl *preorder_ctrl) | ||
221 | { | ||
222 | setup_timer(&preorder_ctrl->reordering_ctrl_timer, | ||
223 | rtw_reordering_ctrl_timeout_handler23a, | ||
224 | (unsigned long)preorder_ctrl); | ||
225 | } | ||
diff --git a/drivers/staging/rtl8723au/os_dep/usb_intf.c b/drivers/staging/rtl8723au/os_dep/usb_intf.c new file mode 100644 index 000000000000..040bf29b9d06 --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/usb_intf.c | |||
@@ -0,0 +1,836 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | ******************************************************************************/ | ||
15 | #define _HCI_INTF_C_ | ||
16 | |||
17 | #include <osdep_service.h> | ||
18 | #include <drv_types.h> | ||
19 | #include <recv_osdep.h> | ||
20 | #include <xmit_osdep.h> | ||
21 | #include <hal_intf.h> | ||
22 | #include <rtw_version.h> | ||
23 | #include <osdep_intf.h> | ||
24 | #include <usb_vendor_req.h> | ||
25 | #include <usb_ops.h> | ||
26 | #include <usb_osintf.h> | ||
27 | #include <usb_hal.h> | ||
28 | |||
29 | static int rtw_suspend(struct usb_interface *intf, pm_message_t message); | ||
30 | static int rtw_resume(struct usb_interface *intf); | ||
31 | static int rtw_drv_init(struct usb_interface *pusb_intf, | ||
32 | const struct usb_device_id *pdid); | ||
33 | static void rtw_disconnect(struct usb_interface *pusb_intf); | ||
34 | |||
35 | #define USB_VENDER_ID_REALTEK 0x0BDA | ||
36 | |||
37 | #define RTL8723A_USB_IDS \ | ||
38 | {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x8724, \ | ||
39 | 0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ \ | ||
40 | {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x1724, \ | ||
41 | 0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ \ | ||
42 | {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x0724, \ | ||
43 | 0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ | ||
44 | |||
45 | static struct usb_device_id rtl8723a_usb_id_tbl[] = { | ||
46 | RTL8723A_USB_IDS | ||
47 | {} /* Terminating entry */ | ||
48 | }; | ||
49 | |||
50 | MODULE_DEVICE_TABLE(usb, rtl8723a_usb_id_tbl); | ||
51 | |||
52 | static struct usb_driver rtl8723a_usb_drv = { | ||
53 | .name = (char *)"rtl8723au", | ||
54 | .probe = rtw_drv_init, | ||
55 | .disconnect = rtw_disconnect, | ||
56 | .id_table = rtl8723a_usb_id_tbl, | ||
57 | .suspend = rtw_suspend, | ||
58 | .resume = rtw_resume, | ||
59 | .reset_resume = rtw_resume, | ||
60 | }; | ||
61 | |||
62 | static struct usb_driver *usb_drv = &rtl8723a_usb_drv; | ||
63 | |||
64 | static inline int RT_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) | ||
65 | { | ||
66 | return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN; | ||
67 | } | ||
68 | |||
69 | static inline int RT_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) | ||
70 | { | ||
71 | return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; | ||
72 | } | ||
73 | |||
74 | static inline int RT_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) | ||
75 | { | ||
76 | return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT; | ||
77 | } | ||
78 | |||
79 | static inline int RT_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) | ||
80 | { | ||
81 | return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK; | ||
82 | } | ||
83 | |||
84 | static inline int RT_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) | ||
85 | { | ||
86 | return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_in(epd); | ||
87 | } | ||
88 | |||
89 | static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) | ||
90 | { | ||
91 | return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_out(epd); | ||
92 | } | ||
93 | |||
94 | static inline int RT_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) | ||
95 | { | ||
96 | return RT_usb_endpoint_xfer_int(epd) && RT_usb_endpoint_dir_in(epd); | ||
97 | } | ||
98 | |||
99 | static inline int RT_usb_endpoint_num(const struct usb_endpoint_descriptor *epd) | ||
100 | { | ||
101 | return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; | ||
102 | } | ||
103 | |||
104 | static u8 rtw_init_intf_priv(struct dvobj_priv *dvobj) | ||
105 | { | ||
106 | u8 rst = _SUCCESS; | ||
107 | |||
108 | mutex_init(&dvobj->usb_vendor_req_mutex); | ||
109 | dvobj->usb_alloc_vendor_req_buf = kzalloc(MAX_USB_IO_CTL_SIZE, | ||
110 | GFP_KERNEL); | ||
111 | if (dvobj->usb_alloc_vendor_req_buf == NULL) { | ||
112 | DBG_8723A("alloc usb_vendor_req_buf failed... /n"); | ||
113 | rst = _FAIL; | ||
114 | goto exit; | ||
115 | } | ||
116 | dvobj->usb_vendor_req_buf = | ||
117 | PTR_ALIGN(dvobj->usb_alloc_vendor_req_buf, ALIGNMENT_UNIT); | ||
118 | exit: | ||
119 | return rst; | ||
120 | } | ||
121 | |||
122 | static u8 rtw_deinit_intf_priv(struct dvobj_priv *dvobj) | ||
123 | { | ||
124 | u8 rst = _SUCCESS; | ||
125 | |||
126 | kfree(dvobj->usb_alloc_vendor_req_buf); | ||
127 | |||
128 | mutex_destroy(&dvobj->usb_vendor_req_mutex); | ||
129 | |||
130 | return rst; | ||
131 | } | ||
132 | |||
133 | static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) | ||
134 | { | ||
135 | struct dvobj_priv *pdvobjpriv; | ||
136 | struct usb_device_descriptor *pdev_desc; | ||
137 | struct usb_host_config *phost_conf; | ||
138 | struct usb_config_descriptor *pconf_desc; | ||
139 | struct usb_host_interface *phost_iface; | ||
140 | struct usb_interface_descriptor *piface_desc; | ||
141 | struct usb_host_endpoint *phost_endp; | ||
142 | struct usb_endpoint_descriptor *pendp_desc; | ||
143 | struct usb_device *pusbd; | ||
144 | int i; | ||
145 | int status = _FAIL; | ||
146 | |||
147 | pdvobjpriv = kzalloc(sizeof(*pdvobjpriv), GFP_KERNEL); | ||
148 | if (!pdvobjpriv) | ||
149 | goto exit; | ||
150 | |||
151 | mutex_init(&pdvobjpriv->hw_init_mutex); | ||
152 | mutex_init(&pdvobjpriv->h2c_fwcmd_mutex); | ||
153 | mutex_init(&pdvobjpriv->setch_mutex); | ||
154 | mutex_init(&pdvobjpriv->setbw_mutex); | ||
155 | |||
156 | pdvobjpriv->pusbintf = usb_intf; | ||
157 | pusbd = interface_to_usbdev(usb_intf); | ||
158 | pdvobjpriv->pusbdev = pusbd; | ||
159 | usb_set_intfdata(usb_intf, pdvobjpriv); | ||
160 | |||
161 | pdvobjpriv->RtNumInPipes = 0; | ||
162 | pdvobjpriv->RtNumOutPipes = 0; | ||
163 | |||
164 | pdev_desc = &pusbd->descriptor; | ||
165 | |||
166 | phost_conf = pusbd->actconfig; | ||
167 | pconf_desc = &phost_conf->desc; | ||
168 | |||
169 | phost_iface = &usb_intf->altsetting[0]; | ||
170 | piface_desc = &phost_iface->desc; | ||
171 | |||
172 | pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces; | ||
173 | pdvobjpriv->InterfaceNumber = piface_desc->bInterfaceNumber; | ||
174 | pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; | ||
175 | |||
176 | for (i = 0; i < pdvobjpriv->nr_endpoint; i++) { | ||
177 | phost_endp = phost_iface->endpoint + i; | ||
178 | if (phost_endp) { | ||
179 | pendp_desc = &phost_endp->desc; | ||
180 | |||
181 | DBG_8723A("\nusb_endpoint_descriptor(%d):\n", i); | ||
182 | DBG_8723A("bLength =%x\n", pendp_desc->bLength); | ||
183 | DBG_8723A("bDescriptorType =%x\n", | ||
184 | pendp_desc->bDescriptorType); | ||
185 | DBG_8723A("bEndpointAddress =%x\n", | ||
186 | pendp_desc->bEndpointAddress); | ||
187 | DBG_8723A("wMaxPacketSize =%d\n", | ||
188 | le16_to_cpu(pendp_desc->wMaxPacketSize)); | ||
189 | DBG_8723A("bInterval =%x\n", pendp_desc->bInterval); | ||
190 | |||
191 | if (RT_usb_endpoint_is_bulk_in(pendp_desc)) { | ||
192 | DBG_8723A("RT_usb_endpoint_is_bulk_in = %x\n", | ||
193 | RT_usb_endpoint_num(pendp_desc)); | ||
194 | pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = | ||
195 | RT_usb_endpoint_num(pendp_desc); | ||
196 | pdvobjpriv->RtNumInPipes++; | ||
197 | } else if (RT_usb_endpoint_is_int_in(pendp_desc)) { | ||
198 | DBG_8723A("RT_usb_endpoint_is_int_in = %x, Interval = %x\n", | ||
199 | RT_usb_endpoint_num(pendp_desc), | ||
200 | pendp_desc->bInterval); | ||
201 | pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = | ||
202 | RT_usb_endpoint_num(pendp_desc); | ||
203 | pdvobjpriv->RtNumInPipes++; | ||
204 | } else if (RT_usb_endpoint_is_bulk_out(pendp_desc)) { | ||
205 | DBG_8723A("RT_usb_endpoint_is_bulk_out = %x\n", | ||
206 | RT_usb_endpoint_num(pendp_desc)); | ||
207 | pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] = | ||
208 | RT_usb_endpoint_num(pendp_desc); | ||
209 | pdvobjpriv->RtNumOutPipes++; | ||
210 | } | ||
211 | pdvobjpriv->ep_num[i] = RT_usb_endpoint_num(pendp_desc); | ||
212 | } | ||
213 | } | ||
214 | DBG_8723A("nr_endpoint =%d, in_num =%d, out_num =%d\n\n", | ||
215 | pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes, | ||
216 | pdvobjpriv->RtNumOutPipes); | ||
217 | |||
218 | if (pusbd->speed == USB_SPEED_HIGH) { | ||
219 | pdvobjpriv->ishighspeed = true; | ||
220 | DBG_8723A("USB_SPEED_HIGH\n"); | ||
221 | } else { | ||
222 | pdvobjpriv->ishighspeed = false; | ||
223 | DBG_8723A("NON USB_SPEED_HIGH\n"); | ||
224 | } | ||
225 | |||
226 | if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) { | ||
227 | RT_TRACE(_module_os_intfs_c_, _drv_err_, | ||
228 | ("\n Can't INIT rtw_init_intf_priv\n")); | ||
229 | goto free_dvobj; | ||
230 | } | ||
231 | /* 3 misc */ | ||
232 | sema_init(&(pdvobjpriv->usb_suspend_sema), 0); | ||
233 | rtw_reset_continual_urb_error(pdvobjpriv); | ||
234 | usb_get_dev(pusbd); | ||
235 | status = _SUCCESS; | ||
236 | free_dvobj: | ||
237 | if (status != _SUCCESS && pdvobjpriv) { | ||
238 | usb_set_intfdata(usb_intf, NULL); | ||
239 | mutex_destroy(&pdvobjpriv->hw_init_mutex); | ||
240 | mutex_destroy(&pdvobjpriv->h2c_fwcmd_mutex); | ||
241 | mutex_destroy(&pdvobjpriv->setch_mutex); | ||
242 | mutex_destroy(&pdvobjpriv->setbw_mutex); | ||
243 | kfree(pdvobjpriv); | ||
244 | pdvobjpriv = NULL; | ||
245 | } | ||
246 | exit: | ||
247 | return pdvobjpriv; | ||
248 | } | ||
249 | |||
250 | static void usb_dvobj_deinit(struct usb_interface *usb_intf) | ||
251 | { | ||
252 | struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf); | ||
253 | |||
254 | usb_set_intfdata(usb_intf, NULL); | ||
255 | if (dvobj) { | ||
256 | /* Modify condition for 92DU DMDP 2010.11.18, by Thomas */ | ||
257 | if ((dvobj->NumInterfaces != 2 && dvobj->NumInterfaces != 3) || | ||
258 | (dvobj->InterfaceNumber == 1)) { | ||
259 | if (interface_to_usbdev(usb_intf)->state != | ||
260 | USB_STATE_NOTATTACHED) { | ||
261 | /* If we didn't unplug usb dongle and | ||
262 | * remove/insert module, driver fails on | ||
263 | * sitesurvey for the first time when | ||
264 | * device is up . | ||
265 | * Reset usb port for sitesurvey fail issue. | ||
266 | */ | ||
267 | DBG_8723A("usb attached..., try to reset usb device\n"); | ||
268 | usb_reset_device(interface_to_usbdev(usb_intf)); | ||
269 | } | ||
270 | } | ||
271 | rtw_deinit_intf_priv(dvobj); | ||
272 | mutex_destroy(&dvobj->hw_init_mutex); | ||
273 | mutex_destroy(&dvobj->h2c_fwcmd_mutex); | ||
274 | mutex_destroy(&dvobj->setch_mutex); | ||
275 | mutex_destroy(&dvobj->setbw_mutex); | ||
276 | kfree(dvobj); | ||
277 | } | ||
278 | usb_put_dev(interface_to_usbdev(usb_intf)); | ||
279 | } | ||
280 | |||
281 | static void decide_chip_type_by_usb_device_id(struct rtw_adapter *padapter, | ||
282 | const struct usb_device_id *pdid) | ||
283 | { | ||
284 | padapter->chip_type = NULL_CHIP_TYPE; | ||
285 | hal_set_hw_type(padapter); | ||
286 | } | ||
287 | |||
288 | static void usb_intf_start(struct rtw_adapter *padapter) | ||
289 | { | ||
290 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_start\n")); | ||
291 | rtw_hal_inirp_init23a(padapter); | ||
292 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_start\n")); | ||
293 | } | ||
294 | |||
295 | static void usb_intf_stop(struct rtw_adapter *padapter) | ||
296 | { | ||
297 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_stop\n")); | ||
298 | |||
299 | /* disable_hw_interrupt */ | ||
300 | if (!padapter->bSurpriseRemoved) { | ||
301 | /* device still exists, so driver can do i/o operation | ||
302 | * TODO: | ||
303 | */ | ||
304 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, | ||
305 | ("SurpriseRemoved == false\n")); | ||
306 | } | ||
307 | |||
308 | /* cancel in irp */ | ||
309 | rtw_hal_inirp_deinit23a(padapter); | ||
310 | |||
311 | /* cancel out irp */ | ||
312 | rtw_write_port_cancel(padapter); | ||
313 | |||
314 | /* todo:cancel other irps */ | ||
315 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_stop\n")); | ||
316 | } | ||
317 | |||
318 | static void rtw_dev_unload(struct rtw_adapter *padapter) | ||
319 | { | ||
320 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_dev_unload\n")); | ||
321 | |||
322 | if (padapter->bup) { | ||
323 | DBG_8723A("===> rtw_dev_unload\n"); | ||
324 | |||
325 | padapter->bDriverStopped = true; | ||
326 | if (padapter->xmitpriv.ack_tx) | ||
327 | rtw_ack_tx_done23a(&padapter->xmitpriv, | ||
328 | RTW_SCTX_DONE_DRV_STOP); | ||
329 | |||
330 | /* s3. */ | ||
331 | if (padapter->intf_stop) | ||
332 | padapter->intf_stop(padapter); | ||
333 | |||
334 | /* s4. */ | ||
335 | if (!padapter->pwrctrlpriv.bInternalAutoSuspend) | ||
336 | rtw_stop_drv_threads23a(padapter); | ||
337 | |||
338 | /* s5. */ | ||
339 | if (!padapter->bSurpriseRemoved) { | ||
340 | rtw_hal_deinit23a(padapter); | ||
341 | padapter->bSurpriseRemoved = true; | ||
342 | } | ||
343 | padapter->bup = false; | ||
344 | } else { | ||
345 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, | ||
346 | ("r871x_dev_unload():padapter->bup == false\n")); | ||
347 | } | ||
348 | DBG_8723A("<=== rtw_dev_unload\n"); | ||
349 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-rtw_dev_unload\n")); | ||
350 | } | ||
351 | |||
352 | int rtw_hw_suspend23a(struct rtw_adapter *padapter) | ||
353 | { | ||
354 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | ||
355 | struct net_device *pnetdev = padapter->pnetdev; | ||
356 | |||
357 | if ((!padapter->bup) || (padapter->bDriverStopped) || | ||
358 | (padapter->bSurpriseRemoved)) { | ||
359 | DBG_8723A("padapter->bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n", | ||
360 | padapter->bup, padapter->bDriverStopped, | ||
361 | padapter->bSurpriseRemoved); | ||
362 | goto error_exit; | ||
363 | } | ||
364 | |||
365 | if (padapter) { /* system suspend */ | ||
366 | LeaveAllPowerSaveMode23a(padapter); | ||
367 | |||
368 | DBG_8723A("==> rtw_hw_suspend23a\n"); | ||
369 | down(&pwrpriv->lock); | ||
370 | pwrpriv->bips_processing = true; | ||
371 | /* padapter->net_closed = true; */ | ||
372 | /* s1. */ | ||
373 | if (pnetdev) { | ||
374 | netif_carrier_off(pnetdev); | ||
375 | netif_tx_stop_all_queues(pnetdev); | ||
376 | } | ||
377 | |||
378 | /* s2. */ | ||
379 | rtw_disassoc_cmd23a(padapter, 500, false); | ||
380 | |||
381 | /* s2-2. indicate disconnect to os */ | ||
382 | /* rtw_indicate_disconnect23a(padapter); */ | ||
383 | { | ||
384 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
385 | |||
386 | if (check_fwstate(pmlmepriv, _FW_LINKED)) { | ||
387 | _clr_fwstate_(pmlmepriv, _FW_LINKED); | ||
388 | |||
389 | rtw_led_control(padapter, LED_CTL_NO_LINK); | ||
390 | |||
391 | rtw_os_indicate_disconnect23a(padapter); | ||
392 | |||
393 | /* donnot enqueue cmd */ | ||
394 | rtw_lps_ctrl_wk_cmd23a(padapter, | ||
395 | LPS_CTRL_DISCONNECT, 0); | ||
396 | } | ||
397 | } | ||
398 | /* s2-3. */ | ||
399 | rtw_free_assoc_resources23a(padapter, 1); | ||
400 | |||
401 | /* s2-4. */ | ||
402 | rtw_free_network_queue23a(padapter, true); | ||
403 | rtw_ips_dev_unload23a(padapter); | ||
404 | pwrpriv->rf_pwrstate = rf_off; | ||
405 | pwrpriv->bips_processing = false; | ||
406 | up(&pwrpriv->lock); | ||
407 | } else { | ||
408 | goto error_exit; | ||
409 | } | ||
410 | return 0; | ||
411 | error_exit: | ||
412 | DBG_8723A("%s, failed\n", __func__); | ||
413 | return -1; | ||
414 | } | ||
415 | |||
416 | int rtw_hw_resume23a(struct rtw_adapter *padapter) | ||
417 | { | ||
418 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | ||
419 | struct net_device *pnetdev = padapter->pnetdev; | ||
420 | |||
421 | if (padapter) { /* system resume */ | ||
422 | DBG_8723A("==> rtw_hw_resume23a\n"); | ||
423 | down(&pwrpriv->lock); | ||
424 | pwrpriv->bips_processing = true; | ||
425 | rtw_reset_drv_sw23a(padapter); | ||
426 | |||
427 | if (pm_netdev_open23a(pnetdev, false)) { | ||
428 | up(&pwrpriv->lock); | ||
429 | goto error_exit; | ||
430 | } | ||
431 | |||
432 | netif_device_attach(pnetdev); | ||
433 | netif_carrier_on(pnetdev); | ||
434 | |||
435 | if (!rtw_netif_queue_stopped(pnetdev)) | ||
436 | netif_tx_start_all_queues(pnetdev); | ||
437 | else | ||
438 | netif_tx_wake_all_queues(pnetdev); | ||
439 | |||
440 | pwrpriv->bkeepfwalive = false; | ||
441 | pwrpriv->brfoffbyhw = false; | ||
442 | |||
443 | pwrpriv->rf_pwrstate = rf_on; | ||
444 | pwrpriv->bips_processing = false; | ||
445 | |||
446 | up(&pwrpriv->lock); | ||
447 | } else { | ||
448 | goto error_exit; | ||
449 | } | ||
450 | return 0; | ||
451 | error_exit: | ||
452 | DBG_8723A("%s, Open net dev failed\n", __func__); | ||
453 | return -1; | ||
454 | } | ||
455 | |||
456 | static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) | ||
457 | { | ||
458 | struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); | ||
459 | struct rtw_adapter *padapter = dvobj->if1; | ||
460 | struct net_device *pnetdev = padapter->pnetdev; | ||
461 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | ||
462 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | ||
463 | int ret = 0; | ||
464 | unsigned long start_time = jiffies; | ||
465 | |||
466 | DBG_8723A("==> %s (%s:%d)\n", __func__, current->comm, current->pid); | ||
467 | |||
468 | if ((!padapter->bup) || (padapter->bDriverStopped) || | ||
469 | (padapter->bSurpriseRemoved)) { | ||
470 | DBG_8723A("padapter->bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n", | ||
471 | padapter->bup, padapter->bDriverStopped, | ||
472 | padapter->bSurpriseRemoved); | ||
473 | goto exit; | ||
474 | } | ||
475 | pwrpriv->bInSuspend = true; | ||
476 | rtw_cancel_all_timer23a(padapter); | ||
477 | LeaveAllPowerSaveMode23a(padapter); | ||
478 | |||
479 | down(&pwrpriv->lock); | ||
480 | /* padapter->net_closed = true; */ | ||
481 | /* s1. */ | ||
482 | if (pnetdev) { | ||
483 | netif_carrier_off(pnetdev); | ||
484 | netif_tx_stop_all_queues(pnetdev); | ||
485 | } | ||
486 | |||
487 | /* s2. */ | ||
488 | rtw_disassoc_cmd23a(padapter, 0, false); | ||
489 | |||
490 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && | ||
491 | check_fwstate(pmlmepriv, _FW_LINKED)) { | ||
492 | DBG_8723A("%s:%d %s(%pM), length:%d assoc_ssid.length:%d\n", | ||
493 | __func__, __LINE__, | ||
494 | pmlmepriv->cur_network.network.Ssid.ssid, | ||
495 | pmlmepriv->cur_network.network.MacAddress, | ||
496 | pmlmepriv->cur_network.network.Ssid.ssid_len, | ||
497 | pmlmepriv->assoc_ssid.ssid_len); | ||
498 | |||
499 | rtw_set_roaming(padapter, 1); | ||
500 | } | ||
501 | /* s2-2. indicate disconnect to os */ | ||
502 | rtw_indicate_disconnect23a(padapter); | ||
503 | /* s2-3. */ | ||
504 | rtw_free_assoc_resources23a(padapter, 1); | ||
505 | /* s2-4. */ | ||
506 | rtw_free_network_queue23a(padapter, true); | ||
507 | |||
508 | rtw_dev_unload(padapter); | ||
509 | up(&pwrpriv->lock); | ||
510 | |||
511 | if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) | ||
512 | rtw_indicate_scan_done23a(padapter, 1); | ||
513 | |||
514 | if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) | ||
515 | rtw_indicate_disconnect23a(padapter); | ||
516 | |||
517 | exit: | ||
518 | DBG_8723A("<=== %s return %d.............. in %dms\n", __func__, | ||
519 | ret, jiffies_to_msecs(jiffies - start_time)); | ||
520 | |||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | static int rtw_resume(struct usb_interface *pusb_intf) | ||
525 | { | ||
526 | struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); | ||
527 | struct rtw_adapter *padapter = dvobj->if1; | ||
528 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | ||
529 | int ret = 0; | ||
530 | |||
531 | if (pwrpriv->bInternalAutoSuspend) | ||
532 | ret = rtw_resume_process23a(padapter); | ||
533 | else | ||
534 | ret = rtw_resume_process23a(padapter); | ||
535 | |||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | int rtw_resume_process23a(struct rtw_adapter *padapter) | ||
540 | { | ||
541 | struct net_device *pnetdev; | ||
542 | struct pwrctrl_priv *pwrpriv = NULL; | ||
543 | int ret = -1; | ||
544 | unsigned long start_time = jiffies; | ||
545 | |||
546 | DBG_8723A("==> %s (%s:%d)\n", __func__, current->comm, current->pid); | ||
547 | |||
548 | if (!padapter) | ||
549 | goto exit; | ||
550 | pnetdev = padapter->pnetdev; | ||
551 | pwrpriv = &padapter->pwrctrlpriv; | ||
552 | |||
553 | down(&pwrpriv->lock); | ||
554 | rtw_reset_drv_sw23a(padapter); | ||
555 | pwrpriv->bkeepfwalive = false; | ||
556 | |||
557 | DBG_8723A("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive); | ||
558 | if (pm_netdev_open23a(pnetdev, true) != 0) | ||
559 | goto exit; | ||
560 | |||
561 | netif_device_attach(pnetdev); | ||
562 | netif_carrier_on(pnetdev); | ||
563 | |||
564 | up(&pwrpriv->lock); | ||
565 | |||
566 | if (padapter->pid[1] != 0) { | ||
567 | DBG_8723A("pid[1]:%d\n", padapter->pid[1]); | ||
568 | rtw_signal_process(padapter->pid[1], SIGUSR2); | ||
569 | } | ||
570 | |||
571 | rtw23a_roaming(padapter, NULL); | ||
572 | |||
573 | ret = 0; | ||
574 | exit: | ||
575 | if (pwrpriv) | ||
576 | pwrpriv->bInSuspend = false; | ||
577 | DBG_8723A("<=== %s return %d.............. in %dms\n", __func__, | ||
578 | ret, jiffies_to_msecs(jiffies - start_time)); | ||
579 | |||
580 | return ret; | ||
581 | } | ||
582 | |||
583 | /* | ||
584 | * drv_init() - a device potentially for us | ||
585 | * | ||
586 | * notes: drv_init() is called when the bus driver has located a card | ||
587 | * for us to support. | ||
588 | * We accept the new device by returning 0. | ||
589 | */ | ||
590 | static struct rtw_adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, | ||
591 | struct usb_interface *pusb_intf, | ||
592 | const struct usb_device_id *pdid) | ||
593 | { | ||
594 | struct rtw_adapter *padapter = NULL; | ||
595 | struct net_device *pnetdev = NULL; | ||
596 | int status = _FAIL; | ||
597 | |||
598 | pnetdev = rtw_init_netdev23a(padapter); | ||
599 | if (!pnetdev) | ||
600 | goto handle_dualmac; | ||
601 | padapter = netdev_priv(pnetdev); | ||
602 | |||
603 | padapter->dvobj = dvobj; | ||
604 | padapter->bDriverStopped = true; | ||
605 | dvobj->if1 = padapter; | ||
606 | dvobj->padapters[dvobj->iface_nums++] = padapter; | ||
607 | padapter->iface_id = IFACE_ID0; | ||
608 | |||
609 | /* step 1-1., decide the chip_type via vid/pid */ | ||
610 | decide_chip_type_by_usb_device_id(padapter, pdid); | ||
611 | |||
612 | if (rtw_handle_dualmac23a(padapter, 1) != _SUCCESS) | ||
613 | goto free_adapter; | ||
614 | |||
615 | SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); | ||
616 | |||
617 | if (rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj))) | ||
618 | goto handle_dualmac; | ||
619 | |||
620 | /* step 2. hook HalFunc, allocate HalData */ | ||
621 | if (rtl8723au_set_hal_ops(padapter)) | ||
622 | return NULL; | ||
623 | |||
624 | padapter->intf_start = &usb_intf_start; | ||
625 | padapter->intf_stop = &usb_intf_stop; | ||
626 | |||
627 | /* step init_io_priv */ | ||
628 | rtw_init_io_priv23a(padapter, usb_set_intf_ops); | ||
629 | |||
630 | /* step read_chip_version */ | ||
631 | rtw_hal_read_chip_version23a(padapter); | ||
632 | |||
633 | /* step usb endpoint mapping */ | ||
634 | rtw_hal_chip_configure23a(padapter); | ||
635 | |||
636 | /* step read efuse/eeprom data and get mac_addr */ | ||
637 | rtw_hal_read_chip_info23a(padapter); | ||
638 | |||
639 | /* step 5. */ | ||
640 | if (rtw_init_drv_sw23a(padapter) == _FAIL) { | ||
641 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, | ||
642 | ("Initialize driver software resource Failed!\n")); | ||
643 | goto free_hal_data; | ||
644 | } | ||
645 | |||
646 | #ifdef CONFIG_PM | ||
647 | if (padapter->pwrctrlpriv.bSupportRemoteWakeup) { | ||
648 | dvobj->pusbdev->do_remote_wakeup = 1; | ||
649 | pusb_intf->needs_remote_wakeup = 1; | ||
650 | device_init_wakeup(&pusb_intf->dev, 1); | ||
651 | DBG_8723A("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n"); | ||
652 | DBG_8723A("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n", | ||
653 | device_may_wakeup(&pusb_intf->dev)); | ||
654 | } | ||
655 | #endif | ||
656 | /* 2012-07-11 Move here to prevent the 8723AS-VAU BT | ||
657 | * auto suspend influence | ||
658 | */ | ||
659 | if (usb_autopm_get_interface(pusb_intf) < 0) | ||
660 | DBG_8723A("can't get autopm:\n"); | ||
661 | #ifdef CONFIG_8723AU_BT_COEXIST | ||
662 | padapter->pwrctrlpriv.autopm_cnt = 1; | ||
663 | #endif | ||
664 | |||
665 | /* set mac addr */ | ||
666 | rtw_macaddr_cfg23a(padapter->eeprompriv.mac_addr); | ||
667 | rtw_init_wifidirect_addrs23a(padapter, padapter->eeprompriv.mac_addr, | ||
668 | padapter->eeprompriv.mac_addr); | ||
669 | |||
670 | DBG_8723A("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n", | ||
671 | padapter->bDriverStopped, padapter->bSurpriseRemoved, | ||
672 | padapter->bup, padapter->hw_init_completed | ||
673 | ); | ||
674 | status = _SUCCESS; | ||
675 | |||
676 | free_hal_data: | ||
677 | if (status != _SUCCESS) | ||
678 | kfree(padapter->HalData); | ||
679 | if (status != _SUCCESS) { | ||
680 | rtw_wdev_unregister(padapter->rtw_wdev); | ||
681 | rtw_wdev_free(padapter->rtw_wdev); | ||
682 | } | ||
683 | handle_dualmac: | ||
684 | if (status != _SUCCESS) | ||
685 | rtw_handle_dualmac23a(padapter, 0); | ||
686 | free_adapter: | ||
687 | if (status != _SUCCESS) { | ||
688 | if (pnetdev) | ||
689 | free_netdev(pnetdev); | ||
690 | padapter = NULL; | ||
691 | } | ||
692 | return padapter; | ||
693 | } | ||
694 | |||
695 | static void rtw_usb_if1_deinit(struct rtw_adapter *if1) | ||
696 | { | ||
697 | struct net_device *pnetdev = if1->pnetdev; | ||
698 | struct mlme_priv *pmlmepriv = &if1->mlmepriv; | ||
699 | |||
700 | if (check_fwstate(pmlmepriv, _FW_LINKED)) | ||
701 | rtw_disassoc_cmd23a(if1, 0, false); | ||
702 | |||
703 | #ifdef CONFIG_8723AU_AP_MODE | ||
704 | free_mlme_ap_info23a(if1); | ||
705 | #endif | ||
706 | |||
707 | if (pnetdev) | ||
708 | unregister_netdev(pnetdev); /* will call netdev_close() */ | ||
709 | |||
710 | rtw_cancel_all_timer23a(if1); | ||
711 | |||
712 | rtw_dev_unload(if1); | ||
713 | |||
714 | DBG_8723A("+r871xu_dev_remove, hw_init_completed =%d\n", | ||
715 | if1->hw_init_completed); | ||
716 | |||
717 | rtw_handle_dualmac23a(if1, 0); | ||
718 | |||
719 | if (if1->rtw_wdev) { | ||
720 | rtw_wdev_unregister(if1->rtw_wdev); | ||
721 | rtw_wdev_free(if1->rtw_wdev); | ||
722 | } | ||
723 | |||
724 | #ifdef CONFIG_8723AU_BT_COEXIST | ||
725 | if (1 == if1->pwrctrlpriv.autopm_cnt) { | ||
726 | usb_autopm_put_interface(adapter_to_dvobj(if1)->pusbintf); | ||
727 | if1->pwrctrlpriv.autopm_cnt--; | ||
728 | } | ||
729 | #endif | ||
730 | |||
731 | rtw_free_drv_sw23a(if1); | ||
732 | |||
733 | if (pnetdev) | ||
734 | free_netdev(pnetdev); | ||
735 | } | ||
736 | |||
737 | static int rtw_drv_init(struct usb_interface *pusb_intf, | ||
738 | const struct usb_device_id *pdid) | ||
739 | { | ||
740 | struct rtw_adapter *if1 = NULL; | ||
741 | struct dvobj_priv *dvobj; | ||
742 | int status = _FAIL; | ||
743 | |||
744 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n")); | ||
745 | |||
746 | /* Initialize dvobj_priv */ | ||
747 | dvobj = usb_dvobj_init(pusb_intf); | ||
748 | if (!dvobj) { | ||
749 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, | ||
750 | ("initialize device object priv Failed!\n")); | ||
751 | goto exit; | ||
752 | } | ||
753 | |||
754 | if1 = rtw_usb_if1_init(dvobj, pusb_intf, pdid); | ||
755 | if (!if1) { | ||
756 | DBG_8723A("rtw_init_primary_adapter Failed!\n"); | ||
757 | goto free_dvobj; | ||
758 | } | ||
759 | |||
760 | /* dev_alloc_name && register_netdev */ | ||
761 | status = rtw_drv_register_netdev(if1); | ||
762 | if (status != _SUCCESS) | ||
763 | goto free_if1; | ||
764 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, | ||
765 | ("-871x_drv - drv_init, success!\n")); | ||
766 | |||
767 | status = _SUCCESS; | ||
768 | |||
769 | free_if1: | ||
770 | if (status != _SUCCESS && if1) | ||
771 | rtw_usb_if1_deinit(if1); | ||
772 | free_dvobj: | ||
773 | if (status != _SUCCESS) | ||
774 | usb_dvobj_deinit(pusb_intf); | ||
775 | exit: | ||
776 | return status == _SUCCESS ? 0 : -ENODEV; | ||
777 | } | ||
778 | |||
779 | /* dev_remove() - our device is being removed */ | ||
780 | static void rtw_disconnect(struct usb_interface *pusb_intf) | ||
781 | { | ||
782 | struct dvobj_priv *dvobj; | ||
783 | struct rtw_adapter *padapter; | ||
784 | struct net_device *pnetdev; | ||
785 | struct mlme_priv *pmlmepriv; | ||
786 | |||
787 | dvobj = usb_get_intfdata(pusb_intf); | ||
788 | if (!dvobj) | ||
789 | return; | ||
790 | |||
791 | padapter = dvobj->if1; | ||
792 | pnetdev = padapter->pnetdev; | ||
793 | pmlmepriv = &padapter->mlmepriv; | ||
794 | |||
795 | usb_set_intfdata(pusb_intf, NULL); | ||
796 | |||
797 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n")); | ||
798 | |||
799 | rtw_pm_set_ips23a(padapter, IPS_NONE); | ||
800 | rtw_pm_set_lps23a(padapter, PS_MODE_ACTIVE); | ||
801 | |||
802 | LeaveAllPowerSaveMode23a(padapter); | ||
803 | |||
804 | rtw_usb_if1_deinit(padapter); | ||
805 | |||
806 | usb_dvobj_deinit(pusb_intf); | ||
807 | |||
808 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-dev_remove()\n")); | ||
809 | DBG_8723A("-r871xu_dev_remove, done\n"); | ||
810 | |||
811 | return; | ||
812 | } | ||
813 | |||
814 | extern int console_suspend_enabled; | ||
815 | |||
816 | static int __init rtw_drv_entry(void) | ||
817 | { | ||
818 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_entry\n")); | ||
819 | rtw_suspend_lock_init(); | ||
820 | return usb_register(usb_drv); | ||
821 | } | ||
822 | |||
823 | static void __exit rtw_drv_halt(void) | ||
824 | { | ||
825 | RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_halt\n")); | ||
826 | DBG_8723A("+rtw_drv_halt\n"); | ||
827 | |||
828 | rtw_suspend_lock_uninit(); | ||
829 | |||
830 | usb_deregister(usb_drv); | ||
831 | |||
832 | DBG_8723A("-rtw_drv_halt\n"); | ||
833 | } | ||
834 | |||
835 | module_init(rtw_drv_entry); | ||
836 | module_exit(rtw_drv_halt); | ||
diff --git a/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c b/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c new file mode 100644 index 000000000000..c49160e477d8 --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c | |||
@@ -0,0 +1,283 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | ******************************************************************************/ | ||
15 | #define _USB_OPS_LINUX_C_ | ||
16 | |||
17 | #include <drv_types.h> | ||
18 | #include <usb_ops_linux.h> | ||
19 | #include <rtw_sreset.h> | ||
20 | |||
21 | unsigned int ffaddr2pipehdl23a(struct dvobj_priv *pdvobj, u32 addr) | ||
22 | { | ||
23 | struct usb_device *pusbd = pdvobj->pusbdev; | ||
24 | unsigned int pipe = 0, ep_num = 0; | ||
25 | |||
26 | if (addr == RECV_BULK_IN_ADDR) { | ||
27 | pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]); | ||
28 | } else if (addr == RECV_INT_IN_ADDR) { | ||
29 | pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]); | ||
30 | } else if (addr < HW_QUEUE_ENTRY) { | ||
31 | ep_num = pdvobj->Queue2Pipe[addr]; | ||
32 | pipe = usb_sndbulkpipe(pusbd, ep_num); | ||
33 | } | ||
34 | return pipe; | ||
35 | } | ||
36 | |||
37 | struct zero_bulkout_context { | ||
38 | void *pbuf; | ||
39 | void *purb; | ||
40 | void *pirp; | ||
41 | void *padapter; | ||
42 | }; | ||
43 | |||
44 | void usb_read_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) | ||
45 | { | ||
46 | } | ||
47 | |||
48 | void usb_write_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) | ||
49 | { | ||
50 | } | ||
51 | |||
52 | void usb_read_port_cancel23a(struct intf_hdl *pintfhdl) | ||
53 | { | ||
54 | struct recv_buf *precvbuf; | ||
55 | struct rtw_adapter *padapter = pintfhdl->padapter; | ||
56 | int i; | ||
57 | |||
58 | precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; | ||
59 | |||
60 | DBG_8723A("%s\n", __func__); | ||
61 | |||
62 | padapter->bReadPortCancel = true; | ||
63 | |||
64 | for (i = 0; i < NR_RECVBUFF ; i++) { | ||
65 | if (precvbuf->purb) | ||
66 | usb_kill_urb(precvbuf->purb); | ||
67 | precvbuf++; | ||
68 | } | ||
69 | usb_kill_urb(padapter->recvpriv.int_in_urb); | ||
70 | } | ||
71 | |||
72 | static void usb_write_port23a_complete(struct urb *purb, struct pt_regs *regs) | ||
73 | { | ||
74 | struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; | ||
75 | struct rtw_adapter *padapter = pxmitbuf->padapter; | ||
76 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
77 | struct hal_data_8723a *phaldata; | ||
78 | unsigned long irqL; | ||
79 | |||
80 | switch (pxmitbuf->flags) { | ||
81 | case VO_QUEUE_INX: | ||
82 | pxmitpriv->voq_cnt--; | ||
83 | break; | ||
84 | case VI_QUEUE_INX: | ||
85 | pxmitpriv->viq_cnt--; | ||
86 | break; | ||
87 | case BE_QUEUE_INX: | ||
88 | pxmitpriv->beq_cnt--; | ||
89 | break; | ||
90 | case BK_QUEUE_INX: | ||
91 | pxmitpriv->bkq_cnt--; | ||
92 | break; | ||
93 | case HIGH_QUEUE_INX: | ||
94 | #ifdef CONFIG_8723AU_AP_MODE | ||
95 | rtw_chk_hi_queue_cmd23a(padapter); | ||
96 | #endif | ||
97 | break; | ||
98 | default: | ||
99 | break; | ||
100 | } | ||
101 | |||
102 | if (padapter->bSurpriseRemoved || padapter->bDriverStopped || | ||
103 | padapter->bWritePortCancel) { | ||
104 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | ||
105 | ("usb_write_port23a_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", | ||
106 | padapter->bDriverStopped, padapter->bSurpriseRemoved)); | ||
107 | DBG_8723A("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n", | ||
108 | __func__, padapter->bDriverStopped, | ||
109 | padapter->bSurpriseRemoved, padapter->bReadPortCancel, | ||
110 | pxmitbuf->ext_tag); | ||
111 | |||
112 | goto check_completion; | ||
113 | } | ||
114 | |||
115 | if (purb->status) { | ||
116 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | ||
117 | ("usb_write_port23a_complete : purb->status(%d) != 0\n", | ||
118 | purb->status)); | ||
119 | DBG_8723A("###=> urb_write_port_complete status(%d)\n", | ||
120 | purb->status); | ||
121 | if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) { | ||
122 | sreset_set_wifi_error_status23a(padapter, | ||
123 | USB_WRITE_PORT_FAIL); | ||
124 | } else if (purb->status == -EINPROGRESS) { | ||
125 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | ||
126 | ("usb_write_port23a_complete: EINPROGESS\n")); | ||
127 | goto check_completion; | ||
128 | } else if (purb->status == -ENOENT) { | ||
129 | DBG_8723A("%s: -ENOENT\n", __func__); | ||
130 | goto check_completion; | ||
131 | } else if (purb->status == -ECONNRESET) { | ||
132 | DBG_8723A("%s: -ECONNRESET\n", __func__); | ||
133 | goto check_completion; | ||
134 | } else if (purb->status == -ESHUTDOWN) { | ||
135 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | ||
136 | ("usb_write_port23a_complete: ESHUTDOWN\n")); | ||
137 | padapter->bDriverStopped = true; | ||
138 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | ||
139 | ("usb_write_port23a_complete:bDriverStopped = true\n")); | ||
140 | goto check_completion; | ||
141 | } else { | ||
142 | padapter->bSurpriseRemoved = true; | ||
143 | DBG_8723A("bSurpriseRemoved = true\n"); | ||
144 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | ||
145 | ("usb_write_port23a_complete:bSurpriseRemoved = true\n")); | ||
146 | goto check_completion; | ||
147 | } | ||
148 | } | ||
149 | phaldata = GET_HAL_DATA(padapter); | ||
150 | phaldata->srestpriv.last_tx_complete_time = jiffies; | ||
151 | |||
152 | check_completion: | ||
153 | spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL); | ||
154 | rtw23a_sctx_done_err(&pxmitbuf->sctx, | ||
155 | purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : | ||
156 | RTW_SCTX_DONE_SUCCESS); | ||
157 | spin_unlock_irqrestore(&pxmitpriv->lock_sctx, irqL); | ||
158 | |||
159 | rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); | ||
160 | |||
161 | tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); | ||
162 | } | ||
163 | |||
164 | u32 usb_write_port23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, | ||
165 | struct xmit_buf *pxmitbuf) | ||
166 | { | ||
167 | struct urb *purb = NULL; | ||
168 | struct rtw_adapter *padapter = (struct rtw_adapter *)pintfhdl->padapter; | ||
169 | struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); | ||
170 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
171 | struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; | ||
172 | struct usb_device *pusbd = pdvobj->pusbdev; | ||
173 | unsigned long irqL; | ||
174 | unsigned int pipe; | ||
175 | int status; | ||
176 | u32 ret = _FAIL; | ||
177 | |||
178 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("+usb_write_port23a\n")); | ||
179 | |||
180 | if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) || | ||
181 | (padapter->pwrctrlpriv.pnp_bstop_trx)) { | ||
182 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | ||
183 | ("usb_write_port23a:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n")); | ||
184 | rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); | ||
185 | goto exit; | ||
186 | } | ||
187 | |||
188 | spin_lock_irqsave(&pxmitpriv->lock, irqL); | ||
189 | |||
190 | switch (addr) { | ||
191 | case VO_QUEUE_INX: | ||
192 | pxmitpriv->voq_cnt++; | ||
193 | pxmitbuf->flags = VO_QUEUE_INX; | ||
194 | break; | ||
195 | case VI_QUEUE_INX: | ||
196 | pxmitpriv->viq_cnt++; | ||
197 | pxmitbuf->flags = VI_QUEUE_INX; | ||
198 | break; | ||
199 | case BE_QUEUE_INX: | ||
200 | pxmitpriv->beq_cnt++; | ||
201 | pxmitbuf->flags = BE_QUEUE_INX; | ||
202 | break; | ||
203 | case BK_QUEUE_INX: | ||
204 | pxmitpriv->bkq_cnt++; | ||
205 | pxmitbuf->flags = BK_QUEUE_INX; | ||
206 | break; | ||
207 | case HIGH_QUEUE_INX: | ||
208 | pxmitbuf->flags = HIGH_QUEUE_INX; | ||
209 | break; | ||
210 | default: | ||
211 | pxmitbuf->flags = MGT_QUEUE_INX; | ||
212 | break; | ||
213 | } | ||
214 | |||
215 | spin_unlock_irqrestore(&pxmitpriv->lock, irqL); | ||
216 | |||
217 | purb = pxmitbuf->pxmit_urb[0]; | ||
218 | |||
219 | /* translate DMA FIFO addr to pipehandle */ | ||
220 | pipe = ffaddr2pipehdl23a(pdvobj, addr); | ||
221 | |||
222 | usb_fill_bulk_urb(purb, pusbd, pipe, | ||
223 | pxmitframe->buf_addr, /* pxmitbuf->pbuf */ | ||
224 | cnt, usb_write_port23a_complete, | ||
225 | pxmitbuf);/* context is pxmitbuf */ | ||
226 | |||
227 | status = usb_submit_urb(purb, GFP_ATOMIC); | ||
228 | if (!status) { | ||
229 | struct hal_data_8723a *phaldata = GET_HAL_DATA(padapter); | ||
230 | phaldata->srestpriv.last_tx_time = jiffies; | ||
231 | } else { | ||
232 | rtw23a_sctx_done_err(&pxmitbuf->sctx, | ||
233 | RTW_SCTX_DONE_WRITE_PORT_ERR); | ||
234 | DBG_8723A("usb_write_port23a, status =%d\n", status); | ||
235 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | ||
236 | ("usb_write_port23a(): usb_submit_urb, status =%x\n", | ||
237 | status)); | ||
238 | |||
239 | switch (status) { | ||
240 | case -ENODEV: | ||
241 | padapter->bDriverStopped = true; | ||
242 | break; | ||
243 | default: | ||
244 | break; | ||
245 | } | ||
246 | goto exit; | ||
247 | } | ||
248 | ret = _SUCCESS; | ||
249 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("-usb_write_port23a\n")); | ||
250 | |||
251 | exit: | ||
252 | if (ret != _SUCCESS) | ||
253 | rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); | ||
254 | |||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | void usb_write_port23a_cancel(struct intf_hdl *pintfhdl) | ||
259 | { | ||
260 | struct rtw_adapter *padapter = pintfhdl->padapter; | ||
261 | struct xmit_buf *pxmitbuf; | ||
262 | struct list_head *plist; | ||
263 | int j; | ||
264 | |||
265 | DBG_8723A("%s\n", __func__); | ||
266 | |||
267 | padapter->bWritePortCancel = true; | ||
268 | |||
269 | list_for_each(plist, &padapter->xmitpriv.xmitbuf_list) { | ||
270 | pxmitbuf = container_of(plist, struct xmit_buf, list2); | ||
271 | for (j = 0; j < 8; j++) { | ||
272 | if (pxmitbuf->pxmit_urb[j]) | ||
273 | usb_kill_urb(pxmitbuf->pxmit_urb[j]); | ||
274 | } | ||
275 | } | ||
276 | list_for_each(plist, &padapter->xmitpriv.xmitextbuf_list) { | ||
277 | pxmitbuf = container_of(plist, struct xmit_buf, list2); | ||
278 | for (j = 0; j < 8; j++) { | ||
279 | if (pxmitbuf->pxmit_urb[j]) | ||
280 | usb_kill_urb(pxmitbuf->pxmit_urb[j]); | ||
281 | } | ||
282 | } | ||
283 | } | ||
diff --git a/drivers/staging/rtl8723au/os_dep/xmit_linux.c b/drivers/staging/rtl8723au/os_dep/xmit_linux.c new file mode 100644 index 000000000000..e1c6fc746233 --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/xmit_linux.c | |||
@@ -0,0 +1,195 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | ******************************************************************************/ | ||
15 | #define _XMIT_OSDEP_C_ | ||
16 | |||
17 | #include <osdep_service.h> | ||
18 | #include <drv_types.h> | ||
19 | |||
20 | #include <linux/if_ether.h> | ||
21 | #include <linux/ip.h> | ||
22 | #include <wifi.h> | ||
23 | #include <mlme_osdep.h> | ||
24 | #include <xmit_osdep.h> | ||
25 | #include <osdep_intf.h> | ||
26 | |||
27 | uint rtw_remainder_len23a(struct pkt_file *pfile) | ||
28 | { | ||
29 | return pfile->buf_len - ((unsigned long)(pfile->cur_addr) - | ||
30 | (unsigned long)(pfile->buf_start)); | ||
31 | } | ||
32 | |||
33 | void _rtw_open_pktfile23a(struct sk_buff *pktptr, struct pkt_file *pfile) | ||
34 | { | ||
35 | pfile->pkt = pktptr; | ||
36 | pfile->buf_start = pktptr->data; | ||
37 | pfile->cur_addr = pktptr->data; | ||
38 | pfile->buf_len = pktptr->len; | ||
39 | pfile->pkt_len = pktptr->len; | ||
40 | |||
41 | pfile->cur_buffer = pfile->buf_start; | ||
42 | } | ||
43 | |||
44 | uint _rtw_pktfile_read23a(struct pkt_file *pfile, u8 *rmem, uint rlen) | ||
45 | { | ||
46 | uint len = 0; | ||
47 | |||
48 | len = rtw_remainder_len23a(pfile); | ||
49 | len = (rlen > len) ? len : rlen; | ||
50 | |||
51 | if (rmem) | ||
52 | skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, | ||
53 | rmem, len); | ||
54 | |||
55 | pfile->cur_addr += len; | ||
56 | pfile->pkt_len -= len; | ||
57 | |||
58 | return len; | ||
59 | } | ||
60 | |||
61 | int rtw_endofpktfile23a(struct pkt_file *pfile) | ||
62 | { | ||
63 | if (pfile->pkt_len == 0) | ||
64 | return true; | ||
65 | return false; | ||
66 | } | ||
67 | |||
68 | int rtw_os_xmit_resource_alloc23a(struct rtw_adapter *padapter, | ||
69 | struct xmit_buf *pxmitbuf, u32 alloc_sz) | ||
70 | { | ||
71 | int i; | ||
72 | |||
73 | pxmitbuf->pallocated_buf = kzalloc(alloc_sz, GFP_KERNEL); | ||
74 | if (pxmitbuf->pallocated_buf == NULL) | ||
75 | return _FAIL; | ||
76 | |||
77 | pxmitbuf->pbuf = PTR_ALIGN(pxmitbuf->pallocated_buf, XMITBUF_ALIGN_SZ); | ||
78 | |||
79 | for (i = 0; i < 8; i++) { | ||
80 | pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); | ||
81 | if (pxmitbuf->pxmit_urb[i] == NULL) { | ||
82 | DBG_8723A("pxmitbuf->pxmit_urb[i]==NULL"); | ||
83 | return _FAIL; | ||
84 | } | ||
85 | } | ||
86 | return _SUCCESS; | ||
87 | } | ||
88 | |||
89 | void rtw_os_xmit_resource_free23a(struct rtw_adapter *padapter, | ||
90 | struct xmit_buf *pxmitbuf) | ||
91 | { | ||
92 | int i; | ||
93 | |||
94 | for (i = 0; i < 8; i++) | ||
95 | usb_free_urb(pxmitbuf->pxmit_urb[i]); | ||
96 | kfree(pxmitbuf->pallocated_buf); | ||
97 | } | ||
98 | |||
99 | #define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5) | ||
100 | |||
101 | void rtw_os_pkt_complete23a(struct rtw_adapter *padapter, struct sk_buff *pkt) | ||
102 | { | ||
103 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
104 | u16 queue; | ||
105 | |||
106 | queue = skb_get_queue_mapping(pkt); | ||
107 | if (padapter->registrypriv.wifi_spec) { | ||
108 | if (__netif_subqueue_stopped(padapter->pnetdev, queue) && | ||
109 | (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD)) | ||
110 | netif_wake_subqueue(padapter->pnetdev, queue); | ||
111 | } else { | ||
112 | if (__netif_subqueue_stopped(padapter->pnetdev, queue)) | ||
113 | netif_wake_subqueue(padapter->pnetdev, queue); | ||
114 | } | ||
115 | dev_kfree_skb_any(pkt); | ||
116 | } | ||
117 | |||
118 | void rtw_os_xmit_complete23a(struct rtw_adapter *padapter, | ||
119 | struct xmit_frame *pxframe) | ||
120 | { | ||
121 | if (pxframe->pkt) | ||
122 | rtw_os_pkt_complete23a(padapter, pxframe->pkt); | ||
123 | |||
124 | pxframe->pkt = NULL; | ||
125 | } | ||
126 | |||
127 | void rtw_os_xmit_schedule23a(struct rtw_adapter *padapter) | ||
128 | { | ||
129 | struct xmit_priv *pxmitpriv; | ||
130 | |||
131 | if (!padapter) | ||
132 | return; | ||
133 | pxmitpriv = &padapter->xmitpriv; | ||
134 | |||
135 | spin_lock_bh(&pxmitpriv->lock); | ||
136 | |||
137 | if (rtw_txframes_pending23a(padapter)) | ||
138 | tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); | ||
139 | spin_unlock_bh(&pxmitpriv->lock); | ||
140 | } | ||
141 | |||
142 | static void rtw_check_xmit_resource(struct rtw_adapter *padapter, | ||
143 | struct sk_buff *pkt) | ||
144 | { | ||
145 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
146 | u16 queue; | ||
147 | |||
148 | queue = skb_get_queue_mapping(pkt); | ||
149 | if (padapter->registrypriv.wifi_spec) { | ||
150 | /* No free space for Tx, tx_worker is too slow */ | ||
151 | if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) | ||
152 | netif_stop_subqueue(padapter->pnetdev, queue); | ||
153 | } else { | ||
154 | if (pxmitpriv->free_xmitframe_cnt <= 4) { | ||
155 | if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue))) | ||
156 | netif_stop_subqueue(padapter->pnetdev, queue); | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | int rtw_xmit23a_entry23a(struct sk_buff *skb, struct net_device *pnetdev) | ||
162 | { | ||
163 | struct rtw_adapter *padapter = netdev_priv(pnetdev); | ||
164 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
165 | int res = 0; | ||
166 | |||
167 | RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n")); | ||
168 | |||
169 | if (!rtw_if_up23a(padapter)) { | ||
170 | RT_TRACE(_module_xmit_osdep_c_, _drv_err_, | ||
171 | ("rtw_xmit23a_entry23a: rtw_if_up23a fail\n")); | ||
172 | goto drop_packet; | ||
173 | } | ||
174 | |||
175 | rtw_check_xmit_resource(padapter, skb); | ||
176 | |||
177 | res = rtw_xmit23a(padapter, skb); | ||
178 | if (res < 0) | ||
179 | goto drop_packet; | ||
180 | |||
181 | pxmitpriv->tx_pkts++; | ||
182 | RT_TRACE(_module_xmit_osdep_c_, _drv_info_, | ||
183 | ("rtw_xmit23a_entry23a: tx_pkts=%d\n", | ||
184 | (u32)pxmitpriv->tx_pkts)); | ||
185 | goto exit; | ||
186 | |||
187 | drop_packet: | ||
188 | pxmitpriv->tx_drop++; | ||
189 | dev_kfree_skb_any(skb); | ||
190 | RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, | ||
191 | ("rtw_xmit23a_entry23a: drop, tx_drop=%d\n", | ||
192 | (u32)pxmitpriv->tx_drop)); | ||
193 | exit: | ||
194 | return 0; | ||
195 | } | ||