1 /******************************************************************************
2 *
3 * Copyright(c) 2007 - 2017 Realtek Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 *****************************************************************************/
15
16 #include <drv_types.h>
17 #include <hal_data.h>
18
19 #ifdef CONFIG_RTW_80211R
20
21 #ifndef RTW_FT_DBG
22 #define RTW_FT_DBG 0
23 #endif
24 #if RTW_FT_DBG
25 #define RTW_FT_INFO(fmt, arg...) \
26 RTW_INFO(fmt, arg)
27 #define RTW_FT_DUMP(str, data, len) \
28 RTW_INFO_DUMP(str, data, len)
29 #else
30 #define RTW_FT_INFO(fmt, arg...) do {} while (0)
31 #define RTW_FT_DUMP(str, data, len) do {} while (0)
32 #endif
33
rtw_ft_info_init(struct ft_roam_info * pft)34 void rtw_ft_info_init(struct ft_roam_info *pft)
35 {
36 _rtw_memset(pft, 0, sizeof(struct ft_roam_info));
37 pft->ft_flags = 0
38 | RTW_FT_EN
39 /* | RTW_FT_OTD_EN */
40 #ifdef CONFIG_RTW_BTM_ROAM
41 | RTW_FT_BTM_ROAM
42 #endif
43 ;
44 pft->ft_updated_bcn = _FALSE;
45 RTW_FT_INFO("%s : ft_flags=0x%02x\n", __func__, pft->ft_flags);
46 }
47
rtw_ft_proc_flags_set(struct file * file,const char __user * buffer,size_t count,loff_t * pos,void * data)48 ssize_t rtw_ft_proc_flags_set(struct file *file,
49 const char __user *buffer, size_t count, loff_t *pos, void *data)
50 {
51 struct net_device *dev = data;
52 _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
53
54 char tmp[32];
55 u8 flags;
56
57 if (count < 1)
58 return -EFAULT;
59
60 if (count > sizeof(tmp)) {
61 rtw_warn_on(1);
62 return -EFAULT;
63 }
64
65 if (buffer && !copy_from_user(tmp, buffer, count)) {
66 int num = sscanf(tmp, "%hhx", &flags);
67 if (num == 1)
68 adapter->mlmepriv.ft_roam.ft_flags = flags;
69 }
70
71 return count;
72
73 }
74
rtw_ft_proc_flags_get(struct seq_file * m,void * v)75 int rtw_ft_proc_flags_get(struct seq_file *m, void *v)
76 {
77 struct net_device *dev = m->private;
78 _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
79
80 RTW_PRINT_SEL(m, "0x%02x\n", adapter->mlmepriv.ft_roam.ft_flags);
81
82 return 0;
83 }
84
rtw_ft_chk_roaming_candidate(_adapter * padapter,struct wlan_network * competitor)85 u8 rtw_ft_chk_roaming_candidate(
86 _adapter *padapter, struct wlan_network *competitor)
87 {
88 u8 *pmdie;
89 u32 mdie_len = 0;
90 struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
91
92 if (!(pmdie = rtw_get_ie(&competitor->network.IEs[12],
93 _MDIE_, &mdie_len, competitor->network.IELength-12))) {
94 RTW_INFO("FT : MDIE not foud in competitor!\n");
95 return _FALSE;
96 }
97
98 if (!_rtw_memcmp(&pft_roam->mdid, (pmdie+2), 2)) {
99 RTW_INFO("FT : unmatched MDIE!\n");
100 return _FALSE;
101 }
102
103 /*The candidate don't support over-the-DS*/
104 if (rtw_ft_valid_otd_candidate(padapter, pmdie)) {
105 RTW_INFO("FT: ignore the candidate("
106 MAC_FMT ") for over-the-DS\n",
107 MAC_ARG(competitor->network.MacAddress));
108 /* rtw_ft_clr_flags(padapter, RTW_FT_PEER_OTD_EN); */
109 return _FALSE;
110 }
111
112 if (rtw_ft_chk_flags(padapter, RTW_FT_TEST_RSSI_ROAM)) {
113 if (!_rtw_memcmp(padapter->mlmepriv.cur_network.network.MacAddress,
114 competitor->network.MacAddress, ETH_ALEN) ) {
115 competitor->network.Rssi +=20;
116 RTW_FT_INFO("%s : update "MAC_FMT" RSSI to %d for RTW_FT_TEST_RSSI_ROAM\n",
117 __func__, MAC_ARG(competitor->network.MacAddress),
118 (int)competitor->network.Rssi);
119 rtw_ft_clr_flags(padapter, RTW_FT_TEST_RSSI_ROAM);
120 }
121 }
122
123 return _TRUE;
124 }
125
rtw_ft_update_stainfo(_adapter * padapter,WLAN_BSSID_EX * pnetwork)126 void rtw_ft_update_stainfo(_adapter *padapter, WLAN_BSSID_EX *pnetwork)
127 {
128 struct sta_priv *pstapriv = &padapter->stapriv;
129 struct sta_info *psta = NULL;
130
131 psta = rtw_get_stainfo(pstapriv, pnetwork->MacAddress);
132 if (psta == NULL)
133 psta = rtw_alloc_stainfo(pstapriv, pnetwork->MacAddress);
134
135 if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
136
137 padapter->securitypriv.binstallGrpkey = _FALSE;
138 padapter->securitypriv.busetkipkey = _FALSE;
139 padapter->securitypriv.bgrpkey_handshake = _FALSE;
140
141 psta->ieee8021x_blocked = _TRUE;
142 psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
143
144 _rtw_memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof(union Keytype));
145 _rtw_memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof(union Keytype));
146 _rtw_memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof(union Keytype));
147 }
148
149 }
150
rtw_ft_reassoc_event_callback(_adapter * padapter,u8 * pbuf)151 void rtw_ft_reassoc_event_callback(_adapter *padapter, u8 *pbuf)
152 {
153 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
154 struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf;
155 struct ft_roam_info *pft_roam = &(pmlmepriv->ft_roam);
156 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
157 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
158 WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&(pmlmeinfo->network);
159 struct cfg80211_ft_event_params ft_evt_parms;
160 _irqL irqL;
161
162 _rtw_memset(&ft_evt_parms, 0, sizeof(ft_evt_parms));
163 rtw_ft_update_stainfo(padapter, pnetwork);
164 ft_evt_parms.ies_len = pft_roam->ft_event.ies_len;
165 ft_evt_parms.ies = rtw_zmalloc(ft_evt_parms.ies_len);
166 if (ft_evt_parms.ies)
167 _rtw_memcpy((void *)ft_evt_parms.ies, pft_roam->ft_event.ies, ft_evt_parms.ies_len);
168 else
169 goto err_2;
170
171 ft_evt_parms.target_ap = rtw_zmalloc(ETH_ALEN);
172 if (ft_evt_parms.target_ap)
173 _rtw_memcpy((void *)ft_evt_parms.target_ap, pstassoc->macaddr, ETH_ALEN);
174 else
175 goto err_1;
176
177 ft_evt_parms.ric_ies = pft_roam->ft_event.ric_ies;
178 ft_evt_parms.ric_ies_len = pft_roam->ft_event.ric_ies_len;
179
180 /* It's a KERNEL issue between v4.11 ~ v4.16,
181 * <= v4.10, NLMSG_DEFAULT_SIZE is used for nlmsg_new().
182 * v4.11 ~ v4.16, only used "100 + >ric_ies_len" for nlmsg_new()
183 * even then DRIVER don't support RIC.
184 * >= v4.17, issue should correct as "100 + ies_len + ric_ies_len".
185 */
186 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) && \
187 (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)))
188 if (!ft_evt_parms.ric_ies_len)
189 ft_evt_parms.ric_ies_len = ft_evt_parms.ies_len;
190 else
191 ft_evt_parms.ric_ies_len += ft_evt_parms.ies_len;
192 #endif
193
194 rtw_ft_lock_set_status(padapter, RTW_FT_AUTHENTICATED_STA, &irqL);
195 rtw_cfg80211_ft_event(padapter, &ft_evt_parms);
196 RTW_INFO("%s: to "MAC_FMT"\n", __func__, MAC_ARG(ft_evt_parms.target_ap));
197
198 rtw_mfree((u8 *)pft_roam->ft_event.target_ap, ETH_ALEN);
199 err_1:
200 rtw_mfree((u8 *)ft_evt_parms.ies, ft_evt_parms.ies_len);
201 err_2:
202 return;
203 }
204
rtw_ft_validate_akm_type(_adapter * padapter,struct wlan_network * pnetwork)205 void rtw_ft_validate_akm_type(_adapter *padapter,
206 struct wlan_network *pnetwork)
207 {
208 struct security_priv *psecuritypriv = &(padapter->securitypriv);
209 struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
210 u32 tmp_len;
211 u8 *ptmp;
212
213 /*IEEE802.11-2012 Std. Table 8-101-AKM suite selectors*/
214 if (rtw_ft_valid_akm(padapter, psecuritypriv->rsn_akm_suite_type)) {
215 ptmp = rtw_get_ie(&pnetwork->network.IEs[12],
216 _MDIE_, &tmp_len, (pnetwork->network.IELength-12));
217 if (ptmp) {
218 pft_roam->mdid = *(u16 *)(ptmp+2);
219 pft_roam->ft_cap = *(ptmp+4);
220
221 RTW_INFO("FT: target " MAC_FMT " mdid=(0x%2x), capacity=(0x%2x)\n",
222 MAC_ARG(pnetwork->network.MacAddress), pft_roam->mdid, pft_roam->ft_cap);
223 rtw_ft_set_flags(padapter, RTW_FT_PEER_EN);
224 RTW_FT_INFO("%s : peer support FTOTA(0x%02x)\n", __func__, pft_roam->ft_flags);
225
226 if (rtw_ft_otd_roam_en(padapter)) {
227 rtw_ft_set_flags(padapter, RTW_FT_PEER_OTD_EN);
228 RTW_FT_INFO("%s : peer support FTOTD(0x%02x)\n", __func__, pft_roam->ft_flags);
229 }
230 } else {
231 /* Don't use FT roaming if target AP cannot support FT */
232 rtw_ft_clr_flags(padapter, (RTW_FT_PEER_EN|RTW_FT_PEER_OTD_EN));
233 rtw_ft_reset_status(padapter);
234 }
235 } else {
236 /* It could be a non-FT connection */
237 rtw_ft_clr_flags(padapter, (RTW_FT_PEER_EN|RTW_FT_PEER_OTD_EN));
238 rtw_ft_reset_status(padapter);
239 }
240
241 RTW_FT_INFO("%s : ft_flags=0x%02x\n", __func__, pft_roam->ft_flags);
242 }
243
rtw_ft_update_bcn(_adapter * padapter,union recv_frame * precv_frame)244 void rtw_ft_update_bcn(_adapter *padapter, union recv_frame *precv_frame)
245 {
246 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
247 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
248 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
249 u8 *pframe = precv_frame->u.hdr.rx_data;
250 uint len = precv_frame->u.hdr.len;
251 WLAN_BSSID_EX *pbss;
252
253 if (rtw_ft_chk_status(padapter,RTW_FT_ASSOCIATED_STA)
254 && (pmlmepriv->ft_roam.ft_updated_bcn == _FALSE)) {
255 pbss = (WLAN_BSSID_EX*)rtw_malloc(sizeof(WLAN_BSSID_EX));
256 if (pbss) {
257 if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) {
258 struct beacon_keys recv_beacon;
259
260 update_network(&(pmlmepriv->cur_network.network), pbss, padapter, _TRUE);
261 /* Move into rtw_get_bcn_keys */
262 /* rtw_get_bcn_info(&(pmlmepriv->cur_network)); */
263
264 /* update bcn keys */
265 if (rtw_get_bcn_keys(padapter, pframe, len, &recv_beacon) == _TRUE) {
266 RTW_FT_INFO("%s: beacon keys ready\n", __func__);
267 _rtw_memcpy(&pmlmepriv->cur_beacon_keys,
268 &recv_beacon, sizeof(recv_beacon));
269 if (is_hidden_ssid(recv_beacon.ssid, recv_beacon.ssid_len)) {
270 _rtw_memcpy(pmlmepriv->cur_beacon_keys.ssid, pmlmeinfo->network.Ssid.Ssid, IW_ESSID_MAX_SIZE);
271 pmlmepriv->cur_beacon_keys.ssid_len = pmlmeinfo->network.Ssid.SsidLength;
272 }
273 } else {
274 RTW_ERR("%s: get beacon keys failed\n", __func__);
275 _rtw_memset(&pmlmepriv->cur_beacon_keys, 0, sizeof(recv_beacon));
276 }
277 #ifdef CONFIG_BCN_CNT_CONFIRM_HDL
278 pmlmepriv->new_beacon_cnts = 0;
279 #endif
280 }
281 rtw_mfree((u8*)pbss, sizeof(WLAN_BSSID_EX));
282 }
283
284 /* check the vendor of the assoc AP */
285 pmlmeinfo->assoc_AP_vendor =
286 check_assoc_AP(pframe+sizeof(struct rtw_ieee80211_hdr_3addr),
287 (len - sizeof(struct rtw_ieee80211_hdr_3addr)));
288
289 rtw_phydm_update_ap_vendor_ie(padapter);
290
291 /* update TSF Value */
292 update_TSF(pmlmeext, pframe, len);
293 pmlmeext->bcn_cnt = 0;
294 pmlmeext->last_bcn_cnt = 0;
295 pmlmepriv->ft_roam.ft_updated_bcn = _TRUE;
296 }
297 }
298
rtw_ft_start_clnt_join(_adapter * padapter)299 void rtw_ft_start_clnt_join(_adapter *padapter)
300 {
301 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
302 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
303 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
304 struct ft_roam_info *pft_roam = &(pmlmepriv->ft_roam);
305
306 if (rtw_ft_otd_roam(padapter)) {
307 pmlmeinfo->state = WIFI_FW_AUTH_SUCCESS | WIFI_FW_STATION_STATE;
308 pft_roam->ft_event.ies =
309 (pft_roam->ft_action + sizeof(struct rtw_ieee80211_hdr_3addr) + 16);
310 pft_roam->ft_event.ies_len =
311 (pft_roam->ft_action_len - sizeof(struct rtw_ieee80211_hdr_3addr));
312
313 /*Not support RIC*/
314 pft_roam->ft_event.ric_ies = NULL;
315 pft_roam->ft_event.ric_ies_len = 0;
316 rtw_ft_report_evt(padapter);
317 return;
318 }
319
320 pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE;
321 start_clnt_auth(padapter);
322 }
323
rtw_ft_update_rsnie(_adapter * padapter,u8 bwrite,struct pkt_attrib * pattrib,u8 ** pframe)324 u8 rtw_ft_update_rsnie(
325 _adapter *padapter, u8 bwrite,
326 struct pkt_attrib *pattrib, u8 **pframe)
327 {
328 struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
329 u8 *pie;
330 u32 len;
331
332 pie = rtw_get_ie(pft_roam->updated_ft_ies, EID_WPA2, &len,
333 pft_roam->updated_ft_ies_len);
334
335 if (!bwrite)
336 return (pie)?_SUCCESS:_FAIL;
337
338 if (pie) {
339 *pframe = rtw_set_ie(((u8 *)*pframe), EID_WPA2, len,
340 pie+2, &(pattrib->pktlen));
341 } else
342 return _FAIL;
343
344 return _SUCCESS;
345 }
346
rtw_ft_update_mdie(_adapter * padapter,struct pkt_attrib * pattrib,u8 ** pframe)347 static u8 rtw_ft_update_mdie(
348 _adapter *padapter, struct pkt_attrib *pattrib, u8 **pframe)
349 {
350 struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
351 u8 *pie, mdie[3];
352 u32 len = 3;
353
354 if (rtw_ft_roam(padapter)) {
355 if ((pie = rtw_get_ie(pft_roam->updated_ft_ies, _MDIE_,
356 &len, pft_roam->updated_ft_ies_len))) {
357 pie = (pie + 2); /* ignore md-id & length */
358 } else
359 return _FAIL;
360 } else {
361 *((u16 *)&mdie[0]) = pft_roam->mdid;
362 mdie[2] = pft_roam->ft_cap;
363 pie = &mdie[0];
364 }
365
366 *pframe = rtw_set_ie(((u8 *)*pframe), _MDIE_, len , pie, &(pattrib->pktlen));
367 return _SUCCESS;
368 }
369
rtw_ft_update_ftie(_adapter * padapter,struct pkt_attrib * pattrib,u8 ** pframe)370 static u8 rtw_ft_update_ftie(
371 _adapter *padapter, struct pkt_attrib *pattrib, u8 **pframe)
372 {
373 struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
374 u8 *pie;
375 u32 len;
376
377 if ((pie = rtw_get_ie(pft_roam->updated_ft_ies, _FTIE_, &len,
378 pft_roam->updated_ft_ies_len)) != NULL) {
379 *pframe = rtw_set_ie(*pframe, _FTIE_, len ,
380 (pie+2), &(pattrib->pktlen));
381 } else
382 return _FAIL;
383
384 return _SUCCESS;
385 }
386
rtw_ft_build_auth_req_ies(_adapter * padapter,struct pkt_attrib * pattrib,u8 ** pframe)387 void rtw_ft_build_auth_req_ies(_adapter *padapter,
388 struct pkt_attrib *pattrib, u8 **pframe)
389 {
390 u8 ftie_append = _TRUE;
391
392 if (!pattrib || !(*pframe))
393 return;
394
395 if (!rtw_ft_roam(padapter))
396 return;
397
398 ftie_append = rtw_ft_update_rsnie(padapter, _TRUE, pattrib, pframe);
399 rtw_ft_update_mdie(padapter, pattrib, pframe);
400 if (ftie_append)
401 rtw_ft_update_ftie(padapter, pattrib, pframe);
402 }
403
rtw_ft_build_assoc_req_ies(_adapter * padapter,u8 is_reassoc,struct pkt_attrib * pattrib,u8 ** pframe)404 void rtw_ft_build_assoc_req_ies(_adapter *padapter,
405 u8 is_reassoc, struct pkt_attrib *pattrib, u8 **pframe)
406 {
407 if (!pattrib || !(*pframe))
408 return;
409
410 if (rtw_ft_chk_flags(padapter, RTW_FT_PEER_EN))
411 rtw_ft_update_mdie(padapter, pattrib, pframe);
412
413 if ((!is_reassoc) || (!rtw_ft_roam(padapter)))
414 return;
415
416 if (rtw_ft_update_rsnie(padapter, _FALSE, pattrib, pframe))
417 rtw_ft_update_ftie(padapter, pattrib, pframe);
418 }
419
rtw_ft_update_auth_rsp_ies(_adapter * padapter,u8 * pframe,u32 len)420 u8 rtw_ft_update_auth_rsp_ies(_adapter *padapter, u8 *pframe, u32 len)
421 {
422 u8 ret = _SUCCESS;
423 u8 target_ap_addr[ETH_ALEN] = {0};
424 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
425 struct ft_roam_info *pft_roam = &(pmlmepriv->ft_roam);
426
427 if (!rtw_ft_roam(padapter))
428 return _FAIL;
429
430 /*rtw_ft_report_reassoc_evt already,
431 * and waiting for cfg80211_rtw_update_ft_ies */
432 if (rtw_ft_authed_sta(padapter))
433 return ret;
434
435 if (!pframe || !len)
436 return _FAIL;
437
438 rtw_buf_update(&pmlmepriv->auth_rsp,
439 &pmlmepriv->auth_rsp_len, pframe, len);
440 pft_roam->ft_event.ies =
441 (pmlmepriv->auth_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + 6);
442 pft_roam->ft_event.ies_len =
443 (pmlmepriv->auth_rsp_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 6);
444
445 /*Not support RIC*/
446 pft_roam->ft_event.ric_ies = NULL;
447 pft_roam->ft_event.ric_ies_len = 0;
448 _rtw_memcpy(target_ap_addr, pmlmepriv->assoc_bssid, ETH_ALEN);
449 rtw_ft_report_reassoc_evt(padapter, target_ap_addr);
450
451 return ret;
452 }
453
rtw_ft_start_clnt_action(_adapter * padapter,u8 * pTargetAddr)454 static void rtw_ft_start_clnt_action(_adapter *padapter, u8 *pTargetAddr)
455 {
456 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
457
458 rtw_ft_set_status(padapter, RTW_FT_REQUESTING_STA);
459 rtw_ft_issue_action_req(padapter, pTargetAddr);
460 _set_timer(&pmlmeext->ft_link_timer, REASSOC_TO);
461 }
462
rtw_ft_start_roam(_adapter * padapter,u8 * pTargetAddr)463 void rtw_ft_start_roam(_adapter *padapter, u8 *pTargetAddr)
464 {
465 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
466
467 if (rtw_ft_otd_roam(padapter)) {
468 RTW_FT_INFO("%s : try OTD roaming\n", __func__);
469 rtw_ft_start_clnt_action(padapter, pTargetAddr);
470 } else {
471 /*wait a little time to retrieve packets buffered in the current ap while scan*/
472 RTW_FT_INFO("%s : start roaming timer\n", __func__);
473 _set_timer(&pmlmeext->ft_roam_timer, 30);
474 }
475 }
476
rtw_ft_issue_action_req(_adapter * padapter,u8 * pTargetAddr)477 void rtw_ft_issue_action_req(_adapter *padapter, u8 *pTargetAddr)
478 {
479 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
480 struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
481 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
482 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
483 struct xmit_frame *pmgntframe;
484 struct rtw_ieee80211_hdr *pwlanhdr;
485 struct pkt_attrib *pattrib;
486 u8 *pframe;
487 u8 category = RTW_WLAN_CATEGORY_FT;
488 u8 action = RTW_WLAN_ACTION_FT_REQ;
489
490 pmgntframe = alloc_mgtxmitframe(pxmitpriv);
491 if (pmgntframe == NULL)
492 return;
493
494 pattrib = &pmgntframe->attrib;
495 update_mgntframe_attrib(padapter, pattrib);
496 _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
497
498 pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
499 pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
500 pwlanhdr->frame_ctl = 0;
501
502 _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
503 _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
504 _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
505
506 SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
507 pmlmeext->mgnt_seq++;
508 set_frame_sub_type(pframe, WIFI_ACTION);
509
510 pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
511 pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
512
513 pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
514 pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
515
516 _rtw_memcpy(pframe, adapter_mac_addr(padapter), ETH_ALEN);
517 pframe += ETH_ALEN;
518 pattrib->pktlen += ETH_ALEN;
519
520 _rtw_memcpy(pframe, pTargetAddr, ETH_ALEN);
521 pframe += ETH_ALEN;
522 pattrib->pktlen += ETH_ALEN;
523
524 rtw_ft_update_mdie(padapter, pattrib, &pframe);
525 if (rtw_ft_update_rsnie(padapter, _TRUE, pattrib, &pframe))
526 rtw_ft_update_ftie(padapter, pattrib, &pframe);
527
528 RTW_INFO("FT : issue RTW_WLAN_ACTION_FT_REQ\n");
529 pattrib->last_txcmdsz = pattrib->pktlen;
530 dump_mgntframe(padapter, pmgntframe);
531 }
532
rtw_ft_report_evt(_adapter * padapter)533 void rtw_ft_report_evt(_adapter *padapter)
534 {
535 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
536 struct ft_roam_info *pft_roam = &(pmlmepriv->ft_roam);
537 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
538 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
539 WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&(pmlmeinfo->network);
540 struct cfg80211_ft_event_params ft_evt_parms;
541 _irqL irqL;
542
543 _rtw_memset(&ft_evt_parms, 0, sizeof(ft_evt_parms));
544 rtw_ft_update_stainfo(padapter, pnetwork);
545
546 if (!pnetwork)
547 goto err_2;
548
549 ft_evt_parms.ies_len = pft_roam->ft_event.ies_len;
550 ft_evt_parms.ies = rtw_zmalloc(ft_evt_parms.ies_len);
551 if (ft_evt_parms.ies)
552 _rtw_memcpy((void *)ft_evt_parms.ies, pft_roam->ft_event.ies, ft_evt_parms.ies_len);
553 else
554 goto err_2;
555
556 ft_evt_parms.target_ap = rtw_zmalloc(ETH_ALEN);
557 if (ft_evt_parms.target_ap)
558 _rtw_memcpy((void *)ft_evt_parms.target_ap, pnetwork->MacAddress, ETH_ALEN);
559 else
560 goto err_1;
561
562 ft_evt_parms.ric_ies = pft_roam->ft_event.ric_ies;
563 ft_evt_parms.ric_ies_len = pft_roam->ft_event.ric_ies_len;
564
565 /* It's a KERNEL issue between v4.11 ~ v4.16,
566 * <= v4.10, NLMSG_DEFAULT_SIZE is used for nlmsg_new().
567 * v4.11 ~ v4.16, only used "100 + >ric_ies_len" for nlmsg_new()
568 * even then DRIVER don't support RIC.
569 * >= v4.17, issue should correct as "100 + ies_len + ric_ies_len".
570 */
571 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) && \
572 (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)))
573 ft_evt_parms.ric_ies_len = (ft_evt_parms.ies_len <= 100 )?
574 (0):(ft_evt_parms.ies_len - 100);
575 #endif
576
577 rtw_ft_lock_set_status(padapter, RTW_FT_AUTHENTICATED_STA, &irqL);
578 rtw_cfg80211_ft_event(padapter, &ft_evt_parms);
579 RTW_INFO("FT: rtw_ft_report_evt\n");
580 rtw_mfree((u8 *)pft_roam->ft_event.target_ap, ETH_ALEN);
581 err_1:
582 rtw_mfree((u8 *)ft_evt_parms.ies, ft_evt_parms.ies_len);
583 err_2:
584 return;
585 }
586
rtw_ft_report_reassoc_evt(_adapter * padapter,u8 * pMacAddr)587 void rtw_ft_report_reassoc_evt(_adapter *padapter, u8 *pMacAddr)
588 {
589 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
590 struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
591 struct cmd_obj *pcmd_obj = NULL;
592 struct stassoc_event *passoc_sta_evt = NULL;
593 struct rtw_evt_header *evt_hdr = NULL;
594 u8 *pevtcmd = NULL;
595 u32 cmdsz = 0;
596
597 pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
598 if (pcmd_obj == NULL)
599 return;
600
601 cmdsz = (sizeof(struct stassoc_event) + sizeof(struct rtw_evt_header));
602 pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
603 if (pevtcmd == NULL) {
604 rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj));
605 return;
606 }
607
608 _rtw_init_listhead(&pcmd_obj->list);
609 pcmd_obj->cmdcode = CMD_SET_MLME_EVT;
610 pcmd_obj->cmdsz = cmdsz;
611 pcmd_obj->parmbuf = pevtcmd;
612 pcmd_obj->rsp = NULL;
613 pcmd_obj->rspsz = 0;
614
615 evt_hdr = (struct rtw_evt_header *)(pevtcmd);
616 evt_hdr->len = sizeof(struct stassoc_event);
617 evt_hdr->id = EVT_FT_REASSOC;
618 evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
619
620 passoc_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct rtw_evt_header));
621 _rtw_memcpy((unsigned char *)(&(passoc_sta_evt->macaddr)), pMacAddr, ETH_ALEN);
622 rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
623 }
624
rtw_ft_link_timer_hdl(void * ctx)625 void rtw_ft_link_timer_hdl(void *ctx)
626 {
627 _adapter *padapter = (_adapter *)ctx;
628 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
629 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
630 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
631 struct ft_roam_info *pft_roam = &(pmlmepriv->ft_roam);
632
633 if (rtw_ft_chk_status(padapter, RTW_FT_REQUESTING_STA)) {
634 if (pft_roam->ft_req_retry_cnt < RTW_FT_ACTION_REQ_LMT) {
635 pft_roam->ft_req_retry_cnt++;
636 rtw_ft_issue_action_req(padapter, (u8 *)pmlmepriv->roam_network->network.MacAddress);
637 _set_timer(&pmlmeext->ft_link_timer, REASSOC_TO);
638 } else {
639 pft_roam->ft_req_retry_cnt = 0;
640 if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
641 rtw_ft_set_status(padapter, RTW_FT_ASSOCIATED_STA);
642 else
643 rtw_ft_reset_status(padapter);
644 }
645 }
646 }
647
rtw_ft_roam_timer_hdl(void * ctx)648 void rtw_ft_roam_timer_hdl(void *ctx)
649 {
650 _adapter *padapter = (_adapter *)ctx;
651 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
652
653 RTW_FT_INFO("%s : try roaming\n", __func__);
654 receive_disconnect(padapter, pmlmepriv->cur_network.network.MacAddress
655 , WLAN_REASON_ACTIVE_ROAM, _FALSE);
656 }
657
rtw_ft_roam_status_reset(_adapter * padapter)658 void rtw_ft_roam_status_reset(_adapter *padapter)
659 {
660 struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
661
662 if ((rtw_to_roam(padapter) > 0) &&
663 (!rtw_ft_chk_status(padapter, RTW_FT_REQUESTED_STA))) {
664 rtw_ft_reset_status(padapter);
665 }
666
667 padapter->mlmepriv.ft_roam.ft_updated_bcn = _FALSE;
668 }
669
670 #endif /* CONFIG_RTW_80211R */
671