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