1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5  *
6  ******************************************************************************/
7 
8 #include <drv_types.h>
9 #include <rtw_debug.h>
10 
11 u8 rtw_validate_bssid(u8 *bssid)
12 {
13 	u8 ret = true;
14 
15 	if (is_zero_mac_addr(bssid)
16 		|| is_broadcast_mac_addr(bssid)
17 		|| is_multicast_mac_addr(bssid)
18 	) {
19 		ret = false;
20 	}
21 
22 	return ret;
23 }
24 
25 u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid)
26 {
27 	u8 ret = true;
28 
29 	if (ssid->ssid_length > 32) {
30 		ret = false;
31 		goto exit;
32 	}
33 
34 exit:
35 	return ret;
36 }
37 
38 u8 rtw_do_join(struct adapter *padapter)
39 {
40 	struct list_head	*plist, *phead;
41 	u8 *pibss = NULL;
42 	struct	mlme_priv *pmlmepriv = &(padapter->mlmepriv);
43 	struct __queue	*queue	= &(pmlmepriv->scanned_queue);
44 	u8 ret = _SUCCESS;
45 
46 	spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
47 	phead = get_list_head(queue);
48 	plist = get_next(phead);
49 
50 	pmlmepriv->cur_network.join_res = -2;
51 
52 	set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
53 
54 	pmlmepriv->pscanned = plist;
55 
56 	pmlmepriv->to_join = true;
57 
58 	if (list_empty(&queue->queue)) {
59 		spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
60 		_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
61 
62 		/* when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty */
63 		/* we try to issue sitesurvey firstly */
64 
65 		if (pmlmepriv->LinkDetectInfo.bBusyTraffic == false
66 			|| rtw_to_roam(padapter) > 0
67 		) {
68 			/*  submit site_survey_cmd */
69 			ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
70 			if (ret != _SUCCESS)
71 				pmlmepriv->to_join = false;
72 
73 		} else {
74 			pmlmepriv->to_join = false;
75 			ret = _FAIL;
76 		}
77 
78 		goto exit;
79 	} else {
80 		int select_ret;
81 
82 		spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
83 		select_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
84 		if (select_ret == _SUCCESS) {
85 			pmlmepriv->to_join = false;
86 			_set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
87 		} else {
88 			if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) {
89 				/*  submit createbss_cmd to change to a ADHOC_MASTER */
90 
91 				/* pmlmepriv->lock has been acquired by caller... */
92 				struct wlan_bssid_ex    *pdev_network = &(padapter->registrypriv.dev_network);
93 
94 				pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
95 
96 				pibss = padapter->registrypriv.dev_network.mac_address;
97 
98 				memcpy(&pdev_network->ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid));
99 
100 				rtw_update_registrypriv_dev_network(padapter);
101 
102 				rtw_generate_random_ibss(pibss);
103 
104 				if (rtw_createbss_cmd(padapter) != _SUCCESS) {
105 					ret =  false;
106 					goto exit;
107 				}
108 
109 				pmlmepriv->to_join = false;
110 
111 			} else {
112 				/*  can't associate ; reset under-linking */
113 				_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
114 
115 				/* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */
116 				/* we try to issue sitesurvey firstly */
117 				if (pmlmepriv->LinkDetectInfo.bBusyTraffic == false
118 					|| rtw_to_roam(padapter) > 0
119 				) {
120 					ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
121 					if (ret != _SUCCESS)
122 						pmlmepriv->to_join = false;
123 
124 				} else {
125 					ret = _FAIL;
126 					pmlmepriv->to_join = false;
127 				}
128 			}
129 
130 		}
131 
132 	}
133 
134 exit:
135 	return ret;
136 }
137 
138 u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
139 {
140 	u8 status = _SUCCESS;
141 
142 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
143 	struct wlan_network *pnetwork = &pmlmepriv->cur_network;
144 
145 	netdev_dbg(padapter->pnetdev, "set ssid [%s] fw_state = 0x%08x\n",
146 		   ssid->ssid, get_fwstate(pmlmepriv));
147 
148 	if (padapter->hw_init_completed == false) {
149 		status = _FAIL;
150 		goto exit;
151 	}
152 
153 	spin_lock_bh(&pmlmepriv->lock);
154 
155 	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true)
156 		goto handle_tkip_countermeasure;
157 	else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)
158 		goto release_mlme_lock;
159 
160 	if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) {
161 		if ((pmlmepriv->assoc_ssid.ssid_length == ssid->ssid_length) &&
162 		    (!memcmp(&pmlmepriv->assoc_ssid.ssid, ssid->ssid, ssid->ssid_length))) {
163 			if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false) {
164 				if (rtw_is_same_ibss(padapter, pnetwork) == false) {
165 					/* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */
166 					rtw_disassoc_cmd(padapter, 0, true);
167 
168 					if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
169 						rtw_indicate_disconnect(padapter);
170 
171 					rtw_free_assoc_resources(padapter, 1);
172 
173 					if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
174 						_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
175 						set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
176 					}
177 				} else {
178 					goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
179 				}
180 			} else {
181 				rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1);
182 			}
183 		} else {
184 			rtw_disassoc_cmd(padapter, 0, true);
185 
186 			if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
187 				rtw_indicate_disconnect(padapter);
188 
189 			rtw_free_assoc_resources(padapter, 1);
190 
191 			if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
192 				_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
193 				set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
194 			}
195 		}
196 	}
197 
198 handle_tkip_countermeasure:
199 	if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) {
200 		status = _FAIL;
201 		goto release_mlme_lock;
202 	}
203 
204 	if (rtw_validate_ssid(ssid) == false) {
205 		status = _FAIL;
206 		goto release_mlme_lock;
207 	}
208 
209 	memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid));
210 	pmlmepriv->assoc_by_bssid = false;
211 
212 	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true)
213 		pmlmepriv->to_join = true;
214 	else
215 		status = rtw_do_join(padapter);
216 
217 release_mlme_lock:
218 	spin_unlock_bh(&pmlmepriv->lock);
219 
220 exit:
221 
222 	return status;
223 }
224 
225 u8 rtw_set_802_11_connect(struct adapter *padapter, u8 *bssid, struct ndis_802_11_ssid *ssid)
226 {
227 	u8 status = _SUCCESS;
228 	bool bssid_valid = true;
229 	bool ssid_valid = true;
230 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
231 
232 	if (!ssid || rtw_validate_ssid(ssid) == false)
233 		ssid_valid = false;
234 
235 	if (!bssid || rtw_validate_bssid(bssid) == false)
236 		bssid_valid = false;
237 
238 	if (!ssid_valid && !bssid_valid) {
239 		status = _FAIL;
240 		goto exit;
241 	}
242 
243 	if (padapter->hw_init_completed == false) {
244 		status = _FAIL;
245 		goto exit;
246 	}
247 
248 	spin_lock_bh(&pmlmepriv->lock);
249 
250 	netdev_dbg(padapter->pnetdev, FUNC_ADPT_FMT "  fw_state = 0x%08x\n",
251 		   FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv));
252 
253 	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true)
254 		goto handle_tkip_countermeasure;
255 	else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)
256 		goto release_mlme_lock;
257 
258 handle_tkip_countermeasure:
259 	if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) {
260 		status = _FAIL;
261 		goto release_mlme_lock;
262 	}
263 
264 	if (ssid && ssid_valid)
265 		memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid));
266 	else
267 		memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid));
268 
269 	if (bssid && bssid_valid) {
270 		memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN);
271 		pmlmepriv->assoc_by_bssid = true;
272 	} else {
273 		pmlmepriv->assoc_by_bssid = false;
274 	}
275 
276 	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true)
277 		pmlmepriv->to_join = true;
278 	else
279 		status = rtw_do_join(padapter);
280 
281 release_mlme_lock:
282 	spin_unlock_bh(&pmlmepriv->lock);
283 
284 exit:
285 	return status;
286 }
287 
288 u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter,
289 	enum ndis_802_11_network_infrastructure networktype)
290 {
291 	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
292 	struct	wlan_network	*cur_network = &pmlmepriv->cur_network;
293 	enum ndis_802_11_network_infrastructure *pold_state = &(cur_network->network.infrastructure_mode);
294 
295 	if (*pold_state != networktype) {
296 		if (*pold_state == Ndis802_11APMode) {
297 			/* change to other mode from Ndis802_11APMode */
298 			cur_network->join_res = -1;
299 
300 			stop_ap_mode(padapter);
301 		}
302 
303 		spin_lock_bh(&pmlmepriv->lock);
304 
305 		if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || (*pold_state == Ndis802_11IBSS))
306 			rtw_disassoc_cmd(padapter, 0, true);
307 
308 		if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) ||
309 			(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true))
310 			rtw_free_assoc_resources(padapter, 1);
311 
312 		if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) {
313 			if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
314 				rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have checked whether issue dis-assoc_cmd or not */
315 		}
316 
317 		*pold_state = networktype;
318 
319 		_clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE);
320 
321 		switch (networktype) {
322 		case Ndis802_11IBSS:
323 			set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
324 			break;
325 
326 		case Ndis802_11Infrastructure:
327 			set_fwstate(pmlmepriv, WIFI_STATION_STATE);
328 			break;
329 
330 		case Ndis802_11APMode:
331 			set_fwstate(pmlmepriv, WIFI_AP_STATE);
332 			start_ap_mode(padapter);
333 			/* rtw_indicate_connect(padapter); */
334 
335 			break;
336 
337 		case Ndis802_11AutoUnknown:
338 		case Ndis802_11InfrastructureMax:
339 			break;
340 		}
341 
342 		/* SecClearAllKeys(adapter); */
343 
344 		spin_unlock_bh(&pmlmepriv->lock);
345 	}
346 	return true;
347 }
348 
349 
350 u8 rtw_set_802_11_disassociate(struct adapter *padapter)
351 {
352 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
353 
354 	spin_lock_bh(&pmlmepriv->lock);
355 
356 	if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
357 		rtw_disassoc_cmd(padapter, 0, true);
358 		rtw_indicate_disconnect(padapter);
359 		/* modify for CONFIG_IEEE80211W, none 11w can use it */
360 		rtw_free_assoc_resources_cmd(padapter);
361 		rtw_pwr_wakeup(padapter);
362 	}
363 
364 	spin_unlock_bh(&pmlmepriv->lock);
365 
366 	return true;
367 }
368 
369 u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num)
370 {
371 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
372 	u8 res = true;
373 
374 	if (!padapter) {
375 		res = false;
376 		goto exit;
377 	}
378 	if (padapter->hw_init_completed == false) {
379 		res = false;
380 		goto exit;
381 	}
382 
383 	if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) ||
384 		(pmlmepriv->LinkDetectInfo.bBusyTraffic == true)) {
385 		/*  Scan or linking is in progress, do nothing. */
386 		res = true;
387 
388 	} else {
389 		if (rtw_is_scan_deny(padapter))
390 			return _SUCCESS;
391 
392 		spin_lock_bh(&pmlmepriv->lock);
393 
394 		res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0);
395 
396 		spin_unlock_bh(&pmlmepriv->lock);
397 	}
398 exit:
399 
400 	return res;
401 }
402 
403 u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11_authentication_mode authmode)
404 {
405 	struct security_priv *psecuritypriv = &padapter->securitypriv;
406 	int res;
407 	u8 ret;
408 
409 	psecuritypriv->ndisauthtype = authmode;
410 
411 	if (psecuritypriv->ndisauthtype > 3)
412 		psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
413 
414 	res = rtw_set_auth(padapter, psecuritypriv);
415 
416 	if (res == _SUCCESS)
417 		ret = true;
418 	else
419 		ret = false;
420 
421 	return ret;
422 }
423 
424 u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
425 {
426 
427 	signed int		keyid, res;
428 	struct security_priv *psecuritypriv = &(padapter->securitypriv);
429 	u8 ret = _SUCCESS;
430 
431 	keyid = wep->key_index & 0x3fffffff;
432 
433 	if (keyid >= 4) {
434 		ret = false;
435 		goto exit;
436 	}
437 
438 	switch (wep->key_length) {
439 	case 5:
440 		psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
441 		break;
442 	case 13:
443 		psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
444 		break;
445 	default:
446 		psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
447 		break;
448 	}
449 
450 	memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]), &(wep->key_material), wep->key_length);
451 
452 	psecuritypriv->dot11DefKeylen[keyid] = wep->key_length;
453 
454 	psecuritypriv->dot11PrivacyKeyIndex = keyid;
455 
456 	res = rtw_set_key(padapter, psecuritypriv, keyid, 1, true);
457 
458 	if (res == _FAIL)
459 		ret = false;
460 exit:
461 
462 	return ret;
463 }
464 
465 /*
466  * rtw_get_cur_max_rate -
467  * @adapter: pointer to struct adapter structure
468  *
469  * Return 0 or 100Kbps
470  */
471 u16 rtw_get_cur_max_rate(struct adapter *adapter)
472 {
473 	int	i = 0;
474 	u16 rate = 0, max_rate = 0;
475 	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
476 	struct wlan_bssid_ex	*pcur_bss = &pmlmepriv->cur_network.network;
477 	struct sta_info *psta = NULL;
478 	u8 short_GI = 0;
479 
480 	if ((check_fwstate(pmlmepriv, _FW_LINKED) != true)
481 		&& (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != true))
482 		return 0;
483 
484 	psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(pmlmepriv));
485 	if (!psta)
486 		return 0;
487 
488 	short_GI = query_ra_short_GI(psta);
489 
490 	if (is_supported_ht(psta->wireless_mode)) {
491 		max_rate = rtw_mcs_rate(psta->bw_mode == CHANNEL_WIDTH_40 ? 1 : 0,
492 					short_GI,
493 					psta->htpriv.ht_cap.mcs.rx_mask);
494 	} else {
495 		while ((pcur_bss->supported_rates[i] != 0) && (pcur_bss->supported_rates[i] != 0xFF)) {
496 			rate = pcur_bss->supported_rates[i]&0x7F;
497 			if (rate > max_rate)
498 				max_rate = rate;
499 			i++;
500 		}
501 
502 		max_rate = max_rate*10/2;
503 	}
504 
505 	return max_rate;
506 }
507