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