]>
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 | ||
0c45e617 JS |
913 | if (!ether_addr_equal(cur_network->network.MacAddress, mgmt->bssid)) { |
914 | DBG_8723A("%s: linked but recv other bssid bcn" | |
915 | MAC_FMT MAC_FMT "\n", __func__, MAC_ARG(mgmt->bssid), | |
c146551f | 916 | MAC_ARG(cur_network->network.MacAddress)); |
5e93f352 LF |
917 | return true; |
918 | } | |
919 | ||
e1a35432 | 920 | bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC); |
5bd28bc2 JS |
921 | if (!bssid) |
922 | return _FAIL; | |
5e93f352 | 923 | |
c146551f | 924 | bssid->reserved = 1; |
5e93f352 | 925 | |
5bd28bc2 | 926 | bssid->Length = offsetof(struct wlan_bssid_ex, IEs) + len; |
5e93f352 LF |
927 | |
928 | /* below is to copy the information element */ | |
929 | bssid->IELength = len; | |
5bd28bc2 | 930 | memcpy(bssid->IEs, &mgmt->u, len); |
5e93f352 LF |
931 | |
932 | /* check bw and channel offset */ | |
933 | /* parsing HT_CAP_IE */ | |
3ffa4355 JS |
934 | ie_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable) - |
935 | offsetof(struct ieee80211_mgmt, u); | |
936 | pie = bssid->IEs + ie_offset; | |
937 | pie_len = pkt_len - ie_offset; | |
938 | ||
5e93f352 | 939 | /* Checking for channel */ |
3ffa4355 JS |
940 | p = cfg80211_find_ie(WLAN_EID_DS_PARAMS, pie, pie_len); |
941 | if (p) | |
942 | bcn_channel = p[2]; | |
943 | else { | |
944 | /* In 5G, some ap do not have DSSET IE checking HT | |
945 | info for channel */ | |
946 | p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, pie, pie_len); | |
947 | ||
ed08b4de JS |
948 | if (p && p[1] > 0) { |
949 | pht_info = (struct ieee80211_ht_operation *)(p + 2); | |
4dc5f8ba | 950 | bcn_channel = pht_info->primary_chan; |
ed08b4de | 951 | } else { /* we don't find channel IE, so don't check it */ |
3ffa4355 JS |
952 | DBG_8723A("Oops: %s we don't find channel IE, so don't " |
953 | "check it\n", __func__); | |
954 | bcn_channel = Adapter->mlmeextpriv.cur_channel; | |
955 | } | |
5e93f352 LF |
956 | } |
957 | if (bcn_channel != Adapter->mlmeextpriv.cur_channel) { | |
3ffa4355 JS |
958 | DBG_8723A("%s beacon channel:%d cur channel:%d disconnect\n", |
959 | __func__, bcn_channel, | |
960 | Adapter->mlmeextpriv.cur_channel); | |
961 | goto _mismatch; | |
5e93f352 LF |
962 | } |
963 | ||
964 | /* checking SSID */ | |
3ffa4355 | 965 | p = cfg80211_find_ie(WLAN_EID_SSID, pie, pie_len); |
82695d5c JS |
966 | if (p && p[1]) { |
967 | memcpy(bssid->Ssid.ssid, p + 2, p[1]); | |
968 | bssid->Ssid.ssid_len = p[1]; | |
969 | } else { | |
3ffa4355 JS |
970 | DBG_8723A("%s marc: cannot find SSID for survey event\n", |
971 | __func__); | |
5e93f352 LF |
972 | bssid->Ssid.ssid_len = 0; |
973 | bssid->Ssid.ssid[0] = '\0'; | |
974 | } | |
975 | ||
976 | RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, | |
977 | ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d " | |
978 | "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, | |
979 | bssid->Ssid.ssid, bssid->Ssid.ssid_len, | |
980 | cur_network->network.Ssid.ssid, | |
981 | cur_network->network.Ssid.ssid_len)); | |
982 | ||
983 | if (memcmp(bssid->Ssid.ssid, cur_network->network.Ssid.ssid, 32) || | |
984 | bssid->Ssid.ssid_len != cur_network->network.Ssid.ssid_len) { | |
985 | if (bssid->Ssid.ssid[0] != '\0' && | |
986 | bssid->Ssid.ssid_len != 0) { /* not hidden ssid */ | |
987 | DBG_8723A("%s(), SSID is not match return FAIL\n", | |
988 | __func__); | |
989 | goto _mismatch; | |
990 | } | |
991 | } | |
992 | ||
993 | /* check encryption info */ | |
52017955 | 994 | val16 = rtw_get_capability23a(bssid); |
5e93f352 | 995 | |
a665bcc2 | 996 | if (val16 & WLAN_CAPABILITY_PRIVACY) |
5e93f352 LF |
997 | bssid->Privacy = 1; |
998 | else | |
999 | bssid->Privacy = 0; | |
1000 | ||
1001 | RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, | |
c3761836 JS |
1002 | ("%s(): cur_network->network.Privacy is %d, bssid.Privacy " |
1003 | "is %d\n", __func__, cur_network->network.Privacy, | |
1004 | bssid->Privacy)); | |
5e93f352 LF |
1005 | if (cur_network->network.Privacy != bssid->Privacy) { |
1006 | DBG_8723A("%s(), privacy is not match return FAIL\n", __func__); | |
1007 | goto _mismatch; | |
1008 | } | |
1009 | ||
77953edf JS |
1010 | p = cfg80211_find_ie(WLAN_EID_RSN, pie, pie_len); |
1011 | if (p && p[1]) { | |
5e93f352 | 1012 | encryp_protocol = ENCRYP_PROTOCOL_WPA2; |
77953edf JS |
1013 | } else if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, |
1014 | WLAN_OUI_TYPE_MICROSOFT_WPA, | |
1015 | pie, pie_len)) { | |
5e93f352 | 1016 | encryp_protocol = ENCRYP_PROTOCOL_WPA; |
77953edf | 1017 | } else { |
5e93f352 LF |
1018 | if (bssid->Privacy) |
1019 | encryp_protocol = ENCRYP_PROTOCOL_WEP; | |
c3761836 JS |
1020 | else |
1021 | encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; | |
5e93f352 LF |
1022 | } |
1023 | ||
1024 | if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { | |
c3761836 | 1025 | DBG_8723A("%s(): enctyp is not match, return FAIL\n", __func__); |
5e93f352 LF |
1026 | goto _mismatch; |
1027 | } | |
1028 | ||
c3761836 JS |
1029 | if (encryp_protocol == ENCRYP_PROTOCOL_WPA || |
1030 | encryp_protocol == ENCRYP_PROTOCOL_WPA2) { | |
f88ca604 JS |
1031 | p = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, |
1032 | WLAN_OUI_TYPE_MICROSOFT_WPA, | |
1033 | pie, pie_len); | |
1034 | if (p && p[1] > 0) { | |
1035 | r = rtw_parse_wpa_ie23a(p, p[1] + 2, &group_cipher, | |
c3761836 JS |
1036 | &pairwise_cipher, &is_8021x); |
1037 | if (r == _SUCCESS) | |
5e93f352 | 1038 | RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, |
c3761836 JS |
1039 | ("%s pnetwork->pairwise_cipher: %d, " |
1040 | "group_cipher is %d, is_8021x is " | |
1041 | "%d\n", __func__, pairwise_cipher, | |
1042 | group_cipher, is_8021x)); | |
5e93f352 | 1043 | } else { |
f88ca604 | 1044 | p = cfg80211_find_ie(WLAN_EID_RSN, pie, pie_len); |
5e93f352 | 1045 | |
f88ca604 JS |
1046 | if (p && p[1] > 0) { |
1047 | r = rtw_parse_wpa2_ie23a(p, p[1] + 2, | |
c3761836 JS |
1048 | &group_cipher, |
1049 | &pairwise_cipher, | |
1050 | &is_8021x); | |
1051 | if (r == _SUCCESS) | |
1052 | RT_TRACE(_module_rtl871x_mlme_c_, | |
1053 | _drv_info_, | |
1054 | ("%s pnetwork->pairwise_cipher" | |
1055 | ": %d, pnetwork->group_cipher" | |
1056 | " is %d, is_802x is %d\n", | |
1057 | __func__, pairwise_cipher, | |
1058 | group_cipher, is_8021x)); | |
5e93f352 LF |
1059 | } |
1060 | } | |
1061 | ||
1062 | RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, | |
c3761836 JS |
1063 | ("%s cur_network->group_cipher is %d: %d\n", __func__, |
1064 | cur_network->BcnInfo.group_cipher, group_cipher)); | |
1065 | if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || | |
1066 | group_cipher != cur_network->BcnInfo.group_cipher) { | |
1067 | DBG_8723A("%s pairwise_cipher(%x:%x) or group_cipher " | |
1068 | "(%x:%x) is not match, return FAIL\n", | |
1069 | __func__, pairwise_cipher, | |
1070 | cur_network->BcnInfo.pairwise_cipher, | |
1071 | group_cipher, | |
1072 | cur_network->BcnInfo.group_cipher); | |
5e93f352 LF |
1073 | goto _mismatch; |
1074 | } | |
1075 | ||
1076 | if (is_8021x != cur_network->BcnInfo.is_8021x) { | |
c3761836 JS |
1077 | DBG_8723A("%s authentication is not match, return " |
1078 | "FAIL\n", __func__); | |
5e93f352 LF |
1079 | goto _mismatch; |
1080 | } | |
1081 | } | |
1082 | ||
1083 | kfree(bssid); | |
1084 | return _SUCCESS; | |
1085 | ||
1086 | _mismatch: | |
1087 | kfree(bssid); | |
1088 | ||
1089 | return _FAIL; | |
1090 | } | |
1091 | ||
7882ef45 JS |
1092 | void update_beacon23a_info(struct rtw_adapter *padapter, |
1093 | struct ieee80211_mgmt *mgmt, | |
b171da3c | 1094 | uint pkt_len, struct sta_info *psta) |
5e93f352 | 1095 | { |
5e93f352 | 1096 | unsigned int len; |
7882ef45 | 1097 | const u8 *p; |
5e93f352 | 1098 | |
7882ef45 | 1099 | len = pkt_len - offsetof(struct ieee80211_mgmt, u.beacon.variable); |
5e93f352 | 1100 | |
7882ef45 JS |
1101 | p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, mgmt->u.beacon.variable, |
1102 | len); | |
1103 | if (p) | |
1104 | bwmode_update_check(padapter, p); | |
5e93f352 | 1105 | |
7882ef45 JS |
1106 | p = cfg80211_find_ie(WLAN_EID_ERP_INFO, mgmt->u.beacon.variable, len); |
1107 | if (p) { | |
1108 | ERP_IE_handler23a(padapter, p); | |
1109 | VCS_update23a(padapter, psta); | |
5e93f352 LF |
1110 | } |
1111 | } | |
1112 | ||
d5789247 | 1113 | bool is_ap_in_tkip23a(struct rtw_adapter *padapter) |
5e93f352 LF |
1114 | { |
1115 | u32 i; | |
5e93f352 LF |
1116 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1117 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; | |
1118 | struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; | |
b171da3c | 1119 | const u8 *p; |
c164bcff JS |
1120 | int bcn_fixed_size; |
1121 | ||
1122 | bcn_fixed_size = offsetof(struct ieee80211_mgmt, u.beacon.variable) - | |
1123 | offsetof(struct ieee80211_mgmt, u.beacon); | |
5e93f352 | 1124 | |
52017955 | 1125 | if (rtw_get_capability23a(cur_network) & WLAN_CAPABILITY_PRIVACY) { |
c164bcff | 1126 | for (i = bcn_fixed_size; i < pmlmeinfo->network.IELength;) { |
b171da3c | 1127 | p = pmlmeinfo->network.IEs + i; |
5e93f352 | 1128 | |
b171da3c | 1129 | switch (p[0]) { |
9300c94b | 1130 | case WLAN_EID_VENDOR_SPECIFIC: |
b171da3c JS |
1131 | if (!memcmp(p + 2, RTW_WPA_OUI23A_TYPE, 4) && |
1132 | !memcmp(p + 2 + 12, WPA_TKIP_CIPHER, 4)) | |
5e93f352 LF |
1133 | return true; |
1134 | break; | |
25c934fa | 1135 | case WLAN_EID_RSN: |
b171da3c | 1136 | if (!memcmp(p + 2 + 8, RSN_TKIP_CIPHER, 4)) |
5e93f352 LF |
1137 | return true; |
1138 | break; | |
1139 | default: | |
1140 | break; | |
1141 | } | |
b171da3c | 1142 | i += (p[1] + 2); |
5e93f352 LF |
1143 | } |
1144 | return false; | |
c227ed0a | 1145 | } else |
5e93f352 | 1146 | return false; |
5e93f352 LF |
1147 | } |
1148 | ||
d5789247 | 1149 | bool should_forbid_n_rate23a(struct rtw_adapter * padapter) |
5e93f352 LF |
1150 | { |
1151 | u32 i; | |
c227ed0a | 1152 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
5e93f352 | 1153 | struct wlan_bssid_ex *cur_network = &pmlmepriv->cur_network.network; |
b171da3c | 1154 | const u8 *p; |
c164bcff JS |
1155 | int bcn_fixed_size; |
1156 | ||
1157 | bcn_fixed_size = offsetof(struct ieee80211_mgmt, u.beacon.variable) - | |
1158 | offsetof(struct ieee80211_mgmt, u.beacon); | |
5e93f352 | 1159 | |
52017955 | 1160 | if (rtw_get_capability23a(cur_network) & WLAN_CAPABILITY_PRIVACY) { |
c164bcff | 1161 | for (i = bcn_fixed_size; i < cur_network->IELength;) { |
b171da3c | 1162 | p = cur_network->IEs + i; |
5e93f352 | 1163 | |
b171da3c | 1164 | switch (p[0]) { |
9300c94b | 1165 | case WLAN_EID_VENDOR_SPECIFIC: |
b171da3c JS |
1166 | if (!memcmp(p + 2, RTW_WPA_OUI23A_TYPE, 4) && |
1167 | (!memcmp(p + 2 + 12, | |
c227ed0a | 1168 | WPA_CIPHER_SUITE_CCMP23A, 4) || |
b171da3c | 1169 | !memcmp(p + 2 + 16, |
c227ed0a | 1170 | WPA_CIPHER_SUITE_CCMP23A, 4))) |
5e93f352 LF |
1171 | return false; |
1172 | break; | |
25c934fa | 1173 | case WLAN_EID_RSN: |
b171da3c | 1174 | if (!memcmp(p + 2 + 8, |
c227ed0a | 1175 | RSN_CIPHER_SUITE_CCMP23A, 4) || |
b171da3c | 1176 | !memcmp(p + 2 + 12, |
c227ed0a | 1177 | RSN_CIPHER_SUITE_CCMP23A, 4)) |
5e93f352 LF |
1178 | return false; |
1179 | default: | |
1180 | break; | |
1181 | } | |
1182 | ||
b171da3c | 1183 | i += (p[1] + 2); |
5e93f352 LF |
1184 | } |
1185 | return true; | |
1186 | } else { | |
1187 | return false; | |
1188 | } | |
1189 | } | |
1190 | ||
d5789247 | 1191 | bool is_ap_in_wep23a(struct rtw_adapter *padapter) |
5e93f352 LF |
1192 | { |
1193 | u32 i; | |
5e93f352 LF |
1194 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1195 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; | |
1196 | struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; | |
b171da3c | 1197 | const u8 *p; |
c164bcff JS |
1198 | int bcn_fixed_size; |
1199 | ||
1200 | bcn_fixed_size = offsetof(struct ieee80211_mgmt, u.beacon.variable) - | |
1201 | offsetof(struct ieee80211_mgmt, u.beacon); | |
5e93f352 | 1202 | |
52017955 | 1203 | if (rtw_get_capability23a(cur_network) & WLAN_CAPABILITY_PRIVACY) { |
c164bcff | 1204 | for (i = bcn_fixed_size; i < pmlmeinfo->network.IELength;) { |
b171da3c | 1205 | p = pmlmeinfo->network.IEs + i; |
5e93f352 | 1206 | |
b171da3c | 1207 | switch (p[0]) { |
9300c94b | 1208 | case WLAN_EID_VENDOR_SPECIFIC: |
b171da3c | 1209 | if (!memcmp(p + 2, RTW_WPA_OUI23A_TYPE, 4)) |
5e93f352 LF |
1210 | return false; |
1211 | break; | |
25c934fa | 1212 | case WLAN_EID_RSN: |
5e93f352 LF |
1213 | return false; |
1214 | ||
1215 | default: | |
1216 | break; | |
1217 | } | |
1218 | ||
b171da3c | 1219 | i += (p[1] + 2); |
5e93f352 LF |
1220 | } |
1221 | ||
1222 | return true; | |
c227ed0a | 1223 | } else |
5e93f352 | 1224 | return false; |
5e93f352 LF |
1225 | } |
1226 | ||
c0b99bed | 1227 | static int wifirate2_ratetbl_inx23a(unsigned char rate) |
5e93f352 | 1228 | { |
c227ed0a | 1229 | int inx = 0; |
5e93f352 LF |
1230 | rate = rate & 0x7f; |
1231 | ||
1232 | switch (rate) { | |
1233 | case 54*2: | |
1234 | inx = 11; | |
1235 | break; | |
1236 | case 48*2: | |
1237 | inx = 10; | |
1238 | break; | |
1239 | case 36*2: | |
1240 | inx = 9; | |
1241 | break; | |
1242 | case 24*2: | |
1243 | inx = 8; | |
1244 | break; | |
1245 | case 18*2: | |
1246 | inx = 7; | |
1247 | break; | |
1248 | case 12*2: | |
1249 | inx = 6; | |
1250 | break; | |
1251 | case 9*2: | |
1252 | inx = 5; | |
1253 | break; | |
1254 | case 6*2: | |
1255 | inx = 4; | |
1256 | break; | |
1257 | case 11*2: | |
1258 | inx = 3; | |
1259 | break; | |
1260 | case 11: | |
1261 | inx = 2; | |
1262 | break; | |
1263 | case 2*2: | |
1264 | inx = 1; | |
1265 | break; | |
1266 | case 1*2: | |
1267 | inx = 0; | |
1268 | break; | |
1269 | } | |
1270 | return inx; | |
1271 | } | |
1272 | ||
1273 | unsigned int update_basic_rate23a(unsigned char *ptn, unsigned int ptn_sz) | |
1274 | { | |
1275 | unsigned int i, num_of_rate; | |
1276 | unsigned int mask = 0; | |
1277 | ||
1278 | num_of_rate = (ptn_sz > NumRates)? NumRates: ptn_sz; | |
1279 | ||
1280 | for (i = 0; i < num_of_rate; i++) { | |
1281 | if ((*(ptn + i)) & 0x80) | |
1282 | mask |= 0x1 << wifirate2_ratetbl_inx23a(*(ptn + i)); | |
1283 | } | |
1284 | return mask; | |
1285 | } | |
1286 | ||
1287 | unsigned int update_supported_rate23a(unsigned char *ptn, unsigned int ptn_sz) | |
1288 | { | |
1289 | unsigned int i, num_of_rate; | |
1290 | unsigned int mask = 0; | |
1291 | ||
c227ed0a | 1292 | num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz; |
5e93f352 LF |
1293 | |
1294 | for (i = 0; i < num_of_rate; i++) | |
1295 | mask |= 0x1 << wifirate2_ratetbl_inx23a(*(ptn + i)); | |
1296 | return mask; | |
1297 | } | |
1298 | ||
65be27da | 1299 | unsigned int update_MSC_rate23a(struct ieee80211_ht_cap *pHT_caps) |
5e93f352 LF |
1300 | { |
1301 | unsigned int mask = 0; | |
1302 | ||
65be27da JS |
1303 | mask = pHT_caps->mcs.rx_mask[0] << 12 | |
1304 | pHT_caps->mcs.rx_mask[1] << 20; | |
5e93f352 LF |
1305 | |
1306 | return mask; | |
1307 | } | |
1308 | ||
1309 | int support_short_GI23a(struct rtw_adapter *padapter, | |
65be27da | 1310 | struct ieee80211_ht_cap *pHT_caps) |
5e93f352 | 1311 | { |
c227ed0a | 1312 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
1313 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
1314 | unsigned char bit_offset; | |
1315 | ||
c227ed0a | 1316 | if (!pmlmeinfo->HT_enable) |
5e93f352 | 1317 | return _FAIL; |
c227ed0a | 1318 | if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK) |
5e93f352 LF |
1319 | return _FAIL; |
1320 | bit_offset = (pmlmeext->cur_bwmode & HT_CHANNEL_WIDTH_40)? 6: 5; | |
1321 | ||
65be27da | 1322 | if (pHT_caps->cap_info & cpu_to_le16(0x1 << bit_offset)) |
5e93f352 LF |
1323 | return _SUCCESS; |
1324 | else | |
1325 | return _FAIL; | |
1326 | } | |
1327 | ||
1328 | unsigned char get_highest_rate_idx23a(u32 mask) | |
1329 | { | |
1330 | int i; | |
1331 | unsigned char rate_idx = 0; | |
1332 | ||
1333 | for (i = 27; i >= 0; i--) { | |
1334 | if (mask & BIT(i)) { | |
1335 | rate_idx = i; | |
1336 | break; | |
1337 | } | |
1338 | } | |
1339 | return rate_idx; | |
1340 | } | |
1341 | ||
5e93f352 LF |
1342 | void Update_RA_Entry23a(struct rtw_adapter *padapter, struct sta_info *psta) |
1343 | { | |
1344 | rtw_hal_update_ra_mask23a(psta, 0); | |
1345 | } | |
1346 | ||
c0b99bed LF |
1347 | static void enable_rate_adaptive(struct rtw_adapter *padapter, |
1348 | struct sta_info *psta) | |
5e93f352 LF |
1349 | { |
1350 | Update_RA_Entry23a(padapter, psta); | |
1351 | } | |
1352 | ||
1353 | void set_sta_rate23a(struct rtw_adapter *padapter, struct sta_info *psta) | |
1354 | { | |
1355 | /* rate adaptive */ | |
1356 | enable_rate_adaptive(padapter, psta); | |
1357 | } | |
1358 | ||
1359 | /* Update RRSR and Rate for USERATE */ | |
1360 | void update_tx_basic_rate23a(struct rtw_adapter *padapter, u8 wirelessmode) | |
1361 | { | |
1362 | unsigned char supported_rates[NDIS_802_11_LENGTH_RATES_EX]; | |
5e93f352 LF |
1363 | |
1364 | memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX); | |
1365 | ||
ff516e70 | 1366 | if (wirelessmode == WIRELESS_11B) { |
5e93f352 LF |
1367 | memcpy(supported_rates, rtw_basic_rate_cck, 4); |
1368 | } else if (wirelessmode & WIRELESS_11B) { | |
1369 | memcpy(supported_rates, rtw_basic_rate_mix, 7); | |
1370 | } else { | |
1371 | memcpy(supported_rates, rtw_basic_rate_ofdm, 3); | |
1372 | } | |
1373 | ||
1374 | if (wirelessmode & WIRELESS_11B) | |
1375 | update_mgnt_tx_rate23a(padapter, IEEE80211_CCK_RATE_1MB); | |
1376 | else | |
1377 | update_mgnt_tx_rate23a(padapter, IEEE80211_OFDM_RATE_6MB); | |
1378 | ||
fa2e5209 | 1379 | HalSetBrateCfg23a(padapter, supported_rates); |
5e93f352 LF |
1380 | } |
1381 | ||
1382 | unsigned char check_assoc_AP23a(u8 *pframe, uint len) | |
1383 | { | |
c164bcff | 1384 | int i, bcn_fixed_size; |
c227ed0a JS |
1385 | u8 epigram_vendor_flag; |
1386 | u8 ralink_vendor_flag; | |
b171da3c | 1387 | const u8 *p; |
5e93f352 LF |
1388 | epigram_vendor_flag = 0; |
1389 | ralink_vendor_flag = 0; | |
1390 | ||
c164bcff JS |
1391 | bcn_fixed_size = offsetof(struct ieee80211_mgmt, u.beacon.variable) - |
1392 | offsetof(struct ieee80211_mgmt, u.beacon); | |
1393 | ||
1394 | for (i = bcn_fixed_size; i < len;) { | |
b171da3c | 1395 | p = pframe + i; |
5e93f352 | 1396 | |
b171da3c | 1397 | switch (p[0]) { |
9300c94b | 1398 | case WLAN_EID_VENDOR_SPECIFIC: |
b171da3c JS |
1399 | if (!memcmp(p + 2, ARTHEROS_OUI1, 3) || |
1400 | !memcmp(p + 2, ARTHEROS_OUI2, 3)) { | |
5e93f352 LF |
1401 | DBG_8723A("link to Artheros AP\n"); |
1402 | return HT_IOT_PEER_ATHEROS; | |
b171da3c JS |
1403 | } else if (!memcmp(p + 2, BROADCOM_OUI1, 3) || |
1404 | !memcmp(p + 2, BROADCOM_OUI2, 3) || | |
1405 | !memcmp(p + 2, BROADCOM_OUI2, 3)) { | |
5e93f352 LF |
1406 | DBG_8723A("link to Broadcom AP\n"); |
1407 | return HT_IOT_PEER_BROADCOM; | |
b171da3c | 1408 | } else if (!memcmp(p + 2, MARVELL_OUI, 3)) { |
5e93f352 LF |
1409 | DBG_8723A("link to Marvell AP\n"); |
1410 | return HT_IOT_PEER_MARVELL; | |
b171da3c | 1411 | } else if (!memcmp(p + 2, RALINK_OUI, 3)) { |
c227ed0a | 1412 | if (!ralink_vendor_flag) |
5e93f352 | 1413 | ralink_vendor_flag = 1; |
c227ed0a | 1414 | else { |
5e93f352 LF |
1415 | DBG_8723A("link to Ralink AP\n"); |
1416 | return HT_IOT_PEER_RALINK; | |
1417 | } | |
b171da3c | 1418 | } else if (!memcmp(p + 2, CISCO_OUI, 3)) { |
5e93f352 LF |
1419 | DBG_8723A("link to Cisco AP\n"); |
1420 | return HT_IOT_PEER_CISCO; | |
b171da3c | 1421 | } else if (!memcmp(p + 2, REALTEK_OUI, 3)) { |
5e93f352 LF |
1422 | DBG_8723A("link to Realtek 96B\n"); |
1423 | return HT_IOT_PEER_REALTEK; | |
b171da3c | 1424 | } else if (!memcmp(p + 2, AIRGOCAP_OUI, 3)) { |
5e93f352 LF |
1425 | DBG_8723A("link to Airgo Cap\n"); |
1426 | return HT_IOT_PEER_AIRGO; | |
b171da3c | 1427 | } else if (!memcmp(p + 2, EPIGRAM_OUI, 3)) { |
5e93f352 LF |
1428 | epigram_vendor_flag = 1; |
1429 | if (ralink_vendor_flag) { | |
1430 | DBG_8723A("link to Tenda W311R AP\n"); | |
1431 | return HT_IOT_PEER_TENDA; | |
c227ed0a | 1432 | } else |
5e93f352 | 1433 | DBG_8723A("Capture EPIGRAM_OUI\n"); |
c227ed0a | 1434 | } else |
5e93f352 | 1435 | break; |
5e93f352 LF |
1436 | default: |
1437 | break; | |
1438 | } | |
1439 | ||
b171da3c | 1440 | i += (p[1] + 2); |
5e93f352 LF |
1441 | } |
1442 | ||
1443 | if (ralink_vendor_flag && !epigram_vendor_flag) { | |
1444 | DBG_8723A("link to Ralink AP\n"); | |
1445 | return HT_IOT_PEER_RALINK; | |
1446 | } else if (ralink_vendor_flag && epigram_vendor_flag) { | |
1447 | DBG_8723A("link to Tenda W311R AP\n"); | |
1448 | return HT_IOT_PEER_TENDA; | |
1449 | } else { | |
1450 | DBG_8723A("link to new AP\n"); | |
1451 | return HT_IOT_PEER_UNKNOWN; | |
1452 | } | |
1453 | } | |
1454 | ||
1455 | void update_IOT_info23a(struct rtw_adapter *padapter) | |
1456 | { | |
c227ed0a | 1457 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
1458 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
1459 | ||
1460 | switch (pmlmeinfo->assoc_AP_vendor) { | |
1461 | case HT_IOT_PEER_MARVELL: | |
1462 | pmlmeinfo->turboMode_cts2self = 1; | |
1463 | pmlmeinfo->turboMode_rtsen = 0; | |
1464 | break; | |
1465 | case HT_IOT_PEER_RALINK: | |
1466 | pmlmeinfo->turboMode_cts2self = 0; | |
1467 | pmlmeinfo->turboMode_rtsen = 1; | |
1468 | /* disable high power */ | |
585eefb4 JS |
1469 | rtl8723a_odm_support_ability_clr(padapter, (u32) |
1470 | ~DYNAMIC_BB_DYNAMIC_TXPWR); | |
5e93f352 LF |
1471 | break; |
1472 | case HT_IOT_PEER_REALTEK: | |
1473 | /* rtw_write16(padapter, 0x4cc, 0xffff); */ | |
1474 | /* rtw_write16(padapter, 0x546, 0x01c0); */ | |
1475 | /* disable high power */ | |
585eefb4 JS |
1476 | rtl8723a_odm_support_ability_clr(padapter, (u32) |
1477 | ~DYNAMIC_BB_DYNAMIC_TXPWR); | |
5e93f352 LF |
1478 | break; |
1479 | default: | |
1480 | pmlmeinfo->turboMode_cts2self = 0; | |
1481 | pmlmeinfo->turboMode_rtsen = 1; | |
1482 | break; | |
1483 | } | |
1484 | } | |
1485 | ||
1486 | void update_capinfo23a(struct rtw_adapter *Adapter, u16 updateCap) | |
1487 | { | |
c227ed0a | 1488 | struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; |
5e93f352 | 1489 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
5e93f352 LF |
1490 | |
1491 | if (updateCap & cShortPreamble) { | |
1492 | /* Short Preamble */ | |
1493 | if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) { | |
1494 | /* PREAMBLE_LONG or PREAMBLE_AUTO */ | |
5e93f352 | 1495 | pmlmeinfo->preamble_mode = PREAMBLE_SHORT; |
093dd41e | 1496 | rtl8723a_ack_preamble(Adapter, true); |
5e93f352 LF |
1497 | } |
1498 | } else { /* Long Preamble */ | |
1499 | if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) { | |
1500 | /* PREAMBLE_SHORT or PREAMBLE_AUTO */ | |
5e93f352 | 1501 | pmlmeinfo->preamble_mode = PREAMBLE_LONG; |
093dd41e | 1502 | rtl8723a_ack_preamble(Adapter, false); |
5e93f352 LF |
1503 | } |
1504 | } | |
1505 | if (updateCap & cIBSS) { | |
1506 | /* Filen: See 802.11-2007 p.91 */ | |
1507 | pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; | |
1508 | } else { | |
1509 | /* Filen: See 802.11-2007 p.90 */ | |
c227ed0a JS |
1510 | if (pmlmeext->cur_wireless_mode & |
1511 | (WIRELESS_11G | WIRELESS_11_24N)) { | |
5e93f352 LF |
1512 | if (updateCap & cShortSlotTime) { /* Short Slot Time */ |
1513 | if (pmlmeinfo->slotTime != SHORT_SLOT_TIME) | |
1514 | pmlmeinfo->slotTime = SHORT_SLOT_TIME; | |
1515 | } else { /* Long Slot Time */ | |
1516 | if (pmlmeinfo->slotTime != NON_SHORT_SLOT_TIME) | |
c227ed0a JS |
1517 | pmlmeinfo->slotTime = |
1518 | NON_SHORT_SLOT_TIME; | |
5e93f352 | 1519 | } |
c227ed0a JS |
1520 | } else if (pmlmeext->cur_wireless_mode & |
1521 | (WIRELESS_11A | WIRELESS_11_5N)) { | |
5e93f352 LF |
1522 | pmlmeinfo->slotTime = SHORT_SLOT_TIME; |
1523 | } else { | |
1524 | /* B Mode */ | |
1525 | pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; | |
1526 | } | |
1527 | } | |
04c38427 | 1528 | rtl8723a_set_slot_time(Adapter, pmlmeinfo->slotTime); |
5e93f352 LF |
1529 | } |
1530 | ||
1531 | void update_wireless_mode23a(struct rtw_adapter *padapter) | |
1532 | { | |
1533 | int ratelen, network_type = 0; | |
c227ed0a | 1534 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5e93f352 LF |
1535 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
1536 | struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; | |
c227ed0a | 1537 | unsigned char *rate = cur_network->SupportedRates; |
5e93f352 LF |
1538 | |
1539 | ratelen = rtw_get_rateset_len23a(cur_network->SupportedRates); | |
1540 | ||
1541 | if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) | |
1542 | pmlmeinfo->HT_enable = 1; | |
1543 | ||
1544 | if (pmlmeext->cur_channel > 14) { | |
1545 | if (pmlmeinfo->HT_enable) | |
1546 | network_type = WIRELESS_11_5N; | |
1547 | network_type |= WIRELESS_11A; | |
1548 | } else { | |
1549 | if (pmlmeinfo->HT_enable) | |
1550 | network_type = WIRELESS_11_24N; | |
1551 | ||
c227ed0a | 1552 | if (cckratesonly_included23a(rate, ratelen) == true) |
5e93f352 | 1553 | network_type |= WIRELESS_11B; |
c227ed0a | 1554 | else if (cckrates_included23a(rate, ratelen) == true) |
5e93f352 LF |
1555 | network_type |= WIRELESS_11BG; |
1556 | else | |
1557 | network_type |= WIRELESS_11G; | |
1558 | } | |
1559 | ||
c227ed0a JS |
1560 | pmlmeext->cur_wireless_mode = |
1561 | network_type & padapter->registrypriv.wireless_mode; | |
5e93f352 | 1562 | |
7b7aefaa JS |
1563 | /* 0x0808 -> for CCK, 0x0a0a -> for OFDM */ |
1564 | /* change this value if having IOT issues. */ | |
1565 | rtl8723a_set_resp_sifs(padapter, 0x08, 0x08, 0x0a, 0x0a); | |
5e93f352 LF |
1566 | |
1567 | if (pmlmeext->cur_wireless_mode & WIRELESS_11B) | |
1568 | update_mgnt_tx_rate23a(padapter, IEEE80211_CCK_RATE_1MB); | |
1569 | else | |
1570 | update_mgnt_tx_rate23a(padapter, IEEE80211_OFDM_RATE_6MB); | |
1571 | } | |
1572 | ||
1573 | void update_bmc_sta_support_rate23a(struct rtw_adapter *padapter, u32 mac_id) | |
1574 | { | |
1575 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | |
1576 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; | |
1577 | ||
1578 | if (pmlmeext->cur_wireless_mode & WIRELESS_11B) { | |
1579 | /* Only B, B/G, and B/G/N AP could use CCK rate */ | |
5bd28bc2 JS |
1580 | memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), |
1581 | rtw_basic_rate_cck, 4); | |
5e93f352 | 1582 | } else { |
c227ed0a | 1583 | memcpy(pmlmeinfo->FW_sta_info[mac_id].SupportedRates, |
5bd28bc2 | 1584 | rtw_basic_rate_ofdm, 3); |
5e93f352 LF |
1585 | } |
1586 | } | |
1587 | ||
bf350274 JS |
1588 | int update_sta_support_rate23a(struct rtw_adapter *padapter, u8 *pvar_ie, |
1589 | uint var_ie_len, int cam_idx) | |
5e93f352 | 1590 | { |
bf350274 | 1591 | int supportRateNum = 0; |
5e93f352 LF |
1592 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1593 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; | |
bf350274 | 1594 | const u8 *p; |
5e93f352 | 1595 | |
bf350274 JS |
1596 | p = cfg80211_find_ie(WLAN_EID_SUPP_RATES, pvar_ie, var_ie_len); |
1597 | if (!p) | |
5e93f352 LF |
1598 | return _FAIL; |
1599 | ||
bf350274 JS |
1600 | memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, p + 2, p[1]); |
1601 | supportRateNum = p[1]; | |
5e93f352 | 1602 | |
bf350274 JS |
1603 | p = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, pvar_ie, var_ie_len); |
1604 | if (p) | |
1605 | memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + | |
1606 | supportRateNum, p + 2, p[1]); | |
5e93f352 LF |
1607 | return _SUCCESS; |
1608 | } | |
1609 | ||
c227ed0a JS |
1610 | void process_addba_req23a(struct rtw_adapter *padapter, |
1611 | u8 *paddba_req, u8 *addr) | |
5e93f352 LF |
1612 | { |
1613 | struct sta_info *psta; | |
1614 | u16 tid, start_seq, param; | |
1615 | struct recv_reorder_ctrl *preorder_ctrl; | |
1616 | struct sta_priv *pstapriv = &padapter->stapriv; | |
c227ed0a JS |
1617 | struct ADDBA_request *preq = (struct ADDBA_request*)paddba_req; |
1618 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; | |
5e93f352 LF |
1619 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
1620 | ||
1621 | psta = rtw_get_stainfo23a(pstapriv, addr); | |
1622 | ||
1623 | if (psta) { | |
1624 | start_seq = le16_to_cpu(preq->BA_starting_seqctrl) >> 4; | |
1625 | ||
1626 | param = le16_to_cpu(preq->BA_para_set); | |
c227ed0a | 1627 | tid = (param >> 2) & 0x0f; |
5e93f352 LF |
1628 | |
1629 | preorder_ctrl = &psta->recvreorder_ctrl[tid]; | |
1630 | ||
1631 | preorder_ctrl->indicate_seq = 0xffff; | |
1632 | ||
c227ed0a JS |
1633 | preorder_ctrl->enable = (pmlmeinfo->bAcceptAddbaReq == true) ? |
1634 | true : false; | |
5e93f352 LF |
1635 | } |
1636 | } |