1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  * rtl871x_ioctl_set.c
4  *
5  * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
6  * Linux device driver for RTL8192SU
7  *
8  * Modifications for inclusion into the Linux staging tree are
9  * Copyright(c) 2010 Larry Finger. All rights reserved.
10  *
11  * Contact information:
12  * WLAN FAE <wlanfae@realtek.com>
13  * Larry Finger <Larry.Finger@lwfinger.net>
14  *
15  ******************************************************************************/
16 
17 #define _RTL871X_IOCTL_SET_C_
18 
19 #include "osdep_service.h"
20 #include "drv_types.h"
21 #include "rtl871x_ioctl_set.h"
22 #include "usb_osintf.h"
23 #include "usb_ops.h"
24 
validate_ssid(struct ndis_802_11_ssid * ssid)25 static u8 validate_ssid(struct ndis_802_11_ssid *ssid)
26 {
27 	u8 i;
28 
29 	if (ssid->SsidLength > 32)
30 		return false;
31 	for (i = 0; i < ssid->SsidLength; i++) {
32 		/* wifi, printable ascii code must be supported */
33 		if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e)))
34 			return false;
35 	}
36 	return true;
37 }
38 
do_join(struct _adapter * padapter)39 static u8 do_join(struct _adapter *padapter)
40 {
41 	struct list_head *plist, *phead;
42 	u8 *pibss = NULL;
43 	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
44 	struct  __queue	*queue	= &(pmlmepriv->scanned_queue);
45 	int ret;
46 
47 	phead = &queue->queue;
48 	plist = phead->next;
49 	pmlmepriv->cur_network.join_res = -2;
50 	pmlmepriv->fw_state |= _FW_UNDER_LINKING;
51 	pmlmepriv->pscanned = plist;
52 	pmlmepriv->to_join = true;
53 
54 	/* adhoc mode will start with an empty queue, but skip checking */
55 	if (!check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) &&
56 	    list_empty(&queue->queue)) {
57 		if (pmlmepriv->fw_state & _FW_UNDER_LINKING)
58 			pmlmepriv->fw_state ^= _FW_UNDER_LINKING;
59 		/* when set_ssid/set_bssid for do_join(), but scanning queue
60 		 * is empty we try to issue sitesurvey firstly
61 		 */
62 		if (!pmlmepriv->sitesurveyctrl.traffic_busy)
63 			r8712_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid);
64 		return true;
65 	}
66 
67 	ret = r8712_select_and_join_from_scan(pmlmepriv);
68 	if (!ret) {
69 		mod_timer(&pmlmepriv->assoc_timer,
70 			  jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT));
71 	} else {
72 		if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
73 			/* submit r8712_createbss_cmd to change to an
74 			 * ADHOC_MASTER pmlmepriv->lock has been
75 			 * acquired by caller...
76 			 */
77 			struct wlan_bssid_ex *pdev_network =
78 				&padapter->registrypriv.dev_network;
79 			pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
80 			pibss = padapter->registrypriv.dev_network.MacAddress;
81 			memcpy(&pdev_network->Ssid,
82 			       &pmlmepriv->assoc_ssid,
83 			       sizeof(struct ndis_802_11_ssid));
84 			r8712_update_registrypriv_dev_network(padapter);
85 			r8712_generate_random_ibss(pibss);
86 			if (r8712_createbss_cmd(padapter))
87 				return false;
88 			pmlmepriv->to_join = false;
89 		} else {
90 			/* can't associate ; reset under-linking */
91 			if (pmlmepriv->fw_state & _FW_UNDER_LINKING)
92 				pmlmepriv->fw_state ^=
93 					_FW_UNDER_LINKING;
94 			/* when set_ssid/set_bssid for do_join(), but
95 			 * there are no desired bss in scanning queue
96 			 * we try to issue sitesurvey first
97 			 */
98 			if (!pmlmepriv->sitesurveyctrl.traffic_busy)
99 				r8712_sitesurvey_cmd(padapter,
100 						     &pmlmepriv->assoc_ssid);
101 		}
102 	}
103 	return true;
104 }
105 
r8712_set_802_11_bssid(struct _adapter * padapter,u8 * bssid)106 u8 r8712_set_802_11_bssid(struct _adapter *padapter, u8 *bssid)
107 {
108 	unsigned long irqL;
109 	u8 status = true;
110 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
111 
112 	if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) {
113 		status = false;
114 		return status;
115 	}
116 	spin_lock_irqsave(&pmlmepriv->lock, irqL);
117 	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY |
118 	    _FW_UNDER_LINKING)) {
119 		status = check_fwstate(pmlmepriv, _FW_UNDER_LINKING);
120 		goto _Abort_Set_BSSID;
121 	}
122 	if (check_fwstate(pmlmepriv,
123 	    _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
124 		if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid,
125 		    ETH_ALEN)) {
126 			if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE))
127 				/* driver is in
128 				 * WIFI_ADHOC_MASTER_STATE
129 				 */
130 				goto _Abort_Set_BSSID;
131 		} else {
132 			r8712_disassoc_cmd(padapter);
133 			if (check_fwstate(pmlmepriv, _FW_LINKED))
134 				r8712_ind_disconnect(padapter);
135 			r8712_free_assoc_resources(padapter);
136 			if ((check_fwstate(pmlmepriv,
137 			     WIFI_ADHOC_MASTER_STATE))) {
138 				_clr_fwstate_(pmlmepriv,
139 					      WIFI_ADHOC_MASTER_STATE);
140 				set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
141 			}
142 		}
143 	}
144 	memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN);
145 	pmlmepriv->assoc_by_bssid = true;
146 	status = do_join(padapter);
147 	goto done;
148 _Abort_Set_BSSID:
149 done:
150 	spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
151 	return status;
152 }
153 
r8712_set_802_11_ssid(struct _adapter * padapter,struct ndis_802_11_ssid * ssid)154 void r8712_set_802_11_ssid(struct _adapter *padapter,
155 			   struct ndis_802_11_ssid *ssid)
156 {
157 	unsigned long irqL;
158 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
159 	struct wlan_network *pnetwork = &pmlmepriv->cur_network;
160 
161 	if (!padapter->hw_init_completed)
162 		return;
163 	spin_lock_irqsave(&pmlmepriv->lock, irqL);
164 	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) {
165 		check_fwstate(pmlmepriv, _FW_UNDER_LINKING);
166 		goto _Abort_Set_SSID;
167 	}
168 	if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
169 		if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) &&
170 		    (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid,
171 		    ssid->SsidLength))) {
172 			if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
173 				if (!r8712_is_same_ibss(padapter,
174 				     pnetwork)) {
175 					/* if in WIFI_ADHOC_MASTER_STATE or
176 					 *  WIFI_ADHOC_STATE, create bss or
177 					 * rejoin again
178 					 */
179 					r8712_disassoc_cmd(padapter);
180 					if (check_fwstate(pmlmepriv,
181 					    _FW_LINKED))
182 						r8712_ind_disconnect(padapter);
183 					r8712_free_assoc_resources(padapter);
184 					if (check_fwstate(pmlmepriv,
185 					     WIFI_ADHOC_MASTER_STATE)) {
186 						_clr_fwstate_(pmlmepriv,
187 						    WIFI_ADHOC_MASTER_STATE);
188 						set_fwstate(pmlmepriv,
189 							    WIFI_ADHOC_STATE);
190 					}
191 				} else {
192 					/* driver is in
193 					 * WIFI_ADHOC_MASTER_STATE
194 					 */
195 					goto _Abort_Set_SSID;
196 				}
197 			}
198 		} else {
199 			r8712_disassoc_cmd(padapter);
200 			if (check_fwstate(pmlmepriv, _FW_LINKED))
201 				r8712_ind_disconnect(padapter);
202 			r8712_free_assoc_resources(padapter);
203 			if (check_fwstate(pmlmepriv,
204 			    WIFI_ADHOC_MASTER_STATE)) {
205 				_clr_fwstate_(pmlmepriv,
206 					      WIFI_ADHOC_MASTER_STATE);
207 				set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
208 			}
209 		}
210 	}
211 	if (padapter->securitypriv.btkip_countermeasure)
212 		goto _Abort_Set_SSID;
213 	if (!validate_ssid(ssid))
214 		goto _Abort_Set_SSID;
215 	memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid));
216 	pmlmepriv->assoc_by_bssid = false;
217 	do_join(padapter);
218 	goto done;
219 _Abort_Set_SSID:
220 done:
221 	spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
222 }
223 
r8712_set_802_11_infrastructure_mode(struct _adapter * padapter,enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype)224 void r8712_set_802_11_infrastructure_mode(struct _adapter *padapter,
225 	enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype)
226 {
227 	unsigned long irqL;
228 	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
229 	struct wlan_network	*cur_network = &pmlmepriv->cur_network;
230 	enum NDIS_802_11_NETWORK_INFRASTRUCTURE *pold_state =
231 				&(cur_network->network.InfrastructureMode);
232 
233 	if (*pold_state != networktype) {
234 		spin_lock_irqsave(&pmlmepriv->lock, irqL);
235 		if (check_fwstate(pmlmepriv, _FW_LINKED) ||
236 		    (*pold_state == Ndis802_11IBSS))
237 			r8712_disassoc_cmd(padapter);
238 		if (check_fwstate(pmlmepriv,
239 		    _FW_LINKED | WIFI_ADHOC_MASTER_STATE))
240 			r8712_free_assoc_resources(padapter);
241 		if (check_fwstate(pmlmepriv, _FW_LINKED) ||
242 		    (*pold_state == Ndis802_11Infrastructure) ||
243 		    (*pold_state == Ndis802_11IBSS)) {
244 			/* will clr Linked_state before this function,
245 			 * we must have checked whether issue dis-assoc_cmd or
246 			 * not
247 			 */
248 			r8712_ind_disconnect(padapter);
249 		}
250 		*pold_state = networktype;
251 		/* clear WIFI_STATION_STATE; WIFI_AP_STATE; WIFI_ADHOC_STATE;
252 		 * WIFI_ADHOC_MASTER_STATE
253 		 */
254 		_clr_fwstate_(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE |
255 			      WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE);
256 		switch (networktype) {
257 		case Ndis802_11IBSS:
258 			set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
259 			break;
260 		case Ndis802_11Infrastructure:
261 			set_fwstate(pmlmepriv, WIFI_STATION_STATE);
262 			break;
263 		case Ndis802_11APMode:
264 			set_fwstate(pmlmepriv, WIFI_AP_STATE);
265 			break;
266 		case Ndis802_11AutoUnknown:
267 		case Ndis802_11InfrastructureMax:
268 			break;
269 		}
270 		spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
271 	}
272 }
273 
r8712_set_802_11_disassociate(struct _adapter * padapter)274 u8 r8712_set_802_11_disassociate(struct _adapter *padapter)
275 {
276 	unsigned long irqL;
277 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
278 
279 	spin_lock_irqsave(&pmlmepriv->lock, irqL);
280 	if (check_fwstate(pmlmepriv, _FW_LINKED)) {
281 		r8712_disassoc_cmd(padapter);
282 		r8712_ind_disconnect(padapter);
283 		r8712_free_assoc_resources(padapter);
284 	}
285 	spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
286 	return true;
287 }
288 
r8712_set_802_11_bssid_list_scan(struct _adapter * padapter)289 u8 r8712_set_802_11_bssid_list_scan(struct _adapter *padapter)
290 {
291 	struct mlme_priv *pmlmepriv = NULL;
292 	unsigned long irqL;
293 	u8 ret = true;
294 
295 	if (!padapter)
296 		return false;
297 	pmlmepriv = &padapter->mlmepriv;
298 	if (!padapter->hw_init_completed)
299 		return false;
300 	spin_lock_irqsave(&pmlmepriv->lock, irqL);
301 	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) ||
302 	    pmlmepriv->sitesurveyctrl.traffic_busy) {
303 		/* Scan or linking is in progress, do nothing. */
304 		ret = (u8)check_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
305 	} else {
306 		r8712_free_network_queue(padapter);
307 		ret = r8712_sitesurvey_cmd(padapter, NULL);
308 	}
309 	spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
310 	return ret;
311 }
312 
r8712_set_802_11_authentication_mode(struct _adapter * padapter,enum NDIS_802_11_AUTHENTICATION_MODE authmode)313 u8 r8712_set_802_11_authentication_mode(struct _adapter *padapter,
314 				enum NDIS_802_11_AUTHENTICATION_MODE authmode)
315 {
316 	struct security_priv *psecuritypriv = &padapter->securitypriv;
317 	u8 ret;
318 
319 	psecuritypriv->ndisauthtype = authmode;
320 	if (psecuritypriv->ndisauthtype > 3)
321 		psecuritypriv->AuthAlgrthm = 2; /* 802.1x */
322 	if (r8712_set_auth(padapter, psecuritypriv))
323 		ret = false;
324 	else
325 		ret = true;
326 	return ret;
327 }
328 
r8712_set_802_11_add_wep(struct _adapter * padapter,struct NDIS_802_11_WEP * wep)329 int r8712_set_802_11_add_wep(struct _adapter *padapter,
330 			     struct NDIS_802_11_WEP *wep)
331 {
332 	sint	keyid;
333 	struct security_priv *psecuritypriv = &padapter->securitypriv;
334 
335 	keyid = wep->KeyIndex & 0x3fffffff;
336 	if (keyid >= WEP_KEYS)
337 		return -EINVAL;
338 	switch (wep->KeyLength) {
339 	case 5:
340 		psecuritypriv->PrivacyAlgrthm = _WEP40_;
341 		break;
342 	case 13:
343 		psecuritypriv->PrivacyAlgrthm = _WEP104_;
344 		break;
345 	default:
346 		psecuritypriv->PrivacyAlgrthm = _NO_PRIVACY_;
347 		break;
348 	}
349 	memcpy(psecuritypriv->DefKey[keyid].skey, &wep->KeyMaterial,
350 		wep->KeyLength);
351 	psecuritypriv->DefKeylen[keyid] = wep->KeyLength;
352 	psecuritypriv->PrivacyKeyIndex = keyid;
353 	return r8712_set_key(padapter, psecuritypriv, keyid);
354 }
355