Linux-libre 4.14.12-gnu
[librecmc/linux-libre.git] / drivers / staging / rtl8712 / rtl871x_ioctl_rtl.c
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 }