1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. |
5 | * |
6 | ******************************************************************************/ |
7 | #include <drv_types.h> |
8 | #include <rtw_debug.h> |
9 | #include <rtw_wifi_regd.h> |
10 | #include <hal_btcoex.h> |
11 | #include <linux/kernel.h> |
12 | #include <asm/unaligned.h> |
13 | |
14 | static struct mlme_handler mlme_sta_tbl[] = { |
15 | {WIFI_ASSOCREQ, "OnAssocReq" , &OnAssocReq}, |
16 | {WIFI_ASSOCRSP, "OnAssocRsp" , &OnAssocRsp}, |
17 | {WIFI_REASSOCREQ, "OnReAssocReq" , &OnAssocReq}, |
18 | {WIFI_REASSOCRSP, "OnReAssocRsp" , &OnAssocRsp}, |
19 | {WIFI_PROBEREQ, "OnProbeReq" , &OnProbeReq}, |
20 | {WIFI_PROBERSP, "OnProbeRsp" , &OnProbeRsp}, |
21 | |
22 | /*---------------------------------------------------------- |
23 | below 2 are reserved |
24 | -----------------------------------------------------------*/ |
25 | {0, "DoReserved" , &DoReserved}, |
26 | {0, "DoReserved" , &DoReserved}, |
27 | {WIFI_BEACON, "OnBeacon" , &OnBeacon}, |
28 | {WIFI_ATIM, "OnATIM" , &OnAtim}, |
29 | {WIFI_DISASSOC, "OnDisassoc" , &OnDisassoc}, |
30 | {WIFI_AUTH, "OnAuth" , &OnAuthClient}, |
31 | {WIFI_DEAUTH, "OnDeAuth" , &OnDeAuth}, |
32 | {WIFI_ACTION, "OnAction" , &OnAction}, |
33 | {WIFI_ACTION_NOACK, "OnActionNoAck" , &OnAction}, |
34 | }; |
35 | |
36 | static struct action_handler OnAction_tbl[] = { |
37 | {RTW_WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT" , on_action_spct}, |
38 | {RTW_WLAN_CATEGORY_QOS, "ACTION_QOS" , &DoReserved}, |
39 | {RTW_WLAN_CATEGORY_DLS, "ACTION_DLS" , &DoReserved}, |
40 | {RTW_WLAN_CATEGORY_BACK, "ACTION_BACK" , &OnAction_back}, |
41 | {RTW_WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC" , on_action_public}, |
42 | {RTW_WLAN_CATEGORY_RADIO_MEASUREMENT, "ACTION_RADIO_MEASUREMENT" , &DoReserved}, |
43 | {RTW_WLAN_CATEGORY_FT, "ACTION_FT" , &DoReserved}, |
44 | {RTW_WLAN_CATEGORY_HT, "ACTION_HT" , &OnAction_ht}, |
45 | {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY" , &OnAction_sa_query}, |
46 | {RTW_WLAN_CATEGORY_UNPROTECTED_WNM, "ACTION_UNPROTECTED_WNM" , &DoReserved}, |
47 | {RTW_WLAN_CATEGORY_SELF_PROTECTED, "ACTION_SELF_PROTECTED" , &DoReserved}, |
48 | {RTW_WLAN_CATEGORY_WMM, "ACTION_WMM" , &DoReserved}, |
49 | {RTW_WLAN_CATEGORY_P2P, "ACTION_P2P" , &DoReserved}, |
50 | }; |
51 | |
52 | static u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; |
53 | |
54 | /************************************************** |
55 | OUI definitions for the vendor specific IE |
56 | ***************************************************/ |
57 | unsigned char RTW_WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; |
58 | unsigned char WMM_OUI[] = {0x00, 0x50, 0xf2, 0x02}; |
59 | unsigned char WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; |
60 | unsigned char P2P_OUI[] = {0x50, 0x6F, 0x9A, 0x09}; |
61 | unsigned char WFD_OUI[] = {0x50, 0x6F, 0x9A, 0x0A}; |
62 | |
63 | unsigned char WMM_INFO_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; |
64 | unsigned char WMM_PARA_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; |
65 | |
66 | static unsigned char REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20}; |
67 | |
68 | /******************************************************** |
69 | ChannelPlan definitions |
70 | *********************************************************/ |
71 | static struct rt_channel_plan_2g RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = { |
72 | {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 */ |
73 | {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 */ |
74 | {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, /* 0x02, RT_CHANNEL_DOMAIN_2G_FCC1 */ |
75 | {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, /* 0x03, RT_CHANNEL_DOMAIN_2G_MIKK1 */ |
76 | {{10, 11, 12, 13}, 4}, /* 0x04, RT_CHANNEL_DOMAIN_2G_ETSI2 */ |
77 | {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, /* 0x05, RT_CHANNEL_DOMAIN_2G_GLOBAL , Passive scan CH 12, 13, 14 */ |
78 | {{}, 0}, /* 0x06, RT_CHANNEL_DOMAIN_2G_NULL */ |
79 | }; |
80 | |
81 | static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = { |
82 | /* 0x00 ~ 0x1F , Old Define ===== */ |
83 | {0x02}, /* 0x00, RT_CHANNEL_DOMAIN_FCC */ |
84 | {0x02}, /* 0x01, RT_CHANNEL_DOMAIN_IC */ |
85 | {0x01}, /* 0x02, RT_CHANNEL_DOMAIN_ETSI */ |
86 | {0x01}, /* 0x03, RT_CHANNEL_DOMAIN_SPAIN */ |
87 | {0x01}, /* 0x04, RT_CHANNEL_DOMAIN_FRANCE */ |
88 | {0x03}, /* 0x05, RT_CHANNEL_DOMAIN_MKK */ |
89 | {0x03}, /* 0x06, RT_CHANNEL_DOMAIN_MKK1 */ |
90 | {0x01}, /* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */ |
91 | {0x03}, /* 0x08, RT_CHANNEL_DOMAIN_TELEC */ |
92 | {0x03}, /* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */ |
93 | {0x00}, /* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */ |
94 | {0x02}, /* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */ |
95 | {0x01}, /* 0x0C, RT_CHANNEL_DOMAIN_CHINA */ |
96 | {0x02}, /* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */ |
97 | {0x02}, /* 0x0E, RT_CHANNEL_DOMAIN_KOREA */ |
98 | {0x02}, /* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */ |
99 | {0x01}, /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */ |
100 | {0x02}, /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */ |
101 | {0x01}, /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */ |
102 | {0x00}, /* 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G */ |
103 | {0x02}, /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */ |
104 | {0x00}, /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */ |
105 | {0x00}, /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */ |
106 | {0x03}, /* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */ |
107 | {0x06}, /* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */ |
108 | {0x02}, /* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */ |
109 | {0x00}, /* 0x1A, */ |
110 | {0x00}, /* 0x1B, */ |
111 | {0x00}, /* 0x1C, */ |
112 | {0x00}, /* 0x1D, */ |
113 | {0x00}, /* 0x1E, */ |
114 | {0x06}, /* 0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G */ |
115 | /* 0x20 ~ 0x7F , New Define ===== */ |
116 | {0x00}, /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */ |
117 | {0x01}, /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */ |
118 | {0x02}, /* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */ |
119 | {0x03}, /* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */ |
120 | {0x04}, /* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */ |
121 | {0x02}, /* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */ |
122 | {0x00}, /* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */ |
123 | {0x03}, /* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */ |
124 | {0x00}, /* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */ |
125 | {0x00}, /* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */ |
126 | {0x00}, /* 0x2A, */ |
127 | {0x00}, /* 0x2B, */ |
128 | {0x00}, /* 0x2C, */ |
129 | {0x00}, /* 0x2D, */ |
130 | {0x00}, /* 0x2E, */ |
131 | {0x00}, /* 0x2F, */ |
132 | {0x00}, /* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */ |
133 | {0x00}, /* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */ |
134 | {0x00}, /* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */ |
135 | {0x00}, /* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */ |
136 | {0x02}, /* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */ |
137 | {0x00}, /* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */ |
138 | {0x00}, /* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */ |
139 | {0x03}, /* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */ |
140 | {0x03}, /* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */ |
141 | {0x02}, /* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */ |
142 | {0x00}, /* 0x3A, */ |
143 | {0x00}, /* 0x3B, */ |
144 | {0x00}, /* 0x3C, */ |
145 | {0x00}, /* 0x3D, */ |
146 | {0x00}, /* 0x3E, */ |
147 | {0x00}, /* 0x3F, */ |
148 | {0x02}, /* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */ |
149 | {0x05}, /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_NULL */ |
150 | {0x01}, /* 0x42, RT_CHANNEL_DOMAIN_ETSI1_ETSI4 */ |
151 | {0x02}, /* 0x43, RT_CHANNEL_DOMAIN_FCC1_FCC2 */ |
152 | {0x02}, /* 0x44, RT_CHANNEL_DOMAIN_FCC1_NCC3 */ |
153 | {0x00}, /* 0x45, RT_CHANNEL_DOMAIN_WORLD_ETSI5 */ |
154 | {0x02}, /* 0x46, RT_CHANNEL_DOMAIN_FCC1_FCC8 */ |
155 | {0x00}, /* 0x47, RT_CHANNEL_DOMAIN_WORLD_ETSI6 */ |
156 | {0x00}, /* 0x48, RT_CHANNEL_DOMAIN_WORLD_ETSI7 */ |
157 | {0x00}, /* 0x49, RT_CHANNEL_DOMAIN_WORLD_ETSI8 */ |
158 | {0x00}, /* 0x50, RT_CHANNEL_DOMAIN_WORLD_ETSI9 */ |
159 | {0x00}, /* 0x51, RT_CHANNEL_DOMAIN_WORLD_ETSI10 */ |
160 | {0x00}, /* 0x52, RT_CHANNEL_DOMAIN_WORLD_ETSI11 */ |
161 | {0x02}, /* 0x53, RT_CHANNEL_DOMAIN_FCC1_NCC4 */ |
162 | {0x00}, /* 0x54, RT_CHANNEL_DOMAIN_WORLD_ETSI12 */ |
163 | {0x02}, /* 0x55, RT_CHANNEL_DOMAIN_FCC1_FCC9 */ |
164 | {0x00}, /* 0x56, RT_CHANNEL_DOMAIN_WORLD_ETSI13 */ |
165 | {0x02}, /* 0x57, RT_CHANNEL_DOMAIN_FCC1_FCC10 */ |
166 | }; |
167 | |
168 | /* use the combination for max channel numbers */ |
169 | static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03}; |
170 | |
171 | /* Search the @param ch in given @param ch_set |
172 | * @ch_set: the given channel set |
173 | * @ch: the given channel number |
174 | * |
175 | * return the index of channel_num in channel_set, -1 if not found |
176 | */ |
177 | int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch) |
178 | { |
179 | int i; |
180 | |
181 | for (i = 0; ch_set[i].ChannelNum != 0; i++) { |
182 | if (ch == ch_set[i].ChannelNum) |
183 | break; |
184 | } |
185 | |
186 | if (i >= ch_set[i].ChannelNum) |
187 | return -1; |
188 | return i; |
189 | } |
190 | |
191 | /**************************************************************************** |
192 | |
193 | Following are the initialization functions for WiFi MLME |
194 | |
195 | *****************************************************************************/ |
196 | |
197 | int init_hw_mlme_ext(struct adapter *padapter) |
198 | { |
199 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
200 | |
201 | set_channel_bwmode(padapter, channel: pmlmeext->cur_channel, channel_offset: pmlmeext->cur_ch_offset, bwmode: pmlmeext->cur_bwmode); |
202 | return _SUCCESS; |
203 | } |
204 | |
205 | void init_mlme_default_rate_set(struct adapter *padapter) |
206 | { |
207 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
208 | |
209 | unsigned char mixed_datarate[NumRates] = {_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_, _48M_RATE_, _54M_RATE_, 0xff}; |
210 | unsigned char mixed_basicrate[NumRates] = {_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, _12M_RATE_, _24M_RATE_, 0xff,}; |
211 | unsigned char supported_mcs_set[16] = {0xff, 0xff, 0x00, 0x00, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; |
212 | |
213 | memcpy(pmlmeext->datarate, mixed_datarate, NumRates); |
214 | memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates); |
215 | |
216 | memcpy(pmlmeext->default_supported_mcs_set, supported_mcs_set, sizeof(pmlmeext->default_supported_mcs_set)); |
217 | } |
218 | |
219 | static void init_mlme_ext_priv_value(struct adapter *padapter) |
220 | { |
221 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
222 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
223 | |
224 | atomic_set(v: &pmlmeext->event_seq, i: 0); |
225 | pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ |
226 | pmlmeext->sa_query_seq = 0; |
227 | pmlmeext->mgnt_80211w_IPN = 0; |
228 | pmlmeext->mgnt_80211w_IPN_rx = 0; |
229 | pmlmeext->cur_channel = padapter->registrypriv.channel; |
230 | pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; |
231 | pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; |
232 | |
233 | pmlmeext->retry = 0; |
234 | |
235 | pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode; |
236 | |
237 | init_mlme_default_rate_set(padapter); |
238 | |
239 | pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB; |
240 | pmlmeext->sitesurvey_res.state = SCAN_DISABLE; |
241 | pmlmeext->sitesurvey_res.channel_idx = 0; |
242 | pmlmeext->sitesurvey_res.bss_cnt = 0; |
243 | pmlmeext->scan_abort = false; |
244 | |
245 | pmlmeinfo->state = WIFI_FW_NULL_STATE; |
246 | pmlmeinfo->reauth_count = 0; |
247 | pmlmeinfo->reassoc_count = 0; |
248 | pmlmeinfo->link_count = 0; |
249 | pmlmeinfo->auth_seq = 0; |
250 | pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; |
251 | pmlmeinfo->key_index = 0; |
252 | pmlmeinfo->iv = 0; |
253 | |
254 | pmlmeinfo->enc_algo = _NO_PRIVACY_; |
255 | pmlmeinfo->authModeToggle = 0; |
256 | |
257 | memset(pmlmeinfo->chg_txt, 0, 128); |
258 | |
259 | pmlmeinfo->slotTime = SHORT_SLOT_TIME; |
260 | pmlmeinfo->preamble_mode = PREAMBLE_AUTO; |
261 | |
262 | pmlmeinfo->dialogToken = 0; |
263 | |
264 | pmlmeext->action_public_rxseq = 0xffff; |
265 | pmlmeext->action_public_dialog_token = 0xff; |
266 | } |
267 | |
268 | static int has_channel(struct rt_channel_info *channel_set, |
269 | u8 chanset_size, |
270 | u8 chan) |
271 | { |
272 | int i; |
273 | |
274 | for (i = 0; i < chanset_size; i++) |
275 | if (channel_set[i].ChannelNum == chan) |
276 | return 1; |
277 | |
278 | return 0; |
279 | } |
280 | |
281 | static void init_channel_list(struct adapter *padapter, struct rt_channel_info *channel_set, |
282 | u8 chanset_size, |
283 | struct p2p_channels *channel_list) |
284 | { |
285 | |
286 | static const struct p2p_oper_class_map op_class[] = { |
287 | { IEEE80211G, 81, 1, 13, 1, BW20 }, |
288 | { IEEE80211G, 82, 14, 14, 1, BW20 }, |
289 | { IEEE80211A, 115, 36, 48, 4, BW20 }, |
290 | { IEEE80211A, 116, 36, 44, 8, BW40PLUS }, |
291 | { IEEE80211A, 117, 40, 48, 8, BW40MINUS }, |
292 | { IEEE80211A, 124, 149, 161, 4, BW20 }, |
293 | { IEEE80211A, 125, 149, 169, 4, BW20 }, |
294 | { IEEE80211A, 126, 149, 157, 8, BW40PLUS }, |
295 | { IEEE80211A, 127, 153, 161, 8, BW40MINUS }, |
296 | { -1, 0, 0, 0, 0, BW20 } |
297 | }; |
298 | |
299 | int cla, op; |
300 | |
301 | cla = 0; |
302 | |
303 | for (op = 0; op_class[op].op_class; op++) { |
304 | u8 ch; |
305 | const struct p2p_oper_class_map *o = &op_class[op]; |
306 | struct p2p_reg_class *reg = NULL; |
307 | |
308 | for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { |
309 | if (!has_channel(channel_set, chanset_size, chan: ch)) |
310 | continue; |
311 | |
312 | if ((padapter->registrypriv.ht_enable == 0) && (o->inc == 8)) |
313 | continue; |
314 | |
315 | if ((0 < (padapter->registrypriv.bw_mode & 0xf0)) && |
316 | ((o->bw == BW40MINUS) || (o->bw == BW40PLUS))) |
317 | continue; |
318 | |
319 | if (!reg) { |
320 | reg = &channel_list->reg_class[cla]; |
321 | cla++; |
322 | reg->reg_class = o->op_class; |
323 | reg->channels = 0; |
324 | } |
325 | reg->channel[reg->channels] = ch; |
326 | reg->channels++; |
327 | } |
328 | } |
329 | channel_list->reg_classes = cla; |
330 | |
331 | } |
332 | |
333 | static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_channel_info *channel_set) |
334 | { |
335 | u8 index, chanset_size = 0; |
336 | u8 b2_4GBand = false; |
337 | u8 Index2G = 0; |
338 | |
339 | memset(channel_set, 0, sizeof(struct rt_channel_info)*MAX_CHANNEL_NUM); |
340 | |
341 | if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) |
342 | return chanset_size; |
343 | |
344 | if (is_supported_24g(padapter->registrypriv.wireless_mode)) { |
345 | b2_4GBand = true; |
346 | if (ChannelPlan == RT_CHANNEL_DOMAIN_REALTEK_DEFINE) |
347 | Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G; |
348 | else |
349 | Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G; |
350 | } |
351 | |
352 | if (b2_4GBand) { |
353 | for (index = 0; index < RTW_ChannelPlan2G[Index2G].Len; index++) { |
354 | channel_set[chanset_size].ChannelNum = RTW_ChannelPlan2G[Index2G].Channel[index]; |
355 | |
356 | if ((ChannelPlan == RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN) ||/* Channel 1~11 is active, and 12~14 is passive */ |
357 | (ChannelPlan == RT_CHANNEL_DOMAIN_GLOBAL_NULL)) { |
358 | if (channel_set[chanset_size].ChannelNum >= 1 && channel_set[chanset_size].ChannelNum <= 11) |
359 | channel_set[chanset_size].ScanType = SCAN_ACTIVE; |
360 | else if ((channel_set[chanset_size].ChannelNum >= 12 && channel_set[chanset_size].ChannelNum <= 14)) |
361 | channel_set[chanset_size].ScanType = SCAN_PASSIVE; |
362 | } else if (ChannelPlan == RT_CHANNEL_DOMAIN_WORLD_WIDE_13 || |
363 | Index2G == RT_CHANNEL_DOMAIN_2G_WORLD) { /* channel 12~13, passive scan */ |
364 | if (channel_set[chanset_size].ChannelNum <= 11) |
365 | channel_set[chanset_size].ScanType = SCAN_ACTIVE; |
366 | else |
367 | channel_set[chanset_size].ScanType = SCAN_PASSIVE; |
368 | } else |
369 | channel_set[chanset_size].ScanType = SCAN_ACTIVE; |
370 | |
371 | chanset_size++; |
372 | } |
373 | } |
374 | |
375 | return chanset_size; |
376 | } |
377 | |
378 | void init_mlme_ext_priv(struct adapter *padapter) |
379 | { |
380 | struct registry_priv *pregistrypriv = &padapter->registrypriv; |
381 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
382 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
383 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
384 | |
385 | pmlmeext->padapter = padapter; |
386 | |
387 | /* fill_fwpriv(padapter, &(pmlmeext->fwpriv)); */ |
388 | |
389 | init_mlme_ext_priv_value(padapter); |
390 | pmlmeinfo->accept_addba_req = pregistrypriv->accept_addba_req; |
391 | |
392 | init_mlme_ext_timer(padapter); |
393 | |
394 | init_mlme_ap_info(padapter); |
395 | |
396 | pmlmeext->max_chan_nums = init_channel_set(padapter, ChannelPlan: pmlmepriv->ChannelPlan, channel_set: pmlmeext->channel_set); |
397 | init_channel_list(padapter, channel_set: pmlmeext->channel_set, chanset_size: pmlmeext->max_chan_nums, channel_list: &pmlmeext->channel_list); |
398 | pmlmeext->last_scan_time = 0; |
399 | pmlmeext->chan_scan_time = SURVEY_TO; |
400 | pmlmeext->mlmeext_init = true; |
401 | pmlmeext->active_keep_alive_check = true; |
402 | |
403 | #ifdef DBG_FIXED_CHAN |
404 | pmlmeext->fixed_chan = 0xFF; |
405 | #endif |
406 | } |
407 | |
408 | void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext) |
409 | { |
410 | struct adapter *padapter = pmlmeext->padapter; |
411 | |
412 | if (!padapter) |
413 | return; |
414 | |
415 | if (padapter->bDriverStopped) { |
416 | del_timer_sync(timer: &pmlmeext->survey_timer); |
417 | del_timer_sync(timer: &pmlmeext->link_timer); |
418 | /* del_timer_sync(&pmlmeext->ADDBA_timer); */ |
419 | } |
420 | } |
421 | |
422 | static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, union recv_frame *precv_frame) |
423 | { |
424 | u8 *pframe = precv_frame->u.hdr.rx_data; |
425 | |
426 | if (ptable->func) { |
427 | /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ |
428 | if (memcmp(GetAddr1Ptr(pframe), q: myid(peepriv: &padapter->eeprompriv), ETH_ALEN) && |
429 | !is_broadcast_ether_addr(GetAddr1Ptr(pframe))) |
430 | return; |
431 | |
432 | ptable->func(padapter, precv_frame); |
433 | } |
434 | } |
435 | |
436 | void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame) |
437 | { |
438 | int index; |
439 | struct mlme_handler *ptable; |
440 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
441 | u8 *pframe = precv_frame->u.hdr.rx_data; |
442 | struct sta_info *psta = rtw_get_stainfo(pstapriv: &padapter->stapriv, GetAddr2Ptr(pframe)); |
443 | struct dvobj_priv *psdpriv = padapter->dvobj; |
444 | struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; |
445 | |
446 | if (GetFrameType(pframe) != WIFI_MGT_TYPE) |
447 | return; |
448 | |
449 | /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ |
450 | if (memcmp(GetAddr1Ptr(pframe), q: myid(peepriv: &padapter->eeprompriv), ETH_ALEN) && |
451 | !is_broadcast_ether_addr(GetAddr1Ptr(pframe))) { |
452 | return; |
453 | } |
454 | |
455 | ptable = mlme_sta_tbl; |
456 | |
457 | index = GetFrameSubType(pframe) >> 4; |
458 | |
459 | if (index >= ARRAY_SIZE(mlme_sta_tbl)) |
460 | return; |
461 | |
462 | ptable += index; |
463 | |
464 | if (psta) { |
465 | if (GetRetry(pframe)) { |
466 | if (precv_frame->u.hdr.attrib.seq_num == psta->RxMgmtFrameSeqNum) { |
467 | /* drop the duplicate management frame */ |
468 | pdbgpriv->dbg_rx_dup_mgt_frame_drop_count++; |
469 | return; |
470 | } |
471 | } |
472 | psta->RxMgmtFrameSeqNum = precv_frame->u.hdr.attrib.seq_num; |
473 | } |
474 | |
475 | switch (GetFrameSubType(pframe)) { |
476 | case WIFI_AUTH: |
477 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) |
478 | ptable->func = &OnAuth; |
479 | else |
480 | ptable->func = &OnAuthClient; |
481 | fallthrough; |
482 | case WIFI_ASSOCREQ: |
483 | case WIFI_REASSOCREQ: |
484 | _mgt_dispatcher(padapter, ptable, precv_frame); |
485 | break; |
486 | case WIFI_PROBEREQ: |
487 | _mgt_dispatcher(padapter, ptable, precv_frame); |
488 | break; |
489 | case WIFI_BEACON: |
490 | _mgt_dispatcher(padapter, ptable, precv_frame); |
491 | break; |
492 | case WIFI_ACTION: |
493 | /* if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) */ |
494 | _mgt_dispatcher(padapter, ptable, precv_frame); |
495 | break; |
496 | default: |
497 | _mgt_dispatcher(padapter, ptable, precv_frame); |
498 | break; |
499 | } |
500 | } |
501 | |
502 | /**************************************************************************** |
503 | |
504 | Following are the callback functions for each subtype of the management frames |
505 | |
506 | *****************************************************************************/ |
507 | |
508 | unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame) |
509 | { |
510 | unsigned int ielen; |
511 | unsigned char *p; |
512 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
513 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
514 | struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; |
515 | struct wlan_bssid_ex *cur = &pmlmeinfo->network; |
516 | u8 *pframe = precv_frame->u.hdr.rx_data; |
517 | uint len = precv_frame->u.hdr.len; |
518 | u8 is_valid_p2p_probereq = false; |
519 | |
520 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) |
521 | return _SUCCESS; |
522 | |
523 | if (check_fwstate(pmlmepriv, _FW_LINKED) == false && |
524 | check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE) == false) { |
525 | return _SUCCESS; |
526 | } |
527 | |
528 | p = rtw_get_ie(pbuf: pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, index: WLAN_EID_SSID, len: (int *)&ielen, |
529 | limit: len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); |
530 | |
531 | |
532 | /* check (wildcard) SSID */ |
533 | if (p) { |
534 | if (is_valid_p2p_probereq) |
535 | goto _issue_probersp; |
536 | |
537 | if ((ielen != 0 && false == !memcmp(p: (void *)(p+2), q: (void *)cur->ssid.ssid, size: cur->ssid.ssid_length)) |
538 | || (ielen == 0 && pmlmeinfo->hidden_ssid_mode) |
539 | ) |
540 | return _SUCCESS; |
541 | |
542 | _issue_probersp: |
543 | if ((check_fwstate(pmlmepriv, _FW_LINKED) && |
544 | pmlmepriv->cur_network.join_res) || |
545 | check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) |
546 | issue_probersp(padapter, da: get_sa(pframe), is_valid_p2p_probereq); |
547 | } |
548 | |
549 | return _SUCCESS; |
550 | |
551 | } |
552 | |
553 | unsigned int OnProbeRsp(struct adapter *padapter, union recv_frame *precv_frame) |
554 | { |
555 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
556 | |
557 | if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { |
558 | report_survey_event(padapter, precv_frame); |
559 | return _SUCCESS; |
560 | } |
561 | |
562 | return _SUCCESS; |
563 | |
564 | } |
565 | |
566 | unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame) |
567 | { |
568 | int cam_idx; |
569 | struct sta_info *psta; |
570 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
571 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
572 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
573 | struct sta_priv *pstapriv = &padapter->stapriv; |
574 | u8 *pframe = precv_frame->u.hdr.rx_data; |
575 | uint len = precv_frame->u.hdr.len; |
576 | struct wlan_bssid_ex *pbss; |
577 | int ret = _SUCCESS; |
578 | u8 *p = NULL; |
579 | u32 ielen = 0; |
580 | |
581 | p = rtw_get_ie(pbuf: pframe + sizeof(struct ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, index: WLAN_EID_EXT_SUPP_RATES, len: &ielen, limit: precv_frame->u.hdr.len - sizeof(struct ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_); |
582 | if (p && ielen > 0) { |
583 | if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) |
584 | /* Invalid value 0x2D is detected in Extended Supported Rates (ESR) IE. Try to fix the IE length to avoid failed Beacon parsing. */ |
585 | *(p + 1) = ielen - 1; |
586 | } |
587 | |
588 | if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { |
589 | report_survey_event(padapter, precv_frame); |
590 | return _SUCCESS; |
591 | } |
592 | |
593 | if (!memcmp(GetAddr3Ptr(pframe), q: get_my_bssid(pnetwork: &pmlmeinfo->network), ETH_ALEN)) { |
594 | if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { |
595 | /* we should update current network before auth, or some IE is wrong */ |
596 | pbss = rtw_malloc(sizeof(struct wlan_bssid_ex)); |
597 | if (pbss) { |
598 | if (collect_bss_info(padapter, precv_frame, bssid: pbss) == _SUCCESS) { |
599 | update_network(dst: &(pmlmepriv->cur_network.network), src: pbss, padapter, update_ie: true); |
600 | rtw_get_bcn_info(pnetwork: &(pmlmepriv->cur_network)); |
601 | } |
602 | kfree(objp: pbss); |
603 | } |
604 | |
605 | /* check the vendor of the assoc AP */ |
606 | pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe: pframe+sizeof(struct ieee80211_hdr_3addr), len: len-sizeof(struct ieee80211_hdr_3addr)); |
607 | |
608 | /* update TSF Value */ |
609 | update_TSF(pmlmeext, pframe, len); |
610 | |
611 | /* reset for adaptive_early_32k */ |
612 | pmlmeext->adaptive_tsf_done = false; |
613 | pmlmeext->DrvBcnEarly = 0xff; |
614 | pmlmeext->DrvBcnTimeOut = 0xff; |
615 | pmlmeext->bcn_cnt = 0; |
616 | memset(pmlmeext->bcn_delay_cnt, 0, sizeof(pmlmeext->bcn_delay_cnt)); |
617 | memset(pmlmeext->bcn_delay_ratio, 0, sizeof(pmlmeext->bcn_delay_ratio)); |
618 | |
619 | /* start auth */ |
620 | start_clnt_auth(padapter); |
621 | |
622 | return _SUCCESS; |
623 | } |
624 | |
625 | if (((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { |
626 | psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); |
627 | if (psta) { |
628 | ret = rtw_check_bcn_info(Adapter: padapter, pframe, packet_len: len); |
629 | if (!ret) { |
630 | netdev_dbg(padapter->pnetdev, |
631 | "ap has changed, disconnect now\n " ); |
632 | receive_disconnect(padapter, |
633 | MacAddr: pmlmeinfo->network.mac_address, reason: 0); |
634 | return _SUCCESS; |
635 | } |
636 | /* update WMM, ERP in the beacon */ |
637 | /* todo: the timer is used instead of the number of the beacon received */ |
638 | if ((sta_rx_pkts(psta) & 0xf) == 0) |
639 | update_beacon_info(padapter, pframe, len, psta); |
640 | |
641 | adaptive_early_32k(pmlmeext, pframe, len); |
642 | } |
643 | } else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { |
644 | psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); |
645 | if (psta) { |
646 | /* update WMM, ERP in the beacon */ |
647 | /* todo: the timer is used instead of the number of the beacon received */ |
648 | if ((sta_rx_pkts(psta) & 0xf) == 0) |
649 | update_beacon_info(padapter, pframe, len, psta); |
650 | } else { |
651 | /* allocate a new CAM entry for IBSS station */ |
652 | cam_idx = allocate_fw_sta_entry(padapter); |
653 | if (cam_idx == NUM_STA) |
654 | goto _END_ONBEACON_; |
655 | |
656 | /* get supported rate */ |
657 | if (update_sta_support_rate(padapter, pvar_ie: (pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_), var_ie_len: (len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) { |
658 | pmlmeinfo->FW_sta_info[cam_idx].status = 0; |
659 | goto _END_ONBEACON_; |
660 | } |
661 | |
662 | /* update TSF Value */ |
663 | update_TSF(pmlmeext, pframe, len); |
664 | |
665 | /* report sta add event */ |
666 | report_add_sta_event(padapter, GetAddr2Ptr(pframe), cam_idx); |
667 | } |
668 | } |
669 | } |
670 | |
671 | _END_ONBEACON_: |
672 | |
673 | return _SUCCESS; |
674 | |
675 | } |
676 | |
677 | unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) |
678 | { |
679 | unsigned int auth_mode, seq, ie_len; |
680 | unsigned char *sa, *p; |
681 | u16 algorithm; |
682 | int status; |
683 | static struct sta_info stat; |
684 | struct sta_info *pstat = NULL; |
685 | struct sta_priv *pstapriv = &padapter->stapriv; |
686 | struct security_priv *psecuritypriv = &padapter->securitypriv; |
687 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
688 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
689 | u8 *pframe = precv_frame->u.hdr.rx_data; |
690 | uint len = precv_frame->u.hdr.len; |
691 | u8 offset = 0; |
692 | |
693 | if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) |
694 | return _FAIL; |
695 | |
696 | sa = GetAddr2Ptr(pframe); |
697 | |
698 | auth_mode = psecuritypriv->dot11AuthAlgrthm; |
699 | |
700 | if (GetPrivacy(pframe)) { |
701 | u8 *iv; |
702 | struct rx_pkt_attrib *prxattrib = &(precv_frame->u.hdr.attrib); |
703 | |
704 | prxattrib->hdrlen = WLAN_HDR_A3_LEN; |
705 | prxattrib->encrypt = _WEP40_; |
706 | |
707 | iv = pframe+prxattrib->hdrlen; |
708 | prxattrib->key_index = ((iv[3]>>6)&0x3); |
709 | |
710 | prxattrib->iv_len = 4; |
711 | prxattrib->icv_len = 4; |
712 | |
713 | rtw_wep_decrypt(padapter, precvframe: (u8 *)precv_frame); |
714 | |
715 | offset = 4; |
716 | } |
717 | |
718 | algorithm = le16_to_cpu(*(__le16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset)); |
719 | seq = le16_to_cpu(*(__le16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2)); |
720 | |
721 | if (auth_mode == 2 && |
722 | psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ && |
723 | psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) |
724 | auth_mode = 0; |
725 | |
726 | if ((algorithm > 0 && auth_mode == 0) || /* rx a shared-key auth but shared not enabled */ |
727 | (algorithm == 0 && auth_mode == 1)) { /* rx a open-system auth but shared-key is enabled */ |
728 | |
729 | status = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; |
730 | |
731 | goto auth_fail; |
732 | } |
733 | |
734 | if (rtw_access_ctrl(padapter, mac_addr: sa) == false) { |
735 | status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; |
736 | goto auth_fail; |
737 | } |
738 | |
739 | pstat = rtw_get_stainfo(pstapriv, hwaddr: sa); |
740 | if (!pstat) { |
741 | |
742 | /* allocate a new one */ |
743 | pstat = rtw_alloc_stainfo(pstapriv, hwaddr: sa); |
744 | if (!pstat) { |
745 | status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; |
746 | goto auth_fail; |
747 | } |
748 | |
749 | pstat->state = WIFI_FW_AUTH_NULL; |
750 | pstat->auth_seq = 0; |
751 | |
752 | /* pstat->flags = 0; */ |
753 | /* pstat->capability = 0; */ |
754 | } else { |
755 | |
756 | spin_lock_bh(lock: &pstapriv->asoc_list_lock); |
757 | if (list_empty(head: &pstat->asoc_list) == false) { |
758 | list_del_init(entry: &pstat->asoc_list); |
759 | pstapriv->asoc_list_cnt--; |
760 | if (pstat->expire_to > 0) { |
761 | /* TODO: STA re_auth within expire_to */ |
762 | } |
763 | } |
764 | spin_unlock_bh(lock: &pstapriv->asoc_list_lock); |
765 | |
766 | if (seq == 1) { |
767 | /* TODO: STA re_auth and auth timeout */ |
768 | } |
769 | } |
770 | |
771 | spin_lock_bh(lock: &pstapriv->auth_list_lock); |
772 | if (list_empty(head: &pstat->auth_list)) { |
773 | |
774 | list_add_tail(new: &pstat->auth_list, head: &pstapriv->auth_list); |
775 | pstapriv->auth_list_cnt++; |
776 | } |
777 | spin_unlock_bh(lock: &pstapriv->auth_list_lock); |
778 | |
779 | if (pstat->auth_seq == 0) |
780 | pstat->expire_to = pstapriv->auth_to; |
781 | |
782 | |
783 | if ((pstat->auth_seq + 1) != seq) { |
784 | status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; |
785 | goto auth_fail; |
786 | } |
787 | |
788 | if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2 || auth_mode == 3)) { |
789 | if (seq == 1) { |
790 | pstat->state &= ~WIFI_FW_AUTH_NULL; |
791 | pstat->state |= WIFI_FW_AUTH_SUCCESS; |
792 | pstat->expire_to = pstapriv->assoc_to; |
793 | pstat->authalg = algorithm; |
794 | } else { |
795 | status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; |
796 | goto auth_fail; |
797 | } |
798 | } else { /* shared system or auto authentication */ |
799 | if (seq == 1) { |
800 | /* prepare for the challenging txt... */ |
801 | memset((void *)pstat->chg_txt, 78, 128); |
802 | |
803 | pstat->state &= ~WIFI_FW_AUTH_NULL; |
804 | pstat->state |= WIFI_FW_AUTH_STATE; |
805 | pstat->authalg = algorithm; |
806 | } else if (seq == 3) { |
807 | |
808 | p = rtw_get_ie(pbuf: pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_, index: WLAN_EID_CHALLENGE, len: (int *)&ie_len, |
809 | limit: len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4); |
810 | |
811 | if (!p || ie_len <= 0) { |
812 | status = WLAN_STATUS_CHALLENGE_FAIL; |
813 | goto auth_fail; |
814 | } |
815 | |
816 | if (!memcmp(p: (void *)(p + 2), q: pstat->chg_txt, size: 128)) { |
817 | pstat->state &= (~WIFI_FW_AUTH_STATE); |
818 | pstat->state |= WIFI_FW_AUTH_SUCCESS; |
819 | /* challenging txt is correct... */ |
820 | pstat->expire_to = pstapriv->assoc_to; |
821 | } else { |
822 | status = WLAN_STATUS_CHALLENGE_FAIL; |
823 | goto auth_fail; |
824 | } |
825 | } else { |
826 | status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; |
827 | goto auth_fail; |
828 | } |
829 | } |
830 | |
831 | |
832 | /* Now, we are going to issue_auth... */ |
833 | pstat->auth_seq = seq + 1; |
834 | |
835 | issue_auth(padapter, psta: pstat, status: (unsigned short)(WLAN_STATUS_SUCCESS)); |
836 | |
837 | if (pstat->state & WIFI_FW_AUTH_SUCCESS) |
838 | pstat->auth_seq = 0; |
839 | |
840 | |
841 | return _SUCCESS; |
842 | |
843 | auth_fail: |
844 | |
845 | if (pstat) |
846 | rtw_free_stainfo(padapter, psta: pstat); |
847 | |
848 | pstat = &stat; |
849 | memset((char *)pstat, '\0', sizeof(stat)); |
850 | pstat->auth_seq = 2; |
851 | memcpy(pstat->hwaddr, sa, 6); |
852 | |
853 | issue_auth(padapter, psta: pstat, status: (unsigned short)status); |
854 | |
855 | return _FAIL; |
856 | |
857 | } |
858 | |
859 | unsigned int OnAuthClient(struct adapter *padapter, union recv_frame *precv_frame) |
860 | { |
861 | unsigned int seq, len, status, offset; |
862 | unsigned char *p; |
863 | unsigned int go2asoc = 0; |
864 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
865 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
866 | u8 *pframe = precv_frame->u.hdr.rx_data; |
867 | uint pkt_len = precv_frame->u.hdr.len; |
868 | |
869 | /* check A1 matches or not */ |
870 | if (memcmp(p: myid(peepriv: &(padapter->eeprompriv)), q: get_da(pframe), ETH_ALEN)) |
871 | return _SUCCESS; |
872 | |
873 | if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) |
874 | return _SUCCESS; |
875 | |
876 | offset = (GetPrivacy(pframe)) ? 4 : 0; |
877 | |
878 | seq = le16_to_cpu(*(__le16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2)); |
879 | status = le16_to_cpu(*(__le16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 4)); |
880 | |
881 | if (status != 0) { |
882 | if (status == 13) { /* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ |
883 | if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) |
884 | pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; |
885 | else |
886 | pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; |
887 | /* pmlmeinfo->reauth_count = 0; */ |
888 | } |
889 | |
890 | set_link_timer(pmlmeext, 1); |
891 | goto authclnt_fail; |
892 | } |
893 | |
894 | if (seq == 2) { |
895 | if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) { |
896 | /* legendary shared system */ |
897 | p = rtw_get_ie(pbuf: pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, index: WLAN_EID_CHALLENGE, len: (int *)&len, |
898 | limit: pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_); |
899 | |
900 | if (!p) |
901 | goto authclnt_fail; |
902 | |
903 | memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); |
904 | pmlmeinfo->auth_seq = 3; |
905 | issue_auth(padapter, NULL, status: 0); |
906 | set_link_timer(pmlmeext, REAUTH_TO); |
907 | |
908 | return _SUCCESS; |
909 | } |
910 | /* open system */ |
911 | go2asoc = 1; |
912 | } else if (seq == 4) { |
913 | if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) |
914 | go2asoc = 1; |
915 | else |
916 | goto authclnt_fail; |
917 | } else { |
918 | /* this is also illegal */ |
919 | goto authclnt_fail; |
920 | } |
921 | |
922 | if (go2asoc) { |
923 | netdev_dbg(padapter->pnetdev, "auth success, start assoc\n" ); |
924 | start_clnt_assoc(padapter); |
925 | return _SUCCESS; |
926 | } |
927 | |
928 | authclnt_fail: |
929 | |
930 | /* pmlmeinfo->state &= ~(WIFI_FW_AUTH_STATE); */ |
931 | |
932 | return _FAIL; |
933 | |
934 | } |
935 | |
936 | unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) |
937 | { |
938 | u16 capab_info; |
939 | struct rtw_ieee802_11_elems elems; |
940 | struct sta_info *pstat; |
941 | unsigned char *p, *pos, *wpa_ie; |
942 | unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; |
943 | int i, ie_len, wpa_ie_len, left; |
944 | unsigned char supportRate[16]; |
945 | int supportRateNum; |
946 | unsigned short status = WLAN_STATUS_SUCCESS; |
947 | unsigned short frame_type, ie_offset = 0; |
948 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
949 | struct security_priv *psecuritypriv = &padapter->securitypriv; |
950 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
951 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
952 | struct wlan_bssid_ex *cur = &(pmlmeinfo->network); |
953 | struct sta_priv *pstapriv = &padapter->stapriv; |
954 | u8 *pframe = precv_frame->u.hdr.rx_data; |
955 | uint pkt_len = precv_frame->u.hdr.len; |
956 | |
957 | if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) |
958 | return _FAIL; |
959 | |
960 | frame_type = GetFrameSubType(pframe); |
961 | if (frame_type == WIFI_ASSOCREQ) |
962 | ie_offset = _ASOCREQ_IE_OFFSET_; |
963 | else /* WIFI_REASSOCREQ */ |
964 | ie_offset = _REASOCREQ_IE_OFFSET_; |
965 | |
966 | |
967 | if (pkt_len < sizeof(struct ieee80211_hdr_3addr) + ie_offset) |
968 | return _FAIL; |
969 | |
970 | pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); |
971 | if (!pstat) { |
972 | status = WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA; |
973 | goto asoc_class2_error; |
974 | } |
975 | |
976 | capab_info = get_unaligned_le16(p: pframe + WLAN_HDR_A3_LEN); |
977 | /* capab_info = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN)); */ |
978 | |
979 | left = pkt_len - (sizeof(struct ieee80211_hdr_3addr) + ie_offset); |
980 | pos = pframe + (sizeof(struct ieee80211_hdr_3addr) + ie_offset); |
981 | |
982 | /* check if this stat has been successfully authenticated/assocated */ |
983 | if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) { |
984 | if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) { |
985 | status = WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA; |
986 | goto asoc_class2_error; |
987 | } else { |
988 | pstat->state &= (~WIFI_FW_ASSOC_SUCCESS); |
989 | pstat->state |= WIFI_FW_ASSOC_STATE; |
990 | } |
991 | } else { |
992 | pstat->state &= (~WIFI_FW_AUTH_SUCCESS); |
993 | pstat->state |= WIFI_FW_ASSOC_STATE; |
994 | } |
995 | |
996 | |
997 | pstat->capability = capab_info; |
998 | |
999 | /* now parse all ieee802_11 ie to point to elems */ |
1000 | if (rtw_ieee802_11_parse_elems(start: pos, len: left, elems: &elems, show_errors: 1) == ParseFailed || |
1001 | !elems.ssid) { |
1002 | status = WLAN_STATUS_CHALLENGE_FAIL; |
1003 | goto OnAssocReqFail; |
1004 | } |
1005 | |
1006 | /* now we should check all the fields... */ |
1007 | /* checking SSID */ |
1008 | p = rtw_get_ie(pbuf: pframe + WLAN_HDR_A3_LEN + ie_offset, index: WLAN_EID_SSID, len: &ie_len, |
1009 | limit: pkt_len - WLAN_HDR_A3_LEN - ie_offset); |
1010 | |
1011 | if (!p || ie_len == 0) { |
1012 | /* broadcast ssid, however it is not allowed in assocreq */ |
1013 | status = WLAN_STATUS_CHALLENGE_FAIL; |
1014 | goto OnAssocReqFail; |
1015 | } else { |
1016 | /* check if ssid match */ |
1017 | if (memcmp(p: (void *)(p+2), q: cur->ssid.ssid, size: cur->ssid.ssid_length)) |
1018 | status = WLAN_STATUS_CHALLENGE_FAIL; |
1019 | |
1020 | if (ie_len != cur->ssid.ssid_length) |
1021 | status = WLAN_STATUS_CHALLENGE_FAIL; |
1022 | } |
1023 | |
1024 | if (status != WLAN_STATUS_SUCCESS) |
1025 | goto OnAssocReqFail; |
1026 | |
1027 | /* check if the supported rate is ok */ |
1028 | p = rtw_get_ie(pbuf: pframe + WLAN_HDR_A3_LEN + ie_offset, index: WLAN_EID_SUPP_RATES, len: &ie_len, limit: pkt_len - WLAN_HDR_A3_LEN - ie_offset); |
1029 | if (!p) { |
1030 | /* use our own rate set as statoin used */ |
1031 | /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */ |
1032 | /* supportRateNum = AP_BSSRATE_LEN; */ |
1033 | |
1034 | status = WLAN_STATUS_CHALLENGE_FAIL; |
1035 | goto OnAssocReqFail; |
1036 | } else { |
1037 | memcpy(supportRate, p+2, ie_len); |
1038 | supportRateNum = ie_len; |
1039 | |
1040 | p = rtw_get_ie(pbuf: pframe + WLAN_HDR_A3_LEN + ie_offset, index: WLAN_EID_EXT_SUPP_RATES, len: &ie_len, |
1041 | limit: pkt_len - WLAN_HDR_A3_LEN - ie_offset); |
1042 | if (p) { |
1043 | |
1044 | if (supportRateNum <= sizeof(supportRate)) { |
1045 | memcpy(supportRate+supportRateNum, p+2, ie_len); |
1046 | supportRateNum += ie_len; |
1047 | } |
1048 | } |
1049 | } |
1050 | |
1051 | /* todo: mask supportRate between AP & STA -> move to update raid */ |
1052 | /* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */ |
1053 | |
1054 | /* update station supportRate */ |
1055 | pstat->bssratelen = supportRateNum; |
1056 | memcpy(pstat->bssrateset, supportRate, supportRateNum); |
1057 | UpdateBrateTblForSoftAP(bssrateset: pstat->bssrateset, bssratelen: pstat->bssratelen); |
1058 | |
1059 | /* check RSN/WPA/WPS */ |
1060 | pstat->dot8021xalg = 0; |
1061 | pstat->wpa_psk = 0; |
1062 | pstat->wpa_group_cipher = 0; |
1063 | pstat->wpa2_group_cipher = 0; |
1064 | pstat->wpa_pairwise_cipher = 0; |
1065 | pstat->wpa2_pairwise_cipher = 0; |
1066 | memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie)); |
1067 | if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) { |
1068 | |
1069 | int group_cipher = 0, pairwise_cipher = 0; |
1070 | |
1071 | wpa_ie = elems.rsn_ie; |
1072 | wpa_ie_len = elems.rsn_ie_len; |
1073 | |
1074 | if (rtw_parse_wpa2_ie(wpa_ie: wpa_ie-2, wpa_ie_len: wpa_ie_len+2, group_cipher: &group_cipher, pairwise_cipher: &pairwise_cipher, NULL) == _SUCCESS) { |
1075 | pstat->dot8021xalg = 1;/* psk, todo:802.1x */ |
1076 | pstat->wpa_psk |= BIT(1); |
1077 | |
1078 | pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher; |
1079 | pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher; |
1080 | |
1081 | if (!pstat->wpa2_group_cipher) |
1082 | status = WLAN_STATUS_INVALID_GROUP_CIPHER; |
1083 | |
1084 | if (!pstat->wpa2_pairwise_cipher) |
1085 | status = WLAN_STATUS_INVALID_PAIRWISE_CIPHER; |
1086 | } else { |
1087 | status = WLAN_STATUS_INVALID_IE; |
1088 | } |
1089 | |
1090 | } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) { |
1091 | |
1092 | int group_cipher = 0, pairwise_cipher = 0; |
1093 | |
1094 | wpa_ie = elems.wpa_ie; |
1095 | wpa_ie_len = elems.wpa_ie_len; |
1096 | |
1097 | if (rtw_parse_wpa_ie(wpa_ie: wpa_ie-2, wpa_ie_len: wpa_ie_len+2, group_cipher: &group_cipher, pairwise_cipher: &pairwise_cipher, NULL) == _SUCCESS) { |
1098 | pstat->dot8021xalg = 1;/* psk, todo:802.1x */ |
1099 | pstat->wpa_psk |= BIT(0); |
1100 | |
1101 | pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher; |
1102 | pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher; |
1103 | |
1104 | if (!pstat->wpa_group_cipher) |
1105 | status = WLAN_STATUS_INVALID_GROUP_CIPHER; |
1106 | |
1107 | if (!pstat->wpa_pairwise_cipher) |
1108 | status = WLAN_STATUS_INVALID_PAIRWISE_CIPHER; |
1109 | |
1110 | } else { |
1111 | status = WLAN_STATUS_INVALID_IE; |
1112 | } |
1113 | |
1114 | } else { |
1115 | wpa_ie = NULL; |
1116 | wpa_ie_len = 0; |
1117 | } |
1118 | |
1119 | if (status != WLAN_STATUS_SUCCESS) |
1120 | goto OnAssocReqFail; |
1121 | |
1122 | pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); |
1123 | if (!wpa_ie) { |
1124 | if (elems.wps_ie) { |
1125 | pstat->flags |= WLAN_STA_WPS; |
1126 | /* wpabuf_free(sta->wps_ie); */ |
1127 | /* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */ |
1128 | /* elems.wps_ie_len - 4); */ |
1129 | } else { |
1130 | pstat->flags |= WLAN_STA_MAYBE_WPS; |
1131 | } |
1132 | |
1133 | |
1134 | /* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */ |
1135 | /* that the selected registrar of AP is _FLASE */ |
1136 | if ((psecuritypriv->wpa_psk > 0) |
1137 | && (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) { |
1138 | if (pmlmepriv->wps_beacon_ie) { |
1139 | u8 selected_registrar = 0; |
1140 | |
1141 | rtw_get_wps_attr_content(wps_ie: pmlmepriv->wps_beacon_ie, wps_ielen: pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR, buf_content: &selected_registrar, NULL); |
1142 | |
1143 | if (!selected_registrar) { |
1144 | status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; |
1145 | |
1146 | goto OnAssocReqFail; |
1147 | } |
1148 | } |
1149 | } |
1150 | |
1151 | } else { |
1152 | int copy_len; |
1153 | |
1154 | if (psecuritypriv->wpa_psk == 0) { |
1155 | status = WLAN_STATUS_INVALID_IE; |
1156 | |
1157 | goto OnAssocReqFail; |
1158 | |
1159 | } |
1160 | |
1161 | if (elems.wps_ie) { |
1162 | pstat->flags |= WLAN_STA_WPS; |
1163 | copy_len = 0; |
1164 | } else { |
1165 | copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)):(wpa_ie_len+2); |
1166 | } |
1167 | |
1168 | |
1169 | if (copy_len > 0) |
1170 | memcpy(pstat->wpa_ie, wpa_ie-2, copy_len); |
1171 | |
1172 | } |
1173 | |
1174 | |
1175 | /* check if there is WMM IE & support WWM-PS */ |
1176 | pstat->flags &= ~WLAN_STA_WME; |
1177 | pstat->qos_option = 0; |
1178 | pstat->qos_info = 0; |
1179 | pstat->has_legacy_ac = true; |
1180 | pstat->uapsd_vo = 0; |
1181 | pstat->uapsd_vi = 0; |
1182 | pstat->uapsd_be = 0; |
1183 | pstat->uapsd_bk = 0; |
1184 | if (pmlmepriv->qospriv.qos_option) { |
1185 | p = pframe + WLAN_HDR_A3_LEN + ie_offset; ie_len = 0; |
1186 | for (;;) { |
1187 | p = rtw_get_ie(pbuf: p, index: WLAN_EID_VENDOR_SPECIFIC, len: &ie_len, limit: pkt_len - WLAN_HDR_A3_LEN - ie_offset); |
1188 | if (p) { |
1189 | if (!memcmp(p: p+2, q: WMM_IE, size: 6)) { |
1190 | |
1191 | pstat->flags |= WLAN_STA_WME; |
1192 | |
1193 | pstat->qos_option = 1; |
1194 | pstat->qos_info = *(p+8); |
1195 | |
1196 | pstat->max_sp_len = (pstat->qos_info>>5)&0x3; |
1197 | |
1198 | if ((pstat->qos_info&0xf) != 0xf) |
1199 | pstat->has_legacy_ac = true; |
1200 | else |
1201 | pstat->has_legacy_ac = false; |
1202 | |
1203 | if (pstat->qos_info&0xf) { |
1204 | if (pstat->qos_info&BIT(0)) |
1205 | pstat->uapsd_vo = BIT(0)|BIT(1); |
1206 | else |
1207 | pstat->uapsd_vo = 0; |
1208 | |
1209 | if (pstat->qos_info&BIT(1)) |
1210 | pstat->uapsd_vi = BIT(0)|BIT(1); |
1211 | else |
1212 | pstat->uapsd_vi = 0; |
1213 | |
1214 | if (pstat->qos_info&BIT(2)) |
1215 | pstat->uapsd_bk = BIT(0)|BIT(1); |
1216 | else |
1217 | pstat->uapsd_bk = 0; |
1218 | |
1219 | if (pstat->qos_info&BIT(3)) |
1220 | pstat->uapsd_be = BIT(0)|BIT(1); |
1221 | else |
1222 | pstat->uapsd_be = 0; |
1223 | |
1224 | } |
1225 | |
1226 | break; |
1227 | } |
1228 | } else { |
1229 | break; |
1230 | } |
1231 | p = p + ie_len + 2; |
1232 | } |
1233 | } |
1234 | |
1235 | /* save HT capabilities in the sta object */ |
1236 | memset(&pstat->htpriv.ht_cap, 0, sizeof(struct ieee80211_ht_cap)); |
1237 | if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct ieee80211_ht_cap)) { |
1238 | pstat->flags |= WLAN_STA_HT; |
1239 | |
1240 | pstat->flags |= WLAN_STA_WME; |
1241 | |
1242 | memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct ieee80211_ht_cap)); |
1243 | |
1244 | } else |
1245 | pstat->flags &= ~WLAN_STA_HT; |
1246 | |
1247 | |
1248 | if ((pmlmepriv->htpriv.ht_option == false) && (pstat->flags&WLAN_STA_HT)) { |
1249 | status = WLAN_STATUS_CHALLENGE_FAIL; |
1250 | goto OnAssocReqFail; |
1251 | } |
1252 | |
1253 | |
1254 | if ((pstat->flags & WLAN_STA_HT) && |
1255 | ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || |
1256 | (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) { |
1257 | /* status = WLAN_STATUS_CIPHER_SUITE_REJECTED; */ |
1258 | /* goto OnAssocReqFail; */ |
1259 | } |
1260 | pstat->flags |= WLAN_STA_NONERP; |
1261 | for (i = 0; i < pstat->bssratelen; i++) { |
1262 | if ((pstat->bssrateset[i] & 0x7f) > 22) { |
1263 | pstat->flags &= ~WLAN_STA_NONERP; |
1264 | break; |
1265 | } |
1266 | } |
1267 | |
1268 | if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) |
1269 | pstat->flags |= WLAN_STA_SHORT_PREAMBLE; |
1270 | else |
1271 | pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE; |
1272 | |
1273 | |
1274 | |
1275 | if (status != WLAN_STATUS_SUCCESS) |
1276 | goto OnAssocReqFail; |
1277 | |
1278 | /* TODO: identify_proprietary_vendor_ie(); */ |
1279 | /* Realtek proprietary IE */ |
1280 | /* identify if this is Broadcom sta */ |
1281 | /* identify if this is ralink sta */ |
1282 | /* Customer proprietary IE */ |
1283 | |
1284 | |
1285 | |
1286 | /* get a unique AID */ |
1287 | if (pstat->aid == 0) { |
1288 | for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++) |
1289 | if (!pstapriv->sta_aid[pstat->aid - 1]) |
1290 | break; |
1291 | |
1292 | /* if (pstat->aid > NUM_STA) { */ |
1293 | if (pstat->aid > pstapriv->max_num_sta) { |
1294 | |
1295 | pstat->aid = 0; |
1296 | |
1297 | status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; |
1298 | |
1299 | goto OnAssocReqFail; |
1300 | |
1301 | |
1302 | } else { |
1303 | pstapriv->sta_aid[pstat->aid - 1] = pstat; |
1304 | } |
1305 | } |
1306 | |
1307 | |
1308 | pstat->state &= (~WIFI_FW_ASSOC_STATE); |
1309 | pstat->state |= WIFI_FW_ASSOC_SUCCESS; |
1310 | |
1311 | spin_lock_bh(lock: &pstapriv->auth_list_lock); |
1312 | if (!list_empty(head: &pstat->auth_list)) { |
1313 | list_del_init(entry: &pstat->auth_list); |
1314 | pstapriv->auth_list_cnt--; |
1315 | } |
1316 | spin_unlock_bh(lock: &pstapriv->auth_list_lock); |
1317 | |
1318 | spin_lock_bh(lock: &pstapriv->asoc_list_lock); |
1319 | if (list_empty(head: &pstat->asoc_list)) { |
1320 | pstat->expire_to = pstapriv->expire_to; |
1321 | list_add_tail(new: &pstat->asoc_list, head: &pstapriv->asoc_list); |
1322 | pstapriv->asoc_list_cnt++; |
1323 | } |
1324 | spin_unlock_bh(lock: &pstapriv->asoc_list_lock); |
1325 | |
1326 | /* now the station is qualified to join our BSS... */ |
1327 | if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (status == WLAN_STATUS_SUCCESS)) { |
1328 | /* 1 bss_cap_update & sta_info_update */ |
1329 | bss_cap_update_on_sta_join(padapter, psta: pstat); |
1330 | sta_info_update(padapter, psta: pstat); |
1331 | |
1332 | /* 2 issue assoc rsp before notify station join event. */ |
1333 | if (frame_type == WIFI_ASSOCREQ) |
1334 | issue_asocrsp(padapter, status, pstat, pkt_type: WIFI_ASSOCRSP); |
1335 | else |
1336 | issue_asocrsp(padapter, status, pstat, pkt_type: WIFI_REASSOCRSP); |
1337 | |
1338 | spin_lock_bh(lock: &pstat->lock); |
1339 | kfree(objp: pstat->passoc_req); |
1340 | pstat->assoc_req_len = 0; |
1341 | pstat->passoc_req = rtw_zmalloc(pkt_len); |
1342 | if (pstat->passoc_req) { |
1343 | memcpy(pstat->passoc_req, pframe, pkt_len); |
1344 | pstat->assoc_req_len = pkt_len; |
1345 | } |
1346 | spin_unlock_bh(lock: &pstat->lock); |
1347 | |
1348 | /* 3-(1) report sta add event */ |
1349 | report_add_sta_event(padapter, MacAddr: pstat->hwaddr, cam_idx: pstat->aid); |
1350 | } |
1351 | |
1352 | return _SUCCESS; |
1353 | |
1354 | asoc_class2_error: |
1355 | |
1356 | issue_deauth(padapter, da: (void *)GetAddr2Ptr(pframe), reason: status); |
1357 | |
1358 | return _FAIL; |
1359 | |
1360 | OnAssocReqFail: |
1361 | |
1362 | pstat->aid = 0; |
1363 | if (frame_type == WIFI_ASSOCREQ) |
1364 | issue_asocrsp(padapter, status, pstat, pkt_type: WIFI_ASSOCRSP); |
1365 | else |
1366 | issue_asocrsp(padapter, status, pstat, pkt_type: WIFI_REASSOCRSP); |
1367 | |
1368 | return _FAIL; |
1369 | } |
1370 | |
1371 | unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame) |
1372 | { |
1373 | uint i; |
1374 | int res; |
1375 | unsigned short status; |
1376 | struct ndis_80211_var_ie *pIE; |
1377 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
1378 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1379 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
1380 | /* struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); */ |
1381 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1382 | uint pkt_len = precv_frame->u.hdr.len; |
1383 | |
1384 | /* check A1 matches or not */ |
1385 | if (memcmp(p: myid(peepriv: &(padapter->eeprompriv)), q: get_da(pframe), ETH_ALEN)) |
1386 | return _SUCCESS; |
1387 | |
1388 | if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) |
1389 | return _SUCCESS; |
1390 | |
1391 | if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) |
1392 | return _SUCCESS; |
1393 | |
1394 | del_timer_sync(timer: &pmlmeext->link_timer); |
1395 | |
1396 | /* status */ |
1397 | status = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 2)); |
1398 | if (status > 0) { |
1399 | pmlmeinfo->state = WIFI_FW_NULL_STATE; |
1400 | res = -4; |
1401 | goto report_assoc_result; |
1402 | } |
1403 | |
1404 | /* get capabilities */ |
1405 | pmlmeinfo->capability = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); |
1406 | |
1407 | /* set slot time */ |
1408 | pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10)) ? 9 : 20; |
1409 | |
1410 | /* AID */ |
1411 | res = pmlmeinfo->aid = (int)(le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 4))&0x3fff); |
1412 | |
1413 | /* following are moved to join event callback function */ |
1414 | /* to handle HT, WMM, rate adaptive, update MAC reg */ |
1415 | /* for not to handle the synchronous IO in the tasklet */ |
1416 | for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) { |
1417 | pIE = (struct ndis_80211_var_ie *)(pframe + i); |
1418 | |
1419 | switch (pIE->element_id) { |
1420 | case WLAN_EID_VENDOR_SPECIFIC: |
1421 | if (!memcmp(p: pIE->data, q: WMM_PARA_OUI, size: 6)) /* WMM */ |
1422 | WMM_param_handler(padapter, pIE); |
1423 | break; |
1424 | |
1425 | case WLAN_EID_HT_CAPABILITY: /* HT caps */ |
1426 | HT_caps_handler(padapter, pIE); |
1427 | break; |
1428 | |
1429 | case WLAN_EID_HT_OPERATION: /* HT info */ |
1430 | HT_info_handler(padapter, pIE); |
1431 | break; |
1432 | |
1433 | case WLAN_EID_ERP_INFO: |
1434 | ERP_IE_handler(padapter, pIE); |
1435 | break; |
1436 | |
1437 | default: |
1438 | break; |
1439 | } |
1440 | |
1441 | i += (pIE->length + 2); |
1442 | } |
1443 | |
1444 | pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE); |
1445 | pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; |
1446 | |
1447 | /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */ |
1448 | UpdateBrateTbl(padapter, mBratesOS: pmlmeinfo->network.supported_rates); |
1449 | |
1450 | report_assoc_result: |
1451 | if (res > 0) |
1452 | rtw_buf_update(buf: &pmlmepriv->assoc_rsp, buf_len: &pmlmepriv->assoc_rsp_len, src: pframe, src_len: pkt_len); |
1453 | else |
1454 | rtw_buf_free(buf: &pmlmepriv->assoc_rsp, buf_len: &pmlmepriv->assoc_rsp_len); |
1455 | |
1456 | report_join_res(padapter, res); |
1457 | |
1458 | return _SUCCESS; |
1459 | } |
1460 | |
1461 | unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame) |
1462 | { |
1463 | unsigned short reason; |
1464 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
1465 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1466 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
1467 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1468 | int ignore_received_deauth = 0; |
1469 | |
1470 | /* check A3 */ |
1471 | if (memcmp(GetAddr3Ptr(pframe), q: get_my_bssid(pnetwork: &pmlmeinfo->network), ETH_ALEN)) |
1472 | return _SUCCESS; |
1473 | |
1474 | reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); |
1475 | |
1476 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { |
1477 | struct sta_info *psta; |
1478 | struct sta_priv *pstapriv = &padapter->stapriv; |
1479 | |
1480 | /* rtw_free_stainfo(padapter, psta); */ |
1481 | |
1482 | netdev_dbg(padapter->pnetdev, |
1483 | "ap recv deauth reason code(%d) sta:%pM\n" , reason, |
1484 | GetAddr2Ptr(pframe)); |
1485 | |
1486 | psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); |
1487 | if (psta) { |
1488 | u8 updated = false; |
1489 | |
1490 | spin_lock_bh(lock: &pstapriv->asoc_list_lock); |
1491 | if (list_empty(head: &psta->asoc_list) == false) { |
1492 | list_del_init(entry: &psta->asoc_list); |
1493 | pstapriv->asoc_list_cnt--; |
1494 | updated = ap_free_sta(padapter, psta, active: false, reason); |
1495 | |
1496 | } |
1497 | spin_unlock_bh(lock: &pstapriv->asoc_list_lock); |
1498 | |
1499 | associated_clients_update(padapter, updated); |
1500 | } |
1501 | |
1502 | |
1503 | return _SUCCESS; |
1504 | } |
1505 | |
1506 | /* Commented by Albert 20130604 */ |
1507 | /* Before sending the auth frame to start the STA/GC mode connection with AP/GO, */ |
1508 | /* we will send the deauth first. */ |
1509 | /* However, the Win8.1 with BRCM Wi-Fi will send the deauth with reason code 6 to us after receieving our deauth. */ |
1510 | /* Added the following code to avoid this case. */ |
1511 | if ((pmlmeinfo->state & WIFI_FW_AUTH_STATE) || |
1512 | (pmlmeinfo->state & WIFI_FW_ASSOC_STATE)) { |
1513 | if (reason == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA) { |
1514 | ignore_received_deauth = 1; |
1515 | } else if (reason == WLAN_REASON_PREV_AUTH_NOT_VALID) { |
1516 | /* TODO: 802.11r */ |
1517 | ignore_received_deauth = 1; |
1518 | } |
1519 | } |
1520 | |
1521 | netdev_dbg(padapter->pnetdev, |
1522 | "sta recv deauth reason code(%d) sta:%pM, ignore = %d\n" , |
1523 | reason, GetAddr3Ptr(pframe), |
1524 | ignore_received_deauth); |
1525 | |
1526 | if (ignore_received_deauth == 0) |
1527 | receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); |
1528 | |
1529 | pmlmepriv->LinkDetectInfo.bBusyTraffic = false; |
1530 | return _SUCCESS; |
1531 | } |
1532 | |
1533 | unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame) |
1534 | { |
1535 | unsigned short reason; |
1536 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
1537 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1538 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
1539 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1540 | |
1541 | /* check A3 */ |
1542 | if (memcmp(GetAddr3Ptr(pframe), q: get_my_bssid(pnetwork: &pmlmeinfo->network), ETH_ALEN)) |
1543 | return _SUCCESS; |
1544 | |
1545 | reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); |
1546 | |
1547 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { |
1548 | struct sta_info *psta; |
1549 | struct sta_priv *pstapriv = &padapter->stapriv; |
1550 | |
1551 | /* rtw_free_stainfo(padapter, psta); */ |
1552 | |
1553 | netdev_dbg(padapter->pnetdev, |
1554 | "ap recv disassoc reason code(%d) sta:%pM\n" , |
1555 | reason, GetAddr2Ptr(pframe)); |
1556 | |
1557 | psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); |
1558 | if (psta) { |
1559 | u8 updated = false; |
1560 | |
1561 | spin_lock_bh(lock: &pstapriv->asoc_list_lock); |
1562 | if (list_empty(head: &psta->asoc_list) == false) { |
1563 | list_del_init(entry: &psta->asoc_list); |
1564 | pstapriv->asoc_list_cnt--; |
1565 | updated = ap_free_sta(padapter, psta, active: false, reason); |
1566 | |
1567 | } |
1568 | spin_unlock_bh(lock: &pstapriv->asoc_list_lock); |
1569 | |
1570 | associated_clients_update(padapter, updated); |
1571 | } |
1572 | |
1573 | return _SUCCESS; |
1574 | } |
1575 | netdev_dbg(padapter->pnetdev, |
1576 | "sta recv disassoc reason code(%d) sta:%pM\n" , |
1577 | reason, GetAddr3Ptr(pframe)); |
1578 | |
1579 | receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); |
1580 | |
1581 | pmlmepriv->LinkDetectInfo.bBusyTraffic = false; |
1582 | return _SUCCESS; |
1583 | |
1584 | } |
1585 | |
1586 | unsigned int OnAtim(struct adapter *padapter, union recv_frame *precv_frame) |
1587 | { |
1588 | return _SUCCESS; |
1589 | } |
1590 | |
1591 | unsigned int on_action_spct(struct adapter *padapter, union recv_frame *precv_frame) |
1592 | { |
1593 | struct sta_info *psta = NULL; |
1594 | struct sta_priv *pstapriv = &padapter->stapriv; |
1595 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1596 | u8 *frame_body = (u8 *)(pframe + sizeof(struct ieee80211_hdr_3addr)); |
1597 | u8 category; |
1598 | u8 action; |
1599 | |
1600 | psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); |
1601 | |
1602 | if (!psta) |
1603 | goto exit; |
1604 | |
1605 | category = frame_body[0]; |
1606 | if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT) |
1607 | goto exit; |
1608 | |
1609 | action = frame_body[1]; |
1610 | switch (action) { |
1611 | case WLAN_ACTION_SPCT_MSR_REQ: |
1612 | case WLAN_ACTION_SPCT_MSR_RPRT: |
1613 | case WLAN_ACTION_SPCT_TPC_REQ: |
1614 | case WLAN_ACTION_SPCT_TPC_RPRT: |
1615 | case WLAN_ACTION_SPCT_CHL_SWITCH: |
1616 | break; |
1617 | default: |
1618 | break; |
1619 | } |
1620 | |
1621 | exit: |
1622 | return _FAIL; |
1623 | } |
1624 | |
1625 | unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_frame) |
1626 | { |
1627 | u8 *addr; |
1628 | struct sta_info *psta = NULL; |
1629 | struct recv_reorder_ctrl *preorder_ctrl; |
1630 | unsigned char *frame_body; |
1631 | unsigned char category, action; |
1632 | unsigned short tid, status; |
1633 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
1634 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
1635 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1636 | struct sta_priv *pstapriv = &padapter->stapriv; |
1637 | |
1638 | /* check RA matches or not */ |
1639 | if (memcmp(p: myid(peepriv: &(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */ |
1640 | return _SUCCESS; |
1641 | |
1642 | if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) |
1643 | if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) |
1644 | return _SUCCESS; |
1645 | |
1646 | addr = GetAddr2Ptr(pframe); |
1647 | psta = rtw_get_stainfo(pstapriv, hwaddr: addr); |
1648 | |
1649 | if (!psta) |
1650 | return _SUCCESS; |
1651 | |
1652 | frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr)); |
1653 | |
1654 | category = frame_body[0]; |
1655 | if (category == RTW_WLAN_CATEGORY_BACK) {/* representing Block Ack */ |
1656 | if (!pmlmeinfo->HT_enable) |
1657 | return _SUCCESS; |
1658 | |
1659 | action = frame_body[1]; |
1660 | switch (action) { |
1661 | case WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ |
1662 | |
1663 | memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request)); |
1664 | /* process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), GetAddr3Ptr(pframe)); */ |
1665 | process_addba_req(padapter, paddba_req: (u8 *)&(pmlmeinfo->ADDBA_req), addr); |
1666 | |
1667 | if (pmlmeinfo->accept_addba_req) |
1668 | issue_action_BA(padapter, raddr: addr, action: WLAN_ACTION_ADDBA_RESP, status: 0); |
1669 | else |
1670 | issue_action_BA(padapter, raddr: addr, action: WLAN_ACTION_ADDBA_RESP, status: 37);/* reject ADDBA Req */ |
1671 | |
1672 | break; |
1673 | |
1674 | case WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ |
1675 | status = get_unaligned_le16(p: &frame_body[3]); |
1676 | tid = ((frame_body[5] >> 2) & 0x7); |
1677 | |
1678 | if (status == 0) { |
1679 | /* successful */ |
1680 | psta->htpriv.agg_enable_bitmap |= BIT(tid); |
1681 | psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); |
1682 | } else { |
1683 | psta->htpriv.agg_enable_bitmap &= ~BIT(tid); |
1684 | } |
1685 | |
1686 | if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { |
1687 | psta->htpriv.agg_enable_bitmap &= ~BIT(tid); |
1688 | psta->expire_to = pstapriv->expire_to; |
1689 | psta->state ^= WIFI_STA_ALIVE_CHK_STATE; |
1690 | } |
1691 | |
1692 | break; |
1693 | |
1694 | case WLAN_ACTION_DELBA: /* DELBA */ |
1695 | if ((frame_body[3] & BIT(3)) == 0) { |
1696 | psta->htpriv.agg_enable_bitmap &= |
1697 | ~BIT((frame_body[3] >> 4) & 0xf); |
1698 | psta->htpriv.candidate_tid_bitmap &= |
1699 | ~BIT((frame_body[3] >> 4) & 0xf); |
1700 | } else if ((frame_body[3] & BIT(3)) == BIT(3)) { |
1701 | tid = (frame_body[3] >> 4) & 0x0F; |
1702 | |
1703 | preorder_ctrl = &psta->recvreorder_ctrl[tid]; |
1704 | preorder_ctrl->enable = false; |
1705 | preorder_ctrl->indicate_seq = 0xffff; |
1706 | } |
1707 | /* todo: how to notify the host while receiving DELETE BA */ |
1708 | break; |
1709 | |
1710 | default: |
1711 | break; |
1712 | } |
1713 | } |
1714 | return _SUCCESS; |
1715 | } |
1716 | |
1717 | static s32 rtw_action_public_decache(union recv_frame *recv_frame, s32 token) |
1718 | { |
1719 | struct adapter *adapter = recv_frame->u.hdr.adapter; |
1720 | struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv); |
1721 | u8 *frame = recv_frame->u.hdr.rx_data; |
1722 | u16 seq_ctrl = ((recv_frame->u.hdr.attrib.seq_num&0xffff) << 4) | |
1723 | (recv_frame->u.hdr.attrib.frag_num & 0xf); |
1724 | |
1725 | if (GetRetry(frame)) { |
1726 | if (token >= 0) { |
1727 | if ((seq_ctrl == mlmeext->action_public_rxseq) |
1728 | && (token == mlmeext->action_public_dialog_token)) |
1729 | return _FAIL; |
1730 | } else { |
1731 | if (seq_ctrl == mlmeext->action_public_rxseq) |
1732 | return _FAIL; |
1733 | } |
1734 | } |
1735 | |
1736 | mlmeext->action_public_rxseq = seq_ctrl; |
1737 | |
1738 | if (token >= 0) |
1739 | mlmeext->action_public_dialog_token = token; |
1740 | |
1741 | return _SUCCESS; |
1742 | } |
1743 | |
1744 | static unsigned int on_action_public_p2p(union recv_frame *precv_frame) |
1745 | { |
1746 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1747 | u8 *frame_body; |
1748 | u8 dialogToken = 0; |
1749 | |
1750 | frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr)); |
1751 | |
1752 | dialogToken = frame_body[7]; |
1753 | |
1754 | if (rtw_action_public_decache(recv_frame: precv_frame, token: dialogToken) == _FAIL) |
1755 | return _FAIL; |
1756 | |
1757 | return _SUCCESS; |
1758 | } |
1759 | |
1760 | static unsigned int on_action_public_vendor(union recv_frame *precv_frame) |
1761 | { |
1762 | unsigned int ret = _FAIL; |
1763 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1764 | u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); |
1765 | |
1766 | if (!memcmp(p: frame_body + 2, q: P2P_OUI, size: 4)) |
1767 | ret = on_action_public_p2p(precv_frame); |
1768 | |
1769 | return ret; |
1770 | } |
1771 | |
1772 | static unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action) |
1773 | { |
1774 | unsigned int ret = _FAIL; |
1775 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1776 | uint frame_len = precv_frame->u.hdr.len; |
1777 | u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); |
1778 | u8 token; |
1779 | struct adapter *adapter = precv_frame->u.hdr.adapter; |
1780 | char msg[64]; |
1781 | |
1782 | token = frame_body[2]; |
1783 | |
1784 | if (rtw_action_public_decache(recv_frame: precv_frame, token) == _FAIL) |
1785 | goto exit; |
1786 | |
1787 | scnprintf(buf: msg, size: sizeof(msg), fmt: "%s(token:%u)" , action_public_str(action), token); |
1788 | rtw_cfg80211_rx_action(adapter, frame: pframe, frame_len, msg); |
1789 | |
1790 | ret = _SUCCESS; |
1791 | |
1792 | exit: |
1793 | return ret; |
1794 | } |
1795 | |
1796 | unsigned int on_action_public(struct adapter *padapter, union recv_frame *precv_frame) |
1797 | { |
1798 | unsigned int ret = _FAIL; |
1799 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1800 | u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); |
1801 | u8 category, action; |
1802 | |
1803 | /* check RA matches or not */ |
1804 | if (memcmp(p: myid(peepriv: &(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN)) |
1805 | goto exit; |
1806 | |
1807 | category = frame_body[0]; |
1808 | if (category != RTW_WLAN_CATEGORY_PUBLIC) |
1809 | goto exit; |
1810 | |
1811 | action = frame_body[1]; |
1812 | switch (action) { |
1813 | case ACT_PUBLIC_VENDOR: |
1814 | ret = on_action_public_vendor(precv_frame); |
1815 | break; |
1816 | default: |
1817 | ret = on_action_public_default(precv_frame, action); |
1818 | break; |
1819 | } |
1820 | |
1821 | exit: |
1822 | return ret; |
1823 | } |
1824 | |
1825 | unsigned int OnAction_ht(struct adapter *padapter, union recv_frame *precv_frame) |
1826 | { |
1827 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1828 | u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); |
1829 | u8 category, action; |
1830 | |
1831 | /* check RA matches or not */ |
1832 | if (memcmp(p: myid(peepriv: &(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN)) |
1833 | goto exit; |
1834 | |
1835 | category = frame_body[0]; |
1836 | if (category != RTW_WLAN_CATEGORY_HT) |
1837 | goto exit; |
1838 | |
1839 | action = frame_body[1]; |
1840 | switch (action) { |
1841 | case WLAN_HT_ACTION_COMPRESSED_BF: |
1842 | break; |
1843 | default: |
1844 | break; |
1845 | } |
1846 | |
1847 | exit: |
1848 | |
1849 | return _SUCCESS; |
1850 | } |
1851 | |
1852 | unsigned int OnAction_sa_query(struct adapter *padapter, union recv_frame *precv_frame) |
1853 | { |
1854 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1855 | struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; |
1856 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
1857 | unsigned short tid; |
1858 | |
1859 | switch (pframe[WLAN_HDR_A3_LEN+1]) { |
1860 | case 0: /* SA Query req */ |
1861 | memcpy(&tid, &pframe[WLAN_HDR_A3_LEN+2], sizeof(unsigned short)); |
1862 | issue_action_SA_Query(padapter, GetAddr2Ptr(pframe), action: 1, tid); |
1863 | break; |
1864 | |
1865 | case 1: /* SA Query rsp */ |
1866 | del_timer_sync(timer: &pmlmeext->sa_query_timer); |
1867 | break; |
1868 | default: |
1869 | break; |
1870 | } |
1871 | if (0) { |
1872 | int pp; |
1873 | |
1874 | printk("pattrib->pktlen = %d =>" , pattrib->pkt_len); |
1875 | for (pp = 0; pp < pattrib->pkt_len; pp++) |
1876 | printk(" %02x " , pframe[pp]); |
1877 | printk("\n" ); |
1878 | } |
1879 | |
1880 | return _SUCCESS; |
1881 | } |
1882 | |
1883 | unsigned int OnAction(struct adapter *padapter, union recv_frame *precv_frame) |
1884 | { |
1885 | int i; |
1886 | unsigned char category; |
1887 | struct action_handler *ptable; |
1888 | unsigned char *frame_body; |
1889 | u8 *pframe = precv_frame->u.hdr.rx_data; |
1890 | |
1891 | frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr)); |
1892 | |
1893 | category = frame_body[0]; |
1894 | |
1895 | for (i = 0; i < ARRAY_SIZE(OnAction_tbl); i++) { |
1896 | ptable = &OnAction_tbl[i]; |
1897 | |
1898 | if (category == ptable->num) |
1899 | ptable->func(padapter, precv_frame); |
1900 | |
1901 | } |
1902 | |
1903 | return _SUCCESS; |
1904 | |
1905 | } |
1906 | |
1907 | unsigned int DoReserved(struct adapter *padapter, union recv_frame *precv_frame) |
1908 | { |
1909 | return _SUCCESS; |
1910 | } |
1911 | |
1912 | static struct xmit_frame *_alloc_mgtxmitframe(struct xmit_priv *pxmitpriv, bool once) |
1913 | { |
1914 | struct xmit_frame *pmgntframe; |
1915 | struct xmit_buf *pxmitbuf; |
1916 | |
1917 | if (once) |
1918 | pmgntframe = rtw_alloc_xmitframe_once(pxmitpriv); |
1919 | else |
1920 | pmgntframe = rtw_alloc_xmitframe_ext(pxmitpriv); |
1921 | |
1922 | if (!pmgntframe) |
1923 | goto exit; |
1924 | |
1925 | pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv); |
1926 | if (!pxmitbuf) { |
1927 | rtw_free_xmitframe(pxmitpriv, pxmitframe: pmgntframe); |
1928 | pmgntframe = NULL; |
1929 | goto exit; |
1930 | } |
1931 | |
1932 | pmgntframe->frame_tag = MGNT_FRAMETAG; |
1933 | pmgntframe->pxmitbuf = pxmitbuf; |
1934 | pmgntframe->buf_addr = pxmitbuf->pbuf; |
1935 | pxmitbuf->priv_data = pmgntframe; |
1936 | |
1937 | exit: |
1938 | return pmgntframe; |
1939 | |
1940 | } |
1941 | |
1942 | inline struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv) |
1943 | { |
1944 | return _alloc_mgtxmitframe(pxmitpriv, once: false); |
1945 | } |
1946 | |
1947 | /**************************************************************************** |
1948 | |
1949 | Following are some TX functions for WiFi MLME |
1950 | |
1951 | *****************************************************************************/ |
1952 | |
1953 | void update_mgnt_tx_rate(struct adapter *padapter, u8 rate) |
1954 | { |
1955 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
1956 | |
1957 | pmlmeext->tx_rate = rate; |
1958 | } |
1959 | |
1960 | void update_mgntframe_attrib(struct adapter *padapter, struct pkt_attrib *pattrib) |
1961 | { |
1962 | u8 wireless_mode; |
1963 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
1964 | |
1965 | /* memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); */ |
1966 | |
1967 | pattrib->hdrlen = 24; |
1968 | pattrib->nr_frags = 1; |
1969 | pattrib->priority = 7; |
1970 | pattrib->mac_id = 0; |
1971 | pattrib->qsel = 0x12; |
1972 | |
1973 | pattrib->pktlen = 0; |
1974 | |
1975 | if (pmlmeext->tx_rate == IEEE80211_CCK_RATE_1MB) |
1976 | wireless_mode = WIRELESS_11B; |
1977 | else |
1978 | wireless_mode = WIRELESS_11G; |
1979 | pattrib->raid = rtw_get_mgntframe_raid(adapter: padapter, network_type: wireless_mode); |
1980 | pattrib->rate = pmlmeext->tx_rate; |
1981 | |
1982 | pattrib->encrypt = _NO_PRIVACY_; |
1983 | pattrib->bswenc = false; |
1984 | |
1985 | pattrib->qos_en = false; |
1986 | pattrib->ht_en = false; |
1987 | pattrib->bwmode = CHANNEL_WIDTH_20; |
1988 | pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; |
1989 | pattrib->sgi = false; |
1990 | |
1991 | pattrib->seqnum = pmlmeext->mgnt_seq; |
1992 | |
1993 | pattrib->retry_ctrl = true; |
1994 | |
1995 | pattrib->mbssid = 0; |
1996 | |
1997 | } |
1998 | |
1999 | void update_mgntframe_attrib_addr(struct adapter *padapter, struct xmit_frame *pmgntframe) |
2000 | { |
2001 | u8 *pframe; |
2002 | struct pkt_attrib *pattrib = &pmgntframe->attrib; |
2003 | |
2004 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
2005 | |
2006 | memcpy(pattrib->ra, GetAddr1Ptr(pframe), ETH_ALEN); |
2007 | memcpy(pattrib->ta, GetAddr2Ptr(pframe), ETH_ALEN); |
2008 | } |
2009 | |
2010 | void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe) |
2011 | { |
2012 | if (padapter->bSurpriseRemoved || |
2013 | padapter->bDriverStopped) { |
2014 | rtw_free_xmitbuf(pxmitpriv: &padapter->xmitpriv, pxmitbuf: pmgntframe->pxmitbuf); |
2015 | rtw_free_xmitframe(pxmitpriv: &padapter->xmitpriv, pxmitframe: pmgntframe); |
2016 | return; |
2017 | } |
2018 | |
2019 | rtw_hal_mgnt_xmit(padapter, pmgntframe); |
2020 | } |
2021 | |
2022 | s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms) |
2023 | { |
2024 | s32 ret = _FAIL; |
2025 | unsigned long irqL; |
2026 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
2027 | struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; |
2028 | struct submit_ctx sctx; |
2029 | |
2030 | if (padapter->bSurpriseRemoved || |
2031 | padapter->bDriverStopped) { |
2032 | rtw_free_xmitbuf(pxmitpriv: &padapter->xmitpriv, pxmitbuf: pmgntframe->pxmitbuf); |
2033 | rtw_free_xmitframe(pxmitpriv: &padapter->xmitpriv, pxmitframe: pmgntframe); |
2034 | return ret; |
2035 | } |
2036 | |
2037 | rtw_sctx_init(sctx: &sctx, timeout_ms); |
2038 | pxmitbuf->sctx = &sctx; |
2039 | |
2040 | ret = rtw_hal_mgnt_xmit(padapter, pmgntframe); |
2041 | |
2042 | if (ret == _SUCCESS) |
2043 | ret = rtw_sctx_wait(sctx: &sctx); |
2044 | |
2045 | spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL); |
2046 | pxmitbuf->sctx = NULL; |
2047 | spin_unlock_irqrestore(lock: &pxmitpriv->lock_sctx, flags: irqL); |
2048 | |
2049 | return ret; |
2050 | } |
2051 | |
2052 | s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmgntframe) |
2053 | { |
2054 | static u8 seq_no; |
2055 | s32 ret = _FAIL; |
2056 | u32 timeout_ms = 500;/* 500ms */ |
2057 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
2058 | |
2059 | if (padapter->bSurpriseRemoved || |
2060 | padapter->bDriverStopped) { |
2061 | rtw_free_xmitbuf(pxmitpriv: &padapter->xmitpriv, pxmitbuf: pmgntframe->pxmitbuf); |
2062 | rtw_free_xmitframe(pxmitpriv: &padapter->xmitpriv, pxmitframe: pmgntframe); |
2063 | return -1; |
2064 | } |
2065 | |
2066 | if (mutex_lock_interruptible(&pxmitpriv->ack_tx_mutex) == 0) { |
2067 | pxmitpriv->ack_tx = true; |
2068 | pxmitpriv->seq_no = seq_no++; |
2069 | pmgntframe->ack_report = 1; |
2070 | if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) |
2071 | ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms); |
2072 | |
2073 | pxmitpriv->ack_tx = false; |
2074 | mutex_unlock(lock: &pxmitpriv->ack_tx_mutex); |
2075 | } |
2076 | |
2077 | return ret; |
2078 | } |
2079 | |
2080 | static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) |
2081 | { |
2082 | u8 *ssid_ie; |
2083 | signed int ssid_len_ori; |
2084 | int len_diff = 0; |
2085 | |
2086 | ssid_ie = rtw_get_ie(pbuf: ies, index: WLAN_EID_SSID, len: &ssid_len_ori, limit: ies_len); |
2087 | |
2088 | if (ssid_ie && ssid_len_ori > 0) { |
2089 | switch (hidden_ssid_mode) { |
2090 | case 1: |
2091 | { |
2092 | u8 *next_ie = ssid_ie + 2 + ssid_len_ori; |
2093 | u32 remain_len = 0; |
2094 | |
2095 | remain_len = ies_len - (next_ie-ies); |
2096 | |
2097 | ssid_ie[1] = 0; |
2098 | memcpy(ssid_ie+2, next_ie, remain_len); |
2099 | len_diff -= ssid_len_ori; |
2100 | |
2101 | break; |
2102 | } |
2103 | case 2: |
2104 | memset(&ssid_ie[2], 0, ssid_len_ori); |
2105 | break; |
2106 | default: |
2107 | break; |
2108 | } |
2109 | } |
2110 | |
2111 | return len_diff; |
2112 | } |
2113 | |
2114 | void issue_beacon(struct adapter *padapter, int timeout_ms) |
2115 | { |
2116 | struct xmit_frame *pmgntframe; |
2117 | struct pkt_attrib *pattrib; |
2118 | unsigned char *pframe; |
2119 | struct ieee80211_hdr *pwlanhdr; |
2120 | __le16 *fctrl; |
2121 | unsigned int rate_len; |
2122 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
2123 | struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); |
2124 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
2125 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
2126 | struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); |
2127 | |
2128 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
2129 | if (!pmgntframe) |
2130 | return; |
2131 | |
2132 | spin_lock_bh(lock: &pmlmepriv->bcn_update_lock); |
2133 | |
2134 | /* update attribute */ |
2135 | pattrib = &pmgntframe->attrib; |
2136 | update_mgntframe_attrib(padapter, pattrib); |
2137 | pattrib->qsel = 0x10; |
2138 | |
2139 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
2140 | |
2141 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
2142 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
2143 | |
2144 | |
2145 | fctrl = &(pwlanhdr->frame_control); |
2146 | *(fctrl) = 0; |
2147 | |
2148 | eth_broadcast_addr(addr: pwlanhdr->addr1); |
2149 | memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); |
2150 | memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); |
2151 | |
2152 | SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); |
2153 | /* pmlmeext->mgnt_seq++; */ |
2154 | SetFrameSubType(pframe, WIFI_BEACON); |
2155 | |
2156 | pframe += sizeof(struct ieee80211_hdr_3addr); |
2157 | pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); |
2158 | |
2159 | if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { |
2160 | { |
2161 | int len_diff; |
2162 | |
2163 | memcpy(pframe, cur_network->ies, cur_network->ie_length); |
2164 | len_diff = update_hidden_ssid(ies: pframe+_BEACON_IE_OFFSET_, |
2165 | ies_len: cur_network->ie_length-_BEACON_IE_OFFSET_, |
2166 | hidden_ssid_mode: pmlmeinfo->hidden_ssid_mode); |
2167 | pframe += (cur_network->ie_length+len_diff); |
2168 | pattrib->pktlen += (cur_network->ie_length+len_diff); |
2169 | } |
2170 | |
2171 | { |
2172 | u8 *wps_ie; |
2173 | uint wps_ielen; |
2174 | u8 sr = 0; |
2175 | |
2176 | wps_ie = rtw_get_wps_ie(in_ie: pmgntframe->buf_addr+TXDESC_OFFSET+sizeof(struct ieee80211_hdr_3addr)+_BEACON_IE_OFFSET_, |
2177 | in_len: pattrib->pktlen-sizeof(struct ieee80211_hdr_3addr)-_BEACON_IE_OFFSET_, NULL, wps_ielen: &wps_ielen); |
2178 | if (wps_ie && wps_ielen > 0) |
2179 | rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, buf_content: (u8 *)(&sr), NULL); |
2180 | if (sr != 0) |
2181 | set_fwstate(pmlmepriv, WIFI_UNDER_WPS); |
2182 | else |
2183 | _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); |
2184 | } |
2185 | |
2186 | goto _issue_bcn; |
2187 | |
2188 | } |
2189 | |
2190 | /* below for ad-hoc mode */ |
2191 | |
2192 | /* timestamp will be inserted by hardware */ |
2193 | pframe += 8; |
2194 | pattrib->pktlen += 8; |
2195 | |
2196 | /* beacon interval: 2 bytes */ |
2197 | |
2198 | memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->ies)), 2); |
2199 | |
2200 | pframe += 2; |
2201 | pattrib->pktlen += 2; |
2202 | |
2203 | /* capability info: 2 bytes */ |
2204 | |
2205 | memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->ies)), 2); |
2206 | |
2207 | pframe += 2; |
2208 | pattrib->pktlen += 2; |
2209 | |
2210 | /* SSID */ |
2211 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SSID, len: cur_network->ssid.ssid_length, source: cur_network->ssid.ssid, frlen: &pattrib->pktlen); |
2212 | |
2213 | /* supported rates... */ |
2214 | rate_len = rtw_get_rateset_len(rateset: cur_network->supported_rates); |
2215 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SUPP_RATES, len: ((rate_len > 8) ? 8 : rate_len), source: cur_network->supported_rates, frlen: &pattrib->pktlen); |
2216 | |
2217 | /* DS parameter set */ |
2218 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_DS_PARAMS, len: 1, source: (unsigned char *)&(cur_network->configuration.ds_config), frlen: &pattrib->pktlen); |
2219 | |
2220 | /* if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) */ |
2221 | { |
2222 | u8 erpinfo = 0; |
2223 | u32 ATIMWindow; |
2224 | /* IBSS Parameter Set... */ |
2225 | /* ATIMWindow = cur->configuration.ATIMWindow; */ |
2226 | ATIMWindow = 0; |
2227 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_IBSS_PARAMS, len: 2, source: (unsigned char *)(&ATIMWindow), frlen: &pattrib->pktlen); |
2228 | |
2229 | /* ERP IE */ |
2230 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_ERP_INFO, len: 1, source: &erpinfo, frlen: &pattrib->pktlen); |
2231 | } |
2232 | |
2233 | |
2234 | /* EXTERNDED SUPPORTED RATE */ |
2235 | if (rate_len > 8) |
2236 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_EXT_SUPP_RATES, len: (rate_len - 8), source: (cur_network->supported_rates + 8), frlen: &pattrib->pktlen); |
2237 | |
2238 | |
2239 | /* todo:HT for adhoc */ |
2240 | |
2241 | _issue_bcn: |
2242 | |
2243 | pmlmepriv->update_bcn = false; |
2244 | |
2245 | spin_unlock_bh(lock: &pmlmepriv->bcn_update_lock); |
2246 | |
2247 | if ((pattrib->pktlen + TXDESC_SIZE) > 512) |
2248 | return; |
2249 | |
2250 | pattrib->last_txcmdsz = pattrib->pktlen; |
2251 | |
2252 | if (timeout_ms > 0) |
2253 | dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms); |
2254 | else |
2255 | dump_mgntframe(padapter, pmgntframe); |
2256 | |
2257 | } |
2258 | |
2259 | void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq) |
2260 | { |
2261 | struct xmit_frame *pmgntframe; |
2262 | struct pkt_attrib *pattrib; |
2263 | unsigned char *pframe; |
2264 | struct ieee80211_hdr *pwlanhdr; |
2265 | __le16 *fctrl; |
2266 | unsigned char *mac, *bssid; |
2267 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
2268 | |
2269 | u8 *pwps_ie; |
2270 | uint wps_ielen; |
2271 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
2272 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
2273 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
2274 | struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); |
2275 | unsigned int rate_len; |
2276 | |
2277 | if (!da) |
2278 | return; |
2279 | |
2280 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
2281 | if (!pmgntframe) |
2282 | return; |
2283 | |
2284 | /* update attribute */ |
2285 | pattrib = &pmgntframe->attrib; |
2286 | update_mgntframe_attrib(padapter, pattrib); |
2287 | |
2288 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
2289 | |
2290 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
2291 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
2292 | |
2293 | mac = myid(peepriv: &(padapter->eeprompriv)); |
2294 | bssid = cur_network->mac_address; |
2295 | |
2296 | fctrl = &(pwlanhdr->frame_control); |
2297 | *(fctrl) = 0; |
2298 | memcpy(pwlanhdr->addr1, da, ETH_ALEN); |
2299 | memcpy(pwlanhdr->addr2, mac, ETH_ALEN); |
2300 | memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); |
2301 | |
2302 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
2303 | pmlmeext->mgnt_seq++; |
2304 | SetFrameSubType(fctrl, WIFI_PROBERSP); |
2305 | |
2306 | pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); |
2307 | pattrib->pktlen = pattrib->hdrlen; |
2308 | pframe += pattrib->hdrlen; |
2309 | |
2310 | |
2311 | if (cur_network->ie_length > MAX_IE_SZ) |
2312 | return; |
2313 | |
2314 | if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { |
2315 | pwps_ie = rtw_get_wps_ie(in_ie: cur_network->ies+_FIXED_IE_LENGTH_, in_len: cur_network->ie_length-_FIXED_IE_LENGTH_, NULL, wps_ielen: &wps_ielen); |
2316 | |
2317 | /* inerset & update wps_probe_resp_ie */ |
2318 | if (pmlmepriv->wps_probe_resp_ie && pwps_ie && wps_ielen > 0) { |
2319 | uint wps_offset, remainder_ielen; |
2320 | u8 *premainder_ie; |
2321 | |
2322 | wps_offset = (uint)(pwps_ie - cur_network->ies); |
2323 | |
2324 | premainder_ie = pwps_ie + wps_ielen; |
2325 | |
2326 | remainder_ielen = cur_network->ie_length - wps_offset - wps_ielen; |
2327 | |
2328 | memcpy(pframe, cur_network->ies, wps_offset); |
2329 | pframe += wps_offset; |
2330 | pattrib->pktlen += wps_offset; |
2331 | |
2332 | wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */ |
2333 | if ((wps_offset+wps_ielen+2) <= MAX_IE_SZ) { |
2334 | memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2); |
2335 | pframe += wps_ielen+2; |
2336 | pattrib->pktlen += wps_ielen+2; |
2337 | } |
2338 | |
2339 | if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) { |
2340 | memcpy(pframe, premainder_ie, remainder_ielen); |
2341 | pframe += remainder_ielen; |
2342 | pattrib->pktlen += remainder_ielen; |
2343 | } |
2344 | } else { |
2345 | memcpy(pframe, cur_network->ies, cur_network->ie_length); |
2346 | pframe += cur_network->ie_length; |
2347 | pattrib->pktlen += cur_network->ie_length; |
2348 | } |
2349 | |
2350 | /* retrieve SSID IE from cur_network->ssid */ |
2351 | { |
2352 | u8 *ssid_ie; |
2353 | signed int ssid_ielen; |
2354 | signed int ssid_ielen_diff; |
2355 | u8 *buf; |
2356 | u8 *ies = pmgntframe->buf_addr+TXDESC_OFFSET+sizeof(struct ieee80211_hdr_3addr); |
2357 | |
2358 | buf = rtw_zmalloc(MAX_IE_SZ); |
2359 | if (!buf) |
2360 | return; |
2361 | |
2362 | ssid_ie = rtw_get_ie(pbuf: ies+_FIXED_IE_LENGTH_, index: WLAN_EID_SSID, len: &ssid_ielen, |
2363 | limit: (pframe-ies)-_FIXED_IE_LENGTH_); |
2364 | |
2365 | ssid_ielen_diff = cur_network->ssid.ssid_length - ssid_ielen; |
2366 | |
2367 | if (ssid_ie && cur_network->ssid.ssid_length) { |
2368 | uint remainder_ielen; |
2369 | u8 *remainder_ie; |
2370 | |
2371 | remainder_ie = ssid_ie+2; |
2372 | remainder_ielen = (pframe-remainder_ie); |
2373 | |
2374 | if (remainder_ielen > MAX_IE_SZ) { |
2375 | netdev_warn(dev: padapter->pnetdev, |
2376 | FUNC_ADPT_FMT " remainder_ielen > MAX_IE_SZ\n" , |
2377 | FUNC_ADPT_ARG(padapter)); |
2378 | remainder_ielen = MAX_IE_SZ; |
2379 | } |
2380 | |
2381 | memcpy(buf, remainder_ie, remainder_ielen); |
2382 | memcpy(remainder_ie+ssid_ielen_diff, buf, remainder_ielen); |
2383 | *(ssid_ie+1) = cur_network->ssid.ssid_length; |
2384 | memcpy(ssid_ie+2, cur_network->ssid.ssid, cur_network->ssid.ssid_length); |
2385 | |
2386 | pframe += ssid_ielen_diff; |
2387 | pattrib->pktlen += ssid_ielen_diff; |
2388 | } |
2389 | kfree(objp: buf); |
2390 | } |
2391 | } else { |
2392 | /* timestamp will be inserted by hardware */ |
2393 | pframe += 8; |
2394 | pattrib->pktlen += 8; |
2395 | |
2396 | /* beacon interval: 2 bytes */ |
2397 | |
2398 | memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->ies)), 2); |
2399 | |
2400 | pframe += 2; |
2401 | pattrib->pktlen += 2; |
2402 | |
2403 | /* capability info: 2 bytes */ |
2404 | |
2405 | memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->ies)), 2); |
2406 | |
2407 | pframe += 2; |
2408 | pattrib->pktlen += 2; |
2409 | |
2410 | /* below for ad-hoc mode */ |
2411 | |
2412 | /* SSID */ |
2413 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SSID, len: cur_network->ssid.ssid_length, source: cur_network->ssid.ssid, frlen: &pattrib->pktlen); |
2414 | |
2415 | /* supported rates... */ |
2416 | rate_len = rtw_get_rateset_len(rateset: cur_network->supported_rates); |
2417 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SUPP_RATES, len: ((rate_len > 8) ? 8 : rate_len), source: cur_network->supported_rates, frlen: &pattrib->pktlen); |
2418 | |
2419 | /* DS parameter set */ |
2420 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_DS_PARAMS, len: 1, source: (unsigned char *)&(cur_network->configuration.ds_config), frlen: &pattrib->pktlen); |
2421 | |
2422 | if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { |
2423 | u8 erpinfo = 0; |
2424 | u32 ATIMWindow; |
2425 | /* IBSS Parameter Set... */ |
2426 | /* ATIMWindow = cur->configuration.ATIMWindow; */ |
2427 | ATIMWindow = 0; |
2428 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_IBSS_PARAMS, len: 2, source: (unsigned char *)(&ATIMWindow), frlen: &pattrib->pktlen); |
2429 | |
2430 | /* ERP IE */ |
2431 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_ERP_INFO, len: 1, source: &erpinfo, frlen: &pattrib->pktlen); |
2432 | } |
2433 | |
2434 | |
2435 | /* EXTERNDED SUPPORTED RATE */ |
2436 | if (rate_len > 8) |
2437 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_EXT_SUPP_RATES, len: (rate_len - 8), source: (cur_network->supported_rates + 8), frlen: &pattrib->pktlen); |
2438 | |
2439 | |
2440 | /* todo:HT for adhoc */ |
2441 | |
2442 | } |
2443 | |
2444 | pattrib->last_txcmdsz = pattrib->pktlen; |
2445 | |
2446 | |
2447 | dump_mgntframe(padapter, pmgntframe); |
2448 | |
2449 | return; |
2450 | |
2451 | } |
2452 | |
2453 | static int _issue_probereq(struct adapter *padapter, |
2454 | struct ndis_802_11_ssid *pssid, |
2455 | u8 *da, u8 ch, bool append_wps, bool wait_ack) |
2456 | { |
2457 | int ret = _FAIL; |
2458 | struct xmit_frame *pmgntframe; |
2459 | struct pkt_attrib *pattrib; |
2460 | unsigned char *pframe; |
2461 | struct ieee80211_hdr *pwlanhdr; |
2462 | __le16 *fctrl; |
2463 | unsigned char *mac; |
2464 | unsigned char bssrate[NumRates]; |
2465 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
2466 | struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); |
2467 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
2468 | int bssrate_len = 0; |
2469 | |
2470 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
2471 | if (!pmgntframe) |
2472 | goto exit; |
2473 | |
2474 | /* update attribute */ |
2475 | pattrib = &pmgntframe->attrib; |
2476 | update_mgntframe_attrib(padapter, pattrib); |
2477 | |
2478 | |
2479 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
2480 | |
2481 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
2482 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
2483 | |
2484 | mac = myid(peepriv: &(padapter->eeprompriv)); |
2485 | |
2486 | fctrl = &(pwlanhdr->frame_control); |
2487 | *(fctrl) = 0; |
2488 | |
2489 | if (da) { |
2490 | /* unicast probe request frame */ |
2491 | memcpy(pwlanhdr->addr1, da, ETH_ALEN); |
2492 | memcpy(pwlanhdr->addr3, da, ETH_ALEN); |
2493 | } else { |
2494 | /* broadcast probe request frame */ |
2495 | eth_broadcast_addr(addr: pwlanhdr->addr1); |
2496 | eth_broadcast_addr(addr: pwlanhdr->addr3); |
2497 | } |
2498 | |
2499 | memcpy(pwlanhdr->addr2, mac, ETH_ALEN); |
2500 | |
2501 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
2502 | pmlmeext->mgnt_seq++; |
2503 | SetFrameSubType(pframe, WIFI_PROBEREQ); |
2504 | |
2505 | pframe += sizeof(struct ieee80211_hdr_3addr); |
2506 | pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); |
2507 | |
2508 | if (pssid) |
2509 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SSID, len: pssid->ssid_length, source: pssid->ssid, frlen: &(pattrib->pktlen)); |
2510 | else |
2511 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SSID, len: 0, NULL, frlen: &(pattrib->pktlen)); |
2512 | |
2513 | get_rate_set(padapter, pbssrate: bssrate, bssrate_len: &bssrate_len); |
2514 | |
2515 | if (bssrate_len > 8) { |
2516 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SUPP_RATES, len: 8, source: bssrate, frlen: &(pattrib->pktlen)); |
2517 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_EXT_SUPP_RATES, len: (bssrate_len - 8), source: (bssrate + 8), frlen: &(pattrib->pktlen)); |
2518 | } else { |
2519 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SUPP_RATES, len: bssrate_len, source: bssrate, frlen: &(pattrib->pktlen)); |
2520 | } |
2521 | |
2522 | if (ch) |
2523 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_DS_PARAMS, len: 1, source: &ch, frlen: &pattrib->pktlen); |
2524 | |
2525 | if (append_wps) { |
2526 | /* add wps_ie for wps2.0 */ |
2527 | if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) { |
2528 | memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); |
2529 | pframe += pmlmepriv->wps_probe_req_ie_len; |
2530 | pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; |
2531 | } |
2532 | } |
2533 | |
2534 | pattrib->last_txcmdsz = pattrib->pktlen; |
2535 | |
2536 | if (wait_ack) { |
2537 | ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); |
2538 | } else { |
2539 | dump_mgntframe(padapter, pmgntframe); |
2540 | ret = _SUCCESS; |
2541 | } |
2542 | |
2543 | exit: |
2544 | return ret; |
2545 | } |
2546 | |
2547 | inline void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da) |
2548 | { |
2549 | _issue_probereq(padapter, pssid, da, ch: 0, append_wps: 1, wait_ack: false); |
2550 | } |
2551 | |
2552 | int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, u8 ch, bool append_wps, |
2553 | int try_cnt, int wait_ms) |
2554 | { |
2555 | int ret; |
2556 | int i = 0; |
2557 | |
2558 | do { |
2559 | ret = _issue_probereq(padapter, pssid, da, ch, append_wps, |
2560 | wait_ack: wait_ms > 0); |
2561 | |
2562 | i++; |
2563 | |
2564 | if (padapter->bDriverStopped || padapter->bSurpriseRemoved) |
2565 | break; |
2566 | |
2567 | if (i < try_cnt && wait_ms > 0 && ret == _FAIL) |
2568 | msleep(msecs: wait_ms); |
2569 | |
2570 | } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); |
2571 | |
2572 | if (ret != _FAIL) { |
2573 | ret = _SUCCESS; |
2574 | #ifndef DBG_XMIT_ACK |
2575 | goto exit; |
2576 | #endif |
2577 | } |
2578 | |
2579 | exit: |
2580 | return ret; |
2581 | } |
2582 | |
2583 | /* if psta == NULL, indicate we are station(client) now... */ |
2584 | void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short status) |
2585 | { |
2586 | struct xmit_frame *pmgntframe; |
2587 | struct pkt_attrib *pattrib; |
2588 | unsigned char *pframe; |
2589 | struct ieee80211_hdr *pwlanhdr; |
2590 | __le16 *fctrl; |
2591 | unsigned int val32; |
2592 | unsigned short val16; |
2593 | int use_shared_key = 0; |
2594 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
2595 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
2596 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
2597 | __le16 le_tmp; |
2598 | |
2599 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
2600 | if (!pmgntframe) |
2601 | return; |
2602 | |
2603 | /* update attribute */ |
2604 | pattrib = &pmgntframe->attrib; |
2605 | update_mgntframe_attrib(padapter, pattrib); |
2606 | |
2607 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
2608 | |
2609 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
2610 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
2611 | |
2612 | fctrl = &(pwlanhdr->frame_control); |
2613 | *(fctrl) = 0; |
2614 | |
2615 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
2616 | pmlmeext->mgnt_seq++; |
2617 | SetFrameSubType(pframe, WIFI_AUTH); |
2618 | |
2619 | pframe += sizeof(struct ieee80211_hdr_3addr); |
2620 | pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); |
2621 | |
2622 | |
2623 | if (psta) { /* for AP mode */ |
2624 | memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN); |
2625 | memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); |
2626 | memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); |
2627 | |
2628 | /* setting auth algo number */ |
2629 | val16 = (u16)psta->authalg; |
2630 | |
2631 | if (status != WLAN_STATUS_SUCCESS) |
2632 | val16 = 0; |
2633 | |
2634 | if (val16) |
2635 | use_shared_key = 1; |
2636 | |
2637 | le_tmp = cpu_to_le16(val16); |
2638 | |
2639 | pframe = rtw_set_fixed_ie(pbuf: pframe, _AUTH_ALGM_NUM_, source: (unsigned char *)&le_tmp, frlen: &(pattrib->pktlen)); |
2640 | |
2641 | /* setting auth seq number */ |
2642 | val16 = (u16)psta->auth_seq; |
2643 | le_tmp = cpu_to_le16(val16); |
2644 | pframe = rtw_set_fixed_ie(pbuf: pframe, _AUTH_SEQ_NUM_, source: (unsigned char *)&le_tmp, frlen: &(pattrib->pktlen)); |
2645 | |
2646 | /* setting status code... */ |
2647 | val16 = status; |
2648 | le_tmp = cpu_to_le16(val16); |
2649 | pframe = rtw_set_fixed_ie(pbuf: pframe, _STATUS_CODE_, source: (unsigned char *)&le_tmp, frlen: &(pattrib->pktlen)); |
2650 | |
2651 | /* added challenging text... */ |
2652 | if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) |
2653 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_CHALLENGE, len: 128, source: psta->chg_txt, frlen: &(pattrib->pktlen)); |
2654 | |
2655 | } else { |
2656 | memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); |
2657 | memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); |
2658 | memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); |
2659 | |
2660 | /* setting auth algo number */ |
2661 | val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0;/* 0:OPEN System, 1:Shared key */ |
2662 | if (val16) |
2663 | use_shared_key = 1; |
2664 | le_tmp = cpu_to_le16(val16); |
2665 | |
2666 | /* setting IV for auth seq #3 */ |
2667 | if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { |
2668 | __le32 le_tmp32; |
2669 | |
2670 | val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30)); |
2671 | le_tmp32 = cpu_to_le32(val32); |
2672 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 4, source: (unsigned char *)&le_tmp32, frlen: &(pattrib->pktlen)); |
2673 | |
2674 | pattrib->iv_len = 4; |
2675 | } |
2676 | |
2677 | pframe = rtw_set_fixed_ie(pbuf: pframe, _AUTH_ALGM_NUM_, source: (unsigned char *)&le_tmp, frlen: &(pattrib->pktlen)); |
2678 | |
2679 | /* setting auth seq number */ |
2680 | le_tmp = cpu_to_le16(pmlmeinfo->auth_seq); |
2681 | pframe = rtw_set_fixed_ie(pbuf: pframe, _AUTH_SEQ_NUM_, source: (unsigned char *)&le_tmp, frlen: &(pattrib->pktlen)); |
2682 | |
2683 | |
2684 | /* setting status code... */ |
2685 | le_tmp = cpu_to_le16(status); |
2686 | pframe = rtw_set_fixed_ie(pbuf: pframe, _STATUS_CODE_, source: (unsigned char *)&le_tmp, frlen: &(pattrib->pktlen)); |
2687 | |
2688 | /* then checking to see if sending challenging text... */ |
2689 | if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { |
2690 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_CHALLENGE, len: 128, source: pmlmeinfo->chg_txt, frlen: &(pattrib->pktlen)); |
2691 | |
2692 | SetPrivacy(fctrl); |
2693 | |
2694 | pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); |
2695 | |
2696 | pattrib->encrypt = _WEP40_; |
2697 | |
2698 | pattrib->icv_len = 4; |
2699 | |
2700 | pattrib->pktlen += pattrib->icv_len; |
2701 | |
2702 | } |
2703 | |
2704 | } |
2705 | |
2706 | pattrib->last_txcmdsz = pattrib->pktlen; |
2707 | |
2708 | rtw_wep_encrypt(padapter, pxmitframe: (u8 *)pmgntframe); |
2709 | dump_mgntframe(padapter, pmgntframe); |
2710 | } |
2711 | |
2712 | |
2713 | void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type) |
2714 | { |
2715 | struct xmit_frame *pmgntframe; |
2716 | struct ieee80211_hdr *pwlanhdr; |
2717 | struct pkt_attrib *pattrib; |
2718 | unsigned char *pbuf, *pframe; |
2719 | unsigned short val; |
2720 | __le16 *fctrl; |
2721 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
2722 | struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); |
2723 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
2724 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
2725 | struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); |
2726 | u8 *ie = pnetwork->ies; |
2727 | __le16 lestatus, le_tmp; |
2728 | |
2729 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
2730 | if (!pmgntframe) |
2731 | return; |
2732 | |
2733 | /* update attribute */ |
2734 | pattrib = &pmgntframe->attrib; |
2735 | update_mgntframe_attrib(padapter, pattrib); |
2736 | |
2737 | |
2738 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
2739 | |
2740 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
2741 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
2742 | |
2743 | fctrl = &(pwlanhdr->frame_control); |
2744 | *(fctrl) = 0; |
2745 | |
2746 | memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN); |
2747 | memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&(padapter->eeprompriv)), ETH_ALEN); |
2748 | memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
2749 | |
2750 | |
2751 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
2752 | pmlmeext->mgnt_seq++; |
2753 | if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) |
2754 | SetFrameSubType(pwlanhdr, pkt_type); |
2755 | else |
2756 | return; |
2757 | |
2758 | pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); |
2759 | pattrib->pktlen += pattrib->hdrlen; |
2760 | pframe += pattrib->hdrlen; |
2761 | |
2762 | /* capability */ |
2763 | val = *(unsigned short *)rtw_get_capability_from_ie(ie); |
2764 | |
2765 | pframe = rtw_set_fixed_ie(pbuf: pframe, _CAPABILITY_, source: (unsigned char *)&val, frlen: &(pattrib->pktlen)); |
2766 | |
2767 | lestatus = cpu_to_le16(status); |
2768 | pframe = rtw_set_fixed_ie(pbuf: pframe, _STATUS_CODE_, source: (unsigned char *)&lestatus, frlen: &(pattrib->pktlen)); |
2769 | |
2770 | le_tmp = cpu_to_le16(pstat->aid | BIT(14) | BIT(15)); |
2771 | pframe = rtw_set_fixed_ie(pbuf: pframe, _ASOC_ID_, source: (unsigned char *)&le_tmp, frlen: &(pattrib->pktlen)); |
2772 | |
2773 | if (pstat->bssratelen <= 8) { |
2774 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SUPP_RATES, len: pstat->bssratelen, source: pstat->bssrateset, frlen: &(pattrib->pktlen)); |
2775 | } else { |
2776 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SUPP_RATES, len: 8, source: pstat->bssrateset, frlen: &(pattrib->pktlen)); |
2777 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_EXT_SUPP_RATES, len: (pstat->bssratelen-8), source: pstat->bssrateset+8, frlen: &(pattrib->pktlen)); |
2778 | } |
2779 | |
2780 | if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) { |
2781 | uint ie_len = 0; |
2782 | |
2783 | /* FILL HT CAP INFO IE */ |
2784 | /* p = hostapd_eid_ht_capabilities_info(hapd, p); */ |
2785 | pbuf = rtw_get_ie(pbuf: ie + _BEACON_IE_OFFSET_, index: WLAN_EID_HT_CAPABILITY, len: &ie_len, limit: (pnetwork->ie_length - _BEACON_IE_OFFSET_)); |
2786 | if (pbuf && ie_len > 0) { |
2787 | memcpy(pframe, pbuf, ie_len+2); |
2788 | pframe += (ie_len+2); |
2789 | pattrib->pktlen += (ie_len+2); |
2790 | } |
2791 | |
2792 | /* FILL HT ADD INFO IE */ |
2793 | /* p = hostapd_eid_ht_operation(hapd, p); */ |
2794 | pbuf = rtw_get_ie(pbuf: ie + _BEACON_IE_OFFSET_, index: WLAN_EID_HT_OPERATION, len: &ie_len, limit: (pnetwork->ie_length - _BEACON_IE_OFFSET_)); |
2795 | if (pbuf && ie_len > 0) { |
2796 | memcpy(pframe, pbuf, ie_len+2); |
2797 | pframe += (ie_len+2); |
2798 | pattrib->pktlen += (ie_len+2); |
2799 | } |
2800 | |
2801 | } |
2802 | |
2803 | /* FILL WMM IE */ |
2804 | if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) { |
2805 | uint ie_len = 0; |
2806 | unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; |
2807 | |
2808 | for (pbuf = ie + _BEACON_IE_OFFSET_; ; pbuf += (ie_len + 2)) { |
2809 | pbuf = rtw_get_ie(pbuf, index: WLAN_EID_VENDOR_SPECIFIC, len: &ie_len, limit: (pnetwork->ie_length - _BEACON_IE_OFFSET_ - (ie_len + 2))); |
2810 | if (pbuf && !memcmp(p: pbuf+2, q: WMM_PARA_IE, size: 6)) { |
2811 | memcpy(pframe, pbuf, ie_len+2); |
2812 | pframe += (ie_len+2); |
2813 | pattrib->pktlen += (ie_len+2); |
2814 | |
2815 | break; |
2816 | } |
2817 | |
2818 | if (!pbuf || ie_len == 0) |
2819 | break; |
2820 | } |
2821 | |
2822 | } |
2823 | |
2824 | if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) |
2825 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_VENDOR_SPECIFIC, len: 6, source: REALTEK_96B_IE, frlen: &(pattrib->pktlen)); |
2826 | |
2827 | /* add WPS IE ie for wps 2.0 */ |
2828 | if (pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len > 0) { |
2829 | memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len); |
2830 | |
2831 | pframe += pmlmepriv->wps_assoc_resp_ie_len; |
2832 | pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len; |
2833 | } |
2834 | |
2835 | pattrib->last_txcmdsz = pattrib->pktlen; |
2836 | |
2837 | dump_mgntframe(padapter, pmgntframe); |
2838 | } |
2839 | |
2840 | void issue_assocreq(struct adapter *padapter) |
2841 | { |
2842 | int ret = _FAIL; |
2843 | struct xmit_frame *pmgntframe; |
2844 | struct pkt_attrib *pattrib; |
2845 | unsigned char *pframe; |
2846 | struct ieee80211_hdr *pwlanhdr; |
2847 | __le16 *fctrl; |
2848 | __le16 val16; |
2849 | unsigned int i, j, index = 0; |
2850 | unsigned char bssrate[NumRates], sta_bssrate[NumRates]; |
2851 | struct ndis_80211_var_ie *pIE; |
2852 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
2853 | struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); |
2854 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
2855 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
2856 | int bssrate_len = 0, sta_bssrate_len = 0; |
2857 | u8 vs_ie_length = 0; |
2858 | |
2859 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
2860 | if (!pmgntframe) |
2861 | goto exit; |
2862 | |
2863 | /* update attribute */ |
2864 | pattrib = &pmgntframe->attrib; |
2865 | update_mgntframe_attrib(padapter, pattrib); |
2866 | |
2867 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
2868 | |
2869 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
2870 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
2871 | |
2872 | fctrl = &(pwlanhdr->frame_control); |
2873 | *(fctrl) = 0; |
2874 | memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
2875 | memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); |
2876 | memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
2877 | |
2878 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
2879 | pmlmeext->mgnt_seq++; |
2880 | SetFrameSubType(pframe, WIFI_ASSOCREQ); |
2881 | |
2882 | pframe += sizeof(struct ieee80211_hdr_3addr); |
2883 | pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); |
2884 | |
2885 | /* caps */ |
2886 | memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.ies), 2); |
2887 | |
2888 | pframe += 2; |
2889 | pattrib->pktlen += 2; |
2890 | |
2891 | /* listen interval */ |
2892 | /* todo: listen interval for power saving */ |
2893 | val16 = cpu_to_le16(3); |
2894 | memcpy(pframe, (unsigned char *)&val16, 2); |
2895 | pframe += 2; |
2896 | pattrib->pktlen += 2; |
2897 | |
2898 | /* SSID */ |
2899 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SSID, len: pmlmeinfo->network.ssid.ssid_length, source: pmlmeinfo->network.ssid.ssid, frlen: &(pattrib->pktlen)); |
2900 | |
2901 | /* supported rate & extended supported rate */ |
2902 | |
2903 | /* Check if the AP's supported rates are also supported by STA. */ |
2904 | get_rate_set(padapter, pbssrate: sta_bssrate, bssrate_len: &sta_bssrate_len); |
2905 | |
2906 | if (pmlmeext->cur_channel == 14) /* for JAPAN, channel 14 can only uses B Mode(CCK) */ |
2907 | sta_bssrate_len = 4; |
2908 | |
2909 | |
2910 | /* for (i = 0; i < sta_bssrate_len; i++) { */ |
2911 | /* */ |
2912 | |
2913 | for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { |
2914 | if (pmlmeinfo->network.supported_rates[i] == 0) |
2915 | break; |
2916 | } |
2917 | |
2918 | |
2919 | for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { |
2920 | if (pmlmeinfo->network.supported_rates[i] == 0) |
2921 | break; |
2922 | |
2923 | |
2924 | /* Check if the AP's supported rates are also supported by STA. */ |
2925 | for (j = 0; j < sta_bssrate_len; j++) { |
2926 | /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ |
2927 | if ((pmlmeinfo->network.supported_rates[i] | IEEE80211_BASIC_RATE_MASK) |
2928 | == (sta_bssrate[j] | IEEE80211_BASIC_RATE_MASK)) |
2929 | break; |
2930 | } |
2931 | |
2932 | if (j != sta_bssrate_len) |
2933 | /* the rate is supported by STA */ |
2934 | bssrate[index++] = pmlmeinfo->network.supported_rates[i]; |
2935 | } |
2936 | |
2937 | bssrate_len = index; |
2938 | |
2939 | if (bssrate_len == 0) { |
2940 | rtw_free_xmitbuf(pxmitpriv, pxmitbuf: pmgntframe->pxmitbuf); |
2941 | rtw_free_xmitframe(pxmitpriv, pxmitframe: pmgntframe); |
2942 | goto exit; /* don't connect to AP if no joint supported rate */ |
2943 | } |
2944 | |
2945 | |
2946 | if (bssrate_len > 8) { |
2947 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SUPP_RATES, len: 8, source: bssrate, frlen: &(pattrib->pktlen)); |
2948 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_EXT_SUPP_RATES, len: (bssrate_len - 8), source: (bssrate + 8), frlen: &(pattrib->pktlen)); |
2949 | } else |
2950 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_SUPP_RATES, len: bssrate_len, source: bssrate, frlen: &(pattrib->pktlen)); |
2951 | |
2952 | /* vendor specific IE, such as WPA, WMM, WPS */ |
2953 | for (i = sizeof(struct ndis_802_11_fix_ie); i < pmlmeinfo->network.ie_length;) { |
2954 | pIE = (struct ndis_80211_var_ie *)(pmlmeinfo->network.ies + i); |
2955 | |
2956 | switch (pIE->element_id) { |
2957 | case WLAN_EID_VENDOR_SPECIFIC: |
2958 | if ((!memcmp(p: pIE->data, q: RTW_WPA_OUI, size: 4)) || |
2959 | (!memcmp(p: pIE->data, q: WMM_OUI, size: 4)) || |
2960 | (!memcmp(p: pIE->data, q: WPS_OUI, size: 4))) { |
2961 | vs_ie_length = pIE->length; |
2962 | if ((!padapter->registrypriv.wifi_spec) && (!memcmp(p: pIE->data, q: WPS_OUI, size: 4))) { |
2963 | /* Commented by Kurt 20110629 |
2964 | * In some older APs, WPS handshake |
2965 | * would be fail if we append vendor |
2966 | * extensions information to AP |
2967 | */ |
2968 | |
2969 | vs_ie_length = 14; |
2970 | } |
2971 | |
2972 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_VENDOR_SPECIFIC, len: vs_ie_length, source: pIE->data, frlen: &(pattrib->pktlen)); |
2973 | } |
2974 | break; |
2975 | |
2976 | case WLAN_EID_RSN: |
2977 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_RSN, len: pIE->length, source: pIE->data, frlen: &(pattrib->pktlen)); |
2978 | break; |
2979 | case WLAN_EID_HT_CAPABILITY: |
2980 | if (padapter->mlmepriv.htpriv.ht_option) { |
2981 | if (!(is_ap_in_tkip(padapter))) { |
2982 | memcpy(&(pmlmeinfo->HT_caps), pIE->data, sizeof(struct HT_caps_element)); |
2983 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_HT_CAPABILITY, len: pIE->length, source: (u8 *)(&(pmlmeinfo->HT_caps)), frlen: &(pattrib->pktlen)); |
2984 | } |
2985 | } |
2986 | break; |
2987 | |
2988 | case WLAN_EID_EXT_CAPABILITY: |
2989 | if (padapter->mlmepriv.htpriv.ht_option) |
2990 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_EXT_CAPABILITY, len: pIE->length, source: pIE->data, frlen: &(pattrib->pktlen)); |
2991 | break; |
2992 | default: |
2993 | break; |
2994 | } |
2995 | |
2996 | i += (pIE->length + 2); |
2997 | } |
2998 | |
2999 | if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) |
3000 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_VENDOR_SPECIFIC, len: 6, source: REALTEK_96B_IE, frlen: &(pattrib->pktlen)); |
3001 | |
3002 | |
3003 | pattrib->last_txcmdsz = pattrib->pktlen; |
3004 | dump_mgntframe(padapter, pmgntframe); |
3005 | |
3006 | ret = _SUCCESS; |
3007 | |
3008 | exit: |
3009 | if (ret == _SUCCESS) |
3010 | rtw_buf_update(buf: &pmlmepriv->assoc_req, buf_len: &pmlmepriv->assoc_req_len, src: (u8 *)pwlanhdr, src_len: pattrib->pktlen); |
3011 | else |
3012 | rtw_buf_free(buf: &pmlmepriv->assoc_req, buf_len: &pmlmepriv->assoc_req_len); |
3013 | } |
3014 | |
3015 | /* when wait_ack is true, this function should be called at process context */ |
3016 | static int _issue_nulldata(struct adapter *padapter, unsigned char *da, |
3017 | unsigned int power_mode, bool wait_ack) |
3018 | { |
3019 | int ret = _FAIL; |
3020 | struct xmit_frame *pmgntframe; |
3021 | struct pkt_attrib *pattrib; |
3022 | unsigned char *pframe; |
3023 | struct ieee80211_hdr *pwlanhdr; |
3024 | __le16 *fctrl; |
3025 | struct xmit_priv *pxmitpriv; |
3026 | struct mlme_ext_priv *pmlmeext; |
3027 | struct mlme_ext_info *pmlmeinfo; |
3028 | |
3029 | if (!padapter) |
3030 | goto exit; |
3031 | |
3032 | pxmitpriv = &(padapter->xmitpriv); |
3033 | pmlmeext = &(padapter->mlmeextpriv); |
3034 | pmlmeinfo = &(pmlmeext->mlmext_info); |
3035 | |
3036 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
3037 | if (!pmgntframe) |
3038 | goto exit; |
3039 | |
3040 | /* update attribute */ |
3041 | pattrib = &pmgntframe->attrib; |
3042 | update_mgntframe_attrib(padapter, pattrib); |
3043 | pattrib->retry_ctrl = false; |
3044 | |
3045 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
3046 | |
3047 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
3048 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
3049 | |
3050 | fctrl = &(pwlanhdr->frame_control); |
3051 | *(fctrl) = 0; |
3052 | |
3053 | if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) |
3054 | SetFrDs(fctrl); |
3055 | else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) |
3056 | SetToDs(fctrl); |
3057 | |
3058 | if (power_mode) |
3059 | SetPwrMgt(fctrl); |
3060 | |
3061 | memcpy(pwlanhdr->addr1, da, ETH_ALEN); |
3062 | memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); |
3063 | memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
3064 | |
3065 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
3066 | pmlmeext->mgnt_seq++; |
3067 | SetFrameSubType(pframe, WIFI_DATA_NULL); |
3068 | |
3069 | pframe += sizeof(struct ieee80211_hdr_3addr); |
3070 | pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); |
3071 | |
3072 | pattrib->last_txcmdsz = pattrib->pktlen; |
3073 | |
3074 | if (wait_ack) { |
3075 | ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); |
3076 | } else { |
3077 | dump_mgntframe(padapter, pmgntframe); |
3078 | ret = _SUCCESS; |
3079 | } |
3080 | |
3081 | exit: |
3082 | return ret; |
3083 | } |
3084 | |
3085 | /* |
3086 | * [IMPORTANT] Don't call this function in interrupt context |
3087 | * |
3088 | * When wait_ms > 0, this function should be called at process context |
3089 | * da == NULL for station mode |
3090 | */ |
3091 | int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) |
3092 | { |
3093 | int ret; |
3094 | int i = 0; |
3095 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
3096 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
3097 | struct sta_info *psta; |
3098 | |
3099 | |
3100 | /* da == NULL, assume it's null data for sta to ap*/ |
3101 | if (!da) |
3102 | da = get_my_bssid(pnetwork: &(pmlmeinfo->network)); |
3103 | |
3104 | psta = rtw_get_stainfo(pstapriv: &padapter->stapriv, hwaddr: da); |
3105 | if (psta) { |
3106 | if (power_mode) |
3107 | rtw_hal_macid_sleep(padapter, macid: psta->mac_id); |
3108 | else |
3109 | rtw_hal_macid_wakeup(padapter, macid: psta->mac_id); |
3110 | } else { |
3111 | rtw_warn_on(1); |
3112 | } |
3113 | |
3114 | do { |
3115 | ret = _issue_nulldata(padapter, da, power_mode, wait_ack: wait_ms > 0); |
3116 | |
3117 | i++; |
3118 | |
3119 | if (padapter->bDriverStopped || padapter->bSurpriseRemoved) |
3120 | break; |
3121 | |
3122 | if (i < try_cnt && wait_ms > 0 && ret == _FAIL) |
3123 | msleep(msecs: wait_ms); |
3124 | |
3125 | } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); |
3126 | |
3127 | if (ret != _FAIL) { |
3128 | ret = _SUCCESS; |
3129 | #ifndef DBG_XMIT_ACK |
3130 | goto exit; |
3131 | #endif |
3132 | } |
3133 | |
3134 | exit: |
3135 | return ret; |
3136 | } |
3137 | |
3138 | /* |
3139 | * [IMPORTANT] This function run in interrupt context |
3140 | * |
3141 | * The null data packet would be sent without power bit, |
3142 | * and not guarantee success. |
3143 | */ |
3144 | s32 issue_nulldata_in_interrupt(struct adapter *padapter, u8 *da) |
3145 | { |
3146 | struct mlme_ext_priv *pmlmeext; |
3147 | struct mlme_ext_info *pmlmeinfo; |
3148 | |
3149 | |
3150 | pmlmeext = &padapter->mlmeextpriv; |
3151 | pmlmeinfo = &pmlmeext->mlmext_info; |
3152 | |
3153 | /* da == NULL, assume it's null data for sta to ap*/ |
3154 | if (!da) |
3155 | da = get_my_bssid(pnetwork: &(pmlmeinfo->network)); |
3156 | |
3157 | return _issue_nulldata(padapter, da, power_mode: 0, wait_ack: false); |
3158 | } |
3159 | |
3160 | /* when wait_ack is true, this function should be called at process context */ |
3161 | static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, |
3162 | u16 tid, bool wait_ack) |
3163 | { |
3164 | int ret = _FAIL; |
3165 | struct xmit_frame *pmgntframe; |
3166 | struct pkt_attrib *pattrib; |
3167 | unsigned char *pframe; |
3168 | struct ieee80211_hdr *pwlanhdr; |
3169 | __le16 *fctrl; |
3170 | u16 *qc; |
3171 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
3172 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
3173 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
3174 | |
3175 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
3176 | if (!pmgntframe) |
3177 | goto exit; |
3178 | |
3179 | /* update attribute */ |
3180 | pattrib = &pmgntframe->attrib; |
3181 | update_mgntframe_attrib(padapter, pattrib); |
3182 | |
3183 | pattrib->hdrlen += 2; |
3184 | pattrib->qos_en = true; |
3185 | pattrib->eosp = 1; |
3186 | pattrib->ack_policy = 0; |
3187 | pattrib->mdata = 0; |
3188 | |
3189 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
3190 | |
3191 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
3192 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
3193 | |
3194 | fctrl = &(pwlanhdr->frame_control); |
3195 | *(fctrl) = 0; |
3196 | |
3197 | if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) |
3198 | SetFrDs(fctrl); |
3199 | else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) |
3200 | SetToDs(fctrl); |
3201 | |
3202 | qc = (unsigned short *)(pframe + pattrib->hdrlen - 2); |
3203 | |
3204 | SetPriority(qc, tid); |
3205 | |
3206 | SetEOSP(qc, pattrib->eosp); |
3207 | |
3208 | SetAckpolicy(qc, pattrib->ack_policy); |
3209 | |
3210 | memcpy(pwlanhdr->addr1, da, ETH_ALEN); |
3211 | memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); |
3212 | memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
3213 | |
3214 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
3215 | pmlmeext->mgnt_seq++; |
3216 | SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); |
3217 | |
3218 | pframe += sizeof(struct ieee80211_qos_hdr); |
3219 | pattrib->pktlen = sizeof(struct ieee80211_qos_hdr); |
3220 | |
3221 | pattrib->last_txcmdsz = pattrib->pktlen; |
3222 | |
3223 | if (wait_ack) { |
3224 | ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); |
3225 | } else { |
3226 | dump_mgntframe(padapter, pmgntframe); |
3227 | ret = _SUCCESS; |
3228 | } |
3229 | |
3230 | exit: |
3231 | return ret; |
3232 | } |
3233 | |
3234 | /* when wait_ms >0 , this function should be called at process context */ |
3235 | /* da == NULL for station mode */ |
3236 | int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms) |
3237 | { |
3238 | int ret; |
3239 | int i = 0; |
3240 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
3241 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
3242 | |
3243 | /* da == NULL, assume it's null data for sta to ap*/ |
3244 | if (!da) |
3245 | da = get_my_bssid(pnetwork: &(pmlmeinfo->network)); |
3246 | |
3247 | do { |
3248 | ret = _issue_qos_nulldata(padapter, da, tid, wait_ack: wait_ms > 0); |
3249 | |
3250 | i++; |
3251 | |
3252 | if (padapter->bDriverStopped || padapter->bSurpriseRemoved) |
3253 | break; |
3254 | |
3255 | if (i < try_cnt && wait_ms > 0 && ret == _FAIL) |
3256 | msleep(msecs: wait_ms); |
3257 | |
3258 | } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); |
3259 | |
3260 | if (ret != _FAIL) { |
3261 | ret = _SUCCESS; |
3262 | #ifndef DBG_XMIT_ACK |
3263 | goto exit; |
3264 | #endif |
3265 | } |
3266 | |
3267 | exit: |
3268 | return ret; |
3269 | } |
3270 | |
3271 | static int _issue_deauth(struct adapter *padapter, unsigned char *da, |
3272 | unsigned short reason, bool wait_ack) |
3273 | { |
3274 | struct xmit_frame *pmgntframe; |
3275 | struct pkt_attrib *pattrib; |
3276 | unsigned char *pframe; |
3277 | struct ieee80211_hdr *pwlanhdr; |
3278 | __le16 *fctrl; |
3279 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
3280 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
3281 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
3282 | int ret = _FAIL; |
3283 | __le16 le_tmp; |
3284 | |
3285 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
3286 | if (!pmgntframe) |
3287 | goto exit; |
3288 | |
3289 | /* update attribute */ |
3290 | pattrib = &pmgntframe->attrib; |
3291 | update_mgntframe_attrib(padapter, pattrib); |
3292 | pattrib->retry_ctrl = false; |
3293 | |
3294 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
3295 | |
3296 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
3297 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
3298 | |
3299 | fctrl = &(pwlanhdr->frame_control); |
3300 | *(fctrl) = 0; |
3301 | |
3302 | memcpy(pwlanhdr->addr1, da, ETH_ALEN); |
3303 | memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); |
3304 | memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
3305 | |
3306 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
3307 | pmlmeext->mgnt_seq++; |
3308 | SetFrameSubType(pframe, WIFI_DEAUTH); |
3309 | |
3310 | pframe += sizeof(struct ieee80211_hdr_3addr); |
3311 | pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); |
3312 | |
3313 | le_tmp = cpu_to_le16(reason); |
3314 | pframe = rtw_set_fixed_ie(pbuf: pframe, _RSON_CODE_, source: (unsigned char *)&le_tmp, frlen: &(pattrib->pktlen)); |
3315 | |
3316 | pattrib->last_txcmdsz = pattrib->pktlen; |
3317 | |
3318 | |
3319 | if (wait_ack) { |
3320 | ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); |
3321 | } else { |
3322 | dump_mgntframe(padapter, pmgntframe); |
3323 | ret = _SUCCESS; |
3324 | } |
3325 | |
3326 | exit: |
3327 | return ret; |
3328 | } |
3329 | |
3330 | int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason) |
3331 | { |
3332 | return _issue_deauth(padapter, da, reason, wait_ack: false); |
3333 | } |
3334 | |
3335 | int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int try_cnt, |
3336 | int wait_ms) |
3337 | { |
3338 | int ret; |
3339 | int i = 0; |
3340 | |
3341 | do { |
3342 | ret = _issue_deauth(padapter, da, reason, wait_ack: wait_ms > 0); |
3343 | |
3344 | i++; |
3345 | |
3346 | if (padapter->bDriverStopped || padapter->bSurpriseRemoved) |
3347 | break; |
3348 | |
3349 | if (i < try_cnt && wait_ms > 0 && ret == _FAIL) |
3350 | mdelay(wait_ms); |
3351 | |
3352 | } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); |
3353 | |
3354 | if (ret != _FAIL) { |
3355 | ret = _SUCCESS; |
3356 | #ifndef DBG_XMIT_ACK |
3357 | goto exit; |
3358 | #endif |
3359 | } |
3360 | |
3361 | exit: |
3362 | return ret; |
3363 | } |
3364 | |
3365 | void issue_action_SA_Query(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short tid) |
3366 | { |
3367 | u8 category = RTW_WLAN_CATEGORY_SA_QUERY; |
3368 | struct xmit_frame *pmgntframe; |
3369 | struct pkt_attrib *pattrib; |
3370 | u8 *pframe; |
3371 | struct ieee80211_hdr *pwlanhdr; |
3372 | __le16 *fctrl; |
3373 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
3374 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
3375 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
3376 | __le16 le_tmp; |
3377 | |
3378 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
3379 | if (!pmgntframe) |
3380 | return; |
3381 | |
3382 | /* update attribute */ |
3383 | pattrib = &pmgntframe->attrib; |
3384 | update_mgntframe_attrib(padapter, pattrib); |
3385 | |
3386 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
3387 | |
3388 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
3389 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
3390 | |
3391 | fctrl = &(pwlanhdr->frame_control); |
3392 | *(fctrl) = 0; |
3393 | |
3394 | if (raddr) |
3395 | memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); |
3396 | else |
3397 | memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
3398 | memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); |
3399 | memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
3400 | |
3401 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
3402 | pmlmeext->mgnt_seq++; |
3403 | SetFrameSubType(pframe, WIFI_ACTION); |
3404 | |
3405 | pframe += sizeof(struct ieee80211_hdr_3addr); |
3406 | pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); |
3407 | |
3408 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 1, source: &category, frlen: &pattrib->pktlen); |
3409 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 1, source: &action, frlen: &pattrib->pktlen); |
3410 | |
3411 | switch (action) { |
3412 | case 0: /* SA Query req */ |
3413 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 2, source: (unsigned char *)&pmlmeext->sa_query_seq, frlen: &pattrib->pktlen); |
3414 | pmlmeext->sa_query_seq++; |
3415 | /* send sa query request to AP, AP should reply sa query response in 1 second */ |
3416 | set_sa_query_timer(pmlmeext, 1000); |
3417 | break; |
3418 | |
3419 | case 1: /* SA Query rsp */ |
3420 | le_tmp = cpu_to_le16(tid); |
3421 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 2, source: (unsigned char *)&le_tmp, frlen: &pattrib->pktlen); |
3422 | break; |
3423 | default: |
3424 | break; |
3425 | } |
3426 | |
3427 | pattrib->last_txcmdsz = pattrib->pktlen; |
3428 | |
3429 | dump_mgntframe(padapter, pmgntframe); |
3430 | } |
3431 | |
3432 | void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status) |
3433 | { |
3434 | u8 category = RTW_WLAN_CATEGORY_BACK; |
3435 | u16 start_seq; |
3436 | u16 BA_para_set; |
3437 | u16 reason_code; |
3438 | u16 BA_timeout_value; |
3439 | u16 BA_starting_seqctrl = 0; |
3440 | enum ieee80211_max_ampdu_length_exp max_rx_ampdu_factor; |
3441 | struct xmit_frame *pmgntframe; |
3442 | struct pkt_attrib *pattrib; |
3443 | u8 *pframe; |
3444 | struct ieee80211_hdr *pwlanhdr; |
3445 | __le16 *fctrl; |
3446 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
3447 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
3448 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
3449 | struct sta_info *psta; |
3450 | struct sta_priv *pstapriv = &padapter->stapriv; |
3451 | struct registry_priv *pregpriv = &padapter->registrypriv; |
3452 | __le16 le_tmp; |
3453 | |
3454 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
3455 | if (!pmgntframe) |
3456 | return; |
3457 | |
3458 | /* update attribute */ |
3459 | pattrib = &pmgntframe->attrib; |
3460 | update_mgntframe_attrib(padapter, pattrib); |
3461 | |
3462 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
3463 | |
3464 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
3465 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
3466 | |
3467 | fctrl = &(pwlanhdr->frame_control); |
3468 | *(fctrl) = 0; |
3469 | |
3470 | /* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */ |
3471 | memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); |
3472 | memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); |
3473 | memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
3474 | |
3475 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
3476 | pmlmeext->mgnt_seq++; |
3477 | SetFrameSubType(pframe, WIFI_ACTION); |
3478 | |
3479 | pframe += sizeof(struct ieee80211_hdr_3addr); |
3480 | pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); |
3481 | |
3482 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 1, source: &(category), frlen: &(pattrib->pktlen)); |
3483 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 1, source: &(action), frlen: &(pattrib->pktlen)); |
3484 | |
3485 | if (category == 3) { |
3486 | switch (action) { |
3487 | case 0: /* ADDBA req */ |
3488 | do { |
3489 | pmlmeinfo->dialogToken++; |
3490 | } while (pmlmeinfo->dialogToken == 0); |
3491 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 1, source: &(pmlmeinfo->dialogToken), frlen: &(pattrib->pktlen)); |
3492 | |
3493 | if (hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter)) { |
3494 | /* A-MSDU NOT Supported */ |
3495 | BA_para_set = 0; |
3496 | /* immediate Block Ack */ |
3497 | BA_para_set |= BIT(1) & IEEE80211_ADDBA_PARAM_POLICY_MASK; |
3498 | /* TID */ |
3499 | BA_para_set |= (status << 2) & IEEE80211_ADDBA_PARAM_TID_MASK; |
3500 | /* max buffer size is 8 MSDU */ |
3501 | BA_para_set |= (8 << 6) & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; |
3502 | } else { |
3503 | BA_para_set = (0x1002 | ((status & 0xf) << 2)); /* immediate ack & 64 buffer size */ |
3504 | } |
3505 | le_tmp = cpu_to_le16(BA_para_set); |
3506 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 2, source: (unsigned char *)(&(le_tmp)), frlen: &(pattrib->pktlen)); |
3507 | |
3508 | BA_timeout_value = 5000;/* 5ms */ |
3509 | le_tmp = cpu_to_le16(BA_timeout_value); |
3510 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 2, source: (unsigned char *)(&(le_tmp)), frlen: &(pattrib->pktlen)); |
3511 | |
3512 | /* if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.mac_address)) != NULL) */ |
3513 | psta = rtw_get_stainfo(pstapriv, hwaddr: raddr); |
3514 | if (psta) { |
3515 | start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1; |
3516 | |
3517 | psta->BA_starting_seqctrl[status & 0x07] = start_seq; |
3518 | |
3519 | BA_starting_seqctrl = start_seq << 4; |
3520 | } |
3521 | |
3522 | le_tmp = cpu_to_le16(BA_starting_seqctrl); |
3523 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 2, source: (unsigned char *)(&(le_tmp)), frlen: &(pattrib->pktlen)); |
3524 | break; |
3525 | |
3526 | case 1: /* ADDBA rsp */ |
3527 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 1, source: &(pmlmeinfo->ADDBA_req.dialog_token), frlen: &(pattrib->pktlen)); |
3528 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 2, source: (unsigned char *)(&status), frlen: &(pattrib->pktlen)); |
3529 | if (padapter->driver_rx_ampdu_factor != 0xFF) |
3530 | max_rx_ampdu_factor = |
3531 | (enum ieee80211_max_ampdu_length_exp)padapter->driver_rx_ampdu_factor; |
3532 | else |
3533 | rtw_hal_get_def_var(padapter, |
3534 | eVariable: HW_VAR_MAX_RX_AMPDU_FACTOR, pValue: &max_rx_ampdu_factor); |
3535 | |
3536 | if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_64K) |
3537 | BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */ |
3538 | else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_32K) |
3539 | BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0800); /* 32 buffer size */ |
3540 | else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_16K) |
3541 | BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0400); /* 16 buffer size */ |
3542 | else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_8K) |
3543 | BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0200); /* 8 buffer size */ |
3544 | else |
3545 | BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */ |
3546 | |
3547 | if (hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter) && |
3548 | padapter->driver_rx_ampdu_factor == 0xFF) { |
3549 | /* max buffer size is 8 MSDU */ |
3550 | BA_para_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; |
3551 | BA_para_set |= (8 << 6) & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; |
3552 | } |
3553 | |
3554 | if (pregpriv->ampdu_amsdu == 0)/* disabled */ |
3555 | le_tmp = cpu_to_le16(BA_para_set & ~BIT(0)); |
3556 | else if (pregpriv->ampdu_amsdu == 1)/* enabled */ |
3557 | le_tmp = cpu_to_le16(BA_para_set | BIT(0)); |
3558 | else /* auto */ |
3559 | le_tmp = cpu_to_le16(BA_para_set); |
3560 | |
3561 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 2, source: (unsigned char *)(&(le_tmp)), frlen: &(pattrib->pktlen)); |
3562 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 2, source: (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), frlen: &(pattrib->pktlen)); |
3563 | break; |
3564 | case 2:/* DELBA */ |
3565 | BA_para_set = (status & 0x1F) << 3; |
3566 | le_tmp = cpu_to_le16(BA_para_set); |
3567 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 2, source: (unsigned char *)(&(le_tmp)), frlen: &(pattrib->pktlen)); |
3568 | |
3569 | reason_code = 37; |
3570 | le_tmp = cpu_to_le16(reason_code); |
3571 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 2, source: (unsigned char *)(&(le_tmp)), frlen: &(pattrib->pktlen)); |
3572 | break; |
3573 | default: |
3574 | break; |
3575 | } |
3576 | } |
3577 | |
3578 | pattrib->last_txcmdsz = pattrib->pktlen; |
3579 | |
3580 | dump_mgntframe(padapter, pmgntframe); |
3581 | } |
3582 | |
3583 | static void issue_action_BSSCoexistPacket(struct adapter *padapter) |
3584 | { |
3585 | struct list_head *plist, *phead; |
3586 | unsigned char category, action; |
3587 | struct xmit_frame *pmgntframe; |
3588 | struct pkt_attrib *pattrib; |
3589 | unsigned char *pframe; |
3590 | struct ieee80211_hdr *pwlanhdr; |
3591 | __le16 *fctrl; |
3592 | struct wlan_network *pnetwork = NULL; |
3593 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
3594 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
3595 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
3596 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
3597 | struct __queue *queue = &(pmlmepriv->scanned_queue); |
3598 | u8 InfoContent[16] = {0}; |
3599 | u8 ICS[8][15]; |
3600 | |
3601 | if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0)) |
3602 | return; |
3603 | |
3604 | if (true == pmlmeinfo->bwmode_updated) |
3605 | return; |
3606 | |
3607 | category = RTW_WLAN_CATEGORY_PUBLIC; |
3608 | action = ACT_PUBLIC_BSSCOEXIST; |
3609 | |
3610 | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
3611 | if (!pmgntframe) |
3612 | return; |
3613 | |
3614 | /* update attribute */ |
3615 | pattrib = &pmgntframe->attrib; |
3616 | update_mgntframe_attrib(padapter, pattrib); |
3617 | |
3618 | memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
3619 | |
3620 | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
3621 | pwlanhdr = (struct ieee80211_hdr *)pframe; |
3622 | |
3623 | fctrl = &(pwlanhdr->frame_control); |
3624 | *(fctrl) = 0; |
3625 | |
3626 | memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
3627 | memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); |
3628 | memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
3629 | |
3630 | SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); |
3631 | pmlmeext->mgnt_seq++; |
3632 | SetFrameSubType(pframe, WIFI_ACTION); |
3633 | |
3634 | pframe += sizeof(struct ieee80211_hdr_3addr); |
3635 | pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); |
3636 | |
3637 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 1, source: &(category), frlen: &(pattrib->pktlen)); |
3638 | pframe = rtw_set_fixed_ie(pbuf: pframe, len: 1, source: &(action), frlen: &(pattrib->pktlen)); |
3639 | |
3640 | |
3641 | /* */ |
3642 | if (pmlmepriv->num_FortyMHzIntolerant > 0) { |
3643 | u8 iedata = 0; |
3644 | |
3645 | iedata |= BIT(2);/* 20 MHz BSS Width Request */ |
3646 | |
3647 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_BSS_COEX_2040, len: 1, source: &iedata, frlen: &(pattrib->pktlen)); |
3648 | |
3649 | } |
3650 | |
3651 | |
3652 | /* */ |
3653 | memset(ICS, 0, sizeof(ICS)); |
3654 | if (pmlmepriv->num_sta_no_ht > 0) { |
3655 | int i; |
3656 | |
3657 | spin_lock_bh(lock: &(pmlmepriv->scanned_queue.lock)); |
3658 | |
3659 | phead = get_list_head(queue); |
3660 | plist = get_next(list: phead); |
3661 | |
3662 | while (1) { |
3663 | int len; |
3664 | u8 *p; |
3665 | struct wlan_bssid_ex *pbss_network; |
3666 | |
3667 | if (phead == plist) |
3668 | break; |
3669 | |
3670 | pnetwork = container_of(plist, struct wlan_network, list); |
3671 | |
3672 | plist = get_next(list: plist); |
3673 | |
3674 | pbss_network = (struct wlan_bssid_ex *)&pnetwork->network; |
3675 | |
3676 | p = rtw_get_ie(pbuf: pbss_network->ies + _FIXED_IE_LENGTH_, index: WLAN_EID_HT_CAPABILITY, len: &len, limit: pbss_network->ie_length - _FIXED_IE_LENGTH_); |
3677 | if (!p || len == 0) {/* non-HT */ |
3678 | |
3679 | if (pbss_network->configuration.ds_config <= 0) |
3680 | continue; |
3681 | |
3682 | ICS[0][pbss_network->configuration.ds_config] = 1; |
3683 | |
3684 | if (ICS[0][0] == 0) |
3685 | ICS[0][0] = 1; |
3686 | } |
3687 | |
3688 | } |
3689 | |
3690 | spin_unlock_bh(lock: &(pmlmepriv->scanned_queue.lock)); |
3691 | |
3692 | |
3693 | for (i = 0; i < 8; i++) { |
3694 | if (ICS[i][0] == 1) { |
3695 | int j, k = 0; |
3696 | |
3697 | InfoContent[k] = i; |
3698 | /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */ |
3699 | k++; |
3700 | |
3701 | for (j = 1; j <= 14; j++) { |
3702 | if (ICS[i][j] == 1) { |
3703 | if (k < 16) { |
3704 | InfoContent[k] = j; /* channel number */ |
3705 | /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */ |
3706 | k++; |
3707 | } |
3708 | } |
3709 | } |
3710 | |
3711 | pframe = rtw_set_ie(pbuf: pframe, index: WLAN_EID_BSS_INTOLERANT_CHL_REPORT, len: k, source: InfoContent, frlen: &(pattrib->pktlen)); |
3712 | |
3713 | } |
3714 | |
3715 | } |
3716 | |
3717 | |
3718 | } |
3719 | |
3720 | |
3721 | pattrib->last_txcmdsz = pattrib->pktlen; |
3722 | |
3723 | dump_mgntframe(padapter, pmgntframe); |
3724 | } |
3725 | |
3726 | unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) |
3727 | { |
3728 | struct sta_priv *pstapriv = &padapter->stapriv; |
3729 | struct sta_info *psta = NULL; |
3730 | /* struct recv_reorder_ctrl *preorder_ctrl; */ |
3731 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
3732 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
3733 | u16 tid; |
3734 | |
3735 | if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) |
3736 | if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) |
3737 | return _SUCCESS; |
3738 | |
3739 | psta = rtw_get_stainfo(pstapriv, hwaddr: addr); |
3740 | if (!psta) |
3741 | return _SUCCESS; |
3742 | |
3743 | if (initiator == 0) {/* recipient */ |
3744 | for (tid = 0; tid < MAXTID; tid++) { |
3745 | if (psta->recvreorder_ctrl[tid].enable) { |
3746 | issue_action_BA(padapter, raddr: addr, action: WLAN_ACTION_DELBA, status: (((tid << 1) | initiator)&0x1F)); |
3747 | psta->recvreorder_ctrl[tid].enable = false; |
3748 | psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; |
3749 | } |
3750 | } |
3751 | } else if (initiator == 1) {/* originator */ |
3752 | for (tid = 0; tid < MAXTID; tid++) { |
3753 | if (psta->htpriv.agg_enable_bitmap & BIT(tid)) { |
3754 | issue_action_BA(padapter, raddr: addr, action: WLAN_ACTION_DELBA, status: (((tid << 1) | initiator)&0x1F)); |
3755 | psta->htpriv.agg_enable_bitmap &= ~BIT(tid); |
3756 | psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); |
3757 | |
3758 | } |
3759 | } |
3760 | } |
3761 | |
3762 | return _SUCCESS; |
3763 | |
3764 | } |
3765 | |
3766 | unsigned int send_beacon(struct adapter *padapter) |
3767 | { |
3768 | u8 bxmitok = false; |
3769 | int issue = 0; |
3770 | int poll = 0; |
3771 | |
3772 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_BCN_VALID, NULL); |
3773 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_DL_BCN_SEL, NULL); |
3774 | do { |
3775 | issue_beacon(padapter, timeout_ms: 100); |
3776 | issue++; |
3777 | do { |
3778 | cond_resched(); |
3779 | rtw_hal_get_hwreg(padapter, variable: HW_VAR_BCN_VALID, val: (u8 *)(&bxmitok)); |
3780 | poll++; |
3781 | } while ((poll%10) != 0 && false == bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); |
3782 | |
3783 | } while (false == bxmitok && issue < 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); |
3784 | |
3785 | if (padapter->bSurpriseRemoved || padapter->bDriverStopped) |
3786 | return _FAIL; |
3787 | |
3788 | if (!bxmitok) |
3789 | return _FAIL; |
3790 | else |
3791 | return _SUCCESS; |
3792 | } |
3793 | |
3794 | /**************************************************************************** |
3795 | |
3796 | Following are some utility functions for WiFi MLME |
3797 | |
3798 | *****************************************************************************/ |
3799 | |
3800 | void site_survey(struct adapter *padapter) |
3801 | { |
3802 | unsigned char survey_channel = 0, val8; |
3803 | enum rt_scan_type ScanType = SCAN_PASSIVE; |
3804 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
3805 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
3806 | u32 initialgain = 0; |
3807 | u32 channel_scan_time_ms = 0; |
3808 | |
3809 | { |
3810 | struct rtw_ieee80211_channel *ch; |
3811 | |
3812 | if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) { |
3813 | ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx]; |
3814 | survey_channel = ch->hw_value; |
3815 | ScanType = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE; |
3816 | } |
3817 | } |
3818 | |
3819 | if (survey_channel != 0) { |
3820 | /* PAUSE 4-AC Queue when site_survey */ |
3821 | /* rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ |
3822 | /* val8 |= 0x0f; */ |
3823 | /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ |
3824 | if (pmlmeext->sitesurvey_res.channel_idx == 0) { |
3825 | #ifdef DBG_FIXED_CHAN |
3826 | if (pmlmeext->fixed_chan != 0xff) |
3827 | set_channel_bwmode(padapter, pmlmeext->fixed_chan, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); |
3828 | else |
3829 | #endif |
3830 | set_channel_bwmode(padapter, channel: survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, bwmode: CHANNEL_WIDTH_20); |
3831 | } else { |
3832 | #ifdef DBG_FIXED_CHAN |
3833 | if (pmlmeext->fixed_chan != 0xff) |
3834 | SelectChannel(padapter, pmlmeext->fixed_chan); |
3835 | else |
3836 | #endif |
3837 | SelectChannel(padapter, channel: survey_channel); |
3838 | } |
3839 | |
3840 | if (ScanType == SCAN_ACTIVE) { /* obey the channel plan setting... */ |
3841 | { |
3842 | int i; |
3843 | |
3844 | for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { |
3845 | if (pmlmeext->sitesurvey_res.ssid[i].ssid_length) { |
3846 | /* IOT issue, When wifi_spec is not set, send one probe req without WPS IE. */ |
3847 | if (padapter->registrypriv.wifi_spec) |
3848 | issue_probereq(padapter, pssid: &(pmlmeext->sitesurvey_res.ssid[i]), NULL); |
3849 | else |
3850 | issue_probereq_ex(padapter, pssid: &(pmlmeext->sitesurvey_res.ssid[i]), NULL, ch: 0, append_wps: 0, try_cnt: 0, wait_ms: 0); |
3851 | issue_probereq(padapter, pssid: &(pmlmeext->sitesurvey_res.ssid[i]), NULL); |
3852 | } |
3853 | } |
3854 | |
3855 | if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { |
3856 | /* IOT issue, When wifi_spec is not set, send one probe req without WPS IE. */ |
3857 | if (padapter->registrypriv.wifi_spec) |
3858 | issue_probereq(padapter, NULL, NULL); |
3859 | else |
3860 | issue_probereq_ex(padapter, NULL, NULL, ch: 0, append_wps: 0, try_cnt: 0, wait_ms: 0); |
3861 | issue_probereq(padapter, NULL, NULL); |
3862 | } |
3863 | } |
3864 | } |
3865 | |
3866 | channel_scan_time_ms = pmlmeext->chan_scan_time; |
3867 | |
3868 | set_survey_timer(pmlmeext, channel_scan_time_ms); |
3869 | } else { |
3870 | |
3871 | /* channel number is 0 or this channel is not valid. */ |
3872 | |
3873 | { |
3874 | pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; |
3875 | |
3876 | /* switch back to the original channel */ |
3877 | /* SelectChannel(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); */ |
3878 | |
3879 | set_channel_bwmode(padapter, channel: pmlmeext->cur_channel, channel_offset: pmlmeext->cur_ch_offset, bwmode: pmlmeext->cur_bwmode); |
3880 | |
3881 | /* flush 4-AC Queue after site_survey */ |
3882 | /* val8 = 0; */ |
3883 | /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ |
3884 | |
3885 | /* config MSR */ |
3886 | Set_MSR(padapter, type: (pmlmeinfo->state & 0x3)); |
3887 | |
3888 | initialgain = 0xff; /* restore RX GAIN */ |
3889 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_INITIAL_GAIN, val: (u8 *)(&initialgain)); |
3890 | /* turn on dynamic functions */ |
3891 | Restore_DM_Func_Flag(padapter); |
3892 | /* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */ |
3893 | |
3894 | if (is_client_associated_to_ap(padapter)) |
3895 | issue_nulldata(padapter, NULL, power_mode: 0, try_cnt: 3, wait_ms: 500); |
3896 | |
3897 | val8 = 0; /* survey done */ |
3898 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_MLME_SITESURVEY, val: (u8 *)(&val8)); |
3899 | |
3900 | report_surveydone_event(padapter); |
3901 | |
3902 | pmlmeext->chan_scan_time = SURVEY_TO; |
3903 | pmlmeext->sitesurvey_res.state = SCAN_DISABLE; |
3904 | |
3905 | issue_action_BSSCoexistPacket(padapter); |
3906 | issue_action_BSSCoexistPacket(padapter); |
3907 | issue_action_BSSCoexistPacket(padapter); |
3908 | } |
3909 | } |
3910 | |
3911 | return; |
3912 | |
3913 | } |
3914 | |
3915 | /* collect bss info from Beacon and Probe request/response frames. */ |
3916 | u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, struct wlan_bssid_ex *bssid) |
3917 | { |
3918 | int i; |
3919 | u32 len; |
3920 | u8 *p; |
3921 | u16 val16, subtype; |
3922 | u8 *pframe = precv_frame->u.hdr.rx_data; |
3923 | u32 packet_len = precv_frame->u.hdr.len; |
3924 | u8 ie_offset; |
3925 | struct registry_priv *pregistrypriv = &padapter->registrypriv; |
3926 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
3927 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
3928 | __le32 le32_tmp; |
3929 | |
3930 | len = packet_len - sizeof(struct ieee80211_hdr_3addr); |
3931 | |
3932 | if (len > MAX_IE_SZ) |
3933 | return _FAIL; |
3934 | |
3935 | memset(bssid, 0, sizeof(struct wlan_bssid_ex)); |
3936 | |
3937 | subtype = GetFrameSubType(pframe); |
3938 | |
3939 | if (subtype == WIFI_BEACON) { |
3940 | bssid->reserved[0] = 1; |
3941 | ie_offset = _BEACON_IE_OFFSET_; |
3942 | } else { |
3943 | /* FIXME : more type */ |
3944 | if (subtype == WIFI_PROBERSP) { |
3945 | ie_offset = _PROBERSP_IE_OFFSET_; |
3946 | bssid->reserved[0] = 3; |
3947 | } else if (subtype == WIFI_PROBEREQ) { |
3948 | ie_offset = _PROBEREQ_IE_OFFSET_; |
3949 | bssid->reserved[0] = 2; |
3950 | } else { |
3951 | bssid->reserved[0] = 0; |
3952 | ie_offset = _FIXED_IE_LENGTH_; |
3953 | } |
3954 | } |
3955 | |
3956 | bssid->length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; |
3957 | |
3958 | /* below is to copy the information element */ |
3959 | bssid->ie_length = len; |
3960 | memcpy(bssid->ies, (pframe + sizeof(struct ieee80211_hdr_3addr)), bssid->ie_length); |
3961 | |
3962 | /* get the signal strength */ |
3963 | bssid->rssi = precv_frame->u.hdr.attrib.phy_info.RecvSignalPower; /* in dBM.raw data */ |
3964 | bssid->phy_info.signal_quality = precv_frame->u.hdr.attrib.phy_info.SignalQuality;/* in percentage */ |
3965 | bssid->phy_info.signal_strength = precv_frame->u.hdr.attrib.phy_info.SignalStrength;/* in percentage */ |
3966 | |
3967 | /* checking SSID */ |
3968 | p = rtw_get_ie(pbuf: bssid->ies + ie_offset, index: WLAN_EID_SSID, len: &len, limit: bssid->ie_length - ie_offset); |
3969 | if (!p) |
3970 | return _FAIL; |
3971 | |
3972 | if (*(p + 1)) { |
3973 | if (len > NDIS_802_11_LENGTH_SSID) |
3974 | return _FAIL; |
3975 | |
3976 | memcpy(bssid->ssid.ssid, (p + 2), *(p + 1)); |
3977 | bssid->ssid.ssid_length = *(p + 1); |
3978 | } else |
3979 | bssid->ssid.ssid_length = 0; |
3980 | |
3981 | memset(bssid->supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX); |
3982 | |
3983 | /* checking rate info... */ |
3984 | i = 0; |
3985 | p = rtw_get_ie(pbuf: bssid->ies + ie_offset, index: WLAN_EID_SUPP_RATES, len: &len, limit: bssid->ie_length - ie_offset); |
3986 | if (p) { |
3987 | if (len > NDIS_802_11_LENGTH_RATES_EX) |
3988 | return _FAIL; |
3989 | |
3990 | memcpy(bssid->supported_rates, (p + 2), len); |
3991 | i = len; |
3992 | } |
3993 | |
3994 | p = rtw_get_ie(pbuf: bssid->ies + ie_offset, index: WLAN_EID_EXT_SUPP_RATES, len: &len, limit: bssid->ie_length - ie_offset); |
3995 | if (p) { |
3996 | if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) |
3997 | return _FAIL; |
3998 | |
3999 | memcpy(bssid->supported_rates + i, (p + 2), len); |
4000 | } |
4001 | |
4002 | bssid->network_type_in_use = Ndis802_11OFDM24; |
4003 | |
4004 | if (bssid->ie_length < 12) |
4005 | return _FAIL; |
4006 | |
4007 | /* Checking for ds_config */ |
4008 | p = rtw_get_ie(pbuf: bssid->ies + ie_offset, index: WLAN_EID_DS_PARAMS, len: &len, limit: bssid->ie_length - ie_offset); |
4009 | |
4010 | bssid->configuration.ds_config = 0; |
4011 | bssid->configuration.length = 0; |
4012 | |
4013 | if (p) { |
4014 | bssid->configuration.ds_config = *(p + 2); |
4015 | } else { |
4016 | /* In 5G, some ap do not have DSSET IE */ |
4017 | /* checking HT info for channel */ |
4018 | p = rtw_get_ie(pbuf: bssid->ies + ie_offset, index: WLAN_EID_HT_OPERATION, len: &len, limit: bssid->ie_length - ie_offset); |
4019 | if (p) { |
4020 | struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2); |
4021 | |
4022 | bssid->configuration.ds_config = HT_info->primary_channel; |
4023 | } else { /* use current channel */ |
4024 | bssid->configuration.ds_config = rtw_get_oper_ch(adapter: padapter); |
4025 | } |
4026 | } |
4027 | |
4028 | memcpy(&le32_tmp, rtw_get_beacon_interval_from_ie(bssid->ies), 2); |
4029 | bssid->configuration.beacon_period = le32_to_cpu(le32_tmp); |
4030 | |
4031 | val16 = rtw_get_capability(bss: (struct wlan_bssid_ex *)bssid); |
4032 | |
4033 | if (val16 & BIT(0)) { |
4034 | bssid->infrastructure_mode = Ndis802_11Infrastructure; |
4035 | memcpy(bssid->mac_address, GetAddr2Ptr(pframe), ETH_ALEN); |
4036 | } else { |
4037 | bssid->infrastructure_mode = Ndis802_11IBSS; |
4038 | memcpy(bssid->mac_address, GetAddr3Ptr(pframe), ETH_ALEN); |
4039 | } |
4040 | |
4041 | if (val16 & BIT(4)) |
4042 | bssid->privacy = 1; |
4043 | else |
4044 | bssid->privacy = 0; |
4045 | |
4046 | bssid->configuration.atim_window = 0; |
4047 | |
4048 | /* 20/40 BSS Coexistence check */ |
4049 | if ((pregistrypriv->wifi_spec == 1) && (false == pmlmeinfo->bwmode_updated)) { |
4050 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
4051 | |
4052 | p = rtw_get_ie(pbuf: bssid->ies + ie_offset, index: WLAN_EID_HT_CAPABILITY, len: &len, limit: bssid->ie_length - ie_offset); |
4053 | if (p && len > 0) { |
4054 | struct HT_caps_element *pHT_caps; |
4055 | |
4056 | pHT_caps = (struct HT_caps_element *)(p + 2); |
4057 | |
4058 | if (le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info) & BIT(14)) |
4059 | pmlmepriv->num_FortyMHzIntolerant++; |
4060 | } else |
4061 | pmlmepriv->num_sta_no_ht++; |
4062 | } |
4063 | |
4064 | /* mark bss info receiving from nearby channel as signal_quality 101 */ |
4065 | if (bssid->configuration.ds_config != rtw_get_oper_ch(adapter: padapter)) |
4066 | bssid->phy_info.signal_quality = 101; |
4067 | |
4068 | return _SUCCESS; |
4069 | } |
4070 | |
4071 | void start_create_ibss(struct adapter *padapter) |
4072 | { |
4073 | unsigned short caps; |
4074 | u8 val8; |
4075 | u8 join_type; |
4076 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4077 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4078 | struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); |
4079 | |
4080 | pmlmeext->cur_channel = (u8)pnetwork->configuration.ds_config; |
4081 | pmlmeinfo->bcn_interval = get_beacon_interval(bss: pnetwork); |
4082 | |
4083 | /* update wireless mode */ |
4084 | update_wireless_mode(padapter); |
4085 | |
4086 | /* update capability */ |
4087 | caps = rtw_get_capability(bss: (struct wlan_bssid_ex *)pnetwork); |
4088 | update_capinfo(Adapter: padapter, updateCap: caps); |
4089 | if (caps&WLAN_CAPABILITY_IBSS) {/* adhoc master */ |
4090 | val8 = 0xcf; |
4091 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_SEC_CFG, val: (u8 *)(&val8)); |
4092 | |
4093 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_DO_IQK, NULL); |
4094 | |
4095 | /* switch channel */ |
4096 | /* SelectChannel(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */ |
4097 | set_channel_bwmode(padapter, channel: pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, bwmode: CHANNEL_WIDTH_20); |
4098 | |
4099 | beacon_timing_control(padapter); |
4100 | |
4101 | /* set msr to WIFI_FW_ADHOC_STATE */ |
4102 | pmlmeinfo->state = WIFI_FW_ADHOC_STATE; |
4103 | Set_MSR(padapter, type: (pmlmeinfo->state & 0x3)); |
4104 | |
4105 | /* issue beacon */ |
4106 | if (send_beacon(padapter) == _FAIL) { |
4107 | report_join_res(padapter, res: -1); |
4108 | pmlmeinfo->state = WIFI_FW_NULL_STATE; |
4109 | } else { |
4110 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_BSSID, val: padapter->registrypriv.dev_network.mac_address); |
4111 | join_type = 0; |
4112 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_MLME_JOIN, val: (u8 *)(&join_type)); |
4113 | |
4114 | report_join_res(padapter, res: 1); |
4115 | pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; |
4116 | rtw_indicate_connect(adapter: padapter); |
4117 | } |
4118 | } else { |
4119 | return; |
4120 | } |
4121 | /* update bc/mc sta_info */ |
4122 | update_bmc_sta(padapter); |
4123 | |
4124 | } |
4125 | |
4126 | void start_clnt_join(struct adapter *padapter) |
4127 | { |
4128 | unsigned short caps; |
4129 | u8 val8; |
4130 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4131 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4132 | struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); |
4133 | int beacon_timeout; |
4134 | |
4135 | /* update wireless mode */ |
4136 | update_wireless_mode(padapter); |
4137 | |
4138 | /* update capability */ |
4139 | caps = rtw_get_capability(bss: (struct wlan_bssid_ex *)pnetwork); |
4140 | update_capinfo(Adapter: padapter, updateCap: caps); |
4141 | if (caps&WLAN_CAPABILITY_ESS) { |
4142 | Set_MSR(padapter, WIFI_FW_STATION_STATE); |
4143 | |
4144 | val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf; |
4145 | |
4146 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_SEC_CFG, val: (u8 *)(&val8)); |
4147 | |
4148 | /* Because of AP's not receiving deauth before */ |
4149 | /* AP may: 1)not response auth or 2)deauth us after link is complete */ |
4150 | /* issue deauth before issuing auth to deal with the situation */ |
4151 | |
4152 | /* Commented by Albert 2012/07/21 */ |
4153 | /* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */ |
4154 | { |
4155 | /* To avoid connecting to AP fail during resume process, change retry count from 5 to 1 */ |
4156 | issue_deauth_ex(padapter, da: pnetwork->mac_address, reason: WLAN_REASON_DEAUTH_LEAVING, try_cnt: 1, wait_ms: 100); |
4157 | } |
4158 | |
4159 | /* here wait for receiving the beacon to start auth */ |
4160 | /* and enable a timer */ |
4161 | beacon_timeout = decide_wait_for_beacon_timeout(bcn_interval: pmlmeinfo->bcn_interval); |
4162 | set_link_timer(pmlmeext, beacon_timeout); |
4163 | _set_timer(ptimer: &padapter->mlmepriv.assoc_timer, |
4164 | delay_time: (REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO*REASSOC_LIMIT) + beacon_timeout); |
4165 | |
4166 | pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; |
4167 | } else if (caps&WLAN_CAPABILITY_IBSS) { /* adhoc client */ |
4168 | Set_MSR(padapter, WIFI_FW_ADHOC_STATE); |
4169 | |
4170 | val8 = 0xcf; |
4171 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_SEC_CFG, val: (u8 *)(&val8)); |
4172 | |
4173 | beacon_timing_control(padapter); |
4174 | |
4175 | pmlmeinfo->state = WIFI_FW_ADHOC_STATE; |
4176 | |
4177 | report_join_res(padapter, res: 1); |
4178 | } else { |
4179 | return; |
4180 | } |
4181 | |
4182 | } |
4183 | |
4184 | void start_clnt_auth(struct adapter *padapter) |
4185 | { |
4186 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4187 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4188 | |
4189 | del_timer_sync(timer: &pmlmeext->link_timer); |
4190 | |
4191 | pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL); |
4192 | pmlmeinfo->state |= WIFI_FW_AUTH_STATE; |
4193 | |
4194 | pmlmeinfo->auth_seq = 1; |
4195 | pmlmeinfo->reauth_count = 0; |
4196 | pmlmeinfo->reassoc_count = 0; |
4197 | pmlmeinfo->link_count = 0; |
4198 | pmlmeext->retry = 0; |
4199 | |
4200 | |
4201 | netdev_dbg(padapter->pnetdev, "start auth\n" ); |
4202 | issue_auth(padapter, NULL, status: 0); |
4203 | |
4204 | set_link_timer(pmlmeext, REAUTH_TO); |
4205 | |
4206 | } |
4207 | |
4208 | |
4209 | void start_clnt_assoc(struct adapter *padapter) |
4210 | { |
4211 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4212 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4213 | |
4214 | del_timer_sync(timer: &pmlmeext->link_timer); |
4215 | |
4216 | pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE)); |
4217 | pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE); |
4218 | |
4219 | issue_assocreq(padapter); |
4220 | |
4221 | set_link_timer(pmlmeext, REASSOC_TO); |
4222 | } |
4223 | |
4224 | unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) |
4225 | { |
4226 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4227 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4228 | |
4229 | /* check A3 */ |
4230 | if (!(!memcmp(p: MacAddr, q: get_my_bssid(pnetwork: &pmlmeinfo->network), ETH_ALEN))) |
4231 | return _SUCCESS; |
4232 | |
4233 | if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { |
4234 | if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { |
4235 | pmlmeinfo->state = WIFI_FW_NULL_STATE; |
4236 | report_del_sta_event(padapter, MacAddr, reason); |
4237 | |
4238 | } else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) { |
4239 | pmlmeinfo->state = WIFI_FW_NULL_STATE; |
4240 | report_join_res(padapter, res: -2); |
4241 | } |
4242 | } |
4243 | |
4244 | return _SUCCESS; |
4245 | } |
4246 | |
4247 | static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid) |
4248 | { |
4249 | struct registry_priv *pregistrypriv; |
4250 | struct mlme_ext_priv *pmlmeext; |
4251 | struct rt_channel_info *chplan_new; |
4252 | u8 channel; |
4253 | u8 i; |
4254 | |
4255 | |
4256 | pregistrypriv = &padapter->registrypriv; |
4257 | pmlmeext = &padapter->mlmeextpriv; |
4258 | |
4259 | /* Adjust channel plan by AP Country IE */ |
4260 | if (pregistrypriv->enable80211d && |
4261 | (!pmlmeext->update_channel_plan_by_ap_done)) { |
4262 | u8 *ie, *p; |
4263 | u32 len; |
4264 | struct rt_channel_plan chplan_ap; |
4265 | struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM]; |
4266 | u8 country[4]; |
4267 | u8 fcn; /* first channel number */ |
4268 | u8 noc; /* number of channel */ |
4269 | u8 j, k; |
4270 | |
4271 | ie = rtw_get_ie(pbuf: bssid->ies + _FIXED_IE_LENGTH_, index: WLAN_EID_COUNTRY, len: &len, limit: bssid->ie_length - _FIXED_IE_LENGTH_); |
4272 | if (!ie) |
4273 | return; |
4274 | if (len < 6) |
4275 | return; |
4276 | |
4277 | ie += 2; |
4278 | p = ie; |
4279 | ie += len; |
4280 | |
4281 | memset(country, 0, 4); |
4282 | memcpy(country, p, 3); |
4283 | p += 3; |
4284 | |
4285 | i = 0; |
4286 | while ((ie - p) >= 3) { |
4287 | fcn = *(p++); |
4288 | noc = *(p++); |
4289 | p++; |
4290 | |
4291 | for (j = 0; j < noc; j++) { |
4292 | if (fcn <= 14) |
4293 | channel = fcn + j; /* 2.4 GHz */ |
4294 | else |
4295 | channel = fcn + j*4; /* 5 GHz */ |
4296 | |
4297 | chplan_ap.Channel[i++] = channel; |
4298 | } |
4299 | } |
4300 | chplan_ap.Len = i; |
4301 | |
4302 | memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta)); |
4303 | |
4304 | memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set)); |
4305 | chplan_new = pmlmeext->channel_set; |
4306 | |
4307 | i = j = k = 0; |
4308 | if (pregistrypriv->wireless_mode & WIRELESS_11G) { |
4309 | do { |
4310 | if ((i == MAX_CHANNEL_NUM) || |
4311 | (chplan_sta[i].ChannelNum == 0) || |
4312 | (chplan_sta[i].ChannelNum > 14)) |
4313 | break; |
4314 | |
4315 | if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14)) |
4316 | break; |
4317 | |
4318 | if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) { |
4319 | chplan_new[k].ChannelNum = chplan_ap.Channel[j]; |
4320 | chplan_new[k].ScanType = SCAN_ACTIVE; |
4321 | i++; |
4322 | j++; |
4323 | k++; |
4324 | } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) { |
4325 | chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; |
4326 | /* chplan_new[k].ScanType = chplan_sta[i].ScanType; */ |
4327 | chplan_new[k].ScanType = SCAN_PASSIVE; |
4328 | i++; |
4329 | k++; |
4330 | } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) { |
4331 | chplan_new[k].ChannelNum = chplan_ap.Channel[j]; |
4332 | chplan_new[k].ScanType = SCAN_ACTIVE; |
4333 | j++; |
4334 | k++; |
4335 | } |
4336 | } while (1); |
4337 | |
4338 | /* change AP not support channel to Passive scan */ |
4339 | while ((i < MAX_CHANNEL_NUM) && |
4340 | (chplan_sta[i].ChannelNum != 0) && |
4341 | (chplan_sta[i].ChannelNum <= 14)) { |
4342 | |
4343 | chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; |
4344 | /* chplan_new[k].ScanType = chplan_sta[i].ScanType; */ |
4345 | chplan_new[k].ScanType = SCAN_PASSIVE; |
4346 | i++; |
4347 | k++; |
4348 | } |
4349 | |
4350 | /* add channel AP supported */ |
4351 | while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) { |
4352 | chplan_new[k].ChannelNum = chplan_ap.Channel[j]; |
4353 | chplan_new[k].ScanType = SCAN_ACTIVE; |
4354 | j++; |
4355 | k++; |
4356 | } |
4357 | } else { |
4358 | /* keep original STA 2.4G channel plan */ |
4359 | while ((i < MAX_CHANNEL_NUM) && |
4360 | (chplan_sta[i].ChannelNum != 0) && |
4361 | (chplan_sta[i].ChannelNum <= 14)) { |
4362 | chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; |
4363 | chplan_new[k].ScanType = chplan_sta[i].ScanType; |
4364 | i++; |
4365 | k++; |
4366 | } |
4367 | |
4368 | /* skip AP 2.4G channel plan */ |
4369 | while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) |
4370 | j++; |
4371 | } |
4372 | |
4373 | pmlmeext->update_channel_plan_by_ap_done = 1; |
4374 | } |
4375 | |
4376 | /* If channel is used by AP, set channel scan type to active */ |
4377 | channel = bssid->configuration.ds_config; |
4378 | chplan_new = pmlmeext->channel_set; |
4379 | i = 0; |
4380 | while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) { |
4381 | if (chplan_new[i].ChannelNum == channel) { |
4382 | if (chplan_new[i].ScanType == SCAN_PASSIVE) |
4383 | chplan_new[i].ScanType = SCAN_ACTIVE; |
4384 | break; |
4385 | } |
4386 | i++; |
4387 | } |
4388 | } |
4389 | |
4390 | /**************************************************************************** |
4391 | |
4392 | Following are the functions to report events |
4393 | |
4394 | *****************************************************************************/ |
4395 | |
4396 | void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame) |
4397 | { |
4398 | struct cmd_obj *pcmd_obj; |
4399 | u8 *pevtcmd; |
4400 | u32 cmdsz; |
4401 | struct survey_event *psurvey_evt; |
4402 | struct C2HEvent_Header *pc2h_evt_hdr; |
4403 | struct mlme_ext_priv *pmlmeext; |
4404 | struct cmd_priv *pcmdpriv; |
4405 | /* u8 *pframe = precv_frame->u.hdr.rx_data; */ |
4406 | /* uint len = precv_frame->u.hdr.len; */ |
4407 | |
4408 | if (!padapter) |
4409 | return; |
4410 | |
4411 | pmlmeext = &padapter->mlmeextpriv; |
4412 | pcmdpriv = &padapter->cmdpriv; |
4413 | |
4414 | pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj)); |
4415 | if (!pcmd_obj) |
4416 | return; |
4417 | |
4418 | cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header)); |
4419 | pevtcmd = rtw_zmalloc(cmdsz); |
4420 | if (!pevtcmd) { |
4421 | kfree(objp: pcmd_obj); |
4422 | return; |
4423 | } |
4424 | |
4425 | INIT_LIST_HEAD(list: &pcmd_obj->list); |
4426 | |
4427 | pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); |
4428 | pcmd_obj->cmdsz = cmdsz; |
4429 | pcmd_obj->parmbuf = pevtcmd; |
4430 | |
4431 | pcmd_obj->rsp = NULL; |
4432 | pcmd_obj->rspsz = 0; |
4433 | |
4434 | pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); |
4435 | pc2h_evt_hdr->len = sizeof(struct survey_event); |
4436 | pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey); |
4437 | pc2h_evt_hdr->seq = atomic_inc_return(v: &pmlmeext->event_seq); |
4438 | |
4439 | psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); |
4440 | |
4441 | if (collect_bss_info(padapter, precv_frame, bssid: (struct wlan_bssid_ex *)&psurvey_evt->bss) == _FAIL) { |
4442 | kfree(objp: pcmd_obj); |
4443 | kfree(objp: pevtcmd); |
4444 | return; |
4445 | } |
4446 | |
4447 | process_80211d(padapter, bssid: &psurvey_evt->bss); |
4448 | |
4449 | rtw_enqueue_cmd(pcmdpriv, obj: pcmd_obj); |
4450 | |
4451 | pmlmeext->sitesurvey_res.bss_cnt++; |
4452 | |
4453 | return; |
4454 | |
4455 | } |
4456 | |
4457 | void report_surveydone_event(struct adapter *padapter) |
4458 | { |
4459 | struct cmd_obj *pcmd_obj; |
4460 | u8 *pevtcmd; |
4461 | u32 cmdsz; |
4462 | struct surveydone_event *psurveydone_evt; |
4463 | struct C2HEvent_Header *pc2h_evt_hdr; |
4464 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4465 | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; |
4466 | |
4467 | pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj)); |
4468 | if (!pcmd_obj) |
4469 | return; |
4470 | |
4471 | cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header)); |
4472 | pevtcmd = rtw_zmalloc(cmdsz); |
4473 | if (!pevtcmd) { |
4474 | kfree(objp: pcmd_obj); |
4475 | return; |
4476 | } |
4477 | |
4478 | INIT_LIST_HEAD(list: &pcmd_obj->list); |
4479 | |
4480 | pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); |
4481 | pcmd_obj->cmdsz = cmdsz; |
4482 | pcmd_obj->parmbuf = pevtcmd; |
4483 | |
4484 | pcmd_obj->rsp = NULL; |
4485 | pcmd_obj->rspsz = 0; |
4486 | |
4487 | pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); |
4488 | pc2h_evt_hdr->len = sizeof(struct surveydone_event); |
4489 | pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone); |
4490 | pc2h_evt_hdr->seq = atomic_inc_return(v: &pmlmeext->event_seq); |
4491 | |
4492 | psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); |
4493 | psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; |
4494 | |
4495 | rtw_enqueue_cmd(pcmdpriv, obj: pcmd_obj); |
4496 | |
4497 | return; |
4498 | |
4499 | } |
4500 | |
4501 | void report_join_res(struct adapter *padapter, int res) |
4502 | { |
4503 | struct cmd_obj *pcmd_obj; |
4504 | u8 *pevtcmd; |
4505 | u32 cmdsz; |
4506 | struct joinbss_event *pjoinbss_evt; |
4507 | struct C2HEvent_Header *pc2h_evt_hdr; |
4508 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4509 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4510 | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; |
4511 | |
4512 | pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj)); |
4513 | if (!pcmd_obj) |
4514 | return; |
4515 | |
4516 | cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header)); |
4517 | pevtcmd = rtw_zmalloc(cmdsz); |
4518 | if (!pevtcmd) { |
4519 | kfree(objp: pcmd_obj); |
4520 | return; |
4521 | } |
4522 | |
4523 | INIT_LIST_HEAD(list: &pcmd_obj->list); |
4524 | |
4525 | pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); |
4526 | pcmd_obj->cmdsz = cmdsz; |
4527 | pcmd_obj->parmbuf = pevtcmd; |
4528 | |
4529 | pcmd_obj->rsp = NULL; |
4530 | pcmd_obj->rspsz = 0; |
4531 | |
4532 | pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); |
4533 | pc2h_evt_hdr->len = sizeof(struct joinbss_event); |
4534 | pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss); |
4535 | pc2h_evt_hdr->seq = atomic_inc_return(v: &pmlmeext->event_seq); |
4536 | |
4537 | pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); |
4538 | memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); |
4539 | pjoinbss_evt->network.join_res = pjoinbss_evt->network.aid = res; |
4540 | |
4541 | |
4542 | rtw_joinbss_event_prehandle(adapter: padapter, pbuf: (u8 *)&pjoinbss_evt->network); |
4543 | |
4544 | |
4545 | rtw_enqueue_cmd(pcmdpriv, obj: pcmd_obj); |
4546 | |
4547 | return; |
4548 | |
4549 | } |
4550 | |
4551 | void report_wmm_edca_update(struct adapter *padapter) |
4552 | { |
4553 | struct cmd_obj *pcmd_obj; |
4554 | u8 *pevtcmd; |
4555 | u32 cmdsz; |
4556 | struct wmm_event *pwmm_event; |
4557 | struct C2HEvent_Header *pc2h_evt_hdr; |
4558 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4559 | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; |
4560 | |
4561 | pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj)); |
4562 | if (!pcmd_obj) |
4563 | return; |
4564 | |
4565 | cmdsz = (sizeof(struct wmm_event) + sizeof(struct C2HEvent_Header)); |
4566 | pevtcmd = rtw_zmalloc(cmdsz); |
4567 | if (!pevtcmd) { |
4568 | kfree(objp: pcmd_obj); |
4569 | return; |
4570 | } |
4571 | |
4572 | INIT_LIST_HEAD(list: &pcmd_obj->list); |
4573 | |
4574 | pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); |
4575 | pcmd_obj->cmdsz = cmdsz; |
4576 | pcmd_obj->parmbuf = pevtcmd; |
4577 | |
4578 | pcmd_obj->rsp = NULL; |
4579 | pcmd_obj->rspsz = 0; |
4580 | |
4581 | pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); |
4582 | pc2h_evt_hdr->len = sizeof(struct wmm_event); |
4583 | pc2h_evt_hdr->ID = GEN_EVT_CODE(_WMM); |
4584 | pc2h_evt_hdr->seq = atomic_inc_return(v: &pmlmeext->event_seq); |
4585 | |
4586 | pwmm_event = (struct wmm_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); |
4587 | pwmm_event->wmm = 0; |
4588 | |
4589 | rtw_enqueue_cmd(pcmdpriv, obj: pcmd_obj); |
4590 | |
4591 | return; |
4592 | |
4593 | } |
4594 | |
4595 | void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) |
4596 | { |
4597 | struct cmd_obj *pcmd_obj; |
4598 | u8 *pevtcmd; |
4599 | u32 cmdsz; |
4600 | struct sta_info *psta; |
4601 | int mac_id; |
4602 | struct stadel_event *pdel_sta_evt; |
4603 | struct C2HEvent_Header *pc2h_evt_hdr; |
4604 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4605 | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; |
4606 | |
4607 | pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj)); |
4608 | if (!pcmd_obj) |
4609 | return; |
4610 | |
4611 | cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header)); |
4612 | pevtcmd = rtw_zmalloc(cmdsz); |
4613 | if (!pevtcmd) { |
4614 | kfree(objp: pcmd_obj); |
4615 | return; |
4616 | } |
4617 | |
4618 | INIT_LIST_HEAD(list: &pcmd_obj->list); |
4619 | |
4620 | pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); |
4621 | pcmd_obj->cmdsz = cmdsz; |
4622 | pcmd_obj->parmbuf = pevtcmd; |
4623 | |
4624 | pcmd_obj->rsp = NULL; |
4625 | pcmd_obj->rspsz = 0; |
4626 | |
4627 | pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); |
4628 | pc2h_evt_hdr->len = sizeof(struct stadel_event); |
4629 | pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA); |
4630 | pc2h_evt_hdr->seq = atomic_inc_return(v: &pmlmeext->event_seq); |
4631 | |
4632 | pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); |
4633 | memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN); |
4634 | memcpy((unsigned char *)(pdel_sta_evt->rsvd), (unsigned char *)(&reason), 2); |
4635 | |
4636 | |
4637 | psta = rtw_get_stainfo(pstapriv: &padapter->stapriv, hwaddr: MacAddr); |
4638 | if (psta) |
4639 | mac_id = (int)psta->mac_id; |
4640 | else |
4641 | mac_id = (-1); |
4642 | |
4643 | pdel_sta_evt->mac_id = mac_id; |
4644 | |
4645 | rtw_enqueue_cmd(pcmdpriv, obj: pcmd_obj); |
4646 | } |
4647 | |
4648 | void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int cam_idx) |
4649 | { |
4650 | struct cmd_obj *pcmd_obj; |
4651 | u8 *pevtcmd; |
4652 | u32 cmdsz; |
4653 | struct stassoc_event *padd_sta_evt; |
4654 | struct C2HEvent_Header *pc2h_evt_hdr; |
4655 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4656 | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; |
4657 | |
4658 | pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj)); |
4659 | if (!pcmd_obj) |
4660 | return; |
4661 | |
4662 | cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header)); |
4663 | pevtcmd = rtw_zmalloc(cmdsz); |
4664 | if (!pevtcmd) { |
4665 | kfree(objp: pcmd_obj); |
4666 | return; |
4667 | } |
4668 | |
4669 | INIT_LIST_HEAD(list: &pcmd_obj->list); |
4670 | |
4671 | pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); |
4672 | pcmd_obj->cmdsz = cmdsz; |
4673 | pcmd_obj->parmbuf = pevtcmd; |
4674 | |
4675 | pcmd_obj->rsp = NULL; |
4676 | pcmd_obj->rspsz = 0; |
4677 | |
4678 | pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); |
4679 | pc2h_evt_hdr->len = sizeof(struct stassoc_event); |
4680 | pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA); |
4681 | pc2h_evt_hdr->seq = atomic_inc_return(v: &pmlmeext->event_seq); |
4682 | |
4683 | padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); |
4684 | memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN); |
4685 | padd_sta_evt->cam_id = cam_idx; |
4686 | |
4687 | rtw_enqueue_cmd(pcmdpriv, obj: pcmd_obj); |
4688 | } |
4689 | |
4690 | /**************************************************************************** |
4691 | |
4692 | Following are the event callback functions |
4693 | |
4694 | *****************************************************************************/ |
4695 | |
4696 | /* for sta/adhoc mode */ |
4697 | void update_sta_info(struct adapter *padapter, struct sta_info *psta) |
4698 | { |
4699 | struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); |
4700 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4701 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4702 | |
4703 | /* ERP */ |
4704 | VCS_update(padapter, psta); |
4705 | |
4706 | /* HT */ |
4707 | if (pmlmepriv->htpriv.ht_option) { |
4708 | psta->htpriv.ht_option = true; |
4709 | |
4710 | psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable; |
4711 | |
4712 | psta->htpriv.rx_ampdu_min_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para&IEEE80211_HT_CAP_AMPDU_DENSITY)>>2; |
4713 | |
4714 | if (support_short_GI(padapter, pHT_caps: &(pmlmeinfo->HT_caps), bwmode: CHANNEL_WIDTH_20)) |
4715 | psta->htpriv.sgi_20m = true; |
4716 | |
4717 | if (support_short_GI(padapter, pHT_caps: &(pmlmeinfo->HT_caps), bwmode: CHANNEL_WIDTH_40)) |
4718 | psta->htpriv.sgi_40m = true; |
4719 | |
4720 | psta->qos_option = true; |
4721 | |
4722 | psta->htpriv.ldpc_cap = pmlmepriv->htpriv.ldpc_cap; |
4723 | psta->htpriv.stbc_cap = pmlmepriv->htpriv.stbc_cap; |
4724 | psta->htpriv.beamform_cap = pmlmepriv->htpriv.beamform_cap; |
4725 | |
4726 | memcpy(&psta->htpriv.ht_cap, &pmlmeinfo->HT_caps, sizeof(struct ieee80211_ht_cap)); |
4727 | } else { |
4728 | psta->htpriv.ht_option = false; |
4729 | |
4730 | psta->htpriv.ampdu_enable = false; |
4731 | |
4732 | psta->htpriv.sgi_20m = false; |
4733 | psta->htpriv.sgi_40m = false; |
4734 | psta->qos_option = false; |
4735 | |
4736 | } |
4737 | |
4738 | psta->htpriv.ch_offset = pmlmeext->cur_ch_offset; |
4739 | |
4740 | psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ |
4741 | psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ |
4742 | |
4743 | psta->bw_mode = pmlmeext->cur_bwmode; |
4744 | |
4745 | /* QoS */ |
4746 | if (pmlmepriv->qospriv.qos_option) |
4747 | psta->qos_option = true; |
4748 | |
4749 | update_ldpc_stbc_cap(psta); |
4750 | |
4751 | spin_lock_bh(lock: &psta->lock); |
4752 | psta->state = _FW_LINKED; |
4753 | spin_unlock_bh(lock: &psta->lock); |
4754 | |
4755 | } |
4756 | |
4757 | static void rtw_mlmeext_disconnect(struct adapter *padapter) |
4758 | { |
4759 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
4760 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4761 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4762 | struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); |
4763 | |
4764 | /* set_opmode_cmd(padapter, infra_client_with_mlme); */ |
4765 | |
4766 | /* For safety, prevent from keeping macid sleep. |
4767 | * If we can sure all power mode enter/leave are paired, |
4768 | * this check can be removed. |
4769 | * Lucas@20131113 |
4770 | */ |
4771 | /* wakeup macid after disconnect. */ |
4772 | { |
4773 | struct sta_info *psta; |
4774 | |
4775 | psta = rtw_get_stainfo(pstapriv: &padapter->stapriv, hwaddr: get_my_bssid(pnetwork)); |
4776 | if (psta) |
4777 | rtw_hal_macid_wakeup(padapter, macid: psta->mac_id); |
4778 | } |
4779 | |
4780 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_MLME_DISCONNECT, NULL); |
4781 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_BSSID, val: null_addr); |
4782 | |
4783 | /* set MSR to no link state -> infra. mode */ |
4784 | Set_MSR(padapter, _HW_STATE_STATION_); |
4785 | |
4786 | pmlmeinfo->state = WIFI_FW_NULL_STATE; |
4787 | |
4788 | /* switch to the 20M Hz mode after disconnect */ |
4789 | pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; |
4790 | pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; |
4791 | |
4792 | set_channel_bwmode(padapter, channel: pmlmeext->cur_channel, channel_offset: pmlmeext->cur_ch_offset, bwmode: pmlmeext->cur_bwmode); |
4793 | |
4794 | flush_all_cam_entry(padapter); |
4795 | |
4796 | del_timer_sync(timer: &pmlmeext->link_timer); |
4797 | |
4798 | /* pmlmepriv->LinkDetectInfo.TrafficBusyState = false; */ |
4799 | pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0; |
4800 | pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0; |
4801 | |
4802 | } |
4803 | |
4804 | void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) |
4805 | { |
4806 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4807 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4808 | struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); |
4809 | struct sta_priv *pstapriv = &padapter->stapriv; |
4810 | u8 join_type; |
4811 | struct sta_info *psta; |
4812 | |
4813 | if (join_res < 0) { |
4814 | join_type = 1; |
4815 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_MLME_JOIN, val: (u8 *)(&join_type)); |
4816 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_BSSID, val: null_addr); |
4817 | |
4818 | return; |
4819 | } |
4820 | |
4821 | if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) |
4822 | /* update bc/mc sta_info */ |
4823 | update_bmc_sta(padapter); |
4824 | |
4825 | |
4826 | /* turn on dynamic functions */ |
4827 | Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, enable: true); |
4828 | |
4829 | /* update IOT-related issue */ |
4830 | update_IOT_info(padapter); |
4831 | |
4832 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_BASIC_RATE, val: cur_network->supported_rates); |
4833 | |
4834 | /* BCN interval */ |
4835 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_BEACON_INTERVAL, val: (u8 *)(&pmlmeinfo->bcn_interval)); |
4836 | |
4837 | /* update capability */ |
4838 | update_capinfo(Adapter: padapter, updateCap: pmlmeinfo->capability); |
4839 | |
4840 | /* WMM, Update EDCA param */ |
4841 | WMMOnAssocRsp(padapter); |
4842 | |
4843 | /* HT */ |
4844 | HTOnAssocRsp(padapter); |
4845 | |
4846 | /* Set cur_channel&cur_bwmode&cur_ch_offset */ |
4847 | set_channel_bwmode(padapter, channel: pmlmeext->cur_channel, channel_offset: pmlmeext->cur_ch_offset, bwmode: pmlmeext->cur_bwmode); |
4848 | |
4849 | psta = rtw_get_stainfo(pstapriv, hwaddr: cur_network->mac_address); |
4850 | if (psta) { /* only for infra. mode */ |
4851 | |
4852 | pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; |
4853 | |
4854 | psta->wireless_mode = pmlmeext->cur_wireless_mode; |
4855 | |
4856 | /* set per sta rate after updating HT cap. */ |
4857 | set_sta_rate(padapter, psta); |
4858 | |
4859 | rtw_sta_media_status_rpt(adapter: padapter, psta, mstatus: 1); |
4860 | |
4861 | /* wakeup macid after join bss successfully to ensure |
4862 | the subsequent data frames can be sent out normally */ |
4863 | rtw_hal_macid_wakeup(padapter, macid: psta->mac_id); |
4864 | } |
4865 | |
4866 | join_type = 2; |
4867 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_MLME_JOIN, val: (u8 *)(&join_type)); |
4868 | |
4869 | if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { |
4870 | /* correcting TSF */ |
4871 | correct_TSF(padapter, pmlmeext); |
4872 | |
4873 | /* set_link_timer(pmlmeext, DISCONNECT_TO); */ |
4874 | } |
4875 | |
4876 | if (get_iface_type(padapter) == IFACE_PORT0) |
4877 | rtw_lps_ctrl_wk_cmd(padapter, lps_ctrl_type: LPS_CTRL_CONNECT, enqueue: 0); |
4878 | } |
4879 | |
4880 | /* currently only adhoc mode will go here */ |
4881 | void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *psta) |
4882 | { |
4883 | struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); |
4884 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4885 | u8 join_type; |
4886 | |
4887 | if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { |
4888 | if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { /* adhoc master or sta_count>1 */ |
4889 | |
4890 | /* nothing to do */ |
4891 | } else { /* adhoc client */ |
4892 | /* update TSF Value */ |
4893 | /* update_TSF(pmlmeext, pframe, len); */ |
4894 | |
4895 | /* correcting TSF */ |
4896 | correct_TSF(padapter, pmlmeext); |
4897 | |
4898 | /* start beacon */ |
4899 | if (send_beacon(padapter) == _FAIL) { |
4900 | pmlmeinfo->FW_sta_info[psta->mac_id].status = 0; |
4901 | |
4902 | pmlmeinfo->state ^= WIFI_FW_ADHOC_STATE; |
4903 | |
4904 | return; |
4905 | } |
4906 | |
4907 | pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; |
4908 | |
4909 | } |
4910 | |
4911 | join_type = 2; |
4912 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_MLME_JOIN, val: (u8 *)(&join_type)); |
4913 | } |
4914 | |
4915 | pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; |
4916 | |
4917 | psta->bssratelen = rtw_get_rateset_len(rateset: pmlmeinfo->FW_sta_info[psta->mac_id].SupportedRates); |
4918 | memcpy(psta->bssrateset, pmlmeinfo->FW_sta_info[psta->mac_id].SupportedRates, psta->bssratelen); |
4919 | |
4920 | /* update adhoc sta_info */ |
4921 | update_sta_info(padapter, psta); |
4922 | |
4923 | rtw_hal_update_sta_rate_mask(padapter, psta); |
4924 | |
4925 | /* ToDo: HT for Ad-hoc */ |
4926 | psta->wireless_mode = rtw_check_network_type(rate: psta->bssrateset, ratelen: psta->bssratelen, channel: pmlmeext->cur_channel); |
4927 | psta->raid = networktype_to_raid_ex(adapter: padapter, psta); |
4928 | |
4929 | /* rate radaptive */ |
4930 | Update_RA_Entry(padapter, psta); |
4931 | } |
4932 | |
4933 | void mlmeext_sta_del_event_callback(struct adapter *padapter) |
4934 | { |
4935 | if (is_client_associated_to_ap(padapter) || is_IBSS_empty(padapter)) |
4936 | rtw_mlmeext_disconnect(padapter); |
4937 | } |
4938 | |
4939 | /**************************************************************************** |
4940 | |
4941 | Following are the functions for the timer handlers |
4942 | |
4943 | *****************************************************************************/ |
4944 | void _linked_info_dump(struct adapter *padapter) |
4945 | { |
4946 | int i; |
4947 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4948 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4949 | int UndecoratedSmoothedPWDB; |
4950 | struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); |
4951 | |
4952 | if (padapter->bLinkInfoDump) { |
4953 | |
4954 | if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) |
4955 | rtw_hal_get_def_var(padapter, eVariable: HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, pValue: &UndecoratedSmoothedPWDB); |
4956 | |
4957 | for (i = 0; i < NUM_STA; i++) { |
4958 | if (pdvobj->macid[i]) { |
4959 | if (i != 1) /* skip bc/mc sta */ |
4960 | /* tx info ============ */ |
4961 | rtw_hal_get_def_var(padapter, eVariable: HW_DEF_RA_INFO_DUMP, pValue: &i); |
4962 | } |
4963 | } |
4964 | rtw_hal_set_def_var(padapter, eVariable: HAL_DEF_DBG_RX_INFO_DUMP, NULL); |
4965 | } |
4966 | } |
4967 | |
4968 | static u8 chk_ap_is_alive(struct adapter *padapter, struct sta_info *psta) |
4969 | { |
4970 | u8 ret = false; |
4971 | |
4972 | if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) |
4973 | && sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) |
4974 | && sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta) |
4975 | ) { |
4976 | ret = false; |
4977 | } else { |
4978 | ret = true; |
4979 | } |
4980 | |
4981 | sta_update_last_rx_pkts(psta); |
4982 | |
4983 | return ret; |
4984 | } |
4985 | |
4986 | void linked_status_chk(struct adapter *padapter) |
4987 | { |
4988 | u32 i; |
4989 | struct sta_info *psta; |
4990 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
4991 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
4992 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4993 | struct sta_priv *pstapriv = &padapter->stapriv; |
4994 | |
4995 | |
4996 | if (is_client_associated_to_ap(padapter)) { |
4997 | /* linked infrastructure client mode */ |
4998 | |
4999 | int tx_chk = _SUCCESS, rx_chk = _SUCCESS; |
5000 | int rx_chk_limit; |
5001 | int link_count_limit; |
5002 | |
5003 | #if defined(DBG_ROAMING_TEST) |
5004 | rx_chk_limit = 1; |
5005 | #else |
5006 | rx_chk_limit = 8; |
5007 | #endif |
5008 | link_count_limit = 7; /* 16 sec */ |
5009 | |
5010 | /* Marked by Kurt 20130715 */ |
5011 | /* For WiDi 3.5 and latered on, they don't ask WiDi sink to do roaming, so we could not check rx limit that strictly. */ |
5012 | /* todo: To check why we under miracast session, rx_chk would be false */ |
5013 | psta = rtw_get_stainfo(pstapriv, hwaddr: pmlmeinfo->network.mac_address); |
5014 | if (psta) { |
5015 | if (chk_ap_is_alive(padapter, psta) == false) |
5016 | rx_chk = _FAIL; |
5017 | |
5018 | if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts) |
5019 | tx_chk = _FAIL; |
5020 | |
5021 | { |
5022 | if (rx_chk != _SUCCESS) { |
5023 | if (pmlmeext->retry == 0) { |
5024 | issue_probereq_ex(padapter, pssid: &pmlmeinfo->network.ssid, da: pmlmeinfo->network.mac_address, ch: 0, append_wps: 0, try_cnt: 0, wait_ms: 0); |
5025 | issue_probereq_ex(padapter, pssid: &pmlmeinfo->network.ssid, da: pmlmeinfo->network.mac_address, ch: 0, append_wps: 0, try_cnt: 0, wait_ms: 0); |
5026 | issue_probereq_ex(padapter, pssid: &pmlmeinfo->network.ssid, da: pmlmeinfo->network.mac_address, ch: 0, append_wps: 0, try_cnt: 0, wait_ms: 0); |
5027 | } |
5028 | } |
5029 | |
5030 | if (tx_chk != _SUCCESS && |
5031 | pmlmeinfo->link_count++ == link_count_limit) |
5032 | tx_chk = issue_nulldata_in_interrupt(padapter, NULL); |
5033 | } |
5034 | |
5035 | if (rx_chk == _FAIL) { |
5036 | pmlmeext->retry++; |
5037 | if (pmlmeext->retry > rx_chk_limit) { |
5038 | netdev_dbg(padapter->pnetdev, |
5039 | FUNC_ADPT_FMT " disconnect or roaming\n" , |
5040 | FUNC_ADPT_ARG(padapter)); |
5041 | receive_disconnect(padapter, MacAddr: pmlmeinfo->network.mac_address |
5042 | , WLAN_REASON_EXPIRATION_CHK); |
5043 | return; |
5044 | } |
5045 | } else { |
5046 | pmlmeext->retry = 0; |
5047 | } |
5048 | |
5049 | if (tx_chk == _FAIL) { |
5050 | pmlmeinfo->link_count %= (link_count_limit+1); |
5051 | } else { |
5052 | pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts; |
5053 | pmlmeinfo->link_count = 0; |
5054 | } |
5055 | |
5056 | } /* end of if ((psta = rtw_get_stainfo(pstapriv, passoc_res->network.mac_address)) != NULL) */ |
5057 | } else if (is_client_associated_to_ibss(padapter)) { |
5058 | /* linked IBSS mode */ |
5059 | /* for each assoc list entry to check the rx pkt counter */ |
5060 | for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) { |
5061 | if (pmlmeinfo->FW_sta_info[i].status == 1) { |
5062 | psta = pmlmeinfo->FW_sta_info[i].psta; |
5063 | |
5064 | if (psta == NULL) |
5065 | continue; |
5066 | |
5067 | if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta)) { |
5068 | |
5069 | if (pmlmeinfo->FW_sta_info[i].retry < 3) { |
5070 | pmlmeinfo->FW_sta_info[i].retry++; |
5071 | } else { |
5072 | pmlmeinfo->FW_sta_info[i].retry = 0; |
5073 | pmlmeinfo->FW_sta_info[i].status = 0; |
5074 | report_del_sta_event(padapter, MacAddr: psta->hwaddr |
5075 | , reason: 65535/* indicate disconnect caused by no rx */ |
5076 | ); |
5077 | } |
5078 | } else { |
5079 | pmlmeinfo->FW_sta_info[i].retry = 0; |
5080 | pmlmeinfo->FW_sta_info[i].rx_pkt = (u32)sta_rx_pkts(psta); |
5081 | } |
5082 | } |
5083 | } |
5084 | |
5085 | /* set_link_timer(pmlmeext, DISCONNECT_TO); */ |
5086 | |
5087 | } |
5088 | |
5089 | } |
5090 | |
5091 | void survey_timer_hdl(struct timer_list *t) |
5092 | { |
5093 | struct adapter *padapter = |
5094 | from_timer(padapter, t, mlmeextpriv.survey_timer); |
5095 | struct cmd_obj *ph2c; |
5096 | struct sitesurvey_parm *psurveyPara; |
5097 | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; |
5098 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5099 | |
5100 | /* issue rtw_sitesurvey_cmd */ |
5101 | if (pmlmeext->sitesurvey_res.state > SCAN_START) { |
5102 | if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) |
5103 | pmlmeext->sitesurvey_res.channel_idx++; |
5104 | |
5105 | if (pmlmeext->scan_abort) { |
5106 | pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num; |
5107 | |
5108 | pmlmeext->scan_abort = false;/* reset */ |
5109 | } |
5110 | |
5111 | ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); |
5112 | if (!ph2c) |
5113 | return; |
5114 | |
5115 | psurveyPara = rtw_zmalloc(sizeof(struct sitesurvey_parm)); |
5116 | if (!psurveyPara) { |
5117 | kfree(objp: ph2c); |
5118 | return; |
5119 | } |
5120 | |
5121 | init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); |
5122 | rtw_enqueue_cmd(pcmdpriv, obj: ph2c); |
5123 | } |
5124 | } |
5125 | |
5126 | void link_timer_hdl(struct timer_list *t) |
5127 | { |
5128 | struct adapter *padapter = |
5129 | from_timer(padapter, t, mlmeextpriv.link_timer); |
5130 | /* static unsigned int rx_pkt = 0; */ |
5131 | /* static u64 tx_cnt = 0; */ |
5132 | /* struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); */ |
5133 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5134 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
5135 | /* struct sta_priv *pstapriv = &padapter->stapriv; */ |
5136 | |
5137 | |
5138 | if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { |
5139 | pmlmeinfo->state = WIFI_FW_NULL_STATE; |
5140 | report_join_res(padapter, res: -3); |
5141 | } else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) { |
5142 | /* re-auth timer */ |
5143 | if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) { |
5144 | pmlmeinfo->state = 0; |
5145 | report_join_res(padapter, res: -1); |
5146 | return; |
5147 | } |
5148 | |
5149 | pmlmeinfo->auth_seq = 1; |
5150 | issue_auth(padapter, NULL, status: 0); |
5151 | set_link_timer(pmlmeext, REAUTH_TO); |
5152 | } else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) { |
5153 | /* re-assoc timer */ |
5154 | if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) { |
5155 | pmlmeinfo->state = WIFI_FW_NULL_STATE; |
5156 | report_join_res(padapter, res: -2); |
5157 | return; |
5158 | } |
5159 | |
5160 | issue_assocreq(padapter); |
5161 | set_link_timer(pmlmeext, REASSOC_TO); |
5162 | } |
5163 | } |
5164 | |
5165 | void addba_timer_hdl(struct timer_list *t) |
5166 | { |
5167 | struct sta_info *psta = from_timer(psta, t, addba_retry_timer); |
5168 | struct ht_priv *phtpriv; |
5169 | |
5170 | if (!psta) |
5171 | return; |
5172 | |
5173 | phtpriv = &psta->htpriv; |
5174 | |
5175 | if (phtpriv->ht_option && phtpriv->ampdu_enable) { |
5176 | if (phtpriv->candidate_tid_bitmap) |
5177 | phtpriv->candidate_tid_bitmap = 0x0; |
5178 | |
5179 | } |
5180 | } |
5181 | |
5182 | void sa_query_timer_hdl(struct timer_list *t) |
5183 | { |
5184 | struct adapter *padapter = |
5185 | from_timer(padapter, t, mlmeextpriv.sa_query_timer); |
5186 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
5187 | /* disconnect */ |
5188 | spin_lock_bh(lock: &pmlmepriv->lock); |
5189 | |
5190 | if (check_fwstate(pmlmepriv, _FW_LINKED)) { |
5191 | rtw_disassoc_cmd(padapter, deauth_timeout_ms: 0, enqueue: true); |
5192 | rtw_indicate_disconnect(adapter: padapter); |
5193 | rtw_free_assoc_resources(adapter: padapter, lock_scanned_queue: 1); |
5194 | } |
5195 | |
5196 | spin_unlock_bh(lock: &pmlmepriv->lock); |
5197 | } |
5198 | |
5199 | u8 NULL_hdl(struct adapter *padapter, u8 *pbuf) |
5200 | { |
5201 | return H2C_SUCCESS; |
5202 | } |
5203 | |
5204 | u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf) |
5205 | { |
5206 | u8 type; |
5207 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5208 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
5209 | struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf; |
5210 | |
5211 | if (psetop->mode == Ndis802_11APMode) { |
5212 | pmlmeinfo->state = WIFI_FW_AP_STATE; |
5213 | type = _HW_STATE_AP_; |
5214 | /* start_ap_mode(padapter); */ |
5215 | } else if (psetop->mode == Ndis802_11Infrastructure) { |
5216 | pmlmeinfo->state &= ~(BIT(0)|BIT(1));/* clear state */ |
5217 | pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to STATION_STATE */ |
5218 | type = _HW_STATE_STATION_; |
5219 | } else if (psetop->mode == Ndis802_11IBSS) { |
5220 | type = _HW_STATE_ADHOC_; |
5221 | } else { |
5222 | type = _HW_STATE_NOLINK_; |
5223 | } |
5224 | |
5225 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_SET_OPMODE, val: (u8 *)(&type)); |
5226 | /* Set_MSR(padapter, type); */ |
5227 | |
5228 | if (psetop->mode == Ndis802_11APMode) { |
5229 | /* Do this after port switch to */ |
5230 | /* prevent from downloading rsvd page to wrong port */ |
5231 | rtw_btcoex_MediaStatusNotify(padapter, mediaStatus: 1); /* connect */ |
5232 | } |
5233 | |
5234 | return H2C_SUCCESS; |
5235 | |
5236 | } |
5237 | |
5238 | u8 createbss_hdl(struct adapter *padapter, u8 *pbuf) |
5239 | { |
5240 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5241 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
5242 | struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); |
5243 | struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf; |
5244 | /* u32 initialgain; */ |
5245 | |
5246 | if (pmlmeinfo->state == WIFI_FW_AP_STATE) { |
5247 | start_bss_network(padapter); |
5248 | return H2C_SUCCESS; |
5249 | } |
5250 | |
5251 | /* below is for ad-hoc master */ |
5252 | if (pparm->network.infrastructure_mode == Ndis802_11IBSS) { |
5253 | rtw_joinbss_reset(padapter); |
5254 | |
5255 | pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; |
5256 | pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; |
5257 | pmlmeinfo->ERP_enable = 0; |
5258 | pmlmeinfo->WMM_enable = 0; |
5259 | pmlmeinfo->HT_enable = 0; |
5260 | pmlmeinfo->HT_caps_enable = 0; |
5261 | pmlmeinfo->HT_info_enable = 0; |
5262 | pmlmeinfo->agg_enable_bitmap = 0; |
5263 | pmlmeinfo->candidate_tid_bitmap = 0; |
5264 | |
5265 | /* disable dynamic functions, such as high power, DIG */ |
5266 | Save_DM_Func_Flag(padapter); |
5267 | Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, enable: false); |
5268 | |
5269 | /* config the initial gain under linking, need to write the BB registers */ |
5270 | /* initialgain = 0x1E; */ |
5271 | /* rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */ |
5272 | |
5273 | /* cancel link timer */ |
5274 | del_timer_sync(timer: &pmlmeext->link_timer); |
5275 | |
5276 | /* clear CAM */ |
5277 | flush_all_cam_entry(padapter); |
5278 | |
5279 | memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, ie_length)); |
5280 | pnetwork->ie_length = ((struct wlan_bssid_ex *)pbuf)->ie_length; |
5281 | |
5282 | if (pnetwork->ie_length > MAX_IE_SZ)/* Check pbuf->ie_length */ |
5283 | return H2C_PARAMETERS_ERROR; |
5284 | |
5285 | memcpy(pnetwork->ies, ((struct wlan_bssid_ex *)pbuf)->ies, pnetwork->ie_length); |
5286 | |
5287 | start_create_ibss(padapter); |
5288 | |
5289 | } |
5290 | |
5291 | return H2C_SUCCESS; |
5292 | |
5293 | } |
5294 | |
5295 | u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf) |
5296 | { |
5297 | u8 join_type; |
5298 | struct ndis_80211_var_ie *pIE; |
5299 | struct registry_priv *pregpriv = &padapter->registrypriv; |
5300 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5301 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
5302 | struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); |
5303 | u32 i; |
5304 | u8 cbw40_enable = 0; |
5305 | /* u32 initialgain; */ |
5306 | /* u32 acparm; */ |
5307 | u8 ch, bw, offset; |
5308 | |
5309 | /* check already connecting to AP or not */ |
5310 | if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { |
5311 | if (pmlmeinfo->state & WIFI_FW_STATION_STATE) |
5312 | issue_deauth_ex(padapter, da: pnetwork->mac_address, reason: WLAN_REASON_DEAUTH_LEAVING, try_cnt: 1, wait_ms: 100); |
5313 | pmlmeinfo->state = WIFI_FW_NULL_STATE; |
5314 | |
5315 | /* clear CAM */ |
5316 | flush_all_cam_entry(padapter); |
5317 | |
5318 | del_timer_sync(timer: &pmlmeext->link_timer); |
5319 | |
5320 | /* set MSR to nolink -> infra. mode */ |
5321 | /* Set_MSR(padapter, _HW_STATE_NOLINK_); */ |
5322 | Set_MSR(padapter, _HW_STATE_STATION_); |
5323 | |
5324 | |
5325 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_MLME_DISCONNECT, NULL); |
5326 | } |
5327 | |
5328 | rtw_joinbss_reset(padapter); |
5329 | |
5330 | pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; |
5331 | pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; |
5332 | pmlmeinfo->ERP_enable = 0; |
5333 | pmlmeinfo->WMM_enable = 0; |
5334 | pmlmeinfo->HT_enable = 0; |
5335 | pmlmeinfo->HT_caps_enable = 0; |
5336 | pmlmeinfo->HT_info_enable = 0; |
5337 | pmlmeinfo->agg_enable_bitmap = 0; |
5338 | pmlmeinfo->candidate_tid_bitmap = 0; |
5339 | pmlmeinfo->bwmode_updated = false; |
5340 | /* pmlmeinfo->assoc_AP_vendor = HT_IOT_PEER_MAX; */ |
5341 | pmlmeinfo->VHT_enable = 0; |
5342 | |
5343 | memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, ie_length)); |
5344 | pnetwork->ie_length = ((struct wlan_bssid_ex *)pbuf)->ie_length; |
5345 | |
5346 | if (pnetwork->ie_length > MAX_IE_SZ)/* Check pbuf->ie_length */ |
5347 | return H2C_PARAMETERS_ERROR; |
5348 | |
5349 | memcpy(pnetwork->ies, ((struct wlan_bssid_ex *)pbuf)->ies, pnetwork->ie_length); |
5350 | |
5351 | pmlmeext->cur_channel = (u8)pnetwork->configuration.ds_config; |
5352 | pmlmeinfo->bcn_interval = get_beacon_interval(bss: pnetwork); |
5353 | |
5354 | /* Check AP vendor to move rtw_joinbss_cmd() */ |
5355 | /* pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->ies, pnetwork->ie_length); */ |
5356 | |
5357 | /* sizeof(struct ndis_802_11_fix_ie) */ |
5358 | for (i = _FIXED_IE_LENGTH_; i < pnetwork->ie_length;) { |
5359 | pIE = (struct ndis_80211_var_ie *)(pnetwork->ies + i); |
5360 | |
5361 | switch (pIE->element_id) { |
5362 | case WLAN_EID_VENDOR_SPECIFIC:/* Get WMM IE. */ |
5363 | if (!memcmp(p: pIE->data, q: WMM_OUI, size: 4)) |
5364 | WMM_param_handler(padapter, pIE); |
5365 | break; |
5366 | |
5367 | case WLAN_EID_HT_CAPABILITY: /* Get HT Cap IE. */ |
5368 | pmlmeinfo->HT_caps_enable = 1; |
5369 | break; |
5370 | |
5371 | case WLAN_EID_HT_OPERATION: /* Get HT Info IE. */ |
5372 | pmlmeinfo->HT_info_enable = 1; |
5373 | |
5374 | /* spec case only for cisco's ap because cisco's ap issue assoc rsp using mcs rate @40MHz or @20MHz */ |
5375 | { |
5376 | struct HT_info_element *pht_info = (struct HT_info_element *)(pIE->data); |
5377 | |
5378 | if (pnetwork->configuration.ds_config <= 14) { |
5379 | if ((pregpriv->bw_mode & 0x0f) > CHANNEL_WIDTH_20) |
5380 | cbw40_enable = 1; |
5381 | } |
5382 | |
5383 | if ((cbw40_enable) && (pht_info->infos[0] & BIT(2))) { |
5384 | /* switch to the 40M Hz mode according to the AP */ |
5385 | pmlmeext->cur_bwmode = CHANNEL_WIDTH_40; |
5386 | switch (pht_info->infos[0] & 0x3) { |
5387 | case 1: |
5388 | pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; |
5389 | break; |
5390 | |
5391 | case 3: |
5392 | pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; |
5393 | break; |
5394 | |
5395 | default: |
5396 | pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; |
5397 | pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; |
5398 | break; |
5399 | } |
5400 | } |
5401 | } |
5402 | break; |
5403 | default: |
5404 | break; |
5405 | } |
5406 | |
5407 | i += (pIE->length + 2); |
5408 | } |
5409 | |
5410 | /* check channel, bandwidth, offset and switch */ |
5411 | if (rtw_chk_start_clnt_join(padapter, ch: &ch, bw: &bw, offset: &offset) == _FAIL) { |
5412 | report_join_res(padapter, res: (-4)); |
5413 | return H2C_SUCCESS; |
5414 | } |
5415 | |
5416 | /* disable dynamic functions, such as high power, DIG */ |
5417 | /* Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); */ |
5418 | |
5419 | /* config the initial gain under linking, need to write the BB registers */ |
5420 | /* initialgain = 0x1E; */ |
5421 | /* rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */ |
5422 | |
5423 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_BSSID, val: pmlmeinfo->network.mac_address); |
5424 | join_type = 0; |
5425 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_MLME_JOIN, val: (u8 *)(&join_type)); |
5426 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_DO_IQK, NULL); |
5427 | |
5428 | set_channel_bwmode(padapter, channel: ch, channel_offset: offset, bwmode: bw); |
5429 | |
5430 | /* cancel link timer */ |
5431 | del_timer_sync(timer: &pmlmeext->link_timer); |
5432 | |
5433 | start_clnt_join(padapter); |
5434 | |
5435 | return H2C_SUCCESS; |
5436 | |
5437 | } |
5438 | |
5439 | u8 disconnect_hdl(struct adapter *padapter, unsigned char *pbuf) |
5440 | { |
5441 | struct disconnect_parm *param = (struct disconnect_parm *)pbuf; |
5442 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5443 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
5444 | struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); |
5445 | u8 val8; |
5446 | |
5447 | if (is_client_associated_to_ap(padapter)) |
5448 | issue_deauth_ex(padapter, da: pnetwork->mac_address, reason: WLAN_REASON_DEAUTH_LEAVING, try_cnt: param->deauth_timeout_ms/100, wait_ms: 100); |
5449 | |
5450 | if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) { |
5451 | /* Stop BCN */ |
5452 | val8 = 0; |
5453 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_BCN_FUNC, val: (u8 *)(&val8)); |
5454 | } |
5455 | |
5456 | rtw_mlmeext_disconnect(padapter); |
5457 | |
5458 | rtw_free_uc_swdec_pending_queue(adapter: padapter); |
5459 | |
5460 | return H2C_SUCCESS; |
5461 | } |
5462 | |
5463 | static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_channel *out, |
5464 | u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num) |
5465 | { |
5466 | int i, j; |
5467 | int set_idx; |
5468 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5469 | |
5470 | /* clear first */ |
5471 | memset(out, 0, sizeof(struct rtw_ieee80211_channel)*out_num); |
5472 | |
5473 | /* acquire channels from in */ |
5474 | j = 0; |
5475 | for (i = 0; i < in_num; i++) { |
5476 | |
5477 | set_idx = rtw_ch_set_search_ch(ch_set: pmlmeext->channel_set, ch: in[i].hw_value); |
5478 | if (in[i].hw_value && !(in[i].flags & RTW_IEEE80211_CHAN_DISABLED) |
5479 | && set_idx >= 0 |
5480 | ) { |
5481 | if (j >= out_num) { |
5482 | netdev_dbg(padapter->pnetdev, |
5483 | FUNC_ADPT_FMT " out_num:%u not enough\n" , |
5484 | FUNC_ADPT_ARG(padapter), out_num); |
5485 | break; |
5486 | } |
5487 | |
5488 | memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel)); |
5489 | |
5490 | if (pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE) |
5491 | out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN; |
5492 | |
5493 | j++; |
5494 | } |
5495 | if (j >= out_num) |
5496 | break; |
5497 | } |
5498 | |
5499 | /* if out is empty, use channel_set as default */ |
5500 | if (j == 0) { |
5501 | for (i = 0; i < pmlmeext->max_chan_nums; i++) { |
5502 | |
5503 | if (j >= out_num) { |
5504 | netdev_dbg(padapter->pnetdev, |
5505 | FUNC_ADPT_FMT " out_num:%u not enough\n" , |
5506 | FUNC_ADPT_ARG(padapter), |
5507 | out_num); |
5508 | break; |
5509 | } |
5510 | |
5511 | out[j].hw_value = pmlmeext->channel_set[i].ChannelNum; |
5512 | |
5513 | if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE) |
5514 | out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN; |
5515 | |
5516 | j++; |
5517 | } |
5518 | } |
5519 | |
5520 | return j; |
5521 | } |
5522 | |
5523 | u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf) |
5524 | { |
5525 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5526 | struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf; |
5527 | u8 bdelayscan = false; |
5528 | u8 val8; |
5529 | u32 initialgain; |
5530 | u32 i; |
5531 | |
5532 | if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) { |
5533 | pmlmeext->sitesurvey_res.state = SCAN_START; |
5534 | pmlmeext->sitesurvey_res.bss_cnt = 0; |
5535 | pmlmeext->sitesurvey_res.channel_idx = 0; |
5536 | |
5537 | for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { |
5538 | if (pparm->ssid[i].ssid_length) { |
5539 | memcpy(pmlmeext->sitesurvey_res.ssid[i].ssid, pparm->ssid[i].ssid, IW_ESSID_MAX_SIZE); |
5540 | pmlmeext->sitesurvey_res.ssid[i].ssid_length = pparm->ssid[i].ssid_length; |
5541 | } else { |
5542 | pmlmeext->sitesurvey_res.ssid[i].ssid_length = 0; |
5543 | } |
5544 | } |
5545 | |
5546 | pmlmeext->sitesurvey_res.ch_num = rtw_scan_ch_decision(padapter |
5547 | , out: pmlmeext->sitesurvey_res.ch, RTW_CHANNEL_SCAN_AMOUNT |
5548 | , in: pparm->ch, in_num: pparm->ch_num |
5549 | ); |
5550 | |
5551 | pmlmeext->sitesurvey_res.scan_mode = pparm->scan_mode; |
5552 | |
5553 | /* issue null data if associating to the AP */ |
5554 | if (is_client_associated_to_ap(padapter)) { |
5555 | pmlmeext->sitesurvey_res.state = SCAN_TXNULL; |
5556 | |
5557 | issue_nulldata(padapter, NULL, power_mode: 1, try_cnt: 3, wait_ms: 500); |
5558 | |
5559 | bdelayscan = true; |
5560 | } |
5561 | if (bdelayscan) { |
5562 | /* delay 50ms to protect nulldata(1). */ |
5563 | set_survey_timer(pmlmeext, 50); |
5564 | return H2C_SUCCESS; |
5565 | } |
5566 | } |
5567 | |
5568 | if ((pmlmeext->sitesurvey_res.state == SCAN_START) || (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) { |
5569 | /* disable dynamic functions, such as high power, DIG */ |
5570 | Save_DM_Func_Flag(padapter); |
5571 | Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, enable: false); |
5572 | |
5573 | /* config the initial gain under scanning, need to write the BB |
5574 | * registers |
5575 | */ |
5576 | initialgain = 0x1e; |
5577 | |
5578 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_INITIAL_GAIN, val: (u8 *)(&initialgain)); |
5579 | |
5580 | /* set MSR to no link state */ |
5581 | Set_MSR(padapter, _HW_STATE_NOLINK_); |
5582 | |
5583 | val8 = 1; /* under site survey */ |
5584 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_MLME_SITESURVEY, val: (u8 *)(&val8)); |
5585 | |
5586 | pmlmeext->sitesurvey_res.state = SCAN_PROCESS; |
5587 | } |
5588 | |
5589 | site_survey(padapter); |
5590 | |
5591 | return H2C_SUCCESS; |
5592 | |
5593 | } |
5594 | |
5595 | u8 setauth_hdl(struct adapter *padapter, unsigned char *pbuf) |
5596 | { |
5597 | struct setauth_parm *pparm = (struct setauth_parm *)pbuf; |
5598 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5599 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
5600 | |
5601 | if (pparm->mode < 4) |
5602 | pmlmeinfo->auth_algo = pparm->mode; |
5603 | |
5604 | return H2C_SUCCESS; |
5605 | } |
5606 | |
5607 | u8 setkey_hdl(struct adapter *padapter, u8 *pbuf) |
5608 | { |
5609 | u16 ctrl = 0; |
5610 | s16 cam_id = 0; |
5611 | struct setkey_parm *pparm = (struct setkey_parm *)pbuf; |
5612 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5613 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
5614 | unsigned char null_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
5615 | u8 *addr; |
5616 | |
5617 | /* main tx key for wep. */ |
5618 | if (pparm->set_tx) |
5619 | pmlmeinfo->key_index = pparm->keyid; |
5620 | |
5621 | cam_id = rtw_camid_alloc(adapter: padapter, NULL, kid: pparm->keyid); |
5622 | |
5623 | if (cam_id < 0) { |
5624 | } else { |
5625 | if (cam_id > 3) /* not default key, searched by A2 */ |
5626 | addr = get_bssid(pmlmepriv: &padapter->mlmepriv); |
5627 | else |
5628 | addr = null_addr; |
5629 | |
5630 | ctrl = BIT(15) | BIT6 | ((pparm->algorithm) << 2) | pparm->keyid; |
5631 | write_cam(padapter, id: cam_id, ctrl, mac: addr, key: pparm->key); |
5632 | netdev_dbg(padapter->pnetdev, |
5633 | "set group key camid:%d, addr:%pM, kid:%d, type:%s\n" , |
5634 | cam_id, MAC_ARG(addr), pparm->keyid, |
5635 | security_type_str(pparm->algorithm)); |
5636 | } |
5637 | |
5638 | if (cam_id >= 0 && cam_id <= 3) |
5639 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_SEC_DK_CFG, val: (u8 *)true); |
5640 | |
5641 | /* allow multicast packets to driver */ |
5642 | padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_ON_RCR_AM, null_addr); |
5643 | |
5644 | return H2C_SUCCESS; |
5645 | } |
5646 | |
5647 | u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf) |
5648 | { |
5649 | u16 ctrl = 0; |
5650 | s16 cam_id = 0; |
5651 | u8 ret = H2C_SUCCESS; |
5652 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5653 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
5654 | struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf; |
5655 | struct sta_priv *pstapriv = &padapter->stapriv; |
5656 | struct sta_info *psta; |
5657 | |
5658 | if (pparm->algorithm == _NO_PRIVACY_) |
5659 | goto write_to_cam; |
5660 | |
5661 | psta = rtw_get_stainfo(pstapriv, hwaddr: pparm->addr); |
5662 | if (!psta) { |
5663 | netdev_dbg(padapter->pnetdev, "%s sta:%pM not found\n" , |
5664 | __func__, MAC_ARG(pparm->addr)); |
5665 | ret = H2C_REJECTED; |
5666 | goto exit; |
5667 | } |
5668 | |
5669 | pmlmeinfo->enc_algo = pparm->algorithm; |
5670 | cam_id = rtw_camid_alloc(adapter: padapter, sta: psta, kid: 0); |
5671 | if (cam_id < 0) |
5672 | goto exit; |
5673 | |
5674 | write_to_cam: |
5675 | if (pparm->algorithm == _NO_PRIVACY_) { |
5676 | while ((cam_id = rtw_camid_search(adapter: padapter, addr: pparm->addr, kid: -1)) >= 0) { |
5677 | netdev_dbg(padapter->pnetdev, |
5678 | "clear key for addr:%pM, camid:%d\n" , |
5679 | MAC_ARG(pparm->addr), cam_id); |
5680 | clear_cam_entry(padapter, id: cam_id); |
5681 | rtw_camid_free(adapter: padapter, cam_id); |
5682 | } |
5683 | } else { |
5684 | netdev_dbg(padapter->pnetdev, |
5685 | "set pairwise key camid:%d, addr:%pM, kid:%d, type:%s\n" , |
5686 | cam_id, MAC_ARG(pparm->addr), pparm->keyid, |
5687 | security_type_str(pparm->algorithm)); |
5688 | ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid; |
5689 | write_cam(padapter, id: cam_id, ctrl, mac: pparm->addr, key: pparm->key); |
5690 | } |
5691 | ret = H2C_SUCCESS_RSP; |
5692 | |
5693 | exit: |
5694 | return ret; |
5695 | } |
5696 | |
5697 | u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf) |
5698 | { |
5699 | struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf; |
5700 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5701 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
5702 | |
5703 | struct sta_info *psta = rtw_get_stainfo(pstapriv: &padapter->stapriv, hwaddr: pparm->addr); |
5704 | |
5705 | if (!psta) |
5706 | return H2C_SUCCESS; |
5707 | |
5708 | if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) || |
5709 | ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) { |
5710 | /* pmlmeinfo->ADDBA_retry_count = 0; */ |
5711 | /* pmlmeinfo->candidate_tid_bitmap |= (0x1 << pparm->tid); */ |
5712 | /* psta->htpriv.candidate_tid_bitmap |= BIT(pparm->tid); */ |
5713 | issue_action_BA(padapter, raddr: pparm->addr, action: WLAN_ACTION_ADDBA_REQ, status: (u16)pparm->tid); |
5714 | /* _set_timer(&pmlmeext->ADDBA_timer, ADDBA_TO); */ |
5715 | _set_timer(ptimer: &psta->addba_retry_timer, ADDBA_TO); |
5716 | } else { |
5717 | psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid); |
5718 | } |
5719 | return H2C_SUCCESS; |
5720 | } |
5721 | |
5722 | |
5723 | u8 chk_bmc_sleepq_cmd(struct adapter *padapter) |
5724 | { |
5725 | struct cmd_obj *ph2c; |
5726 | struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); |
5727 | u8 res = _SUCCESS; |
5728 | |
5729 | ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); |
5730 | if (!ph2c) { |
5731 | res = _FAIL; |
5732 | goto exit; |
5733 | } |
5734 | |
5735 | init_h2fwcmd_w_parm_no_parm_rsp(ph2c, GEN_CMD_CODE(_ChkBMCSleepq)); |
5736 | |
5737 | res = rtw_enqueue_cmd(pcmdpriv, obj: ph2c); |
5738 | |
5739 | exit: |
5740 | return res; |
5741 | } |
5742 | |
5743 | u8 set_tx_beacon_cmd(struct adapter *padapter) |
5744 | { |
5745 | struct cmd_obj *ph2c; |
5746 | struct Tx_Beacon_param *ptxBeacon_parm; |
5747 | struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); |
5748 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5749 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
5750 | u8 res = _SUCCESS; |
5751 | int len_diff = 0; |
5752 | |
5753 | ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); |
5754 | if (!ph2c) { |
5755 | res = _FAIL; |
5756 | goto exit; |
5757 | } |
5758 | |
5759 | ptxBeacon_parm = rtw_zmalloc(sizeof(struct Tx_Beacon_param)); |
5760 | if (!ptxBeacon_parm) { |
5761 | kfree(objp: ph2c); |
5762 | res = _FAIL; |
5763 | goto exit; |
5764 | } |
5765 | |
5766 | memcpy(&(ptxBeacon_parm->network), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); |
5767 | |
5768 | len_diff = update_hidden_ssid(ies: ptxBeacon_parm->network.ies+_BEACON_IE_OFFSET_, |
5769 | ies_len: ptxBeacon_parm->network.ie_length-_BEACON_IE_OFFSET_, |
5770 | hidden_ssid_mode: pmlmeinfo->hidden_ssid_mode); |
5771 | ptxBeacon_parm->network.ie_length += len_diff; |
5772 | |
5773 | init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon)); |
5774 | |
5775 | res = rtw_enqueue_cmd(pcmdpriv, obj: ph2c); |
5776 | |
5777 | exit: |
5778 | return res; |
5779 | } |
5780 | |
5781 | static struct fwevent wlanevents[] = { |
5782 | {0, rtw_dummy_event_callback}, /*0*/ |
5783 | {0, NULL}, |
5784 | {0, NULL}, |
5785 | {0, NULL}, |
5786 | {0, NULL}, |
5787 | {0, NULL}, |
5788 | {0, NULL}, |
5789 | {0, NULL}, |
5790 | {0, &rtw_survey_event_callback}, /*8*/ |
5791 | {sizeof(struct surveydone_event), &rtw_surveydone_event_callback}, /*9*/ |
5792 | |
5793 | {0, &rtw_joinbss_event_callback}, /*10*/ |
5794 | {sizeof(struct stassoc_event), &rtw_stassoc_event_callback}, |
5795 | {sizeof(struct stadel_event), &rtw_stadel_event_callback}, |
5796 | {0, &rtw_atimdone_event_callback}, |
5797 | {0, rtw_dummy_event_callback}, |
5798 | {0, NULL}, /*15*/ |
5799 | {0, NULL}, |
5800 | {0, NULL}, |
5801 | {0, NULL}, |
5802 | {0, rtw_fwdbg_event_callback}, |
5803 | {0, NULL}, /*20*/ |
5804 | {0, NULL}, |
5805 | {0, NULL}, |
5806 | {0, &rtw_cpwm_event_callback}, |
5807 | {0, NULL}, |
5808 | {0, &rtw_wmm_event_callback}, |
5809 | |
5810 | }; |
5811 | |
5812 | u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf) |
5813 | { |
5814 | u8 evt_code; |
5815 | u16 evt_sz; |
5816 | uint *peventbuf; |
5817 | void (*event_callback)(struct adapter *dev, u8 *pbuf); |
5818 | struct evt_priv *pevt_priv = &(padapter->evtpriv); |
5819 | |
5820 | if (!pbuf) |
5821 | goto _abort_event_; |
5822 | |
5823 | peventbuf = (uint *)pbuf; |
5824 | evt_sz = (u16)(*peventbuf&0xffff); |
5825 | evt_code = (u8)((*peventbuf>>16)&0xff); |
5826 | |
5827 | /* checking if event code is valid */ |
5828 | if (evt_code >= MAX_C2HEVT) |
5829 | goto _abort_event_; |
5830 | |
5831 | /* checking if event size match the event parm size */ |
5832 | if ((wlanevents[evt_code].parmsize != 0) && |
5833 | (wlanevents[evt_code].parmsize != evt_sz)) |
5834 | goto _abort_event_; |
5835 | |
5836 | atomic_inc(v: &pevt_priv->event_seq); |
5837 | |
5838 | peventbuf += 2; |
5839 | |
5840 | if (peventbuf) { |
5841 | event_callback = wlanevents[evt_code].event_callback; |
5842 | event_callback(padapter, (u8 *)peventbuf); |
5843 | |
5844 | pevt_priv->evt_done_cnt++; |
5845 | } |
5846 | |
5847 | |
5848 | _abort_event_: |
5849 | |
5850 | |
5851 | return H2C_SUCCESS; |
5852 | |
5853 | } |
5854 | |
5855 | u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf) |
5856 | { |
5857 | if (!pbuf) |
5858 | return H2C_PARAMETERS_ERROR; |
5859 | |
5860 | return H2C_SUCCESS; |
5861 | } |
5862 | |
5863 | u8 chk_bmc_sleepq_hdl(struct adapter *padapter, unsigned char *pbuf) |
5864 | { |
5865 | struct sta_info *psta_bmc; |
5866 | struct list_head *xmitframe_plist, *xmitframe_phead, *tmp; |
5867 | struct xmit_frame *pxmitframe = NULL; |
5868 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
5869 | struct sta_priv *pstapriv = &padapter->stapriv; |
5870 | |
5871 | /* for BC/MC Frames */ |
5872 | psta_bmc = rtw_get_bcmc_stainfo(padapter); |
5873 | if (!psta_bmc) |
5874 | return H2C_SUCCESS; |
5875 | |
5876 | if ((pstapriv->tim_bitmap&BIT(0)) && (psta_bmc->sleepq_len > 0)) { |
5877 | msleep(msecs: 10);/* 10ms, ATIM(HIQ) Windows */ |
5878 | |
5879 | /* spin_lock_bh(&psta_bmc->sleep_q.lock); */ |
5880 | spin_lock_bh(lock: &pxmitpriv->lock); |
5881 | |
5882 | xmitframe_phead = get_list_head(queue: &psta_bmc->sleep_q); |
5883 | list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) { |
5884 | pxmitframe = list_entry(xmitframe_plist, |
5885 | struct xmit_frame, list); |
5886 | |
5887 | list_del_init(entry: &pxmitframe->list); |
5888 | |
5889 | psta_bmc->sleepq_len--; |
5890 | if (psta_bmc->sleepq_len > 0) |
5891 | pxmitframe->attrib.mdata = 1; |
5892 | else |
5893 | pxmitframe->attrib.mdata = 0; |
5894 | |
5895 | pxmitframe->attrib.triggered = 1; |
5896 | |
5897 | if (xmitframe_hiq_filter(xmitframe: pxmitframe)) |
5898 | pxmitframe->attrib.qsel = 0x11;/* HIQ */ |
5899 | |
5900 | rtw_hal_xmitframe_enqueue(padapter, pxmitframe); |
5901 | } |
5902 | |
5903 | /* spin_unlock_bh(&psta_bmc->sleep_q.lock); */ |
5904 | spin_unlock_bh(lock: &pxmitpriv->lock); |
5905 | |
5906 | /* check hi queue and bmc_sleepq */ |
5907 | rtw_chk_hi_queue_cmd(padapter); |
5908 | } |
5909 | |
5910 | return H2C_SUCCESS; |
5911 | } |
5912 | |
5913 | u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf) |
5914 | { |
5915 | if (send_beacon(padapter) == _FAIL) |
5916 | return H2C_PARAMETERS_ERROR; |
5917 | |
5918 | /* tx bc/mc frames after update TIM */ |
5919 | chk_bmc_sleepq_hdl(padapter, NULL); |
5920 | |
5921 | return H2C_SUCCESS; |
5922 | } |
5923 | |
5924 | int rtw_chk_start_clnt_join(struct adapter *padapter, u8 *ch, u8 *bw, u8 *offset) |
5925 | { |
5926 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5927 | unsigned char cur_ch = pmlmeext->cur_channel; |
5928 | unsigned char cur_bw = pmlmeext->cur_bwmode; |
5929 | unsigned char cur_ch_offset = pmlmeext->cur_ch_offset; |
5930 | bool connect_allow = true; |
5931 | |
5932 | if (!ch || !bw || !offset) { |
5933 | rtw_warn_on(1); |
5934 | connect_allow = false; |
5935 | } |
5936 | |
5937 | if (connect_allow) { |
5938 | *ch = cur_ch; |
5939 | *bw = cur_bw; |
5940 | *offset = cur_ch_offset; |
5941 | } |
5942 | |
5943 | return connect_allow ? _SUCCESS : _FAIL; |
5944 | } |
5945 | |
5946 | u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf) |
5947 | { |
5948 | struct set_ch_parm *set_ch_parm; |
5949 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5950 | |
5951 | if (!pbuf) |
5952 | return H2C_PARAMETERS_ERROR; |
5953 | |
5954 | set_ch_parm = (struct set_ch_parm *)pbuf; |
5955 | |
5956 | pmlmeext->cur_channel = set_ch_parm->ch; |
5957 | pmlmeext->cur_ch_offset = set_ch_parm->ch_offset; |
5958 | pmlmeext->cur_bwmode = set_ch_parm->bw; |
5959 | |
5960 | set_channel_bwmode(padapter, channel: set_ch_parm->ch, channel_offset: set_ch_parm->ch_offset, bwmode: set_ch_parm->bw); |
5961 | |
5962 | return H2C_SUCCESS; |
5963 | } |
5964 | |
5965 | u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf) |
5966 | { |
5967 | struct SetChannelPlan_param *setChannelPlan_param; |
5968 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
5969 | |
5970 | if (!pbuf) |
5971 | return H2C_PARAMETERS_ERROR; |
5972 | |
5973 | setChannelPlan_param = (struct SetChannelPlan_param *)pbuf; |
5974 | |
5975 | pmlmeext->max_chan_nums = init_channel_set(padapter, ChannelPlan: setChannelPlan_param->channel_plan, channel_set: pmlmeext->channel_set); |
5976 | init_channel_list(padapter, channel_set: pmlmeext->channel_set, chanset_size: pmlmeext->max_chan_nums, channel_list: &pmlmeext->channel_list); |
5977 | |
5978 | if (padapter->rtw_wdev && padapter->rtw_wdev->wiphy) { |
5979 | struct regulatory_request request; |
5980 | |
5981 | request.initiator = NL80211_REGDOM_SET_BY_DRIVER; |
5982 | rtw_reg_notifier(wiphy: padapter->rtw_wdev->wiphy, request: &request); |
5983 | } |
5984 | |
5985 | return H2C_SUCCESS; |
5986 | } |
5987 | |
5988 | u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf) |
5989 | { |
5990 | return H2C_REJECTED; |
5991 | } |
5992 | |
5993 | /* TDLS_ESTABLISHED : write RCR DATA BIT */ |
5994 | /* TDLS_CS_OFF : go back to the channel linked with AP, terminating channel switch procedure */ |
5995 | /* TDLS_INIT_CH_SEN : init channel sensing, receive all data and mgnt frame */ |
5996 | /* TDLS_DONE_CH_SEN: channel sensing and report candidate channel */ |
5997 | /* TDLS_OFF_CH : first time set channel to off channel */ |
5998 | /* TDLS_BASE_CH : go back tp the channel linked with AP when set base channel as target channel */ |
5999 | /* TDLS_P_OFF_CH : periodically go to off channel */ |
6000 | /* TDLS_P_BASE_CH : periodically go back to base channel */ |
6001 | /* TDLS_RS_RCR : restore RCR */ |
6002 | /* TDLS_TEAR_STA : free tdls sta */ |
6003 | u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf) |
6004 | { |
6005 | return H2C_REJECTED; |
6006 | } |
6007 | |
6008 | u8 run_in_thread_hdl(struct adapter *padapter, u8 *pbuf) |
6009 | { |
6010 | struct RunInThread_param *p; |
6011 | |
6012 | |
6013 | if (pbuf == NULL) |
6014 | return H2C_PARAMETERS_ERROR; |
6015 | p = (struct RunInThread_param *)pbuf; |
6016 | |
6017 | if (p->func) |
6018 | p->func(p->context); |
6019 | |
6020 | return H2C_SUCCESS; |
6021 | } |
6022 | |