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 /* update TSF Value */
290 update_TSF(pmlmeext, pframe, len);
291 pmlmeext->bcn_cnt = 0;
292 pmlmeext->last_bcn_cnt = 0;
293 pmlmepriv->ft_roam.ft_updated_bcn = _TRUE;
294 }
295 }
296
rtw_ft_start_clnt_join(_adapter * padapter)297 void rtw_ft_start_clnt_join(_adapter *padapter)
298 {
299 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
300 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
301 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
302 struct ft_roam_info *pft_roam = &(pmlmepriv->ft_roam);
303
304 if (rtw_ft_otd_roam(padapter)) {
305 pmlmeinfo->state = WIFI_FW_AUTH_SUCCESS | WIFI_FW_STATION_STATE;
306 pft_roam->ft_event.ies =
307 (pft_roam->ft_action + sizeof(struct rtw_ieee80211_hdr_3addr) + 16);
308 pft_roam->ft_event.ies_len =
309 (pft_roam->ft_action_len - sizeof(struct rtw_ieee80211_hdr_3addr));
310
311 /*Not support RIC*/
312 pft_roam->ft_event.ric_ies = NULL;
313 pft_roam->ft_event.ric_ies_len = 0;
314 rtw_ft_report_evt(padapter);
315 return;
316 }
317
318 pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE;
319 start_clnt_auth(padapter);
320 }
321
rtw_ft_update_rsnie(_adapter * padapter,u8 bwrite,struct pkt_attrib * pattrib,u8 ** pframe)322 u8 rtw_ft_update_rsnie(
323 _adapter *padapter, u8 bwrite,
324 struct pkt_attrib *pattrib, u8 **pframe)
325 {
326 struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
327 u8 *pie;
328 u32 len;
329
330 pie = rtw_get_ie(pft_roam->updated_ft_ies, EID_WPA2, &len,
331 pft_roam->updated_ft_ies_len);
332
333 if (!bwrite)
334 return (pie)?_SUCCESS:_FAIL;
335
336 if (pie) {
337 *pframe = rtw_set_ie(((u8 *)*pframe), EID_WPA2, len,
338 pie+2, &(pattrib->pktlen));
339 } else
340 return _FAIL;
341
342 return _SUCCESS;
343 }
344
rtw_ft_update_mdie(_adapter * padapter,struct pkt_attrib * pattrib,u8 ** pframe)345 static u8 rtw_ft_update_mdie(
346 _adapter *padapter, struct pkt_attrib *pattrib, u8 **pframe)
347 {
348 struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
349 u8 *pie, mdie[3];
350 u32 len = 3;
351
352 if (rtw_ft_roam(padapter)) {
353 if ((pie = rtw_get_ie(pft_roam->updated_ft_ies, _MDIE_,
354 &len, pft_roam->updated_ft_ies_len))) {
355 pie = (pie + 2); /* ignore md-id & length */
356 } else
357 return _FAIL;
358 } else {
359 *((u16 *)&mdie[0]) = pft_roam->mdid;
360 mdie[2] = pft_roam->ft_cap;
361 pie = &mdie[0];
362 }
363
364 *pframe = rtw_set_ie(((u8 *)*pframe), _MDIE_, len , pie, &(pattrib->pktlen));
365 return _SUCCESS;
366 }
367
rtw_ft_update_ftie(_adapter * padapter,struct pkt_attrib * pattrib,u8 ** pframe)368 static u8 rtw_ft_update_ftie(
369 _adapter *padapter, struct pkt_attrib *pattrib, u8 **pframe)
370 {
371 struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
372 u8 *pie;
373 u32 len;
374
375 if ((pie = rtw_get_ie(pft_roam->updated_ft_ies, _FTIE_, &len,
376 pft_roam->updated_ft_ies_len)) != NULL) {
377 *pframe = rtw_set_ie(*pframe, _FTIE_, len ,
378 (pie+2), &(pattrib->pktlen));
379 } else
380 return _FAIL;
381
382 return _SUCCESS;
383 }
384
rtw_ft_build_auth_req_ies(_adapter * padapter,struct pkt_attrib * pattrib,u8 ** pframe)385 void rtw_ft_build_auth_req_ies(_adapter *padapter,
386 struct pkt_attrib *pattrib, u8 **pframe)
387 {
388 u8 ftie_append = _TRUE;
389
390 if (!pattrib || !(*pframe))
391 return;
392
393 if (!rtw_ft_roam(padapter))
394 return;
395
396 ftie_append = rtw_ft_update_rsnie(padapter, _TRUE, pattrib, pframe);
397 rtw_ft_update_mdie(padapter, pattrib, pframe);
398 if (ftie_append)
399 rtw_ft_update_ftie(padapter, pattrib, pframe);
400 }
401
rtw_ft_build_assoc_req_ies(_adapter * padapter,u8 is_reassoc,struct pkt_attrib * pattrib,u8 ** pframe)402 void rtw_ft_build_assoc_req_ies(_adapter *padapter,
403 u8 is_reassoc, struct pkt_attrib *pattrib, u8 **pframe)
404 {
405 if (!pattrib || !(*pframe))
406 return;
407
408 if (rtw_ft_chk_flags(padapter, RTW_FT_PEER_EN))
409 rtw_ft_update_mdie(padapter, pattrib, pframe);
410
411 if ((!is_reassoc) || (!rtw_ft_roam(padapter)))
412 return;
413
414 if (rtw_ft_update_rsnie(padapter, _FALSE, pattrib, pframe))
415 rtw_ft_update_ftie(padapter, pattrib, pframe);
416 }
417
rtw_ft_update_auth_rsp_ies(_adapter * padapter,u8 * pframe,u32 len)418 u8 rtw_ft_update_auth_rsp_ies(_adapter *padapter, u8 *pframe, u32 len)
419 {
420 u8 ret = _SUCCESS;
421 u8 target_ap_addr[ETH_ALEN] = {0};
422 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
423 struct ft_roam_info *pft_roam = &(pmlmepriv->ft_roam);
424
425 if (!rtw_ft_roam(padapter))
426 return _FAIL;
427
428 /*rtw_ft_report_reassoc_evt already,
429 * and waiting for cfg80211_rtw_update_ft_ies */
430 if (rtw_ft_authed_sta(padapter))
431 return ret;
432
433 if (!pframe || !len)
434 return _FAIL;
435
436 rtw_buf_update(&pmlmepriv->auth_rsp,
437 &pmlmepriv->auth_rsp_len, pframe, len);
438 pft_roam->ft_event.ies =
439 (pmlmepriv->auth_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + 6);
440 pft_roam->ft_event.ies_len =
441 (pmlmepriv->auth_rsp_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 6);
442
443 /*Not support RIC*/
444 pft_roam->ft_event.ric_ies = NULL;
445 pft_roam->ft_event.ric_ies_len = 0;
446 _rtw_memcpy(target_ap_addr, pmlmepriv->assoc_bssid, ETH_ALEN);
447 rtw_ft_report_reassoc_evt(padapter, target_ap_addr);
448
449 return ret;
450 }
451
rtw_ft_start_clnt_action(_adapter * padapter,u8 * pTargetAddr)452 static void rtw_ft_start_clnt_action(_adapter *padapter, u8 *pTargetAddr)
453 {
454 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
455
456 rtw_ft_set_status(padapter, RTW_FT_REQUESTING_STA);
457 rtw_ft_issue_action_req(padapter, pTargetAddr);
458 _set_timer(&pmlmeext->ft_link_timer, REASSOC_TO);
459 }
460
rtw_ft_start_roam(_adapter * padapter,u8 * pTargetAddr)461 void rtw_ft_start_roam(_adapter *padapter, u8 *pTargetAddr)
462 {
463 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
464
465 if (rtw_ft_otd_roam(padapter)) {
466 RTW_FT_INFO("%s : try OTD roaming\n", __func__);
467 rtw_ft_start_clnt_action(padapter, pTargetAddr);
468 } else {
469 /*wait a little time to retrieve packets buffered in the current ap while scan*/
470 RTW_FT_INFO("%s : start roaming timer\n", __func__);
471 _set_timer(&pmlmeext->ft_roam_timer, 30);
472 }
473 }
474
rtw_ft_issue_action_req(_adapter * padapter,u8 * pTargetAddr)475 void rtw_ft_issue_action_req(_adapter *padapter, u8 *pTargetAddr)
476 {
477 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
478 struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
479 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
480 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
481 struct xmit_frame *pmgntframe;
482 struct rtw_ieee80211_hdr *pwlanhdr;
483 struct pkt_attrib *pattrib;
484 u8 *pframe;
485 u8 category = RTW_WLAN_CATEGORY_FT;
486 u8 action = RTW_WLAN_ACTION_FT_REQ;
487
488 pmgntframe = alloc_mgtxmitframe(pxmitpriv);
489 if (pmgntframe == NULL)
490 return;
491
492 pattrib = &pmgntframe->attrib;
493 update_mgntframe_attrib(padapter, pattrib);
494 _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
495
496 pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
497 pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
498 pwlanhdr->frame_ctl = 0;
499
500 _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
501 _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
502 _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
503
504 SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
505 pmlmeext->mgnt_seq++;
506 set_frame_sub_type(pframe, WIFI_ACTION);
507
508 pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
509 pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
510
511 pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
512 pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
513
514 _rtw_memcpy(pframe, adapter_mac_addr(padapter), ETH_ALEN);
515 pframe += ETH_ALEN;
516 pattrib->pktlen += ETH_ALEN;
517
518 _rtw_memcpy(pframe, pTargetAddr, ETH_ALEN);
519 pframe += ETH_ALEN;
520 pattrib->pktlen += ETH_ALEN;
521
522 rtw_ft_update_mdie(padapter, pattrib, &pframe);
523 if (rtw_ft_update_rsnie(padapter, _TRUE, pattrib, &pframe))
524 rtw_ft_update_ftie(padapter, pattrib, &pframe);
525
526 RTW_INFO("FT : issue RTW_WLAN_ACTION_FT_REQ\n");
527 pattrib->last_txcmdsz = pattrib->pktlen;
528 dump_mgntframe(padapter, pmgntframe);
529 }
530
rtw_ft_report_evt(_adapter * padapter)531 void rtw_ft_report_evt(_adapter *padapter)
532 {
533 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
534 struct ft_roam_info *pft_roam = &(pmlmepriv->ft_roam);
535 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
536 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
537 WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&(pmlmeinfo->network);
538 struct cfg80211_ft_event_params ft_evt_parms;
539 _irqL irqL;
540
541 _rtw_memset(&ft_evt_parms, 0, sizeof(ft_evt_parms));
542 rtw_ft_update_stainfo(padapter, pnetwork);
543
544 if (!pnetwork)
545 goto err_2;
546
547 ft_evt_parms.ies_len = pft_roam->ft_event.ies_len;
548 ft_evt_parms.ies = rtw_zmalloc(ft_evt_parms.ies_len);
549 if (ft_evt_parms.ies)
550 _rtw_memcpy((void *)ft_evt_parms.ies, pft_roam->ft_event.ies, ft_evt_parms.ies_len);
551 else
552 goto err_2;
553
554 ft_evt_parms.target_ap = rtw_zmalloc(ETH_ALEN);
555 if (ft_evt_parms.target_ap)
556 _rtw_memcpy((void *)ft_evt_parms.target_ap, pnetwork->MacAddress, ETH_ALEN);
557 else
558 goto err_1;
559
560 ft_evt_parms.ric_ies = pft_roam->ft_event.ric_ies;
561 ft_evt_parms.ric_ies_len = pft_roam->ft_event.ric_ies_len;
562
563 /* It's a KERNEL issue between v4.11 ~ v4.16,
564 * <= v4.10, NLMSG_DEFAULT_SIZE is used for nlmsg_new().
565 * v4.11 ~ v4.16, only used "100 + >ric_ies_len" for nlmsg_new()
566 * even then DRIVER don't support RIC.
567 * >= v4.17, issue should correct as "100 + ies_len + ric_ies_len".
568 */
569 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) && \
570 (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)))
571 ft_evt_parms.ric_ies_len = (ft_evt_parms.ies_len <= 100 )?
572 (0):(ft_evt_parms.ies_len - 100);
573 #endif
574
575 rtw_ft_lock_set_status(padapter, RTW_FT_AUTHENTICATED_STA, &irqL);
576 rtw_cfg80211_ft_event(padapter, &ft_evt_parms);
577 RTW_INFO("FT: rtw_ft_report_evt\n");
578 rtw_mfree((u8 *)pft_roam->ft_event.target_ap, ETH_ALEN);
579 err_1:
580 rtw_mfree((u8 *)ft_evt_parms.ies, ft_evt_parms.ies_len);
581 err_2:
582 return;
583 }
584
rtw_ft_report_reassoc_evt(_adapter * padapter,u8 * pMacAddr)585 void rtw_ft_report_reassoc_evt(_adapter *padapter, u8 *pMacAddr)
586 {
587 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
588 struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
589 struct cmd_obj *pcmd_obj = NULL;
590 struct stassoc_event *passoc_sta_evt = NULL;
591 struct rtw_evt_header *evt_hdr = NULL;
592 u8 *pevtcmd = NULL;
593 u32 cmdsz = 0;
594
595 pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
596 if (pcmd_obj == NULL)
597 return;
598
599 cmdsz = (sizeof(struct stassoc_event) + sizeof(struct rtw_evt_header));
600 pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
601 if (pevtcmd == NULL) {
602 rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj));
603 return;
604 }
605
606 _rtw_init_listhead(&pcmd_obj->list);
607 pcmd_obj->cmdcode = CMD_SET_MLME_EVT;
608 pcmd_obj->cmdsz = cmdsz;
609 pcmd_obj->parmbuf = pevtcmd;
610 pcmd_obj->rsp = NULL;
611 pcmd_obj->rspsz = 0;
612
613 evt_hdr = (struct rtw_evt_header *)(pevtcmd);
614 evt_hdr->len = sizeof(struct stassoc_event);
615 evt_hdr->id = EVT_FT_REASSOC;
616 evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
617
618 passoc_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct rtw_evt_header));
619 _rtw_memcpy((unsigned char *)(&(passoc_sta_evt->macaddr)), pMacAddr, ETH_ALEN);
620 rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
621 }
622
rtw_ft_link_timer_hdl(void * ctx)623 void rtw_ft_link_timer_hdl(void *ctx)
624 {
625 _adapter *padapter = (_adapter *)ctx;
626 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
627 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
628 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
629 struct ft_roam_info *pft_roam = &(pmlmepriv->ft_roam);
630
631 if (rtw_ft_chk_status(padapter, RTW_FT_REQUESTING_STA)) {
632 if (pft_roam->ft_req_retry_cnt < RTW_FT_ACTION_REQ_LMT) {
633 pft_roam->ft_req_retry_cnt++;
634 rtw_ft_issue_action_req(padapter, (u8 *)pmlmepriv->roam_network->network.MacAddress);
635 _set_timer(&pmlmeext->ft_link_timer, REASSOC_TO);
636 } else {
637 pft_roam->ft_req_retry_cnt = 0;
638 if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
639 rtw_ft_set_status(padapter, RTW_FT_ASSOCIATED_STA);
640 else
641 rtw_ft_reset_status(padapter);
642 }
643 }
644 }
645
rtw_ft_roam_timer_hdl(void * ctx)646 void rtw_ft_roam_timer_hdl(void *ctx)
647 {
648 _adapter *padapter = (_adapter *)ctx;
649 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
650
651 RTW_FT_INFO("%s : try roaming\n", __func__);
652 receive_disconnect(padapter, pmlmepriv->cur_network.network.MacAddress
653 , WLAN_REASON_ACTIVE_ROAM, _FALSE);
654 }
655
rtw_ft_roam_status_reset(_adapter * padapter)656 void rtw_ft_roam_status_reset(_adapter *padapter)
657 {
658 struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
659
660 if ((rtw_to_roam(padapter) > 0) &&
661 (!rtw_ft_chk_status(padapter, RTW_FT_REQUESTED_STA))) {
662 rtw_ft_reset_status(padapter);
663 }
664
665 padapter->mlmepriv.ft_roam.ft_updated_bcn = _FALSE;
666 }
667
668 #endif /* CONFIG_RTW_80211R */
669