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