| // SPDX-License-Identifier: GPL-2.0 |
| /****************************************************************************** |
| * rtl871x_ioctl_rtl.c |
| * |
| * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. |
| * Linux device driver for RTL8192SU |
| * |
| * Modifications for inclusion into the Linux staging tree are |
| * Copyright(c) 2010 Larry Finger. All rights reserved. |
| * |
| * Contact information: |
| * WLAN FAE <wlanfae@realtek.com> |
| * Larry Finger <Larry.Finger@lwfinger.net> |
| * |
| ******************************************************************************/ |
| |
| #define _RTL871X_IOCTL_RTL_C_ |
| |
| #include <linux/rndis.h> |
| #include "osdep_service.h" |
| #include "drv_types.h" |
| #include "wlan_bssdef.h" |
| #include "wifi.h" |
| #include "rtl871x_ioctl.h" |
| #include "rtl871x_ioctl_set.h" |
| #include "rtl871x_ioctl_rtl.h" |
| #include "mp_custom_oid.h" |
| #include "rtl871x_mp.h" |
| #include "rtl871x_mp_ioctl.h" |
| |
| uint oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len >= sizeof(u32)) { |
| *(u32 *)poid_par_priv->information_buf = |
| padapter->recvpriv.rx_smallpacket_crcerr; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| } else { |
| return RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len >= sizeof(u32)) { |
| *(u32 *)poid_par_priv->information_buf = |
| padapter->recvpriv.rx_middlepacket_crcerr; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| } else { |
| return RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len >= sizeof(u32)) { |
| *(u32 *)poid_par_priv->information_buf = |
| padapter->recvpriv.rx_largepacket_crcerr; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| } else { |
| return RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len >= sizeof(u32)) { |
| *(u32 *)poid_par_priv->information_buf = |
| padapter->recvpriv.rx_pkts + |
| padapter->recvpriv.rx_drop; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| } else { |
| return RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len >= sizeof(u32)) { |
| *(uint *)poid_par_priv->information_buf = |
| padapter->recvpriv.rx_icv_err; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| } else { |
| return RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != SET_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| u32 preamblemode = 0; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len >= sizeof(u32)) { |
| if (padapter->registrypriv.preamble == PREAMBLE_LONG) |
| preamblemode = 0; |
| else if (padapter->registrypriv.preamble == PREAMBLE_AUTO) |
| preamblemode = 1; |
| else if (padapter->registrypriv.preamble == PREAMBLE_SHORT) |
| preamblemode = 2; |
| *(u32 *)poid_par_priv->information_buf = preamblemode; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| } else { |
| return RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| struct eeprom_priv *peeprompriv = &padapter->eeprompriv; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| *(u16 *)poid_par_priv->information_buf = peeprompriv->channel_plan; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_set_channelplan_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| struct eeprom_priv *peeprompriv = &padapter->eeprompriv; |
| |
| if (poid_par_priv->type_of_oid != SET_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| peeprompriv->channel_plan = *(u16 *)poid_par_priv->information_buf; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_set_preamble_mode_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| u32 preamblemode = 0; |
| |
| if (poid_par_priv->type_of_oid != SET_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len >= sizeof(u32)) { |
| preamblemode = *(u32 *)poid_par_priv->information_buf; |
| if (preamblemode == 0) |
| padapter->registrypriv.preamble = PREAMBLE_LONG; |
| else if (preamblemode == 1) |
| padapter->registrypriv.preamble = PREAMBLE_AUTO; |
| else if (preamblemode == 2) |
| padapter->registrypriv.preamble = PREAMBLE_SHORT; |
| *(u32 *)poid_par_priv->information_buf = preamblemode; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| } else { |
| return RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != SET_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_dedicate_probe_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len >= sizeof(u32)) { |
| *(u32 *)poid_par_priv->information_buf = |
| padapter->xmitpriv.tx_bytes; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| } else { |
| return RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len >= sizeof(u32)) { |
| *(u32 *)poid_par_priv->information_buf = |
| padapter->recvpriv.rx_bytes; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| } else { |
| return RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_current_tx_power_level_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
| struct NDIS_802_11_CONFIGURATION *pnic_Config; |
| u32 channelnum; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (check_fwstate(pmlmepriv, _FW_LINKED) || |
| check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) |
| pnic_Config = &pmlmepriv->cur_network.network.Configuration; |
| else |
| pnic_Config = &padapter->registrypriv.dev_network.Configuration; |
| channelnum = pnic_Config->DSConfig; |
| *(u32 *)poid_par_priv->information_buf = channelnum; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_supported_wireless_mode_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| u32 ulInfo = 0; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len >= sizeof(u32)) { |
| ulInfo |= 0x0100; /* WIRELESS_MODE_B */ |
| ulInfo |= 0x0200; /* WIRELESS_MODE_G */ |
| ulInfo |= 0x0400; /* WIRELESS_MODE_A */ |
| *(u32 *) poid_par_priv->information_buf = ulInfo; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| } else { |
| return RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| |
| uint oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv |
| *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv* |
| poid_par_priv) |
| { |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != SET_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv* |
| poid_par_priv) |
| { |
| uint status = RNDIS_STATUS_SUCCESS; |
| struct _adapter *Adapter = poid_par_priv->adapter_context; |
| |
| if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */ |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len == |
| (sizeof(unsigned long) * 3)) { |
| if (!r8712_setrfreg_cmd(Adapter, |
| *(unsigned char *)poid_par_priv->information_buf, |
| (unsigned long)(*((unsigned long *) |
| poid_par_priv->information_buf + 2)))) |
| status = RNDIS_STATUS_NOT_ACCEPTED; |
| } else { |
| status = RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return status; |
| } |
| |
| uint oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| uint status = RNDIS_STATUS_SUCCESS; |
| struct _adapter *Adapter = poid_par_priv->adapter_context; |
| |
| if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */ |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| if (poid_par_priv->information_buf_len == (sizeof(unsigned long) * |
| 3)) { |
| if (Adapter->mppriv.act_in_progress) { |
| status = RNDIS_STATUS_NOT_ACCEPTED; |
| } else { |
| /* init workparam */ |
| Adapter->mppriv.act_in_progress = true; |
| Adapter->mppriv.workparam.bcompleted = false; |
| Adapter->mppriv.workparam.act_type = MPT_READ_RF; |
| Adapter->mppriv.workparam.io_offset = *(unsigned long *) |
| poid_par_priv->information_buf; |
| Adapter->mppriv.workparam.io_value = 0xcccccccc; |
| |
| /* RegOffsetValue - The offset of RF register to read. |
| * RegDataWidth - The data width of RF register to read. |
| * RegDataValue - The value to read. |
| * RegOffsetValue = *((unsigned long *)InformationBuffer); |
| * RegDataWidth = *((unsigned long *)InformationBuffer+1); |
| * RegDataValue = *((unsigned long *)InformationBuffer+2); |
| */ |
| if (!r8712_getrfreg_cmd(Adapter, |
| *(unsigned char *)poid_par_priv->information_buf, |
| (unsigned char *)&Adapter->mppriv.workparam.io_value |
| )) |
| status = RNDIS_STATUS_NOT_ACCEPTED; |
| } |
| } else { |
| status = RNDIS_STATUS_INVALID_LENGTH; |
| } |
| return status; |
| } |
| |
| enum _CONNECT_STATE_ { |
| CHECKINGSTATUS, |
| ASSOCIATED, |
| ADHOCMODE, |
| NOTASSOCIATED |
| }; |
| |
| uint oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| struct _adapter *padapter = poid_par_priv->adapter_context; |
| struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); |
| u32 ulInfo; |
| |
| if (poid_par_priv->type_of_oid != QUERY_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| /* nStatus==0 CheckingStatus |
| * nStatus==1 Associated |
| * nStatus==2 AdHocMode |
| * nStatus==3 NotAssociated |
| */ |
| if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) |
| ulInfo = CHECKINGSTATUS; |
| else if (check_fwstate(pmlmepriv, _FW_LINKED)) |
| ulInfo = ASSOCIATED; |
| else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) |
| ulInfo = ADHOCMODE; |
| else |
| ulInfo = NOTASSOCIATED; |
| *(u32 *)poid_par_priv->information_buf = ulInfo; |
| *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; |
| return RNDIS_STATUS_SUCCESS; |
| } |
| |
| uint oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv) |
| { |
| if (poid_par_priv->type_of_oid != SET_OID) |
| return RNDIS_STATUS_NOT_ACCEPTED; |
| return RNDIS_STATUS_SUCCESS; |
| } |