1 /******************************************************************************
2  * rtl871x_ioctl_rtl.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_RTL_C_
30 
31 #include <linux/rndis.h>
32 #include "osdep_service.h"
33 #include "drv_types.h"
34 #include "wlan_bssdef.h"
35 #include "wifi.h"
36 #include "rtl871x_ioctl.h"
37 #include "rtl871x_ioctl_set.h"
38 #include "rtl871x_ioctl_rtl.h"
39 #include "mp_custom_oid.h"
40 #include "rtl871x_mp.h"
41 #include "rtl871x_mp_ioctl.h"
42 
43 uint oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv)
44 {
45 	if (poid_par_priv->type_of_oid != QUERY_OID)
46 		return RNDIS_STATUS_NOT_ACCEPTED;
47 	return RNDIS_STATUS_SUCCESS;
48 }
49 
50 uint oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv)
51 {
52 	struct _adapter *padapter = poid_par_priv->adapter_context;
53 
54 	if (poid_par_priv->type_of_oid != QUERY_OID)
55 		return RNDIS_STATUS_NOT_ACCEPTED;
56 	if (poid_par_priv->information_buf_len >=  sizeof(u32)) {
57 		*(u32 *)poid_par_priv->information_buf =
58 				padapter->recvpriv.rx_smallpacket_crcerr;
59 		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
60 	} else {
61 		return RNDIS_STATUS_INVALID_LENGTH;
62 	}
63 	return RNDIS_STATUS_SUCCESS;
64 }
65 
66 uint oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv)
67 {
68 	struct _adapter *padapter = poid_par_priv->adapter_context;
69 
70 	if (poid_par_priv->type_of_oid != QUERY_OID)
71 		return RNDIS_STATUS_NOT_ACCEPTED;
72 	if (poid_par_priv->information_buf_len >=  sizeof(u32)) {
73 		*(u32 *)poid_par_priv->information_buf =
74 				padapter->recvpriv.rx_middlepacket_crcerr;
75 		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
76 	} else {
77 		return RNDIS_STATUS_INVALID_LENGTH;
78 	}
79 	return RNDIS_STATUS_SUCCESS;
80 }
81 
82 uint oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv)
83 {
84 	struct _adapter *padapter = poid_par_priv->adapter_context;
85 
86 	if (poid_par_priv->type_of_oid != QUERY_OID)
87 		return RNDIS_STATUS_NOT_ACCEPTED;
88 	if (poid_par_priv->information_buf_len >=  sizeof(u32)) {
89 		*(u32 *)poid_par_priv->information_buf =
90 				 padapter->recvpriv.rx_largepacket_crcerr;
91 		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
92 	} else {
93 		return RNDIS_STATUS_INVALID_LENGTH;
94 	}
95 	return RNDIS_STATUS_SUCCESS;
96 }
97 
98 uint oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv)
99 {
100 	if (poid_par_priv->type_of_oid != QUERY_OID)
101 		return RNDIS_STATUS_NOT_ACCEPTED;
102 	return RNDIS_STATUS_SUCCESS;
103 }
104 
105 uint oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv)
106 {
107 	if (poid_par_priv->type_of_oid != QUERY_OID)
108 		return RNDIS_STATUS_NOT_ACCEPTED;
109 	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
110 	return RNDIS_STATUS_SUCCESS;
111 }
112 
113 uint oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv)
114 {
115 	struct _adapter *padapter = poid_par_priv->adapter_context;
116 
117 	if (poid_par_priv->type_of_oid != QUERY_OID)
118 		return RNDIS_STATUS_NOT_ACCEPTED;
119 	if (poid_par_priv->information_buf_len >=  sizeof(u32)) {
120 		*(u32 *)poid_par_priv->information_buf =
121 					 padapter->recvpriv.rx_pkts +
122 					 padapter->recvpriv.rx_drop;
123 		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
124 	} else {
125 		return RNDIS_STATUS_INVALID_LENGTH;
126 	}
127 	return RNDIS_STATUS_SUCCESS;
128 }
129 
130 uint oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv)
131 {
132 	if (poid_par_priv->type_of_oid != QUERY_OID)
133 		return RNDIS_STATUS_NOT_ACCEPTED;
134 	return RNDIS_STATUS_SUCCESS;
135 }
136 
137 uint oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv)
138 {
139 	if (poid_par_priv->type_of_oid != QUERY_OID)
140 		return RNDIS_STATUS_NOT_ACCEPTED;
141 	return RNDIS_STATUS_SUCCESS;
142 }
143 
144 uint oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv)
145 {
146 	struct _adapter *padapter = poid_par_priv->adapter_context;
147 
148 	if (poid_par_priv->type_of_oid != QUERY_OID)
149 		return RNDIS_STATUS_NOT_ACCEPTED;
150 	if (poid_par_priv->information_buf_len >= sizeof(u32)) {
151 		*(uint *)poid_par_priv->information_buf =
152 					 padapter->recvpriv.rx_icv_err;
153 		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
154 	} else {
155 		return RNDIS_STATUS_INVALID_LENGTH;
156 	}
157 	return RNDIS_STATUS_SUCCESS;
158 }
159 
160 uint oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv
161 						*poid_par_priv)
162 {
163 	if (poid_par_priv->type_of_oid != SET_OID)
164 		return RNDIS_STATUS_NOT_ACCEPTED;
165 	return RNDIS_STATUS_SUCCESS;
166 }
167 
168 uint oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv)
169 {
170 	struct _adapter *padapter = poid_par_priv->adapter_context;
171 	u32 preamblemode = 0;
172 
173 	if (poid_par_priv->type_of_oid != QUERY_OID)
174 		return RNDIS_STATUS_NOT_ACCEPTED;
175 	if (poid_par_priv->information_buf_len >= sizeof(u32)) {
176 		if (padapter->registrypriv.preamble == PREAMBLE_LONG)
177 			preamblemode = 0;
178 		else if (padapter->registrypriv.preamble == PREAMBLE_AUTO)
179 			preamblemode = 1;
180 		else if (padapter->registrypriv.preamble == PREAMBLE_SHORT)
181 			preamblemode = 2;
182 		*(u32 *)poid_par_priv->information_buf = preamblemode;
183 		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
184 	} else {
185 		return RNDIS_STATUS_INVALID_LENGTH;
186 	}
187 	return RNDIS_STATUS_SUCCESS;
188 }
189 
190 uint oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv)
191 {
192 	if (poid_par_priv->type_of_oid != QUERY_OID)
193 		return RNDIS_STATUS_NOT_ACCEPTED;
194 	return RNDIS_STATUS_SUCCESS;
195 }
196 
197 uint oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv)
198 {
199 	struct _adapter *padapter = poid_par_priv->adapter_context;
200 	struct eeprom_priv *peeprompriv = &padapter->eeprompriv;
201 
202 	if (poid_par_priv->type_of_oid != QUERY_OID)
203 		return RNDIS_STATUS_NOT_ACCEPTED;
204 	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
205 	*(u16 *)poid_par_priv->information_buf = peeprompriv->channel_plan;
206 	return RNDIS_STATUS_SUCCESS;
207 }
208 
209 uint oid_rt_set_channelplan_hdl(struct oid_par_priv
210 				       *poid_par_priv)
211 {
212 	struct _adapter *padapter = poid_par_priv->adapter_context;
213 	struct eeprom_priv *peeprompriv = &padapter->eeprompriv;
214 
215 	if (poid_par_priv->type_of_oid != SET_OID)
216 		return RNDIS_STATUS_NOT_ACCEPTED;
217 	peeprompriv->channel_plan = *(u16 *)poid_par_priv->information_buf;
218 	return RNDIS_STATUS_SUCCESS;
219 }
220 
221 uint oid_rt_set_preamble_mode_hdl(struct oid_par_priv
222 					 *poid_par_priv)
223 {
224 	struct _adapter *padapter = poid_par_priv->adapter_context;
225 	u32 preamblemode = 0;
226 
227 	if (poid_par_priv->type_of_oid != SET_OID)
228 		return RNDIS_STATUS_NOT_ACCEPTED;
229 	if (poid_par_priv->information_buf_len >= sizeof(u32)) {
230 		preamblemode = *(u32 *)poid_par_priv->information_buf;
231 		if (preamblemode == 0)
232 			padapter->registrypriv.preamble = PREAMBLE_LONG;
233 		else if (preamblemode == 1)
234 			padapter->registrypriv.preamble = PREAMBLE_AUTO;
235 		else if (preamblemode == 2)
236 			padapter->registrypriv.preamble = PREAMBLE_SHORT;
237 		*(u32 *)poid_par_priv->information_buf = preamblemode;
238 		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
239 	} else {
240 		return RNDIS_STATUS_INVALID_LENGTH;
241 	}
242 	return RNDIS_STATUS_SUCCESS;
243 }
244 
245 uint oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv)
246 {
247 	if (poid_par_priv->type_of_oid != SET_OID)
248 		return RNDIS_STATUS_NOT_ACCEPTED;
249 	return RNDIS_STATUS_SUCCESS;
250 }
251 
252 uint oid_rt_dedicate_probe_hdl(struct oid_par_priv
253 				      *poid_par_priv)
254 {
255 	return RNDIS_STATUS_SUCCESS;
256 }
257 
258 uint oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv
259 					  *poid_par_priv)
260 {
261 	struct _adapter *padapter = poid_par_priv->adapter_context;
262 
263 	if (poid_par_priv->type_of_oid != QUERY_OID)
264 		return RNDIS_STATUS_NOT_ACCEPTED;
265 	if (poid_par_priv->information_buf_len >= sizeof(u32)) {
266 		*(u32 *)poid_par_priv->information_buf =
267 						 padapter->xmitpriv.tx_bytes;
268 		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
269 	} else {
270 		return RNDIS_STATUS_INVALID_LENGTH;
271 	}
272 	return RNDIS_STATUS_SUCCESS;
273 }
274 
275 uint oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv
276 					  *poid_par_priv)
277 {
278 	struct _adapter *padapter = poid_par_priv->adapter_context;
279 
280 	if (poid_par_priv->type_of_oid != QUERY_OID)
281 		return RNDIS_STATUS_NOT_ACCEPTED;
282 	if (poid_par_priv->information_buf_len >= sizeof(u32)) {
283 		*(u32 *)poid_par_priv->information_buf =
284 					   padapter->recvpriv.rx_bytes;
285 		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
286 	} else {
287 		return RNDIS_STATUS_INVALID_LENGTH;
288 	}
289 	return RNDIS_STATUS_SUCCESS;
290 }
291 
292 uint oid_rt_current_tx_power_level_hdl(struct oid_par_priv
293 					      *poid_par_priv)
294 {
295 	return RNDIS_STATUS_SUCCESS;
296 }
297 
298 uint oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv
299 						  *poid_par_priv)
300 {
301 	if (poid_par_priv->type_of_oid != QUERY_OID)
302 		return RNDIS_STATUS_NOT_ACCEPTED;
303 	return RNDIS_STATUS_SUCCESS;
304 }
305 
306 uint oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv
307 					       *poid_par_priv)
308 {
309 	if (poid_par_priv->type_of_oid != QUERY_OID)
310 		return RNDIS_STATUS_NOT_ACCEPTED;
311 	return RNDIS_STATUS_SUCCESS;
312 }
313 
314 uint oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv)
315 {
316 	struct _adapter *padapter = poid_par_priv->adapter_context;
317 	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
318 	struct NDIS_802_11_CONFIGURATION *pnic_Config;
319 	u32   channelnum;
320 
321 	if (poid_par_priv->type_of_oid != QUERY_OID)
322 		return RNDIS_STATUS_NOT_ACCEPTED;
323 	if (check_fwstate(pmlmepriv, _FW_LINKED) ||
324 	    check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
325 		pnic_Config = &pmlmepriv->cur_network.network.Configuration;
326 	else
327 		pnic_Config = &padapter->registrypriv.dev_network.Configuration;
328 	channelnum = pnic_Config->DSConfig;
329 	*(u32 *)poid_par_priv->information_buf = channelnum;
330 	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
331 	return RNDIS_STATUS_SUCCESS;
332 }
333 
334 uint oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv
335 			 *poid_par_priv)
336 {
337 	if (poid_par_priv->type_of_oid != QUERY_OID)
338 		return RNDIS_STATUS_NOT_ACCEPTED;
339 	return RNDIS_STATUS_SUCCESS;
340 }
341 
342 uint oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv)
343 {
344 	if (poid_par_priv->type_of_oid != QUERY_OID)
345 		return RNDIS_STATUS_NOT_ACCEPTED;
346 	return RNDIS_STATUS_SUCCESS;
347 }
348 
349 uint oid_rt_supported_wireless_mode_hdl(struct oid_par_priv
350 					       *poid_par_priv)
351 {
352 	u32 ulInfo = 0;
353 
354 	if (poid_par_priv->type_of_oid != QUERY_OID)
355 		return RNDIS_STATUS_NOT_ACCEPTED;
356 	if (poid_par_priv->information_buf_len >= sizeof(u32)) {
357 		ulInfo |= 0x0100; /* WIRELESS_MODE_B */
358 		ulInfo |= 0x0200; /* WIRELESS_MODE_G */
359 		ulInfo |= 0x0400; /* WIRELESS_MODE_A */
360 		*(u32 *) poid_par_priv->information_buf = ulInfo;
361 		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
362 	} else {
363 		return RNDIS_STATUS_INVALID_LENGTH;
364 	}
365 	return RNDIS_STATUS_SUCCESS;
366 }
367 
368 uint oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv)
369 {
370 	if (poid_par_priv->type_of_oid != QUERY_OID)
371 		return RNDIS_STATUS_NOT_ACCEPTED;
372 	return RNDIS_STATUS_SUCCESS;
373 }
374 
375 uint oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv)
376 {
377 	if (poid_par_priv->type_of_oid != QUERY_OID)
378 		return RNDIS_STATUS_NOT_ACCEPTED;
379 	return RNDIS_STATUS_SUCCESS;
380 }
381 
382 
383 uint oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv)
384 {
385 	return RNDIS_STATUS_SUCCESS;
386 }
387 
388 uint oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv
389 						   *poid_par_priv)
390 {
391 	return RNDIS_STATUS_SUCCESS;
392 }
393 
394 uint oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv
395 					     *poid_par_priv)
396 {
397 	if (poid_par_priv->type_of_oid != QUERY_OID)
398 		return RNDIS_STATUS_NOT_ACCEPTED;
399 	return RNDIS_STATUS_SUCCESS;
400 }
401 
402 uint oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv
403 					      *poid_par_priv)
404 {
405 	return RNDIS_STATUS_SUCCESS;
406 }
407 
408 uint oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv
409 						      *poid_par_priv)
410 {
411 	if (poid_par_priv->type_of_oid != QUERY_OID)
412 		return RNDIS_STATUS_NOT_ACCEPTED;
413 	return RNDIS_STATUS_SUCCESS;
414 }
415 
416 uint oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv*
417 					      poid_par_priv)
418 {
419 	return RNDIS_STATUS_SUCCESS;
420 }
421 
422 uint oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv)
423 {
424 	return RNDIS_STATUS_SUCCESS;
425 }
426 
427 uint oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv)
428 {
429 	if (poid_par_priv->type_of_oid != SET_OID)
430 		return RNDIS_STATUS_NOT_ACCEPTED;
431 	return RNDIS_STATUS_SUCCESS;
432 }
433 
434 uint oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv*
435 					     poid_par_priv)
436 {
437 	uint status = RNDIS_STATUS_SUCCESS;
438 	struct _adapter *Adapter = poid_par_priv->adapter_context;
439 
440 	if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */
441 		return RNDIS_STATUS_NOT_ACCEPTED;
442 	if (poid_par_priv->information_buf_len ==
443 	   (sizeof(unsigned long) * 3)) {
444 		if (!r8712_setrfreg_cmd(Adapter,
445 			*(unsigned char *)poid_par_priv->information_buf,
446 			(unsigned long)(*((unsigned long *)
447 					poid_par_priv->information_buf + 2))))
448 			status = RNDIS_STATUS_NOT_ACCEPTED;
449 	} else {
450 		status = RNDIS_STATUS_INVALID_LENGTH;
451 	}
452 	return status;
453 }
454 
455 uint oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv)
456 {
457 	uint status = RNDIS_STATUS_SUCCESS;
458 	struct _adapter *Adapter = poid_par_priv->adapter_context;
459 
460 	if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */
461 		return RNDIS_STATUS_NOT_ACCEPTED;
462 	if (poid_par_priv->information_buf_len == (sizeof(unsigned long) *
463 						   3)) {
464 		if (Adapter->mppriv.act_in_progress) {
465 			status = RNDIS_STATUS_NOT_ACCEPTED;
466 		} else {
467 			/* init workparam */
468 			Adapter->mppriv.act_in_progress = true;
469 			Adapter->mppriv.workparam.bcompleted = false;
470 			Adapter->mppriv.workparam.act_type = MPT_READ_RF;
471 			Adapter->mppriv.workparam.io_offset = *(unsigned long *)
472 						poid_par_priv->information_buf;
473 			Adapter->mppriv.workparam.io_value = 0xcccccccc;
474 
475 		/* RegOffsetValue	- The offset of RF register to read.
476 		 * RegDataWidth	- The data width of RF register to read.
477 		 * RegDataValue	- The value to read.
478 		 * RegOffsetValue = *((unsigned long *)InformationBuffer);
479 		 * RegDataWidth = *((unsigned long *)InformationBuffer+1);
480 		 * RegDataValue =  *((unsigned long *)InformationBuffer+2);
481 		 */
482 			if (!r8712_getrfreg_cmd(Adapter,
483 			    *(unsigned char *)poid_par_priv->information_buf,
484 			    (unsigned char *)&Adapter->mppriv.workparam.io_value
485 			    ))
486 				status = RNDIS_STATUS_NOT_ACCEPTED;
487 		}
488 	} else {
489 		status = RNDIS_STATUS_INVALID_LENGTH;
490 	}
491 	return status;
492 }
493 
494 enum _CONNECT_STATE_ {
495 	CHECKINGSTATUS,
496 	ASSOCIATED,
497 	ADHOCMODE,
498 	NOTASSOCIATED
499 };
500 
501 uint oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv)
502 {
503 	struct _adapter *padapter = poid_par_priv->adapter_context;
504 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
505 	u32 ulInfo;
506 
507 	if (poid_par_priv->type_of_oid != QUERY_OID)
508 		return RNDIS_STATUS_NOT_ACCEPTED;
509 	/* nStatus==0	CheckingStatus
510 	 * nStatus==1	Associated
511 	 * nStatus==2	AdHocMode
512 	 * nStatus==3	NotAssociated
513 	 */
514 	if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
515 		ulInfo = CHECKINGSTATUS;
516 	else if (check_fwstate(pmlmepriv, _FW_LINKED))
517 		ulInfo = ASSOCIATED;
518 	else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))
519 		ulInfo = ADHOCMODE;
520 	else
521 		ulInfo = NOTASSOCIATED;
522 	*(u32 *)poid_par_priv->information_buf = ulInfo;
523 	*poid_par_priv->bytes_rw =  poid_par_priv->information_buf_len;
524 	return RNDIS_STATUS_SUCCESS;
525 }
526 
527 uint oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv)
528 {
529 	if (poid_par_priv->type_of_oid != SET_OID)
530 		return RNDIS_STATUS_NOT_ACCEPTED;
531 	return RNDIS_STATUS_SUCCESS;
532 }
533