]>
Commit | Line | Data |
---|---|---|
5e93f352 LF |
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 _RTW_WLAN_UTIL_C_ | |
16 | ||
17 | #include <osdep_service.h> | |
18 | #include <drv_types.h> | |
19 | #include <linux/ieee80211.h> | |
20 | #include <wifi.h> | |
21 | ||
22 | static unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f}; | |
23 | static unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74}; | |
24 | ||
25 | static unsigned char BROADCOM_OUI1[] = {0x00, 0x10, 0x18}; | |
26 | static unsigned char BROADCOM_OUI2[] = {0x00, 0x0a, 0xf7}; | |
27 | ||
28 | static unsigned char CISCO_OUI[] = {0x00, 0x40, 0x96}; | |
29 | static unsigned char MARVELL_OUI[] = {0x00, 0x50, 0x43}; | |
30 | static unsigned char RALINK_OUI[] = {0x00, 0x0c, 0x43}; | |
31 | static unsigned char REALTEK_OUI[] = {0x00, 0xe0, 0x4c}; | |
32 | static unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5}; | |
33 | static unsigned char EPIGRAM_OUI[] = {0x00, 0x90, 0x4c}; | |
34 | ||
78717782 JS |
35 | static unsigned char WPA_TKIP_CIPHER[4] = {0x00, 0x50, 0xf2, 0x02}; |
36 | static unsigned char RSN_TKIP_CIPHER[4] = {0x00, 0x0f, 0xac, 0x02}; | |
37 | ||
c227ed0a | 38 | #define R2T_PHY_DELAY 0 |
5e93f352 | 39 | |
c227ed0a JS |
40 | /* define WAIT_FOR_BCN_TO_MIN 3000 */ |
41 | #define WAIT_FOR_BCN_TO_MIN 6000 | |
42 | #define WAIT_FOR_BCN_TO_MAX 20000 | |
5e93f352 LF |
43 | |
44 | static u8 rtw_basic_rate_cck[4] = { | |
c227ed0a JS |
45 | IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK, |
46 | IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK, | |
47 | IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK, | |
48 | IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK | |
5e93f352 LF |
49 | }; |
50 | ||
51 | static u8 rtw_basic_rate_ofdm[3] = { | |
c227ed0a JS |
52 | IEEE80211_OFDM_RATE_6MB | IEEE80211_BASIC_RATE_MASK, |
53 | IEEE80211_OFDM_RATE_12MB | IEEE80211_BASIC_RATE_MASK, | |
54 | IEEE80211_OFDM_RATE_24MB | IEEE80211_BASIC_RATE_MASK | |
5e93f352 LF |
55 | }; |
56 | ||
57 | static u8 rtw_basic_rate_mix[7] = { | |
c227ed0a JS |
58 | IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK, |
59 | IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK, | |
60 | IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK, | |
61 | IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK, | |
62 | IEEE80211_OFDM_RATE_6MB | IEEE80211_BASIC_RATE_MASK, | |
63 | IEEE80211_OFDM_RATE_12MB | IEEE80211_BASIC_RATE_MASK, | |
64 | IEEE80211_OFDM_RATE_24MB | IEEE80211_BASIC_RATE_MASK | |
5e93f352 LF |
65 | }; |
66 | ||
67 | int cckrates_included23a(unsigned char *rate, int ratelen) | |
68 | { | |
69 | int i; | |
70 | ||
71 | for (i = 0; i < ratelen; i++) { | |
c227ed0a JS |
72 | if (((rate[i]) & 0x7f) == 2 || ((rate[i]) & 0x7f) == 4 || |
73 | ((rate[i]) & 0x7f) == 11 || ((rate[i]) & 0x7f) == 22) | |
5e93f352 LF |
74 | return true; |
75 | } | |
76 | ||
77 | return false; | |
78 | } | |
79 | ||
80 | int cckratesonly_included23a(unsigned char *rate, int ratelen) | |
81 | { | |
82 | int i; | |
83 | ||
84 | for (i = 0; i < ratelen; i++) { | |
c227ed0a JS |
85 | if (((rate[i]) & 0x7f) != 2 && ((rate[i]) & 0x7f) != 4 && |
86 | ((rate[i]) & 0x7f) != 11 && ((rate[i]) & 0x7f) != 22) | |
5e93f352 LF |
87 | return false; |
88 | } | |
89 | ||
90 | return true; | |
91 | } | |
92 | ||
93 | unsigned char networktype_to_raid23a(unsigned char network_type) | |
94 | { | |
95 | unsigned char raid; | |
96 | ||
97 | switch (network_type) { | |
98 | case WIRELESS_11B: | |
99 | raid = RATR_INX_WIRELESS_B; | |
100 | break; | |
101 | case WIRELESS_11A: | |
102 | case WIRELESS_11G: | |
103 | raid = RATR_INX_WIRELESS_G; | |
104 | break; | |
105 | case WIRELESS_11BG: | |
106 | raid = RATR_INX_WIRELESS_GB; | |
107 | break; | |
108 | case WIRELESS_11_24N: | |
109 | case WIRELESS_11_5N: | |
110 | raid = RATR_INX_WIRELESS_N; | |
111 | break; | |
112 | case WIRELESS_11A_5N: | |
113 | case WIRELESS_11G_24N: | |
114 | raid = RATR_INX_WIRELESS_NG; | |
115 | break; | |
116 | case WIRELESS_11BG_24N: | |
117 | raid = RATR_INX_WIRELESS_NGB; | |
118 | break; | |
119 | default: | |
120 | raid = RATR_INX_WIRELESS_GB; | |
121 | break; | |
122 | } | |
123 | return raid; | |
124 | } | |
125 | ||
c227ed0a JS |
126 | u8 judge_network_type23a(struct rtw_adapter *padapter, |
127 | unsigned char *rate, int ratelen) | |
5e93f352 LF |
128 | { |
129 | u8 network_type = 0; | |
c227ed0a | 130 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
131 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
132 | ||
133 | if (pmlmeext->cur_channel > 14) { | |
134 | if (pmlmeinfo->HT_enable) | |
135 | network_type = WIRELESS_11_5N; | |
136 | network_type |= WIRELESS_11A; | |
137 | } else { | |
138 | if (pmlmeinfo->HT_enable) | |
139 | network_type = WIRELESS_11_24N; | |
140 | ||
141 | if ((cckratesonly_included23a(rate, ratelen)) == true) | |
142 | network_type |= WIRELESS_11B; | |
143 | else if ((cckrates_included23a(rate, ratelen)) == true) | |
144 | network_type |= WIRELESS_11BG; | |
145 | else | |
146 | network_type |= WIRELESS_11G; | |
147 | } | |
148 | return network_type; | |
149 | } | |
150 | ||
c0b99bed | 151 | static unsigned char ratetbl_val_2wifirate(unsigned char rate) |
5e93f352 LF |
152 | { |
153 | unsigned char val = 0; | |
154 | ||
155 | switch (rate & 0x7f) { | |
156 | case 0: | |
157 | val = IEEE80211_CCK_RATE_1MB; | |
158 | break; | |
159 | case 1: | |
160 | val = IEEE80211_CCK_RATE_2MB; | |
161 | break; | |
162 | case 2: | |
163 | val = IEEE80211_CCK_RATE_5MB; | |
164 | break; | |
165 | case 3: | |
166 | val = IEEE80211_CCK_RATE_11MB; | |
167 | break; | |
168 | case 4: | |
169 | val = IEEE80211_OFDM_RATE_6MB; | |
170 | break; | |
171 | case 5: | |
172 | val = IEEE80211_OFDM_RATE_9MB; | |
173 | break; | |
174 | case 6: | |
175 | val = IEEE80211_OFDM_RATE_12MB; | |
176 | break; | |
177 | case 7: | |
178 | val = IEEE80211_OFDM_RATE_18MB; | |
179 | break; | |
180 | case 8: | |
181 | val = IEEE80211_OFDM_RATE_24MB; | |
182 | break; | |
183 | case 9: | |
184 | val = IEEE80211_OFDM_RATE_36MB; | |
185 | break; | |
186 | case 10: | |
187 | val = IEEE80211_OFDM_RATE_48MB; | |
188 | break; | |
189 | case 11: | |
190 | val = IEEE80211_OFDM_RATE_54MB; | |
191 | break; | |
192 | } | |
193 | return val; | |
194 | } | |
195 | ||
c0b99bed | 196 | static int is_basicrate(struct rtw_adapter *padapter, unsigned char rate) |
5e93f352 LF |
197 | { |
198 | int i; | |
199 | unsigned char val; | |
200 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | |
201 | ||
202 | for (i = 0; i < NumRates; i++) { | |
203 | val = pmlmeext->basicrate[i]; | |
204 | ||
c227ed0a | 205 | if (val != 0xff && val != 0xfe) { |
5e93f352 LF |
206 | if (rate == ratetbl_val_2wifirate(val)) |
207 | return true; | |
208 | } | |
209 | } | |
210 | ||
211 | return false; | |
212 | } | |
213 | ||
c0b99bed LF |
214 | static unsigned int ratetbl2rateset(struct rtw_adapter *padapter, |
215 | unsigned char *rateset) | |
5e93f352 LF |
216 | { |
217 | int i; | |
218 | unsigned char rate; | |
c227ed0a | 219 | unsigned int len = 0; |
5e93f352 LF |
220 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
221 | ||
222 | for (i = 0; i < NumRates; i++) { | |
223 | rate = pmlmeext->datarate[i]; | |
224 | ||
225 | switch (rate) { | |
226 | case 0xff: | |
227 | return len; | |
228 | case 0xfe: | |
229 | continue; | |
230 | default: | |
231 | rate = ratetbl_val_2wifirate(rate); | |
232 | ||
233 | if (is_basicrate(padapter, rate) == true) | |
234 | rate |= IEEE80211_BASIC_RATE_MASK; | |
235 | ||
236 | rateset[len] = rate; | |
237 | len++; | |
238 | break; | |
239 | } | |
240 | } | |
241 | return len; | |
242 | } | |
243 | ||
c227ed0a JS |
244 | void get_rate_set23a(struct rtw_adapter *padapter, |
245 | unsigned char *pbssrate, int *bssrate_len) | |
5e93f352 LF |
246 | { |
247 | unsigned char supportedrates[NumRates]; | |
248 | ||
249 | memset(supportedrates, 0, NumRates); | |
250 | *bssrate_len = ratetbl2rateset(padapter, supportedrates); | |
251 | memcpy(pbssrate, supportedrates, *bssrate_len); | |
252 | } | |
253 | ||
254 | void UpdateBrateTbl23a(struct rtw_adapter *Adapter, u8 *mBratesOS) | |
255 | { | |
c227ed0a JS |
256 | u8 i; |
257 | u8 rate; | |
5e93f352 LF |
258 | |
259 | /* 1M, 2M, 5.5M, 11M, 6M, 12M, 24M are mandatory. */ | |
260 | for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { | |
261 | rate = mBratesOS[i] & 0x7f; | |
262 | switch (rate) { | |
263 | case IEEE80211_CCK_RATE_1MB: | |
264 | case IEEE80211_CCK_RATE_2MB: | |
265 | case IEEE80211_CCK_RATE_5MB: | |
266 | case IEEE80211_CCK_RATE_11MB: | |
267 | case IEEE80211_OFDM_RATE_6MB: | |
268 | case IEEE80211_OFDM_RATE_12MB: | |
269 | case IEEE80211_OFDM_RATE_24MB: | |
270 | mBratesOS[i] |= IEEE80211_BASIC_RATE_MASK; | |
271 | break; | |
272 | default: | |
273 | break; | |
274 | } | |
275 | } | |
276 | } | |
277 | ||
278 | void Update23aTblForSoftAP(u8 *bssrateset, u32 bssratelen) | |
279 | { | |
c227ed0a JS |
280 | u8 i; |
281 | u8 rate; | |
5e93f352 LF |
282 | |
283 | for (i = 0; i < bssratelen; i++) { | |
284 | rate = bssrateset[i] & 0x7f; | |
285 | switch (rate) { | |
286 | case IEEE80211_CCK_RATE_1MB: | |
287 | case IEEE80211_CCK_RATE_2MB: | |
288 | case IEEE80211_CCK_RATE_5MB: | |
289 | case IEEE80211_CCK_RATE_11MB: | |
290 | bssrateset[i] |= IEEE80211_BASIC_RATE_MASK; | |
291 | break; | |
292 | } | |
293 | } | |
294 | } | |
295 | ||
5e93f352 LF |
296 | void Set_MSR23a(struct rtw_adapter *padapter, u8 type) |
297 | { | |
03aa3ec0 | 298 | rtl8723a_set_media_status(padapter, type); |
5e93f352 LF |
299 | } |
300 | ||
301 | inline u8 rtw_get_oper_ch23a(struct rtw_adapter *adapter) | |
302 | { | |
303 | return adapter_to_dvobj(adapter)->oper_channel; | |
304 | } | |
305 | ||
306 | inline void rtw_set_oper_ch23a(struct rtw_adapter *adapter, u8 ch) | |
307 | { | |
308 | adapter_to_dvobj(adapter)->oper_channel = ch; | |
309 | } | |
310 | ||
311 | inline u8 rtw_get_oper_bw23a(struct rtw_adapter *adapter) | |
312 | { | |
313 | return adapter_to_dvobj(adapter)->oper_bwmode; | |
314 | } | |
315 | ||
316 | inline void rtw_set_oper_bw23a(struct rtw_adapter *adapter, u8 bw) | |
317 | { | |
318 | adapter_to_dvobj(adapter)->oper_bwmode = bw; | |
319 | } | |
320 | ||
321 | inline u8 rtw_get_oper_ch23aoffset(struct rtw_adapter *adapter) | |
322 | { | |
323 | return adapter_to_dvobj(adapter)->oper_ch_offset; | |
324 | } | |
325 | ||
326 | inline void rtw_set_oper_ch23aoffset23a(struct rtw_adapter *adapter, u8 offset) | |
327 | { | |
328 | adapter_to_dvobj(adapter)->oper_ch_offset = offset; | |
329 | } | |
330 | ||
331 | void SelectChannel23a(struct rtw_adapter *padapter, unsigned char channel) | |
332 | { | |
333 | mutex_lock(&adapter_to_dvobj(padapter)->setch_mutex); | |
334 | ||
335 | /* saved channel info */ | |
336 | rtw_set_oper_ch23a(padapter, channel); | |
337 | ||
8a6f555f | 338 | PHY_SwChnl8723A(padapter, channel); |
5e93f352 LF |
339 | |
340 | mutex_unlock(&adapter_to_dvobj(padapter)->setch_mutex); | |
341 | } | |
342 | ||
9b0cb4b6 JS |
343 | static void set_bwmode(struct rtw_adapter *padapter, unsigned short bwmode, |
344 | unsigned char channel_offset) | |
5e93f352 LF |
345 | { |
346 | mutex_lock(&adapter_to_dvobj(padapter)->setbw_mutex); | |
347 | ||
348 | /* saved bw info */ | |
349 | rtw_set_oper_bw23a(padapter, bwmode); | |
350 | rtw_set_oper_ch23aoffset23a(padapter, channel_offset); | |
351 | ||
8a6f555f JS |
352 | PHY_SetBWMode23a8723A(padapter, (enum ht_channel_width)bwmode, |
353 | channel_offset); | |
5e93f352 LF |
354 | |
355 | mutex_unlock(&adapter_to_dvobj(padapter)->setbw_mutex); | |
356 | } | |
357 | ||
358 | void set_channel_bwmode23a(struct rtw_adapter *padapter, unsigned char channel, | |
359 | unsigned char channel_offset, unsigned short bwmode) | |
360 | { | |
361 | u8 center_ch; | |
362 | ||
363 | if (padapter->bNotifyChannelChange) | |
c227ed0a JS |
364 | DBG_8723A("[%s] ch = %d, offset = %d, bwmode = %d\n", |
365 | __func__, channel, channel_offset, bwmode); | |
5e93f352 | 366 | |
c227ed0a JS |
367 | if (bwmode == HT_CHANNEL_WIDTH_20 || |
368 | channel_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) { | |
5e93f352 LF |
369 | /* SelectChannel23a(padapter, channel); */ |
370 | center_ch = channel; | |
371 | } else { | |
372 | /* switch to the proper channel */ | |
373 | if (channel_offset == HAL_PRIME_CHNL_OFFSET_LOWER) { | |
374 | /* SelectChannel23a(padapter, channel + 2); */ | |
375 | center_ch = channel + 2; | |
376 | } else { | |
377 | /* SelectChannel23a(padapter, channel - 2); */ | |
378 | center_ch = channel - 2; | |
379 | } | |
380 | } | |
381 | ||
382 | /* set Channel */ | |
383 | mutex_lock(&adapter_to_dvobj(padapter)->setch_mutex); | |
384 | ||
385 | /* saved channel/bw info */ | |
386 | rtw_set_oper_ch23a(padapter, channel); | |
387 | rtw_set_oper_bw23a(padapter, bwmode); | |
388 | rtw_set_oper_ch23aoffset23a(padapter, channel_offset); | |
389 | ||
8a6f555f | 390 | PHY_SwChnl8723A(padapter, center_ch); /* set center channel */ |
5e93f352 LF |
391 | |
392 | mutex_unlock(&adapter_to_dvobj(padapter)->setch_mutex); | |
393 | ||
9b0cb4b6 | 394 | set_bwmode(padapter, bwmode, channel_offset); |
5e93f352 LF |
395 | } |
396 | ||
5e93f352 LF |
397 | inline u8 *get_my_bssid23a(struct wlan_bssid_ex *pnetwork) |
398 | { | |
399 | return pnetwork->MacAddress; | |
400 | } | |
401 | ||
402 | u16 get_beacon_interval23a(struct wlan_bssid_ex *bss) | |
403 | { | |
404 | unsigned short val; | |
c227ed0a | 405 | memcpy(&val, rtw_get_beacon_interval23a_from_ie(bss->IEs), 2); |
5e93f352 LF |
406 | |
407 | return le16_to_cpu(val); | |
408 | } | |
409 | ||
f6fe0a41 | 410 | bool is_client_associated_to_ap23a(struct rtw_adapter *padapter) |
5e93f352 | 411 | { |
c227ed0a JS |
412 | struct mlme_ext_priv *pmlmeext; |
413 | struct mlme_ext_info *pmlmeinfo; | |
5e93f352 LF |
414 | |
415 | if (!padapter) | |
f6fe0a41 | 416 | return false; |
5e93f352 LF |
417 | |
418 | pmlmeext = &padapter->mlmeextpriv; | |
419 | pmlmeinfo = &pmlmeext->mlmext_info; | |
420 | ||
c227ed0a JS |
421 | if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS && |
422 | (pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) | |
5e93f352 LF |
423 | return true; |
424 | else | |
f6fe0a41 | 425 | return false; |
5e93f352 LF |
426 | } |
427 | ||
f6fe0a41 | 428 | bool is_client_associated_to_ibss23a(struct rtw_adapter *padapter) |
5e93f352 | 429 | { |
c227ed0a | 430 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
431 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
432 | ||
c227ed0a JS |
433 | if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS && |
434 | (pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) | |
5e93f352 LF |
435 | return true; |
436 | else | |
f6fe0a41 | 437 | return false; |
5e93f352 LF |
438 | } |
439 | ||
f6fe0a41 | 440 | bool is_IBSS_empty23a(struct rtw_adapter *padapter) |
5e93f352 LF |
441 | { |
442 | unsigned int i; | |
c227ed0a | 443 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
444 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
445 | ||
446 | for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) { | |
447 | if (pmlmeinfo->FW_sta_info[i].status == 1) | |
f6fe0a41 | 448 | return false; |
5e93f352 LF |
449 | } |
450 | ||
451 | return true; | |
452 | } | |
453 | ||
454 | unsigned int decide_wait_for_beacon_timeout23a(unsigned int bcn_interval) | |
455 | { | |
456 | if ((bcn_interval << 2) < WAIT_FOR_BCN_TO_MIN) | |
457 | return WAIT_FOR_BCN_TO_MIN; | |
458 | else if ((bcn_interval << 2) > WAIT_FOR_BCN_TO_MAX) | |
459 | return WAIT_FOR_BCN_TO_MAX; | |
460 | else | |
461 | return bcn_interval << 2; | |
462 | } | |
463 | ||
5e93f352 LF |
464 | void invalidate_cam_all23a(struct rtw_adapter *padapter) |
465 | { | |
763b4247 | 466 | rtl8723a_cam_invalid_all(padapter); |
5e93f352 LF |
467 | } |
468 | ||
5e93f352 LF |
469 | void clear_cam_entry23a(struct rtw_adapter *padapter, u8 entry) |
470 | { | |
471 | unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | |
472 | ||
c227ed0a JS |
473 | unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
474 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
475 | 0x00, 0x00, 0x00, 0x00}; | |
5e93f352 | 476 | |
dc0d16a1 | 477 | rtl8723a_cam_write(padapter, entry, 0, null_sta, null_key); |
5e93f352 LF |
478 | } |
479 | ||
480 | int allocate_fw_sta_entry23a(struct rtw_adapter *padapter) | |
481 | { | |
482 | unsigned int mac_id; | |
c227ed0a | 483 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
484 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
485 | ||
486 | for (mac_id = IBSS_START_MAC_ID; mac_id < NUM_STA; mac_id++) { | |
487 | if (pmlmeinfo->FW_sta_info[mac_id].status == 0) { | |
488 | pmlmeinfo->FW_sta_info[mac_id].status = 1; | |
489 | pmlmeinfo->FW_sta_info[mac_id].retry = 0; | |
490 | break; | |
491 | } | |
492 | } | |
493 | ||
494 | return mac_id; | |
495 | } | |
496 | ||
497 | void flush_all_cam_entry23a(struct rtw_adapter *padapter) | |
498 | { | |
c227ed0a | 499 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
500 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
501 | ||
763b4247 | 502 | rtl8723a_cam_invalid_all(padapter); |
5e93f352 | 503 | |
c227ed0a | 504 | memset(pmlmeinfo->FW_sta_info, 0, sizeof(pmlmeinfo->FW_sta_info)); |
5e93f352 LF |
505 | } |
506 | ||
3cdf2773 | 507 | int WMM_param_handler23a(struct rtw_adapter *padapter, const u8 *p) |
5e93f352 LF |
508 | { |
509 | /* struct registry_priv *pregpriv = &padapter->registrypriv; */ | |
510 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
c227ed0a | 511 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
512 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
513 | ||
bd8ad4a5 | 514 | if (pmlmepriv->qos_option == 0) { |
5e93f352 LF |
515 | pmlmeinfo->WMM_enable = 0; |
516 | return _FAIL; | |
517 | } | |
518 | ||
519 | pmlmeinfo->WMM_enable = 1; | |
b171da3c | 520 | memcpy(&pmlmeinfo->WMM_param, p + 2 + 6, |
5e93f352 LF |
521 | sizeof(struct WMM_para_element)); |
522 | return true; | |
523 | } | |
524 | ||
525 | void WMMOnAssocRsp23a(struct rtw_adapter *padapter) | |
526 | { | |
c227ed0a JS |
527 | u8 ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime; |
528 | u8 acm_mask; | |
529 | u16 TXOP; | |
530 | u32 acParm, i; | |
531 | u32 edca[4], inx[4]; | |
532 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | |
5e93f352 | 533 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
c227ed0a JS |
534 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
535 | struct registry_priv *pregpriv = &padapter->registrypriv; | |
5e93f352 LF |
536 | |
537 | if (pmlmeinfo->WMM_enable == 0) { | |
538 | padapter->mlmepriv.acm_mask = 0; | |
539 | return; | |
540 | } | |
541 | ||
542 | acm_mask = 0; | |
543 | ||
544 | if (pmlmeext->cur_wireless_mode == WIRELESS_11B) | |
545 | aSifsTime = 10; | |
546 | else | |
547 | aSifsTime = 16; | |
548 | ||
549 | for (i = 0; i < 4; i++) { | |
550 | ACI = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 5) & 0x03; | |
551 | ACM = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 4) & 0x01; | |
552 | ||
553 | /* AIFS = AIFSN * slot time + SIFS - r2t phy delay */ | |
c227ed0a JS |
554 | AIFS = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN & 0x0f) * |
555 | pmlmeinfo->slotTime + aSifsTime; | |
5e93f352 | 556 | |
c227ed0a | 557 | ECWMin = pmlmeinfo->WMM_param.ac_param[i].CW & 0x0f; |
5e93f352 LF |
558 | ECWMax = (pmlmeinfo->WMM_param.ac_param[i].CW & 0xf0) >> 4; |
559 | TXOP = le16_to_cpu(pmlmeinfo->WMM_param.ac_param[i].TXOP_limit); | |
560 | ||
561 | acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); | |
562 | ||
563 | switch (ACI) { | |
564 | case 0x0: | |
2487205e | 565 | rtl8723a_set_ac_param_be(padapter, acParm); |
5e93f352 LF |
566 | acm_mask |= (ACM? BIT(1):0); |
567 | edca[XMIT_BE_QUEUE] = acParm; | |
568 | break; | |
569 | case 0x1: | |
2487205e | 570 | rtl8723a_set_ac_param_bk(padapter, acParm); |
5e93f352 LF |
571 | /* acm_mask |= (ACM? BIT(0):0); */ |
572 | edca[XMIT_BK_QUEUE] = acParm; | |
573 | break; | |
574 | case 0x2: | |
2487205e | 575 | rtl8723a_set_ac_param_vi(padapter, acParm); |
5e93f352 LF |
576 | acm_mask |= (ACM? BIT(2):0); |
577 | edca[XMIT_VI_QUEUE] = acParm; | |
578 | break; | |
579 | case 0x3: | |
2487205e | 580 | rtl8723a_set_ac_param_vo(padapter, acParm); |
5e93f352 LF |
581 | acm_mask |= (ACM? BIT(3):0); |
582 | edca[XMIT_VO_QUEUE] = acParm; | |
583 | break; | |
584 | } | |
585 | ||
586 | DBG_8723A("WMM(%x): %x, %x\n", ACI, ACM, acParm); | |
587 | } | |
588 | ||
589 | if (padapter->registrypriv.acm_method == 1) | |
d5cdb9e1 | 590 | rtl8723a_set_acm_ctrl(padapter, acm_mask); |
5e93f352 LF |
591 | else |
592 | padapter->mlmepriv.acm_mask = acm_mask; | |
593 | ||
594 | inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; | |
595 | ||
596 | if (pregpriv->wifi_spec == 1) { | |
c227ed0a | 597 | u32 j, tmp, change_inx = false; |
5e93f352 LF |
598 | |
599 | /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */ | |
600 | for (i = 0; i < 4; i++) { | |
601 | for (j = i+1; j < 4; j++) { | |
602 | /* compare CW and AIFS */ | |
603 | if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) { | |
604 | change_inx = true; | |
c227ed0a JS |
605 | } else if ((edca[j] & 0xFFFF) == |
606 | (edca[i] & 0xFFFF)) { | |
5e93f352 LF |
607 | /* compare TXOP */ |
608 | if ((edca[j] >> 16) > (edca[i] >> 16)) | |
609 | change_inx = true; | |
610 | } | |
611 | ||
612 | if (change_inx) { | |
613 | tmp = edca[i]; | |
614 | edca[i] = edca[j]; | |
615 | edca[j] = tmp; | |
616 | ||
617 | tmp = inx[i]; | |
618 | inx[i] = inx[j]; | |
619 | inx[j] = tmp; | |
620 | ||
621 | change_inx = false; | |
622 | } | |
623 | } | |
624 | } | |
625 | } | |
626 | ||
627 | for (i = 0; i<4; i++) { | |
628 | pxmitpriv->wmm_para_seq[i] = inx[i]; | |
c227ed0a JS |
629 | DBG_8723A("wmm_para_seq(%d): %d\n", i, |
630 | pxmitpriv->wmm_para_seq[i]); | |
5e93f352 LF |
631 | } |
632 | ||
633 | return; | |
634 | } | |
635 | ||
7882ef45 | 636 | static void bwmode_update_check(struct rtw_adapter *padapter, const u8 *p) |
5e93f352 | 637 | { |
4dc5f8ba | 638 | struct ieee80211_ht_operation *pHT_info; |
5e93f352 | 639 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
c227ed0a | 640 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
641 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
642 | struct registry_priv *pregistrypriv = &padapter->registrypriv; | |
c227ed0a JS |
643 | struct ht_priv *phtpriv = &pmlmepriv->htpriv; |
644 | unsigned char new_bwmode; | |
645 | unsigned char new_ch_offset; | |
5e93f352 | 646 | |
b171da3c | 647 | if (!p) |
5e93f352 LF |
648 | return; |
649 | if (!phtpriv->ht_option) | |
650 | return; | |
4dc5f8ba | 651 | if (p[1] != sizeof(struct ieee80211_ht_operation)) |
5e93f352 LF |
652 | return; |
653 | ||
4dc5f8ba | 654 | pHT_info = (struct ieee80211_ht_operation *)(p + 2); |
5e93f352 | 655 | |
4dc5f8ba JS |
656 | if ((pHT_info->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY) && |
657 | pregistrypriv->cbw40_enable) { | |
5e93f352 LF |
658 | new_bwmode = HT_CHANNEL_WIDTH_40; |
659 | ||
4dc5f8ba JS |
660 | switch (pHT_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET){ |
661 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | |
5e93f352 LF |
662 | new_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; |
663 | break; | |
4dc5f8ba | 664 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: |
5e93f352 LF |
665 | new_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; |
666 | break; | |
667 | default: | |
668 | new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; | |
669 | break; | |
670 | } | |
671 | } else { | |
672 | new_bwmode = HT_CHANNEL_WIDTH_20; | |
673 | new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; | |
674 | } | |
675 | ||
c227ed0a JS |
676 | if (new_bwmode != pmlmeext->cur_bwmode || |
677 | new_ch_offset != pmlmeext->cur_ch_offset) { | |
5e93f352 LF |
678 | pmlmeinfo->bwmode_updated = true; |
679 | ||
680 | pmlmeext->cur_bwmode = new_bwmode; | |
681 | pmlmeext->cur_ch_offset = new_ch_offset; | |
682 | ||
683 | /* update HT info also */ | |
b171da3c | 684 | HT_info_handler23a(padapter, p); |
c227ed0a | 685 | } else |
5e93f352 | 686 | pmlmeinfo->bwmode_updated = false; |
5e93f352 LF |
687 | |
688 | if (pmlmeinfo->bwmode_updated) { | |
689 | struct sta_info *psta; | |
690 | struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; | |
691 | struct sta_priv *pstapriv = &padapter->stapriv; | |
692 | ||
c227ed0a JS |
693 | /* set_channel_bwmode23a(padapter, pmlmeext->cur_channel, |
694 | pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ | |
5e93f352 LF |
695 | |
696 | /* update ap's stainfo */ | |
697 | psta = rtw_get_stainfo23a(pstapriv, cur_network->MacAddress); | |
698 | if (psta) { | |
c227ed0a | 699 | struct ht_priv *phtpriv_sta = &psta->htpriv; |
5e93f352 LF |
700 | |
701 | if (phtpriv_sta->ht_option) { | |
702 | /* bwmode */ | |
703 | phtpriv_sta->bwmode = pmlmeext->cur_bwmode; | |
c227ed0a JS |
704 | phtpriv_sta->ch_offset = |
705 | pmlmeext->cur_ch_offset; | |
5e93f352 LF |
706 | } else { |
707 | phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20; | |
c227ed0a JS |
708 | phtpriv_sta->ch_offset = |
709 | HAL_PRIME_CHNL_OFFSET_DONT_CARE; | |
5e93f352 | 710 | } |
5e93f352 LF |
711 | } |
712 | } | |
713 | } | |
714 | ||
3cdf2773 | 715 | void HT_caps_handler23a(struct rtw_adapter *padapter, const u8 *p) |
5e93f352 | 716 | { |
c227ed0a JS |
717 | unsigned int i; |
718 | u8 rf_type; | |
719 | u8 max_AMPDU_len, min_MPDU_spacing; | |
720 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | |
5e93f352 | 721 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
c227ed0a JS |
722 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
723 | struct ht_priv *phtpriv = &pmlmepriv->htpriv; | |
65be27da JS |
724 | struct ieee80211_ht_cap *cap; |
725 | u8 *dstcap; | |
5e93f352 | 726 | |
b171da3c | 727 | if (!p) |
c227ed0a | 728 | return; |
5e93f352 | 729 | |
6a5f657d | 730 | if (!phtpriv->ht_option) |
c227ed0a | 731 | return; |
5e93f352 LF |
732 | |
733 | pmlmeinfo->HT_caps_enable = 1; | |
734 | ||
65be27da JS |
735 | cap = &pmlmeinfo->ht_cap; |
736 | dstcap = (u8 *)cap; | |
b171da3c | 737 | for (i = 0; i < p[1]; i++) { |
5e93f352 | 738 | if (i != 2) { |
65be27da | 739 | dstcap[i] &= p[i + 2]; |
5e93f352 LF |
740 | } else { |
741 | /* modify from fw by Thomas 2010/11/17 */ | |
65be27da JS |
742 | if ((cap->ampdu_params_info & |
743 | IEEE80211_HT_AMPDU_PARM_FACTOR) > | |
744 | (p[i + 2] & IEEE80211_HT_AMPDU_PARM_FACTOR)) | |
745 | max_AMPDU_len = p[i + 2] & | |
746 | IEEE80211_HT_AMPDU_PARM_FACTOR; | |
5e93f352 | 747 | else |
65be27da JS |
748 | max_AMPDU_len = cap->ampdu_params_info & |
749 | IEEE80211_HT_AMPDU_PARM_FACTOR; | |
750 | ||
751 | if ((cap->ampdu_params_info & | |
752 | IEEE80211_HT_AMPDU_PARM_DENSITY) > | |
753 | (p[i + 2] & IEEE80211_HT_AMPDU_PARM_DENSITY)) | |
754 | min_MPDU_spacing = cap->ampdu_params_info & | |
755 | IEEE80211_HT_AMPDU_PARM_DENSITY; | |
5e93f352 | 756 | else |
65be27da JS |
757 | min_MPDU_spacing = p[i + 2] & |
758 | IEEE80211_HT_AMPDU_PARM_DENSITY; | |
5e93f352 | 759 | |
65be27da | 760 | cap->ampdu_params_info = |
b171da3c | 761 | max_AMPDU_len | min_MPDU_spacing; |
5e93f352 LF |
762 | } |
763 | } | |
764 | ||
c2370e83 | 765 | rf_type = rtl8723a_get_rf_type(padapter); |
5e93f352 LF |
766 | |
767 | /* update the MCS rates */ | |
198e95d5 | 768 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) { |
c227ed0a | 769 | if (rf_type == RF_1T1R || rf_type == RF_1T2R) |
65be27da | 770 | cap->mcs.rx_mask[i] &= MCS_rate_1R23A[i]; |
5e93f352 | 771 | else |
65be27da | 772 | cap->mcs.rx_mask[i] &= MCS_rate_2R23A[i]; |
5e93f352 LF |
773 | } |
774 | return; | |
775 | } | |
776 | ||
7882ef45 | 777 | void HT_info_handler23a(struct rtw_adapter *padapter, const u8 *p) |
5e93f352 | 778 | { |
c227ed0a | 779 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 | 780 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
c227ed0a JS |
781 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
782 | struct ht_priv *phtpriv = &pmlmepriv->htpriv; | |
5e93f352 | 783 | |
b171da3c | 784 | if (!p) |
c227ed0a | 785 | return; |
5e93f352 | 786 | |
6a5f657d | 787 | if (!phtpriv->ht_option) |
c227ed0a | 788 | return; |
5e93f352 | 789 | |
4dc5f8ba | 790 | if (p[1] != sizeof(struct ieee80211_ht_operation)) |
5e93f352 LF |
791 | return; |
792 | ||
793 | pmlmeinfo->HT_info_enable = 1; | |
b171da3c | 794 | memcpy(&pmlmeinfo->HT_info, p + 2, p[1]); |
5e93f352 LF |
795 | return; |
796 | } | |
797 | ||
798 | void HTOnAssocRsp23a(struct rtw_adapter *padapter) | |
799 | { | |
c227ed0a JS |
800 | unsigned char max_AMPDU_len; |
801 | unsigned char min_MPDU_spacing; | |
5e93f352 | 802 | /* struct registry_priv *pregpriv = &padapter->registrypriv; */ |
c227ed0a | 803 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
804 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
805 | ||
806 | DBG_8723A("%s\n", __func__); | |
807 | ||
c227ed0a | 808 | if (pmlmeinfo->HT_info_enable && pmlmeinfo->HT_caps_enable) |
5e93f352 | 809 | pmlmeinfo->HT_enable = 1; |
c227ed0a | 810 | else { |
5e93f352 | 811 | pmlmeinfo->HT_enable = 0; |
c227ed0a JS |
812 | /* set_channel_bwmode23a(padapter, pmlmeext->cur_channel, |
813 | pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ | |
5e93f352 LF |
814 | return; |
815 | } | |
816 | ||
817 | /* handle A-MPDU parameter field */ | |
818 | /* | |
819 | AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k | |
820 | AMPDU_para [4:2]:Min MPDU Start Spacing | |
821 | */ | |
65be27da JS |
822 | max_AMPDU_len = pmlmeinfo->ht_cap.ampdu_params_info & |
823 | IEEE80211_HT_AMPDU_PARM_FACTOR; | |
5e93f352 | 824 | |
c227ed0a | 825 | min_MPDU_spacing = |
65be27da JS |
826 | (pmlmeinfo->ht_cap.ampdu_params_info & |
827 | IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; | |
5e93f352 | 828 | |
dce610a7 JS |
829 | rtl8723a_set_ampdu_min_space(padapter, min_MPDU_spacing); |
830 | rtl8723a_set_ampdu_factor(padapter, max_AMPDU_len); | |
5e93f352 LF |
831 | } |
832 | ||
7882ef45 | 833 | void ERP_IE_handler23a(struct rtw_adapter *padapter, const u8 *p) |
5e93f352 | 834 | { |
c227ed0a | 835 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
836 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
837 | ||
b171da3c | 838 | if (p[1] > 1) |
5e93f352 LF |
839 | return; |
840 | ||
841 | pmlmeinfo->ERP_enable = 1; | |
b171da3c | 842 | memcpy(&pmlmeinfo->ERP_IE, p + 2, p[1]); |
5e93f352 LF |
843 | } |
844 | ||
845 | void VCS_update23a(struct rtw_adapter *padapter, struct sta_info *psta) | |
846 | { | |
c227ed0a JS |
847 | struct registry_priv *pregpriv = &padapter->registrypriv; |
848 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | |
5e93f352 LF |
849 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
850 | ||
851 | switch (pregpriv->vrtl_carrier_sense) { /* 0:off 1:on 2:auto */ | |
852 | case 0: /* off */ | |
853 | psta->rtsen = 0; | |
854 | psta->cts2self = 0; | |
855 | break; | |
856 | case 1: /* on */ | |
857 | if (pregpriv->vcs_type == 1) { /* 1:RTS/CTS 2:CTS to self */ | |
858 | psta->rtsen = 1; | |
859 | psta->cts2self = 0; | |
860 | } else { | |
861 | psta->rtsen = 0; | |
862 | psta->cts2self = 1; | |
863 | } | |
864 | break; | |
865 | case 2: /* auto */ | |
866 | default: | |
c227ed0a | 867 | if (pmlmeinfo->ERP_enable && pmlmeinfo->ERP_IE & BIT(1)) { |
5e93f352 LF |
868 | if (pregpriv->vcs_type == 1) { |
869 | psta->rtsen = 1; | |
870 | psta->cts2self = 0; | |
871 | } else { | |
872 | psta->rtsen = 0; | |
873 | psta->cts2self = 1; | |
874 | } | |
875 | } else { | |
876 | psta->rtsen = 0; | |
877 | psta->cts2self = 0; | |
878 | } | |
879 | break; | |
880 | } | |
881 | } | |
882 | ||
c146551f | 883 | int rtw_check_bcn_info23a(struct rtw_adapter *Adapter, |
3ffa4355 | 884 | struct ieee80211_mgmt *mgmt, u32 pkt_len) |
5e93f352 | 885 | { |
5e93f352 | 886 | struct wlan_network *cur_network = &Adapter->mlmepriv.cur_network; |
4dc5f8ba | 887 | struct ieee80211_ht_operation *pht_info; |
5e93f352 | 888 | struct wlan_bssid_ex *bssid; |
c3761836 | 889 | unsigned short val16; |
c3761836 JS |
890 | u8 encryp_protocol; |
891 | int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0, r; | |
5e93f352 | 892 | u32 bcn_channel; |
3ffa4355 JS |
893 | int len, pie_len, ie_offset; |
894 | const u8 *p; | |
895 | u8 *pie; | |
5e93f352 LF |
896 | |
897 | if (is_client_associated_to_ap23a(Adapter) == false) | |
898 | return true; | |
899 | ||
c146551f JS |
900 | if (unlikely(!ieee80211_is_beacon(mgmt->frame_control))) { |
901 | printk(KERN_WARNING "%s: received a non beacon frame!\n", | |
902 | __func__); | |
903 | return false; | |
904 | } | |
905 | ||
3ffa4355 | 906 | len = pkt_len - sizeof(struct ieee80211_hdr_3addr); |
5e93f352 LF |
907 | |
908 | if (len > MAX_IE_SZ) { | |
909 | DBG_8723A("%s IE too long for survey event\n", __func__); | |
910 | return _FAIL; | |
911 | } | |
912 | ||
c146551f JS |
913 | if (memcmp(cur_network->network.MacAddress, mgmt->bssid, 6)) { |
914 | DBG_8723A("Oops: rtw_check_network_encrypt linked but recv " | |
915 | "other bssid bcn\n" MAC_FMT MAC_FMT, | |
916 | MAC_ARG(mgmt->bssid), | |
917 | MAC_ARG(cur_network->network.MacAddress)); | |
5e93f352 LF |
918 | return true; |
919 | } | |
920 | ||
e1a35432 | 921 | bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC); |
5bd28bc2 JS |
922 | if (!bssid) |
923 | return _FAIL; | |
5e93f352 | 924 | |
c146551f | 925 | bssid->reserved = 1; |
5e93f352 | 926 | |
5bd28bc2 | 927 | bssid->Length = offsetof(struct wlan_bssid_ex, IEs) + len; |
5e93f352 LF |
928 | |
929 | /* below is to copy the information element */ | |
930 | bssid->IELength = len; | |
5bd28bc2 | 931 | memcpy(bssid->IEs, &mgmt->u, len); |
5e93f352 LF |
932 | |
933 | /* check bw and channel offset */ | |
934 | /* parsing HT_CAP_IE */ | |
3ffa4355 JS |
935 | ie_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable) - |
936 | offsetof(struct ieee80211_mgmt, u); | |
937 | pie = bssid->IEs + ie_offset; | |
938 | pie_len = pkt_len - ie_offset; | |
939 | ||
5e93f352 | 940 | /* Checking for channel */ |
3ffa4355 JS |
941 | p = cfg80211_find_ie(WLAN_EID_DS_PARAMS, pie, pie_len); |
942 | if (p) | |
943 | bcn_channel = p[2]; | |
944 | else { | |
945 | /* In 5G, some ap do not have DSSET IE checking HT | |
946 | info for channel */ | |
947 | p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, pie, pie_len); | |
948 | ||
ed08b4de JS |
949 | if (p && p[1] > 0) { |
950 | pht_info = (struct ieee80211_ht_operation *)(p + 2); | |
4dc5f8ba | 951 | bcn_channel = pht_info->primary_chan; |
ed08b4de | 952 | } else { /* we don't find channel IE, so don't check it */ |
3ffa4355 JS |
953 | DBG_8723A("Oops: %s we don't find channel IE, so don't " |
954 | "check it\n", __func__); | |
955 | bcn_channel = Adapter->mlmeextpriv.cur_channel; | |
956 | } | |
5e93f352 LF |
957 | } |
958 | if (bcn_channel != Adapter->mlmeextpriv.cur_channel) { | |
3ffa4355 JS |
959 | DBG_8723A("%s beacon channel:%d cur channel:%d disconnect\n", |
960 | __func__, bcn_channel, | |
961 | Adapter->mlmeextpriv.cur_channel); | |
962 | goto _mismatch; | |
5e93f352 LF |
963 | } |
964 | ||
965 | /* checking SSID */ | |
3ffa4355 | 966 | p = cfg80211_find_ie(WLAN_EID_SSID, pie, pie_len); |
82695d5c JS |
967 | if (p && p[1]) { |
968 | memcpy(bssid->Ssid.ssid, p + 2, p[1]); | |
969 | bssid->Ssid.ssid_len = p[1]; | |
970 | } else { | |
3ffa4355 JS |
971 | DBG_8723A("%s marc: cannot find SSID for survey event\n", |
972 | __func__); | |
5e93f352 LF |
973 | bssid->Ssid.ssid_len = 0; |
974 | bssid->Ssid.ssid[0] = '\0'; | |
975 | } | |
976 | ||
977 | RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, | |
978 | ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d " | |
979 | "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, | |
980 | bssid->Ssid.ssid, bssid->Ssid.ssid_len, | |
981 | cur_network->network.Ssid.ssid, | |
982 | cur_network->network.Ssid.ssid_len)); | |
983 | ||
984 | if (memcmp(bssid->Ssid.ssid, cur_network->network.Ssid.ssid, 32) || | |
985 | bssid->Ssid.ssid_len != cur_network->network.Ssid.ssid_len) { | |
986 | if (bssid->Ssid.ssid[0] != '\0' && | |
987 | bssid->Ssid.ssid_len != 0) { /* not hidden ssid */ | |
988 | DBG_8723A("%s(), SSID is not match return FAIL\n", | |
989 | __func__); | |
990 | goto _mismatch; | |
991 | } | |
992 | } | |
993 | ||
994 | /* check encryption info */ | |
52017955 | 995 | val16 = rtw_get_capability23a(bssid); |
5e93f352 | 996 | |
a665bcc2 | 997 | if (val16 & WLAN_CAPABILITY_PRIVACY) |
5e93f352 LF |
998 | bssid->Privacy = 1; |
999 | else | |
1000 | bssid->Privacy = 0; | |
1001 | ||
1002 | RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, | |
c3761836 JS |
1003 | ("%s(): cur_network->network.Privacy is %d, bssid.Privacy " |
1004 | "is %d\n", __func__, cur_network->network.Privacy, | |
1005 | bssid->Privacy)); | |
5e93f352 LF |
1006 | if (cur_network->network.Privacy != bssid->Privacy) { |
1007 | DBG_8723A("%s(), privacy is not match return FAIL\n", __func__); | |
1008 | goto _mismatch; | |
1009 | } | |
1010 | ||
77953edf JS |
1011 | p = cfg80211_find_ie(WLAN_EID_RSN, pie, pie_len); |
1012 | if (p && p[1]) { | |
5e93f352 | 1013 | encryp_protocol = ENCRYP_PROTOCOL_WPA2; |
77953edf JS |
1014 | } else if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, |
1015 | WLAN_OUI_TYPE_MICROSOFT_WPA, | |
1016 | pie, pie_len)) { | |
5e93f352 | 1017 | encryp_protocol = ENCRYP_PROTOCOL_WPA; |
77953edf | 1018 | } else { |
5e93f352 LF |
1019 | if (bssid->Privacy) |
1020 | encryp_protocol = ENCRYP_PROTOCOL_WEP; | |
c3761836 JS |
1021 | else |
1022 | encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; | |
5e93f352 LF |
1023 | } |
1024 | ||
1025 | if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { | |
c3761836 | 1026 | DBG_8723A("%s(): enctyp is not match, return FAIL\n", __func__); |
5e93f352 LF |
1027 | goto _mismatch; |
1028 | } | |
1029 | ||
c3761836 JS |
1030 | if (encryp_protocol == ENCRYP_PROTOCOL_WPA || |
1031 | encryp_protocol == ENCRYP_PROTOCOL_WPA2) { | |
f88ca604 JS |
1032 | p = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, |
1033 | WLAN_OUI_TYPE_MICROSOFT_WPA, | |
1034 | pie, pie_len); | |
1035 | if (p && p[1] > 0) { | |
1036 | r = rtw_parse_wpa_ie23a(p, p[1] + 2, &group_cipher, | |
c3761836 JS |
1037 | &pairwise_cipher, &is_8021x); |
1038 | if (r == _SUCCESS) | |
5e93f352 | 1039 | RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, |
c3761836 JS |
1040 | ("%s pnetwork->pairwise_cipher: %d, " |
1041 | "group_cipher is %d, is_8021x is " | |
1042 | "%d\n", __func__, pairwise_cipher, | |
1043 | group_cipher, is_8021x)); | |
5e93f352 | 1044 | } else { |
f88ca604 | 1045 | p = cfg80211_find_ie(WLAN_EID_RSN, pie, pie_len); |
5e93f352 | 1046 | |
f88ca604 JS |
1047 | if (p && p[1] > 0) { |
1048 | r = rtw_parse_wpa2_ie23a(p, p[1] + 2, | |
c3761836 JS |
1049 | &group_cipher, |
1050 | &pairwise_cipher, | |
1051 | &is_8021x); | |
1052 | if (r == _SUCCESS) | |
1053 | RT_TRACE(_module_rtl871x_mlme_c_, | |
1054 | _drv_info_, | |
1055 | ("%s pnetwork->pairwise_cipher" | |
1056 | ": %d, pnetwork->group_cipher" | |
1057 | " is %d, is_802x is %d\n", | |
1058 | __func__, pairwise_cipher, | |
1059 | group_cipher, is_8021x)); | |
5e93f352 LF |
1060 | } |
1061 | } | |
1062 | ||
1063 | RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, | |
c3761836 JS |
1064 | ("%s cur_network->group_cipher is %d: %d\n", __func__, |
1065 | cur_network->BcnInfo.group_cipher, group_cipher)); | |
1066 | if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || | |
1067 | group_cipher != cur_network->BcnInfo.group_cipher) { | |
1068 | DBG_8723A("%s pairwise_cipher(%x:%x) or group_cipher " | |
1069 | "(%x:%x) is not match, return FAIL\n", | |
1070 | __func__, pairwise_cipher, | |
1071 | cur_network->BcnInfo.pairwise_cipher, | |
1072 | group_cipher, | |
1073 | cur_network->BcnInfo.group_cipher); | |
5e93f352 LF |
1074 | goto _mismatch; |
1075 | } | |
1076 | ||
1077 | if (is_8021x != cur_network->BcnInfo.is_8021x) { | |
c3761836 JS |
1078 | DBG_8723A("%s authentication is not match, return " |
1079 | "FAIL\n", __func__); | |
5e93f352 LF |
1080 | goto _mismatch; |
1081 | } | |
1082 | } | |
1083 | ||
1084 | kfree(bssid); | |
1085 | return _SUCCESS; | |
1086 | ||
1087 | _mismatch: | |
1088 | kfree(bssid); | |
1089 | ||
1090 | return _FAIL; | |
1091 | } | |
1092 | ||
7882ef45 JS |
1093 | void update_beacon23a_info(struct rtw_adapter *padapter, |
1094 | struct ieee80211_mgmt *mgmt, | |
b171da3c | 1095 | uint pkt_len, struct sta_info *psta) |
5e93f352 | 1096 | { |
5e93f352 | 1097 | unsigned int len; |
7882ef45 | 1098 | const u8 *p; |
5e93f352 | 1099 | |
7882ef45 | 1100 | len = pkt_len - offsetof(struct ieee80211_mgmt, u.beacon.variable); |
5e93f352 | 1101 | |
7882ef45 JS |
1102 | p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, mgmt->u.beacon.variable, |
1103 | len); | |
1104 | if (p) | |
1105 | bwmode_update_check(padapter, p); | |
5e93f352 | 1106 | |
7882ef45 JS |
1107 | p = cfg80211_find_ie(WLAN_EID_ERP_INFO, mgmt->u.beacon.variable, len); |
1108 | if (p) { | |
1109 | ERP_IE_handler23a(padapter, p); | |
1110 | VCS_update23a(padapter, psta); | |
5e93f352 LF |
1111 | } |
1112 | } | |
1113 | ||
d5789247 | 1114 | bool is_ap_in_tkip23a(struct rtw_adapter *padapter) |
5e93f352 LF |
1115 | { |
1116 | u32 i; | |
5e93f352 LF |
1117 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1118 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; | |
1119 | struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; | |
b171da3c | 1120 | const u8 *p; |
c164bcff JS |
1121 | int bcn_fixed_size; |
1122 | ||
1123 | bcn_fixed_size = offsetof(struct ieee80211_mgmt, u.beacon.variable) - | |
1124 | offsetof(struct ieee80211_mgmt, u.beacon); | |
5e93f352 | 1125 | |
52017955 | 1126 | if (rtw_get_capability23a(cur_network) & WLAN_CAPABILITY_PRIVACY) { |
c164bcff | 1127 | for (i = bcn_fixed_size; i < pmlmeinfo->network.IELength;) { |
b171da3c | 1128 | p = pmlmeinfo->network.IEs + i; |
5e93f352 | 1129 | |
b171da3c | 1130 | switch (p[0]) { |
9300c94b | 1131 | case WLAN_EID_VENDOR_SPECIFIC: |
b171da3c JS |
1132 | if (!memcmp(p + 2, RTW_WPA_OUI23A_TYPE, 4) && |
1133 | !memcmp(p + 2 + 12, WPA_TKIP_CIPHER, 4)) | |
5e93f352 LF |
1134 | return true; |
1135 | break; | |
25c934fa | 1136 | case WLAN_EID_RSN: |
b171da3c | 1137 | if (!memcmp(p + 2 + 8, RSN_TKIP_CIPHER, 4)) |
5e93f352 LF |
1138 | return true; |
1139 | break; | |
1140 | default: | |
1141 | break; | |
1142 | } | |
b171da3c | 1143 | i += (p[1] + 2); |
5e93f352 LF |
1144 | } |
1145 | return false; | |
c227ed0a | 1146 | } else |
5e93f352 | 1147 | return false; |
5e93f352 LF |
1148 | } |
1149 | ||
d5789247 | 1150 | bool should_forbid_n_rate23a(struct rtw_adapter * padapter) |
5e93f352 LF |
1151 | { |
1152 | u32 i; | |
c227ed0a | 1153 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
5e93f352 | 1154 | struct wlan_bssid_ex *cur_network = &pmlmepriv->cur_network.network; |
b171da3c | 1155 | const u8 *p; |
c164bcff JS |
1156 | int bcn_fixed_size; |
1157 | ||
1158 | bcn_fixed_size = offsetof(struct ieee80211_mgmt, u.beacon.variable) - | |
1159 | offsetof(struct ieee80211_mgmt, u.beacon); | |
5e93f352 | 1160 | |
52017955 | 1161 | if (rtw_get_capability23a(cur_network) & WLAN_CAPABILITY_PRIVACY) { |
c164bcff | 1162 | for (i = bcn_fixed_size; i < cur_network->IELength;) { |
b171da3c | 1163 | p = cur_network->IEs + i; |
5e93f352 | 1164 | |
b171da3c | 1165 | switch (p[0]) { |
9300c94b | 1166 | case WLAN_EID_VENDOR_SPECIFIC: |
b171da3c JS |
1167 | if (!memcmp(p + 2, RTW_WPA_OUI23A_TYPE, 4) && |
1168 | (!memcmp(p + 2 + 12, | |
c227ed0a | 1169 | WPA_CIPHER_SUITE_CCMP23A, 4) || |
b171da3c | 1170 | !memcmp(p + 2 + 16, |
c227ed0a | 1171 | WPA_CIPHER_SUITE_CCMP23A, 4))) |
5e93f352 LF |
1172 | return false; |
1173 | break; | |
25c934fa | 1174 | case WLAN_EID_RSN: |
b171da3c | 1175 | if (!memcmp(p + 2 + 8, |
c227ed0a | 1176 | RSN_CIPHER_SUITE_CCMP23A, 4) || |
b171da3c | 1177 | !memcmp(p + 2 + 12, |
c227ed0a | 1178 | RSN_CIPHER_SUITE_CCMP23A, 4)) |
5e93f352 LF |
1179 | return false; |
1180 | default: | |
1181 | break; | |
1182 | } | |
1183 | ||
b171da3c | 1184 | i += (p[1] + 2); |
5e93f352 LF |
1185 | } |
1186 | return true; | |
1187 | } else { | |
1188 | return false; | |
1189 | } | |
1190 | } | |
1191 | ||
d5789247 | 1192 | bool is_ap_in_wep23a(struct rtw_adapter *padapter) |
5e93f352 LF |
1193 | { |
1194 | u32 i; | |
5e93f352 LF |
1195 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1196 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; | |
1197 | struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; | |
b171da3c | 1198 | const u8 *p; |
c164bcff JS |
1199 | int bcn_fixed_size; |
1200 | ||
1201 | bcn_fixed_size = offsetof(struct ieee80211_mgmt, u.beacon.variable) - | |
1202 | offsetof(struct ieee80211_mgmt, u.beacon); | |
5e93f352 | 1203 | |
52017955 | 1204 | if (rtw_get_capability23a(cur_network) & WLAN_CAPABILITY_PRIVACY) { |
c164bcff | 1205 | for (i = bcn_fixed_size; i < pmlmeinfo->network.IELength;) { |
b171da3c | 1206 | p = pmlmeinfo->network.IEs + i; |
5e93f352 | 1207 | |
b171da3c | 1208 | switch (p[0]) { |
9300c94b | 1209 | case WLAN_EID_VENDOR_SPECIFIC: |
b171da3c | 1210 | if (!memcmp(p + 2, RTW_WPA_OUI23A_TYPE, 4)) |
5e93f352 LF |
1211 | return false; |
1212 | break; | |
25c934fa | 1213 | case WLAN_EID_RSN: |
5e93f352 LF |
1214 | return false; |
1215 | ||
1216 | default: | |
1217 | break; | |
1218 | } | |
1219 | ||
b171da3c | 1220 | i += (p[1] + 2); |
5e93f352 LF |
1221 | } |
1222 | ||
1223 | return true; | |
c227ed0a | 1224 | } else |
5e93f352 | 1225 | return false; |
5e93f352 LF |
1226 | } |
1227 | ||
c0b99bed | 1228 | static int wifirate2_ratetbl_inx23a(unsigned char rate) |
5e93f352 | 1229 | { |
c227ed0a | 1230 | int inx = 0; |
5e93f352 LF |
1231 | rate = rate & 0x7f; |
1232 | ||
1233 | switch (rate) { | |
1234 | case 54*2: | |
1235 | inx = 11; | |
1236 | break; | |
1237 | case 48*2: | |
1238 | inx = 10; | |
1239 | break; | |
1240 | case 36*2: | |
1241 | inx = 9; | |
1242 | break; | |
1243 | case 24*2: | |
1244 | inx = 8; | |
1245 | break; | |
1246 | case 18*2: | |
1247 | inx = 7; | |
1248 | break; | |
1249 | case 12*2: | |
1250 | inx = 6; | |
1251 | break; | |
1252 | case 9*2: | |
1253 | inx = 5; | |
1254 | break; | |
1255 | case 6*2: | |
1256 | inx = 4; | |
1257 | break; | |
1258 | case 11*2: | |
1259 | inx = 3; | |
1260 | break; | |
1261 | case 11: | |
1262 | inx = 2; | |
1263 | break; | |
1264 | case 2*2: | |
1265 | inx = 1; | |
1266 | break; | |
1267 | case 1*2: | |
1268 | inx = 0; | |
1269 | break; | |
1270 | } | |
1271 | return inx; | |
1272 | } | |
1273 | ||
1274 | unsigned int update_basic_rate23a(unsigned char *ptn, unsigned int ptn_sz) | |
1275 | { | |
1276 | unsigned int i, num_of_rate; | |
1277 | unsigned int mask = 0; | |
1278 | ||
1279 | num_of_rate = (ptn_sz > NumRates)? NumRates: ptn_sz; | |
1280 | ||
1281 | for (i = 0; i < num_of_rate; i++) { | |
1282 | if ((*(ptn + i)) & 0x80) | |
1283 | mask |= 0x1 << wifirate2_ratetbl_inx23a(*(ptn + i)); | |
1284 | } | |
1285 | return mask; | |
1286 | } | |
1287 | ||
1288 | unsigned int update_supported_rate23a(unsigned char *ptn, unsigned int ptn_sz) | |
1289 | { | |
1290 | unsigned int i, num_of_rate; | |
1291 | unsigned int mask = 0; | |
1292 | ||
c227ed0a | 1293 | num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz; |
5e93f352 LF |
1294 | |
1295 | for (i = 0; i < num_of_rate; i++) | |
1296 | mask |= 0x1 << wifirate2_ratetbl_inx23a(*(ptn + i)); | |
1297 | return mask; | |
1298 | } | |
1299 | ||
65be27da | 1300 | unsigned int update_MSC_rate23a(struct ieee80211_ht_cap *pHT_caps) |
5e93f352 LF |
1301 | { |
1302 | unsigned int mask = 0; | |
1303 | ||
65be27da JS |
1304 | mask = pHT_caps->mcs.rx_mask[0] << 12 | |
1305 | pHT_caps->mcs.rx_mask[1] << 20; | |
5e93f352 LF |
1306 | |
1307 | return mask; | |
1308 | } | |
1309 | ||
1310 | int support_short_GI23a(struct rtw_adapter *padapter, | |
65be27da | 1311 | struct ieee80211_ht_cap *pHT_caps) |
5e93f352 | 1312 | { |
c227ed0a | 1313 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
1314 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
1315 | unsigned char bit_offset; | |
1316 | ||
c227ed0a | 1317 | if (!pmlmeinfo->HT_enable) |
5e93f352 | 1318 | return _FAIL; |
c227ed0a | 1319 | if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK) |
5e93f352 LF |
1320 | return _FAIL; |
1321 | bit_offset = (pmlmeext->cur_bwmode & HT_CHANNEL_WIDTH_40)? 6: 5; | |
1322 | ||
65be27da | 1323 | if (pHT_caps->cap_info & cpu_to_le16(0x1 << bit_offset)) |
5e93f352 LF |
1324 | return _SUCCESS; |
1325 | else | |
1326 | return _FAIL; | |
1327 | } | |
1328 | ||
1329 | unsigned char get_highest_rate_idx23a(u32 mask) | |
1330 | { | |
1331 | int i; | |
1332 | unsigned char rate_idx = 0; | |
1333 | ||
1334 | for (i = 27; i >= 0; i--) { | |
1335 | if (mask & BIT(i)) { | |
1336 | rate_idx = i; | |
1337 | break; | |
1338 | } | |
1339 | } | |
1340 | return rate_idx; | |
1341 | } | |
1342 | ||
5e93f352 LF |
1343 | void Update_RA_Entry23a(struct rtw_adapter *padapter, struct sta_info *psta) |
1344 | { | |
1345 | rtw_hal_update_ra_mask23a(psta, 0); | |
1346 | } | |
1347 | ||
c0b99bed LF |
1348 | static void enable_rate_adaptive(struct rtw_adapter *padapter, |
1349 | struct sta_info *psta) | |
5e93f352 LF |
1350 | { |
1351 | Update_RA_Entry23a(padapter, psta); | |
1352 | } | |
1353 | ||
1354 | void set_sta_rate23a(struct rtw_adapter *padapter, struct sta_info *psta) | |
1355 | { | |
1356 | /* rate adaptive */ | |
1357 | enable_rate_adaptive(padapter, psta); | |
1358 | } | |
1359 | ||
1360 | /* Update RRSR and Rate for USERATE */ | |
1361 | void update_tx_basic_rate23a(struct rtw_adapter *padapter, u8 wirelessmode) | |
1362 | { | |
1363 | unsigned char supported_rates[NDIS_802_11_LENGTH_RATES_EX]; | |
5e93f352 LF |
1364 | |
1365 | memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX); | |
1366 | ||
ff516e70 | 1367 | if (wirelessmode == WIRELESS_11B) { |
5e93f352 LF |
1368 | memcpy(supported_rates, rtw_basic_rate_cck, 4); |
1369 | } else if (wirelessmode & WIRELESS_11B) { | |
1370 | memcpy(supported_rates, rtw_basic_rate_mix, 7); | |
1371 | } else { | |
1372 | memcpy(supported_rates, rtw_basic_rate_ofdm, 3); | |
1373 | } | |
1374 | ||
1375 | if (wirelessmode & WIRELESS_11B) | |
1376 | update_mgnt_tx_rate23a(padapter, IEEE80211_CCK_RATE_1MB); | |
1377 | else | |
1378 | update_mgnt_tx_rate23a(padapter, IEEE80211_OFDM_RATE_6MB); | |
1379 | ||
fa2e5209 | 1380 | HalSetBrateCfg23a(padapter, supported_rates); |
5e93f352 LF |
1381 | } |
1382 | ||
1383 | unsigned char check_assoc_AP23a(u8 *pframe, uint len) | |
1384 | { | |
c164bcff | 1385 | int i, bcn_fixed_size; |
c227ed0a JS |
1386 | u8 epigram_vendor_flag; |
1387 | u8 ralink_vendor_flag; | |
b171da3c | 1388 | const u8 *p; |
5e93f352 LF |
1389 | epigram_vendor_flag = 0; |
1390 | ralink_vendor_flag = 0; | |
1391 | ||
c164bcff JS |
1392 | bcn_fixed_size = offsetof(struct ieee80211_mgmt, u.beacon.variable) - |
1393 | offsetof(struct ieee80211_mgmt, u.beacon); | |
1394 | ||
1395 | for (i = bcn_fixed_size; i < len;) { | |
b171da3c | 1396 | p = pframe + i; |
5e93f352 | 1397 | |
b171da3c | 1398 | switch (p[0]) { |
9300c94b | 1399 | case WLAN_EID_VENDOR_SPECIFIC: |
b171da3c JS |
1400 | if (!memcmp(p + 2, ARTHEROS_OUI1, 3) || |
1401 | !memcmp(p + 2, ARTHEROS_OUI2, 3)) { | |
5e93f352 LF |
1402 | DBG_8723A("link to Artheros AP\n"); |
1403 | return HT_IOT_PEER_ATHEROS; | |
b171da3c JS |
1404 | } else if (!memcmp(p + 2, BROADCOM_OUI1, 3) || |
1405 | !memcmp(p + 2, BROADCOM_OUI2, 3) || | |
1406 | !memcmp(p + 2, BROADCOM_OUI2, 3)) { | |
5e93f352 LF |
1407 | DBG_8723A("link to Broadcom AP\n"); |
1408 | return HT_IOT_PEER_BROADCOM; | |
b171da3c | 1409 | } else if (!memcmp(p + 2, MARVELL_OUI, 3)) { |
5e93f352 LF |
1410 | DBG_8723A("link to Marvell AP\n"); |
1411 | return HT_IOT_PEER_MARVELL; | |
b171da3c | 1412 | } else if (!memcmp(p + 2, RALINK_OUI, 3)) { |
c227ed0a | 1413 | if (!ralink_vendor_flag) |
5e93f352 | 1414 | ralink_vendor_flag = 1; |
c227ed0a | 1415 | else { |
5e93f352 LF |
1416 | DBG_8723A("link to Ralink AP\n"); |
1417 | return HT_IOT_PEER_RALINK; | |
1418 | } | |
b171da3c | 1419 | } else if (!memcmp(p + 2, CISCO_OUI, 3)) { |
5e93f352 LF |
1420 | DBG_8723A("link to Cisco AP\n"); |
1421 | return HT_IOT_PEER_CISCO; | |
b171da3c | 1422 | } else if (!memcmp(p + 2, REALTEK_OUI, 3)) { |
5e93f352 LF |
1423 | DBG_8723A("link to Realtek 96B\n"); |
1424 | return HT_IOT_PEER_REALTEK; | |
b171da3c | 1425 | } else if (!memcmp(p + 2, AIRGOCAP_OUI, 3)) { |
5e93f352 LF |
1426 | DBG_8723A("link to Airgo Cap\n"); |
1427 | return HT_IOT_PEER_AIRGO; | |
b171da3c | 1428 | } else if (!memcmp(p + 2, EPIGRAM_OUI, 3)) { |
5e93f352 LF |
1429 | epigram_vendor_flag = 1; |
1430 | if (ralink_vendor_flag) { | |
1431 | DBG_8723A("link to Tenda W311R AP\n"); | |
1432 | return HT_IOT_PEER_TENDA; | |
c227ed0a | 1433 | } else |
5e93f352 | 1434 | DBG_8723A("Capture EPIGRAM_OUI\n"); |
c227ed0a | 1435 | } else |
5e93f352 | 1436 | break; |
5e93f352 LF |
1437 | default: |
1438 | break; | |
1439 | } | |
1440 | ||
b171da3c | 1441 | i += (p[1] + 2); |
5e93f352 LF |
1442 | } |
1443 | ||
1444 | if (ralink_vendor_flag && !epigram_vendor_flag) { | |
1445 | DBG_8723A("link to Ralink AP\n"); | |
1446 | return HT_IOT_PEER_RALINK; | |
1447 | } else if (ralink_vendor_flag && epigram_vendor_flag) { | |
1448 | DBG_8723A("link to Tenda W311R AP\n"); | |
1449 | return HT_IOT_PEER_TENDA; | |
1450 | } else { | |
1451 | DBG_8723A("link to new AP\n"); | |
1452 | return HT_IOT_PEER_UNKNOWN; | |
1453 | } | |
1454 | } | |
1455 | ||
1456 | void update_IOT_info23a(struct rtw_adapter *padapter) | |
1457 | { | |
c227ed0a | 1458 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
1459 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
1460 | ||
1461 | switch (pmlmeinfo->assoc_AP_vendor) { | |
1462 | case HT_IOT_PEER_MARVELL: | |
1463 | pmlmeinfo->turboMode_cts2self = 1; | |
1464 | pmlmeinfo->turboMode_rtsen = 0; | |
1465 | break; | |
1466 | case HT_IOT_PEER_RALINK: | |
1467 | pmlmeinfo->turboMode_cts2self = 0; | |
1468 | pmlmeinfo->turboMode_rtsen = 1; | |
1469 | /* disable high power */ | |
585eefb4 JS |
1470 | rtl8723a_odm_support_ability_clr(padapter, (u32) |
1471 | ~DYNAMIC_BB_DYNAMIC_TXPWR); | |
5e93f352 LF |
1472 | break; |
1473 | case HT_IOT_PEER_REALTEK: | |
1474 | /* rtw_write16(padapter, 0x4cc, 0xffff); */ | |
1475 | /* rtw_write16(padapter, 0x546, 0x01c0); */ | |
1476 | /* disable high power */ | |
585eefb4 JS |
1477 | rtl8723a_odm_support_ability_clr(padapter, (u32) |
1478 | ~DYNAMIC_BB_DYNAMIC_TXPWR); | |
5e93f352 LF |
1479 | break; |
1480 | default: | |
1481 | pmlmeinfo->turboMode_cts2self = 0; | |
1482 | pmlmeinfo->turboMode_rtsen = 1; | |
1483 | break; | |
1484 | } | |
1485 | } | |
1486 | ||
1487 | void update_capinfo23a(struct rtw_adapter *Adapter, u16 updateCap) | |
1488 | { | |
c227ed0a | 1489 | struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; |
5e93f352 | 1490 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
5e93f352 LF |
1491 | |
1492 | if (updateCap & cShortPreamble) { | |
1493 | /* Short Preamble */ | |
1494 | if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) { | |
1495 | /* PREAMBLE_LONG or PREAMBLE_AUTO */ | |
5e93f352 | 1496 | pmlmeinfo->preamble_mode = PREAMBLE_SHORT; |
093dd41e | 1497 | rtl8723a_ack_preamble(Adapter, true); |
5e93f352 LF |
1498 | } |
1499 | } else { /* Long Preamble */ | |
1500 | if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) { | |
1501 | /* PREAMBLE_SHORT or PREAMBLE_AUTO */ | |
5e93f352 | 1502 | pmlmeinfo->preamble_mode = PREAMBLE_LONG; |
093dd41e | 1503 | rtl8723a_ack_preamble(Adapter, false); |
5e93f352 LF |
1504 | } |
1505 | } | |
1506 | if (updateCap & cIBSS) { | |
1507 | /* Filen: See 802.11-2007 p.91 */ | |
1508 | pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; | |
1509 | } else { | |
1510 | /* Filen: See 802.11-2007 p.90 */ | |
c227ed0a JS |
1511 | if (pmlmeext->cur_wireless_mode & |
1512 | (WIRELESS_11G | WIRELESS_11_24N)) { | |
5e93f352 LF |
1513 | if (updateCap & cShortSlotTime) { /* Short Slot Time */ |
1514 | if (pmlmeinfo->slotTime != SHORT_SLOT_TIME) | |
1515 | pmlmeinfo->slotTime = SHORT_SLOT_TIME; | |
1516 | } else { /* Long Slot Time */ | |
1517 | if (pmlmeinfo->slotTime != NON_SHORT_SLOT_TIME) | |
c227ed0a JS |
1518 | pmlmeinfo->slotTime = |
1519 | NON_SHORT_SLOT_TIME; | |
5e93f352 | 1520 | } |
c227ed0a JS |
1521 | } else if (pmlmeext->cur_wireless_mode & |
1522 | (WIRELESS_11A | WIRELESS_11_5N)) { | |
5e93f352 LF |
1523 | pmlmeinfo->slotTime = SHORT_SLOT_TIME; |
1524 | } else { | |
1525 | /* B Mode */ | |
1526 | pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; | |
1527 | } | |
1528 | } | |
04c38427 | 1529 | rtl8723a_set_slot_time(Adapter, pmlmeinfo->slotTime); |
5e93f352 LF |
1530 | } |
1531 | ||
1532 | void update_wireless_mode23a(struct rtw_adapter *padapter) | |
1533 | { | |
1534 | int ratelen, network_type = 0; | |
c227ed0a | 1535 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
1536 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
1537 | struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; | |
c227ed0a | 1538 | unsigned char *rate = cur_network->SupportedRates; |
5e93f352 LF |
1539 | |
1540 | ratelen = rtw_get_rateset_len23a(cur_network->SupportedRates); | |
1541 | ||
1542 | if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) | |
1543 | pmlmeinfo->HT_enable = 1; | |
1544 | ||
1545 | if (pmlmeext->cur_channel > 14) { | |
1546 | if (pmlmeinfo->HT_enable) | |
1547 | network_type = WIRELESS_11_5N; | |
1548 | network_type |= WIRELESS_11A; | |
1549 | } else { | |
1550 | if (pmlmeinfo->HT_enable) | |
1551 | network_type = WIRELESS_11_24N; | |
1552 | ||
c227ed0a | 1553 | if (cckratesonly_included23a(rate, ratelen) == true) |
5e93f352 | 1554 | network_type |= WIRELESS_11B; |
c227ed0a | 1555 | else if (cckrates_included23a(rate, ratelen) == true) |
5e93f352 LF |
1556 | network_type |= WIRELESS_11BG; |
1557 | else | |
1558 | network_type |= WIRELESS_11G; | |
1559 | } | |
1560 | ||
c227ed0a JS |
1561 | pmlmeext->cur_wireless_mode = |
1562 | network_type & padapter->registrypriv.wireless_mode; | |
5e93f352 | 1563 | |
7b7aefaa JS |
1564 | /* 0x0808 -> for CCK, 0x0a0a -> for OFDM */ |
1565 | /* change this value if having IOT issues. */ | |
1566 | rtl8723a_set_resp_sifs(padapter, 0x08, 0x08, 0x0a, 0x0a); | |
5e93f352 LF |
1567 | |
1568 | if (pmlmeext->cur_wireless_mode & WIRELESS_11B) | |
1569 | update_mgnt_tx_rate23a(padapter, IEEE80211_CCK_RATE_1MB); | |
1570 | else | |
1571 | update_mgnt_tx_rate23a(padapter, IEEE80211_OFDM_RATE_6MB); | |
1572 | } | |
1573 | ||
1574 | void update_bmc_sta_support_rate23a(struct rtw_adapter *padapter, u32 mac_id) | |
1575 | { | |
1576 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | |
1577 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; | |
1578 | ||
1579 | if (pmlmeext->cur_wireless_mode & WIRELESS_11B) { | |
1580 | /* Only B, B/G, and B/G/N AP could use CCK rate */ | |
5bd28bc2 JS |
1581 | memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), |
1582 | rtw_basic_rate_cck, 4); | |
5e93f352 | 1583 | } else { |
c227ed0a | 1584 | memcpy(pmlmeinfo->FW_sta_info[mac_id].SupportedRates, |
5bd28bc2 | 1585 | rtw_basic_rate_ofdm, 3); |
5e93f352 LF |
1586 | } |
1587 | } | |
1588 | ||
bf350274 JS |
1589 | int update_sta_support_rate23a(struct rtw_adapter *padapter, u8 *pvar_ie, |
1590 | uint var_ie_len, int cam_idx) | |
5e93f352 | 1591 | { |
bf350274 | 1592 | int supportRateNum = 0; |
5e93f352 LF |
1593 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1594 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; | |
bf350274 | 1595 | const u8 *p; |
5e93f352 | 1596 | |
bf350274 JS |
1597 | p = cfg80211_find_ie(WLAN_EID_SUPP_RATES, pvar_ie, var_ie_len); |
1598 | if (!p) | |
5e93f352 LF |
1599 | return _FAIL; |
1600 | ||
bf350274 JS |
1601 | memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, p + 2, p[1]); |
1602 | supportRateNum = p[1]; | |
5e93f352 | 1603 | |
bf350274 JS |
1604 | p = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, pvar_ie, var_ie_len); |
1605 | if (p) | |
1606 | memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + | |
1607 | supportRateNum, p + 2, p[1]); | |
5e93f352 LF |
1608 | return _SUCCESS; |
1609 | } | |
1610 | ||
c227ed0a JS |
1611 | void process_addba_req23a(struct rtw_adapter *padapter, |
1612 | u8 *paddba_req, u8 *addr) | |
5e93f352 LF |
1613 | { |
1614 | struct sta_info *psta; | |
1615 | u16 tid, start_seq, param; | |
1616 | struct recv_reorder_ctrl *preorder_ctrl; | |
1617 | struct sta_priv *pstapriv = &padapter->stapriv; | |
c227ed0a JS |
1618 | struct ADDBA_request *preq = (struct ADDBA_request*)paddba_req; |
1619 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | |
5e93f352 LF |
1620 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
1621 | ||
1622 | psta = rtw_get_stainfo23a(pstapriv, addr); | |
1623 | ||
1624 | if (psta) { | |
1625 | start_seq = le16_to_cpu(preq->BA_starting_seqctrl) >> 4; | |
1626 | ||
1627 | param = le16_to_cpu(preq->BA_para_set); | |
c227ed0a | 1628 | tid = (param >> 2) & 0x0f; |
5e93f352 LF |
1629 | |
1630 | preorder_ctrl = &psta->recvreorder_ctrl[tid]; | |
1631 | ||
1632 | preorder_ctrl->indicate_seq = 0xffff; | |
1633 | ||
c227ed0a JS |
1634 | preorder_ctrl->enable = (pmlmeinfo->bAcceptAddbaReq == true) ? |
1635 | true : false; | |
5e93f352 LF |
1636 | } |
1637 | } |